1<?php 2 3declare(strict_types=1); 4 5use Fisharebest\Webtrees\Age; 6use Fisharebest\Webtrees\Date; 7use Fisharebest\Webtrees\Individual; 8use Fisharebest\Webtrees\Registry; 9use Fisharebest\Webtrees\Family; 10use Fisharebest\Webtrees\I18N; 11use Fisharebest\Webtrees\Tree; 12use Fisharebest\Webtrees\View; 13use Illuminate\Support\Collection; 14 15// lists require a unique ID in case there are multiple lists per page 16$table_id = Registry::idFactory()->id(); 17$today = new Date(strtoupper(date('d M Y'))); 18$today_jd = Registry::timestampFactory()->now()->julianDay(); 19$hundred_years_ago = Registry::timestampFactory()->now()->subtractYears(100)->julianDay(); 20 21/** 22 * @var Tree $tree 23 * @var Collection<int,Family> $families 24 */ 25 26?> 27 28<?php View::push('javascript') ?> 29<script> 30$("#<?= e($table_id) ?> > .wt-table-family").dataTable({ 31 processing: true, 32 retrieve: true, 33 columns: [ 34 /* Given names */ { type: "text" }, 35 /* Surnames */ { type: "text" }, 36 /* Age */ { type: "num" }, 37 /* Given names */ { type: "text" }, 38 /* Surnames */ { type: "text" }, 39 /* Age */ { type: "num" }, 40 /* Marriage date */ { type: "num" }, 41 /* Anniversary */ { type: "num" }, 42 /* Marriage place */ { type: "text" }, 43 /* Children */ { type: "num" }, 44 /* Last change */ { visible: <?= json_encode((bool) $tree->getPreference('SHOW_LAST_CHANGE'), JSON_THROW_ON_ERROR) ?> }, 45 /* Filter marriage */ { sortable: false }, 46 /* Filter alive/dead */ { sortable: false }, 47 /* Filter tree */ { sortable: false } 48 ], 49 sorting: [ 50 [1, "asc"] 51 ] 52}); 53 54$("#<?= e($table_id) ?>") 55 /* Hide/show parents */ 56 .on("click", "#btn-toggle-parents", function() { 57 $(".wt-individual-list-parents").slideToggle(); 58 }) 59 /* Filter buttons in table header */ 60 .on("click", "input[data-filter-column]", function() { 61 let checkbox = $(this); 62 63 // Deselect other options 64 let siblings = checkbox.siblings("input[type='checkbox']"); 65 siblings.prop("checked", false).removeAttr("checked"); 66 67 // Apply (or clear) this filter 68 let checked = checkbox.prop("checked"); 69 let filter = checked ? checkbox.data("filter-value") : ""; 70 let column = $("#<?= e($table_id) ?> .wt-table-family").DataTable().column(checkbox.data("filter-column")); 71 column.search(filter).draw(); 72 }); 73</script> 74<?php View::endpush() ?> 75 76<div id="<?= e($table_id) ?>"> 77 <table class="table table-bordered table-sm wt-table-family" 78 <?= view('lists/datatables-attributes') ?> 79 > 80 <thead> 81 <tr> 82 <th colspan="14"> 83 <div class="btn-toolbar d-flex justify-content-between mb-2"> 84 <div class="btn-group btn-group-sm" role="group"> 85 <input id="<?= e($table_id) ?>-bg-dead-N" class="btn-check" type="checkbox" data-filter-column="12" data-filter-value="N" autocomplete="off"> 86 <label for="<?= e($table_id) ?>-bg-dead-N" class="btn btn-outline-secondary btn-sm" title="' . I18N::translate('Show individuals who are alive or couples where both partners are alive.') ?>"> 87 <?= I18N::translate('Both alive') ?> 88 </label> 89 90 <input id="<?= e($table_id) ?>-bg-dead-W" class="btn-check" type="checkbox" data-filter-column="12" data-filter-value="W" autocomplete="off"> 91 <label for="<?= e($table_id) ?>-bg-dead-W" class="btn btn-outline-secondary" title="<?= I18N::translate('Show couples where only the female partner is dead.') ?>"> 92 <?= I18N::translate('Widower') ?> 93 </label> 94 95 <input id="<?= e($table_id) ?>-bg-dead-H" class="btn-check" type="checkbox" data-filter-column="12" data-filter-value="H" autocomplete="off"> 96 <label for="<?= e($table_id) ?>-bg-dead-H" class="btn btn-outline-secondary" title="<?= I18N::translate('Show couples where only the male partner is dead.') ?>"> 97 <?= I18N::translate('Widow') ?> 98 </label> 99 100 <input id="<?= e($table_id) ?>-bg-dead-Y" class="btn-check" type="checkbox" data-filter-column="12" data-filter-value="Y" autocomplete="off"> 101 <label for="<?= e($table_id) ?>-bg-dead-Y" class="btn btn-outline-secondary" title="<?= I18N::translate('Show individuals who are dead or couples where both partners are dead.') ?>"> 102 <?= I18N::translate('Both dead') ?> 103 </label> 104 </div> 105 106 <div class="btn-group btn-group-sm" role="group"> 107 <input id="<?= e($table_id) ?>-bg-roots-R" class="btn-check" type="checkbox" data-filter-column="13" data-filter-value="R" autocomplete="off"> 108 <label for="<?= e($table_id) ?>-bg-roots-R" class="btn btn-outline-secondary" title="<?= I18N::translate('Show “roots” couples or individuals. These individuals may also be called “patriarchs”. They are individuals who have no parents recorded in the database.') ?>"> 109 <?= I18N::translate('Roots') ?> 110 </label> 111 112 <input id="<?= e($table_id) ?>-bg-roots-L" class="btn-check" type="checkbox" data-filter-column="13" data-filter-value="L" autocomplete="off"> 113 <label for="<?= e($table_id) ?>-bg-roots-L" class="btn btn-outline-secondary" title="<?= I18N::translate('Show “leaves” couples or individuals. These are individuals who are alive but have no children recorded in the database.') ?>"> 114 <?= I18N::translate('Leaves') ?> 115 </label> 116 </div> 117 118 <div class="btn-group btn-group-sm" role="group"> 119 <input id="<?= e($table_id) ?>-bg-marr-U" class="btn-check" type="checkbox" data-filter-column="11" data-filter-value="U" autocomplete="off"> 120 <label for="<?= e($table_id) ?>-bg-marr-U" class="btn btn-outline-secondary" title="<?= I18N::translate('Show couples with an unknown marriage date.') ?>"> 121 <?= I18N::translate('Not married') ?> 122 </label> 123 124 <input id="<?= e($table_id) ?>-bg-marr-YES" class="btn-check" type="checkbox" data-filter-column="11" data-filter-value="YES" autocomplete="off"> 125 <label for="<?= e($table_id) ?>-bg-marr-YES" class="btn btn-outline-secondary" title="<?= I18N::translate('Show couples who married more than 100 years ago.') ?>"> 126 <?= I18N::translate('Marriage') ?>>100 127 </label> 128 129 <input id="<?= e($table_id) ?>-bg-marr-Y100" class="btn-check" type="checkbox" data-filter-column="11" data-filter-value="Y100" autocomplete="off"> 130 <label for="<?= e($table_id) ?>-bg-marr-Y100" class="btn btn-outline-secondary" title="<?= I18N::translate('Show couples who married within the last 100 years.') ?>"> 131 <?= I18N::translate('Marriage') ?><=100 132 </label> 133 134 <input id="<?= e($table_id) ?>-bg-marr-D" class="btn-check" type="checkbox" data-filter-column="11" data-filter-value="D" autocomplete="off"> 135 <label for="<?= e($table_id) ?>-bg-marr-D" class="btn btn-outline-secondary" title="<?= I18N::translate('Show divorced couples.') ?>"> 136 <?= I18N::translate('Divorce') ?> 137 </label> 138 139 <input id="<?= e($table_id) ?>-bg-marr-M" class="btn-check" type="checkbox" data-filter-column="11" data-filter-value="M" autocomplete="off"> 140 <label for="<?= e($table_id) ?>-bg-marr-M" class="btn btn-outline-secondary" title="<?= I18N::translate('Show couples where either partner married more than once.') ?>"> 141 <?= I18N::translate('Multiple marriages') ?> 142 </label> 143 </div> 144 </div> 145 </th> 146 </tr> 147 <tr> 148 <th><?= I18N::translate('Given names') ?></th> 149 <th><?= I18N::translate('Surname') ?></th> 150 <th><?= I18N::translate('Age') ?></th> 151 <th><?= I18N::translate('Given names') ?></th> 152 <th><?= I18N::translate('Surname') ?></th> 153 <th><?= I18N::translate('Age') ?></th> 154 <th><?= I18N::translate('Marriage') ?></th> 155 <th> 156 <span title="<?= I18N::translate('Anniversary') ?>"> 157 <?= view('icons/anniversary') ?> 158 </span> 159 </th> 160 <th><?= I18N::translate('Place') ?></th> 161 <th><i class="icon-children" title="<?= I18N::translate('Children') ?>"></i></th> 162 <th><?= I18N::translate('Last change') ?></th> 163 <th hidden></th> 164 <th hidden></th> 165 <th hidden></th> 166 </tr> 167 </thead> 168 169 <tbody> 170 <?php foreach ($families as $family) : ?> 171 <?php $husb = $family->husband() ?? Registry::individualFactory()->new('H', '0 @H@ INDI', null, $family->tree()) ?> 172 <?php $wife = $family->wife() ?? Registry::individualFactory()->new('W', '0 @W@ INDI', null, $family->tree()) ?> 173 174 <tr class="<?= $family->isPendingAddition() ? 'wt-new' : '' ?> <?= $family->isPendingDeletion() ? 'wt-old' : '' ?>"> 175 <!-- Husband name --> 176 <td colspan="2" data-sort="<?= e(str_replace([',', Individual::PRAENOMEN_NESCIO, Individual::NOMEN_NESCIO], 'AAAA', implode(',', array_reverse(explode(',', $husb->sortName()))))) ?>"> 177 <?php foreach ($husb->getAllNames() as $num => $name) : ?> 178 <?php if ($name['type'] !== '_MARNM' || $num === $husb->getPrimaryName()) : ?> 179 <div> 180 <a title="<?= $name['type'] === '_MARNM' ? I18N::translate('Married name') : '' ?>" href="<?= e($family->url()) ?>" class="<?= $num === $husb->getPrimaryName() ? '' : 'text-muted' ?>"> 181 <?= $name['full'] ?> 182 </a> 183 <?php if ($num === $husb->getPrimaryName()) : ?> 184 <small><?= view('icons/sex', ['sex' => $husb->sex()]) ?></small> 185 <?php endif ?> 186 </div> 187 <?php endif ?> 188 <?php endforeach ?> 189 <?= view('lists/individual-table-parents', ['individual' => $husb]) ?> 190 </td> 191 192 <td hidden data-sort="<?= e(str_replace([',', Individual::PRAENOMEN_NESCIO, Individual::NOMEN_NESCIO], 'AAAA', $husb->sortName())) ?>"></td> 193 194 <!-- Husband age --> 195 <?php $age = new Age($husb->getBirthDate(), $family->getMarriageDate()) ?> 196 <td class="text-center" data-sort="<?= $age->ageDays() ?>"> 197 <?= $age->ageYearsString() ?> 198 </td> 199 200 <!-- Wife name --> 201 <td colspan="2" data-sort="<?= e(str_replace([',', Individual::PRAENOMEN_NESCIO, Individual::NOMEN_NESCIO], 'AAAA', implode(',', array_reverse(explode(',', $wife->sortName()))))) ?>"> 202 <?php foreach ($wife->getAllNames() as $num => $name) : ?> 203 <?php if ($name['type'] !== '_MARNM' || $num === $wife->getPrimaryName()) : ?> 204 <div> 205 <a title="<?= $name['type'] === '_MARNM' ? I18N::translate('Married name') : '' ?>" href="<?= e($family->url()) ?>" class="<?= $num === $wife->getPrimaryName() ? '' : 'text-muted' ?>"> 206 <?= $name['full'] ?> 207 </a> 208 <?php if ($num === $wife->getPrimaryName()) : ?> 209 <small><?= view('icons/sex', ['sex' => $wife->sex()]) ?></small> 210 <?php endif ?> 211 </div> 212 <?php endif ?> 213 <?php endforeach ?> 214 <?= view('lists/individual-table-parents', ['individual' => $wife]) ?> 215 </td> 216 217 <td hidden data-sort="<?= e(str_replace([',', Individual::PRAENOMEN_NESCIO, Individual::NOMEN_NESCIO], 'AAAA', $wife->sortName())) ?>"></td> 218 219 <!-- Wife age --> 220 <?php $age = new Age($wife->getBirthDate(), $family->getMarriageDate()) ?> 221 <td class="text-center" data-sort="<?= $age->ageDays() ?>"> 222 <?= $age->ageYearsString() ?> 223 </td> 224 225 <!-- Marriage date --> 226 <td data-sort="<?= $family->getMarriageDate()->julianDay() ?>"> 227 <?php if ($marriage_dates = $family->getAllMarriageDates()) : ?> 228 <?php foreach ($marriage_dates as $marriage_date) : ?> 229 <div><?= $marriage_date->display($tree, null, true) ?></div> 230 <?php endforeach ?> 231 <?php elseif ($family->facts(['MARR'])->isEmpty()) : ?> 232 <?= I18N::translate('no') ?> 233 <?php elseif ($family->facts(['MARR'])->isNotEmpty()) : ?> 234 <?= I18N::translate('yes') ?> 235 <?php endif ?> 236 </td> 237 238 <!-- Marriage anniversary --> 239 <?php $age = new Age($family->getMarriageDate(), $today) ?> 240 <td class="text-center" data-sort="<?= $age->ageDays() ?>"> 241 <?= $age->ageYearsString() ?> 242 </td> 243 244 <!-- Marriage place --> 245 <td data-sort="<?= e($family->getMarriagePlace()->gedcomName()) ?>"> 246 <?php foreach ($family->getAllMarriagePlaces() as $marriage_place) : ?> 247 <div><?= $marriage_place->shortName(true) ?></div> 248 <?php endforeach ?> 249 </td> 250 251 <!-- Number of children --> 252 <td class="text-center" data-sort="<?= $family->numberOfChildren() ?>"> 253 <?= I18N::number($family->numberOfChildren()) ?> 254 </td> 255 256 <!-- Last change --> 257 <td data-sort="<?= $family->lastChangeTimestamp()->timestamp() ?>"> 258 <?= view('components/datetime', ['timestamp' => $family->lastChangeTimestamp()]) ?> 259 </td> 260 261 <!-- Filter by marriage date --> 262 <td hidden> 263 <?php if ($family->getMarriageDate()->maximumJulianDay() > $hundred_years_ago && $family->getMarriageDate()->maximumJulianDay() <= $today_jd) : ?> 264 Y100 265 <?php elseif ($family->facts(['MARR'])->isNotEmpty()) : ?> 266 YES 267 <?php else : ?> 268 U 269 <?php endif ?> 270 <?php if ($family->facts(['DIV'])->isNotEmpty()) : ?> 271 D 272 <?php endif ?> 273 <?php if (count($husb->spouseFamilies()) > 1 || count($wife->spouseFamilies()) > 1) : ?> 274 M 275 <?php endif ?> 276 </td> 277 278 <!-- Filter by alive/dead --> 279 <td hidden> 280 <?php if ($husb->isDead() && $wife->isDead()) : ?> 281 Y 282 <?php endif ?> 283 <?php if ($husb->isDead() && !$wife->isDead()) : ?> 284 <?php if ($wife->sex() === 'F') : ?> 285 H 286 <?php endif ?> 287 <?php if ($wife->sex() === 'M') : ?> 288 W 289 <?php endif ?> 290 <?php endif ?> 291 <?php if (!$husb->isDead() && $wife->isDead()) : ?> 292 <?php if ($husb->sex() === 'M') : ?> 293 W 294 <?php endif ?> 295 <?php if ($husb->sex() === 'F') : ?> 296 H 297 <?php endif ?> 298 <?php endif ?> 299 <?php if (!$husb->isDead() && !$wife->isDead()) : ?> 300 N 301 <?php endif ?> 302 </td> 303 304 <!-- Filter by roots/leaves --> 305 <td hidden> 306 <?php if ($husb->childFamilies()->isEmpty() && $wife->childFamilies()->isEmpty()) : ?> 307 R 308 <?php elseif (!$husb->isDead() && !$wife->isDead() && $family->numberOfChildren() === 0) : ?> 309 L 310 <?php endif ?> 311 </td> 312 </tr> 313 <?php endforeach ?> 314 </tbody> 315 316 <tfoot> 317 <tr> 318 <th colspan="14"> 319 <div class="btn-group btn-group-sm"> 320 <input type="checkbox" class="btn-check" id="btn-toggle-parents" aria-expanded="false" autocomplete="off"> 321 <label class="btn btn-secondary" for="btn-toggle-parents"> 322 <?= I18N::translate('Show parents') ?> 323 </label> 324 </div> 325 </th> 326 </tr> 327 </tfoot> 328 </table> 329</div> 330