mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-23 16:49:40 +02:00
Merge branch 'develop' into add_mapilio_data
This commit is contained in:
@@ -3,6 +3,7 @@ export function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefa
|
||||
var entity = graph.entity(entityID);
|
||||
var geometry = entity.geometry(graph);
|
||||
var tags = entity.tags;
|
||||
const loc = entity.extent(graph).center();
|
||||
|
||||
// preserve tags that the new preset might care about, if any
|
||||
var preserveKeys;
|
||||
@@ -15,14 +16,14 @@ export function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefa
|
||||
// only if old preset is not a sub-preset of the new one:
|
||||
// preserve tags for which the new preset has a field
|
||||
// https://github.com/openstreetmap/iD/issues/9372
|
||||
newPreset.fields().concat(newPreset.moreFields())
|
||||
newPreset.fields(loc).concat(newPreset.moreFields(loc))
|
||||
.filter(f => f.matchGeometry(geometry))
|
||||
.map(f => f.key).filter(Boolean)
|
||||
.forEach(key => preserveKeys.push(key));
|
||||
}
|
||||
}
|
||||
if (oldPreset) tags = oldPreset.unsetTags(tags, geometry, preserveKeys);
|
||||
if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults);
|
||||
if (oldPreset) tags = oldPreset.unsetTags(tags, geometry, preserveKeys, loc);
|
||||
if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults, loc);
|
||||
|
||||
return graph.replace(entity.update({tags: tags}));
|
||||
};
|
||||
|
||||
@@ -15,9 +15,11 @@ export function modeAddArea(context, mode) {
|
||||
.on('startFromWay', startFromWay)
|
||||
.on('startFromNode', startFromNode);
|
||||
|
||||
var defaultTags = { area: 'yes' };
|
||||
if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'area');
|
||||
|
||||
function defaultTags(loc) {
|
||||
var defaultTags = { area: 'yes' };
|
||||
if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'area', false, loc);
|
||||
return defaultTags;
|
||||
}
|
||||
|
||||
function actionClose(wayId) {
|
||||
return function (graph) {
|
||||
@@ -29,7 +31,7 @@ export function modeAddArea(context, mode) {
|
||||
function start(loc) {
|
||||
var startGraph = context.graph();
|
||||
var node = osmNode({ loc: loc });
|
||||
var way = osmWay({ tags: defaultTags });
|
||||
var way = osmWay({ tags: defaultTags(loc) });
|
||||
|
||||
context.perform(
|
||||
actionAddEntity(node),
|
||||
@@ -45,7 +47,7 @@ export function modeAddArea(context, mode) {
|
||||
function startFromWay(loc, edge) {
|
||||
var startGraph = context.graph();
|
||||
var node = osmNode({ loc: loc });
|
||||
var way = osmWay({ tags: defaultTags });
|
||||
var way = osmWay({ tags: defaultTags(loc) });
|
||||
|
||||
context.perform(
|
||||
actionAddEntity(node),
|
||||
@@ -61,7 +63,7 @@ export function modeAddArea(context, mode) {
|
||||
|
||||
function startFromNode(node) {
|
||||
var startGraph = context.graph();
|
||||
var way = osmWay({ tags: defaultTags });
|
||||
var way = osmWay({ tags: defaultTags(node.loc) });
|
||||
|
||||
context.perform(
|
||||
actionAddEntity(way),
|
||||
|
||||
@@ -15,14 +15,17 @@ export function modeAddLine(context, mode) {
|
||||
.on('startFromWay', startFromWay)
|
||||
.on('startFromNode', startFromNode);
|
||||
|
||||
var defaultTags = {};
|
||||
if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'line');
|
||||
function defaultTags(loc) {
|
||||
var defaultTags = {};
|
||||
if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'line', false, loc);
|
||||
return defaultTags;
|
||||
}
|
||||
|
||||
|
||||
function start(loc) {
|
||||
var startGraph = context.graph();
|
||||
var node = osmNode({ loc: loc });
|
||||
var way = osmWay({ tags: defaultTags });
|
||||
var way = osmWay({ tags: defaultTags(loc) });
|
||||
|
||||
context.perform(
|
||||
actionAddEntity(node),
|
||||
@@ -37,7 +40,7 @@ export function modeAddLine(context, mode) {
|
||||
function startFromWay(loc, edge) {
|
||||
var startGraph = context.graph();
|
||||
var node = osmNode({ loc: loc });
|
||||
var way = osmWay({ tags: defaultTags });
|
||||
var way = osmWay({ tags: defaultTags(loc) });
|
||||
|
||||
context.perform(
|
||||
actionAddEntity(node),
|
||||
@@ -52,7 +55,7 @@ export function modeAddLine(context, mode) {
|
||||
|
||||
function startFromNode(node) {
|
||||
var startGraph = context.graph();
|
||||
var way = osmWay({ tags: defaultTags });
|
||||
var way = osmWay({ tags: defaultTags(node.loc) });
|
||||
|
||||
context.perform(
|
||||
actionAddEntity(way),
|
||||
|
||||
@@ -19,12 +19,15 @@ export function modeAddPoint(context, mode) {
|
||||
.on('cancel', cancel)
|
||||
.on('finish', cancel);
|
||||
|
||||
var defaultTags = {};
|
||||
if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'point');
|
||||
function defaultTags(loc) {
|
||||
var defaultTags = {};
|
||||
if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'point', false, loc);
|
||||
return defaultTags;
|
||||
}
|
||||
|
||||
|
||||
function add(loc) {
|
||||
var node = osmNode({ loc: loc, tags: defaultTags });
|
||||
var node = osmNode({ loc: loc, tags: defaultTags(loc) });
|
||||
|
||||
context.perform(
|
||||
actionAddEntity(node),
|
||||
@@ -36,7 +39,7 @@ export function modeAddPoint(context, mode) {
|
||||
|
||||
|
||||
function addWay(loc, edge) {
|
||||
var node = osmNode({ tags: defaultTags });
|
||||
var node = osmNode({ tags: defaultTags(loc) });
|
||||
|
||||
context.perform(
|
||||
actionAddMidpoint({loc: loc, edge: edge}, node),
|
||||
@@ -54,14 +57,15 @@ export function modeAddPoint(context, mode) {
|
||||
|
||||
|
||||
function addNode(node) {
|
||||
if (Object.keys(defaultTags).length === 0) {
|
||||
const _defaultTags = defaultTags(node.loc);
|
||||
if (Object.keys(_defaultTags).length === 0) {
|
||||
enterSelectMode(node);
|
||||
return;
|
||||
}
|
||||
|
||||
var tags = Object.assign({}, node.tags); // shallow copy
|
||||
for (var key in defaultTags) {
|
||||
tags[key] = defaultTags[key];
|
||||
for (var key in _defaultTags) {
|
||||
tags[key] = _defaultTags[key];
|
||||
}
|
||||
|
||||
context.perform(
|
||||
|
||||
@@ -163,9 +163,6 @@ export function presetIndex() {
|
||||
// Rebuild universal fields array
|
||||
_universal = Object.values(_fields).filter(field => field.universal);
|
||||
|
||||
// Reset all the preset fields - they'll need to be resolved again
|
||||
Object.values(_presets).forEach(preset => preset.resetFields());
|
||||
|
||||
// Rebuild geometry index
|
||||
_geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
|
||||
_this.collection.forEach(preset => {
|
||||
|
||||
+25
-15
@@ -1,7 +1,10 @@
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
import { t } from '../core/localizer';
|
||||
import { osmAreaKeys, osmAreaKeysExceptions } from '../osm/tags';
|
||||
import { utilArrayUniq, utilObjectOmit } from '../util';
|
||||
import { utilSafeClassName } from '../util/util';
|
||||
import { locationManager } from '../core/LocationManager';
|
||||
|
||||
|
||||
//
|
||||
@@ -13,8 +16,6 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
|
||||
allPresets = allPresets || {};
|
||||
let _this = Object.assign({}, preset); // shallow copy
|
||||
let _addable = addable || false;
|
||||
let _resolvedFields; // cache
|
||||
let _resolvedMoreFields; // cache
|
||||
let _searchName; // cache
|
||||
let _searchNameStripped; // cache
|
||||
let _searchAliases; // cache
|
||||
@@ -40,11 +41,9 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
|
||||
|
||||
_this.originalMoreFields = (_this.moreFields || []);
|
||||
|
||||
_this.fields = () => _resolvedFields || (_resolvedFields = resolveFields('fields'));
|
||||
_this.fields = loc => resolveFields('fields', loc);
|
||||
|
||||
_this.moreFields = () => _resolvedMoreFields || (_resolvedMoreFields = resolveFields('moreFields'));
|
||||
|
||||
_this.resetFields = () => _resolvedFields = _resolvedMoreFields = null;
|
||||
_this.moreFields = loc => resolveFields('moreFields', loc);
|
||||
|
||||
_this.tags = _this.tags || {};
|
||||
|
||||
@@ -219,13 +218,13 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
|
||||
};
|
||||
|
||||
|
||||
_this.unsetTags = (tags, geometry, ignoringKeys, skipFieldDefaults) => {
|
||||
_this.unsetTags = (tags, geometry, ignoringKeys, skipFieldDefaults, loc) => {
|
||||
// allow manually keeping some tags
|
||||
let removeTags = ignoringKeys ? utilObjectOmit(_this.removeTags, ignoringKeys) : _this.removeTags;
|
||||
tags = utilObjectOmit(tags, Object.keys(removeTags));
|
||||
|
||||
if (geometry && !skipFieldDefaults) {
|
||||
_this.fields().forEach(field => {
|
||||
_this.fields(loc).forEach(field => {
|
||||
if (field.matchGeometry(geometry) && field.key &&
|
||||
field.default === tags[field.key] &&
|
||||
(!ignoringKeys || ignoringKeys.indexOf(field.key) === -1)) {
|
||||
@@ -239,7 +238,7 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
|
||||
};
|
||||
|
||||
|
||||
_this.setTags = (tags, geometry, skipFieldDefaults) => {
|
||||
_this.setTags = (tags, geometry, skipFieldDefaults, loc) => {
|
||||
const addTags = _this.addTags;
|
||||
tags = Object.assign({}, tags); // shallow copy
|
||||
|
||||
@@ -277,7 +276,7 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
|
||||
}
|
||||
|
||||
if (geometry && !skipFieldDefaults) {
|
||||
_this.fields().forEach(field => {
|
||||
_this.fields(loc).forEach(field => {
|
||||
if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
|
||||
tags[field.key] = field.default;
|
||||
}
|
||||
@@ -290,14 +289,14 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
|
||||
|
||||
// For a preset without fields, use the fields of the parent preset.
|
||||
// Replace {preset} placeholders with the fields of the specified presets.
|
||||
function resolveFields(which) {
|
||||
function resolveFields(which, loc) {
|
||||
const fieldIDs = (which === 'fields' ? _this.originalFields : _this.originalMoreFields);
|
||||
let resolved = [];
|
||||
|
||||
fieldIDs.forEach(fieldID => {
|
||||
const match = fieldID.match(referenceRegex);
|
||||
if (match !== null) { // a presetID wrapped in braces {}
|
||||
resolved = resolved.concat(inheritFields(match[1], which));
|
||||
resolved = resolved.concat(inheritFields(allPresets[match[1]], which));
|
||||
} else if (allFields[fieldID]) { // a normal fieldID
|
||||
resolved.push(allFields[fieldID]);
|
||||
} else {
|
||||
@@ -310,7 +309,19 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
|
||||
const endIndex = _this.id.lastIndexOf('/');
|
||||
const parentID = endIndex && _this.id.substring(0, endIndex);
|
||||
if (parentID) {
|
||||
resolved = inheritFields(parentID, which);
|
||||
let parent = allPresets[parentID];
|
||||
if (loc) {
|
||||
const validHere = locationManager.locationSetsAt(loc);
|
||||
if (!validHere[parent.locationSetID]) {
|
||||
// this is a preset for which a regional variant of the main preset exists
|
||||
const candidateIDs = Object.keys(allPresets).filter(k => k.startsWith(parentID));
|
||||
parent = allPresets[candidateIDs.find(candidateID => {
|
||||
const candidate = allPresets[candidateID];
|
||||
return validHere[candidate.locationSetID] && isEqual(candidate.tags, parent.tags);
|
||||
})];
|
||||
}
|
||||
}
|
||||
resolved = inheritFields(parent, which);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,8 +329,7 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
|
||||
|
||||
|
||||
// returns an array of fields to inherit from the given presetID, if found
|
||||
function inheritFields(presetID, which) {
|
||||
const parent = allPresets[presetID];
|
||||
function inheritFields(parent, which) {
|
||||
if (!parent) return [];
|
||||
|
||||
if (which === 'fields') {
|
||||
|
||||
@@ -17,7 +17,7 @@ export default {
|
||||
|
||||
|
||||
// Search for Wikidata items matching the query
|
||||
itemsForSearchQuery: function(query, callback) {
|
||||
itemsForSearchQuery: function _itemsForSearchQuery(query, callback, language) {
|
||||
if (!query) {
|
||||
if (callback) callback('No query', {});
|
||||
return;
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
search: query,
|
||||
type: 'item',
|
||||
// the language to search
|
||||
language: lang,
|
||||
language: language || lang,
|
||||
// the language for the label and description in the result
|
||||
uselang: lang,
|
||||
limit: 10,
|
||||
@@ -42,7 +42,14 @@ export default {
|
||||
d3_json(url)
|
||||
.then(function(result) {
|
||||
if (result && result.error) {
|
||||
throw new Error(result.error);
|
||||
if (result.error.code === 'badvalue' &&
|
||||
result.error.info.includes(lang) &&
|
||||
!language && lang.includes('-')) {
|
||||
// retry without "country suffix" region subtag
|
||||
_itemsForSearchQuery(query, callback, lang.split('-')[0]);
|
||||
} else {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
}
|
||||
if (callback) callback(null, result.search || {});
|
||||
})
|
||||
|
||||
@@ -159,7 +159,12 @@ export function svgTagClasses() {
|
||||
classes.push('tag-wikidata');
|
||||
}
|
||||
|
||||
return classes.join(' ').trim();
|
||||
// ensure that classes for tags keys/values with special characters like spaces
|
||||
// are not added to the DOM, because it can cause bizarre issues (#9448)
|
||||
return classes
|
||||
.filter(klass => /^[-_a-z0-9]+$/.test(klass))
|
||||
.join(' ')
|
||||
.trim();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ export function uiFieldCombo(field, context) {
|
||||
function objectDifference(a, b) {
|
||||
return a.filter(function(d1) {
|
||||
return !b.some(function(d2) {
|
||||
return !d2.isMixed && d1.value === d2.value;
|
||||
return d1.value === d2.value;
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -416,6 +416,17 @@ export function uiFieldCombo(field, context) {
|
||||
}
|
||||
|
||||
|
||||
function invertMultikey(d3_event, d) {
|
||||
d3_event.preventDefault();
|
||||
d3_event.stopPropagation();
|
||||
var t = {};
|
||||
if (_isMulti) {
|
||||
t[d.key] = _tags[d.key] === 'yes' ? 'no' : 'yes';
|
||||
}
|
||||
dispatch.call('change', this, t);
|
||||
}
|
||||
|
||||
|
||||
function combo(selection) {
|
||||
_container = selection.selectAll('.form-field-input-wrap')
|
||||
.data([0]);
|
||||
@@ -455,6 +466,11 @@ export function uiFieldCombo(field, context) {
|
||||
.attr('class', 'input-wrap')
|
||||
.merge(_inputWrap);
|
||||
|
||||
// Hide 'Add' button if this field uses fixed set of
|
||||
// options and they're all currently used
|
||||
var hideAdd = (!_allowCustomValues && !_comboData.length);
|
||||
_inputWrap.style('display', hideAdd ? 'none' : null);
|
||||
|
||||
_input = _inputWrap.selectAll('input')
|
||||
.data([0]);
|
||||
} else {
|
||||
@@ -557,13 +573,13 @@ export function uiFieldCombo(field, context) {
|
||||
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.slice(field.key.length) : k;
|
||||
_multiData.push({
|
||||
key: k,
|
||||
value: displayValue(suffix),
|
||||
display: renderValue(suffix),
|
||||
state: typeof v === 'string' ? v.toLowerCase() : '',
|
||||
isMixed: Array.isArray(v)
|
||||
});
|
||||
}
|
||||
@@ -623,7 +639,7 @@ export function uiFieldCombo(field, context) {
|
||||
maxLength = Math.max(0, maxLength);
|
||||
|
||||
// Hide 'Add' button if this field is already at its character limit
|
||||
var hideAdd = maxLength <= 0;
|
||||
var hideAdd = maxLength <= 0 || (!_allowCustomValues && !_comboData.length);
|
||||
_container.selectAll('.chiplist .input-wrap')
|
||||
.style('display', hideAdd ? 'none' : null);
|
||||
|
||||
@@ -656,8 +672,24 @@ export function uiFieldCombo(field, context) {
|
||||
return d.isMixed;
|
||||
})
|
||||
.attr('title', function(d) {
|
||||
return d.isMixed ? t('inspector.unshared_value_tooltip') : null;
|
||||
});
|
||||
if (d.isMixed) {
|
||||
return t('inspector.unshared_value_tooltip');
|
||||
}
|
||||
if (!['yes', 'no'].includes(d.state)) {
|
||||
return d.state;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.classed('negated', d => d.state === 'no');
|
||||
|
||||
if (!_isSemi) {
|
||||
chips.selectAll('input[type=checkbox]').remove();
|
||||
chips.insert('input', 'span')
|
||||
.attr('type', 'checkbox')
|
||||
.property('checked', d => d.state === 'yes')
|
||||
.property('indeterminate', d => d.isMixed || !['yes', 'no'].includes(d.state))
|
||||
.on('click', invertMultikey);
|
||||
}
|
||||
|
||||
if (allowDragAndDrop) {
|
||||
registerDragAndDrop(chips);
|
||||
|
||||
@@ -384,6 +384,17 @@ export function uiFieldText(field, context) {
|
||||
}
|
||||
|
||||
|
||||
// returns all values of a (potential) multiselection and/or multi-key field
|
||||
function getVals(tags) {
|
||||
if (field.keys) {
|
||||
return new Set(field.keys.reduce((acc, key) => acc.concat(tags[key]), [])
|
||||
.filter(Boolean));
|
||||
} else {
|
||||
return new Set([].concat(tags[field.key]).filter(Boolean));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function change(onInput) {
|
||||
return function() {
|
||||
var t = {};
|
||||
@@ -391,7 +402,7 @@ export function uiFieldText(field, context) {
|
||||
if (!onInput) val = context.cleanTagValue(val);
|
||||
|
||||
// don't override multiple values with blank string
|
||||
if (!val && Array.isArray(_tags[field.key])) return;
|
||||
if (!val && getVals(_tags).size > 1) return;
|
||||
|
||||
if (!onInput) {
|
||||
if (field.type === 'number' && val) {
|
||||
@@ -405,7 +416,24 @@ export function uiFieldText(field, context) {
|
||||
utilGetSetValue(input, val);
|
||||
}
|
||||
t[field.key] = val || undefined;
|
||||
dispatch.call('change', this, t, onInput);
|
||||
if (field.keys) {
|
||||
// for multi-key fields with: handle alternative tag keys gracefully
|
||||
// https://github.com/openstreetmap/id-tagging-schema/issues/905
|
||||
dispatch.call('change', this, tags => {
|
||||
if (field.keys.some(key => tags[key])) {
|
||||
// use exiting key(s)
|
||||
field.keys.filter(key => tags[key]).forEach(key => {
|
||||
tags[key] = val || undefined;
|
||||
});
|
||||
} else {
|
||||
// fall back to default key if none of the `keys` is preset
|
||||
tags[field.key] = val || undefined;
|
||||
}
|
||||
return tags;
|
||||
}, onInput);
|
||||
} else {
|
||||
dispatch.call('change', this, t, onInput);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -416,14 +444,14 @@ export function uiFieldText(field, context) {
|
||||
return i;
|
||||
};
|
||||
|
||||
|
||||
i.tags = function(tags) {
|
||||
_tags = tags;
|
||||
|
||||
var isMixed = Array.isArray(tags[field.key]);
|
||||
|
||||
utilGetSetValue(input, !isMixed && tags[field.key] ? tags[field.key] : '')
|
||||
.attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : undefined)
|
||||
const vals = getVals(tags);
|
||||
const isMixed = vals.size > 1;
|
||||
const val = vals.size === 1 ? [...vals][0] : '';
|
||||
utilGetSetValue(input, val)
|
||||
.attr('title', isMixed ? [...vals].join('\n') : undefined)
|
||||
.attr('placeholder', isMixed ? t('inspector.multiple_values') : (field.placeholder() || t('inspector.unknown')))
|
||||
.classed('mixed', isMixed);
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ export function uiFieldLocalized(field, context) {
|
||||
var preset = presetManager.match(entity, context.graph());
|
||||
if (preset) {
|
||||
var isSuggestion = preset.suggestion;
|
||||
var fields = preset.fields();
|
||||
var fields = preset.fields(entity.extent(context.graph()).center());
|
||||
var showsBrandField = fields.some(function(d) { return d.id === 'brand'; });
|
||||
var showsOperatorField = fields.some(function(d) { return d.id === 'operator'; });
|
||||
var setsName = preset.addTags.name;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { presetManager } from '../../presets';
|
||||
import { t, localizer } from '../../core/localizer';
|
||||
import { utilArrayIdentical } from '../../util/array';
|
||||
import { utilArrayUnion, utilRebind } from '../../util';
|
||||
import { geoExtent } from '../../geo/extent';
|
||||
import { uiField } from '../field';
|
||||
import { uiFormFields } from '../form_fields';
|
||||
import { uiSection } from '../section';
|
||||
@@ -32,6 +33,11 @@ export function uiSectionPresetFields(context) {
|
||||
return geoms;
|
||||
}, {}));
|
||||
|
||||
const loc = _entityIDs.reduce(function(extent, entityID) {
|
||||
var entity = context.graph().entity(entityID);
|
||||
return extent.extend(entity.extent(context.graph()));
|
||||
}, geoExtent()).center();
|
||||
|
||||
var presetsManager = presetManager;
|
||||
|
||||
var allFields = [];
|
||||
@@ -39,8 +45,8 @@ export function uiSectionPresetFields(context) {
|
||||
var sharedTotalFields;
|
||||
|
||||
_presets.forEach(function(preset) {
|
||||
var fields = preset.fields();
|
||||
var moreFields = preset.moreFields();
|
||||
var fields = preset.fields(loc);
|
||||
var moreFields = preset.moreFields(loc);
|
||||
|
||||
allFields = utilArrayUnion(allFields, fields);
|
||||
allMoreFields = utilArrayUnion(allMoreFields, moreFields);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
import { actionAddMidpoint } from '../actions/add_midpoint';
|
||||
import { actionChangeTags } from '../actions/change_tags';
|
||||
import { actionMergeNodes } from '../actions/merge_nodes';
|
||||
@@ -123,9 +125,8 @@ export function validationCrossingWays(context) {
|
||||
motorway: true, motorway_link: true, trunk: true, trunk_link: true,
|
||||
primary: true, primary_link: true, secondary: true, secondary_link: true
|
||||
};
|
||||
var nonCrossingHighways = { track: true };
|
||||
|
||||
function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
|
||||
function tagsForConnectionNodeIfAllowed(entity1, entity2, graph, lessLikelyTags) {
|
||||
var featureType1 = getFeatureType(entity1, graph);
|
||||
var featureType2 = getFeatureType(entity2, graph);
|
||||
|
||||
@@ -141,11 +142,18 @@ export function validationCrossingWays(context) {
|
||||
// one feature is a path but not both
|
||||
|
||||
var roadFeature = entity1IsPath ? entity2 : entity1;
|
||||
if (nonCrossingHighways[roadFeature.tags.highway]) {
|
||||
// don't mark path connections with certain roads as crossings
|
||||
var pathFeature = entity1IsPath ? entity1 : entity2;
|
||||
// don't mark path connections with tracks as crossings
|
||||
if (roadFeature.tags.highway === 'track') {
|
||||
return {};
|
||||
}
|
||||
// a sidewalk crossing a driveway is unremarkable and unlikely to be interrupted by the driveway
|
||||
// a sidewalk crossing another kind of service road may be similarly unremarkable
|
||||
if (!lessLikelyTags &&
|
||||
roadFeature.tags.highway === 'service' &&
|
||||
pathFeature.tags.highway === 'footway' && pathFeature.tags.footway === 'sidewalk') {
|
||||
return {};
|
||||
}
|
||||
var pathFeature = entity1IsPath ? entity1 : entity2;
|
||||
if (['marked', 'unmarked', 'traffic_signals', 'uncontrolled'].indexOf(pathFeature.tags.crossing) !== -1) {
|
||||
// if the path is a crossing, match the crossing type
|
||||
return bothLines ? { highway: 'crossing', crossing: pathFeature.tags.crossing } : {};
|
||||
@@ -435,6 +443,10 @@ export function validationCrossingWays(context) {
|
||||
|
||||
if (connectionTags) {
|
||||
fixes.push(makeConnectWaysFix(this.data.connectionTags));
|
||||
let lessLikelyConnectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph, true);
|
||||
if (lessLikelyConnectionTags && !isEqual(connectionTags, lessLikelyConnectionTags)) {
|
||||
fixes.push(makeConnectWaysFix(lessLikelyConnectionTags));
|
||||
}
|
||||
}
|
||||
|
||||
if (isCrossingIndoors) {
|
||||
@@ -692,16 +704,23 @@ export function validationCrossingWays(context) {
|
||||
function makeConnectWaysFix(connectionTags) {
|
||||
|
||||
var fixTitleID = 'connect_features';
|
||||
var fixIcon = 'iD-icon-crossing';
|
||||
if (connectionTags.highway === 'crossing') {
|
||||
fixTitleID = 'connect_using_crossing';
|
||||
fixIcon = 'temaki-pedestrian';
|
||||
}
|
||||
if (connectionTags.ford) {
|
||||
fixTitleID = 'connect_using_ford';
|
||||
if (connectionTags.highway) {
|
||||
fixIcon = 'temaki-pedestrian';
|
||||
}
|
||||
}
|
||||
|
||||
return new validationIssueFix({
|
||||
icon: 'iD-icon-crossing',
|
||||
const fix = new validationIssueFix({
|
||||
icon: fixIcon,
|
||||
title: t.append('issues.fix.' + fixTitleID + '.title'),
|
||||
onClick: function(context) {
|
||||
var loc = this.issue.loc;
|
||||
var connectionTags = this.issue.data.connectionTags;
|
||||
var edges = this.issue.data.edges;
|
||||
|
||||
context.perform(
|
||||
@@ -737,6 +756,8 @@ export function validationCrossingWays(context) {
|
||||
);
|
||||
}
|
||||
});
|
||||
fix._connectionTags = connectionTags;
|
||||
return fix;
|
||||
}
|
||||
|
||||
function makeChangeLayerFix(higherOrLower) {
|
||||
|
||||
Reference in New Issue
Block a user