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