xref: /webtrees/app/Module/CensusAssistantModule.php (revision 9001c0b397d39c49755e22f76e158ae0129d2aba)
18c2e8227SGreg Roach<?php
28c2e8227SGreg Roach/**
38c2e8227SGreg Roach * webtrees: online genealogy
41062a142SGreg Roach * Copyright (C) 2018 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;
233d7a8a4cSGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsDb;
240e62c4b8SGreg Roachuse Fisharebest\Webtrees\GedcomRecord;
250e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
2699f222b3SGreg Roachuse Fisharebest\Webtrees\Individual;
27*9001c0b3SGreg Roachuse Fisharebest\Webtrees\Tree;
28*9001c0b3SGreg Roachuse Symfony\Component\HttpFoundation\Request;
29*9001c0b3SGreg Roachuse Symfony\Component\HttpFoundation\Response;
308c2e8227SGreg Roach
318c2e8227SGreg Roach/**
328c2e8227SGreg Roach * Class CensusAssistantModule
338c2e8227SGreg Roach */
3415834aaeSGreg Roachclass CensusAssistantModule extends AbstractModule {
358c2e8227SGreg Roach	/** {@inheritdoc} */
368c2e8227SGreg Roach	public function getTitle() {
3715d603e7SGreg Roach		return /* I18N: Name of a module */
3815d603e7SGreg Roach			I18N::translate('Census assistant');
398c2e8227SGreg Roach	}
408c2e8227SGreg Roach
418c2e8227SGreg Roach	/** {@inheritdoc} */
428c2e8227SGreg Roach	public function getDescription() {
4315d603e7SGreg Roach		return /* I18N: Description of the “Census assistant” module */
4415d603e7SGreg Roach			I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
458c2e8227SGreg Roach	}
468c2e8227SGreg Roach
4776692c8bSGreg Roach	/**
48*9001c0b3SGreg Roach	 * @param Request $request
49*9001c0b3SGreg Roach	 *
50*9001c0b3SGreg Roach	 * @return Response
51*9001c0b3SGreg Roach	 */
52*9001c0b3SGreg Roach	public function getCensusHeaderAction(Request $request): Response {
53*9001c0b3SGreg Roach		$census = $request->get('census');
54*9001c0b3SGreg Roach
55*9001c0b3SGreg Roach		$html = $this->censusTableHeader(new $census);
56*9001c0b3SGreg Roach
57*9001c0b3SGreg Roach		return new Response($html);
58*9001c0b3SGreg Roach	}
59*9001c0b3SGreg Roach
60*9001c0b3SGreg Roach	/**
61*9001c0b3SGreg Roach	 * @param Request $request
62*9001c0b3SGreg Roach	 *
63*9001c0b3SGreg Roach	 * @return Response
64*9001c0b3SGreg Roach	 */
65*9001c0b3SGreg Roach	public function getCensusIndividualAction(Request $request): Response {
66*9001c0b3SGreg Roach		/** @var Tree $tree */
67*9001c0b3SGreg Roach		$tree = $request->attributes->get('tree');
68*9001c0b3SGreg Roach
69*9001c0b3SGreg Roach		$census = $request->get('census');
70*9001c0b3SGreg Roach
71*9001c0b3SGreg Roach		$individual = Individual::getInstance($request->get('xref'), $tree);
72*9001c0b3SGreg Roach		$head       = Individual::getInstance($request->get('head'), $tree);
73*9001c0b3SGreg Roach		$html       = $this->censusTableRow(new $census, $individual, $head);
74*9001c0b3SGreg Roach
75*9001c0b3SGreg Roach		return new Response($html);
76*9001c0b3SGreg Roach	}
77*9001c0b3SGreg Roach
78*9001c0b3SGreg Roach	/**
7976692c8bSGreg Roach	 * This is a general purpose hook, allowing modules to respond to routes
8076692c8bSGreg Roach	 * of the form module.php?mod=FOO&mod_action=BAR
8176692c8bSGreg Roach	 *
8276692c8bSGreg Roach	 * @param string $mod_action
8376692c8bSGreg Roach	 */
848c2e8227SGreg Roach	public function modAction($mod_action) {
858c2e8227SGreg Roach		switch ($mod_action) {
8640990b78SGreg Roach			case 'media_find':
87764a01d9SGreg Roach				self::mediaFind();
888c2e8227SGreg Roach				break;
898c2e8227SGreg Roach			case 'media_query_3a':
90764a01d9SGreg Roach				self::mediaQuery();
918c2e8227SGreg Roach				break;
928c2e8227SGreg Roach			default:
938c2e8227SGreg Roach				http_response_code(404);
948c2e8227SGreg Roach		}
958c2e8227SGreg Roach	}
968c2e8227SGreg Roach
978c2e8227SGreg Roach	/**
9815d603e7SGreg Roach	 * @param Individual $individual
99*9001c0b3SGreg Roach	 *
100*9001c0b3SGreg Roach	 * @return string
1018c2e8227SGreg Roach	 */
10215d603e7SGreg Roach	public function createCensusAssistant(Individual $individual) {
103225e381fSGreg Roach		return view('modules/census-assistant', [
10434cd602eSGreg Roach			'individual' => $individual,
10534cd602eSGreg Roach		]);
10615d603e7SGreg Roach	}
10715d603e7SGreg Roach
10815d603e7SGreg Roach	/**
10915d603e7SGreg Roach	 * @param Individual $individual
11060bc3e3fSGreg Roach	 * @param string     $fact_id
11115d603e7SGreg Roach	 * @param string     $newged
11260bc3e3fSGreg Roach	 * @param bool       $keep_chan
11315d603e7SGreg Roach	 *
11415d603e7SGreg Roach	 * @return string
11515d603e7SGreg Roach	 */
11615d603e7SGreg Roach	public function updateCensusAssistant(Individual $individual, $fact_id, $newged, $keep_chan) {
11715d603e7SGreg Roach		$ca_title       = Filter::post('ca_title');
11815d603e7SGreg Roach		$ca_place       = Filter::post('ca_place');
11915d603e7SGreg Roach		$ca_citation    = Filter::post('ca_citation');
12015d603e7SGreg Roach		$ca_individuals = Filter::postArray('ca_individuals');
12115d603e7SGreg Roach		$ca_notes       = Filter::post('ca_notes');
12215d603e7SGreg Roach		$ca_census      = Filter::post('ca_census', 'Fisharebest\\\\Webtrees\\\\Census\\\\CensusOf[A-Za-z0-9]+');
12315d603e7SGreg Roach
12415d603e7SGreg Roach		if ($ca_census !== '' && !empty($ca_individuals)) {
12515d603e7SGreg Roach			$census = new $ca_census;
12615d603e7SGreg Roach
12715d603e7SGreg Roach			$note_text   = $this->createNoteText($census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes);
12815d603e7SGreg Roach			$note_gedcom = '0 @new@ NOTE ' . str_replace("\n", "\n1 CONT ", $note_text);
12915d603e7SGreg Roach			$note        = $individual->getTree()->createRecord($note_gedcom);
13015d603e7SGreg Roach
13115d603e7SGreg Roach			$newged .= "\n2 NOTE @" . $note->getXref() . '@';
13215d603e7SGreg Roach
13315d603e7SGreg Roach			// Add the census fact to the rest of the household
13415d603e7SGreg Roach			foreach (array_keys($ca_individuals) as $xref) {
13515d603e7SGreg Roach				if ($xref !== $individual->getXref()) {
13615d603e7SGreg Roach					Individual::getInstance($xref, $individual->getTree())
13715d603e7SGreg Roach						->updateFact($fact_id, $newged, !$keep_chan);
13815d603e7SGreg Roach				}
13915d603e7SGreg Roach			}
14015d603e7SGreg Roach		}
14115d603e7SGreg Roach
14215d603e7SGreg Roach		return $newged;
14315d603e7SGreg Roach	}
14415d603e7SGreg Roach
14515d603e7SGreg Roach	/**
14615d603e7SGreg Roach	 * @param CensusInterface $census
14715d603e7SGreg Roach	 * @param string          $ca_title
14815d603e7SGreg Roach	 * @param string          $ca_place
14915d603e7SGreg Roach	 * @param string          $ca_citation
15015d603e7SGreg Roach	 * @param string[][]      $ca_individuals
15115d603e7SGreg Roach	 * @param string          $ca_notes
15215d603e7SGreg Roach	 *
15315d603e7SGreg Roach	 * @return string
15415d603e7SGreg Roach	 */
15515d603e7SGreg Roach	private function createNoteText(CensusInterface $census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes) {
1560d46ec71SGreg Roach		$text = $ca_title . "\n" . $ca_citation . "\n" . $ca_place . "\n\n";
15715d603e7SGreg Roach
15815d603e7SGreg Roach		foreach ($census->columns() as $n => $column) {
1590d46ec71SGreg Roach			if ($n === 0) {
1600d46ec71SGreg Roach				$text .= "\n";
1610d46ec71SGreg Roach			} else {
16215d603e7SGreg Roach				$text .= ' | ';
16315d603e7SGreg Roach			}
1640d46ec71SGreg Roach			$text .= $column->abbreviation();
1650d46ec71SGreg Roach		}
1660d46ec71SGreg Roach
1670d46ec71SGreg Roach		foreach ($census->columns() as $n => $column) {
1680d46ec71SGreg Roach			if ($n === 0) {
1690d46ec71SGreg Roach				$text .= "\n";
1700d46ec71SGreg Roach			} else {
1710d46ec71SGreg Roach				$text .= ' | ';
1720d46ec71SGreg Roach			}
1730d46ec71SGreg Roach			$text .= '-----';
17415d603e7SGreg Roach		}
17515d603e7SGreg Roach
17615d603e7SGreg Roach		foreach ($ca_individuals as $xref => $columns) {
17715d603e7SGreg Roach			$text .= "\n" . implode(' | ', $columns);
17815d603e7SGreg Roach		}
17915d603e7SGreg Roach
1800d46ec71SGreg Roach		return $text . "\n\n" . $ca_notes;
18140990b78SGreg Roach	}
18240990b78SGreg Roach
18340990b78SGreg Roach	/**
18476692c8bSGreg Roach	 * Find a media object.
18540990b78SGreg Roach	 */
186764a01d9SGreg Roach	private static function mediaFind() {
1878c2e8227SGreg Roach		global $WT_TREE;
1888c2e8227SGreg Roach
1898c2e8227SGreg Roach		$controller = new SimpleController;
1908c2e8227SGreg Roach		$filter     = Filter::get('filter');
1918c2e8227SGreg Roach		$multiple   = Filter::getBool('multiple');
1928c2e8227SGreg Roach
1938c2e8227SGreg Roach		$controller
1948c2e8227SGreg Roach			->setPageTitle(I18N::translate('Find an individual'))
1958c2e8227SGreg Roach			->pageHeader();
1968c2e8227SGreg Roach
1978c2e8227SGreg Roach		?>
19899f222b3SGreg Roach		<script>
1998c2e8227SGreg Roach      function pasterow(id, name, gend, yob, age, bpl) {
200*9001c0b3SGreg Roach        window.opener.opener.insertRowToTable(id, name, "", gend, "", yob, age, "Y", "", bpl);
2018c2e8227SGreg Roach      }
2028c2e8227SGreg Roach
2038c2e8227SGreg Roach      function pasteid(id, name, thumb) {
2048c2e8227SGreg Roach        if (thumb) {
2058c2e8227SGreg Roach          window.opener.paste_id(id, name, thumb);
20615d603e7SGreg Roach					<?php if (!$multiple) {
20715d603e7SGreg Roach					echo 'window.close();';
20815d603e7SGreg Roach				} ?>
2098c2e8227SGreg Roach        } else {
2108c2e8227SGreg Roach          // GEDFact_assistant ========================
211*9001c0b3SGreg Roach          if (window.opener.document.getElementById("addlinkQueue")) {
2128c2e8227SGreg Roach            window.opener.insertRowToTable(id, name);
2138c2e8227SGreg Roach          }
2148c2e8227SGreg Roach          window.opener.paste_id(id);
2158c2e8227SGreg Roach          if (window.opener.pastename) {
2168c2e8227SGreg Roach            window.opener.pastename(name);
2178c2e8227SGreg Roach          }
21815d603e7SGreg Roach					<?php if (!$multiple) {
21915d603e7SGreg Roach					echo 'window.close();';
22015d603e7SGreg Roach				} ?>
2218c2e8227SGreg Roach        }
2228c2e8227SGreg Roach      }
22315d603e7SGreg Roach
2248c2e8227SGreg Roach      function checknames(frm) {
225*9001c0b3SGreg Roach        var button = "";
2268c2e8227SGreg Roach        if (document.forms[0].subclick) {
2278c2e8227SGreg Roach          button = document.forms[0].subclick.value;
2288c2e8227SGreg Roach        }
229*9001c0b3SGreg Roach        if (frm.filter.value.length < 2 && button !== "all") {
23015d603e7SGreg Roach          alert('<?= I18N::translate('Please enter more than one character.') ?>');
2318c2e8227SGreg Roach          frm.filter.focus();
2328c2e8227SGreg Roach          return false;
2338c2e8227SGreg Roach        }
234*9001c0b3SGreg Roach        if (button === "all") {
235*9001c0b3SGreg Roach          frm.filter.value = "";
2368c2e8227SGreg Roach        }
2378c2e8227SGreg Roach        return true;
2388c2e8227SGreg Roach      }
23999f222b3SGreg Roach		</script>
2408c2e8227SGreg Roach
24199f222b3SGreg Roach		<?php
242a86dd8b1SGreg Roach		echo '<div>';
2434c621133SGreg Roach		echo '<table class="list_table width90" border="0">';
244d20fc238SGreg Roach		echo '<tr><td style="padding: 10px;" class="width90">'; // start column for find text header
2458c2e8227SGreg Roach		echo $controller->getPageTitle();
2464c621133SGreg Roach		echo '</td>';
2474c621133SGreg Roach		echo '</tr>';
2484c621133SGreg Roach		echo '</table>';
2494c621133SGreg Roach		echo '<br>';
2508c2e8227SGreg Roach		echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
2514c621133SGreg Roach		echo '<br>';
2528c2e8227SGreg Roach
2538c2e8227SGreg Roach		$filter       = trim($filter);
2548c2e8227SGreg Roach		$filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
2554c621133SGreg Roach		echo '<table class="tabs_table width90"><tr>';
25613abd6f3SGreg Roach		$myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
2578c2e8227SGreg Roach		if ($myindilist) {
2584c621133SGreg Roach			echo '<td class="list_value_wrap"><ul>';
2590e62c4b8SGreg Roach			usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
2608c2e8227SGreg Roach			foreach ($myindilist as $indi) {
261d53324c9SGreg Roach				$nam = e($indi->getFullName());
2628c2e8227SGreg Roach				echo "<li><a href=\"#\" onclick=\"pasterow(
2638c2e8227SGreg Roach					'" . $indi->getXref() . "' ,
2648c2e8227SGreg Roach					'" . $nam . "' ,
2658c2e8227SGreg Roach					'" . $indi->getSex() . "' ,
2667820e4d7SGreg Roach					'" . $indi->getBirthYear() . "' ,
2677820e4d7SGreg Roach					'" . (1901 - $indi->getBirthYear()) . "' ,
26816d0b7f7SRico Sonntag					'" . $indi->getBirthPlace()->getGedcomName() . "'); return false;\">
2697a6ee1acSGreg Roach					<b>" . $indi->getFullName() . '</b>&nbsp;&nbsp;&nbsp;';
2708c2e8227SGreg Roach
271564ae2d7SGreg Roach				$born = I18N::translate('Birth');
27216d0b7f7SRico Sonntag				echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace()->getGedcomName(), '</span></a></li>';
2737a6ee1acSGreg Roach				echo '<hr>';
2748c2e8227SGreg Roach			}
2758c2e8227SGreg Roach			echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
2768c2e8227SGreg Roach		} else {
2777a6ee1acSGreg Roach			echo '<td class="list_value_wrap">';
2788c2e8227SGreg Roach			echo I18N::translate('No results found.');
2797a6ee1acSGreg Roach			echo '</td></tr>';
2808c2e8227SGreg Roach		}
2817a6ee1acSGreg Roach		echo '</table>';
2828c2e8227SGreg Roach		echo '</div>';
2838c2e8227SGreg Roach	}
2848c2e8227SGreg Roach
2858c2e8227SGreg Roach	/**
28676692c8bSGreg Roach	 * Search for a media object.
2878c2e8227SGreg Roach	 */
288764a01d9SGreg Roach	private static function mediaQuery() {
28924ec66ceSGreg Roach		global $WT_TREE;
29024ec66ceSGreg Roach
2918c2e8227SGreg Roach		$iid2 = Filter::get('iid', WT_REGEX_XREF);
2928c2e8227SGreg Roach
2938c2e8227SGreg Roach		$controller = new SimpleController;
2948c2e8227SGreg Roach		$controller
2958c2e8227SGreg Roach			->setPageTitle(I18N::translate('Link to an existing media object'))
2968c2e8227SGreg Roach			->pageHeader();
2978c2e8227SGreg Roach
29824ec66ceSGreg Roach		$record = GedcomRecord::getInstance($iid2, $WT_TREE);
2998c2e8227SGreg Roach		if ($record) {
3008c2e8227SGreg Roach			$headjs = '';
3018c2e8227SGreg Roach			if ($record instanceof Family) {
3028c2e8227SGreg Roach				if ($record->getHusband()) {
3038c2e8227SGreg Roach					$headjs = $record->getHusband()->getXref();
3048c2e8227SGreg Roach				} elseif ($record->getWife()) {
3058c2e8227SGreg Roach					$headjs = $record->getWife()->getXref();
3068c2e8227SGreg Roach				}
3078c2e8227SGreg Roach			}
3088c2e8227SGreg Roach			?>
3098c2e8227SGreg Roach			<script>
3108c2e8227SGreg Roach				function insertId() {
3118c2e8227SGreg Roach					if (window.opener.document.getElementById('addlinkQueue')) {
3128c2e8227SGreg Roach						// alert('Please move this alert window and examine the contents of the pop-up window, then click OK')
313564ae2d7SGreg Roach						window.opener.insertRowToTable('<?= $record->getXref() ?>', '<?= htmlspecialchars($record->getFullName()) ?>', '<?= $headjs ?>');
3148c2e8227SGreg Roach						window.close();
3158c2e8227SGreg Roach					}
3168c2e8227SGreg Roach				}
3178c2e8227SGreg Roach			</script>
3188c2e8227SGreg Roach			<?php
3198c2e8227SGreg Roach		} else {
3208c2e8227SGreg Roach			?>
3218c2e8227SGreg Roach			<script>
3228c2e8227SGreg Roach				function insertId() {
323564ae2d7SGreg Roach					window.opener.alert('<?= $iid2 ?> - <?= I18N::translate('Not a valid individual, family, or source ID') ?>');
3248c2e8227SGreg Roach					window.close();
3258c2e8227SGreg Roach				}
3268c2e8227SGreg Roach			</script>
3278c2e8227SGreg Roach			<?php
3288c2e8227SGreg Roach		}
3298c2e8227SGreg Roach		?>
3308c2e8227SGreg Roach		<script>window.onLoad = insertId();</script>
3318c2e8227SGreg Roach		<?php
3328c2e8227SGreg Roach	}
3338c2e8227SGreg Roach
3348c2e8227SGreg Roach	/**
335ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census header
33652bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
33752bc9faeSGreg Roach	 * Add suffix cell (delete button)
33852bc9faeSGreg Roach	 *
339ad51e0bbSGreg Roach	 * @param CensusInterface $census
34099f222b3SGreg Roach	 *
341ad51e0bbSGreg Roach	 * @return string
34299f222b3SGreg Roach	 */
343ad51e0bbSGreg Roach	public static function censusTableHeader(CensusInterface $census) {
34452bc9faeSGreg Roach		$html = '';
345ad51e0bbSGreg Roach		foreach ($census->columns() as $column) {
34615d603e7SGreg Roach			$html .= '<th class="wt-census-assistant-field" title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
34799f222b3SGreg Roach		}
34899f222b3SGreg Roach
34915d603e7SGreg Roach		return '<tr class="wt-census-assistant-row"><th hidden></th>' . $html . '<th></th></tr>';
350ad51e0bbSGreg Roach	}
35199f222b3SGreg Roach
352ad51e0bbSGreg Roach	/**
353ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census
35452bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
35552bc9faeSGreg Roach	 * Add suffix cell (delete button)
35652bc9faeSGreg Roach	 *
357ad51e0bbSGreg Roach	 * @param CensusInterface $census
358ad51e0bbSGreg Roach	 *
359ad51e0bbSGreg Roach	 * @return string
360ad51e0bbSGreg Roach	 */
361ad51e0bbSGreg Roach	public static function censusTableEmptyRow(CensusInterface $census) {
36215d603e7SGreg 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>';
363ad51e0bbSGreg Roach	}
36499f222b3SGreg Roach
365ad51e0bbSGreg Roach	/**
366ad51e0bbSGreg Roach	 * Generate an HTML row of data for the census
36752bc9faeSGreg Roach	 * Add prefix cell (store XREF and drag/drop)
36852bc9faeSGreg Roach	 * Add suffix cell (delete button)
36952bc9faeSGreg Roach	 *
370ad51e0bbSGreg Roach	 * @param CensusInterface $census
371ad51e0bbSGreg Roach	 * @param Individual      $individual
372ad51e0bbSGreg Roach	 * @param Individual      $head
373ad51e0bbSGreg Roach	 *
374ad51e0bbSGreg Roach	 * @return string
375ad51e0bbSGreg Roach	 */
37615d603e7SGreg Roach	public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head) {
37715d603e7SGreg Roach		$html = '';
37815d603e7SGreg Roach		foreach ($census->columns() as $column) {
37915d603e7SGreg 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>';
38099f222b3SGreg Roach		}
38199f222b3SGreg Roach
38215d603e7SGreg 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>';
38399f222b3SGreg Roach	}
3848c2e8227SGreg Roach}
385