Completed
Push — develop ( 891d14...a42dca )
by Greg
09:56
created
app/Datatables.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@
 block discarded – undo
64 64
 
65 65
 		return [
66 66
 			'data-language'    => json_encode($language),
67
-		  'data-length-menu' => json_encode([array_keys($length_menu), array_values($length_menu)])
67
+			'data-length-menu' => json_encode([array_keys($length_menu), array_values($length_menu)])
68 68
 		];
69 69
 	}
70 70
 
Please login to merge, or discard this patch.
app/Theme/AbstractTheme.php 1 patch
Indentation   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -90,9 +90,9 @@
 block discarded – undo
90 90
 		'info'    => 'fa fa-info-circle',
91 91
 		'warning' => 'fa fa-exclamation-circle',
92 92
 
93
-	  // Icons for file types
94
-	  'mime-application-pdf' => '',
95
-	  'mime-text-html'       => '',
93
+		// Icons for file types
94
+		'mime-application-pdf' => '',
95
+		'mime-text-html'       => '',
96 96
 
97 97
 		// Other icons
98 98
 		'mail'    => 'fa fa-envelope-o',
Please login to merge, or discard this patch.
app/Module/CensusAssistantModule.php 1 patch
Indentation   +397 added lines, -397 removed lines patch added patch discarded remove patch
@@ -36,58 +36,58 @@  discard block
 block discarded – undo
36 36
  * Class CensusAssistantModule
37 37
  */
