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