summaryrefslogtreecommitdiff
path: root/app/Elements
diff options
context:
space:
mode:
Diffstat (limited to 'app/Elements')
-rw-r--r--app/Elements/AbstractElement.php308
-rw-r--r--app/Elements/AbstractEventElement.php70
-rw-r--r--app/Elements/AbstractXrefElement.php67
-rw-r--r--app/Elements/AddressCity.php29
-rw-r--r--app/Elements/AddressCountry.php31
-rw-r--r--app/Elements/AddressEmail.php48
-rw-r--r--app/Elements/AddressFax.php51
-rw-r--r--app/Elements/AddressLine.php63
-rw-r--r--app/Elements/AddressLine1.php30
-rw-r--r--app/Elements/AddressLine2.php30
-rw-r--r--app/Elements/AddressLine3.php30
-rw-r--r--app/Elements/AddressPostalCode.php44
-rw-r--r--app/Elements/AddressState.php29
-rw-r--r--app/Elements/AddressWebPage.php48
-rw-r--r--app/Elements/AdoptedByWhichParent.php62
-rw-r--r--app/Elements/Adoption.php37
-rw-r--r--app/Elements/AdultChristening.php36
-rw-r--r--app/Elements/AgeAtEvent.php63
-rw-r--r--app/Elements/AncestralFileNumber.php60
-rw-r--r--app/Elements/Annulment.php27
-rw-r--r--app/Elements/ApprovedSystemId.php47
-rw-r--r--app/Elements/AttributeDescriptor.php42
-rw-r--r--app/Elements/AutomatedRecordId.php32
-rw-r--r--app/Elements/Baptism.php36
-rw-r--r--app/Elements/BarMitzvah.php36
-rw-r--r--app/Elements/BasMitzvah.php36
-rw-r--r--app/Elements/Birth.php36
-rw-r--r--app/Elements/Blessing.php36
-rw-r--r--app/Elements/Burial.php35
-rw-r--r--app/Elements/CasteName.php40
-rw-r--r--app/Elements/CauseOfEvent.php31
-rw-r--r--app/Elements/Census.php36
-rw-r--r--app/Elements/CertaintyAssessment.php55
-rw-r--r--app/Elements/Change.php27
-rw-r--r--app/Elements/ChangeDate.php48
-rw-r--r--app/Elements/CharacterSet.php79
-rw-r--r--app/Elements/ChildLinkageStatus.php66
-rw-r--r--app/Elements/Christening.php37
-rw-r--r--app/Elements/Confirmation.php36
-rw-r--r--app/Elements/ContentDescription.php31
-rw-r--r--app/Elements/CopyrightFile.php30
-rw-r--r--app/Elements/CopyrightSourceData.php32
-rw-r--r--app/Elements/CountOfChildren.php52
-rw-r--r--app/Elements/CountOfMarriages.php51
-rw-r--r--app/Elements/Cremation.php35
-rw-r--r--app/Elements/CustomElement.php27
-rw-r--r--app/Elements/CustomEvent.php40
-rw-r--r--app/Elements/CustomFact.php39
-rw-r--r--app/Elements/DateLdsOrd.php34
-rw-r--r--app/Elements/DateValue.php103
-rw-r--r--app/Elements/Death.php37
-rw-r--r--app/Elements/DescriptiveTitle.php28
-rw-r--r--app/Elements/Divorce.php27
-rw-r--r--app/Elements/DivorceFiled.php27
-rw-r--r--app/Elements/Emigration.php36
-rw-r--r--app/Elements/EmptyElement.php45
-rw-r--r--app/Elements/Engagement.php27
-rw-r--r--app/Elements/EntryRecordingDate.php48
-rw-r--r--app/Elements/EventAttributeType.php33
-rw-r--r--app/Elements/EventDescriptor.php67
-rw-r--r--app/Elements/EventOrFactClassification.php50
-rw-r--r--app/Elements/EventTypeCitedFrom.php35
-rw-r--r--app/Elements/EventsRecorded.php171
-rw-r--r--app/Elements/FileName.php43
-rw-r--r--app/Elements/FirstCommunion.php36
-rw-r--r--app/Elements/Form.php47
-rw-r--r--app/Elements/Gedcom.php27
-rw-r--r--app/Elements/GenerationsOfAncestors.php46
-rw-r--r--app/Elements/GenerationsOfDescendants.php46
-rw-r--r--app/Elements/GovId.php45
-rw-r--r--app/Elements/Graduation.php37
-rw-r--r--app/Elements/Immigration.php36
-rw-r--r--app/Elements/LanguageId.php216
-rw-r--r--app/Elements/LdsBaptism.php35
-rw-r--r--app/Elements/LdsBaptismDateStatus.php80
-rw-r--r--app/Elements/LdsChildSealing.php35
-rw-r--r--app/Elements/LdsChildSealingDateStatus.php73
-rw-r--r--app/Elements/LdsConfirmation.php35
-rw-r--r--app/Elements/LdsEndowment.php35
-rw-r--r--app/Elements/LdsEndowmentDateStatus.php81
-rw-r--r--app/Elements/LdsSpouseSealing.php35
-rw-r--r--app/Elements/LdsSpouseSealingDateStatus.php80
-rw-r--r--app/Elements/Marriage.php38
-rw-r--r--app/Elements/MarriageBanns.php27
-rw-r--r--app/Elements/MarriageContract.php27
-rw-r--r--app/Elements/MarriageLicence.php27
-rw-r--r--app/Elements/MarriageSettlement.php27
-rw-r--r--app/Elements/MarriageType.php66
-rw-r--r--app/Elements/MediaRecord.php36
-rw-r--r--app/Elements/MultimediaFileReference.php34
-rw-r--r--app/Elements/MultimediaFormat.php35
-rw-r--r--app/Elements/NameOfBusiness.php30
-rw-r--r--app/Elements/NameOfFamilyFile.php59
-rw-r--r--app/Elements/NameOfProduct.php29
-rw-r--r--app/Elements/NameOfRepository.php29
-rw-r--r--app/Elements/NameOfSourceData.php31
-rw-r--r--app/Elements/NamePersonal.php145
-rw-r--r--app/Elements/NamePhoneticVariation.php33
-rw-r--r--app/Elements/NamePieceGiven.php67
-rw-r--r--app/Elements/NamePieceNickname.php54
-rw-r--r--app/Elements/NamePiecePrefix.php58
-rw-r--r--app/Elements/NamePieceSuffix.php58
-rw-r--r--app/Elements/NamePieceSurname.php56
-rw-r--r--app/Elements/NamePieceSurnamePrefix.php55
-rw-r--r--app/Elements/NameRomanizedVariation.php58
-rw-r--r--app/Elements/NameType.php66
-rw-r--r--app/Elements/NationOrTribalOrigin.php41
-rw-r--r--app/Elements/NationalIdNumber.php44
-rw-r--r--app/Elements/Naturalization.php36
-rw-r--r--app/Elements/NobilityTypeTitle.php39
-rw-r--r--app/Elements/NoteRecord.php33
-rw-r--r--app/Elements/NoteStructure.php39
-rw-r--r--app/Elements/Occupation.php38
-rw-r--r--app/Elements/OrdinanceProcessFlag.php59
-rw-r--r--app/Elements/Ordination.php36
-rw-r--r--app/Elements/PafUid.php66
-rw-r--r--app/Elements/PedigreeLinkageType.php82
-rw-r--r--app/Elements/PermanentRecordFileNumber.php38
-rw-r--r--app/Elements/PhoneNumber.php53
-rw-r--r--app/Elements/PhoneticType.php55
-rw-r--r--app/Elements/PhysicalDescription.php40
-rw-r--r--app/Elements/PlaceHierarchy.php39
-rw-r--r--app/Elements/PlaceLatitude.php51
-rw-r--r--app/Elements/PlaceLivingOrdinance.php30
-rw-r--r--app/Elements/PlaceLongtitude.php49
-rw-r--r--app/Elements/PlaceName.php76
-rw-r--r--app/Elements/PlacePhoneticVariation.php33
-rw-r--r--app/Elements/PlaceRomanizedVariation.php34
-rw-r--r--app/Elements/Possessions.php36
-rw-r--r--app/Elements/Probate.php35
-rw-r--r--app/Elements/PublicationDate.php29
-rw-r--r--app/Elements/ReceivingSystemName.php48
-rw-r--r--app/Elements/RelationIsDescriptor.php158
-rw-r--r--app/Elements/ReligiousAffiliation.php38
-rw-r--r--app/Elements/RepositoryRecord.php37
-rw-r--r--app/Elements/Residence.php35
-rw-r--r--app/Elements/ResponsibleAgency.php32
-rw-r--r--app/Elements/RestrictionNotice.php81
-rw-r--r--app/Elements/Retirement.php37
-rw-r--r--app/Elements/RoleInEvent.php34
-rw-r--r--app/Elements/RomanizedType.php51
-rw-r--r--app/Elements/ScholasticAchievement.php37
-rw-r--r--app/Elements/SexValue.php78
-rw-r--r--app/Elements/SocialSecurityNumber.php38
-rw-r--r--app/Elements/SourceCallNumber.php46
-rw-r--r--app/Elements/SourceData.php51
-rw-r--r--app/Elements/SourceDescriptiveTitle.php38
-rw-r--r--app/Elements/SourceFiledByEntry.php29
-rw-r--r--app/Elements/SourceJurisdictionPlace.php31
-rw-r--r--app/Elements/SourceMediaType.php84
-rw-r--r--app/Elements/SourceOriginator.php30
-rw-r--r--app/Elements/SourcePublicationFacts.php48
-rw-r--r--app/Elements/SourceRecord.php40
-rw-r--r--app/Elements/SubmissionRecord.php37
-rw-r--r--app/Elements/SubmitterName.php29
-rw-r--r--app/Elements/SubmitterRecord.php38
-rw-r--r--app/Elements/SubmitterRegisteredRfn.php30
-rw-r--r--app/Elements/SubmitterText.php57
-rw-r--r--app/Elements/TempleCode.php215
-rw-r--r--app/Elements/TextFromSource.php76
-rw-r--r--app/Elements/TimeValue.php33
-rw-r--r--app/Elements/TransmissionDate.php29
-rw-r--r--app/Elements/UnknownElement.php40
-rw-r--r--app/Elements/UserReferenceNumber.php30
-rw-r--r--app/Elements/UserReferenceType.php29
-rw-r--r--app/Elements/VersionNumber.php48
-rw-r--r--app/Elements/WebtreesUser.php41
-rw-r--r--app/Elements/WhereWithinSource.php55
-rw-r--r--app/Elements/Will.php35
-rw-r--r--app/Elements/XrefFamily.php67
-rw-r--r--app/Elements/XrefIndividual.php66
-rw-r--r--app/Elements/XrefLocation.php81
-rw-r--r--app/Elements/XrefMedia.php81
-rw-r--r--app/Elements/XrefNote.php81
-rw-r--r--app/Elements/XrefRepository.php81
-rw-r--r--app/Elements/XrefSource.php110
-rw-r--r--app/Elements/XrefSubmission.php81
-rw-r--r--app/Elements/XrefSubmitter.php81
178 files changed, 9035 insertions, 0 deletions
diff --git a/app/Elements/AbstractElement.php b/app/Elements/AbstractElement.php
new file mode 100644
index 0000000000..1d3181a337
--- /dev/null
+++ b/app/Elements/AbstractElement.php
@@ -0,0 +1,308 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Contracts\ElementInterface;
+use Fisharebest\Webtrees\Html;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Tree;
+use League\CommonMark\Block\Element\Document;
+use League\CommonMark\Block\Element\Paragraph;
+use League\CommonMark\Block\Renderer\DocumentRenderer;
+use League\CommonMark\Block\Renderer\ParagraphRenderer;
+use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Element\Text;
+use League\CommonMark\Inline\Parser\AutolinkParser;
+use League\CommonMark\Inline\Renderer\LinkRenderer;
+use League\CommonMark\Inline\Renderer\TextRenderer;
+
+use function array_key_exists;
+use function array_map;
+use function e;
+use function is_numeric;
+use function preg_replace;
+use function strpos;
+use function trim;
+use function view;
+
+/**
+ * A GEDCOM element is a tag/primitive in a GEDCOM file.
+ */
+abstract class AbstractElement implements ElementInterface
+{
+ private const REGEX_URL = '~((https?|ftp]):)(//([^\s/?#<>]*))?([^\s?#<>]*)(\?([^\s#<>]*))?(#[^\s?#<>]+)?~';
+
+ // HTML attributes for an <input>
+ protected const MAX_LENGTH = false;
+
+ // Which child elements can appear under this element.
+ protected const SUBTAGS = [];
+
+ /** @var string A label to describe this element */
+ private $label;
+
+ /** @var array<string,string> */
+ private $subtags;
+
+ /**
+ * AbstractGedcomElement constructor.
+ *
+ * @param string $label
+ * @param array<string>|null $subtags
+ */
+ public function __construct(string $label, array $subtags = null)
+ {
+ $this->label = $label;
+ $this->subtags = $subtags ?? static::SUBTAGS;
+ }
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ $value = strtr($value, ["\t" => ' ', "\r" => ' ', "\n" => ' ']);
+
+ while (strpos($value, ' ') !== false) {
+ $value = strtr($value, [' ' => ' ']);
+ }
+
+ return trim($value);
+ }
+
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ return '';
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ $values = $this->values();
+
+ if ($values !== []) {
+ $value = $this->canonical($value);
+
+ // Ensure the current data is in the list.
+ if (!array_key_exists($value, $values)) {
+ $values = [$value => $value] + $values;
+ }
+
+ // We may use markup to display values, but not when editing them.
+ $values = array_map('strip_tags', $values);
+
+ return view('components/select', [
+ 'id' => $id,
+ 'name' => $name,
+ 'options' => $values,
+ 'selected' => $value,
+ ]);
+ }
+
+ $attributes = [
+ 'class' => 'form-control',
+ 'type' => 'text',
+ 'id' => $id,
+ 'name' => $name,
+ 'value' => $value,
+ 'maxvalue' => static::MAX_LENGTH,
+ ];
+
+ return '<input ' . Html::attributes($attributes) . '">';
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ *
+ * @return string
+ */
+ public function editHidden(string $id, string $name, string $value): string
+ {
+ return '<input class="form-control" type="hidden" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">';
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ *
+ * @return string
+ */
+ public function editTextArea(string $id, string $name, string $value): string
+ {
+ return '<textarea class="form-control" id="' . e($id) . '" name="' . e($name) . '" rows="5" dir="auto">' . e($value) . '</textarea>';
+ }
+
+ /**
+ * Escape @ signs in a GEDCOM export.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function escape(string $value): string
+ {
+ return strtr($value, ['@' => '@@']);
+ }
+
+ /**
+ * Create a label for this element.
+ *
+ * @return string
+ */
+ public function label(): string
+ {
+ return $this->label;
+ }
+
+ /**
+ * Create a label/value pair for this element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function labelValue(string $value, Tree $tree): string
+ {
+ $label = '<span class="label">' . $this->label() . '</span>';
+ $value = '<span class="value">' . $this->value($value, $tree) . '</span>';
+ $html = I18N::translate(/* I18N: e.g. "Occupation: farmer" */ '%1$s: %2$s', $label, $value);
+
+ return '<div>' . $html . '</div>';
+ }
+
+ /**
+ * @param Tree $tree
+ *
+ * @return array<string,string>
+ */
+ public function subtags(Tree $tree): array
+ {
+ return $this->subtags;
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $values = $this->values();
+
+ if ($values === []) {
+ if (str_contains($value, "\n")) {
+ return '<span dir="auto" class="d-inline-block" style="white-space: pre-wrap;">' . e($value) . '</span>';
+ }
+
+ return '<span dir="auto">' . e($value) . '</span>';
+ }
+
+ $canonical = $this->canonical($value);
+
+ return $values[$canonical] ?? '<span dir="auto">' . e($value) . '</span>';
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [];
+ }
+
+ /**
+ * Display the value of this type of element - convert URLs to links
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ protected function valueAutoLink(string $value): string
+ {
+ // Convert URLs into markdown auto-links.
+ $value = preg_replace(self::REGEX_URL, '<$0>', $value);
+
+ // Create a minimal commonmark processor - just add support for autolinks.
+ $environment = new Environment();
+ $environment
+ ->addBlockRenderer(Document::class, new DocumentRenderer())
+ ->addBlockRenderer(Paragraph::class, new ParagraphRenderer())
+ ->addInlineRenderer(Text::class, new TextRenderer())
+ ->addInlineRenderer(Link::class, new LinkRenderer())
+ ->addInlineParser(new AutolinkParser());
+
+ $converter = new CommonMarkConverter(['html_input' => Environment::HTML_INPUT_ESCAPE], $environment);
+
+ return $converter->convertToHtml($value);
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function valueNumeric(string $value): string
+ {
+ $canonical = $this->canonical($value);
+
+ if (is_numeric($canonical)) {
+ return I18N::number((int) $canonical);
+ }
+
+ return e($value);
+ }
+}
diff --git a/app/Elements/AbstractEventElement.php b/app/Elements/AbstractEventElement.php
new file mode 100644
index 0000000000..c2ff3e17f0
--- /dev/null
+++ b/app/Elements/AbstractEventElement.php
@@ -0,0 +1,70 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+
+/**
+ * Events which can take "Y" to indicate that they occurred, but date/place are unknown.
+ */
+class AbstractEventElement extends AbstractElement
+{
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ return 'Y';
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return
+ '<div class="form-check">' .
+ $this->editHidden($id, $name, $value ? 'Y' : '') .
+ '<input class="form-check-input" type="checkbox" value="Y" id="' . e($id) . '-check" ' . ($value ? 'checked' : '') . '>' .
+ '<label class="form-check-label" for="' . e($id) . '-check">' .
+ I18N::translate('This event occurred, but the details are unknown.') .
+ '</label>' .
+ '</div>' .
+ '<script>' .
+ 'document.getElementById("' . e($id) . '-check").addEventListener("change", function () {' .
+ 'document.getElementById("' . e($id) . '").value = this.checked ? "Y" : "";' .
+ '})' .
+ '</script>';
+ }
+}
diff --git a/app/Elements/AbstractXrefElement.php b/app/Elements/AbstractXrefElement.php
new file mode 100644
index 0000000000..021cc4df6f
--- /dev/null
+++ b/app/Elements/AbstractXrefElement.php
@@ -0,0 +1,67 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Gedcom;
+use Fisharebest\Webtrees\GedcomRecord;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function preg_match;
+
+/**
+ * Common behaviour for all XREF links
+ */
+class AbstractXrefElement extends AbstractElement
+{
+ /**
+ * Escape @ signs in a GEDCOM export.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function escape(string $value): string
+ {
+ return $value;
+ }
+
+ /**
+ * Display the value of this type of element - convert XREFs to links.
+ *
+ * @param string $value
+ * @param Tree $tree
+ * @param mixed $factory We can type-hint this from PHP 7.4
+ *
+ * @return string
+ */
+ protected function valueXrefLink(string $value, Tree $tree, $factory): string
+ {
+ if (preg_match('/^@(' . Gedcom::REGEX_XREF . ')@$/', $value, $match)) {
+ $record = $factory->make($match[1], $tree);
+
+ if ($record instanceof GedcomRecord) {
+ return '<a href="' . e($record->url()) . '">' . $record->fullName() . '</a>';
+ }
+ }
+
+ return '<span class="error">' . e($value) . '</span>';
+ }
+}
diff --git a/app/Elements/AddressCity.php b/app/Elements/AddressCity.php
new file mode 100644
index 0000000000..ab5ee8fe1b
--- /dev/null
+++ b/app/Elements/AddressCity.php
@@ -0,0 +1,29 @@
+<?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\Elements;
+
+/**
+ * ADDRESS_CITY := {Size=1:60}
+ * The name of the city used in the address. Isolated for sorting or indexing.
+ */
+class AddressCity extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+}
diff --git a/app/Elements/AddressCountry.php b/app/Elements/AddressCountry.php
new file mode 100644
index 0000000000..cc45fcf378
--- /dev/null
+++ b/app/Elements/AddressCountry.php
@@ -0,0 +1,31 @@
+<?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\Elements;
+
+/**
+ * ADDRESS_COUNTRY := {Size=1:60}
+ * The name of the country that pertains to the associated address. Isolated
+ * by some systems for sorting or indexing. Used in most cases to facilitate
+ * automatic sorting of mail.
+ */
+class AddressCountry extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+}
diff --git a/app/Elements/AddressEmail.php b/app/Elements/AddressEmail.php
new file mode 100644
index 0000000000..13aab39921
--- /dev/null
+++ b/app/Elements/AddressEmail.php
@@ -0,0 +1,48 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+
+/**
+ * ADDRESS_EMAIL := {Size=5:120}
+ * An electronic address that can be used for contact such as an email address.
+ */
+class AddressEmail extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ return '<a dir="ltr" href="mailto:' . e($canonical) . '">' . e($canonical) . '</a>';
+ }
+}
diff --git a/app/Elements/AddressFax.php b/app/Elements/AddressFax.php
new file mode 100644
index 0000000000..f33dc9f2fb
--- /dev/null
+++ b/app/Elements/AddressFax.php
@@ -0,0 +1,51 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function preg_match;
+
+/**
+ * ADDRESS_FAX := {Size=5:60}
+ * A FAX telephone number appropriate for sending data facsimiles.
+ */
+class AddressFax extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ if (preg_match('/^[+0-9-]+$/', $value)) {
+ return '<span dir="ltr">' . e($value) . '</span>';
+ }
+
+ return e($value);
+ }
+}
diff --git a/app/Elements/AddressLine.php b/app/Elements/AddressLine.php
new file mode 100644
index 0000000000..ea00c158d0
--- /dev/null
+++ b/app/Elements/AddressLine.php
@@ -0,0 +1,63 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * ADDRESS_LINE := {Size=1:60}
+ * Typically used to define a mailing address of an individual when used
+ * subordinate to a RESIdent tag. When it is used subordinate to an event tag
+ * it is the address of the place where the event took place. The address
+ * lines usually contain the addressee’s name and other street and city
+ * information so that it forms an address that meets mailing requirements.
+ */
+class AddressLine extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ // Browsers use MS-DOS line endings in multi-line data.
+ return strtr($value, ["\r\n" => "\n", "\r" => "\n"]);
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return $this->editTextArea($id, $name, $value);
+ }
+}
diff --git a/app/Elements/AddressLine1.php b/app/Elements/AddressLine1.php
new file mode 100644
index 0000000000..3f4a4f3305
--- /dev/null
+++ b/app/Elements/AddressLine1.php
@@ -0,0 +1,30 @@
+<?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\Elements;
+
+/**
+ * ADDRESS_LINE1 := {Size=1:60}
+ * The first line of the address used for indexing. This is the value of the
+ * line corresponding to the ADDR tag line in the address structure.
+ */
+class AddressLine1 extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+}
diff --git a/app/Elements/AddressLine2.php b/app/Elements/AddressLine2.php
new file mode 100644
index 0000000000..ef9369d232
--- /dev/null
+++ b/app/Elements/AddressLine2.php
@@ -0,0 +1,30 @@
+<?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\Elements;
+
+/**
+ * ADDRESS_LINE2 := {Size=1:60}
+ * The second line of the address used for indexing. This is the value of
+ * the first CONT line subordinate to the ADDR tag in the address structure.
+ */
+class AddressLine2 extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+}
diff --git a/app/Elements/AddressLine3.php b/app/Elements/AddressLine3.php
new file mode 100644
index 0000000000..8ae0cc69fa
--- /dev/null
+++ b/app/Elements/AddressLine3.php
@@ -0,0 +1,30 @@
+<?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\Elements;
+
+/**
+ * ADDRESS_LINE3 := {Size=1:60}
+ * The third line of the address used for indexing. This is the value of
+ * the second CONT line subordinate to the ADDR tag in the address structure.
+ */
+class AddressLine3 extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+}
diff --git a/app/Elements/AddressPostalCode.php b/app/Elements/AddressPostalCode.php
new file mode 100644
index 0000000000..338ef6e445
--- /dev/null
+++ b/app/Elements/AddressPostalCode.php
@@ -0,0 +1,44 @@
+<?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\Elements;
+
+use function strtoupper;
+
+/**
+ * ADDRESS_POST := {Size=1:10}
+ * The ZIP or postal code used by the various localities in handling of mail.
+ * Isolated for sorting or indexing.
+ */
+class AddressPostalCode extends AbstractElement
+{
+ protected const MAX_LENGTH = 10;
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(parent::canonical($value));
+ }
+}
diff --git a/app/Elements/AddressState.php b/app/Elements/AddressState.php
new file mode 100644
index 0000000000..1ca2cac192
--- /dev/null
+++ b/app/Elements/AddressState.php
@@ -0,0 +1,29 @@
+<?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\Elements;
+
+/**
+ * ADDRESS_STATE := {Size=1:60}
+ * The name of the state used in the address. Isolated for sorting or indexing.
+ */
+class AddressState extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+}
diff --git a/app/Elements/AddressWebPage.php b/app/Elements/AddressWebPage.php
new file mode 100644
index 0000000000..45847209a5
--- /dev/null
+++ b/app/Elements/AddressWebPage.php
@@ -0,0 +1,48 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+
+/**
+ * ADDRESS_WEB_PAGE := {Size=5:120}
+ * The world wide web page address.
+ */
+class AddressWebPage extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ return '<a dir="auto" href="' . e($canonical) . '">' . e($canonical) . '</a>';
+ }
+}
diff --git a/app/Elements/AdoptedByWhichParent.php b/app/Elements/AdoptedByWhichParent.php
new file mode 100644
index 0000000000..e07ee13d74
--- /dev/null
+++ b/app/Elements/AdoptedByWhichParent.php
@@ -0,0 +1,62 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtoupper;
+
+/**
+ * ADDRESS_WEB_PAGE := {Size=1:4}
+ * [ HUSB | WIFE | BOTH ]
+ * A code which shows which parent in the associated family record adopted this person. Where:
+ * HUSB = The HUSBand in the associated family adopted this person.
+ * WIFE = The WIFE in the associated family adopted this person.
+ * BOTH = Both HUSBand and WIFE adopted this person.
+ */
+class AdoptedByWhichParent extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(parent::canonical($value));
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'BOTH' => I18N::translate('Adopted by both parents'),
+ 'HUSB' => I18N::translate('Adopted by father'),
+ 'WIFE' => I18N::translate('Adopted by mother'),
+ ];
+ }
+}
diff --git a/app/Elements/Adoption.php b/app/Elements/Adoption.php
new file mode 100644
index 0000000000..2ae30c5c08
--- /dev/null
+++ b/app/Elements/Adoption.php
@@ -0,0 +1,37 @@
+<?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\Elements;
+
+/**
+ * Adoption
+ */
+class Adoption extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'FAMC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/AdultChristening.php b/app/Elements/AdultChristening.php
new file mode 100644
index 0000000000..a4656145d7
--- /dev/null
+++ b/app/Elements/AdultChristening.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Adult Christening
+ */
+class AdultChristening extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/AgeAtEvent.php b/app/Elements/AgeAtEvent.php
new file mode 100644
index 0000000000..bd762ee366
--- /dev/null
+++ b/app/Elements/AgeAtEvent.php
@@ -0,0 +1,63 @@
+<?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\Elements;
+
+use function strtolower;
+use function strtoupper;
+
+/**
+ * AGE_AT_EVENT := {Size=1:12}
+ * [ < | > | <NULL>]
+ * [ YYy MMm DDDd | YYy | MMm | DDDd |
+ * YYy MMm | YYy DDDd | MMm DDDd |
+ * CHILD | INFANT | STILLBORN ]
+ * ]
+ * Where:
+ * > = greater than indicated age
+ * < = less than indicated age
+ * y = a label indicating years
+ * m = a label indicating months
+ * d = a label indicating days
+ * YY = number of full years
+ * MM = number of months
+ * DDD = number of days
+ * CHILD = age < 8 years
+ * INFANT = age<1year
+ * STILLBORN = died just prior, at, or near birth, 0 years
+ */
+class AgeAtEvent extends AbstractElement
+{
+ protected const MAX_LENGTH = 12;
+
+ public function canonical(string $value): string
+ {
+ $value = parent::canonical($value);
+
+ $upper = strtoupper($value);
+
+ if ($upper === 'CHILD' || $upper === 'INFANT' || $upper === 'STILLBORN') {
+ $value = $upper;
+ } else {
+ $value = strtolower($value);
+ }
+
+ return $value;
+ }
+}
diff --git a/app/Elements/AncestralFileNumber.php b/app/Elements/AncestralFileNumber.php
new file mode 100644
index 0000000000..f081f5c617
--- /dev/null
+++ b/app/Elements/AncestralFileNumber.php
@@ -0,0 +1,60 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function strtoupper;
+
+/**
+ * ANCESTRAL_FILE_NUMBER := {Size=1:12}
+ * A unique permanent record number of an individual record contained in the
+ * Family History Department's Ancestral File.
+ */
+class AncestralFileNumber extends AbstractElement
+{
+ protected const MAX_LENGTH = 12;
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(parent::canonical($value));
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return '<span dir="ltr">' . e($this->canonical($value)) . '</span>';
+ }
+}
diff --git a/app/Elements/Annulment.php b/app/Elements/Annulment.php
new file mode 100644
index 0000000000..7f25dff851
--- /dev/null
+++ b/app/Elements/Annulment.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * Annulment
+ */
+class Annulment extends AbstractEventElement
+{
+}
diff --git a/app/Elements/ApprovedSystemId.php b/app/Elements/ApprovedSystemId.php
new file mode 100644
index 0000000000..55ed6355bd
--- /dev/null
+++ b/app/Elements/ApprovedSystemId.php
@@ -0,0 +1,47 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+use Fisharebest\Webtrees\Webtrees;
+
+/**
+ * ANCESTRAL_FILE_NUMBER := {Size=1:20}
+ * A system identification name which was obtained through the GEDCOM
+ * registration process. This name must be unique from any other product.
+ * Spaces within the name must be substituted with a 0x5F (underscore _)
+ * so as to create one word.
+ */
+class ApprovedSystemId extends AbstractElement
+{
+ protected const MAX_LENGTH = 20;
+
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ return Webtrees::NAME;
+ }
+}
diff --git a/app/Elements/AttributeDescriptor.php b/app/Elements/AttributeDescriptor.php
new file mode 100644
index 0000000000..75fa2872a4
--- /dev/null
+++ b/app/Elements/AttributeDescriptor.php
@@ -0,0 +1,42 @@
+<?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\Elements;
+
+/**
+ * ATTRIBUTE_DESCRIPTOR := {Size=1:90}
+ * Text describing a particular characteristic or attribute assigned to an
+ * individual. This attribute value is assigned to the FACT tag. The
+ * classification of this specific attribute or fact is specified by the value
+ * of the subordinate TYPE tag selected from the EVENT_DETAIL structure. For
+ * example if you were classifying the skills a person had obtained;
+ * 1 FACT Woodworking
+ * 2 TYPE Skills
+ */
+class AttributeDescriptor extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/AutomatedRecordId.php b/app/Elements/AutomatedRecordId.php
new file mode 100644
index 0000000000..72805b9d29
--- /dev/null
+++ b/app/Elements/AutomatedRecordId.php
@@ -0,0 +1,32 @@
+<?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\Elements;
+
+/**
+ * AUTOMATED_RECORD_ID := {Size=1:12}
+ * A unique record identification number assigned to the record by the source
+ * system. This number is intended to serve as a more sure means of
+ * identification of a record for reconciling differences in data between two
+ * interfacing systems.
+ */
+class AutomatedRecordId extends AbstractElement
+{
+ protected const MAX_LENGTH = 12;
+}
diff --git a/app/Elements/Baptism.php b/app/Elements/Baptism.php
new file mode 100644
index 0000000000..ee175dcdde
--- /dev/null
+++ b/app/Elements/Baptism.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Baptism
+ */
+class Baptism extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/BarMitzvah.php b/app/Elements/BarMitzvah.php
new file mode 100644
index 0000000000..dddc70e60d
--- /dev/null
+++ b/app/Elements/BarMitzvah.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Bar Mitzvah
+ */
+class BarMitzvah extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/BasMitzvah.php b/app/Elements/BasMitzvah.php
new file mode 100644
index 0000000000..160dd298a6
--- /dev/null
+++ b/app/Elements/BasMitzvah.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Bas Mitzvah
+ */
+class BasMitzvah extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/Birth.php b/app/Elements/Birth.php
new file mode 100644
index 0000000000..cd7d3b7033
--- /dev/null
+++ b/app/Elements/Birth.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Birth
+ */
+class Birth extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'FAMC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/Blessing.php b/app/Elements/Blessing.php
new file mode 100644
index 0000000000..4b06d07e4e
--- /dev/null
+++ b/app/Elements/Blessing.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Blessing
+ */
+class Blessing extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/Burial.php b/app/Elements/Burial.php
new file mode 100644
index 0000000000..5c2a548146
--- /dev/null
+++ b/app/Elements/Burial.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * Burial
+ */
+class Burial extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/CasteName.php b/app/Elements/CasteName.php
new file mode 100644
index 0000000000..1716154b85
--- /dev/null
+++ b/app/Elements/CasteName.php
@@ -0,0 +1,40 @@
+<?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\Elements;
+
+/**
+ * CASTE_NAME := {Size=1:90}
+ * A name assigned to a particular group that this person was associated with,
+ * such as a particular racial group, religious group, or a group with an
+ * inherited status.
+ */
+class CasteName extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/CauseOfEvent.php b/app/Elements/CauseOfEvent.php
new file mode 100644
index 0000000000..9eb3fe3204
--- /dev/null
+++ b/app/Elements/CauseOfEvent.php
@@ -0,0 +1,31 @@
+<?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\Elements;
+
+/**
+ * CAUSE_OF_EVENT := {Size=1:90}
+ * Used in special cases to record the reasons which precipitated an event.
+ * Normally this will be used subordinate to a death event to show cause of
+ * death, such as might be listed on a death certificate.
+ */
+class CauseOfEvent extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+}
diff --git a/app/Elements/Census.php b/app/Elements/Census.php
new file mode 100644
index 0000000000..772bb2edfe
--- /dev/null
+++ b/app/Elements/Census.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Census
+ */
+class Census extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/CertaintyAssessment.php b/app/Elements/CertaintyAssessment.php
new file mode 100644
index 0000000000..bc4d68174f
--- /dev/null
+++ b/app/Elements/CertaintyAssessment.php
@@ -0,0 +1,55 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+/**
+ * CERTAINTY_ASSESSMENT := {Size=1:1}
+ * [0|1|2|3]
+ * The QUAY tag's value conveys the submitter's quantitative evaluation of the
+ * credibility of a piece of information, based upon its supporting evidence.
+ * Some systems use this feature to rank multiple conflicting opinions for
+ * display of most likely information first. It is not intended to eliminate
+ * the receiver's need to evaluate the evidence for themselves.
+ * 0 = Unreliable evidence or estimated data
+ * 1 = Questionable reliability of evidence (interviews, census, oral
+ * genealogies, or potential for bias for example, an autobiography)
+ * 2 = Secondary evidence, data officially recorded sometime after event
+ * 3 = Direct and primary evidence used, or by dominance of the evidence
+ */
+class CertaintyAssessment extends AbstractElement
+{
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ '0' => /* I18N: Quality of source information - GEDCOM tag “QUAY 0” */ I18N::translate('unreliable evidence'),
+ '1' => /* I18N: Quality of source information - GEDCOM tag “QUAY 1” */ I18N::translate('questionable evidence'),
+ '2' => /* I18N: Quality of source information - GEDCOM tag “QUAY 2” */ I18N::translate('secondary evidence'),
+ '3' => /* I18N: Quality of source information - GEDCOM tag “QUAY 3” */ I18N::translate('primary evidence'),
+ ];
+ }
+}
diff --git a/app/Elements/Change.php b/app/Elements/Change.php
new file mode 100644
index 0000000000..a7889d6d89
--- /dev/null
+++ b/app/Elements/Change.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * *:CHAN is an empty element with children; DATE and NOTE.
+ */
+class Change extends EmptyElement
+{
+}
diff --git a/app/Elements/ChangeDate.php b/app/Elements/ChangeDate.php
new file mode 100644
index 0000000000..767e8e063f
--- /dev/null
+++ b/app/Elements/ChangeDate.php
@@ -0,0 +1,48 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Date;
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * CHANGE_DATE := {Size=10:11}
+ * <DATE_EXACT>
+ * The date that this data was changed.
+ */
+class ChangeDate extends AbstractElement
+{
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ $date = new Date($canonical);
+
+ return $date->display(false);
+ }
+}
diff --git a/app/Elements/CharacterSet.php b/app/Elements/CharacterSet.php
new file mode 100644
index 0000000000..e0da807994
--- /dev/null
+++ b/app/Elements/CharacterSet.php
@@ -0,0 +1,79 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function strtoupper;
+
+/**
+ * CHARACTER_SET := {Size=1:8}
+ * [ ANSEL |UTF-8 | UNICODE | ASCII ]
+ * A code value that represents the character set to be used to interpret this
+ * data. Currently, the preferred character set is ANSEL, which includes ASCII
+ * as a subset. UNICODE is not widely supported by most operating systems;
+ * therefore, GEDCOM produced using the UNICODE character set will be limited
+ * in its interchangeability for a while but should eventually provide the
+ * international flexibility that is desired. See Chapter 3, starting on page
+ * 77.
+ * Note:The IBMPC character set is not allowed. This character set cannot be
+ * interpreted properly without knowing which code page the sender was using.
+ */
+class CharacterSet extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(parent::canonical($value));
+ }
+
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ return 'UTF-8';
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ 'UTF-8' => 'UTF-8',
+ 'UNICODE' => 'UNICODE',
+ 'ANSEL' => 'ANSEL',
+ 'ASCII' => 'ASCII',
+ ];
+ }
+}
diff --git a/app/Elements/ChildLinkageStatus.php b/app/Elements/ChildLinkageStatus.php
new file mode 100644
index 0000000000..e967de2aac
--- /dev/null
+++ b/app/Elements/ChildLinkageStatus.php
@@ -0,0 +1,66 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtolower;
+
+/**
+ * CHILD_LINKAGE_STATUS := {Size=1:15}
+ * [challenged | disproven | proven]
+ * A status code that allows passing on the users opinion of the status of a
+ * child to family link.
+ * challenged = Linking this child to this family is suspect, but the linkage
+ * has been neither proven nor disproven.
+ * disproven = There has been a claim by some that this child belongs to this
+ * family, but the linkage has been disproven.
+ * proven = There has been a claim by some that this child does not belongs
+ * to this family, but the linkage has been proven.
+ */
+class ChildLinkageStatus extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtolower(parent::canonical($value));
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'challenged' => I18N::translate('challenged'),
+ 'disproven' => I18N::translate('disproven'),
+ 'proven' => I18N::translate('proven'),
+ ];
+ }
+}
diff --git a/app/Elements/Christening.php b/app/Elements/Christening.php
new file mode 100644
index 0000000000..a29aeb3e24
--- /dev/null
+++ b/app/Elements/Christening.php
@@ -0,0 +1,37 @@
+<?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\Elements;
+
+/**
+ * Christening
+ */
+class Christening extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'FAMC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/Confirmation.php b/app/Elements/Confirmation.php
new file mode 100644
index 0000000000..c8fab8ee23
--- /dev/null
+++ b/app/Elements/Confirmation.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Confirmation
+ */
+class Confirmation extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/ContentDescription.php b/app/Elements/ContentDescription.php
new file mode 100644
index 0000000000..5d0570d757
--- /dev/null
+++ b/app/Elements/ContentDescription.php
@@ -0,0 +1,31 @@
+<?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\Elements;
+
+/**
+ * GEDCOM_CONTENT_DESCRIPTION := {Size=1:248}
+ * A note that a user enters to describe the contents of the lineage-linked
+ * file in terms of "ancestors or descendants of" so that the person
+ * receiving the data knows what genealogical information the transmission
+ * contains.
+ */
+class ContentDescription extends AbstractElement
+{
+}
diff --git a/app/Elements/CopyrightFile.php b/app/Elements/CopyrightFile.php
new file mode 100644
index 0000000000..d4fb0332c4
--- /dev/null
+++ b/app/Elements/CopyrightFile.php
@@ -0,0 +1,30 @@
+<?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\Elements;
+
+/**
+ * COPYRIGHT_GEDCOM_FILE := {Size=1:90}
+ * A copyright statement needed to protect the copyrights of the submitter of
+ * this GEDCOM file.
+ */
+class CopyrightFile extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+}
diff --git a/app/Elements/CopyrightSourceData.php b/app/Elements/CopyrightSourceData.php
new file mode 100644
index 0000000000..9305f06916
--- /dev/null
+++ b/app/Elements/CopyrightSourceData.php
@@ -0,0 +1,32 @@
+<?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\Elements;
+
+/**
+ * COPYRIGHT_SOURCE_DATA := {Size=1:90}
+ * A copyright statement required by the owner of data from which this
+ * information was down- loaded. For example, when a GEDCOM down-load is
+ * requested from the Ancestral File, this would be the copyright statement to
+ * indicate that the data came from a copyrighted source.
+ */
+class CopyrightSourceData extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+}
diff --git a/app/Elements/CountOfChildren.php b/app/Elements/CountOfChildren.php
new file mode 100644
index 0000000000..ebafc026c9
--- /dev/null
+++ b/app/Elements/CountOfChildren.php
@@ -0,0 +1,52 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * COUNT_OF_CHILDREN := {Size=1:3}
+ * The known number of children of this individual from all marriages or, if
+ * subordinate to a family record, the reported number of children known to
+ * belong to this family, regardless of whether the associated children are
+ * represented in the corresponding structure. This is not necessarily the
+ * count of children listed in a family structure.
+ */
+class CountOfChildren extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueNumeric($value);
+ }
+}
diff --git a/app/Elements/CountOfMarriages.php b/app/Elements/CountOfMarriages.php
new file mode 100644
index 0000000000..517f821060
--- /dev/null
+++ b/app/Elements/CountOfMarriages.php
@@ -0,0 +1,51 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * COUNT_OF_MARRIAGES := {Size=1:3}
+ * The number of different families that this person was known to have been a
+ * member of as a spouse or parent, regardless of whether the associated
+ * families are represented in the GEDCOM file.
+ */
+class CountOfMarriages extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueNumeric($value);
+ }
+}
diff --git a/app/Elements/Cremation.php b/app/Elements/Cremation.php
new file mode 100644
index 0000000000..e718948b68
--- /dev/null
+++ b/app/Elements/Cremation.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * Cremation
+ */
+class Cremation extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/CustomElement.php b/app/Elements/CustomElement.php
new file mode 100644
index 0000000000..255ffd7802
--- /dev/null
+++ b/app/Elements/CustomElement.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * A custom GEDCOM element.
+ */
+class CustomElement extends AbstractElement
+{
+}
diff --git a/app/Elements/CustomEvent.php b/app/Elements/CustomEvent.php
new file mode 100644
index 0000000000..56b4929acb
--- /dev/null
+++ b/app/Elements/CustomEvent.php
@@ -0,0 +1,40 @@
+<?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\Elements;
+
+/**
+ * CustomEvent
+ */
+class CustomEvent extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'ADDR' => '0:1',
+ 'AGNC' => '0:1',
+ 'CAUS' => '0:1',
+ 'RELI' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/CustomFact.php b/app/Elements/CustomFact.php
new file mode 100644
index 0000000000..54bff382d4
--- /dev/null
+++ b/app/Elements/CustomFact.php
@@ -0,0 +1,39 @@
+<?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\Elements;
+
+/**
+ * CustomFact
+ */
+class CustomFact extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'ADDR' => '0:1',
+ 'AGNC' => '0:1',
+ 'CAUS' => '0:1',
+ 'RELI' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/DateLdsOrd.php b/app/Elements/DateLdsOrd.php
new file mode 100644
index 0000000000..bf95246f6d
--- /dev/null
+++ b/app/Elements/DateLdsOrd.php
@@ -0,0 +1,34 @@
+<?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\Elements;
+
+/**
+ * DATE := {Size=4:35}
+ * <DATE_VALUE>
+ * LDS ordinance dates use only the Gregorian date and most often use the form
+ * of day, month, and year. Only in rare instances is there a partial date. The
+ * temple tag and code should always accompany temple ordinance dates.
+ * Sometimes the LDS_(ordinance)_DATE_STATUS is used to indicate that an
+ * ordinance date and temple code is not required, such as when BIC is used.
+ * (See LDS_(ordinance)_DATE_STATUS definitions beginning on page 51.)
+ */
+class DateLdsOrd extends AbstractElement
+{
+}
diff --git a/app/Elements/DateValue.php b/app/Elements/DateValue.php
new file mode 100644
index 0000000000..9f1b70496a
--- /dev/null
+++ b/app/Elements/DateValue.php
@@ -0,0 +1,103 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Date;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Services\LocalizationService;
+use Fisharebest\Webtrees\Tree;
+
+use function app;
+use function e;
+use function preg_replace_callback;
+use function view;
+
+/**
+ * DATE_VALUE := {Size=1:35}
+ * [ <DATE> | <DATE_PERIOD> | <DATE_RANGE>| <DATE_APPROXIMATED> | INT <DATE> (<DATE_PHRASE>) | (<DATE_PHRASE>) ]
+ * The DATE_VALUE represents the date of an activity, attribute, or event where:
+ * INT = Interpreted from knowledge about the associated date phrase included in parentheses.
+ * An acceptable alternative to the date phrase choice is to use one of the other choices such as
+ * <DATE_APPROXIMATED> choice as the DATE line value and then include the date phrase value as a
+ * NOTE value subordinate to the DATE line tag.
+ * The date value can take on the date form of just a date, an approximated date, between a date
+ * and another date, and from one date to another date. The preferred form of showing date
+ * imprecision, is to show, for example, MAY 1890 rather than ABT 12 MAY 1890. This is because
+ * limits have not been assigned to the precision of the prefixes such as ABT or EST.
+ */
+class DateValue extends AbstractElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ // Need to know if the user prefers DMY/MDY/YMD so we can validate dates properly.
+ $dmy = app(LocalizationService::class)->dateFormatToOrder(I18N::dateFormat());
+
+ return
+ '<div class="input-group">' .
+ '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" onchange="webtrees.reformatDate(this, \'' . e($dmy) . '\')" dir="ltr">' .
+ view('edit/input-addon-calendar', ['id' => $id]) .
+ view('edit/input-addon-help', ['fact' => 'DATE']) .
+ '</div>' .
+ '<div id="caldiv' . $id . '" style="position:absolute;visibility:hidden;background-color:white;z-index:1000"></div>' .
+ '<p class="text-muted">' . (new Date($value))->display() . '</p>';
+ }
+
+ /**
+ * Escape @ signs in a GEDCOM export.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function escape(string $value): string
+ {
+ // Only escape @ signs in an INT phrase
+ return preg_replace_callback('/\(.*@.*\)/', static function (array $matches): string {
+ return strtr($matches[0], ['@' => '@@']);
+ }, $value);
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ $date = new Date($canonical);
+
+ return $date->display(true);
+ }
+}
diff --git a/app/Elements/Death.php b/app/Elements/Death.php
new file mode 100644
index 0000000000..88775e7984
--- /dev/null
+++ b/app/Elements/Death.php
@@ -0,0 +1,37 @@
+<?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\Elements;
+
+/**
+ * Death
+ */
+class Death extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'CAUS' => '0:1',
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/DescriptiveTitle.php b/app/Elements/DescriptiveTitle.php
new file mode 100644
index 0000000000..21c02e2c36
--- /dev/null
+++ b/app/Elements/DescriptiveTitle.php
@@ -0,0 +1,28 @@
+<?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\Elements;
+
+/**
+ * DESCRIPTIVE_TITLE := {Size=1:248}
+ * The title of a work, record, item, or object.
+ */
+class DescriptiveTitle extends AbstractElement
+{
+}
diff --git a/app/Elements/Divorce.php b/app/Elements/Divorce.php
new file mode 100644
index 0000000000..f401496888
--- /dev/null
+++ b/app/Elements/Divorce.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * Divorce
+ */
+class Divorce extends AbstractEventElement
+{
+}
diff --git a/app/Elements/DivorceFiled.php b/app/Elements/DivorceFiled.php
new file mode 100644
index 0000000000..f58e2bc423
--- /dev/null
+++ b/app/Elements/DivorceFiled.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * Divorce Filed
+ */
+class DivorceFiled extends AbstractEventElement
+{
+}
diff --git a/app/Elements/Emigration.php b/app/Elements/Emigration.php
new file mode 100644
index 0000000000..9c1cf9149c
--- /dev/null
+++ b/app/Elements/Emigration.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Emigration
+ */
+class Emigration extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/EmptyElement.php b/app/Elements/EmptyElement.php
new file mode 100644
index 0000000000..74d94c6134
--- /dev/null
+++ b/app/Elements/EmptyElement.php
@@ -0,0 +1,45 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+
+/**
+ * An empty element with no data - only child elements.
+ */
+class EmptyElement extends AbstractElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return '<input class="form-control" type="hidden" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">';
+ }
+}
diff --git a/app/Elements/Engagement.php b/app/Elements/Engagement.php
new file mode 100644
index 0000000000..7ad78abad5
--- /dev/null
+++ b/app/Elements/Engagement.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * Engagement
+ */
+class Engagement extends AbstractElement
+{
+}
diff --git a/app/Elements/EntryRecordingDate.php b/app/Elements/EntryRecordingDate.php
new file mode 100644
index 0000000000..fe933263c0
--- /dev/null
+++ b/app/Elements/EntryRecordingDate.php
@@ -0,0 +1,48 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Date;
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * ENTRY_RECORDING_DATE := {Size=1:90}
+ * <DATE_VALUE>
+ * The date that this event data was entered into the original source document.
+ */
+class EntryRecordingDate extends AbstractElement
+{
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ $date = new Date($canonical);
+
+ return $date->display(false);
+ }
+}
diff --git a/app/Elements/EventAttributeType.php b/app/Elements/EventAttributeType.php
new file mode 100644
index 0000000000..797158f2b5
--- /dev/null
+++ b/app/Elements/EventAttributeType.php
@@ -0,0 +1,33 @@
+<?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\Elements;
+
+/**
+ * EVENT_ATTRIBUTE_TYPE := {Size=1:15}
+ * [ <EVENT_TYPE_INDIVIDUAL> | <EVENT_TYPE_FAMILY> | <ATTRIBUTE_TYPE> ]
+ * A code that classifies the principal event or happening that caused the
+ * source record entry to be created. If the event or attribute doesn't
+ * translate to one of these tag codes, then a user supplied value is
+ * expected and will be generally classified in the category of other.
+ */
+class EventAttributeType extends AbstractElement
+{
+ protected const MAX_LENGTH = 15;
+}
diff --git a/app/Elements/EventDescriptor.php b/app/Elements/EventDescriptor.php
new file mode 100644
index 0000000000..a27e774da9
--- /dev/null
+++ b/app/Elements/EventDescriptor.php
@@ -0,0 +1,67 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * EVENT_DESCRIPTOR := {Size=1:90}
+ * Text describing a particular event pertaining to the individual or family.
+ * This event value is usually assigned to the EVEN tag. The classification as
+ * to the difference between this specific event and other occurrences of the
+ * EVENt tag is indicated by the use of a subordinate TYPE tag selected from
+ * the EVENT_DETAIL structure. For example;
+ * 1 EVEN Appointed Zoning Committee Chairperson
+ * 2 TYPE Civic Appointments
+ * 2 DATE FROM JAN 1952 TO JAN 1956
+ * 2 PLAC Cove, Cache, Utah
+ * 2 AGNC Cove City Redevelopment
+ */
+class EventDescriptor extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ // This is a special value used for creating events of close relatives.
+ if ($value === 'CLOSE_RELATIVE') {
+ return '';
+ }
+
+ return parent::value($value, $tree);
+ }
+}
diff --git a/app/Elements/EventOrFactClassification.php b/app/Elements/EventOrFactClassification.php
new file mode 100644
index 0000000000..50a95091e6
--- /dev/null
+++ b/app/Elements/EventOrFactClassification.php
@@ -0,0 +1,50 @@
+<?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\Elements;
+
+/**
+ * EVENT_OR_FACT_CLASSIFICA TION := {Size=1:90}
+ * A descriptive word or phrase used to further classify the parent event or
+ * attribute tag. This should be used whenever either of the generic EVEN or
+ * FACT tags are used. The value of this primative is responsible for
+ * classifying the generic event or fact being cited. For example, if the
+ * attribute being defined was one of the persons skills, such as woodworking,
+ * the FACT tag would have the value of `Woodworking', followed by a
+ * subordinate TYPE tag with the value `Skills.'
+ * 1 FACT Woodworking
+ * 2 TYPE Skills
+ * This groups the fact into a generic skills attribute, and in particular this
+ * entry records the fact that this individual possessed the skill of
+ * woodworking. Using the subordinate TYPE tag classification method with any
+ * of the other defined event tags provides a further classification of the
+ * parent tag but does not change the basic meaning of the parent tag. For
+ * example, a MARR tag could be subordinated with a TYPE tag with an
+ * EVENT_DESCRIPTOR value of `Common Law.'
+ * 1 MARR
+ * 2 TYPE Common Law
+ * This classifies the entry as a common law marriage but the event is still a
+ * marriage event. Other descriptor values might include, for example,
+ * `stillborn' as a qualifier to BIRTh or `Tribal Custom' as a qualifier to
+ * MARRiage.
+ */
+class EventOrFactClassification extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+}
diff --git a/app/Elements/EventTypeCitedFrom.php b/app/Elements/EventTypeCitedFrom.php
new file mode 100644
index 0000000000..30eeace39e
--- /dev/null
+++ b/app/Elements/EventTypeCitedFrom.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * EVENT_OR_FACT_CLASSIFICATION := {Size=1:15}
+ * [ <EVENT_ATTRIBUTE_TYPE> ]
+ * A code that indicates the type of event which was responsible for the source
+ * entry being recorded. For example, if the entry was created to record a
+ * birth of a child, then the type would be BIRT regardless of the assertions
+ * made from that record, such as the mother's name or mother's birth date.
+ * This will allow a prioritized best view choice and a determination of the
+ * certainty associated with the source used in asserting the cited fact.
+ */
+class EventTypeCitedFrom extends AbstractElement
+{
+ protected const MAX_LENGTH = 15;
+}
diff --git a/app/Elements/EventsRecorded.php b/app/Elements/EventsRecorded.php
new file mode 100644
index 0000000000..4ff3efe2bc
--- /dev/null
+++ b/app/Elements/EventsRecorded.php
@@ -0,0 +1,171 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+use Illuminate\Support\Collection;
+use Ramsey\Uuid\Uuid;
+
+use function array_map;
+use function explode;
+use function implode;
+use function strtoupper;
+use function view;
+
+/**
+ * EVENTS_RECORDED := {Size=1:90}
+ * [<EVENT_ATTRIBUTE_TYPE> | <EVENTS_RECORDED>, <EVENT_ATTRIBUTE_TYPE>]
+ * An enumeration of the different kinds of events that were recorded in a
+ * particular source. Each enumeration is separated by a comma. Such as a
+ * parish register of births, deaths, and marriages would be BIRT, DEAT, MARR.
+ */
+class EventsRecorded extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ ];
+
+ protected const EVENTS_RECORDED = [
+ 'INDI:ADOP',
+ 'INDI:BAPM',
+ 'INDI:BARM',
+ 'INDI:BASM',
+ 'INDI:BIRT',
+ 'INDI:BLES',
+ 'INDI:BURI',
+ 'INDI:CAST',
+ 'INDI:CHR',
+ 'INDI:CENS',
+ 'INDI:CHRA',
+ 'INDI:CONF',
+ 'INDI:CREM',
+ 'INDI:DEAT',
+ 'INDI:DSCR',
+ 'INDI:EDUC',
+ 'INDI:EMIG',
+ 'INDI:FCOM',
+ 'INDI:GRAD',
+ 'INDI:IDNO',
+ 'INDI:IMMI',
+ 'INDI:NATI',
+ 'INDI:NATU',
+ 'INDI:NCHI',
+ 'INDI:NMR',
+ 'INDI:OCCU',
+ 'INDI:ORDN',
+ 'INDI:PROB',
+ 'INDI:PROP',
+ 'INDI:RELI',
+ 'INDI:RESI',
+ 'INDI:RETI',
+ 'INDI:SSN',
+ 'INDI:TITL',
+ 'INDI:WILL',
+ 'FAM:ANUL',
+ 'FAM:DIV',
+ 'FAM:DIVF',
+ 'FAM:ENGA',
+ 'FAM:MARB',
+ 'FAM:MARC',
+ 'FAM:MARL',
+ 'FAM:MARS',
+ 'FAM:MARR',
+ ];
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(strtr(parent::canonical($value), [' ' => '']));
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ $factory = Registry::elementFactory();
+
+ $options = Collection::make(self::EVENTS_RECORDED)
+ ->mapWithKeys(static function (string $tag) use ($factory): array {
+ return [explode(':', $tag)[1] => $factory->make($tag)->label()];
+ })
+ ->sort()
+ ->all();
+
+ $id2 = Uuid::uuid4()->toString();
+
+ // Our form element name contains "[]", and multiple selections would create multiple values.
+ $hidden = '<input type="hidden" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">';
+ // Combine them into a single value.
+ // The change event doesn't seem to fire for select2 controls, so use form.submit instead.
+ $js = 'document.getElementById("' . $id2 . '").form.addEventListener("submit", function () { document.getElementById("' . $id . '").value = Array.from(document.getElementById("' . $id2 . '").selectedOptions).map(x => x.value).join(","); });';
+
+ return view('components/select', [
+ 'class' => 'select2',
+ 'name' => '',
+ 'id' => $id2,
+ 'options' => $options,
+ 'selected' => explode(',', strtr($value, [' ' => ''])),
+ ]) . $hidden . '<script>' . $js . '</script>';
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $tags = explode(',', $this->canonical($value));
+
+ $events = array_map(static function (string $tag): string {
+ foreach (['INDI', 'FAM'] as $record_type) {
+ $element = Registry::elementFactory()->make($record_type . ':' . $tag);
+
+ if (!$element instanceof UnknownElement) {
+ return $element->label();
+ }
+ }
+
+ return $tag;
+ }, $tags);
+
+ return implode(I18N::$list_separator, $events);
+ }
+}
diff --git a/app/Elements/FileName.php b/app/Elements/FileName.php
new file mode 100644
index 0000000000..8e408d0b07
--- /dev/null
+++ b/app/Elements/FileName.php
@@ -0,0 +1,43 @@
+<?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\Elements;
+
+/**
+ * FILE_NAME := {Size=1:90}
+ * The name of the GEDCOM transmission file. If the file name includes a file
+ * extension it must be shown in the form (filename.ext).
+ */
+class FileName extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ // Don't change spaces. " Foo bar.jpeg" is a valid file name!
+ return $value;
+ }
+}
diff --git a/app/Elements/FirstCommunion.php b/app/Elements/FirstCommunion.php
new file mode 100644
index 0000000000..eb24946a88
--- /dev/null
+++ b/app/Elements/FirstCommunion.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * First Communion
+ */
+class FirstCommunion extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/Form.php b/app/Elements/Form.php
new file mode 100644
index 0000000000..e264b5daf9
--- /dev/null
+++ b/app/Elements/Form.php
@@ -0,0 +1,47 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * GEDCOM_FORM := {Size=14:20}
+ * [ LINEAGE-LINKED ]
+ * The GEDCOM form used to construct this transmission. There maybe other forms
+ * used such as CommSoft's "EVENT_LINEAGE_LINKED" but these specifications
+ * define only the LINEAGE-LINKED Form. Systems will use this value to specify
+ * GEDCOM compatible with these specifications.
+ */
+class Form extends AbstractElement
+{
+ protected const MAX_LENGTH = 20;
+
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ return 'LINEAGE-LINKED';
+ }
+}
diff --git a/app/Elements/Gedcom.php b/app/Elements/Gedcom.php
new file mode 100644
index 0000000000..a1071a994c
--- /dev/null
+++ b/app/Elements/Gedcom.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * HEAD:GEDC is an empty element with children; VERS and FORM.
+ */
+class Gedcom extends EmptyElement
+{
+}
diff --git a/app/Elements/GenerationsOfAncestors.php b/app/Elements/GenerationsOfAncestors.php
new file mode 100644
index 0000000000..c79714053a
--- /dev/null
+++ b/app/Elements/GenerationsOfAncestors.php
@@ -0,0 +1,46 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * GENERATIONS_OF_ANCESTORS := {Size=1:4}
+ * The number of generations of ancestors included in this transmission. This
+ * value is usually provided when FamilySearch programs build a GEDCOM file for
+ * a patron requesting a download of ancestors.
+ */
+class GenerationsOfAncestors extends AbstractElement
+{
+ protected const MAX_LENGTH = 4;
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueNumeric($value);
+ }
+}
diff --git a/app/Elements/GenerationsOfDescendants.php b/app/Elements/GenerationsOfDescendants.php
new file mode 100644
index 0000000000..844a304375
--- /dev/null
+++ b/app/Elements/GenerationsOfDescendants.php
@@ -0,0 +1,46 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * GENERATIONS_OF_DESCENDANTS := {Size=1:4}
+ * The number of generations of descendants included in this transmission. This
+ * value is usually provided when FamilySearch programs build a GEDCOM file for
+ * a patron requesting a download of descendants.
+ */
+class GenerationsOfDescendants extends AbstractElement
+{
+ protected const MAX_LENGTH = 4;
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueNumeric($value);
+ }
+}
diff --git a/app/Elements/GovId.php b/app/Elements/GovId.php
new file mode 100644
index 0000000000..f1c8fe88cc
--- /dev/null
+++ b/app/Elements/GovId.php
@@ -0,0 +1,45 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+
+/**
+ * A custom field used in _LOC records
+ */
+class GovId extends AbstractElement
+{
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ return '<a dir="ltr" href="https://gov.genealogy.net/item/show/' . e($canonical) . '">' . e($canonical) . '</a>';
+ }
+}
diff --git a/app/Elements/Graduation.php b/app/Elements/Graduation.php
new file mode 100644
index 0000000000..476211fc7f
--- /dev/null
+++ b/app/Elements/Graduation.php
@@ -0,0 +1,37 @@
+<?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\Elements;
+
+/**
+ * Graduation
+ */
+class Graduation extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'AGNC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/Immigration.php b/app/Elements/Immigration.php
new file mode 100644
index 0000000000..d712fae3be
--- /dev/null
+++ b/app/Elements/Immigration.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Immigration
+ */
+class Immigration extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/LanguageId.php b/app/Elements/LanguageId.php
new file mode 100644
index 0000000000..de931e31cd
--- /dev/null
+++ b/app/Elements/LanguageId.php
@@ -0,0 +1,216 @@
+<?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\Elements;
+
+use Fisharebest\Localization\Locale\LocaleAf;
+use Fisharebest\Localization\Locale\LocaleAm;
+use Fisharebest\Localization\Locale\LocaleAng;
+use Fisharebest\Localization\Locale\LocaleAr;
+use Fisharebest\Localization\Locale\LocaleAs;
+use Fisharebest\Localization\Locale\LocaleBe;
+use Fisharebest\Localization\Locale\LocaleBg;
+use Fisharebest\Localization\Locale\LocaleBn;
+use Fisharebest\Localization\Locale\LocaleBo;
+use Fisharebest\Localization\Locale\LocaleCa;
+use Fisharebest\Localization\Locale\LocaleCaEsValencia;
+use Fisharebest\Localization\Locale\LocaleCs;
+use Fisharebest\Localization\Locale\LocaleCu;
+use Fisharebest\Localization\Locale\LocaleDa;
+use Fisharebest\Localization\Locale\LocaleDe;
+use Fisharebest\Localization\Locale\LocaleEl;
+use Fisharebest\Localization\Locale\LocaleEn;
+use Fisharebest\Localization\Locale\LocaleEo;
+use Fisharebest\Localization\Locale\LocaleEs;
+use Fisharebest\Localization\Locale\LocaleEt;
+use Fisharebest\Localization\Locale\LocaleFa;
+use Fisharebest\Localization\Locale\LocaleFi;
+use Fisharebest\Localization\Locale\LocaleFo;
+use Fisharebest\Localization\Locale\LocaleFr;
+use Fisharebest\Localization\Locale\LocaleGu;
+use Fisharebest\Localization\Locale\LocaleHaw;
+use Fisharebest\Localization\Locale\LocaleHe;
+use Fisharebest\Localization\Locale\LocaleHi;
+use Fisharebest\Localization\Locale\LocaleHu;
+use Fisharebest\Localization\Locale\LocaleHy;
+use Fisharebest\Localization\Locale\LocaleId;
+use Fisharebest\Localization\Locale\LocaleIs;
+use Fisharebest\Localization\Locale\LocaleIt;
+use Fisharebest\Localization\Locale\LocaleJa;
+use Fisharebest\Localization\Locale\LocaleKa;
+use Fisharebest\Localization\Locale\LocaleKm;
+use Fisharebest\Localization\Locale\LocaleKn;
+use Fisharebest\Localization\Locale\LocaleKo;
+use Fisharebest\Localization\Locale\LocaleKok;
+use Fisharebest\Localization\Locale\LocaleLo;
+use Fisharebest\Localization\Locale\LocaleLt;
+use Fisharebest\Localization\Locale\LocaleLv;
+use Fisharebest\Localization\Locale\LocaleMk;
+use Fisharebest\Localization\Locale\LocaleMl;
+use Fisharebest\Localization\Locale\LocaleMr;
+use Fisharebest\Localization\Locale\LocaleMy;
+use Fisharebest\Localization\Locale\LocaleNe;
+use Fisharebest\Localization\Locale\LocaleNl;
+use Fisharebest\Localization\Locale\LocaleNn;
+use Fisharebest\Localization\Locale\LocaleOr;
+use Fisharebest\Localization\Locale\LocalePa;
+use Fisharebest\Localization\Locale\LocalePl;
+use Fisharebest\Localization\Locale\LocalePs;
+use Fisharebest\Localization\Locale\LocalePt;
+use Fisharebest\Localization\Locale\LocaleRo;
+use Fisharebest\Localization\Locale\LocaleRu;
+use Fisharebest\Localization\Locale\LocaleSk;
+use Fisharebest\Localization\Locale\LocaleSl;
+use Fisharebest\Localization\Locale\LocaleSq;
+use Fisharebest\Localization\Locale\LocaleSr;
+use Fisharebest\Localization\Locale\LocaleSv;
+use Fisharebest\Localization\Locale\LocaleTa;
+use Fisharebest\Localization\Locale\LocaleTe;
+use Fisharebest\Localization\Locale\LocaleTh;
+use Fisharebest\Localization\Locale\LocaleTl;
+use Fisharebest\Localization\Locale\LocaleTr;
+use Fisharebest\Localization\Locale\LocaleUk;
+use Fisharebest\Localization\Locale\LocaleUr;
+use Fisharebest\Localization\Locale\LocaleVi;
+use Fisharebest\Localization\Locale\LocaleYi;
+use Fisharebest\Localization\Locale\LocaleYue;
+
+use function preg_replace_callback;
+
+/**
+ * LANGUAGE_ID := {Size=1:15}
+ * The human language in which the data in the transmission is normally read or
+ * written. It is used primarily by programs to select language-specific
+ * sorting sequences and phonetic name matching algorithms.
+ */
+class LanguageId extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return preg_replace_callback('/[A-Za-z]+/', static function (array $match): string {
+ return ucwords($match[0]);
+ }, strtolower(parent::canonical($value)));
+ }
+
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'Afrikaans' => (new LocaleAf())->endonym(),
+ 'Albanian' => (new LocaleSq())->endonym(),
+ 'Amharic' => (new LocaleAm())->endonym(),
+ 'Anglo-Saxon' => (new LocaleAng())->endonym(),
+ 'Arabic' => (new LocaleAr())->endonym(),
+ 'Armenian' => (new LocaleHy())->endonym(),
+ 'Assamese' => (new LocaleAs())->endonym(),
+ 'Belorusian' => (new LocaleBe())->endonym(),
+ 'Bengali' => (new LocaleBn())->endonym(),
+ //'Braj' => (new LocaleBra())->endonym(),
+ 'Bulgarian' => (new LocaleBg())->endonym(),
+ 'Burmese' => (new LocaleMy())->endonym(),
+ 'Cantonese' => (new LocaleYue())->endonym(),
+ 'Catalan' => (new LocaleCaEsValencia())->endonym(),
+ 'Catalan_Spn' => (new LocaleCa())->endonym(),
+ 'Church-Slavic' => (new LocaleCu())->endonym(),
+ 'Czech' => (new LocaleCs())->endonym(),
+ 'Danish' => (new LocaleDa())->endonym(),
+ //'Dogri' => (new LocaleDoi())->endonym(),
+ 'Dutch' => (new LocaleNl())->endonym(),
+ 'English' => (new LocaleEn())->endonym(),
+ 'Esperanto' => (new LocaleEo())->endonym(),
+ 'Estonian' => (new LocaleEt())->endonym(),
+ 'Faroese' => (new LocaleFo())->endonym(),
+ 'Finnish' => (new LocaleFi())->endonym(),
+ 'French' => (new LocaleFr())->endonym(),
+ 'Georgian' => (new LocaleKa())->endonym(),
+ 'German' => (new LocaleDe())->endonym(),
+ 'Greek' => (new LocaleEl())->endonym(),
+ 'Gujarati' => (new LocaleGu())->endonym(),
+ 'Hawaiian' => (new LocaleHaw())->endonym(),
+ 'Hebrew' => (new LocaleHe())->endonym(),
+ 'Hindi' => (new LocaleHi())->endonym(),
+ 'Hungarian' => (new LocaleHu())->endonym(),
+ 'Icelandic' => (new LocaleIs())->endonym(),
+ 'Indonesian' => (new LocaleId())->endonym(),
+ 'Italian' => (new LocaleIt())->endonym(),
+ 'Japanese' => (new LocaleJa())->endonym(),
+ 'Kannada' => (new LocaleKn())->endonym(),
+ 'Khmer' => (new LocaleKm())->endonym(),
+ 'Konkani' => (new LocaleKok())->endonym(),
+ 'Korean' => (new LocaleKo())->endonym(),
+ //'Lahnda' => (new LocaleLah())->endonym(),
+ 'Lao' => (new LocaleLo())->endonym(),
+ 'Latvian' => (new LocaleLv())->endonym(),
+ 'Lithuanian' => (new LocaleLt())->endonym(),
+ 'Macedonian' => (new LocaleMk())->endonym(),
+ //'Maithili' => (new LocaleMai())->endonym(),
+ 'Malayalam' => (new LocaleMl())->endonym(),
+ //'Mandrin' => (new LocaleCmn())->endonym(),
+ //'Manipuri' => (new LocaleMni())->endonym(),
+ 'Marathi' => (new LocaleMr())->endonym(),
+ //'Mewari' => (new LocaleMtr())->endonym(),
+ //'Navaho' => (new LocaleNv())->endonym(),
+ 'Nepali' => (new LocaleNe())->endonym(),
+ 'Norwegian' => (new LocaleNn())->endonym(),
+ 'Oriya' => (new LocaleOr())->endonym(),
+ //'Pahari' => (new LocalePhr())->endonym(),
+ //'Pali' => (new LocalePi())->endonym(),
+ 'Panjabi' => (new LocalePa())->endonym(),
+ 'Persian' => (new LocaleFa())->endonym(),
+ 'Polish' => (new LocalePl())->endonym(),
+ 'Portuguese' => (new LocalePt())->endonym(),
+ //'Prakrit' => (new LocalePra())->endonym(),
+ 'Pusto' => (new LocalePs())->endonym(),
+ //'Rajasthani' => (new LocaleRaj())->endonym(),
+ 'Romanian' => (new LocaleRo())->endonym(),
+ 'Russian' => (new LocaleRu())->endonym(),
+ //'Sanskrit' => (new LocaleSa())->endonym(),
+ 'Serb' => (new LocaleSr())->endonym(),
+ //'Serbo_Croa' => (new LocaleHbs())->endonym(),
+ 'Slovak' => (new LocaleSk())->endonym(),
+ 'Slovene' => (new LocaleSl())->endonym(),
+ 'Spanish' => (new LocaleEs())->endonym(),
+ 'Swedish' => (new LocaleSv())->endonym(),
+ 'Tagalog' => (new LocaleTl())->endonym(),
+ 'Tamil' => (new LocaleTa())->endonym(),
+ 'Telugu' => (new LocaleTe())->endonym(),
+ 'Thai' => (new LocaleTh())->endonym(),
+ 'Tibetan' => (new LocaleBo())->endonym(),
+ 'Turkish' => (new LocaleTr())->endonym(),
+ 'Ukrainian' => (new LocaleUk())->endonym(),
+ 'Urdu' => (new LocaleUr())->endonym(),
+ 'Vietnamese' => (new LocaleVi())->endonym(),
+ //'Wendic' => (new LocaleWen())->endonym(),
+ 'Yiddish' => (new LocaleYi())->endonym(),
+ ];
+ }
+}
diff --git a/app/Elements/LdsBaptism.php b/app/Elements/LdsBaptism.php
new file mode 100644
index 0000000000..40a858d2ae
--- /dev/null
+++ b/app/Elements/LdsBaptism.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * INDI:BAPL is an empty element with children; DATE, TEMP, PLAC, STAT, NOTE and SOUR.
+ */
+class LdsBaptism extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'TEMP' => '0:1',
+ 'PLAC' => '0:1',
+ 'STAT' => '0:1',
+ 'NOTE' => '0:M',
+ 'SOUR' => '0:M',
+ ];
+}
diff --git a/app/Elements/LdsBaptismDateStatus.php b/app/Elements/LdsBaptismDateStatus.php
new file mode 100644
index 0000000000..5d921ac195
--- /dev/null
+++ b/app/Elements/LdsBaptismDateStatus.php
@@ -0,0 +1,80 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtoupper;
+
+/**
+ * LDS_BAPTISM_DATE_STATUS := {Size=5:10}
+ * [ CHILD | COMPLETED | EXCLUDED | PRE-1970 | STILLBORN | SUBMITTED | UNCLEARED ]
+ * A code indicating the status of an LDS baptism and confirmation date where:
+ * CHILD = Died before becoming eight years old, baptism not required.
+ * COMPLETED = Completed but the date is not known.
+ * EXCLUDED = Patron excluded this ordinance from being cleared in this submission.
+ * PRE-1970 = Ordinance is likely completed, another ordinance for this person
+ * was converted from temple records of work completed before 1970,
+ * therefore this ordinance is assumed to be complete until all
+ * records are converted.
+ * STILLBORN = Stillborn, baptism not required.
+ * SUBMITTED = Ordinance was previously submitted.
+ * UNCLEARED = Data for clearing ordinance request was insufficient.
+ */
+class LdsBaptismDateStatus extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(parent::canonical($value));
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'CHILD' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Died as a child: exempt'),
+ 'COMPLETED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Completed; date unknown'),
+ 'EXCLUDED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Excluded from this submission'),
+ 'PRE-1970' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Completed before 1970; date not available'),
+ 'STILLBORN' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Stillborn: exempt'),
+ 'SUBMITTED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Submitted but not yet cleared'),
+ 'UNCLEARED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Uncleared: insufficient data'),
+ ];
+ }
+}
diff --git a/app/Elements/LdsChildSealing.php b/app/Elements/LdsChildSealing.php
new file mode 100644
index 0000000000..4f6dd811f4
--- /dev/null
+++ b/app/Elements/LdsChildSealing.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * INDI:SLGC is an empty element with children; DATE, TEMP, PLAC, FAMC, STAT, NOTE and SOUR.
+ */
+class LdsChildSealing extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'TEMP' => '0:1',
+ 'PLAC' => '0:1',
+ 'STAT' => '0:1',
+ 'NOTE' => '0:M',
+ 'SOUR' => '0:M',
+ ];
+}
diff --git a/app/Elements/LdsChildSealingDateStatus.php b/app/Elements/LdsChildSealingDateStatus.php
new file mode 100644
index 0000000000..0f06706614
--- /dev/null
+++ b/app/Elements/LdsChildSealingDateStatus.php
@@ -0,0 +1,73 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtoupper;
+
+/**
+ * LDS_BAPTISM_DATE_STATUS := {Size=5:10}
+ * [ BIC | COMPLETED | EXCLUDED | DNS | PRE-1970 | STILLBORN | SUBMITTED | UNCLEARED ]
+ * BIC = Born in the covenant receiving blessing of child to parent sealing.
+ * EXCLUDED = Patron excluded this ordinance from being cleared in this submission.
+ * PRE-1970 = (See pre-1970 under LDS_BAPTISM_DATE_STATUS on page 51.)
+ * STILLBORN = Stillborn, baptism not required.
+ * SUBMITTED = Ordinance was previously submitted.
+ * UNCLEARED = Data for clearing ordinance request was insufficient.
+ */
+class LdsChildSealingDateStatus extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(parent::canonical($value));
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'BIC' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Born in the covenant'),
+ 'EXCLUDED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Excluded from this submission'),
+ 'PRE-1970' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Completed before 1970; date not available'),
+ 'STILLBORN' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Stillborn: exempt'),
+ 'SUBMITTED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Submitted but not yet cleared'),
+ 'UNCLEARED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Uncleared: insufficient data'),
+ ];
+ }
+}
diff --git a/app/Elements/LdsConfirmation.php b/app/Elements/LdsConfirmation.php
new file mode 100644
index 0000000000..905948e223
--- /dev/null
+++ b/app/Elements/LdsConfirmation.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * INDI:CONL is an empty element with children; DATE, TEMP, PLAC, STAT, NOTE and SOUR.
+ */
+class LdsConfirmation extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'TEMP' => '0:1',
+ 'PLAC' => '0:1',
+ 'STAT' => '0:1',
+ 'NOTE' => '0:M',
+ 'SOUR' => '0:M',
+ ];
+}
diff --git a/app/Elements/LdsEndowment.php b/app/Elements/LdsEndowment.php
new file mode 100644
index 0000000000..3cc0680980
--- /dev/null
+++ b/app/Elements/LdsEndowment.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * INDI:ENDL is an empty element with children; DATE, TEMP, PLAC, STAT, NOTE and SOUR.
+ */
+class LdsEndowment extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'TEMP' => '0:1',
+ 'PLAC' => '0:1',
+ 'STAT' => '0:1',
+ 'NOTE' => '0:M',
+ 'SOUR' => '0:M',
+ ];
+}
diff --git a/app/Elements/LdsEndowmentDateStatus.php b/app/Elements/LdsEndowmentDateStatus.php
new file mode 100644
index 0000000000..e5bef6046f
--- /dev/null
+++ b/app/Elements/LdsEndowmentDateStatus.php
@@ -0,0 +1,81 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtoupper;
+
+/**
+ * LDS_ENDOWMENT_DATE_STATUS := {Size=5:10}
+ * [ CHILD | COMPLETED | EXCLUDED | PRE-1970 | STILLBORN | SUBMITTED | UNCLEARED ]
+ * A code indicating the status of an LDS endowment ordinance where:
+ * CHILD = Died before eight years old.
+ * COMPLETED = Completed but the date is not known.
+ * EXCLUDED = Patron excluded this ordinance from being cleared in this submission.
+ * PRE-1970 = (See pre-1970 under LDS_BAPTISM_DATE_STATUS on page 51.)
+ * STILLBORN = Stillborn, baptism not required.
+ * SUBMITTED = Ordinance was previously submitted.
+ * UNCLEARED = Data for clearing ordinance request was insufficient.
+ */
+class LdsEndowmentDateStatus extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ ];
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(parent::canonical($value));
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'CHILD' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Died as a child: exempt'),
+ 'COMPLETED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Completed; date unknown'),
+ 'EXCLUDED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Excluded from this submission'),
+ 'PRE-1970' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Completed before 1970; date not available'),
+ 'STILLBORN' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Stillborn: exempt'),
+ 'SUBMITTED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Submitted but not yet cleared'),
+ 'UNCLEARED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Uncleared: insufficient data'),
+ ];
+ }
+}
diff --git a/app/Elements/LdsSpouseSealing.php b/app/Elements/LdsSpouseSealing.php
new file mode 100644
index 0000000000..74358093b1
--- /dev/null
+++ b/app/Elements/LdsSpouseSealing.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * FAM:SLGS is an empty element with children; DATE, TEMP, PLAC, STAT, NOTE and SOUR.
+ */
+class LdsSpouseSealing extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'TEMP' => '0:1',
+ 'PLAC' => '0:1',
+ 'STAT' => '0:1',
+ 'NOTE' => '0:M',
+ 'SOUR' => '0:M',
+ ];
+}
diff --git a/app/Elements/LdsSpouseSealingDateStatus.php b/app/Elements/LdsSpouseSealingDateStatus.php
new file mode 100644
index 0000000000..b9b4028e2e
--- /dev/null
+++ b/app/Elements/LdsSpouseSealingDateStatus.php
@@ -0,0 +1,80 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtr;
+
+/**
+ * LDS_BAPTISM_DATE_STATUS := {Size=5:10}
+ * [ CANCELED | COMPLETED | DNS | EXCLUDED | DNS/CAN | PRE-1970 | SUBMITTED | UNCLEARED ]
+ * CANCELED = Canceled and considered invalid.
+ * COMPLETED = Completed but the date is not known.
+ * DNS = This ordinance is not authorized.
+ * EXCLUDED = Patron excluded this ordinance from being cleared in this submission.
+ * DNS/CAN = This ordinance is not authorized, previous sealing cancelled.
+ * PRE-1970 = (See pre-1970 under LDS_BAPTISM_DATE_STATUS on page 51.)
+ * SUBMITTED = Ordinance was previously submitted.
+ * UNCLEARED = Data for clearing ordinance request was insufficient.
+ */
+class LdsSpouseSealingDateStatus extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ * Some applications use the British spelling instead of the US spelling.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtr(strtoupper(parent::canonical($value)), ['CANCELLED' => 'CANCELED']);
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'CANCELED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Sealing canceled (divorce)'),
+ 'COMPLETED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Completed; date unknown'),
+ 'DNS' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Do not seal: unauthorized'),
+ 'DNS/CAN' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Do not seal, previous sealing canceled'),
+ 'EXCLUDED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Excluded from this submission'),
+ 'PRE-1970' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Completed before 1970; date not available'),
+ 'SUBMITTED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Submitted but not yet cleared'),
+ 'UNCLEARED' => /* I18N: LDS sealing status; see https://en.wikipedia.org/wiki/Sealing_(Mormonism) */
+ I18N::translate('Uncleared: insufficient data'),
+ ];
+ }
+}
diff --git a/app/Elements/Marriage.php b/app/Elements/Marriage.php
new file mode 100644
index 0000000000..f750fe44b4
--- /dev/null
+++ b/app/Elements/Marriage.php
@@ -0,0 +1,38 @@
+<?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\Elements;
+
+/**
+ * Marriage
+ */
+class Marriage extends AbstractEventElement
+{
+ protected const SUBTAGS = [
+ 'TYPE' => '0:1',
+ 'DATE' => '0:1',
+ 'HUSB' => '0:1',
+ 'WIFE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/MarriageBanns.php b/app/Elements/MarriageBanns.php
new file mode 100644
index 0000000000..1e6bf61145
--- /dev/null
+++ b/app/Elements/MarriageBanns.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * Marriage Banns
+ */
+class MarriageBanns extends AbstractElement
+{
+}
diff --git a/app/Elements/MarriageContract.php b/app/Elements/MarriageContract.php
new file mode 100644
index 0000000000..f4ba44519d
--- /dev/null
+++ b/app/Elements/MarriageContract.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * Marriage Contract
+ */
+class MarriageContract extends AbstractElement
+{
+}
diff --git a/app/Elements/MarriageLicence.php b/app/Elements/MarriageLicence.php
new file mode 100644
index 0000000000..624cecbdc6
--- /dev/null
+++ b/app/Elements/MarriageLicence.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * Marriage Licence
+ */
+class MarriageLicence extends AbstractElement
+{
+}
diff --git a/app/Elements/MarriageSettlement.php b/app/Elements/MarriageSettlement.php
new file mode 100644
index 0000000000..9c23378bdf
--- /dev/null
+++ b/app/Elements/MarriageSettlement.php
@@ -0,0 +1,27 @@
+<?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\Elements;
+
+/**
+ * Marriage Settlement
+ */
+class MarriageSettlement extends AbstractElement
+{
+}
diff --git a/app/Elements/MarriageType.php b/app/Elements/MarriageType.php
new file mode 100644
index 0000000000..c3a9d44c40
--- /dev/null
+++ b/app/Elements/MarriageType.php
@@ -0,0 +1,66 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtolower;
+use function ucfirst;
+
+/**
+ * MARR:TYPE
+ */
+class MarriageType extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ * GEDCOM 5.5EL uses 'RELI' and 'CIVIL'
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ $value = ucfirst(strtolower(parent::canonical($value)));
+
+ $canonical = [
+ 'Reli' => 'Religious'
+ ];
+
+ return $canonical[$value] ?? $value;
+ }
+
+ /**
+ * A list of controlled values for this element.
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'Civil' => I18N::translate('Civil marriage'),
+ 'Partners' => I18N::translate('Registered partnership'),
+ 'Religious' => I18N::translate('Religious marriage'),
+
+ ];
+ }
+}
diff --git a/app/Elements/MediaRecord.php b/app/Elements/MediaRecord.php
new file mode 100644
index 0000000000..ec597bcf04
--- /dev/null
+++ b/app/Elements/MediaRecord.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * A level 0 media record
+ */
+class MediaRecord extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'FILE' => '1:M',
+ 'REFN' => '0:M',
+ 'RIN' => '0:1',
+ 'NOTE' => '0:M',
+ 'SOUR' => '0:M',
+ 'CHAN' => '0:1',
+ 'RESN' => '0:1', /* *** webtrees extension */
+ ];
+}
diff --git a/app/Elements/MultimediaFileReference.php b/app/Elements/MultimediaFileReference.php
new file mode 100644
index 0000000000..7ae477f5db
--- /dev/null
+++ b/app/Elements/MultimediaFileReference.php
@@ -0,0 +1,34 @@
+<?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\Elements;
+
+/**
+ * MULTIMEDIA_FILE_REFERENCE := {Size=1:30}
+ * A complete local or remote file reference to the auxiliary data to be linked
+ * to the GEDCOM context. Remote reference would include a network address
+ * where the multimedia data may be obtained.
+ */
+class MultimediaFileReference extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'FORM' => '0:1',
+ 'TITL' => '0:1',
+ ];
+}
diff --git a/app/Elements/MultimediaFormat.php b/app/Elements/MultimediaFormat.php
new file mode 100644
index 0000000000..1fa76cd480
--- /dev/null
+++ b/app/Elements/MultimediaFormat.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * MULTIMEDIA_FORMAT := {Size=3:4}
+ * [ bmp | gif | jpg | ole | pcx | tif | wav ]
+ * Indicates the format of the multimedia data associated with the specific
+ * GEDCOM context. This allows processors to determine whether they can process
+ * the data object. Any linked files should contain the data required, in the
+ * indicated format, to process the file data.
+ */
+class MultimediaFormat extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'TYPE' => '0:1',
+ ];
+}
diff --git a/app/Elements/NameOfBusiness.php b/app/Elements/NameOfBusiness.php
new file mode 100644
index 0000000000..1ea4a784da
--- /dev/null
+++ b/app/Elements/NameOfBusiness.php
@@ -0,0 +1,30 @@
+<?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\Elements;
+
+/**
+ * NAME_OF_BUSINESS := {Size=1:90}
+ * Name of the business, corporation, or person that produced or commissioned
+ * the product.
+ */
+class NameOfBusiness extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+}
diff --git a/app/Elements/NameOfFamilyFile.php b/app/Elements/NameOfFamilyFile.php
new file mode 100644
index 0000000000..ec2c6d0e06
--- /dev/null
+++ b/app/Elements/NameOfFamilyFile.php
@@ -0,0 +1,59 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function mb_substr;
+use function pathinfo;
+use function str_ends_with;
+use function strtolower;
+
+use const PATHINFO_EXTENSION;
+
+/**
+ * NAME_OF_FAMILY_FILE := {Size=1:120}
+ * Name under which family names for ordinances are stored in the temple's
+ * family file.
+ */
+class NameOfFamilyFile extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ $value = mb_substr($tree->name(), 0, self::MAX_LENGTH);
+
+ $extension = strtolower(pathinfo($value, PATHINFO_EXTENSION));
+
+ if ($extension !== 'ged') {
+ $value = mb_substr($tree->name(), 0, self::MAX_LENGTH - 4) . '.ged';
+ }
+
+ return $value;
+ }
+}
diff --git a/app/Elements/NameOfProduct.php b/app/Elements/NameOfProduct.php
new file mode 100644
index 0000000000..7ada45ba11
--- /dev/null
+++ b/app/Elements/NameOfProduct.php
@@ -0,0 +1,29 @@
+<?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\Elements;
+
+/**
+ * NAME_OF_PRODUCT := {Size=1:90}
+ * The name of the software product that produced this transmission.
+ */
+class NameOfProduct extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+}
diff --git a/app/Elements/NameOfRepository.php b/app/Elements/NameOfRepository.php
new file mode 100644
index 0000000000..b702ce4d83
--- /dev/null
+++ b/app/Elements/NameOfRepository.php
@@ -0,0 +1,29 @@
+<?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\Elements;
+
+/**
+ * NAME_OF_REPOSITORY := {Size=1:90}
+ * The official name of the archive in which the stated source material is stored.
+ */
+class NameOfRepository extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+}
diff --git a/app/Elements/NameOfSourceData.php b/app/Elements/NameOfSourceData.php
new file mode 100644
index 0000000000..5d6d9165bb
--- /dev/null
+++ b/app/Elements/NameOfSourceData.php
@@ -0,0 +1,31 @@
+<?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\Elements;
+
+/**
+ * NAME_OF_SOURCE_DATA := {Size=1:90}
+ * The name of the electronic data source that was used to obtain the data in
+ * this transmission. For example, the data may have been obtained from a
+ * CD-ROM disc that was named "U.S. 1880 CENSUS CD-ROM vol. 13."
+ */
+class NameOfSourceData extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+}
diff --git a/app/Elements/NamePersonal.php b/app/Elements/NamePersonal.php
new file mode 100644
index 0000000000..0e79f72b45
--- /dev/null
+++ b/app/Elements/NamePersonal.php
@@ -0,0 +1,145 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\SurnameTradition;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function view;
+
+/**
+ * NAME_PERSONAL := {Size=1:120}
+ * [
+ * <NAME_TEXT> | /<NAME_TEXT>/ |
+ * <NAME_TEXT> /<NAME_TEXT>/ | /<NAME_TEXT>/ <NAME_TEXT> |
+ * <NAME_TEXT> /<NAME_TEXT>/ <NAME_TEXT> ]
+ * The surname of an individual, if known, is enclosed between two slash (/)
+ * characters. The order of the name parts should be the order that the person
+ * would, by custom of their culture, have used when giving it to a recorder.
+ * Early versions of Personal Ancestral File ® and other products did not use
+ * the trailing slash when the surname was the last element of the name. If
+ * part of name is illegible, that part is indicated by an ellipsis (...).
+ * Capitalize the name of a person or place in the conventional manner—
+ * capitalize the first letter of each part and lowercase the other letters,
+ * unless conventional usage is otherwise. For example: McMurray.
+ * Examples:
+ * William Lee (given name only or surname not known)
+ * /Parry/ (surname only)
+ * William Lee /Parry/
+ * William Lee /Mac Parry/ (both parts (Mac and Parry) are surname parts
+ * William /Lee/ Parry (surname imbedded in the name string)
+ * William Lee /Pa.../
+ */
+class NamePersonal extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+
+ protected const SUBTAGS = [
+ 'TYPE' => '0:1',
+ 'NPFX' => '0:1',
+ 'GIVN' => '0:1',
+ 'SPFX' => '0:1',
+ 'SURN' => '0:1',
+ 'NSFX' => '0:1',
+ 'NICK' => '0:1',
+ ];
+
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ $surname_tradition = SurnameTradition::create($tree->getPreference('SURNAME_TRADITION'));
+
+ if ($surname_tradition->hasSurnames()) {
+ return '//';
+ }
+
+ return '';
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return
+ '<div class="input-group">' .
+ view('edit/input-addon-edit-name', ['id' => $id]) .
+ '<input class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '" readonly>' .
+ view('edit/input-addon-keyboard', ['id' => $id]) .
+ view('edit/input-addon-help', ['fact' => 'NAME']) .
+ '</div>';
+ }
+
+ /**
+ * @param Tree $tree
+ *
+ * @return array<string,string>
+ */
+ public function subtags(Tree $tree): array
+ {
+ $language = I18N::languageTag();
+
+ switch ($language) {
+ case 'hu':
+ case 'jp':
+ case 'ko':
+ case 'zh-Hans':
+ case 'zh-Hant':
+ $subtags = [
+ 'TYPE' => '0:1',
+ 'NPFX' => '0:1',
+ 'SPFX' => '0:1',
+ 'SURN' => '0:1',
+ 'GIVN' => '0:1',
+ 'NSFX' => '0:1',
+ 'NICK' => '0:1',
+ ];
+ break;
+ default:
+ $subtags = [
+ 'TYPE' => '0:1',
+ 'NPFX' => '0:1',
+ 'GIVN' => '0:1',
+ 'SPFX' => '0:1',
+ 'SURN' => '0:1',
+ 'NSFX' => '0:1',
+ 'NICK' => '0:1',
+ ];
+ break;
+ }
+
+ return $subtags;
+ }
+}
diff --git a/app/Elements/NamePhoneticVariation.php b/app/Elements/NamePhoneticVariation.php
new file mode 100644
index 0000000000..42fe464dc6
--- /dev/null
+++ b/app/Elements/NamePhoneticVariation.php
@@ -0,0 +1,33 @@
+<?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\Elements;
+
+/**
+ * NAME_PHONETIC_VARIATION := {Size=1:120}
+ * The phonetic variation of the name is written in the same form as the was
+ * the name used in the superior <NAME_PERSONAL> primitive, but phonetically
+ * written using the method indicated by the subordinate <PHONETIC_TYPE> value,
+ * for example if hiragana was used to provide a reading of a name written in
+ * kanji, then the <PHONETIC_TYPE> value would indicate ‘kana’. See page 57.
+ */
+class NamePhoneticVariation extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+}
diff --git a/app/Elements/NamePieceGiven.php b/app/Elements/NamePieceGiven.php
new file mode 100644
index 0000000000..3c6f4809aa
--- /dev/null
+++ b/app/Elements/NamePieceGiven.php
@@ -0,0 +1,67 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function view;
+
+/**
+ * NAME_PERSONAL := {Size=1:120}
+ * [ <NAME_PIECE> | <NAME_PIECE_GIVEN>, <NAME_PIECE> ]
+ * Given name or earned name. Different given names are separated by a comma.
+ */
+class NamePieceGiven extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return
+ '<div class="input-group">' .
+ '<input class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">' .
+ view('edit/input-addon-keyboard', ['id' => $id]) .
+ '</div>';
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return '<span dir="auto">' . preg_replace('/(\S*)\*/', '<span class="starredname">\\1</span>', e($value)) . '</span>';
+ }
+}
diff --git a/app/Elements/NamePieceNickname.php b/app/Elements/NamePieceNickname.php
new file mode 100644
index 0000000000..6f51448cb6
--- /dev/null
+++ b/app/Elements/NamePieceNickname.php
@@ -0,0 +1,54 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function view;
+
+/**
+ * NAME_PIECE_NICKNAME := {Size=1:30}
+ * [ <NAME_PIECE> | <NAME_PIECE_NICKNAME>, <NAME_PIECE> ]
+ * A descriptive or familiar name used in connection with one's proper name.
+ */
+class NamePieceNickname extends AbstractElement
+{
+ protected const MAX_LENGTH = 30;
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return
+ '<div class="input-group">' .
+ '<input class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">' .
+ view('edit/input-addon-keyboard', ['id' => $id]) .
+ '</div>';
+ }
+}
diff --git a/app/Elements/NamePiecePrefix.php b/app/Elements/NamePiecePrefix.php
new file mode 100644
index 0000000000..321291752e
--- /dev/null
+++ b/app/Elements/NamePiecePrefix.php
@@ -0,0 +1,58 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function view;
+
+/**
+ * NAME_PIECE_PREFIX := {Size=1:30}
+ * [ <NAME_PIECE> | <NAME_PIECE_PREFIX>, <NAME_PIECE> ]
+ * Non indexing name piece that appears preceding the given name and surname parts. Different name
+ * prefix parts are separated by a comma.
+ * For example:
+ * Lt. Cmndr. Joseph /Allen/ jr.
+ * In this example Lt. Cmndr. is considered as the name prefix portion.
+ */
+class NamePiecePrefix extends AbstractElement
+{
+ protected const MAX_LENGTH = 30;
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return
+ '<div class="input-group">' .
+ '<input class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">' .
+ view('edit/input-addon-keyboard', ['id' => $id]) .
+ '</div>';
+ }
+}
diff --git a/app/Elements/NamePieceSuffix.php b/app/Elements/NamePieceSuffix.php
new file mode 100644
index 0000000000..a1f1192828
--- /dev/null
+++ b/app/Elements/NamePieceSuffix.php
@@ -0,0 +1,58 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function view;
+
+/**
+ * NAME_PIECE_SUFFIX := {Size=1:30}
+ * [ <NAME_PIECE> | <NAME_PIECE_SUFFIX>, <NAME_PIECE> ]
+ * Non-indexing name piece that appears after the given name and surname parts. Different name
+ * suffix parts are separated by a comma.
+ * For example:
+ * Lt. Cmndr. Joseph /Allen/ jr.
+ * In this example jr. is considered as the name suffix portion.
+ */
+class NamePieceSuffix extends AbstractElement
+{
+ protected const MAX_LENGTH = 30;
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return
+ '<div class="input-group">' .
+ '<input class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">' .
+ view('edit/input-addon-keyboard', ['id' => $id]) .
+ '</div>';
+ }
+}
diff --git a/app/Elements/NamePieceSurname.php b/app/Elements/NamePieceSurname.php
new file mode 100644
index 0000000000..d54227e427
--- /dev/null
+++ b/app/Elements/NamePieceSurname.php
@@ -0,0 +1,56 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\AutoCompleteSurname;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function view;
+
+/**
+ * NAME_PIECE_SUFFIX := {Size=1:30}
+ * [ <NAME_PIECE> | <NAME_PIECE_SURNAME>, <NAME_PIECE> ]
+ * Surname or family name. Different surnames are separated by a comma.
+ */
+class NamePieceSurname extends AbstractElement
+{
+ protected const MAX_LENGTH = 30;
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return
+ '<div class="input-group">' .
+ '<input data-autocomplete-url="' . e(route(AutoCompleteSurname::class, ['tree' => $tree->name()])) . '" autocomplete="off" class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">' .
+ view('edit/input-addon-keyboard', ['id' => $id]) .
+ view('edit/input-addon-help', ['fact' => 'SURN']) .
+ '</div>';
+ }
+}
diff --git a/app/Elements/NamePieceSurnamePrefix.php b/app/Elements/NamePieceSurnamePrefix.php
new file mode 100644
index 0000000000..3c7bed7186
--- /dev/null
+++ b/app/Elements/NamePieceSurnamePrefix.php
@@ -0,0 +1,55 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function view;
+
+/**
+ * NAME_PIECE_SUFFIX := {Size=1:30}
+ * [ <NAME_PIECE> | <NAME_PIECE_SURNAME_PREFIX>, <NAME_PIECE> ]
+ * Surname prefix or article used in a family name. Different surname articles are separated by a
+ * comma, for example in the name "de la Cruz", this value would be "de, la".
+ */
+class NamePieceSurnamePrefix extends AbstractElement
+{
+ protected const MAX_LENGTH = 30;
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return
+ '<div class="input-group">' .
+ '<input class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">' .
+ view('edit/input-addon-keyboard', ['id' => $id]) .
+ '</div>';
+ }
+}
diff --git a/app/Elements/NameRomanizedVariation.php b/app/Elements/NameRomanizedVariation.php
new file mode 100644
index 0000000000..00d9a316fe
--- /dev/null
+++ b/app/Elements/NameRomanizedVariation.php
@@ -0,0 +1,58 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function view;
+
+/**
+ * NAME_ROMANIZED_VARIATION := {Size=1:120}
+ * The romanized variation of the name is written in the same form prescribed
+ * for the name used in the superior <NAME_PERSONAL> context. The method used
+ * to romanize the name is indicated by the line_value of the subordinate
+ * <ROMANIZED_TYPE>, for example if romaji was used to provide a reading of a
+ * name written in kanji, then the ROMANIZED_TYPE subordinate to the ROMN tag
+ * would indicate romaji. See page 61.
+ */
+class NameRomanizedVariation extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return
+ '<div class="input-group">' .
+ '<input class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">' .
+ view('help/link', ['topic' => 'ROMN']) .
+ '</div>';
+ }
+}
diff --git a/app/Elements/NameType.php b/app/Elements/NameType.php
new file mode 100644
index 0000000000..6410dca6bd
--- /dev/null
+++ b/app/Elements/NameType.php
@@ -0,0 +1,66 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+/**
+ * NAME_TYPE := {Size=5:30}
+ * [ aka | birth | immigrant | maiden | married | <user defined>]
+ * Indicates the name type, for example the name issued or assumed as an immigrant.
+ * aka = also known as, alias, etc.
+ * birth = name given on birth certificate.
+ * immigrant = name assumed at the time of immigration.
+ * maiden = maiden name, name before first marriage.
+ * married =name was persons previous married name.
+ * user_defined = other text name that defines the name type.
+ */
+class NameType extends AbstractElement
+{
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'adopted' => /* I18N: The name given to a child by its adoptive parents */
+ I18N::translate('adopted name'),
+ 'aka' => /* I18N: The name by which an individual is also known. e.g. a professional name or a stage name */
+ I18N::translate('also known as'),
+ 'birth' => /* I18N: The name given to an individual at their birth */
+ I18N::translate('birth name'),
+ 'change' => /* I18N: A name chosen by an individual, to replace their existing name (whether legal or otherwise) */
+ I18N::translate('change of name'),
+ 'estate' => /* I18N: A name given to an individual, from the farm or estate on which they lived or worked */
+ I18N::translate('estate name'),
+ 'immigrant' => /* I18N: A name taken on immigration - e.g. migrants to the USA frequently anglicized their names */
+ I18N::translate('immigration name'),
+ 'maiden' => /* I18N: A woman’s name, before she marries (in cultures where women take their new husband’s name on marriage) */
+ I18N::translate('maiden name'),
+ 'married' => /* I18N: A name taken on marriage - usually the wife takes the husband’s surname */
+ I18N::translate('married name'),
+ 'religious' => /* I18N: A name taken when entering a religion or a religious order */
+ I18N::translate('religious name'),
+ ];
+ }
+}
diff --git a/app/Elements/NationOrTribalOrigin.php b/app/Elements/NationOrTribalOrigin.php
new file mode 100644
index 0000000000..e1fa3b5e70
--- /dev/null
+++ b/app/Elements/NationOrTribalOrigin.php
@@ -0,0 +1,41 @@
+<?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\Elements;
+
+/**
+ * NATIONAL_OR_TRIBAL_ORIGIN := {Size=1:120}
+ * The person's division of national origin or other folk, house, kindred,
+ * lineage, or tribal interest. Examples: Irish, Swede, Egyptian Coptic, Sioux
+ * Dakota Rosebud, Apache Chiricawa, Navajo Bitter Water, Eastern Cherokee
+ * Taliwa Wolf, and so forth.
+ */
+class NationOrTribalOrigin extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/NationalIdNumber.php b/app/Elements/NationalIdNumber.php
new file mode 100644
index 0000000000..23483df026
--- /dev/null
+++ b/app/Elements/NationalIdNumber.php
@@ -0,0 +1,44 @@
+<?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\Elements;
+
+/**
+ * NATIONAL_ID_NUMBER := {Size=1:30}
+ * A nationally-controlled number assigned to an individual. Commonly known
+ * national numbers should be assigned their own tag, such as SSN for U.S.
+ * Social Security Number. The use of the IDNO tag requires a subordinate TYPE
+ * tag to identify what kind of number is being stored.
+ * For example:
+ * n IDNO 43-456-1899
+ * +1 TYPE Canadian Health Registration
+ */
+class NationalIdNumber extends AbstractElement
+{
+ protected const MAX_LENGTH = 30;
+
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/Naturalization.php b/app/Elements/Naturalization.php
new file mode 100644
index 0000000000..e96c9c88ea
--- /dev/null
+++ b/app/Elements/Naturalization.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Naturalization
+ */
+class Naturalization extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/NobilityTypeTitle.php b/app/Elements/NobilityTypeTitle.php
new file mode 100644
index 0000000000..7a396cad01
--- /dev/null
+++ b/app/Elements/NobilityTypeTitle.php
@@ -0,0 +1,39 @@
+<?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\Elements;
+
+/**
+ * NOBILITY_TYPE_TITLE := {Size=1:120}
+ * The title given to or used by a person, especially of royalty or other noble
+ * class within a locality.
+ */
+class NobilityTypeTitle extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/NoteRecord.php b/app/Elements/NoteRecord.php
new file mode 100644
index 0000000000..e9aec25d27
--- /dev/null
+++ b/app/Elements/NoteRecord.php
@@ -0,0 +1,33 @@
+<?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\Elements;
+
+/**
+ * A level 0 note record
+ */
+class NoteRecord extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'CONC' => '0:1',
+ 'REFN' => '0:1',
+ 'RIN' => '0:1',
+ 'SOUR' => '0:M',
+ ];
+}
diff --git a/app/Elements/NoteStructure.php b/app/Elements/NoteStructure.php
new file mode 100644
index 0000000000..27fbf7276d
--- /dev/null
+++ b/app/Elements/NoteStructure.php
@@ -0,0 +1,39 @@
+<?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\Elements;
+
+/**
+ * NOTE can be text or an XREF.
+ */
+class NoteStructure extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ // Browsers use MS-DOS line endings in multi-line data.
+ return strtr($value, ["\r\n" => "\n", "\r" => "\n"]);
+ }
+}
diff --git a/app/Elements/Occupation.php b/app/Elements/Occupation.php
new file mode 100644
index 0000000000..31b98fd9cb
--- /dev/null
+++ b/app/Elements/Occupation.php
@@ -0,0 +1,38 @@
+<?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\Elements;
+
+/**
+ * OCCUPATION := {Size=1:90}
+ * The kind of activity that an individual does for a job, profession, or
+ * principal activity.
+ */
+class Occupation extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'AGNC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/OrdinanceProcessFlag.php b/app/Elements/OrdinanceProcessFlag.php
new file mode 100644
index 0000000000..b850caf9e9
--- /dev/null
+++ b/app/Elements/OrdinanceProcessFlag.php
@@ -0,0 +1,59 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtolower;
+
+/**
+ * ORDINANCE_PROCESS_FLAG := {Size=2:3}
+ * [ yes | no ]
+ * A flag that indicates whether submission should be processed for clearing
+ * temple ordinances.
+ */
+class OrdinanceProcessFlag extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtolower(parent::canonical($value));
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ '' => '',
+ 'no' => I18N::translate('no'),
+ 'yes' => I18N::translate('yes'),
+ ];
+ }
+}
diff --git a/app/Elements/Ordination.php b/app/Elements/Ordination.php
new file mode 100644
index 0000000000..7bfe4dac16
--- /dev/null
+++ b/app/Elements/Ordination.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * Ordination
+ */
+class Ordination extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/PafUid.php b/app/Elements/PafUid.php
new file mode 100644
index 0000000000..1c1bd15870
--- /dev/null
+++ b/app/Elements/PafUid.php
@@ -0,0 +1,66 @@
+<?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\Elements;
+
+use Exception;
+use Fisharebest\Webtrees\Tree;
+use Ramsey\Uuid\Uuid;
+
+use function dechex;
+use function hexdec;
+use function strtoupper;
+use function strtr;
+use function substr;
+
+/**
+ * _UID fields, as created by PAF and other applications
+ */
+class PafUid extends AbstractElement
+{
+ protected const MAX_LENGTH = 34;
+
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ try {
+ $uid = strtr(Uuid::uuid4()->toString(), ['-' => '']);
+ } catch (Exception $ex) {
+ // uuid4() can fail if there is insufficient entropy in the system.
+ return '';
+ }
+
+ $checksum_a = 0; // a sum of the bytes
+ $checksum_b = 0; // a sum of the incremental values of $checksum_a
+
+ // Compute checksums
+ for ($i = 0; $i < 32; $i += 2) {
+ $checksum_a += hexdec(substr($uid, $i, 2));
+ $checksum_b += $checksum_a & 0xff;
+ }
+
+ return strtoupper($uid . substr(dechex($checksum_a), -2) . substr(dechex($checksum_b), -2));
+ }
+}
diff --git a/app/Elements/PedigreeLinkageType.php b/app/Elements/PedigreeLinkageType.php
new file mode 100644
index 0000000000..a024b74d0a
--- /dev/null
+++ b/app/Elements/PedigreeLinkageType.php
@@ -0,0 +1,82 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+/**
+ * PEDIGREE_LINKAGE_TYPE := {Size=5:7}
+ * [ adopted | birth | foster | sealing ]
+ * A code used to indicate the child to family relationship for pedigree navigation purposes.
+ * Where:
+ * adopted = indicates adoptive parents.
+ * birth = indicates birth parents.
+ * foster = indicates child was included in a foster or guardian family.
+ * sealing = indicates child was sealed to parents other than birth parents.
+ */
+class PedigreeLinkageType extends AbstractElement
+{
+ protected const MAX_LENGTH = 7;
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @param string $sex - the text depends on the sex of the individual
+ *
+ * @return array<int|string,string>
+ */
+ public function values(string $sex = 'U'): array
+ {
+ $values = [
+ 'M' => [
+ '' => '',
+ 'birth' => I18N::translateContext('Male pedigree', 'Birth'),
+ 'adopted' => I18N::translateContext('Male pedigree', 'Adopted'),
+ 'foster' => I18N::translateContext('Male pedigree', 'Foster'),
+ 'sealing' => /* I18N: “sealing” is a Mormon ceremony. */
+ I18N::translateContext('Male pedigree', 'Sealing'),
+ 'rada' => /* I18N: “rada” is an Arabic word, pronounced “ra DAH”. It is child-to-parent pedigree, established by wet-nursing. */
+ I18N::translateContext('Male pedigree', 'Rada'),
+ ],
+ 'F' => [
+ '' => '',
+ 'birth' => I18N::translateContext('Female pedigree', 'Birth'),
+ 'adopted' => I18N::translateContext('Female pedigree', 'Adopted'),
+ 'foster' => I18N::translateContext('Female pedigree', 'Foster'),
+ 'sealing' => /* I18N: “sealing” is a Mormon ceremony. */
+ I18N::translateContext('Female pedigree', 'Sealing'),
+ 'rada' => /* I18N: “rada” is an Arabic word, pronounced “ra DAH”. It is child-to-parent pedigree, established by wet-nursing. */
+ I18N::translateContext('Female pedigree', 'Rada'),
+ ],
+ 'U' => [
+ '' => '',
+ 'birth' => I18N::translateContext('Pedigree', 'Birth'),
+ 'adopted' => I18N::translateContext('Pedigree', 'Adopted'),
+ 'foster' => I18N::translateContext('Pedigree', 'Foster'),
+ 'sealing' => /* I18N: “sealing” is a Mormon ceremony. */
+ I18N::translateContext('Pedigree', 'Sealing'),
+ 'rada' => /* I18N: “rada” is an Arabic word, pronounced “ra DAH”. It is child-to-parent pedigree, established by wet-nursing. */
+ I18N::translateContext('Pedigree', 'Rada'),
+ ],
+ ];
+
+ return $values[$sex] ?? $values['U'];
+ }
+}
diff --git a/app/Elements/PermanentRecordFileNumber.php b/app/Elements/PermanentRecordFileNumber.php
new file mode 100644
index 0000000000..b335ec60ef
--- /dev/null
+++ b/app/Elements/PermanentRecordFileNumber.php
@@ -0,0 +1,38 @@
+<?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\Elements;
+
+/**
+ * PERMANENT_RECORD_FILE_NUMBER := {Size=1:90}
+ * <REGISTERED_RESOURCE_IDENTIFIER>:<RECORD_IDENTIFIER>
+ * The record number that uniquely identifies this record within a registered
+ * network resource. The number will be usable as a cross-reference pointer.
+ * The use of the colon (:) is reserved to indicate the separation of the
+ * "registered resource identifier" (which precedes the colon) and the unique
+ * "record identifier" within that resource (which follows the colon). If the
+ * colon is used, implementations that check pointers should not expect to find
+ * a matching cross-reference identifier in the transmission but would find it
+ * in the indicated database within a network. Making resource files available
+ * to a public network is a future implementation.
+ */
+class PermanentRecordFileNumber extends AbstractElement
+{
+ protected const MAX_LENGTH = 90;
+}
diff --git a/app/Elements/PhoneNumber.php b/app/Elements/PhoneNumber.php
new file mode 100644
index 0000000000..71365be23c
--- /dev/null
+++ b/app/Elements/PhoneNumber.php
@@ -0,0 +1,53 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function preg_match;
+
+/**
+ * PHONE_NUMBER := {Size=1:25}
+ * A phone number.
+ */
+class PhoneNumber extends AbstractElement
+{
+ protected const MAX_LENGTH = 25;
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ if (preg_match('/^[+0-9-]+$/', $canonical)) {
+ return '<a dir="ltr" href="tel:' . e($canonical) . '">' . e($canonical) . '</a>';
+ }
+
+ return e($value);
+ }
+}
diff --git a/app/Elements/PhoneticType.php b/app/Elements/PhoneticType.php
new file mode 100644
index 0000000000..089ab80379
--- /dev/null
+++ b/app/Elements/PhoneticType.php
@@ -0,0 +1,55 @@
+<?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\Elements;
+
+use function strtolower;
+
+/**
+ * PHONETIC_TYPE := {Size=5:30}
+ * [<user defined> | hangul | kana]
+ * Indicates the method used in transforming the text to the phonetic variation.
+ * <user define> record method used to arrive at the phonetic variation of the name.
+ * hangul Phonetic method for sounding Korean glifs.
+ * kana Hiragana and/or Katakana characters were used in sounding the Kanji
+ * character used by japanese
+ */
+class PhoneticType extends AbstractElement
+{
+ protected const MAX_LENGTH = 30;
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ $value = parent::canonical($value);
+ $lower = strtolower($value);
+
+ if ($lower === 'hangul' || $lower === 'kana') {
+ return $lower;
+ }
+
+ return $value;
+ }
+}
diff --git a/app/Elements/PhysicalDescription.php b/app/Elements/PhysicalDescription.php
new file mode 100644
index 0000000000..b58aea2ddc
--- /dev/null
+++ b/app/Elements/PhysicalDescription.php
@@ -0,0 +1,40 @@
+<?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\Elements;
+
+/**
+ * PHYSICAL_DESCRIPTION := {Size=1:248}
+ * An unstructured list of the attributes that describe the physical
+ * characteristics of a person, place, or object. Commas separate each attribute.
+ * Example:
+ * 1 DSCR Hair Brown, Eyes Brown, Height 5 ft 8 in
+ * 2 DATE 23 JUL 1935
+ */
+class PhysicalDescription extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/PlaceHierarchy.php b/app/Elements/PlaceHierarchy.php
new file mode 100644
index 0000000000..035e35ecfb
--- /dev/null
+++ b/app/Elements/PlaceHierarchy.php
@@ -0,0 +1,39 @@
+<?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\Elements;
+
+/**
+ * PLACE_HIERARCHY := {Size=1:120}
+ * This shows the jurisdictional entities that are named in a sequence from the
+ * lowest to the highest jurisdiction. The jurisdictions are separated by
+ * commas, and any jurisdiction's name that is missing is still accounted for
+ * by a comma. When a PLAC.FORM structure is included in the HEADER of a GEDCOM
+ * transmission, it implies that all place names follow this jurisdictional
+ * format and each jurisdiction is accounted for by a comma, whether the name
+ * is known or not. When the PLAC.FORM is subordinate to an event, it
+ * temporarily overrides the implications made by the PLAC.FORM structure
+ * stated in the HEADER. This usage is not common and, therefore, not
+ * encouraged. It should only be used when a system has over-structured its
+ * place-names.
+ */
+class PlaceHierarchy extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+}
diff --git a/app/Elements/PlaceLatitude.php b/app/Elements/PlaceLatitude.php
new file mode 100644
index 0000000000..66e80fa0fb
--- /dev/null
+++ b/app/Elements/PlaceLatitude.php
@@ -0,0 +1,51 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * PLACE_LATITUDE := {Size=5:8}
+ * The value specifying the latitudinal coordinate of the place name. The
+ * latitude coordinate is the direction North or South from the equator in
+ * degrees and fraction of degrees carried out to give the desired accuracy.
+ * For example: 18 degrees, 9 minutes, and 3.4 seconds North would be
+ * formatted as N18.150944. Minutes and seconds are converted by dividing
+ * the minutes value by 60 and the seconds value by 3600 and adding the
+ * results together. This sum becomes the fractional part of the degree’s
+ * value.
+ */
+class PlaceLatitude extends AbstractElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" onchange="webtrees.reformatLatitude(this)">';
+ }
+}
diff --git a/app/Elements/PlaceLivingOrdinance.php b/app/Elements/PlaceLivingOrdinance.php
new file mode 100644
index 0000000000..f9eb0a80cb
--- /dev/null
+++ b/app/Elements/PlaceLivingOrdinance.php
@@ -0,0 +1,30 @@
+<?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\Elements;
+
+/**
+ * PLACE_LIVING_ORDINANCE := {Size=1:120}
+ * <PLACE_NAME>
+ * The locality of the place where a living LDS ordinance took place.
+ * Typically, a living LDS baptism place would be recorded in this field.
+ */
+class PlaceLivingOrdinance extends AbstractElement
+{
+}
diff --git a/app/Elements/PlaceLongtitude.php b/app/Elements/PlaceLongtitude.php
new file mode 100644
index 0000000000..916fe385af
--- /dev/null
+++ b/app/Elements/PlaceLongtitude.php
@@ -0,0 +1,49 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+
+/**
+ * PLACE_LONGITUDE := {Size=5:8}
+ * The value specifying the longitudinal coordinate of the place name. The
+ * longitude coordinate is Degrees and fraction of degrees east or west of the
+ * zero or base meridian coordinate. For example: 168 degrees, 9 minutes, and
+ * 3.4 seconds East would be formatted as E168.150944.
+ */
+class PlaceLongtitude extends AbstractElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return '<input class="form-control" type="text" id="' . $id . '" name="' . $name . '" value="' . e($value) . '" onchange="webtrees.reformatLongitude(this)">';
+ }
+}
diff --git a/app/Elements/PlaceName.php b/app/Elements/PlaceName.php
new file mode 100644
index 0000000000..5250e37a20
--- /dev/null
+++ b/app/Elements/PlaceName.php
@@ -0,0 +1,76 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\AutoCompletePlace;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function route;
+
+/**
+ * PLACE_NAME := {1,120}
+ * [ <PLACE_TEXT> | <PLACE_TEXT>, <PLACE_NAME> ]
+ * The jurisdictional name of the place where the event took place. Jurisdictions are separated by
+ * commas, for example, "Cove, Cache, Utah, USA." If the actual jurisdictional names of these
+ * places have been identified, they can be shown using a PLAC.FORM structure either in the HEADER
+ * or in the event structure. (See <PLACE_HIERARCHY>, page 58.)
+ */
+class PlaceName extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ $value = parent::canonical($value);
+
+ // Arabic, Chinese and Japanese commas.
+ $value = strtr($value, ['،' => ',', ',' => ',', '、' => ',']);
+
+ // Spaces before commas.
+ $value = strtr($value, [' ,' => ',']);
+
+ // Spaces after commas.
+ $value = strtr($value, [',' => ', ']);
+ $value = strtr($value, [', ' => ', ']);
+
+ return $value;
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return '<input data-autocomplete-url="' . e(route(AutoCompletePlace::class, ['tree' => $tree->name()])) . '" autocomplete="off" class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">';
+ }
+}
diff --git a/app/Elements/PlacePhoneticVariation.php b/app/Elements/PlacePhoneticVariation.php
new file mode 100644
index 0000000000..42b3a2c020
--- /dev/null
+++ b/app/Elements/PlacePhoneticVariation.php
@@ -0,0 +1,33 @@
+<?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\Elements;
+
+/**
+ * PLACE_PHONETIC_VARIATION := {Size=1:120}
+ * The phonetic variation of the place name is written in the same form as was
+ * the place name used in the superior <PLACE_NAME> primitive, but phonetically
+ * written using the method indicated by the subordinate <PHONETIC_TYPE> value,
+ * for example if hiragana was used to provide a reading of a a name written in
+ * kanji, then the <PHONETIC_TYPE> value would indicate kana.
+ * (See <PHONETIC_TYPE> page 57.)
+ */
+class PlacePhoneticVariation extends AbstractElement
+{
+}
diff --git a/app/Elements/PlaceRomanizedVariation.php b/app/Elements/PlaceRomanizedVariation.php
new file mode 100644
index 0000000000..c45c49a255
--- /dev/null
+++ b/app/Elements/PlaceRomanizedVariation.php
@@ -0,0 +1,34 @@
+<?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\Elements;
+
+/**
+ * PLACE_ROMANIZED_VARIATION := {Size=1:120}
+ * The romanized variation of the place name is written in the same form
+ * prescribed for the place name used in the superior <PLACE_NAME> context. The
+ * method used to romanize the name is indicated by the line_value of the
+ * subordinate <ROMANIZED_TYPE>, for example if romaji was used to provide a
+ * reading of a place name written in kanji, then the <ROMANIZED_TYPE>
+ * subordinate to the ROMN tag would indicate ‘romaji’. (See <ROMANIZED_TYPE>
+ * page 61.)
+ */
+class PlaceRomanizedVariation extends AbstractElement
+{
+}
diff --git a/app/Elements/Possessions.php b/app/Elements/Possessions.php
new file mode 100644
index 0000000000..077ddc94e7
--- /dev/null
+++ b/app/Elements/Possessions.php
@@ -0,0 +1,36 @@
+<?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\Elements;
+
+/**
+ * POSSESSIONS := {Size=1:248}
+ * A list of possessions (real estate or other property) belonging to this individual.
+ */
+class Possessions extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/Probate.php b/app/Elements/Probate.php
new file mode 100644
index 0000000000..47c44ebe26
--- /dev/null
+++ b/app/Elements/Probate.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * Probate
+ */
+class Probate extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/PublicationDate.php b/app/Elements/PublicationDate.php
new file mode 100644
index 0000000000..5b631b2462
--- /dev/null
+++ b/app/Elements/PublicationDate.php
@@ -0,0 +1,29 @@
+<?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\Elements;
+
+/**
+ * PUBLICATION_DATE := {Size=10:11}
+ * <DATE_EXACT>
+ * The date this source was published or created.
+ */
+class PublicationDate extends AbstractElement
+{
+}
diff --git a/app/Elements/ReceivingSystemName.php b/app/Elements/ReceivingSystemName.php
new file mode 100644
index 0000000000..79faff8e62
--- /dev/null
+++ b/app/Elements/ReceivingSystemName.php
@@ -0,0 +1,48 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * RECEIVING_SYSTEM_NAME := {Size=1:20}
+ * The name of the system expected to process the GEDCOM-compatible
+ * transmission. The registered RECEIVING_SYSTEM_NAME for all GEDCOM
+ * submissions to the Family History Department must be one of the following
+ * names:
+ * ! "ANSTFILE" when submitting to Ancestral File.
+ * ! "TempleReady" when submitting for temple ordinance clearance.
+ */
+class ReceivingSystemName extends AbstractElement
+{
+ protected const MAX_LENGTH = 20;
+
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ return 'DISKETTE';
+ }
+}
diff --git a/app/Elements/RelationIsDescriptor.php b/app/Elements/RelationIsDescriptor.php
new file mode 100644
index 0000000000..bd3289d309
--- /dev/null
+++ b/app/Elements/RelationIsDescriptor.php
@@ -0,0 +1,158 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+/**
+ * RELATION_IS_DESCRIPTOR := {Size=1:25}
+ * A word or phrase that states object 1's relation is object 2. For example
+ * you would read the following as "Joe Jacob's great grandson is the submitter
+ * pointed to by the @XREF:SUBM@":
+ * 0 INDI
+ * 1 NAME Joe /Jacob/
+ * 1 ASSO @<XREF:SUBM>@
+ * 2 RELA great grandson
+ */
+class RelationIsDescriptor extends AbstractElement
+{
+ protected const MAX_LENGTH = 25;
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @param string $sex - the text depends on the sex of the *linked* individual
+ *
+ * @return array<int|string,string>
+ */
+ public function values(string $sex = 'U'): array
+ {
+ $values = [
+ 'M' => [
+ '' => '',
+ 'attendant' => I18N::translateContext('MALE', 'Attendant'),
+ 'attending' => I18N::translateContext('MALE', 'Attending'),
+ 'best_man' => I18N::translate('Best man'),
+ 'bridesmaid' => I18N::translate('Bridesmaid'),
+ 'buyer' => I18N::translateContext('MALE', 'Buyer'),
+ 'circumciser' => I18N::translate('Circumciser'),
+ 'civil_registrar' => I18N::translateContext('MALE', 'Civil registrar'),
+ 'employee' => I18N::translateContext('MALE', 'Employee'),
+ 'employer' => I18N::translateContext('MALE', 'Employer'),
+ 'foster_child' => I18N::translate('Foster child'),
+ 'foster_father' => I18N::translate('Foster father'),
+ 'foster_mother' => I18N::translate('Foster mother'),
+ 'friend' => I18N::translateContext('MALE', 'Friend'),
+ 'godfather' => I18N::translate('Godfather'),
+ 'godmother' => I18N::translate('Godmother'),
+ 'godparent' => I18N::translate('Godparent'),
+ 'godson' => I18N::translate('Godson'),
+ 'goddaughter' => I18N::translate('Goddaughter'),
+ 'godchild' => I18N::translate('Godchild'),
+ 'guardian' => I18N::translateContext('MALE', 'Guardian'),
+ 'informant' => I18N::translateContext('MALE', 'Informant'),
+ 'lodger' => I18N::translateContext('MALE', 'Lodger'),
+ 'nanny' => I18N::translate('Nanny'),
+ 'nurse' => I18N::translateContext('MALE', 'Nurse'),
+ 'owner' => I18N::translateContext('MALE', 'Owner'),
+ 'priest' => I18N::translate('Priest'),
+ 'rabbi' => I18N::translate('Rabbi'),
+ 'registry_officer' => I18N::translateContext('MALE', 'Registry officer'),
+ 'seller' => I18N::translateContext('MALE', 'Seller'),
+ 'servant' => I18N::translateContext('MALE', 'Servant'),
+ 'slave' => I18N::translateContext('MALE', 'Slave'),
+ 'ward' => I18N::translateContext('MALE', 'Ward'),
+ 'witness' => I18N::translate('Witness'),
+ ],
+ 'F' => [
+ 'attendant' => I18N::translateContext('FEMALE', 'Attendant'),
+ 'attending' => I18N::translateContext('FEMALE', 'Attending'),
+ 'best_man' => I18N::translate('Best man'),
+ 'bridesmaid' => I18N::translate('Bridesmaid'),
+ 'buyer' => I18N::translateContext('FEMALE', 'Buyer'),
+ 'circumciser' => I18N::translate('Circumciser'),
+ 'civil_registrar' => I18N::translateContext('FEMALE', 'Civil registrar'),
+ 'employee' => I18N::translateContext('FEMALE', 'Employee'),
+ 'employer' => I18N::translateContext('FEMALE', 'Employer'),
+ 'foster_child' => I18N::translate('Foster child'),
+ 'foster_father' => I18N::translate('Foster father'),
+ 'foster_mother' => I18N::translate('Foster mother'),
+ 'friend' => I18N::translateContext('FEMALE', 'Friend'),
+ 'godfather' => I18N::translate('Godfather'),
+ 'godmother' => I18N::translate('Godmother'),
+ 'godparent' => I18N::translate('Godparent'),
+ 'godson' => I18N::translate('Godson'),
+ 'goddaughter' => I18N::translate('Goddaughter'),
+ 'godchild' => I18N::translate('Godchild'),
+ 'guardian' => I18N::translateContext('FEMALE', 'Guardian'),
+ 'informant' => I18N::translateContext('FEMALE', 'Informant'),
+ 'lodger' => I18N::translateContext('FEMALE', 'Lodger'),
+ 'nanny' => I18N::translate('Nanny'),
+ 'nurse' => I18N::translateContext('FEMALE', 'Nurse'),
+ 'owner' => I18N::translateContext('FEMALE', 'Owner'),
+ 'priest' => I18N::translate('Priest'),
+ 'rabbi' => I18N::translate('Rabbi'),
+ 'registry_officer' => I18N::translateContext('FEMALE', 'Registry officer'),
+ 'seller' => I18N::translateContext('FEMALE', 'Seller'),
+ 'servant' => I18N::translateContext('FEMALE', 'Servant'),
+ 'slave' => I18N::translateContext('FEMALE', 'Slave'),
+ 'ward' => I18N::translateContext('FEMALE', 'Ward'),
+ 'witness' => I18N::translate('Witness'),
+ ],
+ 'U' => [
+ 'attendant' => I18N::translate('Attendant'),
+ 'attending' => I18N::translate('Attending'),
+ 'best_man' => I18N::translate('Best man'),
+ 'bridesmaid' => I18N::translate('Bridesmaid'),
+ 'buyer' => I18N::translate('Buyer'),
+ 'circumciser' => I18N::translate('Circumciser'),
+ 'civil_registrar' => I18N::translate('Civil registrar'),
+ 'employee' => I18N::translate('Employee'),
+ 'employer' => I18N::translate('Employer'),
+ 'foster_child' => I18N::translate('Foster child'),
+ 'foster_father' => I18N::translate('Foster father'),
+ 'foster_mother' => I18N::translate('Foster mother'),
+ 'friend' => I18N::translate('Friend'),
+ 'godfather' => I18N::translate('Godfather'),
+ 'godmother' => I18N::translate('Godmother'),
+ 'godparent' => I18N::translate('Godparent'),
+ 'godson' => I18N::translate('Godson'),
+ 'goddaughter' => I18N::translate('Goddaughter'),
+ 'godchild' => I18N::translate('Godchild'),
+ 'guardian' => I18N::translate('Guardian'),
+ 'informant' => I18N::translate('Informant'),
+ 'lodger' => I18N::translate('Lodger'),
+ 'nanny' => I18N::translate('Nanny'),
+ 'nurse' => I18N::translate('Nurse'),
+ 'owner' => I18N::translate('Owner'),
+ 'priest' => I18N::translate('Priest'),
+ 'rabbi' => I18N::translate('Rabbi'),
+ 'registry_officer' => I18N::translate('Registry officer'),
+ 'seller' => I18N::translate('Seller'),
+ 'servant' => I18N::translate('Servant'),
+ 'slave' => I18N::translate('Slave'),
+ 'ward' => I18N::translate('Ward'),
+ 'witness' => I18N::translate('Witness'),
+ ],
+ ];
+
+ return $values[$sex] ?? $values['U'];
+ }
+}
diff --git a/app/Elements/ReligiousAffiliation.php b/app/Elements/ReligiousAffiliation.php
new file mode 100644
index 0000000000..7f667120e7
--- /dev/null
+++ b/app/Elements/ReligiousAffiliation.php
@@ -0,0 +1,38 @@
+<?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\Elements;
+
+/**
+ * RELIGIOUS_AFFILIATION := {Size=1:120}
+ * A name of the religion with which this person, event, or record was affiliated.
+ */
+class ReligiousAffiliation extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/RepositoryRecord.php b/app/Elements/RepositoryRecord.php
new file mode 100644
index 0000000000..4f073ee648
--- /dev/null
+++ b/app/Elements/RepositoryRecord.php
@@ -0,0 +1,37 @@
+<?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\Elements;
+
+/**
+ * A level 0 repository record
+ */
+class RepositoryRecord extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'NAME' => '0:1',
+ 'ADDR' => '0:1',
+ 'PHON' => '0:1',
+ 'EMAIL' => '0:1',
+ 'WWW' => '0:1',
+ 'NOTE' => '0:M',
+ 'REFN' => '0:1',
+ 'RIN' => '0:1',
+ ];
+}
diff --git a/app/Elements/Residence.php b/app/Elements/Residence.php
new file mode 100644
index 0000000000..b194f94d2f
--- /dev/null
+++ b/app/Elements/Residence.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * Residence
+ */
+class Residence extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/ResponsibleAgency.php b/app/Elements/ResponsibleAgency.php
new file mode 100644
index 0000000000..d5c14414fa
--- /dev/null
+++ b/app/Elements/ResponsibleAgency.php
@@ -0,0 +1,32 @@
+<?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\Elements;
+
+/**
+ * RESPONSIBLE_AGENCY := {Size=1:120}
+ * The organization, institution, corporation, person, or other entity that has
+ * responsibility for the associated context. For example, an employer of a
+ * person of an associated occupation, or a church that administered rites or
+ * events, or an organization responsible for creating and/or archiving records.
+ */
+class ResponsibleAgency extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+}
diff --git a/app/Elements/RestrictionNotice.php b/app/Elements/RestrictionNotice.php
new file mode 100644
index 0000000000..f4b0df6fd3
--- /dev/null
+++ b/app/Elements/RestrictionNotice.php
@@ -0,0 +1,81 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtolower;
+
+/**
+ * RESTRICTION_NOTICE := {Size=6:7}
+ * [confidential | locked | privacy ]
+ * The restriction notice is defined for Ancestral File usage. Ancestral File
+ * download GEDCOM files may contain this data.
+ * Where:
+ * confidential = This data was marked as confidential by the user. In some systems data marked as
+ * confidential will be treated differently, for example, there might be an option
+ * that would stop confidential data from appearing on printed reports or would
+ * prevent that information from being exported.
+ * locked = Some records in Ancestral File have been satisfactorily proven by evidence, but
+ * because of source conflicts or incorrect traditions, there are repeated attempts
+ * to change this record. By arrangement, the Ancestral File Custodian can lock a
+ * record so that it cannot be changed without an agreement from the person assigned
+ * as the steward of such a record. The assigned steward is either the submitter
+ * listed for the record or Family History Support when no submitter is listed.
+ * privacy = Indicate that information concerning this record is not present due to rights of
+ * or an approved request for privacy. For example, data from requested downloads of
+ * the Ancestral File may have individuals marked with ‘privacy’ if they are assumed
+ * living, that is they were born within the last 110 years and there isn’t a death
+ * date. In certain cases family records may also be marked with the RESN tag of
+ * privacy if either individual acting in the role of HUSB or WIFE is assumed living.
+ */
+class RestrictionNotice extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtolower(parent::canonical($value));
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ // Note: "1 RESN none" is not valid gedcom.
+ // However, webtrees privacy rules will interpret it as "show an otherwise private record to public".
+
+ return [
+ '' => '',
+ 'none' => '<i class="icon-resn-none"></i> ' . I18N::translate('Show to visitors'),
+ 'privacy' => '<i class="icon-resn-privacy"></i> ' . I18N::translate('Show to members'),
+ 'confidential' => '<i class="icon-resn-confidential"></i> ' . I18N::translate('Show to managers'),
+ 'locked' => '<i class="icon-resn-locked"></i> ' . I18N::translate('Only managers can edit'),
+ ];
+ }
+}
diff --git a/app/Elements/Retirement.php b/app/Elements/Retirement.php
new file mode 100644
index 0000000000..15aa242a4a
--- /dev/null
+++ b/app/Elements/Retirement.php
@@ -0,0 +1,37 @@
+<?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\Elements;
+
+/**
+ * Retirement
+ */
+class Retirement extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'AGE' => '0:1',
+ 'PLAC' => '0:1',
+ 'AGNC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/RoleInEvent.php b/app/Elements/RoleInEvent.php
new file mode 100644
index 0000000000..5fe1a1fbf2
--- /dev/null
+++ b/app/Elements/RoleInEvent.php
@@ -0,0 +1,34 @@
+<?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\Elements;
+
+/**
+ * ROLE_IN_EVENT := {Size=1:15}
+ * [ CHIL | HUSB | WIFE | MOTH | FATH | SPOU | (<ROLE_DESCRIPTOR>) ]
+ * Indicates what role this person played in the event that is being cited in this context. For
+ * example, if you cite a child's birth record as the source of the mother's name, the value for
+ * this field is "MOTH." If you describe the groom of a marriage, the role is "HUSB." If the role
+ * is something different than one of the six relationship role tags listed above then enclose the
+ * role name within matching parentheses.
+ */
+class RoleInEvent extends AbstractElement
+{
+ protected const MAX_LENGTH = 15;
+}
diff --git a/app/Elements/RomanizedType.php b/app/Elements/RomanizedType.php
new file mode 100644
index 0000000000..2df79b16f8
--- /dev/null
+++ b/app/Elements/RomanizedType.php
@@ -0,0 +1,51 @@
+<?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\Elements;
+
+use function strtolower;
+
+/**
+ * ROMANIZED_TYPE := {Size=5:30}
+ * [<user defined> | pinyin | romaji | wadegiles]
+ * Indicates the method used in transforming the text to a romanized variation.
+ */
+class RomanizedType extends AbstractElement
+{
+ protected const MAX_LENGTH = 30;
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ $value = parent::canonical($value);
+ $lower = strtolower($value);
+
+ if ($lower === 'pinyin' || $lower === 'romaji' || $lower === 'wadegiles') {
+ return $lower;
+ }
+
+ return $value;
+ }
+}
diff --git a/app/Elements/ScholasticAchievement.php b/app/Elements/ScholasticAchievement.php
new file mode 100644
index 0000000000..c6be60a909
--- /dev/null
+++ b/app/Elements/ScholasticAchievement.php
@@ -0,0 +1,37 @@
+<?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\Elements;
+
+/**
+ * SCHOLASTIC_ACHIEVEMENT := {Size=1:248}
+ * A description of a scholastic or educational achievement or pursuit.
+ */
+class ScholasticAchievement extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'AGNC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/SexValue.php b/app/Elements/SexValue.php
new file mode 100644
index 0000000000..34975ceafc
--- /dev/null
+++ b/app/Elements/SexValue.php
@@ -0,0 +1,78 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Tree;
+
+use function strtoupper;
+use function view;
+
+/**
+ * SEX_VALUE := {Size=1:7}
+ * A code that indicates the sex of the individual
+ */
+class SexValue extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(parent::canonical($value));
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return view('components/radios-inline', [
+ 'name' => $name,
+ 'options' => $this->values(),
+ 'selected' => $value,
+ ]);
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ return [
+ 'M' => I18N::translate('Male'),
+ 'F' => I18N::translate('Female'),
+ 'U' => I18N::translateContext('unknown gender', 'Unknown'),
+ ];
+ }
+}
diff --git a/app/Elements/SocialSecurityNumber.php b/app/Elements/SocialSecurityNumber.php
new file mode 100644
index 0000000000..0cefa6fc40
--- /dev/null
+++ b/app/Elements/SocialSecurityNumber.php
@@ -0,0 +1,38 @@
+<?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\Elements;
+
+/**
+ * SOCIAL_SECURITY_NUMBER := {Size=10:11}
+ * A number assigned to a person in the United States for identification purposes.
+ */
+class SocialSecurityNumber extends AbstractElement
+{
+ protected const MAX_LENGTH = 11;
+
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/SourceCallNumber.php b/app/Elements/SourceCallNumber.php
new file mode 100644
index 0000000000..0028496d4c
--- /dev/null
+++ b/app/Elements/SourceCallNumber.php
@@ -0,0 +1,46 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * SOURCE_CALL_NUMBER := {Size=1:120}
+ * An identification or reference description used to file and retrieve items from the holdings of
+ * a repository.
+ */
+class SourceCallNumber extends AbstractElement
+{
+ protected const MAX_LENGTH = 120;
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ return $this->valueAutoLink($canonical);
+ }
+}
diff --git a/app/Elements/SourceData.php b/app/Elements/SourceData.php
new file mode 100644
index 0000000000..80019f1137
--- /dev/null
+++ b/app/Elements/SourceData.php
@@ -0,0 +1,51 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * SOUR:DATA is an empty element with children; EVEN, AGNC and NOTE.
+ */
+class SourceData extends EmptyElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'TEXT' => '0:M',
+ ];
+
+ protected const ABRIDGED_SUBTAGS = [
+ 'TEXT' => '0:M',
+ ];
+
+ /**
+ * @param Tree $tree
+ *
+ * @return array<string,string>
+ */
+ public function subtags(Tree $tree): array
+ {
+ if ($tree->getPreference('FULL_SOURCES') === '1') {
+ return static::SUBTAGS;
+ }
+
+ return static::ABRIDGED_SUBTAGS;
+ }
+}
diff --git a/app/Elements/SourceDescriptiveTitle.php b/app/Elements/SourceDescriptiveTitle.php
new file mode 100644
index 0000000000..4725a4a138
--- /dev/null
+++ b/app/Elements/SourceDescriptiveTitle.php
@@ -0,0 +1,38 @@
+<?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\Elements;
+
+/**
+ * SOURCE_DESCRIPTIVE_TITLE := {Size=1:248}
+ * The title of the work, record, or item and, when appropriate, the title of the larger work or
+ * series of which it is a part.
+ * For a published work, a book for example, might have a title plus the title of the series of
+ * which the book is a part. A magazine article would have a title plus the title of the magazine
+ * that published the article.
+ * For An unpublished work, such as:
+ * ! A letter might include the date, the sender, and the receiver.
+ * ! A transaction between a buyer and seller might have their names and the transaction date.
+ * ! A family Bible containing genealogical information might have past and present owners and a
+ * physical description of the book.
+ * ! A personal interview would cite the informant and interviewer.
+ */
+class SourceDescriptiveTitle extends AbstractElement
+{
+}
diff --git a/app/Elements/SourceFiledByEntry.php b/app/Elements/SourceFiledByEntry.php
new file mode 100644
index 0000000000..43dd2da544
--- /dev/null
+++ b/app/Elements/SourceFiledByEntry.php
@@ -0,0 +1,29 @@
+<?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\Elements;
+
+/**
+ * SOURCE_FILED_BY_ENTRY := {Size=1:60}
+ * This entry is to provide a short title used for sorting, filing, and retrieving source records.
+ */
+class SourceFiledByEntry extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+}
diff --git a/app/Elements/SourceJurisdictionPlace.php b/app/Elements/SourceJurisdictionPlace.php
new file mode 100644
index 0000000000..bdcbaf13d6
--- /dev/null
+++ b/app/Elements/SourceJurisdictionPlace.php
@@ -0,0 +1,31 @@
+<?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\Elements;
+
+/**
+ * PLACE_NAME := {Size=1:120}
+ * The name of the lowest jurisdiction that encompasses all lower-level places named in this
+ * source. For example, "Oneida, Idaho" would be used as a source jurisdiction place for events
+ * occurring in the various towns within Oneida County. "Idaho" would be the source jurisdiction
+ * place if the events recorded took place in other counties as well as Oneida County.
+ */
+class SourceJurisdictionPlace extends PlaceName
+{
+}
diff --git a/app/Elements/SourceMediaType.php b/app/Elements/SourceMediaType.php
new file mode 100644
index 0000000000..3b72426517
--- /dev/null
+++ b/app/Elements/SourceMediaType.php
@@ -0,0 +1,84 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtolower;
+use function uasort;
+
+/**
+ * SOURCE_MEDIA_TYPE := {Size=1:15}
+ * [ audio | book | card | electronic | fiche | film | magazine |
+ * manuscript | map | newspaper | photo | tombstone | video ]
+ * A code, selected from one of the media classifications choices above, that indicates the type of
+ * material in which the referenced source is stored.
+ */
+class SourceMediaType extends AbstractElement
+{
+ protected const MAX_LENGTH = 15;
+
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtolower(parent::canonical($value));
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ // *** indicates custom values
+ $values = [
+ '' => '',
+ 'audio' => /* I18N: Type of media object */ I18N::translate('Audio'),
+ 'book' => /* I18N: Type of media object */ I18N::translate('Book'),
+ 'card' => /* I18N: Type of media object */ I18N::translate('Card'),
+ 'certificate' => /* I18N: Type of media object */ I18N::translate('Certificate'), // ***
+ 'coat' => /* I18N: Type of media object */ I18N::translate('Coat of arms'), // ***
+ 'document' => /* I18N: Type of media object */ I18N::translate('Document'), // ***
+ 'electronic' => /* I18N: Type of media object */ I18N::translate('Electronic'),
+ 'fiche' => /* I18N: Type of media object */ I18N::translate('Microfiche'),
+ 'film' => /* I18N: Type of media object */ I18N::translate('Microfilm'),
+ 'magazine' => /* I18N: Type of media object */ I18N::translate('Magazine'),
+ 'manuscript' => /* I18N: Type of media object */ I18N::translate('Manuscript'),
+ 'map' => /* I18N: Type of media object */ I18N::translate('Map'),
+ 'newspaper' => /* I18N: Type of media object */ I18N::translate('Newspaper'),
+ 'other' => /* I18N: Type of media object */ I18N::translate('Other'), // ***
+ 'photo' => /* I18N: Type of media object */ I18N::translate('Photo'),
+ 'painting' => /* I18N: Type of media object */ I18N::translate('Painting'), // ***
+ 'tombstone' => /* I18N: Type of media object */ I18N::translate('Tombstone'),
+ 'video' => /* I18N: Type of media object */ I18N::translate('Video'),
+ ];
+
+ uasort($values, '\Fisharebest\Webtrees\I18N::strcasecmp');
+
+ return $values;
+ }
+}
diff --git a/app/Elements/SourceOriginator.php b/app/Elements/SourceOriginator.php
new file mode 100644
index 0000000000..8deea58662
--- /dev/null
+++ b/app/Elements/SourceOriginator.php
@@ -0,0 +1,30 @@
+<?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\Elements;
+
+/**
+ * SOURCE_ORIGINATOR := {Size=1:248}
+ * The person, agency, or entity who created the record. For a published work, this could be the
+ * author, compiler, transcriber, abstractor, or editor. For an unpublished source, this may be an
+ * individual, a government agency, church organization, or private organization, etc.
+ */
+class SourceOriginator extends AbstractElement
+{
+}
diff --git a/app/Elements/SourcePublicationFacts.php b/app/Elements/SourcePublicationFacts.php
new file mode 100644
index 0000000000..e90c38d319
--- /dev/null
+++ b/app/Elements/SourcePublicationFacts.php
@@ -0,0 +1,48 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * SOURCE_PUBLICATION_FACTS := {Size=1:248}
+ * When and where the record was created. For published works, this includes information such as
+ * the city of publication, name of the publisher, and year of publication.
+ * For an unpublished work, it includes the date the record was created and the place where it was
+ * created. For example, the county and state of residence of a person making a declaration for a
+ * pension or the city and state of residence of the writer of a letter.
+ */
+class SourcePublicationFacts extends AbstractElement
+{
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ return $this->valueAutoLink($canonical);
+ }
+}
diff --git a/app/Elements/SourceRecord.php b/app/Elements/SourceRecord.php
new file mode 100644
index 0000000000..b71c0ecd77
--- /dev/null
+++ b/app/Elements/SourceRecord.php
@@ -0,0 +1,40 @@
+<?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\Elements;
+
+/**
+ * A level 0 source record
+ */
+class SourceRecord extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'TITL' => '0:1',
+ 'ABBR' => '0:1',
+ 'AUTH' => '0:1',
+ 'PUBL' => '0:1',
+ 'REPO' => '0:M',
+ 'TEXT' => '0:1',
+ 'OBJE' => '0:M',
+ 'NOTE' => '0:M',
+ 'DATA' => '0:1',
+ 'REFN' => '0:1',
+ 'RIN' => '0:1',
+ ];
+}
diff --git a/app/Elements/SubmissionRecord.php b/app/Elements/SubmissionRecord.php
new file mode 100644
index 0000000000..2265c34e71
--- /dev/null
+++ b/app/Elements/SubmissionRecord.php
@@ -0,0 +1,37 @@
+<?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\Elements;
+
+/**
+ * A level 0 submission record
+ */
+class SubmissionRecord extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'SUBM' => '0:1',
+ 'FAMF' => '0:1',
+ 'TEMP' => '0:1',
+ 'ANCE' => '0:1',
+ 'DESC' => '0:1',
+ 'ORDI' => '0:1',
+ 'RIN' => '0:1',
+ 'NOTE' => '0:1',
+ ];
+}
diff --git a/app/Elements/SubmitterName.php b/app/Elements/SubmitterName.php
new file mode 100644
index 0000000000..fd09564553
--- /dev/null
+++ b/app/Elements/SubmitterName.php
@@ -0,0 +1,29 @@
+<?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\Elements;
+
+/**
+ * SUBMITTER_NAME := {Size=1:60}
+ * The name of the submitter formatted for display and address generation.
+ */
+class SubmitterName extends AbstractElement
+{
+ protected const MAX_LENGTH = 60;
+}
diff --git a/app/Elements/SubmitterRecord.php b/app/Elements/SubmitterRecord.php
new file mode 100644
index 0000000000..c78018b03d
--- /dev/null
+++ b/app/Elements/SubmitterRecord.php
@@ -0,0 +1,38 @@
+<?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\Elements;
+
+/**
+ * A level 0 submitter record
+ */
+class SubmitterRecord extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'NAME' => '0:1',
+ 'ADDR' => '0:1',
+ 'PHON' => '0:1',
+ 'EMAIL' => '0:1',
+ 'WWW' => '0:1',
+ 'LANG' => '0:3',
+ 'RFN' => '0:1',
+ 'RIN' => '0:1',
+ 'NOTE' => '0:1',
+ ];
+}
diff --git a/app/Elements/SubmitterRegisteredRfn.php b/app/Elements/SubmitterRegisteredRfn.php
new file mode 100644
index 0000000000..6c0c90f8be
--- /dev/null
+++ b/app/Elements/SubmitterRegisteredRfn.php
@@ -0,0 +1,30 @@
+<?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\Elements;
+
+/**
+ * SUBMITTER_REGISTERED_RFN := {Size=1:30}
+ * A registered number of a submitter of Ancestral File data. This number is used in subsequent
+ * submissions or inquiries by the submitter for identification purposes.
+ */
+class SubmitterRegisteredRfn extends AbstractElement
+{
+ protected const MAX_LENGTH = 30;
+}
diff --git a/app/Elements/SubmitterText.php b/app/Elements/SubmitterText.php
new file mode 100644
index 0000000000..583d9c937c
--- /dev/null
+++ b/app/Elements/SubmitterText.php
@@ -0,0 +1,57 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * SUBMITTER_TEXT:= {Size=1:248}
+ * Comments or opinions from the submitter.
+ */
+class SubmitterText extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ // Browsers use MS-DOS line endings in multi-line data.
+ return strtr($value, ["\r\n" => "\n", "\r" => "\n"]);
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return $this->editTextArea($id, $name, $value);
+ }
+}
diff --git a/app/Elements/TempleCode.php b/app/Elements/TempleCode.php
new file mode 100644
index 0000000000..8ac67d4f76
--- /dev/null
+++ b/app/Elements/TempleCode.php
@@ -0,0 +1,215 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+use function strtoupper;
+
+/**
+ * TEMPLE_CODE := {Size=4:5}
+ * An abbreviation of the temple in which the LDS ordinances were performed.
+ * (See Appendix B, page 96.)
+ */
+class TempleCode extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ return strtoupper(parent::canonical($value));
+ }
+
+ /**
+ * A list of controlled values for this element
+ *
+ * @return array<int|string,string>
+ */
+ public function values(): array
+ {
+ $values = [
+ 'ABA' => /* I18N: Location of an LDS church temple */ I18N::translate('Aba, Nigeria'),
+ 'ACCRA' => /* I18N: Location of an LDS church temple */ I18N::translate('Accra, Ghana'),
+ 'ADELA' => /* I18N: Location of an LDS church temple */ I18N::translate('Adelaide, Australia'),
+ 'ALBER' => /* I18N: Location of an LDS church temple */ I18N::translate('Cardston, Alberta, Canada'),
+ 'ALBUQ' => /* I18N: Location of an LDS church temple */ I18N::translate('Albuquerque, New Mexico, United States'),
+ 'ANCHO' => /* I18N: Location of an LDS church temple */ I18N::translate('Anchorage, Alaska, United States'),
+ 'APIA' => /* I18N: Location of an LDS church temple */ I18N::translate('Apia, Samoa'),
+ 'ARIZO' => /* I18N: Location of an LDS church temple */ I18N::translate('Mesa, Arizona, United States'),
+ 'ASUNC' => /* I18N: Location of an LDS church temple */ I18N::translate('Asuncion, Paraguay'),
+ 'ATLAN' => /* I18N: Location of an LDS church temple */ I18N::translate('Atlanta, Georgia, United States'),
+ 'BAIRE' => /* I18N: Location of an LDS church temple */ I18N::translate('Buenos Aires, Argentina'),
+ 'BILLI' => /* I18N: Location of an LDS church temple */ I18N::translate('Billings, Montana, United States'),
+ 'BIRMI' => /* I18N: Location of an LDS church temple */ I18N::translate('Birmingham, Alabama, United States'),
+ 'BISMA' => /* I18N: Location of an LDS church temple */ I18N::translate('Bismarck, North Dakota, United States'),
+ 'BOGOT' => /* I18N: Location of an LDS church temple */ I18N::translate('Bogota, Colombia'),
+ 'BOISE' => /* I18N: Location of an LDS church temple */ I18N::translate('Boise, Idaho, United States'),
+ 'BOSTO' => /* I18N: Location of an LDS church temple */ I18N::translate('Boston, Massachusetts, United States'),
+ 'BOUNT' => /* I18N: Location of an LDS church temple */ I18N::translate('Bountiful, Utah, United States'),
+ 'BRIGH' => /* I18N: Location of an LDS church temple */ I18N::translate('Brigham City, Utah, United States'),
+ 'BRISB' => /* I18N: Location of an LDS church temple */ I18N::translate('Brisbane, Australia'),
+ 'BROUG' => /* I18N: Location of an LDS church temple */ I18N::translate('Baton Rouge, Louisiana, United States'),
+ 'CALGA' => /* I18N: Location of an LDS church temple */ I18N::translate('Calgary, Alberta, Canada'),
+ 'CAMPI' => /* I18N: Location of an LDS church temple */ I18N::translate('Campinas, Brazil'),
+ 'CARAC' => /* I18N: Location of an LDS church temple */ I18N::translate('Caracas, Venezuela'),
+ 'CEBUP' => /* I18N: Location of an LDS church temple */ I18N::translate('Cebu City, Philippines'),
+ 'CHICA' => /* I18N: Location of an LDS church temple */ I18N::translate('Chicago, Illinois, United States'),
+ 'CIUJU' => /* I18N: Location of an LDS church temple */ I18N::translate('Ciudad Juarez, Mexico'),
+ 'COCHA' => /* I18N: Location of an LDS church temple */ I18N::translate('Cochabamba, Bolivia'),
+ 'COLJU' => /* I18N: Location of an LDS church temple */ I18N::translate('Colonia Juarez, Mexico'),
+ 'COLSC' => /* I18N: Location of an LDS church temple */ I18N::translate('Columbia, South Carolina, United States'),
+ 'COLUM' => /* I18N: Location of an LDS church temple */ I18N::translate('Columbus, Ohio, United States'),
+ 'COPEN' => /* I18N: Location of an LDS church temple */ I18N::translate('Copenhagen, Denmark'),
+ 'CORDO' => /* I18N: Location of an LDS church temple */ I18N::translate('Cordoba, Argentina'),
+ 'CRIVE' => /* I18N: Location of an LDS church temple */ I18N::translate('Columbia River, Washington, United States'),
+ 'CURIT' => /* I18N: Location of an LDS church temple */ I18N::translate('Curitiba, Brazil'),
+ 'DALLA' => /* I18N: Location of an LDS church temple */ I18N::translate('Dallas, Texas, United States'),
+ 'DENVE' => /* I18N: Location of an LDS church temple */ I18N::translate('Denver, Colorado, United States'),
+ 'DETRO' => /* I18N: Location of an LDS church temple */ I18N::translate('Detroit, Michigan, United States'),
+ 'DRAPE' => /* I18N: Location of an LDS church temple */ I18N::translate('Draper, Utah, United States'),
+ 'EDMON' => /* I18N: Location of an LDS church temple */ I18N::translate('Edmonton, Alberta, Canada'),
+ 'EHOUS' => /* I18N: Location of an historic LDS church temple - http://en.wikipedia.org/wiki/Endowment_house */ I18N::translate('Endowment House'),
+ 'FORTL' => /* I18N: Location of an LDS church temple */ I18N::translate('Fort Lauderdale, Florida, United States'),
+ 'FRANK' => /* I18N: Location of an LDS church temple */ I18N::translate('Frankfurt am Main, Germany'),
+ 'FREIB' => /* I18N: Location of an LDS church temple */ I18N::translate('Freiburg, Germany'),
+ 'FRESN' => /* I18N: Location of an LDS church temple */ I18N::translate('Fresno, California, United States'),
+ 'FUKUO' => /* I18N: Location of an LDS church temple */ I18N::translate('Fukuoka, Japan'),
+ 'GILAV' => /* I18N: Location of an LDS church temple */ I18N::translate('Gila Valley, Arizona, United States'),
+ 'GILBE' => /* I18N: Location of an LDS church temple */ I18N::translate('Gilbert, Arizona, United States'),
+ 'GUADA' => /* I18N: Location of an LDS church temple */ I18N::translate('Guadalajara, Mexico'),
+ 'GUATE' => /* I18N: Location of an LDS church temple */ I18N::translate('Guatemala City, Guatemala'),
+ 'GUAYA' => /* I18N: Location of an LDS church temple */ I18N::translate('Guayaquil, Ecuador'),
+ 'HAGUE' => /* I18N: Location of an LDS church temple */ I18N::translate('The Hague, Netherlands'),
+ 'HALIF' => /* I18N: Location of an LDS church temple */ I18N::translate('Halifax, Nova Scotia, Canada'),
+ 'HARTF' => /* I18N: Location of an LDS church temple */ I18N::translate('Hartford, Connecticut, United States'),
+ 'HAWAI' => /* I18N: Location of an LDS church temple */ I18N::translate('Laie, Hawaii, United States'),
+ 'HELSI' => /* I18N: Location of an LDS church temple */ I18N::translate('Helsinki, Finland'),
+ 'HERMO' => /* I18N: Location of an LDS church temple */ I18N::translate('Hermosillo, Mexico'),
+ 'HKONG' => /* I18N: Location of an LDS church temple */ I18N::translate('Hong Kong'),
+ 'HOUST' => /* I18N: Location of an LDS church temple */ I18N::translate('Houston, Texas, United States'),
+ 'IFALL' => /* I18N: Location of an LDS church temple */ I18N::translate('Idaho Falls, Idaho, United States'),
+ 'INDIA' => /* I18N: Location of an LDS church temple */ I18N::translate('Indianapolis, Indiana, United States'),
+ 'JOHAN' => /* I18N: Location of an LDS church temple */ I18N::translate('Johannesburg, South Africa'),
+ 'JRIVE' => /* I18N: Location of an LDS church temple */ I18N::translate('Jordan River, Utah, United States'),
+ 'KANSA' => /* I18N: Location of an LDS church temple */ I18N::translate('Kansas City, Missouri, United States'),
+ 'KONA' => /* I18N: Location of an LDS church temple */ I18N::translate('Kona, Hawaii, United States'),
+ 'KYIV' => /* I18N: Location of an LDS church temple */ I18N::translate('Kiev, Ukraine'),
+ 'LANGE' => /* I18N: Location of an LDS church temple */ I18N::translate('Los Angeles, California, United States'),
+ 'LIMA' => /* I18N: Location of an LDS church temple */ I18N::translate('Lima, Peru'),
+ 'LOGAN' => /* I18N: Location of an LDS church temple */ I18N::translate('Logan, Utah, United States'),
+ 'LONDO' => /* I18N: Location of an LDS church temple */ I18N::translate('London, England'),
+ 'LOUIS' => /* I18N: Location of an LDS church temple */ I18N::translate('Louisville, Kentucky, United States'),
+ 'LUBBO' => /* I18N: Location of an LDS church temple */ I18N::translate('Lubbock, Texas, United States'),
+ 'LVEGA' => /* I18N: Location of an LDS church temple */ I18N::translate('Las Vegas, Nevada, United States'),
+ 'MADRI' => /* I18N: Location of an LDS church temple */ I18N::translate('Madrid, Spain'),
+ 'MANAU' => /* I18N: Location of an LDS church temple */ I18N::translate('Manaus, Brazil'),
+ 'MANHA' => /* I18N: Location of an LDS church temple */ I18N::translate('Manhattan, New York, United States'),
+ 'MANIL' => /* I18N: Location of an LDS church temple */ I18N::translate('Manila, Philippines'),
+ 'MANTI' => /* I18N: Location of an LDS church temple */ I18N::translate('Manti, Utah, United States'),
+ 'MEDFO' => /* I18N: Location of an LDS church temple */ I18N::translate('Medford, Oregon, United States'),
+ 'MELBO' => /* I18N: Location of an LDS church temple */ I18N::translate('Melbourne, Australia'),
+ 'MEMPH' => /* I18N: Location of an LDS church temple */ I18N::translate('Memphis, Tennessee, United States'),
+ 'MERID' => /* I18N: Location of an LDS church temple */ I18N::translate('Merida, Mexico'),
+ 'MEXIC' => /* I18N: Location of an LDS church temple */ I18N::translate('Mexico City, Mexico'),
+ 'MNTVD' => /* I18N: Location of an LDS church temple */ I18N::translate('Montevideo, Uruguay'),
+ 'MONTE' => /* I18N: Location of an LDS church temple */ I18N::translate('Monterrey, Mexico'),
+ 'MONTI' => /* I18N: Location of an LDS church temple */ I18N::translate('Monticello, Utah, United States'),
+ 'MONTR' => /* I18N: Location of an LDS church temple */ I18N::translate('Montreal, Quebec, Canada'),
+ 'MTIMP' => /* I18N: Location of an LDS church temple */ I18N::translate('Mount Timpanogos, Utah, United States'),
+ 'NASHV' => /* I18N: Location of an LDS church temple */ I18N::translate('Nashville, Tennessee, United States'),
+ 'NAUV2' => /* I18N: Location of an LDS church temple */ I18N::translate('Nauvoo (new), Illinois, United States'),
+ 'NAUVO' => /* I18N: Location of an LDS church temple */ I18N::translate('Nauvoo (original), Illinois, United States'),
+ 'NBEAC' => /* I18N: Location of an LDS church temple */ I18N::translate('Newport Beach, California, United States'),
+ 'NUKUA' => /* I18N: Location of an LDS church temple */ I18N::translate('Nuku’Alofa, Tonga'),
+ 'NYORK' => /* I18N: Location of an LDS church temple */ I18N::translate('New York, New York, United States'),
+ 'NZEAL' => /* I18N: Location of an LDS church temple */ I18N::translate('Hamilton, New Zealand'),
+ 'OAKLA' => /* I18N: Location of an LDS church temple */ I18N::translate('Oakland, California, United States'),
+ 'OAXAC' => /* I18N: Location of an LDS church temple */ I18N::translate('Oaxaca, Mexico'),
+ 'OGDEN' => /* I18N: Location of an LDS church temple */ I18N::translate('Ogden, Utah, United States'),
+ 'OKLAH' => /* I18N: Location of an LDS church temple */ I18N::translate('Oklahoma City, Oklahoma, United States'),
+ 'OQUIR' => /* I18N: Location of an LDS church temple */ I18N::translate('Oquirrh Mountain, Utah, United States'),
+ 'ORLAN' => /* I18N: Location of an LDS church temple */ I18N::translate('Orlando, Florida, United States'),
+ 'PALEG' => /* I18N: Location of an LDS church temple */ I18N::translate('Porto Alegre, Brazil'),
+ 'PALMY' => /* I18N: Location of an LDS church temple */ I18N::translate('Palmyra, New York, United States'),
+ 'PANAM' => /* I18N: Location of an LDS church temple */ I18N::translate('Panama City, Panama'),
+ 'PAPEE' => /* I18N: Location of an LDS church temple */ I18N::translate('Papeete, Tahiti'),
+ 'PAYSO' => /* I18N: Location of an LDS church temple */ I18N::translate('Payson, Utah, United States'),
+ 'PERTH' => /* I18N: Location of an LDS church temple */ I18N::translate('Perth, Australia'),
+ 'PHOEN' => /* I18N: Location of an LDS church temple */ I18N::translate('Phoenix, Arizona, United States'),
+ 'POFFI' => /* I18N: Location of an historic LDS church temple - http://en.wikipedia.org/wiki/President_of_the_Church */ I18N::translate('President’s Office'),
+ 'PORTL' => /* I18N: Location of an LDS church temple */ I18N::translate('Portland, Oregon, United States'),
+ 'PREST' => /* I18N: Location of an LDS church temple */ I18N::translate('Preston, England'),
+ 'PROCC' => /* I18N: Location of an LDS church temple */ I18N::translate('Provo City Center, Utah, United States'),
+ 'PROVO' => /* I18N: Location of an LDS church temple */ I18N::translate('Provo, Utah, United States'),
+ 'QUETZ' => /* I18N: Location of an LDS church temple */ I18N::translate('Quetzaltenango, Guatemala'),
+ 'RALEI' => /* I18N: Location of an LDS church temple */ I18N::translate('Raleigh, North Carolina, United States'),
+ 'RECIF' => /* I18N: Location of an LDS church temple */ I18N::translate('Recife, Brazil'),
+ 'REDLA' => /* I18N: Location of an LDS church temple */ I18N::translate('Redlands, California, United States'),
+ 'REGIN' => /* I18N: Location of an LDS church temple */ I18N::translate('Regina, Saskatchewan, Canada'),
+ 'RENO' => /* I18N: Location of an LDS church temple */ I18N::translate('Reno, Nevada, United States'),
+ 'REXBU' => /* I18N: Location of an LDS church temple */ I18N::translate('Rexburg, Idaho, United States'),
+ 'SACRA' => /* I18N: Location of an LDS church temple */ I18N::translate('Sacramento, California, United States'),
+ 'SANSA' => /* I18N: Location of an LDS church temple */ I18N::translate('San Salvador, El Salvador'),
+ 'SANTI' => /* I18N: Location of an LDS church temple */ I18N::translate('Santiago, Chile'),
+ 'SANTO' => /* I18N: Location of an LDS church temple */ I18N::translate('San Antonio, Texas, United States'),
+ 'SDIEG' => /* I18N: Location of an LDS church temple */ I18N::translate('San Diego, California, United States'),
+ 'SDOMI' => /* I18N: Location of an LDS church temple */ I18N::translate('Santo Domingo, Dominican Republic'),
+ 'SEATT' => /* I18N: Location of an LDS church temple */ I18N::translate('Seattle, Washington, United States'),
+ 'SEOUL' => /* I18N: Location of an LDS church temple */ I18N::translate('Seoul, Korea'),
+ 'SGEOR' => /* I18N: Location of an LDS church temple */ I18N::translate('St. George, Utah, United States'),
+ 'SJOSE' => /* I18N: Location of an LDS church temple */ I18N::translate('San Jose, Costa Rica'),
+ 'SLAKE' => /* I18N: Location of an LDS church temple */ I18N::translate('Salt Lake City, Utah, United States'),
+ 'SLOUI' => /* I18N: Location of an LDS church temple */ I18N::translate('St. Louis, Missouri, United States'),
+ 'SNOWF' => /* I18N: Location of an LDS church temple */ I18N::translate('Snowflake, Arizona, United States'),
+ 'SPAUL' => /* I18N: Location of an LDS church temple */ I18N::translate('Sao Paulo, Brazil'),
+ 'SPMIN' => /* I18N: Location of an LDS church temple */ I18N::translate('St. Paul, Minnesota, United States'),
+ 'SPOKA' => /* I18N: Location of an LDS church temple */ I18N::translate('Spokane, Washington, United States'),
+ 'STOCK' => /* I18N: Location of an LDS church temple */ I18N::translate('Stockholm, Sweden'),
+ 'SUVA' => /* I18N: Location of an LDS church temple */ I18N::translate('Suva, Fiji'),
+ 'SWISS' => /* I18N: Location of an LDS church temple */ I18N::translate('Bern, Switzerland'),
+ 'SYDNE' => /* I18N: Location of an LDS church temple */ I18N::translate('Sydney, Australia'),
+ 'TAIPE' => /* I18N: Location of an LDS church temple */ I18N::translate('Taipei, Taiwan'),
+ 'TAMPI' => /* I18N: Location of an LDS church temple */ I18N::translate('Tampico, Mexico'),
+ 'TEGUC' => /* I18N: Location of an LDS church temple */ I18N::translate('Tegucigalpa, Honduras'),
+ 'TGUTI' => /* I18N: Location of an LDS church temple */ I18N::translate('Tuxtla Gutierrez, Mexico'),
+ 'TIJUA' => /* I18N: Location of an LDS church temple */ I18N::translate('Tijuana, Mexico'),
+ 'TOKYO' => /* I18N: Location of an LDS church temple */ I18N::translate('Tokyo, Japan'),
+ 'TORNO' => /* I18N: Location of an LDS church temple */ I18N::translate('Toronto, Ontario, Canada'),
+ 'TRUJI' => /* I18N: Location of an LDS church temple */ I18N::translate('Trujillo, Peru'),
+ 'TWINF' => /* I18N: Location of an LDS church temple */ I18N::translate('Twin Falls, Idaho, United States'),
+ 'VANCO' => /* I18N: Location of an LDS church temple */ I18N::translate('Vancouver, British Columbia, Canada'),
+ 'VERAC' => /* I18N: Location of an LDS church temple */ I18N::translate('Veracruz, Mexico'),
+ 'VERNA' => /* I18N: Location of an LDS church temple */ I18N::translate('Vernal, Utah, United States'),
+ 'VILLA' => /* I18N: Location of an LDS church temple */ I18N::translate('Villa Hermosa, Mexico'),
+ 'WASHI' => /* I18N: Location of an LDS church temple */ I18N::translate('Washington, District of Columbia, United States'),
+ 'WINTE' => /* I18N: Location of an LDS church temple */ I18N::translate('Winter Quarters, Nebraska, United States'),
+ ];
+
+ uasort($values, [I18N::class, 'strcasecmp']);
+ $values = ['' => I18N::translate('No temple - living ordinance')] + $values;
+
+ return $values;
+ }
+}
diff --git a/app/Elements/TextFromSource.php b/app/Elements/TextFromSource.php
new file mode 100644
index 0000000000..3bbd5092ec
--- /dev/null
+++ b/app/Elements/TextFromSource.php
@@ -0,0 +1,76 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Filter;
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * TEXT_FROM_SOURCE := {Size=1:248}
+ * <TEXT>
+ * A verbatim copy of any description contained within the source. This indicates notes or text
+ * that are actually contained in the source document, not the submitter's opinion about the
+ * source. This should be, from the evidence point of view, "what the original record keeper
+ * said" as opposed to the researcher's interpretation. The word TEXT, in this case, means from
+ * the text which appeared in the source record including labels.
+ */
+class TextFromSource extends AbstractElement
+{
+ /**
+ * Convert a value to a canonical form.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ public function canonical(string $value): string
+ {
+ // Browsers use MS-DOS line endings in multi-line data.
+ return strtr($value, ["\r\n" => "\n", "\r" => "\n"]);
+ }
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return $this->editTextArea($id, $name, $value);
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return Filter::formatText($value, $tree);
+ }
+}
diff --git a/app/Elements/TimeValue.php b/app/Elements/TimeValue.php
new file mode 100644
index 0000000000..f0f25da13f
--- /dev/null
+++ b/app/Elements/TimeValue.php
@@ -0,0 +1,33 @@
+<?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\Elements;
+
+/**
+ * TIME_VALUE := {Size=1:12}
+ * [ hh:mm:ss.fs ]
+ * The time of a specific event, usually a computer-timed event, where:
+ * hh = hours on a 24-hour clock
+ * mm = minutes
+ * ss = seconds (optional)
+ * fs = decimal fraction of a second (optional)
+ */
+class TimeValue extends AbstractElement
+{
+}
diff --git a/app/Elements/TransmissionDate.php b/app/Elements/TransmissionDate.php
new file mode 100644
index 0000000000..6989d56f1e
--- /dev/null
+++ b/app/Elements/TransmissionDate.php
@@ -0,0 +1,29 @@
+<?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\Elements;
+
+/**
+ * TRANSMISSION_DATE := {Size=11:12}
+ * <DATE_EXACT>
+ * The date that this transmission was created.
+ */
+class TransmissionDate extends AbstractElement
+{
+}
diff --git a/app/Elements/UnknownElement.php b/app/Elements/UnknownElement.php
new file mode 100644
index 0000000000..dbe1b8c90e
--- /dev/null
+++ b/app/Elements/UnknownElement.php
@@ -0,0 +1,40 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\I18N;
+
+/**
+ * An unrecognised GEDCOM element.
+ */
+class UnknownElement extends AbstractElement
+{
+ /**
+ * Name for this GEDCOM primitive.
+ *
+ * @return string
+ */
+ public function label(): string
+ {
+ $title = I18N::translate('Unrecognized GEDCOM code');
+
+ return '<span class="error" title="' . $title . '">' . parent::label() . '</span>';
+ }
+}
diff --git a/app/Elements/UserReferenceNumber.php b/app/Elements/UserReferenceNumber.php
new file mode 100644
index 0000000000..c0b3012b7d
--- /dev/null
+++ b/app/Elements/UserReferenceNumber.php
@@ -0,0 +1,30 @@
+<?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\Elements;
+
+/**
+ * USER_REFERENCE_NUMBER := {Size=1:20}
+ * A user-defined number or text that the submitter uses to identify this record. For instance, it
+ * may be a record number within the submitter's automated or manual system, or it may be a page
+ * and position number on a pedigree chart.
+ */
+class UserReferenceNumber extends AbstractElement
+{
+}
diff --git a/app/Elements/UserReferenceType.php b/app/Elements/UserReferenceType.php
new file mode 100644
index 0000000000..f577c7d9cf
--- /dev/null
+++ b/app/Elements/UserReferenceType.php
@@ -0,0 +1,29 @@
+<?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\Elements;
+
+/**
+ * USER_REFERENCE_TYPE := {Size=1:40}
+ * A user-defined definition of the USER_REFERENCE_NUMBER.
+ */
+class UserReferenceType extends AbstractElement
+{
+ protected const MAX_LENGTH = 40;
+}
diff --git a/app/Elements/VersionNumber.php b/app/Elements/VersionNumber.php
new file mode 100644
index 0000000000..6493188a2f
--- /dev/null
+++ b/app/Elements/VersionNumber.php
@@ -0,0 +1,48 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+
+/**
+ * VERSION_NUMBER := {Size=1:15}
+ * An identifier that represents the version level assigned to the associated product. It is
+ * defined and changed by the creators of the product.
+ */
+class VersionNumber extends AbstractElement
+{
+ protected const MAX_LENGTH = 15;
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ $canonical = $this->canonical($value);
+
+ return '<span dir="ltr">' . e($canonical) . '</span>';
+ }
+}
diff --git a/app/Elements/WebtreesUser.php b/app/Elements/WebtreesUser.php
new file mode 100644
index 0000000000..bef049e038
--- /dev/null
+++ b/app/Elements/WebtreesUser.php
@@ -0,0 +1,41 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Auth;
+use Fisharebest\Webtrees\Tree;
+
+/**
+ * The webtrees user for a CHAN or _TODO element
+ */
+class WebtreesUser extends AbstractElement
+{
+ /**
+ * Create a default value for this element.
+ *
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function default(Tree $tree): string
+ {
+ return Auth::user()->userName();
+ }
+}
diff --git a/app/Elements/WhereWithinSource.php b/app/Elements/WhereWithinSource.php
new file mode 100644
index 0000000000..fb2d380e87
--- /dev/null
+++ b/app/Elements/WhereWithinSource.php
@@ -0,0 +1,55 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\AutoCompleteCitation;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function route;
+
+/**
+ * WHERE_WITHIN_SOURCE := {Size=1:248}
+ * Specific location with in the information referenced. For a published work, this could include
+ * the volume of a multi-volume work and the page number(s). For a periodical, it could include
+ * volume, issue, and page numbers. For a newspaper, it could include a column number and page
+ * number. For an unpublished source or microfilmed works, this could be a film or sheet number,
+ * page number, frame number, etc. A census record might have an enumerating district, page number,
+ * line number, dwelling number, and family number. The data in this field should be in the form of
+ * a label and value pair, such as Label1: value, Label2: value, with each pair being separated by
+ * a comma. For example, Film: 1234567, Frame: 344, Line: 28.
+ */
+class WhereWithinSource extends AbstractElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return '<input data-autocomplete-url="' . e(route(AutoCompleteCitation::class, ['tree' => $tree->name()])) . '" data-autocomplete-extra="SOUR" autocomplete="off" class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">';
+ }
+}
diff --git a/app/Elements/Will.php b/app/Elements/Will.php
new file mode 100644
index 0000000000..f6e2fd5e26
--- /dev/null
+++ b/app/Elements/Will.php
@@ -0,0 +1,35 @@
+<?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\Elements;
+
+/**
+ * Will
+ */
+class Will extends AbstractElement
+{
+ protected const SUBTAGS = [
+ 'DATE' => '0:1',
+ 'PLAC' => '0:1',
+ 'NOTE' => '0:M',
+ 'OBJE' => '0:M',
+ 'SOUR' => '0:M',
+ 'RESN' => '0:1',
+ ];
+}
diff --git a/app/Elements/XrefFamily.php b/app/Elements/XrefFamily.php
new file mode 100644
index 0000000000..26d8cb66a6
--- /dev/null
+++ b/app/Elements/XrefFamily.php
@@ -0,0 +1,67 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+
+use function trim;
+use function view;
+
+/**
+ * XREF:FAM := {Size=1:22}
+ * A pointer to, or a cross-reference identifier of, a family record.
+ */
+class XrefFamily extends AbstractXrefElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return view('components/select-family', [
+ 'id' => $id,
+ 'name' => $name,
+ 'family' => Registry::familyFactory()->make(trim($value, '@'), $tree),
+ 'tree' => $tree,
+ 'at' => '@',
+ ]);
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueXrefLink($value, $tree, Registry::familyFactory());
+ }
+}
diff --git a/app/Elements/XrefIndividual.php b/app/Elements/XrefIndividual.php
new file mode 100644
index 0000000000..a52aca06be
--- /dev/null
+++ b/app/Elements/XrefIndividual.php
@@ -0,0 +1,66 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+
+use function view;
+
+/**
+ * XREF:INDI := {Size=1:22}
+ * A pointer to, or a cross-reference identifier of, an individual record.
+ */
+class XrefIndividual extends AbstractXrefElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ return view('components/select-individual', [
+ 'id' => $id,
+ 'name' => $name,
+ 'individual' => Registry::individualFactory()->make(trim($value, '@'), $tree),
+ 'tree' => $tree,
+ 'at' => '@',
+ ]);
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueXrefLink($value, $tree, Registry::individualFactory());
+ }
+}
diff --git a/app/Elements/XrefLocation.php b/app/Elements/XrefLocation.php
new file mode 100644
index 0000000000..50bb654a0f
--- /dev/null
+++ b/app/Elements/XrefLocation.php
@@ -0,0 +1,81 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\CreateLocationModal;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function route;
+use function trim;
+use function view;
+
+/**
+ * XREF:_LOC := {Size=1:22}
+ * A pointer to, or a cross-reference identifier of, a location record.
+ */
+class XrefLocation extends AbstractXrefElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ $select = view('components/select-location', [
+ 'id' => $id,
+ 'name' => $name,
+ 'location' => Registry::locationFactory()->make(trim($value, '@'), $tree),
+ 'tree' => $tree,
+ 'at' => '@',
+ ]);
+
+ return
+ '<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(CreateLocationModal::class, ['tree' => $tree->name()])) . '" data-select-id="' . $id . '" title="' . I18N::translate('Create a location') . '">' .
+ view('icons/add') .
+ '</button>' .
+ '</div>' .
+ $select .
+ '</div>';
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueXrefLink($value, $tree, Registry::locationFactory());
+ }
+}
diff --git a/app/Elements/XrefMedia.php b/app/Elements/XrefMedia.php
new file mode 100644
index 0000000000..532b3daa47
--- /dev/null
+++ b/app/Elements/XrefMedia.php
@@ -0,0 +1,81 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\CreateMediaObjectModal;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function route;
+use function trim;
+use function view;
+
+/**
+ * XREF:OBJE := {Size=1:22}
+ * A pointer to, or a cross-reference identifier of, a multimedia object.
+ */
+class XrefMedia extends AbstractXrefElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ $select = view('components/select-media', [
+ 'id' => $id,
+ 'name' => $name,
+ 'media' => Registry::mediaFactory()->make(trim($value, '@'), $tree),
+ 'tree' => $tree,
+ 'at' => '@',
+ ]);
+
+ return
+ '<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(CreateMediaObjectModal::class, ['tree' => $tree->name()])) . '" data-select-id="' . $id . '" title="' . I18N::translate('Create a media object') . '">' .
+ view('icons/add') .
+ '</button>' .
+ '</div>' .
+ $select .
+ '</div>';
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueXrefLink($value, $tree, Registry::mediaFactory());
+ }
+}
diff --git a/app/Elements/XrefNote.php b/app/Elements/XrefNote.php
new file mode 100644
index 0000000000..38d148abb2
--- /dev/null
+++ b/app/Elements/XrefNote.php
@@ -0,0 +1,81 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\CreateNoteModal;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function route;
+use function trim;
+use function view;
+
+/**
+ * XREF:NOTE := {Size=1:22}
+ * A pointer to, or a cross-reference identifier of, a note record.
+ */
+class XrefNote extends AbstractXrefElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ $select = view('components/select-note', [
+ 'id' => $id,
+ 'name' => $name,
+ 'note' => Registry::noteFactory()->make(trim($value, '@'), $tree),
+ 'tree' => $tree,
+ 'at' => '@',
+ ]);
+
+ return
+ '<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>' .
+ $select .
+ '</div>';
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueXrefLink($value, $tree, Registry::noteFactory());
+ }
+}
diff --git a/app/Elements/XrefRepository.php b/app/Elements/XrefRepository.php
new file mode 100644
index 0000000000..99d33693c9
--- /dev/null
+++ b/app/Elements/XrefRepository.php
@@ -0,0 +1,81 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\CreateRepositoryModal;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function route;
+use function trim;
+use function view;
+
+/**
+ * XREF:REPO := {Size=1:22}
+ * A pointer to, or a cross-reference identifier of, a repository record.
+ */
+class XrefRepository extends AbstractXrefElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ $select = view('components/select-repository', [
+ 'id' => $id,
+ 'name' => $name,
+ 'repository' => Registry::repositoryFactory()->make(trim($value, '@'), $tree),
+ 'tree' => $tree,
+ 'at' => '@',
+ ]);
+
+ return
+ '<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(CreateRepositoryModal::class, ['tree' => $tree->name()])) . '" data-select-id="' . $id . '" title="' . I18N::translate('Create a repository') . '">' .
+ view('icons/add') .
+ '</button>' .
+ '</div>' .
+ $select .
+ '</div>';
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueXrefLink($value, $tree, Registry::repositoryFactory());
+ }
+}
diff --git a/app/Elements/XrefSource.php b/app/Elements/XrefSource.php
new file mode 100644
index 0000000000..8cf861eb32
--- /dev/null
+++ b/app/Elements/XrefSource.php
@@ -0,0 +1,110 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\CreateSourceModal;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function route;
+use function trim;
+use function view;
+
+/**
+ * XREF:SOUR := {Size=1:22}
+ * A pointer to, or a cross-reference identifier of, a SOURce record.
+ */
+class XrefSource extends AbstractXrefElement
+{
+ protected const SUBTAGS = [
+ 'PAGE' => '0:1',
+ 'EVEN' => '0:1',
+ 'DATA' => '0:1',
+ 'OBJE' => '0:M',
+ 'NOTE' => '0:M',
+ 'QUAY' => '0:1',
+ ];
+
+ protected const ABRIDGED_SUBTAGS = [
+ 'PAGE' => '0:1',
+ 'DATA' => '0:1',
+ 'OBJE' => '0:M',
+ ];
+
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ $select = view('components/select-source', [
+ 'id' => $id,
+ 'name' => $name,
+ 'source' => Registry::sourceFactory()->make(trim($value, '@'), $tree),
+ 'tree' => $tree,
+ 'at' => '@',
+ ]);
+
+ return
+ '<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(CreateSourceModal::class, ['tree' => $tree->name()])) . '" data-select-id="' . $id . '" title="' . I18N::translate('Create a source') . '">' .
+ view('icons/add') .
+ '</button>' .
+ '</div>' .
+ $select .
+ '</div>';
+ }
+
+ /**
+ * @param Tree $tree
+ *
+ * @return array<string,string>
+ */
+ public function subtags(Tree $tree): array
+ {
+ if ($tree->getPreference('FULL_SOURCES') === '1') {
+ return static::SUBTAGS;
+ }
+
+ return static::ABRIDGED_SUBTAGS;
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueXrefLink($value, $tree, Registry::sourceFactory());
+ }
+}
diff --git a/app/Elements/XrefSubmission.php b/app/Elements/XrefSubmission.php
new file mode 100644
index 0000000000..376911c1f8
--- /dev/null
+++ b/app/Elements/XrefSubmission.php
@@ -0,0 +1,81 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\CreateSubmissionModal;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function route;
+use function trim;
+use function view;
+
+/**
+ * XREF:SUBN := {Size=1:22}
+ * A pointer to, or a cross-reference identifier of, a SUBmissioN record.
+ */
+class XrefSubmission extends AbstractXrefElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ $select = view('components/select-submission', [
+ 'id' => $id,
+ 'name' => $name,
+ 'submission' => Registry::submissionFactory()->make(trim($value, '@'), $tree),
+ 'tree' => $tree,
+ 'at' => '@',
+ ]);
+
+ return
+ '<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(CreateSubmissionModal::class, ['tree' => $tree->name()])) . '" data-select-id="' . $id . '" title="' . I18N::translate('Create a submission') . '">' .
+ view('icons/add') .
+ '</button>' .
+ '</div>' .
+ $select .
+ '</div>';
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueXrefLink($value, $tree, Registry::submissionFactory());
+ }
+}
diff --git a/app/Elements/XrefSubmitter.php b/app/Elements/XrefSubmitter.php
new file mode 100644
index 0000000000..a77c8c1afc
--- /dev/null
+++ b/app/Elements/XrefSubmitter.php
@@ -0,0 +1,81 @@
+<?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\Elements;
+
+use Fisharebest\Webtrees\Http\RequestHandlers\CreateSubmitterModal;
+use Fisharebest\Webtrees\I18N;
+use Fisharebest\Webtrees\Registry;
+use Fisharebest\Webtrees\Tree;
+
+use function e;
+use function route;
+use function trim;
+use function view;
+
+/**
+ * XREF:SUBM := {Size=1:22}
+ * A pointer to, or a cross-reference identifier of, a SUBMitter record.
+ */
+class XrefSubmitter extends AbstractXrefElement
+{
+ /**
+ * An edit control for this data.
+ *
+ * @param string $id
+ * @param string $name
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function edit(string $id, string $name, string $value, Tree $tree): string
+ {
+ $select = view('components/select-submitter', [
+ 'id' => $id,
+ 'name' => $name,
+ 'submitter' => Registry::submitterFactory()->make(trim($value, '@'), $tree),
+ 'tree' => $tree,
+ 'at' => '@',
+ ]);
+
+ return
+ '<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(CreateSubmitterModal::class, ['tree' => $tree->name()])) . '" data-select-id="' . $id . '" title="' . I18N::translate('Create a submitter') . '">' .
+ view('icons/add') .
+ '</button>' .
+ '</div>' .
+ $select .
+ '</div>';
+ }
+
+ /**
+ * Display the value of this type of element.
+ *
+ * @param string $value
+ * @param Tree $tree
+ *
+ * @return string
+ */
+ public function value(string $value, Tree $tree): string
+ {
+ return $this->valueXrefLink($value, $tree, Registry::submitterFactory());
+ }
+}