Files
iD/modules/presets/preset.js
Bryan Housel 20bcfc5730 Delimit name-suggestion-preset names on en-dash, not hyphen
To avoid conflicts with hyphenated names, or bilingual names
with hyphens in them (like used in Brussels)
2019-01-23 09:44:24 -05:00

250 lines
7.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import _clone from 'lodash-es/clone';
import _omit from 'lodash-es/omit';
import _uniq from 'lodash-es/uniq';
import { t } from '../util/locale';
import { areaKeys } from '../core/context';
export function presetPreset(id, preset, fields, visible, rawPresets) {
preset = _clone(preset);
preset.id = id;
preset.parentPresetID = function() {
var endIndex = preset.id.lastIndexOf('/');
if (endIndex < 0) return null;
return preset.id.substring(0, endIndex);
};
// For a preset without fields, use the fields of the parent preset.
// Replace {preset} placeholders with the fields of the specified presets.
function resolveFieldInheritance() {
// Skip `fields` for the keys which define the preset.
// These are usually `typeCombo` fields like `shop=*`
function withoutKeyFields(fieldID) {
var f = fields[fieldID];
if (f.key) {
return preset.tags[f.key] === undefined;
}
return true;
}
// returns an array of field IDs to inherit from the given presetID, if found
function inheritedFieldIDs(presetID, prop) {
if (!presetID) return null;
var inheritPreset = rawPresets[presetID];
if (!inheritPreset) return null;
var inheritFieldIDs = inheritPreset[prop] || [];
if (prop === 'fields') {
inheritFieldIDs = inheritFieldIDs.filter(withoutKeyFields);
}
return inheritFieldIDs;
}
['fields', 'moreFields'].forEach(function(prop) {
var fieldIDs = [];
if (preset[prop] && preset[prop].length) { // fields were defined
preset[prop].forEach(function(fieldID) {
var match = fieldID.match(/\{(.*)\}/);
if (match !== null) { // presetID wrapped in braces {}
var inheritIDs = inheritedFieldIDs(match[1], prop);
if (inheritIDs !== null) {
fieldIDs = fieldIDs.concat(inheritIDs);
} else {
/* eslint-disable no-console */
console.log('Cannot resolve presetID ' + match[0] +
' found in ' + preset.id + ' ' + prop);
/* eslint-enable no-console */
}
} else {
fieldIDs.push(fieldID); // no braces - just a normal field
}
});
} else { // no fields defined, so use the parent's if possible
fieldIDs = inheritedFieldIDs(preset.parentPresetID(), prop);
}
// resolve duplicate fields
fieldIDs = _uniq(fieldIDs);
// update this preset with the results
preset[prop] = fieldIDs;
// update the raw object to allow for multiple levels of inheritance
rawPresets[preset.id][prop] = fieldIDs;
});
}
if (rawPresets) {
resolveFieldInheritance();
}
preset.fields = (preset.fields || []).map(getFields);
preset.moreFields = (preset.moreFields || []).map(getFields);
preset.geometry = (preset.geometry || []);
visible = visible || false;
function getFields(f) {
return fields[f];
}
preset.matchGeometry = function(geometry) {
return preset.geometry.indexOf(geometry) >= 0;
};
preset.originalScore = preset.matchScore || 1;
preset.matchScore = function(entity) {
var tags = preset.tags;
var score = 0;
for (var t in tags) {
if (entity.tags[t] === tags[t]) {
score += preset.originalScore;
} else if (tags[t] === '*' && t in entity.tags) {
score += preset.originalScore / 2;
} else {
return -1;
}
}
return score;
};
preset.t = function(scope, options) {
return t('presets.presets.' + id + '.' + scope, options);
};
var origName = preset.name || '';
preset.name = function() {
if (preset.suggestion) {
var path = id.split('/');
path.pop(); // remove brand name
// NOTE: insert an en-dash, not a hypen (to avoid conflict with fr - nl names in Brussels etc)
return origName + ' ' + t('presets.presets.' + path.join('/') + '.name');
}
return preset.t('name', { 'default': origName });
};
var origTerms = (preset.terms || []).join();
preset.terms = function() {
return preset.t('terms', { 'default': origTerms }).toLowerCase().trim().split(/\s*,+\s*/);
};
preset.isFallback = function() {
var tagCount = Object.keys(preset.tags).length;
return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
};
preset.visible = function(val) {
if (!arguments.length) return visible;
visible = val;
return visible;
};
var reference = preset.reference || {};
preset.reference = function(geometry) {
var key = reference.key || Object.keys(_omit(preset.tags, 'name'))[0],
value = reference.value || preset.tags[key];
if (geometry === 'relation' && key === 'type') {
if (value in preset.tags) {
key = value;
value = preset.tags[key];
} else {
return { rtype: value };
}
}
if (value === '*') {
return { key: key };
} else {
return { key: key, value: value };
}
};
preset.removeTags = preset.removeTags || preset.tags || {};
preset.unsetTags = function(tags, geometry) {
tags = _omit(tags, Object.keys(preset.removeTags));
for (var f in preset.fields) {
var field = preset.fields[f];
if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
delete tags[field.key];
}
}
delete tags.area;
return tags;
};
preset.addTags = preset.addTags || preset.tags || {};
preset.setTags = function(tags, geometry) {
var addTags = preset.addTags;
var k;
tags = _clone(tags);
for (k in addTags) {
if (addTags[k] === '*') {
tags[k] = 'yes';
} else {
tags[k] = addTags[k];
}
}
// Add area=yes if necessary.
// This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
// 1. chosen preset could be either an area or a line (`barrier=city_wall`)
// 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
if (!addTags.hasOwnProperty('area')) {
delete tags.area;
if (geometry === 'area') {
var needsAreaTag = true;
if (preset.geometry.indexOf('line') === -1) {
for (k in addTags) {
if (k in areaKeys) {
needsAreaTag = false;
break;
}
}
}
if (needsAreaTag) {
tags.area = 'yes';
}
}
}
for (var f in preset.fields) {
var field = preset.fields[f];
if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
tags[field.key] = field.default;
}
}
return tags;
};
return preset;
}