mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-30 03:39:36 +02:00
presetIndex.build -> presetIndex.merge, and make it merge data
This commit is contained in:
@@ -43,9 +43,8 @@ of iD (e.g. `http://preview.ideditor.com/release/`), the following parameters ar
|
||||
* __`photo_overlay`__ - The street-level photo overlay layers to enable.<br/>
|
||||
_Example:_ `photo_overlay=streetside,mapillary,openstreetcam`<br/>
|
||||
_Available values:_ `streetside` (Microsoft Bing), `mapillary`, `mapillary-signs`, `mapillary-map-features`, `openstreetcam`
|
||||
* __`presets`__ - A path to an external presets file or a comma-separated list of preset IDs. These will be the only presets the user may select.<br/>
|
||||
_Example:_ `presets=https://path/to/presets.json`
|
||||
_Example 2:_ `presets=building,highway/residential,highway/unclassified`
|
||||
* __`presets`__ - A comma-separated list of preset IDs. These will be the only presets the user may select.<br/>
|
||||
_Example:_ `presets=building,highway/residential,highway/unclassified`
|
||||
* __`rtl=true`__ - Force iD into right-to-left mode (useful for testing).
|
||||
* __`source`__ - Prefills the changeset source. Pass a url encoded string.<br/>
|
||||
_Example:_ `source=Bing%3BMapillary`
|
||||
|
||||
@@ -2,12 +2,18 @@ import { t } from '../util/locale';
|
||||
import { presetCollection } from './collection';
|
||||
|
||||
|
||||
//
|
||||
// `presetCategory` builds a `presetCollection` of member presets,
|
||||
// decorated with some extra methods for searching and matching geometry
|
||||
//
|
||||
export function presetCategory(categoryID, category, all) {
|
||||
let _this = Object.assign({}, category); // shallow copy
|
||||
|
||||
_this.id = categoryID;
|
||||
|
||||
_this.members = presetCollection(_this.members.map(presetID => all.item(presetID)));
|
||||
_this.members = presetCollection(
|
||||
category.members.map(presetID => all.item(presetID)).filter(Boolean)
|
||||
);
|
||||
|
||||
_this.geometry = _this.members.collection
|
||||
.reduce((acc, preset) => {
|
||||
|
||||
@@ -2,6 +2,10 @@ import { t } from '../util/locale';
|
||||
import { utilSafeClassName } from '../util/util';
|
||||
|
||||
|
||||
//
|
||||
// `presetField` decorates a given `field` Object
|
||||
// with some extra methods for searching and matching geometry
|
||||
//
|
||||
export function presetField(fieldID, field) {
|
||||
let _this = Object.assign({}, field); // shallow copy
|
||||
|
||||
|
||||
+62
-93
@@ -1,5 +1,4 @@
|
||||
import { dispatch as d3_dispatch } from 'd3-dispatch';
|
||||
// import { json as d3_json } from 'd3-fetch';
|
||||
|
||||
import { osmNodeGeometriesForTags } from '../osm/tags';
|
||||
import { presetCategory } from './category';
|
||||
@@ -29,9 +28,10 @@ export function presetIndex(context) {
|
||||
const LINE = presetPreset('line', { name: 'Line', tags: {}, geometry: ['line'], matchScore: 0.1 } );
|
||||
const AREA = presetPreset('area', { name: 'Area', tags: { area: 'yes' }, geometry: ['area'], matchScore: 0.1 } );
|
||||
const RELATION = presetPreset('relation', { name: 'Relation', tags: {}, geometry: ['relation'], matchScore: 0.1 } );
|
||||
const FALLBACKS = [POINT, VERTEX, LINE, AREA, RELATION];
|
||||
|
||||
let _this = presetCollection(FALLBACKS);
|
||||
let _this = presetCollection([POINT, VERTEX, LINE, AREA, RELATION]);
|
||||
let _presets = { point: POINT, vertex: VERTEX, line: LINE, area: AREA, relation: RELATION };
|
||||
|
||||
let _defaults = {
|
||||
point: presetCollection([POINT]),
|
||||
vertex: presetCollection([VERTEX]),
|
||||
@@ -41,9 +41,10 @@ export function presetIndex(context) {
|
||||
};
|
||||
|
||||
let _fields = {};
|
||||
let _categories = {};
|
||||
let _universal = [];
|
||||
let _recents;
|
||||
// let _addablePresetIDs; // presets that the user can add
|
||||
let _addablePresetIDs; // presets that the user can add
|
||||
|
||||
// Index of presets by (geometry, tag key).
|
||||
let _geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
|
||||
@@ -70,120 +71,87 @@ export function presetIndex(context) {
|
||||
}
|
||||
|
||||
|
||||
// _this.init = (addablePresetIDs) => {
|
||||
_this.init = () => {
|
||||
// _addablePresetIDs = addablePresetIDs;
|
||||
|
||||
// let addable = true;
|
||||
// if (addablePresetIDs) {
|
||||
// addable = (presetID) => addablePresetIDs.indexOf(presetID) !== -1;
|
||||
// }
|
||||
// return _this.build(d, addable);
|
||||
|
||||
return ensurePresetData()
|
||||
.then(d => _this.build(d));
|
||||
.then(_this.merge);
|
||||
};
|
||||
|
||||
|
||||
// _this.reset = () => {
|
||||
// _defaults = {
|
||||
// point: presetCollection([]),
|
||||
// vertex: presetCollection([]),
|
||||
// line: presetCollection([]),
|
||||
// area: presetCollection([]),
|
||||
// relation: presetCollection([])
|
||||
// };
|
||||
|
||||
// _this.collection = [];
|
||||
// _recents = null;
|
||||
// _fields = {};
|
||||
// _universal = [];
|
||||
// _geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
|
||||
|
||||
// return _this;
|
||||
// };
|
||||
|
||||
|
||||
// _this.fromExternal = (external, done) => {
|
||||
// _this.reset();
|
||||
// d3_json(external)
|
||||
// .then(externalPresets => {
|
||||
// _this.build(data.presets, false); // load the default presets as non-addable to start
|
||||
// _addablePresetIDs = externalPresets.presets && Object.keys(externalPresets.presets);
|
||||
// _this.build(externalPresets, true); // then load the external presets as addable
|
||||
// })
|
||||
// .catch(() => _this.init())
|
||||
// .finally(() => done(_this));
|
||||
// };
|
||||
|
||||
// _this.build = (d, addable) => {
|
||||
_this.build = (d) => {
|
||||
if (d.fields && Object.keys(d.fields).length) {
|
||||
_this.merge = (d) => {
|
||||
// Merge Fields
|
||||
if (d.fields) {
|
||||
Object.keys(d.fields).forEach(fieldID => {
|
||||
const f = d.fields[fieldID];
|
||||
_fields[fieldID] = presetField(fieldID, f);
|
||||
if (f.universal) {
|
||||
_universal.push(_fields[fieldID]);
|
||||
if (f) { // add or replace
|
||||
_fields[fieldID] = presetField(fieldID, f);
|
||||
} else { // remove
|
||||
delete _fields[fieldID];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (d.presets && Object.keys(d.presets).length) {
|
||||
const rawPresets = d.presets;
|
||||
// Merge Presets
|
||||
if (d.presets) {
|
||||
Object.keys(d.presets).forEach(presetID => {
|
||||
const p = d.presets[presetID];
|
||||
const existing = _this.index(presetID);
|
||||
// const isAddable = typeof addable === 'function' ? addable(presetID, p) : addable;
|
||||
const isAddable = true;
|
||||
if (existing !== -1) {
|
||||
_this.collection[existing] = presetPreset(presetID, p, _fields, isAddable, rawPresets);
|
||||
} else {
|
||||
_this.collection.push(presetPreset(presetID, p, _fields, isAddable, rawPresets));
|
||||
if (p) { // add or replace
|
||||
// _presets[presetID] = presetPreset(presetID, p, _fields, isAddable, _presets);
|
||||
_presets[presetID] = presetPreset(presetID, p, _fields, true);
|
||||
} else { // remove (but not if it's a fallback)
|
||||
const existing = _presets[presetID];
|
||||
if (existing && !existing.isFallback()) {
|
||||
delete _presets[presetID];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (d.categories && Object.keys(d.categories).length) {
|
||||
// Merge Categories
|
||||
if (d.categories) {
|
||||
Object.keys(d.categories).forEach(categoryID => {
|
||||
const c = d.categories[categoryID];
|
||||
const existing = _this.index(categoryID);
|
||||
if (existing !== -1) {
|
||||
_this.collection[existing] = presetCategory(categoryID, c, _this);
|
||||
} else {
|
||||
_this.collection.push(presetCategory(categoryID, c, _this));
|
||||
if (c) { // add or replace
|
||||
_categories[categoryID] = presetCategory(categoryID, c, _this);
|
||||
} else { // remove
|
||||
delete _categories[categoryID];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const getItem = (_this.item).bind(_this);
|
||||
// if (_addablePresetIDs) {
|
||||
// ['area', 'line', 'point', 'vertex', 'relation'].forEach(geometry => {
|
||||
// _defaults[geometry] = presetCollection(
|
||||
// _addablePresetIDs.map(getItem).filter(preset => preset.geometry.indexOf(geometry) !== -1)
|
||||
// );
|
||||
// });
|
||||
// } else if (d.defaults) {
|
||||
if (d.defaults && Object.keys(d.defaults).length) {
|
||||
_defaults = {
|
||||
point: presetCollection(d.defaults.point.map(getItem)),
|
||||
vertex: presetCollection(d.defaults.vertex.map(getItem)),
|
||||
line: presetCollection(d.defaults.line.map(getItem)),
|
||||
area: presetCollection(d.defaults.area.map(getItem)),
|
||||
relation: presetCollection(d.defaults.relation.map(getItem))
|
||||
};
|
||||
}
|
||||
|
||||
for (let i = 0; i < _this.collection.length; i++) {
|
||||
const preset = _this.collection[i];
|
||||
const geometry = preset.geometry;
|
||||
|
||||
for (let j = 0; j < geometry.length; j++) {
|
||||
let g = _geometryIndex[geometry[j]];
|
||||
for (let k in preset.tags) {
|
||||
(g[k] = g[k] || []).push(preset);
|
||||
// Merge Defaults
|
||||
if (d.defaults) {
|
||||
Object.keys(d.defaults).forEach(geometry => {
|
||||
const def = d.defaults[geometry];
|
||||
if (Array.isArray(def)) { // add or replace
|
||||
_defaults[geometry] = presetCollection(
|
||||
def.map(presetID => _presets[presetID]).filter(Boolean)
|
||||
);
|
||||
} else { // remove
|
||||
delete _defaults[geometry];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Rebuild universal fields
|
||||
_universal = Object.values(_fields).reduce((acc, field) => {
|
||||
if (field.universal) acc.push(field);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Rebuild _this.collection
|
||||
_this.collection = Object.values(_presets).concat(Object.values(_categories));
|
||||
|
||||
// Rebuild geometry index
|
||||
_geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
|
||||
_this.collection.forEach(preset => {
|
||||
(preset.geometry || []).forEach(geometry => {
|
||||
let g = _geometryIndex[geometry];
|
||||
for (let key in preset.tags) {
|
||||
(g[key] = g[key] || []).push(preset);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return _this;
|
||||
};
|
||||
|
||||
@@ -482,5 +450,6 @@ export function presetIndex(context) {
|
||||
setRecents(items);
|
||||
};
|
||||
|
||||
|
||||
return utilRebind(_this, dispatch, 'on');
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@ import { utilArrayUniq, utilObjectOmit } from '../util';
|
||||
import { utilSafeClassName } from '../util/util';
|
||||
|
||||
|
||||
//
|
||||
// `presetPreset` decorates a given `preset` Object
|
||||
// with some extra methods for searching and matching geometry
|
||||
//
|
||||
export function presetPreset(presetID, preset, fields, addable, rawPresets) {
|
||||
let _this = Object.assign({}, preset); // shallow copy
|
||||
|
||||
|
||||
@@ -1,31 +1,25 @@
|
||||
describe('iD.presetCategory', function() {
|
||||
var category, residential;
|
||||
var category = {
|
||||
'geometry': 'line',
|
||||
'icon': 'highway',
|
||||
'name': 'roads',
|
||||
'members': [ 'highway/residential' ]
|
||||
};
|
||||
|
||||
var residential = iD.presetPreset('highway/residential',
|
||||
{ tags: { highway: 'residential' }, geometry: ['line'] }
|
||||
);
|
||||
var all = iD.presetCollection([residential]);
|
||||
|
||||
beforeEach(function() {
|
||||
category = {
|
||||
'geometry': 'line',
|
||||
'icon': 'highway',
|
||||
'name': 'roads',
|
||||
'members': [
|
||||
'highway/residential'
|
||||
]
|
||||
};
|
||||
residential = iD.presetPreset('highway/residential', {
|
||||
tags: {
|
||||
highway: 'residential'
|
||||
},
|
||||
geometry: ['line']
|
||||
});
|
||||
});
|
||||
|
||||
it('maps members names to preset instances', function() {
|
||||
var c = iD.presetCategory('road', category, iD.presetCollection([residential]));
|
||||
var c = iD.presetCategory('road', category, all);
|
||||
expect(c.members.collection[0]).to.eql(residential);
|
||||
});
|
||||
|
||||
describe('#matchGeometry', function() {
|
||||
it('matches the type of an entity', function() {
|
||||
var c = iD.presetCategory('road', category, iD.presetCollection([residential]));
|
||||
var c = iD.presetCategory('road', category, all);
|
||||
expect(c.matchGeometry('line')).to.eql(true);
|
||||
expect(c.matchGeometry('point')).to.eql(false);
|
||||
});
|
||||
|
||||
@@ -15,56 +15,56 @@ describe('iD.presetCollection', function() {
|
||||
tags: {},
|
||||
geometry: ['area']
|
||||
}),
|
||||
grill: iD.presetPreset('__test/amenity/bbq', {
|
||||
grill: iD.presetPreset('amenity/bbq', {
|
||||
name: 'Grill',
|
||||
tags: { amenity: 'bbq' },
|
||||
geometry: ['point'],
|
||||
terms: []
|
||||
}),
|
||||
sandpit: iD.presetPreset('__test/amenity/grit_bin', {
|
||||
sandpit: iD.presetPreset('amenity/grit_bin', {
|
||||
name: 'Sandpit',
|
||||
tags: { amenity: 'grit_bin' },
|
||||
geometry: ['point'],
|
||||
terms: []
|
||||
}),
|
||||
residential: iD.presetPreset('__test/highway/residential', {
|
||||
residential: iD.presetPreset('highway/residential', {
|
||||
name: 'Residential Area',
|
||||
tags: { highway: 'residential' },
|
||||
geometry: ['point', 'area'],
|
||||
terms: []
|
||||
}),
|
||||
grass1: iD.presetPreset('__test/landuse/grass1', {
|
||||
grass1: iD.presetPreset('landuse/grass1', {
|
||||
name: 'Grass',
|
||||
tags: { landuse: 'grass' },
|
||||
geometry: ['point', 'area'],
|
||||
terms: []
|
||||
}),
|
||||
grass2: iD.presetPreset('__test/landuse/grass2', {
|
||||
grass2: iD.presetPreset('landuse/grass2', {
|
||||
name: 'Ğṝȁß',
|
||||
tags: { landuse: 'ğṝȁß' },
|
||||
geometry: ['point', 'area'],
|
||||
terms: []
|
||||
}),
|
||||
park: iD.presetPreset('__test/leisure/park', {
|
||||
park: iD.presetPreset('leisure/park', {
|
||||
name: 'Park',
|
||||
tags: { leisure: 'park' },
|
||||
geometry: ['point', 'area'],
|
||||
terms: [ 'grass' ],
|
||||
matchScore: 0.5
|
||||
}),
|
||||
parking: iD.presetPreset('__test/amenity/parking', {
|
||||
parking: iD.presetPreset('amenity/parking', {
|
||||
name: 'Parking',
|
||||
tags: { amenity: 'parking' },
|
||||
geometry: ['point', 'area'],
|
||||
terms: [ 'cars' ]
|
||||
}),
|
||||
soccer: iD.presetPreset('__test/leisure/pitch/soccer', {
|
||||
soccer: iD.presetPreset('leisure/pitch/soccer', {
|
||||
name: 'Soccer Field',
|
||||
tags: { leisure: 'pitch', sport: 'soccer' },
|
||||
geometry: ['point', 'area'],
|
||||
terms: ['fußball']
|
||||
}),
|
||||
football: iD.presetPreset('__test/leisure/pitch/american_football', {
|
||||
football: iD.presetPreset('leisure/pitch/american_football', {
|
||||
name: 'Football Field',
|
||||
tags: { leisure: 'pitch', sport: 'american_football' },
|
||||
geometry: ['point', 'area'],
|
||||
@@ -80,7 +80,7 @@ describe('iD.presetCollection', function() {
|
||||
|
||||
describe('#item', function() {
|
||||
it('fetches a preset by id', function() {
|
||||
expect(c.item('__test/highway/residential')).to.equal(p.residential);
|
||||
expect(c.item('highway/residential')).to.equal(p.residential);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -148,7 +148,7 @@ describe('iD.presetCollection', function() {
|
||||
});
|
||||
|
||||
it('excludes presets with searchable: false', function() {
|
||||
var excluded = iD.presetPreset('__test/excluded', {
|
||||
var excluded = iD.presetPreset('excluded', {
|
||||
name: 'excluded',
|
||||
tags: { amenity: 'excluded' },
|
||||
geometry: ['point'],
|
||||
|
||||
Reference in New Issue
Block a user