Skip to content

Commit

Permalink
Reimplemented EDTF dates as part of date field
Browse files Browse the repository at this point in the history
Removed the separate fields for the start_date:edtf and end_date:edtf keys in favor of extending the date field type to manage *:edtf subkeys in the same manner that a localized field type manages language subkeys.
  • Loading branch information
1ec5 committed Dec 17, 2023
1 parent eddb334 commit 6aa4293
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 38 deletions.
25 changes: 17 additions & 8 deletions css/80_app.css
Original file line number Diff line number Diff line change
Expand Up @@ -1996,18 +1996,20 @@ a.hide-toggle {
}


/* Field - Localized Name
/* Field - Localized Name, Date
------------------------------------------------------- */
.form-field-input-localized > input.localized-main {
border-radius: 0 0 0 4px;
}
.ideditor[dir='rtl'] .form-field-input-localized > input.localized-main {
border-radius: 0 0 4px 0;
}
.form-field-input-localized > button.localized-add {
.form-field-input-localized > button.localized-add,
.form-field-input-date > button.date-add {
border-radius: 0 0 4px 0;
}
.ideditor[dir='rtl'] .form-field-input-localized > button.localized-add {
.ideditor[dir='rtl'] .form-field-input-localized > button.localized-add,
.ideditor[dir='rtl'] .form-field-input-date > button.date-add {
border-radius: 0 0 0 4px;
}

Expand All @@ -2020,18 +2022,21 @@ a.hide-toggle {
cursor: not-allowed;
}

/* nested subfields for name in different languages */
.localized-multilingual {
/* nested subfields for name in different languages or date in different formats */
.localized-multilingual,
.date-edtf {
padding: 0 10px;
flex-basis: 100%;
}
.localized-multilingual .entry {
.localized-multilingual .entry,
.date-edtf .entry {
position: relative;
overflow: hidden;
}

/* draws a little line connecting the multilingual field up to the name field */
.localized-multilingual .entry::before {
.localized-multilingual .entry::before,
.date-edtf .entry::before {
content: "";
display: block;
position: absolute;
Expand All @@ -2049,7 +2054,8 @@ a.hide-toggle {
border-top-width: 0;
width: 100%;
}
.localized-multilingual .entry .localized-value {
.localized-multilingual .entry .localized-value,
.date-edtf .entry .date-value {
border-top-width: 0;
border-radius: 0 0 4px 4px;
width: 100%;
Expand All @@ -2062,6 +2068,9 @@ a.hide-toggle {
.ideditor .form-field-input-date > .combobox-caret + input.date-main {
border-left: 0;
}
.ideditor .form-field-input-date > input.date-main:last-of-type {
border-radius: 0;
}


/* Field - Address
Expand Down
11 changes: 3 additions & 8 deletions data/core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,9 @@ en:
month: Month
# placeholder for day of the month
day: Day
edtf: Add EDTF date
edtf_label: Extended Date/Time Format
edtf_placeholder: 1849~, 1804?, 189X, 1906/1908, 1814-23, 1960-05-01T13:00...
max_length_reached: "This string is longer than the maximum length of {maxChars} characters. Anything exceeding that length will be truncated."
background:
title: Background
Expand Down Expand Up @@ -2461,14 +2464,6 @@ en:
label: End Date
placeholder: YYYY-MM-DD
terms: abandoned, destruction, destroyed, demolition, demolished, closed, closure
start_date/edtf:
label: Start Date (EDTF)
placeholder: 1849~, 1804?, 189X, 1906/1908, 1814-23, 1960-05-01T13:00...
terms: edtf, extended, uncertain, approximate, season, time
end_date/edtf:
label: End Date (EDTF)
placeholder: 1871~, 1804?, 196X, 1840/1845, 1940-24, 2011-10-04T05:00...
terms: edtf, extended, uncertain, approximate, season, time
license:
label: License
placeholder: CC0
Expand Down
18 changes: 0 additions & 18 deletions modules/presets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,24 +51,6 @@ function addHistoricalFields(fields) {
key: 'end_date'
};

fields['start_date/edtf'] = {
key: 'start_date/edtf',
type: 'combo',
universal: true,
snake_case: false,
caseSensitive: true,
prerequisiteTag: {
key: 'start_date',
},
};
fields['end_date/edtf'] = {
...fields['start_date/edtf'],
key: 'end_date/edtf',
prerequisiteTag: {
key: 'end_date',
},
};

// A combo box would encourage mappers to choose one of the suggestions, but we want mappers to be as detailed as possible.
fields.source.type = 'text';

Expand Down
197 changes: 194 additions & 3 deletions modules/ui/fields/date.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { select as d3_select } from 'd3-selection';
import * as countryCoder from '@ideditor/country-coder';

import { svgIcon } from '../../svg';
import { uiTooltip } from '../tooltip';
import { uiCombobox } from '../combobox';
import { t, localizer } from '../../core/localizer';
import { utilGetSetValue, utilNoAuto, utilRebind, utilTotalExtent } from '../../util';
import { utilGetSetValue, utilNoAuto, utilRebind, utilUniqueDomId } from '../../util';


export function uiFieldDate(field, context) {
Expand All @@ -13,8 +14,13 @@ export function uiFieldDate(field, context) {
let eraInput = d3_select(null);
let monthInput = d3_select(null);
let dayInput = d3_select(null);
let edtfInput = d3_select(null);
let _entityIDs = [];
let _tags;
let _selection = d3_select(null);
let _edtfValue;

let edtfKey = field.key + ':edtf';

let dateTimeFormat = new Intl.DateTimeFormat(localizer.languageCode(), {
year: 'numeric',
Expand Down Expand Up @@ -100,9 +106,27 @@ export function uiFieldDate(field, context) {
};
}));

let buttonTip = uiTooltip()
.title(() => t.append('inspector.date.edtf'))
.placement('left');


// update _edtfValue
function calcEDTFValue(tags) {
if (_edtfValue && !tags[edtfKey]) {
// Don't unset the variable based on deleted tags, since this makes the UI
// disappear unexpectedly when clearing values - #8164
_edtfValue = '';
} else {
_edtfValue = tags[edtfKey];
}
}


function date(selection) {
_selection = selection;

var wrap = selection.selectAll('.form-field-input-wrap')
let wrap = selection.selectAll('.form-field-input-wrap')
.data([0]);

wrap = wrap.enter()
Expand Down Expand Up @@ -169,6 +193,47 @@ export function uiFieldDate(field, context) {
dayInput
.on('change', change)
.on('blur', change);

if (_tags && _edtfValue === undefined) {
calcEDTFValue(_tags);
}

let edtfButton = wrap.selectAll('.date-add')
.data([0]);

edtfButton = edtfButton.enter()
.append('button')
.attr('class', 'date-add form-field-button')
.attr('aria-label', t('icons.plus'))
.call(svgIcon('#iD-icon-plus'))
.merge(edtfButton);

edtfButton
.classed('disabled', typeof _edtfValue === 'string' || Array.isArray(_edtfValue))
.call(buttonTip)
.on('click', addEDTF);

edtfInput = selection.selectAll('.date-edtf')
.data([0]);

edtfInput = edtfInput.enter()
.append('div')
.attr('class', 'date-edtf')
.merge(edtfInput);

edtfInput
.call(renderEDTF);
}


function addEDTF(d3_event) {
d3_event.preventDefault();

if (typeof _edtfValue !== 'string' && !Array.isArray(_edtfValue)) {
_edtfValue = '';

edtfInput.call(renderEDTF);
}
}


Expand Down Expand Up @@ -210,6 +275,125 @@ export function uiFieldDate(field, context) {
}


function changeEDTFValue(d3_event, d) {
let value = context.cleanTagValue(utilGetSetValue(d3_select(this))) || undefined;

// don't override multiple values with blank string
if (!value && Array.isArray(d.value)) return;

let t = {};
t[edtfKey] = value;
d.value = value;
dispatch.call('change', this, t);
}


function renderEDTF(selection) {
let entries = selection.selectAll('div.entry')
.data((typeof _edtfValue === 'string' || Array.isArray(_edtfValue)) ? [_edtfValue] : []);

entries.exit()
.style('top', '0')
.style('max-height', '240px')
.transition()
.duration(200)
.style('opacity', '0')
.style('max-height', '0px')
.remove();

let entriesEnter = entries.enter()
.append('div')
.attr('class', 'entry')
.each(function() {
var wrap = d3_select(this);

let domId = utilUniqueDomId('edtf');
let label = wrap
.append('label')
.attr('class', 'field-label')
.attr('for', domId);

let text = label
.append('span')
.attr('class', 'label-text');

text
.append('span')
.attr('class', 'label-textvalue')
.call(t.append('inspector.date.edtf_label'));

text
.append('span')
.attr('class', 'label-textannotation');

label
.append('button')
.attr('class', 'remove-icon-edtf')
.attr('title', t('icons.remove'))
.on('click', function(d3_event) {
d3_event.preventDefault();

// remove the UI item manually
_edtfValue = undefined;

if (edtfKey && edtfKey in _tags) {
delete _tags[edtfKey];
// remove from entity tags
let t = {};
t[edtfKey] = undefined;
dispatch.call('change', this, t);
return;
}

renderEDTF(selection);
})
.call(svgIcon('#iD-operation-delete'));

wrap
.append('input')
.attr('type', 'text')
.attr('class', 'date-value')
.on('blur', changeEDTFValue)
.on('change', changeEDTFValue);
});

entriesEnter
.style('margin-top', '0px')
.style('max-height', '0px')
.style('opacity', '0')
.transition()
.duration(200)
.style('margin-top', '10px')
.style('max-height', '240px')
.style('opacity', '1')
.on('end', function() {
d3_select(this)
.style('max-height', '')
.style('overflow', 'visible');
});

entries = entries.merge(entriesEnter);

entries.order();

// allow removing the entry UIs even if there isn't a tag to remove
entries.classed('present', true);

utilGetSetValue(entries.select('.date-value'), function(d) {
return typeof d === 'string' ? d : '';
})
.attr('title', function(d) {
return Array.isArray(d) ? d.filter(Boolean).join('\n') : null;
})
.attr('placeholder', function(d) {
return Array.isArray(d) ? t('inspector.multiple_values') : t('inspector.date.edtf_placeholder');
})
.classed('mixed', function(d) {
return Array.isArray(d);
});
}


date.tags = function(tags) {
_tags = tags;

Expand Down Expand Up @@ -250,6 +434,10 @@ export function uiFieldDate(field, context) {
.attr('placeholder', t('inspector.date.month'));
utilGetSetValue(dayInput, typeof dayValue === 'number' ? dayValue : '')
.attr('placeholder', t('inspector.date.day'));

calcEDTFValue(tags);

_selection.call(date);
};


Expand All @@ -260,7 +448,10 @@ export function uiFieldDate(field, context) {


date.entityIDs = function(val) {
if (!arguments.length) return _entityIDs;
_entityIDs = val;
_edtfValue = undefined;
return date;
};


Expand Down
2 changes: 1 addition & 1 deletion modules/ui/sections/preset_fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function uiSectionPresetFields(context) {
_fieldsArr = [];

// Ideally, everything in OpenHistoricalMap is dated and sourced.
let coreKeys = ['start_date', 'start_date/edtf', 'end_date', 'end_date/edtf', 'source'];
let coreKeys = ['start_date', 'end_date', 'source'];
coreKeys.forEach(key => {
let field = presetsManager.field(key);
if (field) {
Expand Down

0 comments on commit 6aa4293

Please sign in to comment.