in modules/ui/fields/combo.js [416:589]
combo.tags = function(tags) {
_tags = tags;
if (_isMulti || _isSemi) {
_multiData = [];
var maxLength;
if (_isMulti) {
// Build _multiData array containing keys already set..
for (var k in tags) {
if (field.key && k.indexOf(field.key) !== 0) continue;
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.substr(field.key.length) : k;
_multiData.push({
key: k,
value: displayValue(suffix),
isMixed: Array.isArray(v)
});
}
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);
} else {
maxLength = context.maxCharsForTagKey();
}
} else if (_isSemi) {
var allValues = [];
var commonValues;
if (Array.isArray(tags[field.key])) {
tags[field.key].forEach(function(tagVal) {
var thisVals = utilArrayUniq((tagVal || '').split(';')).filter(Boolean);
allValues = allValues.concat(thisVals);
if (!commonValues) {
commonValues = thisVals;
} else {
commonValues = commonValues.filter(value => thisVals.includes(value));
}
});
allValues = utilArrayUniq(allValues).filter(Boolean);
} else {
allValues = utilArrayUniq((tags[field.key] || '').split(';')).filter(Boolean);
commonValues = allValues;
}
_multiData = allValues.map(function(v) {
return {
key: v,
value: displayValue(v),
isMixed: !commonValues.includes(v)
};
});
var currLength = utilUnicodeCharsCount(commonValues.join(';'));
// limit the input length to the remaining available characters
maxLength = context.maxCharsForTagValue() - currLength;
if (currLength > 0) {
// account for the separator if a new value will be appended to existing
maxLength -= 1;
}
}
// a negative maxlength doesn't make sense
maxLength = Math.max(0, maxLength);
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);
// Hide 'Add' button if this field uses fixed set of
// options and they're all currently used,
// or if the field is already at its character limit
var hideAdd = (!_allowCustomValues && !available.length) || maxLength <= 0;
_container.selectAll('.chiplist .input-wrap')
.style('display', hideAdd ? 'none' : null);
// Render chips
var chips = _container.selectAll('.chip')
.data(_multiData);
chips.exit()
.remove();
var enter = chips.enter()
.insert('li', '.input-wrap')
.attr('class', 'chip');
enter.append('span');
enter.append('a');
chips = chips.merge(enter)
.order()
.classed('raw-value', function(d) {
var k = d.key;
if (_isMulti) k = k.replace(field.key, '');
return !field.hasTextForStringId('options.' + k);
})
.classed('draggable', allowDragAndDrop)
.classed('mixed', function(d) {
return d.isMixed;
})
.attr('title', function(d) {
return d.isMixed ? t('inspector.unshared_value_tooltip') : null;
});
if (allowDragAndDrop) {
registerDragAndDrop(chips);
}
chips.select('span')
.html(function(d) { return d.value; });
chips.select('a')
.attr('href', '#')
.on('click', removeMultikey)
.attr('class', 'remove')
.text(function(d) {
// don't show 'x' on the digitalglobe/maxar label on ML road
// TODO: switch to check on __fbid__
return _entityIDs[0] && isFbRoadId(_entityIDs[0]) && field.key === 'source' && (d.value === 'digitalglobe' || d.value === 'maxar') ? '' : '×';
});
} else {
var isMixed = Array.isArray(tags[field.key]);
var mixedValues = isMixed && tags[field.key].map(function(val) {
return displayValue(val);
}).filter(Boolean);
var showsValue = !isMixed && tags[field.key] && !(field.type === 'typeCombo' && tags[field.key] === 'yes');
var isRawValue = showsValue && !field.hasTextForStringId('options.' + tags[field.key]);
var isKnownValue = showsValue && !isRawValue;
var isReadOnly = !_allowCustomValues || isKnownValue;
utilGetSetValue(_input, !isMixed ? displayValue(tags[field.key]) : '')
.classed('raw-value', isRawValue)
.classed('known-value', isKnownValue)
.attr('readonly', isReadOnly ? 'readonly' : undefined)
.attr('title', isMixed ? mixedValues.join('\n') : undefined)
.attr('placeholder', isMixed ? t('inspector.multiple_values') : _staticPlaceholder || '')
.classed('mixed', isMixed)
.on('keydown.deleteCapture', function(d3_event) {
if (isReadOnly &&
isKnownValue &&
(d3_event.keyCode === utilKeybinding.keyCodes['⌫'] ||
d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
d3_event.preventDefault();
d3_event.stopPropagation();
var t = {};
t[field.key] = undefined;
dispatch.call('change', this, t);
}
});
}
};