From 805becfe3b902bd52b8a1e3026351886d89ba807 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Thu, 25 May 2023 18:05:36 +0200 Subject: [PATCH] support `no` and "other" states of options of multiCombo/manyCombo fields closes https://github.com/openstreetmap/id-tagging-schema/issues/895 and #7427 --- CHANGELOG.md | 2 ++ css/80_app.css | 6 ++++++ modules/ui/fields/combo.js | 40 ++++++++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa2784e66..59fb1f624 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ _Breaking developer changes, which may affect downstream projects or sites that # Unreleased (2.26.0-dev) #### :tada: New Features +* Combo fields for tags with `yes/no` values now correctly display the `no` state and allow to toggle between the two states ([#7427]) #### :sparkles: Usability & Accessibility * Make it easier to search for OSM objects by id ([#9520], thanks [@k-yle]) #### :scissors: Operations @@ -65,6 +66,7 @@ _Breaking developer changes, which may affect downstream projects or sites that * Bundle `package-lock.json` file in repository for faster `clean-install` builds * Build icons from configured presets source and also process field value `icons` in `npm run build:data` +[#7427]: https://github.com/openstreetmap/iD/issues/7427 [#9482]: https://github.com/openstreetmap/iD/pull/9482 [#9483]: https://github.com/openstreetmap/iD/pull/9483 [#9492]: https://github.com/openstreetmap/iD/pull/9492 diff --git a/css/80_app.css b/css/80_app.css index 738d3a268..72c0545b6 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1676,6 +1676,12 @@ input.date-selector { max-width: 100%; color: #7092ff; } +.form-field-input-multicombo li.chip.negated span { + text-decoration: line-through; +} +.form-field-input-multicombo li.chip input { + width: 1em; +} .ideditor[dir='ltr'] .form-field-input-multicombo li.chip { padding: 2px 0px 2px 5px; } diff --git a/modules/ui/fields/combo.js b/modules/ui/fields/combo.js index 45af9aff8..b3e9975ed 100644 --- a/modules/ui/fields/combo.js +++ b/modules/ui/fields/combo.js @@ -416,6 +416,17 @@ export function uiFieldCombo(field, context) { } + function invertMultikey(d3_event, d) { + d3_event.preventDefault(); + d3_event.stopPropagation(); + var t = {}; + if (_isMulti) { + t[d.key] = _tags[d.key] === 'yes' ? 'no' : 'yes'; + } + dispatch.call('change', this, t); + } + + function combo(selection) { _container = selection.selectAll('.form-field-input-wrap') .data([0]); @@ -455,6 +466,11 @@ export function uiFieldCombo(field, context) { .attr('class', 'input-wrap') .merge(_inputWrap); + // Hide 'Add' button if this field uses fixed set of + // options and they're all currently used + var hideAdd = (!_allowCustomValues && !_comboData.length); + _inputWrap.style('display', hideAdd ? 'none' : null); + _input = _inputWrap.selectAll('input') .data([0]); } else { @@ -557,13 +573,13 @@ export function uiFieldCombo(field, context) { if (!field.key && field.keys.indexOf(k) === -1) continue; var v = tags[k]; - if (!v || (typeof v === 'string' && v.toLowerCase() === 'no')) continue; var suffix = field.key ? k.slice(field.key.length) : k; _multiData.push({ key: k, value: displayValue(suffix), display: renderValue(suffix), + state: typeof v === 'string' ? v.toLowerCase() : '', isMixed: Array.isArray(v) }); } @@ -623,7 +639,7 @@ export function uiFieldCombo(field, context) { maxLength = Math.max(0, maxLength); // Hide 'Add' button if this field is already at its character limit - var hideAdd = maxLength <= 0; + var hideAdd = maxLength <= 0 || (!_allowCustomValues && !_comboData.length); _container.selectAll('.chiplist .input-wrap') .style('display', hideAdd ? 'none' : null); @@ -656,8 +672,24 @@ export function uiFieldCombo(field, context) { return d.isMixed; }) .attr('title', function(d) { - return d.isMixed ? t('inspector.unshared_value_tooltip') : null; - }); + if (d.isMixed) { + return t('inspector.unshared_value_tooltip'); + } + if (!['yes', 'no'].includes(d.state)) { + return d.state; + } + return null; + }) + .classed('negated', d => d.state === 'no'); + + if (!_isSemi) { + chips.selectAll('input[type=checkbox]').remove(); + chips.insert('input', 'span') + .attr('type', 'checkbox') + .property('checked', d => d.state === 'yes') + .property('indeterminate', d => d.isMixed || !['yes', 'no'].includes(d.state)) + .on('click', invertMultikey); + } if (allowDragAndDrop) { registerDragAndDrop(chips);