xref: /webtrees/app/Module/CensusAssistantModule.php (revision d2681c37325a35ab01be82034f4afd3b58010fb8)
1<?php
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
17namespace Fisharebest\Webtrees\Module;
18
19use Fisharebest\Webtrees\Census\Census;
20use Fisharebest\Webtrees\Census\CensusInterface;
21use Fisharebest\Webtrees\Family;
22use Fisharebest\Webtrees\Filter;
23use Fisharebest\Webtrees\Functions\FunctionsDb;
24use Fisharebest\Webtrees\GedcomRecord;
25use Fisharebest\Webtrees\I18N;
26use Fisharebest\Webtrees\Individual;
27
28/**
29 * Class CensusAssistantModule
30 */
31class CensusAssistantModule extends AbstractModule {
32	/** {@inheritdoc} */
33	public function getTitle() {
34		return /* I18N: Name of a module */
35			I18N::translate('Census assistant');
36	}
37
38	/** {@inheritdoc} */
39	public function getDescription() {
40		return /* I18N: Description of the “Census assistant” module */
41			I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
42	}
43
44	/**
45	 * This is a general purpose hook, allowing modules to respond to routes
46	 * of the form module.php?mod=FOO&mod_action=BAR
47	 *
48	 * @param string $mod_action
49	 */
50	public function modAction($mod_action) {
51		global $WT_TREE;
52
53		switch ($mod_action) {
54			case 'census-header':
55				header('Content-Type: text/html; charset=utf8');
56				$census = Filter::get('census');
57				echo $this->censusTableHeader(new $census);
58				break;
59
60			case 'census-individual':
61				header('Content-Type: text/html; charset=utf8');
62				$census     = Filter::get('census');
63				$individual = Individual::getInstance(Filter::get('xref'), $WT_TREE);
64				$head       = Individual::getInstance(Filter::get('head'), $WT_TREE);
65				echo $this->censusTableRow(new $census, $individual, $head);
66				break;
67
68			case 'media_find':
69				self::mediaFind();
70				break;
71			case 'media_query_3a':
72				self::mediaQuery();
73				break;
74			default:
75				http_response_code(404);
76		}
77	}
78
79	/**
80	 * @param Individual $individual
81	 */
82	public function createCensusAssistant(Individual $individual) {
83		return view('modules/census-assistant', [
84			'individual' => $individual,
85		]);
86	}
87
88	/**
89	 * @param Individual $individual
90	 * @param string     $fact_id
91	 * @param string     $newged
92	 * @param bool       $keep_chan
93	 *
94	 * @return string
95	 */
96	public function updateCensusAssistant(Individual $individual, $fact_id, $newged, $keep_chan) {
97		$ca_title       = Filter::post('ca_title');
98		$ca_place       = Filter::post('ca_place');
99		$ca_citation    = Filter::post('ca_citation');
100		$ca_individuals = Filter::postArray('ca_individuals');
101		$ca_notes       = Filter::post('ca_notes');
102		$ca_census      = Filter::post('ca_census', 'Fisharebest\\\\Webtrees\\\\Census\\\\CensusOf[A-Za-z0-9]+');
103
104		if ($ca_census !== '' && !empty($ca_individuals)) {
105			$census = new $ca_census;
106
107			$note_text   = $this->createNoteText($census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes);
108			$note_gedcom = '0 @new@ NOTE ' . str_replace("\n", "\n1 CONT ", $note_text);
109			$note        = $individual->getTree()->createRecord($note_gedcom);
110
111			$newged .= "\n2 NOTE @" . $note->getXref() . '@';
112
113			// Add the census fact to the rest of the household
114			foreach (array_keys($ca_individuals) as $xref) {
115				if ($xref !== $individual->getXref()) {
116					Individual::getInstance($xref, $individual->getTree())
117						->updateFact($fact_id, $newged, !$keep_chan);
118				}
119			}
120		}
121
122		return $newged;
123	}
124
125	/**
126	 * @param CensusInterface $census
127	 * @param string          $ca_title
128	 * @param string          $ca_place
129	 * @param string          $ca_citation
130	 * @param string[][]      $ca_individuals
131	 * @param string          $ca_notes
132	 *
133	 * @return string
134	 */
135	private function createNoteText(CensusInterface $census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes) {
136		$text = $ca_title . "\n" . $ca_citation . "\n" . $ca_place . "\n\n";
137
138		foreach ($census->columns() as $n => $column) {
139			if ($n === 0) {
140				$text .= "\n";
141			} else {
142				$text .= ' | ';
143			}
144			$text .= $column->abbreviation();
145		}
146
147		foreach ($census->columns() as $n => $column) {
148			if ($n === 0) {
149				$text .= "\n";
150			} else {
151				$text .= ' | ';
152			}
153			$text .= '-----';
154		}
155
156		foreach ($ca_individuals as $xref => $columns) {
157			$text .= "\n" . implode(' | ', $columns);
158		}
159
160		return $text . "\n\n" . $ca_notes;
161	}
162
163	/**
164	 * Find a media object.
165	 */
166	private static function mediaFind() {
167		global $WT_TREE;
168
169		$controller = new SimpleController;
170		$filter     = Filter::get('filter');
171		$multiple   = Filter::getBool('multiple');
172
173		$controller
174			->setPageTitle(I18N::translate('Find an individual'))
175			->pageHeader();
176
177		?>
178		<script>
179			function pasterow(id, name, gend, yob, age, bpl) {
180				window.opener.opener.insertRowToTable(id, name, '', gend, '', yob, age, 'Y', '', bpl);
181			}
182
183			function pasteid(id, name, thumb) {
184				if (thumb) {
185					window.opener.paste_id(id, name, thumb);
186					<?php if (!$multiple) {
187					echo 'window.close();';
188				} ?>
189				} else {
190					// GEDFact_assistant ========================
191					if (window.opener.document.getElementById('addlinkQueue')) {
192						window.opener.insertRowToTable(id, name);
193					}
194					window.opener.paste_id(id);
195					if (window.opener.pastename) {
196						window.opener.pastename(name);
197					}
198					<?php if (!$multiple) {
199						echo 'window.close();';
200					} ?>
201				}
202			}
203
204			function checknames(frm) {
205				var button = '';
206				if (document.forms[0].subclick) {
207					button = document.forms[0].subclick.value;
208				}
209				if (frm.filter.value.length < 2 && button !== 'all') {
210					alert('<?= I18N::translate('Please enter more than one character.') ?>');
211					frm.filter.focus();
212					return false;
213				}
214				if (button === 'all') {
215					frm.filter.value = '';
216				}
217				return true;
218			}
219		</script>
220
221		<?php
222		echo '<div>';
223		echo '<table class="list_table width90" border="0">';
224		echo '<tr><td style="padding: 10px;" class="width90">'; // start column for find text header
225		echo $controller->getPageTitle();
226		echo '</td>';
227		echo '</tr>';
228		echo '</table>';
229		echo '<br>';
230		echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
231		echo '<br>';
232
233		$filter       = trim($filter);
234		$filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
235		echo '<table class="tabs_table width90"><tr>';
236		$myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
237		if ($myindilist) {
238			echo '<td class="list_value_wrap"><ul>';
239			usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
240			foreach ($myindilist as $indi) {
241				$nam = e($indi->getFullName());
242				echo "<li><a href=\"#\" onclick=\"pasterow(
243					'" . $indi->getXref() . "' ,
244					'" . $nam . "' ,
245					'" . $indi->getSex() . "' ,
246					'" . $indi->getBirthYear() . "' ,
247					'" . (1901 - $indi->getBirthYear()) . "' ,
248					'" . $indi->getBirthPlace()->getGedcomName() . "'); return false;\">
249					<b>" . $indi->getFullName() . '</b>&nbsp;&nbsp;&nbsp;';
250
251				$born = I18N::translate('Birth');
252				echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace()->getGedcomName(), '</span></a></li>';
253				echo '<hr>';
254			}
255			echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
256		} else {
257			echo '<td class="list_value_wrap">';
258			echo I18N::translate('No results found.');
259			echo '</td></tr>';
260		}
261		echo '</table>';
262		echo '</div>';
263	}
264
265	/**
266	 * Search for a media object.
267	 */
268	private static function mediaQuery() {
269		global $WT_TREE;
270
271		$iid2 = Filter::get('iid', WT_REGEX_XREF);
272
273		$controller = new SimpleController;
274		$controller
275			->setPageTitle(I18N::translate('Link to an existing media object'))
276			->pageHeader();
277
278		$record = GedcomRecord::getInstance($iid2, $WT_TREE);
279		if ($record) {
280			$headjs = '';
281			if ($record instanceof Family) {
282				if ($record->getHusband()) {
283					$headjs = $record->getHusband()->getXref();
284				} elseif ($record->getWife()) {
285					$headjs = $record->getWife()->getXref();
286				}
287			}
288			?>
289			<script>
290				function insertId() {
291					if (window.opener.document.getElementById('addlinkQueue')) {
292						// alert('Please move this alert window and examine the contents of the pop-up window, then click OK')
293						window.opener.insertRowToTable('<?= $record->getXref() ?>', '<?= htmlspecialchars($record->getFullName()) ?>', '<?= $headjs ?>');
294						window.close();
295					}
296				}
297			</script>
298			<?php
299		} else {
300			?>
301			<script>
302				function insertId() {
303					window.opener.alert('<?= $iid2 ?> - <?= I18N::translate('Not a valid individual, family, or source ID') ?>');
304					window.close();
305				}
306			</script>
307			<?php
308		}
309		?>
310		<script>window.onLoad = insertId();</script>
311		<?php
312	}
313
314	/**
315	 * Generate an HTML row of data for the census header
316	 * Add prefix cell (store XREF and drag/drop)
317	 * Add suffix cell (delete button)
318	 *
319	 * @param CensusInterface $census
320	 *
321	 * @return string
322	 */
323	public static function censusTableHeader(CensusInterface $census) {
324		$html = '';
325		foreach ($census->columns() as $column) {
326			$html .= '<th class="wt-census-assistant-field" title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
327		}
328
329		return '<tr class="wt-census-assistant-row"><th hidden></th>' . $html . '<th></th></tr>';
330	}
331
332	/**
333	 * Generate an HTML row of data for the census
334	 * Add prefix cell (store XREF and drag/drop)
335	 * Add suffix cell (delete button)
336	 *
337	 * @param CensusInterface $census
338	 *
339	 * @return string
340	 */
341	public static function censusTableEmptyRow(CensusInterface $census) {
342		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>';
343	}
344
345	/**
346	 * Generate an HTML row of data for the census
347	 * Add prefix cell (store XREF and drag/drop)
348	 * Add suffix cell (delete button)
349	 *
350	 * @param CensusInterface $census
351	 * @param Individual      $individual
352	 * @param Individual      $head
353	 *
354	 * @return string
355	 */
356	public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head) {
357		$html = '';
358		foreach ($census->columns() as $column) {
359			$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>';
360		}
361
362		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>';
363	}
364}
365