1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/webtrees_ynh.git synced 2024-09-03 18:26:37 +02:00
webtrees_ynh/sources/app/Functions/FunctionsEdit.php

1810 lines
59 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* webtrees: online genealogy
* Copyright (C) 2016 webtrees development team
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Fisharebest\Webtrees\Functions;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Census\Census;
use Fisharebest\Webtrees\Census\CensusOfCzechRepublic;
use Fisharebest\Webtrees\Census\CensusOfDenmark;
use Fisharebest\Webtrees\Census\CensusOfEngland;
use Fisharebest\Webtrees\Census\CensusOfFrance;
use Fisharebest\Webtrees\Census\CensusOfScotland;
use Fisharebest\Webtrees\Census\CensusOfUnitedStates;
use Fisharebest\Webtrees\Census\CensusOfWales;
use Fisharebest\Webtrees\Config;
use Fisharebest\Webtrees\Date;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeAdop;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeName;
use Fisharebest\Webtrees\GedcomCode\GedcomCodePedi;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeQuay;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeRela;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeStat;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeTemp;
use Fisharebest\Webtrees\GedcomRecord;
use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Media;
use Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Note;
use Fisharebest\Webtrees\Repository;
use Fisharebest\Webtrees\Source;
use Fisharebest\Webtrees\User;
use Rhumsaa\Uuid\Uuid;
/**
* Class FunctionsEdit - common functions
*/
class FunctionsEdit {
/**
* Create a <select> control for a form.
*
* @param string $name
* @param string[] $values
* @param string|null $empty
* @param string $selected
* @param string $extra
*
* @return string
*/
public static function selectEditControl($name, $values, $empty, $selected, $extra = '') {
if (is_null($empty)) {
$html = '';
} else {
if (empty($selected)) {
$html = '<option value="" selected>' . Filter::escapeHtml($empty) . '</option>';
} else {
$html = '<option value="">' . Filter::escapeHtml($empty) . '</option>';
}
}
// A completely empty list would be invalid, and break various things
if (empty($values) && empty($html)) {
$html = '<option value=""></option>';
}
foreach ($values as $key => $value) {
// PHP array keys are cast to integers! Cast them back
if ((string) $key === (string) $selected) {
$html .= '<option value="' . Filter::escapeHtml($key) . '" selected dir="auto">' . Filter::escapeHtml($value) . '</option>';
} else {
$html .= '<option value="' . Filter::escapeHtml($key) . '" dir="auto">' . Filter::escapeHtml($value) . '</option>';
}
}
if (substr($name, -2) === '[]') {
// id attribute is not used for arrays
return '<select name="' . $name . '" ' . $extra . '>' . $html . '</select>';
} else {
return '<select id="' . $name . '" name="' . $name . '" ' . $extra . '>' . $html . '</select>';
}
}
/**
* Create a set of radio buttons for a form
*
* @param string $name The ID for the form element
* @param string[] $values Array of value=>display items
* @param string $selected The currently selected item
* @param string $extra Additional markup for the label
*
* @return string
*/
public static function radioButtons($name, $values, $selected, $extra = '') {
$html = '';
foreach ($values as $key => $value) {
$html .=
'<label ' . $extra . '>' .
'<input type="radio" name="' . $name . '" value="' . Filter::escapeHtml($key) . '"';
// PHP array keys are cast to integers! Cast them back
if ((string) $key === (string) $selected) {
$html .= ' checked';
}
$html .= '>' . Filter::escapeHtml($value) . '</label>';
}
return $html;
}
/**
* Print an edit control for a Yes/No field
*
* @param string $name
* @param bool $selected
* @param string $extra
*
* @return string
*/
public static function editFieldYesNo($name, $selected = false, $extra = '') {
return self::radioButtons(
$name, array(I18N::translate('no'), I18N::translate('yes')), $selected, $extra
);
}
/**
* Print an edit control for a checkbox.
*
* @param string $name
* @param bool $is_checked
* @param string $extra
*
* @return string
*/
public static function checkbox($name, $is_checked = false, $extra = '') {
return '<input type="checkbox" name="' . $name . '" value="1" ' . ($is_checked ? 'checked ' : '') . $extra . '>';
}
/**
* Print an edit control for a checkbox, with a hidden field to store one of the two states.
* By default, a checkbox is either set, or not sent.
* This function gives us a three options, set, unset or not sent.
* Useful for dynamically generated forms where we don't know what elements are present.
*
* @param string $name
* @param int $is_checked 0 or 1
* @param string $extra
*
* @return string
*/
public static function twoStateCheckbox($name, $is_checked = 0, $extra = '') {
return
'<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . ($is_checked ? 1 : 0) . '">' .
'<input type="checkbox" name="' . $name . '-GUI-ONLY" value="1"' .
($is_checked ? ' checked' : '') .
' onclick="document.getElementById(\'' . $name . '\').value=(this.checked?1:0);" ' . $extra . '>';
}
/**
* Function edit_language_checkboxes
*
* @param string $parameter_name
* @param array $accepted_languages
*
* @return string
*/
public static function editLanguageCheckboxes($parameter_name, $accepted_languages) {
$html = '';
foreach (I18N::activeLocales() as $locale) {
$html .= '<div class="checkbox">';
$html .= '<label title="' . $locale->languageTag() . '">';
$html .= '<input type="checkbox" name="' . $parameter_name . '[]" value="' . $locale->languageTag() . '"';
$html .= in_array($locale->languageTag(), $accepted_languages) ? ' checked>' : '>';
$html .= $locale->endonym();
$html .= '</label>';
$html .= '</div>';
}
return $html;
}
/**
* Print an edit control for access level.
*
* @param string $name
* @param string $selected
* @param string $extra
*
* @return string
*/
public static function editFieldAccessLevel($name, $selected = '', $extra = '') {
$ACCESS_LEVEL = 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'),
);
return self::selectEditControl($name, $ACCESS_LEVEL, null, $selected, $extra);
}
/**
* Print an edit control for a RESN field.
*
* @param string $name
* @param string $selected
* @param string $extra
*
* @return string
*/
public static function editFieldRestriction($name, $selected = '', $extra = '') {
$RESN = array(
'' => '',
'none' => I18N::translate('Show to visitors'), // Not valid GEDCOM, but very useful
'privacy' => I18N::translate('Show to members'),
'confidential' => I18N::translate('Show to managers'),
'locked' => I18N::translate('Only managers can edit'),
);
return self::selectEditControl($name, $RESN, null, $selected, $extra);
}
/**
* Print an edit control for a contact method field.
*
* @param string $name
* @param string $selected
* @param string $extra
*
* @return string
*/
public static function editFieldContact($name, $selected = '', $extra = '') {
// Different ways to contact the users
$CONTACT_METHODS = array(
'messaging' => I18N::translate('Internal messaging'),
'messaging2' => I18N::translate('Internal messaging with emails'),
'messaging3' => I18N::translate('webtrees sends emails with no storage'),
'mailto' => I18N::translate('Mailto link'),
'none' => I18N::translate('No contact'),
);
return self::selectEditControl($name, $CONTACT_METHODS, null, $selected, $extra);
}
/**
* Print an edit control for a language field.
*
* @param string $name
* @param string $selected
* @param string $extra
*
* @return string
*/
public static function editFieldLanguage($name, $selected = '', $extra = '') {
$languages = array();
foreach (I18N::activeLocales() as $locale) {
$languages[$locale->languageTag()] = $locale->endonym();
}
return self::selectEditControl($name, $languages, null, $selected, $extra);
}
/**
* Print an edit control for a range of integers.
*
* @param string $name
* @param string $selected
* @param int $min
* @param int $max
* @param string $extra
*
* @return string
*/
public static function editFieldInteger($name, $selected = '', $min, $max, $extra = '') {
$array = array();
for ($i = $min; $i <= $max; ++$i) {
$array[$i] = I18N::number($i);
}
return self::selectEditControl($name, $array, null, $selected, $extra);
}
/**
* Print an edit control for a username.
*
* @param string $name
* @param string $selected
* @param string $extra
*
* @return string
*/
public static function editFieldUsername($name, $selected = '', $extra = '') {
$users = array();
foreach (User::all() as $user) {
$users[$user->getUserName()] = $user->getRealName() . ' - ' . $user->getUserName();
}
// The currently selected user may not exist
if ($selected && !array_key_exists($selected, $users)) {
$users[$selected] = $selected;
}
return self::selectEditControl($name, $users, '-', $selected, $extra);
}
/**
* Print an edit control for a ADOP field.
*
* @param string $name
* @param string $selected
* @param string $extra
* @param Individual|null $individual
*
* @return string
*/
public static function editFieldAdoption($name, $selected = '', $extra = '', Individual $individual = null) {
return self::selectEditControl($name, GedcomCodeAdop::getValues($individual), null, $selected, $extra);
}
/**
* Print an edit control for a PEDI field.
*
* @param string $name
* @param string $selected
* @param string $extra
* @param Individual|null $individual
*
* @return string
*/
public static function editFieldPedigree($name, $selected = '', $extra = '', Individual $individual = null) {
return self::selectEditControl($name, GedcomCodePedi::getValues($individual), '', $selected, $extra);
}
/**
* Print an edit control for a NAME TYPE field.
*
* @param string $name
* @param string $selected
* @param string $extra
* @param Individual|null $individual
*
* @return string
*/
public static function editFieldNameType($name, $selected = '', $extra = '', Individual $individual = null) {
return self::selectEditControl($name, GedcomCodeName::getValues($individual), '', $selected, $extra);
}
/**
* Print an edit control for a RELA field.
*
* @param string $name
* @param string $selected
* @param string $extra
*
* @return string
*/
public static function editFieldRelationship($name, $selected = '', $extra = '') {
$rela_codes = GedcomCodeRela::getValues();
// The user is allowed to specify values that aren't in the list.
if (!array_key_exists($selected, $rela_codes)) {
$rela_codes[$selected] = I18N::translate($selected);
}
return self::selectEditControl($name, $rela_codes, '', $selected, $extra);
}
/**
* Remove all links from $gedrec to $xref, and any sub-tags.
*
* @param string $gedrec
* @param string $xref
*
* @return string
*/
public static function removeLinks($gedrec, $xref) {
$gedrec = preg_replace('/\n1 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[2-9].*)*/', '', $gedrec);
$gedrec = preg_replace('/\n2 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[3-9].*)*/', '', $gedrec);
$gedrec = preg_replace('/\n3 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[4-9].*)*/', '', $gedrec);
$gedrec = preg_replace('/\n4 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[5-9].*)*/', '', $gedrec);
$gedrec = preg_replace('/\n5 ' . WT_REGEX_TAG . ' @' . $xref . '@(\n[6-9].*)*/', '', $gedrec);
return $gedrec;
}
/**
* Generates javascript code for calendar popup in users language.
*
* @param string $id
*
* @return string
*/
public static function printCalendarPopup($id) {
return
' <a href="#" onclick="cal_toggleDate(\'caldiv' . $id . '\', \'' . $id . '\'); return false;" class="icon-button_calendar" title="' . I18N::translate('Select a date') . '"></a>' .
'<div id="caldiv' . $id . '" style="position:absolute;visibility:hidden;background-color:white;z-index:1000;"></div>';
}
/**
* An HTML link to create a new media object.
*
* @param string $element_id
*
* @return string
*/
public static function printAddNewMediaLink($element_id) {
return '<a href="#" onclick="pastefield=document.getElementById(\'' . $element_id . '\'); window.open(\'addmedia.php?action=showmediaform\', \'_blank\', edit_window_specs); return false;" class="icon-button_addmedia" title="' . I18N::translate('Create a media object') . '"></a>';
}
/**
* An HTML link to create a new repository.
*
* @param string $element_id
*
* @return string
*/
public static function printAddNewRepositoryLink($element_id) {
return '<a href="#" onclick="addnewrepository(document.getElementById(\'' . $element_id . '\')); return false;" class="icon-button_addrepository" title="' . I18N::translate('Create a repository') . '"></a>';
}
/**
* An HTML link to create a new note.
*
* @param string $element_id
*
* @return string
*/
public static function printAddNewNoteLink($element_id) {
return '<a href="#" onclick="addnewnote(document.getElementById(\'' . $element_id . '\')); return false;" class="icon-button_addnote" title="' . I18N::translate('Create a shared note') . '"></a>';
}
/**
* An HTML link to edit a note.
*
* @param string $note_id
*
* @return string
*/
public static function printEditNoteLink($note_id) {
return '<a href="#" onclick="edit_note(\'' . $note_id . '\'); return false;" class="icon-button_note" title="' . I18N::translate('Edit the shared note') . '"></a>';
}
/**
* An HTML link to create a new source.
*
* @param string $element_id
*
* @return string
*/
public static function printAddNewSourceLink($element_id) {
return '<a href="#" onclick="addnewsource(document.getElementById(\'' . $element_id . '\')); return false;" class="icon-button_addsource" title="' . I18N::translate('Create a source') . '"></a>';
}
/**
* add a new tag input field
*
* called for each fact to be edited on a form.
* Fact level=0 means a new empty form : data are POSTed by name
* else data are POSTed using arrays :
* glevels[] : tag level
* islink[] : tag is a link
* tag[] : tag name
* text[] : tag value
*
* @param string $tag fact record to edit (eg 2 DATE xxxxx)
* @param string $upperlevel optional upper level tag (eg BIRT)
* @param string $label An optional label to echo instead of the default
* @param string $extra optional text to display after the input field
* @param Individual $person For male/female translations
*
* @return string
*/
public static function addSimpleTag($tag, $upperlevel = '', $label = '', $extra = null, Individual $person = null) {
global $tags, $main_fact, $xref, $bdm, $action, $WT_TREE;
// Keep track of SOUR fields, so we can reference them in subsequent PAGE fields.
static $source_element_id;
$subnamefacts = array('NPFX', 'GIVN', 'SPFX', 'SURN', 'NSFX', '_MARNM_SURN');
preg_match('/^(?:(\d+) (' . WT_REGEX_TAG . ') ?(.*))/', $tag, $match);
list(, $level, $fact, $value) = $match;
$level = (int) $level;
// element name : used to POST data
if ($level === 0) {
if ($upperlevel) {
$element_name = $upperlevel . '_' . $fact;
} else {
$element_name = $fact;
}
} else {
$element_name = 'text[]';
}
if ($level === 1) {
$main_fact = $fact;
}
// element id : used by javascript functions
if ($level === 0) {
$element_id = $fact;
} else {
$element_id = $fact . Uuid::uuid4();
}
if ($upperlevel) {
$element_id = $upperlevel . '_' . $fact . Uuid::uuid4();
}
// field value
$islink = (substr($value, 0, 1) === '@' && substr($value, 0, 2) !== '@#');
if ($islink) {
$value = trim(substr($tag, strlen($fact) + 3), ' @\r');
} else {
$value = (string) substr($tag, strlen($fact) + 3);
}
if ($fact === 'REPO' || $fact === 'SOUR' || $fact === 'OBJE' || $fact === 'FAMC') {
$islink = true;
}
if ($fact === 'SHARED_NOTE_EDIT' || $fact === 'SHARED_NOTE') {
$islink = true;
$fact = 'NOTE';
}
// label
echo '<tr id="', $element_id, '_tr"';
if ($fact === 'DATA' || $fact === 'MAP' || ($fact === 'LATI' || $fact === 'LONG') && $value === '') {
echo ' style="display:none;"';
}
echo '>';
if (in_array($fact, $subnamefacts) || $fact === 'LATI' || $fact === 'LONG') {
echo '<td class="optionbox wrap width25">';
} else {
echo '<td class="descriptionbox wrap width25">';
}
// tag name
if ($label) {
echo $label;
} elseif ($upperlevel) {
echo GedcomTag::getLabel($upperlevel . ':' . $fact);
} else {
echo GedcomTag::getLabel($fact);
}
// If using GEDFact-assistant window
if ($action === 'addnewnote_assisted') {
// Do not print on GEDFact Assistant window
} else {
// Not all facts have help text.
switch ($fact) {
case 'NAME':
if ($upperlevel !== 'REPO' && $upperlevel !== 'UNKNOWN') {
echo FunctionsPrint::helpLink($fact);
}
break;
case 'DATE':
case 'PLAC':
case 'RESN':
case 'ROMN':
case 'SURN':
case '_HEB':
echo FunctionsPrint::helpLink($fact);
break;
}
}
// tag level
if ($level > 0) {
echo '<input type="hidden" name="glevels[]" value="', $level, '">';
echo '<input type="hidden" name="islink[]" value="', $islink, '">';
echo '<input type="hidden" name="tag[]" value="', $fact, '">';
}
echo '</td>';
// value
echo '<td class="optionbox wrap">';
// retrieve linked NOTE
if ($fact === 'NOTE' && $islink) {
$note1 = Note::getInstance($value, $WT_TREE);
if ($note1) {
$noterec = $note1->getGedcom();
preg_match('/' . $value . '/i', $noterec, $notematch);
$value = $notematch[0];
}
}
// Show names for spouses in MARR/HUSB/AGE and MARR/WIFE/AGE
if ($fact === 'HUSB' || $fact === 'WIFE') {
$family = Family::getInstance($xref, $WT_TREE);
if ($family) {
$spouse_link = $family->getFirstFact($fact);
if ($spouse_link) {
$spouse = $spouse_link->getTarget();
if ($spouse) {
echo $spouse->getFullName();
}
}
}
}
if (in_array($fact, Config::emptyFacts()) && ($value === '' || $value === 'Y' || $value === 'y')) {
echo '<input type="hidden" id="', $element_id, '" name="', $element_name, '" value="', $value, '">';
if ($level <= 1) {
echo '<input type="checkbox" ';
if ($value) {
echo 'checked';
}
echo ' onclick="document.getElementById(\'' . $element_id . '\').value = (this.checked) ? \'Y\' : \'\';">';
echo I18N::translate('yes');
}
if ($fact === 'CENS' && $value === 'Y') {
echo self::censusDateSelector(WT_LOCALE, $xref);
if (Module::getModuleByName('GEDFact_assistant') && GedcomRecord::getInstance($xref, $WT_TREE) instanceof Individual) {
echo
'<div></div><a href="#" style="display: none;" id="assistant-link" onclick="return activateCensusAssistant();">' .
I18N::translate('Create a shared note using the census assistant') .
'</a></div>';
}
}
} elseif ($fact === 'TEMP') {
echo self::selectEditControl($element_name, GedcomCodeTemp::templeNames(), I18N::translate('No temple - living ordinance'), $value);
} elseif ($fact === 'ADOP') {
echo self::editFieldAdoption($element_name, $value, '', $person);
} elseif ($fact === 'PEDI') {
echo self::editFieldPedigree($element_name, $value, '', $person);
} elseif ($fact === 'STAT') {
echo self::selectEditControl($element_name, GedcomCodeStat::statusNames($upperlevel), '', $value);
} elseif ($fact === 'RELA') {
echo self::editFieldRelationship($element_name, strtolower($value));
} elseif ($fact === 'QUAY') {
echo self::selectEditControl($element_name, GedcomCodeQuay::getValues(), '', $value);
} elseif ($fact === '_WT_USER') {
echo self::editFieldUsername($element_name, $value);
} elseif ($fact === 'RESN') {
echo self::editFieldRestriction($element_name, $value);
} elseif ($fact === '_PRIM') {
echo '<select id="', $element_id, '" name="', $element_name, '" >';
echo '<option value=""></option>';
echo '<option value="Y" ';
if ($value === 'Y') {
echo ' selected';
}
echo '>', /* I18N: option in list box “always use this image” */
I18N::translate('always'), '</option>';
echo '<option value="N" ';
if ($value === 'N') {
echo 'selected';
}
echo '>', /* I18N: option in list box “never use this image” */
I18N::translate('never'), '</option>';
echo '</select>';
echo '<p class="small text-muted">', I18N::translate('Use this image for charts and on the individuals page.'), '</p>';
} elseif ($fact === 'SEX') {
echo '<select id="', $element_id, '" name="', $element_name, '"><option value="M" ';
if ($value === 'M') {
echo 'selected';
}
echo '>', I18N::translate('Male'), '</option><option value="F" ';
if ($value === 'F') {
echo 'selected';
}
echo '>', I18N::translate('Female'), '</option><option value="U" ';
if ($value === 'U' || empty($value)) {
echo 'selected';
}
echo '>', I18N::translateContext('unknown gender', 'Unknown'), '</option></select>';
} elseif ($fact === 'TYPE' && $level === 3) {
//-- Build the selector for the Media 'TYPE' Fact
echo '<select name="text[]"><option selected value="" ></option>';
$selectedValue = strtolower($value);
if (!array_key_exists($selectedValue, GedcomTag::getFileFormTypes())) {
echo '<option selected value="', Filter::escapeHtml($value), '" >', Filter::escapeHtml($value), '</option>';
}
foreach (GedcomTag::getFileFormTypes() as $typeName => $typeValue) {
echo '<option value="', $typeName, '" ';
if ($selectedValue === $typeName) {
echo 'selected';
}
echo '>', $typeValue, '</option>';
}
echo '</select>';
} elseif (($fact === 'NAME' && $upperlevel !== 'REPO' && $upperlevel !== 'UNKNOWN') || $fact === '_MARNM') {
// Populated in javascript from sub-tags
echo '<input type="hidden" id="', $element_id, '" name="', $element_name, '" onchange="updateTextName(\'', $element_id, '\');" value="', Filter::escapeHtml($value), '" class="', $fact, '">';
echo '<span id="', $element_id, '_display" dir="auto">', Filter::escapeHtml($value), '</span>';
echo ' <a href="#edit_name" onclick="convertHidden(\'', $element_id, '\'); return false;" class="icon-edit_indi" title="' . I18N::translate('Edit the name') . '"></a>';
} else {
// textarea
if ($fact === 'TEXT' || $fact === 'ADDR' || ($fact === 'NOTE' && !$islink)) {
echo '<textarea id="', $element_id, '" name="', $element_name, '" dir="auto">', Filter::escapeHtml($value), '</textarea><br>';
} else {
// text
// If using GEDFact-assistant window
if ($action === 'addnewnote_assisted') {
echo '<input type="text" id="', $element_id, '" name="', $element_name, '" value="', Filter::escapeHtml($value), '" style="width:4.1em;" dir="ltr"';
} else {
echo '<input type="text" id="', $element_id, '" name="', $element_name, '" value="', Filter::escapeHtml($value), '" dir="ltr"';
}
echo ' class="', $fact, '"';
if (in_array($fact, $subnamefacts)) {
echo ' onblur="updatewholename();" onkeyup="updatewholename();"';
}
// Extra markup for specific fact types
switch ($fact) {
case 'ALIA':
case 'ASSO':
case '_ASSO':
echo ' data-autocomplete-type="ASSO" data-autocomplete-extra="input.DATE"';
break;
case 'DATE':
echo ' onblur="valid_date(this);" onmouseout="valid_date(this);"';
break;
case 'GIVN':
echo ' autofocus data-autocomplete-type="GIVN"';
break;
case 'LATI':
echo ' onblur="valid_lati_long(this, \'N\', \'S\');" onmouseout="valid_lati_long(this, \'N\', \'S\');"';
break;
case 'LONG':
echo ' onblur="valid_lati_long(this, \'E\', \'W\');" onmouseout="valid_lati_long(this, \'E\', \'W\');"';
break;
case 'NOTE':
// Shared notes. Inline notes are handled elsewhere.
echo ' data-autocomplete-type="NOTE"';
break;
case 'OBJE':
echo ' data-autocomplete-type="OBJE"';
break;
case 'PAGE':
echo ' data-autocomplete-type="PAGE" data-autocomplete-extra="#' . $source_element_id . '"';
break;
case 'PLAC':
echo ' data-autocomplete-type="PLAC"';
break;
case 'REPO':
echo ' data-autocomplete-type="REPO"';
break;
case 'SOUR':
$source_element_id = $element_id;
echo ' data-autocomplete-type="SOUR"';
break;
case 'SURN':
case '_MARNM_SURN':
echo ' data-autocomplete-type="SURN"';
break;
case 'TIME':
echo ' pattern="([0-1][0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?" dir="ltr" placeholder="' . /* I18N: Examples of valid time formats (hours:minutes:seconds) */
I18N::translate('hh:mm or hh:mm:ss') . '"';
break;
}
echo '>';
}
$tmp_array = array('TYPE', 'TIME', 'NOTE', 'SOUR', 'REPO', 'OBJE', 'ASSO', '_ASSO', 'AGE');
// split PLAC
if ($fact === 'PLAC') {
echo '<div id="', $element_id, '_pop" style="display: inline;">';
echo FunctionsPrint::printSpecialCharacterLink($element_id), ' ', FunctionsPrint::printFindPlaceLink($element_id);
echo '<span onclick="jQuery(\'tr[id^=', $upperlevel, '_LATI],tr[id^=', $upperlevel, '_LONG],tr[id^=LATI],tr[id^=LONG]\').toggle(\'fast\'); return false;" class="icon-target" title="', GedcomTag::getLabel('LATI'), ' / ', GedcomTag::getLabel('LONG'), '"></span>';
echo '</div>';
if (Module::getModuleByName('places_assistant')) {
\PlacesAssistantModule::setup_place_subfields($element_id);
\PlacesAssistantModule::print_place_subfields($element_id);
}
} elseif (!in_array($fact, $tmp_array)) {
echo FunctionsPrint::printSpecialCharacterLink($element_id);
}
}
// MARRiage TYPE : hide text field and show a selection list
if ($fact === 'TYPE' && $level === 2 && $tags[0] === 'MARR') {
echo '<script>';
echo 'document.getElementById(\'', $element_id, '\').style.display=\'none\'';
echo '</script>';
echo '<select id="', $element_id, '_sel" onchange="document.getElementById(\'', $element_id, '\').value=this.value;" >';
foreach (array('Unknown', 'Civil', 'Religious', 'Partners') as $key) {
if ($key === 'Unknown') {
echo '<option value="" ';
} else {
echo '<option value="', $key, '" ';
}
$a = strtolower($key);
$b = strtolower($value);
if ($b !== '' && strpos($a, $b) !== false || strpos($b, $a) !== false) {
echo 'selected';
}
echo '>', GedcomTag::getLabel('MARR_' . strtoupper($key)), '</option>';
}
echo '</select>';
} elseif ($fact === 'TYPE' && $level === 0) {
// NAME TYPE : hide text field and show a selection list
$onchange = 'onchange="document.getElementById(\'' . $element_id . '\').value=this.value;"';
echo self::editFieldNameType($element_name, $value, $onchange, $person);
echo '<script>document.getElementById("', $element_id, '").style.display="none";</script>';
}
// popup links
switch ($fact) {
case 'DATE':
echo self::printCalendarPopup($element_id);
break;
case 'FAMC':
case 'FAMS':
echo FunctionsPrint::printFindFamilyLink($element_id);
break;
case 'ALIA':
case 'ASSO':
case '_ASSO':
echo FunctionsPrint::printFindIndividualLink($element_id, $element_id . '_description');
break;
case 'FILE':
FunctionsPrint::printFindMediaLink($element_id, '0file');
break;
case 'SOUR':
echo FunctionsPrint::printFindSourceLink($element_id, $element_id . '_description'), ' ', self::printAddNewSourceLink($element_id);
//-- checkboxes to apply '1 SOUR' to BIRT/MARR/DEAT as '2 SOUR'
if ($level === 1) {
echo '<br>';
switch ($WT_TREE->getPreference('PREFER_LEVEL2_SOURCES')) {
case '2': // records
$level1_checked = 'checked';
$level2_checked = '';
break;
case '1': // facts
$level1_checked = '';
$level2_checked = 'checked';
break;
case '0': // none
default:
$level1_checked = '';
$level2_checked = '';
break;
}
if (strpos($bdm, 'B') !== false) {
echo ' <label><input type="checkbox" name="SOUR_INDI" ', $level1_checked, ' value="1">', I18N::translate('Individual'), '</label>';
if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
foreach ($matches[1] as $match) {
if (!in_array($match, explode('|', WT_EVENTS_DEAT))) {
echo ' <label><input type="checkbox" name="SOUR_', $match, '" ', $level2_checked, ' value="1">', GedcomTag::getLabel($match), '</label>';
}
}
}
}
if (strpos($bdm, 'D') !== false) {
if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
foreach ($matches[1] as $match) {
if (in_array($match, explode('|', WT_EVENTS_DEAT))) {
echo ' <label><input type="checkbox" name="SOUR_', $match, '"', $level2_checked, ' value="1">', GedcomTag::getLabel($match), '</label>';
}
}
}
}
if (strpos($bdm, 'M') !== false) {
echo ' <label><input type="checkbox" name="SOUR_FAM" ', $level1_checked, ' value="1">', I18N::translate('Family'), '</label>';
if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches)) {
foreach ($matches[1] as $match) {
echo ' <label><input type="checkbox" name="SOUR_', $match, '"', $level2_checked, ' value="1">', GedcomTag::getLabel($match), '</label>';
}
}
}
}
break;
case 'REPO':
echo FunctionsPrint::printFindRepositoryLink($element_id), ' ', self::printAddNewRepositoryLink($element_id);
break;
case 'NOTE':
// Shared Notes Icons ========================================
if ($islink) {
// Print regular Shared Note icons ---------------------------
echo ' ', FunctionsPrint::printFindNoteLink($element_id, $element_id . '_description'), ' ', self::printAddNewNoteLink($element_id);
if ($value) {
echo ' ', self::printEditNoteLink($value);
}
}
break;
case 'OBJE':
echo FunctionsPrint::printFindMediaLink($element_id, '1media');
if (!$value) {
echo ' ', self::printAddNewMediaLink($element_id);
$value = 'new';
}
break;
}
echo '<div id="' . $element_id . '_description">';
// current value
if ($fact === 'DATE') {
$date = new Date($value);
echo $date->display();
}
if (($fact === 'ASSO' || $fact === '_ASSO') && $value === '') {
if ($level === 1) {
echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this individual, such as a friend or an employer.') . '</p>';
} else {
echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this fact or event, such as a witness or a priest.') . '</p>';
}
}
if ($value && $value !== 'new' && $islink) {
switch ($fact) {
case 'ALIA':
case 'ASSO':
case '_ASSO':
$tmp = Individual::getInstance($value, $WT_TREE);
if ($tmp) {
echo ' ', $tmp->getFullName();
}
break;
case 'SOUR':
$tmp = Source::getInstance($value, $WT_TREE);
if ($tmp) {
echo ' ', $tmp->getFullName();
}
break;
case 'NOTE':
$tmp = Note::getInstance($value, $WT_TREE);
if ($tmp) {
echo ' ', $tmp->getFullName();
}
break;
case 'OBJE':
$tmp = Media::getInstance($value, $WT_TREE);
if ($tmp) {
echo ' ', $tmp->getFullName();
}
break;
case 'REPO':
$tmp = Repository::getInstance($value, $WT_TREE);
if ($tmp) {
echo ' ', $tmp->getFullName();
}
break;
}
}
// pastable values
if ($fact === 'FORM' && $upperlevel === 'OBJE') {
FunctionsPrint::printAutoPasteLink($element_id, Config::fileFormats());
}
echo '</div>', $extra, '</td></tr>';
return $element_id;
}
/**
* Genearate a <select> element, with the dates/places of all known censuses
*
*
* @param string $locale - Sort the censuses for this locale
* @param string $xref - The individual for whom we are adding a census
*/
public static function censusDateSelector($locale, $xref) {
global $controller;
// Show more likely census details at the top of the list.
switch (WT_LOCALE) {
case 'cs':
$census_places = array(new CensusOfCzechRepublic);
break;
case 'en-AU':
case 'en-GB':
$census_places = array(new CensusOfEngland, new CensusOfWales, new CensusOfScotland);
break;
case 'en-US':
$census_places = array(new CensusOfUnitedStates);
break;
case 'fr':
case 'fr-CA':
$census_places = array(new CensusOfFrance);
break;
case 'da':
$census_places = array(new CensusOfDenmark);
break;
default:
$census_places = array();
break;
}
foreach (Census::allCensusPlaces() as $census_place) {
if (!in_array($census_place, $census_places)) {
$census_places[] = $census_place;
}
}
$controller->addInlineJavascript('
function selectCensus(el) {
var option = jQuery(":selected", el);
jQuery("input.DATE", jQuery(el).closest("table")).val(option.val());
jQuery("input.PLAC", jQuery(el).closest("table")).val(option.data("place"));
jQuery("input.census-class", jQuery(el).closest("table")).val(option.data("census"));
if (option.data("place")) {
jQuery("#assistant-link").show();
} else {
jQuery("#assistant-link").hide();
}
}
function set_pid_array(pa) {
jQuery("#pid_array").val(pa);
}
function activateCensusAssistant() {
if (jQuery("#newshared_note_img").hasClass("icon-plus")) {
expand_layer("newshared_note");
}
var field = jQuery("#newshared_note input.NOTE")[0];
var xref = jQuery("input[name=xref]").val();
var census = jQuery(".census-assistant-selector :selected").data("census");
return addnewnote_assisted(field, xref, census);
}
');
$options = '<option value="">' . I18N::translate('Census date') . '</option>';
foreach ($census_places as $census_place) {
$options .= '<option value=""></option>';
foreach ($census_place->allCensusDates() as $census) {
$date = new Date($census->censusDate());
$year = $date->minimumDate()->format('%Y');
$place_hierarchy = explode(', ', $census->censusPlace());
$options .= '<option value="' . $census->censusDate() . '" data-place="' . $census->censusPlace() . '" data-census="' . get_class($census) . '">' . $place_hierarchy[0] . ' ' . $year . '</option>';
}
}
return
'<input type="hidden" id="pid_array" name="pid_array" value="">' .
'<select class="census-assistant-selector" onchange="selectCensus(this);">' . $options . '</select>';
}
/**
* Prints collapsable fields to add ASSO/RELA, SOUR, OBJE, etc.
*
* @param string $tag
* @param int $level
* @param string $parent_tag
*/
public static function printAddLayer($tag, $level = 2, $parent_tag = '') {
global $WT_TREE;
switch ($tag) {
case 'SOUR':
echo '<a href="#" onclick="return expand_layer(\'newsource\');"><i id="newsource_img" class="icon-plus"></i> ', I18N::translate('Add a source citation'), '</a>';
echo '<br>';
echo '<div id="newsource" style="display: none;">';
echo '<table class="facts_table">';
// 2 SOUR
self::addSimpleTag($level . ' SOUR @');
// 3 PAGE
self::addSimpleTag(($level + 1) . ' PAGE');
// 3 DATA
self::addSimpleTag(($level + 1) . ' DATA');
// 4 TEXT
self::addSimpleTag(($level + 2) . ' TEXT');
if ($WT_TREE->getPreference('FULL_SOURCES')) {
// 4 DATE
self::addSimpleTag(($level + 2) . ' DATE', '', GedcomTag::getLabel('DATA:DATE'));
// 3 QUAY
self::addSimpleTag(($level + 1) . ' QUAY');
}
// 3 OBJE
self::addSimpleTag(($level + 1) . ' OBJE');
// 3 SHARED_NOTE
self::addSimpleTag(($level + 1) . ' SHARED_NOTE');
echo '</table></div>';
break;
case 'ASSO':
case 'ASSO2':
//-- Add a new ASSOciate
if ($tag === 'ASSO') {
echo "<a href=\"#\" onclick=\"return expand_layer('newasso');\"><i id=\"newasso_img\" class=\"icon-plus\"></i> ", I18N::translate('Add an associate'), '</a>';
echo '<br>';
echo '<div id="newasso" style="display: none;">';
} else {
echo "<a href=\"#\" onclick=\"return expand_layer('newasso2');\"><i id=\"newasso2_img\" class=\"icon-plus\"></i> ", I18N::translate('Add an associate'), '</a>';
echo '<br>';
echo '<div id="newasso2" style="display: none;">';
}
echo '<table class="facts_table">';
// 2 ASSO
self::addSimpleTag($level . ' _ASSO @');
// 3 RELA
self::addSimpleTag(($level + 1) . ' RELA');
// 3 NOTE
self::addSimpleTag(($level + 1) . ' NOTE');
// 3 SHARED_NOTE
self::addSimpleTag(($level + 1) . ' SHARED_NOTE');
echo '</table></div>';
break;
case 'NOTE':
//-- Retrieve existing note or add new note to fact
echo "<a href=\"#\" onclick=\"return expand_layer('newnote');\"><i id=\"newnote_img\" class=\"icon-plus\"></i> ", I18N::translate('Add a note'), '</a>';
echo '<br>';
echo '<div id="newnote" style="display: none;">';
echo '<table class="facts_table">';
// 2 NOTE
self::addSimpleTag($level . ' NOTE');
echo '</table></div>';
break;
case 'SHARED_NOTE':
echo "<a href=\"#\" onclick=\"return expand_layer('newshared_note');\"><i id=\"newshared_note_img\" class=\"icon-plus\"></i> ", I18N::translate('Add a shared note'), '</a>';
echo '<br>';
echo '<div id="newshared_note" style="display: none;">';
echo '<table class="facts_table">';
// 2 SHARED NOTE
self::addSimpleTag($level . ' SHARED_NOTE', $parent_tag);
echo '</table></div>';
break;
case 'OBJE':
if ($WT_TREE->getPreference('MEDIA_UPLOAD') >= Auth::accessLevel($WT_TREE)) {
echo "<a href=\"#\" onclick=\"return expand_layer('newobje');\"><i id=\"newobje_img\" class=\"icon-plus\"></i> ", I18N::translate('Add a media object'), '</a>';
echo '<br>';
echo '<div id="newobje" style="display: none;">';
echo '<table class="facts_table">';
self::addSimpleTag($level . ' OBJE');
echo '</table></div>';
}
break;
case 'RESN':
echo "<a href=\"#\" onclick=\"return expand_layer('newresn');\"><i id=\"newresn_img\" class=\"icon-plus\"></i> ", I18N::translate('Add a restriction'), '</a>';
echo '<br>';
echo '<div id="newresn" style="display: none;">';
echo '<table class="facts_table">';
// 2 RESN
self::addSimpleTag($level . ' RESN');
echo '</table></div>';
break;
}
}
/**
* Add some empty tags to create a new fact.
*
* @param string $fact
*/
public static function addSimpleTags($fact) {
global $WT_TREE;
// For new individuals, these facts default to "Y"
if ($fact === 'MARR') {
self::addSimpleTag('0 ' . $fact . ' Y');
} else {
self::addSimpleTag('0 ' . $fact);
}
if (!in_array($fact, Config::nonDateFacts())) {
self::addSimpleTag('0 DATE', $fact, GedcomTag::getLabel($fact . ':DATE'));
}
if (!in_array($fact, Config::nonPlaceFacts())) {
self::addSimpleTag('0 PLAC', $fact, GedcomTag::getLabel($fact . ':PLAC'));
if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('ADVANCED_PLAC_FACTS'), $match)) {
foreach ($match[1] as $tag) {
self::addSimpleTag('0 ' . $tag, $fact, GedcomTag::getLabel($fact . ':PLAC:' . $tag));
}
}
self::addSimpleTag('0 MAP', $fact);
self::addSimpleTag('0 LATI', $fact);
self::addSimpleTag('0 LONG', $fact);
}
}
/**
* Assemble the pieces of a newly created record into gedcom
*
* @return string
*/
public static function addNewName() {
global $WT_TREE;
$gedrec = "\n1 NAME " . Filter::post('NAME');
$tags = array('NPFX', 'GIVN', 'SPFX', 'SURN', 'NSFX');
if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('ADVANCED_NAME_FACTS'), $match)) {
$tags = array_merge($tags, $match[1]);
}
// Paternal and Polish and Lithuanian surname traditions can also create a _MARNM
$SURNAME_TRADITION = $WT_TREE->getPreference('SURNAME_TRADITION');
if ($SURNAME_TRADITION === 'paternal' || $SURNAME_TRADITION === 'polish' || $SURNAME_TRADITION === 'lithuanian') {
$tags[] = '_MARNM';
}
foreach (array_unique($tags) as $tag) {
$TAG = Filter::post($tag);
if ($TAG) {
$gedrec .= "\n2 {$tag} {$TAG}";
}
}
return $gedrec;
}
/**
* Create a form to add a sex record.
*
* @return string
*/
public static function addNewSex() {
switch (Filter::post('SEX', '[MF]', 'U')) {
case 'M':
return "\n1 SEX M";
case 'F':
return "\n1 SEX F";
default:
return "\n1 SEX U";
}
}
/**
* Create a form to add a new fact.
*
* @param string $fact
*
* @return string
*/
public static function addNewFact($fact) {
global $WT_TREE;
$FACT = Filter::post($fact);
$DATE = Filter::post($fact . '_DATE');
$PLAC = Filter::post($fact . '_PLAC');
if ($DATE || $PLAC || $FACT && $FACT !== 'Y') {
if ($FACT && $FACT !== 'Y') {
$gedrec = "\n1 " . $fact . ' ' . $FACT;
} else {
$gedrec = "\n1 " . $fact;
}
if ($DATE) {
$gedrec .= "\n2 DATE " . $DATE;
}
if ($PLAC) {
$gedrec .= "\n2 PLAC " . $PLAC;
if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('ADVANCED_PLAC_FACTS'), $match)) {
foreach ($match[1] as $tag) {
$TAG = Filter::post($fact . '_' . $tag);
if ($TAG) {
$gedrec .= "\n3 " . $tag . ' ' . $TAG;
}
}
}
$LATI = Filter::post($fact . '_LATI');
$LONG = Filter::post($fact . '_LONG');
if ($LATI || $LONG) {
$gedrec .= "\n3 MAP\n4 LATI " . $LATI . "\n4 LONG " . $LONG;
}
}
if (Filter::postBool('SOUR_' . $fact)) {
return self::updateSource($gedrec, 2);
} else {
return $gedrec;
}
} elseif ($FACT === 'Y') {
if (Filter::postBool('SOUR_' . $fact)) {
return self::updateSource("\n1 " . $fact . ' Y', 2);
} else {
return "\n1 " . $fact . ' Y';
}
} else {
return '';
}
}
/**
* This function splits the $glevels, $tag, $islink, and $text arrays so that the
* entries associated with a SOUR record are separate from everything else.
*
* Input arrays:
* - $glevels[] - an array of the gedcom level for each line that was edited
* - $tag[] - an array of the tags for each gedcom line that was edited
* - $islink[] - an array of 1 or 0 values to indicate when the text is a link element
* - $text[] - an array of the text data for each line
*
* Output arrays:
* ** For the SOUR record:
* - $glevelsSOUR[] - an array of the gedcom level for each line that was edited
* - $tagSOUR[] - an array of the tags for each gedcom line that was edited
* - $islinkSOUR[] - an array of 1 or 0 values to indicate when the text is a link element
* - $textSOUR[] - an array of the text data for each line
* ** For the remaining records:
* - $glevelsRest[] - an array of the gedcom level for each line that was edited
* - $tagRest[] - an array of the tags for each gedcom line that was edited
* - $islinkRest[] - an array of 1 or 0 values to indicate when the text is a link element
* - $textRest[] - an array of the text data for each line
*/
public static function splitSource() {
global $glevels, $tag, $islink, $text;
global $glevelsSOUR, $tagSOUR, $islinkSOUR, $textSOUR;
global $glevelsRest, $tagRest, $islinkRest, $textRest;
$glevelsSOUR = array();
$tagSOUR = array();
$islinkSOUR = array();
$textSOUR = array();
$glevelsRest = array();
$tagRest = array();
$islinkRest = array();
$textRest = array();
$inSOUR = false;
for ($i = 0; $i < count($glevels); $i++) {
if ($inSOUR) {
if ($levelSOUR < $glevels[$i]) {
$dest = 'S';
} else {
$inSOUR = false;
$dest = 'R';
}
} else {
if ($tag[$i] === 'SOUR') {
$inSOUR = true;
$levelSOUR = $glevels[$i];
$dest = 'S';
} else {
$dest = 'R';
}
}
if ($dest === 'S') {
$glevelsSOUR[] = $glevels[$i];
$tagSOUR[] = $tag[$i];
$islinkSOUR[] = $islink[$i];
$textSOUR[] = $text[$i];
} else {
$glevelsRest[] = $glevels[$i];
$tagRest[] = $tag[$i];
$islinkRest[] = $islink[$i];
$textRest[] = $text[$i];
}
}
}
/**
* Add new GEDCOM lines from the $xxxSOUR interface update arrays, which
* were produced by the splitSOUR() function.
* See the FunctionsEdit::handle_updatesges() function for details.
*
* @param string $inputRec
* @param string $levelOverride
*
* @return string
*/
public static function updateSource($inputRec, $levelOverride = 'no') {
global $glevels, $tag, $islink, $text;
global $glevelsSOUR, $tagSOUR, $islinkSOUR, $textSOUR;
if (count($tagSOUR) === 0) {
return $inputRec; // No update required
}
// Save original interface update arrays before replacing them with the xxxSOUR ones
$glevelsSave = $glevels;
$tagSave = $tag;
$islinkSave = $islink;
$textSave = $text;
$glevels = $glevelsSOUR;
$tag = $tagSOUR;
$islink = $islinkSOUR;
$text = $textSOUR;
$myRecord = self::handleUpdates($inputRec, $levelOverride); // Now do the update
// Restore the original interface update arrays (just in case ...)
$glevels = $glevelsSave;
$tag = $tagSave;
$islink = $islinkSave;
$text = $textSave;
return $myRecord;
}
/**
* Add new GEDCOM lines from the $xxxRest interface update arrays, which
* were produced by the splitSOUR() function.
* See the FunctionsEdit::handle_updatesges() function for details.
*
* @param string $inputRec
* @param string $levelOverride
*
* @return string
*/
public static function updateRest($inputRec, $levelOverride = 'no') {
global $glevels, $tag, $islink, $text;
global $glevelsRest, $tagRest, $islinkRest, $textRest;
if (count($tagRest) === 0) {
return $inputRec; // No update required
}
// Save original interface update arrays before replacing them with the xxxRest ones
$glevelsSave = $glevels;
$tagSave = $tag;
$islinkSave = $islink;
$textSave = $text;
$glevels = $glevelsRest;
$tag = $tagRest;
$islink = $islinkRest;
$text = $textRest;
$myRecord = self::handleUpdates($inputRec, $levelOverride); // Now do the update
// Restore the original interface update arrays (just in case ...)
$glevels = $glevelsSave;
$tag = $tagSave;
$islink = $islinkSave;
$text = $textSave;
return $myRecord;
}
/**
* Add new gedcom lines from interface update arrays
* The edit_interface and FunctionsEdit::add_simple_tag function produce the following
* arrays incoming from the $_POST form
* - $glevels[] - an array of the gedcom level for each line that was edited
* - $tag[] - an array of the tags for each gedcom line that was edited
* - $islink[] - an array of 1 or 0 values to tell whether the text is a link element and should be surrounded by @@
* - $text[] - an array of the text data for each line
* With these arrays you can recreate the gedcom lines like this
* <code>$glevel[0].' '.$tag[0].' '.$text[0]</code>
* There will be an index in each of these arrays for each line of the gedcom
* fact that is being edited.
* If the $text[] array is empty for the given line, then it means that the
* user removed that line during editing or that the line is supposed to be
* empty (1 DEAT, 1 BIRT) for example. To know if the line should be removed
* there is a section of code that looks ahead to the next lines to see if there
* are sub lines. For example we don't want to remove the 1 DEAT line if it has
* a 2 PLAC or 2 DATE line following it. If there are no sub lines, then the line
* can be safely removed.
*
* @param string $newged the new gedcom record to add the lines to
* @param string $levelOverride Override GEDCOM level specified in $glevels[0]
*
* @return string The updated gedcom record
*/
public static function handleUpdates($newged, $levelOverride = 'no') {
global $glevels, $islink, $tag, $uploaded_files, $text;
if ($levelOverride === 'no' || count($glevels) === 0) {
$levelAdjust = 0;
} else {
$levelAdjust = $levelOverride - $glevels[0];
}
for ($j = 0; $j < count($glevels); $j++) {
// Look for empty SOUR reference with non-empty sub-records.
// This can happen when the SOUR entry is deleted but its sub-records
// were incorrectly left intact.
// The sub-records should be deleted.
if ($tag[$j] === 'SOUR' && ($text[$j] === '@@' || $text[$j] === '')) {
$text[$j] = '';
$k = $j + 1;
while (($k < count($glevels)) && ($glevels[$k] > $glevels[$j])) {
$text[$k] = '';
$k++;
}
}
if (trim($text[$j]) !== '') {
$pass = true;
} else {
//-- for facts with empty values they must have sub records
//-- this section checks if they have subrecords
$k = $j + 1;
$pass = false;
while (($k < count($glevels)) && ($glevels[$k] > $glevels[$j])) {
if ($text[$k] !== '') {
if (($tag[$j] !== 'OBJE') || ($tag[$k] === 'FILE')) {
$pass = true;
break;
}
}
if (($tag[$k] === 'FILE') && (count($uploaded_files) > 0)) {
$filename = array_shift($uploaded_files);
if (!empty($filename)) {
$text[$k] = $filename;
$pass = true;
break;
}
}
$k++;
}
}
//-- if the value is not empty or it has sub lines
//--- then write the line to the gedcom record
//-- we have to let some emtpy text lines pass through... (DEAT, BIRT, etc)
if ($pass) {
$newline = $glevels[$j] + $levelAdjust . ' ' . $tag[$j];
if ($text[$j] !== '') {
if ($islink[$j]) {
$newline .= ' @' . $text[$j] . '@';
} else {
$newline .= ' ' . $text[$j];
}
}
$newged .= "\n" . str_replace("\n", "\n" . (1 + substr($newline, 0, 1)) . ' CONT ', $newline);
}
}
return $newged;
}
/**
* builds the form for adding new facts
*
* @param string $fact the new fact we are adding
*/
public static function createAddForm($fact) {
global $tags, $WT_TREE;
$tags = array();
// handle MARRiage TYPE
if (substr($fact, 0, 5) === 'MARR_') {
$tags[0] = 'MARR';
self::addSimpleTag('1 MARR');
self::insertMissingSubtags($fact);
} else {
$tags[0] = $fact;
if ($fact === '_UID') {
$fact .= ' ' . GedcomTag::createUid();
}
// These new level 1 tags need to be turned into links
if (in_array($fact, array('ALIA', 'ASSO'))) {
$fact .= ' @';
}
if (in_array($fact, Config::emptyFacts())) {
self::addSimpleTag('1 ' . $fact . ' Y');
} else {
self::addSimpleTag('1 ' . $fact);
}
self::insertMissingSubtags($tags[0]);
//-- handle the special SOURce case for level 1 sources [ 1759246 ]
if ($fact === 'SOUR') {
self::addSimpleTag('2 PAGE');
self::addSimpleTag('3 TEXT');
if ($WT_TREE->getPreference('FULL_SOURCES')) {
self::addSimpleTag('3 DATE', '', GedcomTag::getLabel('DATA:DATE'));
self::addSimpleTag('2 QUAY');
}
}
}
}
/**
* Create a form to edit a Fact object.
*
* @param Fact $fact
*
* @return string
*/
public static function createEditForm(Fact $fact) {
global $tags;
$record = $fact->getParent();
$tags = array();
$gedlines = explode("\n", $fact->getGedcom());
$linenum = 0;
$fields = explode(' ', $gedlines[$linenum]);
$glevel = $fields[0];
$level = $glevel;
$type = $fact->getTag();
$level0type = $record::RECORD_TYPE;
$level1type = $type;
$i = $linenum;
$inSource = false;
$levelSource = 0;
$add_date = true;
// List of tags we would expect at the next level
// NB add_missing_subtags() already takes care of the simple cases
// where a level 1 tag is missing a level 2 tag. Here we only need to
// handle the more complicated cases.
$expected_subtags = array(
'SOUR' => array('PAGE', 'DATA'),
'DATA' => array('TEXT'),
'PLAC' => array('MAP'),
'MAP' => array('LATI', 'LONG'),
);
if ($record->getTree()->getPreference('FULL_SOURCES')) {
$expected_subtags['SOUR'][] = 'QUAY';
$expected_subtags['DATA'][] = 'DATE';
}
if (GedcomCodeTemp::isTagLDS($level1type)) {
$expected_subtags['STAT'] = array('DATE');
}
if (in_array($level1type, Config::dateAndTime())) {
$expected_subtags['DATE'] = array('TIME'); // TIME is NOT a valid 5.5.1 tag
}
if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $record->getTree()->getPreference('ADVANCED_PLAC_FACTS'), $match)) {
$expected_subtags['PLAC'] = array_merge($match[1], $expected_subtags['PLAC']);
}
$stack = array();
// Loop on existing tags :
while (true) {
// Keep track of our hierarchy, e.g. 1=>BIRT, 2=>PLAC, 3=>FONE
$stack[$level] = $type;
// Merge them together, e.g. BIRT:PLAC:FONE
$label = implode(':', array_slice($stack, 0, $level));
$text = '';
for ($j = 2; $j < count($fields); $j++) {
if ($j > 2) {
$text .= ' ';
}
$text .= $fields[$j];
}
$text = rtrim($text);
while (($i + 1 < count($gedlines)) && (preg_match("/" . ($level + 1) . ' CONT ?(.*)/', $gedlines[$i + 1], $cmatch) > 0)) {
$text .= "\n" . $cmatch[1];
$i++;
}
if ($type === 'SOUR') {
$inSource = true;
$levelSource = $level;
} elseif ($levelSource >= $level) {
$inSource = false;
}
if ($type !== 'CONT') {
$tags[] = $type;
$subrecord = $level . ' ' . $type . ' ' . $text;
if ($inSource && $type === 'DATE') {
self::addSimpleTag($subrecord, '', GedcomTag::getLabel($label, $record));
} elseif (!$inSource && $type === 'DATE') {
self::addSimpleTag($subrecord, $level1type, GedcomTag::getLabel($label, $record));
if ($level === '2') {
// We already have a date - no need to add one.
$add_date = false;
}
} elseif ($type === 'STAT') {
self::addSimpleTag($subrecord, $level1type, GedcomTag::getLabel($label, $record));
} else {
self::addSimpleTag($subrecord, $level0type, GedcomTag::getLabel($label, $record));
}
}
// Get a list of tags present at the next level
$subtags = array();
for ($ii = $i + 1; isset($gedlines[$ii]) && preg_match('/^(\d+) (\S+)/', $gedlines[$ii], $mm) && $mm[1] > $level; ++$ii) {
if ($mm[1] == $level + 1) {
$subtags[] = $mm[2];
}
}
// Insert missing tags
if (!empty($expected_subtags[$type])) {
foreach ($expected_subtags[$type] as $subtag) {
if (!in_array($subtag, $subtags)) {
self::addSimpleTag(($level + 1) . ' ' . $subtag, '', GedcomTag::getLabel($label . ':' . $subtag));
if (!empty($expected_subtags[$subtag])) {
foreach ($expected_subtags[$subtag] as $subsubtag) {
self::addSimpleTag(($level + 2) . ' ' . $subsubtag, '', GedcomTag::getLabel($label . ':' . $subtag . ':' . $subsubtag));
}
}
}
}
}
$i++;
if (isset($gedlines[$i])) {
$fields = explode(' ', $gedlines[$i]);
$level = $fields[0];
if (isset($fields[1])) {
$type = trim($fields[1]);
} else {
$level = 0;
}
} else {
$level = 0;
}
if ($level <= $glevel) {
break;
}
}
if ($level1type !== '_PRIM') {
self::insertMissingSubtags($level1type, $add_date);
}
return $level1type;
}
/**
* Populates the global $tags array with any missing sub-tags.
*
* @param string $level1tag the type of the level 1 gedcom record
* @param bool $add_date
*/
public static function insertMissingSubtags($level1tag, $add_date = false) {
global $tags, $WT_TREE;
// handle MARRiage TYPE
$type_val = '';
if (substr($level1tag, 0, 5) === 'MARR_') {
$type_val = substr($level1tag, 5);
$level1tag = 'MARR';
}
foreach (Config::levelTwoTags() as $key => $value) {
if ($key === 'DATE' && in_array($level1tag, Config::nonDateFacts()) || $key === 'PLAC' && in_array($level1tag, Config::nonPlaceFacts())) {
continue;
}
if (in_array($level1tag, $value) && !in_array($key, $tags)) {
if ($key === 'TYPE') {
self::addSimpleTag('2 TYPE ' . $type_val, $level1tag);
} elseif ($level1tag === '_TODO' && $key === 'DATE') {
self::addSimpleTag('2 ' . $key . ' ' . strtoupper(date('d M Y')), $level1tag);
} elseif ($level1tag === '_TODO' && $key === '_WT_USER') {
self::addSimpleTag('2 ' . $key . ' ' . Auth::user()->getUserName(), $level1tag);
} elseif ($level1tag === 'TITL' && strstr($WT_TREE->getPreference('ADVANCED_NAME_FACTS'), $key) !== false) {
self::addSimpleTag('2 ' . $key, $level1tag);
} elseif ($level1tag === 'NAME' && strstr($WT_TREE->getPreference('ADVANCED_NAME_FACTS'), $key) !== false) {
self::addSimpleTag('2 ' . $key, $level1tag);
} elseif ($level1tag !== 'TITL' && $level1tag !== 'NAME') {
self::addSimpleTag('2 ' . $key, $level1tag);
}
// Add level 3/4 tags as appropriate
switch ($key) {
case 'PLAC':
if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('ADVANCED_PLAC_FACTS'), $match)) {
foreach ($match[1] as $tag) {
self::addSimpleTag('3 ' . $tag, '', GedcomTag::getLabel($level1tag . ':PLAC:' . $tag));
}
}
self::addSimpleTag('3 MAP');
self::addSimpleTag('4 LATI');
self::addSimpleTag('4 LONG');
break;
case 'FILE':
self::addSimpleTag('3 FORM');
break;
case 'EVEN':
self::addSimpleTag('3 DATE');
self::addSimpleTag('3 PLAC');
break;
case 'STAT':
if (GedcomCodeTemp::isTagLDS($level1tag)) {
self::addSimpleTag('3 DATE', '', GedcomTag::getLabel('STAT:DATE'));
}
break;
case 'DATE':
// TIME is NOT a valid 5.5.1 tag
if (in_array($level1tag, Config::dateAndTime())) {
self::addSimpleTag('3 TIME');
}
break;
case 'HUSB':
case 'WIFE':
self::addSimpleTag('3 AGE');
break;
case 'FAMC':
if ($level1tag === 'ADOP') {
self::addSimpleTag('3 ADOP BOTH');
}
break;
}
} elseif ($key === 'DATE' && $add_date) {
self::addSimpleTag('2 DATE', $level1tag, GedcomTag::getLabel($level1tag . ':DATE'));
}
}
// Do something (anything!) with unrecognized custom tags
if (substr($level1tag, 0, 1) === '_' && $level1tag !== '_UID' && $level1tag !== '_TODO') {
foreach (array('DATE', 'PLAC', 'ADDR', 'AGNC', 'TYPE', 'AGE') as $tag) {
if (!in_array($tag, $tags)) {
self::addSimpleTag('2 ' . $tag);
if ($tag === 'PLAC') {
if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('ADVANCED_PLAC_FACTS'), $match)) {
foreach ($match[1] as $ptag) {
self::addSimpleTag('3 ' . $ptag, '', GedcomTag::getLabel($level1tag . ':PLAC:' . $ptag));
}
}
self::addSimpleTag('3 MAP');
self::addSimpleTag('4 LATI');
self::addSimpleTag('4 LONG');
}
}
}
}
}
}