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