xref: /webtrees/app/Module/CensusAssistantModule.php (revision 047f239b70b792655dbaa183656298db216028ae)
18c2e8227SGreg Roach<?php
28c2e8227SGreg Roach/**
38c2e8227SGreg Roach * webtrees: online genealogy
46bdf7674SGreg Roach * Copyright (C) 2017 webtrees development team
58c2e8227SGreg Roach * This program is free software: you can redistribute it and/or modify
68c2e8227SGreg Roach * it under the terms of the GNU General Public License as published by
78c2e8227SGreg Roach * the Free Software Foundation, either version 3 of the License, or
88c2e8227SGreg Roach * (at your option) any later version.
98c2e8227SGreg Roach * This program is distributed in the hope that it will be useful,
108c2e8227SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
118c2e8227SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
128c2e8227SGreg Roach * GNU General Public License for more details.
138c2e8227SGreg Roach * You should have received a copy of the GNU General Public License
148c2e8227SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
158c2e8227SGreg Roach */
1615d603e7SGreg Roach
1776692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module;
1876692c8bSGreg Roach
193a7bc14aSDavid Druryuse Fisharebest\Webtrees\Census\Census;
20ad51e0bbSGreg Roachuse Fisharebest\Webtrees\Census\CensusInterface;
210e62c4b8SGreg Roachuse Fisharebest\Webtrees\Family;
220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Filter;
2315d603e7SGreg Roachuse Fisharebest\Webtrees\FontAwesome;
243d7a8a4cSGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsDb;
2515d603e7SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsEdit;
260e62c4b8SGreg Roachuse Fisharebest\Webtrees\GedcomRecord;
27*047f239bSGreg Roachuse Fisharebest\Webtrees\Html;
280e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
2999f222b3SGreg Roachuse Fisharebest\Webtrees\Individual;
300e62c4b8SGreg Roachuse Fisharebest\Webtrees\Note;
31dc46b574SDavid Druryuse Fisharebest\Webtrees\Soundex;
328c2e8227SGreg Roach
338c2e8227SGreg Roach/**
348c2e8227SGreg Roach * Class CensusAssistantModule
358c2e8227SGreg Roach */
3615834aaeSGreg Roachclass CensusAssistantModule extends AbstractModule {
378c2e8227SGreg Roach	/** {@inheritdoc} */
388c2e8227SGreg Roach	public function getTitle() {
3915d603e7SGreg Roach		return /* I18N: Name of a module */
4015d603e7SGreg Roach			I18N::translate('Census assistant');
418c2e8227SGreg Roach	}
428c2e8227SGreg Roach
438c2e8227SGreg Roach	/** {@inheritdoc} */
448c2e8227SGreg Roach	public function getDescription() {
4515d603e7SGreg Roach		return /* I18N: Description of the “Census assistant” module */
4615d603e7SGreg Roach			I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
478c2e8227SGreg Roach	}
488c2e8227SGreg Roach
4976692c8bSGreg Roach	/**
5076692c8bSGreg Roach	 * This is a general purpose hook, allowing modules to respond to routes
5176692c8bSGreg Roach	 * of the form module.php?mod=FOO&mod_action=BAR
5276692c8bSGreg Roach	 *
5376692c8bSGreg Roach	 * @param string $mod_action
5476692c8bSGreg Roach	 */
558c2e8227SGreg Roach	public function modAction($mod_action) {
5615d603e7SGreg Roach		global $WT_TREE;
5715d603e7SGreg Roach
588c2e8227SGreg Roach		switch ($mod_action) {
5915d603e7SGreg Roach		case 'census-header':
6015d603e7SGreg Roach			header('Content-Type: text/html; charset=utf8');
6115d603e7SGreg Roach			$census = Filter::get('census');
6215d603e7SGreg Roach			echo $this->censusTableHeader(new $census);
638c2e8227SGreg Roach			break;
6415d603e7SGreg Roach
6515d603e7SGreg Roach		case 'census-individual':
6615d603e7SGreg Roach			header('Content-Type: text/html; charset=utf8');
6715d603e7SGreg Roach			$census     = Filter::get('census');
6815d603e7SGreg Roach			$individual = Individual::getInstance(Filter::get('xref'), $WT_TREE);
6915d603e7SGreg Roach			$head       = Individual::getInstance(Filter::get('head'), $WT_TREE);
7015d603e7SGreg Roach			echo $this->censusTableRow(new $census, $individual, $head);
7115d603e7SGreg Roach			break;
7215d603e7SGreg Roach
7340990b78SGreg Roach		case 'media_find':
74764a01d9SGreg Roach			self::mediaFind();
758c2e8227SGreg Roach			break;
768c2e8227SGreg Roach		case 'media_query_3a':
77764a01d9SGreg Roach			self::mediaQuery();
788c2e8227SGreg Roach			break;
798c2e8227SGreg Roach		default:
808c2e8227SGreg Roach			http_response_code(404);
818c2e8227SGreg Roach		}
828c2e8227SGreg Roach	}
838c2e8227SGreg Roach
848c2e8227SGreg Roach	/**
8515d603e7SGreg Roach	 * @param Individual $individual
868c2e8227SGreg Roach	 */
8715d603e7SGreg Roach	public function createCensusAssistant(Individual $individual) {
8815d603e7SGreg Roach		?>
8940990b78SGreg Roach
9015d603e7SGreg Roach		<div id="census-assistant-link" hidden>
9115d603e7SGreg Roach			<a href="#">
9215d603e7SGreg Roach				<?= I18N::translate('Create a shared note using the census assistant') ?>
9315d603e7SGreg Roach			</a>
9415d603e7SGreg Roach		</div>
9540990b78SGreg Roach
9615d603e7SGreg Roach		<div id="census-assistant" hidden>
9715d603e7SGreg Roach			<input type="hidden" name="ca_census" id="ca-census">
9815d603e7SGreg Roach			<div class="form-group">
9915d603e7SGreg Roach				<div class="input-group">
10015d603e7SGreg Roach					<label for="census-assistant-title" class="input-group-addon">
10115d603e7SGreg Roach						<?= I18N::translate('Title') ?>
10215d603e7SGreg Roach					</label>
10315d603e7SGreg Roach					<input class="form-control" id="ca-title" name="ca_title" value="">
10415d603e7SGreg Roach				</div>
10515d603e7SGreg Roach			</div>
10640990b78SGreg Roach
10715d603e7SGreg Roach			<div class="row">
10815d603e7SGreg Roach				<div class="form-group col-sm-6">
10915d603e7SGreg Roach					<div class="input-group">
11015d603e7SGreg Roach						<label for="census-assistant-citation" class="input-group-addon">
11115d603e7SGreg Roach							<?= I18N::translate('Citation') ?>
11215d603e7SGreg Roach						</label>
11315d603e7SGreg Roach						<input class="form-control" id="census-assistant-citation" name="ca_citation">
11415d603e7SGreg Roach					</div>
11515d603e7SGreg Roach				</div>
11640990b78SGreg Roach
11715d603e7SGreg Roach				<div class="form-group col-sm-6">
11815d603e7SGreg Roach					<div class="input-group">
11915d603e7SGreg Roach						<label for="census-assistant-place" class="input-group-addon">
12015d603e7SGreg Roach							<?= I18N::translate('Place') ?>
12115d603e7SGreg Roach						</label>
12215d603e7SGreg Roach						<input class="form-control" id="census-assistant-place" name="ca_place">
12315d603e7SGreg Roach					</div>
12415d603e7SGreg Roach				</div>
12515d603e7SGreg Roach			</div>
12640990b78SGreg Roach
12715d603e7SGreg Roach			<div class="form-group">
12815d603e7SGreg Roach				<div class="input-group">
12915d603e7SGreg Roach					<span class="input-group-addon"><?= I18N::translate('Individuals') ?></span>
13015d603e7SGreg Roach					<?= FunctionsEdit::formControlIndividual($individual, ['id' => 'census-assistant-individual', 'style' => 'width:100%']) ?>
13115d603e7SGreg Roach					<span class="input-group-btn">
13215d603e7SGreg Roach						<button type="button" class="btn btn-primary" id="census-assistant-add">
13315d603e7SGreg Roach							<?= FontAwesome::semanticIcon('add', I18N::translate('Add')) ?>
13415d603e7SGreg Roach						</button>
13515d603e7SGreg Roach					</span>
13615d603e7SGreg Roach					<span class="input-group-btn">
13715d603e7SGreg Roach						<button type="button" class="btn btn-primary" id="census-assistant-head"
13815d603e7SGreg Roach						        title="<?= I18N::translate('Head of household') ?>">
13915d603e7SGreg Roach							<?= FontAwesome::semanticIcon('individual', I18N::translate('Head of household')) ?>
14015d603e7SGreg Roach						</button>
14115d603e7SGreg Roach					</span>
14215d603e7SGreg Roach				</div>
14315d603e7SGreg Roach			</div>
14415d603e7SGreg Roach
14515d603e7SGreg Roach			<table class="table table-bordered table-small table-responsive wt-census-assistant-table"
14615d603e7SGreg Roach			       id="census-assistant-table">
14715d603e7SGreg Roach				<thead class="wt-census-assistant-header"></thead>
14815d603e7SGreg Roach				<tbody class="wt-census-assistant-body"></tbody>
14915d603e7SGreg Roach			</table>
15015d603e7SGreg Roach
15115d603e7SGreg Roach			<div class="form-group">
15215d603e7SGreg Roach				<div class="input-group">
15315d603e7SGreg Roach					<label for="census-assistant-notes" class="input-group-addon">
15415d603e7SGreg Roach						<?= I18N::translate('Notes') ?>
15515d603e7SGreg Roach					</label>
15615d603e7SGreg Roach					<input class="form-control" id="census-assistant-notes" name="ca_notes">
15715d603e7SGreg Roach				</div>
15815d603e7SGreg Roach			</div>
15915d603e7SGreg Roach		</div>
16015d603e7SGreg Roach
16115d603e7SGreg Roach		<script>
16215d603e7SGreg Roach			// When a census date/place is selected, activate the census-assistant
16315d603e7SGreg Roach			function censusAssistantSelect() {
16415d603e7SGreg Roach				var censusAssistantLink = document.querySelector('#census-assistant-link');
16515d603e7SGreg Roach				var censusAssistant     = document.querySelector('#census-assistant');
16615d603e7SGreg Roach				var censusOption        = this.options[this.selectedIndex];
16715d603e7SGreg Roach				var census              = censusOption.dataset.census;
16815d603e7SGreg Roach				var censusPlace         = censusOption.dataset.place;
16915d603e7SGreg Roach				var censusYear          = censusOption.value.substr(-4);
17015d603e7SGreg Roach
17115d603e7SGreg Roach				if (censusOption.value !== '') {
17215d603e7SGreg Roach					censusAssistantLink.removeAttribute('hidden');
17340990b78SGreg Roach				} else {
17415d603e7SGreg Roach					censusAssistantLink.setAttribute('hidden', '');
17540990b78SGreg Roach				}
17615d603e7SGreg Roach
17715d603e7SGreg Roach				censusAssistant.setAttribute('hidden', '');
17815d603e7SGreg Roach				document.querySelector('#ca-census').value = census;
17915d603e7SGreg Roach				document.querySelector('#ca-title').value  = censusYear + ' ' + censusPlace + ' - <?= I18N::translate('Census transcript') ?> - <?= strip_tags($individual->getFullName()) ?> - <?= I18N::translate('Household') ?>';
18015d603e7SGreg Roach
18115d603e7SGreg Roach				fetch('module.php?mod=GEDFact_assistant&mod_action=census-header&census=' + census)
18215d603e7SGreg Roach					.then(function (response) {
18315d603e7SGreg Roach						return response.text();
18415d603e7SGreg Roach					})
18515d603e7SGreg Roach					.then(function (text) {
18615d603e7SGreg Roach						document.querySelector('#census-assistant-table thead').innerHTML = text;
18715d603e7SGreg Roach						document.querySelector('#census-assistant-table tbody').innerHTML = '';
18815d603e7SGreg Roach					});
189ad51e0bbSGreg Roach			}
19015d603e7SGreg Roach
19115d603e7SGreg Roach			// When the census assistant is activated, show the input fields
19215d603e7SGreg Roach			function censusAssistantLink() {
19315d603e7SGreg Roach				document.querySelector('#census-selector').setAttribute('hidden', '');
19415d603e7SGreg Roach				this.setAttribute('hidden', '');
19515d603e7SGreg Roach				document.getElementById('census-assistant').removeAttribute('hidden');
19615d603e7SGreg Roach				// Set the current individual as the head of household.
19715d603e7SGreg Roach				censusAssistantHead();
19815d603e7SGreg Roach
19915d603e7SGreg Roach				return false;
20015d603e7SGreg Roach			}
20115d603e7SGreg Roach
20215d603e7SGreg Roach			// Add the currently selected individual to the census
20315d603e7SGreg Roach			function censusAssistantAdd() {
20415d603e7SGreg Roach				var censusSelector = document.querySelector('#census-selector');
20515d603e7SGreg Roach				var census         = censusSelector.options[censusSelector.selectedIndex].dataset.census;
20615d603e7SGreg Roach				var indi_selector  = document.querySelector('#census-assistant-individual');
20715d603e7SGreg Roach				var xref           = indi_selector.options[indi_selector.selectedIndex].value;
20815d603e7SGreg Roach				var headTd         = document.querySelector('#census-assistant-table td');
20915d603e7SGreg Roach				var head           = headTd === null ? xref : headTd.innerHTML;
21015d603e7SGreg Roach
21115d603e7SGreg Roach				fetch('module.php?mod=GEDFact_assistant&mod_action=census-individual&census=' + census + '&xref=' + xref + '&head=' + head, {credentials: 'same-origin'})
21215d603e7SGreg Roach					.then(function (response) {
21315d603e7SGreg Roach						return response.text();
21415d603e7SGreg Roach					})
21515d603e7SGreg Roach					.then(function (text) {
21615d603e7SGreg Roach						document.querySelector('#census-assistant-table tbody').innerHTML += text;
21715d603e7SGreg Roach					});
21815d603e7SGreg Roach
21915d603e7SGreg Roach				return false;
22015d603e7SGreg Roach			}
22115d603e7SGreg Roach
22215d603e7SGreg Roach			// Set the currently selected individual as the head of household
22315d603e7SGreg Roach			function censusAssistantHead() {
22415d603e7SGreg Roach				var censusSelector = document.querySelector('#census-selector');
22515d603e7SGreg Roach				var census         = censusSelector.options[censusSelector.selectedIndex].dataset.census;
22615d603e7SGreg Roach				var indi_selector  = document.querySelector('#census-assistant-individual');
22715d603e7SGreg Roach				var xref           = indi_selector.options[indi_selector.selectedIndex].value;
22815d603e7SGreg Roach
22915d603e7SGreg Roach				fetch('module.php?mod=GEDFact_assistant&mod_action=census-individual&census=' + census + '&xref=' + xref + '&head=' + xref, {credentials: 'same-origin'})
23015d603e7SGreg Roach					.then(function (response) {
23115d603e7SGreg Roach						return response.text();
23215d603e7SGreg Roach					})
23315d603e7SGreg Roach					.then(function (text) {
23415d603e7SGreg Roach						document.querySelector('#census-assistant-table tbody').innerHTML = text;
23515d603e7SGreg Roach					});
23615d603e7SGreg Roach
23715d603e7SGreg Roach				return false;
23815d603e7SGreg Roach			}
23915d603e7SGreg Roach
24015d603e7SGreg Roach			document.querySelector('#census-selector').addEventListener('change', censusAssistantSelect);
24115d603e7SGreg Roach			document.querySelector('#census-assistant-link').addEventListener('click', censusAssistantLink);
24215d603e7SGreg Roach			document.querySelector('#census-assistant-add').addEventListener('click', censusAssistantAdd);
24315d603e7SGreg Roach			document.querySelector('#census-assistant-head').addEventListener('click', censusAssistantHead);
24415d603e7SGreg Roach		</script>
24515d603e7SGreg Roach		<?php
24615d603e7SGreg Roach	}
24715d603e7SGreg Roach
24815d603e7SGreg Roach	/**
24915d603e7SGreg Roach	 * @param Individual $individual
25060bc3e3fSGreg Roach	 * @param string     $fact_id
25115d603e7SGreg Roach	 * @param string     $newged
25260bc3e3fSGreg Roach	 * @param bool       $keep_chan
25315d603e7SGreg Roach	 *
25415d603e7SGreg Roach	 * @return string
25515d603e7SGreg Roach	 */
25615d603e7SGreg Roach	public function updateCensusAssistant(Individual $individual, $fact_id, $newged, $keep_chan) {
25715d603e7SGreg Roach		$ca_title       = Filter::post('ca_title');
25815d603e7SGreg Roach		$ca_place       = Filter::post('ca_place');
25915d603e7SGreg Roach		$ca_citation    = Filter::post('ca_citation');
26015d603e7SGreg Roach		$ca_individuals = Filter::postArray('ca_individuals');
26115d603e7SGreg Roach		$ca_notes       = Filter::post('ca_notes');
26215d603e7SGreg Roach		$ca_census      = Filter::post('ca_census', 'Fisharebest\\\\Webtrees\\\\Census\\\\CensusOf[A-Za-z0-9]+');
26315d603e7SGreg Roach
26415d603e7SGreg Roach		if ($ca_census !== '' && !empty($ca_individuals)) {
26515d603e7SGreg Roach			$census = new $ca_census;
26615d603e7SGreg Roach
26715d603e7SGreg Roach			$note_text   = $this->createNoteText($census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes);
26815d603e7SGreg Roach			$note_gedcom = '0 @new@ NOTE ' . str_replace("\n", "\n1 CONT ", $note_text);
26915d603e7SGreg Roach			$note        = $individual->getTree()->createRecord($note_gedcom);
27015d603e7SGreg Roach
27115d603e7SGreg Roach			$newged .= "\n2 NOTE @" . $note->getXref() . '@';
27215d603e7SGreg Roach
27315d603e7SGreg Roach			// Add the census fact to the rest of the household
27415d603e7SGreg Roach			foreach (array_keys($ca_individuals) as $xref) {
27515d603e7SGreg Roach				if ($xref !== $individual->getXref()) {
27615d603e7SGreg Roach					Individual::getInstance($xref, $individual->getTree())
27715d603e7SGreg Roach						->updateFact($fact_id, $newged, !$keep_chan);
27815d603e7SGreg Roach				}
27915d603e7SGreg Roach			}
28015d603e7SGreg Roach		}
28115d603e7SGreg Roach
28215d603e7SGreg Roach		return $newged;
28315d603e7SGreg Roach	}
28415d603e7SGreg Roach
28515d603e7SGreg Roach	/**
28615d603e7SGreg Roach	 * @param CensusInterface $census
28715d603e7SGreg Roach	 * @param string          $ca_title
28815d603e7SGreg Roach	 * @param string          $ca_place
28915d603e7SGreg Roach	 * @param string          $ca_citation
29015d603e7SGreg Roach	 * @param string[][]      $ca_individuals
29115d603e7SGreg Roach	 * @param string          $ca_notes
29215d603e7SGreg Roach	 *
29315d603e7SGreg Roach	 * @return string
29415d603e7SGreg Roach	 */
29515d603e7SGreg Roach	private function createNoteText(CensusInterface $census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes) {
29615d603e7SGreg Roach		$text = $ca_title . "\n" . $ca_citation . "\n" . $ca_place . "\n\n.start_formatted_area.\n\n";
29715d603e7SGreg Roach
29815d603e7SGreg Roach		foreach ($census->columns() as $n => $column) {
29915d603e7SGreg Roach			if ($n > 0) {
30015d603e7SGreg Roach				$text .= '|';
30115d603e7SGreg Roach			}
30215d603e7SGreg Roach			$text .= '.b.' . $column->abbreviation();
30315d603e7SGreg Roach		}
30415d603e7SGreg Roach
30515d603e7SGreg Roach		foreach ($ca_individuals as $xref => $columns) {
30615d603e7SGreg Roach			$text .= "\n" . implode('|', $columns);
30715d603e7SGreg Roach		}
30815d603e7SGreg Roach
30915d603e7SGreg Roach		return $text . "\n.end_formatted_area.\n\n" . $ca_notes;
31040990b78SGreg Roach	}
31140990b78SGreg Roach
31240990b78SGreg Roach	/**
31376692c8bSGreg Roach	 * Find a media object.
31440990b78SGreg Roach	 */
315764a01d9SGreg Roach	private static function mediaFind() {
3168c2e8227SGreg Roach		global $WT_TREE;
3178c2e8227SGreg Roach
3188c2e8227SGreg Roach		$controller = new SimpleController;
3198c2e8227SGreg Roach		$filter     = Filter::get('filter');
3208c2e8227SGreg Roach		$multiple   = Filter::getBool('multiple');
3218c2e8227SGreg Roach
3228c2e8227SGreg Roach		$controller
3238c2e8227SGreg Roach			->setPageTitle(I18N::translate('Find an individual'))
3248c2e8227SGreg Roach			->pageHeader();
3258c2e8227SGreg Roach
3268c2e8227SGreg Roach		?>
32799f222b3SGreg Roach		<script>
3288c2e8227SGreg Roach			function pasterow(id, name, gend, yob, age, bpl) {
3298c2e8227SGreg Roach				window.opener.opener.insertRowToTable(id, name, '', gend, '', yob, age, 'Y', '', bpl);
3308c2e8227SGreg Roach			}
3318c2e8227SGreg Roach
3328c2e8227SGreg Roach			function pasteid(id, name, thumb) {
3338c2e8227SGreg Roach				if (thumb) {
3348c2e8227SGreg Roach					window.opener.paste_id(id, name, thumb);
33515d603e7SGreg Roach					<?php if (!$multiple) {
33615d603e7SGreg Roach					echo 'window.close();';
33715d603e7SGreg Roach				} ?>
3388c2e8227SGreg Roach				} else {
3398c2e8227SGreg Roach					// GEDFact_assistant ========================
3408c2e8227SGreg Roach					if (window.opener.document.getElementById('addlinkQueue')) {
3418c2e8227SGreg Roach						window.opener.insertRowToTable(id, name);
3428c2e8227SGreg Roach					}
3438c2e8227SGreg Roach					window.opener.paste_id(id);
3448c2e8227SGreg Roach					if (window.opener.pastename) {
3458c2e8227SGreg Roach						window.opener.pastename(name);
3468c2e8227SGreg Roach					}
34715d603e7SGreg Roach					<?php if (!$multiple) {
34815d603e7SGreg Roach					echo 'window.close();';
34915d603e7SGreg Roach				} ?>
3508c2e8227SGreg Roach				}
3518c2e8227SGreg Roach			}
35215d603e7SGreg Roach
3538c2e8227SGreg Roach			function checknames(frm) {
3546fde90caSGreg Roach				var button = '';
3558c2e8227SGreg Roach				if (document.forms[0].subclick) {
3568c2e8227SGreg Roach					button = document.forms[0].subclick.value;
3578c2e8227SGreg Roach				}
35815d603e7SGreg Roach				if (frm.filter.value.length < 2 && button !== 'all') {
35915d603e7SGreg Roach					alert('<?= I18N::translate('Please enter more than one character.') ?>');
3608c2e8227SGreg Roach					frm.filter.focus();
3618c2e8227SGreg Roach					return false;
3628c2e8227SGreg Roach				}
3636fde90caSGreg Roach				if (button === 'all') {
36415d603e7SGreg Roach					frm.filter.value = '';
3658c2e8227SGreg Roach				}
3668c2e8227SGreg Roach				return true;
3678c2e8227SGreg Roach			}
36899f222b3SGreg Roach		</script>
3698c2e8227SGreg Roach
37099f222b3SGreg Roach		<?php
371a86dd8b1SGreg Roach		echo '<div>';
3724c621133SGreg Roach		echo '<table class="list_table width90" border="0">';
373a86dd8b1SGreg Roach		echo '<tr><td style="padding: 10px;" class="facts_label03 width90">'; // start column for find text header
3748c2e8227SGreg Roach		echo $controller->getPageTitle();
3754c621133SGreg Roach		echo '</td>';
3764c621133SGreg Roach		echo '</tr>';
3774c621133SGreg Roach		echo '</table>';
3784c621133SGreg Roach		echo '<br>';
3798c2e8227SGreg Roach		echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
3804c621133SGreg Roach		echo '<br>';
3818c2e8227SGreg Roach
3828c2e8227SGreg Roach		$filter       = trim($filter);
3838c2e8227SGreg Roach		$filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
3844c621133SGreg Roach		echo '<table class="tabs_table width90"><tr>';
38513abd6f3SGreg Roach		$myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
3868c2e8227SGreg Roach		if ($myindilist) {
3874c621133SGreg Roach			echo '<td class="list_value_wrap"><ul>';
3880e62c4b8SGreg Roach			usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
3898c2e8227SGreg Roach			foreach ($myindilist as $indi) {
390cc5ab399SGreg Roach				$nam = Html::escape($indi->getFullName());
3918c2e8227SGreg Roach				echo "<li><a href=\"#\" onclick=\"pasterow(
3928c2e8227SGreg Roach					'" . $indi->getXref() . "' ,
3938c2e8227SGreg Roach					'" . $nam . "' ,
3948c2e8227SGreg Roach					'" . $indi->getSex() . "' ,
3957820e4d7SGreg Roach					'" . $indi->getBirthYear() . "' ,
3967820e4d7SGreg Roach					'" . (1901 - $indi->getBirthYear()) . "' ,
3977820e4d7SGreg Roach					'" . $indi->getBirthPlace() . "'); return false;\">
3987a6ee1acSGreg Roach					<b>" . $indi->getFullName() . '</b>&nbsp;&nbsp;&nbsp;';
3998c2e8227SGreg Roach
400564ae2d7SGreg Roach				$born = I18N::translate('Birth');
4017a6ee1acSGreg Roach				echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace(), '</span></a></li>';
4027a6ee1acSGreg Roach				echo '<hr>';
4038c2e8227SGreg Roach			}
4048c2e8227SGreg Roach			echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
4058c2e8227SGreg Roach		} else {
4067a6ee1acSGreg Roach			echo '<td class="list_value_wrap">';
4078c2e8227SGreg Roach			echo I18N::translate('No results found.');
4087a6ee1acSGreg Roach			echo '</td></tr>';
4098c2e8227SGreg Roach		}
4107a6ee1acSGreg Roach		echo '</table>';
4118c2e8227SGreg Roach		echo '</div>';
4128c2e8227SGreg Roach	}
4138c2e8227SGreg Roach
4148c2e8227SGreg Roach	/**
41576692c8bSGreg Roach	 * Search for a media object.
4168c2e8227SGreg Roach	 */
417764a01d9SGreg Roach	private static function mediaQuery() {
41824ec66ceSGreg Roach		global $WT_TREE;
41924ec66ceSGreg Roach
4208c2e8227SGreg Roach		$iid2 = Filter::get('iid', WT_REGEX_XREF);
4218c2e8227SGreg Roach
4228c2e8227SGreg Roach		$controller = new SimpleController;
4238c2e8227SGreg Roach		$controller
4248c2e8227SGreg Roach			->setPageTitle(I18N::translate('Link to an existing media object'))
4258c2e8227SGreg Roach			->pageHeader();
4268c2e8227SGreg Roach
42724ec66ceSGreg Roach		$record = GedcomRecord::getInstance($iid2, $WT_TREE);
4288c2e8227SGreg Roach		if ($record) {
4298c2e8227SGreg Roach			$headjs = '';
4308c2e8227SGreg Roach			if ($record instanceof Family) {
4318c2e8227SGreg Roach				if ($record->getHusband()) {
4328c2e8227SGreg Roach					$headjs = $record->getHusband()->getXref();
4338c2e8227SGreg Roach				} elseif ($record->getWife()) {
4348c2e8227SGreg Roach					$headjs = $record->getWife()->getXref();
4358c2e8227SGreg Roach				}
4368c2e8227SGreg Roach			}
4378c2e8227SGreg Roach			?>
4388c2e8227SGreg Roach			<script>
4398c2e8227SGreg Roach				function insertId() {
4408c2e8227SGreg Roach					if (window.opener.document.getElementById('addlinkQueue')) {
4418c2e8227SGreg Roach						// alert('Please move this alert window and examine the contents of the pop-up window, then click OK')
442564ae2d7SGreg Roach						window.opener.insertRowToTable('<?= $record->getXref() ?>', '<?= htmlspecialchars($record->getFullName()) ?>', '<?= $headjs ?>');
4438c2e8227SGreg Roach						window.close();
4448c2e8227SGreg Roach					}
4458c2e8227SGreg Roach				}
4468c2e8227SGreg Roach			</script>
4478c2e8227SGreg Roach			<?php
4488c2e8227SGreg Roach		} else {
4498c2e8227SGreg Roach			?>
4508c2e8227SGreg Roach			<script>
4518c2e8227SGreg Roach				function insertId() {
452564ae2d7SGreg Roach					window.opener.alert('<?= $iid2 ?> - <?= I18N::translate('Not a valid individual, family, or source ID') ?>');
4538c2e8227SGreg Roach					window.close();
4548c2e8227SGreg Roach				}
4558c2e8227SGreg Roach			</script>
4568c2e8227SGreg Roach			<?php
4578c2e8227SGreg Roach		}
4588c2e8227SGreg Roach		?>
4598c2e8227SGreg Roach		<script>window.onLoad = insertId();</script>
4608c2e8227SGreg Roach		<?php
4618c2e8227SGreg Roach	}
4628c2e8227SGreg Roach
4638c2e8227SGreg Roach	/**
4648c2e8227SGreg Roach	 * Convert custom markup into HTML
4658c2e8227SGreg Roach	 *
4668c2e8227SGreg Roach	 * @param Note $note
4678c2e8227SGreg Roach	 *
4688c2e8227SGreg Roach	 * @return string
4698c2e8227SGreg Roach	 */
4708c2e8227SGreg Roach	public static function formatCensusNote(Note $note) {
47114c3d3fbSGreg Roach		if (preg_match('/(.*)((?:\n.*)*)\n\.start_formatted_area\.\n(.+)\n(.+(?:\n.+)*)\n.end_formatted_area\.((?:\n.*)*)/', $note->getNote(), $match)) {
4728c2e8227SGreg Roach			// This looks like a census-assistant shared note
473cc5ab399SGreg Roach			$title     = Html::escape($match[1]);
474cc5ab399SGreg Roach			$preamble  = Html::escape($match[2]);
475cc5ab399SGreg Roach			$header    = Html::escape($match[3]);
476cc5ab399SGreg Roach			$data      = Html::escape($match[4]);
477cc5ab399SGreg Roach			$postamble = Html::escape($match[5]);
4788c2e8227SGreg Roach
479dc46b574SDavid Drury			// Get the column headers for the census to which this note refers
480dc46b574SDavid Drury			// requires the fact place & date to match the specific census
481dc46b574SDavid Drury			// censusPlace() (Soundex match) and censusDate() functions
48213abd6f3SGreg Roach			$fmt_headers = [];
48315d603e7SGreg Roach			/** @var GedcomRecord[] $linkedRecords */
484dc46b574SDavid Drury			$linkedRecords = array_merge($note->linkedIndividuals('NOTE'), $note->linkedFamilies('NOTE'));
485dc46b574SDavid Drury			$firstRecord   = array_shift($linkedRecords);
486dc46b574SDavid Drury			if ($firstRecord) {
487dc46b574SDavid Drury				$countryCode = '';
488dc46b574SDavid Drury				$date        = '';
489dc46b574SDavid Drury				foreach ($firstRecord->getFacts('CENS') as $fact) {
490dc46b574SDavid Drury					if (trim($fact->getAttribute('NOTE'), '@') === $note->getXref()) {
491dc46b574SDavid Drury						$date        = $fact->getAttribute('DATE');
492dc46b574SDavid Drury						$place       = explode(',', strip_tags($fact->getPlace()->getFullName()));
493dc46b574SDavid Drury						$countryCode = Soundex::daitchMokotoff(array_pop($place));
494dc46b574SDavid Drury						break;
495dc46b574SDavid Drury					}
4968c2e8227SGreg Roach				}
4978c2e8227SGreg Roach
498dc46b574SDavid Drury				foreach (Census::allCensusPlaces() as $censusPlace) {
499dc46b574SDavid Drury					if (Soundex::compare($countryCode, Soundex::daitchMokotoff($censusPlace->censusPlace()))) {
500dc46b574SDavid Drury						foreach ($censusPlace->allCensusDates() as $census) {
501dc46b574SDavid Drury							if ($census->censusDate() == $date) {
502dc46b574SDavid Drury								foreach ($census->columns() as $column) {
503dc46b574SDavid Drury									$abbrev = $column->abbreviation();
504dc46b574SDavid Drury									if ($abbrev) {
505dc46b574SDavid Drury										$description          = $column->title() ? $column->title() : I18N::translate('Description unavailable');
506dc46b574SDavid Drury										$fmt_headers[$abbrev] = '<span title="' . $description . '">' . $abbrev . '</span>';
507dc46b574SDavid Drury									}
508dc46b574SDavid Drury								}
509dc46b574SDavid Drury								break 2;
510dc46b574SDavid Drury							}
511dc46b574SDavid Drury						}
512dc46b574SDavid Drury					}
513dc46b574SDavid Drury				}
514dc46b574SDavid Drury			}
515dc46b574SDavid Drury			// Substitute header labels and format as HTML
5168c2e8227SGreg Roach			$thead = '<tr><th>' . strtr(str_replace('|', '</th><th>', $header), $fmt_headers) . '</th></tr>';
517ad51e0bbSGreg Roach			$thead = str_replace('.b.', '', $thead);
5188c2e8227SGreg Roach
5198c2e8227SGreg Roach			// Format data as HTML
5208c2e8227SGreg Roach			$tbody = '';
52114c3d3fbSGreg Roach			foreach (explode("\n", $data) as $row) {
5228c2e8227SGreg Roach				$tbody .= '<tr>';
5238c2e8227SGreg Roach				foreach (explode('|', $row) as $column) {
5248c2e8227SGreg Roach					$tbody .= '<td>' . $column . '</td>';
5258c2e8227SGreg Roach				}
5268c2e8227SGreg Roach				$tbody .= '</tr>';
5278c2e8227SGreg Roach			}
5288c2e8227SGreg Roach
5298c2e8227SGreg Roach			return
5308c2e8227SGreg Roach				$title . "\n" . // The newline allows the framework to expand the details and turn the first line into a link
531673157b0SGreg Roach				'<div class="markdown">' .
5328c2e8227SGreg Roach				'<p>' . $preamble . '</p>' .
533dc46b574SDavid Drury				'<table>' .
5348c2e8227SGreg Roach				'<thead>' . $thead . '</thead>' .
5358c2e8227SGreg Roach				'<tbody>' . $tbody . '</tbody>' .
5368c2e8227SGreg Roach				'</table>' .
537dc46b574SDavid Drury				'<p>' . $postamble . '</p>' .
538dc46b574SDavid Drury				'</div>';
5398c2e8227SGreg Roach		} else {
5408c2e8227SGreg Roach			// Not a census-assistant shared note - apply default formatting
54115d603e7SGreg Roach			return Filter::formatText($note->getNote(), $note->getTree());
5428c2e8227SGreg Roach		}
5438c2e8227SGreg Roach	}
54499f222b3SGreg Roach
54599f222b3SGreg Roach	/**
546ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census header
54752bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
54852bc9faeSGreg Roach	 * Add suffix cell (delete button)
54952bc9faeSGreg Roach	 *
550ad51e0bbSGreg Roach	 * @param CensusInterface $census
55199f222b3SGreg Roach	 *
552ad51e0bbSGreg Roach	 * @return string
55399f222b3SGreg Roach	 */
554ad51e0bbSGreg Roach	public static function censusTableHeader(CensusInterface $census) {
55552bc9faeSGreg Roach		$html = '';
556ad51e0bbSGreg Roach		foreach ($census->columns() as $column) {
55715d603e7SGreg Roach			$html .= '<th class="wt-census-assistant-field" title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
55899f222b3SGreg Roach		}
55999f222b3SGreg Roach
56015d603e7SGreg Roach		return '<tr class="wt-census-assistant-row"><th hidden></th>' . $html . '<th></th></tr>';
561ad51e0bbSGreg Roach	}
56299f222b3SGreg Roach
563ad51e0bbSGreg Roach	/**
564ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census
56552bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
56652bc9faeSGreg Roach	 * Add suffix cell (delete button)
56752bc9faeSGreg Roach	 *
568ad51e0bbSGreg Roach	 * @param CensusInterface $census
569ad51e0bbSGreg Roach	 *
570ad51e0bbSGreg Roach	 * @return string
571ad51e0bbSGreg Roach	 */
572ad51e0bbSGreg Roach	public static function censusTableEmptyRow(CensusInterface $census) {
57315d603e7SGreg Roach		return '<tr class="wt-census-assistant-row"><td hidden></td>' . str_repeat('<td class="wt-census-assistant-field"><input type="text" class="form-control wt-census-assistant-form-control"></td>', count($census->columns())) . '<td><a class="icon-remove" href="#" title="' . I18N::translate('Remove') . '"></a></td></tr>';
574ad51e0bbSGreg Roach	}
57599f222b3SGreg Roach
576ad51e0bbSGreg Roach	/**
577ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census
57852bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
57952bc9faeSGreg Roach	 * Add suffix cell (delete button)
58052bc9faeSGreg Roach	 *
581ad51e0bbSGreg Roach	 * @param CensusInterface $census
582ad51e0bbSGreg Roach	 * @param Individual      $individual
583ad51e0bbSGreg Roach	 * @param Individual      $head
584ad51e0bbSGreg Roach	 *
585ad51e0bbSGreg Roach	 * @return string
586ad51e0bbSGreg Roach	 */
58715d603e7SGreg Roach	public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head) {
58815d603e7SGreg Roach		$html = '';
58915d603e7SGreg Roach		foreach ($census->columns() as $column) {
59015d603e7SGreg Roach			$html .= '<td class="wt-census-assistant-field"><input class="form-control wt-census-assistant-form-control" type="text" value="' . $column->generate($individual, $head) . '" name="ca_individuals[' . $individual->getXref() . '][]"></td>';
59199f222b3SGreg Roach		}
59299f222b3SGreg Roach
59315d603e7SGreg Roach		return '<tr class="wt-census-assistant-row"><td class="wt-census-assistant-field" hidden>' . $individual->getXref() . '</td>' . $html . '<td class="wt-census-assistant-field"><a class="icon-remove" href="#" title="' . I18N::translate('Remove') . '"></a></td></tr>';
59499f222b3SGreg Roach	}
5958c2e8227SGreg Roach}
596