xref: /webtrees/app/Module/CensusAssistantModule.php (revision 60bc3e3fa6818f7ba65df666d54efde701a9fe49)
18c2e8227SGreg Roach<?php
28c2e8227SGreg Roach/**
38c2e8227SGreg Roach * webtrees: online genealogy
46bdf7674SGreg Roach * Copyright (C) 2017 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;
2315d603e7SGreg Roachuse Fisharebest\Webtrees\FontAwesome;
24ad51e0bbSGreg Roachuse Fisharebest\Webtrees\Functions\Functions;
253d7a8a4cSGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsDb;
2615d603e7SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsEdit;
270e62c4b8SGreg Roachuse Fisharebest\Webtrees\GedcomRecord;
280e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
2999f222b3SGreg Roachuse Fisharebest\Webtrees\Individual;
30ad51e0bbSGreg Roachuse Fisharebest\Webtrees\Menu;
310e62c4b8SGreg Roachuse Fisharebest\Webtrees\Note;
32dc46b574SDavid Druryuse Fisharebest\Webtrees\Soundex;
338c2e8227SGreg Roach
348c2e8227SGreg Roach/**
358c2e8227SGreg Roach * Class CensusAssistantModule
368c2e8227SGreg Roach */
3715834aaeSGreg Roachclass CensusAssistantModule extends AbstractModule {
388c2e8227SGreg Roach    /** {@inheritdoc} */
398c2e8227SGreg Roach    public function getTitle() {
4015d603e7SGreg Roach        return /* I18N: Name of a module */
4115d603e7SGreg Roach            I18N::translate('Census assistant');
428c2e8227SGreg Roach    }
438c2e8227SGreg Roach
448c2e8227SGreg Roach    /** {@inheritdoc} */
458c2e8227SGreg Roach    public function getDescription() {
4615d603e7SGreg Roach        return /* I18N: Description of the “Census assistant” module */
4715d603e7SGreg Roach            I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
488c2e8227SGreg Roach    }
498c2e8227SGreg Roach
5076692c8bSGreg Roach    /**
5176692c8bSGreg Roach     * This is a general purpose hook, allowing modules to respond to routes
5276692c8bSGreg Roach     * of the form module.php?mod=FOO&mod_action=BAR
5376692c8bSGreg Roach     *
5476692c8bSGreg Roach     * @param string $mod_action
5576692c8bSGreg Roach     */
568c2e8227SGreg Roach    public function modAction($mod_action) {
5715d603e7SGreg Roach        global $WT_TREE;
5815d603e7SGreg Roach
598c2e8227SGreg Roach        switch ($mod_action) {
6015d603e7SGreg Roach        case 'census-header':
6115d603e7SGreg Roach            header('Content-Type: text/html; charset=utf8');
6215d603e7SGreg Roach            $census = Filter::get('census');
6315d603e7SGreg Roach            echo $this->censusTableHeader(new $census);
648c2e8227SGreg Roach            break;
6515d603e7SGreg Roach
6615d603e7SGreg Roach        case 'census-individual':
6715d603e7SGreg Roach            header('Content-Type: text/html; charset=utf8');
6815d603e7SGreg Roach            $census     = Filter::get('census');
6915d603e7SGreg Roach            $individual = Individual::getInstance(Filter::get('xref'), $WT_TREE);
7015d603e7SGreg Roach            $head       = Individual::getInstance(Filter::get('head'), $WT_TREE);
7115d603e7SGreg Roach            echo $this->censusTableRow(new $census, $individual, $head);
7215d603e7SGreg Roach            break;
7315d603e7SGreg Roach
7440990b78SGreg Roach        case 'media_find':
75764a01d9SGreg Roach            self::mediaFind();
768c2e8227SGreg Roach            break;
778c2e8227SGreg Roach        case 'media_query_3a':
78764a01d9SGreg Roach            self::mediaQuery();
798c2e8227SGreg Roach            break;
808c2e8227SGreg Roach        default:
818c2e8227SGreg Roach            http_response_code(404);
828c2e8227SGreg Roach        }
838c2e8227SGreg Roach    }
848c2e8227SGreg Roach
858c2e8227SGreg Roach    /**
8615d603e7SGreg Roach     * @param Individual $individual
878c2e8227SGreg Roach     */
8815d603e7SGreg Roach    public function createCensusAssistant(Individual $individual) {
8915d603e7SGreg Roach        ?>
9040990b78SGreg Roach
9115d603e7SGreg Roach        <div id="census-assistant-link" hidden>
9215d603e7SGreg Roach            <a href="#">
9315d603e7SGreg Roach                <?= I18N::translate('Create a shared note using the census assistant') ?>
9415d603e7SGreg Roach            </a>
9515d603e7SGreg Roach        </div>
9640990b78SGreg Roach
9715d603e7SGreg Roach        <div id="census-assistant" hidden>
9815d603e7SGreg Roach            <input type="hidden" name="ca_census" id="ca-census">
9915d603e7SGreg Roach            <div class="form-group">
10015d603e7SGreg Roach                <div class="input-group">
10115d603e7SGreg Roach                    <label for="census-assistant-title" class="input-group-addon">
10215d603e7SGreg Roach                        <?= I18N::translate('Title') ?>
10315d603e7SGreg Roach                    </label>
10415d603e7SGreg Roach                    <input class="form-control" id="ca-title" name="ca_title" value="">
10515d603e7SGreg Roach                </div>
10615d603e7SGreg Roach            </div>
10740990b78SGreg Roach
10815d603e7SGreg Roach            <div class="row">
10915d603e7SGreg Roach                <div class="form-group col-sm-6">
11015d603e7SGreg Roach                    <div class="input-group">
11115d603e7SGreg Roach                        <label for="census-assistant-citation" class="input-group-addon">
11215d603e7SGreg Roach                            <?= I18N::translate('Citation') ?>
11315d603e7SGreg Roach                        </label>
11415d603e7SGreg Roach                        <input class="form-control" id="census-assistant-citation" name="ca_citation">
11515d603e7SGreg Roach                    </div>
11615d603e7SGreg Roach                </div>
11740990b78SGreg Roach
11815d603e7SGreg Roach                <div class="form-group col-sm-6">
11915d603e7SGreg Roach                    <div class="input-group">
12015d603e7SGreg Roach                        <label for="census-assistant-place" class="input-group-addon">
12115d603e7SGreg Roach                            <?= I18N::translate('Place') ?>
12215d603e7SGreg Roach                        </label>
12315d603e7SGreg Roach                        <input class="form-control" id="census-assistant-place" name="ca_place">
12415d603e7SGreg Roach                    </div>
12515d603e7SGreg Roach                </div>
12615d603e7SGreg Roach            </div>
12740990b78SGreg Roach
12815d603e7SGreg Roach            <div class="form-group">
12915d603e7SGreg Roach                <div class="input-group">
13015d603e7SGreg Roach                    <span class="input-group-addon"><?= I18N::translate('Individuals') ?></span>
13115d603e7SGreg Roach                    <?= FunctionsEdit::formControlIndividual($individual, ['id' => 'census-assistant-individual', 'style' => 'width:100%']) ?>
13215d603e7SGreg Roach                    <span class="input-group-btn">
13315d603e7SGreg Roach						<button type="button" class="btn btn-primary" id="census-assistant-add">
13415d603e7SGreg Roach							<?= FontAwesome::semanticIcon('add', I18N::translate('Add')) ?>
13515d603e7SGreg Roach						</button>
13615d603e7SGreg Roach					</span>
13715d603e7SGreg Roach                    <span class="input-group-btn">
13815d603e7SGreg Roach						<button type="button" class="btn btn-primary" id="census-assistant-head"
13915d603e7SGreg Roach                                title="<?= I18N::translate('Head of household') ?>">
14015d603e7SGreg Roach							<?= FontAwesome::semanticIcon('individual', I18N::translate('Head of household')) ?>
14115d603e7SGreg Roach						</button>
14215d603e7SGreg Roach					</span>
14315d603e7SGreg Roach                </div>
14415d603e7SGreg Roach            </div>
14515d603e7SGreg Roach
14615d603e7SGreg Roach            <table class="table table-bordered table-small table-responsive wt-census-assistant-table"
14715d603e7SGreg Roach                   id="census-assistant-table">
14815d603e7SGreg Roach                <thead class="wt-census-assistant-header"></thead>
14915d603e7SGreg Roach                <tbody class="wt-census-assistant-body"></tbody>
15015d603e7SGreg Roach            </table>
15115d603e7SGreg Roach
15215d603e7SGreg Roach            <div class="form-group">
15315d603e7SGreg Roach                <div class="input-group">
15415d603e7SGreg Roach                    <label for="census-assistant-notes" class="input-group-addon">
15515d603e7SGreg Roach                        <?= I18N::translate('Notes') ?>
15615d603e7SGreg Roach                    </label>
15715d603e7SGreg Roach                    <input class="form-control" id="census-assistant-notes" name="ca_notes">
15815d603e7SGreg Roach                </div>
15915d603e7SGreg Roach            </div>
16015d603e7SGreg Roach        </div>
16115d603e7SGreg Roach
16215d603e7SGreg Roach        <script>
16315d603e7SGreg Roach            // When a census date/place is selected, activate the census-assistant
16415d603e7SGreg Roach            function censusAssistantSelect () {
16515d603e7SGreg Roach                var censusAssistantLink = document.querySelector('#census-assistant-link');
16615d603e7SGreg Roach                var censusAssistant     = document.querySelector('#census-assistant');
16715d603e7SGreg Roach                var censusOption        = this.options[this.selectedIndex];
16815d603e7SGreg Roach                var census              = censusOption.dataset.census;
16915d603e7SGreg Roach                var censusPlace         = censusOption.dataset.place;
17015d603e7SGreg Roach                var censusYear          = censusOption.value.substr(-4);
17115d603e7SGreg Roach
17215d603e7SGreg Roach                if (censusOption.value !== '') {
17315d603e7SGreg Roach                    censusAssistantLink.removeAttribute('hidden');
17440990b78SGreg Roach                } else {
17515d603e7SGreg Roach                    censusAssistantLink.setAttribute('hidden', '');
17640990b78SGreg Roach                }
17715d603e7SGreg Roach
17815d603e7SGreg Roach                censusAssistant.setAttribute('hidden', '');
17915d603e7SGreg Roach                document.querySelector('#ca-census').value = census;
18015d603e7SGreg Roach                document.querySelector('#ca-title').value  = censusYear + ' ' + censusPlace + ' - <?= I18N::translate('Census transcript') ?> - <?= strip_tags($individual->getFullName()) ?> - <?= I18N::translate('Household') ?>';
18115d603e7SGreg Roach
18215d603e7SGreg Roach                fetch('module.php?mod=GEDFact_assistant&mod_action=census-header&census=' + census)
18315d603e7SGreg Roach                    .then(function (response) {
18415d603e7SGreg Roach                        return response.text();
18515d603e7SGreg Roach                    })
18615d603e7SGreg Roach                    .then(function (text) {
18715d603e7SGreg Roach                        document.querySelector('#census-assistant-table thead').innerHTML = text;
18815d603e7SGreg Roach                        document.querySelector('#census-assistant-table tbody').innerHTML = '';
18915d603e7SGreg Roach                    });
190ad51e0bbSGreg Roach            }
19115d603e7SGreg Roach
19215d603e7SGreg Roach            // When the census assistant is activated, show the input fields
19315d603e7SGreg Roach            function censusAssistantLink () {
19415d603e7SGreg Roach                document.querySelector('#census-selector').setAttribute('hidden', '');
19515d603e7SGreg Roach                this.setAttribute('hidden', '');
19615d603e7SGreg Roach                document.getElementById('census-assistant').removeAttribute('hidden');
19715d603e7SGreg Roach                // Set the current individual as the head of household.
19815d603e7SGreg Roach                censusAssistantHead();
19915d603e7SGreg Roach
20015d603e7SGreg Roach                return false;
20115d603e7SGreg Roach            }
20215d603e7SGreg Roach
20315d603e7SGreg Roach            // Add the currently selected individual to the census
20415d603e7SGreg Roach            function censusAssistantAdd () {
20515d603e7SGreg Roach                var censusSelector = document.querySelector('#census-selector');
20615d603e7SGreg Roach                var census         = censusSelector.options[censusSelector.selectedIndex].dataset.census;
20715d603e7SGreg Roach                var indi_selector  = document.querySelector('#census-assistant-individual');
20815d603e7SGreg Roach                var xref           = indi_selector.options[indi_selector.selectedIndex].value;
20915d603e7SGreg Roach                var headTd         = document.querySelector('#census-assistant-table td');
21015d603e7SGreg Roach                var head           = headTd === null ? xref : headTd.innerHTML;
21115d603e7SGreg Roach
21215d603e7SGreg Roach                fetch('module.php?mod=GEDFact_assistant&mod_action=census-individual&census=' + census + '&xref=' + xref + '&head=' + head, {credentials: 'same-origin'})
21315d603e7SGreg Roach                    .then(function (response) {
21415d603e7SGreg Roach                        return response.text();
21515d603e7SGreg Roach                    })
21615d603e7SGreg Roach                    .then(function (text) {
21715d603e7SGreg Roach                        document.querySelector('#census-assistant-table tbody').innerHTML += text;
21815d603e7SGreg Roach                    });
21915d603e7SGreg Roach
22015d603e7SGreg Roach                return false;
22115d603e7SGreg Roach            }
22215d603e7SGreg Roach
22315d603e7SGreg Roach            // Set the currently selected individual as the head of household
22415d603e7SGreg Roach            function censusAssistantHead () {
22515d603e7SGreg Roach                var censusSelector = document.querySelector('#census-selector');
22615d603e7SGreg Roach                var census         = censusSelector.options[censusSelector.selectedIndex].dataset.census;
22715d603e7SGreg Roach                var indi_selector  = document.querySelector('#census-assistant-individual');
22815d603e7SGreg Roach                var xref           = indi_selector.options[indi_selector.selectedIndex].value;
22915d603e7SGreg Roach
23015d603e7SGreg Roach                fetch('module.php?mod=GEDFact_assistant&mod_action=census-individual&census=' + census + '&xref=' + xref + '&head=' + xref, {credentials: 'same-origin'})
23115d603e7SGreg Roach                    .then(function (response) {
23215d603e7SGreg Roach                        return response.text();
23315d603e7SGreg Roach                    })
23415d603e7SGreg Roach                    .then(function (text) {
23515d603e7SGreg Roach                        document.querySelector('#census-assistant-table tbody').innerHTML = text;
23615d603e7SGreg Roach                    });
23715d603e7SGreg Roach
23815d603e7SGreg Roach                return false;
23915d603e7SGreg Roach            }
24015d603e7SGreg Roach
24115d603e7SGreg Roach            document.querySelector('#census-selector').addEventListener('change', censusAssistantSelect);
24215d603e7SGreg Roach            document.querySelector('#census-assistant-link').addEventListener('click', censusAssistantLink);
24315d603e7SGreg Roach            document.querySelector('#census-assistant-add').addEventListener('click', censusAssistantAdd);
24415d603e7SGreg Roach            document.querySelector('#census-assistant-head').addEventListener('click', censusAssistantHead);
24515d603e7SGreg Roach        </script>
24615d603e7SGreg Roach        <?php
24715d603e7SGreg Roach    }
24815d603e7SGreg Roach
24915d603e7SGreg Roach	/**
25015d603e7SGreg Roach	 * @param Individual $individual
251*60bc3e3fSGreg Roach	 * @param string     $fact_id
25215d603e7SGreg Roach	 * @param string     $newged
253*60bc3e3fSGreg Roach	 * @param bool       $keep_chan
25415d603e7SGreg Roach	 *
25515d603e7SGreg Roach	 * @return string
25615d603e7SGreg Roach	 */
25715d603e7SGreg Roach    public function updateCensusAssistant(Individual $individual, $fact_id, $newged, $keep_chan) {
25815d603e7SGreg Roach        $ca_title       = Filter::post('ca_title');
25915d603e7SGreg Roach        $ca_place       = Filter::post('ca_place');
26015d603e7SGreg Roach        $ca_citation    = Filter::post('ca_citation');
26115d603e7SGreg Roach        $ca_individuals = Filter::postArray('ca_individuals');
26215d603e7SGreg Roach        $ca_notes       = Filter::post('ca_notes');
26315d603e7SGreg Roach        $ca_census      = Filter::post('ca_census', 'Fisharebest\\\\Webtrees\\\\Census\\\\CensusOf[A-Za-z0-9]+');
26415d603e7SGreg Roach
26515d603e7SGreg Roach        if ($ca_census !== '' && !empty($ca_individuals)) {
26615d603e7SGreg Roach            $census = new $ca_census;
26715d603e7SGreg Roach
26815d603e7SGreg Roach            $note_text   = $this->createNoteText($census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes);
26915d603e7SGreg Roach            $note_gedcom = '0 @new@ NOTE ' . str_replace("\n", "\n1 CONT ", $note_text);
27015d603e7SGreg Roach            $note        = $individual->getTree()->createRecord($note_gedcom);
27115d603e7SGreg Roach
27215d603e7SGreg Roach            $newged .= "\n2 NOTE @" . $note->getXref() . '@';
27315d603e7SGreg Roach
27415d603e7SGreg Roach            // Add the census fact to the rest of the household
27515d603e7SGreg Roach            foreach (array_keys($ca_individuals) as $xref) {
27615d603e7SGreg Roach                if ($xref !== $individual->getXref()) {
27715d603e7SGreg Roach                    Individual::getInstance($xref, $individual->getTree())
27815d603e7SGreg Roach                        ->updateFact($fact_id, $newged, !$keep_chan);
27915d603e7SGreg Roach                }
28015d603e7SGreg Roach            }
28115d603e7SGreg Roach        }
28215d603e7SGreg Roach
28315d603e7SGreg Roach        return $newged;
28415d603e7SGreg Roach    }
28515d603e7SGreg Roach
28615d603e7SGreg Roach    /**
28715d603e7SGreg Roach     * @param CensusInterface $census
28815d603e7SGreg Roach     * @param string          $ca_title
28915d603e7SGreg Roach     * @param string          $ca_place
29015d603e7SGreg Roach     * @param string          $ca_citation
29115d603e7SGreg Roach     * @param string[][]      $ca_individuals
29215d603e7SGreg Roach     * @param string          $ca_notes
29315d603e7SGreg Roach     *
29415d603e7SGreg Roach     * @return string
29515d603e7SGreg Roach     */
29615d603e7SGreg Roach    private function createNoteText(CensusInterface $census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes) {
29715d603e7SGreg Roach        $text = $ca_title . "\n" . $ca_citation . "\n" . $ca_place . "\n\n.start_formatted_area.\n\n";
29815d603e7SGreg Roach
29915d603e7SGreg Roach        foreach ($census->columns() as $n => $column) {
30015d603e7SGreg Roach            if ($n > 0) {
30115d603e7SGreg Roach                $text .= '|';
30215d603e7SGreg Roach            }
30315d603e7SGreg Roach            $text .= '.b.' . $column->abbreviation();
30415d603e7SGreg Roach        }
30515d603e7SGreg Roach
30615d603e7SGreg Roach        foreach ($ca_individuals as $xref => $columns) {
30715d603e7SGreg Roach            $text .= "\n" . implode('|', $columns);
30815d603e7SGreg Roach        }
30915d603e7SGreg Roach
31015d603e7SGreg Roach        return $text . "\n.end_formatted_area.\n\n" . $ca_notes;
31140990b78SGreg Roach    }
31240990b78SGreg Roach
31340990b78SGreg Roach    /**
31476692c8bSGreg Roach     * Find a media object.
31540990b78SGreg Roach     */
316764a01d9SGreg Roach    private static function mediaFind() {
3178c2e8227SGreg Roach        global $WT_TREE;
3188c2e8227SGreg Roach
3198c2e8227SGreg Roach        $controller = new SimpleController;
3208c2e8227SGreg Roach        $filter     = Filter::get('filter');
3218c2e8227SGreg Roach        $multiple   = Filter::getBool('multiple');
3228c2e8227SGreg Roach
3238c2e8227SGreg Roach        $controller
3248c2e8227SGreg Roach            ->setPageTitle(I18N::translate('Find an individual'))
3258c2e8227SGreg Roach            ->pageHeader();
3268c2e8227SGreg Roach
3278c2e8227SGreg Roach        ?>
32899f222b3SGreg Roach        <script>
3298c2e8227SGreg Roach            function pasterow (id, name, gend, yob, age, bpl) {
3308c2e8227SGreg Roach                window.opener.opener.insertRowToTable(id, name, '', gend, '', yob, age, 'Y', '', bpl);
3318c2e8227SGreg Roach            }
3328c2e8227SGreg Roach
3338c2e8227SGreg Roach            function pasteid (id, name, thumb) {
3348c2e8227SGreg Roach                if (thumb) {
3358c2e8227SGreg Roach                    window.opener.paste_id(id, name, thumb);
33615d603e7SGreg Roach                    <?php if (!$multiple) {
33715d603e7SGreg Roach                    echo 'window.close();';
33815d603e7SGreg Roach                } ?>
3398c2e8227SGreg Roach                } else {
3408c2e8227SGreg Roach                    // GEDFact_assistant ========================
3418c2e8227SGreg Roach                    if (window.opener.document.getElementById('addlinkQueue')) {
3428c2e8227SGreg Roach                        window.opener.insertRowToTable(id, name);
3438c2e8227SGreg Roach                    }
3448c2e8227SGreg Roach                    window.opener.paste_id(id);
3458c2e8227SGreg Roach                    if (window.opener.pastename) {
3468c2e8227SGreg Roach                        window.opener.pastename(name);
3478c2e8227SGreg Roach                    }
34815d603e7SGreg Roach                    <?php if (!$multiple) {
34915d603e7SGreg Roach                    echo 'window.close();';
35015d603e7SGreg Roach                } ?>
3518c2e8227SGreg Roach                }
3528c2e8227SGreg Roach            }
35315d603e7SGreg Roach
3548c2e8227SGreg Roach            function checknames (frm) {
3558c2e8227SGreg Roach                if (document.forms[0].subclick) {
3568c2e8227SGreg Roach                    button = document.forms[0].subclick.value;
3578c2e8227SGreg Roach                } else {
35815d603e7SGreg Roach                    button = '';
3598c2e8227SGreg Roach                }
36015d603e7SGreg Roach                if (frm.filter.value.length < 2 && button !== 'all') {
36115d603e7SGreg Roach                    alert('<?= I18N::translate('Please enter more than one character.') ?>');
3628c2e8227SGreg Roach                    frm.filter.focus();
3638c2e8227SGreg Roach                    return false;
3648c2e8227SGreg Roach                }
36515d603e7SGreg Roach                if (button == 'all') {
36615d603e7SGreg Roach                    frm.filter.value = '';
3678c2e8227SGreg Roach                }
3688c2e8227SGreg Roach                return true;
3698c2e8227SGreg Roach            }
37099f222b3SGreg Roach        </script>
3718c2e8227SGreg Roach
37299f222b3SGreg Roach        <?php
373a86dd8b1SGreg Roach        echo '<div>';
3744c621133SGreg Roach        echo '<table class="list_table width90" border="0">';
375a86dd8b1SGreg Roach        echo '<tr><td style="padding: 10px;" class="facts_label03 width90">'; // start column for find text header
3768c2e8227SGreg Roach        echo $controller->getPageTitle();
3774c621133SGreg Roach        echo '</td>';
3784c621133SGreg Roach        echo '</tr>';
3794c621133SGreg Roach        echo '</table>';
3804c621133SGreg Roach        echo '<br>';
3818c2e8227SGreg Roach        echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
3824c621133SGreg Roach        echo '<br>';
3838c2e8227SGreg Roach
3848c2e8227SGreg Roach        $filter       = trim($filter);
3858c2e8227SGreg Roach        $filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
3864c621133SGreg Roach        echo '<table class="tabs_table width90"><tr>';
38713abd6f3SGreg Roach        $myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
3888c2e8227SGreg Roach        if ($myindilist) {
3894c621133SGreg Roach            echo '<td class="list_value_wrap"><ul>';
3900e62c4b8SGreg Roach            usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
3918c2e8227SGreg Roach            foreach ($myindilist as $indi) {
3928c2e8227SGreg Roach                $nam = Filter::escapeHtml($indi->getFullName());
3938c2e8227SGreg Roach                echo "<li><a href=\"#\" onclick=\"pasterow(
3948c2e8227SGreg Roach					'" . $indi->getXref() . "' ,
3958c2e8227SGreg Roach					'" . $nam . "' ,
3968c2e8227SGreg Roach					'" . $indi->getSex() . "' ,
3977820e4d7SGreg Roach					'" . $indi->getBirthYear() . "' ,
3987820e4d7SGreg Roach					'" . (1901 - $indi->getBirthYear()) . "' ,
3997820e4d7SGreg Roach					'" . $indi->getBirthPlace() . "'); return false;\">
4007a6ee1acSGreg Roach					<b>" . $indi->getFullName() . '</b>&nbsp;&nbsp;&nbsp;';
4018c2e8227SGreg Roach
402564ae2d7SGreg Roach                $born = I18N::translate('Birth');
4037a6ee1acSGreg Roach                echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace(), '</span></a></li>';
4047a6ee1acSGreg Roach                echo '<hr>';
4058c2e8227SGreg Roach            }
4068c2e8227SGreg Roach            echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
4078c2e8227SGreg Roach        } else {
4087a6ee1acSGreg Roach            echo '<td class="list_value_wrap">';
4098c2e8227SGreg Roach            echo I18N::translate('No results found.');
4107a6ee1acSGreg Roach            echo '</td></tr>';
4118c2e8227SGreg Roach        }
4127a6ee1acSGreg Roach        echo '</table>';
4138c2e8227SGreg Roach        echo '</div>';
4148c2e8227SGreg Roach    }
4158c2e8227SGreg Roach
4168c2e8227SGreg Roach    /**
41776692c8bSGreg Roach     * Search for a media object.
4188c2e8227SGreg Roach     */
419764a01d9SGreg Roach    private static function mediaQuery() {
42024ec66ceSGreg Roach        global $WT_TREE;
42124ec66ceSGreg Roach
4228c2e8227SGreg Roach        $iid2 = Filter::get('iid', WT_REGEX_XREF);
4238c2e8227SGreg Roach
4248c2e8227SGreg Roach        $controller = new SimpleController;
4258c2e8227SGreg Roach        $controller
4268c2e8227SGreg Roach            ->setPageTitle(I18N::translate('Link to an existing media object'))
4278c2e8227SGreg Roach            ->pageHeader();
4288c2e8227SGreg Roach
42924ec66ceSGreg Roach        $record = GedcomRecord::getInstance($iid2, $WT_TREE);
4308c2e8227SGreg Roach        if ($record) {
4318c2e8227SGreg Roach            $headjs = '';
4328c2e8227SGreg Roach            if ($record instanceof Family) {
4338c2e8227SGreg Roach                if ($record->getHusband()) {
4348c2e8227SGreg Roach                    $headjs = $record->getHusband()->getXref();
4358c2e8227SGreg Roach                } elseif ($record->getWife()) {
4368c2e8227SGreg Roach                    $headjs = $record->getWife()->getXref();
4378c2e8227SGreg Roach                }
4388c2e8227SGreg Roach            }
4398c2e8227SGreg Roach            ?>
4408c2e8227SGreg Roach            <script>
4418c2e8227SGreg Roach                function insertId () {
4428c2e8227SGreg Roach                    if (window.opener.document.getElementById('addlinkQueue')) {
4438c2e8227SGreg Roach                        // alert('Please move this alert window and examine the contents of the pop-up window, then click OK')
444564ae2d7SGreg Roach                        window.opener.insertRowToTable('<?= $record->getXref() ?>', '<?= htmlspecialchars($record->getFullName()) ?>', '<?= $headjs ?>');
4458c2e8227SGreg Roach                        window.close();
4468c2e8227SGreg Roach                    }
4478c2e8227SGreg Roach                }
4488c2e8227SGreg Roach            </script>
4498c2e8227SGreg Roach            <?php
4508c2e8227SGreg Roach        } else {
4518c2e8227SGreg Roach            ?>
4528c2e8227SGreg Roach            <script>
4538c2e8227SGreg Roach                function insertId () {
454564ae2d7SGreg Roach                    window.opener.alert('<?= $iid2 ?> - <?= I18N::translate('Not a valid individual, family, or source ID') ?>');
4558c2e8227SGreg Roach                    window.close();
4568c2e8227SGreg Roach                }
4578c2e8227SGreg Roach            </script>
4588c2e8227SGreg Roach            <?php
4598c2e8227SGreg Roach        }
4608c2e8227SGreg Roach        ?>
4618c2e8227SGreg Roach        <script>window.onLoad = insertId();</script>
4628c2e8227SGreg Roach        <?php
4638c2e8227SGreg Roach    }
4648c2e8227SGreg Roach
4658c2e8227SGreg Roach    /**
4668c2e8227SGreg Roach     * Convert custom markup into HTML
4678c2e8227SGreg Roach     *
4688c2e8227SGreg Roach     * @param Note $note
4698c2e8227SGreg Roach     *
4708c2e8227SGreg Roach     * @return string
4718c2e8227SGreg Roach     */
4728c2e8227SGreg Roach    public static function formatCensusNote(Note $note) {
47314c3d3fbSGreg Roach        if (preg_match('/(.*)((?:\n.*)*)\n\.start_formatted_area\.\n(.+)\n(.+(?:\n.+)*)\n.end_formatted_area\.((?:\n.*)*)/', $note->getNote(), $match)) {
4748c2e8227SGreg Roach            // This looks like a census-assistant shared note
4758c2e8227SGreg Roach            $title     = Filter::escapeHtml($match[1]);
4768c2e8227SGreg Roach            $preamble  = Filter::escapeHtml($match[2]);
4778c2e8227SGreg Roach            $header    = Filter::escapeHtml($match[3]);
4788c2e8227SGreg Roach            $data      = Filter::escapeHtml($match[4]);
4798c2e8227SGreg Roach            $postamble = Filter::escapeHtml($match[5]);
4808c2e8227SGreg Roach
481dc46b574SDavid Drury            // Get the column headers for the census to which this note refers
482dc46b574SDavid Drury            // requires the fact place & date to match the specific census
483dc46b574SDavid Drury            // censusPlace() (Soundex match) and censusDate() functions
48413abd6f3SGreg Roach            $fmt_headers = [];
48515d603e7SGreg Roach            /** @var GedcomRecord[] $linkedRecords */
486dc46b574SDavid Drury            $linkedRecords = array_merge($note->linkedIndividuals('NOTE'), $note->linkedFamilies('NOTE'));
487dc46b574SDavid Drury            $firstRecord   = array_shift($linkedRecords);
488dc46b574SDavid Drury            if ($firstRecord) {
489dc46b574SDavid Drury                $countryCode = '';
490dc46b574SDavid Drury                $date        = '';
491dc46b574SDavid Drury                foreach ($firstRecord->getFacts('CENS') as $fact) {
492dc46b574SDavid Drury                    if (trim($fact->getAttribute('NOTE'), '@') === $note->getXref()) {
493dc46b574SDavid Drury                        $date        = $fact->getAttribute('DATE');
494dc46b574SDavid Drury                        $place       = explode(',', strip_tags($fact->getPlace()->getFullName()));
495dc46b574SDavid Drury                        $countryCode = Soundex::daitchMokotoff(array_pop($place));
496dc46b574SDavid Drury                        break;
497dc46b574SDavid Drury                    }
4988c2e8227SGreg Roach                }
4998c2e8227SGreg Roach
500dc46b574SDavid Drury                foreach (Census::allCensusPlaces() as $censusPlace) {
501dc46b574SDavid Drury                    if (Soundex::compare($countryCode, Soundex::daitchMokotoff($censusPlace->censusPlace()))) {
502dc46b574SDavid Drury                        foreach ($censusPlace->allCensusDates() as $census) {
503dc46b574SDavid Drury                            if ($census->censusDate() == $date) {
504dc46b574SDavid Drury                                foreach ($census->columns() as $column) {
505dc46b574SDavid Drury                                    $abbrev = $column->abbreviation();
506dc46b574SDavid Drury                                    if ($abbrev) {
507dc46b574SDavid Drury                                        $description          = $column->title() ? $column->title() : I18N::translate('Description unavailable');
508dc46b574SDavid Drury                                        $fmt_headers[$abbrev] = '<span title="' . $description . '">' . $abbrev . '</span>';
509dc46b574SDavid Drury                                    }
510dc46b574SDavid Drury                                }
511dc46b574SDavid Drury                                break 2;
512dc46b574SDavid Drury                            }
513dc46b574SDavid Drury                        }
514dc46b574SDavid Drury                    }
515dc46b574SDavid Drury                }
516dc46b574SDavid Drury            }
517dc46b574SDavid Drury            // Substitute header labels and format as HTML
5188c2e8227SGreg Roach            $thead = '<tr><th>' . strtr(str_replace('|', '</th><th>', $header), $fmt_headers) . '</th></tr>';
519ad51e0bbSGreg Roach            $thead = str_replace('.b.', '', $thead);
5208c2e8227SGreg Roach
5218c2e8227SGreg Roach            // Format data as HTML
5228c2e8227SGreg Roach            $tbody = '';
52314c3d3fbSGreg Roach            foreach (explode("\n", $data) as $row) {
5248c2e8227SGreg Roach                $tbody .= '<tr>';
5258c2e8227SGreg Roach                foreach (explode('|', $row) as $column) {
5268c2e8227SGreg Roach                    $tbody .= '<td>' . $column . '</td>';
5278c2e8227SGreg Roach                }
5288c2e8227SGreg Roach                $tbody .= '</tr>';
5298c2e8227SGreg Roach            }
5308c2e8227SGreg Roach
5318c2e8227SGreg Roach            return
5328c2e8227SGreg Roach                $title . "\n" . // The newline allows the framework to expand the details and turn the first line into a link
533673157b0SGreg Roach                '<div class="markdown">' .
5348c2e8227SGreg Roach                '<p>' . $preamble . '</p>' .
535dc46b574SDavid Drury                '<table>' .
5368c2e8227SGreg Roach                '<thead>' . $thead . '</thead>' .
5378c2e8227SGreg Roach                '<tbody>' . $tbody . '</tbody>' .
5388c2e8227SGreg Roach                '</table>' .
539dc46b574SDavid Drury                '<p>' . $postamble . '</p>' .
540dc46b574SDavid Drury                '</div>';
5418c2e8227SGreg Roach        } else {
5428c2e8227SGreg Roach            // Not a census-assistant shared note - apply default formatting
54315d603e7SGreg Roach            return Filter::formatText($note->getNote(), $note->getTree());
5448c2e8227SGreg Roach        }
5458c2e8227SGreg Roach    }
54699f222b3SGreg Roach
54799f222b3SGreg Roach    /**
548ad51e0bbSGreg Roach     * Generate an HTML row of data for the census header
54952bc9faeSGreg Roach     * Add prefix cell (store XREF and drag/drop)
55052bc9faeSGreg Roach     * Add suffix cell (delete button)
55152bc9faeSGreg Roach     *
552ad51e0bbSGreg Roach     * @param CensusInterface $census
55399f222b3SGreg Roach     *
554ad51e0bbSGreg Roach     * @return string
55599f222b3SGreg Roach     */
556ad51e0bbSGreg Roach    public static function censusTableHeader(CensusInterface $census) {
55752bc9faeSGreg Roach        $html = '';
558ad51e0bbSGreg Roach        foreach ($census->columns() as $column) {
55915d603e7SGreg Roach            $html .= '<th class="wt-census-assistant-field" title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
56099f222b3SGreg Roach        }
56199f222b3SGreg Roach
56215d603e7SGreg Roach        return '<tr class="wt-census-assistant-row"><th hidden></th>' . $html . '<th></th></tr>';
563ad51e0bbSGreg Roach    }
56499f222b3SGreg Roach
565ad51e0bbSGreg Roach    /**
566ad51e0bbSGreg Roach     * Generate an HTML row of data for the census
56752bc9faeSGreg Roach     * Add prefix cell (store XREF and drag/drop)
56852bc9faeSGreg Roach     * Add suffix cell (delete button)
56952bc9faeSGreg Roach     *
570ad51e0bbSGreg Roach     * @param CensusInterface $census
571ad51e0bbSGreg Roach     *
572ad51e0bbSGreg Roach     * @return string
573ad51e0bbSGreg Roach     */
574ad51e0bbSGreg Roach    public static function censusTableEmptyRow(CensusInterface $census) {
57515d603e7SGreg 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>';
576ad51e0bbSGreg Roach    }
57799f222b3SGreg Roach
578ad51e0bbSGreg Roach    /**
579ad51e0bbSGreg Roach     * Generate an HTML row of data for the census
58052bc9faeSGreg Roach     * Add prefix cell (store XREF and drag/drop)
58152bc9faeSGreg Roach     * Add suffix cell (delete button)
58252bc9faeSGreg Roach     *
583ad51e0bbSGreg Roach     * @param CensusInterface $census
584ad51e0bbSGreg Roach     * @param Individual      $individual
585ad51e0bbSGreg Roach     * @param Individual      $head
586ad51e0bbSGreg Roach     *
587ad51e0bbSGreg Roach     * @return string
588ad51e0bbSGreg Roach     */
58915d603e7SGreg Roach    public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head) {
59015d603e7SGreg Roach        $html = '';
59115d603e7SGreg Roach        foreach ($census->columns() as $column) {
59215d603e7SGreg 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>';
59399f222b3SGreg Roach        }
59499f222b3SGreg Roach
59515d603e7SGreg 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>';
59699f222b3SGreg Roach    }
5978c2e8227SGreg Roach}
598