From 5d0bf09430d54d77ae998f2af24be686798f32b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sun, 17 Dec 2023 01:28:17 -0800 Subject: [PATCH] Extract EDTF date from OSM approximate date --- modules/validations/invalid_format.js | 98 +++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 13 deletions(-) diff --git a/modules/validations/invalid_format.js b/modules/validations/invalid_format.js index 50e596791c6..f6db1aaf356 100644 --- a/modules/validations/invalid_format.js +++ b/modules/validations/invalid_format.js @@ -8,6 +8,51 @@ import * as edtf from 'edtf'; export function validationFormatting() { var type = 'invalid_format'; + /** + * Converts a date in OSM approximate date format to EDTF. + */ + function edtfFromOSMDate(osm) { + // https://wiki.openstreetmap.org/wiki/Key:start_date#Approximations + // https://wiki.openstreetmap.org/wiki/Special:Diff/510218/557626#Proposal_for_date_formatting + let [match, year, bc] = osm.match(/^~(\d+)( BC)?$/) || []; + if (match) { + if (bc) year = -parseInt(year, 10) + 1; + return `${year}~`; + } + + let circa, decade; + [match, circa, decade, bc] = osm.match(/^(~)?(\d+)0s( BC)?$/) || []; + if (match) { + if (!circa) circa = ''; + if (!bc) return `${decade}X${circa}`; + let startYear = -parseInt(decade, 10) * 10 - 8; + let endYear = -parseInt(decade, 10) * 10 + 1; + return `${startYear}${circa}/${endYear}${circa}`; + } + + let century; + [match, circa, century, bc] = osm.match(/^(~)?C(\d+)( BC)?$/) || []; + if (match) { + if (!circa) circa = ''; + if (!bc) return `${parseInt(century, 10) - 1}XX${circa}`; + let startYear = (parseInt(century, 10) - 1) * -100 - 98; + let endYear = (parseInt(century, 10) - 1) * -100 + 1; + return `${startYear}${circa}/${endYear}${circa}`; + } + + let end; + [match, end] = osm.match(/^before (\d{4}(?:-\d\d)?(?:-\d\d)?)$/) || []; + if (match) { + return `[..${end}]`; + } + + let start; + [match, start] = osm.match(/^after (\d{4}(?:-\d\d)?(?:-\d\d)?)$/) || []; + if (match) { + return `[${start}..]`; + } + } + var validation = function(entity) { var issues = []; @@ -38,21 +83,47 @@ export function validationFormatting() { hash: key + entity.tags[key], dynamicFixes: function() { var fixes = []; + + let alternatives = []; if (normalized !== null) { - var localeDateString = normalized.date.toLocaleDateString(localizer.languageCode(), normalized.localeOptions); - fixes.push(new validationIssueFix({ - title: t.append('issues.fix.reformat_date.title', { date: localeDateString }), - onClick: function(context) { - context.perform(function(graph) { - var entityInGraph = graph.hasEntity(entity.id); - if (!entityInGraph) return graph; - var newTags = Object.assign({}, entityInGraph.tags); - newTags[key] = normalized.value; - return actionChangeTags(entityInGraph.id, newTags)(graph); - }, t('issues.fix.reformat_date.annotation')); - } - })); + let label = normalized.date.toLocaleDateString(localizer.languageCode(), normalized.localeOptions); + alternatives.push({ + date: normalized.value, + label: label || normalized.value, + }); } + let edtfFromOSM = edtfFromOSMDate(entity.tags[key]); + if (edtfFromOSM) { + let label; + try { + label = edtf.default(edtfFromOSM).format(localizer.languageCode()); + } catch (e) { + label = edtfFromOSM; + } + alternatives.push({ + edtf: edtfFromOSM, + label: label, + }); + } + + fixes.push(...alternatives.map(alt => new validationIssueFix({ + title: t.append('issues.fix.reformat_date.title', { date: alt.label }), + onClick: function(context) { + context.perform(function(graph) { + var entityInGraph = graph.hasEntity(entity.id); + if (!entityInGraph) return graph; + var newTags = Object.assign({}, entityInGraph.tags); + if (alt.date) { + newTags[key] = alt.date; + } else { + delete newTags[key]; + } + newTags[key + ':edtf'] = alt.edtf; + return actionChangeTags(entityInGraph.id, newTags)(graph); + }, t('issues.fix.reformat_date.annotation')); + } + }))); + fixes.push(new validationIssueFix({ icon: 'iD-operation-delete', title: t.append('issues.fix.remove_tag.title'), @@ -66,6 +137,7 @@ export function validationFormatting() { }, t('issues.fix.remove_tag.annotation')); } })); + return fixes; } }));