xref: /webtrees/app/Module/CensusAssistantModule.php (revision ffd703ea1e658c7dcb5e5f1f9ef137a420f2d167)
1<?php
2namespace Fisharebest\Webtrees;
3
4/**
5 * webtrees: online genealogy
6 * Copyright (C) 2015 webtrees development team
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * Class CensusAssistantModule
21 */
22class CensusAssistantModule extends AbstractModule {
23	/** {@inheritdoc} */
24	public function getTitle() {
25		return /* I18N: Name of a module */ I18N::translate('Census assistant');
26	}
27
28	/** {@inheritdoc} */
29	public function getDescription() {
30		return /* I18N: Description of the “Census assistant” module */ I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
31	}
32
33	/** {@inheritdoc} */
34	public function modAction($mod_action) {
35		switch ($mod_action) {
36		case '_CENS/census_3_find':
37			// TODO: this file should be a method in this class
38			require WT_ROOT . WT_MODULES_DIR . $this->getName() . '/_CENS/census_3_find.php';
39			break;
40		case 'media_3_find':
41			self::mediaFind();
42			break;
43		case 'media_query_3a':
44			self::mediaQuery();
45			break;
46		default:
47			echo $mod_action;
48			http_response_code(404);
49		}
50	}
51
52	/**
53	 * ...
54	 */
55	private static function mediaFind() {
56		global $WT_TREE;
57
58		$controller = new SimpleController;
59		$filter     = Filter::get('filter');
60		$multiple   = Filter::getBool('multiple');
61
62		$controller
63			->setPageTitle(I18N::translate('Find an individual'))
64			->pageHeader();
65
66		echo '<script>';
67		?>
68
69			function pasterow(id, name, gend, yob, age, bpl) {
70				window.opener.opener.insertRowToTable(id, name, '', gend, '', yob, age, 'Y', '', bpl);
71			}
72
73			function pasteid(id, name, thumb) {
74				if (thumb) {
75					window.opener.paste_id(id, name, thumb);
76					<?php if (!$multiple) echo "window.close();"; ?>
77				} else {
78					// GEDFact_assistant ========================
79					if (window.opener.document.getElementById('addlinkQueue')) {
80						window.opener.insertRowToTable(id, name);
81					}
82					window.opener.paste_id(id);
83					if (window.opener.pastename) {
84						window.opener.pastename(name);
85					}
86					<?php if (!$multiple) echo "window.close();"; ?>
87				}
88			}
89			function checknames(frm) {
90				if (document.forms[0].subclick) {
91					button = document.forms[0].subclick.value;
92				} else {
93					button = "";
94				}
95				if (frm.filter.value.length<2&button!="all") {
96					alert("<?php echo I18N::translate('Please enter more than one character.'); ?>");
97					frm.filter.focus();
98					return false;
99				}
100				if (button=="all") {
101					frm.filter.value = "";
102				}
103				return true;
104			}
105		<?php
106		echo '</script>';
107
108		echo "<div align=\"center\">";
109		echo "<table class=\"list_table width90\" border=\"0\">";
110		echo "<tr><td style=\"padding: 10px;\" valign=\"top\" class=\"facts_label03 width90\">"; // start column for find text header
111		echo $controller->getPageTitle();
112		echo "</td>";
113		echo "</tr>";
114		echo "</table>";
115		echo "<br>";
116		echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
117		echo "<br>";
118
119		$filter = trim($filter);
120		$filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
121		echo "<table class=\"tabs_table width90\"><tr>";
122		$myindilist = search_indis_names($filter_array, array($WT_TREE));
123		if ($myindilist) {
124			echo "<td class=\"list_value_wrap\"><ul>";
125			usort($myindilist, __NAMESPACE__ . '\GedcomRecord::compare');
126			foreach ($myindilist as $indi) {
127				$nam = Filter::escapeHtml($indi->getFullName());
128				echo "<li><a href=\"#\" onclick=\"pasterow(
129					'".$indi->getXref() . "' ,
130					'".$nam . "' ,
131					'".$indi->getSex() . "' ,
132					'".$indi->getbirthyear() . "' ,
133					'".(1901 - $indi->getbirthyear()) . "' ,
134					'".$indi->getbirthplace() . "'); return false;\">
135					<b>".$indi->getFullName() . "</b>&nbsp;&nbsp;&nbsp;";
136
137				$born = GedcomTag::getLabel('BIRT');
138				echo "</span><br><span class=\"list_item\">", $born, " ", $indi->getbirthyear(), "&nbsp;&nbsp;&nbsp;", $indi->getbirthplace(), "</span></a></li>";
139			echo "<hr>";
140			}
141			echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
142		} else {
143			echo "<td class=\"list_value_wrap\">";
144			echo I18N::translate('No results found.');
145			echo "</td></tr>";
146		}
147		echo "</table>";
148		echo '</div>';
149	}
150
151	/**
152	 * ...
153	 */
154	private static function mediaQuery() {
155		global $WT_TREE;
156
157		$iid2 = Filter::get('iid', WT_REGEX_XREF);
158
159		$controller = new SimpleController;
160		$controller
161			->setPageTitle(I18N::translate('Link to an existing media object'))
162			->pageHeader();
163
164		$record = GedcomRecord::getInstance($iid2, $WT_TREE);
165		if ($record) {
166			$headjs = '';
167			if ($record instanceof Family) {
168				if ($record->getHusband()) {
169					$headjs = $record->getHusband()->getXref();
170				} elseif ($record->getWife()) {
171					$headjs = $record->getWife()->getXref();
172				}
173			}
174			?>
175			<script>
176			function insertId() {
177				if (window.opener.document.getElementById('addlinkQueue')) {
178					// alert('Please move this alert window and examine the contents of the pop-up window, then click OK')
179					window.opener.insertRowToTable('<?php echo $record->getXref(); ?>', '<?php echo htmlSpecialChars($record->getFullName()); ?>', '<?php echo $headjs; ?>');
180					window.close();
181				}
182			}
183			</script>
184			<?php
185
186		} else {
187			?>
188			<script>
189			function insertId() {
190				window.opener.alert('<?php echo $iid2; ?> - <?php echo I18N::translate('Not a valid individual, family, or source ID'); ?>');
191				window.close();
192			}
193			</script>
194			<?php
195		}
196		?>
197		<script>window.onLoad = insertId();</script>
198		<?php
199	}
200
201	/**
202	 * Convert custom markup into HTML
203	 *
204	 * @param Note $note
205	 *
206	 * @return string
207	 */
208	public static function formatCensusNote(Note $note) {
209		global $WT_TREE;
210
211		$headers = array(
212			'AgM'        => 'Age at first marriage',
213			'Age'        => 'Age at last birthday',
214			'Assets'     => 'Assets = Owned,Rented - Value,Rent - Radio - Farm',
215			'BIC'        => 'Born in County',
216			'BOE'        => 'Born outside England',
217			'BP'         => 'Birthplace - (Chapman format)',
218			'Birthplace' => 'Birthplace (Full format)',
219			'Bmth'       => 'Month of birth - If born within Census year',
220			'ChB'        => 'Children born alive',
221			'ChD'        => 'Children who have died',
222			'ChL'        => 'Children still living',
223			'DOB'        => 'Date of birth',
224			'Edu'        => 'Education - At School, Can Read, Can Write', // or "Cannot Read, Cannot Write" ??
225			'EmD'        => 'Employed?',
226			'EmN'        => 'Unemployed?',
227			'EmR'        => 'Employer?',
228			'Employ'     => 'Employment',
229			'Eng?'       => 'English spoken?',
230			'EngL'       => 'English spoken?, if not, Native Language',
231			'FBP'        => 'Father’s Birthplace - (Chapman format)',
232			'Health'     => 'Health - 1.Blind, 2.Deaf & Dumb, 3.Idiotic, 4.Insane, 5.Disabled etc',
233			'Home'       => 'Home Ownership - Owned/Rented-Free/Mortgaged-Farm/House-Farm Schedule number',
234			'Industry'   => 'Industry',
235			'Infirm'     => 'Infirmities - 1. Deaf & Dumb, 2. Blind, 3. Lunatic, 4. Imbecile/feeble-minded',
236			'Lang'       => 'If Foreign Born - Native Language',
237			'MBP'        => 'Mother’s Birthplace - (Chapman format)',
238			'MC'         => 'Marital Condition - Married, Single, Unmarried, Widowed or Divorced',
239			'Mmth'       => 'Month of marriage - If married during Census Year',
240			'MnsE'       => 'Months employed during Census Year',
241			'MnsU'       => 'Months unemployed during Census Year',
242			'N/A'        => 'If Foreign Born - Naturalized, Alien',
243			'NL'         => 'If Foreign Born - Native Language',
244			'Name'       => 'Full Name or Married name if married',
245			'Occupation' => 'Occupation',
246			'Par'        => 'Parentage - Father if foreign born, Mother if foreign born',
247			'Race'       => 'Race or Color - Black, White, Mulatto, Asian, Indian, Chinese etc',
248			'Relation'   => 'Relationship to Head of Household',
249			'Sex'        => 'Male or Female',
250			'Situ'       => 'Situation - Disease, Infirmity, Convict, Pauper etc',
251			'Ten'        => 'Tenure - Owned/Rented, (if owned)Free/Morgaged',
252			'Vet'        => 'War Veteran?',
253			'WH'         => 'Working at Home?',
254			'War'        => 'War or Expedition',
255			'WksU'       => 'Weeks unemployed during Census Year',
256			'YOI'        => 'If Foreign Born - Year of immigration',
257			'YON'        => 'If Foreign Born - Year of naturalization',
258			'YUS'        => 'If Foreign Born - Years in the USA',
259			'YrsM'       => 'Years Married, or Y if married in Census Year',
260		);
261
262		if (preg_match('/(.*)((?:\n.*)*)\n\.start_formatted_area\.\n(.*)((?:\n.*)*)\n.end_formatted_area\.((?:\n.*)*)/', $note->getNote(), $match)) {
263			// This looks like a census-assistant shared note
264			$title     = Filter::escapeHtml($match[1]);
265			$preamble  = Filter::escapeHtml($match[2]);
266			$header    = Filter::escapeHtml($match[3]);
267			$data      = Filter::escapeHtml($match[4]);
268			$postamble = Filter::escapeHtml($match[5]);
269
270			$fmt_headers = array();
271			foreach ($headers as $key=>$value) {
272				$fmt_headers['.b.' . $key] = '<span title="' . Filter::escapeHtml($value) . '">' . $key . '</span>';
273			}
274
275			// Substitue header labels and format as HTML
276			$thead = '<tr><th>' . strtr(str_replace('|', '</th><th>', $header), $fmt_headers) . '</th></tr>';
277
278			// Format data as HTML
279			$tbody = '';
280			foreach (explode("\n", $data) as $row) {
281				$tbody .= '<tr>';
282				foreach (explode('|', $row) as $column) {
283					$tbody .= '<td>' . $column . '</td>';
284				}
285				$tbody .= '</tr>';
286			}
287
288			return
289				$title . "\n" . // The newline allows the framework to expand the details and turn the first line into a link
290				'<p>' . $preamble . '</p>' .
291				'<table class="table-census-assistant">' .
292				'<thead>' . $thead . '</thead>' .
293				'<tbody>' . $tbody . '</tbody>' .
294				'</table>' .
295				'<p>' . $postamble . '</p>';
296		} else {
297			// Not a census-assistant shared note - apply default formatting
298			return Filter::formatText($note->getNote(), $WT_TREE);
299		}
300	}
301
302	/**
303	 * Modify the “add shared note” field, to create a note using the assistant
304	 *
305	 * @param string $element_id
306	 * @param string $xref
307	 * @param string $action
308	 *
309	 * @return string
310	 */
311	public static function addNoteWithAssistantLink($element_id, $xref, $action) {
312		global $controller, $WT_TREE;
313
314		// We do not yet support family records
315		if (!GedcomRecord::getInstance($xref, $WT_TREE) instanceof Individual) {
316			return '';
317		}
318
319		// Only modify “add shared note” links on the add/edit actions.
320		// TODO: does the “edit” action work?
321		if ($action != 'add' && $action != 'edit') {
322			return '';
323		}
324
325		$controller->addInlineJavascript('
326			var pid_array=jQuery("#pid_array");
327			function set_pid_array(pa) {
328				pid_array.val(pa);
329			}
330		');
331
332		return
333			'<br>' .
334			'<input type="hidden" name="pid_array" id="pid_array" value="">' .
335			'<a href="#" onclick="return addnewnote_assisted(document.getElementById(\'' . $element_id . '\'), \'' . $xref . '\');">' .
336			I18N::translate('Create a new shared note using assistant') .
337			'</a>';
338	}
339
340	/**
341	 * Add a selector containing UK/US/FR census dates
342	 *
343	 * @param string $action
344	 * @param string $tag
345	 * @param string $element_id
346	 *
347	 * @return string
348	 */
349	public static function censusDateSelector($action, $tag, $element_id) {
350		global $controller;
351
352		if ($action == 'add' && $tag == 'CENS') {
353			$controller->addInlineJavascript('
354				function addDate(theCensDate) {
355					var ddate = theCensDate.split(", ");
356					document.getElementById("setctry").value = ddate[3];
357					document.getElementById("setyear").value = ddate[0];
358					cal_setDateField("' . $element_id . '", parseInt(ddate[0]), parseInt(ddate[1]), parseInt(ddate[2]));
359					return false;
360				}
361				function pasteAsstDate(setcy, setyr) {
362					document.getElementById(setcy+setyr).selected = true;
363					addDate(document.getElementById("selcensdate").options[document.getElementById(\'selcensdate\').selectedIndex].value);
364					return false;
365				}
366			');
367
368			return '
369				<select id="selcensdate" name="selcensdate" onchange = "if (this.options[this.selectedIndex].value!=\'\') {
370										addDate(this.options[this.selectedIndex].value);
371									}">
372					<option id="defdate" value="" selected>' . I18N::translate('Census date') . '</option>
373					<option value=""></option>
374					<option id="UK1911" class="UK"  value="1911, 3, 02, UK">UK 1911</option>
375					<option id="UK1901" class="UK"  value="1901, 2, 31, UK">UK 1901</option>
376					<option id="UK1891" class="UK"  value="1891, 3, 05, UK">UK 1891</option>
377					<option id="UK1881" class="UK"  value="1881, 3, 03, UK">UK 1881</option>
378					<option id="UK1871" class="UK"  value="1871, 3, 02, UK">UK 1871</option>
379					<option id="UK1861" class="UK"  value="1861, 3, 07, UK">UK 1861</option>
380					<option id="UK1851" class="UK"  value="1851, 2, 30, UK">UK 1851</option>
381					<option id="UK1841" class="UK"  value="1841, 5, 06, UK">UK 1841</option>
382					<option value=""></option>
383					<option id="USA1940" class="USA" value="1940, 3, 01, USA">US 1940</option>
384					<option id="USA1930" class="USA" value="1930, 3, 01, USA">US 1930</option>
385					<option id="USA1920" class="USA" value="1920, 0, 01, USA">US 1920</option>
386					<option id="USA1910" class="USA" value="1910, 3, 15, USA">US 1910</option>
387					<option id="USA1900" class="USA" value="1900, 5, 01, USA">US 1900</option>
388					<option id="USA1890" class="USA" value="1890, 5, 01, USA">US 1890</option>
389					<option id="USA1880" class="USA" value="1880, 5, 01, USA">US 1880</option>
390					<option id="USA1870" class="USA" value="1870, 5, 01, USA">US 1870</option>
391					<option id="USA1860" class="USA" value="1860, 5, 01, USA">US 1860</option>
392					<option id="USA1850" class="USA" value="1850, 5, 01, USA">US 1850</option>
393					<option id="USA1840" class="USA" value="1840, 5, 01, USA">US 1840</option>
394					<option id="USA1830" class="USA" value="1830, 5, 01, USA">US 1830</option>
395					<option id="USA1820" class="USA" value="1820, 7, 07, USA">US 1820</option>
396					<option id="USA1810" class="USA" value="1810, 7, 06, USA">US 1810</option>
397					<option id="USA1800" class="USA" value="1800, 7, 04, USA">US 1800</option>
398					<option id="USA1790" class="USA" value="1790, 7, 02, USA">US 1790</option>
399					<option value=""></option>
400					<option id="FR1951" class="FR" value="1951, 0, 01, FR">FR 1951</option>
401					<option id="FR1946" class="FR" value="1946, 0, 01, FR">FR 1946</option>
402					<option id="FR1941" class="FR" value="1941, 0, 01, FR">FR 1941</option>
403					<option id="FR1936" class="FR" value="1936, 0, 01, FR">FR 1936</option>
404					<option id="FR1931" class="FR" value="1931, 0, 01, FR">FR 1931</option>
405					<option id="FR1926" class="FR" value="1926, 0, 01, FR">FR 1926</option>
406					<option id="FR1921" class="FR" value="1921, 0, 01, FR">FR 1921</option>
407					<option id="FR1916" class="FR" value="1916, 0, 01, FR">FR 1916</option>
408					<option id="FR1911" class="FR" value="1911, 0, 01, FR">FR 1911</option>
409					<option id="FR1906" class="FR" value="1906, 0, 01, FR">FR 1906</option>
410					<option id="FR1901" class="FR" value="1901, 0, 01, FR">FR 1901</option>
411					<option id="FR1896" class="FR" value="1896, 0, 01, FR">FR 1896</option>
412					<option id="FR1891" class="FR" value="1891, 0, 01, FR">FR 1891</option>
413					<option id="FR1886" class="FR" value="1886, 0, 01, FR">FR 1886</option>
414					<option id="FR1881" class="FR" value="1881, 0, 01, FR">FR 1881</option>
415					<option id="FR1876" class="FR" value="1876, 0, 01, FR">FR 1876</option>
416					<option value=""></option>
417				</select>
418
419				<input type="hidden" id="setctry" name="setctry" value="">
420				<input type="hidden" id="setyear" name="setyear" value="">
421			';
422		} else {
423			return '';
424		}
425	}
426}
427