Ejemplo n.º 1
0
 /**
  * Create the chart controller
  *
  * @param int $show_full needed for use by charts module
  */
 public function __construct($show_full = 1)
 {
     global $WT_TREE;
     parent::__construct();
     $rootid = Filter::get('rootid', WT_REGEX_XREF);
     $this->root = Individual::getInstance($rootid, $WT_TREE);
     if (!$this->root) {
         // Missing root individual? Show the chart for someone.
         $this->root = $this->getSignificantIndividual();
     }
     if (!$this->root || !$this->root->canShowName()) {
         http_response_code(404);
         $this->error_message = I18N::translate('This individual does not exist or you do not have permission to view it.');
     }
     // Extract parameter from form
     if ($show_full) {
         $this->show_full = Filter::getInteger('show_full', 0, 1, $WT_TREE->getPreference('PEDIGREE_FULL_DETAILS'));
     } else {
         $this->show_full = 0;
     }
     $this->box = new \stdClass();
     if ($this->showFull()) {
         $this->box->width = Theme::theme()->parameter('chart-box-x');
         $this->box->height = Theme::theme()->parameter('chart-box-y');
     } else {
         $this->box->width = Theme::theme()->parameter('compact-chart-box-x');
         $this->box->height = Theme::theme()->parameter('compact-chart-box-y');
     }
 }
Ejemplo n.º 2
0
 /**
  * {@inheritDoc}
  * @see \MyArtJaub\Webtrees\Mvc\Controller\MvcController::__construct(AbstractModule $module)
  */
 public function __construct(AbstractModule $module)
 {
     global $WT_TREE;
     parent::__construct($module);
     $this->sosa_provider = new SosaProvider($WT_TREE, Auth::user());
     $this->generation = Filter::getInteger('gen');
     $this->view_bag = new ViewBag();
     $this->view_bag->set('generation', $this->generation);
     $this->view_bag->set('max_gen', $this->sosa_provider->getLastGeneration());
     $this->view_bag->set('is_setup', $this->sosa_provider->isSetup() && $this->view_bag->get('max_gen', 0) > 0);
 }
Ejemplo n.º 3
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;
     switch (Filter::get('action')) {
         case 'deletenews':
             $news_id = Filter::get('news_id');
             if ($news_id) {
                 Database::prepare("DELETE FROM `##news` WHERE news_id = ?")->execute(array($news_id));
             }
             break;
     }
     $more_news = Filter::getInteger('more_news');
     $limit = 5 * (1 + $more_news);
     $articles = Database::prepare("SELECT SQL_CACHE news_id, user_id, gedcom_id, UNIX_TIMESTAMP(updated) + :offset AS updated, subject, body FROM `##news` WHERE gedcom_id = :tree_id ORDER BY updated DESC LIMIT :limit")->execute(array('offset' => WT_TIMESTAMP_OFFSET, 'tree_id' => $WT_TREE->getTreeId(), 'limit' => $limit))->fetchAll();
     $count = Database::prepare("SELECT SQL_CACHE COUNT(*) FROM `##news` WHERE gedcom_id = :tree_id")->execute(array('tree_id' => $WT_TREE->getTreeId()))->fetchOne();
     $id = $this->getName() . $block_id;
     $class = $this->getName() . '_block';
     $title = $this->getTitle();
     $content = '';
     if (empty($articles)) {
         $content .= I18N::translate('No news articles have been submitted.');
     }
     foreach ($articles as $article) {
         $content .= '<div class="news_box">';
         $content .= '<div class="news_title">' . Filter::escapeHtml($article->subject) . '</div>';
         $content .= '<div class="news_date">' . FunctionsDate::formatTimestamp($article->updated) . '</div>';
         if ($article->body == strip_tags($article->body)) {
             $article->body = nl2br($article->body, false);
         }
         $content .= $article->body;
         if (Auth::isManager($WT_TREE)) {
             $content .= '<hr>';
             $content .= '<a href="#" onclick="window.open(\'editnews.php?news_id=\'+' . $article->news_id . ', \'_blank\', news_window_specs); return false;">' . I18N::translate('Edit') . '</a>';
             $content .= ' | ';
             $content .= '<a href="index.php?action=deletenews&amp;news_id=' . $article->news_id . '&amp;ctype=' . $ctype . '&amp;ged=' . $WT_TREE->getNameHtml() . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($article->subject)) . "');\">" . I18N::translate('Delete') . '</a><br>';
         }
         $content .= '</div>';
     }
     if (Auth::isManager($WT_TREE)) {
         $content .= '<a href="#" onclick="window.open(\'editnews.php?gedcom_id=' . $WT_TREE->getTreeId() . '\', \'_blank\', news_window_specs); return false;">' . I18N::translate('Add a news article') . '</a>';
     }
     if ($count > $limit) {
         if (Auth::isManager($WT_TREE)) {
             $content .= ' | ';
         }
         $content .= '<a href="#" onclick="jQuery(\'#' . $id . '\').load(\'index.php?ctype=gedcom&amp;ged=' . $WT_TREE->getNameUrl() . '&amp;block_id=' . $block_id . '&amp;action=ajax&amp;more_news=' . ($more_news + 1) . '\'); return false;">' . I18N::translate('More news articles') . "</a>";
     }
     if ($template) {
         return Theme::theme()->formatBlock($id, $title, $class, $content);
     } else {
         return $content;
     }
 }
Ejemplo n.º 4
0
 /**
  * Create the descendancy controller
  */
 public function __construct()
 {
     global $WT_TREE;
     parent::__construct();
     // Extract parameters from form
     $this->chart_style = Filter::getInteger('chart_style', 0, 3, 0);
     $this->generations = Filter::getInteger('generations', 2, $WT_TREE->getPreference('MAX_DESCENDANCY_GENERATIONS'), $WT_TREE->getPreference('DEFAULT_PEDIGREE_GENERATIONS'));
     if ($this->root && $this->root->canShowName()) {
         $this->setPageTitle(I18N::translate('Descendants of %s', $this->root->getFullName()));
     } else {
         $this->setPageTitle(I18N::translate('Descendants'));
     }
 }
Ejemplo n.º 5
0
 /**
  * Startup activity
  */
 public function __construct()
 {
     global $WT_TREE;
     parent::__construct();
     // Extract form parameters
     $this->show_cousins = Filter::getInteger('show_cousins', 0, 1);
     $this->chart_style = Filter::getInteger('chart_style', 0, 3);
     $this->generations = Filter::getInteger('PEDIGREE_GENERATIONS', 2, $WT_TREE->getPreference('MAX_PEDIGREE_GENERATIONS'), $WT_TREE->getPreference('DEFAULT_PEDIGREE_GENERATIONS'));
     if ($this->root && $this->root->canShowName()) {
         $this->setPageTitle(I18N::translate('Ancestors of %s', $this->root->getFullName()));
     } else {
         $this->setPageTitle(I18N::translate('Ancestors'));
     }
 }
Ejemplo n.º 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;
     switch (Filter::get('action')) {
         case 'deletenews':
             $news_id = Filter::getInteger('news_id');
             if ($news_id) {
                 Database::prepare("DELETE FROM `##news` WHERE news_id = ?")->execute(array($news_id));
             }
             break;
     }
     $block = $this->getBlockSetting($block_id, 'block', '1');
     foreach (array('block') as $name) {
         if (array_key_exists($name, $cfg)) {
             ${$name} = $cfg[$name];
         }
     }
     $usernews = Database::prepare("SELECT SQL_CACHE news_id, user_id, gedcom_id, UNIX_TIMESTAMP(updated) AS updated, subject, body FROM `##news` WHERE user_id = ? ORDER BY updated DESC")->execute(array(Auth::id()))->fetchAll();
     $id = $this->getName() . $block_id;
     $class = $this->getName() . '_block';
     $title = '';
     $title .= $this->getTitle();
     $content = '';
     if (!$usernews) {
         $content .= I18N::translate('You have not created any journal items.');
     }
     foreach ($usernews as $news) {
         $content .= '<div class="journal_box">';
         $content .= '<div class="news_title">' . $news->subject . '</div>';
         $content .= '<div class="news_date">' . FunctionsDate::formatTimestamp($news->updated) . '</div>';
         if ($news->body == strip_tags($news->body)) {
             // No HTML?
             $news->body = nl2br($news->body, false);
         }
         $content .= $news->body . '<br><br>';
         $content .= '<a href="#" onclick="window.open(\'editnews.php?news_id=\'+' . $news->news_id . ', \'_blank\', indx_window_specs); return false;">' . I18N::translate('Edit') . '</a> | ';
         $content .= '<a href="index.php?action=deletenews&amp;news_id=' . $news->news_id . '&amp;ctype=' . $ctype . '&amp;ged=' . $WT_TREE->getNameHtml() . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($news->subject)) . "');\">" . I18N::translate('Delete') . '</a><br>';
         $content .= "</div><br>";
     }
     $content .= '<br><a href="#" onclick="window.open(\'editnews.php?user_id=' . Auth::id() . '\', \'_blank\', indx_window_specs); return false;">' . I18N::translate('Add a new journal entry') . '</a>';
     if ($template) {
         if ($block) {
             $class .= ' small_inner_block';
         }
         return Theme::theme()->formatBlock($id, $title, $class, $content);
     } else {
         return $content;
     }
 }
