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