xref: /webtrees/resources/views/edit/new-individual.phtml (revision b4a2f8851f56e7ca6fae19d0a51ff909996d7a30)
1<?php
2
3use Fisharebest\Webtrees\Auth;
4use Fisharebest\Webtrees\Fact;
5use Fisharebest\Webtrees\Functions\FunctionsEdit;
6use Fisharebest\Webtrees\Gedcom;
7use Fisharebest\Webtrees\GedcomTag;
8use Fisharebest\Webtrees\Http\RequestHandlers\AddChildToFamilyAction;
9use Fisharebest\Webtrees\Http\RequestHandlers\AddChildToIndividualAction;
10use Fisharebest\Webtrees\Http\RequestHandlers\AddParentToIndividualAction;
11use Fisharebest\Webtrees\Http\RequestHandlers\AddSpouseToFamilyAction;
12use Fisharebest\Webtrees\Http\RequestHandlers\AddSpouseToIndividualAction;
13use Fisharebest\Webtrees\Http\RequestHandlers\AddUnlinkedAction;
14use Fisharebest\Webtrees\Http\RequestHandlers\EditRawFactPage;
15use Fisharebest\Webtrees\Http\RequestHandlers\EditFactAction;
16use Fisharebest\Webtrees\I18N;
17use Fisharebest\Webtrees\Individual;
18use Fisharebest\Webtrees\SurnameTradition;
19use Fisharebest\Webtrees\View;
20use Illuminate\Support\Collection;
21
22/**
23 * @var Individual|null $individual
24 * @var Fact|null       $name_fact
25 */
26
27?>
28
29<?php
30if ($individual instanceof Individual) {
31    $xref       = $individual->xref();
32    $cancel_url = $individual->url();
33} elseif ($family !== null) {
34    $xref       = $family->xref();
35    $cancel_url = $family->url();
36} else {
37    $cancel_url = route('manage-trees', ['tree' => $tree->name()]);
38    $xref       = 'new';
39}
40
41// Different cultures do surnames differently
42$surname_tradition = SurnameTradition::create($tree->getPreference('SURNAME_TRADITION'));
43
44if ($name_fact instanceof Fact) {
45    // Editing an existing name
46    $name_fact_id = $name_fact->id();
47    $namerec      = $name_fact->gedcom();
48    $name_fields  = [
49        'NAME' => $name_fact->value(),
50        'TYPE' => $name_fact->attribute('TYPE'),
51        'NPFX' => $name_fact->attribute('NPFX'),
52        'GIVN' => $name_fact->attribute('GIVN'),
53        'NICK' => $name_fact->attribute('NICK'),
54        'SPFX' => $name_fact->attribute('SPFX'),
55        'SURN' => $name_fact->attribute('SURN'),
56        'NSFX' => $name_fact->attribute('NSFX'),
57    ];
58} else {
59    // Creating a new name
60    $name_fact_id = '';
61    $namerec      = '';
62    $name_fields  = [
63        'NAME' => '',
64        'TYPE' => '',
65        'NPFX' => '',
66        'GIVN' => '',
67        'NICK' => '',
68        'SPFX' => '',
69        'SURN' => '',
70        'NSFX' => '',
71    ];
72
73    // Inherit surname from parents, spouse or child
74    if ($family) {
75        $father = $family->husband();
76        if ($father instanceof Individual && $father->facts(['NAME'])->isNotEmpty()) {
77            $father_name = $father->facts(['NAME'])->first()->value();
78        } else {
79            $father_name = '';
80        }
81        $mother = $family->wife();
82        if ($mother instanceof Individual && $mother->facts(['NAME'])->isNotEmpty()) {
83            $mother_name = $mother->facts(['NAME'])->first()->value();
84        } else {
85            $mother_name = '';
86        }
87    } else {
88        $father      = null;
89        $mother      = null;
90        $father_name = '';
91        $mother_name = '';
92    }
93    if ($individual && $individual->facts(['NAME'])->isNotEmpty()) {
94        $indi_name = $individual->facts(['NAME'])->first()->value();
95    } else {
96        $indi_name = '';
97    }
98
99    switch ($next_action) {
100        case AddChildToFamilyAction::class:
101            $name_fields = array_merge($name_fields, $surname_tradition->newChildNames($father_name, $mother_name, $gender));
102            break;
103        case AddChildToIndividualAction::class:
104            if ($individual->sex() === 'F') {
105                $name_fields = array_merge($name_fields, $surname_tradition->newChildNames('', $indi_name, $gender));
106            } else {
107                $name_fields = array_merge($name_fields, $surname_tradition->newChildNames($indi_name, '', $gender));
108            }
109            break;
110        case AddParentToIndividualAction::class:
111            $name_fields = array_merge($name_fields, $surname_tradition->newParentNames($indi_name, $gender));
112            break;
113        case AddSpouseToFamilyAction::class:
114            if ($father) {
115                $name_fields = array_merge($name_fields, $surname_tradition->newSpouseNames($father_name, $gender));
116            } else {
117                $name_fields = array_merge($name_fields, $surname_tradition->newSpouseNames($mother_name, $gender));
118            }
119            break;
120        case AddSpouseToIndividualAction::class:
121            $name_fields = array_merge($name_fields, $surname_tradition->newSpouseNames($indi_name, $gender));
122            break;
123        case AddUnlinkedAction::class:
124        case EditFactAction::class:
125            if ($surname_tradition->hasSurnames()) {
126                $name_fields['NAME'] = '//';
127            }
128            break;
129    }
130}
131
132$bdm = ''; // used to copy '1 SOUR' to '2 SOUR' for BIRT DEAT MARR
133
134?>
135<h2 class="wt-page-title"><?= $title ?></h2>
136
137<form method="post" action="<?= e(route($next_action, ['tree' => $tree->name(), 'xref' => $xref])) ?>" onsubmit="return checkform();">
138    <input type="hidden" name="fact_id" value="<?= e($name_fact_id) ?>">
139    <input type="hidden" name="famtag" value="<?= e($famtag) ?>">
140    <input type="hidden" name="gender" value="<?= $gender ?>">
141    <?= csrf_field() ?>
142
143    <?php if ($next_action === AddChildToFamilyAction::class || $next_action === AddChildToIndividualAction::class) : ?>
144        <?= FunctionsEdit::addSimpleTag($tree, '0 PEDI') ?>
145    <?php endif ?>
146
147    <?php
148    // If we are adding a new individual, choose the sex.
149    if ($next_action !== EditFactAction::class) {
150        if ($famtag === 'HUSB' || $gender === 'M') {
151            echo FunctionsEdit::addSimpleTag($tree, '0 SEX M');
152        } elseif ($famtag === 'WIFE' || $gender === 'F') {
153            echo FunctionsEdit::addSimpleTag($tree, '0 SEX F');
154        } else {
155            echo FunctionsEdit::addSimpleTag($tree, '0 SEX');
156        }
157    }
158    ?>
159
160    <?php
161    // First - standard name fields
162    foreach ($name_fields as $tag => $value) {
163        if (substr_compare($tag, '_', 0, 1) !== 0) {
164            echo FunctionsEdit::addSimpleTag($tree, '0 ' . $tag . ' ' . $value, '', '');
165        }
166    }
167
168    // Second - advanced name fields
169    if ($surname_tradition->hasMarriedNames() || preg_match('/\n2 _MARNM /', $namerec)) {
170        $adv_name_fields = ['_MARNM' => ''];
171    } else {
172        $adv_name_fields = [];
173    }
174    if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('ADVANCED_NAME_FACTS'), $match)) {
175        foreach ($match[1] as $tag) {
176            // Ignore advanced facts that duplicate standard facts
177            if (!in_array($tag, ['TYPE', 'NPFX', 'GIVN', 'NICK', 'SPFX', 'SURN', 'NSFX'])) {
178                $adv_name_fields[$tag] = '';
179            }
180        }
181    }
182
183    foreach (array_keys($adv_name_fields) as $tag) {
184        // Edit existing tags, grouped together
185        if (preg_match_all('/2 ' . $tag . ' (.+)/', $namerec, $match)) {
186            foreach ($match[1] as $value) {
187                echo FunctionsEdit::addSimpleTag($tree, '2 ' . $tag . ' ' . $value, '', GedcomTag::getLabel('NAME:' . $tag));
188                if ($tag === '_MARNM') {
189                    preg_match_all('/\/([^\/]*)\//', $value, $matches);
190                    echo FunctionsEdit::addSimpleTag($tree, '2 _MARNM_SURN ' . implode(',', $matches[1]));
191                }
192            }
193        }
194        // Allow a new tag to be entered
195        if (!array_key_exists($tag, $name_fields)) {
196            echo FunctionsEdit::addSimpleTag($tree, '0 ' . $tag, '', GedcomTag::getLabel('NAME:' . $tag));
197            if ($tag === '_MARNM') {
198                echo FunctionsEdit::addSimpleTag($tree, '0 _MARNM_SURN');
199            }
200        }
201    }
202
203    // Third - new/existing custom name fields
204    foreach ($name_fields as $tag => $value) {
205        if (substr_compare($tag, '_', 0, 1) === 0) {
206            echo FunctionsEdit::addSimpleTag($tree, '0 ' . $tag . ' ' . $value);
207            if ($tag === '_MARNM') {
208                preg_match_all('/\/([^\/]*)\//', $value, $matches);
209                echo FunctionsEdit::addSimpleTag($tree, '2 _MARNM_SURN ' . implode(',', $matches[1]));
210            }
211        }
212    }
213
214    // Fourth - SOUR, NOTE, _CUSTOM, etc.
215    if ($namerec !== '') {
216        $gedlines = explode("\n", $namerec); // -- find the number of lines in the record
217        $fields   = explode(' ', $gedlines[0]);
218        $glevel   = $fields[0];
219        $level    = $glevel;
220        $type     = $fields[1];
221        $tags     = [];
222        $i        = 0;
223        do {
224            if ($type !== 'TYPE' && !array_key_exists($type, $name_fields) && !array_key_exists($type, $adv_name_fields)) {
225                $text = '';
226                for ($j = 2; $j < count($fields); $j++) {
227                    if ($j > 2) {
228                        $text .= ' ';
229                    }
230                    $text .= $fields[$j];
231                }
232                while (($i + 1 < count($gedlines)) && (preg_match('/' . ($level + 1) . ' CONT ?(.*)/', $gedlines[$i + 1], $cmatch) > 0)) {
233                    $text .= "\n" . $cmatch[1];
234                    $i++;
235                }
236                echo FunctionsEdit::addSimpleTag($tree, $level . ' ' . $type . ' ' . $text);
237            }
238            $tags[] = $type;
239            $i++;
240            if (isset($gedlines[$i])) {
241                $fields = explode(' ', $gedlines[$i]);
242                $level  = $fields[0];
243                if (isset($fields[1])) {
244                    $type = $fields[1];
245                }
246            }
247        } while (($level > $glevel) && ($i < count($gedlines)));
248    }
249
250    // If we are adding a new individual, add the basic details
251    if ($next_action !== EditFactAction::class) {
252        $bdm = 'BD';
253        $tags = new Collection();
254        preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches);
255        $tags = $tags->merge($matches[1]);
256
257        // If adding a spouse add the option to add a marriage fact to the new family
258        if ($next_action === AddSpouseToIndividualAction::class || $next_action === AddSpouseToFamilyAction::class) {
259            $bdm .= 'M';
260            preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches);
261            $tags = $tags->merge($matches[1]);
262        }
263
264        foreach (Fact::sortFactTags($tags) as $tag) {
265            echo view('cards/add-fact', [
266                'tag' => $tag,
267                'tree'  => $tree,
268            ]);
269        }
270    }
271
272    if ($next_action === EditFactAction::class ) {
273        // GEDCOM 5.5.1 spec says NAME doesn’t get a OBJE
274        echo view('cards/add-source-citation', [
275            'level'          => 2,
276            'full_citations' => $tree->getPreference('FULL_SOURCES'),
277            'tree'           => $tree,
278        ]);
279        echo view('cards/add-note', [
280            'level' => 2,
281            'tree'  => $tree,
282        ]);
283        echo view('cards/add-shared-note', [
284            'level' => 2,
285            'tree'  => $tree,
286        ]);
287        echo view('cards/add-restriction', [
288            'level' => 2,
289            'tree'  => $tree,
290        ]);
291    } else {
292        echo view('cards/add-source-citation', [
293            'bdm'                     => $bdm,
294            'level'                   => 1,
295            'full_citations'          => $tree->getPreference('FULL_SOURCES'),
296            'prefer_level2_sources'   => $tree->getPreference('PREFER_LEVEL2_SOURCES'),
297            'quick_required_facts'    => $tree->getPreference('QUICK_REQUIRED_FACTS'),
298            'quick_required_famfacts' => $tree->getPreference('QUICK_REQUIRED_FAMFACTS'),
299            'tree'                    => $tree,
300        ]);
301        echo view('cards/add-note', [
302            'level' => 1,
303            'tree'  => $tree,
304        ]);
305        echo view('cards/add-shared-note', [
306            'level' => 1,
307            'tree'  => $tree,
308        ]);
309        echo view('cards/add-restriction', [
310            'level' => 1,
311            'tree'  => $tree,
312        ]);
313    }
314
315    ?>
316    <div class="row form-group">
317        <div class="col-sm-9 offset-sm-3">
318            <button class="btn btn-primary" type="submit">
319                <?= view('icons/save') ?>
320                <?= /* I18N: A button label. */
321                I18N::translate('save') ?>
322            </button>
323            <?php if ($next_action !== EditFactAction::class) : ?>
324                <button class="btn btn-primary" type="submit" name="goto" value="new">
325                    <?= view('icons/save') ?>
326                    <?= /* I18N: A button label. */
327                    I18N::translate('go to new individual') ?>
328                </button>
329            <?php endif ?>
330            <a class="btn btn-secondary" href="<?= e($cancel_url) ?>">
331                <?= view('icons/cancel') ?>
332                <?= /* I18N: A button label. */
333                I18N::translate('cancel') ?>
334            </a>
335
336            <?php if ($name_fact instanceof Fact && (Auth::isAdmin() || $tree->getPreference('SHOW_GEDCOM_RECORD'))) : ?>
337                <a class="btn btn-link" href="<?= e(route(EditRawFactPage::class, ['xref' => $xref, 'fact_id' => $name_fact->id(), 'tree' => $tree->name()])) ?>">
338                    <?= I18N::translate('Edit the raw GEDCOM') ?>
339                </a>
340            <?php endif ?>
341        </div>
342    </div>
343</form>
344
345<?= view('modals/on-screen-keyboard') ?>
346<?= view('modals/ajax') ?>
347<?= view('edit/initialize-calendar-popup') ?>
348
349<?php View::push('javascript') ?>
350<script>
351    var SURNAME_TRADITION = <?= json_encode($tree->getPreference('SURNAME_TRADITION')) ?>;
352
353    var NAME = $("[name=NAME]");
354
355    // Generate a full name from the name components
356    function generate_name() {
357        var npfx      = document.querySelector("[name=NPFX]").value;
358        var givn      = document.querySelector("[name=GIVN]").value;
359        var spfx      = document.querySelector("[name=SPFX]").value;
360        var surn      = document.querySelector("[name=SURN]").value;
361        var nsfx      = document.querySelector("[name=NSFX]").value;
362        var sex_input = document.querySelector("[name=SEX]:checked");
363        var sex       = sex_input ? sex_input.value : "U";
364
365        return webtrees.buildNameFromParts(npfx, givn, spfx, surn, nsfx, sex);
366    }
367
368    // Update the NAME and _MARNM fields from the name components
369    // and also display the value in read-only "gedcom" format.
370    function updatewholename() {
371        // Don’t update the name if the user manually changed it
372        if (manualChange) {
373            return;
374        }
375
376        var npfx = document.querySelector("[name=NPFX]").value;
377        var givn = document.querySelector("[name=GIVN]").value;
378        var spfx = document.querySelector("[name=SPFX]").value;
379        var nsfx = document.querySelector("[name=NSFX]").value;
380        var name = generate_name();
381
382        var display_id = NAME.attr("id") + "_display";
383
384        NAME.val(name);
385        $("#" + display_id).text(name);
386
387        // Married names inherit some NSFX values, but not these
388        nsfx = nsfx.replace(/^(I|II|III|IV|V|VI|Junior|Jr\.?|Senior|Sr\.?)$/i, "");
389
390        // Update _MARNM field from _MARNM_SURN field and display it
391        var ip       = document.getElementsByTagName("input");
392        var marnm_id = "";
393        var romn     = "";
394        var heb      = "";
395        var i;
396
397        for (i = 0; i < ip.length; i++) {
398            if (ip[i].id.indexOf("_HEB") === 0) {
399                // Remember this field - we might need it later
400                heb = val;
401            }
402            if (ip[i].id.indexOf("ROMN") === 0) {
403                // Remember this field - we might need it later
404                romn = val;
405            }
406        }
407
408        for (i = 0; i < ip.length; i++) {
409            var val = ip[i].value;
410
411            if (ip[i].id.indexOf("_MARNM") === 0) {
412                if (ip[i].id.indexOf("_MARNM_SURN") === 0) {
413                    var msurn = "";
414                    if (val !== "") {
415                        if (webtrees.detectScript(val) === webtrees.detectScript(name)) {
416                            // Same script as NAME field?
417                            msurn = webtrees.buildNameFromParts(npfx, givn, spfx, val, nsfx);
418                        } else if (heb !== "" && webtrees.detectScript(val) === webtrees.detectScript(heb)) {
419                            // Same script as _HEB field?
420                            msurn = heb.replace(/\/.*\//, "/" + val + "/");
421                        } else if (romn !== "" && webtrees.detectScript(val) === webtrees.detectScript(romn)) {
422                            //. Same script as ROMN field
423                            msurn = romn.replace(/\/.*\//, "/" + val + "/");
424                        }
425                    }
426                    document.getElementById(marnm_id).value                  = msurn;
427                    document.getElementById(marnm_id + "_display").innerHTML = msurn;
428                } else {
429                    marnm_id = ip[i].id;
430                }
431            }
432        }
433    }
434
435    // Toggle the name editor fields between
436    // <input type="hidden"> <span style="display:inline">
437    // <input type="text">   <span style="display:none">
438
439    var oldName = "";
440
441    // Calls to generate_name() trigger an update - hence need to
442    // set the manual change to true first. We are probably
443    // listening to the wrong events on the input fields...
444    var manualChange = generate_name() !== NAME.val();
445
446    function convertHidden(eid) {
447        var input1 = $("#" + eid);
448        var input2 = $("#" + eid + "_display");
449
450        if (input1.attr("type") === "hidden") {
451            input1.attr("type", "text");
452            input2.hide();
453        } else {
454            input1.attr("type", "hidden");
455            input2.show();
456        }
457    }
458
459    /**
460     * if the user manually changed the NAME field, then update the textual
461     * HTML representation of it
462     * If the value changed set manualChange to true so that changing
463     * the other fields doesn’t change the NAME line
464     */
465    function updateTextName(eid) {
466        var element = document.getElementById(eid);
467        if (element) {
468            if (element.value !== oldName) {
469                manualChange = true;
470            }
471            var delement = document.getElementById(eid + "_display");
472            if (delement) {
473                delement.innerHTML = element.value;
474            }
475        }
476    }
477
478    function checkform() {
479        var ip = document.getElementsByTagName("input");
480        for (var i = 0; i < ip.length; i++) {
481            // ADD slashes to _HEB and _AKA names
482            if (ip[i].id.indexOf("_AKA") === 0 || ip[i].id.indexOf("_HEB") === 0 || ip[i].id.indexOf("ROMN") === 0)
483                if (ip[i].value.indexOf("/") < 0 && ip[i].value !== "")
484                    ip[i].value = ip[i].value.replace(/([^\s]+)\s*$/, "/$1/");
485            // Blank out temporary _MARNM_SURN
486            if (ip[i].id.indexOf("_MARNM_SURN") === 0)
487                ip[i].value = "";
488            // Convert "xxx yyy" and "xxx y yyy" surnames to "xxx,yyy"
489            if ((SURNAME_TRADITION === "spanish" || "SURNAME_TRADITION" === "portuguese") && ip[i].id.indexOf("SURN") === 0) {
490                ip[i].value = document.forms[0].SURN.value.replace(/^\s*([^\s,]{2,})\s+([iIyY] +)?([^\s,]{2,})\s*$/, "$1,$3");
491            }
492        }
493        return true;
494    }
495
496    // If the name isnt initially formed from the components in a standard way,
497    // then dont automatically update it.
498    if (NAME.val() !== generate_name() && NAME.val() !== "//") {
499        convertHidden(NAME.attr("id"));
500    }
501</script>
502<?php View::endpush() ?>
503
504