mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-24 00:54:03 +02:00
Merge branch 'develop' into lang-attributes
# Conflicts: # modules/ui/fields/combo.js
This commit is contained in:
+1
-1
@@ -185,7 +185,7 @@ export function uiField(context, presetField, entityIDs, options) {
|
||||
|
||||
// instantiate tag reference
|
||||
if (options.wrap && options.info) {
|
||||
var referenceKey = d.key;
|
||||
var referenceKey = d.key || '';
|
||||
if (d.type === 'multiCombo') { // lookup key without the trailing ':'
|
||||
referenceKey = referenceKey.replace(/:$/, '');
|
||||
}
|
||||
|
||||
+103
-101
@@ -20,20 +20,18 @@ export {
|
||||
|
||||
export function uiFieldCombo(field, context) {
|
||||
var dispatch = d3_dispatch('change');
|
||||
var taginfo = services.taginfo;
|
||||
var isMulti = (field.type === 'multiCombo');
|
||||
var isNetwork = (field.type === 'networkCombo');
|
||||
var isSemi = (field.type === 'semiCombo');
|
||||
var optstrings = field.strings && field.strings.options;
|
||||
var optarray = field.options;
|
||||
var snake_case = (field.snake_case || (field.snake_case === undefined));
|
||||
var caseSensitive = field.caseSensitive;
|
||||
var combobox = uiCombobox(context, 'combo-' + field.safeid)
|
||||
.caseSensitive(caseSensitive)
|
||||
.minItems(isMulti || isSemi ? 1 : 2);
|
||||
var container = d3_select(null);
|
||||
var inputWrap = d3_select(null);
|
||||
var input = d3_select(null);
|
||||
var _isMulti = (field.type === 'multiCombo');
|
||||
var _isNetwork = (field.type === 'networkCombo');
|
||||
var _isSemi = (field.type === 'semiCombo');
|
||||
var _optstrings = field.strings && field.strings.options;
|
||||
var _optarray = field.options;
|
||||
var _snake_case = (field.snake_case || (field.snake_case === undefined));
|
||||
var _combobox = uiCombobox(context, 'combo-' + field.safeid)
|
||||
.caseSensitive(field.caseSensitive)
|
||||
.minItems(_isMulti || _isSemi ? 1 : 2);
|
||||
var _container = d3_select(null);
|
||||
var _inputWrap = d3_select(null);
|
||||
var _input = d3_select(null);
|
||||
var _comboData = [];
|
||||
var _multiData = [];
|
||||
var _entityIDs = [];
|
||||
@@ -49,7 +47,7 @@ export function uiFieldCombo(field, context) {
|
||||
|
||||
|
||||
// ensure multiCombo field.key ends with a ':'
|
||||
if (isMulti && /[^:]$/.test(field.key)) {
|
||||
if (_isMulti && field.key && /[^:]$/.test(field.key)) {
|
||||
field.key += ':';
|
||||
}
|
||||
|
||||
@@ -74,7 +72,7 @@ export function uiFieldCombo(field, context) {
|
||||
function tagValue(dval) {
|
||||
dval = clean(dval || '');
|
||||
|
||||
if (optstrings) {
|
||||
if (_optstrings) {
|
||||
var found = _comboData.find(function(o) {
|
||||
return o.key && clean(o.value) === dval;
|
||||
});
|
||||
@@ -87,7 +85,7 @@ export function uiFieldCombo(field, context) {
|
||||
return 'yes';
|
||||
}
|
||||
|
||||
return (snake_case ? snake(dval) : dval) || undefined;
|
||||
return (_snake_case ? snake(dval) : dval) || undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +94,7 @@ export function uiFieldCombo(field, context) {
|
||||
function displayValue(tval) {
|
||||
tval = tval || '';
|
||||
|
||||
if (optstrings) {
|
||||
if (_optstrings) {
|
||||
var found = _comboData.find(function(o) {
|
||||
return o.key === tval && o.value;
|
||||
});
|
||||
@@ -109,7 +107,7 @@ export function uiFieldCombo(field, context) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return snake_case ? unsnake(tval) : tval;
|
||||
return _snake_case ? unsnake(tval) : tval;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,28 +126,28 @@ export function uiFieldCombo(field, context) {
|
||||
|
||||
|
||||
function initCombo(selection, attachTo) {
|
||||
if (optstrings) {
|
||||
if (_optstrings) {
|
||||
selection.attr('readonly', 'readonly');
|
||||
selection.call(combobox, attachTo);
|
||||
selection.call(_combobox, attachTo);
|
||||
setStaticValues(setPlaceholder);
|
||||
|
||||
} else if (optarray) {
|
||||
selection.call(combobox, attachTo);
|
||||
} else if (_optarray) {
|
||||
selection.call(_combobox, attachTo);
|
||||
setStaticValues(setPlaceholder);
|
||||
|
||||
} else if (taginfo) {
|
||||
selection.call(combobox.fetcher(setTaginfoValues), attachTo);
|
||||
} else if (services.taginfo) {
|
||||
selection.call(_combobox.fetcher(setTaginfoValues), attachTo);
|
||||
setTaginfoValues('', setPlaceholder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setStaticValues(callback) {
|
||||
if (!(optstrings || optarray)) return;
|
||||
if (!(_optstrings || _optarray)) return;
|
||||
|
||||
if (optstrings) {
|
||||
_comboData = Object.keys(optstrings).map(function(k) {
|
||||
var v = field.t('options.' + k, { 'default': optstrings[k], html: false });
|
||||
if (_optstrings) {
|
||||
_comboData = Object.keys(_optstrings).map(function(k) {
|
||||
var v = field.t('options.' + k, { 'default': _optstrings[k], html: false });
|
||||
return {
|
||||
key: k,
|
||||
value: v,
|
||||
@@ -157,9 +155,9 @@ export function uiFieldCombo(field, context) {
|
||||
};
|
||||
});
|
||||
|
||||
} else if (optarray) {
|
||||
_comboData = optarray.map(function(k) {
|
||||
var v = snake_case ? unsnake(k) : k;
|
||||
} else if (_optarray) {
|
||||
_comboData = _optarray.map(function(k) {
|
||||
var v = _snake_case ? unsnake(k) : k;
|
||||
return {
|
||||
key: k,
|
||||
value: v,
|
||||
@@ -168,15 +166,15 @@ export function uiFieldCombo(field, context) {
|
||||
});
|
||||
}
|
||||
|
||||
combobox.data(objectDifference(_comboData, _multiData));
|
||||
_combobox.data(objectDifference(_comboData, _multiData));
|
||||
if (callback) callback(_comboData);
|
||||
}
|
||||
|
||||
|
||||
function setTaginfoValues(q, callback) {
|
||||
var fn = isMulti ? 'multikeys' : 'values';
|
||||
var query = (isMulti ? field.key : '') + q;
|
||||
var hasCountryPrefix = isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
|
||||
var fn = _isMulti ? 'multikeys' : 'values';
|
||||
var query = (_isMulti ? field.key : '') + q;
|
||||
var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
|
||||
if (hasCountryPrefix) {
|
||||
query = _countryCode + ':';
|
||||
}
|
||||
@@ -191,7 +189,7 @@ export function uiFieldCombo(field, context) {
|
||||
params.geometry = context.graph().geometry(_entityIDs[0]);
|
||||
}
|
||||
|
||||
taginfo[fn](params, function(err, data) {
|
||||
services.taginfo[fn](params, function(err, data) {
|
||||
if (err) return;
|
||||
|
||||
data = data.filter(function(d) {
|
||||
@@ -220,16 +218,16 @@ export function uiFieldCombo(field, context) {
|
||||
}
|
||||
|
||||
// hide the caret if there are no suggestions
|
||||
container.classed('empty-combobox', data.length === 0);
|
||||
_container.classed('empty-combobox', data.length === 0);
|
||||
|
||||
_comboData = data.map(function(d) {
|
||||
var k = d.value;
|
||||
if (isMulti) k = k.replace(field.key, '');
|
||||
var v = snake_case ? unsnake(k) : k;
|
||||
if (_isMulti) k = k.replace(field.key, '');
|
||||
var v = _snake_case ? unsnake(k) : k;
|
||||
return {
|
||||
key: k,
|
||||
value: v,
|
||||
title: isMulti ? v : d.title
|
||||
title: _isMulti ? v : d.title
|
||||
};
|
||||
});
|
||||
|
||||
@@ -241,7 +239,7 @@ export function uiFieldCombo(field, context) {
|
||||
|
||||
function setPlaceholder(values) {
|
||||
|
||||
if (isMulti || isSemi) {
|
||||
if (_isMulti || _isSemi) {
|
||||
_staticPlaceholder = field.placeholder() || t('inspector.add', { html: false });
|
||||
} else {
|
||||
var vals = values
|
||||
@@ -257,13 +255,13 @@ export function uiFieldCombo(field, context) {
|
||||
}
|
||||
|
||||
var ph;
|
||||
if (!isMulti && !isSemi && _tags && Array.isArray(_tags[field.key])) {
|
||||
if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
|
||||
ph = t('inspector.multiple_values', { html: false });
|
||||
} else {
|
||||
ph = _staticPlaceholder;
|
||||
}
|
||||
|
||||
container.selectAll('input')
|
||||
_container.selectAll('input')
|
||||
.attr('placeholder', ph);
|
||||
}
|
||||
|
||||
@@ -272,17 +270,17 @@ export function uiFieldCombo(field, context) {
|
||||
var t = {};
|
||||
var val;
|
||||
|
||||
if (isMulti || isSemi) {
|
||||
val = tagValue(utilGetSetValue(input).replace(/,/g, ';')) || '';
|
||||
container.classed('active', false);
|
||||
utilGetSetValue(input, '');
|
||||
if (_isMulti || _isSemi) {
|
||||
val = tagValue(utilGetSetValue(_input).replace(/,/g, ';')) || '';
|
||||
_container.classed('active', false);
|
||||
utilGetSetValue(_input, '');
|
||||
|
||||
var vals = val.split(';').filter(Boolean);
|
||||
if (!vals.length) return;
|
||||
|
||||
if (isMulti) {
|
||||
if (_isMulti) {
|
||||
utilArrayUniq(vals).forEach(function(v) {
|
||||
var key = field.key + v;
|
||||
var key = (field.key || '') + v;
|
||||
if (_tags) {
|
||||
// don't set a multicombo value to 'yes' if it already has a non-'no' value
|
||||
// e.g. `language:de=main`
|
||||
@@ -294,16 +292,16 @@ export function uiFieldCombo(field, context) {
|
||||
t[key] = 'yes';
|
||||
});
|
||||
|
||||
} else if (isSemi) {
|
||||
} else if (_isSemi) {
|
||||
var arr = _multiData.map(function(d) { return d.key; });
|
||||
arr = arr.concat(vals);
|
||||
t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';'));
|
||||
}
|
||||
|
||||
window.setTimeout(function() { input.node().focus(); }, 10);
|
||||
window.setTimeout(function() { _input.node().focus(); }, 10);
|
||||
|
||||
} else {
|
||||
var rawValue = utilGetSetValue(input);
|
||||
var rawValue = utilGetSetValue(_input);
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (!rawValue && Array.isArray(_tags[field.key])) return;
|
||||
@@ -319,9 +317,9 @@ export function uiFieldCombo(field, context) {
|
||||
function removeMultikey(d) {
|
||||
d3_event.stopPropagation();
|
||||
var t = {};
|
||||
if (isMulti) {
|
||||
if (_isMulti) {
|
||||
t[d.key] = undefined;
|
||||
} else if (isSemi) {
|
||||
} else if (_isSemi) {
|
||||
var arr = _multiData.map(function(md) {
|
||||
return md.key === d.key ? null : md.key;
|
||||
}).filter(Boolean);
|
||||
@@ -334,17 +332,17 @@ export function uiFieldCombo(field, context) {
|
||||
|
||||
|
||||
function combo(selection) {
|
||||
container = selection.selectAll('.form-field-input-wrap')
|
||||
_container = selection.selectAll('.form-field-input-wrap')
|
||||
.data([0]);
|
||||
|
||||
var type = (isMulti || isSemi) ? 'multicombo': 'combo';
|
||||
container = container.enter()
|
||||
var type = (_isMulti || _isSemi) ? 'multicombo': 'combo';
|
||||
_container = _container.enter()
|
||||
.append('div')
|
||||
.attr('class', 'form-field-input-wrap form-field-input-' + type)
|
||||
.merge(container);
|
||||
.merge(_container);
|
||||
|
||||
if (isMulti || isSemi) {
|
||||
container = container.selectAll('.chiplist')
|
||||
if (_isMulti || _isSemi) {
|
||||
_container = _container.selectAll('.chiplist')
|
||||
.data([0]);
|
||||
|
||||
var listClass = 'chiplist';
|
||||
@@ -355,67 +353,67 @@ export function uiFieldCombo(field, context) {
|
||||
listClass += ' full-line-chips';
|
||||
}
|
||||
|
||||
container = container.enter()
|
||||
_container = _container.enter()
|
||||
.append('ul')
|
||||
.attr('class', listClass)
|
||||
.on('click', function() {
|
||||
window.setTimeout(function() { input.node().focus(); }, 10);
|
||||
window.setTimeout(function() { _input.node().focus(); }, 10);
|
||||
})
|
||||
.merge(container);
|
||||
.merge(_container);
|
||||
|
||||
|
||||
inputWrap = container.selectAll('.input-wrap')
|
||||
_inputWrap = _container.selectAll('.input-wrap')
|
||||
.data([0]);
|
||||
|
||||
inputWrap = inputWrap.enter()
|
||||
_inputWrap = _inputWrap.enter()
|
||||
.append('li')
|
||||
.attr('class', 'input-wrap')
|
||||
.merge(inputWrap);
|
||||
.merge(_inputWrap);
|
||||
|
||||
input = inputWrap.selectAll('input')
|
||||
_input = _inputWrap.selectAll('input')
|
||||
.data([0]);
|
||||
} else {
|
||||
input = container.selectAll('input')
|
||||
_input = _container.selectAll('input')
|
||||
.data([0]);
|
||||
}
|
||||
|
||||
input = input.enter()
|
||||
_input = _input.enter()
|
||||
.append('input')
|
||||
.attr('type', 'text')
|
||||
.attr('id', field.domId)
|
||||
.call(utilNoAuto)
|
||||
.call(initCombo, selection)
|
||||
.merge(input);
|
||||
.merge(_input);
|
||||
|
||||
if (isNetwork) {
|
||||
if (_isNetwork) {
|
||||
var extent = combinedEntityExtent();
|
||||
var countryCode = extent && countryCoder.iso1A2Code(extent.center());
|
||||
_countryCode = countryCode && countryCode.toLowerCase();
|
||||
}
|
||||
|
||||
input
|
||||
_input
|
||||
.on('change', change)
|
||||
.on('blur', change);
|
||||
|
||||
input
|
||||
_input
|
||||
.on('keydown.field', function() {
|
||||
switch (d3_event.keyCode) {
|
||||
case 13: // ↩ Return
|
||||
input.node().blur(); // blurring also enters the value
|
||||
_input.node().blur(); // blurring also enters the value
|
||||
d3_event.stopPropagation();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (isMulti || isSemi) {
|
||||
combobox
|
||||
if (_isMulti || _isSemi) {
|
||||
_combobox
|
||||
.on('accept', function() {
|
||||
input.node().blur();
|
||||
input.node().focus();
|
||||
_input.node().blur();
|
||||
_input.node().focus();
|
||||
});
|
||||
|
||||
input
|
||||
.on('focus', function() { container.classed('active', true); });
|
||||
_input
|
||||
.on('focus', function() { _container.classed('active', true); });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,19 +421,19 @@ export function uiFieldCombo(field, context) {
|
||||
combo.tags = function(tags) {
|
||||
_tags = tags;
|
||||
|
||||
if (isMulti || isSemi) {
|
||||
if (_isMulti || _isSemi) {
|
||||
_multiData = [];
|
||||
|
||||
var maxLength;
|
||||
|
||||
if (isMulti) {
|
||||
if (_isMulti) {
|
||||
// Build _multiData array containing keys already set..
|
||||
for (var k in tags) {
|
||||
if (k.indexOf(field.key) !== 0) continue;
|
||||
if ((field.key && k.indexOf(field.key) !== 0) || field.keys.indexOf(k) === -1) continue;
|
||||
var v = tags[k];
|
||||
if (!v || (typeof v === 'string' && v.toLowerCase() === 'no')) continue;
|
||||
|
||||
var suffix = k.substring(field.key.length);
|
||||
var suffix = field.key ? k.substring(field.key.length) : k;
|
||||
_multiData.push({
|
||||
key: k,
|
||||
value: displayValue(suffix),
|
||||
@@ -443,13 +441,17 @@ export function uiFieldCombo(field, context) {
|
||||
});
|
||||
}
|
||||
|
||||
// Set keys for form-field modified (needed for undo and reset buttons)..
|
||||
field.keys = _multiData.map(function(d) { return d.key; });
|
||||
if (field.key) {
|
||||
// Set keys for form-field modified (needed for undo and reset buttons)..
|
||||
field.keys = _multiData.map(function(d) { return d.key; });
|
||||
|
||||
// limit the input length so it fits after prepending the key prefix
|
||||
maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
|
||||
// limit the input length so it fits after prepending the key prefix
|
||||
maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
|
||||
} else {
|
||||
maxLength = context.maxCharsForTagKey();
|
||||
}
|
||||
|
||||
} else if (isSemi) {
|
||||
} else if (_isSemi) {
|
||||
|
||||
var allValues = [];
|
||||
var commonValues;
|
||||
@@ -492,23 +494,23 @@ export function uiFieldCombo(field, context) {
|
||||
// a negative maxlength doesn't make sense
|
||||
maxLength = Math.max(0, maxLength);
|
||||
|
||||
var allowDragAndDrop = isSemi // only semiCombo values are ordered
|
||||
var allowDragAndDrop = _isSemi // only semiCombo values are ordered
|
||||
&& !Array.isArray(tags[field.key]);
|
||||
|
||||
// Exclude existing multikeys from combo options..
|
||||
var available = objectDifference(_comboData, _multiData);
|
||||
combobox.data(available);
|
||||
_combobox.data(available);
|
||||
|
||||
// Hide 'Add' button if this field uses fixed set of
|
||||
// translateable optstrings and they're all currently used,
|
||||
// translateable _optstrings and they're all currently used,
|
||||
// or if the field is already at its character limit
|
||||
var hideAdd = (optstrings && !available.length) || maxLength <= 0;
|
||||
container.selectAll('.chiplist .input-wrap')
|
||||
var hideAdd = (_optstrings && !available.length) || maxLength <= 0;
|
||||
_container.selectAll('.chiplist .input-wrap')
|
||||
.style('display', hideAdd ? 'none' : null);
|
||||
|
||||
|
||||
// Render chips
|
||||
var chips = container.selectAll('.chip')
|
||||
var chips = _container.selectAll('.chip')
|
||||
.data(_multiData);
|
||||
|
||||
chips.exit()
|
||||
@@ -550,7 +552,7 @@ export function uiFieldCombo(field, context) {
|
||||
return displayValue(val);
|
||||
}).filter(Boolean);
|
||||
|
||||
utilGetSetValue(input, !isMixed ? displayValue(tags[field.key]) : '')
|
||||
utilGetSetValue(_input, !isMixed ? displayValue(tags[field.key]) : '')
|
||||
.attr('title', isMixed ? mixedValues.join('\n') : undefined)
|
||||
.attr('placeholder', isMixed ? t('inspector.multiple_values', { html: false }) : _staticPlaceholder || '')
|
||||
.classed('mixed', isMixed);
|
||||
@@ -585,7 +587,7 @@ export function uiFieldCombo(field, context) {
|
||||
var draggedTagWidth = d3_select(this).node().offsetWidth;
|
||||
|
||||
if (field.key === 'destination') { // meaning tags are full width
|
||||
container.selectAll('.chip')
|
||||
_container.selectAll('.chip')
|
||||
.style('transform', function(d2, index2) {
|
||||
var node = d3_select(this).node();
|
||||
|
||||
@@ -607,7 +609,7 @@ export function uiFieldCombo(field, context) {
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
container.selectAll('.chip')
|
||||
_container.selectAll('.chip')
|
||||
.each(function(d2, index2) {
|
||||
var node = d3_select(this).node();
|
||||
|
||||
@@ -650,7 +652,7 @@ export function uiFieldCombo(field, context) {
|
||||
d3_select(this)
|
||||
.classed('dragging', false);
|
||||
|
||||
container.selectAll('.chip')
|
||||
_container.selectAll('.chip')
|
||||
.style('transform', null);
|
||||
|
||||
if (typeof targetIndex === 'number') {
|
||||
@@ -678,7 +680,7 @@ export function uiFieldCombo(field, context) {
|
||||
|
||||
|
||||
combo.focus = function() {
|
||||
input.node().focus();
|
||||
_input.node().focus();
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user