/** * Print a new fact box on details pages * * @param string $id the id of the person, family, source etc the fact will be added to * @param array $usedfacts an array of facts already used in this record * @param string $type the type of record INDI, FAM, SOUR etc */ public static function printAddNewFact($id, $usedfacts, $type) { global $WT_TREE; // -- Add from clipboard if (is_array(Session::get('clipboard'))) { $newRow = true; foreach (array_reverse(Session::get('clipboard'), true) as $fact_id => $fact) { if ($fact["type"] == $type || $fact["type"] == 'all') { if ($newRow) { $newRow = false; echo '<tr><td class="descriptionbox">'; echo I18N::translate('Add from clipboard'), '</td>'; echo '<td class="optionbox wrap"><form method="get" name="newFromClipboard" action="?" onsubmit="return false;">'; echo '<select id="newClipboardFact">'; } echo '<option value="', Filter::escapeHtml($fact_id), '">', GedcomTag::getLabel($fact['fact']); // TODO use the event class to store/parse the clipboard events if (preg_match('/^2 DATE (.+)/m', $fact['factrec'], $match)) { $tmp = new Date($match[1]); echo '; ', $tmp->minimumDate()->format('%Y'); } if (preg_match('/^2 PLAC ([^,\\n]+)/m', $fact['factrec'], $match)) { echo '; ', $match[1]; } echo '</option>'; } } if (!$newRow) { echo '</select>'; echo ' <input type="button" value="', I18N::translate('Add'), "\" onclick=\"return paste_fact('{$id}', '#newClipboardFact');\"> "; echo '</form></td></tr>', "\n"; } } // -- Add from pick list switch ($type) { case "INDI": $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('INDI_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('INDI_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('INDI_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); break; case "FAM": $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('FAM_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('FAM_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('FAM_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); break; case "SOUR": $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('SOUR_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('SOUR_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('SOUR_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); break; case "NOTE": $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('NOTE_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('NOTE_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('NOTE_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); break; case "REPO": $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('REPO_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY); $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('REPO_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY); $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('REPO_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY); break; default: return; } $addfacts = array_merge(self::checkFactUnique($uniquefacts, $usedfacts, $type), $addfacts); $quickfacts = array_intersect($quickfacts, $addfacts); $translated_addfacts = array(); foreach ($addfacts as $addfact) { $translated_addfacts[$addfact] = GedcomTag::getLabel($addfact); } uasort($translated_addfacts, function ($x, $y) { return I18N::strcasecmp(I18N::translate($x), I18N::translate($y)); }); echo '<tr><td class="descriptionbox">'; echo I18N::translate('Fact or event'); echo '</td>'; echo '<td class="optionbox wrap">'; echo '<form method="get" name="newfactform" action="?" onsubmit="return false;">'; echo '<select id="newfact" name="newfact">'; echo '<option value="" disabled selected>' . I18N::translate('<select>') . '</option>'; foreach ($translated_addfacts as $fact => $fact_name) { echo '<option value="', $fact, '">', $fact_name, '</option>'; } if ($type == 'INDI' || $type == 'FAM') { echo '<option value="FACT">', I18N::translate('Custom fact'), '</option>'; echo '<option value="EVEN">', I18N::translate('Custom event'), '</option>'; } echo '</select>'; echo '<input type="button" value="', I18N::translate('Add'), '" onclick="add_record(\'' . $id . '\', \'newfact\');">'; echo '<span class="quickfacts">'; foreach ($quickfacts as $fact) { echo '<a href="#" onclick="add_new_record(\'' . $id . '\', \'' . $fact . '\');return false;">', GedcomTag::getLabel($fact), '</a>'; } echo '</span></form>'; echo '</td></tr>'; }
if (($d + $cal_date->minJD - $week_start) % $days_in_week === 1) { echo '<tr>'; } echo '<td class="optionbox wrap">'; if ($d < 1 || $d > $days_in_month) { if (count($cal_facts[0]) > 0) { echo '<span class="cal_day">', I18N::translate('Day not set'), '</span><br style="clear: both;">'; echo '<div class="details1" style="height: 180px; overflow: auto;">'; echo calendar_list_text($cal_facts[0], '', '', false); echo '</div>'; $cal_facts[0] = array(); } } else { // Format the day number using the calendar $tmp = new Date($cal_date->format("%@ {$d} %O %E")); $d_fmt = $tmp->minimumDate()->format('%j'); if ($d === $today->d && $cal_date->m === $today->m) { echo '<span class="cal_day current_day">', $d_fmt, '</span>'; } else { echo '<span class="cal_day">', $d_fmt, '</span>'; } // Show a converted date foreach (explode('_and_', $CALENDAR_FORMAT) as $convcal) { switch ($convcal) { case 'french': $alt_date = new FrenchDate($cal_date->minJD + $d - 1); break; case 'gregorian': $alt_date = new GregorianDate($cal_date->minJD + $d - 1); break; case 'jewish':
use Fisharebest\Webtrees\Controller\SimpleController; use Fisharebest\Webtrees\Module\CensusAssistantModule; /** @var SimpleController $controller */ global $controller; /** @var Tree $WT_TREE */ global $WT_TREE; $xref = Filter::get('xref', WT_REGEX_XREF); $census = Filter::get('census'); $head = Individual::getInstance($xref, $WT_TREE); check_record_access($head); $controller->restrictAccess(class_exists($census)); /** @var CensusInterface */ $census = new $census(); $controller->restrictAccess($census instanceof CensusInterface); $date = new Date($census->censusDate()); $year = $date->minimumDate()->format('%Y'); $headImg = '<i class="icon-button_head"></i>'; $controller->setPageTitle(I18N::translate('Create a shared note using the census assistant'))->addInlineJavascript('jQuery("head").append(\'<link rel="stylesheet" href="' . WT_STATIC_URL . WT_MODULES_DIR . 'GEDFact_assistant/census/style.css" type="text/css">\');' . 'jQuery("#tblSample").on("click", ".icon-remove", function() { jQuery(this).closest("tr").remove(); });')->pageHeader(); ?> <h2> <?php echo $controller->getPageTitle(); ?> </h2> <form method="post" action="edit_interface.php" onsubmit="updateCensusText();"> <input type="hidden" name="action" value="addnoteaction_assisted"> <input id="pid_array" type="hidden" name="pid_array" value="none"> <input type="hidden" name="NOTE" id="NOTE"> <?php
/** * 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 }
/** * Extract all the dates from the given record and insert them into the database. * * @param string $xref * @param int $ged_id * @param string $gedrec */ public static function updateDates($xref, $ged_id, $gedrec) { if (strpos($gedrec, '2 DATE ') && preg_match_all("/\n1 (\\w+).*(?:\n[2-9].*)*(?:\n2 DATE (.+))(?:\n[2-9].*)*/", $gedrec, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $fact = $match[1]; if (($fact == 'FACT' || $fact == 'EVEN') && preg_match("/\n2 TYPE ([A-Z]{3,5})/", $match[0], $tmatch)) { $fact = $tmatch[1]; } $date = new Date($match[2]); Database::prepare("INSERT INTO `##dates` (d_day,d_month,d_mon,d_year,d_julianday1,d_julianday2,d_fact,d_gid,d_file,d_type) VALUES (?,?,?,?,?,?,?,?,?,?)")->execute(array($date->minimumDate()->d, $date->minimumDate()->format('%O'), $date->minimumDate()->m, $date->minimumDate()->y, $date->minimumDate()->minJD, $date->minimumDate()->maxJD, $fact, $xref, $ged_id, $date->minimumDate()->format('%@'))); if ($date->minimumDate() !== $date->maximumDate()) { Database::prepare("INSERT INTO `##dates` (d_day,d_month,d_mon,d_year,d_julianday1,d_julianday2,d_fact,d_gid,d_file,d_type) VALUES (?,?,?,?,?,?,?,?,?,?)")->execute(array($date->maximumDate()->d, $date->maximumDate()->format('%O'), $date->maximumDate()->m, $date->maximumDate()->y, $date->maximumDate()->minJD, $date->maximumDate()->maxJD, $fact, $xref, $ged_id, $date->maximumDate()->format('%@'))); } } } }
/** * Calculate the the age of a person, on a date. * * @param Date $d1 * @param Date $d2 * @param int $format * * @throws \InvalidArgumentException * * @return int|string */ public static function getAge(Date $d1, Date $d2 = null, $format = 0) { if ($d2) { if ($d2->maximumJulianDay() >= $d1->minimumJulianDay() && $d2->minimumJulianDay() <= $d1->minimumJulianDay()) { // Overlapping dates $jd = $d1->minimumJulianDay(); } else { // Non-overlapping dates $jd = $d2->minimumJulianDay(); } } else { // If second date not specified, use today’s date $jd = WT_CLIENT_JD; } switch ($format) { case 0: // Years - integer only (for statistics, rather than for display) if ($jd && $d1->minimumJulianDay() && $d1->minimumJulianDay() <= $jd) { return $d1->minimumDate()->getAge(false, $jd, false); } else { return -1; } case 1: // Days - integer only (for sorting, rather than for display) if ($jd && $d1->minimumJulianDay()) { return $jd - $d1->minimumJulianDay(); } else { return -1; } case 2: // Just years, in local digits, with warning for negative/ if ($jd && $d1->minimumJulianDay()) { if ($d1->minimumJulianDay() > $jd) { return '<i class="icon-warning"></i>'; } else { return I18N::number($d1->minimumDate()->getAge(false, $jd)); } } else { return ''; } default: throw new \InvalidArgumentException('format: ' . $format); } }
/** * Genearate a <select> element, with the dates/places of all known censuses * * * @param string $locale - Sort the censuses for this locale * @param string $xref - The individual for whom we are adding a census */ public static function censusDateSelector($locale, $xref) { global $controller; // Show more likely census details at the top of the list. switch (WT_LOCALE) { case 'cs': $census_places = array(new CensusOfCzechRepublic()); break; case 'en-AU': case 'en-GB': $census_places = array(new CensusOfEngland(), new CensusOfWales(), new CensusOfScotland()); break; case 'en-US': $census_places = array(new CensusOfUnitedStates()); break; case 'fr': case 'fr-CA': $census_places = array(new CensusOfFrance()); break; case 'da': $census_places = array(new CensusOfDenmark()); break; default: $census_places = array(); break; } foreach (Census::allCensusPlaces() as $census_place) { if (!in_array($census_place, $census_places)) { $census_places[] = $census_place; } } $controller->addInlineJavascript(' function selectCensus(el) { var option = jQuery(":selected", el); jQuery("input.DATE", jQuery(el).closest("table")).val(option.val()); jQuery("input.PLAC", jQuery(el).closest("table")).val(option.data("place")); jQuery("input.census-class", jQuery(el).closest("table")).val(option.data("census")); if (option.data("place")) { jQuery("#assistant-link").show(); } else { jQuery("#assistant-link").hide(); } } function set_pid_array(pa) { jQuery("#pid_array").val(pa); } function activateCensusAssistant() { if (jQuery("#newshared_note_img").hasClass("icon-plus")) { expand_layer("newshared_note"); } var field = jQuery("#newshared_note input.NOTE")[0]; var xref = jQuery("input[name=xref]").val(); var census = jQuery(".census-assistant-selector :selected").data("census"); return addnewnote_assisted(field, xref, census); } '); $options = '<option value="">' . I18N::translate('Census date') . '</option>'; foreach ($census_places as $census_place) { $options .= '<option value=""></option>'; foreach ($census_place->allCensusDates() as $census) { $date = new Date($census->censusDate()); $year = $date->minimumDate()->format('%Y'); $place_hierarchy = explode(', ', $census->censusPlace()); $options .= '<option value="' . $census->censusDate() . '" data-place="' . $census->censusPlace() . '" data-census="' . get_class($census) . '">' . $place_hierarchy[0] . ' ' . $year . '</option>'; } } return '<input type="hidden" id="pid_array" name="pid_array" value="">' . '<select class="census-assistant-selector" onchange="selectCensus(this);">' . $options . '</select>'; }
> <?php echo Filter::getCsrf(); $summary = $person->formatFirstMajorFact(WT_EVENTS_BIRT, 2); if (!$person->isDead()) { // If alive display age $bdate = $person->getBirthDate(); $age = Date::getAgeGedcom($bdate); if ($age != "") { $summary .= "<span class=\"label\">" . I18N::translate('Age') . ":</span><span class=\"field\"> " . FunctionsDate::getAgeAtEvent($age, true) . "</span>"; } } $summary .= $person->formatFirstMajorFact(WT_EVENTS_DEAT, 2); global $summary, $censyear, $censdate; $censdate = new Date('31 MAR 1901'); $censyear = $censdate->minimumDate()->y; $ctry = 'UK'; // === Set $married to "Not married as we only want the Birth name here" === $married = -1; $nam = $person->getAllNames(); if ($person->getDeathYear() == 0) { $DeathYr = ''; } else { $DeathYr = $person->getDeathYear(); } if ($person->getBirthYear() == 0) { $BirthYr = ''; } else { $BirthYr = $person->getBirthYear(); } $fulln = rtrim($nam[0]['givn'], '*') . " " . $nam[0]['surname'];
/** * Get a list of events which occured during a given date range. * * @param int $jd1 the start range of julian day * @param int $jd2 the end range of julian day * @param string $facts restrict the search to just these facts or leave blank for all * @param Tree $tree the tree to search * * @return Fact[] */ public static function getCalendarEvents($jd1, $jd2, $facts, Tree $tree) { // If no facts specified, get all except these $skipfacts = "CHAN,BAPL,SLGC,SLGS,ENDL,CENS,RESI,NOTE,ADDR,OBJE,SOUR,PAGE,DATA,TEXT"; if ($facts != '_TODO') { $skipfacts .= ',_TODO'; } $found_facts = array(); // Events that start or end during the period $where = "WHERE (d_julianday1>={$jd1} AND d_julianday1<={$jd2} OR d_julianday2>={$jd1} AND d_julianday2<={$jd2})"; // Restrict to certain types of fact if (empty($facts)) { $excl_facts = "'" . preg_replace('/\\W+/', "','", $skipfacts) . "'"; $where .= " AND d_fact NOT IN ({$excl_facts})"; } else { $incl_facts = "'" . preg_replace('/\\W+/', "','", $facts) . "'"; $where .= " AND d_fact IN ({$incl_facts})"; } // Only get events from the current gedcom $where .= " AND d_file=" . $tree->getTreeId(); // Now fetch these events $ind_sql = "SELECT d_gid AS xref, i_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact, d_type FROM `##dates`, `##individuals` {$where} AND d_gid=i_id AND d_file=i_file ORDER BY d_julianday1"; $fam_sql = "SELECT d_gid AS xref, f_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact, d_type FROM `##dates`, `##families` {$where} AND d_gid=f_id AND d_file=f_file ORDER BY d_julianday1"; foreach (array('INDI' => $ind_sql, 'FAM' => $fam_sql) as $type => $sql) { $rows = Database::prepare($sql)->fetchAll(); foreach ($rows as $row) { if ($type === 'INDI') { $record = Individual::getInstance($row->xref, $tree, $row->gedcom); } else { $record = Family::getInstance($row->xref, $tree, $row->gedcom); } $anniv_date = new Date($row->d_type . ' ' . $row->d_day . ' ' . $row->d_month . ' ' . $row->d_year); foreach ($record->getFacts() as $fact) { if (($fact->getDate()->minimumDate() == $anniv_date->minimumDate() || $fact->getDate()->maximumDate() == $anniv_date->minimumDate()) && $fact->getTag() === $row->d_fact) { $fact->anniv = 0; $found_facts[] = $fact; } } } } return $found_facts; }