Ejemplo n.º 7
0
 /**
  * Create the controller
  */
 public function __construct()
 {
     global $WT_TREE;
     parent::__construct();
     $default_generations = $WT_TREE->getPreference('DEFAULT_PEDIGREE_GENERATIONS');
     // Extract the request parameters
     $this->fan_style = Filter::getInteger('fan_style', 2, 4, 3);
     $this->fan_width = Filter::getInteger('fan_width', 50, 500, 100);
     $this->generations = Filter::getInteger('generations', 2, 9, $default_generations);
     if ($this->root && $this->root->canShowName()) {
         $this->setPageTitle(I18N::translate('Fan chart of %s', $this->root->getFullName()));
     } else {
         $this->setPageTitle(I18N::translate('Fan chart'));
     }
 }
Ejemplo n.º 8
0
 /**
  * Create a family-book controller
  */
 public function __construct()
 {
     global $WT_TREE;
     parent::__construct();
     // Extract the request parameters
     $this->show_spouse = Filter::getInteger('show_spouse', 0, 1);
     $this->descent = Filter::getInteger('descent', 0, 9, 5);
     $this->generations = Filter::getInteger('generations', 2, $WT_TREE->getPreference('MAX_DESCENDANCY_GENERATIONS'), 2);
     $this->bhalfheight = $this->getBoxDimensions()->height / 2;
     if ($this->root && $this->root->canShowName()) {
         $this->setPageTitle(I18N::translate('Family book of %s', $this->root->getFullName()));
     } else {
         $this->setPageTitle(I18N::translate('Family book'));
     }
     //Checks how many generations of descendency is for the person for formatting purposes
     $this->dgenerations = $this->maxDescendencyGenerations($this->root->getXref(), 0);
     if ($this->dgenerations < 1) {
         $this->dgenerations = 1;
     }
 }
Ejemplo n.º 9
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;
     switch (Filter::get('action')) {
         case 'deletenews':
             $news_id = Filter::getInteger('news_id');
             if ($news_id) {
                 Database::prepare("DELETE FROM `##news` WHERE news_id = ?")->execute(array($news_id));
             }
             break;
     }
     $articles = Database::prepare("SELECT SQL_CACHE news_id, user_id, gedcom_id, UNIX_TIMESTAMP(updated) + :offset AS updated, subject, body FROM `##news` WHERE user_id = :user_id ORDER BY updated DESC")->execute(array('offset' => WT_TIMESTAMP_OFFSET, 'user_id' => Auth::id()))->fetchAll();
     $id = $this->getName() . $block_id;
     $class = $this->getName() . '_block';
     $title = $this->getTitle();
     $content = '';
     if (empty($articles)) {
         $content .= '<p>' . I18N::translate('You have not created any journal items.') . '</p>';
     }
     foreach ($articles as $article) {
         $content .= '<div class="journal_box">';
         $content .= '<div class="news_title">' . Filter::escapeHtml($article->subject) . '</div>';
         $content .= '<div class="news_date">' . FunctionsDate::formatTimestamp($article->updated) . '</div>';
         if ($article->body == strip_tags($article->body)) {
             $article->body = nl2br($article->body, false);
         }
         $content .= $article->body;
         $content .= '<a href="#" onclick="window.open(\'editnews.php?news_id=\'+' . $article->news_id . ', \'_blank\', indx_window_specs); return false;">' . I18N::translate('Edit') . '</a>';
         $content .= ' | ';
         $content .= '<a href="index.php?action=deletenews&amp;news_id=' . $article->news_id . '&amp;ctype=' . $ctype . '&amp;ged=' . $WT_TREE->getNameHtml() . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($article->subject)) . "');\">" . I18N::translate('Delete') . '</a><br>';
         $content .= '</div><br>';
     }
     $content .= '<p><a href="#" onclick="window.open(\'editnews.php?user_id=' . Auth::id() . '\', \'_blank\', indx_window_specs); return false;">' . I18N::translate('Add a journal entry') . '</a></p>';
     if ($template) {
         return Theme::theme()->formatBlock($id, $title, $class, $content);
     } else {
         return $content;
     }
 }
Ejemplo n.º 10
0
 /**
  * Create the hourglass controller.
  *
  * @param string $rootid
  * @param int    $show_full
  * @param bool   $loadJS
  */
 public function __construct($rootid = '', $show_full = 1, $loadJS = true)
 {
     global $WT_TREE;
     parent::__construct($show_full);
     // Extract parameters from
     $this->show_spouse = Filter::getInteger('show_spouse', 0, 1, 0);
     $this->generations = Filter::getInteger('generations', 2, $WT_TREE->getPreference('MAX_DESCENDANCY_GENERATIONS'), 3);
     $this->canLoadJS = $loadJS;
     //-- flip the arrows for RTL languages
     if (I18N::direction() === 'ltr') {
         $this->left_arrow = 'icon-larrow';
         $this->right_arrow = 'icon-rarrow';
     } else {
         $this->left_arrow = 'icon-rarrow';
         $this->right_arrow = 'icon-larrow';
     }
     $this->bhalfheight = (int) ($this->getBoxDimensions()->height / 2);
     //Checks how many generations of descendency is for the person for formatting purposes
     $this->dgenerations = $this->maxDescendencyGenerations($this->root, 0);
     if ($this->dgenerations < 1) {
         $this->dgenerations = 1;
     }
     $this->setPageTitle(I18N::translate('Hourglass chart of %s', $this->root->getFullName()));
 }
Ejemplo n.º 11
0
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
namespace Fisharebest\Webtrees;

/**
 * Defined in session.php
 *
 * @global Tree $WT_TREE
 */
global $WT_TREE;
use Fisharebest\Webtrees\Controller\PageController;
use Fisharebest\Webtrees\Module\CkeditorModule;
define('WT_SCRIPT_NAME', 'block_edit.php');
require './includes/session.php';
$block_id = Filter::getInteger('block_id');
$block = Database::prepare("SELECT SQL_CACHE * FROM `##block` WHERE block_id=?")->execute(array($block_id))->fetchOneRow();
// Check access.  (1) the block must exist and be enabled, (2) gedcom blocks require
// managers, (3) user blocks require the user or an admin
$blocks = Module::getActiveBlocks($WT_TREE);
if (!$block || !array_key_exists($block->module_name, $blocks) || $block->gedcom_id && !Auth::isManager(Tree::findById($block->gedcom_id)) || $block->user_id && $block->user_id != Auth::id() && !Auth::isAdmin()) {
    header('Location: ' . WT_BASE_URL);
    return;
}
$block = $blocks[$block->module_name];
if (Filter::post('save')) {
    $ctype = Filter::post('ctype', 'user', 'gedcom');
    header('Location: ' . WT_BASE_URL . 'index.php?ctype=' . $ctype . '&ged=' . $WT_TREE->getNameUrl());
    $block->configureBlock($block_id);
    return;
}
Ejemplo n.º 12
0
    /**
     * Display a map showing the originas of ones ancestors.
     */
    private function pedigreeMap()
    {
        global $controller, $WT_TREE;
        $MAX_PEDIGREE_GENERATIONS = $WT_TREE->getPreference('MAX_PEDIGREE_GENERATIONS');
        $controller = new ChartController();
        $this->generations = Filter::getInteger('PEDIGREE_GENERATIONS', 2, $WT_TREE->getPreference('MAX_PEDIGREE_GENERATIONS'), $WT_TREE->getPreference('DEFAULT_PEDIGREE_GENERATIONS'));
        $this->treesize = pow(2, $this->generations) - 1;
        $this->ancestors = array_values($controller->sosaAncestors($this->generations));
        // Start of internal configuration variables
        // Limit this to match available number of icons.
        // 8 generations equals 255 individuals
        $MAX_PEDIGREE_GENERATIONS = min($MAX_PEDIGREE_GENERATIONS, 8);
        // End of internal configuration variables
        $controller->setPageTitle(I18N::translate('Pedigree map of %s', $controller->root->getFullName()))->pageHeader()->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)->addInlineJavascript('autocomplete();');
        echo '<link type="text/css" href="', WT_STATIC_URL, WT_MODULES_DIR, 'googlemap/css/wt_v3_googlemap.css" rel="stylesheet">';
        echo '<div id="pedigreemap-page">
				<h2>', $controller->getPageTitle(), '</h2>';
        // -- print the form to change the number of displayed generations
        ?>
		<form name="people" method="get" action="?">
			<input type="hidden" name="ged" value="<?php 
        echo $WT_TREE->getNameHtml();
        ?>
">
			<input type="hidden" name="mod" value="googlemap">
			<input type="hidden" name="mod_action" value="pedigree_map">
			<table class="list_table" width="555">
				<tr>
					<td class="descriptionbox wrap">
						<?php 
        echo I18N::translate('Individual');
        ?>
					</td>
					<td class="optionbox">
						<input class="pedigree_form" data-autocomplete-type="INDI" type="text" id="rootid" name="rootid" size="3" value="<?php 
        echo $controller->root->getXref();
        ?>
">
						<?php 
        echo FunctionsPrint::printFindIndividualLink('rootid');
        ?>
					</td>
					<td class="topbottombar" rowspan="2">
						<input type="submit" value="<?php 
        echo I18N::translate('View');
        ?>
