/**
  * Get the translatable country name for the search area.
  * 
  * @global type $WT_TREE
  * @param type $area
  * @return string
  */
 static function getSearchAreaName($area)
 {
     global $WT_TREE;
     $stats = new Stats($WT_TREE);
     $countries = $stats->getAllCountries();
     if (array_key_exists($area, $countries)) {
         $area = $countries[$area];
     } else {
         $area = I18N::translate("International");
     }
     return $area;
 }
Пример #2
0
    /**
     * 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 $ctype, $WT_TREE;
        $num = $this->getBlockSetting($block_id, 'num', '10');
        $infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
        $block = $this->getBlockSetting($block_id, 'block', '0');
        foreach (array('num', 'infoStyle', 'block') as $name) {
            if (array_key_exists($name, $cfg)) {
                ${$name} = $cfg[$name];
            }
        }
        $stats = new Stats($WT_TREE);
        $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 . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
        } else {
            $title = '';
        }
        if ($num == 1) {
            // I18N: i.e. most popular given name.
            $title .= I18N::translate('Top given name');
        } else {
            // I18N: Title for a list of the most common given names, %s is a number. Note that a separate translation exists when %s is 1
            $title .= I18N::plural('Top %s given name', 'Top %s given names', $num, I18N::number($num));
        }
        $content = '<div class="normal_inner_block">';
        //Select List or Table
        switch ($infoStyle) {
            case "list":
                // Output style 1:  Simple list style. Better suited to left side of page.
                if (I18N::direction() === 'ltr') {
                    $padding = 'padding-left: 15px';
                } else {
                    $padding = 'padding-right: 15px';
                }
                $params = array(1, $num, 'rcount');
                // List Female names
                $totals = $stats->commonGivenFemaleTotals($params);
                if ($totals) {
                    $content .= '<b>' . I18N::translate('Females') . '</b><div class="wrap" style="' . $padding . '">' . $totals . '</div><br>';
                }
                // List Male names
                $totals = $stats->commonGivenMaleTotals($params);
                if ($totals) {
                    $content .= '<b>' . I18N::translate('Males') . '</b><div class="wrap" style="' . $padding . '">' . $totals . '</div><br>';
                }
                break;
            case "table":
                // Style 2: Tabular format. Narrow, 2 or 3 column table, good on right side of page
                $params = array(1, $num, 'rcount');
                $content .= '<table style="margin:auto;">
						<tr valign="top">
						<td>' . $stats->commonGivenFemaleTable($params) . '</td>
						<td>' . $stats->commonGivenMaleTable($params) . '</td>';
                $content .= '</tr></table>';
                break;
        }
        $content .= "</div>";
        if ($template) {
            if ($block) {
                $class .= ' small_inner_block';
            }
            return Theme::theme()->formatBlock($id, $title, $class, $content);
        } else {
            return $content;
        }
    }
 /**
  * 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 . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;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&amp;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&amp;surname_sublist=yes&amp;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') . ':&nbsp;' . $stats->averageLifespanMale();
             $content .= '&nbsp;&nbsp;&nbsp;' . I18N::translate('Females') . ':&nbsp;' . $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>';
     }
     $content .= '</div>';
     if ($stat_link) {
         $content .= '<div class="clearfloat"><a href="statistics.php?ged=' . $WT_TREE->getNameUrl() . '" rel="nofollow"><b>' . I18N::translate('View statistics as graphs') . '</b></a></div>';
     }
     if ($show_common_surnames) {
         $surnames = FunctionsDb::getCommonSurnames($WT_TREE->getPreference('COMMON_NAMES_THRESHOLD'), $WT_TREE);
         if (count($surnames) > 0) {
             $content .= '<div class="clearfloat"><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() . "&amp;surname=" . rawurlencode($surname['name']) . '">' . $surname['name'] . '</a>';
                     $i++;
                 }
             }
             $content .= '</div>';
         }
     }
     if ($template) {
         return Theme::theme()->formatBlock($id, $title, $class, $content);
     } else {
         return $content;
     }
 }
Пример #4
0
    /**
     * Places administration.
     */
    private function adminPlaces()
    {
        global $WT_TREE;
        $action = Filter::get('action');
        $parent = Filter::get('parent');
        $inactive = Filter::getBool('inactive');
        $deleteRecord = Filter::get('deleteRecord');
        if (!isset($parent)) {
            $parent = 0;
        }
        $controller = new PageController();
        $controller->restrictAccess(Auth::isAdmin());
        if ($action == 'ExportFile' && Auth::isAdmin()) {
            $tmp = $this->placeIdToHierarchy($parent);
            $maxLevel = $this->getHighestLevel();
            if ($maxLevel > 8) {
                $maxLevel = 8;
            }
            $tmp[0] = 'places';
            $outputFileName = preg_replace('/[:;\\/\\\\(\\)\\{\\}\\[\\] $]/', '_', implode('-', $tmp)) . '.csv';
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename="' . $outputFileName . '"');
            echo '"', I18N::translate('Level'), '";"', I18N::translate('Country'), '";';
            if ($maxLevel > 0) {
                echo '"', I18N::translate('State'), '";';
            }
            if ($maxLevel > 1) {
                echo '"', I18N::translate('County'), '";';
            }
            if ($maxLevel > 2) {
                echo '"', I18N::translate('City'), '";';
            }
            if ($maxLevel > 3) {
                echo '"', I18N::translate('Place'), '";';
            }
            if ($maxLevel > 4) {
                echo '"', I18N::translate('Place'), '";';
            }
            if ($maxLevel > 5) {
                echo '"', I18N::translate('Place'), '";';
            }
            if ($maxLevel > 6) {
                echo '"', I18N::translate('Place'), '";';
            }
            if ($maxLevel > 7) {
                echo '"', I18N::translate('Place'), '";';
            }
            echo '"', I18N::translate('Longitude'), '";"', I18N::translate('Latitude'), '";';
            echo '"', I18N::translate('Zoom level'), '";"', I18N::translate('Icon'), '";', WT_EOL;
            $this->outputLevel($parent);
            exit;
        }
        $controller->setPageTitle(I18N::translate('Google Maps™'))->pageHeader();
        ?>
		<ol class="breadcrumb small">
			<li><a href="admin.php"><?php 
        echo I18N::translate('Control panel');
        ?>
</a></li>
			<li><a href="admin_modules.php"><?php 
        echo I18N::translate('Module administration');
        ?>
</a></li>
			<li class="active"><?php 
        echo $controller->getPageTitle();
        ?>
</li>
		</ol>

		<ul class="nav nav-tabs nav-justified" role="tablist">
			<li role="presentation">
				<a href="?mod=googlemap&amp;mod_action=admin_config" role="tab">
					<?php 
        echo I18N::translate('Google Maps™ preferences');
        ?>
				</a>
			</li>
			<li role="presentation" class="active">
				<a href="#">
					<?php 
        echo I18N::translate('Geographic data');
        ?>
				</a>
			</li>
			<li role="presentation">
				<a href="?mod=googlemap&amp;mod_action=admin_placecheck">
					<?php 
        echo I18N::translate('Place check');
        ?>
				</a>
			</li>
		</ul>

		<h2><?php 
        echo I18N::translate('Geographic data');
        ?>
</h2>
		<?php 
        if ($action == 'ImportGedcom') {
            $placelist = array();
            $j = 0;
            $gedcom_records = Database::prepare("SELECT i_gedcom FROM `##individuals` WHERE i_file=? UNION ALL SELECT f_gedcom FROM `##families` WHERE f_file=?")->execute(array($WT_TREE->getTreeId(), $WT_TREE->getTreeId()))->fetchOneColumn();
            foreach ($gedcom_records as $gedrec) {
                $i = 1;
                $placerec = Functions::getSubRecord(2, '2 PLAC', $gedrec, $i);
                while (!empty($placerec)) {
                    if (preg_match("/2 PLAC (.+)/", $placerec, $match)) {
                        $placelist[$j] = array();
                        $placelist[$j]['place'] = trim($match[1]);
                        if (preg_match("/4 LATI (.*)/", $placerec, $match)) {
                            $placelist[$j]['lati'] = trim($match[1]);
                            if ($placelist[$j]['lati'][0] != 'N' && $placelist[$j]['lati'][0] != 'S') {
                                if ($placelist[$j]['lati'] < 0) {
                                    $placelist[$j]['lati'][0] = 'S';
                                } else {
                                    $placelist[$j]['lati'] = 'N' . $placelist[$j]['lati'];
                                }
                            }
                        } else {
                            $placelist[$j]['lati'] = null;
                        }
                        if (preg_match("/4 LONG (.*)/", $placerec, $match)) {
                            $placelist[$j]['long'] = trim($match[1]);
                            if ($placelist[$j]['long'][0] != 'E' && $placelist[$j]['long'][0] != 'W') {
                                if ($placelist[$j]['long'] < 0) {
                                    $placelist[$j]['long'][0] = 'W';
                                } else {
                                    $placelist[$j]['long'] = 'E' . $placelist[$j]['long'];
                                }
                            }
                        } else {
                            $placelist[$j]['long'] = null;
                        }
                        $j = $j + 1;
                    }
                    $i = $i + 1;
                    $placerec = Functions::getSubRecord(2, '2 PLAC', $gedrec, $i);
                }
            }
            asort($placelist);
            $prevPlace = '';
            $prevLati = '';
            $prevLong = '';
            $placelistUniq = array();
            $j = 0;
            foreach ($placelist as $k => $place) {
                if ($place['place'] != $prevPlace) {
                    $placelistUniq[$j] = array();
                    $placelistUniq[$j]['place'] = $place['place'];
                    $placelistUniq[$j]['lati'] = $place['lati'];
                    $placelistUniq[$j]['long'] = $place['long'];
                    $j = $j + 1;
                } elseif ($place['place'] == $prevPlace && ($place['lati'] != $prevLati || $place['long'] != $prevLong)) {
                    if ($placelistUniq[$j - 1]['lati'] == 0 || $placelistUniq[$j - 1]['long'] == 0) {
                        $placelistUniq[$j - 1]['lati'] = $place['lati'];
                        $placelistUniq[$j - 1]['long'] = $place['long'];
                    } elseif ($place['lati'] != '0' || $place['long'] != '0') {
                        echo 'Difference: previous value = ', $prevPlace, ', ', $prevLati, ', ', $prevLong, ' current = ', $place['place'], ', ', $place['lati'], ', ', $place['long'], '<br>';
                    }
                }
                $prevPlace = $place['place'];
                $prevLati = $place['lati'];
                $prevLong = $place['long'];
            }
            $highestIndex = $this->getHighestIndex();
            $default_zoom_level = array(4, 7, 10, 12);
            foreach ($placelistUniq as $k => $place) {
                $parent = preg_split('/ *, */', $place['place']);
                $parent = array_reverse($parent);
                $parent_id = 0;
                for ($i = 0; $i < count($parent); $i++) {
                    if (!isset($default_zoom_level[$i])) {
                        $default_zoom_level[$i] = $default_zoom_level[$i - 1];
                    }
                    $escparent = $parent[$i];
                    if ($escparent == '') {
                        $escparent = 'Unknown';
                    }
                    $row = Database::prepare("SELECT pl_id, pl_long, pl_lati, pl_zoom FROM `##placelocation` WHERE pl_level=? AND pl_parent_id=? AND pl_place LIKE ?")->execute(array($i, $parent_id, $escparent))->fetchOneRow();
                    if ($i < count($parent) - 1) {
                        // Create higher-level places, if necessary
                        if (empty($row)) {
                            $highestIndex++;
                            Database::prepare("INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_zoom) VALUES (?, ?, ?, ?, ?)")->execute(array($highestIndex, $parent_id, $i, $escparent, $default_zoom_level[$i]));
                            echo Filter::escapeHtml($escparent), '<br>';
                            $parent_id = $highestIndex;
                        } else {
                            $parent_id = $row->pl_id;
                        }
                    } else {
                        // Create lowest-level place, if necessary
                        if (empty($row->pl_id)) {
                            $highestIndex++;
                            Database::prepare("INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom) VALUES (?, ?, ?, ?, ?, ?, ?)")->execute(array($highestIndex, $parent_id, $i, $escparent, $place['long'], $place['lati'], $default_zoom_level[$i]));
                            echo Filter::escapeHtml($escparent), '<br>';
                        } else {
                            if (empty($row->pl_long) && empty($row->pl_lati) && $place['lati'] != '0' && $place['long'] != '0') {
                                Database::prepare("UPDATE `##placelocation` SET pl_lati=?, pl_long=? WHERE pl_id=?")->execute(array($place['lati'], $place['long'], $row->pl_id));
                                echo Filter::escapeHtml($escparent), '<br>';
                            }
                        }
                    }
                }
            }
            $parent = 0;
        }
        if ($action === 'ImportFile') {
            $placefiles = $this->findFiles(WT_MODULES_DIR . 'googlemap/extra');
            sort($placefiles);
            ?>
		<form class="form-horizontal" method="post" enctype="multipart/form-data" id="importfile" name="importfile" action="module.php?mod=googlemap&amp;mod_action=admin_places&amp;action=ImportFile2">

			<!-- PLACES FILE -->
			<div class="form-group">
				<label class="control-label col-sm-4" for="placesfile">
					<?php 
            echo I18N::translate('File containing places (CSV)');
            ?>
				</label>
				<div class="col-sm-8">
					<div class="btn btn-default">
					<input id="placesfile" type="file" name="placesfile">
					</div>
				</div>
			</div>

			<!-- LOCAL FILE -->
			<?php 
            if (count($placefiles) > 0) {
                ?>
			<div class="form-group">
				<label class="control-label col-sm-4" for="localfile">
					<?php 
                echo I18N::translate('Server file containing places (CSV)');
                ?>
				</label>
				<div class="col-sm-8">
					<div class="input-group">
						<span class="input-group-addon">
							<?php 
                echo WT_MODULES_DIR . 'googlemap/extra/';
                ?>
						</span>
						<?php 
                foreach ($placefiles as $p => $placefile) {
                    unset($placefiles[$p]);
                    $p = Filter::escapeHtml($placefile);
                    if (substr($placefile, 0, 1) == "/") {
                        $placefiles[$p] = substr($placefile, 1);
                    } else {
                        $placefiles[$p] = $placefile;
                    }
                }
                echo FunctionsEdit::selectEditControl('localfile', $placefiles, '', '', 'class="form-control"');
                ?>
					</div>
				</div>
			</div>
			<?php 
            }
            ?>

			<!-- CLEAR DATABASE -->
			<fieldset class="form-group">
				<legend class="control-label col-sm-4">
					<?php 
            echo I18N::translate('Delete all existing geographic data before importing the file.');
            ?>
				</legend>
				<div class="col-sm-8">
					<?php 
            echo FunctionsEdit::editFieldYesNo('cleardatabase', 0, 'class="radio-inline"');
            ?>
				</div>
			</fieldset>

			<!-- UPDATE ONLY -->
			<fieldset class="form-group">
				<legend class="control-label col-sm-4">
					<?php 
            echo I18N::translate('Do not create new locations, just import coordinates for existing locations.');
            ?>
				</legend>
				<div class="col-sm-8">
					<?php 
            echo FunctionsEdit::editFieldYesNo('updateonly', 0, 'class="radio-inline"');
            ?>
				</div>
			</fieldset>

			<!-- OVERWRITE DATA -->
			<fieldset class="form-group">
				<legend class="control-label col-sm-4">
					<?php 
            echo I18N::translate('Overwrite existing coordinates.');
            ?>
				</legend>
				<div class="col-sm-8">
					<?php 
            echo FunctionsEdit::editFieldYesNo('overwritedata', 0, 'class="radio-inline"');
            ?>
				</div>
			</fieldset>

			<!-- SAVE BUTTON -->
			<div class="form-group">
				<div class="col-sm-offset-4 col-sm-8">
					<button type="submit" class="btn btn-primary">
						<i class="fa fa-check"></i>
						<?php 
            echo I18N::translate('Continue adding');
            ?>
					</button>
				</div>
			</div>
		</form>
		<?php 
            exit;
        }
        if ($action === 'ImportFile2') {
            $country_names = array();
            $stats = new Stats($WT_TREE);
            foreach ($stats->iso3166() as $key => $value) {
                $country_names[$key] = I18N::translate($key);
            }
            if (Filter::postBool('cleardatabase')) {
                Database::exec("DELETE FROM `##placelocation` WHERE 1=1");
            }
            if (!empty($_FILES['placesfile']['tmp_name'])) {
                $lines = file($_FILES['placesfile']['tmp_name']);
            } elseif (!empty($_REQUEST['localfile'])) {
                $lines = file(WT_MODULES_DIR . 'googlemap/extra' . $_REQUEST['localfile']);
            }
            // Strip BYTE-ORDER-MARK, if present
            if (!empty($lines[0]) && substr($lines[0], 0, 3) === WT_UTF8_BOM) {
                $lines[0] = substr($lines[0], 3);
            }
            asort($lines);
            $highestIndex = $this->getHighestIndex();
            $placelist = array();
            $j = 0;
            $maxLevel = 0;
            foreach ($lines as $p => $placerec) {
                $fieldrec = explode(';', $placerec);
                if ($fieldrec[0] > $maxLevel) {
                    $maxLevel = $fieldrec[0];
                }
            }
            $fields = count($fieldrec);
            $set_icon = true;
            if (!is_dir(WT_MODULES_DIR . 'googlemap/places/flags/')) {
                $set_icon = false;
            }
            foreach ($lines as $p => $placerec) {
                $fieldrec = explode(';', $placerec);
                if (is_numeric($fieldrec[0]) && $fieldrec[0] <= $maxLevel) {
                    $placelist[$j] = array();
                    $placelist[$j]['place'] = '';
                    for ($ii = $fields - 4; $ii > 1; $ii--) {
                        if ($fieldrec[0] > $ii - 2) {
                            $placelist[$j]['place'] .= $fieldrec[$ii] . ',';
                        }
                    }
                    foreach ($country_names as $countrycode => $countryname) {
                        if ($countrycode == strtoupper($fieldrec[1])) {
                            $fieldrec[1] = $countryname;
                            break;
                        }
                    }
                    $placelist[$j]['place'] .= $fieldrec[1];
                    $placelist[$j]['long'] = $fieldrec[$fields - 4];
                    $placelist[$j]['lati'] = $fieldrec[$fields - 3];
                    $placelist[$j]['zoom'] = $fieldrec[$fields - 2];
                    if ($set_icon) {
                        $placelist[$j]['icon'] = trim($fieldrec[$fields - 1]);
                    } else {
                        $placelist[$j]['icon'] = '';
                    }
                    $j = $j + 1;
                }
            }
            $prevPlace = '';
            $prevLati = '';
            $prevLong = '';
            $placelistUniq = array();
            $j = 0;
            foreach ($placelist as $k => $place) {
                if ($place['place'] != $prevPlace) {
                    $placelistUniq[$j] = array();
                    $placelistUniq[$j]['place'] = $place['place'];
                    $placelistUniq[$j]['lati'] = $place['lati'];
                    $placelistUniq[$j]['long'] = $place['long'];
                    $placelistUniq[$j]['zoom'] = $place['zoom'];
                    $placelistUniq[$j]['icon'] = $place['icon'];
                    $j = $j + 1;
                } elseif ($place['place'] == $prevPlace && ($place['lati'] != $prevLati || $place['long'] != $prevLong)) {
                    if ($placelistUniq[$j - 1]['lati'] == 0 || $placelistUniq[$j - 1]['long'] == 0) {
                        $placelistUniq[$j - 1]['lati'] = $place['lati'];
                        $placelistUniq[$j - 1]['long'] = $place['long'];
                        $placelistUniq[$j - 1]['zoom'] = $place['zoom'];
                        $placelistUniq[$j - 1]['icon'] = $place['icon'];
                    } elseif ($place['lati'] != '0' || $place['long'] != '0') {
                        echo 'Difference: previous value = ', $prevPlace, ', ', $prevLati, ', ', $prevLong, ' current = ', $place['place'], ', ', $place['lati'], ', ', $place['long'], '<br>';
                    }
                }
                $prevPlace = $place['place'];
                $prevLati = $place['lati'];
                $prevLong = $place['long'];
            }
            $default_zoom_level = array();
            $default_zoom_level[0] = 4;
            $default_zoom_level[1] = 7;
            $default_zoom_level[2] = 10;
            $default_zoom_level[3] = 12;
            foreach ($placelistUniq as $k => $place) {
                $parent = explode(',', $place['place']);
                $parent = array_reverse($parent);
                $parent_id = 0;
                for ($i = 0; $i < count($parent); $i++) {
                    $escparent = $parent[$i];
                    if ($escparent == '') {
                        $escparent = 'Unknown';
                    }
                    $row = Database::prepare("SELECT pl_id, pl_long, pl_lati, pl_zoom, pl_icon FROM `##placelocation` WHERE pl_level=? AND pl_parent_id=? AND pl_place LIKE ? ORDER BY pl_place")->execute(array($i, $parent_id, $escparent))->fetchOneRow();
                    if (empty($row)) {
                        // this name does not yet exist: create entry
                        if (!Filter::postBool('updateonly')) {
                            $highestIndex = $highestIndex + 1;
                            if ($i + 1 == count($parent)) {
                                $zoomlevel = $place['zoom'];
                            } elseif (isset($default_zoom_level[$i])) {
                                $zoomlevel = $default_zoom_level[$i];
                            } else {
                                $zoomlevel = $this->getSetting('GM_MAX_ZOOM');
                            }
                            if ($place['lati'] == '0' || $place['long'] == '0' || $i + 1 < count($parent)) {
                                Database::prepare("INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_zoom, pl_icon) VALUES (?, ?, ?, ?, ?, ?)")->execute(array($highestIndex, $parent_id, $i, $escparent, $zoomlevel, $place['icon']));
                            } else {
                                //delete leading zero
                                $pl_lati = str_replace(array('N', 'S', ','), array('', '-', '.'), $place['lati']);
                                $pl_long = str_replace(array('E', 'W', ','), array('', '-', '.'), $place['long']);
                                if ($pl_lati >= 0) {
                                    $place['lati'] = 'N' . abs($pl_lati);
                                } elseif ($pl_lati < 0) {
                                    $place['lati'] = 'S' . abs($pl_lati);
                                }
                                if ($pl_long >= 0) {
                                    $place['long'] = 'E' . abs($pl_long);
                                } elseif ($pl_long < 0) {
                                    $place['long'] = 'W' . abs($pl_long);
                                }
                                Database::prepare("INSERT INTO `##placelocation` (pl_id, pl_parent_id, pl_level, pl_place, pl_long, pl_lati, pl_zoom, pl_icon) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")->execute(array($highestIndex, $parent_id, $i, $escparent, $place['long'], $place['lati'], $zoomlevel, $place['icon']));
                            }
                            $parent_id = $highestIndex;
                        }
                    } else {
                        $parent_id = $row->pl_id;
                        if (Filter::postBool('overwritedata') && $i + 1 == count($parent)) {
                            Database::prepare("UPDATE `##placelocation` SET pl_lati = ?, pl_long = ?, pl_zoom = ?, pl_icon = ? WHERE pl_id = ?")->execute(array($place['lati'], $place['long'], $place['zoom'], $place['icon'], $parent_id));
                        } else {
                            // Update only if existing data is missing
                            if (!$row->pl_long && !$row->pl_lati) {
                                Database::prepare("UPDATE `##placelocation` SET pl_lati = ?, pl_long = ? WHERE pl_id = ?")->execute(array($place['lati'], $place['long'], $parent_id));
                            }
                            if (!$row->pl_icon && $place['icon']) {
                                Database::prepare("UPDATE `##placelocation` SET pl_icon = ? WHERE pl_id = ?")->execute(array($place['icon'], $parent_id));
                            }
                        }
                    }
                }
            }
            $parent = 0;
        }
        if ($action == 'DeleteRecord') {
            $exists = Database::prepare("SELECT 1 FROM `##placelocation` WHERE pl_parent_id=?")->execute(array($deleteRecord))->fetchOne();
            if (!$exists) {
                Database::prepare("DELETE FROM `##placelocation` WHERE pl_id=?")->execute(array($deleteRecord));
            } else {
                echo '<table class="facts_table"><tr><td>', I18N::translate('Location not removed: this location contains sub-locations'), '</td></tr></table>';
            }
        }
        ?>
		<script>
		function updateList(inactive) {
			window.location.href='<?php 
        if (strstr($_SERVER['REQUEST_URI'], '&inactive', true)) {
            $uri = strstr($_SERVER['REQUEST_URI'], '&inactive', true);
        } else {
            $uri = $_SERVER['REQUEST_URI'];
        }
        echo $uri, '&inactive=';
        ?>
'+inactive;
		}

		function edit_place_location(placeid) {
			window.open('module.php?mod=googlemap&mod_action=places_edit&action=update&placeid='+placeid, '_blank', gmap_window_specs);
			return false;
		}

		function add_place_location(placeid) {
			window.open('module.php?mod=googlemap&mod_action=places_edit&action=add&placeid='+placeid, '_blank', gmap_window_specs);
			return false;
		}

		function delete_place(placeid) {
			var answer=confirm('<?php 
        echo I18N::translate('Remove this location?');
        ?>
');
			if (answer == true) {
				window.location = '<?php 
        echo Functions::getQueryUrl(array('action' => 'DeleteRecord'));
        ?>
&action=DeleteRecord&deleteRecord=' + placeid;
			}
		}
		</script>
		<p id="gm_breadcrumb">
			<?php 
        $where_am_i = $this->placeIdToHierarchy($parent);
        foreach (array_reverse($where_am_i, true) as $id => $place) {
            if ($id == $parent) {
                if ($place != 'Unknown') {
                    echo Filter::escapeHtml($place);
                } else {
                    echo I18N::translate('unknown');
                }
            } else {
                echo '<a href="module.php?mod=googlemap&mod_action=admin_places&parent=', $id, '&inactive=', $inactive, '">';
                if ($place != 'Unknown') {
                    echo Filter::escapeHtml($place), '</a>';
                } else {
                    echo I18N::translate('unknown'), '</a>';
                }
            }
            echo ' - ';
        }
        ?>
			<a href="module.php?mod=googlemap&mod_action=admin_places&parent=0&inactive=', $inactive, '"><?php 
        echo I18N::translate('Top level');
        ?>
</a>
		</p>

		<form class="form-inline" name="active" method="post" action="module.php?mod=googlemap&mod_action=admin_places&parent=', $parent, '&inactive=', $inactive, '">
			<div class="checkbox">
				<label for="inactive">
				   <?php 
        echo FunctionsEdit::checkbox('inactive', $inactive, 'onclick="updateList(this.checked)"');
        ?>
				   <?php 
        echo I18N::translate('Show inactive places');
        ?>
				</label>
			</div>
			<p class="small text-muted">
				<?php 
        echo I18N::translate('By default, the list shows only those places which can be found in your family trees.  You may have details for other places, such as those imported in bulk from an external file.  Selecting this option will show all places, including ones that are not currently used.');
        ?>
				<?php 
        echo I18N::translate('If you have a large number of inactive places, it can be slow to generate the list.');
        ?>
			</p>
		</form>

		<?php 
        $placelist = $this->getPlaceListLocation($parent, $inactive);
        echo '<div class="gm_plac_edit">';
        echo '<table class="table table-bordered table-condensed table-hover"><tr>';
        echo '<th>', GedcomTag::getLabel('PLAC'), '</th>';
        echo '<th>', GedcomTag::getLabel('LATI'), '</th>';
        echo '<th>', GedcomTag::getLabel('LONG'), '</th>';
        echo '<th>', I18N::translate('Zoom level'), '</th>';
        echo '<th>', I18N::translate('Icon'), '</th>';
        echo '<th>';
        echo I18N::translate('Edit'), '</th><th>', I18N::translate('Delete'), '</th></tr>';
        if (count($placelist) == 0) {
            echo '<tr><td colspan="7">', I18N::translate('No places found'), '</td></tr>';
        }
        foreach ($placelist as $place) {
            echo '<tr><td><a href="module.php?mod=googlemap&mod_action=admin_places&parent=', $place['place_id'], '&inactive=', $inactive, '">';
            if ($place['place'] != 'Unknown') {
                echo Filter::escapeHtml($place['place']), '</a></td>';
            } else {
                echo I18N::translate('unknown'), '</a></td>';
            }
            echo '<td>', $place['lati'], '</td>';
            echo '<td>', $place['long'], '</td>';
            echo '<td>', $place['zoom'], '</td>';
            echo '<td>';
            if ($place['icon']) {
                echo '<img src="', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/', $place['icon'], '" width="25" height="15">';
            } else {
                if ($place['lati'] || $place['long']) {
                    echo '<img src="', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/images/mm_20_red.png">';
                } else {
                    echo '<img src="', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/images/mm_20_yellow.png">';
                }
            }
            echo '</td>';
            echo '<td class="narrow"><a href="#" onclick="edit_place_location(', $place['place_id'], ');return false;" class="icon-edit" title="', I18N::translate('Edit'), '"></a></td>';
            $noRows = Database::prepare("SELECT COUNT(pl_id) FROM `##placelocation` WHERE pl_parent_id=?")->execute(array($place['place_id']))->fetchOne();
            if ($noRows == 0) {
                ?>
				<td><a href="#" onclick="delete_place(<?php 
                echo $place['place_id'];
                ?>
);return false;" class="icon-delete" title="<?php 
                echo I18N::translate('Remove');
                ?>
"></a></td>
		<?php 
            } else {
                ?>
				<td><i class="icon-delete-grey"></i></td>
		<?php 
            }
            ?>
			</tr>
			<?php 
        }
        ?>
		</table>
		</div>

		<hr>
		<form class="form-horizontal" action="?" onsubmit="add_place_location(this.parent_id.options[this.parent_id.selectedIndex].value); return false;">
			<div class="form-group">
				<label class="form-control-static col-sm-4" for="parent_id">
					<?php 
        echo I18N::translate('Add a new geographic location');
        ?>
				</label>
				<div class="col-sm-8">
					<div class="col-sm-6">
						<?php 
        echo FunctionsEdit::selectEditControl('parent_id', $where_am_i, I18N::translate('Top level'), $parent, 'class="form-control"');
        ?>
					</div>
					<button type="submit" class="btn btn-default">
						<i class="fa fa-plus"></i>
						<?php 
        echo I18N::translate('Add');
        ?>
					</button>
				</div>
			</div>
		</form>

		<form class="form-horizontal" action="module.php" method="get">
			<input type="hidden" name="mod" value="googlemap">
			<input type="hidden" name="mod_action" value="admin_places">
			<input type="hidden" name="action" value="ImportGedcom">
			<div class="form-group">
				<label class="form-control-static col-sm-4" for="ged">
					<?php 
        echo I18N::translate('Import all places from a family tree');
        ?>
				</label>
				<div class="col-sm-8">
					<div class="col-sm-6">
						<?php 
        echo FunctionsEdit::selectEditControl('ged', Tree::getNameList(), null, $WT_TREE->getName(), 'class="form-control"');
        ?>
					</div>
					<button type="submit" class="btn btn-default">
						<i class="fa fa-upload"></i>
						<?php 
        echo I18N::translate('Import');
        ?>
					</button>
				</div>
			</div>
		</form>

		<form class="form-horizontal" action="module.php" method="get">
			<input type="hidden" name="mod" value="googlemap">
			<input type="hidden" name="mod_action" value="admin_places">
			<input type="hidden" name="action" value="ImportFile">
			<div class="form-group">
				<label class="form-control-static col-sm-4">
					<?php 
        echo I18N::translate('Upload geographic data');
        ?>
				</label>
				<div class="col-sm-8">
					<div class="col-sm-6">
						<button type="submit" class="btn btn-default">
							<i class="fa fa-upload"></i>
							<?php 
        echo I18N::translate('Upload');
        ?>
						</button>
					</div>
				</div>
			</div>
		</form>

		<form class="form-horizontal" action="module.php" method="get">
			<input type="hidden" name="mod" value="googlemap">
			<input type="hidden" name="mod_action" value="admin_places">
			<input type="hidden" name="action" value="ExportFile">
			<div class="form-group">
				<label class="form-control-static col-sm-4">
					<?php 
        echo I18N::translate('Download geographic data');
        ?>
				</label>
				<div class="col-sm-8">
					<div class="col-sm-6">
						<?php 
        echo FunctionsEdit::selectEditControl('parent', $where_am_i, I18N::translate('All'), $WT_TREE->getTreeId(), 'class="form-control"');
        ?>
					</div>
					<button type="submit" class="btn btn-default">
						<i class="fa fa-download"></i>
						<?php 
        echo I18N::translate('Download');
        ?>
					</button>
				</div>
			</div>
		</form>
		<?php 
    }
