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