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