Use live bound object for presets object, change context.presets() getter

This commit is contained in:
Bryan Housel
2016-11-14 15:44:02 -05:00
parent 93d50b4e87
commit 9b7d79a3fe
24 changed files with 393 additions and 331 deletions
+53 -8
View File
@@ -145,7 +145,7 @@ certain parts of the iD code to be replaced at runtime by custom code or data.
iD is written in a modular style and bundled with [rollup.js](http://rollupjs.org/),
which makes hot code replacement tricky. (ES6 module exports are
[immutable bindings](http://www.2ality.com/2015/07/es6-module-exports.html)).
[immutable live bindings](http://www.2ality.com/2015/07/es6-module-exports.html)).
Because of this, the parts of iD which are designed for customization are exported
as live bound objects that can be overriden at runtime _before initializing the iD context_.
@@ -169,7 +169,9 @@ delete iD.services.mapillary;
### Background Imagery
iD's background imagery database is stored in the `iD.data.imagery` array and can be
overridden. (Note that the "None" and "Custom" options will always be shown in the list)
overridden or modified prior to creating the iD context.
Note that the "None" and "Custom" options will always be shown in the list.
To remove all imagery from iD:
```js
@@ -213,16 +215,59 @@ For more details about the `iD.data.imagery` structure, see
### Presets
iD can use external presets exclusively or along with the default OpenStreetMap presets. This is configured using the `context.presets` accessor. To use external presets alone, initialize the iD context with a custom `Presets` object:
iD's preset database is stored in the `iD.data.presets` object and can be overridden
or modified prior to creating the iD context.
The format of the `presets` object is
[documented here](https://github.com/openstreetmap/iD/tree/master/data/presets#custom-presets).
To add a new preset to iD's existing preset database.
```js
var id = iD.Context()
.presets(customPresets);
iD.data.presets.presets["aerialway/zipline"] = {
geometry: ["line"],
fields: ["incline"],
tags: { "aerialway": "zip_line" },
name: "Zipline"
};
```
The format of the Preset object is [documented here](https://github.com/openstreetmap/iD/tree/master/data/presets#custom-presets).
To completely replace iD's default presets with your own:
```js
iD.data.presets = myPresets;
```
To run iD with the minimal set of presets that only match basic geometry types:
```js
iD.data.presets = {
presets: {
"area": {
"name": "Area",
"tags": {},
"geometry": ["area"]
},
"line": {
"name": "Line",
"tags": {},
"geometry": ["line"]
},
"point": {
"name": "Point",
"tags": {},
"geometry": ["point"]
},
"vertex": {
"name": "Vertex",
"tags": {},
"geometry": ["vertex"]
},
"relation": {
"name": "Relation",
"tags": {},
"geometry": ["relation"]
}
}
};
```
### Minimum Editable Zoom
+3
View File
@@ -7,6 +7,9 @@
* :warning: Flattened namespace means that all functions have changed names (#3479)
* e.g. `iD.actions.Move` -> `iD.actionMove`, `iD.geo.Extent` -> `iD.geoExtent`
* Many deprecated names are still exported as symbols, e.g. `iD.Context` - we will remove these eventually
* :warning: Customized iD deployments can manipulate live objects, rather than iD.Context accessors
* No longer need to call things like `presets()`, `imagery()`, `taginfo()` when creating `iD.Context`
* See [API.md](https://github.com/openstreetmap/iD/blob/master/API.md#customized-deployments) for details on customized deployments
* :warning: iD has upgraded to the latest released versions of d3, lodash, rbush, etc.
* d3 no longer adds itself to the global namespace, but can now be accessed via `iD.d3`
* :warning: iD now uses `npm` scripts for all build processes
+8 -9
View File
@@ -12,19 +12,18 @@ export { default as dataImperial } from './imperial.json';
export { default as dataDriveLeft } from './drive-left.json';
export { en as dataEn } from '../dist/locales/en.json';
import { dataImagery } from './imagery.json';
import { presets } from './presets/presets.json';
import { defaults } from './presets/defaults.json';
import { categories } from './presets/categories.json';
import { fields } from './presets/fields.json';
export var dataPresets = {
presets: presets,
defaults: defaults,
categories: categories,
fields: fields
};
import { dataImagery } from './imagery.json';
export var data = {
imagery: dataImagery
imagery: dataImagery,
presets: {
presets: presets,
defaults: defaults,
categories: categories,
fields: fields
}
};
+6
View File
@@ -274,6 +274,12 @@ For example:
"tags": {},
"geometry": ["vertex"],
"matchScore": 0.1
},
"relation": {
"name": "Relation",
"tags": {},
"geometry": ["relation"],
"matchScore": 0.1
}
```
+1 -3
View File
@@ -37,9 +37,7 @@
document.getElementById('id-container').innerHTML = 'Sorry, your browser is not currently supported. Please use Potlatch 2 to edit the map.';
document.getElementById('id-container').className = 'unsupported';
} else {
var id = iD.Context()
.presets(iD.dataPresets);
var id = iD.Context();
id.ui()(document.getElementById('id-container'));
}
</script>
-1
View File
@@ -19,7 +19,6 @@
<script>
id = iD.Context()
.presets(iD.dataPresets)
.assetPath('dist/');
id.ui()(document.getElementById('id-container'), function() {
+9 -12
View File
@@ -5,7 +5,7 @@ import { coreHistory } from './history';
import { dataLocales, dataEn } from '../../data/index';
import { geoRawMercator } from '../geo/raw_mercator';
import { modeSelect } from '../modes/select';
import { presetInit } from '../presets/init';
import { presetIndex } from '../presets/index';
import { rendererBackground } from '../renderer/background';
import { rendererFeatures } from '../renderer/features';
import { rendererMap } from '../renderer/map';
@@ -212,6 +212,11 @@ export function coreContext() {
};
/* Presets */
var presets;
context.presets = function() { return presets; };
/* Map */
var map;
context.map = function() { return map; };
@@ -249,16 +254,6 @@ export function coreContext() {
};
/* Presets */
var presets;
context.presets = function(_) {
if (!arguments.length) return presets;
presets.load(_);
areaKeys = presets.areaKeys();
return context;
};
/* Container */
var container, embed;
context.container = function(_) {
@@ -389,6 +384,7 @@ export function coreContext() {
background = rendererBackground(context);
features = rendererFeatures(context);
presets = presetIndex();
map = rendererMap(context);
context.mouse = map.mouse;
@@ -401,7 +397,8 @@ export function coreContext() {
context.redrawEnable = map.redrawEnable;
background.init();
presets = presetInit();
presets.init();
areaKeys = presets.areaKeys();
_.each(services, function(service) {
if (service && typeof service.init === 'function') {
+10 -6
View File
@@ -244,10 +244,11 @@ export function modeSelect(context, selectedIDs) {
return;
}
var parent = singularParent();
if (parent) {
surface.selectAll('.related')
.classed('related', false);
surface.selectAll('.related')
.classed('related', false);
singularParent();
if (relatedParent) {
surface.selectAll(utilEntitySelector([relatedParent]))
.classed('related', true);
}
@@ -363,8 +364,11 @@ export function modeSelect(context, selectedIDs) {
var surface = context.surface();
surface.selectAll('.related')
.classed('related', false);
surface.selectAll(utilEntitySelector([relatedParent]))
.classed('related', true);
if (relatedParent) {
surface.selectAll(utilEntitySelector([relatedParent]))
.classed('related', true);
}
}
+177 -5
View File
@@ -1,5 +1,177 @@
export { presetCategory } from './category.js';
export { presetCollection } from './collection.js';
export { presetField } from './field.js';
export { presetInit } from './init.js';
export { presetPreset } from './preset.js';
import _ from 'lodash';
import { data } from '../../data/index';
import { presetCategory } from './category';
import { presetCollection } from './collection';
import { presetField } from './field';
import { presetPreset } from './preset';
export { presetCategory };
export { presetCollection };
export { presetField };
export { presetPreset };
export function presetIndex() {
// a presetCollection with methods for
// loading new data and returning defaults
var all = presetCollection([]),
defaults = { area: all, line: all, point: all, vertex: all, relation: all },
fields = {},
universal = [],
recent = presetCollection([]);
// Index of presets by (geometry, tag key).
var index = {
point: {},
vertex: {},
line: {},
area: {},
relation: {}
};
all.match = function(entity, resolver) {
var geometry = entity.geometry(resolver);
// Treat entities on addr:interpolation lines as points, not vertices (#3241)
if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
geometry = 'point';
}
var geometryMatches = index[geometry],
best = -1,
match;
for (var k in entity.tags) {
var keyMatches = geometryMatches[k];
if (!keyMatches) continue;
for (var i = 0; i < keyMatches.length; i++) {
var score = keyMatches[i].matchScore(entity);
if (score > best) {
best = score;
match = keyMatches[i];
}
}
}
return match || all.item(geometry);
};
// Because of the open nature of tagging, iD will never have a complete
// list of tags used in OSM, so we want it to have logic like "assume
// that a closed way with an amenity tag is an area, unless the amenity
// is one of these specific types". This function computes a structure
// that allows testing of such conditions, based on the presets designated
// as as supporting (or not supporting) the area geometry.
//
// The returned object L is a whitelist/blacklist of tags. A closed way
// with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
// (see `Way#isArea()`). In other words, the keys of L form the whitelist,
// and the subkeys form the blacklist.
all.areaKeys = function() {
var areaKeys = {},
ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],
presets = _.reject(all.collection, 'suggestion');
// whitelist
presets.forEach(function(d) {
for (var key in d.tags) break;
if (!key) return;
if (ignore.indexOf(key) !== -1) return;
if (d.geometry.indexOf('area') !== -1) {
areaKeys[key] = areaKeys[key] || {};
}
});
// blacklist
presets.forEach(function(d) {
for (var key in d.tags) break;
if (!key) return;
if (ignore.indexOf(key) !== -1) return;
var value = d.tags[key];
if (d.geometry.indexOf('area') === -1 &&
d.geometry.indexOf('line') !== -1 &&
key in areaKeys && value !== '*') {
areaKeys[key][value] = true;
}
});
return areaKeys;
};
all.init = function() {
var d = data.presets;
if (d.fields) {
_.forEach(d.fields, function(d, id) {
fields[id] = presetField(id, d);
if (d.universal) universal.push(fields[id]);
});
}
if (d.presets) {
_.forEach(d.presets, function(d, id) {
all.collection.push(presetPreset(id, d, fields));
});
}
if (d.categories) {
_.forEach(d.categories, function(d, id) {
all.collection.push(presetCategory(id, d, all));
});
}
if (d.defaults) {
var getItem = _.bind(all.item, all);
defaults = {
area: presetCollection(d.defaults.area.map(getItem)),
line: presetCollection(d.defaults.line.map(getItem)),
point: presetCollection(d.defaults.point.map(getItem)),
vertex: presetCollection(d.defaults.vertex.map(getItem)),
relation: presetCollection(d.defaults.relation.map(getItem))
};
}
for (var i = 0; i < all.collection.length; i++) {
var preset = all.collection[i],
geometry = preset.geometry;
for (var j = 0; j < geometry.length; j++) {
var g = index[geometry[j]];
for (var k in preset.tags) {
(g[k] = g[k] || []).push(preset);
}
}
}
return all;
};
all.field = function(id) {
return fields[id];
};
all.universal = function() {
return universal;
};
all.defaults = function(geometry, n) {
var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
def = _.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
return presetCollection(_.uniq(rec.concat(def).concat(all.item(geometry))));
};
all.choose = function(preset) {
if (!preset.isFallback()) {
recent = presetCollection(_.uniq([preset].concat(recent.collection)));
}
return all;
};
return all;
}
-168
View File
@@ -1,168 +0,0 @@
import _ from 'lodash';
import { presetCategory } from './category';
import { presetCollection } from './collection';
import { presetField } from './field';
import { presetPreset } from './preset';
export function presetInit() {
// a presetCollection with methods for
// loading new data and returning defaults
var all = presetCollection([]),
defaults = { area: all, line: all, point: all, vertex: all, relation: all },
fields = {},
universal = [],
recent = presetCollection([]);
// Index of presets by (geometry, tag key).
var index = {
point: {},
vertex: {},
line: {},
area: {},
relation: {}
};
all.match = function(entity, resolver) {
var geometry = entity.geometry(resolver);
// Treat entities on addr:interpolation lines as points, not vertices (#3241)
if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
geometry = 'point';
}
var geometryMatches = index[geometry],
best = -1,
match;
for (var k in entity.tags) {
var keyMatches = geometryMatches[k];
if (!keyMatches) continue;
for (var i = 0; i < keyMatches.length; i++) {
var score = keyMatches[i].matchScore(entity);
if (score > best) {
best = score;
match = keyMatches[i];
}
}
}
return match || all.item(geometry);
};
// Because of the open nature of tagging, iD will never have a complete
// list of tags used in OSM, so we want it to have logic like "assume
// that a closed way with an amenity tag is an area, unless the amenity
// is one of these specific types". This function computes a structure
// that allows testing of such conditions, based on the presets designated
// as as supporting (or not supporting) the area geometry.
//
// The returned object L is a whitelist/blacklist of tags. A closed way
// with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
// (see `Way#isArea()`). In other words, the keys of L form the whitelist,
// and the subkeys form the blacklist.
all.areaKeys = function() {
var areaKeys = {},
ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],
presets = _.reject(all.collection, 'suggestion');
// whitelist
presets.forEach(function(d) {
for (var key in d.tags) break;
if (!key) return;
if (ignore.indexOf(key) !== -1) return;
if (d.geometry.indexOf('area') !== -1) {
areaKeys[key] = areaKeys[key] || {};
}
});
// blacklist
presets.forEach(function(d) {
for (var key in d.tags) break;
if (!key) return;
if (ignore.indexOf(key) !== -1) return;
var value = d.tags[key];
if (d.geometry.indexOf('area') === -1 &&
d.geometry.indexOf('line') !== -1 &&
key in areaKeys && value !== '*') {
areaKeys[key][value] = true;
}
});
return areaKeys;
};
all.load = function(d) {
if (d.fields) {
_.forEach(d.fields, function(d, id) {
fields[id] = presetField(id, d);
if (d.universal) universal.push(fields[id]);
});
}
if (d.presets) {
_.forEach(d.presets, function(d, id) {
all.collection.push(presetPreset(id, d, fields));
});
}
if (d.categories) {
_.forEach(d.categories, function(d, id) {
all.collection.push(presetCategory(id, d, all));
});
}
if (d.defaults) {
var getItem = _.bind(all.item, all);
defaults = {
area: presetCollection(d.defaults.area.map(getItem)),
line: presetCollection(d.defaults.line.map(getItem)),
point: presetCollection(d.defaults.point.map(getItem)),
vertex: presetCollection(d.defaults.vertex.map(getItem)),
relation: presetCollection(d.defaults.relation.map(getItem))
};
}
for (var i = 0; i < all.collection.length; i++) {
var preset = all.collection[i],
geometry = preset.geometry;
for (var j = 0; j < geometry.length; j++) {
var g = index[geometry[j]];
for (var k in preset.tags) {
(g[k] = g[k] || []).push(preset);
}
}
}
return all;
};
all.field = function(id) {
return fields[id];
};
all.universal = function() {
return universal;
};
all.defaults = function(geometry, n) {
var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
def = _.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
return presetCollection(_.uniq(rec.concat(def).concat(all.item(geometry))));
};
all.choose = function(preset) {
if (!preset.isFallback()) {
recent = presetCollection(_.uniq([preset].concat(recent.collection)));
}
return all;
};
return all;
}
+10 -3
View File
@@ -1,11 +1,15 @@
import * as d3 from 'd3';
import _ from 'lodash';
import { d3combobox } from '../lib/d3.combobox.js';
import { t } from '../util/locale';
import { d3combobox } from '../lib/d3.combobox.js';
import { modeSelect } from '../modes/index';
import { svgIcon } from '../svg/index';
import { tooltip } from '../util/tooltip';
import { utilDisplayName, utilEntityOrMemberSelector } from '../util/index';
import {
utilDisplayName,
utilDisplayType,
utilEntityOrMemberSelector
} from '../util/index';
import { utilRebind } from '../util/rebind';
import { utilTriggerEvent } from '../util/trigger_event';
@@ -229,7 +233,10 @@ export function uiCommit(context) {
li.append('strong')
.attr('class', 'entity-type')
.text(function(d) { return context.presets().match(d.entity, d.graph).name(); });
.text(function(d) {
var matched = context.presets().match(d.entity, d.graph);
return (matched && matched.name()) || utilDisplayType(d.entity.id);
});
li.append('span')
.attr('class', 'entity-name')
+8 -2
View File
@@ -5,7 +5,11 @@ import { geoExtent, geoChooseEdge } from '../geo/index';
import { modeSelect } from '../modes/index';
import { osmEntity } from '../osm/index';
import { svgIcon } from '../svg/index';
import { utilDisplayName, utilEntityOrMemberSelector } from '../util/index';
import {
utilDisplayName,
utilDisplayType,
utilEntityOrMemberSelector
} from '../util/index';
export function uiFeatureList(context) {
@@ -111,11 +115,13 @@ export function uiFeatureList(context) {
var name = utilDisplayName(entity) || '';
if (name.toLowerCase().indexOf(q) >= 0) {
var matched = context.presets().match(entity, graph),
type = (matched && matched.name()) || utilDisplayType(entity.id);
result.push({
id: entity.id,
entity: entity,
geometry: context.geometry(entity.id),
type: context.presets().match(entity, graph).name(),
type: type,
name: name
});
}
+10 -5
View File
@@ -95,9 +95,14 @@ export function uiPreset(context) {
function content(selection) {
if (!fieldsArr) {
var entity = context.entity(id),
geometry = context.geometry(id);
geometry = context.geometry(id),
presets = context.presets();
fieldsArr = [UIField(context.presets().field('name'), entity)];
fieldsArr = [];
if (presets.field('name')) {
fieldsArr.push(UIField(presets.field('name'), entity));
}
preset.fields.forEach(function(field) {
if (field.matchGeometry(geometry)) {
@@ -105,11 +110,11 @@ export function uiPreset(context) {
}
});
if (entity.isHighwayIntersection(context.graph())) {
fieldsArr.push(UIField(context.presets().field('restrictions'), entity, true));
if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) {
fieldsArr.push(UIField(presets.field('restrictions'), entity, true));
}
context.presets().universal().forEach(function(field) {
presets.universal().forEach(function(field) {
if (preset.fields.indexOf(field) < 0) {
fieldsArr.push(UIField(field, entity));
}
+5 -2
View File
@@ -7,7 +7,7 @@ import { osmEntity } from '../osm/index';
import { svgIcon } from '../svg/index';
import { services } from '../services/index';
import { uiDisclosure } from './disclosure';
import { utilDisplayName } from '../util/index';
import { utilDisplayName, utilDisplayType } from '../util/index';
export function uiRawMemberEditor(context) {
@@ -109,7 +109,10 @@ export function uiRawMemberEditor(context) {
label.append('span')
.attr('class', 'member-entity-type')
.text(function(d) { return context.presets().match(d.member, context.graph()).name(); });
.text(function(d) {
var matched = context.presets().match(d.member, context.graph());
return (matched && matched.name()) || utilDisplayType(d.member.id);
});
label.append('span')
.attr('class', 'member-entity-name')
+4 -2
View File
@@ -80,7 +80,8 @@ export function uiRawMembershipEditor(context) {
if (entity.type !== 'relation' || entity.id === id)
return;
var presetName = context.presets().match(entity, graph).name(),
var matched = context.presets().match(entity, graph),
presetName = (matched && matched.name()) || t('inspector.relation'),
entityName = utilDisplayName(entity) || '';
var value = presetName + ' ' + entityName;
@@ -175,7 +176,8 @@ export function uiRawMembershipEditor(context) {
.append('span')
.attr('class', 'member-entity-type')
.text(function(d) {
return context.presets().match(d.relation, context.graph()).name();
var matched = context.presets().match(d.relation, context.graph());
return (matched && matched.name()) || t('inspector.relation');
});
label
+1 -1
View File
@@ -90,7 +90,7 @@
<script src='spec/presets/category.js'></script>
<script src='spec/presets/collection.js'></script>
<script src='spec/presets/init.js'></script>
<script src='spec/presets/index.js'></script>
<script src='spec/presets/preset.js'></script>
<script src='spec/renderer/background_source.js'></script>
+1 -1
View File
@@ -46,7 +46,7 @@
};
context.presets = function() {
return iD.presetInit().load({
return iD.presetIndex().load({
presets: {
'amenity/restaurant': {
geometry: ['point'],
+1 -2
View File
@@ -1,8 +1,7 @@
describe('iD.actionSplit', function () {
beforeEach(function () {
iD.areaKeys = iD.Context()
.presets(iD.dataPresets).presets().areaKeys();
iD.areaKeys = iD.Context().presets().areaKeys();
});
describe('#disabled', function () {
-48
View File
@@ -51,54 +51,6 @@ describe('iD.Context', function() {
});
});
describe('#presets', function() {
it('supports custom presets', function() {
var presetsCollection = {
presets: {
'mines': {
geometry: ['point', 'area'],
name: 'Mining Concession',
tags: { 'concession': 'mining' }
},
'area': {
'name': 'Area',
'tags': {},
'geometry': ['area']
},
'point': {
'name': 'Point',
'tags': {},
'geometry': ['point']
},
'line': {
'name': 'Line',
'tags': {},
'geometry': ['line']
},
'vertex': {
'name': 'Other',
'tags': {},
'geometry': ['vertex']
}
},
fields: {
'name': {
'key': 'name',
'type': 'localized',
'label': 'Name',
'placeholder': 'Common name (if any)'
}
}
};
var context = iD.Context().presets(presetsCollection),
way = iD.Way({tags: {concession: 'mining', area: 'yes'}}),
graph = iD.Graph([way]);
expect(context.presets().match(way, graph).id).to.eql('mines');
});
});
describe('#debug', function() {
it('sets and gets debug flags', function() {
var context = iD.Context(),
-1
View File
@@ -5,7 +5,6 @@ describe.skip('iD.modeAddPoint', function() {
var container = d3.select(document.createElement('div'));
context = iD.Context()
.presets(iD.dataPresets)
.container(container);
context.loadTiles = function () {};
+1 -1
View File
@@ -318,7 +318,7 @@ describe('iD.osmWay', function() {
describe('#isArea', function() {
before(function() {
iD.Context().presets(iD.dataPresets);
iD.Context();
});
it('returns false when the way has no tags', function() {
@@ -1,65 +1,84 @@
describe('iD.presetInit', function() {
var p = {
point: {
tags: {},
geometry: ['point']
},
line: {
tags: {},
geometry: ['line']
},
vertex: {
tags: {},
geometry: ['vertex']
},
residential: {
tags: { highway: 'residential' },
geometry: ['line']
},
park: {
tags: { leisure: 'park' },
geometry: ['point', 'area']
}
};
describe('iD.presetIndex', function() {
var savedPresets;
var c = iD.presetInit().load({presets: p});
before(function () {
savedPresets = iD.data.presets;
});
after(function () {
iD.data.presets = savedPresets;
});
describe('#match', function() {
var testPresets = {
presets: {
point: {
tags: {},
geometry: ['point']
},
line: {
tags: {},
geometry: ['line']
},
vertex: {
tags: {},
geometry: ['vertex']
},
residential: {
tags: { highway: 'residential' },
geometry: ['line']
},
park: {
tags: { leisure: 'park' },
geometry: ['point', 'area']
}
}
};
it('returns a collection containing presets matching a geometry and tags', function() {
var way = iD.Way({ tags: { highway: 'residential' } }),
iD.data.presets = testPresets;
var presets = iD.Context().presets(),
way = iD.Way({ tags: { highway: 'residential' } }),
graph = iD.Graph([way]);
expect(c.match(way, graph).id).to.eql('residential');
expect(presets.match(way, graph).id).to.eql('residential');
});
it('returns the appropriate fallback preset when no tags match', function() {
var point = iD.Node(),
iD.data.presets = testPresets;
var presets = iD.Context().presets(),
point = iD.Node(),
line = iD.Way({ tags: { foo: 'bar' } }),
graph = iD.Graph([point, line]);
expect(c.match(point, graph).id).to.eql('point');
expect(c.match(line, graph).id).to.eql('line');
expect(presets.match(point, graph).id).to.eql('point');
expect(presets.match(line, graph).id).to.eql('line');
});
it('matches vertices on a line as vertices', function() {
var point = iD.Node({ tags: { leisure: 'park' } }),
iD.data.presets = testPresets;
var presets = iD.Context().presets(),
point = iD.Node({ tags: { leisure: 'park' } }),
line = iD.Way({ nodes: [point.id], tags: { 'highway': 'residential' } }),
graph = iD.Graph([point, line]);
expect(c.match(point, graph).id).to.eql('vertex');
expect(presets.match(point, graph).id).to.eql('vertex');
});
it('matches vertices on an addr:interpolation line as points', function() {
var point = iD.Node({ tags: { leisure: 'park' } }),
iD.data.presets = testPresets;
var presets = iD.Context().presets(),
point = iD.Node({ tags: { leisure: 'park' } }),
line = iD.Way({ nodes: [point.id], tags: { 'addr:interpolation': 'even' } }),
graph = iD.Graph([point, line]);
expect(c.match(point, graph).id).to.eql('park');
expect(presets.match(point, graph).id).to.eql('park');
});
});
describe('#areaKeys', function() {
var presets = iD.presetInit().load({
var testPresets = {
presets: {
'amenity/fuel/shell': {
tags: { 'amenity': 'fuel' },
@@ -91,62 +110,78 @@ describe('iD.presetInit', function() {
geometry: ['point', 'area']
}
}
});
};
it('whitelists keys for presets with area geometry', function() {
iD.data.presets = testPresets;
var presets = iD.Context().presets();
expect(presets.areaKeys()).to.include.keys('natural');
});
it('blacklists key-values for presets with a line geometry', function() {
iD.data.presets = testPresets;
var presets = iD.Context().presets();
expect(presets.areaKeys().natural).to.include.keys('tree_row');
expect(presets.areaKeys().natural.tree_row).to.be.true;
});
it('does not blacklist key-values for presets with both area and line geometry', function() {
iD.data.presets = testPresets;
var presets = iD.Context().presets();
expect(presets.areaKeys().golf).not.to.include.keys('water_hazard');
});
it('does not blacklist key-values for presets with neither area nor line geometry', function() {
iD.data.presets = testPresets;
var presets = iD.Context().presets();
expect(presets.areaKeys().natural).not.to.include.keys('peak');
});
it('does not blacklist generic \'*\' key-values', function() {
iD.data.presets = testPresets;
var presets = iD.Context().presets();
expect(presets.areaKeys().natural).not.to.include.keys('natural');
});
it('ignores keys like \'highway\' that are assumed to be lines', function() {
iD.data.presets = testPresets;
var presets = iD.Context().presets();
expect(presets.areaKeys()).not.to.include.keys('highway');
});
it('ignores suggestion presets', function() {
iD.data.presets = testPresets;
var presets = iD.Context().presets();
expect(presets.areaKeys()).not.to.include.keys('amenity');
});
});
describe('expected matches', function() {
var presets;
before(function() {
presets = iD.presetInit().load(iD.dataPresets);
});
describe('expected matches', function() {
it('prefers building to multipolygon', function() {
var relation = iD.Relation({tags: {type: 'multipolygon', building: 'yes'}}),
graph = iD.Graph([relation]);
iD.data.presets = savedPresets;
var presets = iD.Context().presets(),
relation = iD.Relation({ tags: { type: 'multipolygon', building: 'yes' }}),
graph = iD.Graph([relation]);
expect(presets.match(relation, graph).id).to.eql('building');
});
it('prefers building to address', function() {
var way = iD.Way({tags: {area: 'yes', building: 'yes', 'addr:housenumber': '1234'}}),
iD.data.presets = savedPresets;
var presets = iD.Context().presets(),
way = iD.Way({ tags: { area: 'yes', building: 'yes', 'addr:housenumber': '1234' }}),
graph = iD.Graph([way]);
expect(presets.match(way, graph).id).to.eql('building');
});
it('prefers pedestrian to area', function() {
var way = iD.Way({tags: {area: 'yes', highway: 'pedestrian'}}),
iD.data.presets = savedPresets;
var presets = iD.Context().presets(),
way = iD.Way({ tags: { area: 'yes', highway: 'pedestrian' }}),
graph = iD.Graph([way]);
expect(presets.match(way, graph).id).to.eql('highway/pedestrian');
});
});
});
+1 -2
View File
@@ -2,8 +2,7 @@ describe('iD.uiFieldAccess', function() {
var selection, field;
beforeEach(function() {
selection = d3.select(document.createElement('div'));
field = iD.Context()
.presets(iD.dataPresets).presets().field('access');
field = iD.Context().presets().field('access');
});
it('creates inputs for a variety of modes of access', function() {
+3 -3
View File
@@ -14,7 +14,7 @@ describe('iD.uiFieldWikipedia', function() {
context = iD.Context();
context.history().merge([entity]);
selection = d3.select(document.createElement('div'));
field = context.presets(iD.dataPresets).presets().field('wikipedia');
field = context.presets().field('wikipedia');
window.JSONP_DELAY = 0;
window.JSONP_FIX = {
entities: {
@@ -114,7 +114,7 @@ describe('iD.uiFieldWikipedia', function() {
// skip delayed wikidata for 'Skip' // 'Skip' wikidata +20ms
expect(spy.getCall(4)).to.have.been.calledWith({ wikipedia: 'de:Title', wikidata: 'Q216353' }); // 'Title' wikidata +40ms
done();
}, 50);
}, 100);
});
it('does not set delayed wikidata tag if selected entity has changed', function(done) {
@@ -140,7 +140,7 @@ describe('iD.uiFieldWikipedia', function() {
expect(spy.getCall(1)).to.have.been.calledWith({ wikipedia: 'de:Title' }); // 'Title' on blur
// wikidata tag not changed because another entity is now selected
done();
}, 50);
}, 100);
});
});