Пример #5
0
    /**
     * Render the Ajax response for the sortable table of Sosa family
     * @param AjaxController $controller
     */
    protected function renderFamSosaListIndi(AjaxController $controller)
    {
        global $WT_TREE;
        $listFamSosa = $this->sosa_provider->getFamilySosaListAtGeneration($this->generation);
        $this->view_bag->set('has_sosa', false);
        if (count($listFamSosa) > 0) {
            $this->view_bag->set('has_sosa', true);
            $table_id = 'table-sosa-fam-' . 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 . '"><"dt-clear">pf<"dt-clear">irl>t<"F"pl<"dt-clear"><"filtersF_' . $table_id . '">>\',
                    ' . I18N::datatablesI18N(array(16, 32, 64, 128, -1)) . ',
					jQueryUI: true,
					autoWidth: false,
					processing: true,
					retrieve: true,
					columns: [
						/* 0-Sosa */  	   { dataSort: 1, class: "center"},
		                /* 1-SOSA */ 	   { type: "num", visible: false },
						/* 2-Husb Givn */  { dataSort: 4},
						/* 3-Husb Surn */  { dataSort: 5},
						/* 4-GIVN,SURN */  { type: "unicode", visible: false},
						/* 5-SURN,GIVN */  { type: "unicode", visible: false},
						/* 6-Husb Age  */  { dataSort: 7, class: "center"},
						/* 7-AGE       */  { type: "num", visible: false},
						/* 8-Wife Givn */  { dataSort: 10},
						/* 9-Wife Surn */  { dataSort: 11},
						/* 10-GIVN,SURN */ { type: "unicode", visible: false},
						/* 11-SURN,GIVN */ { type: "unicode", visible: false},
						/* 12-Wife Age  */ { dataSort: 13, class: "center"},
						/* 13-AGE       */ { type: "num", visible: false},
						/* 14-Marr Date */ { dataSort: 15, class: "center"},
						/* 15-MARR:DATE */ { visible: false},
						/* 16-Marr Plac */ { type: "unicode", class: "center"},
						/* 17-Marr Sour */ { dataSort : 18, class: "center", visible: ' . (ModuleManager::getInstance()->isOperational(Constants::MODULE_MAJ_ISSOURCED_NAME) ? 'true' : 'false') . ' },
						/* 18-Sort Sour */ { visible: false},
						/* 19-Children  */ { dataSort: 20, class: "center"},
						/* 20-NCHI      */ { type: "num", visible: false},
						/* 21-MARR      */ { visible: false},
						/* 22-DEAT      */ { visible: false},
						/* 23-TREE      */ { visible: false}
					],
					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("#fam_list_table-charts_' . $table_id . '").slideToggle();
				})
				/* Filter buttons in table header */
				.on("click", "button[data-filter-column]", function() {
					var btn = $(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-fam-list").css("visibility", "visible");
				
				jQuery("#btn-toggle-statistics-' . $table_id . '").click();
           ');
            $stats = new Stats($WT_TREE);
            $max_age = max($stats->oldestMarriageMaleAge(), $stats->oldestMarriageFemaleAge()) + 1;
            //-- init chart data
            $marr_by_age = array();
            for ($age = 0; $age <= $max_age; $age++) {
                $marr_by_age[$age] = '';
            }
            $birt_by_decade = array();
            $marr_by_decade = array();
            for ($year = 1550; $year < 2030; $year += 10) {
                $birt_by_decade[$year] = '';
                $marr_by_decade[$year] = '';
            }
            foreach ($listFamSosa as $sosa => $fid) {
                $sfamily = Family::getInstance($fid, $WT_TREE);
                if (!$sfamily || !$sfamily->canShow()) {
                    unset($sfamily[$sosa]);
                    continue;
                }
                $mdate = $sfamily->getMarriageDate();
                if (($husb = $sfamily->getHusband()) && ($hdate = $husb->getBirthDate()) && $hdate->isOK() && $mdate->isOK()) {
                    if (FunctionsPrint::isDateWithinChartsRange($hdate)) {
                        $birt_by_decade[(int) ($hdate->gregorianYear() / 10) * 10] .= $husb->getSex();
                    }
                    $hage = Date::getAge($hdate, $mdate, 0);
                    if ($hage >= 0 && $hage <= $max_age) {
                        $marr_by_age[$hage] .= $husb->getSex();
                    }
                }
                if (($wife = $sfamily->getWife()) && ($wdate = $wife->getBirthDate()) && $wdate->isOK() && $mdate->isOK()) {
                    if (FunctionsPrint::isDateWithinChartsRange($wdate)) {
                        $birt_by_decade[(int) ($wdate->gregorianYear() / 10) * 10] .= $wife->getSex();
                    }
                    $wage = Date::getAge($wdate, $mdate, 0);
                    if ($wage >= 0 && $wage <= $max_age) {
                        $marr_by_age[$wage] .= $wife->getSex();
                    }
                }
                if ($mdate->isOK() && FunctionsPrint::isDateWithinChartsRange($mdate) && $husb && $wife) {
                    $marr_by_decade[(int) ($mdate->gregorianYear() / 10) * 10] .= $husb->getSex() . $wife->getSex();
                }
                $listFamSosa[$sosa] = $sfamily;
            }
            $this->view_bag->set('sosa_list', $listFamSosa);
            $this->view_bag->set('chart_births', FunctionsPrintLists::chartByDecade($birt_by_decade, I18N::translate('Decade of birth')));
            $this->view_bag->set('chart_marriages', FunctionsPrintLists::chartByDecade($marr_by_decade, I18N::translate('Decade of marriage')));
            $this->view_bag->set('chart_ages', FunctionsPrintLists::chartByAge($marr_by_age, I18N::translate('Age in year of marriage')));
        }
        ViewFactory::make('SosaListFam', $this, $controller, $this->view_bag)->render();
    }
Пример #6
0
 /**
  * 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 $ctype, $WT_TREE;
     $title = $this->getBlockSetting($block_id, 'title');
     $html = $this->getBlockSetting($block_id, 'html');
     $gedcom = $this->getBlockSetting($block_id, 'gedcom');
     $show_timestamp = $this->getBlockSetting($block_id, 'show_timestamp', '0');
     $languages = $this->getBlockSetting($block_id, 'languages');
     // Only show this block for certain languages
     if ($languages && !in_array(WT_LOCALE, explode(',', $languages))) {
         return '';
     }
     /*
      * Select GEDCOM
      */
     switch ($gedcom) {
         case '__current__':
             $stats = new Stats($WT_TREE);
             break;
         case '__default__':
             $tree = Tree::findByName(Site::getPreference('DEFAULT_GEDCOM'));
             if ($tree) {
                 $stats = new Stats($tree);
             } else {
                 $stats = new Stats($WT_TREE);
             }
             break;
         default:
             $tree = Tree::findByName($gedcom);
             if ($tree) {
                 $stats = new Stats($tree);
             } else {
                 $stats = new Stats($WT_TREE);
             }
             break;
     }
     /*
      * Retrieve text, process embedded variables
      */
     if (strpos($title, '#') !== false || strpos($html, '#') !== false) {
         $title = $stats->embedTags($title);
         $html = $stats->embedTags($html);
     }
     /*
      * Start Of Output
      */
     $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 . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>' . $title;
     }
     $content = $html;
     if ($show_timestamp) {
         $content .= '<br>' . FunctionsDate::formatTimestamp($this->getBlockSetting($block_id, 'timestamp', WT_TIMESTAMP) + WT_TIMESTAMP_OFFSET);
     }
     if ($template) {
         return Theme::theme()->formatBlock($id, $title, $class, $content);
     } else {
         return $content;
     }
 }
