Completed
Push — develop ( 9087a8...c9b4ef )
by Greg
16:31 queued 05:44
created

print_indi_form()   F

Complexity

Conditions 78
Paths > 20000

Size

Total Lines 310
Code Lines 227

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 78
eloc 227
nc 764418816
nop 6
dl 0
loc 310
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 1730 and the first side effect is on line 25.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * webtrees: online genealogy
4
 * Copyright (C) 2018 webtrees development team
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
 * GNU General Public License for more details.
13
 * You should have received a copy of the GNU General Public License
14
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15
 */
16
17
namespace Fisharebest\Webtrees;
18
19
use Fisharebest\Webtrees\Controller\PageController;
20
use Fisharebest\Webtrees\Functions\FunctionsEdit;
21
use Fisharebest\Webtrees\Functions\FunctionsPrint;
22
use Fisharebest\Webtrees\GedcomCode\GedcomCodePedi;
23
use Fisharebest\Webtrees\Module\CensusAssistantModule;
24
25
require 'includes/session.php';
26
27
$action = Filter::post('action', null, Filter::get('action'));
28
29
$controller = new PageController;
30
$controller
31
	->restrictAccess(Auth::isEditor($controller->tree()))
32
	->addInlineJavascript('var locale_date_format="' . preg_replace('/[^DMY]/', '', str_replace(['j', 'F'], ['D', 'M'], I18N::dateFormat())) . '";');
