mirror of
https://github.com/FoggedLens/iD.git
synced 2026-03-06 03:11:22 +00:00
To avoid conflicts with hyphenated names, or bilingual names with hyphens in them (like used in Brussels)
250 lines
7.6 KiB
JavaScript
250 lines
7.6 KiB
JavaScript
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;
|
||
}
|