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