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 Module { 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> "; 136 137 $born = GedcomTag::getLabel('BIRT'); 138 echo "</span><br><span class=\"list_item\">", $born, " ", $indi->getbirthyear(), " ", $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 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 // There are lots of “add shared note” links. We only need to modify the 2nd one 326 static $n = 0; 327 if (++$n != 2) { 328 return ''; 329 } 330 331 $controller->addInlineJavascript(' 332 var pid_array=jQuery("#pid_array"); 333 function set_pid_array(pa) { 334 pid_array.val(pa); 335 } 336 '); 337 338 return 339 '<br>' . 340 '<input type="hidden" name="pid_array" id="pid_array" value="">' . 341 '<a href="#" onclick="return addnewnote_assisted(document.getElementById(\'' . $element_id . '\'), \'' . $xref . '\');">' . 342 I18N::translate('Create a new shared note using assistant') . 343 '</a>'; 344 } 345 346 /** 347 * Add a selector containing UK/US/FR census dates 348 * 349 * @param string $action 350 * @param string $tag 351 * @param string $element_id 352 * 353 * @return string 354 */ 355 public static function censusDateSelector($action, $tag, $element_id) { 356 global $controller; 357 358 if ($action == 'add' && $tag == 'CENS') { 359 $controller->addInlineJavascript(' 360 function addDate(theCensDate) { 361 var ddate = theCensDate.split(", "); 362 document.getElementById("setctry").value = ddate[3]; 363 document.getElementById("setyear").value = ddate[0]; 364 cal_setDateField("' . $element_id . '", parseInt(ddate[0]), parseInt(ddate[1]), parseInt(ddate[2])); 365 return false; 366 } 367 function pasteAsstDate(setcy, setyr) { 368 document.getElementById(setcy+setyr).selected = true; 369 addDate(document.getElementById("selcensdate").options[document.getElementById(\'selcensdate\').selectedIndex].value); 370 return false; 371 } 372 '); 373 374 return ' 375 <select id="selcensdate" name="selcensdate" onchange = "if (this.options[this.selectedIndex].value!=\'\') { 376 addDate(this.options[this.selectedIndex].value); 377 }"> 378 <option id="defdate" value="" selected>' . I18N::translate('Census date') . '</option> 379 <option value=""></option> 380 <option id="UK1911" class="UK" value="1911, 3, 02, UK">UK 1911</option> 381 <option id="UK1901" class="UK" value="1901, 2, 31, UK">UK 1901</option> 382 <option id="UK1891" class="UK" value="1891, 3, 05, UK">UK 1891</option> 383 <option id="UK1881" class="UK" value="1881, 3, 03, UK">UK 1881</option> 384 <option id="UK1871" class="UK" value="1871, 3, 02, UK">UK 1871</option> 385 <option id="UK1861" class="UK" value="1861, 3, 07, UK">UK 1861</option> 386 <option id="UK1851" class="UK" value="1851, 2, 30, UK">UK 1851</option> 387 <option id="UK1841" class="UK" value="1841, 5, 06, UK">UK 1841</option> 388 <option value=""></option> 389 <option id="USA1940" class="USA" value="1940, 3, 01, USA">US 1940</option> 390 <option id="USA1930" class="USA" value="1930, 3, 01, USA">US 1930</option> 391 <option id="USA1920" class="USA" value="1920, 0, 01, USA">US 1920</option> 392 <option id="USA1910" class="USA" value="1910, 3, 15, USA">US 1910</option> 393 <option id="USA1900" class="USA" value="1900, 5, 01, USA">US 1900</option> 394 <option id="USA1890" class="USA" value="1890, 5, 01, USA">US 1890</option> 395 <option id="USA1880" class="USA" value="1880, 5, 01, USA">US 1880</option> 396 <option id="USA1870" class="USA" value="1870, 5, 01, USA">US 1870</option> 397 <option id="USA1860" class="USA" value="1860, 5, 01, USA">US 1860</option> 398 <option id="USA1850" class="USA" value="1850, 5, 01, USA">US 1850</option> 399 <option id="USA1840" class="USA" value="1840, 5, 01, USA">US 1840</option> 400 <option id="USA1830" class="USA" value="1830, 5, 01, USA">US 1830</option> 401 <option id="USA1820" class="USA" value="1820, 7, 07, USA">US 1820</option> 402 <option id="USA1810" class="USA" value="1810, 7, 06, USA">US 1810</option> 403 <option id="USA1800" class="USA" value="1800, 7, 04, USA">US 1800</option> 404 <option id="USA1790" class="USA" value="1790, 7, 02, USA">US 1790</option> 405 <option value=""></option> 406 <option id="FR1951" class="FR" value="1951, 0, 01, FR">FR 1951</option> 407 <option id="FR1946" class="FR" value="1946, 0, 01, FR">FR 1946</option> 408 <option id="FR1941" class="FR" value="1941, 0, 01, FR">FR 1941</option> 409 <option id="FR1936" class="FR" value="1936, 0, 01, FR">FR 1936</option> 410 <option id="FR1931" class="FR" value="1931, 0, 01, FR">FR 1931</option> 411 <option id="FR1926" class="FR" value="1926, 0, 01, FR">FR 1926</option> 412 <option id="FR1921" class="FR" value="1921, 0, 01, FR">FR 1921</option> 413 <option id="FR1916" class="FR" value="1916, 0, 01, FR">FR 1916</option> 414 <option id="FR1911" class="FR" value="1911, 0, 01, FR">FR 1911</option> 415 <option id="FR1906" class="FR" value="1906, 0, 01, FR">FR 1906</option> 416 <option id="FR1901" class="FR" value="1901, 0, 01, FR">FR 1901</option> 417 <option id="FR1896" class="FR" value="1896, 0, 01, FR">FR 1896</option> 418 <option id="FR1891" class="FR" value="1891, 0, 01, FR">FR 1891</option> 419 <option id="FR1886" class="FR" value="1886, 0, 01, FR">FR 1886</option> 420 <option id="FR1881" class="FR" value="1881, 0, 01, FR">FR 1881</option> 421 <option id="FR1876" class="FR" value="1876, 0, 01, FR">FR 1876</option> 422 <option value=""></option> 423 </select> 424 425 <input type="hidden" id="setctry" name="setctry" value=""> 426 <input type="hidden" id="setyear" name="setyear" value=""> 427 '; 428 } else { 429 return ''; 430 } 431 } 432} 433