1<?php use Fisharebest\Webtrees\Date; ?> 2<?php use Fisharebest\Webtrees\GedcomTag; ?> 3<?php use Fisharebest\Webtrees\I18N; ?> 4<?php use Fisharebest\Webtrees\Individual; ?> 5<?php use Fisharebest\Webtrees\View; ?> 6<?php use Ramsey\Uuid\Uuid; ?> 7 8<?php 9$table_id = 'table-fam-' . Uuid::uuid4()->toString(); // lists requires a unique ID in case there are multiple lists per page 10$hundred_years_ago = new Date(date('Y') - 100); 11?> 12 13<?php View::push('javascript') ?> 14<script> 15 $("#<?= e($table_id) ?>").dataTable( { 16dom: '<"H"<"filtersH_<?= e($table_id) ?>"><"dt-clear">pf<"dt-clear">irl>t<"F"pl<"dt-clear"><"filtersF_<?= e($table_id) ?>">>', 17<?= I18N::datatablesI18N() ?>, 18autoWidth: false, 19processing: true, 20retrieve: true, 21columns: [ 22/* Given names */ { type: "text" }, 23/* Surnames */ { type: "text" }, 24/* Age */ { type: "num" }, 25/* Given names */ { type: "text" }, 26/* Surnames */ { type: "text" }, 27/* Age */ { type: "num" }, 28/* Marriage date */ { type: "num" }, 29/* Anniversary */ { type: "num" }, 30/* Marriage place */ { type: "text" }, 31/* Children */ { type: "num" }, 32/* Last change */ { visible: <?= json_encode((bool) $tree->getPreference('SHOW_LAST_CHANGE')) ?> }, 33/* Filter marriage */ { sortable: false }, 34/* Filter alive/dead */ { sortable: false }, 35/* Filter tree */ { sortable: false } 36], 37sorting: [[1, "asc"]], 38displayLength: 20, 39pagingType: "full_numbers" 40}) 41/* Hide/show parents */ 42.on("click", ".btn-toggle-parents", function() { 43$(this).toggleClass("ui-state-active"); 44$(".parents", $(this).closest("table").DataTable().rows().nodes()).slideToggle(); 45}) 46/* Hide/show statistics */ 47.on("click", ".btn-toggle-statistics", function() { 48$(this).toggleClass("ui-state-active"); 49$("#family-charts-<?= e($table_id) ?>").slideToggle(); 50}) 51/* Filter buttons in table header */ 52.on("click", "button[data-filter-column]", function() { 53var btn = $(this); 54// De-activate the other buttons in this button group 55btn.siblings().removeClass("active"); 56// Apply (or clear) this filter 57var col = $("#<?= e($table_id) ?>").DataTable().column(btn.data("filter-column")); 58if (btn.hasClass("active")) { 59col.search("").draw(); 60} else { 61col.search(btn.data("filter-value")).draw(); 62} 63}); 64</script> 65<?php View::endpush() ?> 66 67<?php 68$max_age = (int) $tree->getPreference('MAX_ALIVE_AGE'); 69 70// init chart data 71$marr_by_age = []; 72for ($age = 0; $age <= $max_age; $age++) { 73 $marr_by_age[$age] = ''; 74} 75$birt_by_decade = []; 76$marr_by_decade = []; 77for ($year = 1550; $year < 2030; $year += 10) { 78 $birt_by_decade[$year] = ''; 79 $marr_by_decade[$year] = ''; 80} 81?> 82 83<div class="fam-list"> 84 <table id="<?= e($table_id) ?>"> 85 <thead> 86 <tr> 87 <th colspan="14"> 88 <div class="btn-toolbar d-flex justify-content-between mb-2"> 89 <div class="btn-group" data-toggle="buttons"> 90 <button 91 class="btn btn-secondary" 92 data-filter-column="12" 93 data-filter-value="N" 94 title="' . I18N::translate('Show individuals who are alive or couples where both partners are alive.') ?>" 95 > 96 <?= I18N::translate('Both alive') ?> 97 </button> 98 <button 99 class="btn btn-secondary" 100 data-filter-column="12" 101 data-filter-value="W" 102 title="<?= I18N::translate('Show couples where only the female partner is dead.') ?>" 103 > 104 <?= I18N::translate('Widower') ?> 105 </button> 106 <button 107 class="btn btn-secondary" 108 data-filter-column="12" 109 data-filter-value="H" 110 title="<?= I18N::translate('Show couples where only the male partner is dead.') ?>" 111 > 112 <?= I18N::translate('Widow') ?> 113 </button> 114 <button 115 class="btn btn-secondary" 116 data-filter-column="12" 117 data-filter-value="Y" 118 title="<?= I18N::translate('Show individuals who are dead or couples where both partners are dead.') ?>" 119 > 120 <?= I18N::translate('Both dead') ?> 121 </button> 122 </div> 123 <div class="btn-group" data-toggle="buttons"> 124 <button 125 class="btn btn-secondary" 126 data-filter-column="13" 127 data-filter-value="R" 128 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.') ?>" 129 > 130 <?= I18N::translate('Roots') ?> 131 </button> 132 <button 133 class="btn btn-secondary" 134 data-filter-column="13" 135 data-filter-value="L" 136 title="<?= I18N::translate('Show “leaves” couples or individuals. These are individuals who are alive but have no children recorded in the database.') ?>" 137 > 138 <?= I18N::translate('Leaves') ?> 139 </button> 140 </div> 141 <div class="btn-group" data-toggle="buttons"> 142 <button 143 class="btn btn-secondary" 144 data-filter-column="11" 145 data-filter-value="U" 146 title="<?= I18N::translate('Show couples with an unknown marriage date.') ?>" 147 > 148 <?= I18N::translate('Marriage') ?> 149 </button> 150 <button 151 class="btn btn-secondary" 152 data-filter-column="11" 153 data-filter-value="YES" 154 title="<?= I18N::translate('Show couples who married more than 100 years ago.') ?>" 155 > 156 <?= I18N::translate('Marriage') ?>>100 157 </button> 158 <button 159 class="btn btn-secondary" 160 data-filter-column="11" 161 data-filter-value="Y100" 162 title="<?= I18N::translate('Show couples who married within the last 100 years.') ?>" 163 > 164 <?= I18N::translate('Marriage') ?><=100 165 </button> 166 <button 167 class="btn btn-secondary" 168 data-filter-column="11" 169 data-filter-value="D" 170 title="<?= I18N::translate('Show divorced couples.') ?>" 171 > 172 <?= I18N::translate('Divorce') ?> 173 </button> 174 <button 175 class="btn btn-secondary" 176 data-filter-column="11" 177 data-filter-value="M" 178 title="<?= I18N::translate('Show couples where either partner married more than once.') ?>" 179 > 180 <?= I18N::translate('Multiple marriages') ?> 181 </button> 182 </div> 183 </div> 184 </th> 185 </tr> 186 <tr> 187 <th><?= I18N::translate('Given names') ?></th> 188 <th><?= I18N::translate('Surname') ?></th> 189 <th><?= I18N::translate('Age') ?></th> 190 <th><?= I18N::translate('Given names') ?></th> 191 <th><?= I18N::translate('Surname') ?></th> 192 <th><?= I18N::translate('Age') ?></th> 193 <th><?= I18N::translate('Marriage') ?></th> 194 <th><i class="icon-reminder" title="<?= I18N::translate('Anniversary') ?>"></i></th> 195 <th><?= I18N::translate('Place') ?></th> 196 <th><i class="icon-children" title="<?= I18N::translate('Children') ?>"></i></th> 197 <th><?= I18N::translate('Last change') ?></th> 198 <th hidden></th> 199 <th hidden></th> 200 <th hidden></th> 201 </tr> 202 </thead> 203 204 <tfoot> 205 <tr> 206 <th colspan="14"> 207 <div class="btn-toolbar"> 208 <div class="btn-group"> 209 <button class="ui-state-default btn-toggle-parents"> 210 <?= I18N::translate('Show parents') ?> 211 </button> 212 <button class="ui-state-default btn-toggle-statistics"> 213 <?= I18N::translate('Show statistics charts') ?> 214 </button> 215 </div> 216 </div> 217 </th> 218 </tr> 219 </tfoot> 220 <tbody> 221 222 <?php foreach ($families as $family) : ?> 223 <?php $husb = $family->getHusband() ?? new Individual('H', '0 @H@ INDI', null, $family->getTree()) ?> 224 <?php $wife = $family->getWife() ?? new Individual('W', '0 @W@ INDI', null, $family->getTree()) ?> 225 226 <tr class="<?= $family->isPendingDeletion() ? 'old' : ($family->isPendingAddition() ? 'new' : '') ?>"> 227 <!-- Husband name --> 228 <td colspan="2" data-sort="<?= e(str_replace([',', '@P.N.', '@N.N.'], 'AAAA', implode(',', array_reverse(explode(',', $husb->getSortName()))))) ?>"> 229 <?php foreach ($husb->getAllNames() as $num => $name) : ?> 230 <?php if ($name['type'] != '_MARNM' || $num == $husb->getPrimaryName()) : ?> 231 <a title="<?= $name['type'] === 'NAME' ? '' : GedcomTag::getLabel($name['type'], $husb) ?>" href="<?= e($family->url()) ?>" class="<?= $num === $husb->getPrimaryName() ? 'name2' : '' ?>"> 232 <?= $name['full'] ?> 233 </a> 234 <?php if ($num === $husb->getPrimaryName()) : ?> 235 <?= $husb->getSexImage() ?> 236 <?php endif ?> 237 <br> 238 <?php endif ?> 239 <?php endforeach ?> 240 <?= $husb->getPrimaryParentsNames('parents details1', 'none') ?> 241 </td> 242 243 <td hidden data-sort="<?= e(str_replace([',', '@P.N.', '@N.N.'], 'AAAA', $husb->getSortName())) ?>"></td> 244 245 <!-- Husband age --> 246 <?php 247 $mdate = $family->getMarriageDate(); 248 $hdate = $husb->getBirthDate(); 249 if ($hdate->isOK() && $mdate->isOK()) { 250 if ($hdate->gregorianYear() >= 1550 && $hdate->gregorianYear() < 2030) { 251 $birt_by_decade[(int) ($hdate->gregorianYear() / 10) * 10] .= $husb->getSex(); 252 } 253 $hage = Date::getAgeYears($hdate, $mdate); 254 if ($hage >= 0 && $hage <= $max_age) { 255 $marr_by_age[$hage] .= $husb->getSex(); 256 } 257 } 258 ?> 259 <td class="center" data-sort="<?= Date::getAgeDays($hdate, $mdate) ?>"> 260 <?= Date::getAge($hdate, $mdate) ?> 261 </td> 262 263 <!-- Wife name --> 264 <td colspan="2" data-sort="<?= e(str_replace([',', '@P.N.', '@N.N.'], 'AAAA', implode(',', array_reverse(explode(',', $wife->getSortName()))))) ?>"> 265 <?php foreach ($wife->getAllNames() as $num => $name) : ?> 266 <?php if ($name['type'] != '_MARNM' || $num == $wife->getPrimaryName()) : ?> 267 <a title="<?= $name['type'] === 'NAME' ? '' : GedcomTag::getLabel($name['type'], $wife) ?>" href="<?= e($family->url()) ?>" class="<?= $num === $wife->getPrimaryName() ? 'name2' : '' ?>"> 268 <?= $name['full'] ?> 269 </a> 270 <?php if ($num === $wife->getPrimaryName()) : ?> 271 <?= $wife->getSexImage() ?> 272 <?php endif ?> 273 <br> 274 <?php endif ?> 275 <?php endforeach ?> 276 <?= $wife->getPrimaryParentsNames('parents details1', 'none') ?> 277 </td> 278 279 <td hidden data-sort="<?= e(str_replace([',', '@P.N.', '@N.N.'], 'AAAA', $wife->getSortName())) ?>"></td> 280 281 <!-- Wife age --> 282 <?php 283 $wdate = $wife->getBirthDate(); 284 if ($wdate->isOK() && $mdate->isOK()) { 285 if ($wdate->gregorianYear() >= 1550 && $wdate->gregorianYear() < 2030) { 286 $birt_by_decade[(int) ($wdate->gregorianYear() / 10) * 10] .= $wife->getSex(); 287 } 288 $wage = Date::getAgeYears($wdate, $mdate); 289 if ($wage >= 0 && $wage <= $max_age) { 290 $marr_by_age[$wage] .= $wife->getSex(); 291 } 292 } 293 ?> 294 295 <td class="center" data-sort="<?= Date::getAgeDays($wdate, $mdate) ?>"> 296 <?= Date::getAge($wdate, $mdate) ?> 297 </td> 298 299 <!-- Marriage date --> 300 <td data-sort="<?= $family->getMarriageDate()->julianDay() ?>"> 301 <?php if ($marriage_dates = $family->getAllMarriageDates()) : ?> 302 <?php foreach ($marriage_dates as $n => $marriage_date) : ?> 303 <div><?= $marriage_date->display(true) ?></div> 304 <?php endforeach ?> 305 <?php if ($marriage_dates[0]->gregorianYear() >= 1550 && $marriage_dates[0]->gregorianYear() < 2030) : ?> 306 <?php $marr_by_decade[(int) ($marriage_dates[0]->gregorianYear() / 10) * 10] .= $husb->getSex() . $wife->getSex() ?> 307 <?php endif ?> 308 <?php elseif ($family->getFacts('_NMR')) : ?> 309 <?= I18N::translate('no') ?> 310 <?php elseif ($family->getFacts('MARR')) : ?> 311 <?= I18N::translate('yes') ?> 312 <?php endif ?> 313 </td> 314 315 <!-- Marriage anniversary --> 316 <td class="center" data-sort="<?= -$family->getMarriageDate()->julianDay() ?>"> 317 <?= Date::getAge($family->getMarriageDate(), null) ?> 318 </td> 319 320 <!-- Marriage place --> 321 <td> 322 <?php foreach ($family->getAllMarriagePlaces() as $n => $marriage_place) : ?> 323 <a href="<?= $marriage_place->getURL() ?>" title="<?= strip_tags($marriage_place->getFullName()) ?>"> 324 <?= $marriage_place->getShortName() ?> 325 </a> 326 <br> 327 <?php endforeach ?> 328 </td> 329 330 <!-- Number of children --> 331 <td class="center" data-sort="<?= $family->getNumberOfChildren() ?>"> 332 <?= I18N::number($family->getNumberOfChildren()) ?> 333 </td> 334 335 <!-- Last change --> 336 <td data-sort="<?= $family->lastChangeTimestamp(true) ?>"> 337 <?= $family->lastChangeTimestamp() ?> 338 </td> 339 340 <!-- Filter by marriage date --> 341 <td hidden> 342 <?php if (!$family->canShow() || !$mdate->isOK()) : ?> 343 U 344 <?php elseif (Date::compare($mdate, $hundred_years_ago) > 0) : ?> 345 Y100 346 <?php else : ?> 347 YES 348 <?php endif ?> 349 <?php if ($family->getFacts(WT_EVENTS_DIV)) : ?> 350 D 351 <?php endif ?> 352 <?php if (count($husb->getSpouseFamilies()) > 1 || count($wife->getSpouseFamilies()) > 1) : ?> 353 M 354 <?php endif ?> 355 </td> 356 357 <!-- Filter by alive/dead --> 358 <td hidden> 359 <?php if ($husb->isDead() && $wife->isDead()) : ?> 360 Y 361 <?php endif ?> 362 <?php if ($husb->isDead() && !$wife->isDead()) : ?> 363 <?php if ($wife->getSex() == 'F') : ?> 364 H 365 <?php endif ?> 366 <?php if ($wife->getSex() == 'M') : ?> 367 W 368 <?php endif ?> 369 <?php endif ?> 370 <?php if (!$husb->isDead() && $wife->isDead()) : ?> 371 <?php if ($husb->getSex() == 'M') : ?> 372 W 373 <?php endif ?> 374 <?php if ($husb->getSex() == 'F') : ?> 375 H 376 <?php endif ?> 377 <?php endif ?> 378 <?php if (!$husb->isDead() && !$wife->isDead()) : ?> 379 N 380 <?php endif ?> 381 </td> 382 383 <!-- Filter by roots/leaves --> 384 <td hidden> 385 <?php if (!$husb->getChildFamilies() && !$wife->getChildFamilies()) : ?> 386 R 387 <?php elseif (!$husb->isDead() && !$wife->isDead() && $family->getNumberOfChildren() === 0) : ?> 388 L 389 <?php endif ?> 390 </td> 391 </tr> 392 <?php endforeach ?> 393 </tbody> 394 </table> 395 396 <div id="family-charts-<?= e($table_id) ?>" style="display:none"> 397 <table class="list-charts"> 398 <tr> 399 <td> 400 <?= view('lists/chart-by-decade', ['data' => $birt_by_decade, 'title' => I18N::translate('Decade of birth')]) ?> 401 </td> 402 <td> 403 <?= view('lists/chart-by-decade', ['data' => $marr_by_decade, 'title' => I18N::translate('Decade of marriage')]) ?> 404 </td> 405 </tr> 406 <tr> 407 <td colspan="2"> 408 <?= view('lists/chart-by-age', ['data' => $marr_by_age, 'title' => I18N::translate('Age in year of marriage')]) ?> 409 </td> 410 </tr> 411 </table> 412 </div> 413</div> 414