33
34
switch ($action) {
35
case 'editraw':
36
	//////////////////////////////////////////////////////////////////////////////
37
	// Edit a GEDCOM record
38
	//////////////////////////////////////////////////////////////////////////////
39
	$xref = Filter::get('xref', WT_REGEX_XREF);
40
41
	$record = GedcomRecord::getInstance($xref, $controller->tree());
42
	check_record_access($record);
43
44
	$controller
45
		->setPageTitle($record->getFullName() . ' - ' . I18N::translate('Edit the raw GEDCOM'))
46
		->pageHeader()
47
		->addInlineJavascript('$("#raw-gedcom-list").sortable({opacity: 0.7, cursor: "move", axis: "y"});');
48
49
	?>
50
	<h2><?= $controller->getPageTitle() ?></h2>
51
52
	<form method="post">
53
		<input type="hidden" name="ged" value="<?= $controller->tree()->getNameHtml() ?>">
54
		<input type="hidden" name="action" value="updateraw">
55
		<input type="hidden" name="xref" value="<?= $xref ?>">
56
		<?= Filter::getCsrf() ?>
57
		<p class="text-muted small">
58
			<?= I18N::translate('This page allows you to bypass the usual forms, and edit the underlying data directly. It is an advanced option, and you should not use it unless you understand the GEDCOM format. If you make a mistake here, it can be difficult to fix.') ?>
59
			<?= /* I18N: %s is a URL */
60
			I18N::translate('You can download a copy of the GEDCOM specification from %s.', '<a href="https://wiki.webtrees.net/w/images-en/Ged551-5.pdf">https://wiki.webtrees.net/w/images-en/Ged551-5.pdf</a>') ?>
61
		</p>
62
		<ul id="raw-gedcom-list">
63
			<li><textarea class="form-control" readonly
64
			              rows="1"><?= '0 @' . $record->getXref() . '@ ' . $record::RECORD_TYPE ?></textarea></li>
65
			<?php foreach ($record->getFacts() as $fact): ?>
66
				<?php if (!$fact->isPendingDeletion()): ?>
67
					<li>
68
						<div style="cursor:move;">
69
							<?= $fact->summary() ?>
70
						</div>
71
						<input type="hidden" name="fact_id[]" value="<?= $fact->getFactId() ?>">
72
						<textarea name="fact[]" dir="ltr" rows="<?= preg_match_all('/\n/', $fact->getGedcom()) ?>"
73
						          style="width:100%;"><?= e($fact->getGedcom()) ?></textarea>
74
					</li>
75
				<?php endif ?>
76
			<?php endforeach ?>
77
			<li>
78
				<div style="cursor:move;">
79
					<b><i><?= I18N::translate('Add a fact') ?></i></b>
80
				</div>
81
				<input type="hidden" name="fact_id[]" value="">
82
				<textarea name="fact[]" dir="ltr" rows="2" style="width:100%;"></textarea>
83
			</li>
84
		</ul>
85
		<div class="row form-group">
86
			<div class="col-sm-9 offset-sm-3">
87
				<button class="btn btn-primary" type="submit">
88
					<?= FontAwesome::decorativeIcon('save') ?>
89
					<?= /* I18N: A button label. */
90
					I18N::translate('save') ?>
91
				</button>
92
				<a class="btn btn-secondary" href="<?= e($record->url()) ?>">
93
					<?= FontAwesome::decorativeIcon('cancel') ?>
94
					<?= /* I18N: A button label. */
95
					I18N::translate('cancel') ?>
96
				</a>
97
			</div>
98
		</div>
99
	</form>
100
	<?php
101
	break;
102
103
case 'updateraw':
104
	//////////////////////////////////////////////////////////////////////////////
105
	// Save an updated GEDCOM record
106
	//////////////////////////////////////////////////////////////////////////////
107
	$xref     = Filter::post('xref', WT_REGEX_XREF);
108
	$facts    = Filter::postArray('fact');
109
	$fact_ids = Filter::postArray('fact_id');
110
111
	if (!Filter::checkCsrf()) {
112
		header('Location: edit_interface.php?action=editraw&xref=' . $xref);
113
		break;
114
	}
115
116
	$record = GedcomRecord::getInstance($xref, $controller->tree());
117
	check_record_access($record);
118
119
	$gedcom = '0 @' . $record->getXref() . '@ ' . $record::RECORD_TYPE;
120
121
	// Retain any private facts
122
	foreach ($record->getFacts(null, false, Auth::PRIV_HIDE) as $fact) {
123
		if (!in_array($fact->getFactId(), $fact_ids) && !$fact->isPendingDeletion()) {
124
			$gedcom .= "\n" . $fact->getGedcom();
125
		}
126
	}
127
	// Append the new facts
128
	foreach ($facts as $fact) {
129
		$gedcom .= "\n" . $fact;
130
	}
131
132
	// Cleanup the client’s bad editing?
133
	$gedcom = preg_replace('/[\r\n]+/', "\n", $gedcom); // Empty lines
134
	$gedcom = trim($gedcom); // Leading/trailing spaces
135
136
	$record->updateRecord($gedcom, false);
137
138
	header('Location: ' . $record->url());
139
	break;
140
141
case 'editrawfact':
142
	//////////////////////////////////////////////////////////////////////////////
143
	// Edit a GEDCOM fact
144
	//////////////////////////////////////////////////////////////////////////////
145
	$xref    = Filter::get('xref', WT_REGEX_XREF);
146
	$fact_id = Filter::get('fact_id');
147
148
	$record = GedcomRecord::getInstance($xref, $controller->tree());
149
	check_record_access($record);
150
151
	// Find the fact to edit
152
	$edit_fact = null;
153
	foreach ($record->getFacts() as $fact) {
154
		if ($fact->getFactId() === $fact_id && $fact->canEdit()) {
155
			$edit_fact = $fact;
156
			break;
157
		}
158
	}
159
	if (!$edit_fact) {
160
		header('Location: ' . $record->url());
161
		break;
162
	}
163
164
	$controller
165
		->setPageTitle($record->getFullName() . ' - ' . I18N::translate('Edit the raw GEDCOM'))
166
		->pageHeader();
167
168
	// How many lines to use in the edit control?
169
	$rows = count(explode("\n", $edit_fact->getGedcom())) + 2;
170
171
	?>
172
	<h2><?= $controller->getPageTitle() ?></h2>
173
174
	<form method="post">
175
		<input type="hidden" name="ged" value="<?= $controller->tree()->getNameHtml() ?>">
176
		<input type="hidden" name="action" value="updaterawfact">
177
		<input type="hidden" name="xref" value="<?= $xref ?>">
178
		<input type="hidden" name="fact_id" value="<?= $fact_id ?>">
179
		<?= Filter::getCsrf() ?>
180
		<p class="text-muted small">
181
			<?= I18N::translate('This page allows you to bypass the usual forms, and edit the underlying data directly. It is an advanced option, and you should not use it unless you understand the GEDCOM format. If you make a mistake here, it can be difficult to fix.') ?>
182
			<?= /* I18N: %s is a URL */
183
			I18N::translate('You can download a copy of the GEDCOM specification from %s.', '<a href="https://wiki.webtrees.net/w/images-en/Ged551-5.pdf">https://wiki.webtrees.net/w/images-en/Ged551-5.pdf</a>') ?>
184
		</p>
185
		<div class="row form-group">
186
			<label class="col-sm-3 col-form-label" for="gedcom">
187
				<?= GedcomTag::getLabel($edit_fact->getTag()) ?>
188
			</label>
189
			<div class="col-sm-9">
190
					<textarea autofocus class="form-control" rows="<?= $rows ?>" name="gedcom" id="gedcom"
191
					          dir="ltr"><?= e($edit_fact->getGedcom()) ?></textarea>
192
			</div>
193
		</div>
194
		<?= keep_chan($record) ?>
195
		<div class="row form-group">
196
			<div class="col-sm-9 offset-sm-3">
197
				<button class="btn btn-primary" type="submit">
198
					<?= FontAwesome::decorativeIcon('save') ?>
199
					<?= /* I18N: A button label. */
200
					I18N::translate('save') ?>
201
				</button>
202
				<a class="btn btn-secondary" href="<?= e($record->url()) ?>">
203
					<?= FontAwesome::decorativeIcon('cancel') ?>
204
					<?= /* I18N: A button label. */
205
					I18N::translate('cancel') ?>
206
				</a>
207
			</div>
208
		</div>
209
	</form>
210
	<?php
211
	break;
212
213
case 'updaterawfact':
214
	//////////////////////////////////////////////////////////////////////////////
215
	// Save an updated GEDCOM fact
216
	//////////////////////////////////////////////////////////////////////////////
217
	$xref      = Filter::post('xref', WT_REGEX_XREF);
218
	$fact_id   = Filter::post('fact_id');
219
	$gedcom    = Filter::post('gedcom');
220
	$keep_chan = Filter::postBool('keep_chan');
221
222
	if (!Filter::checkCsrf()) {
223
		header('Location: edit_interface.php?action=editrawfact&xref=' . $xref . '&fact_id=' . $fact_id);
224
		break;
225
	}
226
227
	$record = GedcomRecord::getInstance($xref, $controller->tree());
228
	check_record_access($record);
229
230
	// Find the fact to edit
231
	foreach ($record->getFacts() as $fact) {
232
		if ($fact->getFactId() === $fact_id && $fact->canEdit()) {
233
			// Cleanup the client’s bad editing?
234
			$gedcom = preg_replace('/[\r\n]+/', "\n", $gedcom); // Empty lines
235
			$gedcom = trim($gedcom); // Leading/trailing spaces
236
237
			$record->updateFact($fact_id, $gedcom, !$keep_chan);
238
			break;
239
		}
240
	}
241
242
	header('Location: ' . $record->url());
243
	break;
244
245
case 'edit':
246
	//////////////////////////////////////////////////////////////////////////////
247
	// Edit a fact
248
	//////////////////////////////////////////////////////////////////////////////
249
	$xref    = Filter::get('xref', WT_REGEX_XREF);
250
	$fact_id = Filter::get('fact_id');
251
252
	$record = GedcomRecord::getInstance($xref, $controller->tree());
253
	check_record_access($record);
254
255
	// Find the fact to edit
256
	$edit_fact = null;
257
	foreach ($record->getFacts() as $fact) {
258
		if ($fact->getFactId() === $fact_id && $fact->canEdit()) {
259
			$edit_fact = $fact;
260
			break;
261
		}
262
	}
263
	if (!$edit_fact) {
264
		header('Location: ' . $record->url());
265
		break;
266
	}
267
268
	$controller
269
		->setPageTitle($record->getFullName() . ' - ' . GedcomTag::getLabel($edit_fact->getTag()))
270
		->pageHeader();
271
272
	echo '<h2>', $controller->getPageTitle(), '</h2>';
273
	FunctionsPrint::initializeCalendarPopup();
274
	echo '<form name="editform" method="post" enctype="multipart/form-data">';
275
	echo '<input type="hidden" name="ged" value="', $controller->tree()->getNameHtml(), '">';
276
	echo '<input type="hidden" name="action" value="update">';
277
	echo '<input type="hidden" name="fact_id" value="', $fact_id, '">';
278
	echo '<input type="hidden" name="xref" value="', $xref, '">';
279
	echo '<input type="hidden" name="prev_action" value="edit">';
280
	echo Filter::getCsrf();
281
	FunctionsEdit::createEditForm($edit_fact);
282
	echo keep_chan($record);
283
284
	$level1type = $edit_fact->getTag();
285
	switch ($record::RECORD_TYPE) {
286
		case 'REPO':
287
			// REPO:NAME facts may take a NOTE (but the REPO record may not).
288
			if ($level1type === 'NAME') {
289
				FunctionsEdit::printAddLayer('NOTE');
290
				FunctionsEdit::printAddLayer('SHARED_NOTE');
291
			}
292
			break;
293
		case 'FAM':
294
		case 'INDI':
295
			// FAM and INDI records have real facts. They can take NOTE/SOUR/OBJE/etc.
296
			if ($level1type !== 'SEX' && $level1type !== 'NOTE' && $level1type !== 'ALIA') {
297
				if ($level1type !== 'SOUR') {
298
					FunctionsEdit::printAddLayer('SOUR');
299
				}
300
				if ($level1type !== 'OBJE') {
301
					FunctionsEdit::printAddLayer('OBJE');
302
				}
303
				FunctionsEdit::printAddLayer('NOTE');
304
				FunctionsEdit::printAddLayer('SHARED_NOTE', 2, $level1type);
305
				if ($level1type !== 'ASSO' && $level1type !== 'NOTE' && $level1type !== 'SOUR') {
306
					FunctionsEdit::printAddLayer('ASSO');
307
				}
308
				// allow to add godfather and godmother for CHR fact or best man and bridesmaid  for MARR fact in one window
309
				if (in_array($level1type, Config::twoAssociates())) {
310
					FunctionsEdit::printAddLayer('ASSO2');
311
				}
312
				if ($level1type !== 'SOUR') {
313
					FunctionsEdit::printAddLayer('RESN');
314
				}
315
			}
316
			break;
317
		default:
318
			// Other types of record do not have these lower-level records
319
			break;
320
	}
321
322
	?>
323
	<div class="row form-group">
324
		<div class="col-sm-9 offset-sm-3">
325
			<button class="btn btn-primary" type="submit">
326
				<?= FontAwesome::decorativeIcon('save') ?>
327
				<?= /* I18N: A button label. */
328
				I18N::translate('save') ?>
329
			</button>
330
			<a class="btn btn-secondary" href="<?= e($record->url()) ?>">
331
				<?= FontAwesome::decorativeIcon('cancel') ?>
332
				<?= /* I18N: A button label. */
333
				I18N::translate('cancel') ?>
334
			</a>
335
			<?php if (Auth::isAdmin() || $controller->tree()->getPreference('SHOW_GEDCOM_RECORD')): ?>
336
				<a class="btn btn-link"
337
				   href="edit_interface.php?action=editrawfact&amp;xref=<?= $xref ?>&amp;fact_id=<?= $fact_id ?>&amp;ged=<?= $controller->tree()->getNameUrl() ?>">
338
					<?= I18N::translate('Edit the raw GEDCOM') ?>
339
				</a>
340
			<?php endif; ?>
341
		</div>
342
	</div>
343
344
	</form>
345
	<?php
346
	echo view('modals/on-screen-keyboard');
347
	echo view('modals/ajax');
348
	break;
349
350
case 'add':
351
	//////////////////////////////////////////////////////////////////////////////
352
	// Add a new fact
353
	//////////////////////////////////////////////////////////////////////////////
354
	$xref = Filter::get('xref', WT_REGEX_XREF);
355
	$fact = Filter::get('fact', WT_REGEX_TAG);
356
357
	$record = GedcomRecord::getInstance($xref, $controller->tree());
358
	check_record_access($record);
359
360
	$controller
361
		->setPageTitle($record->getFullName() . ' - ' . GedcomTag::getLabel($fact, $record))
362
		->pageHeader();
363
364
	$level0type = $record::RECORD_TYPE;
365
366
	echo '<h2>', $controller->getPageTitle(), '</h2>';
367
368
	FunctionsPrint::initializeCalendarPopup();
369
	echo '<form name="addform" method="post" enctype="multipart/form-data">';
370
	echo '<input type="hidden" name="ged" value="', $controller->tree()->getNameHtml(), '">';
371
	echo '<input type="hidden" name="action" value="update">';
372
	echo '<input type="hidden" name="xref" value="', $xref, '">';
373
	echo '<input type="hidden" name="prev_action" value="add">';
374
	echo '<input type="hidden" name="fact_type" value="' . $fact . '">';
375
	echo Filter::getCsrf();
376
	FunctionsEdit::createAddForm($fact);
377
	echo keep_chan($record);
378
379
	// Genealogical facts (e.g. for INDI and FAM records) can have 2 SOUR/NOTE/OBJE/ASSO/RESN ...
380
	if ($level0type === 'INDI' || $level0type === 'FAM') {
381
		// ... but not facts which are simply links to other records
382
		if ($fact !== 'OBJE' && $fact !== 'NOTE' && $fact !== 'SHARED_NOTE' && $fact !== 'REPO' && $fact !== 'SOUR' && $fact !== 'SUBM' && $fact !== 'ASSO' && $fact !== 'ALIA') {
383
			FunctionsEdit::printAddLayer('SOUR');
384
			FunctionsEdit::printAddLayer('OBJE');
385
			// Don’t add notes to notes!
386
			if ($fact !== 'NOTE') {
387
				FunctionsEdit::printAddLayer('NOTE');
388
				FunctionsEdit::printAddLayer('SHARED_NOTE', 2, $fact);
389
			}
390
			FunctionsEdit::printAddLayer('ASSO');
391
			// allow to add godfather and godmother for CHR fact or best man and bridesmaid  for MARR fact in one window
392
			if (in_array($fact, Config::twoAssociates())) {
393
				FunctionsEdit::printAddLayer('ASSO2');
394
			}
395
			FunctionsEdit::printAddLayer('RESN');
396
		}
397
	}
398
	?>
399
	<div class="row form-group">
400
		<div class="col-sm-9 offset-sm-3">
401
			<button class="btn btn-primary" type="submit">
402
				<?= FontAwesome::decorativeIcon('save') ?>
403
				<?= /* I18N: A button label. */
404
				I18N::translate('save') ?>
405
			</button>
406
			<a class="btn btn-secondary" href="<?= e($record->url()) ?>">
407
				<?= FontAwesome::decorativeIcon('cancel') ?>
408
				<?= /* I18N: A button label. */
409
				I18N::translate('cancel') ?>
410
			</a>
411
		</div>
412
	</div>
413
	</form>
414
	<?php
415
	echo view('modals/on-screen-keyboard');
416
	echo view('modals/ajax');
417
418
	break;
419
420
case 'update':
421
	//////////////////////////////////////////////////////////////////////////////
422
	// Save a new/updated fact
423
	//////////////////////////////////////////////////////////////////////////////
424
	$xref      = Filter::post('xref', WT_REGEX_XREF);
425
	$fact_id   = Filter::post('fact_id');
426
	$keep_chan = Filter::postBool('keep_chan');
427
428
	if (!Filter::checkCsrf()) {
429
		$prev_action = Filter::post('prev_action', 'add|edit|addname|editname');
430
		$fact_type   = Filter::post('fact_type', WT_REGEX_TAG);
431
		header('Location: edit_interface.php?action=' . $prev_action . '&xref=' . $xref . '&fact_id=' . $fact_id . '&fact=' . $fact_type);
432
		break;
433
	}
434
435
	$record = GedcomRecord::getInstance($xref, $controller->tree());
436
	check_record_access($record);
437
438
	// Arrays for each GEDCOM line
439
	$glevels = Filter::postArray('glevels', '[0-9]');
440
	$tag     = Filter::postArray('tag', WT_REGEX_TAG);
441
	$text    = Filter::postArray('text');
442
	$islink  = Filter::postArray('islink', '[01]');
443
444
	// If the fact has a DATE or PLAC, then delete any value of Y
445
	if ($text[0] === 'Y') {
446
		foreach ($tag as $n => $value) {
447
			if ($glevels[$n] == 2 && ($value === 'DATE' || $value === 'PLAC') && $text[$n] !== '') {
448
				$text[0] = '';
449
				break;
450
			}
451
		}
452
	}
453
454
	$newged = '';
455
	if (!empty($_POST['NAME'])) {
456
		$newged .= "\n1 NAME " . $_POST['NAME'];
457
		$name_facts = ['TYPE', 'NPFX', 'GIVN', 'NICK', 'SPFX', 'SURN', 'NSFX'];
458
		foreach ($name_facts as $name_fact) {
459
			if (!empty($_POST[$name_fact])) {
460
				$newged .= "\n2 " . $name_fact . ' ' . $_POST[$name_fact];
461
			}
462
		}
463
	}
464
465
	if (isset($_POST['NOTE'])) {
466
		$NOTE = $_POST['NOTE'];
467
	}
468
	if (!empty($NOTE)) {
469
		$tempnote = preg_split('/\r?\n/', trim($NOTE) . "\n"); // make sure only one line ending on the end
470
		$title[]  = '0 @' . $xref . '@ NOTE ' . array_shift($tempnote);
471
		foreach ($tempnote as &$line) {
472
			$line = trim('1 CONT ' . $line, ' ');
473
		}
474
	}
475
476
	$newged = FunctionsEdit::handleUpdates($newged);
477
478
	// Add new names after existing names
479
	if (!empty($_POST['NAME'])) {
480
		preg_match_all('/[_0-9A-Z]+/', $controller->tree()->getPreference('ADVANCED_NAME_FACTS'), $match);
481
		$name_facts = array_unique(array_merge(['_MARNM'], $match[0]));
482
		foreach ($name_facts as $name_fact) {
483
			// Ignore advanced facts that duplicate standard facts.
484
			if (!in_array($name_fact, ['TYPE', 'NPFX', 'GIVN', 'NICK', 'SPFX', 'SURN', 'NSFX']) && !empty($_POST[$name_fact])) {
485
				$newged .= "\n2 " . $name_fact . ' ' . $_POST[$name_fact];
486
			}
487
		}
488
	}
489
490
	$newged = substr($newged, 1); // Remove leading newline
491
492
	/** @var CensusAssistantModule $census_assistant */
493
	$census_assistant = Module::getModuleByName('GEDFact_assistant');
494
	if ($census_assistant !== null && $record instanceof Individual) {
495
		$newged = $census_assistant->updateCensusAssistant($record, $fact_id, $newged, $keep_chan);
496
	}
497
498
	$record->updateFact($fact_id, $newged, !$keep_chan);
499
500
	// For the GEDFact_assistant module
501
	$pid_array = Filter::post('pid_array');
502
	if ($pid_array) {
503
		foreach (explode(',', $pid_array) as $pid) {
504
			if ($pid !== $xref) {
505
				$indi = Individual::getInstance($pid, $controller->tree());
506
				if ($indi && $indi->canEdit()) {
507
					$indi->updateFact($fact_id, $newged, !$keep_chan);
508
				}
509
			}
510
		}
511
	}
512
513
	header('Location: ' . $record->url());
514
	break;
515
516
case 'add_child_to_family':
517
	//////////////////////////////////////////////////////////////////////////////
518
	// Add a child to an existing family
519
	//////////////////////////////////////////////////////////////////////////////
520
	$xref   = Filter::get('xref', WT_REGEX_XREF);
521
	$gender = Filter::get('gender', '[MFU]', 'U');
522
523
	$family = Family::getInstance($xref, $controller->tree());
524
	check_record_access($family);
525
526
	$controller
527
		->setPageTitle($family->getFullName() . ' - ' . I18N::translate('Add a child'))
528
		->pageHeader();
529
530
	print_indi_form('add_child_to_family_action', null, $family, null, 'CHIL', $gender);
531
	break;
532
533
case 'add_child_to_family_action':
534
	//////////////////////////////////////////////////////////////////////////////
535
	// Add a child to an existing family
536
	//////////////////////////////////////////////////////////////////////////////
537
	$xref      = Filter::post('xref', WT_REGEX_XREF);
538
	$PEDI      = Filter::post('PEDI');
539
	$keep_chan = Filter::postBool('keep_chan');
540
	$glevels   = Filter::postArray('glevels', '[0-9]');
541
	$tag       = Filter::postArray('tag', WT_REGEX_TAG);
542
	$text      = Filter::postArray('text');
543
	$islink    = Filter::postArray('islink', '[01]');
544
545
	if (!Filter::checkCsrf()) {
546
		$gender = Filter::get('gender', '[MFU]', 'U');
547
		header('Location: edit_interface.php?action=add_child_to_family&xref=' . $xref . '&gender=' . $gender);
548
		break;
549
	}
550
551
	$family = Family::getInstance($xref, $controller->tree());
552
	check_record_access($family);
553
554
	FunctionsEdit::splitSource();
555
	$gedrec = '0 @REF@ INDI';
556
	$gedrec .= FunctionsEdit::addNewName();
557
	$gedrec .= FunctionsEdit::addNewSex();
558
	if (preg_match_all('/([A-Z0-9_]+)/', $controller->tree()->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
559
		foreach ($matches[1] as $match) {
560
			$gedrec .= FunctionsEdit::addNewFact($match);
561
		}
562
	}
563
	$gedrec .= "\n" . GedcomCodePedi::createNewFamcPedi($PEDI, $xref);
564
	if (Filter::postBool('SOUR_INDI')) {
565
		$gedrec = FunctionsEdit::handleUpdates($gedrec);
566
	} else {
567
		$gedrec = FunctionsEdit::updateRest($gedrec);
568
	}
569
570
	// Create the new child
571
	$new_child = $family->getTree()->createRecord($gedrec);
572
573
	// Insert new child at the right place
574
	$done = false;
575
	foreach ($family->getFacts('CHIL') as $fact) {
576
		$old_child = $fact->getTarget();
577
		if ($old_child && Date::compare($new_child->getEstimatedBirthDate(), $old_child->getEstimatedBirthDate()) < 0) {
578
			// Insert before this child
579
			$family->updateFact($fact->getFactId(), '1 CHIL @' . $new_child->getXref() . "@\n" . $fact->getGedcom(), !$keep_chan);
580
			$done = true;
581
			break;
582
		}
583
	}
584
	if (!$done) {
585
		// Append child at end
586
		$family->createFact('1 CHIL @' . $new_child->getXref() . '@', !$keep_chan);
587
	}
588
589
	if (Filter::post('goto') === 'new') {
590
		header('Location: ' . $new_child->url());
591
	} else {
592
		header('Location: ' . $family->url());
593
	}
594
	break;
595
596
case 'add_child_to_individual':
597
	//////////////////////////////////////////////////////////////////////////////
598
	// Add a child to an existing individual (creating a one-parent family)
599
	//////////////////////////////////////////////////////////////////////////////
600
	$xref = Filter::get('xref', WT_REGEX_XREF);
601
602
	$person = Individual::getInstance($xref, $controller->tree());
603
	check_record_access($person);
604
605
	$controller
606
		->setPageTitle($person->getFullName() . ' - ' . I18N::translate('Add a child to create a one-parent family'))
607
		->pageHeader();
608
609
	print_indi_form('add_child_to_individual_action', $person, null, null, 'CHIL', 'U');
610
	break;
611
612
case 'add_child_to_individual_action':
613
	//////////////////////////////////////////////////////////////////////////////
614
	// Add a child to an existing individual (creating a one-parent family)
615
	//////////////////////////////////////////////////////////////////////////////
616
	$xref    = Filter::post('xref', WT_REGEX_XREF);
617
	$PEDI    = Filter::post('PEDI');
618
	$glevels = Filter::postArray('glevels', '[0-9]');
619
	$tag     = Filter::postArray('tag', WT_REGEX_TAG);
620
	$text    = Filter::postArray('text');
621
	$islink  = Filter::postArray('islink', '[01]');
622
623
	if (!Filter::checkCsrf()) {
624
		header('Location: edit_interface.php?action=add_child_to_individual&xref=' . $xref);
625
		break;
626
	}
627
628
	$person = Individual::getInstance($xref, $controller->tree());
629
	check_record_access($person);
630
631
	// Create a family
632
	if ($person->getSex() === 'F') {
633
		$gedcom = "0 @NEW@ FAM\n1 WIFE @" . $person->getXref() . '@';
634
	} else {
635
		$gedcom = "0 @NEW@ FAM\n1 HUSB @" . $person->getXref() . '@';
636
	}
637
	$family = $person->getTree()->createRecord($gedcom);
638
639
	// Link the parent to the family
640
	$person->createFact('1 FAMS @' . $family->getXref() . '@', true);
641
642
	// Create a child
643
	FunctionsEdit::splitSource(); // separate SOUR record from the rest
644
645
	$gedcom = '0 @NEW@ INDI';
646
	$gedcom .= FunctionsEdit::addNewName();
647
	$gedcom .= FunctionsEdit::addNewSex();
648
	$gedcom .= "\n" . GedcomCodePedi::createNewFamcPedi($PEDI, $family->getXref());
649
	if (preg_match_all('/([A-Z0-9_]+)/', $controller->tree()->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
650
		foreach ($matches[1] as $match) {
651
			$gedcom .= FunctionsEdit::addNewFact($match);
652
		}
653
	}
654
	if (Filter::postBool('SOUR_INDI')) {
655
		$gedcom = FunctionsEdit::handleUpdates($gedcom);
656
	} else {
657
		$gedcom = FunctionsEdit::updateRest($gedcom);
658
	}
659
660
	$child = $person->getTree()->createRecord($gedcom);
661
662
	// Link the family to the child
663
	$family->createFact('1 CHIL @' . $child->getXref() . '@', true);
664
665
	if (Filter::post('goto') === 'new') {
666
		header('Location: ' . $child->url());
667
	} else {
668
		header('Location: ' . $person->url());
669
	}
670
	break;
671
672
case 'add_parent_to_individual':
673
	//////////////////////////////////////////////////////////////////////////////
674
	// Add a new parent to an existing individual (creating a one-parent family)
675
	//////////////////////////////////////////////////////////////////////////////
676
	$xref   = Filter::get('xref', WT_REGEX_XREF);
677
	$gender = Filter::get('gender', '[MF]', 'U');
678
679
	$individual = Individual::getInstance($xref, $controller->tree());
680
	check_record_access($individual);
681
682
	if ($gender === 'F') {
683
		$controller->setPageTitle(I18N::translate('Add a mother'));
684
		$famtag = 'WIFE';
685
	} else {
686
		$controller->setPageTitle(I18N::translate('Add a father'));
687
		$famtag = 'HUSB';
688
	}
689
	$controller->pageHeader();
690
691
	print_indi_form('add_parent_to_individual_action', $individual, null, null, $famtag, $gender);
692
	break;
693
694
case 'add_parent_to_individual_action':
695
	//////////////////////////////////////////////////////////////////////////////
696
	// Add a new parent to an existing individual (creating a one-parent family)
697
	//////////////////////////////////////////////////////////////////////////////
698
	$xref    = Filter::post('xref', WT_REGEX_XREF);
699
	$PEDI    = Filter::post('PEDI');
700
	$glevels = Filter::postArray('glevels', '[0-9]');
701
	$tag     = Filter::postArray('tag', WT_REGEX_TAG);
702
	$text    = Filter::postArray('text');
703
	$islink  = Filter::postArray('islink', '[01]');
704
705
	if (!Filter::checkCsrf()) {
706
		$gender = Filter::get('gender', '[MFU]', 'U');
707
		header('Location: edit_interface.php?action=add_parent_to_individual&xref=' . $xref . '&gender=' . $gender);
708
		break;
709
	}
710
711
	$person = Individual::getInstance($xref, $controller->tree());
712
	check_record_access($person);
713
714
	// Create a new family
715
	$gedcom = "0 @NEW@ FAM\n1 CHIL @" . $person->getXref() . '@';
716
	$family = $person->getTree()->createRecord($gedcom);
717
718
	// Link the child to the family
719
	$person->createFact('1 FAMC @' . $family->getXref() . '@', true);
720
721
	// Create a child
722
	FunctionsEdit::splitSource(); // separate SOUR record from the rest
723
724
	$gedcom = '0 @NEW@ INDI';
725
	$gedcom .= FunctionsEdit::addNewName();
726
	$gedcom .= FunctionsEdit::addNewSex();
727
	if (preg_match_all('/([A-Z0-9_]+)/', $controller->tree()->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
728
		foreach ($matches[1] as $match) {
729
			$gedcom .= FunctionsEdit::addNewFact($match);
730
		}
731
	}
732
	if (Filter::postBool('SOUR_INDI')) {
733
		$gedcom = FunctionsEdit::handleUpdates($gedcom);
734
	} else {
735
		$gedcom = FunctionsEdit::updateRest($gedcom);
736
	}
737
	$gedcom .= "\n1 FAMS @" . $family->getXref() . '@';
738
739
	$parent = $person->getTree()->createRecord($gedcom);
740
741
	// Link the family to the child
742
	if ($parent->getSex() === 'F') {
743
		$family->createFact('1 WIFE @' . $parent->getXref() . '@', true);
744
	} else {
745
		$family->createFact('1 HUSB @' . $parent->getXref() . '@', true);
746
	}
747
748
	if (Filter::post('goto') === 'new') {
749
		header('Location: ' . $parent->url());
750
	} else {
751
		header('Location: ' . $person->url());
752
	}
753
	break;
754
755
case 'add_unlinked_indi':
756
	//////////////////////////////////////////////////////////////////////////////
757
	// Add a new, unlinked individual
758
	//////////////////////////////////////////////////////////////////////////////
759
	$controller
760
		->restrictAccess(Auth::isManager($controller->tree()))
761
		->setPageTitle(I18N::translate('Create an individual'))
762
		->pageHeader();
763
764
	print_indi_form('add_unlinked_indi_action', null, null, null, null, null);
765
	break;
766
767
case 'add_unlinked_indi_action':
768
	//////////////////////////////////////////////////////////////////////////////
769
	// Add a new, unlinked individual
770
	//////////////////////////////////////////////////////////////////////////////
771
	$glevels = Filter::postArray('glevels', '[0-9]');
772
	$tag     = Filter::postArray('tag', WT_REGEX_TAG);
773
	$text    = Filter::postArray('text');
774
	$islink  = Filter::postArray('islink', '[01]');
775
776
	if (!Filter::checkCsrf()) {
777
		header('Location: edit_interface.php?action=add_unlinked_indi');
778
		break;
779
	}
780
781
	$controller->restrictAccess(Auth::isManager($controller->tree()));
782
783
	FunctionsEdit::splitSource();
784
	$gedrec = '0 @REF@ INDI';
785
	$gedrec .= FunctionsEdit::addNewName();
786
	$gedrec .= FunctionsEdit::addNewSex();
787
	if (preg_match_all('/([A-Z0-9_]+)/', $controller->tree()->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
788
		foreach ($matches[1] as $match) {
789
			$gedrec .= FunctionsEdit::addNewFact($match);
790
		}
791
	}
792
	if (Filter::postBool('SOUR_INDI')) {
793
		$gedrec = FunctionsEdit::handleUpdates($gedrec);
794
	} else {
795
		$gedrec = FunctionsEdit::updateRest($gedrec);
796
	}
797
798
	$new_indi = $controller->tree()->createRecord($gedrec);
799
800
	if (Filter::post('goto') === 'new') {
801
		header('Location: ' . $new_indi->url());
802
	} else {
803
		header('Location: admin_trees_manage.php');
804
	}
805
	break;
806
807
case 'add_spouse_to_individual':
808
	//////////////////////////////////////////////////////////////////////////////
809
	// Add a spouse to an existing individual (creating a new family)
810
	//////////////////////////////////////////////////////////////////////////////
811
	$sex  = Filter::get('sex', 'M|F', 'F');
812
	$xref = Filter::get('xref', WT_REGEX_XREF);
813
814
	$individual = Individual::getInstance($xref, $controller->tree());
815
	check_record_access($individual);
816
817
	if ($sex === 'F') {
818
		$controller->setPageTitle(I18N::translate('Add a wife'));
819
		$famtag = 'WIFE';
820
	} else {
821
		$controller->setPageTitle(I18N::translate('Add a husband'));
822
		$famtag = 'HUSB';
823
	}
824
	$controller->pageHeader();
825
826
	print_indi_form('add_spouse_to_individual_action', $individual, null, null, $famtag, $sex);
827
	break;
828
829
case 'add_spouse_to_individual_action':
830
	//////////////////////////////////////////////////////////////////////////////
831
	// Add a spouse to an existing individual (creating a new family)
832
	//////////////////////////////////////////////////////////////////////////////
833
	$xref    = Filter::post('xref'); // Add a spouse to this individual
834
	$sex     = Filter::post('SEX', '[MFU]', 'U');
835
	$glevels = Filter::postArray('glevels', '[0-9]');
836
	$tag     = Filter::postArray('tag', WT_REGEX_TAG);
837
	$text    = Filter::postArray('text');
838
	$islink  = Filter::postArray('islink', '[01]');
839
840
	if (!Filter::checkCsrf()) {
841
		header('Location: edit_interface.php?action=add_spouse_to_individual&xref=' . $xref . '&sex=' . $sex);
842
843
		break;
844
	}
845
846
	$person = Individual::getInstance($xref, $controller->tree());
847
	check_record_access($person);
848
849
	FunctionsEdit::splitSource();
850
	$indi_gedcom = '0 @REF@ INDI';
851
	$indi_gedcom .= FunctionsEdit::addNewName();
852
	$indi_gedcom .= FunctionsEdit::addNewSex();
853
	if (preg_match_all('/([A-Z0-9_]+)/', $controller->tree()->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
854
		foreach ($matches[1] as $match) {
855
			$indi_gedcom .= FunctionsEdit::addNewFact($match);
856
		}
857
	}
858
	if (Filter::postBool('SOUR_INDI')) {
859
		$indi_gedcom = FunctionsEdit::handleUpdates($indi_gedcom);
860
	} else {
861
		$indi_gedcom = FunctionsEdit::updateRest($indi_gedcom);
862
	}
863
864
	$fam_gedcom = '';
865
	if (preg_match_all('/([A-Z0-9_]+)/', $controller->tree()->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches)) {
866
		foreach ($matches[1] as $match) {
867
			$fam_gedcom .= FunctionsEdit::addNewFact($match);
868
		}
869
	}
870
	if (Filter::postBool('SOUR_FAM')) {
871
		$fam_gedcom = FunctionsEdit::handleUpdates($fam_gedcom);
872
	} else {
873
		$fam_gedcom = FunctionsEdit::updateRest($fam_gedcom);
874
	}
875
876
	// Create the new spouse
877
	$spouse = $person->getTree()->createRecord($indi_gedcom);
878
	// Create a new family
879
	if ($sex === 'F') {
880
		$family = $spouse->getTree()->createRecord("0 @NEW@ FAM\n1 WIFE @" . $spouse->getXref() . "@\n1 HUSB @" . $person->getXref() . '@' . $fam_gedcom);
881
	} else {
882
		$family = $spouse->getTree()->createRecord("0 @NEW@ FAM\n1 HUSB @" . $spouse->getXref() . "@\n1 WIFE @" . $person->getXref() . '@' . $fam_gedcom);
883
	}
884
	// Link the spouses to the family
885
	$spouse->createFact('1 FAMS @' . $family->getXref() . '@', true);
886
	$person->createFact('1 FAMS @' . $family->getXref() . '@', true);
887
888
	if (Filter::post('goto') === 'new') {
889
		header('Location: ' . $spouse->url());
890
	} else {
891
		header('Location: ' . $person->url());
892
	}
893
	break;
894
895
case 'add_spouse_to_family':
896
	//////////////////////////////////////////////////////////////////////////////
897
	// Add a spouse to an existing family
898
	//////////////////////////////////////////////////////////////////////////////
899
	$xref   = Filter::get('xref', WT_REGEX_XREF);
900
	$famtag = Filter::get('famtag', 'HUSB|WIFE');
901
902
	$family = Family::getInstance($xref, $controller->tree());
903
	check_record_access($family);
904
905
	if ($famtag === 'WIFE') {
906
		$controller->setPageTitle(I18N::translate('Add a wife'));
907
		$sex = 'F';
908
	} else {
909
		$controller->setPageTitle(I18N::translate('Add a husband'));
910
		$sex = 'M';
911
	}
912
	$controller->pageHeader();
913
914
	print_indi_form('add_spouse_to_family_action', null, $family, null, $famtag, $sex);
915
	break;
916
917
case 'add_spouse_to_family_action':
918
	//////////////////////////////////////////////////////////////////////////////
919
	// Add a spouse to an existing family
920
	//////////////////////////////////////////////////////////////////////////////
921
	$xref    = Filter::post('xref', WT_REGEX_XREF);
922
	$glevels = Filter::postArray('glevels', '[0-9]');
923
	$tag     = Filter::postArray('tag', WT_REGEX_TAG);
924
	$text    = Filter::postArray('text');
925
	$islink  = Filter::postArray('islink', '[01]');
926
927
	$family = Family::getInstance($xref, $controller->tree());
928
	check_record_access($family);
929
930
	if (!Filter::checkCsrf()) {
931
		$famtag = Filter::get('famtag', 'HUSB|WIFE');
932
		header('Location: edit_interface.php?action=add_spouse_to_family&xref=' . $xref . '&famtag=' . $famtag);
933
934
		break;
935
	}
936
937
	// Create the new spouse
938
	FunctionsEdit::splitSource(); // separate SOUR record from the rest
939
940
	$gedrec = '0 @REF@ INDI';
941
	$gedrec .= FunctionsEdit::addNewName();
942
	$gedrec .= FunctionsEdit::addNewSex();
943
	if (preg_match_all('/([A-Z0-9_]+)/', $controller->tree()->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
944
		foreach ($matches[1] as $match) {
945
			$gedrec .= FunctionsEdit::addNewFact($match);
946
		}
947
	}
948
949
	if (Filter::postBool('SOUR_INDI')) {
950
		$gedrec = FunctionsEdit::handleUpdates($gedrec);
951
	} else {
952
		$gedrec = FunctionsEdit::updateRest($gedrec);
953
	}
954
	$gedrec .= "\n1 FAMS @" . $family->getXref() . '@';
955
	$spouse = $family->getTree()->createRecord($gedrec);
956
957
	// Update the existing family - add marriage, etc
958
	if ($family->getFirstFact('HUSB')) {
959
		$family->createFact('1 WIFE @' . $spouse->getXref() . '@', true);
960
	} else {
961
		$family->createFact('1 HUSB @' . $spouse->getXref() . '@', true);
962
	}
963
	$famrec = '';
964
	if (preg_match_all('/([A-Z0-9_]+)/', $controller->tree()->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches)) {
965
		foreach ($matches[1] as $match) {
966
			$famrec .= FunctionsEdit::addNewFact($match);
967
		}
968
	}
969
	if (Filter::postBool('SOUR_FAM')) {
970
		$famrec = FunctionsEdit::handleUpdates($famrec);
971
	} else {
972
		$famrec = FunctionsEdit::updateRest($famrec);
973
	}
974
	$family->createFact(trim($famrec), true); // trim leading \n
975
976
	if (Filter::post('goto') === 'new') {
977
		header('Location: ' . $spouse->url());
978
	} else {
979
		header('Location: ' . $family->url());
980
	}
981
	break;
982
983
case 'addfamlink':
984
	//////////////////////////////////////////////////////////////////////////////
985
	// Link an individual to an existing family, as a child
986
	//////////////////////////////////////////////////////////////////////////////
987
	$xref = Filter::get('xref', WT_REGEX_XREF);
988
989
	$person = Individual::getInstance($xref, $controller->tree());
990
	check_record_access($person);
991
992
	$controller
993
		->setPageTitle($person->getFullName() . ' - ' . I18N::translate('Link this individual to an existing family as a child'))
994
		->pageHeader();
995
996
	?>
997
	<h2><?= $controller->getPageTitle() ?></h2>
998
	<form method="post" name="addchildform">
999
		<input type="hidden" name="ged" value="<?= $controller->tree()->getNameHtml() ?>">
1000
		<input type="hidden" name="action" value="linkfamaction">
1001
		<input type="hidden" name="xref" value="<?= $person->getXref() ?>">
1002
		<?= Filter::getCsrf() ?>
1003
1004
		<div class="row form-group">
1005
			<label class="col-sm-3 col-form-label" for="famid">
1006
				<?= I18N::translate('Family') ?>
1007
			</label>
1008
			<div class="col-sm-9">
1009
				<?= FunctionsEdit::formControlFamily(null, ['id' => 'famid', 'name' => 'famid']) ?>
1010
			</div>
1011
		</div>
1012
1013
		<div class="row form-group">
1014
			<label class="col-sm-3 col-form-label" for="PEDI">
1015
				<?= I18N::translate('Pedigree') ?>
1016
			</label>
1017
			<div class="col-sm-9">
1018
				<?= Bootstrap4::select(GedcomCodePedi::getValues($person), '', ['id' => 'PEDI', 'name' => 'PEDI']) ?>
1019
				<p class="small text-muted">
1020
					<?= I18N::translate('A child may have more than one set of parents. The relationship between the child and the parents can be biological, legal, or based on local culture and tradition. If no pedigree is specified, then a biological relationship will be assumed.') ?>
1021
				</p>
1022
			</div>
1023
		</div>
1024
1025
		<?= keep_chan($person) ?>
1026
1027
		<div class="row form-group">
1028
			<div class="col-sm-9 offset-sm-3">
1029
				<button class="btn btn-primary" type="submit">
1030
					<?= FontAwesome::decorativeIcon('save') ?>
1031
					<?= /* I18N: A button label. */
1032
					I18N::translate('save') ?>
1033
				</button>
1034
				<a class="btn btn-secondary" href="<?= e($person->url()) ?>">
1035
					<?= FontAwesome::decorativeIcon('cancel') ?>
1036
					<?= /* I18N: A button label. */
1037
					I18N::translate('cancel') ?>
1038
				</a>
1039
			</div>
1040
		</div>
1041
	</form>
1042
	<?php
1043
	break;
1044
1045
case 'linkfamaction':
1046
	//////////////////////////////////////////////////////////////////////////////
1047
	// Link an individual to an existing family, as a child
1048
	//////////////////////////////////////////////////////////////////////////////
1049
	$xref  = Filter::post('xref', WT_REGEX_XREF);
1050
	$famid = Filter::post('famid', WT_REGEX_XREF);
1051
	$PEDI  = Filter::post('PEDI');
1052
1053
	if (!Filter::checkCsrf()) {
1054
		header('Location: edit_interface.php?action=addfamlink&xref=' . $xref);
1055
		break;
1056
	}
1057
1058
	$person = Individual::getInstance($xref, $controller->tree());
1059
	$family = Family::getInstance($famid, $controller->tree());
1060
	check_record_access($person);
1061
	check_record_access($family);
1062
1063
	// Replace any existing child->family link (we may be changing the PEDI);
1064
	$fact_id = null;
1065
	foreach ($person->getFacts('FAMC') as $fact) {
1066
		if ($family === $fact->getTarget()) {
1067
			$fact_id = $fact->getFactId();
1068
			break;
1069
		}
1070
	}
1071
1072
	$gedcom = GedcomCodePedi::createNewFamcPedi($PEDI, $famid);
1073
	$person->updateFact($fact_id, $gedcom, true);
1074
1075
	// Only set the family->child link if it does not already exist
1076
	$edit_fact = null;
1077
	foreach ($family->getFacts('CHIL') as $fact) {
1078
		if ($person === $fact->getTarget()) {
1079
			$edit_fact = $fact;
1080
			break;
1081
		}
1082
	}
1083
	if (!$edit_fact) {
1084
		$family->createFact('1 CHIL @' . $person->getXref() . '@', true);
1085
	}
1086
1087
	header('Location: ' . $person->url());
1088
	break;
1089
1090
case 'linkspouse':
1091
	//////////////////////////////////////////////////////////////////////////////
1092
	// Link and individual to an existing individual as a spouse
1093
	//////////////////////////////////////////////////////////////////////////////
1094
	$famtag = Filter::get('famtag', 'HUSB|WIFE');
1095
	$xref   = Filter::get('xref', WT_REGEX_XREF);
1096
1097
	$person = Individual::getInstance($xref, $controller->tree());
1098
	check_record_access($person);
1099
1100
	if ($person->getSex() === 'F') {
1101
		$controller->setPageTitle($person->getFullName() . ' - ' . I18N::translate('Add a husband using an existing individual'));
1102
		$label = I18N::translate('Husband');
1103
	} else {
1104
		$controller->setPageTitle($person->getFullName() . ' - ' . I18N::translate('Add a wife using an existing individual'));
1105
		$label = I18N::translate('Wife');
1106
	}
1107
1108
	$controller->pageHeader();
1109
	FunctionsPrint::initializeCalendarPopup();
1110
1111
	?>
1112
	<h2><?= $controller->getPageTitle() ?></h2>
1113
1114
	<form method="post" name="addchildform">
1115
		<input type="hidden" name="ged" value="<?= $controller->tree()->getNameHtml() ?>">
1116
		<input type="hidden" name="action" value="linkspouseaction">
1117
		<input type="hidden" name="xref" value="<?= $person->getXref() ?>">
1118
		<input type="hidden" name="famtag" value="<?= $famtag ?>">
1119
		<?= Filter::getCsrf() ?>
1120
		<div class="form-group row">
1121
			<label class="col-sm-3 col-form-label" for="spouse">
1122
				<?= $label ?>
1123
			</label>
1124
			<div class="col-sm-9">
1125
				<?= FunctionsEdit::formControlIndividual(null, ['id' => 'spouse', 'name' => 'spid']) ?>
1126
			</div>
1127
		</div>
1128
1129
		<?= FunctionsEdit::addSimpleTag('0 MARR Y') ?>
1130
		<?= FunctionsEdit::addSimpleTag('0 DATE', 'MARR') ?>
1131
		<?= FunctionsEdit::addSimpleTag('0 PLAC', 'MARR') ?>
1132
1133
		<div class="row form-group">
1134
			<div class="col-sm-9 offset-sm-3">
1135
				<button class="btn btn-primary" type="submit">
1136
					<?= FontAwesome::decorativeIcon('save') ?>
1137
					<?= /* I18N: A button label. */ I18N::translate('save') ?>
1138
				</button>
1139
				<a class="btn btn-secondary" href="<?= e($person->url()) ?>">
1140
					<?= FontAwesome::decorativeIcon('cancel') ?>
1141
					<?= /* I18N: A button label. */ I18N::translate('cancel') ?>
1142
				</a>
1143
			</div>
1144
		</div>
1145
	</form>
1146
	<?php
1147
	break;
1148
1149
case 'linkspouseaction':
1150
	//////////////////////////////////////////////////////////////////////////////
1151
	// Link and individual to an existing individual as a spouse
1152
	//////////////////////////////////////////////////////////////////////////////
1153
	$xref    = Filter::post('xref', WT_REGEX_XREF);
1154
	$spid    = Filter::post('spid', WT_REGEX_XREF);
1155
	$famtag  = Filter::post('famtag', 'HUSB|WIFE');
1156
	$glevels = Filter::postArray('glevels', '[0-9]');
1157
	$tag     = Filter::postArray('tag', WT_REGEX_TAG);
1158
	$text    = Filter::postArray('text');
1159
	$islink  = Filter::postArray('islink', '[01]');
1160
1161
	if (!Filter::checkCsrf()) {
1162
		$famtag = Filter::get('famtag', 'HUSB|WIFE');
1163
		header('Location: edit_interface.php?action=linkspouse&xref=' . $xref . '&famtag=' . $famtag);
1164
1165
		break;
1166
	}
1167
1168
	$person = Individual::getInstance($xref, $controller->tree());
1169
	$spouse = Individual::getInstance($spid, $controller->tree());
1170
	check_record_access($person);
1171
	check_record_access($spouse);
1172
1173
	if ($person->getSex() === 'F') {
1174
		$controller->setPageTitle($person->getFullName() . ' - ' . I18N::translate('Add a husband using an existing individual'));
1175
	} else {
1176
		$controller->setPageTitle($person->getFullName() . ' - ' . I18N::translate('Add a wife using an existing individual'));
1177
	}
1178
1179
	if ($person->getSex() === 'M') {
1180
		$gedcom = "0 @new@ FAM\n1 HUSB @" . $person->getXref() . "@\n1 WIFE @" . $spouse->getXref() . '@';
1181
	} else {
1182
		$gedcom = "0 @new@ FAM\n1 HUSB @" . $spouse->getXref() . "@\n1 WIFE @" . $person->getXref() . '@';
1183
	}
1184
	FunctionsEdit::splitSource();
1185
	$gedcom .= FunctionsEdit::addNewFact('MARR');
1186
1187
	if (Filter::postBool('SOUR_FAM') || count($tagSOUR) > 0) {
1188
		// before adding 2 SOUR it needs to add 1 MARR Y first
1189
		if (FunctionsEdit::addNewFact('MARR') === '') {
1190
			$gedcom .= "\n1 MARR Y";
1191
		}
1192
		$gedcom = FunctionsEdit::handleUpdates($gedcom);
1193
	} else {
1194
		// before adding level 2 facts it needs to add 1 MARR Y first
1195
		if (FunctionsEdit::addNewFact('MARR') === '') {
1196
			$gedcom .= "\n1 MARR Y";
1197
		}
1198
		$gedcom = FunctionsEdit::updateRest($gedcom);
1199
	}
1200
1201
	$family = $person->getTree()->createRecord($gedcom);
1202
	$person->createFact('1 FAMS @' . $family->getXref() . '@', true);
1203
	$spouse->createFact('1 FAMS @' . $family->getXref() . '@', true);
1204
1205
	header('Location: ' . $person->url());
1206
	break;
1207
1208
case 'addmedia_links':
1209
	//////////////////////////////////////////////////////////////////////////////
1210
	//
1211
	//////////////////////////////////////////////////////////////////////////////
1212
	$pid = Filter::get('pid', WT_REGEX_XREF);
1213
1214
	$person = Individual::getInstance($pid, $controller->tree());
1215
	check_record_access($person);
1216
1217
	$controller
1218
		->setPageTitle(I18N::translate('Family navigator') . ' — ' . $person->getFullName())
1219
		->pageHeader();
1220
1221
	?>
1222
	<h2><?= $controller->getPageTitle() ?></h2>
1223
1224
	<form method="post" action="edit_interface.php?xref=<?= $person->getXref() ?>" onsubmit="findindi()">
1225
		<input type="hidden" name="ged" value="<?= $controller->tree()->getNameHtml() ?>">
1226
		<input type="hidden" name="action" value="addmedia_links">
1227
		<input type="hidden" name="noteid" value="newnote">
1228
		<?= Filter::getCsrf() ?>
1229
		<?php require WT_ROOT . WT_MODULES_DIR . 'GEDFact_assistant/MEDIA_ctrl.php' ?>
1230
	</form>
1231
	<?php
1232
	break;
1233
1234
case 'editnote':
1235
	//////////////////////////////////////////////////////////////////////////////
1236
	// Edit a note record
1237
	//////////////////////////////////////////////////////////////////////////////
1238
	$xref = Filter::get('xref', WT_REGEX_XREF);
1239
1240
	$note = Note::getInstance($xref, $controller->tree());
1241
	check_record_access($note);
1242
1243
	$controller
1244
		->setPageTitle(I18N::translate('Edit the shared note'))
1245
		->pageHeader();
1246
1247
	?>
1248
	<h2><?= $controller->getPageTitle() ?></h2>
1249
1250
	<form method="post">
1251
		<input type="hidden" name="ged" value="<?= $controller->tree()->getNameHtml() ?>">
1252
		<input type="hidden" name="action" value="editnoteaction">
1253
		<input type="hidden" name="xref" value="<?= $xref ?>">
1254
		<?= Filter::getCsrf() ?>
1255
		<table class="table wt-facts-table">
1256
			<tr>
1257
				<th scope="row"><?= I18N::translate('Shared note') ?></th>
1258
				<td>
1259
					<textarea name="NOTE" id="NOTE" rows="15" cols="90"><?= e($note->getNote()) ?></textarea>
1260
					<br>
1261
					<?= FunctionsPrint::printSpecialCharacterLink('NOTE') ?>
1262
				</td>
1263
			</tr>
1264
			<?= keep_chan($note) ?>
1265
		</table>
1266
		<div class="row form-group">
1267
			<div class="col-sm-9 offset-sm-3">
1268
				<button class="btn btn-primary" type="submit">
1269
					<?= FontAwesome::decorativeIcon('save') ?>
1270
					<?= /* I18N: A button label. */
1271
					I18N::translate('save') ?>
1272
				</button>
1273
				<a class="btn btn-secondary" href="<?= e($note->url()) ?>">
1274
					<?= FontAwesome::decorativeIcon('cancel') ?>
1275
					<?= /* I18N: A button label. */
1276
					I18N::translate('cancel') ?>
1277
				</a>
1278
			</div>
1279
		</div>
1280
	</form>
1281
	<?php
1282
	break;
1283
1284
case 'editnoteaction':
1285
	//////////////////////////////////////////////////////////////////////////////
1286
	// Edit a note record
1287
	//////////////////////////////////////////////////////////////////////////////
1288
	$xref      = Filter::post('xref', WT_REGEX_XREF);
1289
	$keep_chan = Filter::postBool('keep_chan');
1290
	$note      = Filter::post('NOTE');
1291
1292
	if (!Filter::checkCsrf()) {
1293
		header('Location: edit_interface.php?action=editnote&xref=' . $xref);
1294
		break;
1295
	}
1296
1297
	$record = Note::getInstance($xref, $controller->tree());
1298
	check_record_access($record);
1299
1300
	// We have user-supplied data in a replacement string - escape it against backreferences
1301
	$note = str_replace(['\\', '$'], ['\\\\', '\\$'], $note);
1302
1303
	$gedrec = preg_replace(
1304
		'/^0 @' . $record->getXref() . '@ NOTE.*(\n1 CONT.*)*/',
1305
		'0 @' . $record->getXref() . '@ NOTE ' . preg_replace("/\r?\n/", "\n1 CONT ", $note),
1306
		$record->getGedcom()
1307
	);
1308
1309
	$record->updateRecord($gedrec, !$keep_chan);
1310
1311
	header('Location: ' . $record->url());
1312
	break;
1313
1314
case 'add-media-link':
1315
	//////////////////////////////////////////////////////////////////////////////
1316
	// Link a media object to a record.
1317
	//////////////////////////////////////////////////////////////////////////////
1318
	$xref   = Filter::get('xref', WT_REGEX_XREF);
1319
	$record = GedcomRecord::getInstance($xref, $controller->tree());
1320
	check_record_access($record);
1321
1322
	$controller
1323
		->setPageTitle($record->getFullName() . ' — ' . I18N::translate('Add a media object'))
1324
		->pageHeader();
1325
1326
	?>
1327
	<h2><?= $controller->getPageTitle() ?></h2>
1328
1329
	<form method="post">
1330
		<input type="hidden" name="ged" value="<?= $record->getTree()->getNameHtml() ?>">
1331
		<input type="hidden" name="xref" value="<?= $record->getXref() ?>">
1332
		<input type="hidden" name="action" value="save-media-link">
1333
		<?= Filter::getCsrf() ?>
1334
1335
		<div class="row form-group">
1336
			<label class="col-sm-3 col-form-label" for="media-xref">
1337
				<?= I18N::translate('Media object') ?>
1338
			</label>
1339
			<div class="col-sm-9">
1340
				<div class="input-group">
1341
					<?php if ($record->getTree()->getPreference('MEDIA_UPLOAD') >= Auth::accessLevel($record->getTree())): ?>
1342
						<span class="input-group-btn">
1343
							<button class="btn btn-secondary" type="button" data-toggle="modal" data-href="<?= e(route('create-media-object', ['tree' => $record->getTree()->getName()])) ?>" data-target="#wt-ajax-modal" data-select-id="media-xref" title="<?= I18N::translate('Create a media object') ?>">
1344
								<i class="fas fa-plus" aria-hidden="true" title="<?= I18N::translate('add') ?>"></i>
1345
								<span class="sr-only"><?= I18N::translate('add') ?></span>
1346
							</button>
1347
						</span>
1348
					<?php endif ?>
1349
					<?= FunctionsEdit::formControlMediaObject(null, ['id' => 'media-xref', 'name' => 'media-xref', 'data-element-id' => 'media-xref']) ?>
1350
				</div>
1351
			</div>
1352
		</div>
1353
1354
		<div class="row form-group">
1355
			<div class="col-sm-9 offset-sm-3">
1356
				<button class="btn btn-primary" type="submit">
1357
					<?= FontAwesome::decorativeIcon('save') ?>
1358
					<?= /* I18N: A button label. */
1359
					I18N::translate('save') ?>
1360
				</button>
1361
				<a class="btn btn-secondary" href="<?= e($record->url()) ?>">
1362
					<?= FontAwesome::decorativeIcon('cancel') ?>
1363
					<?= /* I18N: A button label. */
1364
					I18N::translate('cancel') ?>
1365
				</a>
1366
			</div>
1367
		</div>
1368
	</form>
1369
	<?= view('modals/ajax') ?>
1370
	<?php
1371
	break;
1372
1373
case 'save-media-link':
1374
	//////////////////////////////////////////////////////////////////////////////
1375
	// Link a media object to a record.
1376
	//////////////////////////////////////////////////////////////////////////////
1377
	if (!Filter::checkCsrf()) {
1378
		header('Location: edit_interface.php?action=addnewrepository&ged=' . $controller->tree()->getNameUrl());
1379
		break;
1380
	}
1381
	$xref       = Filter::post('xref', WT_REGEX_XREF);
1382
	$media_xref = Filter::post('media-xref', WT_REGEX_XREF);
1383
	$record     = GedcomRecord::getInstance($xref, $controller->tree());
1384
	check_record_access($record);
1385
1386
	$gedcom = '1 OBJE @' . $media_xref . '@';
1387
1388
	$record->createFact($gedcom, true);
1389
1390
	header('Location: ' . $record->url());
1391
	break;
1392
1393
case 'editname':
1394
	//////////////////////////////////////////////////////////////////////////////
1395
	//
1396
	//////////////////////////////////////////////////////////////////////////////
1397
	$xref    = Filter::get('xref', WT_REGEX_XREF);
1398
	$fact_id = Filter::get('fact_id');
1399
1400
	$person = Individual::getInstance($xref, $controller->tree());
1401
	check_record_access($person);
1402
1403
	// Find the fact to edit
1404
	$name_fact = null;
1405
	foreach ($person->getFacts() as $fact) {
1406
		if ($fact->getFactId() === $fact_id && $fact->canEdit()) {
1407
			$name_fact = $fact;
1408
		}
1409
	}
1410
	if (!$name_fact) {
1411
		header('Location: ' . $person->url());
1412
		break;
1413
	}
1414
1415
	$controller
1416
		->setPageTitle(I18N::translate('Edit the name'))
1417
		->pageHeader();
1418
1419
	print_indi_form('update', $person, null, $name_fact, '', $person->getSex());
1420
	echo view('modals/ajax');
1421
	break;
1422
1423
case 'addname':
1424
	//////////////////////////////////////////////////////////////////////////////
1425
	//
1426
	//////////////////////////////////////////////////////////////////////////////
1427
	$xref = Filter::get('xref', WT_REGEX_XREF);
1428
1429
	$individual = Individual::getInstance($xref, $controller->tree());
1430
	check_record_access($individual);
1431
1432
	$controller
1433
		->setPageTitle($individual->getFullName() . ' — ' . I18N::translate('Add a name'))
1434
		->pageHeader();
1435
1436
	print_indi_form('update', $individual, null, null, '', $individual->getSex());
1437
	break;
1438
1439
case 'changefamily':
1440
	//////////////////////////////////////////////////////////////////////////////
1441
	// Change the members of a family record
1442
	//////////////////////////////////////////////////////////////////////////////
1443
	$xref = Filter::get('xref', WT_REGEX_XREF);
1444
1445
	$family = Family::getInstance($xref, $controller->tree());
1446
	check_record_access($family);
1447
1448
	$controller
1449
		->setPageTitle(I18N::translate('Change family members') . ' – ' . $family->getFullName())
1450
		->pageHeader();
1451
1452
	$father   = $family->getHusband();
1453
	$mother   = $family->getWife();
1454
	$children = $family->getChildren();
1455
	?>
1456
	<h2><?= $controller->getPageTitle() ?></h2>
1457
1458
	<div id="changefam">
1459
		<form name="changefamform" method="post">
1460
			<input type="hidden" name="ged" value="<?= $controller->tree()->getNameHtml() ?>">
1461
			<input type="hidden" name="action" value="changefamily_update">
1462
			<input type="hidden" name="xref" value="<?= $xref ?>">
1463
			<?= Filter::getCsrf() ?>
1464
			<table>
1465
				<tr>
1466
					<?php if ($father) { ?>
1467
						<td class="descriptionbox">
1468
							<b>
1469
								<?php
1470
								switch ($father->getSex()) {
1471
									case 'M':
1472
										echo I18N::translate('husband');
1473
										break;
1474
									case 'F':
1475
										echo I18N::translate('wife');
1476
										break;
1477
									default:
1478
										echo I18N::translate('spouse');
1479
										break;
1480
								}
1481
								?>
1482
							</b>
1483
							<input type="hidden" name="HUSB" value="<?= $father->getXref() ?>">
1484
						</td>
1485
						<td id="HUSBName" class="optionbox"><?= $father->getFullName() ?>
1486
						</td>
1487
					<?php } else { ?>
1488
						<td class="descriptionbox">
1489
							<b><?= I18N::translate('spouse') ?></b>
1490
							<input type="hidden" name="HUSB" value="">
1491
						</td>
1492
						<td id="HUSBName" class="optionbox">
1493
						</td>
1494
					<?php } ?>
1495
					<td class="optionbox">
1496
						<a href="#" id="husbrem" style="display: <?= is_null($father) ? 'none' : 'block' ?>;"
1497
						   onclick="document.changefamform.HUSB.value=''; document.getElementById('HUSBName').innerHTML=''; this.style.display='none'; return false;">
1498
							<?= I18N::translate('Remove') ?>
1499
						</a>
1500
					</td>
1501
					<td class="optionbox">
1502
					</td>
1503
				</tr>
1504
				<tr>
1505
					<?php if ($mother) { ?>
1506
						<td class="descriptionbox">
1507
							<b>
1508
								<?php
1509
								switch ($mother->getSex()) {
1510
									case 'M':
1511
										echo I18N::translate('husband');
1512
										break;
1513
									case 'F':
1514
										echo I18N::translate('wife');
1515
										break;
1516
									default:
1517
										echo I18N::translate('spouse');
1518
										break;
1519
								}
1520
								?>
1521
							</b>
1522
							<input type="hidden" name="WIFE" value="<?= $mother->getXref() ?>">
1523
						</td>
1524
						<td id="WIFEName" class="optionbox">
1525
							<?= $mother->getFullName() ?>
1526
						</td>
1527
					<?php } else { ?>
1528
						<td class="descriptionbox">
1529
							<b><?= I18N::translate('spouse') ?></b>
1530
							<input type="hidden" name="WIFE" value="">
1531
						</td>
1532
						<td id="WIFEName" class="optionbox">
1533
						</td>
1534
					<?php } ?>
1535
					<td class="optionbox">
1536
						<a href="#" id="wiferem" style="display: <?= is_null($mother) ? 'none' : 'block' ?>;"
1537
						   onclick="document.changefamform.WIFE.value=''; document.getElementById('WIFEName').innerHTML=''; this.style.display='none'; return false;">
1538
							<?= I18N::translate('Remove') ?>
1539
						</a>
1540
					</td>
1541
					<td class="optionbox">
1542
					</td>
1543
				</tr>
1544
				<?php $i = 0;
1545
				foreach ($children as $child) { ?>
1546
					<tr>
1547
						<td class="descriptionbox">
1548
							<b>
1549
								<?php
1550
								switch ($child->getSex()) {
1551
									case 'M':
1552
										echo I18N::translate('son');
1553
										break;
1554
									case 'F':
1555
										echo I18N::translate('daughter');
1556
										break;
1557
									default:
1558
										echo I18N::translate('child');
1559
										break;
1560
								}
1561
								?>
1562
							</b>
1563
							<input type="hidden" name="CHIL<?= $i ?>" value="<?= $child->getXref() ?>">
1564
						</td>
1565
						<td id="CHILName<?= $i ?>" class="optionbox"><?= $child->getFullName() ?>
1566
						</td>
1567
						<td class="optionbox">
1568
							<a href="#" id="childrem<?= $i ?>" style="display: block;"
1569
							   onclick="document.changefamform.CHIL<?= $i ?>.value=''; document.getElementById('CHILName<?= $i ?>').innerHTML=''; this.style.display='none'; return false;">
1570
								<?= I18N::translate('Remove') ?>
1571
							</a>
1572
						</td>
1573
						<td class="optionbox">
1574
						</td>
1575
					</tr>
1576
					<?php $i++;
1577
				} ?>
1578
				<tr>
1579
					<td class="descriptionbox">
1580
						<b><?= I18N::translate('child') ?></b>
1581
						<input type="hidden" name="CHIL<?= $i ?>" value="">
1582
					</td>
1583
					<td id="CHILName<?= $i ?>" class="optionbox">
1584
					</td>
1585
					<td colspan="2" class="optionbox child">
1586
						<a href="#" id="childrem<?= $i ?>" style="display: none;"
1587
						   onclick="document.changefamform.CHIL<?= $i ?>.value=''; document.getElementById('CHILName<?= $i ?>').innerHTML=''; this.style.display='none'; return false;">
1588
							<?= I18N::translate('Remove') ?>
1589
						</a>
1590
					</td>
1591
				</tr>
1592
			</table>
1593
			<div class="row form-group">
1594
				<div class="col-sm-9 offset-sm-3">
1595
					<button class="btn btn-primary" type="submit">
1596
						<?= FontAwesome::decorativeIcon('save') ?>
1597
						<?= /* I18N: A button label. */
1598
						I18N::translate('save') ?>
1599
					</button>
1600
					<a class="btn btn-secondary" href="<?= e($family->url()) ?>">
1601
						<?= FontAwesome::decorativeIcon('cancel') ?>
1602
						<?= /* I18N: A button label. */
1603
						I18N::translate('cancel') ?>
1604
					</a>
1605
				</div>
1606
			</div>
1607
		</form>
1608
	</div>
1609
	<?php
1610
	break;
1611
1612
case 'changefamily_update':
1613
	//////////////////////////////////////////////////////////////////////////////
1614
	// Change the members of a family record
1615
	//////////////////////////////////////////////////////////////////////////////
1616
	$xref      = Filter::post('xref', WT_REGEX_XREF);
1617
	$HUSB      = Filter::post('HUSB', WT_REGEX_XREF);
1618
	$WIFE      = Filter::post('WIFE', WT_REGEX_XREF);
1619
	$keep_chan = Filter::postBool('keep_chan');
1620
1621
	if (!Filter::checkCsrf()) {
1622
		header('Location: edit_interface.php?action=changefamily&xref=' . $xref);
1623
		break;
1624
	}
1625
1626
	$CHIL = [];
1627
	for ($i = 0; isset($_POST['CHIL' . $i]); ++$i) {
1628
		$CHIL[] = Filter::post('CHIL' . $i, WT_REGEX_XREF);
1629
	}
1630
1631
	$family = Family::getInstance($xref, $controller->tree());
1632
	check_record_access($family);
1633
1634
	// Current family members
1635
	$old_father   = $family->getHusband();
1636
	$old_mother   = $family->getWife();
1637
	$old_children = $family->getChildren();
1638
1639
	// New family members
1640
	$new_father   = Individual::getInstance($HUSB, $controller->tree());
1641
	$new_mother   = Individual::getInstance($WIFE, $controller->tree());
1642
	$new_children = [];
1643
	foreach ($CHIL as $child) {
1644
		$new_children[] = Individual::getInstance($child, $controller->tree());
1645
	}
1646
1647
	if ($old_father !== $new_father) {
1648
		if ($old_father) {
1649
			// Remove old FAMS link
1650
			foreach ($old_father->getFacts('FAMS') as $fact) {
1651
				if ($fact->getTarget() === $family) {
1652
					$old_father->deleteFact($fact->getFactId(), !$keep_chan);
1653
				}
1654
			}
1655
			// Remove old HUSB link
1656
			foreach ($family->getFacts('HUSB|WIFE') as $fact) {
1657
				if ($fact->getTarget() === $old_father) {
1658
					$family->deleteFact($fact->getFactId(), !$keep_chan);
1659
				}
1660
			}
1661
		}
1662
		if ($new_father) {
1663
			// Add new FAMS link
1664
			$new_father->createFact('1 FAMS @' . $family->getXref() . '@', !$keep_chan);
1665
			// Add new HUSB link
1666
			$family->createFact('1 HUSB @' . $new_father->getXref() . '@', !$keep_chan);
1667
		}
1668
	}
1669
1670
	if ($old_mother !== $new_mother) {
1671
		if ($old_mother) {
1672
			// Remove old FAMS link
1673
			foreach ($old_mother->getFacts('FAMS') as $fact) {
1674
				if ($fact->getTarget() === $family) {
1675
					$old_mother->deleteFact($fact->getFactId(), !$keep_chan);
1676
				}
1677
			}
1678
			// Remove old WIFE link
1679
			foreach ($family->getFacts('HUSB|WIFE') as $fact) {
1680
				if ($fact->getTarget() === $old_mother) {
1681
					$family->deleteFact($fact->getFactId(), !$keep_chan);
1682
				}
1683
			}
1684
		}
1685
		if ($new_mother) {
1686
			// Add new FAMS link
1687
			$new_mother->createFact('1 FAMS @' . $family->getXref() . '@', !$keep_chan);
1688
			// Add new WIFE link
1689
			$family->createFact('1 WIFE @' . $new_mother->getXref() . '@', !$keep_chan);
1690
		}
1691
	}
1692
1693
	foreach ($old_children as $old_child) {
1694
		if ($old_child && !in_array($old_child, $new_children)) {
1695
			// Remove old FAMC link
1696
			foreach ($old_child->getFacts('FAMC') as $fact) {
1697
				if ($fact->getTarget() === $family) {
1698
					$old_child->deleteFact($fact->getFactId(), !$keep_chan);
1699
				}
1700
			}
1701
			// Remove old CHIL link
1702
			foreach ($family->getFacts('CHIL') as $fact) {
1703
				if ($fact->getTarget() === $old_child) {
1704
					$family->deleteFact($fact->getFactId(), !$keep_chan);
1705
				}
1706
			}
1707
		}
1708
	}
1709
1710
	foreach ($new_children as $new_child) {
1711
		if ($new_child && !in_array($new_child, $old_children)) {
1712
			// Add new FAMC link
1713
			$new_child->createFact('1 FAMC @' . $family->getXref() . '@', !$keep_chan);
1714
			// Add new CHIL link
1715
			$family->createFact('1 CHIL @' . $new_child->getXref() . '@', !$keep_chan);
1716
		}
1717
	}
1718
1719
	header('Location: ' . $family->url());
1720
	break;
1721
}
1722
1723
/**
1724
 * Show an option to preserve the existing CHAN record when editing.
1725
 *
1726
 * @param GedcomRecord $record
1727
 *
1728
 * @return string
1729
 */
1730
function keep_chan(GedcomRecord $record = null) {
1731
	global $controller;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1732
1733
	if (Auth::isAdmin()) {
1734
		if ($record) {
1735
			$details
1736
				= GedcomTag::getLabelValue('DATE', $record->lastChangeTimestamp()) .
1737
				GedcomTag::getLabelValue('_WT_USER', e($record->lastChangeUser()));
1738
		} else {
1739
			$details = '';
1740
		}
1741
1742
		return
1743
			'<div class="form-group row"><label class="col-sm-3 col-form-label" for="keep_chan">' .
1744
			I18N::translate('Last change') .
1745
			'</label><div class="col-sm-9">' .
1746
			Bootstrap4::checkbox(I18N::translate('Keep the existing “last change” information'), true, ['name' => 'keep_chan', 'checked' => (bool) $controller->tree()->getPreference('NO_UPDATE_CHAN')]) .
1747
			$details .
1748
			'</div></div>';
1749
	} else {
1750
		return '';
1751
	}
1752
}
1753
1754
/**
1755
 * Print a form to add an individual or edit an individual’s name
1756
 *
1757
 * @param string     $nextaction
1758
 * @param Individual $person
1759
 * @param Family     $family
1760
 * @param Fact       $name_fact
1761
 * @param string     $famtag
1762
 * @param string     $gender
1763
 */
1764
function print_indi_form($nextaction, Individual $person = null, Family $family = null, Fact $name_fact = null, $famtag = 'CHIL', $gender = 'U') {
1765
	global $bdm, $controller;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1766
1767
	if ($person) {
1768
		$xref = $person->getXref();
1769
	} elseif ($family) {
1770
		$xref = $family->getXref();
1771
	} else {
1772
		$xref = 'new';
1773
	}
1774
1775
	// Different cultures do surnames differently
1776
	$surname_tradition = SurnameTradition::create($controller->tree()->getPreference('SURNAME_TRADITION'));
1777
1778
	if ($name_fact !== null) {
1779
		// Editing an existing name
1780
		$name_fact_id = $name_fact->getFactId();
1781
		$namerec      = $name_fact->getGedcom();
1782
		$name_fields  = [
1783
			'NAME' => $name_fact->getValue(),
1784
			'TYPE' => $name_fact->getAttribute('TYPE'),
1785
			'NPFX' => $name_fact->getAttribute('NPFX'),
1786
			'GIVN' => $name_fact->getAttribute('GIVN'),
1787
			'NICK' => $name_fact->getAttribute('NICK'),
1788
			'SPFX' => $name_fact->getAttribute('SPFX'),
1789
			'SURN' => $name_fact->getAttribute('SURN'),
1790
			'NSFX' => $name_fact->getAttribute('NSFX'),
1791
		];
1792
1793
		// Populate any missing subfields from the NAME field
1794
		$npfx_accept = implode('|', Config::namePrefixes());
1795
		if (preg_match('/(((' . $npfx_accept . ')\.? +)*)([^\n\/"]*)("(.*)")? *\/(([a-z]{2,3} +)*)(.*)\/ *(.*)/i', $name_fields['NAME'], $name_bits)) {
1796
			$name_fields['NPFX'] = $name_fields['NPFX'] ?: $name_bits[1];
1797
			$name_fields['GIVN'] = $name_fields['GIVN'] ?: $name_bits[4];
1798
			$name_fields['NICK'] = $name_fields['NICK'] ?: $name_bits[6];
1799
			$name_fields['SPFX'] = $name_fields['SPFX'] ?: trim($name_bits[7]);
1800
			$name_fields['SURN'] = $name_fields['SURN'] ?: preg_replace('~/[^/]*/~', ',', $name_bits[9]);
1801
			$name_fields['NSFX'] = $name_fields['NSFX'] ?: $name_bits[10];
1802
		}
1803
	} else {
1804
		// Creating a new name
1805
		$name_fact_id = null;
1806
		$namerec      = null;
1807
		$name_fields  = [
1808
			'NAME' => '',
1809
			'TYPE' => '',
1810
			'NPFX' => '',
1811
			'GIVN' => '',
1812
			'NICK' => '',
1813
			'SPFX' => '',
1814
			'SURN' => '',
1815
			'NSFX' => '',
1816
		];
1817
1818
		// Inherit surname from parents, spouse or child
1819
		if ($family) {
1820
			$father = $family->getHusband();
1821
			if ($father && $father->getFirstFact('NAME')) {
1822
				$father_name = $father->getFirstFact('NAME')->getValue();
1823
			} else {
1824
				$father_name = '';
1825
			}
1826
			$mother = $family->getWife();
1827
			if ($mother && $mother->getFirstFact('NAME')) {
1828
				$mother_name = $mother->getFirstFact('NAME')->getValue();
1829
			} else {
1830
				$mother_name = '';
1831
			}
1832
		} else {
1833
			$father      = null;
1834
			$mother      = null;
1835
			$father_name = '';
1836
			$mother_name = '';
1837
		}
1838
		if ($person && $person->getFirstFact('NAME')) {
1839
			$indi_name = $person->getFirstFact('NAME')->getValue();
1840
		} else {
1841
			$indi_name = '';
1842
		}
1843
1844
		switch ($nextaction) {
1845
			case 'add_child_to_family_action':
1846
				$name_fields = array_merge($name_fields, $surname_tradition->newChildNames($father_name, $mother_name, $gender));
1847
				break;
1848
			case 'add_child_to_individual_action':
1849
				if ($person->getSex() === 'F') {
1850
					$name_fields = array_merge($name_fields, $surname_tradition->newChildNames('', $indi_name, $gender));
1851
				} else {
1852
					$name_fields = array_merge($name_fields, $surname_tradition->newChildNames($indi_name, '', $gender));
1853
				}
1854
				break;
1855
			case 'add_parent_to_individual_action':
1856
				$name_fields = array_merge($name_fields, $surname_tradition->newParentNames($indi_name, $gender));
1857
				break;
1858
			case 'add_spouse_to_family_action':
1859
				if ($father) {
1860
					$name_fields = array_merge($name_fields, $surname_tradition->newSpouseNames($father_name, $gender));
1861
				} else {
1862
					$name_fields = array_merge($name_fields, $surname_tradition->newSpouseNames($mother_name, $gender));
1863
				}
1864
				break;
1865
			case 'add_spouse_to_individual_action':
1866
				$name_fields = array_merge($name_fields, $surname_tradition->newSpouseNames($indi_name, $gender));
1867
				break;
1868
			case 'add_unlinked_indi_action':
1869
			case 'update':
1870
				if ($surname_tradition->hasSurnames()) {
1871
					$name_fields['NAME'] = '//';
1872
				}
1873
				break;
1874
		}
1875
	}
1876
1877
	$bdm = ''; // used to copy '1 SOUR' to '2 SOUR' for BIRT DEAT MARR
1878
1879
	echo '<h2>', $controller->getPageTitle(), '</h2>';
1880
1881
	FunctionsPrint::initializeCalendarPopup();
1882
	echo '<form method="post" name="addchildform" onsubmit="return checkform();">';
1883
	echo '<input type="hidden" name="ged" value="', $controller->tree()->getNameHtml(), '">';
1884
	echo '<input type="hidden" name="action" value="', $nextaction, '">';
1885
	echo '<input type="hidden" name="fact_id" value="', $name_fact_id, '">';
1886
	echo '<input type="hidden" name="xref" value="', $xref, '">';
1887
	echo '<input type="hidden" name="famtag" value="', $famtag, '">';
1888
	echo '<input type="hidden" name="gender" value="', $gender, '">';
1889
	echo Filter::getCsrf();
1890
	echo '<table class="table wt-facts-table">';
1891
1892
	switch ($nextaction) {
1893
		case 'add_child_to_family_action':
1894
		case 'add_child_to_individual_action':
1895
			// When adding a new child, specify the pedigree
1896
			echo FunctionsEdit::addSimpleTag('0 PEDI');
1897
			break;
1898
	}
1899
	// First - standard name fields
1900
	foreach ($name_fields as $tag => $value) {
1901
		if (substr_compare($tag, '_', 0, 1) !== 0) {
1902
			echo FunctionsEdit::addSimpleTag('0 ' . $tag . ' ' . $value, '', '', null, $person);
1903
		}
1904
	}
1905
1906
	// Second - advanced name fields
1907
	if ($surname_tradition->hasMarriedNames() || preg_match('/\n2 _MARNM /', $namerec)) {
1908
		$adv_name_fields = ['_MARNM' => ''];
1909
	} else {
1910
		$adv_name_fields = [];
1911
	}
1912
	if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $controller->tree()->getPreference('ADVANCED_NAME_FACTS'), $match)) {
1913
		foreach ($match[1] as $tag) {
1914
			// Ignore advanced facts that duplicate standard facts
1915
			if (!in_array($tag, ['TYPE', 'NPFX', 'GIVN', 'NICK', 'SPFX', 'SURN', 'NSFX'])) {
1916
				$adv_name_fields[$tag] = '';
1917
			}
1918
		}
1919
	}
1920
1921
	foreach (array_keys($adv_name_fields) as $tag) {
1922
		// Edit existing tags, grouped together
1923
		if (preg_match_all('/2 ' . $tag . ' (.+)/', $namerec, $match)) {
1924
			foreach ($match[1] as $value) {
1925
				echo FunctionsEdit::addSimpleTag('2 ' . $tag . ' ' . $value, '', GedcomTag::getLabel('NAME:' . $tag, $person));
1926
				if ($tag === '_MARNM') {
1927
					preg_match_all('/\/([^\/]*)\//', $value, $matches);
1928
					echo FunctionsEdit::addSimpleTag('2 _MARNM_SURN ' . implode(',', $matches[1]));
1929
				}
1930
			}
1931
		}
1932
		// Allow a new tag to be entered
1933
		if (!array_key_exists($tag, $name_fields)) {
1934
			echo FunctionsEdit::addSimpleTag('0 ' . $tag, '', GedcomTag::getLabel('NAME:' . $tag, $person));
1935
			if ($tag === '_MARNM') {
1936
				echo FunctionsEdit::addSimpleTag('0 _MARNM_SURN');
1937
			}
1938
		}
1939
	}
1940
1941
	// Third - new/existing custom name fields
1942
	foreach ($name_fields as $tag => $value) {
1943
		if (substr_compare($tag, '_', 0, 1) === 0) {
1944
			echo FunctionsEdit::addSimpleTag('0 ' . $tag . ' ' . $value);
1945
			if ($tag === '_MARNM') {
1946
				preg_match_all('/\/([^\/]*)\//', $value, $matches);
1947
				echo FunctionsEdit::addSimpleTag('2 _MARNM_SURN ' . implode(',', $matches[1]));
1948
			}
1949
		}
1950
	}
1951
1952
	// Fourth - SOUR, NOTE, _CUSTOM, etc.
1953
	if ($namerec) {
1954
		$gedlines = explode("\n", $namerec); // -- find the number of lines in the record
1955
		$fields   = explode(' ', $gedlines[0]);
1956
		$glevel   = $fields[0];
1957
		$level    = $glevel;
1958
		$type     = $fields[1];
1959
		$tags     = [];
1960
		$i        = 0;
1961
		do {
1962
			if ($type !== 'TYPE' && !array_key_exists($type, $name_fields) && !array_key_exists($type, $adv_name_fields)) {
1963
				$text = '';
1964
				for ($j = 2; $j < count($fields); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1965
					if ($j > 2) {
1966
						$text .= ' ';
1967
					}
1968
					$text .= $fields[$j];
1969
				}
1970
				while (($i + 1 < count($gedlines)) && (preg_match('/' . ($level + 1) . ' CONT ?(.*)/', $gedlines[$i + 1], $cmatch) > 0)) {
1971
					$text .= "\n" . $cmatch[1];
1972
					$i++;
1973
				}
1974
				echo FunctionsEdit::addSimpleTag($level . ' ' . $type . ' ' . $text);
1975
			}
1976
			$tags[] = $type;
1977
			$i++;
1978
			if (isset($gedlines[$i])) {
1979
				$fields = explode(' ', $gedlines[$i]);
1980
				$level  = $fields[0];
1981
				if (isset($fields[1])) {
1982
					$type = $fields[1];
1983
				}
1984
			}
1985
		} while (($level > $glevel) && ($i < count($gedlines)));
1986
	}
1987
1988
	// If we are adding a new individual, add the basic details
1989
	if ($nextaction !== 'update') {
1990
		echo '</table><br><table class="table wt-facts-table">';
1991
		// 1 SEX
1992
		if ($famtag === 'HUSB' || $gender === 'M') {
1993
			echo FunctionsEdit::addSimpleTag('0 SEX M');
1994
		} elseif ($famtag === 'WIFE' || $gender === 'F') {
1995
			echo FunctionsEdit::addSimpleTag('0 SEX F');
1996
		} else {
1997
			echo FunctionsEdit::addSimpleTag('0 SEX U');
1998
		}
1999
		$bdm = 'BD';
2000
		if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $controller->tree()->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
2001
			foreach ($matches[1] as $match) {
2002
				if (!in_array($match, explode('|', WT_EVENTS_DEAT))) {
2003
					FunctionsEdit::addSimpleTags($match);
2004
				}
2005
			}
2006
		}
2007
		//-- if adding a spouse add the option to add a marriage fact to the new family
2008
		if ($nextaction === 'add_spouse_to_individual_action' || $nextaction === 'add_spouse_to_family_action') {
2009
			$bdm .= 'M';
2010
			if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $controller->tree()->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches)) {
2011
				foreach ($matches[1] as $match) {
2012
					FunctionsEdit::addSimpleTags($match);
2013
				}
2014
			}
2015
		}
2016
		if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $controller->tree()->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
2017
			foreach ($matches[1] as $match) {
2018
				if (in_array($match, explode('|', WT_EVENTS_DEAT))) {
2019
					FunctionsEdit::addSimpleTags($match);
2020
				}
2021
			}
2022
		}
2023
	}
2024
2025
	echo keep_chan($person);
2026
	echo '</table>';
2027
	if ($nextaction === 'update') {
2028
		// GEDCOM 5.5.1 spec says NAME doesn’t get a OBJE
2029
		FunctionsEdit::printAddLayer('SOUR');
2030
		FunctionsEdit::printAddLayer('NOTE');
2031
		FunctionsEdit::printAddLayer('SHARED_NOTE');
2032
		FunctionsEdit::printAddLayer('RESN');
2033
	} else {
2034
		FunctionsEdit::printAddLayer('SOUR', 1);
2035
		FunctionsEdit::printAddLayer('NOTE', 1);
2036
		FunctionsEdit::printAddLayer('SHARED_NOTE', 1);
2037
		FunctionsEdit::printAddLayer('RESN', 1);
2038
	}
2039
2040
	?>
2041
	<div class="row form-group">
2042
		<div class="col-sm-9 offset-sm-3">
2043
			<button class="btn btn-primary" type="submit">
2044
				<?= FontAwesome::decorativeIcon('save') ?>
2045
				<?= /* I18N: A button label. */ I18N::translate('save') ?>
2046
			</button>
2047
			<?php if (preg_match('/^add_(child|spouse|parent|unlinked_indi)/', $nextaction)): ?>
2048
2049
				<button class="btn btn-primary" type="submit" name="goto" value="<?= $xref ?>">
2050
					<?= FontAwesome::decorativeIcon('save') ?>
2051
					<?= /* I18N: A button label. */ I18N::translate('go to new individual') ?>
2052
				</button>
2053
			<?php endif ?>
2054
			<a class="btn btn-secondary" href="<?= e($person ? $person->url() : $family->url()) ?>">
2055
				<?= FontAwesome::decorativeIcon('cancel') ?>
2056
				<?= /* I18N: A button label. */ I18N::translate('cancel') ?>
2057
			</a>
2058
			<?php if ($name_fact !== null && (Auth::isAdmin() || $controller->tree()->getPreference('SHOW_GEDCOM_RECORD'))): ?>
2059
				<a class="btn btn-link"
2060
				   href="edit_interface.php?action=editrawfact&amp;xref=<?= $xref ?>&amp;fact_id=<?= $name_fact->getFactId() ?>&amp;ged=<?= $controller->tree()->getNameUrl() ?>">
2061
					<?= I18N::translate('Edit the raw GEDCOM') ?>
2062
				</a>
2063
			<?php endif ?>
2064
		</div>
2065
	</div>
2066
	</form>
2067
	<?= view('modals/ajax') ?>
2068
2069
	<?php
2070
	$controller->addInlineJavascript('
2071
	SURNAME_TRADITION="' . $controller->tree()->getPreference('SURNAME_TRADITION') . '";
2072
	gender="' . $gender . '";
2073
	famtag="' . $famtag . '";
2074
	function trim(str) {
2075
		str=str.replace(/\s\s+/g, " ");
2076
		return str.replace(/(^\s+)|(\s+$)/g, "");
2077
	}
2078
2079
	function lang_class(str) {
2080
		if (str.match(/[\u0370-\u03FF]/)) return "greek";
2081
		if (str.match(/[\u0400-\u04FF]/)) return "cyrillic";
2082
		if (str.match(/[\u0590-\u05FF]/)) return "hebrew";
2083
		if (str.match(/[\u0600-\u06FF]/)) return "arabic";
2084
		return "latin"; // No matched text implies latin :-)
2085
	}
2086
2087
	// Generate a full name from the name components
2088
	function generate_name() {
2089
		var npfx = $("#NPFX").val();
2090
		var givn = $("#GIVN").val();
2091
		var spfx = $("#SPFX").val();
2092
		var surn = $("#SURN").val();
2093
		var nsfx = $("#NSFX").val();
2094
		if (SURNAME_TRADITION === "polish" && (gender === "F" || famtag === "WIFE")) {
2095
			surn = surn.replace(/ski$/, "ska");
2096
			surn = surn.replace(/cki$/, "cka");
2097
			surn = surn.replace(/dzki$/, "dzka");
2098
			surn = surn.replace(/żki$/, "żka");
2099
		}
2100
		// Commas are used in the GIVN and SURN field to separate lists of surnames.
2101
		// For example, to differentiate the two Spanish surnames from an English
2102
		// double-barred name.
2103
		// Commas *may* be used in other fields, and will form part of the NAME.
2104
		if (WT_LOCALE === "vi" || WT_LOCALE === "hu") {
2105
			// Default format: /SURN/ GIVN
2106
			return trim(npfx+" /"+trim(spfx+" "+surn).replace(/ *, */g, " ")+"/ "+givn.replace(/ *, */g, " ")+" "+nsfx);
2107
		} else if (WT_LOCALE === "zh-Hans" || WT_LOCALE === "zh-Hant") {
2108
			// Default format: /SURN/GIVN
2109
			return npfx+"/"+spfx+surn+"/"+givn+nsfx;
2110
		} else {
2111
			// Default format: GIVN /SURN/
2112
			return trim(npfx+" "+givn.replace(/ *, */g, " ")+" /"+trim(spfx+" "+surn).replace(/ *, */g, " ")+"/ "+nsfx);
2113
		}
2114
	}
2115
2116
	// Update the NAME and _MARNM fields from the name components
2117
	// and also display the value in read-only "gedcom" format.
2118
	function updatewholename() {
2119
		// Don’t update the name if the user manually changed it
2120
		if (manualChange) {
2121
			return;
2122
		}
2123
		var npfx = $("#NPFX").val();
2124
		var givn = $("#GIVN").val();
2125
		var spfx = $("#SPFX").val();
2126
		var surn = $("#SURN").val();
2127
		var nsfx = $("#NSFX").val();
2128
		var name = generate_name();
2129
		$("#NAME").val(name);
2130
		$("#NAME_display").text(name);
2131
		// Married names inherit some NSFX values, but not these
2132
		nsfx = nsfx.replace(/^(I|II|III|IV|V|VI|Junior|Jr\.?|Senior|Sr\.?)$/i, "");
2133
		// Update _MARNM field from _MARNM_SURN field and display it
2134
		// Be careful of mixing latin/hebrew/etc. character sets.
2135
		var ip = document.getElementsByTagName("input");
2136
		var marnm_id = "";
2137
		var romn = "";
2138
		var heb = "";
2139
		for (var i = 0; i < ip.length; i++) {
2140
			var val = trim(ip[i].value);
2141
			if (ip[i].id.indexOf("_HEB") === 0)
2142
				heb = val;
2143
			if (ip[i].id.indexOf("ROMN") === 0)
2144
				romn = val;
2145
			if (ip[i].id.indexOf("_MARNM") === 0) {
2146
				if (ip[i].id.indexOf("_MARNM_SURN") === 0) {
2147
					var msurn = "";
2148
					if (val !== "") {
2149
						var lc = lang_class(document.getElementById(ip[i].id).value);
2150
						if (lang_class(name) === lc)
2151
							msurn = trim(npfx + " " + givn + " /" + val + "/ " + nsfx);
2152
						else if (lc === "hebrew")
2153
							msurn = heb.replace(/\/.*\//, "/" + val + "/");
2154
						else if (lang_class(romn) === lc)
2155
							msurn = romn.replace(/\/.*\//, "/" + val + "/");
2156
					}
2157
					document.getElementById(marnm_id).value = msurn;
2158
					document.getElementById(marnm_id+"_display").innerHTML = msurn;
2159
				} else {
2160
					marnm_id = ip[i].id;
2161
				}
2162
			}
2163
		}
2164
	}
2165
2166
	// Toggle the name editor fields between
2167
	// <input type="hidden"> <span style="display:inline">
2168
	// <input type="text">   <span style="display:none">
2169
	var oldName = "";
2170
2171
	// Calls to generate_name() trigger an update - hence need to
2172
	// set the manual change to true first. We are probably
2173
	// listening to the wrong events on the input fields...
2174
	var manualChange = true;
2175
	manualChange = generate_name() !== $("#NAME").val();
2176
2177
	function convertHidden(eid) {
2178
		var input1 = $("#" + eid);
2179
		var input2 = $("#" + eid + "_display");
2180
		// Note that IE does not allow us to change the type of an input, so we must create a new one.
2181
		if (input1.attr("type")=="hidden") {
2182
			input1.replaceWith(input1.clone().attr("type", "text"));
2183
			input2.hide();
2184
		} else {
2185
			input1.replaceWith(input1.clone().attr("type", "hidden"));
2186
			input2.show();
2187
		}
2188
	}
2189
2190
	/**
2191
	 * if the user manually changed the NAME field, then update the textual
2192
	 * HTML representation of it
2193
	 * If the value changed set manualChange to true so that changing
2194
	 * the other fields doesn’t change the NAME line
2195
	 */
2196
	function updateTextName(eid) {
2197
		var element = document.getElementById(eid);
2198
		if (element) {
2199
			if (element.value!=oldName) manualChange = true;
2200
			var delement = document.getElementById(eid+"_display");
2201
			if (delement) {
2202
				delement.innerHTML = element.value;
2203
			}
2204
		}
2205
	}
2206
2207
	function checkform() {
2208
		var ip=document.getElementsByTagName("input");
2209
		for (var i=0; i<ip.length; i++) {
2210
			// ADD slashes to _HEB and _AKA names
2211
			if (ip[i].id.indexOf("_AKA")==0 || ip[i].id.indexOf("_HEB")==0 || ip[i].id.indexOf("ROMN")==0)
2212
				if (ip[i].value.indexOf("/")<0 && ip[i].value!="")
2213
					ip[i].value=ip[i].value.replace(/([^\s]+)\s*$/, "/$1/");
2214
			// Blank out temporary _MARNM_SURN
2215
			if (ip[i].id.indexOf("_MARNM_SURN")==0)
2216
					ip[i].value="";
2217
			// Convert "xxx yyy" and "xxx y yyy" surnames to "xxx,yyy"
2218
			if ((SURNAME_TRADITION=="spanish" || "SURNAME_TRADITION"=="portuguese") && ip[i].id.indexOf("SURN")==0) {
2219
				ip[i].value=document.forms[0].SURN.value.replace(/^\s*([^\s,]{2,})\s+([iIyY] +)?([^\s,]{2,})\s*$/, "$1,$3");
2220
			}
2221
		}
2222
		return true;
2223
	}
2224
2225
	// If the name isn’t initially formed from the components in a standard way,
2226
	// then don’t automatically update it.
2227
	if (document.getElementById("NAME").value!=generate_name() && document.getElementById("NAME").value!="//") {
2228
		convertHidden("NAME");
2229
	}
2230
	');
2231
}
2232
2233
/**
2234
 * Can we edit a GedcomRecord object
2235
 *
2236
 * @param GedcomRecord $record
2237
 */
2238
function check_record_access(GedcomRecord $record = null) {
2239
	if (!$record || !$record->canShow() || !$record->canEdit()) {
2240
		header('Location: ' . $record->url());
2241
2242
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
2243
	}
2244
}
2245