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