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