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> 196 <span title="<?= I18N::translate('Anniversary') ?>"> 197 <?= view('icons/anniversary') ?> 198 </span> 199 </th> 200 <th><?= I18N::translate('Place') ?></th> 201 <th><i class="icon-children" title="<?= I18N::translate('Children') ?>"></i></th> 202 <th><?= I18N::translate('Last change') ?></th> 203 <th hidden></th> 204 <th hidden></th> 205 <th hidden></th> 206 </tr> 207 </thead> 208 209 <tfoot> 210 <tr> 211 <th colspan="14"> 212 <div class="btn-toolbar"> 213 <div class="btn-group"> 214 <button class="ui-state-default btn-toggle-parents"> 215 <?= I18N::translate('Show parents') ?> 216 </button> 217 <button class="ui-state-default btn-toggle-statistics"> 218 <?= I18N::translate('Show statistics charts') ?> 219 </button> 220 </div> 221 </div> 222 </th> 223 </tr> 224 </tfoot> 225 <tbody> 226 227 <?php foreach ($families as $family) : ?> 228 <?php $husb = $family->getHusband() ?? new Individual('H', '0 @H@ INDI', null, $family->tree()) ?> 229 <?php $wife = $family->getWife() ?? new Individual('W', '0 @W@ INDI', null, $family->tree()) ?> 230 231 <tr class="<?= $family->isPendingDeletion() ? 'old' : ($family->isPendingAddition() ? 'new' : '') ?>"> 232 <!-- Husband name --> 233 <td colspan="2" data-sort="<?= e(str_replace([',', '@P.N.', '@N.N.'], 'AAAA', implode(',', array_reverse(explode(',', $husb->getSortName()))))) ?>"> 234 <?php foreach ($husb->getAllNames() as $num => $name) : ?> 235 <?php if ($name['type'] != '_MARNM' || $num == $husb->getPrimaryName()) : ?> 236 <a title="<?= $name['type'] === 'NAME' ? '' : GedcomTag::getLabel($name['type'], $husb) ?>" href="<?= e($family->url()) ?>" class="<?= $num === $husb->getPrimaryName() ? 'name2' : '' ?>"> 237 <?= $name['full'] ?> 238 </a> 239 <?php if ($num === $husb->getPrimaryName()) : ?> 240 <?= $husb->getSexImage() ?> 241 <?php endif ?> 242 <br> 243 <?php endif ?> 244 <?php endforeach ?> 245 <?= $husb->getPrimaryParentsNames('parents details1', 'none') ?> 246 </td> 247 248 <td hidden data-sort="<?= e(str_replace([',', '@P.N.', '@N.N.'], 'AAAA', $husb->getSortName())) ?>"></td> 249 250 <!-- Husband age --> 251 <?php 252 $mdate = $family->getMarriageDate(); 253 $hdate = $husb->getBirthDate(); 254 if ($hdate->isOK() && $mdate->isOK()) { 255 if ($hdate->gregorianYear() >= 1550 && $hdate->gregorianYear() < 2030) { 256 $birt_by_decade[(int) ($hdate->gregorianYear() / 10) * 10] .= $husb->getSex(); 257 } 258 $hage = Date::getAgeYears($hdate, $mdate); 259 if ($hage >= 0 && $hage <= $max_age) { 260 $marr_by_age[$hage] .= $husb->getSex(); 261 } 262 } 263 ?> 264 <td class="center" data-sort="<?= Date::getAgeDays($hdate, $mdate) ?>"> 265 <?= Date::getAge($hdate, $mdate) ?> 266 </td> 267 268 <!-- Wife name --> 269 <td colspan="2" data-sort="<?= e(str_replace([',', '@P.N.', '@N.N.'], 'AAAA', implode(',', array_reverse(explode(',', $wife->getSortName()))))) ?>"> 270 <?php foreach ($wife->getAllNames() as $num => $name) : ?> 271 <?php if ($name['type'] != '_MARNM' || $num == $wife->getPrimaryName()) : ?> 272 <a title="<?= $name['type'] === 'NAME' ? '' : GedcomTag::getLabel($name['type'], $wife) ?>" href="<?= e($family->url()) ?>" class="<?= $num === $wife->getPrimaryName() ? 'name2' : '' ?>"> 273 <?= $name['full'] ?> 274 </a> 275 <?php if ($num === $wife->getPrimaryName()) : ?> 276 <?= $wife->getSexImage() ?> 277 <?php endif ?> 278 <br> 279 <?php endif ?> 280 <?php endforeach ?> 281 <?= $wife->getPrimaryParentsNames('parents details1', 'none') ?> 282 </td> 283 284 <td hidden data-sort="<?= e(str_replace([',', '@P.N.', '@N.N.'], 'AAAA', $wife->getSortName())) ?>"></td> 285 286 <!-- Wife age --> 287 <?php 288 $wdate = $wife->getBirthDate(); 289 if ($wdate->isOK() && $mdate->isOK()) { 290 if ($wdate->gregorianYear() >= 1550 && $wdate->gregorianYear() < 2030) { 291 $birt_by_decade[(int) ($wdate->gregorianYear() / 10) * 10] .= $wife->getSex(); 292 } 293 $wage = Date::getAgeYears($wdate, $mdate); 294 if ($wage >= 0 && $wage <= $max_age) { 295 $marr_by_age[$wage] .= $wife->getSex(); 296 } 297 } 298 ?> 299 300 <td class="center" data-sort="<?= Date::getAgeDays($wdate, $mdate) ?>"> 301 <?= Date::getAge($wdate, $mdate) ?> 302 </td> 303 304 <!-- Marriage date --> 305 <td data-sort="<?= $family->getMarriageDate()->julianDay() ?>"> 306 <?php if ($marriage_dates = $family->getAllMarriageDates()) : ?> 307 <?php foreach ($marriage_dates as $n => $marriage_date) : ?> 308 <div><?= $marriage_date->display(true) ?></div> 309 <?php endforeach ?> 310 <?php if ($marriage_dates[0]->gregorianYear() >= 1550 && $marriage_dates[0]->gregorianYear() < 2030) : ?> 311 <?php $marr_by_decade[(int) ($marriage_dates[0]->gregorianYear() / 10) * 10] .= $husb->getSex() . $wife->getSex() ?> 312 <?php endif ?> 313 <?php elseif ($family->facts(['_NMR'])) : ?> 314 <?= I18N::translate('no') ?> 315 <?php elseif ($family->facts(['MARR'])) : ?> 316 <?= I18N::translate('yes') ?> 317 <?php endif ?> 318 </td> 319 320 <!-- Marriage anniversary --> 321 <td class="center" data-sort="<?= -$family->getMarriageDate()->julianDay() ?>"> 322 <?= Date::getAge($family->getMarriageDate(), null) ?> 323 </td> 324 325 <!-- Marriage place --> 326 <td> 327 <?php foreach ($family->getAllMarriagePlaces() as $n => $marriage_place) : ?> 328 <?= $marriage_place->shortName(true) ?> 329 <br> 330 <?php endforeach ?> 331 </td> 332 333 <!-- Number of children --> 334 <td class="center" data-sort="<?= $family->getNumberOfChildren() ?>"> 335 <?= I18N::number($family->getNumberOfChildren()) ?> 336 </td> 337 338 <!-- Last change --> 339 <td data-sort="<?= $family->lastChangeTimestamp(true) ?>"> 340 <?= $family->lastChangeTimestamp() ?> 341 </td> 342 343 <!-- Filter by marriage date --> 344 <td hidden> 345 <?php if (!$family->canShow() || !$mdate->isOK()) : ?> 346 U 347 <?php elseif (Date::compare($mdate, $hundred_years_ago) > 0) : ?> 348 Y100 349 <?php else : ?> 350 YES 351 <?php endif ?> 352 <?php if ($family->facts(Gedcom::DIVORCE_EVENTS)) : ?> 353 D 354 <?php endif ?> 355 <?php if (count($husb->getSpouseFamilies()) > 1 || count($wife->getSpouseFamilies()) > 1) : ?> 356 M 357 <?php endif ?> 358 </td> 359 360 <!-- Filter by alive/dead --> 361 <td hidden> 362 <?php if ($husb->isDead() && $wife->isDead()) : ?> 363 Y 364 <?php endif ?> 365 <?php if ($husb->isDead() && !$wife->isDead()) : ?> 366 <?php if ($wife->getSex() == 'F') : ?> 367 H 368 <?php endif ?> 369 <?php if ($wife->getSex() == 'M') : ?> 370 W 371 <?php endif ?> 372 <?php endif ?> 373 <?php if (!$husb->isDead() && $wife->isDead()) : ?> 374 <?php if ($husb->getSex() == 'M') : ?> 375 W 376 <?php endif ?> 377 <?php if ($husb->getSex() == 'F') : ?> 378 H 379 <?php endif ?> 380 <?php endif ?> 381 <?php if (!$husb->isDead() && !$wife->isDead()) : ?> 382 N 383 <?php endif ?> 384 </td> 385 386 <!-- Filter by roots/leaves --> 387 <td hidden> 388 <?php if (!$husb->getChildFamilies() && !$wife->getChildFamilies()) : ?> 389 R 390 <?php elseif (!$husb->isDead() && !$wife->isDead() && $family->getNumberOfChildren() === 0) : ?> 391 L 392 <?php endif ?> 393 </td> 394 </tr> 395 <?php endforeach ?> 396 </tbody> 397 </table> 398 399 <div id="family-charts-<?= e($table_id) ?>" style="display:none"> 400 <table class="list-charts"> 401 <tr> 402 <td> 403 <?= view('lists/chart-by-decade', ['data' => $birt_by_decade, 'title' => I18N::translate('Decade of birth')]) ?> 404 </td> 405 <td> 406 <?= view('lists/chart-by-decade', ['data' => $marr_by_decade, 'title' => I18N::translate('Decade of marriage')]) ?> 407 </td> 408 </tr> 409 <tr> 410 <td colspan="2"> 411 <?= view('lists/chart-by-age', ['data' => $marr_by_age, 'title' => I18N::translate('Age in year of marriage')]) ?> 412 </td> 413 </tr> 414 </table> 415 </div> 416</div> 417