'), ENT_QUOTES, 'UTF-8');
break;
}
list($text) = explode("\n", $text);
$first_line = strlen($text) > 100 ? mb_substr($text, 0, 100) . WT_I18N::translate('…') : $text;
}
return
'' .
' ' . WT_Gedcom_Tag::getLabel($label) . ': ' . '
' . $first_line . '' .
'
' .
'' . $html . '
';
}
}
/**
* Print all of the notes in this fact record
*
* @param string $factrec the factrecord to print the notes from
* @param int $level The level of the factrecord
* @param bool $textOnly Don't print the "Note: " introduction
*
* @return string HTML
*/
function print_fact_notes($factrec, $level, $textOnly=false) {
$data = "";
$previous_spos = 0;
$nlevel = $level+1;
$ct = preg_match_all("/$level NOTE (.*)/", $factrec, $match, PREG_SET_ORDER);
for ($j=0; $j<$ct; $j++) {
$spos1 = strpos($factrec, $match[$j][0], $previous_spos);
$spos2 = strpos($factrec."\n$level", "\n$level", $spos1+1);
if (!$spos2) $spos2 = strlen($factrec);
$previous_spos = $spos2;
$nrec = substr($factrec, $spos1, $spos2-$spos1);
if (!isset($match[$j][1])) $match[$j][1]="";
if (!preg_match("/@(.*)@/", $match[$j][1], $nmatch)) {
$data .= print_note_record($match[$j][1], $nlevel, $nrec, $textOnly);
} else {
$note = WT_Note::getInstance($nmatch[1]);
if ($note) {
if ($note->canShow()) {
$noterec = $note->getGedcom();
$nt = preg_match("/0 @$nmatch[1]@ NOTE (.*)/", $noterec, $n1match);
$data .= print_note_record(($nt>0)?$n1match[1]:"", 1, $noterec, $textOnly);
if (!$textOnly) {
if (strpos($noterec, "1 SOUR")!==false) {
require_once WT_ROOT.'includes/functions/functions_print_facts.php';
$data .= print_fact_sources($noterec, 1);
}
}
}
} else {
$data=''.WT_I18N::translate('Note').': '.$nmatch[1].'
';
}
}
if (!$textOnly) {
if (strpos($factrec, "$nlevel SOUR")!==false) {
$data .= "";
$data .= print_fact_sources($nrec, $nlevel);
$data .= "
";
}
}
}
return $data;
}
// Print a link for a popup help window
function help_link($help_topic, $module='') {
return ' ';
}
// Print an external help link to the wiki site, in a new window
function wiki_help_link($topic) {
return ' ';
}
// When a user has searched for text, highlight any matches in
// the displayed string.
function highlight_search_hits($string) {
global $controller;
if ($controller instanceof WT_Controller_Search && $controller->query) {
// TODO: when a search contains multiple words, we search independently.
// e.g. searching for "FOO BAR" will find records containing both FOO and BAR.
// However, we only highlight the original search string, not the search terms.
// The controller needs to provide its "query_terms" array.
$regex=array();
foreach (array($controller->query) as $search_term) {
$regex[]=preg_quote($search_term, '/');
}
// Match these strings, provided they do not occur inside HTML tags
$regex='('.implode('|', $regex).')(?![^<]*>)';
return preg_replace('/'.$regex.'/i', '$1', $string);
} else {
return $string;
}
}
// Print the associations from the associated individuals in $event to the individuals in $record
function format_asso_rela_record(WT_Fact $event) {
global $SEARCH_SPIDER;
$parent = $event->getParent();
// To whom is this record an assocate?
if ($parent instanceof WT_Individual) {
// On an individual page, we just show links to the person
$associates = array($parent);
} elseif ($parent instanceof WT_Family) {
// On a family page, we show links to both spouses
$associates = $parent->getSpouses();
} else {
// On other pages, it does not make sense to show associates
return '';
}
preg_match_all('/^1 ASSO @('.WT_REGEX_XREF.')@((\n[2-9].*)*)/', $event->getGedcom(), $amatches1, PREG_SET_ORDER);
preg_match_all('/\n2 _?ASSO @('.WT_REGEX_XREF.')@((\n[3-9].*)*)/', $event->getGedcom(), $amatches2, PREG_SET_ORDER);
$html = '';
// For each ASSO record
foreach (array_merge($amatches1, $amatches2) as $amatch) {
$person = WT_Individual::getInstance($amatch[1]);
if ($person) {
// Is there a "RELA" tag
if (preg_match('/\n[23] RELA (.+)/', $amatch[2], $rmatch)) {
// Use the supplied relationship as a label
$label = WT_Gedcom_Code_Rela::getValue($rmatch[1], $person);
} else {
// Use a default label
$label = WT_Gedcom_Tag::getLabel('ASSO', $person);
}
$values = array('' . $person->getFullName() . '');
if (!$SEARCH_SPIDER) {
foreach ($associates as $associate) {
$relationship_name = get_associate_relationship_name($associate, $person);
if (!$relationship_name) {
$relationship_name = WT_Gedcom_Tag::getLabel('RELA');
}
if ($parent instanceof WT_Family) {
// For family ASSO records (e.g. MARR), identify the spouse with a sex icon
$relationship_name .= $associate->getSexImage();
}
$values[] = '' . $relationship_name . '';
}
}
$value = implode(' — ', $values);
// Use same markup as WT_Gedcom_Tag::getLabelValue()
$asso = WT_I18N::translate('%1$s: %2$s', $label, $value);
} else {
$asso = WT_Gedcom_Tag::getLabelValue('ASSO', '' . $amatch[1] . '');
}
$html .= '' . $asso . '
';
}
return $html;
}
/**
* Format age of parents in HTML
*
* @param WT_Individual $person child
* @param WT_Date $birth_date
*
* @return string HTML
*/
function format_parents_age(WT_Individual $person, WT_Date $birth_date) {
$html='';
$families=$person->getChildFamilies();
// Multiple sets of parents (e.g. adoption) cause complications, so ignore.
if ($birth_date->isOK() && count($families)==1) {
$family=current($families);
foreach ($family->getSpouses() as $parent) {
if ($parent->getBirthDate()->isOK()) {
$sex=$parent->getSexImage();
$age=WT_Date::getAge($parent->getBirthDate(), $birth_date, 2);
$deatdate=$parent->getDeathDate();
switch ($parent->getSex()) {
case 'F':
// Highlight mothers who die in childbirth or shortly afterwards
if ($deatdate->isOK() && $deatdate->MinJD()<$birth_date->MinJD()+90) {
$html.=' '.$sex.$age.'';
} else {
$html.=' '.$sex.$age.'';
}
break;
case 'M':
// Highlight fathers who die before the birth
if ($deatdate->isOK() && $deatdate->MinJD()<$birth_date->MinJD()) {
$html.=' '.$sex.$age.'';
} else {
$html.=' '.$sex.$age.'';
}
break;
default:
$html.=' '.$sex.$age.'';
break;
}
}
}
if ($html) {
$html=''.$html.'';
}
}
return $html;
}
// print fact DATE TIME
//
// $event - event containing the date/age
// $record - the person (or couple) whose ages should be printed
// $anchor option to print a link to calendar
// $time option to print TIME value
function format_fact_date(WT_Fact $event, WT_GedcomRecord $record, $anchor=false, $time=false) {
global $pid, $SEARCH_SPIDER, $SHOW_PARENTS_AGE;
$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('/2 DATE (.+)/', $factrec, $match)) {
$date=new WT_Date($match[1]);
$html.=' '.$date->Display($anchor && !$SEARCH_SPIDER);
// time
if ($time) {
$timerec=get_sub_record(2, '2 TIME', $factrec);
if ($timerec=='') {
$timerec=get_sub_record(2, '2 DATE', $factrec);
}
if (preg_match('/[2-3] TIME (.*)/', $timerec, $tmatch)) {
$html.=' - '.$tmatch[1].'';
}
}
$fact = $event->getTag();
if ($record instanceof WT_Individual) {
// age of parents at child birth
if ($fact=='BIRT' && $SHOW_PARENTS_AGE) {
$html .= format_parents_age($record, $date);
}
// age at event
else if ($fact!='CHAN' && $fact!='_TODO') {
$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 WT_Date('');
}
$ageText = '';
if ((WT_Date::Compare($date, $death_date)<=0 || !$record->isDead()) || $fact=='DEAT') {
// Before death, print age
$age=WT_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 = '('.WT_I18N::translate('Age').' '.get_age_at_event($age, false).')';
}
}
}
}
if ($fact!='DEAT' && WT_Date::Compare($date, $death_date)>=0) {
// After death, print time since death
$age=get_age_at_event(WT_Date::GetAgeGedcom($death_date, $date), true);
if ($age!='') {
if (WT_Date::GetAgeGedcom($death_date, $date)=="0d") {
$ageText = '('.WT_I18N::translate('on the date of death').')';
} else {
$ageText = '('.$age.' '.WT_I18N::translate('after death').')';
// Family events which occur after death are probably errors
if ($event->getParent() instanceof WT_Family) {
$ageText.='';
}
}
}
}
if ($ageText) $html .= ' '.$ageText.'';
}
} elseif ($record instanceof WT_Family) {
$indi = WT_Individual::getInstance($pid);
if ($indi) {
$birth_date=$indi->getBirthDate();
$death_date=$indi->getDeathDate();
$ageText = '';
if (WT_Date::Compare($date, $death_date)<=0) {
$age=WT_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 = '('.WT_I18N::translate('Age').' '.get_age_at_event($age, false).')';
}
}
}
if ($ageText) $html .= ' '.$ageText.'';
}
}
} 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.=WT_I18N::translate('yes');
}
}
// print gedcom ages
foreach (array(WT_Gedcom_Tag::getLabel('AGE')=>$fact_age, WT_Gedcom_Tag::getLabel('HUSB')=>$husb_age, WT_Gedcom_Tag::getLabel('WIFE')=>$wife_age) as $label=>$age) {
if ($age!='') {
$html.=' '.$label.': '.get_age_at_event($age, false).'';
}
}
return $html;
}
/**
* print fact PLACe TEMPle STATus
*
* @param WT_Fact $event gedcom fact record
* @param bool $anchor to print a link to placelist
* @param bool $sub_records to print place subrecords
* @param bool $lds to print LDS TEMPle and STATus
*
* @return string HTML
*/
function format_fact_place(WT_Fact $event, $anchor=false, $sub_records=false, $lds=false) {
global $SEARCH_SPIDER;
if ($anchor) {
// Show the full place name, for facts/events tab
if ($SEARCH_SPIDER) {
$html = $event->getPlace()->getFullName();
} else {
$html = '' . $event->getPlace()->getFullName() . '';
}
} else {
// Abbreviate the place name, for chart boxes
return ' - ' . $event->getPlace()->getShortName();
}
if ($sub_records) {
$placerec = get_sub_record(2, '2 PLAC', $event->getGedcom());
if (!empty($placerec)) {
if (preg_match_all('/\n3 (?:_HEB|ROMN) (.+)/', $placerec, $matches)) {
foreach ($matches[1] as $match) {
$wt_place=new WT_Place($match, WT_GED_ID);
$html.=' - ' . $wt_place->getFullName();
}
}
$map_lati="";
$cts = preg_match('/\d LATI (.*)/', $placerec, $match);
if ($cts>0) {
$map_lati=$match[1];
$html .= '
' . WT_Gedcom_Tag::getLabel('LATI') . ': ' . $map_lati;
}
$map_long = '';
$cts = preg_match('/\d LONG (.*)/', $placerec, $match);
if ($cts > 0) {
$map_long = $match[1];
$html .= ' ' . WT_Gedcom_Tag::getLabel('LONG') . ': ' . $map_long;
}
if ($map_lati && $map_long) {
$map_lati = trim(strtr($map_lati, "NSEW,�", " - -. ")); // S5,6789 ==> -5.6789
$map_long = trim(strtr($map_long, "NSEW,�", " - -. ")); // E3.456� ==> 3.456
$html .= ' ';
$html .= ' ';
$html .= ' ';
}
if (preg_match('/\d NOTE (.*)/', $placerec, $match)) {
$html .= '
' . print_fact_notes($placerec, 3);
}
}
}
if ($lds) {
if (preg_match('/2 TEMP (.*)/', $event->getGedcom(), $match)) {
$html.='
'.WT_I18N::translate('LDS temple').': '.WT_Gedcom_Code_Temp::templeName($match[1]);
}
if (preg_match('/2 STAT (.*)/', $event->getGedcom(), $match)) {
$html.='
'.WT_I18N::translate('Status').': '.WT_Gedcom_Code_Stat::statusName($match[1]);
if (preg_match('/3 DATE (.*)/', $event->getGedcom(), $match)) {
$date=new WT_Date($match[1]);
$html.=', '.WT_Gedcom_Tag::getLabel('STAT:DATE').': '.$date->Display(false);
}
}
}
return $html;
}
/**
* Check for facts that may exist only once for a certain record type.
* If the fact already exists in the second array, delete it from the first one.
*/
function CheckFactUnique($uniquefacts, $recfacts, $type) {
foreach ($recfacts as $factarray) {
$fact=false;
if (is_object($factarray)) {
/* @var $factarray Event */
$fact = $factarray->getTag();
}
else {
if (($type == "SOUR") || ($type == "REPO")) $factrec = $factarray[0];
if (($type == "FAM") || ($type == "INDI")) $factrec = $factarray[1];
$ft = preg_match("/1 (\w+)(.*)/", $factrec, $match);
if ($ft>0) {
$fact = trim($match[1]);
}
}
if ($fact!==false) {
$key = array_search($fact, $uniquefacts);
if ($key !== false) unset($uniquefacts[$key]);
}
}
return $uniquefacts;
}
/**
* 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
*/
function print_add_new_fact($id, $usedfacts, $type) {
global $WT_SESSION, $WT_TREE;
// -- Add from clipboard
if ($WT_SESSION->clipboard) {
$newRow = true;
foreach (array_reverse($WT_SESSION->clipboard, true) as $fact_id=>$fact) {
if ($fact["type"]==$type || $fact["type"]=='all') {
if ($newRow) {
$newRow = false;
echo '| ';
echo WT_I18N::translate('Add from clipboard'), ' | ';
echo ' |
', "\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(CheckFactUnique($uniquefacts, $usedfacts, $type), $addfacts);
$quickfacts=array_intersect($quickfacts, $addfacts);
$translated_addfacts=array();
foreach ($addfacts as $addfact) {
$translated_addfacts[$addfact] = WT_Gedcom_Tag::getLabel($addfact);
}
uasort($translated_addfacts, function ($x, $y) {
return WT_I18N::strcasecmp(WT_I18N::translate($x), WT_I18N::translate($y));
});
echo '| ';
echo WT_I18N::translate('Fact or event');
echo help_link('add_facts'), ' | ';
echo '';
echo '';
echo ' |
';
}
/**
* javascript declaration for calendar popup
*/
function init_calendar_popup() {
global $WEEK_START, $controller;
$controller->addInlineJavascript('
cal_setMonthNames(
"' . WT_I18N::translate_c('NOMINATIVE', 'January') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'February') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'March') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'April') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'May') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'June') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'July') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'August') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'September') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'October') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'November') . '",
"' . WT_I18N::translate_c('NOMINATIVE', 'December') . '"
)
cal_setDayHeaders(
"' . WT_I18N::translate('Sun') . '",
"' . WT_I18N::translate('Mon') . '",
"' . WT_I18N::translate('Tue') . '",
"' . WT_I18N::translate('Wed') . '",
"' . WT_I18N::translate('Thu') . '",
"' . WT_I18N::translate('Fri') . '",
"' . WT_I18N::translate('Sat') . '"
)
cal_setWeekStart(' . $WEEK_START . ');
');
}
function print_findindi_link($element_id, $indiname='', $ged=WT_GEDCOM) {
return '';
}
function print_findplace_link($element_id) {
return '';
}
function print_findfamily_link($element_id) {
return '';
}
function print_specialchar_link($element_id) {
return '';
}
function print_autopaste_link($element_id, $choices) {
echo '';
foreach ($choices as $choice) {
echo '", $choice, ' ';
}
echo '';
}
function print_findsource_link($element_id, $sourcename='') {
return '';
}
function print_findnote_link($element_id, $notename='') {
return '';
}
function print_findrepository_link($element_id) {
return '';
}
function print_findmedia_link($element_id, $choose='') {
return '';
}
function print_findfact_link($element_id) {
return '';
}
// Summary of LDS ordinances
function get_lds_glance(WT_Individual $indi) {
$BAPL = $indi->getFacts('BAPL') ? 'B' : '_';
$ENDL = $indi->getFacts('ENDL') ? 'E' : '_';
$SLGC = $indi->getFacts('SLGC') ? 'C' : '_';
$SLGS = '_';
foreach ($indi->getSpouseFamilies() as $family) {
if ($family->getFacts('SLGS')) {
$SLGS = '';
}
}
return $BAPL . $ENDL . $SLGS . $SLGC;
}