diff --git a/app/CustomTags/Gedcom7.php b/app/CustomTags/Gedcom7.php index 7044a2763f..edb0d3a13d 100644 --- a/app/CustomTags/Gedcom7.php +++ b/app/CustomTags/Gedcom7.php @@ -79,6 +79,7 @@ public function tags(): array 'FAM:*:ASSO:ROLE' => new RoleInEvent(I18N::translate('Role')), 'FAM:*:ASSO:ROLE:PHRASE' => new CustomElement(I18N::translate('Phrase')), 'FAM:*:DATE:TIME' => new TimeValue(I18N::translate('Time')), + 'FAM:*:DATE:PHRASE' => new CustomElement(I18N::translate('Phrase')), 'FAM:*:PLAC:EXID' => new ExternalIdentifier(I18N::translate('External identifier')), 'FAM:*:PLAC:EXID:TYPE' => new ExternalIdentifierType(I18N::translate('Type')), 'FAM:*:SDATE' => new CustomElement(I18N::translate('Sort date')), @@ -108,6 +109,7 @@ public function tags(): array 'INDI:*:ASSO:ROLE' => new RoleInEvent(I18N::translate('Role')), 'INDI:*:ASSO:ROLE:PHRASE' => new CustomElement(I18N::translate('Phrase')), 'INDI:*:DATE:TIME' => new TimeValue(I18N::translate('Time')), + 'INDI:*:DATE:PHRASE' => new CustomElement(I18N::translate('Phrase')), 'INDI:*:PLAC:EXID' => new ExternalIdentifier(I18N::translate('External identifier')), 'INDI:*:PLAC:EXID:TYPE' => new ExternalIdentifierType(I18N::translate('Type')), 'INDI:*:SDATE' => new CustomElement(I18N::translate('Sort date')), diff --git a/app/Date.php b/app/Date.php index e4a4777786..b1a631f8b8 100644 --- a/app/Date.php +++ b/app/Date.php @@ -60,7 +60,7 @@ public function __construct(string $date) $calendar_date_factory = Registry::calendarDateFactory(); // Extract any explanatory text - if (preg_match('/^(.*) ?[(](.*)[)]/', $date, $match)) { + if (preg_match('/^(.*?) ?[(](.*)[)]/', $date, $match)) { $date = $match[1]; $this->text = $match[2]; } @@ -123,7 +123,7 @@ public function display(Tree|null $tree = null, string|null $date_format = null, } else { $d2 = $this->date2->format($date_format, $this->qual2); } - // Con vert to other calendars, if requested + // Convert to other calendars, if requested $conv1 = ''; $conv2 = ''; foreach ($calendar_format as $cal_fmt) { @@ -180,7 +180,7 @@ public function display(Tree|null $tree = null, string|null $date_format = null, case '': $tmp = $d1 . $conv1; if ($this->text !== '') { - $tmp .= '(' . e($this->text) . ')'; + $tmp .= ' ' . e($this->text) . ''; } break; case 'ABT': @@ -197,7 +197,9 @@ public function display(Tree|null $tree = null, string|null $date_format = null, break; case 'INT': /* I18N: Gedcom INT dates */ - $tmp = I18N::translate('interpreted %s (%s)', $d1 . $conv1, e($this->text)); + $tmp = I18N::translate('interpreted %s (%s)', $d1 . $conv1, '${DATE_PHRASE}'); + $phrase = ($this->text == '') ? '' : '' . e($this->text) . ''; + $tmp = str_replace('(${DATE_PHRASE})', $phrase, $tmp); break; case 'BEF': /* I18N: Gedcom BEF dates */ diff --git a/app/Elements/DateValue.php b/app/Elements/DateValue.php index 0b380ed557..41a05df64a 100644 --- a/app/Elements/DateValue.php +++ b/app/Elements/DateValue.php @@ -80,6 +80,16 @@ public function edit(string $id, string $name, string $value, Tree $tree): strin '
' . (new Date($value))->display() . '
'; } + /** + * Should we collapse the children of this element when editing? + * + * @return bool + */ + public function collapseChildren(): bool + { + return true; + } + /** * Escape @ signs in a GEDCOM export. * diff --git a/app/Gedcom.php b/app/Gedcom.php index c99d06c1e2..d5782a0999 100644 --- a/app/Gedcom.php +++ b/app/Gedcom.php @@ -1052,6 +1052,33 @@ private function customSubTags(): array $subtags['INDI:DEAT:DATE'][] = ['TIME', '0:1']; } + if (Site::getPreference('CUSTOM_DATEPHRASE_TAGS') === '1') { + // needed when the fact date has an explicit translation set in function gedcom551Tags + $subtags['FAM:DIV:DATE'][] = ['PHRASE', '0:1']; + $subtags['FAM:ENGA:DATE'][] = ['PHRASE', '0:1']; + $subtags['FAM:MARB:DATE'][] = ['PHRASE', '0:1']; + $subtags['FAM:MARR:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:ADOP:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:BAPM:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:BARM:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:BASM:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:BIRT:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:BLES:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:BURI:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:CENS:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:CHR:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:CONF:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:CREM:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:DEAT:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:EMIG:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:EVEN:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:FCOM:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:IMMI:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:NATU:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:ORDN:DATE'][] = ['PHRASE', '0:1']; + $subtags['INDI:RESI:DATE'][] = ['PHRASE', '0:1']; + } + if (Site::getPreference('CUSTOM_GEDCOM_L_TAGS') === '1') { $subtags['FAM'][] = ['_ASSO', '0:M']; $subtags['FAM'][] = ['_STAT', '0:1']; diff --git a/app/Http/RequestHandlers/SiteTagsAction.php b/app/Http/RequestHandlers/SiteTagsAction.php index 29e3346503..13453cfbec 100644 --- a/app/Http/RequestHandlers/SiteTagsAction.php +++ b/app/Http/RequestHandlers/SiteTagsAction.php @@ -49,6 +49,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface $custom_fam_nchi = Validator::parsedBody($request)->boolean('custom_fam_nchi', false); $custom_resi_value = Validator::parsedBody($request)->boolean('custom_resi_value', false); $custom_time_tags = Validator::parsedBody($request)->boolean('custom_time_tags', false); + $custom_datephrase_tags = Validator::parsedBody($request)->boolean('custom_datephrase_tags', false); Site::setPreference('CUSTOM_FAMILY_TAGS', implode(',', $custom_family_tags)); Site::setPreference('CUSTOM_INDIVIDUAL_TAGS', implode(',', $custom_individual_tags)); @@ -57,6 +58,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface Site::setPreference('CUSTOM_FAM_NCHI', (string) $custom_fam_nchi); Site::setPreference('CUSTOM_RESI_VALUE', (string) $custom_resi_value); Site::setPreference('CUSTOM_TIME_TAGS', (string) $custom_time_tags); + Site::setPreference('CUSTOM_DATEPHRASE_TAGS', (string) $custom_datephrase_tags); FlashMessages::addMessage(I18N::translate('The website preferences have been updated.'), 'success'); diff --git a/app/Http/RequestHandlers/SiteTagsPage.php b/app/Http/RequestHandlers/SiteTagsPage.php index 7c2ee68e41..8290e8020f 100644 --- a/app/Http/RequestHandlers/SiteTagsPage.php +++ b/app/Http/RequestHandlers/SiteTagsPage.php @@ -56,10 +56,11 @@ public function handle(ServerRequestInterface $request): ResponseInterface $custom_gedcom_l_tags = (bool) Site::getPreference('CUSTOM_GEDCOM_L_TAGS'); // GEDCOM 7 extensions - $custom_fam_fact = (bool) Site::getPreference('CUSTOM_FAM_FACT'); - $custom_fam_nchi = (bool) Site::getPreference('CUSTOM_FAM_NCHI'); - $custom_resi_value = (bool) Site::getPreference('CUSTOM_RESI_VALUE'); - $custom_time_tags = (bool) Site::getPreference('CUSTOM_TIME_TAGS'); + $custom_fam_fact = (bool) Site::getPreference('CUSTOM_FAM_FACT'); + $custom_fam_nchi = (bool) Site::getPreference('CUSTOM_FAM_NCHI'); + $custom_resi_value = (bool) Site::getPreference('CUSTOM_RESI_VALUE'); + $custom_time_tags = (bool) Site::getPreference('CUSTOM_TIME_TAGS'); + $custom_datephrase_tags = (bool) Site::getPreference('CUSTOM_DATEPHRASE_TAGS'); return $this->viewResponse('admin/tags', [ 'all_family_tags' => $all_family_tags->sort()->all(), @@ -71,6 +72,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface 'custom_fam_nchi' => $custom_fam_nchi, 'custom_resi_value' => $custom_resi_value, 'custom_time_tags' => $custom_time_tags, + 'custom_datephrase_tags' => $custom_datephrase_tags, 'element_factory' => Registry::elementFactory(), 'title' => I18N::translate('GEDCOM tags'), ]); diff --git a/resources/css/_base.css b/resources/css/_base.css index 2b4db62231..42bcdd4f00 100644 --- a/resources/css/_base.css +++ b/resources/css/_base.css @@ -152,3 +152,10 @@ a:hover, .btn-link:hover, .nav-link:hover { .leaflet-bottom, .leaflet-top { z-index: 999; } + +.date.phrase::before { + content: "("; +} +.date.phrase::after { + content: ")"; +} \ No newline at end of file diff --git a/resources/views/admin/tags.phtml b/resources/views/admin/tags.phtml index 91d5b9bd58..c3a860dce1 100644 --- a/resources/views/admin/tags.phtml +++ b/resources/views/admin/tags.phtml @@ -18,6 +18,7 @@ use Fisharebest\Webtrees\Site; * @var bool $custom_fam_nchi * @var bool $custom_resi_value * @var bool $custom_time_tags + * @var bool $custom_datephrase_tags * @var ElementFactoryInterface $element_factory * @var string $title */ @@ -971,6 +972,22 @@ use Fisharebest\Webtrees\Site; + + + + + + + INDI:*:DATE:PHRASE +
+ FAM:*:DATE:PHRASE + + + + 'custom_datephrase_tags', 'name' => 'custom_datephrase_tags', 'label' => I18N::translate('show'), 'checked' => $custom_datephrase_tags]) ?> + + + diff --git a/resources/views/fact-date.phtml b/resources/views/fact-date.phtml index 4ef1ab8d71..c44c68e49f 100644 --- a/resources/views/fact-date.phtml +++ b/resources/views/fact-date.phtml @@ -21,7 +21,6 @@ use Fisharebest\Webtrees\Registry; */ $factrec = $fact->gedcom(); -$html = ''; // Recorded age if (preg_match('/\n2 AGE (.+)/', $factrec, $match) === 1) { @@ -42,18 +41,25 @@ if (preg_match('/\n2 WIFE\n3 AGE (.+)/', $factrec, $match) === 1) { $wife_age = ''; } -// Calculated age -[, $tag] = explode(':', $fact->tag()); - -if (preg_match('/\n2 DATE (.+)/', $factrec, $match) === 1) { - $date = new Date($match[1]); - $html .= ' ' . $date->display($cal_link ? $record->tree() : null, null, true); +$date = ''; +$html = ''; +if (preg_match('/\n2 DATE\s(.+)/', $factrec) === 1) { + $htmlParts = []; + if (preg_match('/\n2 DATE (.+)/', $factrec, $match) === 1) { + $date = new Date($match[1]); + $htmlParts[] = $date->display($cal_link ? $record->tree() : null, null, true); + } // Time isn't valid GEDCOM, but it is widely used. if ($time && preg_match('/\n3 TIME (.+)/', $factrec, $match) === 1) { - $html .= ' – ' . $match[1] . ''; + $htmlParts[] = '' . $match[1] . ''; } - - if ($record instanceof Individual) { + $html .= join(' - ', $htmlParts); + if (preg_match('/2 DATE.*(?:\n[3-9].*)*\n3 PHRASE (.+)/', $factrec, $match) === 1) { + $html .= ' ' . $match[1] . ''; + } + if ($date !== '' && $record instanceof Individual) { + // Calculated age + [, $tag] = explode(':', $fact->tag()); if ( in_array($tag, Gedcom::BIRTH_EVENTS, true) && $record === $fact->record() &&