From d7cbf058eee030407be3bbe1c9cfa57c3db97a14 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 9 Dec 2022 13:02:10 +0100 Subject: [PATCH 1/7] make cycleway field modular (i.e. accept any supplied `keys`) --- modules/ui/fields/cycleway.js | 43 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/modules/ui/fields/cycleway.js b/modules/ui/fields/cycleway.js index 1cd94e747..8b2102745 100644 --- a/modules/ui/fields/cycleway.js +++ b/modules/ui/fields/cycleway.js @@ -36,7 +36,7 @@ export function uiFieldCycleway(field, context) { .attr('class', 'rows') .merge(div); - var keys = ['cycleway:left', 'cycleway:right']; + var keys = field.keys.slice(1); items = div.selectAll('li') .data(keys); @@ -78,13 +78,15 @@ export function uiFieldCycleway(field, context) { var newValue = context.cleanTagValue(utilGetSetValue(d3_select(this))); + const commonKey = field.keys[0]; + // don't override multiple values with blank string - if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return; + if (!newValue && (Array.isArray(_tags[commonKey]) || Array.isArray(_tags[key]))) return; if (newValue === 'none' || newValue === '') { newValue = undefined; } - var otherKey = key === 'cycleway:left' ? 'cycleway:right' : 'cycleway:left'; - var otherValue = typeof _tags.cycleway === 'string' ? _tags.cycleway : _tags[otherKey]; + const otherKey = key === field.keys[1] ? field.keys[2] : field.keys[1]; + let otherValue = typeof _tags[commonKey] === 'string' ? _tags[commonKey] : _tags[otherKey]; if (otherValue && Array.isArray(otherValue)) { // we must always have an explicit value for comparison otherValue = otherValue[0]; @@ -93,19 +95,14 @@ export function uiFieldCycleway(field, context) { var tag = {}; - // If the left and right tags match, use the cycleway tag to tag both - // sides the same way + // If the left and right tags match, use the common tag to tag both sides the same way if (newValue === otherValue) { - tag = { - cycleway: newValue, - 'cycleway:left': undefined, - 'cycleway:right': undefined - }; + tag[commonKey] = newValue; + tag[key] = undefined; + tag[otherKey] = undefined; } else { // Always set both left and right as changing one can affect the other - tag = { - cycleway: undefined - }; + tag[commonKey] = undefined; tag[key] = newValue; tag[otherKey] = otherValue; } @@ -128,18 +125,20 @@ export function uiFieldCycleway(field, context) { cycleway.tags = function(tags) { _tags = tags; - // If cycleway is set, use that instead of individual values - var commonValue = typeof tags.cycleway === 'string' && tags.cycleway; + const commonKey = field.keys[0]; + + // If generic key is set, use that instead of individual values + var commonValue = typeof tags[commonKey] === 'string' && tags[commonKey]; utilGetSetValue(items.selectAll('.preset-input-cycleway'), function(d) { if (commonValue) return commonValue; - return !tags.cycleway && typeof tags[d] === 'string' ? tags[d] : ''; + return !tags[commonKey] && typeof tags[d] === 'string' ? tags[d] : ''; }) .attr('title', function(d) { - if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) { + if (Array.isArray(tags[commonKey]) || Array.isArray(tags[d])) { var vals = []; - if (Array.isArray(tags.cycleway)) { - vals = vals.concat(tags.cycleway); + if (Array.isArray(tags[commonKey])) { + vals = vals.concat(tags[commonKey]); } if (Array.isArray(tags[d])) { vals = vals.concat(tags[d]); @@ -149,13 +148,13 @@ export function uiFieldCycleway(field, context) { return null; }) .attr('placeholder', function(d) { - if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) { + if (Array.isArray(tags[commonKey]) || Array.isArray(tags[d])) { return t('inspector.multiple_values'); } return field.placeholder(); }) .classed('mixed', function(d) { - return Array.isArray(tags.cycleway) || Array.isArray(tags[d]); + return Array.isArray(tags[commonKey]) || Array.isArray(tags[d]); }); }; From 80d3e767ccac043d58e1b01211ba4b5c3c2dd949 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 9 Dec 2022 13:52:57 +0100 Subject: [PATCH 2/7] rename to "directional combo" field --- css/80_app.css | 4 +-- .../{cycleway.js => directional_combo.js} | 36 ++++++++++--------- modules/ui/fields/index.js | 7 ++-- 3 files changed, 25 insertions(+), 22 deletions(-) rename modules/ui/fields/{cycleway.js => directional_combo.js} (76%) diff --git a/css/80_app.css b/css/80_app.css index 4d5984c02..de9ea0a8c 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1551,10 +1551,10 @@ a.hide-toggle { } -/* Field - Access, Cycleway +/* Field - Access, DirectionalCombo ------------------------------------------------------- */ .form-field-input-access, -.form-field-input-cycleway { +.form-field-input-directionalcombo { flex: 1 1 auto; display: flex; flex-flow: row wrap; diff --git a/modules/ui/fields/cycleway.js b/modules/ui/fields/directional_combo.js similarity index 76% rename from modules/ui/fields/cycleway.js rename to modules/ui/fields/directional_combo.js index 8b2102745..fe99f7346 100644 --- a/modules/ui/fields/cycleway.js +++ b/modules/ui/fields/directional_combo.js @@ -6,13 +6,13 @@ import { utilGetSetValue, utilNoAuto, utilRebind } from '../../util'; import { t } from '../../core/localizer'; -export function uiFieldCycleway(field, context) { +export function uiFieldDirectionalCombo(field, context) { var dispatch = d3_dispatch('change'); var items = d3_select(null); var wrap = d3_select(null); var _tags; - function cycleway(selection) { + function directionalCombo(selection) { function stripcolon(s) { return s.replace(':', ''); @@ -43,32 +43,32 @@ export function uiFieldCycleway(field, context) { var enter = items.enter() .append('li') - .attr('class', function(d) { return 'labeled-input preset-cycleway-' + stripcolon(d); }); + .attr('class', function(d) { return 'labeled-input preset-directionalcombo-' + stripcolon(d); }); enter .append('span') - .attr('class', 'label preset-label-cycleway') - .attr('for', function(d) { return 'preset-input-cycleway-' + stripcolon(d); }) + .attr('class', 'label preset-label-directionalcombo') + .attr('for', function(d) { return 'preset-input-directionalcombo-' + stripcolon(d); }) .html(function(d) { return field.t.html('types.' + d); }); enter .append('div') - .attr('class', 'preset-input-cycleway-wrap') + .attr('class', 'preset-input-directionalcombo-wrap') .append('input') .attr('type', 'text') - .attr('class', function(d) { return 'preset-input-cycleway preset-input-' + stripcolon(d); }) + .attr('class', function(d) { return 'preset-input-directionalcombo preset-input-' + stripcolon(d); }) .call(utilNoAuto) .each(function(d) { d3_select(this) - .call(uiCombobox(context, 'cycleway-' + stripcolon(d)) - .data(cycleway.options(d)) + .call(uiCombobox(context, 'directionalcombo-' + stripcolon(d)) + .data(directionalCombo.options(d)) ); }); items = items.merge(enter); // Update - wrap.selectAll('.preset-input-cycleway') + wrap.selectAll('.preset-input-directionalcombo') .on('change', change) .on('blur', change); } @@ -111,18 +111,20 @@ export function uiFieldCycleway(field, context) { } - cycleway.options = function() { + directionalCombo.options = function() { var stringsField = field.resolveReference('stringsCrossReference'); return field.options.map(function(option) { + const hasTitle = stringsField.hasTextForStringId('options.' + option + '.title'); + const hasDescription = stringsField.hasTextForStringId('options.' + option + '.description') return { - title: stringsField.t('options.' + option + '.description'), - value: option + title: hasDescription ? stringsField.t('options.' + option + '.description') : null, + value: hasTitle ? stringsField.t('options.' + option + '.title') : stringsField.t('options.' + option) }; }); }; - cycleway.tags = function(tags) { + directionalCombo.tags = function(tags) { _tags = tags; const commonKey = field.keys[0]; @@ -130,7 +132,7 @@ export function uiFieldCycleway(field, context) { // If generic key is set, use that instead of individual values var commonValue = typeof tags[commonKey] === 'string' && tags[commonKey]; - utilGetSetValue(items.selectAll('.preset-input-cycleway'), function(d) { + utilGetSetValue(items.selectAll('.preset-input-directionalcombo'), function(d) { if (commonValue) return commonValue; return !tags[commonKey] && typeof tags[d] === 'string' ? tags[d] : ''; }) @@ -159,11 +161,11 @@ export function uiFieldCycleway(field, context) { }; - cycleway.focus = function() { + directionalCombo.focus = function() { var node = wrap.selectAll('input').node(); if (node) node.focus(); }; - return utilRebind(cycleway, dispatch, 'on'); + return utilRebind(directionalCombo, dispatch, 'on'); } diff --git a/modules/ui/fields/index.js b/modules/ui/fields/index.js index 2c289641b..73733044b 100644 --- a/modules/ui/fields/index.js +++ b/modules/ui/fields/index.js @@ -3,7 +3,7 @@ export * from './combo'; export * from './input'; export * from './access'; export * from './address'; -export * from './cycleway'; +export * from './directional_combo'; export * from './lanes'; export * from './localized'; export * from './roadheight'; @@ -46,7 +46,7 @@ import { import { uiFieldAccess } from './access'; import { uiFieldAddress } from './address'; -import { uiFieldCycleway } from './cycleway'; +import { uiFieldDirectionalCombo } from './directional_combo'; import { uiFieldLanes } from './lanes'; import { uiFieldLocalized } from './localized'; import { uiFieldRoadheight } from './roadheight'; @@ -62,8 +62,9 @@ export var uiFields = { check: uiFieldCheck, colour: uiFieldColour, combo: uiFieldCombo, - cycleway: uiFieldCycleway, + cycleway: uiFieldDirectionalCombo, defaultCheck: uiFieldDefaultCheck, + directionalCombo: uiFieldDirectionalCombo, email: uiFieldEmail, identifier: uiFieldIdentifier, lanes: uiFieldLanes, From 08ae8a3fac098942af8aad1fc27a97a4b3bed612 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 9 Dec 2022 16:53:08 +0100 Subject: [PATCH 3/7] reuse combo field module from within directional_combo reducing duplication of code, and brings missing features to the directional version of the field --- modules/ui/fields/directional_combo.js | 80 +++++++------------------- 1 file changed, 22 insertions(+), 58 deletions(-) diff --git a/modules/ui/fields/directional_combo.js b/modules/ui/fields/directional_combo.js index fe99f7346..6ecf26853 100644 --- a/modules/ui/fields/directional_combo.js +++ b/modules/ui/fields/directional_combo.js @@ -1,9 +1,9 @@ import { dispatch as d3_dispatch } from 'd3-dispatch'; import { select as d3_select } from 'd3-selection'; -import { uiCombobox } from '../combobox'; import { utilGetSetValue, utilNoAuto, utilRebind } from '../../util'; import { t } from '../../core/localizer'; +import { uiFieldCombo } from './combo'; export function uiFieldDirectionalCombo(field, context) { @@ -12,6 +12,8 @@ export function uiFieldDirectionalCombo(field, context) { var wrap = d3_select(null); var _tags; + var _combos = {}; + function directionalCombo(selection) { function stripcolon(s) { @@ -53,16 +55,17 @@ export function uiFieldDirectionalCombo(field, context) { enter .append('div') - .attr('class', 'preset-input-directionalcombo-wrap') - .append('input') - .attr('type', 'text') - .attr('class', function(d) { return 'preset-input-directionalcombo preset-input-' + stripcolon(d); }) - .call(utilNoAuto) - .each(function(d) { - d3_select(this) - .call(uiCombobox(context, 'directionalcombo-' + stripcolon(d)) - .data(directionalCombo.options(d)) - ); + .attr('class', 'preset-input-directionalcombo-wrap form-field-input-wrap') + .each(function(key) { + const subField = { + ...field, + type: 'combo', + key + }; + const combo = uiFieldCombo(subField, context); + combo.on('change', t => change(key, t[key])); + _combos[key] = combo; + d3_select(this).call(combo); }); items = items.merge(enter); @@ -74,10 +77,7 @@ export function uiFieldDirectionalCombo(field, context) { } - function change(d3_event, key) { - - var newValue = context.cleanTagValue(utilGetSetValue(d3_select(this))); - + function change(key, newValue) { const commonKey = field.keys[0]; // don't override multiple values with blank string @@ -111,53 +111,17 @@ export function uiFieldDirectionalCombo(field, context) { } - directionalCombo.options = function() { - var stringsField = field.resolveReference('stringsCrossReference'); - return field.options.map(function(option) { - const hasTitle = stringsField.hasTextForStringId('options.' + option + '.title'); - const hasDescription = stringsField.hasTextForStringId('options.' + option + '.description') - return { - title: hasDescription ? stringsField.t('options.' + option + '.description') : null, - value: hasTitle ? stringsField.t('options.' + option + '.title') : stringsField.t('options.' + option) - }; - }); - }; - - directionalCombo.tags = function(tags) { _tags = tags; const commonKey = field.keys[0]; - - // If generic key is set, use that instead of individual values - var commonValue = typeof tags[commonKey] === 'string' && tags[commonKey]; - - utilGetSetValue(items.selectAll('.preset-input-directionalcombo'), function(d) { - if (commonValue) return commonValue; - return !tags[commonKey] && typeof tags[d] === 'string' ? tags[d] : ''; - }) - .attr('title', function(d) { - if (Array.isArray(tags[commonKey]) || Array.isArray(tags[d])) { - var vals = []; - if (Array.isArray(tags[commonKey])) { - vals = vals.concat(tags[commonKey]); - } - if (Array.isArray(tags[d])) { - vals = vals.concat(tags[d]); - } - return vals.filter(Boolean).join('\n'); - } - return null; - }) - .attr('placeholder', function(d) { - if (Array.isArray(tags[commonKey]) || Array.isArray(tags[d])) { - return t('inspector.multiple_values'); - } - return field.placeholder(); - }) - .classed('mixed', function(d) { - return Array.isArray(tags[commonKey]) || Array.isArray(tags[d]); - }); + for (let key in _combos) { + const uniqueValues = [... new Set([] + .concat(tags[commonKey]) + .concat(tags[key]) + .filter(Boolean))]; + _combos[key].tags({ [key]: uniqueValues.length > 1 ? uniqueValues : uniqueValues[0] }); + } }; From 4c222fde0a39db525067411e763d7a70908b4a6a Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 9 Dec 2022 19:01:17 +0100 Subject: [PATCH 4/7] make sure editing multi selection doesn't corrupt tags because the common tag vs. left/right tag situation can be different for different entities in the multiselection, the approach to merge/split/update the tags needs to be made on a per entity basis this introduces a new way to specify tag changes: a callback function which is called for each to be modified entity --- modules/ui/entity_editor.js | 21 +++++++----- modules/ui/fields/directional_combo.js | 46 ++++++++++---------------- 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/modules/ui/entity_editor.js b/modules/ui/entity_editor.js index 435d2b37d..ba2956ab3 100644 --- a/modules/ui/entity_editor.js +++ b/modules/ui/entity_editor.js @@ -163,14 +163,19 @@ export function uiEntityEditor(context) { var tags = Object.assign({}, entity.tags); // shallow copy - for (var k in changed) { - if (!k) continue; - var v = changed[k]; - if (typeof v === 'object') { - // a "key only" tag change - tags[k] = tags[v.oldKey]; - } else if (v !== undefined || tags.hasOwnProperty(k)) { - tags[k] = v; + if (typeof changed === 'function') { + // a complex callback tag change + tags = changed(tags); + } else { + for (var k in changed) { + if (!k) continue; + var v = changed[k]; + if (typeof v === 'object') { + // a "key only" tag change + tags[k] = tags[v.oldKey]; + } else if (v !== undefined || tags.hasOwnProperty(k)) { + tags[k] = v; + } } } diff --git a/modules/ui/fields/directional_combo.js b/modules/ui/fields/directional_combo.js index 6ecf26853..c64d432d3 100644 --- a/modules/ui/fields/directional_combo.js +++ b/modules/ui/fields/directional_combo.js @@ -79,35 +79,23 @@ export function uiFieldDirectionalCombo(field, context) { function change(key, newValue) { const commonKey = field.keys[0]; - - // don't override multiple values with blank string - if (!newValue && (Array.isArray(_tags[commonKey]) || Array.isArray(_tags[key]))) return; - - if (newValue === 'none' || newValue === '') { newValue = undefined; } - const otherKey = key === field.keys[1] ? field.keys[2] : field.keys[1]; - let otherValue = typeof _tags[commonKey] === 'string' ? _tags[commonKey] : _tags[otherKey]; - if (otherValue && Array.isArray(otherValue)) { - // we must always have an explicit value for comparison - otherValue = otherValue[0]; - } - if (otherValue === 'none' || otherValue === '') { otherValue = undefined; } - var tag = {}; - - // If the left and right tags match, use the common tag to tag both sides the same way - if (newValue === otherValue) { - tag[commonKey] = newValue; - tag[key] = undefined; - tag[otherKey] = undefined; - } else { - // Always set both left and right as changing one can affect the other - tag[commonKey] = undefined; - tag[key] = newValue; - tag[otherKey] = otherValue; - } - - dispatch.call('change', this, tag); + dispatch.call('change', this, tags => { + const otherValue = tags[otherKey] || tags[commonKey]; + if (newValue === otherValue) { + // both tags match, use the common tag to tag both sides the same way + tags[commonKey] = newValue; + delete tags[key]; + delete tags[otherKey]; + } else { + // Always set both left and right as changing one can affect the other + tags[key] = newValue; + delete tags[commonKey]; + tags[otherKey] = otherValue; + } + return tags; + }); } @@ -117,8 +105,8 @@ export function uiFieldDirectionalCombo(field, context) { const commonKey = field.keys[0]; for (let key in _combos) { const uniqueValues = [... new Set([] - .concat(tags[commonKey]) - .concat(tags[key]) + .concat(_tags[commonKey]) + .concat(_tags[key]) .filter(Boolean))]; _combos[key].tags({ [key]: uniqueValues.length > 1 ? uniqueValues : uniqueValues[0] }); } From 479586be37ba7a106b70626605e55f9f6c865484 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Fri, 9 Dec 2022 19:34:13 +0100 Subject: [PATCH 5/7] combo boxes can consume complex label strings now: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit instead of `"strings": { "options": { "": "", …` it is now also supported to have: ``` "strings": { "options": { "": { "title": "", "description": "" }, … ``` --- modules/ui/fields/combo.js | 39 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/modules/ui/fields/combo.js b/modules/ui/fields/combo.js index 7cdfa43e7..827a5d9f8 100644 --- a/modules/ui/fields/combo.js +++ b/modules/ui/fields/combo.js @@ -121,8 +121,9 @@ export function uiFieldCombo(field, context) { tval = tval || ''; var stringsField = field.resolveReference('stringsCrossReference'); - if (stringsField.hasTextForStringId('options.' + tval)) { - return stringsField.t('options.' + tval, { default: tval }); + const labelId = stringsField.hasTextForStringId(`options.${tval}.title`) ? `options.${tval}.title` : `options.${tval}`; + if (stringsField.hasTextForStringId(labelId)) { + return stringsField.t(labelId, { default: tval }); } if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') { @@ -139,8 +140,9 @@ export function uiFieldCombo(field, context) { tval = tval || ''; var stringsField = field.resolveReference('stringsCrossReference'); - if (stringsField.hasTextForStringId('options.' + tval)) { - return stringsField.t.append('options.' + tval, { default: tval }); + const labelId = stringsField.hasTextForStringId(`options.${tval}.title`) ? `options.${tval}.title` : `options.${tval}`; + if (stringsField.hasTextForStringId(labelId)) { + return stringsField.t(labelId, { default: tval }); } if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') { @@ -184,12 +186,14 @@ export function uiFieldCombo(field, context) { if (!(field.options || stringsField.options)) return []; return (field.options || stringsField.options).map(function(v) { + const labelId = stringsField.hasTextForStringId(`options.${v}.title`) ? `options.${v}.title` : `options.${v}`; + const hasDescription = stringsField.hasTextForStringId(`options.${v}.description`); return { key: v, - value: stringsField.t('options.' + v, { default: v }), - title: v, - display: addComboboxIcons(stringsField.t.append('options.' + v, { default: v }), v), - klass: stringsField.hasTextForStringId('options.' + v) ? '' : 'raw-option' + value: stringsField.t(labelId, { default: v }), + title: stringsField.t(`options.${v}.description`, { default: v }), + display: addComboboxIcons(stringsField.t.append(labelId, { default: v }), v), + klass: stringsField.hasTextForStringId(labelId) ? '' : 'raw-option' }; }); } @@ -266,15 +270,17 @@ export function uiFieldCombo(field, context) { _container.classed('empty-combobox', data.length === 0); _comboData = data.concat(additionalOptions).map(function(d) { - var k = d.value; - if (_isMulti) k = k.replace(field.key, ''); - var isLocalizable = stringsField.hasTextForStringId('options.' + k); - var label = stringsField.t('options.' + k, { default: k }); + var v = d.value; + if (_isMulti) v = v.replace(field.key, ''); + const labelId = stringsField.hasTextForStringId(`options.${v}.title`) ? `options.${v}.title` : `options.${v}`; + var isLocalizable = stringsField.hasTextForStringId(labelId); + var label = stringsField.t(labelId, { default: v }); return { - key: k, + key: v, value: label, - display: addComboboxIcons(stringsField.t.append('options.' + k, { default: k }), k), - title: isLocalizable ? k : (d.title !== label ? d.title : ''), + title: stringsField.t(`options.${v}.description`, { default: + isLocalizable ? v : (d.title !== label ? d.title : '') }), + display: addComboboxIcons(stringsField.t.append(labelId, { default: v }), v), klass: isLocalizable ? '' : 'raw-option' }; }); @@ -684,7 +690,8 @@ export function uiFieldCombo(field, context) { }).filter(Boolean); var showsValue = !isMixed && tags[field.key] && !(field.type === 'typeCombo' && tags[field.key] === 'yes'); - var isRawValue = showsValue && !stringsField.hasTextForStringId('options.' + tags[field.key]); + var isRawValue = showsValue && !stringsField.hasTextForStringId(`options.${tags[field.key]}`) + && !stringsField.hasTextForStringId(`options.${tags[field.key]}.title`); var isKnownValue = showsValue && !isRawValue; var isReadOnly = !_allowCustomValues || isKnownValue; From 89afee1ad58b96f36fd268c7ff3768ea183ee33a Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Mon, 12 Dec 2022 16:11:15 +0100 Subject: [PATCH 6/7] lint code --- modules/ui/fields/combo.js | 16 +++++++++++----- modules/ui/fields/directional_combo.js | 3 +-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/modules/ui/fields/combo.js b/modules/ui/fields/combo.js index 827a5d9f8..b343aa293 100644 --- a/modules/ui/fields/combo.js +++ b/modules/ui/fields/combo.js @@ -115,13 +115,20 @@ export function uiFieldCombo(field, context) { } + function getLabelId(field, v) { + return field.hasTextForStringId(`options.${v}.title`) + ? `options.${v}.title` + : `options.${v}`; + } + + // returns the display value for a tag value // (for multiCombo, tval should be the key suffix, not the entire key) function displayValue(tval) { tval = tval || ''; var stringsField = field.resolveReference('stringsCrossReference'); - const labelId = stringsField.hasTextForStringId(`options.${tval}.title`) ? `options.${tval}.title` : `options.${tval}`; + const labelId = getLabelId(stringsField, tval); if (stringsField.hasTextForStringId(labelId)) { return stringsField.t(labelId, { default: tval }); } @@ -140,7 +147,7 @@ export function uiFieldCombo(field, context) { tval = tval || ''; var stringsField = field.resolveReference('stringsCrossReference'); - const labelId = stringsField.hasTextForStringId(`options.${tval}.title`) ? `options.${tval}.title` : `options.${tval}`; + const labelId = getLabelId(stringsField, tval); if (stringsField.hasTextForStringId(labelId)) { return stringsField.t(labelId, { default: tval }); } @@ -186,8 +193,7 @@ export function uiFieldCombo(field, context) { if (!(field.options || stringsField.options)) return []; return (field.options || stringsField.options).map(function(v) { - const labelId = stringsField.hasTextForStringId(`options.${v}.title`) ? `options.${v}.title` : `options.${v}`; - const hasDescription = stringsField.hasTextForStringId(`options.${v}.description`); + const labelId = getLabelId(stringsField, v); return { key: v, value: stringsField.t(labelId, { default: v }), @@ -272,7 +278,7 @@ export function uiFieldCombo(field, context) { _comboData = data.concat(additionalOptions).map(function(d) { var v = d.value; if (_isMulti) v = v.replace(field.key, ''); - const labelId = stringsField.hasTextForStringId(`options.${v}.title`) ? `options.${v}.title` : `options.${v}`; + const labelId = getLabelId(stringsField, v); var isLocalizable = stringsField.hasTextForStringId(labelId); var label = stringsField.t(labelId, { default: v }); return { diff --git a/modules/ui/fields/directional_combo.js b/modules/ui/fields/directional_combo.js index c64d432d3..91a280789 100644 --- a/modules/ui/fields/directional_combo.js +++ b/modules/ui/fields/directional_combo.js @@ -1,8 +1,7 @@ import { dispatch as d3_dispatch } from 'd3-dispatch'; import { select as d3_select } from 'd3-selection'; -import { utilGetSetValue, utilNoAuto, utilRebind } from '../../util'; -import { t } from '../../core/localizer'; +import { utilRebind } from '../../util'; import { uiFieldCombo } from './combo'; From 9f1139ff9c16ac91a759cd886a41dd2a88977dae Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Mon, 12 Dec 2022 22:26:14 +0100 Subject: [PATCH 7/7] add to changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2eea7376a..d082a3ce2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,11 +43,13 @@ _Breaking developer changes, which may affect downstream projects or sites that #### :white_check_mark: Validation #### :bug: Bugfixes * Fix bug which made it impossible to change an object's preset from a sub-preset to the respective parents preset (e.g. from Driveway to Service Road) ([#9372]) +* Fix corruption of (directional) `cycleway` tags when editing a multi-selection ([#9423]) #### :hourglass: Performance #### :rocket: Presets * Clamp degree values in `direction` fields between 0 and 359 degrees ([#9386]) * Disable increment/decrement buttons on number fields if the input value is not numeric or when there is a multi-selection with conflicting values * Filter out misspelled taginfo suggestions in combo field ([#9397]) +* Rename `cycleway` field type to `directionalCombo` and make it reusable for arbitrary directional tags ([#9423]) #### :hammer: Development * Upgrade to Transifex API v3 ([#9375]) * Upgrade dependencies: `d3` to v7.7 @@ -60,6 +62,7 @@ _Breaking developer changes, which may affect downstream projects or sites that [#9390]: https://github.com/openstreetmap/iD/pull/9390 [#9392]: https://github.com/openstreetmap/iD/pull/9392 [#9397]: https://github.com/openstreetmap/iD/issues/9397 +[#9423]: https://github.com/openstreetmap/iD/pull/9423 [@alanb43]: https://github.com/alanb43