Пример #7
0
 /**
  * {@inheritDoc}
  * @see \MyArtJaub\Webtrees\Module\AdminTasks\Model\AbstractTask::executeSteps()
  */
 protected function executeSteps()
 {
     $res = false;
     // Get the number of days to take into account, either last 7 days or since last check
     $interval_sincelast = 0;
     if ($this->last_updated) {
         $tmpInt = $this->last_updated->diff(new \DateTime('now'), true);
         $interval_sincelast = ($tmpInt->days * 24 + $tmpInt->h) * 60 + $tmpInt->i;
     }
     $interval = max($this->frequency, $interval_sincelast);
     $nbdays = ceil($interval / (24 * 60));
     // Check for updates
     $latest_version_txt = Functions::fetchLatestVersion();
     if (preg_match('/^[0-9.]+\\|[0-9.]+\\|/', $latest_version_txt)) {
         list($latest_version, , $download_url) = explode('|', $latest_version_txt);
     } else {
         // Cannot determine the latest version
         list($latest_version, , $download_url) = explode('|', '||');
     }
     // Users statistics
     $warnusers = 0;
     $nverusers = 0;
     $applusers = 0;
     foreach (User::all() as $user) {
         if (date("U") - (int) $user->getPreference('reg_timestamp') > 604800 && !$user->getPreference('verified')) {
             $warnusers++;
         }
         if (!$user->getPreference('verified_by_admin') && $user->getPreference('verified')) {
             $nverusers++;
         }
         if (!$user->getPreference('verified')) {
             $applusers++;
         }
     }
     // Tree specifics checks
     $one_tree_done = false;
     foreach (Tree::getAll() as $tree) {
         $isTreeEnabled = $tree->getPreference('MAJ_AT_' . $this->getName() . '_ENABLED');
         if ((is_null($isTreeEnabled) || $isTreeEnabled) && ($webmaster = User::find($tree->getPreference('WEBMASTER_USER_ID')))) {
             I18N::init($webmaster->getPreference('language'));
             $subject = I18N::translate('Health Check Report') . ' - ' . I18N::translate('Tree %s', $tree->getTitle());
             $message = I18N::translate('Health Check Report for the last %d days', $nbdays) . Mail::EOL . Mail::EOL . I18N::translate('Tree %s', $tree->getTitle()) . Mail::EOL . '==========================================' . Mail::EOL . Mail::EOL;
             // News
             $message_version = '';
             if ($latest_version && version_compare(WT_VERSION, $latest_version) < 0) {
                 $message_version = I18N::translate('News') . Mail::EOL . '-------------' . Mail::EOL . I18N::translate('A new version of *webtrees* is available: %s. Upgrade as soon as possible.', $latest_version) . Mail::EOL . I18N::translate('Download it here: %s.', $download_url) . Mail::EOL . Mail::EOL;
             }
             $message .= $message_version;
             // Statistics users
             $message_users = I18N::translate('Users') . Mail::EOL . '-------------' . Mail::EOL . WT_BASE_URL . 'admin_users.php' . Mail::EOL . I18N::translate('Total number of users') . "\t\t" . User::count() . Mail::EOL . I18N::translate('Not verified by the user') . "\t\t" . $applusers . Mail::EOL . I18N::translate('Not approved by an administrator') . "\t" . $nverusers . Mail::EOL . Mail::EOL;
             $message .= $message_users;
             // Statistics tree:
             $stats = new Stats($tree);
             $sql = 'SELECT ged_type AS type, COUNT(change_id) AS chgcount FROM wt_change' . ' JOIN (' . ' SELECT "indi" AS ged_type, i_id AS ged_id, i_file AS ged_file FROM wt_individuals' . ' UNION SELECT "fam" AS ged_type, f_id AS ged_id, f_file AS ged_file FROM wt_families' . ' UNION SELECT "sour" AS ged_type, s_id AS ged_id, s_file AS ged_file FROM wt_sources' . ' UNION SELECT "media" AS ged_type, m_id AS ged_id, m_file AS ged_file FROM wt_media' . ' UNION SELECT LOWER(o_type) AS ged_type, o_id AS ged_id, o_file AS ged_file FROM wt_other' . ') AS gedrecords ON (xref = ged_id AND gedcom_id = ged_file)' . ' WHERE change_time >= DATE_ADD( NOW(), INTERVAL - :nb_days DAY)' . ' AND status = :status AND gedcom_id = :gedcom_id' . ' GROUP BY ged_type';
             $changes = Database::prepare($sql)->execute(array('status' => 'accepted', 'gedcom_id' => $tree->getTreeId(), 'nb_days' => $nbdays))->fetchAssoc();
             $message_gedcom = I18N::translate('Tree statistics') . Mail::EOL . '-------------' . Mail::EOL . sprintf('%-25s', I18N::translate('Records')) . "\t" . sprintf('%15s', I18N::translate('Count')) . "\t" . sprintf('%15s', I18N::translate('Changes')) . Mail::EOL . sprintf('%-25s', I18N::translate('Individuals')) . "\t" . sprintf('%15s', $stats->totalIndividuals()) . "\t" . sprintf('%15s', isset($changes['indi']) ? $changes['indi'] : 0) . Mail::EOL . sprintf('%-25s', I18N::translate('Families')) . "\t" . sprintf('%15s', $stats->totalFamilies()) . "\t" . sprintf('%15s', isset($changes['fam']) ? $changes['fam'] : 0) . Mail::EOL . sprintf('%-25s', I18N::translate('Sources')) . "\t" . sprintf('%15s', $stats->totalSources()) . "\t" . sprintf('%15s', isset($changes['sour']) ? $changes['sour'] : 0) . Mail::EOL . sprintf('%-25s', I18N::translate('Repositories')) . "\t" . sprintf('%15s', $stats->totalRepositories()) . "\t" . sprintf('%15s', isset($changes['repo']) ? $changes['repo'] : 0) . Mail::EOL . sprintf('%-25s', I18N::translate('Media objects')) . "\t" . sprintf('%15s', $stats->totalMedia()) . "\t" . sprintf('%15s', isset($changes['media']) ? $changes['media'] : 0) . Mail::EOL . sprintf('%-25s', I18N::translate('Notes')) . "\t" . sprintf('%15s', $stats->totalNotes()) . "\t" . sprintf('%15s', isset($changes['note']) ? $changes['note'] : 0) . Mail::EOL . Mail::EOL;
             $message .= $message_gedcom;
             //Errors
             $sql = 'SELECT SQL_CACHE log_message, gedcom_id, COUNT(log_id) as nblogs, MAX(log_time) as lastoccurred' . ' FROM `##log`' . ' WHERE log_type = :log_type AND (gedcom_id = :gedcom_id OR ISNULL(gedcom_id))' . ' AND log_time >= DATE_ADD( NOW(), INTERVAL - :nb_days DAY)' . ' GROUP BY log_message, gedcom_id' . ' ORDER BY lastoccurred DESC';
             $errors = Database::prepare($sql)->execute(array('log_type' => Log::TYPE_ERROR, 'gedcom_id' => $tree->getTreeId(), 'nb_days' => $nbdays))->fetchAll();
             $nb_errors = 0;
             $tmp_message = '';
             $nb_char_count_title = strlen(I18N::translate('Count'));
             $nb_char_type = max(strlen(I18N::translate('Type')), strlen(I18N::translate('Site')), strlen(I18N::translate('Tree')));
             foreach ($errors as $error) {
                 $tmp_message .= sprintf('%' . $nb_char_count_title . 'd', $error->nblogs) . "\t";
                 $tmp_message .= sprintf('%' . $nb_char_type . 's', is_null($error->gedcom_id) ? I18N::translate('Site') : I18N::translate('Tree'));
                 $tmp_message .= "\t" . sprintf('%20s', $error->lastoccurred) . "\t";
                 $tmp_message .= str_replace("\n", "\n\t\t\t\t\t\t", $error->log_message) . Mail::EOL;
                 $nb_errors += $error->nblogs;
             }
             if ($nb_errors > 0) {
                 $message .= I18N::translate('Errors [%d]', $nb_errors) . Mail::EOL . '-------------' . Mail::EOL . WT_BASE_URL . 'admin_site_logs.php' . Mail::EOL . I18N::translate('Count') . "\t" . sprintf('%-' . $nb_char_type . 's', I18N::translate('Type')) . "\t" . sprintf('%-20s', I18N::translate('Last occurrence')) . "\t" . I18N::translate('Error') . Mail::EOL . str_repeat('-', $nb_char_count_title) . "\t" . str_repeat('-', $nb_char_type) . "\t" . str_repeat('-', 20) . "\t" . str_repeat('-', strlen(I18N::translate('Error'))) . Mail::EOL . $tmp_message . Mail::EOL;
             } else {
                 $message .= I18N::translate('No errors', $nb_errors) . Mail::EOL . Mail::EOL;
             }
             $tmpres = true;
             if ($webmaster->getPreference('contactmethod') !== 'messaging' && $webmaster->getPreference('contactmethod') !== 'none') {
                 $tmpres = Mail::systemMessage($tree, $webmaster, $subject, $message);
             }
             $res = $tmpres && (!$one_tree_done || $one_tree_done && $res);
             $one_tree_done = true;
         }
     }
     return $res;
 }
