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