38 38
 class CensusAssistantModule extends AbstractModule {
39
-    /** {@inheritdoc} */
40
-    public function getTitle() {
41
-        return /* I18N: Name of a module */
42
-            I18N::translate('Census assistant');
43
-    }
44
-
45
-    /** {@inheritdoc} */
46
-    public function getDescription() {
47
-        return /* I18N: Description of the “Census assistant” module */
48
-            I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
49
-    }
50
-
51
-    /**
52
-     * This is a general purpose hook, allowing modules to respond to routes
53
-     * of the form module.php?mod=FOO&mod_action=BAR
54
-     *
55
-     * @param string $mod_action
56
-     */
57
-    public function modAction($mod_action) {
58
-        global $WT_TREE;
59
-
60
-        switch ($mod_action) {
61
-        case 'census-header':
62
-            header('Content-Type: text/html; charset=utf8');
63
-            $census = Filter::get('census');
64
-            echo $this->censusTableHeader(new $census);
65
-            break;
66
-
67
-        case 'census-individual':
68
-            header('Content-Type: text/html; charset=utf8');
69
-            $census     = Filter::get('census');
70
-            $individual = Individual::getInstance(Filter::get('xref'), $WT_TREE);
71
-            $head       = Individual::getInstance(Filter::get('head'), $WT_TREE);
72
-            echo $this->censusTableRow(new $census, $individual, $head);
73
-            break;
74
-
75
-        case 'media_find':
76
-            self::mediaFind();
77
-            break;
78
-        case 'media_query_3a':
79
-            self::mediaQuery();
80
-            break;
81
-        default:
82
-            http_response_code(404);
83
-        }
84
-    }
85
-
86
-    /**
87
-     * @param Individual $individual
88
-     */
89
-    public function createCensusAssistant(Individual $individual) {
90
-        ?>
39
+		/** {@inheritdoc} */
40
+		public function getTitle() {
41
+				return /* I18N: Name of a module */
42
+						I18N::translate('Census assistant');
43
+		}
44
+
45
+		/** {@inheritdoc} */
46
+		public function getDescription() {
47
+				return /* I18N: Description of the “Census assistant” module */
48
+						I18N::translate('An alternative way to enter census transcripts and link them to individuals.');
49
+		}
50
+
51
+		/**
52
+		 * This is a general purpose hook, allowing modules to respond to routes
53
+		 * of the form module.php?mod=FOO&mod_action=BAR
54
+		 *
55
+		 * @param string $mod_action
56
+		 */
57
+		public function modAction($mod_action) {
58
+				global $WT_TREE;
59
+
60
+				switch ($mod_action) {
61
+				case 'census-header':
62
+						header('Content-Type: text/html; charset=utf8');
63
+						$census = Filter::get('census');
64
+						echo $this->censusTableHeader(new $census);
65
+						break;
66
+
67
+				case 'census-individual':
68
+						header('Content-Type: text/html; charset=utf8');
69
+						$census     = Filter::get('census');
70
+						$individual = Individual::getInstance(Filter::get('xref'), $WT_TREE);
71
+						$head       = Individual::getInstance(Filter::get('head'), $WT_TREE);
72
+						echo $this->censusTableRow(new $census, $individual, $head);
73
+						break;
74
+
75
+				case 'media_find':
76
+						self::mediaFind();
77
+						break;
78
+				case 'media_query_3a':
79
+						self::mediaQuery();
80
+						break;
81
+				default:
82
+						http_response_code(404);
83
+				}
84
+		}
85
+
86
+		/**
87
+		 * @param Individual $individual
88
+		 */
89
+		public function createCensusAssistant(Individual $individual) {
90
+				?>
91 91
 
92 92
         <div id="census-assistant-link" hidden>
93 93
             <a href="#">
@@ -242,83 +242,83 @@  discard block
 block discarded – undo
242 242
             document.querySelector('#census-assistant-head').addEventListener('click', censusAssistantHead);
243 243
         </script>
244 244
         <?php
245
-    }
246
-
247
-    /**
248
-     * @param Individual $individual
249
-     * @param string     $newged
250
-     *
251
-     * @return string
252
-     */
253
-    public function updateCensusAssistant(Individual $individual, $fact_id, $newged, $keep_chan) {
254
-        $ca_title       = Filter::post('ca_title');
255
-        $ca_place       = Filter::post('ca_place');
256
-        $ca_citation    = Filter::post('ca_citation');
257
-        $ca_individuals = Filter::postArray('ca_individuals');
258
-        $ca_notes       = Filter::post('ca_notes');
259
-        $ca_census      = Filter::post('ca_census', 'Fisharebest\\\\Webtrees\\\\Census\\\\CensusOf[A-Za-z0-9]+');
260
-
261
-        if ($ca_census !== '' && !empty($ca_individuals)) {
262
-            $census = new $ca_census;
263
-
264
-            $note_text = $this->createNoteText($census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes);
265
-            $note = $individual->getTree()->createRecord('0 @new@ NOTE ' . $note_text);
266
-
267
-            $newged .= "\n2 NOTE @" . $note->getXref() . '@';
268
-
269
-            // Add the census fact to the rest of the household
270
-            foreach (array_keys($ca_individuals) as $xref) {
271
-                if ($xref !== $individual->getXref()) {
272
-                    Individual::getInstance($xref, $individual->getTree())
273
-                        ->updateFact($fact_id, $newged, !$keep_chan);
274
-                }
275
-            }
276
-        }
277
-
278
-        return $newged;
279
-    }
280
-
281
-    /**
282
-     * @param CensusInterface $census
283
-     * @param string          $ca_title
284
-     * @param string          $ca_place
285
-     * @param string          $ca_citation
286
-     * @param string[][]      $ca_individuals
287
-     * @param string          $ca_notes
288
-     *
289
-     * @return string
290
-     */
291
-    private function createNoteText(CensusInterface $census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes) {
292
-        $text = '';
293
-        foreach ($census->columns() as $n => $column) {
294
-            if ($n > 0) {
295
-                $text .= ', ';
296
-            }
297
-            $text .= $column->abbreviation();
298
-        }
299
-
300
-        foreach ($ca_individuals as $xref => $columns) {
301
-            $text .= "\n" . implode(', ', $columns);
302
-        }
303
-
304
-        return $ca_title . "\n" . $ca_place . "\n" . $ca_citation . "\n\n" . $text . "\n\n" . $ca_notes;
305
-    }
306
-
307
-    /**
308
-     * Find a media object.
309
-     */
310
-    private static function mediaFind() {
311
-        global $WT_TREE;
312
-
313
-        $controller = new SimpleController;
314
-        $filter     = Filter::get('filter');
315
-        $multiple   = Filter::getBool('multiple');
316
-
317
-        $controller
318
-            ->setPageTitle(I18N::translate('Find an individual'))
319
-            ->pageHeader();
320
-
321
-        ?>
245
+		}
246
+
247
+		/**
248
+		 * @param Individual $individual
249
+		 * @param string     $newged
250
+		 *
251
+		 * @return string
252
+		 */
253
+		public function updateCensusAssistant(Individual $individual, $fact_id, $newged, $keep_chan) {
254
+				$ca_title       = Filter::post('ca_title');
255
+				$ca_place       = Filter::post('ca_place');
256
+				$ca_citation    = Filter::post('ca_citation');
257
+				$ca_individuals = Filter::postArray('ca_individuals');
258
+				$ca_notes       = Filter::post('ca_notes');
259
+				$ca_census      = Filter::post('ca_census', 'Fisharebest\\\\Webtrees\\\\Census\\\\CensusOf[A-Za-z0-9]+');
260
+
261
+				if ($ca_census !== '' && !empty($ca_individuals)) {
262
+						$census = new $ca_census;
263
+
264
+						$note_text = $this->createNoteText($census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes);
265
+						$note = $individual->getTree()->createRecord('0 @new@ NOTE ' . $note_text);
266
+
267
+						$newged .= "\n2 NOTE @" . $note->getXref() . '@';
268
+
269
+						// Add the census fact to the rest of the household
270
+						foreach (array_keys($ca_individuals) as $xref) {
271
+								if ($xref !== $individual->getXref()) {
272
+										Individual::getInstance($xref, $individual->getTree())
273
+												->updateFact($fact_id, $newged, !$keep_chan);
274
+								}
275
+						}
276
+				}
277
+
278
+				return $newged;
279
+		}
280
+
281
+		/**
282
+		 * @param CensusInterface $census
283
+		 * @param string          $ca_title
284
+		 * @param string          $ca_place
285
+		 * @param string          $ca_citation
286
+		 * @param string[][]      $ca_individuals
287
+		 * @param string          $ca_notes
288
+		 *
289
+		 * @return string
290
+		 */
291
+		private function createNoteText(CensusInterface $census, $ca_title, $ca_place, $ca_citation, $ca_individuals, $ca_notes) {
292
+				$text = '';
293
+				foreach ($census->columns() as $n => $column) {
294
+						if ($n > 0) {
295
+								$text .= ', ';
296
+						}
297
+						$text .= $column->abbreviation();
298
+				}
299
+
300
+				foreach ($ca_individuals as $xref => $columns) {
301
+						$text .= "\n" . implode(', ', $columns);
302
+				}
303
+
304
+				return $ca_title . "\n" . $ca_place . "\n" . $ca_citation . "\n\n" . $text . "\n\n" . $ca_notes;
305
+		}
306
+
307
+		/**
308
+		 * Find a media object.
309
+		 */
310
+		private static function mediaFind() {
311
+				global $WT_TREE;
312
+
313
+				$controller = new SimpleController;
314
+				$filter     = Filter::get('filter');
315
+				$multiple   = Filter::getBool('multiple');
316
+
317
+				$controller
318
+						->setPageTitle(I18N::translate('Find an individual'))
319
+						->pageHeader();
320
+
321
+				?>
322 322
         <script>
323 323
             function pasterow (id, name, gend, yob, age, bpl) {
324 324
                 window.opener.opener.insertRowToTable(id, name, '', gend, '', yob, age, 'Y', '', bpl);
@@ -328,8 +328,8 @@  discard block
 block discarded – undo
328 328
                 if (thumb) {
329 329
                     window.opener.paste_id(id, name, thumb);
330 330
                     <?php if (!$multiple) {
331
-                    echo 'window.close();';
332
-                } ?>
331
+										echo 'window.close();';
332
+								} ?>
333 333
                 } else {
334 334
                     // GEDFact_assistant ========================
335 335
                     if (window.opener.document.getElementById('addlinkQueue')) {
@@ -340,8 +340,8 @@  discard block
 block discarded – undo
340 340
                         window.opener.pastename(name);
341 341
                     }
342 342
                     <?php if (!$multiple) {
343
-                    echo 'window.close();';
344
-                } ?>
343
+										echo 'window.close();';
344
+								} ?>
345 345
                 }
346 346
             }
347 347
 
@@ -364,27 +364,27 @@  discard block
 block discarded – undo
364 364
         </script>
365 365
 
366 366
         <?php
367
-        echo '<div>';
368
-        echo '<table class="list_table width90" border="0">';
369
-        echo '<tr><td style="padding: 10px;" class="facts_label03 width90">'; // start column for find text header
370
-        echo $controller->getPageTitle();
371
-        echo '</td>';
372
-        echo '</tr>';
373
-        echo '</table>';
374
-        echo '<br>';
375
-        echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
376
-        echo '<br>';
377
-
378
-        $filter       = trim($filter);
379
-        $filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
380
-        echo '<table class="tabs_table width90"><tr>';
381
-        $myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
382
-        if ($myindilist) {
383
-            echo '<td class="list_value_wrap"><ul>';
384
-            usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
385
-            foreach ($myindilist as $indi) {
386
-                $nam = Filter::escapeHtml($indi->getFullName());
387
-                echo "<li><a href=\"#\" onclick=\"pasterow(
367
+				echo '<div>';
368
+				echo '<table class="list_table width90" border="0">';
369
+				echo '<tr><td style="padding: 10px;" class="facts_label03 width90">'; // start column for find text header
370
+				echo $controller->getPageTitle();
371
+				echo '</td>';
372
+				echo '</tr>';
373
+				echo '</table>';
374
+				echo '<br>';
375
+				echo '<button onclick="window.close();">', I18N::translate('close'), '</button>';
376
+				echo '<br>';
377
+
378
+				$filter       = trim($filter);
379
+				$filter_array = explode(' ', preg_replace('/ {2,}/', ' ', $filter));
380
+				echo '<table class="tabs_table width90"><tr>';
381
+				$myindilist = FunctionsDb::searchIndividualNames($filter_array, [$WT_TREE]);
382
+				if ($myindilist) {
383
+						echo '<td class="list_value_wrap"><ul>';
384
+						usort($myindilist, '\Fisharebest\Webtrees\GedcomRecord::compare');
385
+						foreach ($myindilist as $indi) {
386
+								$nam = Filter::escapeHtml($indi->getFullName());
387
+								echo "<li><a href=\"#\" onclick=\"pasterow(
388 388
 					'" . $indi->getXref() . "' ,
389 389
 					'" . $nam . "' ,
390 390
 					'" . $indi->getSex() . "' ,
@@ -393,44 +393,44 @@  discard block
 block discarded – undo
393 393
 					'" . $indi->getBirthPlace() . "'); return false;\">
394 394
 					<b>" . $indi->getFullName() . '</b>&nbsp;&nbsp;&nbsp;';
395 395
 
396
-                $born = I18N::translate('Birth');
397
-                echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace(), '</span></a></li>';
398
-                echo '<hr>';
399
-            }
400
-            echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
401
-        } else {
402
-            echo '<td class="list_value_wrap">';
403
-            echo I18N::translate('No results found.');
404
-            echo '</td></tr>';
405
-        }
406
-        echo '</table>';
407
-        echo '</div>';
408
-    }
409
-
410
-    /**
411
-     * Search for a media object.
412
-     */
413
-    private static function mediaQuery() {
414
-        global $WT_TREE;
415
-
416
-        $iid2 = Filter::get('iid', WT_REGEX_XREF);
417
-
418
-        $controller = new SimpleController;
419
-        $controller
420
-            ->setPageTitle(I18N::translate('Link to an existing media object'))
421
-            ->pageHeader();
422
-
423
-        $record = GedcomRecord::getInstance($iid2, $WT_TREE);
424
-        if ($record) {
425
-            $headjs = '';
426
-            if ($record instanceof Family) {
427
-                if ($record->getHusband()) {
428
-                    $headjs = $record->getHusband()->getXref();
429
-                } elseif ($record->getWife()) {
430
-                    $headjs = $record->getWife()->getXref();
431
-                }
432
-            }
433
-            ?>
396
+								$born = I18N::translate('Birth');
397
+								echo '</span><br><span class="list_item">', $born, ' ', $indi->getBirthYear(), '&nbsp;&nbsp;&nbsp;', $indi->getBirthPlace(), '</span></a></li>';
398
+								echo '<hr>';
399
+						}
400
+						echo '</ul></td></tr><tr><td class="list_label">', I18N::translate('Total individuals: %s', count($myindilist)), '</tr></td>';
401
+				} else {
402
+						echo '<td class="list_value_wrap">';
403
+						echo I18N::translate('No results found.');
404
+						echo '</td></tr>';
405
+				}
406
+				echo '</table>';
407
+				echo '</div>';
408
+		}
409
+
410
+		/**
411
+		 * Search for a media object.
412
+		 */
413
+		private static function mediaQuery() {
414
+				global $WT_TREE;
415
+
416
+				$iid2 = Filter::get('iid', WT_REGEX_XREF);
417
+
418
+				$controller = new SimpleController;
419
+				$controller
420
+						->setPageTitle(I18N::translate('Link to an existing media object'))
421
+						->pageHeader();
422
+
423
+				$record = GedcomRecord::getInstance($iid2, $WT_TREE);
424
+				if ($record) {
425
+						$headjs = '';
426
+						if ($record instanceof Family) {
427
+								if ($record->getHusband()) {
428
+										$headjs = $record->getHusband()->getXref();
429
+								} elseif ($record->getWife()) {
430
+										$headjs = $record->getWife()->getXref();
431
+								}
432
+						}
433
+						?>
434 434
             <script>
435 435
                 function insertId () {
436 436
                     if (window.opener.document.getElementById('addlinkQueue')) {
@@ -441,8 +441,8 @@  discard block
 block discarded – undo
441 441
                 }
442 442
             </script>
443 443
             <?php
444
-        } else {
445
-            ?>
444
+				} else {
445
+						?>
446 446
             <script>
447 447
                 function insertId () {
448 448
                     window.opener.alert('<?= $iid2 ?> - <?= I18N::translate('Not a valid individual, family, or source ID') ?>');
@@ -450,176 +450,176 @@  discard block
 block discarded – undo
450 450
                 }
451 451
             </script>
452 452
             <?php
453
-        }
454
-        ?>
453
+				}
454
+				?>
455 455
         <script>window.onLoad = insertId();</script>
456 456
         <?php
457
-    }
458
-
459
-    /**
460
-     * Convert custom markup into HTML
461
-     *
462
-     * @param Note $note
463
-     *
464
-     * @return string
465
-     */
466
-    public static function formatCensusNote(Note $note) {
467
-        global $WT_TREE;
468
-
469
-        if (preg_match('/(.*)((?:\n.*)*)\n\.start_formatted_area\.\n(.+)\n(.+(?:\n.+)*)\n.end_formatted_area\.((?:\n.*)*)/', $note->getNote(), $match)) {
470
-            // This looks like a census-assistant shared note
471
-            $title     = Filter::escapeHtml($match[1]);
472
-            $preamble  = Filter::escapeHtml($match[2]);
473
-            $header    = Filter::escapeHtml($match[3]);
474
-            $data      = Filter::escapeHtml($match[4]);
475
-            $postamble = Filter::escapeHtml($match[5]);
476
-
477
-            // Get the column headers for the census to which this note refers
478
-            // requires the fact place & date to match the specific census
479
-            // censusPlace() (Soundex match) and censusDate() functions
480
-            $fmt_headers = [];
481
-            /** @var GedcomRecord[] $linkedRecords */
482
-            $linkedRecords = array_merge($note->linkedIndividuals('NOTE'), $note->linkedFamilies('NOTE'));
483
-            $firstRecord   = array_shift($linkedRecords);
484
-            if ($firstRecord) {
485
-                $countryCode = '';
486
-                $date        = '';
487
-                foreach ($firstRecord->getFacts('CENS') as $fact) {
488
-                    if (trim($fact->getAttribute('NOTE'), '@') === $note->getXref()) {
489
-                        $date        = $fact->getAttribute('DATE');
490
-                        $place       = explode(',', strip_tags($fact->getPlace()->getFullName()));
491
-                        $countryCode = Soundex::daitchMokotoff(array_pop($place));
492
-                        break;
493
-                    }
494
-                }
495
-
496
-                foreach (Census::allCensusPlaces() as $censusPlace) {
497
-                    if (Soundex::compare($countryCode, Soundex::daitchMokotoff($censusPlace->censusPlace()))) {
498
-                        foreach ($censusPlace->allCensusDates() as $census) {
499
-                            if ($census->censusDate() == $date) {
500
-                                foreach ($census->columns() as $column) {
501
-                                    $abbrev = $column->abbreviation();
502
-                                    if ($abbrev) {
503
-                                        $description          = $column->title() ? $column->title() : I18N::translate('Description unavailable');
504
-                                        $fmt_headers[$abbrev] = '<span title="' . $description . '">' . $abbrev . '</span>';
505
-                                    }
506
-                                }
507
-                                break 2;
508
-                            }
509
-                        }
510
-                    }
511
-                }
512
-            }
513
-            // Substitute header labels and format as HTML
514
-            $thead = '<tr><th>' . strtr(str_replace('|', '</th><th>', $header), $fmt_headers) . '</th></tr>';
515
-            $thead = str_replace('.b.', '', $thead);
516
-
517
-            // Format data as HTML
518
-            $tbody = '';
519
-            foreach (explode("\n", $data) as $row) {
520
-                $tbody .= '<tr>';
521
-                foreach (explode('|', $row) as $column) {
522
-                    $tbody .= '<td>' . $column . '</td>';
523
-                }
524
-                $tbody .= '</tr>';
525
-            }
526
-
527
-            return
528
-                $title . "\n" . // The newline allows the framework to expand the details and turn the first line into a link
529
-                '<div class="markdown">' .
530
-                '<p>' . $preamble . '</p>' .
531
-                '<table>' .
532
-                '<thead>' . $thead . '</thead>' .
533
-                '<tbody>' . $tbody . '</tbody>' .
534
-                '</table>' .
535
-                '<p>' . $postamble . '</p>' .
536
-                '</div>';
537
-        } else {
538
-            // Not a census-assistant shared note - apply default formatting
539
-            return Filter::formatText($note->getNote(), $WT_TREE);
540
-        }
541
-    }
542
-
543
-    /**
544
-     * Generate an HTML row of data for the census header
545
-     * Add prefix cell (store XREF and drag/drop)
546
-     * Add suffix cell (delete button)
547
-     *
548
-     * @param CensusInterface $census
549
-     *
550
-     * @return string
551
-     */
552
-    public static function censusTableHeader(CensusInterface $census) {
553
-        $html = '';
554
-        foreach ($census->columns() as $column) {
555
-            $html .= '<th class="wt-census-assistant-field" title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
556
-        }
557
-
558
-        return '<tr class="wt-census-assistant-row"><th hidden></th>' . $html . '<th></th></tr>';
559
-    }
560
-
561
-    /**
562
-     * Generate an HTML row of data for the census
563
-     * Add prefix cell (store XREF and drag/drop)
564
-     * Add suffix cell (delete button)
565
-     *
566
-     * @param CensusInterface $census
567
-     *
568
-     * @return string
569
-     */
570
-    public static function censusTableEmptyRow(CensusInterface $census) {
571
-        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>';
572
-    }
573
-
574
-    /**
575
-     * Generate an HTML row of data for the census
576
-     * Add prefix cell (store XREF and drag/drop)
577
-     * Add suffix cell (delete button)
578
-     *
579
-     * @param CensusInterface $census
580
-     * @param Individual      $individual
581
-     * @param Individual|null $head
582
-     *
583
-     * @return string
584
-     */
585
-    public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head = null) {
586
-        $html = '';
587
-        foreach ($census->columns() as $column) {
588
-            $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>';
589
-        }
590
-
591
-        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>';
592
-    }
593
-
594
-    /**
595
-     * Create a family on the census navigator.
596
-     *
597
-     * @param CensusInterface $census
598
-     * @param Family          $family
599
-     * @param Individual      $head
600
-     *
601
-     * @return string
602
-     */
603
-    public static function censusNavigatorFamily(CensusInterface $census, Family $family, Individual $head) {
604
-        $headImg2 = '<i class="icon-button_head" title="' . I18N::translate('Head of household') . '"></i>';
605
-
606
-        foreach ($family->getSpouses() as $spouse) {
607
-            $menu = new Menu(Functions::getCloseRelationshipName($head, $spouse));
608
-            foreach ($spouse->getChildFamilies() as $grandparents) {
609
-                foreach ($grandparents->getSpouses() as $grandparent) {
610
-                    $submenu = new Menu(
611
-                        Functions::getCloseRelationshipName($head, $grandparent) . ' - ' . $grandparent->getFullName(),
612
-                        '#',
613
-                        '',
614
-                        ['onclick' => 'return appendCensusRow("' . Filter::escapeJs(self::censusTableRow($census, $grandparent, $head)) . '");']
615
-                    );
616
-                    $submenu->addClass('submenuitem', '');
617
-                    $menu->addSubmenu($submenu);
618
-                    $menu->addClass('', 'submenu');
619
-                }
620
-            }
621
-
622
-            ?>
457
+		}
458
+
459
+		/**
460
+		 * Convert custom markup into HTML
461
+		 *
462
+		 * @param Note $note
463
+		 *
464
+		 * @return string
465
+		 */
466
+		public static function formatCensusNote(Note $note) {
467
+				global $WT_TREE;
468
+
469
+				if (preg_match('/(.*)((?:\n.*)*)\n\.start_formatted_area\.\n(.+)\n(.+(?:\n.+)*)\n.end_formatted_area\.((?:\n.*)*)/', $note->getNote(), $match)) {
470
+						// This looks like a census-assistant shared note
471
+						$title     = Filter::escapeHtml($match[1]);
472
+						$preamble  = Filter::escapeHtml($match[2]);
473
+						$header    = Filter::escapeHtml($match[3]);
474
+						$data      = Filter::escapeHtml($match[4]);
475
+						$postamble = Filter::escapeHtml($match[5]);
476
+
477
+						// Get the column headers for the census to which this note refers
478
+						// requires the fact place & date to match the specific census
479
+						// censusPlace() (Soundex match) and censusDate() functions
480
+						$fmt_headers = [];
481
+						/** @var GedcomRecord[] $linkedRecords */
482
+						$linkedRecords = array_merge($note->linkedIndividuals('NOTE'), $note->linkedFamilies('NOTE'));
483
+						$firstRecord   = array_shift($linkedRecords);
484
+						if ($firstRecord) {
485
+								$countryCode = '';
486
+								$date        = '';
487
+								foreach ($firstRecord->getFacts('CENS') as $fact) {
488
+										if (trim($fact->getAttribute('NOTE'), '@') === $note->getXref()) {
489
+												$date        = $fact->getAttribute('DATE');
490
+												$place       = explode(',', strip_tags($fact->getPlace()->getFullName()));
491
+												$countryCode = Soundex::daitchMokotoff(array_pop($place));
492
+												break;
493
+										}
494
+								}
495
+
496
+								foreach (Census::allCensusPlaces() as $censusPlace) {
497
+										if (Soundex::compare($countryCode, Soundex::daitchMokotoff($censusPlace->censusPlace()))) {
498
+												foreach ($censusPlace->allCensusDates() as $census) {
499
+														if ($census->censusDate() == $date) {
500
+																foreach ($census->columns() as $column) {
501
+																		$abbrev = $column->abbreviation();
502
+																		if ($abbrev) {
503
+																				$description          = $column->title() ? $column->title() : I18N::translate('Description unavailable');
504
+																				$fmt_headers[$abbrev] = '<span title="' . $description . '">' . $abbrev . '</span>';
505
+																		}
506
+																}
507
+																break 2;
508
+														}
509
+												}
510
+										}
511
+								}
512
+						}
513
+						// Substitute header labels and format as HTML
514
+						$thead = '<tr><th>' . strtr(str_replace('|', '</th><th>', $header), $fmt_headers) . '</th></tr>';
515
+						$thead = str_replace('.b.', '', $thead);
516
+
517
+						// Format data as HTML
518
+						$tbody = '';
519
+						foreach (explode("\n", $data) as $row) {
520
+								$tbody .= '<tr>';
521
+								foreach (explode('|', $row) as $column) {
522
+										$tbody .= '<td>' . $column . '</td>';
523
+								}
524
+								$tbody .= '</tr>';
525
+						}
526
+
527
+						return
528
+								$title . "\n" . // The newline allows the framework to expand the details and turn the first line into a link
529
+								'<div class="markdown">' .
530
+								'<p>' . $preamble . '</p>' .
531
+								'<table>' .
532
+								'<thead>' . $thead . '</thead>' .
533
+								'<tbody>' . $tbody . '</tbody>' .
534
+								'</table>' .
535
+								'<p>' . $postamble . '</p>' .
536
+								'</div>';
537
+				} else {
538
+						// Not a census-assistant shared note - apply default formatting
539
+						return Filter::formatText($note->getNote(), $WT_TREE);
540
+				}
541
+		}
542
+
543
+		/**
544
+		 * Generate an HTML row of data for the census header
545
+		 * Add prefix cell (store XREF and drag/drop)
546
+		 * Add suffix cell (delete button)
547
+		 *
548
+		 * @param CensusInterface $census
549
+		 *
550
+		 * @return string
551
+		 */
552
+		public static function censusTableHeader(CensusInterface $census) {
553
+				$html = '';
554
+				foreach ($census->columns() as $column) {
555
+						$html .= '<th class="wt-census-assistant-field" title="' . $column->title() . '">' . $column->abbreviation() . '</th>';
556
+				}
557
+
558
+				return '<tr class="wt-census-assistant-row"><th hidden></th>' . $html . '<th></th></tr>';
559
+		}
560
+
561
+		/**
562
+		 * Generate an HTML row of data for the census
563
+		 * Add prefix cell (store XREF and drag/drop)
564
+		 * Add suffix cell (delete button)
565
+		 *
566
+		 * @param CensusInterface $census
567
+		 *
568
+		 * @return string
569
+		 */
570
+		public static function censusTableEmptyRow(CensusInterface $census) {
571
+				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>';
572
+		}
573
+
574
+		/**
575
+		 * Generate an HTML row of data for the census
576
+		 * Add prefix cell (store XREF and drag/drop)
577
+		 * Add suffix cell (delete button)
578
+		 *
579
+		 * @param CensusInterface $census
580
+		 * @param Individual      $individual
581
+		 * @param Individual|null $head
582
+		 *
583
+		 * @return string
584
+		 */
585
+		public static function censusTableRow(CensusInterface $census, Individual $individual, Individual $head = null) {
586
+				$html = '';
587
+				foreach ($census->columns() as $column) {
588
+						$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>';
589
+				}
590
+
591
+				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>';
592
+		}
593
+
594
+		/**
595
+		 * Create a family on the census navigator.
596
+		 *
597
+		 * @param CensusInterface $census
598
+		 * @param Family          $family
599
+		 * @param Individual      $head
600
+		 *
601
+		 * @return string
602
+		 */
603
+		public static function censusNavigatorFamily(CensusInterface $census, Family $family, Individual $head) {
604
+				$headImg2 = '<i class="icon-button_head" title="' . I18N::translate('Head of household') . '"></i>';
605
+
606
+				foreach ($family->getSpouses() as $spouse) {
607
+						$menu = new Menu(Functions::getCloseRelationshipName($head, $spouse));
608
+						foreach ($spouse->getChildFamilies() as $grandparents) {
609
+								foreach ($grandparents->getSpouses() as $grandparent) {
610
+										$submenu = new Menu(
611
+												Functions::getCloseRelationshipName($head, $grandparent) . ' - ' . $grandparent->getFullName(),
612
+												'#',
613
+												'',
614
+												['onclick' => 'return appendCensusRow("' . Filter::escapeJs(self::censusTableRow($census, $grandparent, $head)) . '");']
615
+										);
616
+										$submenu->addClass('submenuitem', '');
617
+										$menu->addSubmenu($submenu);
618
+										$menu->addClass('', 'submenu');
619
+								}
620
+						}
621
+
622
+						?>
623 623
             <tr>
624 624
                 <td class="optionbox">
625 625
                     <?= $menu->bootstrap4() ?>
@@ -640,38 +640,38 @@  discard block
 block discarded – undo
640 640
                 </td>
641 641
             </tr>
642 642
             <?php
643
-        }
644
-
645
-        foreach ($family->getChildren() as $child) {
646
-            $menu = new Menu(Functions::getCloseRelationshipName($head, $child));
647
-            foreach ($child->getSpouseFamilies() as $spouse_family) {
648
-                foreach ($spouse_family->getSpouses() as $spouse_family_spouse) {
649
-                    if ($spouse_family_spouse != $child) {
650
-                        $submenu = new Menu(
651
-                            Functions::getCloseRelationshipName($head, $spouse_family_spouse) . ' - ' . $spouse_family_spouse->getFullName(),
652
-                            '#',
653
-                            '',
654
-                            ['onclick' => 'return appendCensusRow("' . Filter::escapeJs(self::censusTableRow($census, $spouse_family_spouse, $head)) . '");']
655
-                        );
656
-                        $submenu->addClass('submenuitem', '');
657
-                        $menu->addSubmenu($submenu);
658
-                        $menu->addClass('', 'submenu');
659
-                    }
660
-                }
661
-                foreach ($spouse_family->getChildren() as $spouse_family_child) {
662
-                    $submenu = new Menu(
663
-                        Functions::getCloseRelationshipName($head, $spouse_family_child) . ' - ' . $spouse_family_child->getFullName(),
664
-                        '#',
665
-                        '',
666
-                        ['onclick' => 'return appendCensusRow("' . Filter::escapeJs(self::censusTableRow($census, $spouse_family_child, $head)) . '");']
667
-                    );
668
-                    $submenu->addClass('submenuitem', '');
669
-                    $menu->addSubmenu($submenu);
670
-                    $menu->addClass('', 'submenu');
671
-                }
672
-            }
673
-
674
-            ?>
643
+				}
644
+
645
+				foreach ($family->getChildren() as $child) {
646
+						$menu = new Menu(Functions::getCloseRelationshipName($head, $child));
647
+						foreach ($child->getSpouseFamilies() as $spouse_family) {
648
+								foreach ($spouse_family->getSpouses() as $spouse_family_spouse) {
649
+										if ($spouse_family_spouse != $child) {
650
+												$submenu = new Menu(
651
+														Functions::getCloseRelationshipName($head, $spouse_family_spouse) . ' - ' . $spouse_family_spouse->getFullName(),
652
+														'#',
653
+														'',
654
+														['onclick' => 'return appendCensusRow("' . Filter::escapeJs(self::censusTableRow($census, $spouse_family_spouse, $head)) . '");']
655
+												);
656
+												$submenu->addClass('submenuitem', '');
657
+												$menu->addSubmenu($submenu);
658
+												$menu->addClass('', 'submenu');
659
+										}
660
+								}
661
+								foreach ($spouse_family->getChildren() as $spouse_family_child) {
662
+										$submenu = new Menu(
663
+												Functions::getCloseRelationshipName($head, $spouse_family_child) . ' - ' . $spouse_family_child->getFullName(),
664
+												'#',
665
+												'',
666
+												['onclick' => 'return appendCensusRow("' . Filter::escapeJs(self::censusTableRow($census, $spouse_family_child, $head)) . '");']
667
+										);
668
+										$submenu->addClass('submenuitem', '');
669
+										$menu->addSubmenu($submenu);
670
+										$menu->addClass('', 'submenu');
671
+								}
672
+						}
673
+
674
+						?>
675 675
             <tr>
676 676
                 <td class="optionbox">
677 677
                     <?= $menu->bootstrap4() ?>
@@ -692,7 +692,7 @@  discard block
 block discarded – undo
692 692
                 </td>
693 693
             </tr>
694 694
             <?php
695
-        }
696
-        echo '<tr><td><br></td></tr>';
697
-    }
695
+				}
696
+				echo '<tr><td><br></td></tr>';
697
+		}
698 698
 }
Please login to merge, or discard this patch.