/** * Default previewer for plugins with no custom preview. * * @param GedcomRecord $record * * @return string */ public function getActionPreview(GedcomRecord $record) { $old_lines = preg_split('/[\\n]+/', $record->getGedcom()); $new_lines = preg_split('/[\\n]+/', $this->updateRecord($record->getXref(), $record->getGedcom())); // Find matching lines using longest-common-subsequence algorithm. $lcs = self::longestCommonSubsequence($old_lines, $new_lines, 0, count($old_lines) - 1, 0, count($new_lines) - 1); $diff_lines = array(); $last_old = -1; $last_new = -1; while ($lcs) { list($old, $new) = array_shift($lcs); while ($last_old < $old - 1) { $diff_lines[] = self::decorateDeletedText($old_lines[++$last_old]); } while ($last_new < $new - 1) { $diff_lines[] = self::decorateInsertedText($new_lines[++$last_new]); } $diff_lines[] = $new_lines[$new]; $last_old = $old; $last_new = $new; } while ($last_old < count($old_lines) - 1) { $diff_lines[] = self::decorateDeletedText($old_lines[++$last_old]); } while ($last_new < count($new_lines) - 1) { $diff_lines[] = self::decorateInsertedText($new_lines[++$last_new]); } return '<pre class="gedcom-data">' . self::createEditLinks(implode("\n", $diff_lines)) . '</pre>'; }
/** * Translate a code, for an optional record * * @param string $type * @param GedcomRecord|null $record * * @return string */ public static function getValue($type, GedcomRecord $record = null) { if ($record instanceof Individual) { $sex = $record->getSex(); } else { $sex = 'U'; } switch ($type) { case 'birth': switch ($sex) { case 'M': return I18N::translateContext('Male pedigree', 'Birth'); case 'F': return I18N::translateContext('Female pedigree', 'Birth'); default: return I18N::translateContext('Pedigree', 'Birth'); } case 'adopted': switch ($sex) { case 'M': return I18N::translateContext('Male pedigree', 'Adopted'); case 'F': return I18N::translateContext('Female pedigree', 'Adopted'); default: return I18N::translateContext('Pedigree', 'Adopted'); } case 'foster': switch ($sex) { case 'M': return I18N::translateContext('Male pedigree', 'Foster'); case 'F': return I18N::translateContext('Female pedigree', 'Foster'); default: return I18N::translateContext('Pedigree', 'Foster'); } case 'sealing': switch ($sex) { case 'M': return I18N::translateContext('Male pedigree', 'Sealing'); case 'F': return I18N::translateContext('Female pedigree', 'Sealing'); default: return I18N::translateContext('Pedigree', 'Sealing'); } case 'rada': // Not standard GEDCOM - a webtrees extension // This is an arabic word which does not exist in other languages. // So, it will not have any inflected forms. return I18N::translate('Rada'); default: return $type; } }
/** * get edit menu */ public function getEditMenu() { if (!$this->record || $this->record->isPendingDeletion()) { return null; } // edit menu $menu = new Menu(I18N::translate('Edit'), '#', 'menu-record'); // edit raw if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) { $menu->addSubmenu(new Menu(I18N::translate('Edit raw GEDCOM'), '#', 'menu-record-editraw', array('onclick' => 'return edit_raw("' . $this->record->getXref() . '");'))); } // delete if (Auth::isEditor($this->record->getTree())) { $menu->addSubmenu(new Menu(I18N::translate('Delete'), '#', 'menu-record-del', array('onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($this->record->getFullName()))) . '", "' . $this->record->getXref() . '");'))); } // add to favorites if (Module::getModuleByName('user_favorites')) { $menu->addSubmenu(new Menu(I18N::translate('Add to favorites'), '#', 'menu-record-addfav', array('onclick' => 'jQuery.post("module.php?mod=user_favorites&mod_action=menu-add-favorite" ,{xref:"' . $this->record->getXref() . '"},function(){location.reload();})'))); } // Get the link for the first submenu and set it as the link for the main menu if ($menu->getSubmenus()) { $submenus = $menu->getSubmenus(); $menu->setLink($submenus[0]->getLink()); $menu->setAttrs($submenus[0]->getAttrs()); } return $menu; }
/** * Each object type may have its own special rules, and re-implement this function. * * @param int $access_level * * @return bool */ protected function canShowByType($access_level) { // Hide media objects if they are attached to private records $linked_ids = Database::prepare("SELECT l_from FROM `##link` WHERE l_to = ? AND l_file = ?")->execute(array($this->xref, $this->tree->getTreeId()))->fetchOneColumn(); foreach ($linked_ids as $linked_id) { $linked_record = GedcomRecord::getInstance($linked_id, $this->tree); if ($linked_record && !$linked_record->canShow($access_level)) { return false; } } // ... otherwise apply default behaviour return parent::canShowByType($access_level); }
/** * Translate a code, for an (optional) record * * @param string $type * @param GedcomRecord|null $record * * @return string */ public static function getValue($type, GedcomRecord $record = null) { if ($record instanceof Individual) { $sex = $record->getSex(); } else { $sex = 'U'; } switch ($type) { case 'BOTH': switch ($sex) { case 'M': return I18N::translateContext('MALE', 'Adopted by both parents'); case 'F': return I18N::translateContext('FEMALE', 'Adopted by both parents'); default: return I18N::translate('Adopted by both parents'); } case 'HUSB': switch ($sex) { case 'M': return I18N::translateContext('MALE', 'Adopted by father'); case 'F': return I18N::translateContext('FEMALE', 'Adopted by father'); default: return I18N::translate('Adopted by father'); } case 'WIFE': switch ($sex) { case 'M': return I18N::translateContext('MALE', 'Adopted by mother'); case 'F': return I18N::translateContext('FEMALE', 'Adopted by mother'); default: return I18N::translate('Adopted by mother'); } default: return $type; } }
/** * Generate the HTML content of this block. * * @param int $block_id * @param bool $template * @param string[] $cfg * * @return string */ public function getBlock($block_id, $template = true, $cfg = array()) { global $ctype, $WT_TREE; $num = $this->getBlockSetting($block_id, 'num', '10'); $count_placement = $this->getBlockSetting($block_id, 'count_placement', 'before'); $block = $this->getBlockSetting($block_id, 'block', '0'); foreach (array('count_placement', 'num', 'block') as $name) { if (array_key_exists($name, $cfg)) { ${$name} = $cfg[$name]; } } $id = $this->getName() . $block_id; $class = $this->getName() . '_block'; if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) { $title = '<a class="icon-admin" title="' . I18N::translate('Configure') . '" href="block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype . '"></a>'; } else { $title = ''; } $title .= $this->getTitle(); $content = ''; // load the lines from the file $top10 = Database::prepare("SELECT page_parameter, page_count" . " FROM `##hit_counter`" . " WHERE gedcom_id = :tree_id AND page_name IN ('individual.php','family.php','source.php','repo.php','note.php','mediaviewer.php')" . " ORDER BY page_count DESC LIMIT :limit")->execute(array('tree_id' => $WT_TREE->getTreeId(), 'limit' => (int) $num))->fetchAssoc(); if ($block) { $content .= '<table width="90%">'; } else { $content .= '<table>'; } foreach ($top10 as $id => $count) { $record = GedcomRecord::getInstance($id, $WT_TREE); if ($record && $record->canShow()) { $content .= '<tr>'; if ($count_placement == 'before') { $content .= '<td dir="ltr" style="text-align:right">[' . $count . ']</td>'; } $content .= '<td class="name2" ><a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a></td>'; if ($count_placement == 'after') { $content .= '<td dir="ltr" style="text-align:right">[' . $count . ']</td>'; } $content .= '</tr>'; } } $content .= "</table>"; if ($template) { if ($block) { $class .= ' small_inner_block'; } return Theme::theme()->formatBlock($id, $title, $class, $content); } else { return $content; } }
/** * This is a general purpose hook, allowing modules to respond to routes * of the form module.php?mod=FOO&mod_action=BAR * * @param string $mod_action */ public function modAction($mod_action) { global $WT_TREE; switch ($mod_action) { case 'menu-add-favorite': // Process the "add to user favorites" menu item on indi/fam/etc. pages $record = GedcomRecord::getInstance(Filter::post('xref', WT_REGEX_XREF), $WT_TREE); if (Auth::check() && $record->canShowName()) { self::addFavorite(array('user_id' => Auth::id(), 'gedcom_id' => $record->getTree()->getTreeId(), 'gid' => $record->getXref(), 'type' => $record::RECORD_TYPE, 'url' => null, 'note' => null, 'title' => null)); FlashMessages::addMessage(I18N::translate('“%s” has been added to your favorites.', $record->getFullName())); } break; } }
/** * get edit menu */ public function getEditMenu() { if (!$this->record || $this->record->isPendingDeletion()) { return null; } // edit menu $menu = new Menu(I18N::translate('Edit'), '#', 'menu-record'); // edit raw if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) { $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), '#', 'menu-record-editraw', array('onclick' => 'return edit_raw("' . $this->record->getXref() . '");'))); } // delete if (Auth::isEditor($this->record->getTree())) { $menu->addSubmenu(new Menu(I18N::translate('Delete'), '#', 'menu-record-del', array('onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($this->record->getFullName()))) . '", "' . $this->record->getXref() . '");'))); } return $menu; }
/** * Default previewer for plugins with no custom preview. * * @param GedcomRecord $record * * @return string */ public function getActionPreview(GedcomRecord $record) { $old_lines = preg_split('/[\\n]+/', $record->getGedcom()); $new_lines = preg_split('/[\\n]+/', $this->updateRecord($record->getXref(), $record->getGedcom())); $algorithm = new MyersDiff(); $differences = $algorithm->calculate($old_lines, $new_lines); $diff_lines = array(); foreach ($differences as $difference) { switch ($difference[1]) { case MyersDiff::DELETE: $diff_lines[] = self::decorateDeletedText($difference[0]); break; case MyersDiff::INSERT: $diff_lines[] = self::decorateInsertedText($difference[0]); break; default: $diff_lines[] = $difference[0]; } } return '<pre class="gedcom-data">' . self::createEditLinks(implode("\n", $diff_lines)) . '</pre>'; }
/** * Get the current view of a record, allowing for pending changes * * @param string $xref * @param string $type * * @return string */ public static function getLatestRecord($xref, $type) { global $WT_TREE; switch ($type) { case 'INDI': return Individual::getInstance($xref, $WT_TREE)->getGedcom(); case 'FAM': return Family::getInstance($xref, $WT_TREE)->getGedcom(); case 'SOUR': return Source::getInstance($xref, $WT_TREE)->getGedcom(); case 'REPO': return Repository::getInstance($xref, $WT_TREE)->getGedcom(); case 'OBJE': return Media::getInstance($xref, $WT_TREE)->getGedcom(); case 'NOTE': return Note::getInstance($xref, $WT_TREE)->getGedcom(); default: return GedcomRecord::getInstance($xref, $WT_TREE)->getGedcom(); } }
/** * Sort the records by (1) name and (2) last change date * * @param GedcomRecord $a * @param GedcomRecord $b * * @return int */ private static function sortByNameAndChangeDate(GedcomRecord $a, GedcomRecord $b) { return GedcomRecord::compare($a, $b) ?: $b->lastChangeTimestamp(true) - $a->lastChangeTimestamp(true); }
/** * Determine if the family parents are married. * * Don't use the default function because we want to privatize the record but display the name * and the parents of the spouse if the spouse him/herself is not private. * * @param type $family * @return boolean */ private function getMarriage($family) { $record = GedcomRecord::getInstance($family->getXref(), $this->tree); foreach ($record->getFacts('MARR', false, Auth::PRIV_HIDE) as $fact) { if ($fact) { return true; } } }
// Level 1 links $source->deleteFact($fact->getFactId(), true); } elseif (strpos($fact->getGedcom(), ' @' . $target . '@')) { // Level 2-3 links $source->updateFact($fact->getFactId(), preg_replace(array('/\\n2 OBJE @' . $target . '@(\\n[3-9].*)*/', '/\\n3 OBJE @' . $target . '@(\\n[4-9].*)*/'), '', $fact->getGedcom()), true); } } } } } else { http_response_code(406); } break; case 'reject-changes': // Reject all the pending changes for a record $record = GedcomRecord::getInstance(Filter::post('xref', WT_REGEX_XREF), $WT_TREE); if ($record && $record->canEdit() && Auth::isModerator($record->getTree())) { FlashMessages::addMessage(I18N::translate('The changes to “%s” have been rejected.', $record->getFullName())); FunctionsImport::rejectAllChanges($record); } else { http_response_code(406); } break; case 'theme': // Change the current theme $theme = Filter::post('theme'); if (Site::getPreference('ALLOW_USER_THEMES') && array_key_exists($theme, Theme::themeNames())) { Session::put('theme_id', $theme); // Remember our selection Auth::user()->setPreference('theme', $theme); } else {
// Insert the 1 FILE xxx record into the arrays used by function FunctionsEdit::handle_updatesges() $glevels = array_merge(array('1'), $glevels); $tag = array_merge(array('FILE'), $tag); $islink = array_merge(array(0), $islink); $text = array_merge(array($newFilename), $text); $record = GedcomRecord::getInstance($pid, $WT_TREE); $newrec = "0 @{$pid}@ OBJE\n"; $newrec = FunctionsEdit::handleUpdates($newrec); $record->updateRecord($newrec, $update_CHAN); if ($move_file) { // We've moved a file. Therefore we must approve the change, as rejecting // the change will create broken references. FunctionsImport::acceptAllChanges($record->getXref(), $record->getTree()->getTreeId()); } if ($pid && $linktoid) { $record = GedcomRecord::getInstance($linktoid, $WT_TREE); $record->createFact('1 OBJE @' . $pid . '@', true); Log::addEditLog('Media ID ' . $pid . " successfully added to {$linktoid}."); } $controller->pageHeader(); if ($messages) { echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>'; } else { $controller->addInlineJavascript('closePopupAndReloadParent();'); } return; case 'showmediaform': $controller->setPageTitle(I18N::translate('Create a new media object')); $action = 'create'; break; case 'editmedia':
/** * Print a row for the notes tab on the individual page. * * @param Fact $fact * @param int $level */ public static function printMainNotes(Fact $fact, $level) { $factrec = $fact->getGedcom(); $fact_id = $fact->getFactId(); $parent = $fact->getParent(); $pid = $parent->getXref(); if ($fact->isPendingAddition()) { $styleadd = ' new'; $can_edit = $level == 1 && $fact->canEdit(); } elseif ($fact->isPendingDeletion()) { $styleadd = ' old'; $can_edit = false; } else { $styleadd = ''; $can_edit = $level == 1 && $fact->canEdit(); } $ct = preg_match_all("/{$level} NOTE (.*)/", $factrec, $match, PREG_SET_ORDER); for ($j = 0; $j < $ct; $j++) { // Note object, or inline note? if (preg_match("/{$level} NOTE @(.*)@/", $match[$j][0], $nmatch)) { $note = Note::getInstance($nmatch[1], $fact->getParent()->getTree()); if ($note && !$note->canShow()) { continue; } } else { $note = null; } if ($level >= 2) { echo '<tr class="row_note2"><td class="descriptionbox rela ', $styleadd, ' width20">'; } else { echo '<tr><td class="descriptionbox ', $styleadd, ' width20">'; } if ($can_edit) { echo '<a onclick="return edit_record(\'', $pid, '\', \'', $fact_id, '\');" href="#" title="', I18N::translate('Edit'), '">'; if ($level < 2) { if ($fact->getParent()->getTree()->getPreference('SHOW_FACT_ICONS')) { echo '<i class="icon-note"></i> '; } if ($note) { echo GedcomTag::getLabel('SHARED_NOTE'); } else { echo GedcomTag::getLabel('NOTE'); } echo '</a>'; echo '<div class="editfacts">'; echo "<div class=\"editlink\"><a class=\"editicon\" onclick=\"return edit_record('{$pid}', '{$fact_id}');\" href=\"#\" title=\"" . I18N::translate('Edit') . "\"><span class=\"link_text\">" . I18N::translate('Edit') . "</span></a></div>"; echo '<div class="copylink"><a class="copyicon" href="#" onclick="return copy_fact(\'', $pid, '\', \'', $fact_id, '\');" title="' . I18N::translate('Copy') . '"><span class="link_text">' . I18N::translate('Copy') . '</span></a></div>'; echo "<div class=\"deletelink\"><a class=\"deleteicon\" onclick=\"return delete_fact('" . I18N::translate('Are you sure you want to delete this fact?') . "', '{$pid}', '{$fact_id}');\" href=\"#\" title=\"" . I18N::translate('Delete') . "\"><span class=\"link_text\">" . I18N::translate('Delete') . "</span></a></div>"; if ($note) { echo '<a class="icon-note" href="', $note->getHtmlUrl(), '" title="' . I18N::translate('View') . '"><span class="link_text">' . I18N::translate('View') . '</span></a>'; } echo '</div>'; } } else { if ($level < 2) { if ($fact->getParent()->getTree()->getPreference('SHOW_FACT_ICONS')) { echo '<i class="icon-note"></i> '; } if ($note) { echo GedcomTag::getLabel('SHARED_NOTE'); } else { echo GedcomTag::getLabel('NOTE'); } } $factlines = explode("\n", $factrec); // 1 BIRT Y\n2 NOTE ... $factwords = explode(" ", $factlines[0]); // 1 BIRT Y $factname = $factwords[1]; // BIRT $parent = GedcomRecord::getInstance($pid, $fact->getParent()->getTree()); if ($factname == 'EVEN' || $factname == 'FACT') { // Add ' EVEN' to provide sensible output for an event with an empty TYPE record $ct = preg_match("/2 TYPE (.*)/", $factrec, $ematch); if ($ct > 0) { $factname = trim($ematch[1]); echo $factname; } else { echo GedcomTag::getLabel($factname, $parent); } } elseif ($factname != 'NOTE') { // Note is already printed echo GedcomTag::getLabel($factname, $parent); if ($note) { echo '<div class="editfacts"><a class="icon-note" href="', $note->getHtmlUrl(), '" title="' . I18N::translate('View') . '"><span class="link_text">' . I18N::translate('View') . '</span></a></div>'; } } } echo '</td>'; if ($note) { // Note objects if (Module::getModuleByName('GEDFact_assistant')) { // If Census assistant installed, allow it to format the note $text = CensusAssistantModule::formatCensusNote($note); } else { $text = Filter::formatText($note->getNote(), $fact->getParent()->getTree()); } } else { // Inline notes $nrec = Functions::getSubRecord($level, "{$level} NOTE", $factrec, $j + 1); $text = $match[$j][1] . Functions::getCont($level + 1, $nrec); $text = Filter::formatText($text, $fact->getParent()->getTree()); } echo '<td class="optionbox', $styleadd, ' wrap">'; echo $text; if (!empty($noterec)) { echo self::printFactSources($noterec, 1); } // 2 RESN tags. Note, there can be more than one, such as "privacy" and "locked" if (preg_match_all("/\n2 RESN (.+)/", $factrec, $matches)) { foreach ($matches[1] as $match) { echo '<br><span class="label">', GedcomTag::getLabel('RESN'), ':</span> <span class="field">'; switch ($match) { case 'none': // Note: "2 RESN none" is not valid gedcom, and the GUI will not let you add it. // However, webtrees privacy rules will interpret it as "show an otherwise private fact to public". echo '<i class="icon-resn-none"></i> ', I18N::translate('Show to visitors'); break; case 'privacy': echo '<i class="icon-resn-privacy"></i> ', I18N::translate('Show to members'); break; case 'confidential': echo '<i class="icon-resn-confidential"></i> ', I18N::translate('Show to managers'); break; case 'locked': echo '<i class="icon-resn-locked"></i> ', I18N::translate('Only managers can edit'); break; default: echo $match; break; } echo '</span>'; } } echo '</td></tr>'; } }
/** * Format a list of facts for display * * @param Fact[] $list * @param string $tag1 * @param string $tag2 * @param bool $show_sex_symbols * * @return string */ function calendar_list_text($list, $tag1, $tag2, $show_sex_symbols) { global $males, $females, $WT_TREE; $html = ''; foreach ($list as $id => $facts) { $tmp = GedcomRecord::getInstance($id, $WT_TREE); $html .= $tag1 . '<a href="' . $tmp->getHtmlUrl() . '">' . $tmp->getFullName() . '</a> '; if ($show_sex_symbols && $tmp instanceof Individual) { switch ($tmp->getSex()) { case 'M': $html .= '<i class="icon-sex_m_9x9" title="' . I18N::translate('Male') . '"></i>'; ++$males; break; case 'F': $html .= '<i class="icon-sex_f_9x9" title="' . I18N::translate('Female') . '"></i>'; ++$females; break; default: $html .= '<i class="icon-sex_u_9x9" title="' . I18N::translateContext('unknown gender', 'Unknown') . '"></i>'; break; } } $html .= '<div class="indent">' . $facts . '</div>' . $tag2; } return $html; }
/** * Favorites menu. * * @return Menu|null */ protected function menuFavorites() { global $controller; $show_user_favorites = $this->tree && Module::getModuleByName('user_favorites') && Auth::check(); $show_tree_favorites = $this->tree && Module::getModuleByName('gedcom_favorites'); if ($show_user_favorites && $show_tree_favorites) { $favorites = array_merge(FamilyTreeFavoritesModule::getFavorites($this->tree->getTreeId()), UserFavoritesModule::getFavorites(Auth::id())); } elseif ($show_user_favorites) { $favorites = UserFavoritesModule::getFavorites(Auth::id()); } elseif ($show_tree_favorites) { $favorites = FamilyTreeFavoritesModule::getFavorites($this->tree->getTreeId()); } else { $favorites = array(); } $submenus = array(); $records = array(); foreach ($favorites as $favorite) { switch ($favorite['type']) { case 'URL': $submenus[] = new Menu($favorite['title'], $favorite['url']); break; case 'INDI': case 'FAM': case 'SOUR': case 'OBJE': case 'NOTE': $record = GedcomRecord::getInstance($favorite['gid'], $this->tree); if ($record && $record->canShowName()) { $submenus[] = new Menu($record->getFullName(), $record->getHtmlUrl()); $records[] = $record; } break; } } if ($show_user_favorites && isset($controller->record) && $controller->record instanceof GedcomRecord && !in_array($controller->record, $records)) { $submenus[] = new Menu(I18N::translate('Add to favorites'), '#', '', array('onclick' => 'jQuery.post("module.php?mod=user_favorites&mod_action=menu-add-favorite", {xref:"' . $controller->record->getXref() . '"},function(){location.reload();})')); } if (empty($submenus)) { return null; } else { return new Menu(I18N::translate('Favorites'), '#', 'menu-favorites', array(), $submenus); } }
/** * Print fact DATE/TIME * * @param Fact $event event containing the date/age * @param GedcomRecord $record the person (or couple) whose ages should be printed * @param bool $anchor option to print a link to calendar * @param bool $time option to print TIME value * * @return string */ public static function formatFactDate(Fact $event, GedcomRecord $record, $anchor, $time) { global $pid; $factrec = $event->getGedcom(); $html = ''; // Recorded age if (preg_match('/\\n2 AGE (.+)/', $factrec, $match)) { $fact_age = $match[1]; } else { $fact_age = ''; } if (preg_match('/\\n2 HUSB\\n3 AGE (.+)/', $factrec, $match)) { $husb_age = $match[1]; } else { $husb_age = ''; } if (preg_match('/\\n2 WIFE\\n3 AGE (.+)/', $factrec, $match)) { $wife_age = $match[1]; } else { $wife_age = ''; } // Calculated age if (preg_match('/\\n2 DATE (.+)/', $factrec, $match)) { $date = new Date($match[1]); $html .= ' ' . $date->display($anchor); // time if ($time && preg_match('/\\n3 TIME (.+)/', $factrec, $match)) { $html .= ' – <span class="date">' . $match[1] . '</span>'; } $fact = $event->getTag(); if ($record instanceof Individual) { if ($fact === 'BIRT' && $record->getTree()->getPreference('SHOW_PARENTS_AGE')) { // age of parents at child birth $html .= self::formatParentsAges($record, $date); } elseif ($fact !== 'CHAN' && $fact !== '_TODO') { // age at event $birth_date = $record->getBirthDate(); // Can't use getDeathDate(), as this also gives BURI/CREM events, which // wouldn't give the correct "days after death" result for people with // no DEAT. $death_event = $record->getFirstFact('DEAT'); if ($death_event) { $death_date = $death_event->getDate(); } else { $death_date = new Date(''); } $ageText = ''; if (Date::compare($date, $death_date) <= 0 || !$record->isDead() || $fact == 'DEAT') { // Before death, print age $age = Date::getAgeGedcom($birth_date, $date); // Only show calculated age if it differs from recorded age if ($age != '') { if ($fact_age != '' && $fact_age != $age || $fact_age == '' && $husb_age == '' && $wife_age == '' || $husb_age != '' && $record->getSex() == 'M' && $husb_age != $age || $wife_age != '' && $record->getSex() == 'F' && $wife_age != $age) { if ($age != "0d") { $ageText = '(' . I18N::translate('Age') . ' ' . FunctionsDate::getAgeAtEvent($age, false) . ')'; } } } } if ($fact != 'DEAT' && Date::compare($date, $death_date) >= 0) { // After death, print time since death $age = FunctionsDate::getAgeAtEvent(Date::getAgeGedcom($death_date, $date), true); if ($age != '') { if (Date::getAgeGedcom($death_date, $date) == "0d") { $ageText = '(' . I18N::translate('on the date of death') . ')'; } else { $ageText = '(' . $age . ' ' . I18N::translate('after death') . ')'; // Family events which occur after death are probably errors if ($event->getParent() instanceof Family) { $ageText .= '<i class="icon-warning"></i>'; } } } } if ($ageText) { $html .= ' <span class="age">' . $ageText . '</span>'; } } } elseif ($record instanceof Family) { $indi = Individual::getInstance($pid, $record->getTree()); if ($indi) { $birth_date = $indi->getBirthDate(); $death_date = $indi->getDeathDate(); $ageText = ''; if (Date::compare($date, $death_date) <= 0) { $age = Date::getAgeGedcom($birth_date, $date); // Only show calculated age if it differs from recorded age if ($age != '' && $age > 0) { if ($fact_age != '' && $fact_age != $age || $fact_age == '' && $husb_age == '' && $wife_age == '' || $husb_age != '' && $indi->getSex() == 'M' && $husb_age != $age || $wife_age != '' && $indi->getSex() == 'F' && $wife_age != $age) { $ageText = '(' . I18N::translate('Age') . ' ' . FunctionsDate::getAgeAtEvent($age, false) . ')'; } } } if ($ageText) { $html .= ' <span class="age">' . $ageText . '</span>'; } } } } else { // 1 DEAT Y with no DATE => print YES // 1 BIRT 2 SOUR @S1@ => print YES // 1 DEAT N is not allowed // It is not proper GEDCOM form to use a N(o) value with an event tag to infer that it did not happen. $factdetail = explode(' ', trim($factrec)); if (isset($factdetail) && (count($factdetail) == 3 && strtoupper($factdetail[2]) == 'Y') || count($factdetail) == 4 && $factdetail[2] == 'SOUR') { $html .= I18N::translate('yes'); } } // print gedcom ages foreach (array(GedcomTag::getLabel('AGE') => $fact_age, GedcomTag::getLabel('HUSB') => $husb_age, GedcomTag::getLabel('WIFE') => $wife_age) as $label => $age) { if ($age != '') { $html .= ' <span class="label">' . $label . ':</span> <span class="age">' . FunctionsDate::getAgeAtEvent($age, false) . '</span>'; } } return $html; }
/** * Events * * @param string $type * @param string $direction * @param string $facts * * @return string */ private function eventQuery($type, $direction, $facts) { $eventTypes = array('BIRT' => I18N::translate('birth'), 'DEAT' => I18N::translate('death'), 'MARR' => I18N::translate('marriage'), 'ADOP' => I18N::translate('adoption'), 'BURI' => I18N::translate('burial'), 'CENS' => I18N::translate('census added')); $fact_query = "IN ('" . str_replace('|', "','", $facts) . "')"; if ($direction != 'ASC') { $direction = 'DESC'; } $rows = $this->runSql('' . ' SELECT SQL_CACHE' . ' d_gid AS id,' . ' d_year AS year,' . ' d_fact AS fact,' . ' d_type AS type' . ' FROM' . " `##dates`" . ' WHERE' . " d_file={$this->tree->getTreeId()} AND" . " d_gid<>'HEAD' AND" . " d_fact {$fact_query} AND" . ' d_julianday1<>0' . ' ORDER BY' . " d_julianday1 {$direction}, d_type LIMIT 1"); if (!isset($rows[0])) { return ''; } $row = $rows[0]; $record = GedcomRecord::getInstance($row['id'], $this->tree); switch ($type) { default: case 'full': if ($record->canShow()) { $result = $record->formatList('span', false, $record->getFullName()); } else { $result = I18N::translate('This information is private and cannot be shown.'); } break; case 'year': $date = new Date($row['type'] . ' ' . $row['year']); $result = $date->display(); break; case 'type': if (isset($eventTypes[$row['fact']])) { $result = $eventTypes[$row['fact']]; } else { $result = GedcomTag::getLabel($row['fact']); } break; case 'name': $result = "<a href=\"" . $record->getHtmlUrl() . "\">" . $record->getFullName() . "</a>"; break; case 'place': $fact = $record->getFirstFact($row['fact']); if ($fact) { $result = FunctionsPrint::formatFactPlace($fact, true, true, true); } else { $result = I18N::translate('Private'); } break; } return $result; }
/** * Sort a list events for the today/upcoming blocks * * @param array $a * @param array $b * * @return int */ public static function eventSortName($a, $b) { if ($a['jd'] == $b['jd']) { return GedcomRecord::compare($a['record'], $b['record']); } else { return $a['jd'] - $b['jd']; } }
$record = new Family($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; case 'SOUR': $record = new Source($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; case 'REPO': $record = new Repository($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; case 'OBJE': $record = new Media($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; case 'NOTE': $record = new Note($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; default: $record = new GedcomRecord($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; } if ($change->xref != $prev_xref || $change->gedcom_id != $prev_gedcom_id) { if ($prev_xref) { $output .= '</table></td></tr>'; } $prev_xref = $change->xref; $prev_gedcom_id = $change->gedcom_id; $output .= '<tr><td class="list_value">'; $output .= '<b><a href="#" onclick="return show_diff(\'' . $record->getHtmlUrl() . '\');"> ' . $record->getFullName() . '</a></b>'; $output .= '<div class="indent">'; $output .= '<table class="list_table"><tr>'; $output .= '<td class="list_label">' . I18N::translate('Accept') . '</td>'; $output .= '<td class="list_label">' . I18N::translate('Changes') . '</td>'; $output .= '<td class="list_label">' . I18N::translate('User') . '</td>';
$formats = array('' => I18N::translate('none'), 'markdown' => I18N::translate('markdown')); $source_types = array(0 => I18N::translate('none'), 1 => I18N::translate('facts'), 2 => I18N::translate('records')); $no_yes = array(0 => I18N::translate('no'), 1 => I18N::translate('yes')); $PRIVACY_CONSTANTS = array('none' => I18N::translate('Show to visitors'), 'privacy' => I18N::translate('Show to members'), 'confidential' => I18N::translate('Show to managers'), 'hidden' => I18N::translate('Hide from everyone')); $privacy = array(Auth::PRIV_PRIVATE => I18N::translate('Show to visitors'), Auth::PRIV_USER => I18N::translate('Show to members'), Auth::PRIV_NONE => I18N::translate('Show to managers'), Auth::PRIV_HIDE => I18N::translate('Hide from everyone')); $tags = array_unique(array_merge(explode(',', $WT_TREE->getPreference('INDI_FACTS_ADD')), explode(',', $WT_TREE->getPreference('INDI_FACTS_UNIQUE')), explode(',', $WT_TREE->getPreference('FAM_FACTS_ADD')), explode(',', $WT_TREE->getPreference('FAM_FACTS_UNIQUE')), explode(',', $WT_TREE->getPreference('NOTE_FACTS_ADD')), explode(',', $WT_TREE->getPreference('NOTE_FACTS_UNIQUE')), explode(',', $WT_TREE->getPreference('SOUR_FACTS_ADD')), explode(',', $WT_TREE->getPreference('SOUR_FACTS_UNIQUE')), explode(',', $WT_TREE->getPreference('REPO_FACTS_ADD')), explode(',', $WT_TREE->getPreference('REPO_FACTS_UNIQUE')), array('SOUR', 'REPO', 'OBJE', '_PRIM', 'NOTE', 'SUBM', 'SUBN', '_UID', 'CHAN'))); $all_tags = array(); foreach ($tags as $tag) { if ($tag) { $all_tags[$tag] = GedcomTag::getLabel($tag); } } uasort($all_tags, '\\Fisharebest\\Webtrees\\I18N::strcasecmp'); $resns = Database::prepare("SELECT default_resn_id, tag_type, xref, resn" . " FROM `##default_resn`" . " LEFT JOIN `##name` ON (gedcom_id=n_file AND xref=n_id AND n_num=0)" . " WHERE gedcom_id=?" . " ORDER BY xref IS NULL, n_sort, xref, tag_type")->execute(array($WT_TREE->getTreeId()))->fetchAll(); foreach ($resns as $resn) { $resn->record = GedcomRecord::getInstance($resn->xref, $WT_TREE); if ($resn->tag_type) { $resn->tag_label = GedcomTag::getLabel($resn->tag_type); } else { $resn->tag_label = ''; } } usort($resns, function (\stdClass $x, \stdClass $y) { return I18N::strcasecmp($x->tag_label, $y->tag_label); }); // We have two fields in one $CALENDAR_FORMATS = explode('_and_', $WT_TREE->getPreference('CALENDAR_FORMAT') . '_and_'); // Split into separate fields $relatives_events = explode(',', $WT_TREE->getPreference('SHOW_RELATIVES_EVENTS')); switch (Filter::post('action')) { case 'privacy':
/** * Export the database in GEDCOM format * * @param Tree $tree Which tree to export * @param resource $gedout Handle to a writable stream * @param string[] $exportOptions Export options are as follows: * 'privatize': which Privacy rules apply? (none, visitor, user, manager) * 'toANSI': should the output be produced in ISO-8859-1 instead of UTF-8? (yes, no) * 'path': what constant should prefix all media file paths? (eg: media/ or c:\my pictures\my family * 'slashes': what folder separators apply to media file paths? (forward, backward) */ public static function exportGedcom(Tree $tree, $gedout, $exportOptions) { switch ($exportOptions['privatize']) { case 'gedadmin': $access_level = Auth::PRIV_NONE; break; case 'user': $access_level = Auth::PRIV_USER; break; case 'visitor': $access_level = Auth::PRIV_PRIVATE; break; case 'none': $access_level = Auth::PRIV_HIDE; break; } $head = self::gedcomHeader($tree); if ($exportOptions['toANSI'] == 'yes') { $head = str_replace('UTF-8', 'ANSI', $head); $head = utf8_decode($head); } $head = self::reformatRecord($head); fwrite($gedout, $head); // Buffer the output. Lots of small fwrite() calls can be very slow when writing large gedcoms. $buffer = ''; // Generate the OBJE/SOUR/REPO/NOTE records first, as their privacy calcualations involve // database queries, and we wish to avoid large gaps between queries due to MySQL connection timeouts. $tmp_gedcom = ''; $rows = Database::prepare("SELECT m_id AS xref, m_gedcom AS gedcom" . " FROM `##media` WHERE m_file = :tree_id ORDER BY m_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { $rec = Media::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level); $rec = self::convertMediaPath($rec, $exportOptions['path']); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $tmp_gedcom .= self::reformatRecord($rec); } $rows = Database::prepare("SELECT s_id AS xref, s_file AS gedcom_id, s_gedcom AS gedcom" . " FROM `##sources` WHERE s_file = :tree_id ORDER BY s_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { $rec = Source::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $tmp_gedcom .= self::reformatRecord($rec); } $rows = Database::prepare("SELECT o_type AS type, o_id AS xref, o_gedcom AS gedcom" . " FROM `##other` WHERE o_file = :tree_id AND o_type NOT IN ('HEAD', 'TRLR') ORDER BY o_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { switch ($row->type) { case 'NOTE': $record = Note::getInstance($row->xref, $tree, $row->gedcom); break; case 'REPO': $record = Repository::getInstance($row->xref, $tree, $row->gedcom); break; default: $record = GedcomRecord::getInstance($row->xref, $tree, $row->gedcom); break; } $rec = $record->privatizeGedcom($access_level); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $tmp_gedcom .= self::reformatRecord($rec); } $rows = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom" . " FROM `##individuals` WHERE i_file = :tree_id ORDER BY i_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { $rec = Individual::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $buffer .= self::reformatRecord($rec); if (strlen($buffer) > 65536) { fwrite($gedout, $buffer); $buffer = ''; } } $rows = Database::prepare("SELECT f_id AS xref, f_gedcom AS gedcom" . " FROM `##families` WHERE f_file = :tree_id ORDER BY f_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { $rec = Family::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $buffer .= self::reformatRecord($rec); if (strlen($buffer) > 65536) { fwrite($gedout, $buffer); $buffer = ''; } } fwrite($gedout, $buffer); fwrite($gedout, $tmp_gedcom); fwrite($gedout, '0 TRLR' . WT_EOL); }
/** * A list for the side bar. * * @return string */ public function getCartList() { global $WT_TREE; $cart = Session::get('cart', array()); if (!array_key_exists($WT_TREE->getTreeId(), $cart)) { $cart[$WT_TREE->getTreeId()] = array(); } $pid = Filter::get('pid', WT_REGEX_XREF); if (!$cart[$WT_TREE->getTreeId()]) { $out = I18N::translate('Your clippings cart is empty.'); } else { $out = '<ul>'; foreach (array_keys($cart[$WT_TREE->getTreeId()]) as $xref) { $record = GedcomRecord::getInstance($xref, $WT_TREE); if ($record instanceof Individual || $record instanceof Family) { switch ($record::RECORD_TYPE) { case 'INDI': $icon = 'icon-indis'; break; case 'FAM': $icon = 'icon-sfamily'; break; } $out .= '<li>'; if (!empty($icon)) { $out .= '<i class="' . $icon . '"></i>'; } $out .= '<a href="' . $record->getHtmlUrl() . '">'; if ($record instanceof Individual) { $out .= $record->getSexImage(); } $out .= ' ' . $record->getFullName() . ' '; if ($record instanceof Individual && $record->canShow()) { $out .= ' (' . $record->getLifeSpan() . ')'; } $out .= '</a>'; $out .= '<a class="icon-remove remove_cart" href="module.php?mod=' . $this->getName() . '&mod_action=ajax&sb_action=clippings&remove=' . $xref . '&pid=' . $pid . '" title="' . I18N::translate('Remove') . '"></a>'; $out .= '</li>'; } } $out .= '</ul>'; } if ($cart[$WT_TREE->getTreeId()]) { $out .= '<br><a href="module.php?mod=' . $this->getName() . '&mod_action=ajax&sb_action=clippings&empty=true&pid=' . $pid . '" class="remove_cart">' . I18N::translate('Empty the clippings cart') . '</a>' . '<br>' . '<a href="module.php?mod=' . $this->getName() . '&mod_action=ajax&sb_action=clippings&download=true&pid=' . $pid . '" class="add_cart">' . I18N::translate('Download') . '</a>'; } $record = Individual::getInstance($pid, $WT_TREE); if ($record && !array_key_exists($record->getXref(), $cart[$WT_TREE->getTreeId()])) { $out .= '<br><a href="module.php?mod=' . $this->getName() . '&mod_action=ajax&sb_action=clippings&add=' . $pid . '&pid=' . $pid . '" class="add_cart"><i class="icon-clippings"></i> ' . I18N::translate('Add %s to the clippings cart', $record->getFullName()) . '</a>'; } return $out; }
/** * Can we edit a GedcomRecord object * * @param GedcomRecord $object */ function check_record_access(GedcomRecord $object = null) { global $controller; if (!$object || !$object->canShow() || !$object->canEdit()) { $controller->pageHeader()->addInlineJavascript('closePopupAndReloadParent();'); exit; } }
/** * Get the record to which this fact links * * @return Individual|Family|Source|Repository|Media|Note|null */ public function getTarget() { $xref = trim($this->getValue(), '@'); switch ($this->tag) { case 'FAMC': case 'FAMS': return Family::getInstance($xref, $this->getParent()->getTree()); case 'HUSB': case 'WIFE': case 'CHIL': return Individual::getInstance($xref, $this->getParent()->getTree()); case 'SOUR': return Source::getInstance($xref, $this->getParent()->getTree()); case 'OBJE': return Media::getInstance($xref, $this->getParent()->getTree()); case 'REPO': return Repository::getInstance($xref, $this->getParent()->getTree()); case 'NOTE': return Note::getInstance($xref, $this->getParent()->getTree()); default: return GedcomRecord::getInstance($xref, $this->getParent()->getTree()); } }
/** * Translate a tag, for an (optional) record * * @param string $tag * @param GedcomRecord|null $record * * @return string */ public static function getLabel($tag, GedcomRecord $record = null) { if ($record instanceof Individual) { $sex = $record->getSex(); } else { $sex = 'U'; } switch ($tag) { case 'ABBR': return I18N::translate('Abbreviation'); case 'ADDR': return I18N::translate('Address'); case 'ADR1': return I18N::translate('Address line 1'); case 'ADR2': return I18N::translate('Address line 2'); case 'ADOP': return I18N::translate('Adoption'); case 'ADOP:DATE': return I18N::translate('Date of adoption'); case 'ADOP:PLAC': return I18N::translate('Place of adoption'); case 'AFN': return I18N::translate('Ancestral file number'); case 'AGE': return I18N::translate('Age'); case 'AGNC': return I18N::translate('Agency'); case 'ALIA': return I18N::translate('Alias'); case 'ANCE': return I18N::translate('Generations of ancestors'); case 'ANCI': return I18N::translate('Ancestors interest'); case 'ANUL': return I18N::translate('Annulment'); case 'ASSO': return I18N::translate('Associate'); /* see also _ASSO */ /* see also _ASSO */ case 'AUTH': return I18N::translate('Author'); case 'BAPL': return I18N::translate('LDS baptism'); case 'BAPL:DATE': return I18N::translate('Date of LDS baptism'); case 'BAPL:PLAC': return I18N::translate('Place of LDS baptism'); case 'BAPM': return I18N::translate('Baptism'); case 'BAPM:DATE': return I18N::translate('Date of baptism'); case 'BAPM:PLAC': return I18N::translate('Place of baptism'); case 'BARM': return I18N::translate('Bar mitzvah'); case 'BARM:DATE': return I18N::translate('Date of bar mitzvah'); case 'BARM:PLAC': return I18N::translate('Place of bar mitzvah'); case 'BASM': return I18N::translate('Bat mitzvah'); case 'BASM:DATE': return I18N::translate('Date of bat mitzvah'); case 'BASM:PLAC': return I18N::translate('Place of bat mitzvah'); case 'BIRT': return I18N::translate('Birth'); case 'BIRT:DATE': return I18N::translate('Date of birth'); case 'BIRT:PLAC': return I18N::translate('Place of birth'); case 'BLES': return I18N::translate('Blessing'); case 'BLES:DATE': return I18N::translate('Date of blessing'); case 'BLES:PLAC': return I18N::translate('Place of blessing'); case 'BLOB': return I18N::translate('Binary data object'); case 'BURI': return I18N::translate('Burial'); case 'BURI:DATE': return I18N::translate('Date of burial'); case 'BURI:PLAC': return I18N::translate('Place of burial'); case 'CALN': return I18N::translate('Call number'); case 'CAST': return I18N::translate('Caste'); case 'CAUS': return I18N::translate('Cause'); case 'CEME': return I18N::translate('Cemetery'); case 'CENS': return I18N::translate('Census'); case 'CENS:DATE': return I18N::translate('Census date'); case 'CENS:PLAC': return I18N::translate('Census place'); case 'CHAN': return I18N::translate('Last change'); case 'CHAN:DATE': return I18N::translate('Date of last change'); case 'CHAN:_WT_USER': return I18N::translate('Author of last change'); case 'CHAR': return I18N::translate('Character set'); case 'CHIL': return I18N::translate('Child'); case 'CHR': return I18N::translate('Christening'); case 'CHR:DATE': return I18N::translate('Date of christening'); case 'CHR:PLAC': return I18N::translate('Place of christening'); case 'CHRA': return I18N::translate('Adult christening'); case 'CITN': return I18N::translate('Citizenship'); case 'CITY': return I18N::translate('City'); case 'COMM': return I18N::translate('Comment'); case 'CONC': return I18N::translate('Concatenation'); case 'CONT': return I18N::translate('Continued'); case 'CONF': return I18N::translate('Confirmation'); case 'CONF:DATE': return I18N::translate('Date of confirmation'); case 'CONF:PLAC': return I18N::translate('Place of confirmation'); case 'CONL': return I18N::translate('LDS confirmation'); case 'COPR': return I18N::translate('Copyright'); case 'CORP': return I18N::translate('Corporation'); case 'CREM': return I18N::translate('Cremation'); case 'CREM:DATE': return I18N::translate('Date of cremation'); case 'CREM:PLAC': return I18N::translate('Place of cremation'); case 'CTRY': return I18N::translate('Country'); case 'DATA': return I18N::translate('Data'); case 'DATA:DATE': return I18N::translate('Date of entry in original source'); case 'DATE': return I18N::translate('Date'); case 'DEAT': return I18N::translate('Death'); case 'DEAT:CAUS': return I18N::translate('Cause of death'); case 'DEAT:DATE': return I18N::translate('Date of death'); case 'DEAT:PLAC': return I18N::translate('Place of death'); case 'DESC': return I18N::translate('Descendants'); case 'DESI': return I18N::translate('Descendants interest'); case 'DEST': return I18N::translate('Destination'); case 'DIV': return I18N::translate('Divorce'); case 'DIVF': return I18N::translate('Divorce filed'); case 'DSCR': return I18N::translate('Description'); case 'EDUC': return I18N::translate('Education'); case 'EDUC:AGNC': return I18N::translate('School or college'); case 'EMAI': return I18N::translate('Email address'); case 'EMAIL': return I18N::translate('Email address'); case 'EMAL': return I18N::translate('Email address'); case 'EMIG': return I18N::translate('Emigration'); case 'EMIG:DATE': return I18N::translate('Date of emigration'); case 'EMIG:PLAC': return I18N::translate('Place of emigration'); case 'ENDL': return I18N::translate('LDS endowment'); case 'ENDL:DATE': return I18N::translate('Date of LDS endowment'); case 'ENDL:PLAC': return I18N::translate('Place of LDS endowment'); case 'ENGA': return I18N::translate('Engagement'); case 'ENGA:DATE': return I18N::translate('Date of engagement'); case 'ENGA:PLAC': return I18N::translate('Place of engagement'); case 'EVEN': return I18N::translate('Event'); case 'EVEN:DATE': return I18N::translate('Date of event'); case 'EVEN:PLAC': return I18N::translate('Place of event'); case 'FACT': return I18N::translate('Fact'); case 'FAM': return I18N::translate('Family'); case 'FAMC': return I18N::translate('Family as a child'); case 'FAMF': return I18N::translate('Family file'); case 'FAMS': return I18N::translate('Family as a spouse'); case 'FAMS:CENS:DATE': return I18N::translate('Spouse census date'); case 'FAMS:CENS:PLAC': return I18N::translate('Spouse census place'); case 'FAMS:DIV:DATE': return I18N::translate('Date of divorce'); case 'FAMS:MARR:DATE': return I18N::translate('Date of marriage'); case 'FAMS:MARR:PLAC': return I18N::translate('Place of marriage'); case 'FAMS:NOTE': return I18N::translate('Spouse note'); case 'FAMS:SLGS:DATE': return I18N::translate('Date of LDS spouse sealing'); case 'FAMS:SLGS:PLAC': return I18N::translate('Place of LDS spouse sealing'); case 'FAX': return I18N::translate('Fax'); case 'FCOM': return I18N::translate('First communion'); case 'FCOM:DATE': return I18N::translate('Date of first communion'); case 'FCOM:PLAC': return I18N::translate('Place of first communion'); case 'FILE': return I18N::translate('Filename'); case 'FONE': return I18N::translate('Phonetic'); case 'FORM': return I18N::translate('Format'); case 'GEDC': return I18N::translate('GEDCOM file'); case 'GIVN': return I18N::translate('Given names'); case 'GRAD': return I18N::translate('Graduation'); case 'HEAD': return I18N::translate('Header'); case 'HUSB': return I18N::translate('Husband'); case 'IDNO': return I18N::translate('Identification number'); case 'IMMI': return I18N::translate('Immigration'); case 'IMMI:DATE': return I18N::translate('Date of immigration'); case 'IMMI:PLAC': return I18N::translate('Place of immigration'); case 'INDI': return I18N::translate('Individual'); case 'INFL': return I18N::translate('Infant'); case 'LANG': return I18N::translate('Language'); case 'LATI': return I18N::translate('Latitude'); case 'LEGA': return I18N::translate('Legatee'); case 'LONG': return I18N::translate('Longitude'); case 'MAP': return I18N::translate('Map'); case 'MARB': return I18N::translate('Marriage banns'); case 'MARB:DATE': return I18N::translate('Date of marriage banns'); case 'MARB:PLAC': return I18N::translate('Place of marriage banns'); case 'MARC': return I18N::translate('Marriage contract'); case 'MARL': return I18N::translate('Marriage license'); case 'MARR': return I18N::translate('Marriage'); case 'MARR:DATE': return I18N::translate('Date of marriage'); case 'MARR:PLAC': return I18N::translate('Place of marriage'); case 'MARR_CIVIL': return I18N::translate('Civil marriage'); case 'MARR_PARTNERS': return I18N::translate('Registered partnership'); case 'MARR_RELIGIOUS': return I18N::translate('Religious marriage'); case 'MARR_UNKNOWN': return I18N::translate('Marriage type unknown'); case 'MARS': return I18N::translate('Marriage settlement'); case 'MEDI': return I18N::translate('Media type'); case 'NAME': if ($record instanceof Repository) { return I18N::translateContext('Repository', 'Name'); } else { return I18N::translate('Name'); } case 'NAME:FONE': return I18N::translate('Phonetic name'); case 'NAME:_HEB': return I18N::translate('Name in Hebrew'); case 'NATI': return I18N::translate('Nationality'); case 'NATU': return I18N::translate('Naturalization'); case 'NATU:DATE': return I18N::translate('Date of naturalization'); case 'NATU:PLAC': return I18N::translate('Place of naturalization'); case 'NCHI': return I18N::translate('Number of children'); case 'NICK': return I18N::translate('Nickname'); case 'NMR': return I18N::translate('Number of marriages'); case 'NOTE': return I18N::translate('Note'); case 'NPFX': return I18N::translate('Name prefix'); case 'NSFX': return I18N::translate('Name suffix'); case 'OBJE': return I18N::translate('Media object'); case 'OCCU': return I18N::translate('Occupation'); case 'OCCU:AGNC': return I18N::translate('Employer'); case 'ORDI': return I18N::translate('Ordinance'); case 'ORDN': return I18N::translate('Ordination'); case 'ORDN:AGNC': return I18N::translate('Religious institution'); case 'ORDN:DATE': return I18N::translate('Date of ordination'); case 'ORDN:PLAC': return I18N::translate('Place of ordination'); case 'PAGE': return I18N::translate('Citation details'); case 'PEDI': return I18N::translate('Relationship to parents'); case 'PHON': return I18N::translate('Phone'); case 'PLAC': return I18N::translate('Place'); case 'PLAC:FONE': return I18N::translate('Phonetic place'); case 'PLAC:ROMN': return I18N::translate('Romanized place'); case 'PLAC:_HEB': return I18N::translate('Place in Hebrew'); case 'POST': return I18N::translate('Postal code'); case 'PROB': return I18N::translate('Probate'); case 'PROP': return I18N::translate('Property'); case 'PUBL': return I18N::translate('Publication'); case 'QUAY': return I18N::translate('Quality of data'); case 'REFN': return I18N::translate('Reference number'); case 'RELA': return I18N::translate('Relationship'); case 'RELI': return I18N::translate('Religion'); case 'REPO': return I18N::translate('Repository'); case 'RESI': return I18N::translate('Residence'); case 'RESI:DATE': return I18N::translate('Date of residence'); case 'RESI:PLAC': return I18N::translate('Place of residence'); case 'RESN': return I18N::translate('Restriction'); case 'RETI': return I18N::translate('Retirement'); case 'RETI:AGNC': return I18N::translate('Employer'); case 'RFN': return I18N::translate('Record file number'); case 'RIN': return I18N::translate('Record ID number'); case 'ROLE': return I18N::translate('Role'); case 'ROMN': return I18N::translate('Romanized'); case 'SERV': return I18N::translate('Remote server'); case 'SEX': return I18N::translate('Gender'); case 'SHARED_NOTE': return I18N::translate('Shared note'); case 'SLGC': return I18N::translate('LDS child sealing'); case 'SLGC:DATE': return I18N::translate('Date of LDS child sealing'); case 'SLGC:PLAC': return I18N::translate('Place of LDS child sealing'); case 'SLGS': return I18N::translate('LDS spouse sealing'); case 'SOUR': return I18N::translate('Source'); case 'SPFX': return I18N::translate('Surname prefix'); case 'SSN': return I18N::translate('Social security number'); case 'STAE': return I18N::translate('State'); case 'STAT': return I18N::translate('Status'); case 'STAT:DATE': return I18N::translate('Status change date'); case 'SUBM': return I18N::translate('Submitter'); case 'SUBN': return I18N::translate('Submission'); case 'SURN': return I18N::translate('Surname'); case 'TEMP': return I18N::translate('Temple'); case 'TEXT': return I18N::translate('Text'); case 'TIME': return I18N::translate('Time'); case 'TITL': return I18N::translate('Title'); case 'TITL:FONE': return I18N::translate('Phonetic title'); case 'TITL:ROMN': return I18N::translate('Romanized title'); case 'TITL:_HEB': return I18N::translate('Title in Hebrew'); case 'TRLR': return I18N::translate('Trailer'); case 'TYPE': return I18N::translate('Type'); case 'URL': return I18N::translate('URL'); case 'VERS': return I18N::translate('Version'); case 'WIFE': return I18N::translate('Wife'); case 'WILL': return I18N::translate('Will'); case 'WWW': return I18N::translate('URL'); case '_ADOP_CHIL': switch ($sex) { case 'M': return I18N::translate('Adoption of a son'); case 'F': return I18N::translate('Adoption of a daughter'); default: return I18N::translate('Adoption of a child'); } case '_ADOP_GCHI': switch ($sex) { case 'M': return I18N::translate('Adoption of a grandson'); case 'F': return I18N::translate('Adoption of a granddaughter'); default: return I18N::translate('Adoption of a grandchild'); } case '_ADOP_GCH1': switch ($sex) { case 'M': return I18N::translateContext('daughter’s son', 'Adoption of a grandson'); case 'F': return I18N::translateContext('daughter’s daughter', 'Adoption of a granddaughter'); default: return I18N::translate('Adoption of a grandchild'); } case '_ADOP_GCH2': switch ($sex) { case 'M': return I18N::translateContext('son’s son', 'Adoption of a grandson'); case 'F': return I18N::translateContext('son’s daughter', 'Adoption of a granddaughter'); default: return I18N::translate('Adoption of a grandchild'); } case '_ADOP_HSIB': switch ($sex) { case 'M': return I18N::translate('Adoption of a half-brother'); case 'F': return I18N::translate('Adoption of a half-sister'); default: return I18N::translate('Adoption of a half-sibling'); } case '_ADOP_SIBL': switch ($sex) { case 'M': return I18N::translate('Adoption of a brother'); case 'F': return I18N::translate('Adoption of a sister'); default: return I18N::translate('Adoption of a sibling'); } case '_ADPF': switch ($sex) { case 'M': return I18N::translateContext('MALE', 'Adopted by father'); case 'F': return I18N::translateContext('FEMALE', 'Adopted by father'); default: return I18N::translate('Adopted by father'); } case '_ADPM': switch ($sex) { case 'M': return I18N::translateContext('MALE', 'Adopted by mother'); case 'F': return I18N::translateContext('FEMALE', 'Adopted by mother'); default: return I18N::translate('Adopted by mother'); } case '_AKA': case '_AKAN': switch ($sex) { case 'M': return I18N::translateContext('MALE', 'Also known as'); case 'F': return I18N::translateContext('FEMALE', 'Also known as'); default: return I18N::translate('Also known as'); } case '_ASSO': return I18N::translate('Associate'); /* see also ASSO */ /* see also ASSO */ case '_BAPM_CHIL': switch ($sex) { case 'M': return I18N::translate('Baptism of a son'); case 'F': return I18N::translate('Baptism of a daughter'); default: return I18N::translate('Baptism of a child'); } case '_BAPM_GCHI': switch ($sex) { case 'M': return I18N::translate('Baptism of a grandson'); case 'F': return I18N::translate('Baptism of a granddaughter'); default: return I18N::translate('Baptism of a grandchild'); } case '_BAPM_GCH1': switch ($sex) { case 'M': return I18N::translateContext('daughter’s son', 'Baptism of a grandson'); case 'F': return I18N::translateContext('daughter’s daughter', 'Baptism of a granddaughter'); default: return I18N::translate('Baptism of a grandchild'); } case '_BAPM_GCH2': switch ($sex) { case 'M': return I18N::translateContext('son’s son', 'Baptism of a grandson'); case 'F': return I18N::translateContext('son’s daughter', 'Baptism of a granddaughter'); default: return I18N::translate('Baptism of a grandchild'); } case '_BAPM_HSIB': switch ($sex) { case 'M': return I18N::translate('Baptism of a half-brother'); case 'F': return I18N::translate('Baptism of a half-sister'); default: return I18N::translate('Baptism of a half-sibling'); } case '_BAPM_SIBL': switch ($sex) { case 'M': return I18N::translate('Baptism of a brother'); case 'F': return I18N::translate('Baptism of a sister'); default: return I18N::translate('Baptism of a sibling'); } case '_BIBL': return I18N::translate('Bibliography'); case '_BIRT_CHIL': switch ($sex) { case 'M': return I18N::translate('Birth of a son'); case 'F': return I18N::translate('Birth of a daughter'); default: return I18N::translate('Birth of a child'); } case '_BIRT_GCHI': switch ($sex) { case 'M': return I18N::translate('Birth of a grandson'); case 'F': return I18N::translate('Birth of a granddaughter'); default: return I18N::translate('Birth of a grandchild'); } case '_BIRT_GCH1': switch ($sex) { case 'M': return I18N::translateContext('daughter’s son', 'Birth of a grandson'); case 'F': return I18N::translateContext('daughter’s daughter', 'Birth of a granddaughter'); default: return I18N::translate('Birth of a grandchild'); } case '_BIRT_GCH2': switch ($sex) { case 'M': return I18N::translateContext('son’s son', 'Birth of a grandson'); case 'F': return I18N::translateContext('son’s daughter', 'Birth of a granddaughter'); default: return I18N::translate('Birth of a grandchild'); } case '_BIRT_HSIB': switch ($sex) { case 'M': return I18N::translate('Birth of a half-brother'); case 'F': return I18N::translate('Birth of a half-sister'); default: return I18N::translate('Birth of a half-sibling'); } case '_BIRT_SIBL': switch ($sex) { case 'M': return I18N::translate('Birth of a brother'); case 'F': return I18N::translate('Birth of a sister'); default: return I18N::translate('Birth of a sibling'); } case '_BRTM': return I18N::translate('Brit milah'); case '_BRTM:DATE': return I18N::translate('Date of brit milah'); case '_BRTM:PLAC': return I18N::translate('Place of brit milah'); case '_BURI_CHIL': switch ($sex) { case 'M': return I18N::translate('Burial of a son'); case 'F': return I18N::translate('Burial of a daughter'); default: return I18N::translate('Burial of a child'); } case '_BURI_GCHI': switch ($sex) { case 'M': return I18N::translate('Burial of a grandson'); case 'F': return I18N::translate('Burial of a granddaughter'); default: return I18N::translate('Burial of a grandchild'); } case '_BURI_GCH1': switch ($sex) { case 'M': return I18N::translateContext('daughter’s son', 'Burial of a grandson'); case 'F': return I18N::translateContext('daughter’s daughter', 'Burial of a granddaughter'); default: return I18N::translate('Burial of a grandchild'); } case '_BURI_GCH2': switch ($sex) { case 'M': return I18N::translateContext('son’s son', 'Burial of a grandson'); case 'F': return I18N::translateContext('son’s daughter', 'Burial of a granddaughter'); default: return I18N::translate('Burial of a grandchild'); } case '_BURI_GPAR': switch ($sex) { case 'M': return I18N::translate('Burial of a grandfather'); case 'F': return I18N::translate('Burial of a grandmother'); default: return I18N::translate('Burial of a grandparent'); } case '_BURI_GPA1': switch ($sex) { case 'M': return I18N::translate('Burial of a paternal grandfather'); case 'F': return I18N::translate('Burial of a paternal grandmother'); default: return I18N::translate('Burial of a paternal grandparent'); } case '_BURI_GPA2': switch ($sex) { case 'M': return I18N::translate('Burial of a maternal grandfather'); case 'F': return I18N::translate('Burial of a maternal grandmother'); default: return I18N::translate('Burial of a maternal grandparent'); } case '_BURI_HSIB': switch ($sex) { case 'M': return I18N::translate('Burial of a half-brother'); case 'F': return I18N::translate('Burial of a half-sister'); default: return I18N::translate('Burial of a half-sibling'); } case '_BURI_PARE': switch ($sex) { case 'M': return I18N::translate('Burial of a father'); case 'F': return I18N::translate('Burial of a mother'); default: return I18N::translate('Burial of a parent'); } case '_BURI_SIBL': switch ($sex) { case 'M': return I18N::translate('Burial of a brother'); case 'F': return I18N::translate('Burial of a sister'); default: return I18N::translate('Burial of a sibling'); } case '_BURI_SPOU': switch ($sex) { case 'M': return I18N::translate('Burial of a husband'); case 'F': return I18N::translate('Burial of a wife'); default: return I18N::translate('Burial of a spouse'); } case '_CHR_CHIL': switch ($sex) { case 'M': return I18N::translate('Christening of a son'); case 'F': return I18N::translate('Christening of a daughter'); default: return I18N::translate('Christening of a child'); } case '_CHR_GCHI': switch ($sex) { case 'M': return I18N::translate('Christening of a grandson'); case 'F': return I18N::translate('Christening of a granddaughter'); default: return I18N::translate('Christening of a grandchild'); } case '_CHR_GCH1': switch ($sex) { case 'M': return I18N::translateContext('daughter’s son', 'Christening of a grandson'); case 'F': return I18N::translateContext('daughter’s daughter', 'Christening of a granddaughter'); default: return I18N::translate('Christening of a grandchild'); } case '_CHR_GCH2': switch ($sex) { case 'M': return I18N::translateContext('son’s son', 'Christening of a grandson'); case 'F': return I18N::translateContext('son’s daughter', 'Christening of a granddaughter'); default: return I18N::translate('Christening of a grandchild'); } case '_CHR_HSIB': switch ($sex) { case 'M': return I18N::translate('Christening of a half-brother'); case 'F': return I18N::translate('Christening of a half-sister'); default: return I18N::translate('Christening of a half-sibling'); } case '_CHR_SIBL': switch ($sex) { case 'M': return I18N::translate('Christening of a brother'); case 'F': return I18N::translate('Christening of a sister'); default: return I18N::translate('Christening of a sibling'); } case '_COML': return I18N::translate('Common law marriage'); case '_CREM_CHIL': switch ($sex) { case 'M': return I18N::translate('Cremation of a son'); case 'F': return I18N::translate('Cremation of a daughter'); default: return I18N::translate('Cremation of a child'); } case '_CREM_GCHI': switch ($sex) { case 'M': return I18N::translate('Cremation of a grandson'); case 'F': return I18N::translate('Cremation of a granddaughter'); default: return I18N::translate('Cremation of a grandchild'); } case '_CREM_GCH1': switch ($sex) { case 'M': return I18N::translateContext('daughter’s son', 'Cremation of a grandson'); case 'F': return I18N::translateContext('daughter’s daughter', 'Cremation of a granddaughter'); default: return I18N::translate('Cremation of a grandchild'); } case '_CREM_GCH2': switch ($sex) { case 'M': return I18N::translateContext('son’s son', 'Cremation of a grandson'); case 'F': return I18N::translateContext('son’s daughter', 'Cremation of a granddaughter'); default: return I18N::translate('Cremation of a grandchild'); } case '_CREM_GPAR': switch ($sex) { case 'M': return I18N::translate('Cremation of a grandfather'); case 'F': return I18N::translate('Cremation of a grandmother'); default: return I18N::translate('Cremation of a grand-parent'); } case '_CREM_GPA1': switch ($sex) { case 'M': return I18N::translate('Cremation of a paternal grandfather'); case 'F': return I18N::translate('Cremation of a paternal grandmother'); default: return I18N::translate('Cremation of a grand-parent'); } case '_CREM_GPA2': switch ($sex) { case 'M': return I18N::translate('Cremation of a maternal grandfather'); case 'F': return I18N::translate('Cremation of a maternal grandmother'); default: return I18N::translate('Cremation of a grand-parent'); } case '_CREM_HSIB': switch ($sex) { case 'M': return I18N::translate('Cremation of a half-brother'); case 'F': return I18N::translate('Cremation of a half-sister'); default: return I18N::translate('Cremation of a half-sibling'); } case '_CREM_PARE': switch ($sex) { case 'M': return I18N::translate('Cremation of a father'); case 'F': return I18N::translate('Cremation of a mother'); default: return I18N::translate('Cremation of a parent'); } case '_CREM_SIBL': switch ($sex) { case 'M': return I18N::translate('Cremation of a brother'); case 'F': return I18N::translate('Cremation of a sister'); default: return I18N::translate('Cremation of a sibling'); } case '_CREM_SPOU': switch ($sex) { case 'M': return I18N::translate('Cremation of a husband'); case 'F': return I18N::translate('Cremation of a wife'); default: return I18N::translate('Cremation of a spouse'); } case '_DBID': return I18N::translate('Linked database ID'); case '_DEAT_CHIL': switch ($sex) { case 'M': return I18N::translate('Death of a son'); case 'F': return I18N::translate('Death of a daughter'); default: return I18N::translate('Death of a child'); } case '_DEAT_GCHI': switch ($sex) { case 'M': return I18N::translate('Death of a grandson'); case 'F': return I18N::translate('Death of a granddaughter'); default: return I18N::translate('Death of a grandchild'); } case '_DEAT_GCH1': switch ($sex) { case 'M': return I18N::translateContext('daughter’s son', 'Death of a grandson'); case 'F': return I18N::translateContext('daughter’s daughter', 'Death of a granddaughter'); default: return I18N::translate('Death of a grandchild'); } case '_DEAT_GCH2': switch ($sex) { case 'M': return I18N::translateContext('son’s son', 'Death of a grandson'); case 'F': return I18N::translateContext('son’s daughter', 'Death of a granddaughter'); default: return I18N::translate('Death of a grandchild'); } case '_DEAT_GPAR': switch ($sex) { case 'M': return I18N::translate('Death of a grandfather'); case 'F': return I18N::translate('Death of a grandmother'); default: return I18N::translate('Death of a grand-parent'); } case '_DEAT_GPA1': switch ($sex) { case 'M': return I18N::translate('Death of a paternal grandfather'); case 'F': return I18N::translate('Death of a paternal grandmother'); default: return I18N::translate('Death of a grand-parent'); } case '_DEAT_GPA2': switch ($sex) { case 'M': return I18N::translate('Death of a maternal grandfather'); case 'F': return I18N::translate('Death of a maternal grandmother'); default: return I18N::translate('Death of a grand-parent'); } case '_DEAT_HSIB': switch ($sex) { case 'M': return I18N::translate('Death of a half-brother'); case 'F': return I18N::translate('Death of a half-sister'); default: return I18N::translate('Death of a half-sibling'); } case '_DEAT_PARE': switch ($sex) { case 'M': return I18N::translate('Death of a father'); case 'F': return I18N::translate('Death of a mother'); default: return I18N::translate('Death of a parent'); } case '_DEAT_SIBL': switch ($sex) { case 'M': return I18N::translate('Death of a brother'); case 'F': return I18N::translate('Death of a sister'); default: return I18N::translate('Death of a sibling'); } case '_DEAT_SPOU': switch ($sex) { case 'M': return I18N::translate('Death of a husband'); case 'F': return I18N::translate('Death of a wife'); default: return I18N::translate('Death of a spouse'); } case '_DEG': return I18N::translate('Degree'); case '_DETS': return I18N::translate('Death of one spouse'); case '_DNA': return I18N::translate('DNA markers'); case '_EMAIL': return I18N::translate('Email address'); case '_EYEC': return I18N::translate('Eye color'); case '_FA1': return I18N::translate('Fact 1'); case '_FA2': return I18N::translate('Fact 2'); case '_FA3': return I18N::translate('Fact 3'); case '_FA4': return I18N::translate('Fact 4'); case '_FA5': return I18N::translate('Fact 5'); case '_FA6': return I18N::translate('Fact 6'); case '_FA7': return I18N::translate('Fact 7'); case '_FA8': return I18N::translate('Fact 8'); case '_FA9': return I18N::translate('Fact 9'); case '_FA10': return I18N::translate('Fact 10'); case '_FA11': return I18N::translate('Fact 11'); case '_FA12': return I18N::translate('Fact 12'); case '_FA13': return I18N::translate('Fact 13'); case '_FNRL': return I18N::translate('Funeral'); case '_FREL': return I18N::translate('Relationship to father'); case '_GEDF': return I18N::translate('GEDCOM file'); case '_GODP': return I18N::translate('Godparent'); case '_HAIR': return I18N::translate('Hair color'); case '_HEB': return I18N::translate('Hebrew'); case '_HEIG': return I18N::translate('Height'); case '_HNM': return I18N::translate('Hebrew name'); case '_HOL': return I18N::translate('Holocaust'); case '_INTE': switch ($sex) { case 'M': return I18N::translateContext('MALE', 'Interred'); case 'F': return I18N::translateContext('FEMALE', 'Interred'); default: return I18N::translate('Interred'); } case '_LOC': return I18N::translate('Location'); case '_MARI': return I18N::translate('Marriage intention'); case '_MARNM': return I18N::translate('Married name'); case '_PRIM': return I18N::translate('Highlighted image'); case '_MARNM_SURN': return I18N::translate('Married surname'); case '_MARR_CHIL': switch ($sex) { case 'M': return I18N::translate('Marriage of a son'); case 'F': return I18N::translate('Marriage of a daughter'); default: return I18N::translate('Marriage of a child'); } case '_MARR_FAMC': return I18N::translate('Marriage of parents'); case '_MARR_GCHI': switch ($sex) { case 'M': return I18N::translate('Marriage of a grandson'); case 'F': return I18N::translate('Marriage of a granddaughter'); default: return I18N::translate('Marriage of a grandchild'); } case '_MARR_GCH1': switch ($sex) { case 'M': return I18N::translateContext('daughter’s son', 'Marriage of a grandson'); case 'F': return I18N::translateContext('daughter’s daughter', 'Marriage of a granddaughter'); default: return I18N::translate('Marriage of a grandchild'); } case '_MARR_GCH2': switch ($sex) { case 'M': return I18N::translateContext('son’s son', 'Marriage of a grandson'); case 'F': return I18N::translateContext('son’s daughter', 'Marriage of a granddaughter'); default: return I18N::translate('Marriage of a grandchild'); } case '_MARR_HSIB': switch ($sex) { case 'M': return I18N::translate('Marriage of a half-brother'); case 'F': return I18N::translate('Marriage of a half-sister'); default: return I18N::translate('Marriage of a half-sibling'); } case '_MARR_PARE': switch ($sex) { case 'M': return I18N::translate('Marriage of a father'); case 'F': return I18N::translate('Marriage of a mother'); default: return I18N::translate('Marriage of a parent'); } case '_MARR_SIBL': switch ($sex) { case 'M': return I18N::translate('Marriage of a brother'); case 'F': return I18N::translate('Marriage of a sister'); default: return I18N::translate('Marriage of a sibling'); } case '_MBON': return I18N::translate('Marriage bond'); case '_MDCL': return I18N::translate('Medical'); case '_MEDC': return I18N::translate('Medical condition'); case '_MEND': return I18N::translate('Marriage ending status'); case '_MILI': return I18N::translate('Military'); case '_MILT': return I18N::translate('Military service'); case '_MREL': return I18N::translate('Relationship to mother'); case '_MSTAT': return I18N::translate('Marriage beginning status'); case '_NAME': return I18N::translate('Mailing name'); case '_NAMS': return I18N::translate('Namesake'); case '_NLIV': return I18N::translate('Not living'); case '_NMAR': switch ($sex) { case 'M': return I18N::translateContext('MALE', 'Never married'); case 'F': return I18N::translateContext('FEMALE', 'Never married'); default: return I18N::translate('Never married'); } case '_NMR': switch ($sex) { case 'M': return I18N::translateContext('MALE', 'Not married'); case 'F': return I18N::translateContext('FEMALE', 'Not married'); default: return I18N::translate('Not married'); } case '_WT_USER': return I18N::translate('by'); case '_PRMN': return I18N::translate('Permanent number'); case '_SCBK': return I18N::translate('Scrapbook'); case '_SEPR': return I18N::translate('Separated'); case '_SSHOW': return I18N::translate('Slide show'); case '_STAT': return I18N::translate('Marriage status'); case '_SUBQ': return I18N::translate('Short version'); case '_TODO': return I18N::translate('Research task'); case '_TYPE': return I18N::translate('Media type'); case '_UID': return I18N::translate('Globally unique identifier'); case '_URL': return I18N::translate('URL'); case '_WEIG': return I18N::translate('Weight'); case '_WITN': return I18N::translate('Witness'); case '_WT_OBJE_SORT': return I18N::translate('Re-order media'); case '_YART': return I18N::translate('Yahrzeit'); // Brit milah applies only to males, no need for male/female translations // Brit milah applies only to males, no need for male/female translations case '__BRTM_CHIL': return I18N::translate('Brit milah of a son'); case '__BRTM_GCHI': return I18N::translate('Brit milah of a grandson'); case '__BRTM_GCH1': return I18N::translateContext('daughter’s son', 'Brit milah of a grandson'); case '__BRTM_GCH2': return I18N::translateContext('son’s son', 'Brit milah of a grandson'); case '__BRTM_HSIB': return I18N::translate('Brit milah of a half-brother'); case '__BRTM_SIBL': return I18N::translate('Brit milah of a brother'); // These "pseudo" tags are generated internally to present information about a media object // These "pseudo" tags are generated internally to present information about a media object case '__FILE_SIZE__': return I18N::translate('File size'); case '__IMAGE_SIZE__': return I18N::translate('Image dimensions'); default: // If no specialisation exists (e.g. DEAT:CAUS), then look for the general (CAUS) if (strpos($tag, ':')) { list(, $tag) = explode(':', $tag, 2); return self::getLabel($tag, $record); } // Still no translation? Highlight this as an error return '<span class="error" title="' . I18N::translate('Unrecognized GEDCOM code') . '">' . Filter::escapeHtml($tag) . '</span>'; } }
/** * Create a new record from GEDCOM data. * * @param string $gedcom * * @throws \Exception * * @return GedcomRecord */ public function createRecord($gedcom) { if (preg_match('/^0 @(' . WT_REGEX_XREF . ')@ (' . WT_REGEX_TAG . ')/', $gedcom, $match)) { $xref = $match[1]; $type = $match[2]; } else { throw new \Exception('Invalid argument to GedcomRecord::createRecord(' . $gedcom . ')'); } if (strpos("\r", $gedcom) !== false) { // MSDOS line endings will break things in horrible ways throw new \Exception('Evil line endings found in GedcomRecord::createRecord(' . $gedcom . ')'); } // webtrees creates XREFs containing digits. Anything else (e.g. “new”) is just a placeholder. if (!preg_match('/\\d/', $xref)) { $xref = $this->getNewXref($type); $gedcom = preg_replace('/^0 @(' . WT_REGEX_XREF . ')@/', '0 @' . $xref . '@', $gedcom); } // Create a change record, if not already present if (!preg_match('/\\n1 CHAN/', $gedcom)) { $gedcom .= "\n1 CHAN\n2 DATE " . date('d M Y') . "\n3 TIME " . date('H:i:s') . "\n2 _WT_USER " . Auth::user()->getUserName(); } // Create a pending change Database::prepare("INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, '', ?, ?)")->execute(array($this->tree_id, $xref, $gedcom, Auth::id())); Log::addEditLog('Create: ' . $type . ' ' . $xref); // Accept this pending change if (Auth::user()->getPreference('auto_accept')) { FunctionsImport::acceptAllChanges($xref, $this->tree_id); } // Return the newly created record. Note that since GedcomRecord // has a cache of pending changes, we cannot use it to create a // record with a newly created pending change. return GedcomRecord::getInstance($xref, $this, $gedcom); }
/** * Startup activity */ public function __construct() { global $WT_TREE; parent::__construct(); // $action comes from GET (search) or POST (replace) if (Filter::post('action')) { $this->action = Filter::post('action', 'replace', 'general'); $this->query = Filter::post('query'); $this->replace = Filter::post('replace'); $this->replaceNames = Filter::post('replaceNames', 'checked', ''); $this->replacePlaces = Filter::post('replacePlaces', 'checked', ''); $this->replacePlacesWord = Filter::post('replacePlacesWord', 'checked', ''); $this->replaceAll = Filter::post('replaceAll', 'checked', ''); } else { $this->action = Filter::get('action', 'advanced|general|soundex|replace|header', 'general'); $this->query = Filter::get('query'); $this->replace = Filter::get('replace'); $this->replaceNames = Filter::get('replaceNames', 'checked', ''); $this->replacePlaces = Filter::get('replacePlaces', 'checked', ''); $this->replacePlacesWord = Filter::get('replacePlacesWord', 'checked', ''); $this->replaceAll = Filter::get('replaceAll', 'checked', ''); } // Only editors can use search/replace if ($this->action === 'replace' && !Auth::isEditor($WT_TREE)) { $this->action = 'general'; } $this->srindi = Filter::get('srindi', 'checked', ''); $this->srfams = Filter::get('srfams', 'checked', ''); $this->srsour = Filter::get('srsour', 'checked', ''); $this->srnote = Filter::get('srnote', 'checked', ''); $this->soundex = Filter::get('soundex', 'DaitchM|Russell', 'DaitchM'); $this->showasso = Filter::get('showasso'); $this->firstname = Filter::get('firstname'); $this->lastname = Filter::get('lastname'); $this->place = Filter::get('place'); $this->year = Filter::get('year'); // If no record types specified, search individuals if (!$this->srfams && !$this->srsour && !$this->srnote) { $this->srindi = 'checked'; } // If no replace types specifiied, replace full records if (!$this->replaceNames && !$this->replacePlaces && !$this->replacePlacesWord) { $this->replaceAll = 'checked'; } // Trees to search if (Site::getPreference('ALLOW_CHANGE_GEDCOM')) { foreach (Tree::getAll() as $search_tree) { if (Filter::get('tree_' . $search_tree->getTreeId())) { $this->search_trees[] = $search_tree; } } if (!$this->search_trees) { $this->search_trees[] = $WT_TREE; } } else { $this->search_trees[] = $WT_TREE; } // If we want to show associated persons, build the list switch ($this->action) { case 'header': // We can type in an XREF into the header search, and jump straight to it. // Otherwise, the header search is the same as the general search if (preg_match('/' . WT_REGEX_XREF . '/', $this->query)) { $record = GedcomRecord::getInstance($this->query, $WT_TREE); if ($record && $record->canShowName()) { header('Location: ' . WT_BASE_URL . $record->getRawUrl()); exit; } } $this->action = 'general'; $this->srindi = 'checked'; $this->srfams = 'checked'; $this->srsour = 'checked'; $this->srnote = 'checked'; $this->setPageTitle(I18N::translate('General search')); $this->generalSearch(); break; case 'general': $this->setPageTitle(I18N::translate('General search')); $this->generalSearch(); break; case 'soundex': // Create a dummy search query to use as a title to the results list $this->query = trim($this->firstname . ' ' . $this->lastname . ' ' . $this->place); $this->setPageTitle(I18N::translate('Phonetic search')); $this->soundexSearch(); break; case 'replace': $this->setPageTitle(I18N::translate('Search and replace')); $this->search_trees = array($WT_TREE); $this->srindi = 'checked'; $this->srfams = 'checked'; $this->srsour = 'checked'; $this->srnote = 'checked'; if (Filter::post('query')) { $this->searchAndReplace($WT_TREE); header('Location: ' . WT_BASE_URL . WT_SCRIPT_NAME . '?action=replace&query=' . Filter::escapeUrl($this->query) . '&replace=' . Filter::escapeUrl($this->replace) . '&replaceAll=' . $this->replaceAll . '&replaceNames=' . $this->replaceNames . '&replacePlaces=' . $this->replacePlaces . '&replacePlacesWord=' . $this->replacePlacesWord); exit; } } }
/** * Search for a media object. */ private static function mediaQuery() { global $WT_TREE; $iid2 = Filter::get('iid', WT_REGEX_XREF); $controller = new SimpleController(); $controller->setPageTitle(I18N::translate('Link to an existing media object'))->pageHeader(); $record = GedcomRecord::getInstance($iid2, $WT_TREE); if ($record) { $headjs = ''; if ($record instanceof Family) { if ($record->getHusband()) { $headjs = $record->getHusband()->getXref(); } elseif ($record->getWife()) { $headjs = $record->getWife()->getXref(); } } ?> <script> function insertId() { if (window.opener.document.getElementById('addlinkQueue')) { // alert('Please move this alert window and examine the contents of the pop-up window, then click OK') window.opener.insertRowToTable('<?php echo $record->getXref(); ?> ', '<?php echo htmlspecialchars($record->getFullName()); ?> ', '<?php echo $headjs; ?> '); window.close(); } } </script> <?php } else { ?> <script> function insertId() { window.opener.alert('<?php echo $iid2; ?> - <?php echo I18N::translate('Not a valid individual, family, or source ID'); ?> '); window.close(); } </script> <?php } ?> <script>window.onLoad = insertId();</script> <?php }