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