diff --git a/data/presets.yaml b/data/presets.yaml index 861a9fd4d..69df4b690 100644 --- a/data/presets.yaml +++ b/data/presets.yaml @@ -1129,7 +1129,7 @@ en: label: Source sport: # sport=* - label: Sport + label: Sports sport_ice: # sport=* label: Sport diff --git a/data/presets/README.md b/data/presets/README.md index 3e9fb6ccf..e45f202ed 100644 --- a/data/presets/README.md +++ b/data/presets/README.md @@ -111,6 +111,8 @@ The complete JSON schema for fields can be found in [`data/presets/schema/field. * `multiCombo` - Dropdown field for adding `yes` values to a common multikey
(e.g. `recycling:*` -> `recycling:glass=yes`, `recycling:paper=yes`, etc.) * `networkCombo` - Dropdown field that helps users pick a route `network` tag (localized for editing location) +* `semiCombo` - Dropdown field for adding multiple values to a semicolon-delimited list
+(e.g. `sport=*` -> `soccer;lacrosse;athletics;field_hockey`) **Checkboxes** * `check` - 3-state checkbox: `yes`, `no`, unknown (no tag) diff --git a/data/presets/fields.json b/data/presets/fields.json index 1d329dea0..ff86c589f 100644 --- a/data/presets/fields.json +++ b/data/presets/fields.json @@ -1524,8 +1524,8 @@ }, "sport": { "key": "sport", - "type": "combo", - "label": "Sport" + "type": "semiCombo", + "label": "Sports" }, "stars": { "key": "stars", diff --git a/data/presets/fields/sport.json b/data/presets/fields/sport.json index cc83a5c07..a3ebb3b70 100644 --- a/data/presets/fields/sport.json +++ b/data/presets/fields/sport.json @@ -1,5 +1,5 @@ { "key": "sport", - "type": "combo", - "label": "Sport" -} \ No newline at end of file + "type": "semiCombo", + "label": "Sports" +} diff --git a/data/presets/schema/field.json b/data/presets/schema/field.json index 3855b644f..92698150b 100644 --- a/data/presets/schema/field.json +++ b/data/presets/schema/field.json @@ -64,6 +64,7 @@ "onewayCheck", "radio", "restrictions", + "semiCombo", "tel", "textarea", "text", diff --git a/dist/locales/en.json b/dist/locales/en.json index e8cc898a0..f3733f4af 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -1692,7 +1692,7 @@ "label": "Sport" }, "sport": { - "label": "Sport" + "label": "Sports" }, "stars": { "label": "Stars" diff --git a/modules/ui/fields/combo.js b/modules/ui/fields/combo.js index 55fcf50ce..1fdb7759c 100644 --- a/modules/ui/fields/combo.js +++ b/modules/ui/fields/combo.js @@ -9,11 +9,11 @@ import { utilRebind } from '../../util'; - export { - uiFieldCombo as uiFieldTypeCombo, uiFieldCombo as uiFieldMultiCombo, - uiFieldCombo as uiFieldNetworkCombo + uiFieldCombo as uiFieldNetworkCombo, + uiFieldCombo as uiFieldSemiCombo, + uiFieldCombo as uiFieldTypeCombo }; @@ -23,10 +23,11 @@ export function uiFieldCombo(field, context) { taginfo = services.taginfo, isMulti = (field.type === 'multiCombo'), isNetwork = (field.type === 'networkCombo'), + isSemi = (field.type === 'semiCombo'), optstrings = field.strings && field.strings.options, optarray = field.options, snake_case = (field.snake_case || (field.snake_case === undefined)), - combobox = d3combobox().minItems(isMulti ? 1 : 2), + combobox = d3combobox().minItems(isMulti || isSemi ? 1 : 2), comboData = [], multiData = [], container, @@ -190,7 +191,7 @@ export function uiFieldCombo(field, context) { function setPlaceholder(d) { var ph; - if (isMulti) { + if (isMulti || isSemi) { ph = field.placeholder() || t('inspector.add'); } else { var vals = _.map(d, 'value').filter(function(s) { return s.length < 20; }), @@ -207,12 +208,18 @@ export function uiFieldCombo(field, context) { var val = tagValue(utilGetSetValue(input)), t = {}; - if (isMulti) { + if (isMulti || isSemi) { if (!val) return; container.classed('active', false); utilGetSetValue(input, ''); - field.keys.push(field.key + val); - t[field.key + val] = 'yes'; + if (isMulti) { + field.keys.push(field.key + val); + t[field.key + val] = 'yes'; + } else if (isSemi) { + var arr = multiData.map(function(d) { return d.key; }); + arr.push(val); + t[field.key] = _.compact(_.uniq(arr)).join(';'); + } window.setTimeout(function() { input.node().focus(); }, 10); } else { @@ -226,13 +233,19 @@ export function uiFieldCombo(field, context) { function removeMultikey(d) { d3.event.stopPropagation(); var t = {}; - t[d.key] = undefined; + if (isMulti) { + t[d.key] = undefined; + } else if (isSemi) { + var arr = multiData.map(function(md) { return md.key; }); + arr = _.compact(_.uniq(_.without(arr, d.key))); + t[field.key] = arr.length ? arr.join(';') : undefined; + } dispatch.call('change', this, t); } function combo(selection) { - if (isMulti) { + if (isMulti || isSemi) { container = selection.selectAll('ul').data([0]); container = container.enter() @@ -269,7 +282,7 @@ export function uiFieldCombo(field, context) { .on('change', change) .on('blur', change); - if (isMulti) { + if (isMulti || isSemi) { combobox .on('accept', function() { input.node().blur(); @@ -283,22 +296,33 @@ export function uiFieldCombo(field, context) { combo.tags = function(tags) { - if (isMulti) { + if (isMulti || isSemi) { multiData = []; - // Build multiData array containing keys already set.. - Object.keys(tags).forEach(function(key) { - if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return; + if (isMulti) { + // Build multiData array containing keys already set.. + Object.keys(tags).forEach(function(key) { + if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return; - var suffix = key.substring(field.key.length); - multiData.push({ - key: key, - value: displayValue(suffix) + var suffix = key.substring(field.key.length); + multiData.push({ + key: key, + value: displayValue(suffix) + }); }); - }); - // Set keys for form-field modified (needed for undo and reset buttons).. - field.keys = _.map(multiData, 'key'); + // Set keys for form-field modified (needed for undo and reset buttons).. + field.keys = _.map(multiData, 'key'); + + } else if (isSemi) { + var arr = _.compact(_.uniq((tags[field.key] || '').split(';'))); + multiData = arr.map(function(key) { + return { + key: key, + value: displayValue(key) + }; + }); + } // Exclude existing multikeys from combo options.. var available = objectDifference(comboData, multiData); diff --git a/modules/ui/fields/index.js b/modules/ui/fields/index.js index 77d55bccd..b92f2bf06 100644 --- a/modules/ui/fields/index.js +++ b/modules/ui/fields/index.js @@ -22,6 +22,7 @@ import { uiFieldCombo, uiFieldMultiCombo, uiFieldNetworkCombo, + uiFieldSemiCombo, uiFieldTypeCombo } from './combo'; @@ -61,6 +62,7 @@ export var uiFields = { onewayCheck: uiFieldOnewayCheck, radio: uiFieldRadio, restrictions: uiFieldRestrictions, + semiCombo: uiFieldSemiCombo, tel: uiFieldTel, text: uiFieldText, textarea: uiFieldTextarea,