xref: /webtrees/app/Module/CensusAssistantModule.php (revision cc5ab399cc3c8f78158c8e3027cb0ecf038648dc)
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;
270e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
2899f222b3SGreg Roachuse Fisharebest\Webtrees\Individual;
290e62c4b8SGreg Roachuse Fisharebest\Webtrees\Note;
30dc46b574SDavid Druryuse Fisharebest\Webtrees\Soundex;
318c2e8227SGreg Roach
328c2e8227SGreg Roach/**
338c2e8227SGreg Roach * Class CensusAssistantModule
348c2e8227SGreg Roach */
3515834aaeSGreg Roachclass CensusAssistantModule extends AbstractModule {
368c2e8227SGreg Roach	/** {@inheritdoc} */
378c2e8227SGreg Roach	public function getTitle() {
3815d603e7SGreg Roach		return /* I18N: Name of a module */
3915d603e7SGreg Roach			I18N::translate('Census assistant');
408c2e8227SGreg Roach	}
418c2e8227SGreg Roach
428c2e8227SGreg Roach	/** {@inheritdoc} */
438c2e8227SGreg Roach	public function getDescription() {
4415d603e7SGreg Roach		return /* I18N: Description of the “Census assistant” module */
4515d603e7SGreg Roach			I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
468c2e8227SGreg Roach	}
478c2e8227SGreg Roach
4876692c8bSGreg Roach	/**
4976692c8bSGreg Roach	 * This is a general purpose hook, allowing modules to respond to routes
5076692c8bSGreg Roach	 * of the form module.php?mod=FOO&mod_action=BAR
5176692c8bSGreg Roach	 *
5276692c8bSGreg Roach	 * @param string $mod_action
5376692c8bSGreg Roach	 */
548c2e8227SGreg Roach	public function modAction($mod_action) {
5515d603e7SGreg Roach		global $WT_TREE;
5615d603e7SGreg Roach
578c2e8227SGreg Roach		switch ($mod_action) {
5815d603e7SGreg Roach		case 'census-header':
5915d603e7SGreg Roach			header('Content-Type: text/html; charset=utf8');
6015d603e7SGreg Roach			$census = Filter::get('census');
6115d603e7SGreg Roach			echo $this->censusTableHeader(new $census);
628c2e8227SGreg Roach			break;
6315d603e7SGreg Roach
6415d603e7SGreg Roach		case 'census-individual':
6515d603e7SGreg Roach			header('Content-Type: text/html; charset=utf8');
6615d603e7SGreg Roach			$census     = Filter::get('census');
6715d603e7SGreg Roach			$individual = Individual::getInstance(Filter::get('xref'), $WT_TREE);
6815d603e7SGreg Roach			$head       = Individual::getInstance(Filter::get('head'), $WT_TREE);
6915d603e7SGreg Roach			echo $this->censusTableRow(new $census, $individual, $head);
7015d603e7SGreg Roach			break;
7115d603e7SGreg Roach
7240990b78SGreg Roach		case 'media_find':
73764a01d9SGreg Roach			self::mediaFind();
748c2e8227SGreg Roach			break;
758c2e8227SGreg Roach		case 'media_query_3a':
76764a01d9SGreg Roach			self::mediaQuery();
778c2e8227SGreg Roach			break;
788c2e8227SGreg Roach		default:
798c2e8227SGreg Roach			http_response_code(404);
808c2e8227SGreg Roach		}
818c2e8227SGreg Roach	}
828c2e8227SGreg Roach
838c2e8227SGreg Roach	/**
8415d603e7SGreg Roach	 * @param Individual $individual
858c2e8227SGreg Roach	 */
8615d603e7SGreg Roach	public function createCensusAssistant(Individual $individual) {
8715d603e7SGreg Roach		?>
8840990b78SGreg Roach
8915d603e7SGreg Roach		<div id="census-assistant-link" hidden>
9015d603e7SGreg Roach			<a href="#">
9115d603e7SGreg Roach				<?= I18N::translate('Create a shared note using the census assistant') ?>
9215d603e7SGreg Roach			</a>
9315d603e7SGreg Roach		</div>
9440990b78SGreg Roach
9515d603e7SGreg Roach		<div id="census-assistant" hidden>
9615d603e7SGreg Roach			<input type="hidden" name="ca_census" id="ca-census">
9715d603e7SGreg Roach			<div class="form-group">
9815d603e7SGreg Roach				<div class="input-group">
9915d603e7SGreg Roach					<label for="census-assistant-title" class="input-group-addon">
10015d603e7SGreg Roach						<?= I18N::translate('Title') ?>
10115d603e7SGreg Roach					</label>
10215d603e7SGreg Roach					<input class="form-control" id="ca-title" name="ca_title" value="">
10315d603e7SGreg Roach				</div>
10415d603e7SGreg Roach			</div>
10540990b78SGreg Roach
10615d603e7SGreg Roach			<div class="row">
10715d603e7SGreg Roach				<div class="form-group col-sm-6">
10815d603e7SGreg Roach					<div class="input-group">
10915d603e7SGreg Roach						<label for="census-assistant-citation" class="input-group-addon">
11015d603e7SGreg Roach							<?= I18N::translate('Citation') ?>
11115d603e7SGreg Roach						</label>
11215d603e7SGreg Roach						<input class="form-control" id="census-assistant-citation" name="ca_citation">
11315d603e7SGreg Roach					</div>
11415d603e7SGreg Roach				</div>
11540990b78SGreg Roach
11615d603e7SGreg Roach				<div class="form-group col-sm-6">
11715d603e7SGreg Roach					<div class="input-group">
11815d603e7SGreg Roach						<label for="census-assistant-place" class="input-group-addon">
11915d603e7SGreg Roach							<?= I18N::translate('Place') ?>
12015d603e7SGreg Roach						</label>
12115d603e7SGreg Roach						<input class="form-control" id="census-assistant-place" name="ca_place">
12215d603e7SGreg Roach					</div>
12315d603e7SGreg Roach				</div>
12415d603e7SGreg Roach			</div>
12540990b78SGreg Roach
12615d603e7SGreg Roach			<div class="form-group">
12715d603e7SGreg Roach				<div class="input-group">
12815d603e7SGreg Roach					<span class="input-group-addon"><?= I18N::translate('Individuals') ?></span>
12915d603e7SGreg Roach					<?= FunctionsEdit::formControlIndividual($individual, ['id' => 'census-assistant-individual', 'style' => 'width:100%']) ?>
13015d603e7SGreg Roach					<span class="input-group-btn">
13115d603e7SGreg Roach						<button type="button" class="btn btn-primary" id="census-assistant-add">
13215d603e7SGreg Roach							<?= FontAwesome::semanticIcon('add', I18N::translate('Add')) ?>
13315d603e7SGreg Roach						</button>
13415d603e7SGreg Roach					</span>
13515d603e7SGreg Roach					<span class="input-group-btn">
13615d603e7SGreg Roach						<button type="button" class="btn btn-primary" id="census-assistant-head"
13715d603e7SGreg Roach						        title="<?= I18N::translate('Head of household') ?>">
13815d603e7SGreg Roach							<?= FontAwesome::semanticIcon('individual', I18N::translate('Head of household')) ?>
13915d603e7SGreg Roach						</button>
14015d603e7SGreg Roach					</span>
14115d603e7SGreg Roach				</div>
14215d603e7SGreg Roach			</div>
14315d603e7SGreg Roach
14415d603e7SGreg Roach			<table class="table table-bordered table-small table-responsive wt-census-assistant-table"
14515d603e7SGreg Roach			       id="census-assistant-table">
14615d603e7SGreg Roach				<thead class="wt-census-assistant-header"></thead>
14715d603e7SGreg Roach				<tbody class="wt-census-assistant-body"></tbody>
14815d603e7SGreg Roach			</table>
14915d603e7SGreg Roach
15015d603e7SGreg Roach			<div class="form-group">
15115d603e7SGreg Roach				<div class="input-group">
15215d603e7SGreg Roach					<label for="census-assistant-notes" class="input-group-addon">
15315d603e7SGreg Roach						<?= I18N::translate('Notes') ?>
15415d603e7SGreg Roach					</label>
15515d603e7SGreg Roach					<input class="form-control" id="census-assistant-notes" name="ca_notes">
15615d603e7SGreg Roach				</div>
15715d603e7SGreg Roach			</div>
15815d603e7SGreg Roach		</div>
15915d603e7SGreg Roach
16015d603e7SGreg Roach		<script>
16115d603e7SGreg Roach			// When a census date/place is selected, activate the census-assistant
16215d603e7SGreg Roach			function censusAssistantSelect() {
16315d603e7SGreg Roach				var censusAssistantLink = document.querySelector('#census-assistant-link');
16415d603e7SGreg Roach				var censusAssistant     = document.querySelector('#census-assistant');
16515d603e7SGreg Roach				var censusOption        = this.options[this.selectedIndex];
16615d603e7SGreg Roach				var census              = censusOption.dataset.census;
16715d603e7SGreg Roach				var censusPlace         = censusOption.dataset.place;
16815d603e7SGreg Roach				var censusYear          = censusOption.value.substr(-4);
16915d603e7SGreg Roach
17015d603e7SGreg Roach				if (censusOption.value !== '') {
17115d603e7SGreg Roach					censusAssistantLink.removeAttribute('hidden');
17240990b78SGreg Roach				} else {
17315d603e7SGreg Roach					censusAssistantLink.setAttribute('hidden', '');
17440990b78SGreg Roach				}
17515d603e7SGreg Roach
17615d603e7SGreg Roach				censusAssistant.setAttribute('hidden', '');
17715d603e7SGreg Roach				document.querySelector('#ca-census').value = census;
17815d603e7SGreg Roach				document.querySelector('#ca-title').value  = censusYear + ' ' + censusPlace + ' - <?= I18N::translate('Census transcript') ?> - <?= strip_tags($individual->getFullName()) ?> - <?= I18N::translate('Household') ?>';
17915d603e7SGreg Roach
18015d603e7SGreg Roach				fetch('module.php?mod=GEDFact_assistant&mod_action=census-header&census=' + census)
18115d603e7SGreg Roach					.then(function (response) {
18215d603e7SGreg Roach						return response.text();
18315d603e7SGreg Roach					})
18415d603e7SGreg Roach					.then(function (text) {
18515d603e7SGreg Roach						document.querySelector('#census-assistant-table thead').innerHTML = text;
18615d603e7SGreg Roach						document.querySelector('#census-assistant-table tbody').innerHTML = '';
18715d603e7SGreg Roach					});
188ad51e0bbSGreg Roach			}
18915d603e7SGreg Roach
19015d603e7SGreg Roach			// When the census assistant is activated, show the input fields
19115d603e7SGreg Roach			function censusAssistantLink() {
19215d603e7SGreg Roach				document.querySelector('#census-selector').setAttribute('hidden', '');
19315d603e7SGreg Roach				this.setAttribute('hidden', '');
19415d603e7SGreg Roach				document.getElementById('census-assistant').removeAttribute('hidden');
19515d603e7SGreg Roach				// Set the current individual as the head of household.
19615d603e7SGreg Roach				censusAssistantHead();
19715d603e7SGreg Roach
19815d603e7SGreg Roach				return false;
19915d603e7SGreg Roach			}
20015d603e7SGreg Roach
20115d603e7SGreg Roach			// Add the currently selected individual to the census
20215d603e7SGreg Roach			function censusAssistantAdd() {
20315d603e7SGreg Roach				var censusSelector = document.querySelector('#census-selector');
20415d603e7SGreg Roach				var census         = censusSelector.options[censusSelector.selectedIndex].dataset.census;
20515d603e7SGreg Roach				var indi_selector  = document.querySelector('#census-assistant-individual');
20615d603e7SGreg Roach				var xref           = indi_selector.options[indi_selector.selectedIndex].value;
20715d603e7SGreg Roach				var headTd         = document.querySelector('#census-assistant-table td');
20815d603e7SGreg Roach				var head           = headTd === null ? xref : headTd.innerHTML;
20915d603e7SGreg Roach
21015d603e7SGreg Roach				fetch('module.php?mod=GEDFact_assistant&mod_action=census-individual&census=' + census + '&xref=' + xref + '&head=' + head, {credentials: 'same-origin'})
21115d603e7SGreg Roach					.then(function (response) {
21215d603e7SGreg Roach						return response.text();
21315d603e7SGreg Roach					})
21415d603e7SGreg Roach					.then(function (text) {
21515d603e7SGreg Roach						document.querySelector('#census-assistant-table tbody').innerHTML += text;
21615d603e7SGreg Roach					});
21715d603e7SGreg Roach
21815d603e7SGreg Roach				return false;
21915d603e7SGreg Roach			}
22015d603e7SGreg Roach
22115d603e7SGreg Roach			// Set the currently selected individual as the head of household
22215d603e7SGreg Roach			function censusAssistantHead() {
22315d603e7SGreg Roach				var censusSelector = document.querySelector('#census-selector');
22415d603e7SGreg Roach				var census         = censusSelector.options[censusSelector.selectedIndex].dataset.census;
22515d603e7SGreg Roach				var indi_selector  = document.querySelector('#census-assistant-individual');
22615d603e7SGreg Roach				var xref           = indi_selector.options[indi_selector.selectedIndex].value;
22715d603e7SGreg Roach
22815d603e7SGreg Roach				fetch('module.php?mod=GEDFact_assistant&mod_action=census-individual&census=' + census + '&xref=' + xref + '&head=' + xref, {credentials: 'same-origin'})
22915d603e7SGreg Roach					.then(function (response) {
23015d603e7SGreg Roach						return response.text();
23115d603e7SGreg Roach					})
23215d603e7SGreg Roach					.then(function (text) {
23315d603e7SGreg Roach						document.querySelector('#census-assistant-table tbody').innerHTML = text;
23415d603e7SGreg Roach					});
23515d603e7SGreg Roach
23615d603e7SGreg Roach				return false;
23715d603e7SGreg Roach			}
23815d603e7SGreg Roach
23915d603e7SGreg Roach			document.querySelector('#census-selector').addEventListener('change', censusAssistantSelect);
24015d603e7SGreg Roach			document.querySelector('#census-assistant-link').addEventListener('click', censusAssistantLink);
24115d603e7SGreg Roach			document.querySelector('#census-assistant-add').addEventListener('click', censusAssistantAdd);
24215d603e7SGreg Roach			document.querySelector('#census-assistant-head').addEventListener('click', censusAssistantHead);
24315d603e7SGreg Roach		</script>
24415d603e7SGreg Roach		<?php
24515d603e7SGreg Roach	}
24615d603e7SGreg Roach
24715d603e7SGreg Roach	/**
24815d603e7SGreg Roach	 * @param Individual $individual
24960bc3e3fSGreg Roach	 * @param string     $fact_id
25015d603e7SGreg Roach	 * @param string     $newged
25160bc3e3fSGreg Roach	 * @param bool       $keep_chan
25215d603e7SGreg Roach	 *
25315d603e7SGreg Roach	 * @return string
25415d603e7SGreg Roach	 */
25515d603e7SGreg Roach	public function updateCensusAssistant(Individual $individual, $fact_id, $newged, $keep_chan) {
25615d603e7SGreg Roach		$ca_title       = Filter::post('ca_title');
25715d603e7SGreg Roach		$ca_place       = Filter::post('ca_place');
25815d603e7SGreg Roach		$ca_citation    = Filter::post('ca_citation');
25915d603e7SGreg Roach		$ca_individuals = Filter::postArray('ca_individuals');
26015d603e7SGreg Roach		$ca_notes       = Filter::post('ca_notes');
26115d603e7SGreg Roach		$ca_census      = Filter::post('ca_census', 'Fisharebest\\\\Webtrees\\\\Census\\\\CensusOf[A-Za-z0-9]+');
26215d603e7SGreg Roach
26315d603e7SGreg Roach		if ($ca_census !== '' && !empty($ca_individuals)) {
26415d603e7SGreg Roach			$census = new $ca_census;
26515d603e7SGreg Roach
26615d603e7SGreg Roach			$note_text   = $this->createNoteText($census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes);
26715d603e7SGreg Roach			$note_gedcom = '0 @new@ NOTE ' . str_replace("\n", "\n1 CONT ", $note_text);
26815d603e7SGreg Roach			$note        = $individual->getTree()->createRecord($note_gedcom);
26915d603e7SGreg Roach
27015d603e7SGreg Roach			$newged .= "\n2 NOTE @" . $note->getXref() . '@';
27115d603e7SGreg Roach
27215d603e7SGreg Roach			// Add the census fact to the rest of the household
27315d603e7SGreg Roach			foreach (array_keys($ca_individuals) as $xref) {
27415d603e7SGreg Roach				if ($xref !== $individual->getXref()) {
27515d603e7SGreg Roach					Individual::getInstance($xref, $individual->getTree())
27615d603e7SGreg Roach						->updateFact($fact_id, $newged, !$keep_chan);
27715d603e7SGreg Roach				}
27815d603e7SGreg Roach			}
27915d603e7SGreg Roach		}
28015d603e7SGreg Roach
28115d603e7SGreg Roach		return $newged;
28215d603e7SGreg Roach	}
28315d603e7SGreg Roach
28415d603e7SGreg Roach	/**
28515d603e7SGreg Roach	 * @param CensusInterface $census
28615d603e7SGreg Roach	 * @param string          $ca_title
28715d603e7SGreg Roach	 * @param string          $ca_place
28815d603e7SGreg Roach	 * @param string          $ca_citation
28915d603e7SGreg Roach	 * @param string[][]      $ca_individuals
29015d603e7SGreg Roach	 * @param string          $ca_notes
29115d603e7SGreg Roach	 *
29215d603e7SGreg Roach	 * @return string
29315d603e7SGreg Roach	 */
29415d603e7SGreg Roach	private function createNoteText(CensusInterface $census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes) {
29515d603e7SGreg Roach		$text = $ca_title . "\n" . $ca_citation . "\n" . $ca_place . "\n\n.start_formatted_area.\n\n";
29615d603e7SGreg Roach
29715d603e7SGreg Roach		foreach ($census->columns() as $n => $column) {
29815d603e7SGreg Roach			if ($n > 0) {
29915d603e7SGreg Roach				$text .= '|';
30015d603e7SGreg Roach			}
30115d603e7SGreg Roach			$text .= '.b.' . $column->abbreviation();
30215d603e7SGreg Roach		}
30315d603e7SGreg Roach
30415d603e7SGreg Roach		foreach ($ca_individuals as $xref => $columns) {
30515d603e7SGreg Roach			$text .= "\n" . implode('|', $columns);
30615d603e7SGreg Roach		}
30715d603e7SGreg Roach
30815d603e7SGreg Roach		return $text . "\n.end_formatted_area.\n\n" . $ca_notes;
30940990b78SGreg Roach	}
31040990b78SGreg Roach
31140990b78SGreg Roach	/**
31276692c8bSGreg Roach	 * Find a media object.
31340990b78SGreg Roach	 */
314764a01d9SGreg Roach	private static function mediaFind() {
3158c2e8227SGreg Roach		global $WT_TREE;
3168c2e8227SGreg Roach
3178c2e8227SGreg Roach		$controller = new SimpleController;
3188c2e8227SGreg Roach		$filter     = Filter::get('filter');
3198c2e8227SGreg Roach		$multiple   = Filter::getBool('multiple');
3208c2e8227SGreg Roach
3218c2e8227SGreg Roach		$controller
3228c2e8227SGreg Roach			->setPageTitle(I18N::translate('Find an individual'))
3238c2e8227SGreg Roach			->pageHeader();
3248c2e8227SGreg Roach
3258c2e8227SGreg Roach		?>
32699f222b3SGreg Roach		<script>
3278c2e8227SGreg Roach			function pasterow(id, name, gend, yob, age, bpl) {
3288c2e8227SGreg Roach				window.opener.opener.insertRowToTable(id, name, '', gend, '', yob, age, 'Y', '', bpl);
3298c2e8227SGreg Roach			}
3308c2e8227SGreg Roach
3318c2e8227SGreg Roach			function pasteid(id, name, thumb) {
3328c2e8227SGreg Roach				if (thumb) {
3338c2e8227SGreg Roach					window.opener.paste_id(id, name, thumb);
33415d603e7SGreg Roach					<?php if (!$multiple) {
33515d603e7SGreg Roach					echo 'window.close();';
33615d603e7SGreg Roach				} ?>
3378c2e8227SGreg Roach				} else {
3388c2e8227SGreg Roach					// GEDFact_assistant ========================
3398c2e8227SGreg Roach					if (window.opener.document.getElementById('addlinkQueue')) {
3408c2e8227SGreg Roach						window.opener.insertRowToTable(id, name);
3418c2e8227SGreg Roach					}
3428c2e8227SGreg Roach					window.opener.paste_id(id);
3438c2e8227SGreg Roach					if (window.opener.pastename) {
3448c2e8227SGreg Roach						window.opener.pastename(name);
3458c2e8227SGreg Roach					}
34615d603e7SGreg Roach					<?php if (!$multiple) {
34715d603e7SGreg Roach					echo 'window.close();';
34815d603e7SGreg Roach				} ?>
3498c2e8227SGreg Roach				}
3508c2e8227SGreg Roach			}
35115d603e7SGreg Roach
3528c2e8227SGreg Roach			function checknames(frm) {
3536fde90caSGreg Roach				var button = '';
3548c2e8227SGreg Roach				if (document.forms[0].subclick) {
3558c2e8227SGreg Roach					button = document.forms[0].subclick.value;
3568c2e8227SGreg Roach				}
35715d603e7SGreg Roach				if (frm.filter.value.length < 2 && button !== 'all') {
35815d603e7SGreg Roach					alert('<?= I18N::translate('Please enter more than one character.') ?>');
3598c2e8227SGreg Roach					frm.filter.focus();
3608c2e8227SGreg Roach					return false;
3618c2e8227SGreg Roach				}
3626fde90caSGreg Roach				if (button === 'all') {
36315d603e7SGreg Roach					frm.filter.value = '';
3648c2e8227SGreg Roach				}
3658c2e8227SGreg Roach				return true;
3668c2e8227SGreg Roach			}
36799f222b3SGreg Roach		</script>
3688c2e8227SGreg Roach
36999f222b3SGreg Roach		<?php
370a86dd8b1SGreg Roach		echo '<div>';
3714c621133SGreg Roach		echo '<table class="list_table width90" border="0">';
372a86dd8b1SGreg Roach		echo '<tr><td style="padding: 10px;" class="facts_label03 width90">'; // start column for find text header
3738c2e8227SGreg Roach		echo $controller->getPageTitle();
3744c621133SGreg Roach		echo '</td>';
3754c621133SGreg Roach		echo '</tr>';
3764c621133SGreg Roach		echo '</table>';
3774c621133SGreg Roach		echo '<br>';
3788c2e8227SGreg Roach		echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
3794c621133SGreg Roach		echo '<br>';
3808c2e8227SGreg Roach
3818c2e8227SGreg Roach		$filter       = trim($filter);
3828c2e8227SGreg Roach		$filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
3834c621133SGreg Roach		echo '<table class="tabs_table width90"><tr>';
38413abd6f3SGreg Roach		$myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
3858c2e8227SGreg Roach		if ($myindilist) {
3864c621133SGreg Roach			echo '<td class="list_value_wrap"><ul>';
3870e62c4b8SGreg Roach			usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
3888c2e8227SGreg Roach			foreach ($myindilist as $indi) {
389*cc5ab399SGreg Roach				$nam = Html::escape($indi->getFullName());
3908c2e8227SGreg Roach				echo "<li><a href=\"#\" onclick=\"pasterow(
3918c2e8227SGreg Roach					'" . $indi->getXref() . "' ,
3928c2e8227SGreg Roach					'" . $nam . "' ,
3938c2e8227SGreg Roach					'" . $indi->getSex() . "' ,
3947820e4d7SGreg Roach					'" . $indi->getBirthYear() . "' ,
3957820e4d7SGreg Roach					'" . (1901 - $indi->getBirthYear()) . "' ,
3967820e4d7SGreg Roach					'" . $indi->getBirthPlace() . "'); return false;\">
3977a6ee1acSGreg Roach					<b>" . $indi->getFullName() . '</b>&nbsp;&nbsp;&nbsp;';
3988c2e8227SGreg Roach
399564ae2d7SGreg Roach				$born = I18N::translate('Birth');
4007a6ee1acSGreg Roach				echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace(), '</span></a></li>';
4017a6ee1acSGreg Roach				echo '<hr>';
4028c2e8227SGreg Roach			}
4038c2e8227SGreg Roach			echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
4048c2e8227SGreg Roach		} else {
4057a6ee1acSGreg Roach			echo '<td class="list_value_wrap">';
4068c2e8227SGreg Roach			echo I18N::translate('No results found.');
4077a6ee1acSGreg Roach			echo '</td></tr>';
4088c2e8227SGreg Roach		}
4097a6ee1acSGreg Roach		echo '</table>';
4108c2e8227SGreg Roach		echo '</div>';
4118c2e8227SGreg Roach	}
4128c2e8227SGreg Roach
4138c2e8227SGreg Roach	/**
41476692c8bSGreg Roach	 * Search for a media object.
4158c2e8227SGreg Roach	 */
416764a01d9SGreg Roach	private static function mediaQuery() {
41724ec66ceSGreg Roach		global $WT_TREE;
41824ec66ceSGreg Roach
4198c2e8227SGreg Roach		$iid2 = Filter::get('iid', WT_REGEX_XREF);
4208c2e8227SGreg Roach
4218c2e8227SGreg Roach		$controller = new SimpleController;
4228c2e8227SGreg Roach		$controller
4238c2e8227SGreg Roach			->setPageTitle(I18N::translate('Link to an existing media object'))
4248c2e8227SGreg Roach			->pageHeader();
4258c2e8227SGreg Roach
42624ec66ceSGreg Roach		$record = GedcomRecord::getInstance($iid2, $WT_TREE);
4278c2e8227SGreg Roach		if ($record) {
4288c2e8227SGreg Roach			$headjs = '';
4298c2e8227SGreg Roach			if ($record instanceof Family) {
4308c2e8227SGreg Roach				if ($record->getHusband()) {
4318c2e8227SGreg Roach					$headjs = $record->getHusband()->getXref();
4328c2e8227SGreg Roach				} elseif ($record->getWife()) {
4338c2e8227SGreg Roach					$headjs = $record->getWife()->getXref();
4348c2e8227SGreg Roach				}
4358c2e8227SGreg Roach			}
4368c2e8227SGreg Roach			?>
4378c2e8227SGreg Roach			<script>
4388c2e8227SGreg Roach				function insertId() {
4398c2e8227SGreg Roach					if (window.opener.document.getElementById('addlinkQueue')) {
4408c2e8227SGreg Roach						// alert('Please move this alert window and examine the contents of the pop-up window, then click OK')
441564ae2d7SGreg Roach						window.opener.insertRowToTable('<?= $record->getXref() ?>', '<?= htmlspecialchars($record->getFullName()) ?>', '<?= $headjs ?>');
4428c2e8227SGreg Roach						window.close();
4438c2e8227SGreg Roach					}
4448c2e8227SGreg Roach				}
4458c2e8227SGreg Roach			</script>
4468c2e8227SGreg Roach			<?php
4478c2e8227SGreg Roach		} else {
4488c2e8227SGreg Roach			?>
4498c2e8227SGreg Roach			<script>
4508c2e8227SGreg Roach				function insertId() {
451564ae2d7SGreg Roach					window.opener.alert('<?= $iid2 ?> - <?= I18N::translate('Not a valid individual, family, or source ID') ?>');
4528c2e8227SGreg Roach					window.close();
4538c2e8227SGreg Roach				}
4548c2e8227SGreg Roach			</script>
4558c2e8227SGreg Roach			<?php
4568c2e8227SGreg Roach		}
4578c2e8227SGreg Roach		?>
4588c2e8227SGreg Roach		<script>window.onLoad = insertId();</script>
4598c2e8227SGreg Roach		<?php
4608c2e8227SGreg Roach	}
4618c2e8227SGreg Roach
4628c2e8227SGreg Roach	/**
4638c2e8227SGreg Roach	 * Convert custom markup into HTML
4648c2e8227SGreg Roach	 *
4658c2e8227SGreg Roach	 * @param Note $note
4668c2e8227SGreg Roach	 *
4678c2e8227SGreg Roach	 * @return string
4688c2e8227SGreg Roach	 */
4698c2e8227SGreg Roach	public static function formatCensusNote(Note $note) {
47014c3d3fbSGreg Roach		if (preg_match('/(.*)((?:\n.*)*)\n\.start_formatted_area\.\n(.+)\n(.+(?:\n.+)*)\n.end_formatted_area\.((?:\n.*)*)/', $note->getNote(), $match)) {
4718c2e8227SGreg Roach			// This looks like a census-assistant shared note
472*cc5ab399SGreg Roach			$title     = Html::escape($match[1]);
473*cc5ab399SGreg Roach			$preamble  = Html::escape($match[2]);
474*cc5ab399SGreg Roach			$header    = Html::escape($match[3]);
475*cc5ab399SGreg Roach			$data      = Html::escape($match[4]);
476*cc5ab399SGreg Roach			$postamble = Html::escape($match[5]);
4778c2e8227SGreg Roach
478dc46b574SDavid Drury			// Get the column headers for the census to which this note refers
479dc46b574SDavid Drury			// requires the fact place & date to match the specific census
480dc46b574SDavid Drury			// censusPlace() (Soundex match) and censusDate() functions
48113abd6f3SGreg Roach			$fmt_headers = [];
48215d603e7SGreg Roach			/** @var GedcomRecord[] $linkedRecords */
483dc46b574SDavid Drury			$linkedRecords = array_merge($note->linkedIndividuals('NOTE'), $note->linkedFamilies('NOTE'));
484dc46b574SDavid Drury			$firstRecord   = array_shift($linkedRecords);
485dc46b574SDavid Drury			if ($firstRecord) {
486dc46b574SDavid Drury				$countryCode = '';
487dc46b574SDavid Drury				$date        = '';
488dc46b574SDavid Drury				foreach ($firstRecord->getFacts('CENS') as $fact) {
489dc46b574SDavid Drury					if (trim($fact->getAttribute('NOTE'), '@') === $note->getXref()) {
490dc46b574SDavid Drury						$date        = $fact->getAttribute('DATE');
491dc46b574SDavid Drury						$place       = explode(',', strip_tags($fact->getPlace()->getFullName()));
492dc46b574SDavid Drury						$countryCode = Soundex::daitchMokotoff(array_pop($place));
493dc46b574SDavid Drury						break;
494dc46b574SDavid Drury					}
4958c2e8227SGreg Roach				}
4968c2e8227SGreg Roach
497dc46b574SDavid Drury				foreach (Census::allCensusPlaces() as $censusPlace) {
498dc46b574SDavid Drury					if (Soundex::compare($countryCode, Soundex::daitchMokotoff($censusPlace->censusPlace()))) {
499dc46b574SDavid Drury						foreach ($censusPlace->allCensusDates() as $census) {
500dc46b574SDavid Drury							if ($census->censusDate() == $date) {
501dc46b574SDavid Drury								foreach ($census->columns() as $column) {
502dc46b574SDavid Drury									$abbrev = $column->abbreviation();
503dc46b574SDavid Drury									if ($abbrev) {
504dc46b574SDavid Drury										$description          = $column->title() ? $column->title() : I18N::translate('Description unavailable');
505dc46b574SDavid Drury										$fmt_headers[$abbrev] = '<span title="' . $description . '">' . $abbrev . '</span>';
506dc46b574SDavid Drury									}
507dc46b574SDavid Drury								}
508dc46b574SDavid Drury								break 2;
509dc46b574SDavid Drury							}
510dc46b574SDavid Drury						}
511dc46b574SDavid Drury					}
512dc46b574SDavid Drury				}
513dc46b574SDavid Drury			}
514dc46b574SDavid Drury			// Substitute header labels and format as HTML
5158c2e8227SGreg Roach			$thead = '<tr><th>' . strtr(str_replace('|', '</th><th>', $header), $fmt_headers) . '</th></tr>';
516ad51e0bbSGreg Roach			$thead = str_replace('.b.', '', $thead);
5178c2e8227SGreg Roach
5188c2e8227SGreg Roach			// Format data as HTML
5198c2e8227SGreg Roach			$tbody = '';
52014c3d3fbSGreg Roach			foreach (explode("\n", $data) as $row) {
5218c2e8227SGreg Roach				$tbody .= '<tr>';
5228c2e8227SGreg Roach				foreach (explode('|', $row) as $column) {
5238c2e8227SGreg Roach					$tbody .= '<td>' . $column . '</td>';
5248c2e8227SGreg Roach				}
5258c2e8227SGreg Roach				$tbody .= '</tr>';
5268c2e8227SGreg Roach			}
5278c2e8227SGreg Roach
5288c2e8227SGreg Roach			return
5298c2e8227SGreg Roach				$title . "\n" . // The newline allows the framework to expand the details and turn the first line into a link
530673157b0SGreg Roach				'<div class="markdown">' .
5318c2e8227SGreg Roach				'<p>' . $preamble . '</p>' .
532dc46b574SDavid Drury				'<table>' .
5338c2e8227SGreg Roach				'<thead>' . $thead . '</thead>' .
5348c2e8227SGreg Roach				'<tbody>' . $tbody . '</tbody>' .
5358c2e8227SGreg Roach				'</table>' .
536dc46b574SDavid Drury				'<p>' . $postamble . '</p>' .
537dc46b574SDavid Drury				'</div>';
5388c2e8227SGreg Roach		} else {
5398c2e8227SGreg Roach			// Not a census-assistant shared note - apply default formatting
54015d603e7SGreg Roach			return Filter::formatText($note->getNote(), $note->getTree());
5418c2e8227SGreg Roach		}
5428c2e8227SGreg Roach	}
54399f222b3SGreg Roach
54499f222b3SGreg Roach	/**
545ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census header
54652bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
54752bc9faeSGreg Roach	 * Add suffix cell (delete button)
54852bc9faeSGreg Roach	 *
549ad51e0bbSGreg Roach	 * @param CensusInterface $census
55099f222b3SGreg Roach	 *
551ad51e0bbSGreg Roach	 * @return string
55299f222b3SGreg Roach	 */
553ad51e0bbSGreg Roach	public static function censusTableHeader(CensusInterface $census) {
55452bc9faeSGreg Roach		$html = '';
555ad51e0bbSGreg Roach		foreach ($census->columns() as $column) {
55615d603e7SGreg Roach			$html .= '<th class="wt-census-assistant-field" title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
55799f222b3SGreg Roach		}
55899f222b3SGreg Roach
55915d603e7SGreg Roach		return '<tr class="wt-census-assistant-row"><th hidden></th>' . $html . '<th></th></tr>';
560ad51e0bbSGreg Roach	}
56199f222b3SGreg Roach
562ad51e0bbSGreg Roach	/**
563ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census
56452bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
56552bc9faeSGreg Roach	 * Add suffix cell (delete button)
56652bc9faeSGreg Roach	 *
567ad51e0bbSGreg Roach	 * @param CensusInterface $census
568ad51e0bbSGreg Roach	 *
569ad51e0bbSGreg Roach	 * @return string
570ad51e0bbSGreg Roach	 */
571ad51e0bbSGreg Roach	public static function censusTableEmptyRow(CensusInterface $census) {
57215d603e7SGreg 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>';
573ad51e0bbSGreg Roach	}
57499f222b3SGreg Roach
575ad51e0bbSGreg Roach	/**
576ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census
57752bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
57852bc9faeSGreg Roach	 * Add suffix cell (delete button)
57952bc9faeSGreg Roach	 *
580ad51e0bbSGreg Roach	 * @param CensusInterface $census
581ad51e0bbSGreg Roach	 * @param Individual      $individual
582ad51e0bbSGreg Roach	 * @param Individual      $head
583ad51e0bbSGreg Roach	 *
584ad51e0bbSGreg Roach	 * @return string
585ad51e0bbSGreg Roach	 */
58615d603e7SGreg Roach	public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head) {
58715d603e7SGreg Roach		$html = '';
58815d603e7SGreg Roach		foreach ($census->columns() as $column) {
58915d603e7SGreg 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>';
59099f222b3SGreg Roach		}
59199f222b3SGreg Roach
59215d603e7SGreg 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>';
59399f222b3SGreg Roach	}
5948c2e8227SGreg Roach}
595