Пример #8
0
/**
 * Number of children
 *
 * @param int   $z_axis
 * @param int[] $z_boundaries
 * @param Stats $stats
 *
 * @return int
 */
function number_of_children($z_axis, array $z_boundaries, Stats $stats)
{
    $total = 0;
    if ($z_axis === 300) {
        $num = $stats->statsChildrenQuery(false);
        foreach ($num as $values) {
            fill_y_data(0, $values['f_numchil'], $values['total']);
            $total += $values['f_numchil'] * $values['total'];
        }
    } elseif ($z_axis === 301) {
        $num = $stats->statsChildrenQuery(false, 'M');
        foreach ($num as $values) {
            fill_y_data(0, $values['num'], $values['total']);
            $total += $values['num'] * $values['total'];
        }
        $num = $stats->statsChildrenQuery(false, 'F');
        foreach ($num as $values) {
            fill_y_data(1, $values['num'], $values['total']);
            $total += $values['num'] * $values['total'];
        }
    } else {
        $zstart = 0;
        foreach ($z_boundaries as $boundary) {
            $num = $stats->statsChildrenQuery(false, 'BOTH', $zstart, $boundary);
            foreach ($num as $values) {
                fill_y_data($boundary, $values['f_numchil'], $values['total']);
                $total += $values['f_numchil'] * $values['total'];
            }
            $zstart = $boundary + 1;
        }
    }
    return $total;
}
Пример #9
0
    /**
     * Print a table of families
     *
     * @param Family[] $datalist
     *
     * @return string
     */
    public static function familyTable($datalist)
    {
        global $WT_TREE, $controller;
        $table_id = 'table-fam-' . 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("#' . $table_id . '").dataTable( {
					dom: \'<"H"<"filtersH_' . $table_id . '"><"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 husb givn */ {dataSort: 2},
						/*  1 husb surn */ {dataSort: 3},
						/*  2 GIVN,SURN */ {type: "unicode", visible: false},
						/*  3 SURN,GIVN */ {type: "unicode", visible: false},
						/*  4 age       */ {dataSort: 5, class: "center"},
						/*  5 AGE       */ {type: "num", visible: false},
						/*  6 wife givn */ {dataSort: 8},
						/*  7 wife surn */ {dataSort: 9},
						/*  8 GIVN,SURN */ {type: "unicode", visible: false},
						/*  9 SURN,GIVN */ {type: "unicode", visible: false},
						/* 10 age       */ {dataSort: 11, class: "center"},
						/* 11 AGE       */ {type: "num", visible: false},
						/* 12 marr date */ {dataSort: 13},
						/* 13 MARR:DATE */ {visible: false},
						/* 14 anniv     */ {dataSort: 13, class: "center"},
						/* 15 marr plac */ {type: "unicode"},
						/* 16 children  */ {dataSort: 17, class: "center"},
						/* 17 NCHI      */ {type: "num", visible: false},
						/* 18 CHAN      */ {dataSort: 19, visible: ' . ($WT_TREE->getPreference('SHOW_LAST_CHANGE') ? 'true' : 'false') . '},
						/* 19 CHAN_sort */ {visible: false},
						/* 20 MARR      */ {visible: false},
						/* 21 DEAT      */ {visible: false},
						/* 22 TREE      */ {visible: false}
					],
					sorting: [[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("#fam_list_table-charts_' . $table_id . '").slideToggle();
				})
				/* Filter buttons in table header */
				.on("click", "button[data-filter-column]", function() {
					var btn = $(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(".fam-list").css("visibility", "visible");
				jQuery(".loading-image").css("display", "none");
		');
        $stats = new Stats($WT_TREE);
        $max_age = max($stats->oldestMarriageMaleAge(), $stats->oldestMarriageFemaleAge()) + 1;
        //-- init chart data
        $marr_by_age = array();
        for ($age = 0; $age <= $max_age; $age++) {
            $marr_by_age[$age] = '';
        }
        $birt_by_decade = array();
        $marr_by_decade = array();
        for ($year = 1550; $year < 2030; $year += 10) {
            $birt_by_decade[$year] = '';
            $marr_by_decade[$year] = '';
        }
        $html = '
			<div class="loading-image">&nbsp;</div>
			<div class="fam-list">
				<table id="' . $table_id . '">
					<thead>
						<tr>
							<th colspan="23">
								<div class="btn-toolbar">
									<div class="btn-group">
										<button
											type="button"
											data-filter-column="21"
											data-filter-value="N"
											class="ui-state-default"
											title="' . I18N::translate('Show individuals who are alive or couples where both partners are alive.') . '"
										>
											' . I18N::translate('Both alive') . '
										</button>
										<button
											type="button"
											data-filter-column="21"
											data-filter-value="W"
											class="ui-state-default"
											title="' . I18N::translate('Show couples where only the female partner is deceased.') . '"
										>
											' . I18N::translate('Widower') . '
										</button>
										<button
											type="button"
											data-filter-column="21"
											data-filter-value="H"
											class="ui-state-default"
											title="' . I18N::translate('Show couples where only the male partner is deceased.') . '"
										>
											' . I18N::translate('Widow') . '
										</button>
										<button
											type="button"
											data-filter-column="21"
											data-filter-value="Y"
											class="ui-state-default"
											title="' . I18N::translate('Show individuals who are dead or couples where both partners are deceased.') . '"
										>
											' . I18N::translate('Both dead') . '
										</button>
									</div>
									<div class="btn-group">
										<button
											type="button"
											data-filter-column="22"
											data-filter-value="R"
											class="ui-state-default"
											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.') . '"
										>
											' . I18N::translate('Roots') . '
										</button>
										<button
											type="button"
											data-filter-column="22"
											data-filter-value="L"
											class="ui-state-default"
											title="' . I18N::translate('Show “leaves” couples or individuals.  These are individuals who are alive but have no children recorded in the database.') . '"
										>
											' . I18N::translate('Leaves') . '
										</button>
									</div>
									<div class="btn-group">
										<button
											type="button"
											data-filter-column="20"
											data-filter-value="U"
											class="ui-state-default"
											title="' . I18N::translate('Show couples with an unknown marriage date.') . '"
										>
											' . GedcomTag::getLabel('MARR') . '
										</button>
										<button
											type="button"
											data-filter-column="20"
											data-filter-value="YES"
											class="ui-state-default"
											title="' . I18N::translate('Show couples who married more than 100 years ago.') . '"
										>
											' . GedcomTag::getLabel('MARR') . '&gt;100
										</button>
										<button
											type="button"
											data-filter-column="20"
											data-filter-value="Y100"
											class="ui-state-default"
											title="' . I18N::translate('Show couples who married within the last 100 years.') . '"
										>
											' . GedcomTag::getLabel('MARR') . '&lt;=100
										</button>
										<button
											type="button"
											data-filter-column="20"
											data-filter-value="D"
											class="ui-state-default"
											title="' . I18N::translate('Show divorced couples.') . '"
										>
											' . GedcomTag::getLabel('DIV') . '
										</button>
										<button
											type="button"
											data-filter-column="20"
											data-filter-value="M"
											class="ui-state-default"
											title="' . I18N::translate('Show couples where either partner married more than once.') . '"
										>
											' . I18N::translate('Multiple marriages') . '
										</button>
									</div>
								</div>
							</th>
						</tr>
						<tr>
							<th>' . GedcomTag::getLabel('GIVN') . '</th>
							<th>' . GedcomTag::getLabel('SURN') . '</th>
							<th>HUSB:GIVN_SURN</th>
							<th>HUSB:SURN_GIVN</th>
							<th>' . GedcomTag::getLabel('AGE') . '</th>
							<th>AGE</th>
							<th>' . GedcomTag::getLabel('GIVN') . '</th>
							<th>' . GedcomTag::getLabel('SURN') . '</th>
							<th>WIFE:GIVN_SURN</th>
							<th>WIFE:SURN_GIVN</th>
							<th>' . GedcomTag::getLabel('AGE') . '</th>
							<th>AGE</th>
							<th>' . GedcomTag::getLabel('MARR') . '</th>
							<th>MARR:DATE</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('CHAN') . '</th>
						<th>CHAN</th>
						<th>MARR</th>
						<th>DEAT</th>
						<th>TREE</th>
					</tr>
				</thead>
				<tfoot>
					<tr>
						<th colspan="23">
							<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
        foreach ($datalist as $family) {
            //-- Retrieve husband and wife
            $husb = $family->getHusband();
            if (is_null($husb)) {
                $husb = new Individual('H', '0 @H@ INDI', null, $family->getTree());
            }
            $wife = $family->getWife();
            if (is_null($wife)) {
                $wife = new Individual('W', '0 @W@ INDI', null, $family->getTree());
            }
            if (!$family->canShow()) {
                continue;
            }
            if ($family->isPendingAddtion()) {
                $class = ' class="new"';
            } elseif ($family->isPendingDeletion()) {
                $class = ' class="old"';
            } else {
                $class = '';
            }
            $html .= '<tr' . $class . '>';
            //-- Husband name(s)
            $html .= '<td colspan="2">';
            foreach ($husb->getAllNames() as $num => $name) {
                if ($name['type'] == 'NAME') {
                    $title = '';
                } else {
                    $title = 'title="' . strip_tags(GedcomTag::getLabel($name['type'], $husb)) . '"';
                }
                if ($num == $husb->getPrimaryName()) {
                    $class = ' class="name2"';
                    $sex_image = $husb->getSexImage();
                    list($surn, $givn) = explode(',', $name['sort']);
                } else {
                    $class = '';
                    $sex_image = '';
                }
                // Only show married names if they are the name we are filtering by.
                if ($name['type'] != '_MARNM' || $num == $husb->getPrimaryName()) {
                    $html .= '<a ' . $title . ' href="' . $family->getHtmlUrl() . '"' . $class . '>' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>' . $sex_image . '<br>';
                }
            }
            // Husband parents
            $html .= $husb->getPrimaryParentsNames('parents details1', 'none');
            $html .= '</td>';
            // Dummy column to match colspan in header
            $html .= '<td style="display:none;"></td>';
            //-- Husb GIVN
            // 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>';
            $mdate = $family->getMarriageDate();
            //-- Husband age
            $hdate = $husb->getBirthDate();
            if ($hdate->isOK() && $mdate->isOK()) {
                if ($hdate->gregorianYear() >= 1550 && $hdate->gregorianYear() < 2030) {
                    $birt_by_decade[(int) ($hdate->gregorianYear() / 10) * 10] .= $husb->getSex();
                }
                $hage = Date::getAge($hdate, $mdate, 0);
                if ($hage >= 0 && $hage <= $max_age) {
                    $marr_by_age[$hage] .= $husb->getSex();
                }
            }
            $html .= '<td>' . Date::getAge($hdate, $mdate, 2) . '</td><td>' . Date::getAge($hdate, $mdate, 1) . '</td>';
            //-- Wife name(s)
            $html .= '<td colspan="2">';
            foreach ($wife->getAllNames() as $num => $name) {
                if ($name['type'] == 'NAME') {
                    $title = '';
                } else {
                    $title = 'title="' . strip_tags(GedcomTag::getLabel($name['type'], $wife)) . '"';
                }
                if ($num == $wife->getPrimaryName()) {
                    $class = ' class="name2"';
                    $sex_image = $wife->getSexImage();
                    list($surn, $givn) = explode(',', $name['sort']);
                } else {
                    $class = '';
                    $sex_image = '';
                }
                // Only show married names if they are the name we are filtering by.
                if ($name['type'] != '_MARNM' || $num == $wife->getPrimaryName()) {
                    $html .= '<a ' . $title . ' href="' . $family->getHtmlUrl() . '"' . $class . '>' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>' . $sex_image . '<br>';
                }
            }
            // Wife parents
            $html .= $wife->getPrimaryParentsNames('parents details1', 'none');
            $html .= '</td>';
            // Dummy column to match colspan in header
            $html .= '<td style="display:none;"></td>';
            //-- Wife GIVN
            //-- Husb GIVN
            // 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>';
            $mdate = $family->getMarriageDate();
            //-- Wife age
            $wdate = $wife->getBirthDate();
            if ($wdate->isOK() && $mdate->isOK()) {
                if ($wdate->gregorianYear() >= 1550 && $wdate->gregorianYear() < 2030) {
                    $birt_by_decade[(int) ($wdate->gregorianYear() / 10) * 10] .= $wife->getSex();
                }
                $wage = Date::getAge($wdate, $mdate, 0);
                if ($wage >= 0 && $wage <= $max_age) {
                    $marr_by_age[$wage] .= $wife->getSex();
                }
            }
            $html .= '<td>' . Date::getAge($wdate, $mdate, 2) . '</td><td>' . Date::getAge($wdate, $mdate, 1) . '</td>';
            //-- Marriage date
            $html .= '<td>';
            if ($marriage_dates = $family->getAllMarriageDates()) {
                foreach ($marriage_dates as $n => $marriage_date) {
                    if ($n) {
                        $html .= '<br>';
                    }
                    $html .= '<div>' . $marriage_date->display(true) . '</div>';
                }
                if ($marriage_dates[0]->gregorianYear() >= 1550 && $marriage_dates[0]->gregorianYear() < 2030) {
                    $marr_by_decade[(int) ($marriage_dates[0]->gregorianYear() / 10) * 10] .= $husb->getSex() . $wife->getSex();
                }
            } elseif ($family->getFacts('_NMR')) {
                $html .= I18N::translate('no');
            } elseif ($family->getFacts('MARR')) {
                $html .= I18N::translate('yes');
            } else {
                $html .= '&nbsp;';
            }
            $html .= '</td>';
            //-- Event date (sortable)hidden by datatables code
            $html .= '<td>';
            if ($marriage_dates) {
                $html .= $marriage_date->julianDay();
            } else {
                $html .= 0;
            }
            $html .= '</td>';
            //-- Marriage anniversary
            $html .= '<td>' . Date::getAge($mdate, null, 2) . '</td>';
            //-- Marriage place
            $html .= '<td>';
            foreach ($family->getAllMarriagePlaces() as $n => $marriage_place) {
                $tmp = new Place($marriage_place, $family->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 = $family->getNumberOfChildren();
            $html .= '<td>' . I18N::number($nchi) . '</td><td>' . $nchi . '</td>';
            //-- Last change
            $html .= '<td>' . $family->LastChangeTimestamp() . '</td>';
            $html .= '<td>' . $family->LastChangeTimestamp(true) . '</td>';
            //-- Sorting by marriage date
            $html .= '<td>';
            if (!$family->canShow() || !$mdate->isOK()) {
                $html .= 'U';
            } else {
                if (Date::compare($mdate, $d100y) > 0) {
                    $html .= 'Y100';
                } else {
                    $html .= 'YES';
                }
            }
            if ($family->getFacts(WT_EVENTS_DIV)) {
                $html .= 'D';
            }
            if (count($husb->getSpouseFamilies()) > 1 || count($wife->getSpouseFamilies()) > 1) {
                $html .= 'M';
            }
            $html .= '</td>';
            //-- Sorting alive/dead
            $html .= '<td>';
            if ($husb->isDead() && $wife->isDead()) {
                $html .= 'Y';
            }
            if ($husb->isDead() && !$wife->isDead()) {
                if ($wife->getSex() == 'F') {
                    $html .= 'H';
                }
                if ($wife->getSex() == 'M') {
                    $html .= 'W';
                }
                // male partners
            }
            if (!$husb->isDead() && $wife->isDead()) {
                if ($husb->getSex() == 'M') {
                    $html .= 'W';
                }
                if ($husb->getSex() == 'F') {
                    $html .= 'H';
                }
                // female partners
            }
            if (!$husb->isDead() && !$wife->isDead()) {
                $html .= 'N';
            }
            $html .= '</td>';
            //-- Roots or Leaves
            $html .= '<td>';
            if (!$husb->getChildFamilies() && !$wife->getChildFamilies()) {
                $html .= 'R';
            } elseif (!$husb->isDead() && !$wife->isDead() && $family->getNumberOfChildren() < 1) {
                $html .= 'L';
            } else {
                $html .= '&nbsp;';
            }
            $html .= '</td>
			</tr>';
        }
        $html .= '
					</tbody>
				</table>
				<div id="fam_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($marr_by_decade, I18N::translate('Decade of marriage')) . '
							</td>
						</tr>
						<tr>
							<td colspan="2">
								' . self::chartByAge($marr_by_age, I18N::translate('Age in year of marriage')) . '
							</td>
						</tr>
					</table>
				</div>
			</div>';
        return $html;
    }
 /**
  * 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');
     $number_of_surnames = $this->getBlockSetting($block_id, 'number_of_surnames', self::DEFAULT_NUMBER_OF_SURNAMES);
     $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';
     foreach (array('show_common_surnames', 'number_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', '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('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
     } else {
         $title = '';
     }
     $title .= $this->getTitle() . ' — ' . $WT_TREE->getTitleHtml();
     $stats = new Stats($WT_TREE);
     $content = '';
     if ($show_last_update) {
         $content .= '<p>' . I18N::translate('This family tree was last updated on %s.', strip_tags($stats->gedcomUpdated())) . '</p>';
     }
     /** 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&amp;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&amp;surname_sublist=yes&amp;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') . ':&nbsp;' . $stats->averageLifespanMale();
             $content .= '&nbsp;&nbsp;&nbsp;' . I18N::translate('Females') . ':&nbsp;' . $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>';
     }
     $content .= '</div>';
     if ($show_common_surnames) {
         $surnames = FunctionsDb::getTopSurnames($WT_TREE->getTreeId(), 0, (int) $number_of_surnames);
         $all_surnames = array();
         foreach (array_keys($surnames) as $surname) {
             $all_surnames = array_merge($all_surnames, QueryName::surnames($WT_TREE, $surname, '', false, false));
         }
         if (!empty($surnames)) {
             ksort($all_surnames);
             $content .= '<div class="clearfloat">';
             $content .= '<p>';
             $content .= '<strong>' . I18N::translate('Most common surnames') . '</strong>';
             $content .= '<br>';
             $content .= '<span class="common_surnames">' . FunctionsPrintLists::surnameList($all_surnames, 2, false, 'indilist.php', $WT_TREE) . '</span>';
             $content .= '</p>';
             $content .= '</div>';
         }
     }
     if ($template) {
         return Theme::theme()->formatBlock($id, $title, $class, $content);
     } else {
         return $content;
     }
 }
Пример #11
0
						return;
					}
					else {
						jQuery("#loading-indicator").addClass("loading-image");
					}
					ui.jqXHR.success(function() {
						ui.tab.data("loaded", true);
					});
				}
			});
		')->pageHeader();
    echo '<div id="statistics-page"><h2>', I18N::translate('Statistics'), '</h2>', '<div id="statistics_chart">', '<ul>', '<li><a href="statistics.php?ged=', $WT_TREE->getNameUrl(), '&amp;ajax=1&amp;tab=0">', '<span id="stats-indi">', I18N::translate('Individuals'), '</span></a></li>', '<li><a href="statistics.php?ged=', $WT_TREE->getNameUrl(), '&amp;ajax=1&amp;tab=1">', '<span id="stats-fam">', I18N::translate('Families'), '</span></a></li>', '<li><a href="statistics.php?ged=', $WT_TREE->getNameUrl(), '&amp;ajax=1&amp;tab=2">', '<span id="stats-other">', I18N::translate('Others'), '</span></a></li>', '<li><a href="statistics.php?ged=', $WT_TREE->getNameUrl(), '&amp;ajax=1&amp;tab=3">', '<span id="stats-own">', I18N::translate('Own charts'), '</span></a></li>', '</ul>', '<div id="loading-indicator" style="margin:auto;width:100%;"></div>', '</div>', '</div>', '<br><br>';
} else {
    $controller = new AjaxController();
    $controller->pageHeader()->addInlineJavascript('autocomplete();')->addInlineJavascript('jQuery("#loading-indicator").removeClass("loading-image");');
    $stats = new Stats($WT_TREE);
    if ($tab == 0) {
        echo '<fieldset>
		<legend>', I18N::translate('Total individuals: %s', $stats->totalIndividuals()), '</legend>
		<table class="facts_table">
			<tr>
				<td class="facts_label">', I18N::translate('Total males'), '</td>
				<td class="facts_label">', I18N::translate('Total females'), '</td>
				<td class="facts_label">', I18N::translate('Total living'), '</td>
				<td class="facts_label">', I18N::translate('Total dead'), '</td>
			</tr>
			<tr>
				<td class="facts_value" align="center">', $stats->totalSexMales(), '</td>
				<td class="facts_value" align="center">', $stats->totalSexFemales(), '</td>
				<td class="facts_value" align="center">', $stats->totalLiving(), '</td>
				<td class="facts_value" align="center">', $stats->totalDeceased(), '</td>
Пример #12
0
    /**
     * Print a table of families
     *
     * @param Family[] $families
     *
     * @return string
     */
    public static function familyTable($families)
    {
        global $WT_TREE, $controller;
        $table_id = 'table-fam-' . 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["text-asc"] = textCompareAsc;
				jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
				jQuery("#' . $table_id . '").dataTable( {
					dom: \'<"H"<"filtersH_' . $table_id . '"><"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: [
						/* Given names         */ { type: "text" },
						/* Surnames            */ { type: "text" },
						/* Age                 */ { type: "num" },
						/* Given names         */ { type: "text" },
						/* Surnames            */ { type: "text" },
						/* Age                 */ { type: "num" },
						/* Marriage date       */ { type: "num" },
						/* Anniversary         */ { type: "num" },
						/* Marriage place      */ { type: "text" },
						/* Children            */ { type: "num" },
						/* Last change         */ { visible: ' . ($WT_TREE->getPreference('SHOW_LAST_CHANGE') ? 'true' : 'false') . ' },
						/* Filter marriage     */ { sortable: false },
						/* Filter alive/dead   */ { sortable: false },
						/* Filter tree         */ { sortable: false }
					],
					sorting: [[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("#fam_list_table-charts_' . $table_id . '").slideToggle();
				})
				/* Filter buttons in table header */
				.on("click", "button[data-filter-column]", function() {
					var btn = $(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(".fam-list").css("visibility", "visible");
				jQuery(".loading-image").css("display", "none");
		');
        $stats = new Stats($WT_TREE);
        $max_age = max($stats->oldestMarriageMaleAge(), $stats->oldestMarriageFemaleAge()) + 1;
        // init chart data
        $marr_by_age = array();
        for ($age = 0; $age <= $max_age; $age++) {
            $marr_by_age[$age] = '';
        }
        $birt_by_decade = array();
        $marr_by_decade = array();
        for ($year = 1550; $year < 2030; $year += 10) {
            $birt_by_decade[$year] = '';
            $marr_by_decade[$year] = '';
        }
        $html = '
			<div class="loading-image"></div>
			<div class="fam-list">
				<table id="' . $table_id . '">
					<thead>
						<tr>
							<th colspan="14">
								<div class="btn-toolbar">
									<div class="btn-group">
										<button
											type="button"
											data-filter-column="12"
											data-filter-value="N"
											class="ui-state-default"
											title="' . I18N::translate('Show individuals who are alive or couples where both partners are alive.') . '"
										>
											' . I18N::translate('Both alive') . '
										</button>
										<button
											type="button"
											data-filter-column="12"
											data-filter-value="W"
											class="ui-state-default"
											title="' . I18N::translate('Show couples where only the female partner is dead.') . '"
										>
											' . I18N::translate('Widower') . '
										</button>
										<button
											type="button"
											data-filter-column="12"
											data-filter-value="H"
											class="ui-state-default"
											title="' . I18N::translate('Show couples where only the male partner is dead.') . '"
										>
											' . I18N::translate('Widow') . '
										</button>
										<button
											type="button"
											data-filter-column="12"
											data-filter-value="Y"
											class="ui-state-default"
											title="' . I18N::translate('Show individuals who are dead or couples where both partners are dead.') . '"
										>
											' . I18N::translate('Both dead') . '
										</button>
									</div>
									<div class="btn-group">
										<button
											type="button"
											data-filter-column="13"
											data-filter-value="R"
											class="ui-state-default"
											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.') . '"
										>
											' . I18N::translate('Roots') . '
										</button>
										<button
											type="button"
											data-filter-column="13"
											data-filter-value="L"
											class="ui-state-default"
											title="' . I18N::translate('Show “leaves” couples or individuals. These are individuals who are alive but have no children recorded in the database.') . '"
										>
											' . I18N::translate('Leaves') . '
										</button>
									</div>
									<div class="btn-group">
										<button
											type="button"
											data-filter-column="11"
											data-filter-value="U"
											class="ui-state-default"
											title="' . I18N::translate('Show couples with an unknown marriage date.') . '"
										>
											' . GedcomTag::getLabel('MARR') . '
										</button>
										<button
											type="button"
											data-filter-column="11"
											data-filter-value="YES"
											class="ui-state-default"
											title="' . I18N::translate('Show couples who married more than 100 years ago.') . '"
										>
											' . GedcomTag::getLabel('MARR') . '&gt;100
										</button>
										<button
											type="button"
											data-filter-column="11"
											data-filter-value="Y100"
											class="ui-state-default"
											title="' . I18N::translate('Show couples who married within the last 100 years.') . '"
										>
											' . GedcomTag::getLabel('MARR') . '&lt;=100
										</button>
										<button
											type="button"
											data-filter-column="11"
											data-filter-value="D"
											class="ui-state-default"
											title="' . I18N::translate('Show divorced couples.') . '"
										>
											' . GedcomTag::getLabel('DIV') . '
										</button>
										<button
											type="button"
											data-filter-column="11"
											data-filter-value="M"
											class="ui-state-default"
											title="' . I18N::translate('Show couples where either partner married more than once.') . '"
										>
											' . I18N::translate('Multiple marriages') . '
										</button>
									</div>
								</div>
							</th>
						</tr>
						<tr>
							<th>' . GedcomTag::getLabel('GIVN') . '</th>
							<th>' . GedcomTag::getLabel('SURN') . '</th>
							<th>' . GedcomTag::getLabel('AGE') . '</th>
							<th>' . GedcomTag::getLabel('GIVN') . '</th>
							<th>' . GedcomTag::getLabel('SURN') . '</th>
							<th>' . GedcomTag::getLabel('AGE') . '</th>
							<th>' . GedcomTag::getLabel('MARR') . '</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>' . GedcomTag::getLabel('CHAN') . '</th>
							<th hidden></th>
							<th hidden></th>
							<th hidden></th>
						</tr>
					</thead>
					<tfoot>
						<tr>
							<th colspan="14">
								<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>';
        $hundred_years_ago = new Date(date('Y') - 100);
        foreach ($families as $family) {
            // Retrieve husband and wife
            $husb = $family->getHusband();
            if (is_null($husb)) {
                $husb = new Individual('H', '0 @H@ INDI', null, $family->getTree());
            }
            $wife = $family->getWife();
            if (is_null($wife)) {
                $wife = new Individual('W', '0 @W@ INDI', null, $family->getTree());
            }
            if (!$family->canShow()) {
                continue;
            }
            if ($family->isPendingAddtion()) {
                $class = ' class="new"';
            } elseif ($family->isPendingDeletion()) {
                $class = ' class="old"';
            } else {
                $class = '';
            }
            $html .= '<tr' . $class . '>';
            // Husband name(s)
            // Extract Given names and Surnames for sorting
            list($surn_givn, $givn_surn) = self::sortableNames($husb);
            $html .= '<td colspan="2" data-sort="' . Filter::escapeHtml($givn_surn) . '">';
            foreach ($husb->getAllNames() as $num => $name) {
                if ($name['type'] == 'NAME') {
                    $title = '';
                } else {
                    $title = 'title="' . strip_tags(GedcomTag::getLabel($name['type'], $husb)) . '"';
                }
                if ($num == $husb->getPrimaryName()) {
                    $class = ' class="name2"';
                    $sex_image = $husb->getSexImage();
                } else {
                    $class = '';
                    $sex_image = '';
                }
                // Only show married names if they are the name we are filtering by.
                if ($name['type'] != '_MARNM' || $num == $husb->getPrimaryName()) {
                    $html .= '<a ' . $title . ' href="' . $family->getHtmlUrl() . '"' . $class . '>' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>' . $sex_image . '<br>';
                }
            }
            // Husband parents
            $html .= $husb->getPrimaryParentsNames('parents details1', 'none');
            $html .= '</td>';
            // Hidden column for sortable name
            $html .= '<td hidden data-sort="' . Filter::escapeHtml($surn_givn) . '"></td>';
            // Husband age
            $mdate = $family->getMarriageDate();
            $hdate = $husb->getBirthDate();
            if ($hdate->isOK() && $mdate->isOK()) {
                if ($hdate->gregorianYear() >= 1550 && $hdate->gregorianYear() < 2030) {
                    $birt_by_decade[(int) ($hdate->gregorianYear() / 10) * 10] .= $husb->getSex();
                }
                $hage = Date::getAge($hdate, $mdate, 0);
                if ($hage >= 0 && $hage <= $max_age) {
                    $marr_by_age[$hage] .= $husb->getSex();
                }
            }
            $html .= '<td class="center" data=-sort="' . Date::getAge($hdate, $mdate, 1) . '">' . Date::getAge($hdate, $mdate, 2) . '</td>';
            // Wife name(s)
            // Extract Given names and Surnames for sorting
            list($surn_givn, $givn_surn) = self::sortableNames($wife);
            $html .= '<td colspan="2" data-sort="' . Filter::escapeHtml($givn_surn) . '">';
            foreach ($wife->getAllNames() as $num => $name) {
                if ($name['type'] == 'NAME') {
                    $title = '';
                } else {
                    $title = 'title="' . strip_tags(GedcomTag::getLabel($name['type'], $wife)) . '"';
                }
                if ($num == $wife->getPrimaryName()) {
                    $class = ' class="name2"';
                    $sex_image = $wife->getSexImage();
                } else {
                    $class = '';
                    $sex_image = '';
                }
                // Only show married names if they are the name we are filtering by.
                if ($name['type'] != '_MARNM' || $num == $wife->getPrimaryName()) {
                    $html .= '<a ' . $title . ' href="' . $family->getHtmlUrl() . '"' . $class . '>' . FunctionsPrint::highlightSearchHits($name['full']) . '</a>' . $sex_image . '<br>';
                }
            }
            // Wife parents
            $html .= $wife->getPrimaryParentsNames('parents details1', 'none');
            $html .= '</td>';
            // Hidden column for sortable name
            $html .= '<td hidden data-sort="' . Filter::escapeHtml($surn_givn) . '"></td>';
            // Wife age
            $mdate = $family->getMarriageDate();
            $wdate = $wife->getBirthDate();
            if ($wdate->isOK() && $mdate->isOK()) {
                if ($wdate->gregorianYear() >= 1550 && $wdate->gregorianYear() < 2030) {
                    $birt_by_decade[(int) ($wdate->gregorianYear() / 10) * 10] .= $wife->getSex();
                }
                $wage = Date::getAge($wdate, $mdate, 0);
                if ($wage >= 0 && $wage <= $max_age) {
                    $marr_by_age[$wage] .= $wife->getSex();
                }
            }
            $html .= '<td class="center" data-sort="' . Date::getAge($wdate, $mdate, 1) . '">' . Date::getAge($wdate, $mdate, 2) . '</td>';
            // Marriage date
            $html .= '<td data-sort="' . $family->getMarriageDate()->julianDay() . '">';
            if ($marriage_dates = $family->getAllMarriageDates()) {
                foreach ($marriage_dates as $n => $marriage_date) {
                    if ($n) {
                        $html .= '<br>';
                    }
                    $html .= '<div>' . $marriage_date->display(true) . '</div>';
                }
                if ($marriage_dates[0]->gregorianYear() >= 1550 && $marriage_dates[0]->gregorianYear() < 2030) {
                    $marr_by_decade[(int) ($marriage_dates[0]->gregorianYear() / 10) * 10] .= $husb->getSex() . $wife->getSex();
                }
            } elseif ($family->getFacts('_NMR')) {
                $html .= I18N::translate('no');
            } elseif ($family->getFacts('MARR')) {
                $html .= I18N::translate('yes');
            } else {
                $html .= '&nbsp;';
            }
            $html .= '</td>';
            // Marriage anniversary
            $html .= '<td class="center" data-sort="' . -$family->getMarriageDate()->julianDay() . '">' . Date::getAge($family->getMarriageDate(), null, 2) . '</td>';
            // Marriage place
            $html .= '<td>';
            foreach ($family->getAllMarriagePlaces() as $n => $marriage_place) {
                $tmp = new Place($marriage_place, $family->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
            $html .= '<td class="center" data-sort="' . $family->getNumberOfChildren() . '">' . I18N::number($family->getNumberOfChildren()) . '</td>';
            // Last change
            $html .= '<td data-sort="' . $family->lastChangeTimestamp(true) . '">' . $family->lastChangeTimestamp() . '</td>';
            // Filter by marriage date
            $html .= '<td hidden>';
            if (!$family->canShow() || !$mdate->isOK()) {
                $html .= 'U';
            } else {
                if (Date::compare($mdate, $hundred_years_ago) > 0) {
                    $html .= 'Y100';
                } else {
                    $html .= 'YES';
                }
            }
            if ($family->getFacts(WT_EVENTS_DIV)) {
                $html .= 'D';
            }
            if (count($husb->getSpouseFamilies()) > 1 || count($wife->getSpouseFamilies()) > 1) {
                $html .= 'M';
            }
            $html .= '</td>';
            // Filter by alive/dead
            $html .= '<td hidden>';
            if ($husb->isDead() && $wife->isDead()) {
                $html .= 'Y';
            }
            if ($husb->isDead() && !$wife->isDead()) {
                if ($wife->getSex() == 'F') {
                    $html .= 'H';
                }
                if ($wife->getSex() == 'M') {
                    $html .= 'W';
                }
                // male partners
            }
            if (!$husb->isDead() && $wife->isDead()) {
                if ($husb->getSex() == 'M') {
                    $html .= 'W';
                }
                if ($husb->getSex() == 'F') {
                    $html .= 'H';
                }
                // female partners
            }
            if (!$husb->isDead() && !$wife->isDead()) {
                $html .= 'N';
            }
            $html .= '</td>';
            // Filter by roots/leaves
            $html .= '<td hidden>';
            if (!$husb->getChildFamilies() && !$wife->getChildFamilies()) {
                $html .= 'R';
            } elseif (!$husb->isDead() && !$wife->isDead() && $family->getNumberOfChildren() === 0) {
                $html .= 'L';
            }
            $html .= '</td>
			</tr>';
        }
        $html .= '
					</tbody>
				</table>
				<div id="fam_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($marr_by_decade, I18N::translate('Decade of marriage')) . '</td>
						</tr>
						<tr>
							<td colspan="2">' . self::chartByAge($marr_by_age, I18N::translate('Age in year of marriage')) . '</td>
						</tr>
					</table>
				</div>
			</div>';
        return $html;
    }