xref: /webtrees/app/Module/CensusAssistantModule.php (revision 16d0b7f74e80c16cb445079b0322702930031dc7)
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;
27047f239bSGreg Roachuse Fisharebest\Webtrees\Html;
280e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
2999f222b3SGreg Roachuse Fisharebest\Webtrees\Individual;
300e62c4b8SGreg Roachuse Fisharebest\Webtrees\Note;
31dc46b574SDavid Druryuse Fisharebest\Webtrees\Soundex;
3234cd602eSGreg Roachuse Fisharebest\Webtrees\View;
338c2e8227SGreg Roach
348c2e8227SGreg Roach/**
358c2e8227SGreg Roach * Class CensusAssistantModule
368c2e8227SGreg Roach */
3715834aaeSGreg Roachclass CensusAssistantModule extends AbstractModule {
388c2e8227SGreg Roach	/** {@inheritdoc} */
398c2e8227SGreg Roach	public function getTitle() {
4015d603e7SGreg Roach		return /* I18N: Name of a module */
4115d603e7SGreg Roach			I18N::translate('Census assistant');
428c2e8227SGreg Roach	}
438c2e8227SGreg Roach
448c2e8227SGreg Roach	/** {@inheritdoc} */
458c2e8227SGreg Roach	public function getDescription() {
4615d603e7SGreg Roach		return /* I18N: Description of the “Census assistant” module */
4715d603e7SGreg Roach			I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
488c2e8227SGreg Roach	}
498c2e8227SGreg Roach
5076692c8bSGreg Roach	/**
5176692c8bSGreg Roach	 * This is a general purpose hook, allowing modules to respond to routes
5276692c8bSGreg Roach	 * of the form module.php?mod=FOO&mod_action=BAR
5376692c8bSGreg Roach	 *
5476692c8bSGreg Roach	 * @param string $mod_action
5576692c8bSGreg Roach	 */
568c2e8227SGreg Roach	public function modAction($mod_action) {
5715d603e7SGreg Roach		global $WT_TREE;
5815d603e7SGreg Roach
598c2e8227SGreg Roach		switch ($mod_action) {
6015d603e7SGreg Roach		case 'census-header':
6115d603e7SGreg Roach			header('Content-Type: text/html; charset=utf8');
6215d603e7SGreg Roach			$census = Filter::get('census');
6315d603e7SGreg Roach			echo $this->censusTableHeader(new $census);
648c2e8227SGreg Roach			break;
6515d603e7SGreg Roach
6615d603e7SGreg Roach		case 'census-individual':
6715d603e7SGreg Roach			header('Content-Type: text/html; charset=utf8');
6815d603e7SGreg Roach			$census     = Filter::get('census');
6915d603e7SGreg Roach			$individual = Individual::getInstance(Filter::get('xref'), $WT_TREE);
7015d603e7SGreg Roach			$head       = Individual::getInstance(Filter::get('head'), $WT_TREE);
7115d603e7SGreg Roach			echo $this->censusTableRow(new $census, $individual, $head);
7215d603e7SGreg Roach			break;
7315d603e7SGreg Roach
7440990b78SGreg Roach		case 'media_find':
75764a01d9SGreg Roach			self::mediaFind();
768c2e8227SGreg Roach			break;
778c2e8227SGreg Roach		case 'media_query_3a':
78764a01d9SGreg Roach			self::mediaQuery();
798c2e8227SGreg Roach			break;
808c2e8227SGreg Roach		default:
818c2e8227SGreg Roach			http_response_code(404);
828c2e8227SGreg Roach		}
838c2e8227SGreg Roach	}
848c2e8227SGreg Roach
858c2e8227SGreg Roach	/**
8615d603e7SGreg Roach	 * @param Individual $individual
878c2e8227SGreg Roach	 */
8815d603e7SGreg Roach	public function createCensusAssistant(Individual $individual) {
8934cd602eSGreg Roach		return View::make('modules/census-assistant', [
9034cd602eSGreg Roach			'individual' => $individual,
9134cd602eSGreg Roach		]);
9215d603e7SGreg Roach	}
9315d603e7SGreg Roach
9415d603e7SGreg Roach	/**
9515d603e7SGreg Roach	 * @param Individual $individual
9660bc3e3fSGreg Roach	 * @param string     $fact_id
9715d603e7SGreg Roach	 * @param string     $newged
9860bc3e3fSGreg Roach	 * @param bool       $keep_chan
9915d603e7SGreg Roach	 *
10015d603e7SGreg Roach	 * @return string
10115d603e7SGreg Roach	 */
10215d603e7SGreg Roach	public function updateCensusAssistant(Individual $individual, $fact_id, $newged, $keep_chan) {
10315d603e7SGreg Roach		$ca_title       = Filter::post('ca_title');
10415d603e7SGreg Roach		$ca_place       = Filter::post('ca_place');
10515d603e7SGreg Roach		$ca_citation    = Filter::post('ca_citation');
10615d603e7SGreg Roach		$ca_individuals = Filter::postArray('ca_individuals');
10715d603e7SGreg Roach		$ca_notes       = Filter::post('ca_notes');
10815d603e7SGreg Roach		$ca_census      = Filter::post('ca_census', 'Fisharebest\\\\Webtrees\\\\Census\\\\CensusOf[A-Za-z0-9]+');
10915d603e7SGreg Roach
11015d603e7SGreg Roach		if ($ca_census !== '' && !empty($ca_individuals)) {
11115d603e7SGreg Roach			$census = new $ca_census;
11215d603e7SGreg Roach
11315d603e7SGreg Roach			$note_text   = $this->createNoteText($census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes);
11415d603e7SGreg Roach			$note_gedcom = '0 @new@ NOTE ' . str_replace("\n", "\n1 CONT ", $note_text);
11515d603e7SGreg Roach			$note        = $individual->getTree()->createRecord($note_gedcom);
11615d603e7SGreg Roach
11715d603e7SGreg Roach			$newged .= "\n2 NOTE @" . $note->getXref() . '@';
11815d603e7SGreg Roach
11915d603e7SGreg Roach			// Add the census fact to the rest of the household
12015d603e7SGreg Roach			foreach (array_keys($ca_individuals) as $xref) {
12115d603e7SGreg Roach				if ($xref !== $individual->getXref()) {
12215d603e7SGreg Roach					Individual::getInstance($xref, $individual->getTree())
12315d603e7SGreg Roach						->updateFact($fact_id, $newged, !$keep_chan);
12415d603e7SGreg Roach				}
12515d603e7SGreg Roach			}
12615d603e7SGreg Roach		}
12715d603e7SGreg Roach
12815d603e7SGreg Roach		return $newged;
12915d603e7SGreg Roach	}
13015d603e7SGreg Roach
13115d603e7SGreg Roach	/**
13215d603e7SGreg Roach	 * @param CensusInterface $census
13315d603e7SGreg Roach	 * @param string          $ca_title
13415d603e7SGreg Roach	 * @param string          $ca_place
13515d603e7SGreg Roach	 * @param string          $ca_citation
13615d603e7SGreg Roach	 * @param string[][]      $ca_individuals
13715d603e7SGreg Roach	 * @param string          $ca_notes
13815d603e7SGreg Roach	 *
13915d603e7SGreg Roach	 * @return string
14015d603e7SGreg Roach	 */
14115d603e7SGreg Roach	private function createNoteText(CensusInterface $census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes) {
1420d46ec71SGreg Roach		$text = $ca_title . "\n" . $ca_citation . "\n" . $ca_place . "\n\n";
14315d603e7SGreg Roach
14415d603e7SGreg Roach		foreach ($census->columns() as $n => $column) {
1450d46ec71SGreg Roach			if ($n === 0) {
1460d46ec71SGreg Roach				$text .= "\n";
1470d46ec71SGreg Roach			} else {
14815d603e7SGreg Roach				$text .= ' | ';
14915d603e7SGreg Roach			}
1500d46ec71SGreg Roach			$text .= $column->abbreviation();
1510d46ec71SGreg Roach		}
1520d46ec71SGreg Roach
1530d46ec71SGreg Roach		foreach ($census->columns() as $n => $column) {
1540d46ec71SGreg Roach			if ($n === 0) {
1550d46ec71SGreg Roach				$text .= "\n";
1560d46ec71SGreg Roach			} else {
1570d46ec71SGreg Roach				$text .= ' | ';
1580d46ec71SGreg Roach			}
1590d46ec71SGreg Roach			$text .= '-----';
16015d603e7SGreg Roach		}
16115d603e7SGreg Roach
16215d603e7SGreg Roach		foreach ($ca_individuals as $xref => $columns) {
16315d603e7SGreg Roach			$text .= "\n" . implode(' | ', $columns);
16415d603e7SGreg Roach		}
16515d603e7SGreg Roach
1660d46ec71SGreg Roach		return $text . "\n\n" . $ca_notes;
16740990b78SGreg Roach	}
16840990b78SGreg Roach
16940990b78SGreg Roach	/**
17076692c8bSGreg Roach	 * Find a media object.
17140990b78SGreg Roach	 */
172764a01d9SGreg Roach	private static function mediaFind() {
1738c2e8227SGreg Roach		global $WT_TREE;
1748c2e8227SGreg Roach
1758c2e8227SGreg Roach		$controller = new SimpleController;
1768c2e8227SGreg Roach		$filter     = Filter::get('filter');
1778c2e8227SGreg Roach		$multiple   = Filter::getBool('multiple');
1788c2e8227SGreg Roach
1798c2e8227SGreg Roach		$controller
1808c2e8227SGreg Roach			->setPageTitle(I18N::translate('Find an individual'))
1818c2e8227SGreg Roach			->pageHeader();
1828c2e8227SGreg Roach
1838c2e8227SGreg Roach		?>
18499f222b3SGreg Roach		<script>
1858c2e8227SGreg Roach			function pasterow(id, name, gend, yob, age, bpl) {
1868c2e8227SGreg Roach				window.opener.opener.insertRowToTable(id, name, '', gend, '', yob, age, 'Y', '', bpl);
1878c2e8227SGreg Roach			}
1888c2e8227SGreg Roach
1898c2e8227SGreg Roach			function pasteid(id, name, thumb) {
1908c2e8227SGreg Roach				if (thumb) {
1918c2e8227SGreg Roach					window.opener.paste_id(id, name, thumb);
19215d603e7SGreg Roach					<?php if (!$multiple) {
19315d603e7SGreg Roach					echo 'window.close();';
19415d603e7SGreg Roach				} ?>
1958c2e8227SGreg Roach				} else {
1968c2e8227SGreg Roach					// GEDFact_assistant ========================
1978c2e8227SGreg Roach					if (window.opener.document.getElementById('addlinkQueue')) {
1988c2e8227SGreg Roach						window.opener.insertRowToTable(id, name);
1998c2e8227SGreg Roach					}
2008c2e8227SGreg Roach					window.opener.paste_id(id);
2018c2e8227SGreg Roach					if (window.opener.pastename) {
2028c2e8227SGreg Roach						window.opener.pastename(name);
2038c2e8227SGreg Roach					}
20415d603e7SGreg Roach					<?php if (!$multiple) {
20515d603e7SGreg Roach					echo 'window.close();';
20615d603e7SGreg Roach				} ?>
2078c2e8227SGreg Roach				}
2088c2e8227SGreg Roach			}
20915d603e7SGreg Roach
2108c2e8227SGreg Roach			function checknames(frm) {
2116fde90caSGreg Roach				var button = '';
2128c2e8227SGreg Roach				if (document.forms[0].subclick) {
2138c2e8227SGreg Roach					button = document.forms[0].subclick.value;
2148c2e8227SGreg Roach				}
21515d603e7SGreg Roach				if (frm.filter.value.length < 2 && button !== 'all') {
21615d603e7SGreg Roach					alert('<?= I18N::translate('Please enter more than one character.') ?>');
2178c2e8227SGreg Roach					frm.filter.focus();
2188c2e8227SGreg Roach					return false;
2198c2e8227SGreg Roach				}
2206fde90caSGreg Roach				if (button === 'all') {
22115d603e7SGreg Roach					frm.filter.value = '';
2228c2e8227SGreg Roach				}
2238c2e8227SGreg Roach				return true;
2248c2e8227SGreg Roach			}
22599f222b3SGreg Roach		</script>
2268c2e8227SGreg Roach
22799f222b3SGreg Roach		<?php
228a86dd8b1SGreg Roach		echo '<div>';
2294c621133SGreg Roach		echo '<table class="list_table width90" border="0">';
230d20fc238SGreg Roach		echo '<tr><td style="padding: 10px;" class="width90">'; // start column for find text header
2318c2e8227SGreg Roach		echo $controller->getPageTitle();
2324c621133SGreg Roach		echo '</td>';
2334c621133SGreg Roach		echo '</tr>';
2344c621133SGreg Roach		echo '</table>';
2354c621133SGreg Roach		echo '<br>';
2368c2e8227SGreg Roach		echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
2374c621133SGreg Roach		echo '<br>';
2388c2e8227SGreg Roach
2398c2e8227SGreg Roach		$filter       = trim($filter);
2408c2e8227SGreg Roach		$filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
2414c621133SGreg Roach		echo '<table class="tabs_table width90"><tr>';
24213abd6f3SGreg Roach		$myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
2438c2e8227SGreg Roach		if ($myindilist) {
2444c621133SGreg Roach			echo '<td class="list_value_wrap"><ul>';
2450e62c4b8SGreg Roach			usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
2468c2e8227SGreg Roach			foreach ($myindilist as $indi) {
247cc5ab399SGreg Roach				$nam = Html::escape($indi->getFullName());
2488c2e8227SGreg Roach				echo "<li><a href=\"#\" onclick=\"pasterow(
2498c2e8227SGreg Roach					'" . $indi->getXref() . "' ,
2508c2e8227SGreg Roach					'" . $nam . "' ,
2518c2e8227SGreg Roach					'" . $indi->getSex() . "' ,
2527820e4d7SGreg Roach					'" . $indi->getBirthYear() . "' ,
2537820e4d7SGreg Roach					'" . (1901 - $indi->getBirthYear()) . "' ,
254*16d0b7f7SRico Sonntag					'" . $indi->getBirthPlace()->getGedcomName(). "'); return false;\">
2557a6ee1acSGreg Roach					<b>" . $indi->getFullName() . '</b>&nbsp;&nbsp;&nbsp;';
2568c2e8227SGreg Roach
257564ae2d7SGreg Roach				$born = I18N::translate('Birth');
258*16d0b7f7SRico Sonntag				echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace()->getGedcomName(), '</span></a></li>';
2597a6ee1acSGreg Roach				echo '<hr>';
2608c2e8227SGreg Roach			}
2618c2e8227SGreg Roach			echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
2628c2e8227SGreg Roach		} else {
2637a6ee1acSGreg Roach			echo '<td class="list_value_wrap">';
2648c2e8227SGreg Roach			echo I18N::translate('No results found.');
2657a6ee1acSGreg Roach			echo '</td></tr>';
2668c2e8227SGreg Roach		}
2677a6ee1acSGreg Roach		echo '</table>';
2688c2e8227SGreg Roach		echo '</div>';
2698c2e8227SGreg Roach	}
2708c2e8227SGreg Roach
2718c2e8227SGreg Roach	/**
27276692c8bSGreg Roach	 * Search for a media object.
2738c2e8227SGreg Roach	 */
274764a01d9SGreg Roach	private static function mediaQuery() {
27524ec66ceSGreg Roach		global $WT_TREE;
27624ec66ceSGreg Roach
2778c2e8227SGreg Roach		$iid2 = Filter::get('iid', WT_REGEX_XREF);
2788c2e8227SGreg Roach
2798c2e8227SGreg Roach		$controller = new SimpleController;
2808c2e8227SGreg Roach		$controller
2818c2e8227SGreg Roach			->setPageTitle(I18N::translate('Link to an existing media object'))
2828c2e8227SGreg Roach			->pageHeader();
2838c2e8227SGreg Roach
28424ec66ceSGreg Roach		$record = GedcomRecord::getInstance($iid2, $WT_TREE);
2858c2e8227SGreg Roach		if ($record) {
2868c2e8227SGreg Roach			$headjs = '';
2878c2e8227SGreg Roach			if ($record instanceof Family) {
2888c2e8227SGreg Roach				if ($record->getHusband()) {
2898c2e8227SGreg Roach					$headjs = $record->getHusband()->getXref();
2908c2e8227SGreg Roach				} elseif ($record->getWife()) {
2918c2e8227SGreg Roach					$headjs = $record->getWife()->getXref();
2928c2e8227SGreg Roach				}
2938c2e8227SGreg Roach			}
2948c2e8227SGreg Roach			?>
2958c2e8227SGreg Roach			<script>
2968c2e8227SGreg Roach				function insertId() {
2978c2e8227SGreg Roach					if (window.opener.document.getElementById('addlinkQueue')) {
2988c2e8227SGreg Roach						// alert('Please move this alert window and examine the contents of the pop-up window, then click OK')
299564ae2d7SGreg Roach						window.opener.insertRowToTable('<?= $record->getXref() ?>', '<?= htmlspecialchars($record->getFullName()) ?>', '<?= $headjs ?>');
3008c2e8227SGreg Roach						window.close();
3018c2e8227SGreg Roach					}
3028c2e8227SGreg Roach				}
3038c2e8227SGreg Roach			</script>
3048c2e8227SGreg Roach			<?php
3058c2e8227SGreg Roach		} else {
3068c2e8227SGreg Roach			?>
3078c2e8227SGreg Roach			<script>
3088c2e8227SGreg Roach				function insertId() {
309564ae2d7SGreg Roach					window.opener.alert('<?= $iid2 ?> - <?= I18N::translate('Not a valid individual, family, or source ID') ?>');
3108c2e8227SGreg Roach					window.close();
3118c2e8227SGreg Roach				}
3128c2e8227SGreg Roach			</script>
3138c2e8227SGreg Roach			<?php
3148c2e8227SGreg Roach		}
3158c2e8227SGreg Roach		?>
3168c2e8227SGreg Roach		<script>window.onLoad = insertId();</script>
3178c2e8227SGreg Roach		<?php
3188c2e8227SGreg Roach	}
3198c2e8227SGreg Roach
3208c2e8227SGreg Roach	/**
321ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census header
32252bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
32352bc9faeSGreg Roach	 * Add suffix cell (delete button)
32452bc9faeSGreg Roach	 *
325ad51e0bbSGreg Roach	 * @param CensusInterface $census
32699f222b3SGreg Roach	 *
327ad51e0bbSGreg Roach	 * @return string
32899f222b3SGreg Roach	 */
329ad51e0bbSGreg Roach	public static function censusTableHeader(CensusInterface $census) {
33052bc9faeSGreg Roach		$html = '';
331ad51e0bbSGreg Roach		foreach ($census->columns() as $column) {
33215d603e7SGreg Roach			$html .= '<th class="wt-census-assistant-field" title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
33399f222b3SGreg Roach		}
33499f222b3SGreg Roach
33515d603e7SGreg Roach		return '<tr class="wt-census-assistant-row"><th hidden></th>' . $html . '<th></th></tr>';
336ad51e0bbSGreg Roach	}
33799f222b3SGreg Roach
338ad51e0bbSGreg Roach	/**
339ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census
34052bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
34152bc9faeSGreg Roach	 * Add suffix cell (delete button)
34252bc9faeSGreg Roach	 *
343ad51e0bbSGreg Roach	 * @param CensusInterface $census
344ad51e0bbSGreg Roach	 *
345ad51e0bbSGreg Roach	 * @return string
346ad51e0bbSGreg Roach	 */
347ad51e0bbSGreg Roach	public static function censusTableEmptyRow(CensusInterface $census) {
34815d603e7SGreg 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>';
349ad51e0bbSGreg Roach	}
35099f222b3SGreg Roach
351ad51e0bbSGreg Roach	/**
352ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census
35352bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
35452bc9faeSGreg Roach	 * Add suffix cell (delete button)
35552bc9faeSGreg Roach	 *
356ad51e0bbSGreg Roach	 * @param CensusInterface $census
357ad51e0bbSGreg Roach	 * @param Individual      $individual
358ad51e0bbSGreg Roach	 * @param Individual      $head
359ad51e0bbSGreg Roach	 *
360ad51e0bbSGreg Roach	 * @return string
361ad51e0bbSGreg Roach	 */
36215d603e7SGreg Roach	public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head) {
36315d603e7SGreg Roach		$html = '';
36415d603e7SGreg Roach		foreach ($census->columns() as $column) {
36515d603e7SGreg 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>';
36699f222b3SGreg Roach		}
36799f222b3SGreg Roach
36815d603e7SGreg 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>';
36999f222b3SGreg Roach	}
3708c2e8227SGreg Roach}
371