Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EDTF start and end date fields #187

Merged
merged 5 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
14 changes: 14 additions & 0 deletions data/core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,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 @@ -1844,10 +1847,21 @@ en:
message_start: '{feature} has an invalid start date'
message_end: '{feature} has an invalid end date'
reference: 'A date must be formatted as YYYY-MM-DD, YYYY-MM, or YYYY.'
edtf:
message_start: '{feature} has an invalid EDTF start date'
message_end: '{feature} has an invalid EDTF end date'
reference: 'There is an unexpected "{token}" at character {position}.'
line_as_area:
message: '{feature} should be a line, not an area'
line_as_point:
message: '{feature} should be a line, not a point'
mismatched_dates:
title: Mismatched Dates
tip: Find dates that are contradictory or anachronistic
edtf:
message_start: '{feature} has a start date that falls outside of the EDTF start date'
message_end: '{feature} has an end date that falls outside of the EDTF end date'
reference: 'The basic date value should overlap with the range of possible dates described by the EDTF date.'
mismatched_geometry:
title: Mismatched Geometry
tip: "Find features with conflicting tags and geometry"
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
1 change: 1 addition & 0 deletions modules/validations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { validationHelpRequest } from './help_request';
export { validationImpossibleOneway } from './impossible_oneway';
export { validationIncompatibleSource } from './incompatible_source';
export { validationMaprules } from './maprules';
export { validationMismatchedDates } from './mismatched_dates';
export { validationMismatchedGeometry } from './mismatched_geometry';
export { validationMissingRole } from './missing_role';
export { validationMissingTag } from './missing_tag';
Expand Down
Loading
Loading