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,