/** * Generate the HTML content of this block. * * @param int $block_id * @param bool $template * @param string[] $cfg * * @return string */ public function getBlock($block_id, $template = true, $cfg = array()) { global $WT_TREE, $ctype; $show_last_update = $this->getBlockSetting($block_id, 'show_last_update', '1'); $show_common_surnames = $this->getBlockSetting($block_id, 'show_common_surnames', '1'); $stat_indi = $this->getBlockSetting($block_id, 'stat_indi', '1'); $stat_fam = $this->getBlockSetting($block_id, 'stat_fam', '1'); $stat_sour = $this->getBlockSetting($block_id, 'stat_sour', '1'); $stat_media = $this->getBlockSetting($block_id, 'stat_media', '1'); $stat_repo = $this->getBlockSetting($block_id, 'stat_repo', '1'); $stat_surname = $this->getBlockSetting($block_id, 'stat_surname', '1'); $stat_events = $this->getBlockSetting($block_id, 'stat_events', '1'); $stat_users = $this->getBlockSetting($block_id, 'stat_users', '1'); $stat_first_birth = $this->getBlockSetting($block_id, 'stat_first_birth', '1'); $stat_last_birth = $this->getBlockSetting($block_id, 'stat_last_birth', '1'); $stat_first_death = $this->getBlockSetting($block_id, 'stat_first_death', '1'); $stat_last_death = $this->getBlockSetting($block_id, 'stat_last_death', '1'); $stat_long_life = $this->getBlockSetting($block_id, 'stat_long_life', '1'); $stat_avg_life = $this->getBlockSetting($block_id, 'stat_avg_life', '1'); $stat_most_chil = $this->getBlockSetting($block_id, 'stat_most_chil', '1'); $stat_avg_chil = $this->getBlockSetting($block_id, 'stat_avg_chil', '1'); // This can be overriden when embedding in an HTML block $block = '0'; $stat_link = '1'; foreach (array('show_common_surnames', 'stat_indi', 'stat_fam', 'stat_sour', 'stat_media', 'stat_surname', 'stat_events', 'stat_users', 'stat_first_birth', 'stat_last_birth', 'stat_first_death', 'stat_last_death', 'stat_long_life', 'stat_avg_life', 'stat_most_chil', 'stat_avg_chil', 'stat_link', 'block') as $name) { if (array_key_exists($name, $cfg)) { ${$name} = $cfg[$name]; } } $id = $this->getName() . $block_id; $class = $this->getName() . '_block'; if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) { $title = '<a class="icon-admin" title="' . I18N::translate('Configure') . '" href="block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype . '"></a>'; } else { $title = ''; } $title .= $this->getTitle(); $stats = new Stats($WT_TREE); $content = '<b>' . $WT_TREE->getTitleHtml() . '</b><br>'; if ($show_last_update) { $content .= '<div>' . I18N::translate('This family tree was last updated on %s.', strip_tags($stats->gedcomUpdated())) . '</div>'; } /** Responsive Design */ $content .= '<div class="stat-table1">'; if ($stat_indi) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Individuals') . '</div><div class="facts_value stats_value stat-cell"><a href="' . "indilist.php?surname_sublist=no&ged=" . $WT_TREE->getNameUrl() . '">' . $stats->totalIndividuals() . '</a></div></div>'; $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Males') . '</div><div class="facts_value stats_value stat-cell">' . $stats->totalSexMales() . '<br>' . $stats->totalSexMalesPercentage() . '</div></div>'; $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Females') . '</div><div class="facts_value stats_value stat-cell">' . $stats->totalSexFemales() . '<br>' . $stats->totalSexFemalesPercentage() . '</div></div>'; } if ($stat_surname) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Total surnames') . '</div><div class="facts_value stats_value stat-cell"><a href="indilist.php?show_all=yes&surname_sublist=yes&ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalSurnames() . '</a></div></div>'; } if ($stat_fam) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Families') . '</div><div class="facts_value stats_value stat-cell"><a href="famlist.php?ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalFamilies() . '</a></div></div>'; } if ($stat_sour) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Sources') . '</div><div class="facts_value stats_value stat-cell"><a href="sourcelist.php?ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalSources() . '</a></div></div>'; } if ($stat_media) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Media objects') . '</div><div class="facts_value stats_value stat-cell"><a href="medialist.php?ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalMedia() . '</a></div></div>'; } if ($stat_repo) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Repositories') . '</div><div class="facts_value stats_value stat-cell"><a href="repolist.php?ged=' . $WT_TREE->getNameUrl() . '">' . $stats->totalRepositories() . '</a></div></div>'; } if ($stat_events) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Total events') . '</div><div class="facts_value stats_value stat-cell">' . $stats->totalEvents() . '</div></div>'; } if ($stat_users) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Total users') . '</div><div class="facts_value stats_value stat-cell">'; if (Auth::isManager($WT_TREE)) { $content .= '<a href="admin_users.php">' . $stats->totalUsers() . '</a>'; } else { $content .= $stats->totalUsers(); } $content .= '</div></div>'; } if (!$block) { $content .= '</div><div class="facts_table stat-table2">'; } if ($stat_first_birth) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Earliest birth year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->firstBirthYear() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->firstBirth() . '</div>'; } $content .= '</div>'; } if ($stat_last_birth) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Latest birth year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->lastBirthYear() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->lastBirth() . '</div>'; } $content .= '</div>'; } if ($stat_first_death) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Earliest death year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->firstDeathYear() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->firstDeath() . '</div>'; } $content .= '</div>'; } if ($stat_last_death) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Latest death year') . '</div><div class="facts_value stats_value stat-cell">' . $stats->lastDeathYear() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->lastDeath() . '</div>'; } $content .= '</div>'; } if ($stat_long_life) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Individual who lived the longest') . '</div><div class="facts_value stats_value stat-cell">' . $stats->LongestLifeAge() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->LongestLife() . '</div>'; } $content .= '</div>'; } if ($stat_avg_life) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Average age at death') . '</div><div class="facts_value stats_value stat-cell">' . $stats->averageLifespan() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . I18N::translate('Males') . ': ' . $stats->averageLifespanMale(); $content .= ' ' . I18N::translate('Females') . ': ' . $stats->averageLifespanFemale() . '</div>'; } $content .= '</div>'; } if ($stat_most_chil && !$block) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Family with the most children') . '</div><div class="facts_value stats_value stat-cell">' . $stats->largestFamilySize() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left">' . $stats->largestFamily() . '</div>'; } $content .= '</div>'; } if ($stat_avg_chil) { $content .= '<div class="stat-row"><div class="facts_label stat-cell">' . I18N::translate('Average number of children per family') . '</div><div class="facts_value stats_value stat-cell">' . $stats->averageChildren() . '</div>'; if (!$block) { $content .= '<div class="facts_value stat-cell left"></div>'; } $content .= '</div>'; } if ($stat_link) { $content .= '</div><div class="clearfloat"><a href="statistics.php?ged=' . $WT_TREE->getNameUrl() . '" rel="nofollow"><b>' . I18N::translate('View statistics as graphs') . '</b></a></div>'; } // NOTE: Print the most common surnames if ($show_common_surnames) { $surnames = FunctionsDb::getCommonSurnames($WT_TREE->getPreference('COMMON_NAMES_THRESHOLD'), $WT_TREE); if (count($surnames) > 0) { $content .= '<p><b>' . I18N::translate('Most common surnames') . '</b></p>'; $content .= '<div class="common_surnames">'; $i = 0; foreach ($surnames as $indexval => $surname) { if (stristr($surname['name'], '@N.N') === false) { if ($i > 0) { $content .= ', '; } $content .= '<a href="' . "indilist.php?ged=" . $WT_TREE->getNameUrl() . "&surname=" . rawurlencode($surname['name']) . '">' . $surname['name'] . '</a>'; $i++; } } } } if ($template) { return Theme::theme()->formatBlock($id, $title, $class, $content); } else { return $content; } }
/** * Render the Ajax response for the sortable table of Sosa individuals * @param AjaxController $controller */ protected function renderSosaListIndi(AjaxController $controller) { global $WT_TREE; $listSosa = $this->sosa_provider->getSosaListAtGeneration($this->generation); $this->view_bag->set('has_sosa', false); if (count($listSosa) > 0) { $this->view_bag->set('has_sosa', true); $table_id = 'table-sosa-indi-' . Uuid::uuid4(); $this->view_bag->set('table_id', $table_id); $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addInlineJavascript(' jQuery.fn.dataTableExt.oSort["unicode-asc" ]=function(a,b) {return a.replace(/<[^<]*>/, "").localeCompare(b.replace(/<[^<]*>/, ""))}; jQuery.fn.dataTableExt.oSort["unicode-desc" ]=function(a,b) {return b.replace(/<[^<]*>/, "").localeCompare(a.replace(/<[^<]*>/, ""))}; jQuery.fn.dataTableExt.oSort["num-html-asc" ]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a<b) ? -1 : (a>b ? 1 : 0);}; jQuery.fn.dataTableExt.oSort["num-html-desc"]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a>b) ? -1 : (a<b ? 1 : 0);}; jQuery("#' . $table_id . '").dataTable( { dom: \'<"H"<"filtersH_' . $table_id . '">T<"dt-clear">pf<"dt-clear">irl>t<"F"pl<"dt-clear"><"filtersF_' . $table_id . '">>\', ' . I18N::datatablesI18N() . ', jQueryUI: true, autoWidth: false, processing: true, retrieve: true, columns: [ /* 0-Sosa */ { type: "num", class: "center" }, /* 1-ID */ { visible: false }, /* 2-givn */ { dataSort: 4, class: "left"}, /* 3-surn */ { datasort: 5}, /* 4-GIVN,SURN */ { type: "unicode", visible: false}, /* 5-SURN,GIVN */ { type: "unicode", visible: false}, /* 6-Birth */ { dataSort : 7 , class: "center"}, /* 7-SORT_BIRT */ { visible : false}, /* 8-BIRT_PLAC */ { type: "unicode", class: "center"}, /* PERSO Modify table to include IsSourced module */ /* 9-BIRT_SOUR */ { dataSort : 10, class: "center", visible: ' . (ModuleManager::getInstance()->isOperational(Constants::MODULE_MAJ_ISSOURCED_NAME) ? 'true' : 'false') . ' }, /* 10-SORT_BIRTSC */{ visible : false}, /* 11-Death */ { dataSort : 12 , class: "center"}, /* 12-SORT_DEAT */ { visible : false}, /* 13-Age */ { dataSort : 14 , class: "center"}, /* 14-AGE */ { type: "num", visible: false}, /* 15-DEAT_PLAC */ { type: "unicode", class: "center" }, /* 16-DEAT_SOUR */ { dataSort : 17, class: "center", visible: ' . (ModuleManager::getInstance()->isOperational(Constants::MODULE_MAJ_ISSOURCED_NAME) ? 'true' : 'false') . ' }, /* 17-SORT_DEATSC */{ visible : false}, /* 18-SEX */ { visible : false}, /* 19-BIRT */ { visible : false}, /* 20-DEAT */ { visible : false}, /* 21-TREE */ { visible : false} /* END PERSO */ ], sorting: [[0,"asc"]], displayLength: 16, pagingType: "full_numbers" }); jQuery("#' . $table_id . '") /* Hide/show parents */ .on("click", ".btn-toggle-parents", function() { jQuery(this).toggleClass("ui-state-active"); jQuery(".parents", jQuery(this).closest("table").DataTable().rows().nodes()).slideToggle(); }) /* Hide/show statistics */ .on("click", ".btn-toggle-statistics", function() { jQuery(this).toggleClass("ui-state-active"); jQuery("#indi_list_table-charts_' . $table_id . '").slideToggle(); }) /* Filter buttons in table header */ .on("click", "button[data-filter-column]", function() { var btn = jQuery(this); // De-activate the other buttons in this button group btn.siblings().removeClass("ui-state-active"); // Apply (or clear) this filter var col = jQuery("#' . $table_id . '").DataTable().column(btn.data("filter-column")); if (btn.hasClass("ui-state-active")) { btn.removeClass("ui-state-active"); col.search("").draw(); } else { btn.addClass("ui-state-active"); col.search(btn.data("filter-value")).draw(); } }); jQuery("#sosa-indi-list").css("visibility", "visible"); jQuery("#btn-toggle-statistics-' . $table_id . '").click(); '); $stats = new Stats($WT_TREE); // Bad data can cause "longest life" to be huge, blowing memory limits $max_age = min($WT_TREE->getPreference('MAX_ALIVE_AGE'), $stats->LongestLifeAge()) + 1; // Inititialise chart data $deat_by_age = array(); for ($age = 0; $age <= $max_age; $age++) { $deat_by_age[$age] = ''; } $birt_by_decade = array(); $deat_by_decade = array(); for ($year = 1550; $year < 2030; $year += 10) { $birt_by_decade[$year] = ''; $deat_by_decade[$year] = ''; } $unique_indis = array(); // Don't double-count indis with multiple names. $nb_displayed = 0; Individual::load($WT_TREE, $listSosa); foreach ($listSosa as $sosa => $pid) { $person = Individual::getInstance($pid, $WT_TREE); if (!$person || !$person->canShowName()) { unset($listSosa[$sosa]); continue; } $nb_displayed++; if ($birth_dates = $person->getAllBirthDates()) { if (FunctionsPrint::isDateWithinChartsRange($birth_dates[0]) && !isset($unique_indis[$person->getXref()])) { $birt_by_decade[(int) ($birth_dates[0]->gregorianYear() / 10) * 10] .= $person->getSex(); } } else { $birth_dates[0] = new Date(''); } if ($death_dates = $person->getAllDeathDates()) { if (FunctionsPrint::isDateWithinChartsRange($death_dates[0]) && !isset($unique_indis[$person->getXref()])) { $deat_by_decade[(int) ($death_dates[0]->gregorianYear() / 10) * 10] .= $person->getSex(); } } else { $death_dates[0] = new Date(''); } $age = Date::getAge($birth_dates[0], $death_dates[0], 0); if (!isset($unique_indis[$person->getXref()]) && $age >= 0 && $age <= $max_age) { $deat_by_age[$age] .= $person->getSex(); } $listSosa[$sosa] = $person; $unique_indis[$person->getXref()] = true; } $this->view_bag->set('sosa_list', $listSosa); $this->view_bag->set('sosa_count', count($listSosa)); $this->view_bag->set('sosa_theo', pow(2, $this->generation - 1)); $this->view_bag->set('sosa_ratio', Functions::safeDivision($this->view_bag->get('sosa_count'), $this->view_bag->get('sosa_theo'))); $this->view_bag->set('sosa_hidden', $this->view_bag->get('sosa_count') - $nb_displayed); $this->view_bag->set('chart_births', FunctionsPrintLists::chartByDecade($birt_by_decade, I18N::translate('Decade of birth'))); $this->view_bag->set('chart_deaths', FunctionsPrintLists::chartByDecade($deat_by_decade, I18N::translate('Decade of death'))); $this->view_bag->set('chart_ages', FunctionsPrintLists::chartByAge($deat_by_age, I18N::translate('Age related to death year'))); } ViewFactory::make('SosaListIndi', $this, $controller, $this->view_bag)->render(); }
/** * Print a table of individuals * * @param Individual[] $datalist * @param string $option * * @return string */ public static function individualTable($datalist, $option = '') { global $controller, $WT_TREE; $table_id = 'table-indi-' . Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addInlineJavascript(' jQuery.fn.dataTableExt.oSort["unicode-asc" ]=function(a,b) {return a.replace(/<[^<]*>/, "").localeCompare(b.replace(/<[^<]*>/, ""))}; jQuery.fn.dataTableExt.oSort["unicode-desc" ]=function(a,b) {return b.replace(/<[^<]*>/, "").localeCompare(a.replace(/<[^<]*>/, ""))}; jQuery.fn.dataTableExt.oSort["num-html-asc" ]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a<b) ? -1 : (a>b ? 1 : 0);}; jQuery.fn.dataTableExt.oSort["num-html-desc"]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a>b) ? -1 : (a<b ? 1 : 0);}; jQuery("#' . $table_id . '").dataTable( { dom: \'<"H"<"filtersH_' . $table_id . '">T<"dt-clear">pf<"dt-clear">irl>t<"F"pl<"dt-clear"><"filtersF_' . $table_id . '">>\', ' . I18N::datatablesI18N() . ', jQueryUI: true, autoWidth: false, processing: true, retrieve: true, columns: [ /* 0 givn */ { dataSort: 2 }, /* 1 surn */ { dataSort: 3 }, /* 2 GIVN,SURN */ { type: "unicode", visible: false }, /* 3 SURN,GIVN */ { type: "unicode", visible: false }, /* 4 sosa */ { dataSort: 5, class: "center", visible: ' . ($option == 'sosa' ? 'true' : 'false') . ' }, /* 5 SOSA */ { type: "num", visible: false }, /* 6 birt date */ { dataSort: 7 }, /* 7 BIRT:DATE */ { visible: false }, /* 8 anniv */ { dataSort: 7, class: "center" }, /* 9 birt plac */ { type: "unicode" }, /* 10 children */ { dataSort: 11, class: "center" }, /* 11 children */ { type: "num", visible: false }, /* 12 deat date */ { dataSort: 13 }, /* 13 DEAT:DATE */ { visible: false }, /* 14 anniv */ { dataSort: 13, class: "center" }, /* 15 age */ { dataSort: 16, class: "center" }, /* 16 AGE */ { type: "num", visible: false }, /* 17 deat plac */ { type: "unicode" }, /* 18 CHAN */ { dataSort: 19, visible: ' . ($WT_TREE->getPreference('SHOW_LAST_CHANGE') ? 'true' : 'false') . ' }, /* 19 CHAN_sort */ { visible: false }, /* 20 SEX */ { visible: false }, /* 21 BIRT */ { visible: false }, /* 22 DEAT */ { visible: false }, /* 23 TREE */ { visible: false } ], sorting: [[' . ($option == 'sosa' ? '4, "asc"' : '1, "asc"') . ']], displayLength: 20, pagingType: "full_numbers" }); jQuery("#' . $table_id . '") /* Hide/show parents */ .on("click", ".btn-toggle-parents", function() { jQuery(this).toggleClass("ui-state-active"); jQuery(".parents", jQuery(this).closest("table").DataTable().rows().nodes()).slideToggle(); }) /* Hide/show statistics */ .on("click", ".btn-toggle-statistics", function() { jQuery(this).toggleClass("ui-state-active"); jQuery("#indi_list_table-charts_' . $table_id . '").slideToggle(); }) /* Filter buttons in table header */ .on("click", "button[data-filter-column]", function() { var btn = jQuery(this); // De-activate the other buttons in this button group btn.siblings().removeClass("ui-state-active"); // Apply (or clear) this filter var col = jQuery("#' . $table_id . '").DataTable().column(btn.data("filter-column")); if (btn.hasClass("ui-state-active")) { btn.removeClass("ui-state-active"); col.search("").draw(); } else { btn.addClass("ui-state-active"); col.search(btn.data("filter-value")).draw(); } }); jQuery(".indi-list").css("visibility", "visible"); jQuery(".loading-image").css("display", "none"); '); $stats = new Stats($WT_TREE); // Bad data can cause "longest life" to be huge, blowing memory limits $max_age = min($WT_TREE->getPreference('MAX_ALIVE_AGE'), $stats->LongestLifeAge()) + 1; // Inititialise chart data $deat_by_age = array(); for ($age = 0; $age <= $max_age; $age++) { $deat_by_age[$age] = ''; } $birt_by_decade = array(); $deat_by_decade = array(); for ($year = 1550; $year < 2030; $year += 10) { $birt_by_decade[$year] = ''; $deat_by_decade[$year] = ''; } $html = ' <div class="loading-image"> </div> <div class="indi-list"> <table id="' . $table_id . '"> <thead> <tr> <th colspan="24"> <div class="btn-toolbar"> <div class="btn-group"> <button class="ui-state-default" data-filter-column="20" data-filter-value="M" title="' . I18N::translate('Show only males.') . '" type="button" > ' . Individual::sexImage('M', 'large') . ' </button> <button class="ui-state-default" data-filter-column="20" data-filter-value="F" title="' . I18N::translate('Show only females.') . '" type="button" > ' . Individual::sexImage('F', 'large') . ' </button> <button class="ui-state-default" data-filter-column="20" data-filter-value="U" title="' . I18N::translate('Show only individuals for whom the gender is not known.') . '" type="button" > ' . Individual::sexImage('U', 'large') . ' </button> </div> <div class="btn-group"> <button class="ui-state-default" data-filter-column="22" data-filter-value="N" title="' . I18N::translate('Show individuals who are alive or couples where both partners are alive.') . '" type="button" > ' . I18N::translate('Alive') . ' </button> <button class="ui-state-default" data-filter-column="22" data-filter-value="Y" title="' . I18N::translate('Show individuals who are dead or couples where both partners are deceased.') . '" type="button" > ' . I18N::translate('Dead') . ' </button> <button class="ui-state-default" data-filter-column="22" data-filter-value="YES" title="' . I18N::translate('Show individuals who died more than 100 years ago.') . '" type="button" > ' . GedcomTag::getLabel('DEAT') . '>100 </button> <button class="ui-state-default" data-filter-column="22" data-filter-value="Y100" title="' . I18N::translate('Show individuals who died within the last 100 years.') . '" type="button" > ' . GedcomTag::getLabel('DEAT') . '<=100 </button> </div> <div class="btn-group"> <button class="ui-state-default" data-filter-column="21" data-filter-value="YES" title="' . I18N::translate('Show individuals born more than 100 years ago.') . '" type="button" > ' . GedcomTag::getLabel('BIRT') . '>100 </button> <button class="ui-state-default" data-filter-column="21" data-filter-value="Y100" title="' . I18N::translate('Show individuals born within the last 100 years.') . '" type="button" > ' . GedcomTag::getLabel('BIRT') . '<=100 </button> </div> <div class="btn-group"> <button class="ui-state-default" data-filter-column="23" data-filter-value="R" 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.') . '" type="button" > ' . I18N::translate('Roots') . ' </button> <button class="ui-state-default" data-filter-column="23" data-filter-value="L" title="' . I18N::translate('Show “leaves” couples or individuals. These are individuals who are alive but have no children recorded in the database.') . '" type="button" > ' . I18N::translate('Leaves') . ' </button> </div> </div> </th> </tr> <tr> <th>' . GedcomTag::getLabel('GIVN') . '</th> <th>' . GedcomTag::getLabel('SURN') . '</th> <th>GIVN</th> <th>SURN</th> <th>' . I18N::translate('Sosa') . '</th> <th>SOSA</th> <th>' . GedcomTag::getLabel('BIRT') . '</th> <th>SORT_BIRT</th> <th><i class="icon-reminder" title="' . I18N::translate('Anniversary') . '"></i></th> <th>' . GedcomTag::getLabel('PLAC') . '</th> <th><i class="icon-children" title="' . I18N::translate('Children') . '"></i></th> <th>NCHI</th> <th>' . GedcomTag::getLabel('DEAT') . '</th> <th>SORT_DEAT</th> <th><i class="icon-reminder" title="' . I18N::translate('Anniversary') . '"></i></th> <th>' . GedcomTag::getLabel('AGE') . '</th> <th>AGE</th> <th>' . GedcomTag::getLabel('PLAC') . '</th> <th>' . GedcomTag::getLabel('CHAN') . '</th> <th>CHAN</th> <th>SEX</th> <th>BIRT</th> <th>DEAT</th> <th>TREE</th> </tr> </thead> <tfoot> <tr> <th colspan="24"> <div class="btn-toolbar"> <div class="btn-group"> <button type="button" class="ui-state-default btn-toggle-parents"> ' . I18N::translate('Show parents') . ' </button> <button type="button" class="ui-state-default btn-toggle-statistics"> ' . I18N::translate('Show statistics charts') . ' </button> </div> </div> </th> </tr> </tfoot> <tbody>'; $d100y = new Date(date('Y') - 100); // 100 years ago $unique_indis = array(); // Don't double-count indis with multiple names. foreach ($datalist as $key => $person) { if (!$person->canShowName()) { continue; } if ($person->isPendingAddtion()) { $class = ' class="new"'; } elseif ($person->isPendingDeletion()) { $class = ' class="old"'; } else { $class = ''; } $html .= '<tr' . $class . '>'; //-- Indi name(s) $html .= '<td colspan="2">'; foreach ($person->getAllNames() as $num => $name) { if ($name['type'] == 'NAME') { $title = ''; } else { $title = 'title="' . strip_tags(GedcomTag::getLabel($name['type'], $person)) . '"'; } if ($num == $person->getPrimaryName()) { $class = ' class="name2"'; $sex_image = $person->getSexImage(); list($surn, $givn) = explode(',', $name['sort']); } else { $class = ''; $sex_image = ''; } $html .= '<a ' . $title . ' href="' . $person->getHtmlUrl() . '"' . $class . '>' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>' . $sex_image . '<br>'; } // Indi parents $html .= $person->getPrimaryParentsNames('parents details1', 'none'); $html .= '</td>'; // Dummy column to match colspan in header $html .= '<td style="display:none;"></td>'; //-- GIVN/SURN // Use "AAAA" as a separator (instead of ",") as Javascript.localeCompare() ignores // punctuation and "ANN,ROACH" would sort after "ANNE,ROACH", instead of before it. // Similarly, @N.N. would sort as NN. $html .= '<td>' . Filter::escapeHtml(str_replace('@P.N.', 'AAAA', $givn)) . 'AAAA' . Filter::escapeHtml(str_replace('@N.N.', 'AAAA', $surn)) . '</td>'; $html .= '<td>' . Filter::escapeHtml(str_replace('@N.N.', 'AAAA', $surn)) . 'AAAA' . Filter::escapeHtml(str_replace('@P.N.', 'AAAA', $givn)) . '</td>'; //-- SOSA if ($option == 'sosa') { $html .= '<td><a href="../../relationship.php?pid1=' . $datalist[1] . '&pid2=' . $person->getXref() . '" title="' . I18N::translate('Relationships') . '">' . I18N::number($key) . '</a></td><td>' . $key . '</td>'; } else { $html .= '<td></td><td>0</td>'; } //-- Birth date $html .= '<td>'; if ($birth_dates = $person->getAllBirthDates()) { foreach ($birth_dates as $num => $birth_date) { if ($num) { $html .= '<br>'; } $html .= $birth_date->display(true); } if ($birth_dates[0]->gregorianYear() >= 1550 && $birth_dates[0]->gregorianYear() < 2030 && !isset($unique_indis[$person->getXref()])) { $birt_by_decade[(int) ($birth_dates[0]->gregorianYear() / 10) * 10] .= $person->getSex(); } } else { $birth_date = $person->getEstimatedBirthDate(); if ($person->getTree()->getPreference('SHOW_EST_LIST_DATES')) { $html .= $birth_date->display(true); } else { $html .= ' '; } $birth_dates[0] = new Date(''); } $html .= '</td>'; //-- Event date (sortable)hidden by datatables code $html .= '<td>' . $birth_date->julianDay() . '</td>'; //-- Birth anniversary $html .= '<td>' . Date::getAge($birth_dates[0], null, 2) . '</td>'; //-- Birth place $html .= '<td>'; foreach ($person->getAllBirthPlaces() as $n => $birth_place) { $tmp = new Place($birth_place, $person->getTree()); if ($n) { $html .= '<br>'; } $html .= '<a href="' . $tmp->getURL() . '" title="' . strip_tags($tmp->getFullName()) . '">'; $html .= FunctionsPrint::highlightSearchHits($tmp->getShortName()) . '</a>'; } $html .= '</td>'; //-- Number of children $nchi = $person->getNumberOfChildren(); $html .= '<td>' . I18N::number($nchi) . '</td><td>' . $nchi . '</td>'; //-- Death date $html .= '<td>'; if ($death_dates = $person->getAllDeathDates()) { foreach ($death_dates as $num => $death_date) { if ($num) { $html .= '<br>'; } $html .= $death_date->display(true); } if ($death_dates[0]->gregorianYear() >= 1550 && $death_dates[0]->gregorianYear() < 2030 && !isset($unique_indis[$person->getXref()])) { $deat_by_decade[(int) ($death_dates[0]->gregorianYear() / 10) * 10] .= $person->getSex(); } } else { $death_date = $person->getEstimatedDeathDate(); // Estimated death dates are a fixed number of years after the birth date. // Don't show estimates in the future. if ($person->getTree()->getPreference('SHOW_EST_LIST_DATES') && $death_date->minimumJulianDay() < WT_CLIENT_JD) { $html .= $death_date->display(true); } elseif ($person->isDead()) { $html .= I18N::translate('yes'); } else { $html .= ' '; } $death_dates[0] = new Date(''); } $html .= '</td>'; //-- Event date (sortable)hidden by datatables code $html .= '<td>' . $death_date->julianDay() . '</td>'; //-- Death anniversary $html .= '<td>' . Date::getAge($death_dates[0], null, 2) . '</td>'; //-- Age at death $age = Date::getAge($birth_dates[0], $death_dates[0], 0); if (!isset($unique_indis[$person->getXref()]) && $age >= 0 && $age <= $max_age) { $deat_by_age[$age] .= $person->getSex(); } // Need both display and sortable age $html .= '<td>' . Date::getAge($birth_dates[0], $death_dates[0], 2) . '</td><td>' . Date::getAge($birth_dates[0], $death_dates[0], 1) . '</td>'; //-- Death place $html .= '<td>'; foreach ($person->getAllDeathPlaces() as $n => $death_place) { $tmp = new Place($death_place, $person->getTree()); if ($n) { $html .= '<br>'; } $html .= '<a href="' . $tmp->getURL() . '" title="' . strip_tags($tmp->getFullName()) . '">'; $html .= FunctionsPrint::highlightSearchHits($tmp->getShortName()) . '</a>'; } $html .= '</td>'; //-- Last change $html .= '<td>' . $person->lastChangeTimestamp() . '</td>'; $html .= '<td>' . $person->lastChangeTimestamp(true) . '</td>'; //-- Sorting by gender $html .= '<td>' . $person->getSex() . '</td>'; //-- Filtering by birth date $html .= '<td>'; if (!$person->canShow() || Date::compare($birth_date, $d100y) > 0) { $html .= 'Y100'; } else { $html .= 'YES'; } $html .= '</td>'; //-- Filtering by death date $html .= '<td>'; // Died in last 100 years? Died? Not dead? if (Date::compare($death_dates[0], $d100y) > 0) { $html .= 'Y100'; } elseif ($death_dates[0]->minimumJulianDay() || $person->isDead()) { $html .= 'YES'; } else { $html .= 'N'; } $html .= '</td>'; //-- Roots or Leaves ? $html .= '<td>'; if (!$person->getChildFamilies()) { $html .= 'R'; } elseif (!$person->isDead() && $person->getNumberOfChildren() < 1) { $html .= 'L'; } else { $html .= ' '; } $html .= '</td>'; $html .= '</tr>'; $unique_indis[$person->getXref()] = true; } $html .= ' </tbody> </table> <div id="indi_list_table-charts_' . $table_id . '" style="display:none"> <table class="list-charts"> <tr> <td> ' . self::chartByDecade($birt_by_decade, I18N::translate('Decade of birth')) . ' </td> <td> ' . self::chartByDecade($deat_by_decade, I18N::translate('Decade of death')) . ' </td> </tr> <tr> <td colspan="2"> ' . self::chartByAge($deat_by_age, I18N::translate('Age related to death year')) . ' </td> </tr> </table> </div> </div>'; return $html; }