">
					</td>
				</tr>
				<tr>
					<td class="descriptionbox wrap">
						<?php 
        echo I18N::translate('Generations');
        ?>
					</td>
					<td class="optionbox">
						<select name="PEDIGREE_GENERATIONS">
						<?php 
        for ($p = 3; $p <= $MAX_PEDIGREE_GENERATIONS; $p++) {
            echo '<option value="', $p, '" ';
            if ($p == $this->generations) {
                echo 'selected';
            }
            echo '>', $p, '</option>';
        }
        ?>
						</select>
					</td>
				</tr>
			</table>
		</form>
		<!-- end of form -->

		<!-- count records by type -->
		<?php 
        $curgen = 1;
        $priv = 0;
        $count = 0;
        $miscount = 0;
        $missing = '';
        $latlongval = array();
        $lat = array();
        $lon = array();
        for ($i = 0; $i < $this->treesize; $i++) {
            // -- check to see if we have moved to the next generation
            if ($i + 1 >= pow(2, $curgen)) {
                $curgen++;
            }
            $person = $this->ancestors[$i];
            if (!empty($person)) {
                $name = $person->getFullName();
                if ($name == I18N::translate('Private')) {
                    $priv++;
                }
                $place = $person->getBirthPlace();
                if (empty($place)) {
                    $latlongval[$i] = null;
                } else {
                    $latlongval[$i] = $this->getLatitudeAndLongitudeFromPlaceLocation($person->getBirthPlace());
                }
                if ($latlongval[$i]) {
                    $lat[$i] = str_replace(array('N', 'S', ','), array('', '-', '.'), $latlongval[$i]->pl_lati);
                    $lon[$i] = str_replace(array('E', 'W', ','), array('', '-', '.'), $latlongval[$i]->pl_long);
                    if ($lat[$i] && $lon[$i]) {
                        $count++;
                    } else {
                        // The place is in the table but has empty values
                        if ($name) {
                            if ($missing) {
                                $missing .= ', ';
                            }
                            $missing .= '<a href="' . $person->getHtmlUrl() . '">' . $name . '</a>';
                            $miscount++;
                        }
                    }
                } else {
                    // There was no place, or not listed in the map table
                    if ($name) {
                        if ($missing) {
                            $missing .= ', ';
                        }
                        $missing .= '<a href="' . $person->getHtmlUrl() . '">' . $name . '</a>';
                        $miscount++;
                    }
                }
            }
        }
        //<!-- end of count records by type -->
        //<!-- start of map display -->
        echo '<div id="pedigreemap_chart">';
        echo '<table class="tabs_table" cellspacing="0" cellpadding="0" border="0" width="100%">';
        echo '<tr>';
        echo '<td valign="top">';
        echo '<div id="pm_map" style="border: 1px solid gray; height: ', $this->getSetting('GM_YSIZE'), 'px; font-size: 0.9em;';
        echo '"><i class="icon-loading-large"></i></div>';
        if (Auth::isAdmin()) {
            echo '<table width="100%">';
            echo '<tr><td align="left">';
            echo '<a href="module.php?mod=googlemap&amp;mod_action=admin_config">', I18N::translate('Google Maps™ preferences'), '</a>';
            echo '</td>';
            echo '<td align="center">';
            echo '<a href="module.php?mod=googlemap&amp;mod_action=admin_places">', I18N::translate('Geographic data'), '</a>';
            echo '</td>';
            echo '<td align="right">';
            echo '<a href="module.php?mod=googlemap&amp;mod_action=admin_placecheck">', I18N::translate('Place check'), '</a>';
            echo '</td></tr>';
            echo '</table>';
        }
        echo '</td><td width="15px"></td>';
        echo '<td width="310px" valign="top">';
        echo '<div id="side_bar" style="width:300px; font-size:0.9em; overflow:auto; overflow-x:hidden; overflow-y:auto; height:', $this->getSetting('GM_YSIZE'), 'px;"></div></td>';
        echo '</tr>';
        echo '</table>';
        // display info under map
        echo '<hr>';
        echo '<table cellspacing="0" cellpadding="0" border="0" width="100%">';
        echo '<tr>';
        echo '<td valign="top">';
        // print summary statistics
        if (isset($curgen)) {
            $total = pow(2, $curgen) - 1;
            echo I18N::plural('%1$s individual displayed, out of the normal total of %2$s, from %3$s generations.', '%1$s individuals displayed, out of the normal total of %2$s, from %3$s generations.', $count, I18N::number($count), I18N::number($total), I18N::number($curgen)), '<br>';
            echo '</td>';
            echo '</tr>';
            echo '<tr>';
            echo '<td valign="top">';
            if ($priv) {
                echo I18N::plural('%s individual is private.', '%s individuals are private.', $priv, $priv), '<br>';
            }
            if ($count + $priv != $total) {
                if ($miscount == 0) {
                    echo I18N::translate('No ancestors in the database.'), "<br>";
                } else {
                    echo I18N::plural('%1$s individual is missing birthplace map coordinates: %2$s.', '%1$s individuals are missing birthplace map coordinates: %2$s.', $miscount, I18N::number($miscount), $missing), '<br>';
                }
            }
        }
        echo '</td>';
        echo '</tr>';
        echo '</table>';
        echo '</div>';
        // close #pedigreemap_chart
        echo '</div>';
        // close #pedigreemap-page
        ?>
		<!-- end of map display -->
		<!-- Start of map scripts -->
		<?php 
        echo '<script src="', $this->googleMapsScript(), '"></script>';
        $controller->addInlineJavascript($this->pedigreeMapJavascript());
    }
