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 isn’t initially formed from the components in a standard way, 494 // then don’t 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