Add semiCombo field for setting values in semicolon-delimited lists

(closes #3905)
This commit is contained in:
Bryan Housel
2017-03-17 01:47:00 -04:00
parent 3a175c277c
commit 1205e1758e
8 changed files with 58 additions and 29 deletions
+1 -1
View File
@@ -1129,7 +1129,7 @@ en:
label: Source
sport:
# sport=*
label: Sport
label: Sports
sport_ice:
# sport=*
label: Sport
+2
View File
@@ -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<br/>
(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<br/>
(e.g. `sport=*` -> `soccer;lacrosse;athletics;field_hockey`)
**Checkboxes**
* `check` - 3-state checkbox: `yes`, `no`, unknown (no tag)
+2 -2
View File
@@ -1524,8 +1524,8 @@
},
"sport": {
"key": "sport",
"type": "combo",
"label": "Sport"
"type": "semiCombo",
"label": "Sports"
},
"stars": {
"key": "stars",
+3 -3
View File
@@ -1,5 +1,5 @@
{
"key": "sport",
"type": "combo",
"label": "Sport"
}
"type": "semiCombo",
"label": "Sports"
}
+1
View File
@@ -64,6 +64,7 @@
"onewayCheck",
"radio",
"restrictions",
"semiCombo",
"tel",
"textarea",
"text",
+1 -1
View File
@@ -1692,7 +1692,7 @@
"label": "Sport"
},
"sport": {
"label": "Sport"
"label": "Sports"
},
"stars": {
"label": "Stars"
+46 -22
View File
@@ -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);
+2
View File
@@ -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,