Ejemplo n.º 13
0
        // This becomes a JSON list, not array, so need to fetch with numeric keys.
        $data = Database::prepare($sql_select . $where . $order_by . $limit)->execute($args)->fetchAll(PDO::FETCH_NUM);
        foreach ($data as &$datum) {
            $datum[2] = I18N::translate($datum[2]);
            $datum[3] = '<a href="gedrecord.php?pid=' . $datum[3] . '&ged=' . $datum[7] . '">' . $datum[3] . '</a>';
            $datum[4] = '<div class="gedcom-data" dir="ltr">' . Filter::escapeHtml($datum[4]) . '</div>';
            $datum[5] = '<div class="gedcom-data" dir="ltr">' . Filter::escapeHtml($datum[5]) . '</div>';
            $datum[6] = Filter::escapeHtml($datum[6]);
            $datum[7] = Filter::escapeHtml($datum[7]);
        }
        // Total filtered/unfiltered rows
        $recordsFiltered = (int) Database::prepare("SELECT FOUND_ROWS()")->fetchOne();
        $recordsTotal = (int) Database::prepare("SELECT COUNT(*) FROM `##change`")->fetchOne();
        header('Content-type: application/json');
        // See http://www.datatables.net/usage/server-side
        echo json_encode(array('draw' => Filter::getInteger('draw'), 'recordsTotal' => $recordsTotal, 'recordsFiltered' => $recordsFiltered, 'data' => $data));
        return;
}
$controller->pageHeader()->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addExternalJavascript(WT_DATATABLES_BOOTSTRAP_JS_URL)->addExternalJavascript(WT_MOMENT_JS_URL)->addExternalJavascript(WT_BOOTSTRAP_DATETIMEPICKER_JS_URL)->addInlineJavascript('
		jQuery(".table-site-changes").dataTable( {
			processing: true,
			serverSide: true,
			ajax: "' . WT_BASE_URL . WT_SCRIPT_NAME . '?action=load_json&from=' . $from . '&to=' . $to . '&type=' . $type . '&oldged=' . rawurlencode($oldged) . '&newged=' . rawurlencode($newged) . '&xref=' . rawurlencode($xref) . '&user='******'&gedc=' . rawurlencode($gedc) . '",
			' . I18N::datatablesI18N(array(10, 20, 50, 100, 500, 1000, -1)) . ',
			sorting: [[ 0, "desc" ]],
			pageLength: ' . Auth::user()->getPreference('admin_site_change_page_size', 10) . ',
			columns: [
			/* change_id   */ { visible: false },
			/* Timestamp   */ { sort: 0 },
			/* Status      */ { },
			/* Record      */ { },
Ejemplo n.º 14
0
 /**
  * Startup activity
  */
 public function __construct()
 {
     global $WT_TREE;
     parent::__construct();
     $this->setPageTitle(I18N::translate('Timeline'));
     $this->baseyear = (int) date('Y');
     $pids = Filter::getArray('pids', WT_REGEX_XREF);
     $remove = Filter::get('remove', WT_REGEX_XREF);
     foreach (array_unique($pids) as $pid) {
         if ($pid !== $remove) {
             $person = Individual::getInstance($pid, $WT_TREE);
             if ($person && $person->canShow()) {
                 $this->people[] = $person;
             }
         }
     }
     $this->pidlinks = '';
     foreach ($this->people as $indi) {
         // setup string of valid pids for links
         $this->pidlinks .= 'pids%5B%5D=' . $indi->getXref() . '&amp;';
         $bdate = $indi->getBirthDate();
         if ($bdate->isOK()) {
             $date = new GregorianDate($bdate->minimumJulianDay());
             $this->birthyears[$indi->getXref()] = $date->y;
             $this->birthmonths[$indi->getXref()] = max(1, $date->m);
             $this->birthdays[$indi->getXref()] = max(1, $date->d);
         }
         // find all the fact information
         $facts = $indi->getFacts();
         foreach ($indi->getSpouseFamilies() as $family) {
             foreach ($family->getFacts() as $fact) {
                 $facts[] = $fact;
             }
         }
         foreach ($facts as $event) {
             // get the fact type
             $fact = $event->getTag();
             if (!in_array($fact, $this->nonfacts)) {
                 // check for a date
                 $date = $event->getDate();
                 if ($date->isOK()) {
                     $date = new GregorianDate($date->minimumJulianDay());
                     $this->baseyear = min($this->baseyear, $date->y);
                     $this->topyear = max($this->topyear, $date->y);
                     if (!$indi->isDead()) {
                         $this->topyear = max($this->topyear, (int) date('Y'));
                     }
                     // do not add the same fact twice (prevents marriages from being added multiple times)
                     if (!in_array($event, $this->indifacts, true)) {
                         $this->indifacts[] = $event;
                     }
                 }
             }
         }
     }
     $scale = Filter::getInteger('scale', 0, 200);
     if ($scale === 0) {
         $this->scale = (int) (($this->topyear - $this->baseyear) / 20 * count($this->indifacts) / 4);
         if ($this->scale < 6) {
             $this->scale = 6;
         }
     } else {
         $this->scale = $scale;
     }
     if ($this->scale < 2) {
         $this->scale = 2;
     }
     $this->baseyear -= 5;
     $this->topyear += 5;
 }
Ejemplo n.º 15
0
/**
 * Defined in session.php
 *
 * @global Tree    $WT_TREE
 */
global $WT_TREE;
use Fisharebest\Webtrees\Controller\RelationshipController;
use Fisharebest\Webtrees\Functions\Functions;
use Fisharebest\Webtrees\Functions\FunctionsEdit;
use Fisharebest\Webtrees\Functions\FunctionsPrint;
define('WT_SCRIPT_NAME', 'relationship.php');
require './includes/session.php';
$controller = new RelationshipController();
$pid1 = Filter::get('pid1', WT_REGEX_XREF);
$pid2 = Filter::get('pid2', WT_REGEX_XREF);
$show_full = Filter::getInteger('show_full', 0, 1, $WT_TREE->getPreference('PEDIGREE_FULL_DETAILS'));
$find_all = Filter::getBool('find_all');
$person1 = Individual::getInstance($pid1, $WT_TREE);
$person2 = Individual::getInstance($pid2, $WT_TREE);
$controller->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)->addInlineJavascript('autocomplete();');
if ($person1 && $person2) {
    $controller->setPageTitle(I18N::translate('Relationships between %1$s and %2$s', $person1->getFullName(), $person2->getFullName()))->pageHeader();
    $paths = $controller->calculateRelationships($person1, $person2, $find_all);
} else {
    $controller->setPageTitle(I18N::translate('Relationships'))->pageHeader();
    $paths = array();
}
?>
<h2><?php 
echo $controller->getPageTitle();
?>
Ejemplo n.º 16
0
</a></li>
		<li class="active"><?php 
        echo $controller->getPageTitle();
        ?>
</li>
	</ol>
	<h1><?php 
        echo $controller->getPageTitle();
        ?>
</h1>

	<form method="post" action="?action=cleanup2">
	<table class="table table-bordered">
	<?php 
        // Check for idle users
        $month = Filter::getInteger('month', 1, 12, 6);
        echo '<tr><th colspan="2">', I18N::translate('Number of months since the last sign-in for a user’s account to be considered inactive: '), '</th>';
        echo '<td><select onchange="document.location=options[selectedIndex].value;">';
        for ($i = 1; $i <= 12; $i++) {
            echo '<option value="admin_users.php?action=cleanup&amp;month=' . $i . '" ';
            if ($i === $month) {
                echo 'selected';
            }
            echo '>', $i, '</option>';
        }
        echo '</select></td></tr>';
        // Check users not logged in too long
        $ucnt = 0;
        foreach (User::all() as $user) {
            if ($user->getPreference('sessiontime') === '0') {
                $datelogin = (int) $user->getPreference('reg_timestamp');
Ejemplo n.º 17
0
 /**
  * Create any of the other blocks.
  *
  * Use as #callBlock:block_name#
  *
  * @param string[] $params
  *
  * @return string
  */
 public function callBlock($params = array())
 {
     global $ctype;
     if (isset($params[0]) && $params[0] != '') {
         $block = $params[0];
     } else {
         return '';
     }
     $all_blocks = array();
     foreach (Module::getActiveBlocks($this->tree) as $name => $active_block) {
         if ($ctype == 'user' && $active_block->isUserBlock() || $ctype == 'gedcom' && $active_block->isGedcomBlock()) {
             $all_blocks[$name] = $active_block;
         }
     }
     if (!array_key_exists($block, $all_blocks) || $block == 'html') {
         return '';
     }
     // Build the config array
     array_shift($params);
     $cfg = array();
     foreach ($params as $config) {
         $bits = explode('=', $config);
         if (count($bits) < 2) {
             continue;
         }
         $v = array_shift($bits);
         $cfg[$v] = implode('=', $bits);
     }
     $block = $all_blocks[$block];
     $block_id = Filter::getInteger('block_id');
     $content = $block->getBlock($block_id, false, $cfg);
     return $content;
 }
Ejemplo n.º 18
0
    /**
     * Display a map showing the origins of ones ancestors.
     */
    private function pedigreeMap()
    {
        global $controller, $WT_TREE;
        $MAX_PEDIGREE_GENERATIONS = $WT_TREE->getPreference('MAX_PEDIGREE_GENERATIONS');
        // Limit this to match available number of icons.
        // 8 generations equals 255 individuals
        $MAX_PEDIGREE_GENERATIONS = min($MAX_PEDIGREE_GENERATIONS, 8);
        $controller = new ChartController();
        $generations = Filter::getInteger('PEDIGREE_GENERATIONS', 2, $MAX_PEDIGREE_GENERATIONS, $WT_TREE->getPreference('DEFAULT_PEDIGREE_GENERATIONS'));
        $this->treesize = pow(2, $generations) - 1;
        $this->ancestors = array_values($controller->sosaAncestors($generations));
        $controller->setPageTitle(I18N::translate('Pedigree map of %s', $controller->root->getFullName()))->pageHeader()->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)->addInlineJavascript("\n\t\t\t\tjQuery('head').prepend('<link type=\"text/css\" href =\"" . WT_STATIC_URL . WT_MODULES_DIR . "googlemap/css/wt_v3_googlemap.css\" rel=\"stylesheet\">');\n\t\t\t\tautocomplete();" . $this->pedigreeMapJavascript());
        echo '<div id="pedigreemap-page"><h2>', $controller->getPageTitle(), '</h2>';
        // -- print the form to change the number of displayed generations
        ?>
		<form name="people" method="get" action="?">
			<input type="hidden" name="ged" value="<?php 
        echo $WT_TREE->getNameHtml();
        ?>
">
			<input type="hidden" name="mod" value="googlemap">
			<input type="hidden" name="mod_action" value="pedigree_map">
			<table class="list_table">
				<tr>
					<td class="descriptionbox wrap">
						<label for="rootid">
							<?php 
        echo I18N::translate('Individual');
        ?>
						</label>
					</td>
					<td class="optionbox">
						<input class="pedigree_form" data-autocomplete-type="INDI" type="text" id="rootid" name="rootid" size="3" value="<?php 
        echo $controller->root->getXref();
        ?>
">
						<?php 
        echo FunctionsPrint::printFindIndividualLink('rootid');
        ?>
					</td>
					<td class="topbottombar" rowspan="2">
						<input type="submit" value="<?php 
        echo I18N::translate('view');
        ?>
">
					</td>
				</tr>
				<tr>
					<td class="descriptionbox wrap">
						<label for="PEDIGREE_GENERATIONS">
							<?php 
        echo I18N::translate('Generations');
        ?>
						</label>
					</td>
					<td class="optionbox">
						<select name="PEDIGREE_GENERATIONS" id="PEDIGREE_GENERATIONS">
						<?php 
        for ($p = 3; $p <= $MAX_PEDIGREE_GENERATIONS; $p++) {
            echo '<option value="', $p, '" ';
            if ($p == $generations) {
                echo 'selected';
            }
            echo '>', $p, '</option>';
        }
        ?>
						</select>
					</td>
				</tr>
			</table>
		</form>
		<!-- end of form -->

		<!-- count records by type -->
		<?php 
        $curgen = 1;
        $priv = 0;
        $count = 0;
        $miscount = 0;
        $missing = array();
        $latlongval = array();
        $lat = array();
        $lon = array();
        for ($i = 0; $i < $this->treesize; $i++) {
            // -- check to see if we have moved to the next generation
            if ($i + 1 >= pow(2, $curgen)) {
                $curgen++;
            }
            $person = $this->ancestors[$i];
            if (!empty($person)) {
                $name = $person->getFullName();
                if ($name == I18N::translate('Private')) {
                    $priv++;
                }
                $place = $person->getBirthPlace();
                if (empty($place)) {
                    $latlongval[$i] = null;
                } else {
                    $latlongval[$i] = $this->getLatitudeAndLongitudeFromPlaceLocation($person->getBirthPlace());
                }
                if ($latlongval[$i]) {
                    $lat[$i] = strtr($latlongval[$i]->pl_lati, array('N' => '', 'S' => '-', ',' => '.'));
                    $lon[$i] = strtr($latlongval[$i]->pl_long, array('N' => '', 'S' => '-', ',' => '.'));
                    if ($lat[$i] && $lon[$i]) {
                        $count++;
                    } else {
                        // The place is in the table but has empty values
                        if ($name) {
                            $missing[] = '<a href="' . $person->getHtmlUrl() . '">' . $name . '</a>';
                            $miscount++;
                        }
                    }
                } else {
                    // There was no place, or not listed in the map table
                    if ($name) {
                        $missing[] = '<a href="' . $person->getHtmlUrl() . '">' . $name . '</a>';
                        $miscount++;
                    }
                }
            }
        }
        //<!-- end of count records by type -->
        //<!-- start of map display -->
        echo '<div class="gm-pedigree-map">';
        echo '<div class="gm-wrapper">';
        echo '<div class="gm-map"><i class="icon-loading-large"></i></div>';
        echo '<div class="gm-ancestors"></div>';
        echo '</div>';
        if (Auth::isAdmin()) {
            echo '<div class="gm-options noprint">';
            echo '<a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_config">' . I18N::translate('Google Maps™ preferences') . '</a>';
            echo ' | <a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_places">' . I18N::translate('Geographic data') . '</a>';
            echo ' | <a href="module.php?mod=' . $this->getName() . '&amp;mod_action=admin_placecheck">' . I18N::translate('Place check') . '</a>';
            echo '</div>';
        }
        // display info under map
        echo '<hr>';
        // print summary statistics
        if (isset($curgen)) {
            $total = pow(2, $curgen) - 1;
            echo '<div>';
            echo I18N::plural('%1$s individual displayed, out of the normal total of %2$s, from %3$s generations.', '%1$s individuals displayed, out of the normal total of %2$s, from %3$s generations.', $count, I18N::number($count), I18N::number($total), I18N::number($curgen));
            echo '</div>';
            if ($priv) {
                echo '<div>' . I18N::plural('%s individual is private.', '%s individuals are private.', $priv, $priv), '</div>';
            }
            if ($count + $priv != $total) {
                if ($miscount == 0) {
                    echo '<div>' . I18N::translate('No ancestors in the database.'), '</div>';
                } else {
                    echo '<div>' . I18N::plural('%1$s individual is missing birthplace map coordinates: %2$s.', '%1$s individuals are missing birthplace map coordinates: %2$s.', $miscount, I18N::number($miscount), implode(I18N::$list_separator, $missing)), '</div>';
                }
            }
        }
        echo '</div>';
        echo '</div>';
        echo '<script src="', $this->googleMapsScript(), '"></script>';
    }
Ejemplo n.º 19
0
 /**
  * Respond to a request to delete a story.
  */
 private function delete()
 {
     global $WT_TREE;
     if (Auth::isEditor($WT_TREE)) {
         $block_id = Filter::getInteger('block_id');
         Database::prepare("DELETE FROM `##block_setting` WHERE block_id=?")->execute(array($block_id));
         Database::prepare("DELETE FROM `##block` WHERE block_id=?")->execute(array($block_id));
     } else {
         header('Location: ' . WT_BASE_URL);
         exit;
     }
 }
Ejemplo n.º 20
0
define('WT_SCRIPT_NAME', 'medialist.php');
require './includes/session.php';
$controller = new PageController();
$controller->setPageTitle(I18N::translate('Media objects'))->pageHeader();
$action = Filter::get('action');
$sortby = Filter::get('sortby', 'file|title', 'title');
if (!Auth::isEditor($WT_TREE)) {
    $sortby = 'title';
}
$page = Filter::getInteger('page');
$max = Filter::get('max', '10|20|30|40|50|75|100|125|150|200', '20');
$folder = Filter::get('folder', null, '');
// MySQL needs an empty string, not NULL
$filter = Filter::get('filter', null, '');
// MySQL needs an empty string, not NULL
$columns = Filter::getInteger('columns', 1, 2, 2);
$subdirs = Filter::get('subdirs', 'on');
$form_type = Filter::get('form_type', implode('|', array_keys(GedcomTag::getFileFormTypes())));
$currentdironly = $subdirs === 'on' ? false : true;
// reset all variables
if ($action === 'reset') {
    $sortby = 'title';
    $max = '20';
    $folder = '';
    $columns = '2';
    $currentdironly = true;
    $filter = '';
    $form_type = '';
}
// A list of all subfolders used by this tree
$folders = QueryMedia::folderList();
Ejemplo n.º 21
0
        $i++;
    }
    $zmax = $i;
    $zmax1 = $zmax - 1;
    $date = new Date('AFT ' . $hulpar[$zmax1]);
    $legend[$zmax] = strip_tags($date->display());
    $z_boundaries[$zmax] = 10000;
    $zmax = $zmax + 1;
    if ($zmax > 8) {
        $zmax = 8;
    }
}
global $legend, $xdata, $ydata, $xmax, $zmax, $z_boundaries, $xgiven, $zgiven, $percentage, $male_female;
$x_axis = Filter::getInteger('x-as', 1, 21, 11);
$y_axis = Filter::getInteger('y-as', 201, 202, 201);
$z_axis = Filter::getInteger('z-as', 300, 302, 302);
$stats = new Stats($WT_TREE);
$z_boundaries = array();
echo '<div class="statistics_chart" title="', I18N::translate('Statistics plot'), '">';
switch ($x_axis) {
    case '1':
        echo $stats->chartDistribution(array(Filter::get('chart_shows'), Filter::get('chart_type'), Filter::get('SURN')));
        break;
    case '2':
        echo $stats->chartDistribution(array(Filter::get('chart_shows'), 'birth_distribution_chart'));
        break;
    case '3':
        echo $stats->chartDistribution(array(Filter::get('chart_shows'), 'death_distribution_chart'));
        break;
    case '4':
        echo $stats->chartDistribution(array(Filter::get('chart_shows'), 'marriage_distribution_chart'));
 /**
  * Respond to a request to move a FAQ up the list.
  */
 private function moveup()
 {
     $block_id = Filter::getInteger('block_id');
     $block_order = Database::prepare("SELECT block_order FROM `##block` WHERE block_id = :block_id")->execute(array('block_id' => $block_id))->fetchOne();
     $swap_block = Database::prepare("SELECT block_order, block_id" . " FROM `##block`" . " WHERE block_order = (" . "  SELECT MAX(block_order) FROM `##block` WHERE block_order < :block_order AND module_name = :module_name_1" . " ) AND module_name = :module_name_2" . " LIMIT 1")->execute(array('block_order' => $block_order, 'module_name_1' => $this->getName(), 'module_name_2' => $this->getName()))->fetchOneRow();
     if ($swap_block) {
         Database::prepare("UPDATE `##block` SET block_order = :block_order WHERE block_id = :block_id")->execute(array('block_order' => $swap_block->block_order, 'block_id' => $block_id));
         Database::prepare("UPDATE `##block` SET block_order = :block_order WHERE block_id = :block_id")->execute(array('block_order' => $block_order, 'block_id' => $swap_block->block_id));
     }
 }
Ejemplo n.º 23
0
/**
 * Defined in session.php
 *
 * @global Tree $WT_TREE
 */
global $WT_TREE;
use Fisharebest\Webtrees\Controller\SimpleController;
use Fisharebest\Webtrees\Functions\FunctionsImport;
define('WT_SCRIPT_NAME', 'edit_changes.php');
require './includes/session.php';
$controller = new SimpleController();
$controller->restrictAccess(Auth::isModerator($WT_TREE))->setPageTitle(I18N::translate('Pending changes'))->pageHeader()->addInlineJavascript("\n\t\tfunction show_diff(diffurl) {\n\t\t\twindow.opener.location = diffurl;\n\t\t\treturn false;\n\t\t}\n\t");
$action = Filter::get('action');
$change_id = Filter::getInteger('change_id');
$index = Filter::get('index');
$ged = Filter::getInteger('ged');
echo '<div id="pending"><h2>', I18N::translate('Pending changes'), '</h2>';
switch ($action) {
    case 'undo':
        $gedcom_id = Database::prepare("SELECT gedcom_id FROM `##change` WHERE change_id=?")->execute(array($change_id))->fetchOne();
        $xref = Database::prepare("SELECT xref      FROM `##change` WHERE change_id=?")->execute(array($change_id))->fetchOne();
        // Undo a change, and subsequent changes to the same record
        Database::prepare("UPDATE `##change`" . " SET   status     = 'rejected'" . " WHERE status     = 'pending'" . " AND   gedcom_id  = ?" . " AND   xref       = ?" . " AND   change_id >= ?")->execute(array($gedcom_id, $xref, $change_id));
        break;
    case 'accept':
        $gedcom_id = Database::prepare("SELECT gedcom_id FROM `##change` WHERE change_id=?")->execute(array($change_id))->fetchOne();
        $xref = Database::prepare("SELECT xref      FROM `##change` WHERE change_id=?")->execute(array($change_id))->fetchOne();
        // Accept a change, and all previous changes to the same record
        $changes = Database::prepare("SELECT change_id, gedcom_id, gedcom_name, xref, old_gedcom, new_gedcom" . " FROM  `##change` c" . " JOIN  `##gedcom` g USING (gedcom_id)" . " WHERE c.status   = 'pending'" . " AND   gedcom_id  = ?" . " AND   xref       = ?" . " AND   change_id <= ?" . " ORDER BY change_id")->execute(array($gedcom_id, $xref, $change_id))->fetchAll();
        foreach ($changes as $change) {
            if (empty($change->new_gedcom)) {
Ejemplo n.º 24
0
 /** {@inheritdoc} */
 public function modAction($mod_action)
 {
     Database::updateSchema(self::SCHEMA_MIGRATION_PREFIX, self::SCHEMA_SETTING_NAME, self::SCHEMA_TARGET_VERSION);
     switch ($mod_action) {
         case 'admin_config':
             $template = new AdminTemplate();
             return $template->pageContent();
         case 'admin_search':
             // new settings
             $surname = Filter::post('SURNAME');
             $pid = Filter::post('PID');
             if ($surname) {
                 $soundex_std = Filter::postBool('soundex_std');
                 $soundex_dm = Filter::postBool('soundex_dm');
                 $indis = $this->module()->indisArray($surname, $soundex_std, $soundex_dm);
                 usort($indis, 'Fisharebest\\Webtrees\\Individual::compareBirthDate');
                 if (isset($indis) && count($indis) > 0) {
                     $pid = $indis[0]->getXref();
                 } else {
                     $result['error'] = I18N::translate('Error: The surname you entered doesn’t exist in this tree.');
                 }
             }
             if (isset($pid)) {
                 $FTV_SETTINGS = unserialize($this->getSetting('FTV_SETTINGS'));
                 if ($this->module()->searchArray($this->module()->searchArray($FTV_SETTINGS, 'TREE', Filter::getInteger('tree')), 'PID', $pid)) {
                     if ($surname) {
                         $result['error'] = I18N::translate('Error: The root person belonging to this surname already exists');
                     } else {
                         $result['error'] = I18N::translate('Error: A root person with ID %s already exists', $pid);
                     }
                 } else {
                     $record = Individual::getInstance($pid, $this->tree);
                     if ($record) {
                         $root = $record->getFullName() . ' (' . $record->getLifeSpan() . ')';
                         $title = $this->module()->getPageLink($pid);
                         $result = array('access_level' => '2', 'pid' => $pid, 'root' => $root, 'sort' => count($this->module()->searchArray($FTV_SETTINGS, 'TREE', Filter::getInteger('tree'))) + 1, 'surname' => $this->module()->getSurname($pid), 'title' => $title, 'tree' => Filter::getInteger('tree'));
                     } else {
                         if (empty($result['error'])) {
                             $result['error'] = I18N::translate('Error: A person with ID %s does not exist in this tree', $pid);
                         }
                     }
                 }
             }
             echo json_encode($result);
             break;
         case 'admin_add':
             $FTV_SETTINGS = unserialize($this->getSetting('FTV_SETTINGS'));
             $NEW_FTV_SETTINGS = $FTV_SETTINGS;
             $NEW_FTV_SETTINGS[] = array('TREE' => Filter::getInteger('tree'), 'SURNAME' => Filter::post('surname'), 'PID' => Filter::post('pid'), 'ACCESS_LEVEL' => Filter::postInteger('access_level'), 'SORT' => Filter::postInteger('sort'));
             $this->setSetting('FTV_SETTINGS', serialize(array_values($NEW_FTV_SETTINGS)));
             Log::addConfigurationLog($this->getTitle() . ' config updated');
             break;
         case 'admin_update':
             $FTV_SETTINGS = unserialize($this->getSetting('FTV_SETTINGS'));
             $new_surname = Filter::postArray('surname');
             $new_access_level = Filter::postArray('access_level');
             $new_sort = Filter::postArray('sort');
             foreach ($new_surname as $key => $new_surname) {
                 $FTV_SETTINGS[$key]['SURNAME'] = $new_surname;
             }
             foreach ($new_access_level as $key => $new_access_level) {
                 $FTV_SETTINGS[$key]['ACCESS_LEVEL'] = $new_access_level;
             }
             foreach ($new_sort as $key => $new_sort) {
                 $FTV_SETTINGS[$key]['SORT'] = $new_sort;
             }
             $NEW_FTV_SETTINGS = $this->module()->sortArray($FTV_SETTINGS, 'SORT');
             $this->setSetting('FTV_SETTINGS', serialize($NEW_FTV_SETTINGS));
             break;
         case 'admin_save':
             $FTV_OPTIONS = unserialize($this->getSetting('FTV_OPTIONS'));
             $FTV_OPTIONS[Filter::getInteger('tree')] = Filter::postArray('NEW_FTV_OPTIONS');
             $this->setSetting('FTV_OPTIONS', serialize($FTV_OPTIONS));
             Log::addConfigurationLog($this->getTitle() . ' config updated');
             // the cache has to be recreated because the image options could have been changed
             $this->module()->emptyCache();
             break;
         case 'admin_reset':
             $FTV_OPTIONS = unserialize($this->getSetting('FTV_OPTIONS'));
             unset($FTV_OPTIONS[Filter::getInteger('tree')]);
             $this->setSetting('FTV_OPTIONS', serialize($FTV_OPTIONS));
             Log::addConfigurationLog($this->getTitle() . ' options set to default');
             break;
         case 'admin_delete':
             $FTV_SETTINGS = unserialize($this->getSetting('FTV_SETTINGS'));
             unset($FTV_SETTINGS[Filter::getInteger('key')]);
             $this->setSetting('FTV_SETTINGS', serialize($FTV_SETTINGS));
             Log::addConfigurationLog($this->getTitle() . ' item deleted');
             break;
         case 'page':
             $template = new PageTemplate();
             return $template->pageContent();
             // See mediafirewall.php
         // See mediafirewall.php
         case 'thumbnail':
             $mid = Filter::get('mid', WT_REGEX_XREF);
             $media = Media::getInstance($mid, $this->tree);
             $mimetype = $media->mimeType();
             $cache_filename = $this->module()->cacheFileName($media);
             $filetime = filemtime($cache_filename);
             $filetimeHeader = gmdate('D, d M Y H:i:s', $filetime) . ' GMT';
             $expireOffset = 3600 * 24 * 7;
             // tell browser to cache this image for 7 days
             $expireHeader = gmdate('D, d M Y H:i:s', WT_TIMESTAMP + $expireOffset) . ' GMT';
             $etag = $media->getEtag();
             $filesize = filesize($cache_filename);
             // parse IF_MODIFIED_SINCE header from client
             $if_modified_since = 'x';
             if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
                 $if_modified_since = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']);
             }
             // parse IF_NONE_MATCH header from client
             $if_none_match = 'x';
             if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
                 $if_none_match = str_replace('"', '', $_SERVER['HTTP_IF_NONE_MATCH']);
             }
             // add caching headers.  allow browser to cache file, but not proxy
             header('Last-Modified: ' . $filetimeHeader);
             header('ETag: "' . $etag . '"');
             header('Expires: ' . $expireHeader);
             header('Cache-Control: max-age=' . $expireOffset . ', s-maxage=0, proxy-revalidate');
             // if this file is already in the user’s cache, don’t resend it
             // first check if the if_modified_since param matches
             if ($if_modified_since === $filetimeHeader) {
                 // then check if the etag matches
                 if ($if_none_match === $etag) {
                     http_response_code(304);
                     return;
                 }
             }
             // send headers for the image
             header('Content-Type: ' . $mimetype);
             header('Content-Disposition: filename="' . basename($cache_filename) . '"');
             header('Content-Length: ' . $filesize);
             // Some servers disable fpassthru() and readfile()
             if (function_exists('readfile')) {
                 readfile($cache_filename);
             } else {
                 $fp = fopen($cache_filename, 'rb');
                 if (function_exists('fpassthru')) {
                     fpassthru($fp);
                 } else {
                     while (!feof($fp)) {
                         echo fread($fp, 65536);
                     }
                 }
                 fclose($fp);
             }
             break;
         case 'show_pdf':
             $template = new PdfTemplate();
             return $template->pageBody();
         case 'pdf_data':
             $template = new PdfTemplate();
             return $template->pageData();
         case 'pdf_thumb_data':
             $xref = Filter::get('mid');
             $mediaobject = Media::getInstance($xref, $this->tree);
             $thumb = Filter::get('thumb');
             if ($thumb === '2') {
                 // Fancy thumb
                 echo $this->module()->cacheFileName($mediaobject);
             } else {
                 echo $mediaobject->getServerFilename('thumb');
             }
             break;
         default:
             http_response_code(404);
             break;
     }
 }
Ejemplo n.º 25
0
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
namespace Fisharebest\Webtrees;

use Fisharebest\Webtrees\Controller\AjaxController;
use Fisharebest\Webtrees\Functions\FunctionsImport;
use PDOException;
define('WT_SCRIPT_NAME', 'import.php');
require './includes/session.php';
// Don't use ged=XX as we want to be able to run without changing the current gedcom.
// This will let us load several gedcoms together, or to edit one while loading another.
$gedcom_id = Filter::getInteger('gedcom_id');
$tree = Tree::findById($gedcom_id);
if (!$tree || !Auth::isManager($tree, Auth::user())) {
    http_response_code(403);
    return;
}
$controller = new AjaxController();
$controller->pageHeader();
// Don't allow the user to cancel the request.  We do not want to be left
// with an incomplete transaction.
ignore_user_abort(true);
// Run in a transaction
Database::beginTransaction();
// Only allow one process to import each gedcom at a time
Database::prepare("SELECT * FROM `##gedcom_chunk` WHERE gedcom_id=? FOR UPDATE")->execute(array($gedcom_id));
// What is the current import status?
Ejemplo n.º 26
0
		<li><a href="admin_trees_manage.php"><?php 
        echo I18N::translate('Manage family trees');
        ?>
</a></li>
		<li class="active"><?php 
        echo $controller->getPageTitle();
        ?>
</li>
	</ol>

	<h1><?php 
        echo $controller->getPageTitle();
        ?>
</h1>
	<?php 
        $tree = Tree::findById(Filter::getInteger('gedcom_id'));
        // Check it exists
        if (!$tree) {
            break;
        }
        $gedcom_filename = $tree->getPreference('gedcom_filename');
        ?>
	<p>
		<?php 
        echo I18N::translate('This will delete all the genealogy data from “%s” and replace it with data from a GEDCOM file.', $tree->getTitleHtml());
        ?>
	</p>
	<form class="form form-horizontal" name="gedcomimportform" method="post" enctype="multipart/form-data" onsubmit="return checkGedcomImportForm('<?php 
        echo Filter::escapeHtml(I18N::translate('You have selected a GEDCOM file with a different name.  Is this correct?'));
        ?>
');">
Ejemplo n.º 27
0
 /**
  * SosaConfig@computePartial
  */
 public function computePartial()
 {
     global $WT_TREE;
     $controller = new AjaxController();
     $controller->restrictAccess($this->canUpdate());
     $view_bag = new ViewBag();
     $view_bag->set('is_success', false);
     $user = User::find(Filter::getInteger('userid', -1));
     $indi = Individual::getInstance(Filter::get('pid', WT_REGEX_XREF), $WT_TREE);
     if ($user && $indi) {
         $calculator = new SosaCalculator($WT_TREE, $user);
         if ($calculator->computeFromIndividual($indi)) {
             $view_bag->set('is_success', true);
         }
     } else {
         $view_bag->set('error', I18N::translate('Non existing individual'));
     }
     ViewFactory::make('SosaComputeResult', $this, $controller, $view_bag)->render();
 }
 /**
  * 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, $controller, $WT_TREE;
     $action = Filter::get('action');
     switch ($action) {
         case 'deletefav':
             $favorite_id = Filter::getInteger('favorite_id');
             if ($favorite_id) {
                 self::deleteFavorite($favorite_id);
             }
             break;
         case 'addfav':
             $gid = Filter::get('gid', WT_REGEX_XREF);
             $favnote = Filter::get('favnote');
             $url = Filter::getUrl('url');
             $favtitle = Filter::get('favtitle');
             if ($gid) {
                 $record = GedcomRecord::getInstance($gid, $WT_TREE);
                 if ($record && $record->canShow()) {
                     self::addFavorite(array('user_id' => $ctype === 'user' ? Auth::id() : null, 'gedcom_id' => $WT_TREE->getTreeId(), 'gid' => $record->getXref(), 'type' => $record::RECORD_TYPE, 'url' => null, 'note' => $favnote, 'title' => $favtitle));
                 }
             } elseif ($url) {
                 self::addFavorite(array('user_id' => $ctype === 'user' ? Auth::id() : null, 'gedcom_id' => $WT_TREE->getTreeId(), 'gid' => null, 'type' => 'URL', 'url' => $url, 'note' => $favnote, 'title' => $favtitle ? $favtitle : $url));
             }
             break;
     }
     $block = $this->getBlockSetting($block_id, 'block', '0');
     foreach (array('block') as $name) {
         if (array_key_exists($name, $cfg)) {
             ${$name} = $cfg[$name];
         }
     }
     $userfavs = $this->getFavorites($ctype === 'user' ? Auth::id() : $WT_TREE->getTreeId());
     if (!is_array($userfavs)) {
         $userfavs = array();
     }
     $id = $this->getName() . $block_id;
     $class = $this->getName() . '_block';
     $title = $this->getTitle();
     if (Auth::check()) {
         $controller->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)->addInlineJavascript('autocomplete();');
     }
     $content = '';
     if ($userfavs) {
         foreach ($userfavs as $key => $favorite) {
             if (isset($favorite['id'])) {
                 $key = $favorite['id'];
             }
             $removeFavourite = '<a class="font9" href="index.php?ctype=' . $ctype . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;action=deletefav&amp;favorite_id=' . $key . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to remove this item from your list of favorites?') . '\');">' . I18N::translate('Remove') . '</a> ';
             if ($favorite['type'] == 'URL') {
                 $content .= '<div id="boxurl' . $key . '.0" class="person_box">';
                 if ($ctype == 'user' || Auth::isManager($WT_TREE)) {
                     $content .= $removeFavourite;
                 }
                 $content .= '<a href="' . $favorite['url'] . '"><b>' . $favorite['title'] . '</b></a>';
                 $content .= '<br>' . $favorite['note'];
                 $content .= '</div>';
             } else {
                 $record = GedcomRecord::getInstance($favorite['gid'], $WT_TREE);
                 if ($record && $record->canShow()) {
                     if ($record instanceof Individual) {
                         $content .= '<div id="box' . $favorite["gid"] . '.0" class="person_box action_header';
                         switch ($record->getsex()) {
                             case 'M':
                                 break;
                             case 'F':
                                 $content .= 'F';
                                 break;
                             default:
                                 $content .= 'NN';
                                 break;
                         }
                         $content .= '">';
                         if ($ctype == "user" || Auth::isManager($WT_TREE)) {
                             $content .= $removeFavourite;
                         }
                         $content .= Theme::theme()->individualBoxLarge($record);
                         $content .= $favorite['note'];
                         $content .= '</div>';
                     } else {
                         $content .= '<div id="box' . $favorite['gid'] . '.0" class="person_box">';
                         if ($ctype == 'user' || Auth::isManager($WT_TREE)) {
                             $content .= $removeFavourite;
                         }
                         $content .= $record->formatList('span');
                         $content .= '<br>' . $favorite['note'];
                         $content .= '</div>';
                     }
                 }
             }
         }
     }
     if ($ctype == 'user' || Auth::isManager($WT_TREE)) {
         $uniqueID = Uuid::uuid4();
         // This block can theoretically appear multiple times, so use a unique ID.
         $content .= '<div class="add_fav_head">';
         $content .= '<a href="#" onclick="return expand_layer(\'add_fav' . $uniqueID . '\');">' . I18N::translate('Add a new favorite') . '<i id="add_fav' . $uniqueID . '_img" class="icon-plus"></i></a>';
         $content .= '</div>';
         $content .= '<div id="add_fav' . $uniqueID . '" style="display: none;">';
         $content .= '<form name="addfavform" method="get" action="index.php">';
         $content .= '<input type="hidden" name="action" value="addfav">';
         $content .= '<input type="hidden" name="ctype" value="' . $ctype . '">';
         $content .= '<input type="hidden" name="ged" value="' . $WT_TREE->getNameHtml() . '">';
         $content .= '<div class="add_fav_ref">';
         $content .= '<input type="radio" name="fav_category" value="record" checked onclick="jQuery(\'#gid' . $uniqueID . '\').removeAttr(\'disabled\'); jQuery(\'#url, #favtitle\').attr(\'disabled\',\'disabled\').val(\'\');">';
         $content .= '<label for="gid' . $uniqueID . '">' . I18N::translate('Enter an individual, family, or source ID') . '</label>';
         $content .= '<input class="pedigree_form" data-autocomplete-type="IFSRO" type="text" name="gid" id="gid' . $uniqueID . '" size="5" value="">';
         $content .= ' ' . FunctionsPrint::printFindIndividualLink('gid' . $uniqueID);
         $content .= ' ' . FunctionsPrint::printFindFamilyLink('gid' . $uniqueID);
         $content .= ' ' . FunctionsPrint::printFindSourceLink('gid' . $uniqueID);
         $content .= ' ' . FunctionsPrint::printFindRepositoryLink('gid' . $uniqueID);
         $content .= ' ' . FunctionsPrint::printFindNoteLink('gid' . $uniqueID);
         $content .= ' ' . FunctionsPrint::printFindMediaLink('gid' . $uniqueID);
         $content .= '</div>';
         $content .= '<div class="add_fav_url">';
         $content .= '<input type="radio" name="fav_category" value="url" onclick="jQuery(\'#url, #favtitle\').removeAttr(\'disabled\'); jQuery(\'#gid' . $uniqueID . '\').attr(\'disabled\',\'disabled\').val(\'\');">';
         $content .= '<input type="text" name="url" id="url" size="20" value="" placeholder="' . GedcomTag::getLabel('URL') . '" disabled> ';
         $content .= '<input type="text" name="favtitle" id="favtitle" size="20" value="" placeholder="' . I18N::translate('Title') . '" disabled>';
         $content .= '<p>' . I18N::translate('Enter an optional note about this favorite') . '</p>';
         $content .= '<textarea name="favnote" rows="6" cols="50"></textarea>';
         $content .= '</div>';
         $content .= '<input type="submit" value="' . I18N::translate('Add') . '">';
         $content .= '</form></div>';
     }
     if ($template) {
         if ($block) {
             $class .= ' small_inner_block';
         }
         return Theme::theme()->formatBlock($id, $title, $class, $content);
     } else {
         return $content;
     }
 }
Ejemplo n.º 29
0
 /** {@inheritdoc} */
 public function getSidebarAjaxContent()
 {
     global $WT_TREE;
     $cart = Session::get('cart');
     $clip_ctrl = new ClippingsCartController();
     $add = Filter::get('add', WT_REGEX_XREF);
     $add1 = Filter::get('add1', WT_REGEX_XREF);
     $remove = Filter::get('remove', WT_REGEX_XREF);
     $others = Filter::get('others');
     $clip_ctrl->level1 = Filter::getInteger('level1');
     $clip_ctrl->level2 = Filter::getInteger('level2');
     $clip_ctrl->level3 = Filter::getInteger('level3');
     if ($add) {
         $record = GedcomRecord::getInstance($add, $WT_TREE);
         if ($record) {
             $clip_ctrl->id = $record->getXref();
             $clip_ctrl->type = $record::RECORD_TYPE;
             $clip_ctrl->addClipping($record);
         }
     } elseif ($add1) {
         $record = Individual::getInstance($add1, $WT_TREE);
         if ($record) {
             $clip_ctrl->id = $record->getXref();
             $clip_ctrl->type = $record::RECORD_TYPE;
             if ($others == 'parents') {
                 foreach ($record->getChildFamilies() as $family) {
                     $clip_ctrl->addClipping($family);
                     $clip_ctrl->addFamilyMembers($family);
                 }
             } elseif ($others == 'ancestors') {
                 $clip_ctrl->addAncestorsToCart($record, $clip_ctrl->level1);
             } elseif ($others == 'ancestorsfamilies') {
                 $clip_ctrl->addAncestorsToCartFamilies($record, $clip_ctrl->level2);
             } elseif ($others == 'members') {
                 foreach ($record->getSpouseFamilies() as $family) {
                     $clip_ctrl->addClipping($family);
                     $clip_ctrl->addFamilyMembers($family);
                 }
             } elseif ($others == 'descendants') {
                 foreach ($record->getSpouseFamilies() as $family) {
                     $clip_ctrl->addClipping($family);
                     $clip_ctrl->addFamilyDescendancy($family, $clip_ctrl->level3);
                 }
             }
         }
     } elseif ($remove) {
         unset($cart[$WT_TREE->getTreeId()][$remove]);
         Session::put('cart', $cart);
     } elseif (isset($_REQUEST['empty'])) {
         $cart[$WT_TREE->getTreeId()] = array();
         Session::put('cart', $cart);
     } elseif (isset($_REQUEST['download'])) {
         return $this->downloadForm($clip_ctrl);
     }
     return $this->getCartList();
 }
Ejemplo n.º 30
0
 /**
  * Startup activity
  */
 public function __construct()
 {
     global $WT_TREE;
     parent::__construct();
     $this->setPageTitle(I18N::translate('Lifespans'));
     $this->facts = explode('|', WT_EVENTS_BIRT . '|' . WT_EVENTS_DEAT . '|' . WT_EVENTS_MARR . '|' . WT_EVENTS_DIV);
     $tmp = explode('\\', get_class(I18N::defaultCalendar()));
     $cal = strtolower(array_pop($tmp));
     $this->defaultCalendar = str_replace('calendar', '', $cal);
     $filterPids = false;
     // Request parameters
     $clear = Filter::getBool('clear');
     $newpid = Filter::get('newpid', WT_REGEX_XREF);
     $addfam = Filter::getBool('addFamily');
     $this->place = Filter::get('place');
     $this->beginYear = Filter::getInteger('beginYear', 0, PHP_INT_MAX, null);
     $this->endYear = Filter::getInteger('endYear', 0, PHP_INT_MAX, null);
     $this->calendar = Filter::get('calendar', null, $this->defaultCalendar);
     $this->strictDate = Filter::getBool('strictDate');
     // Set up base color parameters
     $this->colors['M'] = new ColorGenerator(240, self::SATURATION, self::LIGHTNESS, self::ALPHA, self::RANGE * -1);
     $this->colors['F'] = new ColorGenerator(00, self::SATURATION, self::LIGHTNESS, self::ALPHA, self::RANGE);
     // Build a list of people based on the input parameters
     if ($clear) {
         // Empty list & reset form
         $xrefs = array();
         $this->place = null;
         $this->beginYear = null;
         $this->endYear = null;
         $this->calendar = $this->defaultCalendar;
     } elseif ($this->place) {
         // Get all individual & family records found for a place
         $this->place_obj = new Place($this->place, $WT_TREE);
         $xrefs = Database::prepare("SELECT DISTINCT `i_id` FROM `##placelinks`" . " JOIN `##individuals` ON `pl_gid`=`i_id` AND `pl_file`=`i_file`" . " WHERE `i_file`=:tree_id" . " AND `pl_p_id`=:place_id" . " UNION" . " SELECT DISTINCT `f_id` FROM `##placelinks`" . " JOIN `##families` ON `pl_gid`=`f_id` AND `pl_file`=`f_file`" . " WHERE `f_file`=:tree_id" . " AND `pl_p_id`=:place_id")->execute(array('tree_id' => $WT_TREE->getTreeId(), 'place_id' => $this->place_obj->getPlaceId()))->fetchOneColumn();
     } else {
         // Modify an existing list of records
         $xrefs = Session::get(self::SESSION_DATA, array());
         if ($newpid) {
             $xrefs = array_merge($xrefs, $this->addFamily(Individual::getInstance($newpid, $WT_TREE), $addfam));
             $xrefs = array_unique($xrefs);
         } elseif (!$xrefs) {
             $xrefs = $this->addFamily($this->getSignificantIndividual(), false);
         }
     }
     $tmp = $this->getCalendarDate(unixtojd());
     $this->currentYear = $tmp->today()->y;
     $tmp = strtoupper(strtr($this->calendar, array('jewish' => 'hebrew', 'french' => 'french r')));
     $this->calendarEscape = sprintf('@#D%s@', $tmp);
     if ($xrefs) {
         // ensure date ranges are valid in preparation for filtering list
         if ($this->beginYear || $this->endYear) {
             $filterPids = true;
             if (!$this->beginYear) {
                 $tmp = new Date($this->calendarEscape . ' 1');
                 $this->beginYear = $tmp->minimumDate()->y;
             }
             if (!$this->endYear) {
                 $this->endYear = $this->currentYear;
             }
             $this->startDate = new Date($this->calendarEscape . $this->beginYear);
             $this->endDate = new Date($this->calendarEscape . $this->endYear);
         }
         // Test each xref to see if the search criteria are met
         foreach ($xrefs as $key => $xref) {
             $valid = false;
             $person = Individual::getInstance($xref, $WT_TREE);
             if ($person) {
                 if ($person->canShow()) {
                     foreach ($person->getFacts() as $fact) {
                         if ($this->checkFact($fact)) {
                             $this->people[] = $person;
                             $valid = true;
                             break;
                         }
                     }
                 }
             } else {
                 $family = Family::getInstance($xref, $WT_TREE);
                 if ($family && $family->canShow() && $this->checkFact($family->getMarriage())) {
                     $valid = true;
                     $this->people[] = $family->getHusband();
                     $this->people[] = $family->getWife();
                 }
             }
             if (!$valid) {
                 unset($xrefs[$key]);
                 // no point in storing a xref if we can't use it
             }
         }
         Session::put(self::SESSION_DATA, $xrefs);
     } else {
         Session::forget(self::SESSION_DATA);
     }
     $this->people = array_filter(array_unique($this->people));
     $count = count($this->people);
     if ($count) {
         // Build the subtitle
         if ($this->place && $filterPids) {
             $this->subtitle = I18N::plural('%s individual with events in %s between %s and %s', '%s individuals with events in %s between %s and %s', $count, I18N::number($count), $this->place, $this->startDate->display(false, '%Y'), $this->endDate->display(false, '%Y'));
         } elseif ($this->place) {
             $this->subtitle = I18N::plural('%s individual with events in %s', '%s individuals with events in %s', $count, I18N::number($count), $this->place);
         } elseif ($filterPids) {
             $this->subtitle = I18N::plural('%s individual with events between %s and %s', '%s individuals with events between %s and %s', $count, I18N::number($count), $this->startDate->display(false, '%Y'), $this->endDate->display(false, '%Y'));
         } else {
             $this->subtitle = I18N::plural('%s individual', '%s individuals', $count, I18N::number($count));
         }
         // Sort the array in order of birth year
         usort($this->people, function (Individual $a, Individual $b) {
             return Date::compare($a->getEstimatedBirthDate(), $b->getEstimatedBirthDate());
         });
         //Find the mimimum birth year and maximum death year from the individuals in the array.
         $bdate = $this->getCalendarDate($this->people[0]->getEstimatedBirthDate()->minimumJulianDay());
         $minyear = $bdate->y;
         $that = $this;
         // PHP5.3 cannot access $this inside a closure
         $maxyear = array_reduce($this->people, function ($carry, Individual $item) use($that) {
             $date = $that->getCalendarDate($item->getEstimatedDeathDate()->maximumJulianDay());
             return max($carry, $date->y);
         }, 0);
     } elseif ($filterPids) {
         $minyear = $this->endYear;
         $maxyear = $this->endYear;
     } else {
         $minyear = $this->currentYear;
         $maxyear = $this->currentYear;
     }
     $maxyear = min($maxyear, $this->currentYear);
     // Limit maximum year to current year as we can't forecast the future
     $minyear = min($minyear, $maxyear - $WT_TREE->getPreference('MAX_ALIVE_AGE'));
     // Set default minimum chart length
     $this->timelineMinYear = (int) floor($minyear / 10) * 10;
     // round down to start of the decade
     $this->timelineMaxYear = (int) ceil($maxyear / 10) * 10;
     // round up to start of next decade
 }