diff options
71 files changed, 718 insertions, 3883 deletions
diff --git a/app/Config.php b/app/Config.php deleted file mode 100644 index 3bffb3ff51..0000000000 --- a/app/Config.php +++ /dev/null @@ -1,448 +0,0 @@ -<?php - -/** - * webtrees: online genealogy - * Copyright (C) 2021 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 <https://www.gnu.org/licenses/>. - */ - -declare(strict_types=1); - -namespace Fisharebest\Webtrees; - -/** - * Application configuration data. Data here has no GUI to edit it, - * although most of it can be altered to customise local installations. - * - * @deprecated since 2.0.7. Will be removed in 2.1.0 - */ -class Config -{ - /** - * NPFX tags - name prefixes - * - * @return array<string> - */ - public static function namePrefixes(): array - { - return [ - 'Adm', - 'Amb', - 'Brig', - 'Can', - 'Capt', - 'Chan', - 'Chapln', - 'Cmdr', - 'Col', - 'Cpl', - 'Cpt', - 'Dr', - 'Gen', - 'Gov', - 'Hon', - 'Lady', - 'Lt', - 'Mr', - 'Mrs', - 'Ms', - 'Msgr', - 'Pfc', - 'Pres', - 'Prof', - 'Pvt', - 'Rabbi', - 'Rep', - 'Rev', - 'Sen', - 'Sgt', - 'Sir', - 'Sr', - 'Sra', - 'Srta', - 'Ven', - ]; - } - - /** - * FILE:FORM tags - file formats - * - * @return array<string> - */ - public static function fileFormats(): array - { - return [ - 'avi', - 'bmp', - 'gif', - 'jpeg', - 'mp3', - 'ole', - 'pcx', - 'png', - 'tiff', - 'wav', - ]; - } - - /** - * Facts and events that don't normally have a value - * - * @return array<string> - */ - public static function emptyFacts(): array - { - return [ - 'ADOP', - 'ANUL', - 'BAPL', - 'BAPM', - 'BARM', - 'BASM', - 'BIRT', - 'BLES', - 'BURI', - 'CENS', - 'CHAN', - 'CHR', - 'CHRA', - 'CONF', - 'CONL', - 'CREM', - 'DATA', - 'DEAT', - 'DIV', - 'DIVF', - 'EMIG', - 'ENDL', - 'ENGA', - 'FCOM', - 'GRAD', - 'HUSB', - 'IMMI', - 'MAP', - 'MARB', - 'MARC', - 'MARL', - 'MARR', - 'MARS', - 'NATU', - 'ORDN', - 'PROB', - 'RESI', - 'RETI', - 'SLGC', - 'SLGS', - 'WIFE', - 'WILL', - '_HOL', - '_NMR', - '_NMAR', - '_SEPR', - ]; - } - - /** - * Tags that don't require a PLAC subtag - * - * @return array<string> - */ - public static function nonPlaceFacts(): array - { - return [ - 'ENDL', - 'NCHI', - 'REFN', - 'SLGC', - 'SLGS', - ]; - } - - /** - * Tags that don't require a DATE subtag - * - * @return array<string> - */ - public static function nonDateFacts(): array - { - return [ - 'ABBR', - 'ADDR', - 'AFN', - 'ALIA', - 'AUTH', - 'CHIL', - 'EMAIL', - 'FAX', - 'FILE', - 'HUSB', - 'LANG', - 'NAME', - 'NCHI', - 'NOTE', - 'OBJE', - 'PHON', - 'PUBL', - 'REFN', - 'REPO', - 'RESN', - 'SEX', - 'SOUR', - 'SSN', - 'TEXT', - 'WIFE', - 'WWW', - '_EMAIL', - ]; - } - - /** - * Tags that require a DATE:TIME as well as a DATE - * - * @return array<string> - */ - public static function dateAndTime(): array - { - return [ - 'BIRT', - 'DEAT', - ]; - } - - /** - * Level 2 tags that apply to specific Level 1 tags - * Tags are applied in the order they appear here. - * - * @return array<string,array<string>> - */ - public static function levelTwoTags(): array - { - return [ - 'TYPE' => [ - 'EVEN', - 'FACT', - 'GRAD', - 'IDNO', - 'MARR', - 'ORDN', - 'SSN', - ], - 'AGNC' => [ - 'EDUC', - 'GRAD', - 'OCCU', - 'ORDN', - 'RETI', - ], - 'CALN' => [ - 'REPO', - ], - 'CEME' => [ - // CEME is NOT a valid 5.5.1 tag - //'BURI', - ], - 'RELA' => [ - 'ASSO', - '_ASSO', - ], - 'DATE' => [ - 'ADOP', - 'ANUL', - 'BAPL', - 'BAPM', - 'BARM', - 'BASM', - 'BIRT', - 'BLES', - 'BURI', - 'CENS', - 'CENS', - 'CHR', - 'CHRA', - 'CONF', - 'CONL', - 'CREM', - 'DEAT', - 'DIV', - 'DIVF', - 'DSCR', - 'EDUC', - 'EMIG', - 'ENDL', - 'ENGA', - 'EVEN', - 'FCOM', - 'GRAD', - 'IMMI', - 'MARB', - 'MARC', - 'MARL', - 'MARR', - 'MARS', - 'NATU', - 'OCCU', - 'ORDN', - 'PROB', - 'PROP', - 'RELI', - 'RESI', - 'RETI', - 'SLGC', - 'SLGS', - 'TITL', - 'WILL', - '_TODO', - ], - 'AGE' => [ - 'CENS', - 'DEAT', - ], - 'TEMP' => [ - 'BAPL', - 'CONL', - 'ENDL', - 'SLGC', - 'SLGS', - ], - 'PLAC' => [ - 'ADOP', - 'ANUL', - 'BAPL', - 'BAPM', - 'BARM', - 'BASM', - 'BIRT', - 'BLES', - 'BURI', - 'CENS', - 'CHR', - 'CHRA', - 'CONF', - 'CONL', - 'CREM', - 'DEAT', - 'DIV', - 'DIVF', - 'EDUC', - 'EMIG', - 'ENDL', - 'ENGA', - 'EVEN', - 'FCOM', - 'GRAD', - 'IMMI', - 'MARB', - 'MARC', - 'MARL', - 'MARR', - 'MARS', - 'NATU', - 'OCCU', - 'ORDN', - 'PROB', - 'PROP', - 'RELI', - 'RESI', - 'RETI', - 'SLGC', - 'SLGS', - 'SSN', - 'TITL', - 'WILL', - ], - 'STAT' => [ - 'BAPL', - 'CONL', - 'ENDL', - 'SLGC', - 'SLGS', - ], - 'ADDR' => [ - 'BAPM', - 'BIRT', - 'BURI', - 'CENS', - 'CHR', - 'CHRA', - 'CONF', - 'CREM', - 'DEAT', - 'EDUC', - 'EVEN', - 'GRAD', - 'MARR', - 'OCCU', - 'ORDN', - 'PROP', - 'RESI', - ], - 'CAUS' => [ - 'DEAT', - ], - 'PHON' => [ - 'OCCU', - 'RESI', - ], - 'FAX' => [ - 'OCCU', - 'RESI', - ], - 'WWW' => [ - 'OCCU', - 'RESI', - ], - 'EMAIL' => [ - 'OCCU', - 'RESI', - ], - 'HUSB' => [ - 'MARR', - ], - 'WIFE' => [ - 'MARR', - ], - 'FAMC' => [ - 'ADOP', - 'SLGC', - ], - 'EVEN' => [ - 'DATA', - ], - '_WT_USER' => [ - '_TODO', - ], - // See https://bugs.launchpad.net/webtrees/+bug/1082666 - 'RELI' => [ - 'CHR', - 'CHRA', - 'BAPM', - 'MARR', - 'BURI', - ], - ]; - } - - /** - * A list of facts/events that generally have two associates - * (two witnesses, two godparents, etc.) - * - * @return array<string> - */ - public static function twoAssociates(): array - { - return [ - 'CHR', - 'BAPM', - 'MARR', - ]; - } -} diff --git a/app/Contracts/ElementInterface.php b/app/Contracts/ElementInterface.php index 145e3a50f4..b47890d8e1 100644 --- a/app/Contracts/ElementInterface.php +++ b/app/Contracts/ElementInterface.php @@ -91,7 +91,7 @@ interface ElementInterface * * @return void */ - public function subtag(string $subtag, string $repeat, string $before): void; + public function subtag(string $subtag, string $repeat = '0:1', string $before = ''): void; /** * @return array<string,string> diff --git a/app/Elements/AbstractElement.php b/app/Elements/AbstractElement.php index 1886fa85bc..f27300605d 100644 --- a/app/Elements/AbstractElement.php +++ b/app/Elements/AbstractElement.php @@ -218,7 +218,7 @@ abstract class AbstractElement implements ElementInterface * * @return void */ - public function subtag(string $subtag, string $repeat, string $before): void + public function subtag(string $subtag, string $repeat = '0:1', string $before = ''): void { if ($repeat === '') { unset($this->subtags[$subtag]); @@ -229,7 +229,7 @@ abstract class AbstractElement implements ElementInterface foreach ($this->subtags as $key => $value) { if ($key === $before) { - $tmp[$key] = $repeat; + $tmp[$subtag] = $repeat; } $tmp[$key] = $value; } diff --git a/app/Functions/FunctionsEdit.php b/app/Functions/FunctionsEdit.php deleted file mode 100644 index c59d520b79..0000000000 --- a/app/Functions/FunctionsEdit.php +++ /dev/null @@ -1,911 +0,0 @@ -<?php - -/** - * webtrees: online genealogy - * Copyright (C) 2021 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 <https://www.gnu.org/licenses/>. - */ - -declare(strict_types=1); - -namespace Fisharebest\Webtrees\Functions; - -use Fisharebest\Webtrees\Auth; -use Fisharebest\Webtrees\Census\Census; -use Fisharebest\Webtrees\Config; -use Fisharebest\Webtrees\Date; -use Fisharebest\Webtrees\Elements\PafUid; -use Fisharebest\Webtrees\Fact; -use Fisharebest\Webtrees\Family; -use Fisharebest\Webtrees\Gedcom; -use Fisharebest\Webtrees\GedcomTag; -use Fisharebest\Webtrees\Html; -use Fisharebest\Webtrees\Http\RequestHandlers\AutoCompleteCitation; -use Fisharebest\Webtrees\Http\RequestHandlers\AutoCompletePlace; -use Fisharebest\Webtrees\Http\RequestHandlers\AutoCompleteSurname; -use Fisharebest\Webtrees\Http\RequestHandlers\CreateMediaObjectModal; -use Fisharebest\Webtrees\Http\RequestHandlers\CreateNoteModal; -use Fisharebest\Webtrees\Http\RequestHandlers\CreateRepositoryModal; -use Fisharebest\Webtrees\Http\RequestHandlers\CreateSourceModal; -use Fisharebest\Webtrees\Http\RequestHandlers\CreateSubmitterModal; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Individual; -use Fisharebest\Webtrees\Module\CensusAssistantModule; -use Fisharebest\Webtrees\Registry; -use Fisharebest\Webtrees\Services\LocalizationService; -use Fisharebest\Webtrees\Services\MessageService; -use Fisharebest\Webtrees\Services\ModuleService; -use Fisharebest\Webtrees\Services\UserService; -use Fisharebest\Webtrees\Tree; -use Psr\Http\Message\ServerRequestInterface; -use Ramsey\Uuid\Uuid; - -use function app; -use function array_merge; -use function array_slice; -use function count; -use function date; -use function e; -use function explode; -use function implode; -use function in_array; -use function preg_match; -use function preg_match_all; -use function route; -use function str_contains; -use function strtolower; -use function strtoupper; -use function substr; -use function trim; -use function ucfirst; -use function view; - -/** - * Class FunctionsEdit - common functions for editing - * - * @deprecated since 2.0.6. Will be removed in 2.1.0 - */ -class FunctionsEdit -{ - /** @var string[] - a list of GEDCOM tags in the edit form. */ - private static $tags = []; - - /** - * Function edit_language_checkboxes - * - * @param string $parameter_name - * @param array<string> $languages - * - * @return string - */ - public static function editLanguageCheckboxes(string $parameter_name, array $languages): string - { - return view('edit/language-checkboxes', ['languages' => $languages]); - } - - /** - * A list of access levels (e.g. for an edit control). - * - * @return array<string> - */ - public static function optionsAccessLevels(): array - { - return Auth::accessLevelNames(); - } - - /** - * A list of active languages (e.g. for an edit control). - * - * @return array<string> - */ - public static function optionsActiveLanguages(): array - { - $languages = []; - foreach (I18N::activeLocales() as $locale) { - $languages[$locale->languageTag()] = $locale->endonym(); - } - - return $languages; - } - - /** - * A list of calendar conversions (e.g. for an edit control). - * - * @return array<string> - */ - public static function optionsCalendarConversions(): array - { - return ['none' => I18N::translate('No calendar conversion')] + Date::calendarNames(); - } - - /** - * A list of contact methods (e.g. for an edit control). - * - * @return array<string> - */ - public static function optionsContactMethods(): array - { - return app(MessageService::class)->contactMethods(); - } - - /** - * A list of hide/show options (e.g. for an edit control). - * - * @return array<string> - */ - public static function optionsHideShow(): array - { - return [ - '0' => I18N::translate('no'), - '1' => I18N::translate('yes'), - ]; - } - - /** - * A list of integers (e.g. for an edit control). - * - * @param array<int> $integers - * - * @return array<int,string> - */ - public static function numericOptions(array $integers): array - { - $array = []; - foreach ($integers as $integer) { - if ($integer === -1) { - $array[$integer] = I18N::translate('All'); - } else { - $array[$integer] = I18N::number($integer); - } - } - - return $array; - } - - /** - * A list of no/yes options (e.g. for an edit control). - * - * @return array<string> - */ - public static function optionsNoYes(): array - { - return [ - '0' => I18N::translate('no'), - '1' => I18N::translate('yes'), - ]; - } - - /** - * A list of GEDCOM restrictions for inline data. - * - * @param bool $include_empty - * - * @return array<string> - */ - public static function optionsRestrictions(bool $include_empty): array - { - $options = [ - 'none' => I18N::translate('Show to visitors'), - 'privacy' => I18N::translate('Show to members'), - 'confidential' => I18N::translate('Show to managers'), - 'locked' => I18N::translate('Only managers can edit'), - ]; - - if ($include_empty) { - $options = ['' => ''] + $options; - } - - return $options; - } - - /** - * A list of GEDCOM restrictions for privacy rules. - * - * @return array<string> - */ - public static function optionsRestrictionsRule(): array - { - return Auth::privacyRuleNames(); - } - - /** - * A list of temple options (e.g. for an edit control). - * - * @return array<string> - */ - public static function optionsTemples(): array - { - return Registry::elementFactory()->make('SUBN:TEMP')->values(); - } - - /** - * A list of user options (e.g. for an edit control). - * - * @return array<string> - */ - public static function optionsUsers(): array - { - $options = ['' => '-']; - - foreach (app(UserService::class)->all() as $user) { - $options[$user->userName()] = $user->realName() . ' - ' . $user->userName(); - } - - return $options; - } - - /** - * 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 Tree $tree - * @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 - * - * @return string - */ - public static function addSimpleTag(Tree $tree, string $tag, string $upperlevel = '', string $label = ''): string - { - $localization_service = app(LocalizationService::class); - - $request = app(ServerRequestInterface::class); - $xref = $request->getAttribute('xref', ''); - - // Some form fields need access to previous form fields. - static $previous_ids = [ - 'SOUR' => '', - 'PLAC' => '', - ]; - - $parts = explode(' ', $tag, 3); - $level = $parts[0] ?? ''; - $fact = $parts[1] ?? ''; - $value = $parts[2] ?? ''; - - if ($level === '0') { - // Adding a new fact. - if ($upperlevel) { - $name = $upperlevel . '_' . $fact; - } else { - $name = $fact; - } - } else { - // Editing an existing fact. - $name = 'text[]'; - } - - $id = $fact . Uuid::uuid4()->toString(); - - $previous_ids[$fact] = $id; - - // field value - $islink = (bool) preg_match('/^@[^#@][^@]*@$/', $value); - if ($islink) { - $value = trim($value, '@'); - } - - if ($fact === 'REPO' || $fact === 'SOUR' || $fact === 'OBJE' || $fact === 'FAMC' || $fact === 'SUBM' || $fact === 'ASSO' || $fact === '_ASSO' || $fact === 'ALIA') { - $islink = true; - } - - if ($fact === 'SHARED_NOTE_EDIT' || $fact === 'SHARED_NOTE') { - $islink = true; - $fact = 'NOTE'; - } - - $row_class = 'form-group row'; - switch ($fact) { - case 'DATA': - case 'MAP': - // These GEDCOM tags should have no data, just child tags. - if ($value === '') { - $row_class .= ' d-none'; - } - break; - case 'LATI': - case 'LONG': - // Indicate that this row is a child of a previous row, so we can expand/collapse them. - $row_class .= ' child_of_' . $previous_ids['PLAC']; - if ($value === '') { - $row_class .= ' collapse'; - } - break; - } - - $html = ''; - $html .= '<div class="' . $row_class . '">'; - $html .= '<label class="col-sm-3 col-form-label" for="' . $id . '">'; - - // tag name - if ($label) { - $html .= $label; - } elseif ($upperlevel) { - $html .= GedcomTag::getLabel($upperlevel . ':' . $fact); - } else { - $html .= GedcomTag::getLabel($fact); - } - - // Not all facts have help text. - switch ($fact) { - case 'NAME': - if ($upperlevel !== 'REPO' && $upperlevel !== 'UNKNOWN') { - $html .= view('help/link', ['topic' => $fact]); - } - break; - case 'ROMN': - case 'SURN': - case '_HEB': - $html .= view('help/link', ['topic' => $fact]); - break; - } - - // tag level - if ($level !== '0') { - $html .= '<input type="hidden" name="glevels[]" value="' . $level . '">'; - $html .= '<input type="hidden" name="islink[]" value="' . $islink . '">'; - $html .= '<input type="hidden" name="tag[]" value="' . $fact . '">'; - } - $html .= '</label>'; - - // value - $html .= '<div class="col-sm-9">'; - - // Show names for spouses in MARR/HUSB/AGE and MARR/WIFE/AGE - if ($fact === 'HUSB' || $fact === 'WIFE') { - $family = Registry::familyFactory()->make($xref, $tree); - if ($family instanceof Family) { - $spouse_link = $family->facts([$fact])->first(); - if ($spouse_link instanceof Fact) { - $spouse = $spouse_link->target(); - if ($spouse instanceof Individual) { - $html .= $spouse->fullName(); - } - } - } - } - - if (in_array($fact, Config::emptyFacts(), true) && ($value === '' || $value === 'Y' || $value === 'y')) { - $html .= '<input type="hidden" id="' . $id . '" name="' . $name . '" value="' . $value . '">'; - - $checked = $value === '' ? '' : 'checked'; - $onchange = 'this.previousSibling.value=this.checked ? this.value : ""'; - $html .= '<input type="checkbox" value="Y" ' . $checked . ' onchange="' . $onchange . '">'; - - if ($fact === 'CENS' && $value === 'Y') { - $html .= view('modules/GEDFact_assistant/select-census', [ - 'census_places' => Census::censusPlaces(I18N::languageTag()), - ]); - - $census_assistant = app(ModuleService::class)->findByInterface(CensusAssistantModule::class)->first(); - $record = Registry::individualFactory()->make($xref, $tree); - - if ($census_assistant instanceof CensusAssistantModule && $record instanceof Individual) { - $html .= $census_assistant->createCensusAssistant($record); - } - } - } elseif ($fact === 'NPFX' || $fact === 'NSFX' || $fact === 'SPFX' || $fact === 'NICK') { - $html .= '<div class="input-group">'; - $html .= '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" oninput="updatewholename()">'; - $html .= view('edit/input-addon-keyboard', ['id' => $id]); - $html .= '</div>'; - } elseif ($fact === 'GIVN') { - $html .= '<div class="input-group">'; - $html .= '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" oninput="updatewholename()" autofocus>'; - $html .= view('edit/input-addon-keyboard', ['id' => $id]); - $html .= '</div>'; - } elseif ($fact === 'SURN' || $fact === '_MARNM_SURN') { - $html .= '<div class="input-group">'; - $html .= '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" autocomplete="off" data-autocomplete-url="' . e(route(AutoCompleteSurname::class, ['tree' => $tree->name()])) . '" oninput="updatewholename()" onblur="updatewholename()">'; - $html .= view('edit/input-addon-keyboard', ['id' => $id]); - $html .= '</div>'; - } elseif ($fact === 'ADOP') { - $element = Registry::elementFactory()->make('INDI:ADOP:FAMC:ADOP'); - $html .= view('components/select', ['id' => $id, 'name' => $name, 'selected' => $value, 'options' => $element->values()]); - } elseif ($fact === 'LANG') { - $element = Registry::elementFactory()->make('HEAD:LANG'); - $html .= view('components/select', ['id' => $id, 'name' => $name, 'selected' => $value, 'options' => $element->values()]); - } elseif ($fact === 'ALIA') { - $html .= '<div class="input-group">'; - $html .= view('components/select-individual', ['id' => $id, 'name' => $name, 'individual' => Registry::individualFactory()->make($value, $tree), 'tree' => $tree]); - $html .= '</div>'; - } elseif ($fact === 'ASSO' || $fact === '_ASSO') { - $html .= '<div class="input-group">'; - $html .= view('components/select-individual', ['id' => $id, 'name' => $name, 'individual' => Registry::individualFactory()->make($value, $tree), 'tree' => $tree]); - $html .= '</div>'; - if ($level === '1') { - $html .= '<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 { - $html .= '<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>'; - } - } elseif ($fact === 'DATE') { - // Need to know if the user prefers DMY/MDY/YMD so we can validate dates properly. - $dmy = '"' . $localization_service->dateFormatToOrder(I18N::dateFormat()) . '"'; - - $html .= '<div class="input-group">'; - $html .= '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" onchange="webtrees.reformatDate(this, ' . e($dmy) . ')" dir="ltr">'; - $html .= view('edit/input-addon-calendar', ['id' => $id]); - $html .= view('edit/input-addon-help', ['fact' => 'DATE']); - $html .= '</div>'; - $html .= '<div id="caldiv' . $id . '" style="position:absolute;visibility:hidden;background-color:white;z-index:1000"></div>'; - $html .= '<p class="text-muted">' . (new Date($value))->display() . '</p>'; - } elseif ($fact === 'FAMC') { - $html .= view('components/select-family', ['id' => $id, 'name' => $name, 'family' => Registry::familyFactory()->make($value, $tree), 'tree' => $tree]); - } elseif ($fact === 'LATI') { - $html .= '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" oninput="webtrees.reformatLatitude(this)">'; - } elseif ($fact === 'LONG') { - $html .= '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" oninput="webtrees.reformatLongitude(this)">'; - } elseif ($fact === 'NOTE' && $islink) { - $html .= - '<div class="input-group">' . - '<div class="input-group-prepend">' . - '<button class="btn btn-secondary" type="button" data-toggle="modal" data-backdrop="static" data-target="#wt-ajax-modal" data-href="' . e(route(CreateNoteModal::class, ['tree' => $tree->name()])) . '" data-select-id="' . $id . '" title="' . I18N::translate('Create a shared note') . '">' . - '' . view('icons/add') . '<' . - '/button>' . - '</div>' . - view('components/select-note', ['id' => $id, 'name' => $name, 'note' => Registry::noteFactory()->make($value, $tree), 'tree' => $tree]) . - '</div>'; - } elseif ($fact === 'OBJE') { - $html .= - '<div class="input-group">' . - '<div class="input-group-prepend"><button class="btn btn-secondary" type="button" data-toggle="modal" data-backdrop="static" data-href="' . e(route(CreateMediaObjectModal::class, ['tree' => $tree->name()])) . '" data-target="#wt-ajax-modal" data-select-id="' . $id . '" title="' . I18N::translate('Create a media object') . '">' . view('icons/add') . '</button></div>' . - view('components/select-media', ['id' => $id, 'name' => $name, 'media' => Registry::mediaFactory()->make($value, $tree), 'tree' => $tree]) . - '</div>'; - } elseif ($fact === 'PAGE') { - $html .= '<input ' . Html::attributes([ - 'autocomplete' => 'off', - 'class' => 'form-control', - 'id' => $id, - 'name' => $name, - 'value' => $value, - 'type' => 'text', - 'data-autocomplete-url' => route(AutoCompleteCitation::class, ['tree' => $tree->name()]), - 'data-autocomplete-extra' => 'SOUR', - ]) . '>'; - } elseif ($fact === 'PEDI') { - $element = Registry::elementFactory()->make('INDI:FAMC:PEDI'); - - $html .= view('components/select', ['id' => $id, 'name' => $name, 'selected' => $value, 'options' => $element->values()]); - } elseif ($fact === 'PLAC') { - $html .= '<div class="input-group">'; - $html .= '<input ' . Html::attributes([ - 'autocomplete' => 'off', - 'class' => 'form-control', - 'id' => $id, - 'name' => $name, - 'value' => $value, - 'type' => 'text', - 'data-autocomplete-url' => route(AutoCompletePlace::class, ['tree' => $tree->name()]), - ]) . '>'; - - $html .= view('edit/input-addon-coordinates', ['id' => $id]); - $html .= view('edit/input-addon-help', ['fact' => 'PLAC']); - $html .= '</div>'; - } elseif ($fact === 'QUAY') { - $element = Registry::elementFactory()->make('INDI:SOUR:QUAY'); - $html .= view('components/select', ['id' => $id, 'name' => $name, 'selected' => $value, 'options' => $element->values()]); - } elseif ($fact === 'RELA') { - $html .= Registry::elementFactory()->make('INDI:ASSO:RELA')->edit($id, $name, $value, $tree); - } elseif ($fact === 'REPO') { - $html .= - '<div class="input-group">' . - '<div class="input-group-prepend"><button class="btn btn-secondary" type="button" data-toggle="modal" data-backdrop="static" data-href="' . e(route(CreateRepositoryModal::class, ['tree' => $tree->name()])) . '" data-target="#wt-ajax-modal" data-select-id="' . $id . '" title="' . I18N::translate('Create a repository') . '">' . view('icons/add') . '</button></div>' . - view('components/select-repository', ['id' => $id, 'name' => $name, 'repository' => Registry::repositoryFactory()->make($value, $tree), 'tree' => $tree]) . - '</div>'; - } elseif ($fact === 'RESN') { - $html .= '<div class="input-group">'; - $html .= view('components/select', ['id' => $id, 'name' => $name, 'selected' => $value, 'options' => self::optionsRestrictions(true)]); - $html .= view('edit/input-addon-help', ['fact' => 'RESN']); - $html .= '</span>'; - $html .= '</div>'; - } elseif ($fact === 'SEX') { - $html .= view('components/radios-inline', ['name' => $name, 'options' => ['M' => I18N::translate('Male'), 'F' => I18N::translate('Female'), 'U' => I18N::translateContext('unknown gender', 'Unknown')], 'selected' => $value]); - } elseif ($fact === 'SOUR') { - $html .= - '<div class="input-group">' . - '<div class="input-group-prepend"><button class="btn btn-secondary" type="button" data-toggle="modal" data-backdrop="static" data-href="' . e(route(CreateSourceModal::class, ['tree' => $tree->name()])) . '" data-target="#wt-ajax-modal" data-select-id="' . $id . '" title="' . I18N::translate('Create a source') . '">' . view('icons/add') . '</button></div>' . - view('components/select-source', ['id' => $id, 'name' => $name, 'source' => Registry::sourceFactory()->make($value, $tree), 'tree' => $tree]) . - '</div>'; - } elseif ($fact === 'STAT') { - $html .= Registry::elementFactory()->make(($upperlevel === 'SLGS' ? 'FAM:' : 'INDI:') . $upperlevel . ':STAT')->edit($id, $name, $value, $tree); - } elseif ($fact === 'SUBM') { - $html .= - '<div class="input-group">' . - '<div class="input-group-prepend"><button class="btn btn-secondary" type="button" data-toggle="modal" data-backdrop="static" data-href="' . e(route(CreateSubmitterModal::class, ['tree' => $tree->name()])) . '" data-target="#wt-ajax-modal" data-select-id="' . $id . '" title="' . I18N::translate('Create a submitter') . '">' . view('icons/add') . '</button></div>' . - view('components/select-submitter', ['id' => $id, 'name' => $name, 'submitter' => Registry::submitterFactory()->make($value, $tree), 'tree' => $tree]) . - '</div>'; - } elseif ($fact === 'TEMP') { - $html .= view('components/select', ['id' => $id, 'name' => $name, 'selected' => $value, 'options' => self::optionsTemples()]); - } elseif ($fact === 'TIME') { - /* I18N: Examples of valid time formats (hours:minutes:seconds) */ - $html .= '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" pattern="([0-1][0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?" dir="ltr" placeholder="' . I18N::translate('hh:mm or hh:mm:ss') . '">'; - } elseif ($fact === '_WT_USER') { - $html .= view('components/select', ['id' => $id, 'name' => $name, 'selected' => $value, 'options' => self::optionsUsers()]); - } elseif ($fact === '_PRIM') { - $html .= view('components/select', ['id' => $id, 'name' => $name, 'selected' => $value, 'options' => ['' => '', 'Y' => I18N::translate('always'), 'N' => I18N::translate('never')]]); - $html .= '<p class="small text-muted">' . I18N::translate('Use this image for charts and on the individual’s page.') . '</p>'; - } elseif ($fact === 'TYPE' && $level === '0') { - // Level 0 TYPE fields are only used for NAME records - $html .= Registry::elementFactory()->make('INDI:NAME:TYPE')->edit($id, $name, $value, $tree); - } elseif (($fact !== 'NAME' || $upperlevel === 'REPO' || $upperlevel === 'SUBM' || $upperlevel === 'UNKNOWN') && $fact !== '_MARNM') { - if ($fact === 'TEXT' || $fact === 'ADDR' || ($fact === 'NOTE' && !$islink)) { - $html .= '<div class="input-group">'; - $html .= '<textarea class="form-control" id="' . $id . '" name="' . $name . '" rows="5" dir="auto">' . e($value) . '</textarea>'; - $html .= '</div>'; - } else { - // If using GEDFact-assistant window - $html .= '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '">'; - } - } else { - // Populated in javascript from sub-tags - $html .= '<input type="hidden" id="' . $id . '" name="' . $name . '" oninput="updateTextName(\'' . $id . '\')" value="' . e($value) . '" class="' . $fact . '">'; - $html .= '<span id="' . $id . '_display" dir="auto">' . e($value) . '</span>'; - $html .= ' <a href="#edit_name" onclick="convertHidden(\'' . $id . '\'); return false" class="icon-edit_indi" title="' . I18N::translate('Edit the name') . '"></a>'; - } - // MARRiage TYPE : hide text field and show a selection list - if ($fact === 'TYPE' && $level === '2' && self::$tags[0] === 'MARR') { - $html .= '<script>'; - $html .= 'document.getElementById(\'' . $id . '\').style.display=\'none\''; - $html .= '</script>'; - $html .= '<select id="' . $id . '_sel" oninput="document.getElementById(\'' . $id . '\').value=this.value" >'; - - $marriage_types = [ - '' => '', - 'Civil' => I18N::translate('Civil marriage'), - 'Religious' => I18N::translate('Religious marriage'), - 'Partners' => I18N::translate('Registered partnership'), - ]; - - foreach ($marriage_types as $key => $type_label) { - $html .= '<option value="' . $key . '" '; - if (strtolower($key) === strtolower($value)) { - $html .= 'selected'; - } - $html .= '>' . $type_label . '</option>'; - } - $html .= '</select>'; - } - - $html .= '</div></div>'; - - return $html; - } - - /** - * Add some empty tags to create a new fact. - * - * @param Tree $tree - * @param string $fact - * - * @return void - */ - public static function addSimpleTags(Tree $tree, string $fact): void - { - // For new individuals, these facts default to "Y" - if ($fact === 'MARR') { - echo self::addSimpleTag($tree, '0 ' . $fact . ' Y'); - } else { - echo self::addSimpleTag($tree, '0 ' . $fact); - } - - if (!in_array($fact, Config::nonDateFacts(), true)) { - echo self::addSimpleTag($tree, '0 DATE', $fact, GedcomTag::getLabel($fact . ':DATE')); - } - - if (!in_array($fact, Config::nonPlaceFacts(), true)) { - echo self::addSimpleTag($tree, '0 PLAC', $fact, GedcomTag::getLabel($fact . ':PLAC')); - - if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('ADVANCED_PLAC_FACTS'), $match)) { - foreach ($match[1] as $tag) { - echo self::addSimpleTag($tree, '0 ' . $tag, $fact, GedcomTag::getLabel($fact . ':PLAC:' . $tag)); - } - } - echo self::addSimpleTag($tree, '0 MAP', $fact); - echo self::addSimpleTag($tree, '0 LATI', $fact); - echo self::addSimpleTag($tree, '0 LONG', $fact); - } - } - - /** - * builds the form for adding new facts - * - * @param Tree $tree - * @param string $fact the new fact we are adding - * - * @return void - */ - public static function createAddForm(Tree $tree, string $fact): void - { - self::$tags = []; - - // handle MARRiage TYPE - if (substr($fact, 0, 5) === 'MARR_') { - self::$tags[0] = 'MARR'; - echo self::addSimpleTag($tree, '1 MARR'); - self::insertMissingSubtags($tree, $fact); - } else { - self::$tags[0] = $fact; - if ($fact === '_UID') { - $fact .= ' ' . (new PafUid(''))->default($tree); - } - // These new level 1 tags need to be turned into links - if (in_array($fact, ['ALIA', 'ASSO'], true)) { - $fact .= ' @'; - } - if (in_array($fact, Config::emptyFacts(), true)) { - echo self::addSimpleTag($tree, '1 ' . $fact . ' Y'); - } else { - echo self::addSimpleTag($tree, '1 ' . $fact); - } - self::insertMissingSubtags($tree, self::$tags[0]); - //-- handle the special SOURce case for level 1 sources [ 1759246 ] - if ($fact === 'SOUR') { - echo self::addSimpleTag($tree, '2 PAGE'); - echo self::addSimpleTag($tree, '2 DATA'); - echo self::addSimpleTag($tree, '3 TEXT'); - if ($tree->getPreference('FULL_SOURCES')) { - echo self::addSimpleTag($tree, '3 DATE', '', GedcomTag::getLabel('DATA:DATE')); - echo self::addSimpleTag($tree, '2 QUAY'); - } - } - } - } - - /** - * Create a form to edit a Fact object. - * - * @param Fact $fact - * - * @return void - */ - public static function createEditForm(Fact $fact): void - { - $record = $fact->record(); - $tree = $record->tree(); - - self::$tags = []; - - $level0type = $record->tag(); - $level1type = $fact->getTag(); - - // List of tags we would expect at the next level - // NB insertMissingSubtags() 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 = [ - 'SOUR' => [ - 'PAGE', - 'DATA', - ], - 'PLAC' => ['MAP'], - 'MAP' => [ - 'LATI', - 'LONG', - ], - ]; - - if ($record->tag() !== 'SOUR') { - //source citations within other records, i.e. n SOUR / +1 DATA / +2 TEXT - $expected_subtags['DATA'][] = 'TEXT'; - } //else: source records themselves, i.e. 0 SOUR / 1 DATA don't get a 2 TEXT! - - if ($record->tag() === 'SOUR') { - //source records themselves, i.e. 0 SOUR / 1 DATA / 2 EVEN get a 3 DATE and a 3 PLAC - $expected_subtags['EVEN'][] = 'DATE'; - $expected_subtags['EVEN'][] = 'PLAC'; - } - - if ($record->tree()->getPreference('FULL_SOURCES')) { - $expected_subtags['SOUR'][] = 'QUAY'; - - if ($record->tag() !== 'SOUR') { - //source citations within other records, i.e. n SOUR / +1 DATA / +2 DATE - $expected_subtags['DATA'][] = 'DATE'; - } //else: source records themselves, i.e. 0 SOUR / 1 DATA don't get a 2 DATE! - } - - if ($level1type === 'BAPL' || $level1type === 'CONL' || $level1type === 'ENDL' || $level1type === 'SLGC' || $level1type === 'SLGS') { - $expected_subtags['STAT'] = ['DATE']; - } - - if (in_array($level1type, Config::dateAndTime(), true)) { - // TIME is NOT a valid 5.5.1 tag - $expected_subtags['DATE'] = ['TIME']; - } - - if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $record->tree()->getPreference('ADVANCED_PLAC_FACTS'), $match)) { - $expected_subtags['PLAC'] = array_merge($match[1], $expected_subtags['PLAC']); - } - - $stack = []; - $gedlines = explode("\n", $fact->gedcom()); - $count = count($gedlines); - $i = 0; - $inSource = false; - $levelSource = 0; - $add_date = true; - - // Loop on existing tags : - while ($i < $count) { - $fields = explode(' ', $gedlines[$i], 3); - $level = (int) $fields[0]; - $type = $fields[1] ?? ''; - $text = $fields[2] ?? ''; - - // 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)); - - // Merge text from continuation lines - while ($i + 1 < $count && 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; - } - - self::$tags[] = $type; - $subrecord = $level . ' ' . $type . ' ' . $text; - - // Dates need different labels, depending on whether they are inside sources. - if ($inSource && $type === 'DATE') { - echo self::addSimpleTag($tree, $subrecord, '', GedcomTag::getLabel($label)); - } elseif (!$inSource && $type === 'DATE') { - echo self::addSimpleTag($tree, $subrecord, $level1type, GedcomTag::getLabel($label)); - if ($level === 2) { - // We already have a date - no need to add one. - $add_date = false; - } - } elseif ($type === 'STAT') { - echo self::addSimpleTag($tree, $subrecord, $level1type, GedcomTag::getLabel($label)); - } else { - echo self::addSimpleTag($tree, $subrecord, $level0type, GedcomTag::getLabel($label)); - } - - // Get a list of tags present at the next level - $subtags = []; - 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 - foreach ($expected_subtags[$type] ?? [] as $subtag) { - if (!in_array($subtag, $subtags, true)) { - echo self::addSimpleTag($tree, ($level + 1) . ' ' . $subtag, '', GedcomTag::getLabel($label . ':' . $subtag)); - foreach ($expected_subtags[$subtag] ?? [] as $subsubtag) { - echo self::addSimpleTag($tree, ($level + 2) . ' ' . $subsubtag, '', GedcomTag::getLabel($label . ':' . $subtag . ':' . $subsubtag)); - } - } - } - - $i++; - } - - if ($level1type !== '_PRIM') { - //0 SOUR / 1 DATA doesn't get a 2 DATE! - //0 SOUR / 1 DATA doesn't get a 2 EVEN here either, we rather handle this via cards/add-sour-data-even - if ($record->tag() !== 'SOUR') { - self::insertMissingSubtags($tree, $level1type, $add_date); - } - } - } - - /** - * Populates the global $tags array with any missing sub-tags. - * - * @param Tree $tree - * @param string $level1tag the type of the level 1 gedcom record - * @param bool $add_date - * - * @return void - */ - public static function insertMissingSubtags(Tree $tree, string $level1tag, bool $add_date = false): void - { - // handle MARRiage TYPE - $type_val = ''; - if (substr($level1tag, 0, 5) === 'MARR_') { - $type_val = ucfirst(strtolower(substr($level1tag, 5))); - $level1tag = 'MARR'; - } - - foreach (Config::levelTwoTags() as $key => $value) { - if ($key === 'DATE' && in_array($level1tag, Config::nonDateFacts(), true) || $key === 'PLAC' && in_array($level1tag, Config::nonPlaceFacts(), true)) { - continue; - } - if (in_array($level1tag, $value, true) && !in_array($key, self::$tags, true)) { - if ($key === 'TYPE') { - echo self::addSimpleTag($tree, '2 TYPE ' . $type_val, $level1tag); - } elseif ($level1tag === '_TODO' && $key === 'DATE') { - $today = strtoupper(date('d M Y')); - echo self::addSimpleTag($tree, '2 ' . $key . ' ' . $today, $level1tag); - } elseif ($level1tag === '_TODO' && $key === '_WT_USER') { - echo self::addSimpleTag($tree, '2 ' . $key . ' ' . Auth::user()->userName(), $level1tag); - } elseif ($level1tag === 'NAME' && str_contains($tree->getPreference('ADVANCED_NAME_FACTS'), $key)) { - echo self::addSimpleTag($tree, '2 ' . $key, $level1tag); - } elseif ($level1tag !== 'NAME') { - echo self::addSimpleTag($tree, '2 ' . $key, $level1tag); - } - // Add level 3/4 tags as appropriate - switch ($key) { - case 'PLAC': - if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('ADVANCED_PLAC_FACTS'), $match)) { - foreach ($match[1] as $tag) { - echo self::addSimpleTag($tree, '3 ' . $tag, '', GedcomTag::getLabel($level1tag . ':PLAC:' . $tag)); - } - } - echo self::addSimpleTag($tree, '3 MAP'); - echo self::addSimpleTag($tree, '4 LATI'); - echo self::addSimpleTag($tree, '4 LONG'); - break; - case 'EVEN': - echo self::addSimpleTag($tree, '3 DATE'); - echo self::addSimpleTag($tree, '3 PLAC'); - break; - case 'STAT': - if ($level1tag === 'BAPL' || $level1tag === 'CONL' || $level1tag === 'ENDL' || $level1tag === 'SLGC' || $level1tag === 'SLGS') { - echo self::addSimpleTag($tree, '3 DATE', '', GedcomTag::getLabel('STAT:DATE')); - } - break; - case 'DATE': - // TIME is NOT a valid 5.5.1 tag - if (in_array($level1tag, Config::dateAndTime(), true)) { - echo self::addSimpleTag($tree, '3 TIME'); - } - break; - case 'HUSB': - case 'WIFE': - echo self::addSimpleTag($tree, '3 AGE'); - break; - case 'FAMC': - if ($level1tag === 'ADOP') { - echo self::addSimpleTag($tree, '3 ADOP BOTH'); - } - break; - } - } elseif ($key === 'DATE' && $add_date) { - echo self::addSimpleTag($tree, '2 DATE', $level1tag, GedcomTag::getLabel($level1tag . ':DATE')); - } - } - // Do something (anything!) with unrecognized custom tags - if (substr($level1tag, 0, 1) === '_' && $level1tag !== '_UID' && $level1tag !== '_PRIM' && $level1tag !== '_TODO') { - foreach (['DATE', 'PLAC', 'ADDR', 'AGNC', 'TYPE', 'AGE'] as $tag) { - if (!in_array($tag, self::$tags, true)) { - echo self::addSimpleTag($tree, '2 ' . $tag); - if ($tag === 'PLAC') { - if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('ADVANCED_PLAC_FACTS'), $match)) { - foreach ($match[1] as $ptag) { - echo self::addSimpleTag($tree, '3 ' . $ptag, '', GedcomTag::getLabel($level1tag . ':PLAC:' . $ptag)); - } - } - echo self::addSimpleTag($tree, '3 MAP'); - echo self::addSimpleTag($tree, '4 LATI'); - echo self::addSimpleTag($tree, '4 LONG'); - } - } - } - } - } -} diff --git a/app/GedcomRecord.php b/app/GedcomRecord.php index 2dcbd8ef99..737b30a297 100644 --- a/app/GedcomRecord.php +++ b/app/GedcomRecord.php @@ -41,6 +41,7 @@ use function e; use function explode; use function implode; use function in_array; +use function max; use function md5; use function preg_match; use function preg_match_all; @@ -1352,7 +1353,11 @@ class GedcomRecord if ($default !== '') { $gedcom .= ' ' . $default; } - $return .= "\n" . $this->insertMissingLevels($tag . ':' . $subtag, $gedcom); + + $number_to_add = max(1, $min - $count); + $gedcom_to_add = "\n" . $this->insertMissingLevels($tag . ':' . $subtag, $gedcom); + + $return .= \str_repeat($gedcom_to_add, $number_to_add); } } diff --git a/app/GedcomTag.php b/app/GedcomTag.php index 8a5a11f697..882c3aff14 100644 --- a/app/GedcomTag.php +++ b/app/GedcomTag.php @@ -33,853 +33,9 @@ class GedcomTag * * @return string */ - public static function getLabel(string $tag): string + public static function getLabel($tag): string { - switch ($tag) { - case 'ABBR': - /* I18N: gedcom tag ABBR */ - return I18N::translate('Abbreviation'); - case 'ADDR': - /* I18N: gedcom tag ADDR */ - return I18N::translate('Address'); - case 'ADR1': - /* I18N: gedcom tag ADR1 */ - return I18N::translate('Address line 1'); - case 'ADR2': - /* I18N: gedcom tag ADR2 */ - return I18N::translate('Address line 2'); - case 'ADR3': - /* I18N: gedcom tag ADR3 */ - return I18N::translate('Address line 3'); - case 'ADOP': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag AFN */ - return I18N::translate('Ancestral file number'); - case 'AGE': - /* I18N: gedcom tag AGE */ - return I18N::translate('Age'); - case 'AGNC': - /* I18N: gedcom tag AGNC */ - return I18N::translate('Agency'); - case 'ALIA': - /* I18N: gedcom tag ALIA */ - return I18N::translate('Alias'); - case 'ANCE': - /* I18N: gedcom tag ANCE */ - return I18N::translate('Generations of ancestors'); - case 'ANCI': - /* I18N: gedcom tag ANCI */ - return I18N::translate('Ancestors interest'); - case 'ANUL': - /* I18N: gedcom tag ANUL */ - return I18N::translate('Annulment'); - case 'ASSO': - /* I18N: gedcom tag ASSO */ - return I18N::translate('Associate'); - case 'AUTH': - /* I18N: gedcom tag AUTH */ - return I18N::translate('Author'); - case 'BAPL': - /* I18N: gedcom tag BAPL. LDS = Church of Latter Day Saints. */ - return I18N::translate('LDS baptism'); - case 'BAPL:DATE': - /* I18N: LDS = Church of Latter Day Saints. */ - return I18N::translate('Date of LDS baptism'); - case 'BAPL:PLAC': - /* I18N: LDS = Church of Latter Day Saints. */ - return I18N::translate('Place of LDS baptism'); - case 'BAPM': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag BLOB */ - return I18N::translate('Binary data object'); - case 'BURI': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag CALN */ - return I18N::translate('Call number'); - case 'CAST': - /* I18N: gedcom tag CAST */ - return I18N::translate('Caste'); - case 'CAUS': - /* I18N: gedcom tag CAUS */ - return I18N::translate('Cause'); - case 'CEME': - /* I18N: gedcom tag CEME */ - return I18N::translate('Cemetery'); - case 'CENS': - /* I18N: gedcom tag CENS */ - return I18N::translate('Census'); - case 'CENS:DATE': - return I18N::translate('Census date'); - case 'CENS:PLAC': - return I18N::translate('Census place'); - case '_UPD': // Family Tree Builder uses "1 _UPD 14 APR 2012 00:14:10 GMT-5" instead of 1 CHAN/2 DATE/3 TIME - case 'CHAN': - /* I18N: gedcom tag CHAN */ - return I18N::translate('Last change'); - case 'CHAN:DATE': - /* I18N: gedcom tag CHAN:DATE */ - return I18N::translate('Date of last change'); - case 'CHAN:_WT_USER': - /* I18N: gedcom tag CHAN:_WT_USER */ - return I18N::translate('Author of last change'); - case 'CHAR': - /* I18N: gedcom tag CHAR */ - return I18N::translate('Character set'); - case 'CHIL': - /* I18N: gedcom tag CHIL */ - return I18N::translate('Child'); - case 'CHR': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag CHRA */ - return I18N::translate('Adult christening'); - case 'CITN': - /* I18N: gedcom tag CITN */ - return I18N::translate('Citizenship'); - case 'CITY': - /* I18N: gedcom tag CITY */ - return I18N::translate('City'); - case 'COMM': - /* I18N: gedcom tag COMM */ - return I18N::translate('Comment'); - case 'CONC': - /* I18N: gedcom tag CONC */ - return I18N::translate('Concatenation'); - case 'CONT': - /* I18N: gedcom tag CONT */ - return I18N::translate('Continued'); - case 'CONF': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag CONL. LDS = Church of Latter Day Saints. */ - return I18N::translate('LDS confirmation'); - case 'COPR': - /* I18N: gedcom tag COPR */ - return I18N::translate('Copyright'); - case 'CORP': - /* I18N: gedcom tag CORP */ - return I18N::translate('Corporation'); - case 'CREM': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag CTRY */ - return I18N::translate('Country'); - case 'DATA': - /* I18N: gedcom tag DATA */ - return I18N::translate('Data'); - case 'DATA:DATE': - return I18N::translate('Date of entry in original source'); - case '_DATE': // Family Tree Builder uses OBJE:_DATE - case 'DATE': - /* I18N: gedcom tag DATE */ - return I18N::translate('Date'); - case 'DEAT': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag DESC */ - return I18N::translate('Descendants'); - case 'DESI': - /* I18N: gedcom tag DESI */ - return I18N::translate('Descendants interest'); - case 'DEST': - /* I18N: gedcom tag DEST */ - return I18N::translate('Destination'); - case 'DIV': - /* I18N: gedcom tag DIV */ - return I18N::translate('Divorce'); - case 'DIVF': - /* I18N: gedcom tag DIVF */ - return I18N::translate('Divorce filed'); - case 'DSCR': - /* I18N: gedcom tag DSCR */ - return I18N::translate('Description'); - case 'EDUC': - /* I18N: gedcom tag EDUC */ - return I18N::translate('Education'); - case 'EDUC:AGNC': - return I18N::translate('School or college'); - case 'EMAI': - case 'EMAL': - case 'EMAIL': - /* I18N: gedcom tag EMAIL */ - return I18N::translate('Email address'); - case 'EMIG': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag ENDL. LDS = Church of Latter Day Saints. */ - return I18N::translate('LDS endowment'); - case 'ENDL:DATE': - /* I18N: LDS = Church of Latter Day Saints. */ - return I18N::translate('Date of LDS endowment'); - case 'ENDL:PLAC': - /* I18N: LDS = Church of Latter Day Saints. */ - return I18N::translate('Place of LDS endowment'); - case 'ENGA': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag EVEN */ - return I18N::translate('Event'); - case 'EVEN:DATE': - return I18N::translate('Date of event'); - case 'EVEN:PLAC': - return I18N::translate('Place of event'); - case 'EVEN:TYPE': - return I18N::translate('Type of event'); - case 'FACT': - /* I18N: gedcom tag FACT */ - return I18N::translate('Fact'); - case 'FACT:TYPE': - return I18N::translate('Type of fact'); - case 'FAM': - /* I18N: gedcom tag FAM */ - return I18N::translate('Family'); - case 'FAMC': - /* I18N: gedcom tag FAMC */ - return I18N::translate('Family as a child'); - case 'FAMF': - /* I18N: gedcom tag FAMF */ - return I18N::translate('Family file'); - case 'FAMS': - /* I18N: gedcom tag FAMS */ - return I18N::translate('Family as a spouse'); - case 'FAX': - /* I18N: gedcom tag FAX */ - return I18N::translate('Fax'); - case 'FCOM': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag FILE */ - return I18N::translate('Filename'); - case 'FONE': - /* I18N: gedcom tag FONE */ - return I18N::translate('Phonetic'); - case 'FORM': - /* I18N: gedcom tag FORM */ - return I18N::translate('Format'); - case 'GEDC': - /* I18N: gedcom tag GEDC */ - return I18N::translate('GEDCOM file'); - case 'GIVN': - /* I18N: gedcom tag GIVN */ - return I18N::translate('Given names'); - case 'GRAD': - /* I18N: gedcom tag GRAD */ - return I18N::translate('Graduation'); - case 'HEAD': - /* I18N: gedcom tag HEAD */ - return I18N::translate('Header'); - case 'HUSB': - /* I18N: gedcom tag HUSB */ - return I18N::translate('Husband'); - case 'IDNO': - /* I18N: gedcom tag IDNO */ - return I18N::translate('Identification number'); - case 'IMMI': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag INDI */ - return I18N::translate('Individual'); - case 'INFL': - /* I18N: gedcom tag INFL */ - return I18N::translate('Infant'); - case 'LANG': - /* I18N: gedcom tag LANG */ - return I18N::translate('Language'); - case 'LATI': - /* I18N: gedcom tag LATI */ - return I18N::translate('Latitude'); - case 'LEGA': - /* I18N: gedcom tag LEGA */ - return I18N::translate('Legatee'); - case 'LONG': - /* I18N: gedcom tag LONG */ - return I18N::translate('Longitude'); - case 'MAP': - /* I18N: gedcom tag MAP */ - return I18N::translate('Coordinates'); - case 'MARB': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag MARC */ - return I18N::translate('Marriage contract'); - case 'MARL': - /* I18N: gedcom tag MARL */ - return I18N::translate('Marriage license'); - case 'MARR': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag MARS */ - return I18N::translate('Marriage settlement'); - case 'MEDI': - /* I18N: gedcom tag MEDI */ - return I18N::translate('Media type'); - case 'NAME': - /* I18N: gedcom tag NAME */ - return I18N::translate('Name'); - case 'NAME:FONE': - return I18N::translate('Phonetic name'); - case 'NAME:_HEB': - return I18N::translate('Name in Hebrew'); - case 'NATI': - /* I18N: gedcom tag NATI */ - return I18N::translate('Nationality'); - case 'NATU': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag NCHI */ - return I18N::translate('Number of children'); - case 'NICK': - /* I18N: gedcom tag NICK */ - return I18N::translate('Nickname'); - case 'NMR': - /* I18N: gedcom tag NMR */ - return I18N::translate('Number of marriages'); - case 'NOTE': - /* I18N: gedcom tag NOTE */ - return I18N::translate('Note'); - case 'NPFX': - /* I18N: gedcom tag NPFX */ - return I18N::translate('Name prefix'); - case 'NSFX': - /* I18N: gedcom tag NSFX */ - return I18N::translate('Name suffix'); - case 'OBJE': - /* I18N: gedcom tag OBJE */ - return I18N::translate('Media object'); - case 'OCCU': - /* I18N: gedcom tag OCCU */ - return I18N::translate('Occupation'); - case 'OCCU:AGNC': - return I18N::translate('Employer'); - case 'ORDI': - /* I18N: gedcom tag ORDI */ - return I18N::translate('Ordinance'); - case 'ORDN': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag PAGE */ - return I18N::translate('Citation details'); - case 'PEDI': - /* I18N: gedcom tag PEDI */ - return I18N::translate('Relationship to parents'); - case 'PHON': - /* I18N: gedcom tag PHON */ - return I18N::translate('Phone'); - case '_PLACE': // Family Tree Builder uses OBJE:_PLACE - case 'PLAC': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag POST */ - return I18N::translate('Postal code'); - case 'PROB': - /* I18N: gedcom tag PROB */ - return I18N::translate('Probate'); - case 'PROP': - /* I18N: gedcom tag PROP */ - return I18N::translate('Property'); - case 'PUBL': - /* I18N: gedcom tag PUBL */ - return I18N::translate('Publication'); - case 'QUAY': - /* I18N: gedcom tag QUAY */ - return I18N::translate('Quality of data'); - case 'REFN': - /* I18N: gedcom tag REFN */ - return I18N::translate('Reference number'); - case 'RELA': - /* I18N: gedcom tag RELA */ - return I18N::translate('Relationship'); - case 'RELI': - /* I18N: gedcom tag RELI */ - return I18N::translate('Religion'); - case 'REPO': - /* I18N: gedcom tag REPO */ - return I18N::translate('Repository'); - case 'REPO:NAME': - return I18N::translateContext('Repository', 'Name'); - case 'RESI': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag RESN */ - return I18N::translate('Restriction'); - case 'RETI': - /* I18N: gedcom tag RETI */ - return I18N::translate('Retirement'); - case 'RETI:AGNC': - return I18N::translate('Employer'); - case 'RFN': - /* I18N: gedcom tag RFN */ - return I18N::translate('Record file number'); - case '_PHOTO_RIN': - // Family Tree Builder uses "0 OBJE/1 _PHOTO_RIN" - // no break - case '_PRIN':// Family Tree Builder uses "0 _ALBUM/1 _PHOTO/2 _PRIN" - case 'RIN': - /* I18N: gedcom tag RIN */ - return I18N::translate('Record ID number'); - case 'ROLE': - /* I18N: gedcom tag ROLE */ - return I18N::translate('Role'); - case 'ROMN': - /* I18N: gedcom tag ROMN */ - return I18N::translate('Romanized'); - case 'SERV': - /* I18N: gedcom tag SERV */ - return I18N::translate('Remote server'); - case 'SEX': - /* I18N: gedcom tag SEX */ - return I18N::translate('Gender'); - case 'SHARED_NOTE': - return I18N::translate('Shared note'); - case 'SLGC': - /* I18N: gedcom tag SLGC. LDS = Church of Latter Day Saints. */ - return I18N::translate('LDS child sealing'); - case 'SLGC:DATE': - /* I18N: LDS = Church of Latter Day Saints. */ - return I18N::translate('Date of LDS child sealing'); - case 'SLGC:PLAC': - /* I18N: LDS = Church of Latter Day Saints. */ - return I18N::translate('Place of LDS child sealing'); - case 'SLGS': - /* I18N: gedcom tag SLGS. LDS = Church of Latter Day Saints. */ - return I18N::translate('LDS spouse sealing'); - case 'SOUR': - /* I18N: gedcom tag SOUR */ - return I18N::translate('Source'); - case 'SPFX': - /* I18N: gedcom tag SPFX */ - return I18N::translate('Surname prefix'); - case 'SSN': - /* I18N: gedcom tag SSN */ - return I18N::translate('Social security number'); - case 'STAE': - /* I18N: gedcom tag STAE */ - return I18N::translate('State'); - case 'STAT': - /* I18N: gedcom tag STAT */ - return I18N::translate('Status'); - case 'STAT:DATE': - return I18N::translate('Status change date'); - case 'SUBM': - /* I18N: gedcom tag SUBM */ - return I18N::translate('Submitter'); - case 'SUBN': - /* I18N: gedcom tag SUBN */ - return I18N::translate('Submission'); - case 'SURN': - /* I18N: gedcom tag SURN */ - return I18N::translate('Surname'); - case 'TEMP': - /* I18N: gedcom tag TEMP */ - return I18N::translate('Temple'); - case 'TEXT': - /* I18N: gedcom tag TEXT */ - return I18N::translate('Text'); - case 'TIME': - /* I18N: gedcom tag TIME */ - return I18N::translate('Time'); - case 'TITL': - /* I18N: gedcom tag 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': - /* I18N: gedcom tag TRLR */ - return I18N::translate('Trailer'); - case 'TYPE': - /* I18N: gedcom tag TYPE */ - return I18N::translate('Type'); - case 'URL': - /* I18N: gedcom tag URL (A web address / URL) */ - return I18N::translate('URL'); - case 'VERS': - /* I18N: gedcom tag VERS */ - return I18N::translate('Version'); - case 'WIFE': - /* I18N: gedcom tag WIFE */ - return I18N::translate('Wife'); - case 'WILL': - /* I18N: gedcom tag WILL */ - return I18N::translate('Will'); - case 'WWW': - /* I18N: gedcom tag WWW (A web address / URL) */ - return I18N::translate('URL'); - - case '_ADPF': - /* I18N: gedcom tag _ADPF */ - return I18N::translate('Adopted by father'); - - case '_ADPM': - /* I18N: gedcom tag _ADPM */ - return I18N::translate('Adopted by mother'); - - case '_AKA': - case '_AKAN': - /* I18N: gedcom tag _AKA */ - return I18N::translate('Also known as'); - - case '_ALBUM': - // Family Tree Builder uses OBJE:_ALBUM - /* I18N: gedcom tag _ALBUM */ - return I18N::translate('Album'); - case '_ASSO': - /* I18N: gedcom tag _ASSO */ - return I18N::translate('Associate'); - - case '_BIBL': - /* I18N: gedcom tag _BIBL */ - return I18N::translate('Bibliography'); - - case '_BRTM': - /* I18N: gedcom tag _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 '_COML': - /* I18N: gedcom tag _COML */ - return I18N::translate('Common law marriage'); - - case '_DBID': - /* I18N: gedcom tag _DBID */ - return I18N::translate('Linked database ID'); - - case '_DEG': - /* I18N: gedcom tag _DEG */ - return I18N::translate('Degree'); - case '_DETS': - /* I18N: gedcom tag _DETS */ - return I18N::translate('Death of one spouse'); - case '_DNA': - /* I18N: gedcom tag _DNA (from FTM 2010) */ - return I18N::translate('DNA markers'); - case '_EMAIL': - /* I18N: gedcom tag _EMAIL */ - return I18N::translate('Email address'); - case '_EYEC': - /* I18N: gedcom tag _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': - /* I18N: gedcom tag _FNRL */ - return I18N::translate('Funeral'); - case '_FREL': - /* I18N: gedcom tag _FREL */ - return I18N::translate('Relationship to father'); - case '_GEDF': - /* I18N: gedcom tag _GEDF */ - return I18N::translate('GEDCOM file'); - case '_GODP': - /* I18N: gedcom tag _GODP */ - return I18N::translate('Godparent'); - case '_GOV': - /* I18N: gedcom tag _GOV - see https://gov.genealogy.net */ - return I18N::translate('GOV identifier'); - case '_HAIR': - /* I18N: gedcom tag _HAIR */ - return I18N::translate('Hair color'); - case '_HEB': - /* I18N: gedcom tag _HEB */ - return I18N::translate('Hebrew'); - case '_HEIG': - /* I18N: gedcom tag _HEIG */ - return I18N::translate('Height'); - case '_HNM': - /* I18N: gedcom tag _HNM */ - return I18N::translate('Hebrew name'); - case '_HOL': - /* I18N: gedcom tag _HOL */ - return I18N::translate('Holocaust'); - - case '_INTE': - /* I18N: gedcom tag _INTE */ - return I18N::translate('Interment'); - - case '_LOC': - /* I18N: gedcom tag _LOC */ - return I18N::translate('Location'); - case '_MARI': - /* I18N: gedcom tag _MARI */ - return I18N::translate('Marriage intention'); - case '_MARNM': - /* I18N: gedcom tag _MARNM */ - return I18N::translate('Married name'); - case '_PRIM': - /* I18N: gedcom tag _PRIM */ - return I18N::translate('Highlighted image'); - case '_MARNM_SURN': - return I18N::translate('Married surname'); - - case '_MBON': - /* I18N: gedcom tag _MBON */ - return I18N::translate('Marriage bond'); - case '_MDCL': - /* I18N: gedcom tag _MDCL */ - return I18N::translate('Medical'); - case '_MEDC': - /* I18N: gedcom tag _MEDC */ - return I18N::translate('Medical condition'); - case '_MEND': - /* I18N: gedcom tag _MEND */ - return I18N::translate('Marriage ending status'); - case '_MILI': - /* I18N: gedcom tag _MILI */ - return I18N::translate('Military'); - case '_MILT': - /* I18N: gedcom tag _MILT */ - return I18N::translate('Military service'); - case '_MREL': - /* I18N: gedcom tag _MREL */ - return I18N::translate('Relationship to mother'); - case '_MSTAT': - /* I18N: gedcom tag _MSTAT */ - return I18N::translate('Marriage beginning status'); - case '_NAME': - /* I18N: gedcom tag _NAME */ - return I18N::translate('Mailing name'); - case '_NAMS': - /* I18N: gedcom tag _NAMS */ - return I18N::translate('Namesake'); - case '_NLIV': - /* I18N: gedcom tag _NLIV */ - return I18N::translate('Not living'); - case '_NMAR': - /* I18N: gedcom tag _NMAR */ - return I18N::translate('Never married'); - - case '_NMR': - /* I18N: gedcom tag _NMR */ - return I18N::translate('Not married'); - - case '_PHOTO': - // Family Tree Builder uses "0 _ALBUM/1_PHOTO" - return I18N::translate('Photo'); - case '_WT_USER': - return I18N::translate('by'); - case '_PRMN': - /* I18N: gedcom tag _PRMN */ - return I18N::translate('Permanent number'); - case '_RNAME': - return I18N::translate('Religious name'); - - case '_SCBK': - /* I18N: gedcom tag _SCBK */ - return I18N::translate('Scrapbook'); - case '_SEPR': - /* I18N: gedcom tag _SEPR */ - return I18N::translate('Separation'); - case '_SSHOW': - /* I18N: gedcom tag _SSHOW */ - return I18N::translate('Slide show'); - case '_STAT': - /* I18N: gedcom tag _STAT */ - return I18N::translate('Marriage status'); - case '_SUBQ': - /* I18N: gedcom tag _SUBQ */ - return I18N::translate('Short version'); - case '_TODO': - /* I18N: gedcom tag _TODO */ - return I18N::translate('Research task'); - case '_TYPE': - /* I18N: gedcom tag _TYPE */ - return I18N::translate('Media type'); - case '_UID': - /* I18N: gedcom tag _UID */ - return I18N::translate('Unique identifier'); - case '_URL': - /* I18N: gedcom tag _URL */ - return I18N::translate('URL'); - case '_WEIG': - /* I18N: gedcom tag _WEIG */ - return I18N::translate('Weight'); - case '_WITN': - /* I18N: gedcom tag _WITN */ - return I18N::translate('Witness'); - case '_WT_OBJE_SORT': - /* I18N: gedcom tag _WT_OBJE_SORT */ - return I18N::translate('Re-order media'); - case '_YART': - /* I18N: gedcom tag _YART - A yahrzeit is a special anniversary of death in the Hebrew faith/calendar. */ - return I18N::translate('Yahrzeit'); - case '_FILESIZE': // Family Tree Builder uses OBJE:_FILESIZE - case '__FILE_SIZE__': - // This pseudo-tag is generated internally to present information about a media object - return I18N::translate('File size'); - case '__IMAGE_SIZE__': - // This pseudo-tag is generated internally to present information about a media object - return I18N::translate('Image dimensions'); - default: - // If no specialisation exists (e.g. DEAT:CAUS), then look for the general (CAUS) - if (str_contains($tag, ':')) { - [, $tag] = explode(':', $tag, 2); - - return self::getLabel($tag); - } - - // Still no translation? Highlight this as an error - return '<span class="error" title="' . I18N::translate('Unrecognized GEDCOM code') . '">' . e($tag) . '</span>'; - } + return Registry::elementFactory()->make($tag)->label(); } /** diff --git a/app/Http/RequestHandlers/AddChildToFamilyAction.php b/app/Http/RequestHandlers/AddChildToFamilyAction.php index da916d5eb0..76afb028c9 100644 --- a/app/Http/RequestHandlers/AddChildToFamilyAction.php +++ b/app/Http/RequestHandlers/AddChildToFamilyAction.php @@ -30,7 +30,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; -use function preg_match_all; +use function is_string; use function redirect; /** @@ -61,78 +61,25 @@ class AddChildToFamilyAction implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; - - $family = Registry::familyFactory()->make($xref, $tree); - $family = Auth::checkFamilyAccess($family, true); + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); $params = (array) $request->getParsedBody(); - $PEDI = $params['PEDI']; - $keep_chan = (bool) ($params['keep_chan'] ?? false); - - $this->gedcom_edit_service->glevels = $params['glevels'] ?? []; - $this->gedcom_edit_service->tag = $params['tag'] ?? []; - $this->gedcom_edit_service->text = $params['text'] ?? []; - $this->gedcom_edit_service->islink = $params['islink'] ?? []; - - $this->gedcom_edit_service->splitSource(); - $gedrec = '0 @@ INDI'; - $gedrec .= $this->gedcom_edit_service->addNewName($request, $tree); - $gedrec .= $this->gedcom_edit_service->addNewSex($request); - if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches)) { - foreach ($matches[1] as $match) { - $gedrec .= $this->gedcom_edit_service->addNewFact($request, $tree, $match); - } - } - - switch ($PEDI) { - case '': - $gedrec .= "\n1 FAMC @$xref@"; - break; - case 'adopted': - $gedrec .= "\n1 FAMC @$xref@\n2 PEDI $PEDI\n1 ADOP\n2 FAMC @$xref@\n3 ADOP BOTH"; - break; - case 'sealing': - $gedrec .= "\n1 FAMC @$xref@\n2 PEDI $PEDI\n1 SLGC\n2 FAMC @$xref@"; - break; - case 'foster': - $gedrec .= "\n1 FAMC @$xref@\n2 PEDI $PEDI\n1 EVEN\n2 TYPE $PEDI"; - break; - default: - $gedrec .= "\n1 FAMC @$xref@\n2 PEDI $PEDI"; - break; - } + $family = Registry::familyFactory()->make($xref, $tree); + $family = Auth::checkFamilyAccess($family, true); - if ($params['SOUR_INDI'] ?? false) { - $gedrec = $this->gedcom_edit_service->handleUpdates($gedrec); - } else { - $gedrec = $this->gedcom_edit_service->updateRest($gedrec); - } + $levels = $params['ilevels'] ?? []; + $tags = $params['itags'] ?? []; + $values = $params['ivalues'] ?? []; // Create the new child - $new_child = $tree->createIndividual($gedrec); - - // Insert new child at the right place - $done = false; - foreach ($family->facts(['CHIL']) as $fact) { - $old_child = $fact->target(); - if ($old_child instanceof Individual && Date::compare($new_child->getEstimatedBirthDate(), $old_child->getEstimatedBirthDate()) < 0) { - // Insert before this child - $family->updateFact($fact->id(), '1 CHIL @' . $new_child->xref() . "@\n" . $fact->gedcom(), !$keep_chan); - $done = true; - break; - } - } - if (!$done) { - // Append child at end - $family->createFact('1 CHIL @' . $new_child->xref() . '@', !$keep_chan); - } + $gedcom = "0 @@ INDI\n1 FAMC @" . $xref . "@\n" . $this->gedcom_edit_service->editLinesToGedcom('INDI', $levels, $tags, $values); + $child = $tree->createIndividual($gedcom); - if (($params['goto'] ?? '') === 'new') { - return redirect($new_child->url()); - } + // Link the child to the family + $family->createFact('1 CHIL @' . $child->xref() . '@', false); - return redirect($family->url()); + return redirect($params['url'] ?? $child->url()); } } diff --git a/app/Http/RequestHandlers/AddChildToFamilyPage.php b/app/Http/RequestHandlers/AddChildToFamilyPage.php index ccca8d1c3e..f1eb504726 100644 --- a/app/Http/RequestHandlers/AddChildToFamilyPage.php +++ b/app/Http/RequestHandlers/AddChildToFamilyPage.php @@ -20,6 +20,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; +use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Registry; @@ -29,6 +30,8 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function is_string; +use function route; /** * Add a new child to a family. @@ -47,32 +50,42 @@ class AddChildToFamilyPage implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); + + $sex = $request->getAttribute('sex'); + assert(is_string($sex)); $family = Registry::familyFactory()->make($xref, $tree); $family = Auth::checkFamilyAccess($family, true); - $gender = $request->getQueryParams()['gender']; + // Create a dummy individual, so that we can create new/empty facts. + $element = Registry::elementFactory()->make('INDI:NAME'); + $dummy = Registry::individualFactory()->new('', '0 @@ INDI', null, $tree); + $facts = [ + 'i' => [ + new Fact('1 SEX ' . $sex, $dummy, ''), + new Fact('1 NAME ' . $element->default($tree), $dummy, ''), + new Fact('1 BIRT', $dummy, ''), + new Fact('1 DEAT', $dummy, ''), + ], + ]; - $subtitles = [ + $titles = [ 'M' => I18N::translate('Add a son'), 'F' => I18N::translate('Add a daughter'), 'U' => I18N::translate('Add a child'), ]; - $subtitle = $subtitles[$gender] ?? $subtitles['U']; - - $title = $family->fullName() . ' - ' . $subtitle; + $title = $titles[$sex] ?? $titles['U']; return $this->viewResponse('edit/new-individual', [ - 'next_action' => AddChildToFamilyAction::class, - 'tree' => $tree, - 'title' => $title, - 'individual' => null, - 'family' => $family, - 'name_fact' => null, - 'famtag' => 'CHIL', - 'gender' => $gender, + 'cancel_url' => $family->url(), + 'facts' => $facts, + 'post_url' => route(AddChildToFamilyAction::class, ['tree' => $tree->name(), 'xref' => $xref]), + 'title' => $family->fullName() . ' - ' . $title, + 'tree' => $tree, + 'url' => $request->getQueryParams()['url'] ?? $family->url(), ]); } } diff --git a/app/Http/RequestHandlers/AddChildToIndividualAction.php b/app/Http/RequestHandlers/AddChildToIndividualAction.php index 2d87d950ac..016367a58e 100644 --- a/app/Http/RequestHandlers/AddChildToIndividualAction.php +++ b/app/Http/RequestHandlers/AddChildToIndividualAction.php @@ -28,7 +28,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; -use function preg_match_all; +use function is_string; use function redirect; /** @@ -59,77 +59,33 @@ class AddChildToIndividualAction implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); + + $params = (array) $request->getParsedBody(); $individual = Registry::individualFactory()->make($xref, $tree); $individual = Auth::checkIndividualAccess($individual, true); - $params = (array) $request->getParsedBody(); + $levels = $params['ilevels'] ?? []; + $tags = $params['itags'] ?? []; + $values = $params['ivalues'] ?? []; - $PEDI = $params['PEDI']; + // Create the new child + $gedcom = "0 @@ INDI\n" . $this->gedcom_edit_service->editLinesToGedcom('INDI', $levels, $tags, $values); + $child = $tree->createIndividual($gedcom); - $this->gedcom_edit_service->glevels = $params['glevels'] ?? []; - $this->gedcom_edit_service->tag = $params['tag'] ?? []; - $this->gedcom_edit_service->text = $params['text'] ?? []; - $this->gedcom_edit_service->islink = $params['islink'] ?? []; - - // Create a family - if ($individual->sex() === 'F') { - $gedcom = "0 @@ FAM\n1 WIFE @" . $individual->xref() . '@'; - } else { - $gedcom = "0 @@ FAM\n1 HUSB @" . $individual->xref() . '@'; - } + // Create a new family + $link = $child->sex() === 'F' ? 'WIFE' : 'HUSB'; + $gedcom = "0 @@ FAM\n1 " . $link . " @" . $individual->xref() . "@\n1 CHIL @" . $child->xref() . '@'; $family = $tree->createFamily($gedcom); - // Link the parent to the family - $individual->createFact('1 FAMS @' . $family->xref() . '@', true); - - // Create a child - $this->gedcom_edit_service->splitSource(); // separate SOUR record from the rest - - $gedcom = '0 @@ INDI'; - $gedcom .= $this->gedcom_edit_service->addNewName($request, $tree); - $gedcom .= $this->gedcom_edit_service->addNewSex($request); - - $fam_xref = $family->xref(); - switch ($PEDI) { - case '': - $gedcom .= "\n1 FAMC @$fam_xref@"; - break; - case 'adopted': - $gedcom .= "\n1 FAMC @$fam_xref@\n2 PEDI $PEDI\n1 ADOP\n2 FAMC @$fam_xref@\n3 ADOP BOTH"; - break; - case 'sealing': - $gedcom .= "\n1 FAMC @$fam_xref@\n2 PEDI $PEDI\n1 SLGC\n2 FAMC @$fam_xref@"; - break; - case 'foster': - $gedcom .= "\n1 FAMC @$fam_xref@\n2 PEDI $PEDI\n1 EVEN\n2 TYPE $PEDI"; - break; - default: - $gedcom .= "\n1 FAMC @$fam_xref@\n2 PEDI $PEDI"; - break; - } - - if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches)) { - foreach ($matches[1] as $match) { - $gedcom .= $this->gedcom_edit_service->addNewFact($request, $tree, $match); - } - } - if ($params['SOUR_INDI'] ?? false) { - $gedcom = $this->gedcom_edit_service->handleUpdates($gedcom); - } else { - $gedcom = $this->gedcom_edit_service->updateRest($gedcom); - } - - $child = $tree->createIndividual($gedcom); - - // Link the family to the child - $family->createFact('1 CHIL @' . $child->xref() . '@', true); + // Link the individual to the family + $individual->createFact('1 FAMS @' . $family->xref() . '@', false); - if (($params['goto'] ?? '') === 'new') { - return redirect($child->url()); - } + // Link the child to the family + $child->createFact('1 FAMC @' . $family->xref() . '@', false); - return redirect($individual->url()); + return redirect($params['url'] ?? $child->url()); } } diff --git a/app/Http/RequestHandlers/AddChildToIndividualPage.php b/app/Http/RequestHandlers/AddChildToIndividualPage.php index 4f0512fe64..662d165b87 100644 --- a/app/Http/RequestHandlers/AddChildToIndividualPage.php +++ b/app/Http/RequestHandlers/AddChildToIndividualPage.php @@ -20,6 +20,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; +use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Registry; @@ -29,6 +30,8 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function is_string; +use function route; /** * Add a new child to an individual, creating a one-parent family. @@ -47,22 +50,33 @@ class AddChildToIndividualPage implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); $individual = Registry::individualFactory()->make($xref, $tree); $individual = Auth::checkIndividualAccess($individual, true); - $title = $individual->fullName() . ' - ' . I18N::translate('Add a child to create a one-parent family'); + // Create a dummy individual, so that we can create new/empty facts. + $element = Registry::elementFactory()->make('INDI:NAME'); + $dummy = Registry::individualFactory()->new('', '0 @@ INDI', null, $tree); + $facts = [ + 'i' => [ + new Fact('1 SEX ', $dummy, ''), + new Fact('1 NAME ' . $element->default($tree), $dummy, ''), + new Fact('1 BIRT', $dummy, ''), + new Fact('1 DEAT', $dummy, ''), + ], + ]; + + $title = I18N::translate('Add a child to create a one-parent family'); return $this->viewResponse('edit/new-individual', [ - 'next_action' => AddChildToIndividualAction::class, - 'tree' => $tree, - 'title' => $title, - 'individual' => $individual, - 'family' => null, - 'name_fact' => null, - 'famtag' => 'CHIL', - 'gender' => 'U', + 'cancel_url' => $individual->url(), + 'facts' => $facts, + 'post_url' => route(AddChildToIndividualAction::class, ['tree' => $tree->name(), 'xref' => $xref]), + 'title' => $individual->fullName() . ' - ' . $title, + 'tree' => $tree, + 'url' => $request->getQueryParams()['url'] ?? $individual->url(), ]); } } diff --git a/app/Http/RequestHandlers/AddName.php b/app/Http/RequestHandlers/AddName.php deleted file mode 100644 index 03cada10fc..0000000000 --- a/app/Http/RequestHandlers/AddName.php +++ /dev/null @@ -1,68 +0,0 @@ -<?php - -/** - * webtrees: online genealogy - * Copyright (C) 2021 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 <https://www.gnu.org/licenses/>. - */ - -declare(strict_types=1); - -namespace Fisharebest\Webtrees\Http\RequestHandlers; - -use Fisharebest\Webtrees\Auth; -use Fisharebest\Webtrees\Http\ViewResponseTrait; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Registry; -use Fisharebest\Webtrees\Tree; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; - -use function assert; - -/** - * Add a new individual name. - */ -class AddName implements RequestHandlerInterface -{ - use ViewResponseTrait; - - /** - * @param ServerRequestInterface $request - * - * @return ResponseInterface - */ - public function handle(ServerRequestInterface $request): ResponseInterface - { - $tree = $request->getAttribute('tree'); - assert($tree instanceof Tree); - - $xref = $request->getQueryParams()['xref']; - - $individual = Registry::individualFactory()->make($xref, $tree); - $individual = Auth::checkIndividualAccess($individual, true); - - $title = $individual->fullName() . ' — ' . I18N::translate('Add a name'); - - return $this->viewResponse('edit/new-individual', [ - 'next_action' => EditFactAction::class, - 'tree' => $tree, - 'title' => $title, - 'individual' => $individual, - 'family' => null, - 'name_fact' => null, - 'famtag' => '', - 'gender' => $individual->sex(), - ]); - } -} diff --git a/app/Http/RequestHandlers/AddNewFact.php b/app/Http/RequestHandlers/AddNewFact.php index 2576d63aed..ad3099ffa6 100644 --- a/app/Http/RequestHandlers/AddNewFact.php +++ b/app/Http/RequestHandlers/AddNewFact.php @@ -20,6 +20,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; +use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\Tree; @@ -29,6 +30,7 @@ use Psr\Http\Server\RequestHandlerInterface; use function assert; use function is_string; +use function trim; /** * Add a new fact. @@ -50,20 +52,19 @@ class AddNewFact implements RequestHandlerInterface $xref = $request->getAttribute('xref'); assert(is_string($xref)); - $fact = $request->getAttribute('fact'); + $subtag = $request->getAttribute('fact'); + $record = Registry::gedcomRecordFactory()->make($xref, $tree); + $record = Auth::checkRecordAccess($record, true); + $element = Registry::elementFactory()->make($record->tag() . ':' . $subtag); + $title = $record->fullName() . ' - ' . $element->label(); + $fact = new Fact(trim('1 ' . $subtag . ' ' . $element->default($tree)), $record, 'new'); - $record = Registry::gedcomRecordFactory()->make($xref, $tree); - $record = Auth::checkRecordAccess($record, true); - - $element = Registry::elementFactory()->make($record->tag() . ':' . $fact); - - $title = $record->fullName() . ' - ' . $element->label(); - - return $this->viewResponse('edit/add-fact', [ - 'fact' => $fact, - 'record' => $record, - 'title' => $title, - 'tree' => $tree, + return $this->viewResponse('edit/edit-fact', [ + 'can_edit_raw' => false, + 'fact' => $fact, + 'title' => $title, + 'tree' => $tree, + 'url' => $record->url(), ]); } } diff --git a/app/Http/RequestHandlers/AddParentToIndividualAction.php b/app/Http/RequestHandlers/AddParentToIndividualAction.php index 1c22a4ea51..8a2f2100d4 100644 --- a/app/Http/RequestHandlers/AddParentToIndividualAction.php +++ b/app/Http/RequestHandlers/AddParentToIndividualAction.php @@ -28,7 +28,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; -use function preg_match_all; +use function is_string; use function redirect; /** @@ -59,56 +59,33 @@ class AddParentToIndividualAction implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); + + $params = (array) $request->getParsedBody(); $individual = Registry::individualFactory()->make($xref, $tree); $individual = Auth::checkIndividualAccess($individual, true); - $params = (array) $request->getParsedBody(); + $levels = $params['ilevels'] ?? []; + $tags = $params['itags'] ?? []; + $values = $params['ivalues'] ?? []; - $this->gedcom_edit_service->glevels = $params['glevels'] ?? []; - $this->gedcom_edit_service->tag = $params['tag'] ?? []; - $this->gedcom_edit_service->text = $params['text'] ?? []; - $this->gedcom_edit_service->islink = $params['islink'] ?? []; + // Create the new parent + $gedcom = "0 @@ INDI\n" . $this->gedcom_edit_service->editLinesToGedcom('INDI', $levels, $tags, $values); + $parent = $tree->createIndividual($gedcom); // Create a new family - $gedcom = "0 @@ FAM\n1 CHIL @" . $individual->xref() . '@'; + $link = $parent->sex() === 'F' ? 'WIFE' : 'HUSB'; + $gedcom = "0 @@ FAM\n1 CHIL @" . $individual->xref() . "@\n1 " . $link . ' @' . $parent->xref() . '@'; $family = $tree->createFamily($gedcom); - // Link the child to the family - $individual->createFact('1 FAMC @' . $family->xref() . '@', true); - - // Create a child - $this->gedcom_edit_service->splitSource(); // separate SOUR record from the rest - - $gedcom = '0 @@ INDI'; - $gedcom .= $this->gedcom_edit_service->addNewName($request, $tree); - $gedcom .= $this->gedcom_edit_service->addNewSex($request); - if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches)) { - foreach ($matches[1] as $match) { - $gedcom .= $this->gedcom_edit_service->addNewFact($request, $tree, $match); - } - } - if ($params['SOUR_INDI'] ?? false) { - $gedcom = $this->gedcom_edit_service->handleUpdates($gedcom); - } else { - $gedcom = $this->gedcom_edit_service->updateRest($gedcom); - } - $gedcom .= "\n1 FAMS @" . $family->xref() . '@'; - - $parent = $tree->createIndividual($gedcom); - - // Link the family to the child - if ($parent->sex() === 'F') { - $family->createFact('1 WIFE @' . $parent->xref() . '@', true); - } else { - $family->createFact('1 HUSB @' . $parent->xref() . '@', true); - } + // Link the individual to the family + $individual->createFact('1 FAMC @' . $family->xref() . '@', false); - if (($params['goto'] ?? '') === 'new') { - return redirect($parent->url()); - } + // Link the parent to the family + $parent->createFact('1 FAMS @' . $family->xref() . '@', false); - return redirect($individual->url()); + return redirect($params['url'] ?? $parent->url()); } } diff --git a/app/Http/RequestHandlers/AddParentToIndividualPage.php b/app/Http/RequestHandlers/AddParentToIndividualPage.php index 35d55a6b4d..d44f29ebea 100644 --- a/app/Http/RequestHandlers/AddParentToIndividualPage.php +++ b/app/Http/RequestHandlers/AddParentToIndividualPage.php @@ -20,6 +20,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; +use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Registry; @@ -29,6 +30,8 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function is_string; +use function route; /** * Add a new parent to an individual, creating a one-parent family. @@ -47,30 +50,40 @@ class AddParentToIndividualPage implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); + + $sex = $request->getAttribute('sex'); + assert(is_string($xref)); $individual = Registry::individualFactory()->make($xref, $tree); $individual = Auth::checkIndividualAccess($individual, true); - $gender = $request->getQueryParams()['gender']; + // Create a dummy individual, so that we can create new/empty facts. + $element = Registry::elementFactory()->make('INDI:NAME'); + $dummy = Registry::individualFactory()->new('', '0 @@ INDI', null, $tree); + $facts = [ + 'i' => [ + new Fact('1 SEX ' . $sex, $dummy, ''), + new Fact('1 NAME ' . $element->default($tree), $dummy, ''), + new Fact('1 BIRT', $dummy, ''), + new Fact('1 DEAT', $dummy, ''), + ], + ]; - if ($gender === 'F') { - $title = $individual->fullName() . ' - ' . I18N::translate('Add a mother'); - $famtag = 'WIFE'; + if ($sex === 'F') { + $title = I18N::translate('Add a mother'); } else { - $title = $individual->fullName() . ' - ' . I18N::translate('Add a father'); - $famtag = 'HUSB'; + $title = I18N::translate('Add a father'); } return $this->viewResponse('edit/new-individual', [ - 'next_action' => AddParentToIndividualAction::class, - 'tree' => $tree, - 'title' => $title, - 'individual' => $individual, - 'family' => null, - 'name_fact' => null, - 'famtag' => $famtag, - 'gender' => $gender, + 'cancel_url' => $individual->url(), + 'facts' => $facts, + 'post_url' => route(AddParentToIndividualAction::class, ['tree' => $tree->name(), 'xref' => $xref]), + 'title' => $individual->fullName() . ' - ' . $title, + 'tree' => $tree, + 'url' => $request->getQueryParams()['url'] ?? $individual->url(), ]); } } diff --git a/app/Http/RequestHandlers/AddSpouseToFamilyAction.php b/app/Http/RequestHandlers/AddSpouseToFamilyAction.php index fe4773ab6c..d1476dfbed 100644 --- a/app/Http/RequestHandlers/AddSpouseToFamilyAction.php +++ b/app/Http/RequestHandlers/AddSpouseToFamilyAction.php @@ -20,7 +20,6 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; -use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\Services\GedcomEditService; use Fisharebest\Webtrees\Tree; @@ -29,9 +28,8 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; -use function preg_match_all; +use function is_string; use function redirect; -use function trim; /** * Add a new spouse to a family. @@ -61,60 +59,42 @@ class AddSpouseToFamilyAction implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; - $family = Registry::familyFactory()->make($xref, $tree); - $family = Auth::checkFamilyAccess($family, true); + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); $params = (array) $request->getParsedBody(); - $this->gedcom_edit_service->glevels = $params['glevels'] ?? []; - $this->gedcom_edit_service->tag = $params['tag'] ?? []; - $this->gedcom_edit_service->text = $params['text'] ?? []; - $this->gedcom_edit_service->islink = $params['islink'] ?? []; + $family = Registry::familyFactory()->make($xref, $tree); + $family = Auth::checkFamilyAccess($family, true); + + $levels = $params['ilevels'] ?? []; + $tags = $params['itags'] ?? []; + $values = $params['ivalues'] ?? []; // Create the new spouse - $this->gedcom_edit_service->splitSource(); // separate SOUR record from the rest + $gedcom = "0 @@ INDI\n1 FAMS @" . $family->xref() . "@\n" . $this->gedcom_edit_service->editLinesToGedcom('INDI', $levels, $tags, $values); + $spouse = $tree->createIndividual($gedcom); - $gedrec = '0 @@ INDI'; - $gedrec .= $this->gedcom_edit_service->addNewName($request, $tree); - $gedrec .= $this->gedcom_edit_service->addNewSex($request); - if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches)) { - foreach ($matches[1] as $match) { - $gedrec .= $this->gedcom_edit_service->addNewFact($request, $tree, $match); - } - } + // Link the spouse to the family + $husb = $family->facts(['HUSB'], false, null, true)->first(); + $wife = $family->facts(['WIFE'], false, null, true)->first(); - if ($params['SOUR_INDI'] ?? false) { - $gedrec = $this->gedcom_edit_service->handleUpdates($gedrec); + if ($husb === null && $spouse->sex() === 'M') { + $link = 'HUSB'; + } elseif ($wife === null && $spouse->sex() === 'F') { + $link = 'WIFE'; + } elseif ($husb === null) { + $link = 'HUSB'; + } elseif ($wife === null) { + $link = 'WIFE'; } else { - $gedrec = $this->gedcom_edit_service->updateRest($gedrec); + // Family already has husband and wife + return redirect($family->url()); } - $gedrec .= "\n1 FAMS @" . $family->xref() . '@'; - $spouse = $tree->createIndividual($gedrec); - // Update the existing family - add marriage, etc - if ($family->facts(['HUSB'])->first() instanceof Fact) { - $family->createFact('1 WIFE @' . $spouse->xref() . '@', true); - } else { - $family->createFact('1 HUSB @' . $spouse->xref() . '@', true); - } - $famrec = ''; - if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches)) { - foreach ($matches[1] as $match) { - $famrec .= $this->gedcom_edit_service->addNewFact($request, $tree, $match); - } - } - if ($params['SOUR_FAM'] ?? false) { - $famrec = $this->gedcom_edit_service->handleUpdates($famrec); - } else { - $famrec = $this->gedcom_edit_service->updateRest($famrec); - } - $family->createFact(trim($famrec), true); // trim leading \n - - if (($params['goto'] ?? '') === 'new') { - return redirect($spouse->url()); - } + // Link the spouse to the family + $family->createFact('1 ' . $link . ' @' . $spouse->xref() . '@', false); - return redirect($family->url()); + return redirect($params['url'] ?? $spouse->url()); } } diff --git a/app/Http/RequestHandlers/AddSpouseToFamilyPage.php b/app/Http/RequestHandlers/AddSpouseToFamilyPage.php index aefc9b9b53..9086fa6e69 100644 --- a/app/Http/RequestHandlers/AddSpouseToFamilyPage.php +++ b/app/Http/RequestHandlers/AddSpouseToFamilyPage.php @@ -20,6 +20,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; +use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Registry; @@ -29,6 +30,8 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function is_string; +use function route; /** * Add a new spouse to a family. @@ -47,28 +50,44 @@ class AddSpouseToFamilyPage implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; - $famtag = $request->getQueryParams()['famtag']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); + + $sex = $request->getAttribute('sex'); + assert(is_string($sex)); + $family = Registry::familyFactory()->make($xref, $tree); $family = Auth::checkFamilyAccess($family, true); - if ($famtag === 'WIFE') { - $title = I18N::translate('Add a wife'); - $gender = 'F'; + // Create a dummy individual, so that we can create new/empty facts. + $element = Registry::elementFactory()->make('INDI:NAME'); + $dummyi = Registry::individualFactory()->new('', '0 @@ INDI', null, $tree); + $dummyf = Registry::familyFactory()->new('', '0 @@ FAM', null, $tree); + $facts = [ + 'i' => [ + new Fact('1 SEX ' . $sex, $dummyi, ''), + new Fact('1 NAME ' . $element->default($tree), $dummyi, ''), + new Fact('1 BIRT', $dummyi, ''), + new Fact('1 DEAT', $dummyi, ''), + ], + 'f' => [ + new Fact('1 MARR', $dummyf, ''), + ], + ]; + + if ($sex === 'F') { + $title = I18N::translate('Add a wife'); } else { - $title = I18N::translate('Add a husband'); - $gender = 'M'; + $title = I18N::translate('Add a husband'); } return $this->viewResponse('edit/new-individual', [ - 'next_action' => AddSpouseToFamilyAction::class, - 'tree' => $tree, + 'cancel_url' => $family->url(), + 'facts' => $facts, + 'post_url' => route(AddSpouseToFamilyAction::class, ['tree' => $tree->name(), 'xref' => $xref]), 'title' => $title, - 'individual' => null, - 'family' => $family, - 'name_fact' => null, - 'famtag' => $famtag, - 'gender' => $gender, + 'tree' => $tree, + 'url' => $request->getQueryParams()['url'] ?? $family->url(), ]); } } diff --git a/app/Http/RequestHandlers/AddSpouseToIndividualAction.php b/app/Http/RequestHandlers/AddSpouseToIndividualAction.php index a960c5384c..1049b14197 100644 --- a/app/Http/RequestHandlers/AddSpouseToIndividualAction.php +++ b/app/Http/RequestHandlers/AddSpouseToIndividualAction.php @@ -28,7 +28,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; -use function preg_match_all; +use function is_string; use function redirect; /** @@ -59,63 +59,33 @@ class AddSpouseToIndividualAction implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; - - $individual = Registry::individualFactory()->make($xref, $tree); - $individual = Auth::checkIndividualAccess($individual, true); + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); $params = (array) $request->getParsedBody(); - $sex = $params['SEX']; - - $this->gedcom_edit_service->glevels = $params['glevels'] ?? []; - $this->gedcom_edit_service->tag = $params['tag'] ?? []; - $this->gedcom_edit_service->text = $params['text'] ?? []; - $this->gedcom_edit_service->islink = $params['islink'] ?? []; - - $this->gedcom_edit_service->splitSource(); - $indi_gedcom = '0 @@ INDI'; - $indi_gedcom .= $this->gedcom_edit_service->addNewName($request, $tree); - $indi_gedcom .= $this->gedcom_edit_service->addNewSex($request); - if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches)) { - foreach ($matches[1] as $match) { - $indi_gedcom .= $this->gedcom_edit_service->addNewFact($request, $tree, $match); - } - } - if ($params['SOUR_INDI'] ?? false) { - $indi_gedcom = $this->gedcom_edit_service->handleUpdates($indi_gedcom); - } else { - $indi_gedcom = $this->gedcom_edit_service->updateRest($indi_gedcom); - } + $individual = Registry::individualFactory()->make($xref, $tree); + $individual = Auth::checkIndividualAccess($individual, true); - $fam_gedcom = ''; - if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches)) { - foreach ($matches[1] as $match) { - $fam_gedcom .= $this->gedcom_edit_service->addNewFact($request, $tree, $match); - } - } - if ($params['SOUR_FAM'] ?? false) { - $fam_gedcom = $this->gedcom_edit_service->handleUpdates($fam_gedcom); - } else { - $fam_gedcom = $this->gedcom_edit_service->updateRest($fam_gedcom); - } + $levels = $params['ilevels'] ?? []; + $tags = $params['itags'] ?? []; + $values = $params['ivalues'] ?? []; // Create the new spouse - $spouse = $tree->createIndividual($indi_gedcom); + $gedcom = $this->gedcom_edit_service->editLinesToGedcom('INDI', $levels, $tags, $values); + $spouse = $tree->createIndividual("0 @@ INDI\n" . $gedcom); + // Create a new family - if ($sex === 'F') { - $family = $tree->createFamily("0 @@ FAM\n1 WIFE @" . $spouse->xref() . "@\n1 HUSB @" . $individual->xref() . '@' . $fam_gedcom); - } else { - $family = $tree->createFamily("0 @@ FAM\n1 HUSB @" . $spouse->xref() . "@\n1 WIFE @" . $individual->xref() . '@' . $fam_gedcom); - } - // Link the spouses to the family - $spouse->createFact('1 FAMS @' . $family->xref() . '@', true); - $individual->createFact('1 FAMS @' . $family->xref() . '@', true); + $i_link = "\n1 " . ($individual->sex() === 'F' ? 'WIFE' : 'HUSB') . ' @' . $individual->xref() . '@'; + $s_link = "\n1 " . ($individual->sex() !== 'F' ? 'WIFE' : 'HUSB') . ' @' . $spouse->xref() . '@'; + $family = $tree->createFamily("0 @@ FAM\n" . $i_link . $s_link); + + // Link the individual to the family + $individual->createFact('1 FAMS @' . $family->xref() . '@', false); - if (($params['goto'] ?? '') === 'new') { - return redirect($spouse->url()); - } + // Link the spouse to the family + $spouse->createFact('1 FAMS @' . $family->xref() . '@', false); - return redirect($individual->url()); + return redirect($params['url'] ?? $spouse->url()); } } diff --git a/app/Http/RequestHandlers/AddSpouseToIndividualPage.php b/app/Http/RequestHandlers/AddSpouseToIndividualPage.php index 3ad2f39938..09ecedfa6a 100644 --- a/app/Http/RequestHandlers/AddSpouseToIndividualPage.php +++ b/app/Http/RequestHandlers/AddSpouseToIndividualPage.php @@ -20,6 +20,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; +use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Registry; @@ -29,6 +30,8 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function is_string; +use function route; /** * Add a new spouse to an individual, creating a new family. @@ -37,6 +40,12 @@ class AddSpouseToIndividualPage implements RequestHandlerInterface { use ViewResponseTrait; + // Create mixed-sex couples by default + private const OPPOSITE_SEX = [ + 'F' => 'M', + 'M' => 'F', + ]; + /** * @param ServerRequestInterface $request * @@ -47,30 +56,44 @@ class AddSpouseToIndividualPage implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); $individual = Registry::individualFactory()->make($xref, $tree); $individual = Auth::checkIndividualAccess($individual, true); - if ($individual->sex() === 'F') { - $title = $individual->fullName() . ' - ' . I18N::translate('Add a husband'); - $famtag = 'HUSB'; - $gender = 'M'; - } else { - $title = $individual->fullName() . ' - ' . I18N::translate('Add a wife'); - $famtag = 'WIFE'; - $gender = 'F'; - } + // Create a dummy individual, so that we can create new/empty facts. + $sex = self::OPPOSITE_SEX[$individual->sex()] ?? 'U'; + $element = Registry::elementFactory()->make('INDI:NAME'); + $dummyi = Registry::individualFactory()->new('', '0 @@ INDI', null, $tree); + $dummyf = Registry::familyFactory()->new('', '0 @@ FAM', null, $tree); + $facts = [ + 'i' => [ + new Fact('1 SEX ' . $sex, $dummyi, ''), + new Fact('1 NAME ' . $element->default($tree), $dummyi, ''), + new Fact('1 BIRT', $dummyi, ''), + new Fact('1 DEAT', $dummyi, ''), + ], + 'f' => [ + new Fact('1 MARR', $dummyf, ''), + ], + ]; + + $titles = [ + 'F' => I18N::translate('Add a wife'), + 'H' => I18N::translate('Add a husband'), + 'U' => I18N::translate('Add a spouse'), + ]; + + $title = $titles[$sex] ?? $titles['U']; return $this->viewResponse('edit/new-individual', [ - 'next_action' => AddSpouseToIndividualAction::class, - 'tree' => $tree, - 'title' => $title, - 'individual' => $individual, - 'family' => null, - 'name_fact' => null, - 'famtag' => $famtag, - 'gender' => $gender, + 'cancel_url' => $individual->url(), + 'facts' => $facts, + 'post_url' => route(AddSpouseToIndividualAction::class, ['tree' => $tree->name(), 'xref' => $xref]), + 'title' => $individual->fullName() . ' - ' . $title, + 'tree' => $tree, + 'url' => $request->getQueryParams()['url'] ?? $individual->url(), ]); } } diff --git a/app/Http/RequestHandlers/AddUnlinkedAction.php b/app/Http/RequestHandlers/AddUnlinkedAction.php index 42838c5d38..58b16c7fe6 100644 --- a/app/Http/RequestHandlers/AddUnlinkedAction.php +++ b/app/Http/RequestHandlers/AddUnlinkedAction.php @@ -26,9 +26,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; -use function preg_match_all; use function redirect; -use function route; /** * Create a new unlinked individual. @@ -60,32 +58,14 @@ class AddUnlinkedAction implements RequestHandlerInterface $params = (array) $request->getParsedBody(); - $this->gedcom_edit_service->glevels = $params['glevels'] ?? []; - $this->gedcom_edit_service->tag = $params['tag'] ?? []; - $this->gedcom_edit_service->text = $params['text'] ?? []; - $this->gedcom_edit_service->islink = $params['islink'] ?? []; + $levels = $params['ilevels'] ?? []; + $tags = $params['itags'] ?? []; + $values = $params['ivalues'] ?? []; - $this->gedcom_edit_service->splitSource(); - $gedrec = '0 @@ INDI'; - $gedrec .= $this->gedcom_edit_service->addNewName($request, $tree); - $gedrec .= $this->gedcom_edit_service->addNewSex($request); - if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches)) { - foreach ($matches[1] as $match) { - $gedrec .= $this->gedcom_edit_service->addNewFact($request, $tree, $match); - } - } - if ($params['SOUR_INDI'] ?? false) { - $gedrec = $this->gedcom_edit_service->handleUpdates($gedrec); - } else { - $gedrec = $this->gedcom_edit_service->updateRest($gedrec); - } + $gedcom = $this->gedcom_edit_service->editLinesToGedcom('INDI', $levels, $tags, $values); - $new_indi = $tree->createIndividual($gedrec); + $individual = $tree->createIndividual("0 @@ INDI\n" . $gedcom); - if (($params['goto'] ?? '') === 'new') { - return redirect($new_indi->url()); - } - - return redirect(route(ManageTrees::class, ['tree' => $tree->name()])); + return redirect($params['url'] ?? $individual->url()); } } diff --git a/app/Http/RequestHandlers/AddUnlinkedPage.php b/app/Http/RequestHandlers/AddUnlinkedPage.php index 074ee70a7a..9557aa3095 100644 --- a/app/Http/RequestHandlers/AddUnlinkedPage.php +++ b/app/Http/RequestHandlers/AddUnlinkedPage.php @@ -19,14 +19,17 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; +use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; +use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\Tree; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function route; /** * Create a new unlinked individual. @@ -45,15 +48,25 @@ class AddUnlinkedPage implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); + // Create a dummy individual, so that we can create new/empty facts. + $element = Registry::elementFactory()->make('INDI:NAME'); + $dummy = Registry::individualFactory()->new('', '0 @@ INDI', null, $tree); + $facts = [ + 'i' => [ + new Fact('1 SEX', $dummy, ''), + new Fact('1 NAME ' . $element->default($tree), $dummy, ''), + new Fact('1 BIRT', $dummy, ''), + new Fact('1 DEAT', $dummy, ''), + ], + ]; + return $this->viewResponse('edit/new-individual', [ - 'next_action' => AddUnlinkedAction::class, - 'tree' => $tree, - 'title' => I18N::translate('Create an individual'), - 'individual' => null, - 'family' => null, - 'name_fact' => null, - 'famtag' => '', - 'gender' => 'U', + 'cancel_url' => route('manage-trees', ['tree' => $tree->name()]), + 'facts' => $facts, + 'post_url' => route(AddUnlinkedAction::class, ['tree' => $tree->name()]), + 'tree' => $tree, + 'title' => I18N::translate('Create an individual'), + 'url' => $request->getQueryParams()['url'] ?? route('manage-trees', ['tree' => $tree->name()]), ]); } } diff --git a/app/Http/RequestHandlers/EditFactAction.php b/app/Http/RequestHandlers/EditFactAction.php index c5e4a33c8a..9cae393376 100644 --- a/app/Http/RequestHandlers/EditFactAction.php +++ b/app/Http/RequestHandlers/EditFactAction.php @@ -30,15 +30,10 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; -use function array_merge; -use function array_unique; use function assert; use function explode; -use function in_array; use function is_string; -use function preg_match_all; use function redirect; -use function trim; /** * Save an updated GEDCOM fact. @@ -84,78 +79,38 @@ class EditFactAction implements RequestHandlerInterface $params = (array) $request->getParsedBody(); $keep_chan = (bool) ($params['keep_chan'] ?? false); + $levels = $params['levels']; + $tags = $params['tags']; + $values = $params['values']; - $this->gedcom_edit_service->glevels = $params['glevels']; - $this->gedcom_edit_service->tag = $params['tag']; - $this->gedcom_edit_service->text = $params['text']; - $this->gedcom_edit_service->islink = $params['islink']; + $gedcom = $this->gedcom_edit_service->editLinesToGedcom($record::RECORD_TYPE, $levels, $tags, $values); - // If the fact has a DATE or PLAC, then delete any value of Y - if ($this->gedcom_edit_service->text[0] === 'Y') { - foreach ($this->gedcom_edit_service->tag as $n => $value) { - if ($this->gedcom_edit_service->glevels[$n] == 2 && ($value === 'DATE' || $value === 'PLAC') && $this->gedcom_edit_service->text[$n] !== '') { - $this->gedcom_edit_service->text[0] = ''; - break; - } - } - } - - $newged = ''; - - $NAME = $params['NAME'] ?? ''; - - if ($NAME !== '') { - $newged .= "\n1 NAME " . $NAME; - $name_facts = [ - 'TYPE', - 'NPFX', - 'GIVN', - 'NICK', - 'SPFX', - 'SURN', - 'NSFX', - ]; - foreach ($name_facts as $name_fact) { - $NAME_FACT = $params[$name_fact] ?? ''; - if ($NAME_FACT !== '') { - $newged .= "\n2 " . $name_fact . ' ' . $NAME_FACT; - } - } - } - - $newged = $this->gedcom_edit_service->handleUpdates($newged); + $census_assistant = $this->module_service->findByInterface(CensusAssistantModule::class)->first(); - // Add new names after existing names - if ($NAME !== '') { - preg_match_all('/[_0-9A-Z]+/', $tree->getPreference('ADVANCED_NAME_FACTS'), $match); - $name_facts = array_unique(array_merge(['_MARNM'], $match[0])); - foreach ($name_facts as $name_fact) { - $NAME_FACT = $params[$name_fact] ?? ''; - // Ignore advanced facts that duplicate standard facts. - if ($NAME_FACT !== '' && !in_array($name_fact, ['TYPE', 'NPFX', 'GIVN', 'NICK', 'SPFX', 'SURN', 'NSFX'], true)) { - $newged .= "\n2 " . $name_fact . ' ' . $NAME_FACT; + if ($census_assistant instanceof CensusAssistantModule && $record instanceof Individual) { + $gedcom = $census_assistant->updateCensusAssistant($request, $record, $fact_id, $gedcom, $keep_chan); + $pid_array = $params['pid_array'] ?? ''; + if ($pid_array !== '') { + foreach (explode(',', $pid_array) as $pid) { + if ($pid !== $xref) { + $individual = Registry::individualFactory()->make($pid, $tree); + if ($individual instanceof Individual && $individual->canEdit()) { + $individual->updateFact('', $gedcom, !$keep_chan); + } + } } } } - $newged = trim($newged); // Remove leading newline - - $census_assistant = $this->module_service->findByInterface(CensusAssistantModule::class)->first(); - if ($census_assistant instanceof CensusAssistantModule && $record instanceof Individual) { - $newged = $census_assistant->updateCensusAssistant($request, $record, $fact_id, $newged, $keep_chan); - } - - $record->updateFact($fact_id, $newged, !$keep_chan); - - // For the GEDFact_assistant module - $pid_array = $params['pid_array'] ?? ''; - if ($pid_array !== '') { - foreach (explode(',', $pid_array) as $pid) { - if ($pid !== $xref) { - $indi = Registry::individualFactory()->make($pid, $tree); - if ($indi && $indi->canEdit()) { - $indi->updateFact($fact_id, $newged, !$keep_chan); - } + if ($fact_id === 'new') { + // Add a new fact + $record->updateFact('', $gedcom, !$keep_chan); + } else { + // Update (only the first copy of) an existing fact + foreach ($record->facts([], false, null, true) as $fact) { + if ($fact->id() === $fact_id && $fact->canEdit()) { + $record->updateFact($fact_id, $gedcom, !$keep_chan); + break; } } } diff --git a/app/Http/RequestHandlers/EditName.php b/app/Http/RequestHandlers/EditName.php deleted file mode 100644 index 0c4072561d..0000000000 --- a/app/Http/RequestHandlers/EditName.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php - -/** - * webtrees: online genealogy - * Copyright (C) 2021 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 <https://www.gnu.org/licenses/>. - */ - -declare(strict_types=1); - -namespace Fisharebest\Webtrees\Http\RequestHandlers; - -use Fisharebest\Webtrees\Auth; -use Fisharebest\Webtrees\Exceptions\HttpNotFoundException; -use Fisharebest\Webtrees\Fact; -use Fisharebest\Webtrees\Http\ViewResponseTrait; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Registry; -use Fisharebest\Webtrees\Tree; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\RequestHandlerInterface; - -use function assert; -use function is_string; - -/** - * Edit an individual name. - */ -class EditName implements RequestHandlerInterface -{ - use ViewResponseTrait; - - /** - * @param ServerRequestInterface $request - * - * @return ResponseInterface - */ - public function handle(ServerRequestInterface $request): ResponseInterface - { - $tree = $request->getAttribute('tree'); - assert($tree instanceof Tree); - - $xref = $request->getAttribute('xref'); - assert(is_string($xref)); - - $fact_id = $request->getAttribute('fact_id') ?? ''; - - $individual = Registry::individualFactory()->make($xref, $tree); - $individual = Auth::checkIndividualAccess($individual, true); - - // Find the fact to edit - $fact = $individual->facts() - ->first(static function (Fact $fact) use ($fact_id): bool { - return $fact->id() === $fact_id && $fact->canEdit(); - }); - - if ($fact instanceof Fact) { - return $this->viewResponse('edit/new-individual', [ - 'next_action' => EditFactAction::class, - 'tree' => $tree, - 'title' => I18N::translate('Edit the name'), - 'individual' => $individual, - 'family' => null, - 'name_fact' => $fact, - 'famtag' => '', - 'gender' => $individual->sex(), - ]); - } - - throw new HttpNotFoundException(); - } -} diff --git a/app/Http/RequestHandlers/LinkChildToFamilyAction.php b/app/Http/RequestHandlers/LinkChildToFamilyAction.php index bae2852f20..e60e39bccf 100644 --- a/app/Http/RequestHandlers/LinkChildToFamilyAction.php +++ b/app/Http/RequestHandlers/LinkChildToFamilyAction.php @@ -27,6 +27,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function is_string; use function redirect; /** @@ -44,7 +45,8 @@ class LinkChildToFamilyAction implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); $individual = Registry::individualFactory()->make($xref, $tree); $individual = Auth::checkIndividualAccess($individual, true); diff --git a/app/Http/RequestHandlers/LinkChildToFamilyPage.php b/app/Http/RequestHandlers/LinkChildToFamilyPage.php index 24de9e6314..e76e0767f4 100644 --- a/app/Http/RequestHandlers/LinkChildToFamilyPage.php +++ b/app/Http/RequestHandlers/LinkChildToFamilyPage.php @@ -29,6 +29,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function is_string; /** * Link an existing individual as child in an existing family. @@ -47,17 +48,17 @@ class LinkChildToFamilyPage implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); $individual = Registry::individualFactory()->make($xref, $tree); - $individual = Auth::checkIndividualAccess($individual, true); - $title = $individual->fullName() . ' - ' . I18N::translate('Link this individual to an existing family as a child'); + $title = I18N::translate('Link this individual to an existing family as a child'); return $this->viewResponse('edit/link-child-to-family', [ 'individual' => $individual, - 'title' => $title, + 'title' => $individual->fullName() . ' - ' . $title, 'tree' => $tree, 'xref' => $xref, ]); diff --git a/app/Http/RequestHandlers/LinkSpouseToIndividualAction.php b/app/Http/RequestHandlers/LinkSpouseToIndividualAction.php index b961c77699..9bda3def19 100644 --- a/app/Http/RequestHandlers/LinkSpouseToIndividualAction.php +++ b/app/Http/RequestHandlers/LinkSpouseToIndividualAction.php @@ -28,6 +28,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function is_string; use function redirect; /** @@ -58,14 +59,20 @@ class LinkSpouseToIndividualAction implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); $individual = Registry::individualFactory()->make($xref, $tree); $individual = Auth::checkIndividualAccess($individual, true); $params = (array) $request->getParsedBody(); - $spid = $params['spid']; + $levels = $params['flevels'] ?? []; + $tags = $params['ftags'] ?? []; + $values = $params['fvalues'] ?? []; + + // Create the new family + $spid = $params['spid']; $spouse = Registry::individualFactory()->make($spid, $tree); $spouse = Auth::checkIndividualAccess($spouse, true); @@ -75,12 +82,12 @@ class LinkSpouseToIndividualAction implements RequestHandlerInterface $gedcom = "0 @@ FAM\n1 WIFE @" . $individual->xref() . "@\n1 HUSB @" . $spouse->xref() . '@'; } - $gedcom .= $this->gedcom_edit_service->addNewFact($request, $tree, 'MARR'); + $gedcom .= "\n" . $this->gedcom_edit_service->editLinesToGedcom('FAM', $levels, $tags, $values); $family = $tree->createFamily($gedcom); - $individual->createFact('1 FAMS @' . $family->xref() . '@', true); - $spouse->createFact('1 FAMS @' . $family->xref() . '@', true); + $individual->createFact('1 FAMS @' . $family->xref() . '@', false); + $spouse->createFact('1 FAMS @' . $family->xref() . '@', false); return redirect($family->url()); } diff --git a/app/Http/RequestHandlers/LinkSpouseToIndividualPage.php b/app/Http/RequestHandlers/LinkSpouseToIndividualPage.php index 21a12b160e..12c7d8a12a 100644 --- a/app/Http/RequestHandlers/LinkSpouseToIndividualPage.php +++ b/app/Http/RequestHandlers/LinkSpouseToIndividualPage.php @@ -20,6 +20,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; +use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Registry; @@ -29,6 +30,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function assert; +use function is_string; /** * Link an existing individual as a new spouse. @@ -47,11 +49,20 @@ class LinkSpouseToIndividualPage implements RequestHandlerInterface $tree = $request->getAttribute('tree'); assert($tree instanceof Tree); - $xref = $request->getQueryParams()['xref']; + $xref = $request->getAttribute('xref'); + assert(is_string($xref)); $individual = Registry::individualFactory()->make($xref, $tree); $individual = Auth::checkIndividualAccess($individual, true); + // Create a dummy family record, so we can create new/empty facts. + $dummy = Registry::familyFactory()->new('', '0 @@ FAM', null, $tree); + $facts = [ + 'f' => [ + new Fact('1 MARR', $dummy, ''), + ], + ]; + if ($individual->sex() === 'F') { $title = $individual->fullName() . ' - ' . I18N::translate('Add a husband using an existing individual'); $label = I18N::translate('Husband'); @@ -61,9 +72,11 @@ class LinkSpouseToIndividualPage implements RequestHandlerInterface } return $this->viewResponse('edit/link-spouse-to-individual', [ - 'individual' => $individual, + 'post_url' => route(LinkSpouseToIndividualAction::class, ['tree' => $tree->name(), 'xref' => $xref]), + 'cancel_url' => $individual->url(), 'label' => $label, 'title' => $title, + 'facts' => $facts, 'tree' => $tree, 'xref' => $xref, ]); diff --git a/app/Http/RequestHandlers/ModulesCustomTagsPage.php b/app/Http/RequestHandlers/ModulesCustomTagsPage.php index 051c3a506e..6a0f28444e 100644 --- a/app/Http/RequestHandlers/ModulesCustomTagsPage.php +++ b/app/Http/RequestHandlers/ModulesCustomTagsPage.php @@ -40,7 +40,7 @@ class ModulesCustomTagsPage extends AbstractModuleComponentPage { return $this->listComponents( ModuleCustomTagsInterface::class, - view('icons/chart') . I18N::translate('Custom tags'), + view('icons/chart') . ' ' . I18N::translate('Custom GEDCOM tags'), '' ); } diff --git a/app/Http/Routes/WebRoutes.php b/app/Http/Routes/WebRoutes.php index a13dfe5a27..18f74acaef 100644 --- a/app/Http/Routes/WebRoutes.php +++ b/app/Http/Routes/WebRoutes.php @@ -35,7 +35,6 @@ use Fisharebest\Webtrees\Http\RequestHandlers\AddChildToIndividualAction; use Fisharebest\Webtrees\Http\RequestHandlers\AddChildToIndividualPage; use Fisharebest\Webtrees\Http\RequestHandlers\AddMediaFileAction; use Fisharebest\Webtrees\Http\RequestHandlers\AddMediaFileModal; -use Fisharebest\Webtrees\Http\RequestHandlers\AddName; use Fisharebest\Webtrees\Http\RequestHandlers\AddNewFact; use Fisharebest\Webtrees\Http\RequestHandlers\AddParentToIndividualAction; use Fisharebest\Webtrees\Http\RequestHandlers\AddParentToIndividualPage; @@ -98,7 +97,6 @@ use Fisharebest\Webtrees\Http\RequestHandlers\EditFactAction; use Fisharebest\Webtrees\Http\RequestHandlers\EditFactPage; use Fisharebest\Webtrees\Http\RequestHandlers\EditMediaFileAction; use Fisharebest\Webtrees\Http\RequestHandlers\EditMediaFileModal; -use Fisharebest\Webtrees\Http\RequestHandlers\EditName; use Fisharebest\Webtrees\Http\RequestHandlers\EditNoteAction; use Fisharebest\Webtrees\Http\RequestHandlers\EditNotePage; use Fisharebest\Webtrees\Http\RequestHandlers\EditRawFactAction; @@ -528,15 +526,14 @@ class WebRoutes $router->get(AutoCompleteFolder::class, '/autocomplete/folder/{query}'); $router->get(AutoCompletePlace::class, '/autocomplete/place/{query}'); $router->get(AutoCompleteSurname::class, '/autocomplete/surname/{query}'); - $router->get(AddChildToFamilyPage::class, '/add-child-to-family'); - $router->post(AddChildToFamilyAction::class, '/add-child-to-family'); + $router->get(AddChildToFamilyPage::class, '/add-child-to-family/{xref}/{sex}'); + $router->post(AddChildToFamilyAction::class, '/add-child-to-family/{xref}'); $router->get(AddNewFact::class, '/add-fact/{xref}/{fact}'); $router->post(SelectNewFact::class, '/add-fact/{xref}'); $router->get(AddMediaFileModal::class, '/add-media-file/{xref}'); $router->post(AddMediaFileAction::class, '/add-media-file/{xref}'); - $router->get(AddName::class, '/add-name'); - $router->get(AddSpouseToFamilyPage::class, '/add-spouse-to-family'); - $router->post(AddSpouseToFamilyAction::class, '/add-spouse-to-family'); + $router->get(AddSpouseToFamilyPage::class, '/add-spouse-to-family/{xref}/{sex}'); + $router->post(AddSpouseToFamilyAction::class, '/add-spouse-to-family/{xref}'); $router->get(ChangeFamilyMembersPage::class, '/change-family-members'); $router->post(ChangeFamilyMembersAction::class, '/change-family-members'); $router->get(CreateLocationModal::class, '/create-location'); @@ -584,19 +581,18 @@ class WebRoutes $router->post(ReorderFamiliesAction::class, '/reorder-spouses/{xref}'); $router->get(SearchReplacePage::class, '/search-replace'); $router->post(SearchReplaceAction::class, '/search-replace'); - $router->get(AddChildToIndividualPage::class, '/add-child-to-individual'); - $router->post(AddChildToIndividualAction::class, '/add-child-to-individual'); - $router->get(AddParentToIndividualPage::class, '/add-parent-to-individual'); - $router->post(AddParentToIndividualAction::class, '/add-parent-to-individual'); - $router->get(AddSpouseToIndividualPage::class, '/add-spouse-to-individual'); - $router->post(AddSpouseToIndividualAction::class, '/add-spouse-to-individual'); + $router->get(AddChildToIndividualPage::class, '/add-child-to-individual/{xref}'); + $router->post(AddChildToIndividualAction::class, '/add-child-to-individual/{xref}'); + $router->get(AddParentToIndividualPage::class, '/add-parent-to-individual/{xref}/{sex}'); + $router->post(AddParentToIndividualAction::class, '/add-parent-to-individual/{xref}'); + $router->get(AddSpouseToIndividualPage::class, '/add-spouse-to-individual/{xref}'); + $router->post(AddSpouseToIndividualAction::class, '/add-spouse-to-individual/{xref}'); $router->get(AddUnlinkedPage::class, '/add-unlinked-individual'); $router->post(AddUnlinkedAction::class, '/add-unlinked-individual'); - $router->get(LinkChildToFamilyPage::class, '/link-child-to-family'); - $router->post(LinkChildToFamilyAction::class, '/link-child-to-family'); - $router->get(LinkSpouseToIndividualPage::class, '/link-spouse-to-individual'); - $router->post(LinkSpouseToIndividualAction::class, '/link-spouse-to-individual'); - $router->get(EditName::class, '/edit-name/{xref}/{fact_id}'); + $router->get(LinkChildToFamilyPage::class, '/link-child-to-family/{xref}'); + $router->post(LinkChildToFamilyAction::class, '/link-child-to-family/{xref}'); + $router->get(LinkSpouseToIndividualPage::class, '/link-spouse-to-individual/{xref}'); + $router->post(LinkSpouseToIndividualAction::class, '/link-spouse-to-individual/{xref}'); }); // User routes with a tree. diff --git a/app/Module/CustomTagsAldfaer.php b/app/Module/CustomTagsAldfaer.php index 37eafcbcbb..e26039e549 100644 --- a/app/Module/CustomTagsAldfaer.php +++ b/app/Module/CustomTagsAldfaer.php @@ -32,6 +32,16 @@ class CustomTagsAldfaer extends AbstractModule implements ModuleConfigInterface, use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsAncestry.php b/app/Module/CustomTagsAncestry.php index 9d0430cc42..3223970efa 100644 --- a/app/Module/CustomTagsAncestry.php +++ b/app/Module/CustomTagsAncestry.php @@ -33,6 +33,16 @@ class CustomTagsAncestry extends AbstractModule implements ModuleConfigInterface use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsBrothersKeeper.php b/app/Module/CustomTagsBrothersKeeper.php index 2aecdb943b..8830959b8b 100644 --- a/app/Module/CustomTagsBrothersKeeper.php +++ b/app/Module/CustomTagsBrothersKeeper.php @@ -30,7 +30,7 @@ use Fisharebest\Webtrees\Elements\PlaceName; use Fisharebest\Webtrees\I18N; /** - * Custom tags created by Brother’s Keeper + * Custom GEDCOM tags created by Brother’s Keeper * * Class CustomTagsBrothersKeeper */ @@ -40,6 +40,16 @@ class CustomTagsBrothersKeeper extends AbstractModule implements ModuleConfigInt use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> * * @see http://wiki-de.genealogy.net/GEDCOM/_Nutzerdef-Tag diff --git a/app/Module/CustomTagsFamilySearch.php b/app/Module/CustomTagsFamilySearch.php index 92a956054b..5e10a4b469 100644 --- a/app/Module/CustomTagsFamilySearch.php +++ b/app/Module/CustomTagsFamilySearch.php @@ -32,6 +32,16 @@ class CustomTagsFamilySearch extends AbstractModule implements ModuleConfigInter use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsFamilyTreeBuilder.php b/app/Module/CustomTagsFamilyTreeBuilder.php index 9264ad9a0f..99e88d8441 100644 --- a/app/Module/CustomTagsFamilyTreeBuilder.php +++ b/app/Module/CustomTagsFamilyTreeBuilder.php @@ -35,6 +35,16 @@ class CustomTagsFamilyTreeBuilder extends AbstractModule implements ModuleConfig use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsFamilyTreeMaker.php b/app/Module/CustomTagsFamilyTreeMaker.php index eb19e22fd1..e779984d22 100644 --- a/app/Module/CustomTagsFamilyTreeMaker.php +++ b/app/Module/CustomTagsFamilyTreeMaker.php @@ -25,7 +25,7 @@ use Fisharebest\Webtrees\Elements\NamePersonal; use Fisharebest\Webtrees\I18N; /** - * Custom tags created by FamilyTreeMaker (DOS, Windows, ancestry.com) + * Custom GEDCOM tags created by FamilyTreeMaker (DOS, Windows, ancestry.com) * * Class CustomTagsFamilyTreeMaker */ @@ -35,6 +35,16 @@ class CustomTagsFamilyTreeMaker extends AbstractModule implements ModuleConfigIn use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> * * @see http://wiki-de.genealogy.net/GEDCOM/_Nutzerdef-Tag diff --git a/app/Module/CustomTagsGedcom53.php b/app/Module/CustomTagsGedcom53.php index 716f3b3536..12971ed95e 100644 --- a/app/Module/CustomTagsGedcom53.php +++ b/app/Module/CustomTagsGedcom53.php @@ -39,6 +39,16 @@ class CustomTagsGedcom53 extends AbstractModule implements ModuleConfigInterface use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsGedcom55.php b/app/Module/CustomTagsGedcom55.php index 7e671e0fcf..30ce147288 100644 --- a/app/Module/CustomTagsGedcom55.php +++ b/app/Module/CustomTagsGedcom55.php @@ -32,6 +32,16 @@ class CustomTagsGedcom55 extends AbstractModule implements ModuleConfigInterface use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsGedcomL.php b/app/Module/CustomTagsGedcomL.php index eee0bdcb16..cc2d8c0aea 100644 --- a/app/Module/CustomTagsGedcomL.php +++ b/app/Module/CustomTagsGedcomL.php @@ -74,6 +74,16 @@ class CustomTagsGedcomL extends AbstractModule implements ModuleConfigInterface, use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsLegacy.php b/app/Module/CustomTagsLegacy.php index b657d38291..57f4e3632b 100644 --- a/app/Module/CustomTagsLegacy.php +++ b/app/Module/CustomTagsLegacy.php @@ -31,6 +31,16 @@ class CustomTagsLegacy extends AbstractModule implements ModuleConfigInterface, use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @see http://support.legacyfamilytree.com/article/AA-00520/0/GEDCOM-Files-custom-tags-in-Legacy.html * * @return array<string,ElementInterface> diff --git a/app/Module/CustomTagsPersonalAncestralFile.php b/app/Module/CustomTagsPersonalAncestralFile.php index 28827c3f39..1519aa5c7b 100644 --- a/app/Module/CustomTagsPersonalAncestralFile.php +++ b/app/Module/CustomTagsPersonalAncestralFile.php @@ -34,6 +34,16 @@ class CustomTagsPersonalAncestralFile extends AbstractModule implements ModuleCo use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> * * @see http://wiki-de.genealogy.net/GEDCOM/_Nutzerdef-Tag diff --git a/app/Module/CustomTagsPhpGedView.php b/app/Module/CustomTagsPhpGedView.php index e71f38ae3f..a4a679629d 100644 --- a/app/Module/CustomTagsPhpGedView.php +++ b/app/Module/CustomTagsPhpGedView.php @@ -44,6 +44,16 @@ class CustomTagsPhpGedView extends AbstractModule implements ModuleConfigInterfa use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsReunion.php b/app/Module/CustomTagsReunion.php index 355ec70693..b2ada4aeb5 100644 --- a/app/Module/CustomTagsReunion.php +++ b/app/Module/CustomTagsReunion.php @@ -33,6 +33,16 @@ class CustomTagsReunion extends AbstractModule implements ModuleConfigInterface, use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsRootsMagic.php b/app/Module/CustomTagsRootsMagic.php index cbc96d0219..c35cf4b9a0 100644 --- a/app/Module/CustomTagsRootsMagic.php +++ b/app/Module/CustomTagsRootsMagic.php @@ -33,6 +33,16 @@ class CustomTagsRootsMagic extends AbstractModule implements ModuleConfigInterfa use ModuleCustomTagsTrait; /** + * Should this module be enabled when it is first installed? + * + * @return bool + */ + public function isEnabledByDefault(): bool + { + return false; + } + + /** * @return array<string,ElementInterface> */ public function customTags(): array diff --git a/app/Module/CustomTagsWebtrees.php b/app/Module/CustomTagsWebtrees.php index 7c98982690..9436edadd1 100644 --- a/app/Module/CustomTagsWebtrees.php +++ b/app/Module/CustomTagsWebtrees.php @@ -96,19 +96,27 @@ class CustomTagsWebtrees extends AbstractModule implements ModuleConfigInterface } /** - * @return array<array<string>> + * @return array<string,array<string>> */ - public function customSubTags(): array { return [ - ['FAM:CHAN', '_WT_USER', '0:1', ''], - ['INDI:CHAN', '_WT_USER', '0:1', ''], - ['NOTE:CHAN', '_WT_USER', '0:1', ''], - ['OBJE:CHAN', '_WT_USER', '0:1', ''], - ['REPO:CHAN', '_WT_USER', '0:1', ''], - ['SOUR:CHAN', '_WT_USER', '0:1', ''], - ['SUBM:CHAN', '_WT_USER', '0:1', ''], + 'FAM:CHAN' => [['_WT_USER']], + 'FAM:MARR' => [['_ASSO', '0:M', 'NOTE']], + 'FAM:SOUR:DATA' => [['TEXT']], + 'INDI:BIRT' => [['FAMC']], + 'INDI:CHAN' => [['_WT_USER']], + 'INDI:SOUR:DATA' => [['TEXT']], + 'NOTE' => [['RESN', '0:1', 'CHAN']], + 'NOTE:CHAN' => [['_WT_USER']], + 'OBJE' => [['RESN', '0:1', 'CHAN']], + 'OBJE:CHAN' => [['_WT_USER']], + 'REPO' => [['RESN', '0:1', 'CHAN']], + 'REPO:CHAN' => [['_WT_USER']], + 'SOUR' => [['RESN', '0:1', 'CHAN']], + 'SOUR:CHAN' => [['_WT_USER']], + 'SUBM' => [['RESN', '0:1', 'CHAN']], + 'SUBM:CHAN' => [['_WT_USER']], ]; } diff --git a/app/Module/ModuleCustomTagsTrait.php b/app/Module/ModuleCustomTagsTrait.php index 1c8b44bd97..5917f87898 100644 --- a/app/Module/ModuleCustomTagsTrait.php +++ b/app/Module/ModuleCustomTagsTrait.php @@ -38,36 +38,14 @@ trait ModuleCustomTagsTrait $element_factory = Registry::elementFactory(); $element_factory->register($this->customTags()); - foreach ($this->customSubTags() as $subtags) { - [$tag, $subtag, $repeat, $before] = $subtags; - - $element_factory->make($tag)->subtag($subtag, $repeat, $before); + foreach ($this->customSubTags() as $tag => $children) { + foreach ($children as $child) { + $element_factory->make($tag)->subtag(...$child); + } } } /** - * How should this module be identified in the control panel, etc.? - * - * @return string - */ - public function title(): string - { - /* I18N: Name of a module */ - return I18N::translate('Custom tags') . ' — ' . $this->customTagApplication(); - } - - /** - * A sentence describing what this module does. - * - * @return string - */ - public function description(): string - { - /* I18N: Description of the “Custom tags” module */ - return I18N::translate('Support for non-standard GEDCOM tags.') . ' — ' . $this->customTagApplication(); - } - - /** * @see https://www.gencom.org.nz/GEDCOM_tags.html * * @return array<string,ElementInterface> @@ -78,7 +56,7 @@ trait ModuleCustomTagsTrait } /** - * @return array<array<string>> + * @return array<string,array<string>> */ public function customSubTags(): array { @@ -86,6 +64,17 @@ trait ModuleCustomTagsTrait } /** + * A sentence describing what this module does. + * + * @return string + */ + public function description(): string + { + /* I18N: Description of the “Custom GEDCOM tags” module */ + return I18N::translate('Support for non-standard GEDCOM tags.') . ' — ' . $this->customTagApplication(); + } + + /** * The application for which we are supporting custom tags. * * @return string @@ -95,7 +84,6 @@ trait ModuleCustomTagsTrait return ''; } - /** * @param ServerRequestInterface $request * @@ -106,8 +94,21 @@ trait ModuleCustomTagsTrait $this->layout = 'layouts/administration'; return $this->viewResponse('modules/custom-tags/config', [ - 'tags' => $this->customTags(), - 'title' => $this->title(), + 'element_factory' => Registry::elementFactory(), + 'subtags' => $this->customSubTags(), + 'tags' => $this->customTags(), + 'title' => $this->title(), ]); } + + /** + * How should this module be identified in the control panel, etc.? + * + * @return string + */ + public function title(): string + { + /* I18N: Name of a module */ + return I18N::translate('Custom GEDCOM tags') . ' — ' . $this->customTagApplication(); + } } diff --git a/app/Services/GedcomService.php b/app/Services/GedcomService.php index 32c312d204..7328f9d0e5 100644 --- a/app/Services/GedcomService.php +++ b/app/Services/GedcomService.php @@ -153,7 +153,7 @@ class GedcomService '_MILITARY_SERVICE' => '_MILT', ]; - // Custom tags used by other applications, with direct synonyms + // Custom GEDCOM tags used by other applications, with direct synonyms private const TAG_SYNONYMS = [ // Convert PhpGedView tag to webtrees '_PGVU' => '_WT_USER', diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ccbf750c97..e470b6fbc6 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1630,11 +1630,6 @@ parameters: path: app/Services/RelationshipService.php - - message: "#^Method Fisharebest\\\\Webtrees\\\\Services\\\\RelationshipService\\:\\:legacyNameAlgorithm\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: app/Services/RelationshipService.php - - - message: "#^Method Fisharebest\\\\Webtrees\\\\Services\\\\RelationshipService\\:\\:matchRelationships\\(\\) should return array\\<Fisharebest\\\\Webtrees\\\\Relationship\\> but returns array\\<array\\<string\\>\\|Fisharebest\\\\Webtrees\\\\Relationship\\>\\.$#" count: 1 path: app/Services/RelationshipService.php diff --git a/resources/views/admin/control-panel.phtml b/resources/views/admin/control-panel.phtml index a36faf3b6e..9bd1da54f3 100644 --- a/resources/views/admin/control-panel.phtml +++ b/resources/views/admin/control-panel.phtml @@ -691,7 +691,7 @@ use Illuminate\Support\Collection; <li> <span class="fa-li"><?= view('icons/tag') ?></span> <a href="<?= e(route(ModulesCustomTagsPage::class)) ?>"> - <?= I18N::translate('Custom tags') ?> + <?= I18N::translate('Custom GEDCOM tags') ?> </a> <?= view('components/badge', ['count' => $custom_tags_modules_enabled->count(), 'total' => $custom_tags_modules_disabled->count(), 'context' => 'primary']) ?> </li> diff --git a/resources/views/cards/add-associate.phtml b/resources/views/cards/add-associate.phtml deleted file mode 100644 index e69e934f9e..0000000000 --- a/resources/views/cards/add-associate.phtml +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Tree; - -/** - * @var string $id - * @var int $level - * @var Tree $tree - */ - -?> - -<div class="card mb-4"> - <a class="card-header" href="#" data-toggle="collapse" data-target="#add-associate-<?= e($id) ?>" aria-expanded="false" aria-controls="add-associate"> - <?= I18N::translate('Associate') ?> - </a> - - <div class="card-body collapse" id="add-associate-<?= e($id) ?>"> - <?= FunctionsEdit::addSimpleTag($tree, $level . ' _ASSO') ?> - <?= FunctionsEdit::addSimpleTag($tree, ($level + 1) . ' RELA') ?> - <?= FunctionsEdit::addSimpleTag($tree, ($level + 1) . ' NOTE') ?> - <?= FunctionsEdit::addSimpleTag($tree, ($level + 1) . ' SHARED_NOTE') ?> - </div> -</div> diff --git a/resources/views/cards/add-fact.phtml b/resources/views/cards/add-fact.phtml deleted file mode 100644 index e8ae311ecc..0000000000 --- a/resources/views/cards/add-fact.phtml +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\GedcomTag; -use Fisharebest\Webtrees\Tree; - -/** - * @var string $tag - * @var Tree $tree - */ - -?> - -<div class="card mb-4"> - <a class="card-header" href="#" data-toggle="collapse" data-target="#add-fact-<?= $tag ?>" aria-expanded="false" aria-controls="add-fact-<?= $tag ?>"> - <?= GedcomTag::getLabel($tag) ?> - </a> - - <div class="card-body collapse" id="add-fact-<?= $tag ?>"> - <?php FunctionsEdit::addSimpleTags($tree, $tag) ?> - </div> -</div> diff --git a/resources/views/cards/add-media-object.phtml b/resources/views/cards/add-media-object.phtml deleted file mode 100644 index f7dbef1153..0000000000 --- a/resources/views/cards/add-media-object.phtml +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Tree; - -/** - * @var int $level - * @var Tree $tree - */ - -?> - -<div class="card mb-4"> - <a class="card-header" href="#" data-toggle="collapse" data-target="#add-media-object" aria-expanded="false" aria-controls="add-media-object"> - <?= I18N::translate('Add a media object') ?> - </a> - - <div class="card-body collapse" id="add-media-object"> - <?= FunctionsEdit::addSimpleTag($tree, $level . ' OBJE') ?> - </div> -</div> diff --git a/resources/views/cards/add-note.phtml b/resources/views/cards/add-note.phtml deleted file mode 100644 index 85316052d5..0000000000 --- a/resources/views/cards/add-note.phtml +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Tree; - -/** - * @var int $level - * @var Tree $tree - */ - -?> - -<div class="card mb-4"> - <a class="card-header" href="#" data-toggle="collapse" data-target="#add-note" aria-expanded="false" aria-controls="add-note"> - <?= I18N::translate('Note') ?> - </a> - - <div class="card-body collapse" id="add-note"> - <?= FunctionsEdit::addSimpleTag($tree, $level . ' NOTE') ?> - </div> -</div> diff --git a/resources/views/cards/add-restriction.phtml b/resources/views/cards/add-restriction.phtml deleted file mode 100644 index 263ed56c33..0000000000 --- a/resources/views/cards/add-restriction.phtml +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Tree; - -/** - * @var int $level - * @var Tree $tree - */ - -?> - -<div class="card mb-4"> - <a class="card-header" href="#" data-toggle="collapse" data-target="#add-restriction" aria-expanded="false" aria-controls="add-restriction"> - <?= I18N::translate('Restriction') ?> - </a> - - <div class="card-body collapse" id="add-restriction"> - <?= FunctionsEdit::addSimpleTag($tree, $level . ' RESN') ?> - </div> -</div> diff --git a/resources/views/cards/add-shared-note.phtml b/resources/views/cards/add-shared-note.phtml deleted file mode 100644 index 03cf4c4124..0000000000 --- a/resources/views/cards/add-shared-note.phtml +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Tree; - -/** - * @var int $level - * @var Tree $tree - */ - -?> - -<div class="card mb-4"> - <a class="card-header" href="#" data-toggle="collapse" data-target="#add-note-object" aria-expanded="false" aria-controls="add-note-object"> - <?= I18N::translate('Shared note') ?> - </a> - - <div class="card-body collapse" id="add-note-object"> - <?= FunctionsEdit::addSimpleTag($tree, $level . ' SHARED_NOTE') ?> - </div> -</div> diff --git a/resources/views/cards/add-sour-data-even.phtml b/resources/views/cards/add-sour-data-even.phtml deleted file mode 100644 index 943e2b153b..0000000000 --- a/resources/views/cards/add-sour-data-even.phtml +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Tree; - -/** - * @var Tree $tree - */ - -?> - -<div class="card mb-4"> - <a class="card-header" href="#" data-toggle="collapse" data-target="#add-sour-data-even-object" aria-expanded="false" aria-controls="add-sour-data-even-object"> - <?= I18N::translate('Add an event') ?> - </a> - - <div class="card-body collapse" id="add-sour-data-even-object"> - <?= FunctionsEdit::addSimpleTag($tree, '2 EVEN') ?> - <?= FunctionsEdit::addSimpleTag($tree, '3 DATE') ?> - <?= FunctionsEdit::addSimpleTag($tree, '3 PLAC') ?> - </div> -</div> diff --git a/resources/views/cards/add-source-citation.phtml b/resources/views/cards/add-source-citation.phtml deleted file mode 100644 index bcc3c744e7..0000000000 --- a/resources/views/cards/add-source-citation.phtml +++ /dev/null @@ -1,80 +0,0 @@ -<?php - -use Fisharebest\Webtrees\Fact; -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\Gedcom; -use Fisharebest\Webtrees\GedcomTag; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Tree; -use Illuminate\Support\Collection; - -/** - * @var string $bdm - * @var bool $full_citations - * @var int $level - * @var string $prefer_level2_sources - * @var string $quick_required_facts - * @var string $quick_required_famfacts - * @var Tree $tree - */ - -?> - -<div class="card mb-4"> - <a class="card-header" href="#" data-toggle="collapse" data-target="#add-source-citation" aria-expanded="false" aria-controls="add-source-citation"> - <?= I18N::translate('Source') ?> - </a> - - <div class="card-body collapse" id="add-source-citation"> - <?= FunctionsEdit::addSimpleTag($tree, $level . ' SOUR') ?> - - <?php if ($level === 1) : ?> - <div class="row"> - <div class="col-sm-3"></div> - <div class="col-sm-9"> - <?php if (str_contains($bdm, 'B')) : ?> - <label> - <input type="checkbox" name="SOUR_INDI" <?= $prefer_level2_sources === '2' ? 'checked' : '' ?> value="1"> - <?= I18N::translate('Individual') ?> - </label> - <?php if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $quick_required_facts, $matches)) : ?> - <?php foreach (Fact::sortFactTags(new Collection($matches[1])) as $match) : ?> - <label> - <input type="checkbox" name="SOUR_<?= $match ?>" <?= $prefer_level2_sources === '1' ? 'checked' : '' ?> value="1"> - <?= GedcomTag::getLabel($match) ?> - </label> - <?php endforeach ?> - <?php endif ?> - <?php endif ?> - - <?php if (str_contains($bdm, 'M')) : ?> - <label> - <input type="checkbox" name="SOUR_FAM" <?= $prefer_level2_sources === '2' ? 'checked' : '' ?> value="1"> - <?= I18N::translate('Family') ?> - </label> - <?php if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $quick_required_famfacts, $matches)) : ?> - <?php foreach (Fact::sortFactTags(new Collection($matches[1])) as $match) : ?> - <label> - <input type="checkbox" name="SOUR_<?= $match ?>" <?= $prefer_level2_sources === '1' ? 'checked' : '' ?> value="1"> - <?= GedcomTag::getLabel($match) ?> - </label> - <?php endforeach ?> - <?php endif ?> - <?php endif ?> - </div> - </div> - <?php endif ?> - - <?= FunctionsEdit::addSimpleTag($tree, ($level + 1) . ' PAGE') ?> - <?= FunctionsEdit::addSimpleTag($tree, ($level + 1) . ' DATA') ?> - <?= FunctionsEdit::addSimpleTag($tree, ($level + 2) . ' TEXT') ?> - - <?php if ($full_citations) : ?> - <?= FunctionsEdit::addSimpleTag($tree, ($level + 2) . ' DATE', '', I18N::translate('Date of entry in original source')) ?> - <?= FunctionsEdit::addSimpleTag($tree, ($level + 1) . ' QUAY') ?> - <?php endif ?> - - <?= FunctionsEdit::addSimpleTag($tree, ($level + 1) . ' OBJE') ?> - <?= FunctionsEdit::addSimpleTag($tree, ($level + 1) . ' SHARED_NOTE') ?> - </div> -</div> diff --git a/resources/views/edit/add-fact.phtml b/resources/views/edit/add-fact.phtml deleted file mode 100644 index 6bf82e34ac..0000000000 --- a/resources/views/edit/add-fact.phtml +++ /dev/null @@ -1,110 +0,0 @@ -<?php - -use Fisharebest\Webtrees\Auth; -use Fisharebest\Webtrees\Config; -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\GedcomRecord; -use Fisharebest\Webtrees\GedcomTag; -use Fisharebest\Webtrees\Http\RequestHandlers\EditFactAction; -use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Tree; -use Ramsey\Uuid\Uuid; - -/** - * @var string $fact - * @var GedcomRecord $record - * @var string $title - * @var Tree $tree - */ - -?> - -<h2 class="wt-page-title"><?= $title ?></h2> - -<form method="post" action="<?= e(route(EditFactAction::class, ['tree' => $tree->name(), 'xref' => $record->xref()])) ?>" class="wt-page-content"> - <?= csrf_field() ?> - - <?php FunctionsEdit::createAddForm($tree, $fact) ?> - - <?php if ($record->tag() === 'SOUR' && $fact === 'DATA') : ?> - <?= view('cards/add-note', ['level' => 2, 'tree' => $tree]) ?> - <?= view('cards/add-shared-note', ['level' => 2, 'tree' => $tree]) ?> - <?php endif ?> - - <?php if (($record->tag() === 'INDI' || $record->tag() === 'FAM') && $fact !== 'OBJE' && $fact !== 'NOTE' && $fact !== 'SHARED_NOTE' && $fact !== 'REPO' && $fact !== 'SOUR' && $fact !== 'SUBM' && $fact !== 'ASSO' && $fact !== 'ALIA' && $fact !== 'SEX') : ?> - <?= view('cards/add-source-citation', [ - 'level' => 2, - 'full_citations' => $tree->getPreference('FULL_SOURCES'), - 'tree' => $tree, - ]) ?> - - <?php if ($tree->getPreference('MEDIA_UPLOAD') >= Auth::accessLevel($tree)) : ?> - <?= view('cards/add-media-object', [ - 'level' => 2, - 'tree' => $tree, - ]) ?> - <?php endif ?> - - <?php if ($fact !== 'NOTE') : ?> - <?= view('cards/add-note', [ - 'level' => 2, - 'tree' => $tree, - ]) ?> - - <?= view('cards/add-shared-note', [ - 'level' => 2, - 'tree' => $tree, - ]) ?> - <?php endif ?> - - <?= view('cards/add-associate', [ - 'id' => Uuid::uuid4()->toString(), - 'level' => 2, - 'tree' => $tree, - ]) ?> - <?php if (in_array($fact, Config::twoAssociates(), true)) : ?> - <?= view('cards/add-associate', [ - 'id' => Uuid::uuid4()->toString(), - 'level' => 2, - 'tree' => $tree, - ]) ?> - <?php endif ?> - - <?= view('cards/add-restriction', [ - 'level' => 2, - 'tree' => $tree, - ]) ?> - <?php endif ?> - - <div class="form-group row"> - <label class="col-sm-3 col-form-label" for="keep_chan"> - <?= I18N::translate('Last change') ?> - </label> - <div class="col-sm-9"> - <?= view('components/checkbox-inline', ['label' => I18N::translate('Keep the existing “last change” information'), 'name' => 'keep_chan', 'checked' => (bool) $tree->getPreference('NO_UPDATE_CHAN')]) ?> - <?= GedcomTag::getLabelValue('DATE', view('components/datetime', ['timestamp' => $record->lastChangeTimestamp()])) ?> - <?= GedcomTag::getLabelValue('_WT_USER', e($record->lastChangeUser())) ?> - </div> - </div> - - <div class="form-group row"> - <div class="col-sm-3 wt-page-options-label"> - </div> - <div class="col-sm-9 wt-page-options-value"> - <button class="btn btn-primary" type="submit"> - <?= view('icons/save') ?> - <?= /* I18N: A button label. */ - I18N::translate('save') ?> - </button> - <a class="btn btn-secondary" href="<?= e($record->url()) ?>"> - <?= view('icons/cancel') ?> - <?= /* I18N: A button label. */ - I18N::translate('cancel') ?> - </a> - </div> - </div> -</form> - -<?= view('modals/on-screen-keyboard') ?> -<?= view('modals/ajax') ?> -<?= view('edit/initialize-calendar-popup') ?> diff --git a/resources/views/edit/edit-fact.phtml b/resources/views/edit/edit-fact.phtml index fc1350343c..3af77ad995 100644 --- a/resources/views/edit/edit-fact.phtml +++ b/resources/views/edit/edit-fact.phtml @@ -1,14 +1,10 @@ <?php -use Fisharebest\Webtrees\Auth; -use Fisharebest\Webtrees\Config; use Fisharebest\Webtrees\Fact; -use Fisharebest\Webtrees\Functions\FunctionsEdit; use Fisharebest\Webtrees\Http\RequestHandlers\EditFactAction; use Fisharebest\Webtrees\Http\RequestHandlers\EditRawFactPage; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Tree; -use Ramsey\Uuid\Uuid; /** * @var bool $can_edit_raw @@ -26,84 +22,7 @@ use Ramsey\Uuid\Uuid; <?= csrf_field() ?> <input type="hidden" name="url" value="<?= e($url) ?>"> - <?php FunctionsEdit::createEditForm($fact) ?> - - <?php - $level1type = $fact->getTag(); - switch ($fact->record()->tag()) { - case 'SOUR': - if ($level1type === 'DATA') { - // SOUR:DATA facts may take a NOTE (but the SOUR record may not). - echo view('cards/add-note', [ - 'level' => 2, - 'tree' => $tree, - ]); - echo view('cards/add-shared-note', [ - 'level' => 2, - 'tree' => $tree, - ]); - // SOUR:DATA facts may also take multiple EVEN. - echo view('cards/add-sour-data-even', [ - 'tree' => $tree, - ]); - } - break; - case 'FAM': - case 'INDI': - // FAM and INDI records have real facts. They can take NOTE/SOUR/OBJE/etc. - if ($level1type !== 'SEX' && $level1type !== 'NOTE' && $level1type !== 'ALIA') { - if ($level1type !== 'SOUR') { - echo view('cards/add-source-citation', [ - 'level' => 2, - 'full_citations' => $tree->getPreference('FULL_SOURCES'), - 'tree' => $tree, - ]); - } - if ($level1type !== 'OBJE') { - if ($tree->getPreference('MEDIA_UPLOAD') >= Auth::accessLevel($tree)) { - echo view('cards/add-media-object', [ - 'level' => 2, - 'tree' => $tree, - ]); - } - } - echo view('cards/add-note', [ - 'level' => 2, - 'tree' => $tree, - ]); - echo view('cards/add-shared-note', [ - 'level' => 2, - 'tree' => $tree, - ]); - if ($level1type !== 'ASSO' && $level1type !== 'NOTE' && $level1type !== 'SOUR') { - echo view('cards/add-associate', [ - 'id' => Uuid::uuid4()->toString(), - 'level' => 2, - 'tree' => $tree, - ]); - } - // allow to add godfather and godmother for CHR fact or best man and bridesmaid for MARR fact in one window - if (in_array($level1type, Config::twoAssociates(), true)) { - echo view('cards/add-associate', [ - 'id' => Uuid::uuid4()->toString(), - 'level' => 2, - 'tree' => $tree, - ]); - } - if ($level1type !== 'SOUR') { - echo view('cards/add-restriction', [ - 'level' => 2, - 'tree' => $tree, - ]); - } - } - break; - default: - // Other types of record do not have these lower-level records - break; - } - - ?> + <?= view('edit/edit-gedcom-fields', ['gedcom' => $fact->insertMissingSubtags(), 'hierarchy' => explode(':', $fact->tag()), 'tree' => $fact->record()->tree(), 'prefix' => '']) ?> <div class="form-group row"> <div class="col-sm-3 wt-page-options-label"> diff --git a/resources/views/edit/link-spouse-to-individual.phtml b/resources/views/edit/link-spouse-to-individual.phtml index 4091153080..7e5bc01d1d 100644 --- a/resources/views/edit/link-spouse-to-individual.phtml +++ b/resources/views/edit/link-spouse-to-individual.phtml @@ -1,36 +1,44 @@ <?php -use Fisharebest\Webtrees\Functions\FunctionsEdit; -use Fisharebest\Webtrees\Http\RequestHandlers\LinkSpouseToIndividualAction; use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Individual; use Fisharebest\Webtrees\Tree; /** - * @var Individual $individual - * @var string $label - * @var string $title - * @var Tree $tree - * @var string $xref + * @var string $title + * @var string $label + * @var string $cancel_url + * @var string $post_url + * @var Tree $tree */ ?> <h2 class="wt-page-title"><?= $title ?></h2> -<form method="post" action="<?= e(route(LinkSpouseToIndividualAction::class, ['tree' => $tree->name(), 'xref' => $xref])) ?>" class="wt-page-content"> +<form method="post" action="<?= e($post_url) ?>" class="wt-page-content"> <?= csrf_field() ?> - <div class="form-group row"> - <label class="col-sm-3 col-form-label" for="spouse"> + <div class="card mb-2"> + <div class="card-header"> <?= $label ?> - </label> - <div class="col-sm-9"> + </div> + <div class="card-body pb-1"> <?= view('components/select-individual', ['name' => 'spid', 'id' => 'spouse', 'tree' => $tree]) ?> </div> </div> - <?= FunctionsEdit::addSimpleTags($tree, 'MARR') ?> + <?php foreach ($facts ?? [] as $prefix => $prefix_facts) : ?> + <?php foreach ($prefix_facts as $fact) : ?> + <div class="card mb-2"> + <div class="card-header"> + <?= $fact->label() ?> + </div> + <div class="card-body pb-1"> + <?= view('edit/edit-gedcom-fields', ['gedcom' => $fact->insertMissingSubtags(), 'hierarchy' => explode(':', $fact->tag()), 'tree' => $fact->record()->tree(), 'prefix' => $prefix]) ?> + </div> + </div> + <?php endforeach ?> + <?php endforeach ?> <div class="row form-group"> <div class="col-sm-9 offset-sm-3"> @@ -39,7 +47,7 @@ use Fisharebest\Webtrees\Tree; <?= /* I18N: A button label. */ I18N::translate('save') ?> </button> - <a class="btn btn-secondary" href="<?= e($individual->url()) ?>"> + <a class="btn btn-secondary" href="<?= e($cancel_url) ?>"> <?= view('icons/cancel') ?> <?= /* I18N: A button label. */ I18N::translate('cancel') ?> @@ -47,5 +55,3 @@ use Fisharebest\Webtrees\Tree; </div> </div> </form> - -<?= view('modals/ajax') ?> diff --git a/resources/views/edit/new-individual.phtml b/resources/views/edit/new-individual.phtml index d64e097f6f..2c92ba3bd0 100644 --- a/resources/views/edit/new-individual.phtml +++ b/resources/views/edit/new-individual.phtml @@ -11,344 +11,57 @@ use Fisharebest\Webtrees\Http\RequestHandlers\AddParentToIndividualAction; use Fisharebest\Webtrees\Http\RequestHandlers\AddSpouseToFamilyAction; use Fisharebest\Webtrees\Http\RequestHandlers\AddSpouseToIndividualAction; use Fisharebest\Webtrees\Http\RequestHandlers\AddUnlinkedAction; -use Fisharebest\Webtrees\Http\RequestHandlers\EditFactAction; use Fisharebest\Webtrees\Http\RequestHandlers\EditRawFactPage; +use Fisharebest\Webtrees\Http\RequestHandlers\EditFactAction; use Fisharebest\Webtrees\Http\RequestHandlers\ManageTrees; use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Individual; -use Fisharebest\Webtrees\Registry; -use Fisharebest\Webtrees\SurnameTradition; use Fisharebest\Webtrees\Tree; -use Fisharebest\Webtrees\View; -use Illuminate\Support\Collection; /** - * @var Family|null $family - * @var string $famtag - * @var string $gender - * @var Individual|null $individual - * @var Fact|null $name_fact - * @var string $next_action - * @var string $title - * @var Tree $tree + * @var string $cancel_url + * @var string $post_url + * @var string $title + * @var Tree $tree + * @var string $url */ ?> -<?php -if ($individual instanceof Individual) { - $xref = $individual->xref(); - $cancel_url = $individual->url(); -} elseif ($family !== null) { - $xref = $family->xref(); - $cancel_url = $family->url(); -} else { - $cancel_url = route(ManageTrees::class, ['tree' => $tree->name()]); - $xref = 'new'; -} - -// Different cultures do surnames differently -$surname_tradition = SurnameTradition::create($tree->getPreference('SURNAME_TRADITION')); - -if ($name_fact instanceof Fact) { - // Editing an existing name - $name_fact_id = $name_fact->id(); - $namerec = $name_fact->gedcom(); - $name_fields = [ - 'NAME' => $name_fact->value(), - 'TYPE' => $name_fact->attribute('TYPE'), - 'NPFX' => $name_fact->attribute('NPFX'), - 'GIVN' => $name_fact->attribute('GIVN'), - 'NICK' => $name_fact->attribute('NICK'), - 'SPFX' => $name_fact->attribute('SPFX'), - 'SURN' => $name_fact->attribute('SURN'), - 'NSFX' => $name_fact->attribute('NSFX'), - ]; -} else { - // Creating a new name - $name_fact_id = ''; - $namerec = ''; - $name_fields = [ - 'NAME' => '', - 'TYPE' => '', - 'NPFX' => '', - 'GIVN' => '', - 'NICK' => '', - 'SPFX' => '', - 'SURN' => '', - 'NSFX' => '', - ]; - - // Inherit surname from parents, spouse or child - if ($family) { - $father = $family->husband(); - if ($father instanceof Individual && $father->facts(['NAME'])->isNotEmpty()) { - $father_name = $father->facts(['NAME'])->first()->value(); - } else { - $father_name = ''; - } - $mother = $family->wife(); - if ($mother instanceof Individual && $mother->facts(['NAME'])->isNotEmpty()) { - $mother_name = $mother->facts(['NAME'])->first()->value(); - } else { - $mother_name = ''; - } - } else { - $father = null; - $mother = null; - $father_name = ''; - $mother_name = ''; - } - if ($individual && $individual->facts(['NAME'])->isNotEmpty()) { - $indi_name = $individual->facts(['NAME'])->first()->value(); - } else { - $indi_name = ''; - } - - switch ($next_action) { - case AddChildToFamilyAction::class: - $name_fields = array_merge($name_fields, $surname_tradition->newChildNames($father_name, $mother_name, $gender)); - break; - case AddChildToIndividualAction::class: - if ($individual->sex() === 'F') { - $name_fields = array_merge($name_fields, $surname_tradition->newChildNames('', $indi_name, $gender)); - } else { - $name_fields = array_merge($name_fields, $surname_tradition->newChildNames($indi_name, '', $gender)); - } - break; - case AddParentToIndividualAction::class: - $name_fields = array_merge($name_fields, $surname_tradition->newParentNames($indi_name, $gender)); - break; - case AddSpouseToFamilyAction::class: - if ($father) { - $name_fields = array_merge($name_fields, $surname_tradition->newSpouseNames($father_name, $gender)); - } else { - $name_fields = array_merge($name_fields, $surname_tradition->newSpouseNames($mother_name, $gender)); - } - break; - case AddSpouseToIndividualAction::class: - $name_fields = array_merge($name_fields, $surname_tradition->newSpouseNames($indi_name, $gender)); - break; - case AddUnlinkedAction::class: - case EditFactAction::class: - if ($surname_tradition->hasSurnames()) { - $name_fields['NAME'] = '//'; - } - break; - } -} - -$bdm = ''; // used to copy '1 SOUR' to '2 SOUR' for BIRT DEAT MARR - -?> <h2 class="wt-page-title"><?= $title ?></h2> -<form method="post" action="<?= e(route($next_action, ['tree' => $tree->name(), 'xref' => $xref, 'fact_id' => $name_fact ? $name_fact->id() : null])) ?>" onsubmit="return checkform();"> - <input type="hidden" name="fact_id" value="<?= e($name_fact_id) ?>"> - <input type="hidden" name="famtag" value="<?= e($famtag) ?>"> - <input type="hidden" name="gender" value="<?= $gender ?>"> +<form method="post" action="<?= e($post_url) ?>"> <?= csrf_field() ?> - <?php if ($next_action === AddChildToFamilyAction::class || $next_action === AddChildToIndividualAction::class) : ?> - <?= FunctionsEdit::addSimpleTag($tree, '0 PEDI') ?> - <?php endif ?> - - <?php - // If we are adding a new individual, choose the sex. - if ($next_action !== EditFactAction::class) { - if ($famtag === 'HUSB' || $gender === 'M') { - echo FunctionsEdit::addSimpleTag($tree, '0 SEX M'); - } elseif ($famtag === 'WIFE' || $gender === 'F') { - echo FunctionsEdit::addSimpleTag($tree, '0 SEX F'); - } else { - echo FunctionsEdit::addSimpleTag($tree, '0 SEX'); - } - } - ?> - - <?php - // First - standard name fields - foreach ($name_fields as $tag => $value) { - if (substr_compare($tag, '_', 0, 1) !== 0) { - echo FunctionsEdit::addSimpleTag($tree, '0 ' . $tag . ' ' . $value, '', ''); - } - } + <?php foreach ($facts ?? [] as $prefix => $prefix_facts) : ?> + <?php foreach ($prefix_facts as $fact) : ?> + <div class="card mb-2"> + <div class="card-header"> + <?= $fact->label() ?> + </div> + <div class="card-body pb-1"> + <?= view('edit/edit-gedcom-fields', ['gedcom' => $fact->insertMissingSubtags(), 'hierarchy' => explode(':', $fact->tag()), 'tree' => $fact->record()->tree(), 'prefix' => $prefix]) ?> + </div> + </div> + <?php endforeach ?> + <?php endforeach ?> - // Second - advanced name fields - if ($surname_tradition->hasMarriedNames() || preg_match('/\n2 _MARNM /', $namerec)) { - $adv_name_fields = ['_MARNM' => '']; - } else { - $adv_name_fields = []; - } - if (preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('ADVANCED_NAME_FACTS'), $match)) { - foreach ($match[1] as $tag) { - // Ignore advanced facts that duplicate standard facts - if (!in_array($tag, ['TYPE', 'NPFX', 'GIVN', 'NICK', 'SPFX', 'SURN', 'NSFX'])) { - $adv_name_fields[$tag] = ''; - } - } - } - - foreach (array_keys($adv_name_fields) as $tag) { - // Edit existing tags, grouped together - if (preg_match_all('/2 ' . $tag . ' (.+)/', $namerec, $match)) { - foreach ($match[1] as $value) { - $label = Registry::elementFactory()->make('INDI:NAME:' . $tag)->label(); - echo FunctionsEdit::addSimpleTag($tree, '2 ' . $tag . ' ' . $value, '', $label); - if ($tag === '_MARNM') { - preg_match_all('/\/([^\/]*)\//', $value, $matches); - echo FunctionsEdit::addSimpleTag($tree, '2 _MARNM_SURN ' . implode(',', $matches[1])); - } - } - } - // Allow a new tag to be entered - if (!array_key_exists($tag, $name_fields)) { - $label = Registry::elementFactory()->make('INDI:NAME:' . $tag)->label(); - echo FunctionsEdit::addSimpleTag($tree, '0 ' . $tag, '', $label); - if ($tag === '_MARNM') { - echo FunctionsEdit::addSimpleTag($tree, '0 _MARNM_SURN'); - } - } - } - - // Third - new/existing custom name fields - foreach ($name_fields as $tag => $value) { - if (substr_compare($tag, '_', 0, 1) === 0) { - echo FunctionsEdit::addSimpleTag($tree, '0 ' . $tag . ' ' . $value); - if ($tag === '_MARNM') { - preg_match_all('/\/([^\/]*)\//', $value, $matches); - echo FunctionsEdit::addSimpleTag($tree, '2 _MARNM_SURN ' . implode(',', $matches[1])); - } - } - } - - // Fourth - SOUR, NOTE, _CUSTOM, etc. - if ($namerec !== '') { - $gedlines = explode("\n", $namerec); // -- find the number of lines in the record - $fields = explode(' ', $gedlines[0]); - $glevel = $fields[0]; - $level = $glevel; - $type = $fields[1]; - $tags = []; - $i = 0; - do { - if ($type !== 'TYPE' && !array_key_exists($type, $name_fields) && !array_key_exists($type, $adv_name_fields)) { - $text = ''; - for ($j = 2; $j < count($fields); $j++) { - if ($j > 2) { - $text .= ' '; - } - $text .= $fields[$j]; - } - while (($i + 1 < count($gedlines)) && (preg_match('/' . ($level + 1) . ' CONT ?(.*)/', $gedlines[$i + 1], $cmatch) > 0)) { - $text .= "\n" . $cmatch[1]; - $i++; - } - echo FunctionsEdit::addSimpleTag($tree, $level . ' ' . $type . ' ' . $text); - } - $tags[] = $type; - $i++; - if (isset($gedlines[$i])) { - $fields = explode(' ', $gedlines[$i]); - $level = $fields[0]; - if (isset($fields[1])) { - $type = $fields[1]; - } - } - } while (($level > $glevel) && ($i < count($gedlines))); - } - - // If we are adding a new individual, add the basic details - if ($next_action !== EditFactAction::class) { - $bdm = 'BD'; - $tags = new Collection(); - preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches); - $tags = $tags->merge($matches[1]); - - // If adding a spouse add the option to add a marriage fact to the new family - if ($next_action === AddSpouseToIndividualAction::class || $next_action === AddSpouseToFamilyAction::class) { - $bdm .= 'M'; - preg_match_all('/(' . Gedcom::REGEX_TAG . ')/', $tree->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches); - $tags = $tags->merge($matches[1]); - } - - foreach (Fact::sortFactTags($tags) as $tag) { - echo view('cards/add-fact', [ - 'tag' => $tag, - 'tree' => $tree, - ]); - } - } - - if ($next_action === EditFactAction::class ) { - // GEDCOM 5.5.1 spec says NAME doesn’t get a OBJE - echo view('cards/add-source-citation', [ - 'level' => 2, - 'full_citations' => $tree->getPreference('FULL_SOURCES'), - 'tree' => $tree, - ]); - echo view('cards/add-note', [ - 'level' => 2, - 'tree' => $tree, - ]); - echo view('cards/add-shared-note', [ - 'level' => 2, - 'tree' => $tree, - ]); - echo view('cards/add-restriction', [ - 'level' => 2, - 'tree' => $tree, - ]); - } else { - echo view('cards/add-source-citation', [ - 'bdm' => $bdm, - 'level' => 1, - 'full_citations' => (bool) $tree->getPreference('FULL_SOURCES'), - 'prefer_level2_sources' => $tree->getPreference('PREFER_LEVEL2_SOURCES'), - 'quick_required_facts' => $tree->getPreference('QUICK_REQUIRED_FACTS'), - 'quick_required_famfacts' => $tree->getPreference('QUICK_REQUIRED_FAMFACTS'), - 'tree' => $tree, - ]); - echo view('cards/add-note', [ - 'level' => 1, - 'tree' => $tree, - ]); - echo view('cards/add-shared-note', [ - 'level' => 1, - 'tree' => $tree, - ]); - echo view('cards/add-restriction', [ - 'level' => 1, - 'tree' => $tree, - ]); - } - - ?> <div class="row form-group"> <div class="col-sm-9 offset-sm-3"> - <button class="btn btn-primary" type="submit"> + <button class="btn btn-primary" type="submit" name="url" value="<?= e($url) ?>"> <?= view('icons/save') ?> <?= /* I18N: A button label. */ I18N::translate('save') ?> </button> - <?php if ($next_action !== EditFactAction::class) : ?> - <button class="btn btn-primary" type="submit" name="goto" value="new"> - <?= view('icons/save') ?> - <?= /* I18N: A button label. */ - I18N::translate('go to new individual') ?> - </button> - <?php endif ?> + <button class="btn btn-primary" type="submit"> + <?= view('icons/save') ?> + <?= /* I18N: A button label. */ + I18N::translate('go to new individual') ?> + </button> <a class="btn btn-secondary" href="<?= e($cancel_url) ?>"> <?= view('icons/cancel') ?> <?= /* I18N: A button label. */ I18N::translate('cancel') ?> </a> - - <?php if ($name_fact instanceof Fact && (Auth::isAdmin() || $tree->getPreference('SHOW_GEDCOM_RECORD'))) : ?> - <a class="btn btn-link" href="<?= e(route(EditRawFactPage::class, ['xref' => $xref, 'fact_id' => $name_fact->id(), 'tree' => $tree->name()])) ?>"> - <?= I18N::translate('Edit the raw GEDCOM') ?> - </a> - <?php endif ?> </div> </div> </form> @@ -356,160 +69,3 @@ $bdm = ''; // used to copy '1 SOUR' to '2 SOUR' for BIRT DEAT MARR <?= view('modals/on-screen-keyboard') ?> <?= view('modals/ajax') ?> <?= view('edit/initialize-calendar-popup') ?> - -<?php View::push('javascript') ?> -<script> - var SURNAME_TRADITION = <?= json_encode($tree->getPreference('SURNAME_TRADITION')) ?>; - - var NAME = $("[name=NAME]"); - - // Generate a full name from the name components - function generate_name() { - var npfx = document.querySelector("[name=NPFX]").value; - var givn = document.querySelector("[name=GIVN]").value; - var spfx = document.querySelector("[name=SPFX]").value; - var surn = document.querySelector("[name=SURN]").value; - var nsfx = document.querySelector("[name=NSFX]").value; - var sex_input = document.querySelector("[name=SEX]:checked"); - var sex = sex_input ? sex_input.value : "U"; - - return webtrees.buildNameFromParts(npfx, givn, spfx, surn, nsfx, sex); - } - - // Update the NAME and _MARNM fields from the name components - // and also display the value in read-only "gedcom" format. - function updatewholename() { - // Don’t update the name if the user manually changed it - if (manualChange) { - return; - } - - var npfx = document.querySelector("[name=NPFX]").value; - var givn = document.querySelector("[name=GIVN]").value; - var spfx = document.querySelector("[name=SPFX]").value; - var surn = document.querySelector("[name=SURN]").value; - var nsfx = document.querySelector("[name=NSFX]").value; - var name = generate_name(); - - var display_id = NAME.attr("id") + "_display"; - - NAME.val(name); - $("#" + display_id).text(name); - - // Married names inherit some NSFX values, but not these - nsfx = nsfx.replace(/^(I|II|III|IV|V|VI|Junior|Jr\.?|Senior|Sr\.?)$/i, ""); - - // Update _MARNM field from _MARNM_SURN field and display it - var ip = document.getElementsByTagName("input"); - var marnm_id = ""; - var romn = ""; - var heb = ""; - var i; - - for (i = 0; i < ip.length; i++) { - if (ip[i].id.indexOf("_HEB") === 0) { - // Remember this field - we might need it later - heb = val; - } - if (ip[i].id.indexOf("ROMN") === 0) { - // Remember this field - we might need it later - romn = val; - } - } - - for (i = 0; i < ip.length; i++) { - var val = ip[i].value; - - if (ip[i].id.indexOf("_MARNM") === 0) { - if (ip[i].id.indexOf("_MARNM_SURN") === 0) { - var msurn = ""; - if (val !== "") { - if (surn === "" || webtrees.detectScript(val) === webtrees.detectScript(surn)) { - // Same script as NAME field? - msurn = name.replace(/\/.*\//, "/" + val + "/"); - } else if (heb !== "" && webtrees.detectScript(val) === webtrees.detectScript(heb)) { - // Same script as _HEB field? - msurn = heb.replace(/\/.*\//, "/" + val + "/"); - } else if (romn !== "" && webtrees.detectScript(val) === webtrees.detectScript(romn)) { - //. Same script as ROMN field - msurn = romn.replace(/\/.*\//, "/" + val + "/"); - } - } - document.getElementById(marnm_id).value = msurn; - document.getElementById(marnm_id + "_display").innerHTML = msurn; - } else { - marnm_id = ip[i].id; - } - } - } - } - - // Toggle the name editor fields between - // <input type="hidden"> <span style="display:inline"> - // <input type="text"> <span style="display:none"> - - var oldName = ""; - - // Calls to generate_name() trigger an update - hence need to - // set the manual change to true first. We are probably - // listening to the wrong events on the input fields... - var manualChange = generate_name() !== NAME.val(); - - function convertHidden(eid) { - var input1 = $("#" + eid); - var input2 = $("#" + eid + "_display"); - - if (input1.attr("type") === "hidden") { - input1.attr("type", "text"); - input2.hide(); - } else { - input1.attr("type", "hidden"); - input2.show(); - } - } - - /** - * if the user manually changed the NAME field, then update the textual - * HTML representation of it - * If the value changed set manualChange to true so that changing - * the other fields doesn’t change the NAME line - */ - function updateTextName(eid) { - var element = document.getElementById(eid); - if (element) { - if (element.value !== oldName) { - manualChange = true; - } - var delement = document.getElementById(eid + "_display"); - if (delement) { - delement.innerHTML = element.value; - } - } - } - - function checkform() { - var ip = document.getElementsByTagName("input"); - for (var i = 0; i < ip.length; i++) { - // ADD slashes to _HEB and _AKA names - if (ip[i].id.indexOf("_AKA") === 0 || ip[i].id.indexOf("_HEB") === 0 || ip[i].id.indexOf("ROMN") === 0) - if (ip[i].value.indexOf("/") < 0 && ip[i].value !== "") - ip[i].value = ip[i].value.replace(/([^\s]+)\s*$/, "/$1/"); - // Blank out temporary _MARNM_SURN - if (ip[i].id.indexOf("_MARNM_SURN") === 0) - ip[i].value = ""; - // Convert "xxx yyy" and "xxx y yyy" surnames to "xxx,yyy" - if ((SURNAME_TRADITION === "spanish" || "SURNAME_TRADITION" === "portuguese") && ip[i].id.indexOf("SURN") === 0) { - ip[i].value = document.forms[0].SURN.value.replace(/^\s*([^\s,]{2,})\s+([iIyY] +)?([^\s,]{2,})\s*$/, "$1,$3"); - } - } - return true; - } - - // If the name isn’t initially formed from the components in a standard way, - // then don’t automatically update it. - if (NAME.val() !== generate_name() && NAME.val() !== "//") { - convertHidden(NAME.attr("id")); - } -</script> -<?php View::endpush() ?> - diff --git a/resources/views/family-page-children.phtml b/resources/views/family-page-children.phtml index 7920931dab..06907a4ce4 100644 --- a/resources/views/family-page-children.phtml +++ b/resources/views/family-page-children.phtml @@ -37,11 +37,11 @@ use Fisharebest\Webtrees\I18N; <?php endforeach ?> <?php if ($family->canEdit()) : ?> <div class="wt-chart-box"> - <a class="btn btn-link" href="<?= e(route(AddChildToFamilyPage::class, ['gender' => 'M', 'tree' => $family->tree()->name(), 'xref' => $family->xref()])) ?>"> + <a class="btn btn-link" href="<?= e(route(AddChildToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'sex' => 'M'])) ?>"> <?= I18N::translate('Add a son') ?> </a> | - <a class="btn btn-link" href="<?= e(route(AddChildToFamilyPage::class, ['gender' => 'F', 'tree' => $family->tree()->name(), 'xref' => $family->xref()])) ?>"> + <a class="btn btn-link" href="<?= e(route(AddChildToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'sex' => 'F'])) ?>"> <?= I18N::translate('Add a daughter') ?> </a> <br> diff --git a/resources/views/family-page-grandparents.phtml b/resources/views/family-page-grandparents.phtml index 75611764d4..da736c70a5 100644 --- a/resources/views/family-page-grandparents.phtml +++ b/resources/views/family-page-grandparents.phtml @@ -7,8 +7,9 @@ use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Individual; /** - * @var Individual|null $individual - * @var Family|null $family + * @var Family $family + * @var Individual $individual + * @var Family|null $parent_family */ ?> @@ -26,24 +27,24 @@ use Fisharebest\Webtrees\Individual; <div class="align-self-center"> <?php if ($individual === null) : ?> <?= view('chart-box', ['individual' => null]) ?> - <?php elseif ($family === null) : ?> + <?php elseif ($parent_family === null) : ?> <div class="wt-chart-box"> <?php if ($individual->canEdit()) : ?> - <a class="btn btn-link" href="<?= e(route(AddParentToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'gender' => 'M'])) ?>"> + <a class="btn btn-link" href="<?= e(route(AddParentToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'sex' => 'M', 'url' => $family->url()])) ?>"> <?= I18N::translate('Add a father') ?> </a> <?php endif ?> </div> - <?php elseif ($family->husband() === null) : ?> + <?php elseif ($parent_family->husband() === null) : ?> <div class="wt-chart-box"> - <?php if ($family->canEdit()) : ?> - <a class="btn btn-link" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'famtag' => 'HUSB'])) ?>"> + <?php if ($parent_family->canEdit()) : ?> + <a class="btn btn-link" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $parent_family->tree()->name(), 'xref' => $parent_family->xref(), 'sex' => 'M', 'url' => $family->url()])) ?>"> <?= I18N::translate('Add a father') ?> </a> <?php endif ?> </div> <?php else : ?> - <?= view('chart-box', ['individual' => $family ? $family->husband() : null]) ?> + <?= view('chart-box', ['individual' => $parent_family ? $parent_family->husband() : null]) ?> <?php endif ?> </div> </div> @@ -56,31 +57,31 @@ use Fisharebest\Webtrees\Individual; <div class="align-self-center"> <?php if ($individual === null) : ?> <?= view('chart-box', ['individual' => null]) ?> - <?php elseif ($family === null) : ?> + <?php elseif ($parent_family === null) : ?> <div class="wt-chart-box"> <?php if ($individual->canEdit()) : ?> - <a class="btn btn-link" href="<?= e(route(AddParentToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'gender' => 'F'])) ?>"> + <a class="btn btn-link" href="<?= e(route(AddParentToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'sex' => 'F', 'url' => $family->url()])) ?>"> <?= I18N::translate('Add a mother') ?> </a> <?php endif ?> </div> - <?php elseif ($family->wife() === null) : ?> + <?php elseif ($parent_family->wife() === null) : ?> <div class="wt-chart-box"> - <?php if ($family->canEdit()) : ?> - <a class="btn btn-link" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'famtag' => 'WIFE'])) ?>"> + <?php if ($parent_family->canEdit()) : ?> + <a class="btn btn-link" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $parent_family->tree()->name(), 'xref' => $parent_family->xref(), 'sex' => 'F', 'url' => $family->url()])) ?>"> <?= I18N::translate('Add a mother') ?> </a> <?php endif ?> </div> <?php else : ?> - <?= view('chart-box', ['individual' => $family ? $family->wife() : null]) ?> + <?= view('chart-box', ['individual' => $parent_family ? $parent_family->wife() : null]) ?> <?php endif ?> </div> </div> </div> - <?php if ($family !== null) : ?> + <?php if ($parent_family !== null) : ?> <div class="align-self-center"> - <a class="btn btn-text" href="<?= e($family->url()) ?>" title="<?= strip_tags($family->fullName()) ?>"> + <a class="btn btn-text" href="<?= e($parent_family->url()) ?>" title="<?= strip_tags($parent_family->fullName()) ?>"> <?= view('icons/arrow-right') ?> </a> </div> diff --git a/resources/views/family-page-menu.phtml b/resources/views/family-page-menu.phtml index dcafc5c357..5359b10a19 100644 --- a/resources/views/family-page-menu.phtml +++ b/resources/views/family-page-menu.phtml @@ -29,20 +29,20 @@ use Fisharebest\Webtrees\I18N; </a> <?php if ($record->husband() === null) : ?> - <a class="dropdown-item" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $record->tree()->name(), 'xref' => $record->xref(), 'famtag' => 'HUSB'])) ?>"> + <a class="dropdown-item" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $record->tree()->name(), 'xref' => $record->xref(), 'sex' => 'M'])) ?>"> <?= view('icons/add') ?> <?= I18N::translate('Add a husband') ?> </a> <?php endif ?> <?php if ($record->wife() === null) : ?> - <a class="dropdown-item" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $record->tree()->name(), 'xref' => $record->xref(), 'famtag' => 'WIFE'])) ?>"> + <a class="dropdown-item" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $record->tree()->name(), 'xref' => $record->xref(), 'sex' => 'F'])) ?>"> <?= view('icons/add') ?> <?= I18N::translate('Add a wife') ?> </a> <?php endif ?> - <a class="dropdown-item" href="<?= e(route(AddChildToFamilyPage::class, ['gender' => 'U', 'tree' => $record->tree()->name(), 'xref' => $record->xref()])) ?>"> + <a class="dropdown-item" href="<?= e(route(AddChildToFamilyPage::class, ['tree' => $record->tree()->name(), 'xref' => $record->xref(), 'sex' => 'U'])) ?>"> <?= view('icons/add') ?> <?= I18N::translate('Add a child') ?> </a> diff --git a/resources/views/family-page-parents.phtml b/resources/views/family-page-parents.phtml index 1cb009b2af..f72876f591 100644 --- a/resources/views/family-page-parents.phtml +++ b/resources/views/family-page-parents.phtml @@ -23,7 +23,7 @@ use Fisharebest\Webtrees\Individual; <?php else : ?> <div class="wt-chart-box"> <?php if ($family->canEdit()) : ?> - <a class="btn btn-link" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'famtag' => 'HUSB'])) ?>"> + <a class="btn btn-link" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'sex' => 'M'])) ?>"> <?= I18N::translate('Add a husband')?> </a> <?php endif ?> @@ -31,7 +31,7 @@ use Fisharebest\Webtrees\Individual; <?php endif ?> </div> - <?= view('family-page-grandparents', ['family' => $family->husband() ? $family->husband()->childFamilies()->first() : null, 'individual' => $family->husband()]) ?> + <?= view('family-page-grandparents', ['family' => $family, 'parent_family' => $family->husband() ? $family->husband()->childFamilies()->first() : null, 'individual' => $family->husband()]) ?> </div> <div class="d-flex"> @@ -45,7 +45,7 @@ use Fisharebest\Webtrees\Individual; <?php else : ?> <div class="wt-chart-box"> <?php if ($family->canEdit()) : ?> - <a class="btn btn-link" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'famtag' => 'WIFE'])) ?>"> + <a class="btn btn-link" href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'sex' => 'F'])) ?>"> <?= I18N::translate('Add a wife')?> </a> <?php endif ?> @@ -53,7 +53,7 @@ use Fisharebest\Webtrees\Individual; <?php endif ?> </div> - <?= view('family-page-grandparents', ['family' => $family->wife() ? $family->wife()->childFamilies()->first() : null, 'individual' => $family->wife()]) ?> + <?= view('family-page-grandparents', ['family' => $family, 'parent_family' => $family->wife() ? $family->wife()->childFamilies()->first() : null, 'individual' => $family->wife()]) ?> </div> </div> </div> diff --git a/resources/views/individual-name.phtml b/resources/views/individual-name.phtml index 4c3d32792e..a6ca658ae6 100644 --- a/resources/views/individual-name.phtml +++ b/resources/views/individual-name.phtml @@ -6,7 +6,7 @@ use Fisharebest\Webtrees\Functions\FunctionsPrint; use Fisharebest\Webtrees\Functions\FunctionsPrintFacts; use Fisharebest\Webtrees\Http\RequestHandlers\CopyFact; use Fisharebest\Webtrees\Http\RequestHandlers\DeleteFact; -use Fisharebest\Webtrees\Http\RequestHandlers\EditName; +use Fisharebest\Webtrees\Http\RequestHandlers\EditFactPage; use Fisharebest\Webtrees\I18N; /** @@ -43,7 +43,7 @@ if ($fact->isPendingDeletion()) { <?= $fake_individual->fullName() ?> <?php if ($fact->attribute('TYPE') !== '') : ?> — - <?= Registry::elementFactory()->make('INDI:NAME:TYPE')->value($fact->attribute('TYPE'), $tree) ?> + <?= Registry::elementFactory()->make($fact->tag() . ':TYPE')->value($fact->attribute('TYPE'), $tree) ?> <?php endif ?> </a> </div> @@ -56,16 +56,13 @@ if ($fact->isPendingDeletion()) { <?php preg_match_all('/\n2 (\w+) (.+)/', $fact->gedcom(), $matches, PREG_SET_ORDER) ?> <?php foreach ($matches as $key => $match) : ?> <?php [, $tag, $value] = $match ?> + <?php $element = Registry::elementFactory()->make($fact->tag() . ':' . $tag) ?> <?php if ($tag !== 'SOUR' && $tag !== 'NOTE') : ?> <dt class="col-md-4 col-lg-3"> - <?= Registry::elementFactory()->make($fact->tag() . ':' . $tag)->label() ?> + <?= $element->label() ?> </dt> <dd class="col-md-8 col-lg-9"> - <?php if ($tag === 'TYPE') : ?> - <?= Registry::elementFactory()->make('INDI:NAME:TYPE')->value($value, $tree) ?> - <?php else: ?> - <span dir="auto"><?= e($value) ?></span> - <?php endif ?> + <?= $element->value($value, $fact->record()->tree()) ?> </dd> <?php endif ?> <?php endforeach ?> @@ -76,7 +73,7 @@ if ($fact->isPendingDeletion()) { <?php if ($fact->canEdit()) : ?> <div class="d-flex"> - <a class="btn btn-link ml-auto" href="<?= e(route(EditName::class, ['xref' => $individual->xref(), 'fact_id' => $fact->id(), 'tree' => $individual->tree()->name()])) ?>" title="<?= I18N::translate('Edit the name') ?>"> + <a class="btn btn-link ml-auto" href="<?= e(route(EditFactPage::class, ['xref' => $individual->xref(), 'fact_id' => $fact->id(), 'tree' => $individual->tree()->name()])) ?>" title="<?= I18N::translate('Edit the name') ?>"> <?= view('icons/edit') ?> <span class="sr-only"><?= I18N::translate('Edit the name') ?></span> </a> diff --git a/resources/views/individual-page-menu.phtml b/resources/views/individual-page-menu.phtml index a22bc6a946..e93b576dd7 100644 --- a/resources/views/individual-page-menu.phtml +++ b/resources/views/individual-page-menu.phtml @@ -1,7 +1,6 @@ <?php use Fisharebest\Webtrees\Auth; -use Fisharebest\Webtrees\Http\RequestHandlers\AddName; use Fisharebest\Webtrees\Http\RequestHandlers\AddNewFact; use Fisharebest\Webtrees\Http\RequestHandlers\DeleteRecord; use Fisharebest\Webtrees\Http\RequestHandlers\EditFactPage; @@ -36,7 +35,7 @@ use Illuminate\Support\Collection; <hr> <?php endif ?> - <a class="dropdown-item" href="<?= e(route(AddName::class, ['tree' => $record->tree()->name(), 'xref' => $record->xref()])) ?>"> + <a class="dropdown-item" href="<?= e(route(AddNewFact::class, ['tree' => $record->tree()->name(), 'xref' => $record->xref(), 'fact' => 'NAME'])) ?>"> <?= view('icons/add') ?> <?= I18N::translate('Add a name') ?> </a> diff --git a/resources/views/media-page-menu.phtml b/resources/views/media-page-menu.phtml index 2ad7e9459b..8268e1360a 100644 --- a/resources/views/media-page-menu.phtml +++ b/resources/views/media-page-menu.phtml @@ -1,8 +1,7 @@ <?php -use Fisharebest\Webtrees\Auth; use Fisharebest\Webtrees\Http\RequestHandlers\DeleteRecord; -use Fisharebest\Webtrees\Http\RequestHandlers\EditRawRecordPage; +use Fisharebest\Webtrees\Http\RequestHandlers\EditRecordPage; use Fisharebest\Webtrees\Http\RequestHandlers\LinkMediaToFamilyModal; use Fisharebest\Webtrees\Http\RequestHandlers\LinkMediaToIndividualModal; use Fisharebest\Webtrees\Http\RequestHandlers\LinkMediaToSourceModal; @@ -22,6 +21,11 @@ use Fisharebest\Webtrees\Media; </button> <div class="dropdown-menu dropdown-menu-right wt-page-menu-items" aria-labelledby="page-menu"> + <a class="dropdown-item" href="<?= route(EditRecordPage::class, ['xref' => $record->xref(), 'tree' => $record->tree()->name()]) ?>"> + <?= view('icons/edit') ?> + <?= I18N::translate('Edit') ?> + </a> + <a class="dropdown-item" href="#" data-href="<?= e(route(LinkMediaToIndividualModal::class, ['tree' => $record->tree()->name(), 'xref' => $record->xref()])) ?>" data-target="#wt-ajax-modal" data-toggle="modal" data-backdrop="static"> <?= view('icons/link') ?> <?= I18N::translate('Link this media object to an individual') ?> @@ -43,12 +47,5 @@ use Fisharebest\Webtrees\Media; <?= view('icons/delete') ?> <?= I18N::translate('Delete') ?> </a> - - <?php if (Auth::isAdmin() || $record->tree()->getPreference('SHOW_GEDCOM_RECORD')) : ?> - <a class="dropdown-item" href="<?= e(route(EditRawRecordPage::class, ['tree' => $record->tree()->name(), 'xref' => $record->xref()])) ?>"> - <?= view('icons/edit') ?> - <?= I18N::translate('Edit the raw GEDCOM') ?> - </a> - <?php endif ?> </div> </div> diff --git a/resources/views/media-page.phtml b/resources/views/media-page.phtml index fbc6e65bbe..2593c61a71 100644 --- a/resources/views/media-page.phtml +++ b/resources/views/media-page.phtml @@ -1,10 +1,9 @@ <?php use Fisharebest\Webtrees\Auth; -use Fisharebest\Webtrees\Fact; -use Fisharebest\Webtrees\Family; use Fisharebest\Webtrees\Functions\FunctionsPrint; use Fisharebest\Webtrees\Functions\FunctionsPrintFacts; +use Fisharebest\Webtrees\GedcomTag; use Fisharebest\Webtrees\Http\RequestHandlers\AddMediaFileModal; use Fisharebest\Webtrees\Http\RequestHandlers\AddNewFact; use Fisharebest\Webtrees\Http\RequestHandlers\DeleteFact; @@ -12,25 +11,22 @@ use Fisharebest\Webtrees\Http\RequestHandlers\EditMediaFileModal; use Fisharebest\Webtrees\Http\RequestHandlers\PendingChangesAcceptRecord; use Fisharebest\Webtrees\Http\RequestHandlers\PendingChangesRejectRecord; use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Individual; use Fisharebest\Webtrees\Media; -use Fisharebest\Webtrees\Note; use Fisharebest\Webtrees\Registry; -use Fisharebest\Webtrees\Source; use Fisharebest\Webtrees\Tree; use Illuminate\Support\Collection; -use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; /** - * @var Collection<Fact> $clipboard_facts - * @var FilesystemInterface $data_filesystem - * @var Collection<Fact> $facts - * @var Collection<Family> $families - * @var Collection<Individual> $individuals - * @var Media $media - * @var Collection<Note> $notes - * @var Collection<Source> $sources - * @var Tree $tree + * @var Collection $clipboard_facts + * @var FilesystemOperator $data_filesystem + * @var Collection $facts + * @var Collection $families + * @var Collection $individuals + * @var Media $media + * @var Collection $notes + * @var Collection $sources + * @var Tree $tree */ ?> @@ -98,7 +94,7 @@ use League\Flysystem\FilesystemInterface; <div class="tab-pane active fade show" role="tabpanel" id="details"> <table class="table wt-facts-table"> <?php foreach ($media->mediaFiles() as $media_file) : ?> - <tr class="<?= $media_file->isPendingAddition() ? 'wt-new' : '' ?> <?= $media_file->isPendingDeletion() ? 'wt-old' : '' ?>"> + <tr class="<?= $media_file->isPendingAddition() ? 'wt-new' : '' ?><?= $media_file->isPendingDeletion() ? 'wt-old' : '' ?>"> <th scope="row"> <?= I18N::translate('Media file') ?> <?php if ($media->canEdit()) : ?> diff --git a/resources/views/modules/custom-tags/config.phtml b/resources/views/modules/custom-tags/config.phtml index 905a75198f..467bada86c 100644 --- a/resources/views/modules/custom-tags/config.phtml +++ b/resources/views/modules/custom-tags/config.phtml @@ -1,11 +1,14 @@ <?php +use Fisharebest\Webtrees\Contracts\ElementFactoryInterface; use Fisharebest\Webtrees\Contracts\ElementInterface; use Fisharebest\Webtrees\Http\RequestHandlers\ControlPanel; use Fisharebest\Webtrees\Http\RequestHandlers\ModulesAllPage; use Fisharebest\Webtrees\I18N; /** + * @var ElementFactoryInterface $element_factory + * @var array<string,array<string>> $subtags * @var array<string,ElementInterface> $tags * @var string $title */ @@ -16,24 +19,58 @@ use Fisharebest\Webtrees\I18N; <h1><?= $title ?></h1> +<h2><?= I18N::translate('Display custom GEDCOM tags') ?></h2> + <table class="table table-bordered"> - <caption class="sr-only"><?= I18N::translate('Custom tags') ?></caption> + <caption class="sr-only"><?= I18N::translate('Custom GEDCOM tags') ?></caption> + <thead> <tr> - <th><?= I18N::translate('Custom tag') ?></th> + <th><?= I18N::translate('Custom GEDCOM tag') ?></th> <th><?= I18N::translate('Label') ?></th> </tr> </thead> + <tbody> <?php foreach ($tags as $tag => $element) : ?> <tr> - <td><code><?= $tag ?></code></td> + <td dir="ltr"><code><?= $tag ?></code></td> <td><?= $element->label() ?></td> </tr> <?php endforeach ?> </tbody> </table> +<h2><?= I18N::translate('Add/remove GEDCOM tags in the edit forms') ?></h2> + +<table class="table table-bordered"> + <caption class="sr-only"><?= I18N::translate('Custom sub-tags') ?></caption> + + <thead> + <tr> + <th><?= I18N::translate('GEDCOM tag') ?></th> + <th><?= I18N::translate('Label') ?></th> + <th><?= I18N::translate('GEDCOM sub-tag') ?></th> + <th><?= I18N::translate('Label') ?></th> + <th><?= I18N::translate('Count') ?></th> + </tr> + </thead> + + <tbody> + <?php foreach ($subtags as $tag => $children) : ?> + <?php foreach ($children as $child) : ?> + <tr> + <td dir="ltr"><code><?= $tag ?></code></td> + <td><?= $element_factory->make($tag)->label() ?></td> + <td dir="ltr"><code><?= $child[0] ?></code></td> + <td><?= $element_factory->make($tag . ':' . $child[0])->label() ?></td> + <td><?= $child[1] ?? '0:1' ?></td> + </tr> + <?php endforeach ?> + <?php endforeach ?> + </tbody> +</table> + <p> <a href="<?= e(route(ControlPanel::class)) ?>" class="btn btn-primary"> <?= view('icons/save') ?> diff --git a/resources/views/modules/relatives/family.phtml b/resources/views/modules/relatives/family.phtml index f961502611..562f3908c3 100644 --- a/resources/views/modules/relatives/family.phtml +++ b/resources/views/modules/relatives/family.phtml @@ -59,7 +59,7 @@ use Fisharebest\Webtrees\Services\RelationshipService; <tr> <th scope="row"></th> <td> - <a href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'famtag' => 'HUSB'])) ?>"> + <a href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'sex' => 'M', 'url' => $individual->url() . '#tab-relatives'])) ?>"> <?= I18N::translate('Add a husband') ?> </a> </td> @@ -96,7 +96,7 @@ use Fisharebest\Webtrees\Services\RelationshipService; <tr> <th scope="row"></th> <td> - <a href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'famtag' => 'WIFE'])) ?>"> + <a href="<?= e(route(AddSpouseToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'sex' => 'F', 'url' => $individual->url() . '#tab-relatives'])) ?>"> <?= I18N::translate('Add a wife') ?> </a> </td> @@ -216,15 +216,15 @@ use Fisharebest\Webtrees\Services\RelationshipService; </th> <td> - <a href="<?= e(route(AddChildToFamilyPage::class, ['gender' => 'M', 'tree' => $family->tree()->name(), 'xref' => $family->xref()])) ?>"> + <a href="<?= e(route(AddChildToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'sex' => 'M', 'url' => $individual->url() . '#tab-relatives'])) ?>"> <?= $type === 'FAMS' ? I18N::translate('Add a son') : I18N::translate('Add a brother') ?> </a> | - <a href="<?= e(route(AddChildToFamilyPage::class, ['gender' => 'F', 'tree' => $family->tree()->name(), 'xref' => $family->xref()])) ?>"> + <a href="<?= e(route(AddChildToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'sex' => 'F', 'url' => $individual->url() . '#tab-relatives'])) ?>"> <?= $type === 'FAMS' ? I18N::translate('Add a daughter') : I18N::translate('Add a sister') ?> </a> | - <a href="<?= e(route(AddChildToFamilyPage::class, ['gender' => 'U', 'tree' => $family->tree()->name(), 'xref' => $family->xref()])) ?>"> + <a href="<?= e(route(AddChildToFamilyPage::class, ['tree' => $family->tree()->name(), 'xref' => $family->xref(), 'sex' => 'U', 'url' => $individual->url() . '#tab-relatives'])) ?>"> <?= $type === 'FAMS' ? I18N::translate('Add a child') : I18N::translate('Add a sibling') ?> </a> diff --git a/resources/views/modules/relatives/tab.phtml b/resources/views/modules/relatives/tab.phtml index 5a4f610e94..9ecb4f0e46 100644 --- a/resources/views/modules/relatives/tab.phtml +++ b/resources/views/modules/relatives/tab.phtml @@ -45,14 +45,14 @@ use Illuminate\Support\Collection; <tbody> <tr> <td> - <a href="<?= e(route(AddParentToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'gender' => 'M'])) ?>"> + <a href="<?= e(route(AddParentToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'sex' => 'M', 'url' => $individual->url() . '#tab-relatives'])) ?>"> <?= I18N::translate('Add a father') ?> </a> </td> </tr> <tr> <td> - <a href="<?= e(route(AddParentToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'gender' => 'F'])) ?>"> + <a href="<?= e(route(AddParentToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'sex' => 'F', 'url' => $individual->url() . '#tab-relatives'])) ?>"> <?= I18N::translate('Add a mother') ?> </a> </td> @@ -129,7 +129,7 @@ use Illuminate\Support\Collection; <tr> <td> - <a href="<?= e(route(AddSpouseToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref()])) ?>"> + <a href="<?= e(route(AddSpouseToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'url' => $individual->url() . '#tab-relatives'])) ?>"> <?php if ($individual->sex() !== 'F') : ?> <?= I18N::translate('Add a wife') ?> <?php else : ?> @@ -153,7 +153,7 @@ use Illuminate\Support\Collection; <tr> <td> - <a href="<?= e(route(AddChildToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'gender' => 'U'])) ?>"> + <a href="<?= e(route(AddChildToIndividualPage::class, ['tree' => $individual->tree()->name(), 'xref' => $individual->xref(), 'sex' => 'U'])) ?>"> <?= I18N::translate('Add a child to create a one-parent family') ?> </a> </td> diff --git a/tests/.DS_Store b/tests/.DS_Store Binary files differnew file mode 100644 index 0000000000..3d3d369c11 --- /dev/null +++ b/tests/.DS_Store |
