mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-14 05:12:13 +02:00
Merge branch 'master' into validation
This commit is contained in:
+8
-4
@@ -1114,11 +1114,12 @@ a.hide-toggle {
|
||||
img.tag-reference-wiki-image {
|
||||
float: right;
|
||||
width: 33.3333%;
|
||||
width: -webkit-calc(33.3333% - 10px);
|
||||
width: calc(33.3333% - 10px);
|
||||
border-radius: 4px;
|
||||
max-height: 200px;
|
||||
margin: 10px 5px 15px 20px;
|
||||
margin: 10px 5px 15px 10px;
|
||||
}
|
||||
[dir='rtl'] img.tag-reference-wiki-image {
|
||||
float: left;
|
||||
margin: 10px 10px 15px 5px;
|
||||
}
|
||||
|
||||
|
||||
@@ -2630,6 +2631,9 @@ input.key-trap {
|
||||
.error-details-description-text::first-letter {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
[dir='rtl'] .error-details-description-text::first-letter {
|
||||
text-transform: none; /* #5877 */
|
||||
}
|
||||
|
||||
.note-save .new-comment-input,
|
||||
.error-save .new-comment-input {
|
||||
|
||||
+3
-2
@@ -425,7 +425,7 @@ en:
|
||||
role: Role
|
||||
choose: Select feature type
|
||||
results: "{n} results for {search}"
|
||||
no_documentation_key: There is no documentation available for this key
|
||||
no_documentation_key: "There is no documentation available."
|
||||
edit_reference: "edit/translate"
|
||||
wiki_reference: View documentation
|
||||
wiki_en_reference: View documentation in English
|
||||
@@ -668,6 +668,7 @@ en:
|
||||
mr:
|
||||
title: Missing Geometry
|
||||
description: '{num_trips} recorded trips in this area suggest there may be unmapped {geometry_type} here.'
|
||||
description_alt: 'Data from a 3rd party suggests there may be unmapped {geometry_type} here.'
|
||||
tr:
|
||||
title: Missing Turn Restriction
|
||||
description: '{num_passed} of {num_trips} recorded trips (travelling {travel_direction}) make a turn from {from_way} to {to_way} at {junction}. There may be a missing "{turn_restriction}" restriction.'
|
||||
@@ -1641,4 +1642,4 @@ en:
|
||||
wikidata:
|
||||
identifier: "Identifier"
|
||||
label: "Label"
|
||||
description: "Description"
|
||||
description: "Description"
|
||||
Vendored
+3
-2
@@ -520,7 +520,7 @@
|
||||
"role": "Role",
|
||||
"choose": "Select feature type",
|
||||
"results": "{n} results for {search}",
|
||||
"no_documentation_key": "There is no documentation available for this key",
|
||||
"no_documentation_key": "There is no documentation available.",
|
||||
"edit_reference": "edit/translate",
|
||||
"wiki_reference": "View documentation",
|
||||
"wiki_en_reference": "View documentation in English",
|
||||
@@ -811,7 +811,8 @@
|
||||
},
|
||||
"mr": {
|
||||
"title": "Missing Geometry",
|
||||
"description": "{num_trips} recorded trips in this area suggest there may be unmapped {geometry_type} here."
|
||||
"description": "{num_trips} recorded trips in this area suggest there may be unmapped {geometry_type} here.",
|
||||
"description_alt": "Data from a 3rd party suggests there may be unmapped {geometry_type} here."
|
||||
},
|
||||
"tr": {
|
||||
"title": "Missing Turn Restriction",
|
||||
|
||||
@@ -13,6 +13,7 @@ import { behaviorTail } from './tail';
|
||||
import { geoChooseEdge, geoVecLength } from '../geo';
|
||||
import { utilKeybinding, utilRebind } from '../util';
|
||||
|
||||
import _isEmpty from 'lodash-es/isEmpty';
|
||||
|
||||
var _usedTails = {};
|
||||
var _disableSpace = false;
|
||||
@@ -26,7 +27,7 @@ export function behaviorDraw(context) {
|
||||
|
||||
var keybinding = utilKeybinding('draw');
|
||||
|
||||
var hover = behaviorHover(context).altDisables(true)
|
||||
var hover = behaviorHover(context).altDisables(true).ignoreVertex(true)
|
||||
.on('hover', context.ui().sidebar.hover);
|
||||
var tail = behaviorTail();
|
||||
var edit = behaviorEdit(context);
|
||||
@@ -116,6 +117,9 @@ export function behaviorDraw(context) {
|
||||
_mouseLeave = true;
|
||||
}
|
||||
|
||||
function allowsVertex(d) {
|
||||
return _isEmpty(d.tags) || context.presets().allowsVertex(d, context.graph());
|
||||
}
|
||||
|
||||
// related code
|
||||
// - `mode/drag_node.js` `doMode()`
|
||||
@@ -125,7 +129,7 @@ export function behaviorDraw(context) {
|
||||
var d = datum();
|
||||
var target = d && d.properties && d.properties.entity;
|
||||
|
||||
if (target && target.type === 'node') { // Snap to a node
|
||||
if (target && target.type === 'node' && allowsVertex(target)) { // Snap to a node
|
||||
dispatch.call('clickNode', this, target, d);
|
||||
return;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import { modeBrowse, modeSelect } from '../modes';
|
||||
import { osmNode } from '../osm';
|
||||
import { utilKeybinding } from '../util';
|
||||
|
||||
import _isEmpty from 'lodash-es/isEmpty';
|
||||
|
||||
export function behaviorDrawWay(context, wayId, index, mode, startGraph) {
|
||||
var origWay = context.entity(wayId);
|
||||
@@ -65,6 +66,9 @@ export function behaviorDrawWay(context, wayId, index, mode, startGraph) {
|
||||
}
|
||||
}
|
||||
|
||||
function allowsVertex(d) {
|
||||
return _isEmpty(d.tags) || context.presets().allowsVertex(d, context.graph());
|
||||
}
|
||||
|
||||
// related code
|
||||
// - `mode/drag_node.js` `doMode()`
|
||||
@@ -73,7 +77,7 @@ export function behaviorDrawWay(context, wayId, index, mode, startGraph) {
|
||||
function move(datum) {
|
||||
context.surface().classed('nope-disabled', d3_event.altKey);
|
||||
|
||||
var targetLoc = datum && datum.properties && datum.properties.entity && datum.properties.entity.loc;
|
||||
var targetLoc = datum && datum.properties && datum.properties.entity && allowsVertex(datum.properties.entity) && datum.properties.entity.loc;
|
||||
var targetNodes = datum && datum.properties && datum.properties.nodes;
|
||||
var loc = context.map().mouseCoordinates();
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { osmEntity, osmNote, qaError } from '../osm';
|
||||
import { utilKeybinding, utilRebind } from '../util';
|
||||
|
||||
import _isEmpty from 'lodash-es/isEmpty';
|
||||
|
||||
/*
|
||||
The hover behavior adds the `.hover` class on mouseover to all elements to which
|
||||
@@ -24,6 +25,7 @@ export function behaviorHover(context) {
|
||||
var _newId = null;
|
||||
var _buttonDown;
|
||||
var _altDisables;
|
||||
var _vertex;
|
||||
var _target;
|
||||
|
||||
|
||||
@@ -96,6 +98,9 @@ export function behaviorHover(context) {
|
||||
.on('mouseup.hover', null, true);
|
||||
}
|
||||
|
||||
function allowsVertex(d) {
|
||||
return _isEmpty(d.tags) || context.presets().allowsVertex(d, context.graph());
|
||||
}
|
||||
|
||||
function enter(datum) {
|
||||
if (datum === _target) return;
|
||||
@@ -126,7 +131,6 @@ export function behaviorHover(context) {
|
||||
if (entity.type === 'relation') {
|
||||
entity.members.forEach(function(member) { selector += ', .' + member.id; });
|
||||
}
|
||||
|
||||
} else if (datum && datum.properties && (datum.properties.entity instanceof osmEntity)) {
|
||||
entity = datum.properties.entity;
|
||||
selector = '.' + entity.id;
|
||||
@@ -144,7 +148,7 @@ export function behaviorHover(context) {
|
||||
return;
|
||||
}
|
||||
|
||||
var suppressed = _altDisables && d3_event && d3_event.altKey;
|
||||
var suppressed = (_altDisables && d3_event && d3_event.altKey) || (_vertex && !allowsVertex(entity, context.graph()));
|
||||
_selection.selectAll(selector)
|
||||
.classed(suppressed ? 'hover-suppressed' : 'hover', true);
|
||||
|
||||
@@ -182,6 +186,11 @@ export function behaviorHover(context) {
|
||||
return behavior;
|
||||
};
|
||||
|
||||
behavior.ignoreVertex = function(val) {
|
||||
if (!arguments.length) return _vertex;
|
||||
_vertex = val;
|
||||
return behavior;
|
||||
};
|
||||
|
||||
return utilRebind(behavior, dispatch, 'on');
|
||||
}
|
||||
@@ -354,7 +354,6 @@ export function modeDragNode(context) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function end(entity) {
|
||||
if (_isCancelled) return;
|
||||
|
||||
|
||||
@@ -148,8 +148,9 @@ export function modeSelectError(context, selectedErrorID, selectedErrorService)
|
||||
.hide();
|
||||
|
||||
context.selectedErrorID(null);
|
||||
context.features().forceVisible([]);
|
||||
};
|
||||
|
||||
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export function presetIndex() {
|
||||
for (var k in entity.tags) {
|
||||
// If any part of an address is present,
|
||||
// allow fallback to "Address" preset - #4353
|
||||
if (k.match(/^addr:/) !== null && geometryMatches['addr:*']) {
|
||||
if (/^addr:/.test(k) && geometryMatches['addr:*']) {
|
||||
address = geometryMatches['addr:*'][0];
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ export function presetIndex() {
|
||||
match = keyMatches[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (address && (!match || match.isFallback())) {
|
||||
@@ -76,6 +77,40 @@ export function presetIndex() {
|
||||
});
|
||||
};
|
||||
|
||||
all.allowsVertex = function(entity, resolver) {
|
||||
return resolver.transient(entity, 'vertexMatch', function() {
|
||||
var vertexPresets = _index.vertex;
|
||||
var match;
|
||||
|
||||
if (entity.isOnAddressLine(resolver)) {
|
||||
match = true;
|
||||
} else {
|
||||
for (var k in entity.tags) {
|
||||
var keyMatches = vertexPresets[k];
|
||||
if (!keyMatches) continue;
|
||||
for (var i = 0; i < keyMatches.length; i++) {
|
||||
var preset = keyMatches[i];
|
||||
if (preset.searchable !== false) {
|
||||
if (preset.matchScore(entity) > -1) {
|
||||
match = preset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!match && /^addr:/.test(k) && vertexPresets['addr:*']) {
|
||||
match = true;
|
||||
}
|
||||
|
||||
if (match) break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
@@ -166,6 +166,13 @@ export function presetPreset(id, preset, fields, visible, rawPresets) {
|
||||
|
||||
var reference = preset.reference || {};
|
||||
preset.reference = function(geometry) {
|
||||
// Lookup documentation on Wikidata...
|
||||
var qid = preset.tags.wikidata || preset.tags['brand:wikidata'] || preset.tags['operator:wikidata'];
|
||||
if (qid) {
|
||||
return { qid: qid };
|
||||
}
|
||||
|
||||
// Lookup documentation on OSM Wikibase...
|
||||
var key = reference.key || Object.keys(_omit(preset.tags, 'name'))[0];
|
||||
var value = reference.value || preset.tags[key];
|
||||
|
||||
|
||||
@@ -8,10 +8,7 @@ import { dispatch as d3_dispatch } from 'd3-dispatch';
|
||||
|
||||
import { osmEntity } from '../osm';
|
||||
import { utilRebind } from '../util/rebind';
|
||||
import {
|
||||
utilQsString,
|
||||
utilStringQs
|
||||
} from '../util';
|
||||
import { utilQsString, utilStringQs } from '../util';
|
||||
|
||||
|
||||
export function rendererFeatures(context) {
|
||||
@@ -58,13 +55,14 @@ export function rendererFeatures(context) {
|
||||
'obliterated': true
|
||||
};
|
||||
|
||||
var dispatch = d3_dispatch('change', 'redraw'),
|
||||
_cullFactor = 1,
|
||||
_cache = {},
|
||||
_features = {},
|
||||
_stats = {},
|
||||
_keys = [],
|
||||
_hidden = [];
|
||||
var dispatch = d3_dispatch('change', 'redraw');
|
||||
var _cullFactor = 1;
|
||||
var _cache = {};
|
||||
var _features = {};
|
||||
var _stats = {};
|
||||
var _keys = [];
|
||||
var _hidden = [];
|
||||
var _forceVisible = {};
|
||||
|
||||
|
||||
function update() {
|
||||
@@ -277,10 +275,10 @@ export function rendererFeatures(context) {
|
||||
|
||||
|
||||
features.gatherStats = function(d, resolver, dimensions) {
|
||||
var needsRedraw = false,
|
||||
type = _groupBy(d, function(ent) { return ent.type; }),
|
||||
entities = [].concat(type.relation || [], type.way || [], type.node || []),
|
||||
currHidden, geometry, matches, i, j;
|
||||
var needsRedraw = false;
|
||||
var type = _groupBy(d, function(ent) { return ent.type; });
|
||||
var entities = [].concat(type.relation || [], type.way || [], type.node || []);
|
||||
var currHidden, geometry, matches, i, j;
|
||||
|
||||
for (i = 0; i < _keys.length; i++) {
|
||||
_features[_keys[i]].count = 0;
|
||||
@@ -346,8 +344,8 @@ export function rendererFeatures(context) {
|
||||
}
|
||||
|
||||
if (!_cache[ent].matches) {
|
||||
var matches = {},
|
||||
hasMatch = false;
|
||||
var matches = {};
|
||||
var hasMatch = false;
|
||||
|
||||
for (var i = 0; i < _keys.length; i++) {
|
||||
if (_keys[i] === 'others') {
|
||||
@@ -462,6 +460,7 @@ export function rendererFeatures(context) {
|
||||
features.isHidden = function(entity, resolver, geometry) {
|
||||
if (!_hidden.length) return false;
|
||||
if (!entity.version) return false;
|
||||
if (_forceVisible[entity.id]) return false;
|
||||
|
||||
var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
|
||||
return fn(entity, resolver, geometry);
|
||||
@@ -482,6 +481,16 @@ export function rendererFeatures(context) {
|
||||
};
|
||||
|
||||
|
||||
features.forceVisible = function(entityIDs) {
|
||||
if (!arguments.length) return Object.keys(_forceVisible);
|
||||
_forceVisible = {};
|
||||
for (var i = 0; i < entityIDs.length; i++) {
|
||||
_forceVisible[entityIDs[i]] = true;
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
features.init = function() {
|
||||
var storage = context.storage('disabled-features');
|
||||
if (storage) {
|
||||
|
||||
@@ -267,6 +267,11 @@ export default {
|
||||
geometry_type: t('QA.improveOSM.geometry_types.' + geoType)
|
||||
};
|
||||
|
||||
// -1 trips indicates data came from a 3rd party
|
||||
if (feature.numberOfTrips === -1) {
|
||||
d.desc = t('QA.improveOSM.error_types.mr.description_alt', d.replacements);
|
||||
}
|
||||
|
||||
_erCache.data[d.id] = d;
|
||||
_erCache.rtree.insert(encodeErrorRtree(d));
|
||||
});
|
||||
@@ -476,4 +481,4 @@ export default {
|
||||
getClosedIDs: function() {
|
||||
return Object.keys(_erCache.closed).sort();
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -66,6 +66,7 @@ export default {
|
||||
if (!entity.claims[property]) return undefined;
|
||||
var locale = _localeIDs[langCode];
|
||||
var preferredPick, localePick;
|
||||
|
||||
_forEach(entity.claims[property], function(stmt) {
|
||||
// If exists, use value limited to the needed language (has a qualifier P26 = locale)
|
||||
// Or if not found, use the first value with the "preferred" rank
|
||||
@@ -78,8 +79,8 @@ export default {
|
||||
localePick = stmt;
|
||||
}
|
||||
});
|
||||
var result = localePick || preferredPick;
|
||||
|
||||
var result = localePick || preferredPick;
|
||||
if (result) {
|
||||
var datavalue = result.mainsnak.datavalue;
|
||||
return datavalue.type === 'wikibase-entityid' ? datavalue.value.id : datavalue.value;
|
||||
@@ -96,6 +97,7 @@ export default {
|
||||
*/
|
||||
monolingualClaimToValueObj: function(entity, property) {
|
||||
if (!entity || !entity.claims[property]) return undefined;
|
||||
|
||||
return entity.claims[property].reduce(function(acc, obj) {
|
||||
var value = obj.mainsnak.datavalue.value;
|
||||
acc[value.language] = value.text;
|
||||
@@ -105,7 +107,7 @@ export default {
|
||||
|
||||
|
||||
toSitelink: function(key, value) {
|
||||
var result = value ? 'Tag:' + key + '=' + value : 'Key:' + key;
|
||||
var result = value ? ('Tag:' + key + '=' + value) : 'Key:' + key;
|
||||
return result.replace(/_/g, ' ').trim();
|
||||
},
|
||||
|
||||
@@ -113,21 +115,20 @@ export default {
|
||||
//
|
||||
// Pass params object of the form:
|
||||
// {
|
||||
// key: 'string', // required
|
||||
// value: 'string' // optional
|
||||
// }
|
||||
// -or-
|
||||
// {
|
||||
// rtype: 'rtype' // relation type (e.g. 'multipolygon')
|
||||
// key: 'string',
|
||||
// value: 'string',
|
||||
// rtype: 'string',
|
||||
// langCode: 'string'
|
||||
// }
|
||||
//
|
||||
getEntity: function(params, callback) {
|
||||
var doRequest = params.debounce ? debouncedRequest : request;
|
||||
var self = this;
|
||||
var that = this;
|
||||
var titles = [];
|
||||
var result = {};
|
||||
var keySitelink = this.toSitelink(params.key);
|
||||
var tagSitelink = params.value ? this.toSitelink(params.key, params.value) : false;
|
||||
var rtypeSitelink = params.rtype ? ('Relation:' + params.rtype).replace(/_/g, ' ').trim() : false;
|
||||
var keySitelink = params.key ? this.toSitelink(params.key) : false;
|
||||
var tagSitelink = (params.key && params.value) ? this.toSitelink(params.key, params.value) : false;
|
||||
var localeSitelink;
|
||||
|
||||
if (params.langCode && _localeIDs[params.langCode] === undefined) {
|
||||
@@ -138,10 +139,20 @@ export default {
|
||||
titles.push(localeSitelink);
|
||||
}
|
||||
|
||||
if (_wikibaseCache[keySitelink]) {
|
||||
result.key = _wikibaseCache[keySitelink];
|
||||
} else {
|
||||
titles.push(keySitelink);
|
||||
if (rtypeSitelink) {
|
||||
if (_wikibaseCache[rtypeSitelink]) {
|
||||
result.rtype = _wikibaseCache[rtypeSitelink];
|
||||
} else {
|
||||
titles.push(rtypeSitelink);
|
||||
}
|
||||
}
|
||||
|
||||
if (keySitelink) {
|
||||
if (_wikibaseCache[keySitelink]) {
|
||||
result.key = _wikibaseCache[keySitelink];
|
||||
} else {
|
||||
titles.push(keySitelink);
|
||||
}
|
||||
}
|
||||
|
||||
if (tagSitelink) {
|
||||
@@ -185,11 +196,15 @@ export default {
|
||||
var localeID = false;
|
||||
_forEach(d.entities, function(res) {
|
||||
if (res.missing !== '') {
|
||||
var title = res.sitelinks.wiki.title;
|
||||
// Simplify access to the localized values
|
||||
res.description = localizedToString(res.descriptions, params.langCode);
|
||||
res.label = localizedToString(res.labels, params.langCode);
|
||||
if (title === keySitelink) {
|
||||
|
||||
var title = res.sitelinks.wiki.title;
|
||||
if (title === rtypeSitelink) {
|
||||
_wikibaseCache[rtypeSitelink] = res;
|
||||
result.rtype = res;
|
||||
} else if (title === keySitelink) {
|
||||
_wikibaseCache[keySitelink] = res;
|
||||
result.key = res;
|
||||
} else if (title === tagSitelink) {
|
||||
@@ -205,7 +220,7 @@ export default {
|
||||
|
||||
if (localeSitelink) {
|
||||
// If locale ID is not found, store false to prevent repeated queries
|
||||
self.addLocale(params.langCode, localeID);
|
||||
that.addLocale(params.langCode, localeID);
|
||||
}
|
||||
|
||||
callback(null, result);
|
||||
@@ -245,7 +260,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = data.tag || data.key;
|
||||
var entity = data.rtype || data.tag || data.key;
|
||||
if (!entity) {
|
||||
callback('No entity');
|
||||
return;
|
||||
@@ -273,8 +288,7 @@ export default {
|
||||
if (imageroot && image) {
|
||||
result.imageURL = imageroot + '?' + utilQsString({
|
||||
title: 'Special:Redirect/file/' + image,
|
||||
width: 100,
|
||||
height: 100
|
||||
width: 400
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -282,6 +296,7 @@ export default {
|
||||
// Try to get a wiki page from tag data item first, followed by the corresponding key data item.
|
||||
// If neither tag nor key data item contain a wiki page in the needed language nor English,
|
||||
// get the first found wiki page from either the tag or the key item.
|
||||
var rtypeWiki = that.monolingualClaimToValueObj(data.rtype, 'P31');
|
||||
var tagWiki = that.monolingualClaimToValueObj(data.tag, 'P31');
|
||||
var keyWiki = that.monolingualClaimToValueObj(data.key, 'P31');
|
||||
|
||||
@@ -289,7 +304,11 @@ export default {
|
||||
// BUG: in some cases, a more elaborate fallback logic might be needed
|
||||
var langPrefix = langCode.split('-', 2)[0];
|
||||
|
||||
// use the first acceptable wiki page
|
||||
result.wiki =
|
||||
getWikiInfo(rtypeWiki, langCode, 'inspector.wiki_reference') ||
|
||||
getWikiInfo(rtypeWiki, langPrefix, 'inspector.wiki_reference') ||
|
||||
getWikiInfo(rtypeWiki, 'en', 'inspector.wiki_en_reference') ||
|
||||
getWikiInfo(tagWiki, langCode, 'inspector.wiki_reference') ||
|
||||
getWikiInfo(tagWiki, langPrefix, 'inspector.wiki_reference') ||
|
||||
getWikiInfo(tagWiki, 'en', 'inspector.wiki_en_reference') ||
|
||||
|
||||
+108
-14
@@ -5,7 +5,7 @@ import { json as d3_json } from 'd3-request';
|
||||
import { utilQsString } from '../util';
|
||||
import { currentLocale } from '../util/locale';
|
||||
|
||||
var endpoint = 'https://www.wikidata.org/w/api.php?';
|
||||
var apibase = 'https://www.wikidata.org/w/api.php?';
|
||||
var _wikidataCache = {};
|
||||
|
||||
export default {
|
||||
@@ -21,13 +21,13 @@ export default {
|
||||
// corresponding Wikidata entities.
|
||||
itemsByTitle: function(lang, title, callback) {
|
||||
if (!title) {
|
||||
callback('', {});
|
||||
callback('No title', {});
|
||||
return;
|
||||
}
|
||||
|
||||
lang = lang || 'en';
|
||||
|
||||
d3_json(endpoint + utilQsString({
|
||||
d3_json(apibase + utilQsString({
|
||||
action: 'wbgetentities',
|
||||
format: 'json',
|
||||
formatversion: 2,
|
||||
@@ -36,10 +36,13 @@ export default {
|
||||
languages: 'en', // shrink response by filtering to one language
|
||||
origin: '*'
|
||||
}), function(err, data) {
|
||||
if (err || !data || data.error) {
|
||||
callback('', {});
|
||||
if (data && data.error) {
|
||||
err = data.error;
|
||||
}
|
||||
if (err) {
|
||||
callback(err, {});
|
||||
} else {
|
||||
callback(title, data.entities || {});
|
||||
callback(null, data.entities || {});
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -47,11 +50,11 @@ export default {
|
||||
|
||||
entityByQID: function(qid, callback) {
|
||||
if (!qid) {
|
||||
callback('', {});
|
||||
callback('No qid', {});
|
||||
return;
|
||||
}
|
||||
if (_wikidataCache[qid]) {
|
||||
callback('', _wikidataCache[qid]);
|
||||
callback(null, _wikidataCache[qid]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -61,24 +64,115 @@ export default {
|
||||
'en'
|
||||
]);
|
||||
|
||||
d3_json(endpoint + utilQsString({
|
||||
d3_json(apibase + utilQsString({
|
||||
action: 'wbgetentities',
|
||||
format: 'json',
|
||||
formatversion: 2,
|
||||
ids: qid,
|
||||
props: /*sitelinks|*/'labels|descriptions',
|
||||
//sitefilter: lang + 'wiki',
|
||||
props: 'labels|descriptions|claims|sitelinks',
|
||||
sitefilter: langs.map(function(d) { return d + 'wiki'; }).join('|'),
|
||||
languages: langs.join('|'),
|
||||
languagefallback: 1,
|
||||
origin: '*'
|
||||
}), function(err, data) {
|
||||
if (err || !data || data.error) {
|
||||
callback('', {});
|
||||
if (data && data.error) {
|
||||
err = data.error;
|
||||
}
|
||||
if (err) {
|
||||
callback(err, {});
|
||||
} else {
|
||||
_wikidataCache[qid] = data.entities[qid];
|
||||
callback(qid, data.entities[qid] || {});
|
||||
callback(null, data.entities[qid] || {});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// Pass `params` object of the form:
|
||||
// {
|
||||
// qid: 'string' // brand wikidata (e.g. 'Q37158')
|
||||
// }
|
||||
//
|
||||
// Get an result object used to display tag documentation
|
||||
// {
|
||||
// title: 'string',
|
||||
// description: 'string',
|
||||
// editURL: 'string',
|
||||
// imageURL: 'string',
|
||||
// wiki: { title: 'string', text: 'string', url: 'string' }
|
||||
// }
|
||||
//
|
||||
getDocs: function(params, callback) {
|
||||
this.entityByQID(params.qid, function(err, entity) {
|
||||
if (err || !entity) {
|
||||
callback(err || 'No entity');
|
||||
return;
|
||||
}
|
||||
|
||||
var i;
|
||||
|
||||
var description;
|
||||
if (entity.descriptions && Object.keys(entity.descriptions).length > 0) {
|
||||
description = entity.descriptions[Object.keys(entity.descriptions)[0]].value;
|
||||
}
|
||||
|
||||
// prepare result
|
||||
var result = {
|
||||
title: entity.id,
|
||||
description: description,
|
||||
editURL: 'https://www.wikidata.org/wiki/' + entity.id
|
||||
};
|
||||
|
||||
// add image
|
||||
if (entity.claims) {
|
||||
var imageroot = 'https://commons.wikimedia.org/w/index.php';
|
||||
var props = ['P154','P18']; // logo image, image
|
||||
var prop, image;
|
||||
for (i = 0; i < props.length; i++) {
|
||||
prop = entity.claims[props[i]];
|
||||
if (prop && Object.keys(prop).length > 0) {
|
||||
image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value;
|
||||
if (image) {
|
||||
result.imageURL = imageroot + '?' + utilQsString({
|
||||
title: 'Special:Redirect/file/' + image,
|
||||
width: 400
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.sitelinks) {
|
||||
// must be one of these that we requested..
|
||||
var langs = _uniq([
|
||||
currentLocale.toLowerCase(),
|
||||
currentLocale.split('-', 2)[0].toLowerCase(),
|
||||
'en'
|
||||
]);
|
||||
var englishLocale = (currentLocale.split('-', 2)[0].toLowerCase() === 'en');
|
||||
|
||||
for (i = 0; i < langs.length; i++) { // check each, in order of preference
|
||||
var w = langs[i] + 'wiki';
|
||||
if (entity.sitelinks[w]) {
|
||||
var title = entity.sitelinks[w].title;
|
||||
var tKey = 'inspector.wiki_reference';
|
||||
if (!englishLocale && langs[i] === 'en') { // user's currentLocale isn't English but
|
||||
tKey = 'inspector.wiki_en_reference'; // we are sending them to enwiki anyway..
|
||||
}
|
||||
|
||||
result.wiki = {
|
||||
title: title,
|
||||
text: tKey,
|
||||
url: 'https://' + langs[i] + '.wikipedia.org/wiki/' + title.replace(/ /g, '_')
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -297,7 +297,7 @@ export function uiFieldCombo(field, context) {
|
||||
.data([0]);
|
||||
|
||||
var listClass = 'chiplist';
|
||||
|
||||
|
||||
// Use a separate line for each value in the Destinations field
|
||||
// to mimic highway exit signs
|
||||
if (field.id === 'destination_oneway') {
|
||||
|
||||
@@ -138,43 +138,54 @@ export function uiFieldWikidata(field) {
|
||||
|
||||
wiki.tags = function(tags) {
|
||||
var value = tags[field.key] || '';
|
||||
var matches = value.match(/^Q[0-9]*$/);
|
||||
|
||||
utilGetSetValue(title, value);
|
||||
|
||||
// value in correct format
|
||||
if (matches) {
|
||||
_wikiURL = 'https://wikidata.org/wiki/' + value;
|
||||
wikidata.entityByQID(value, function(qid, entity) {
|
||||
var label = '';
|
||||
var description = '';
|
||||
if (!/^Q[0-9]*$/.test(value)) { // not a proper QID
|
||||
unrecognized();
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity.labels && Object.keys(entity.labels).length > 0) {
|
||||
label = entity.labels[Object.keys(entity.labels)[0]].value;
|
||||
}
|
||||
if (entity.descriptions && Object.keys(entity.descriptions).length > 0) {
|
||||
description = entity.descriptions[Object.keys(entity.descriptions)[0]].value;
|
||||
}
|
||||
// QID value in correct format
|
||||
_wikiURL = 'https://wikidata.org/wiki/' + value;
|
||||
wikidata.entityByQID(value, function(err, entity) {
|
||||
if (err) {
|
||||
unrecognized();
|
||||
return;
|
||||
}
|
||||
|
||||
d3_select('.preset-wikidata-label')
|
||||
.style('display', function(){
|
||||
return label.length > 0 ? 'flex' : 'none';
|
||||
})
|
||||
.select('input')
|
||||
.attr('value', label);
|
||||
var label = '';
|
||||
var description = '';
|
||||
|
||||
d3_select('.preset-wikidata-description')
|
||||
.style('display', function(){
|
||||
return description.length > 0 ? 'flex' : 'none';
|
||||
})
|
||||
.select('input')
|
||||
.attr('value', description);
|
||||
});
|
||||
if (entity.labels && Object.keys(entity.labels).length > 0) {
|
||||
label = entity.labels[Object.keys(entity.labels)[0]].value;
|
||||
}
|
||||
if (entity.descriptions && Object.keys(entity.descriptions).length > 0) {
|
||||
description = entity.descriptions[Object.keys(entity.descriptions)[0]].value;
|
||||
}
|
||||
|
||||
d3_select('.preset-wikidata-label')
|
||||
.style('display', function(){
|
||||
return label.length > 0 ? 'flex' : 'none';
|
||||
})
|
||||
.select('input')
|
||||
.attr('value', label);
|
||||
|
||||
d3_select('.preset-wikidata-description')
|
||||
.style('display', function(){
|
||||
return description.length > 0 ? 'flex' : 'none';
|
||||
})
|
||||
.select('input')
|
||||
.attr('value', description);
|
||||
});
|
||||
|
||||
|
||||
// not a proper QID
|
||||
function unrecognized() {
|
||||
d3_select('.preset-wikidata-label')
|
||||
.style('display', 'none');
|
||||
d3_select('.preset-wikidata-description')
|
||||
.style('display', 'none');
|
||||
|
||||
// unrecognized value format
|
||||
} else {
|
||||
d3_select('.preset-wikidata-label').style('display', 'none');
|
||||
d3_select('.preset-wikidata-description').style('display', 'none');
|
||||
if (value && value !== '') {
|
||||
_wikiURL = 'https://wikidata.org/wiki/Special:Search?search=' + value;
|
||||
} else {
|
||||
|
||||
@@ -200,7 +200,9 @@ export function uiFieldWikipedia(field, context) {
|
||||
var initGraph = context.graph();
|
||||
var initEntityID = _entity.id;
|
||||
|
||||
wikidata.itemsByTitle(language()[2], value, function(title, data) {
|
||||
wikidata.itemsByTitle(language()[2], value, function(err, data) {
|
||||
if (err) return;
|
||||
|
||||
// If graph has changed, we can't apply this update.
|
||||
if (context.graph() !== initGraph) return;
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ export function uiImproveOsmDetails(context) {
|
||||
var unknown = t('inspector.unknown');
|
||||
|
||||
if (!d) return unknown;
|
||||
|
||||
if (d.desc) return d.desc;
|
||||
|
||||
var errorType = d.error_key;
|
||||
var et = dataEn.QA.improveOSM.error_types[errorType];
|
||||
|
||||
@@ -61,6 +64,7 @@ export function uiImproveOsmDetails(context) {
|
||||
.html(errorDetail);
|
||||
|
||||
// If there are entity links in the error message..
|
||||
var relatedEntities = [];
|
||||
descriptionEnter.selectAll('.error_entity_link, .error_object_link')
|
||||
.each(function() {
|
||||
var link = d3_select(this);
|
||||
@@ -70,6 +74,8 @@ export function uiImproveOsmDetails(context) {
|
||||
: this.textContent;
|
||||
var entity = context.hasEntity(entityID);
|
||||
|
||||
relatedEntities.push(entityID);
|
||||
|
||||
// Add click handler
|
||||
link
|
||||
.on('mouseover', function() {
|
||||
@@ -113,6 +119,9 @@ export function uiImproveOsmDetails(context) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Don't hide entities related to this error - #5880
|
||||
context.features().forceVisible(relatedEntities);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ export function uiKeepRightDetails(context) {
|
||||
.html(errorDetail);
|
||||
|
||||
// If there are entity links in the error message..
|
||||
var relatedEntities = [];
|
||||
descriptionEnter.selectAll('.error_entity_link, .error_object_link')
|
||||
.each(function() {
|
||||
var link = d3_select(this);
|
||||
@@ -75,6 +76,8 @@ export function uiKeepRightDetails(context) {
|
||||
: this.textContent;
|
||||
var entity = context.hasEntity(entityID);
|
||||
|
||||
relatedEntities.push(entityID);
|
||||
|
||||
// Add click handler
|
||||
link
|
||||
.on('mouseover', function() {
|
||||
@@ -118,6 +121,9 @@ export function uiKeepRightDetails(context) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Don't hide entities related to this error - #5880
|
||||
context.features().forceVisible(relatedEntities);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ export function uiRawTagEditor(context) {
|
||||
var _showBlank = false;
|
||||
var _updatePreference = true;
|
||||
var _expanded = false;
|
||||
var _pendingChange = null;
|
||||
var _state;
|
||||
var _preset;
|
||||
var _tags;
|
||||
@@ -211,7 +212,7 @@ export function uiRawTagEditor(context) {
|
||||
.property('disabled', isReadOnly);
|
||||
|
||||
items.selectAll('button.remove')
|
||||
.on('click', removeTag);
|
||||
.on('mousedown', removeTag); // 'click' fires too late - #5878
|
||||
|
||||
|
||||
|
||||
@@ -335,11 +336,11 @@ export function uiRawTagEditor(context) {
|
||||
}
|
||||
}
|
||||
|
||||
var t = {};
|
||||
_pendingChange = _pendingChange || {};
|
||||
if (kOld) {
|
||||
t[kOld] = undefined;
|
||||
_pendingChange[kOld] = undefined;
|
||||
}
|
||||
t[kNew] = vNew;
|
||||
_pendingChange[kNew] = vNew;
|
||||
|
||||
d.key = kNew; // update datum to avoid exit/enter on tag update
|
||||
d.value = vNew;
|
||||
@@ -347,15 +348,16 @@ export function uiRawTagEditor(context) {
|
||||
this.value = kNew;
|
||||
utilGetSetValue(inputVal, vNew);
|
||||
|
||||
dispatch.call('change', this, t);
|
||||
scheduleChange();
|
||||
}
|
||||
|
||||
|
||||
function valueChange(d) {
|
||||
if (isReadOnly(d)) return;
|
||||
var t = {};
|
||||
t[d.key] = this.value;
|
||||
dispatch.call('change', this, t);
|
||||
|
||||
_pendingChange = _pendingChange || {};
|
||||
_pendingChange[d.key] = this.value;
|
||||
scheduleChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -366,23 +368,32 @@ export function uiRawTagEditor(context) {
|
||||
_showBlank = false;
|
||||
content(wrap);
|
||||
} else {
|
||||
var t = {};
|
||||
t[d.key] = undefined;
|
||||
dispatch.call('change', this, t);
|
||||
_pendingChange = _pendingChange || {};
|
||||
_pendingChange[d.key] = undefined;
|
||||
scheduleChange();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addTag() {
|
||||
// Wrapped in a setTimeout in case it's being called from a blur
|
||||
// handler. Without the setTimeout, the call to `content` would
|
||||
// wipe out the pending value change.
|
||||
// Delay render in case this click is blurring an edited combo.
|
||||
// Without the setTimeout, the `content` render would wipe out the pending tag change.
|
||||
window.setTimeout(function() {
|
||||
_showBlank = true;
|
||||
content(wrap);
|
||||
list.selectAll('li:last-child input.key').node().focus();
|
||||
}, 20);
|
||||
}
|
||||
|
||||
|
||||
function scheduleChange() {
|
||||
// Delay change in case this change is blurring an edited combo. - #5878
|
||||
window.setTimeout(function() {
|
||||
dispatch.call('change', this, _pendingChange);
|
||||
_pendingChange = null;
|
||||
}, 10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ export function uiSidebar(context) {
|
||||
})
|
||||
.on('drag', function() {
|
||||
var isRTL = (textDirection === 'rtl');
|
||||
var scaleX = isRTL ? 0 : 1;
|
||||
var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
|
||||
|
||||
var x = d3_event.x - dragOffset;
|
||||
@@ -84,7 +85,7 @@ export function uiSidebar(context) {
|
||||
.style(xMarginProperty, '-400px')
|
||||
.style('width', '400px');
|
||||
|
||||
context.ui().onResize([sidebarWidth - d3_event.dx, 0]);
|
||||
context.ui().onResize([(sidebarWidth - d3_event.dx) * scaleX, 0]);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -94,9 +95,9 @@ export function uiSidebar(context) {
|
||||
.style('width', widthPct + '%');
|
||||
|
||||
if (isCollapsed) {
|
||||
context.ui().onResize([-sidebarWidth, 0]);
|
||||
context.ui().onResize([-sidebarWidth * scaleX, 0]);
|
||||
} else {
|
||||
context.ui().onResize([-d3_event.dx, 0]);
|
||||
context.ui().onResize([-d3_event.dx * scaleX, 0]);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -298,7 +299,9 @@ export function uiSidebar(context) {
|
||||
|
||||
var isCollapsed = selection.classed('collapsed');
|
||||
var isCollapsing = !isCollapsed;
|
||||
var xMarginProperty = textDirection === 'rtl' ? 'margin-right' : 'margin-left';
|
||||
var isRTL = (textDirection === 'rtl');
|
||||
var scaleX = isRTL ? 0 : 1;
|
||||
var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
|
||||
|
||||
sidebarWidth = selection.node().getBoundingClientRect().width;
|
||||
|
||||
@@ -321,7 +324,7 @@ export function uiSidebar(context) {
|
||||
return function(t) {
|
||||
var dx = lastMargin - Math.round(i(t));
|
||||
lastMargin = lastMargin - dx;
|
||||
context.ui().onResize(moveMap ? undefined : [dx, 0]);
|
||||
context.ui().onResize(moveMap ? undefined : [dx * scaleX, 0]);
|
||||
};
|
||||
})
|
||||
.on('end', function() {
|
||||
@@ -354,4 +357,4 @@ export function uiSidebar(context) {
|
||||
sidebar.toggle = function() {};
|
||||
|
||||
return sidebar;
|
||||
}
|
||||
}
|
||||
|
||||
+66
-57
@@ -8,17 +8,22 @@ import { services } from '../services';
|
||||
import { svgIcon } from '../svg';
|
||||
|
||||
|
||||
// Pass `tag` object of the form:
|
||||
// Pass `which` object of the form:
|
||||
// {
|
||||
// key: 'string', // required
|
||||
// value: 'string' // optional
|
||||
// }
|
||||
// -or-
|
||||
// {
|
||||
// rtype: 'rtype' // relation type (e.g. 'multipolygon')
|
||||
// rtype: 'string' // relation type (e.g. 'multipolygon')
|
||||
// }
|
||||
export function uiTagReference(tag) {
|
||||
var wikibase = services.osmWikibase;
|
||||
// -or-
|
||||
// {
|
||||
// qid: 'string' // brand wikidata (e.g. 'Q37158')
|
||||
// }
|
||||
//
|
||||
export function uiTagReference(what) {
|
||||
var wikibase = what.qid ? services.wikidata : services.osmWikibase;
|
||||
var tagReference = {};
|
||||
|
||||
var _button = d3_select(null);
|
||||
@@ -33,66 +38,69 @@ export function uiTagReference(tag) {
|
||||
_button
|
||||
.classed('tag-reference-loading', true);
|
||||
|
||||
wikibase.getDocs(tag, function(err, docs) {
|
||||
_body.html('');
|
||||
wikibase.getDocs(what, gotDocs);
|
||||
}
|
||||
|
||||
if (!docs || !docs.title) {
|
||||
_body
|
||||
.append('p')
|
||||
.attr('class', 'tag-reference-description')
|
||||
.text(t('inspector.no_documentation_key'));
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (docs.imageURL) {
|
||||
_body
|
||||
.append('img')
|
||||
.attr('class', 'tag-reference-wiki-image')
|
||||
.attr('src', docs.imageURL)
|
||||
.on('load', function() { done(); })
|
||||
.on('error', function() { d3_select(this).remove(); done(); });
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
function gotDocs(err, docs) {
|
||||
_body.html('');
|
||||
|
||||
if (!docs || !docs.title) {
|
||||
_body
|
||||
.append('p')
|
||||
.attr('class', 'tag-reference-description')
|
||||
.text(docs.description || t('inspector.no_documentation_key'))
|
||||
.text(t('inspector.no_documentation_key'));
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (docs.imageURL) {
|
||||
_body
|
||||
.append('img')
|
||||
.attr('class', 'tag-reference-wiki-image')
|
||||
.attr('src', docs.imageURL)
|
||||
.on('load', function() { done(); })
|
||||
.on('error', function() { d3_select(this).remove(); done(); });
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
|
||||
_body
|
||||
.append('p')
|
||||
.attr('class', 'tag-reference-description')
|
||||
.text(docs.description || t('inspector.no_documentation_key'))
|
||||
.append('a')
|
||||
.attr('class', 'tag-reference-edit')
|
||||
.attr('target', '_blank')
|
||||
.attr('tabindex', -1)
|
||||
.attr('title', t('inspector.edit_reference'))
|
||||
.attr('href', docs.editURL)
|
||||
.call(svgIcon('#iD-icon-edit', 'inline'));
|
||||
|
||||
if (docs.wiki) {
|
||||
_body
|
||||
.append('a')
|
||||
.attr('class', 'tag-reference-link')
|
||||
.attr('target', '_blank')
|
||||
.attr('tabindex', -1)
|
||||
.attr('href', docs.wiki.url)
|
||||
.call(svgIcon('#iD-icon-out-link', 'inline'))
|
||||
.append('span')
|
||||
.text(t(docs.wiki.text));
|
||||
}
|
||||
|
||||
// Add link to info about "good changeset comments" - #2923
|
||||
if (what.key === 'comment') {
|
||||
_body
|
||||
.append('a')
|
||||
.attr('class', 'tag-reference-edit')
|
||||
.attr('class', 'tag-reference-comment-link')
|
||||
.attr('target', '_blank')
|
||||
.attr('tabindex', -1)
|
||||
.attr('title', t('inspector.edit_reference'))
|
||||
.attr('href', docs.editURL)
|
||||
.call(svgIcon('#iD-icon-edit', 'inline'));
|
||||
|
||||
if (docs.wiki) {
|
||||
_body
|
||||
.append('a')
|
||||
.attr('class', 'tag-reference-link')
|
||||
.attr('target', '_blank')
|
||||
.attr('tabindex', -1)
|
||||
.attr('href', docs.wiki.url)
|
||||
.call(svgIcon('#iD-icon-out-link', 'inline'))
|
||||
.append('span')
|
||||
.text(t(docs.wiki.text));
|
||||
}
|
||||
|
||||
// Add link to info about "good changeset comments" - #2923
|
||||
if (tag.key === 'comment') {
|
||||
_body
|
||||
.append('a')
|
||||
.attr('class', 'tag-reference-comment-link')
|
||||
.attr('target', '_blank')
|
||||
.attr('tabindex', -1)
|
||||
.call(svgIcon('#iD-icon-out-link', 'inline'))
|
||||
.attr('href', t('commit.about_changeset_comments_link'))
|
||||
.append('span')
|
||||
.text(t('commit.about_changeset_comments'));
|
||||
}
|
||||
});
|
||||
.call(svgIcon('#iD-icon-out-link', 'inline'))
|
||||
.attr('href', t('commit.about_changeset_comments_link'))
|
||||
.append('span')
|
||||
.text(t('commit.about_changeset_comments'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +151,7 @@ export function uiTagReference(tag) {
|
||||
.on('click', function () {
|
||||
d3_event.stopPropagation();
|
||||
d3_event.preventDefault();
|
||||
this.blur(); // avoid keeping focus on the button - #4641
|
||||
if (_showing) {
|
||||
hide();
|
||||
} else if (_loaded) {
|
||||
@@ -155,9 +164,9 @@ export function uiTagReference(tag) {
|
||||
|
||||
|
||||
tagReference.body = function(selection) {
|
||||
var tagid = tag.rtype || (tag.key + '-' + tag.value);
|
||||
var itemID = what.qid || what.rtype || (what.key + '-' + what.value);
|
||||
_body = selection.selectAll('.tag-reference-body')
|
||||
.data([tagid], function(d) { return d; });
|
||||
.data([itemID], function(d) { return d; });
|
||||
|
||||
_body.exit()
|
||||
.remove();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
describe('iD.Features', function() {
|
||||
var dimensions = [1000, 1000],
|
||||
context, features;
|
||||
var dimensions = [1000, 1000];
|
||||
var context, features;
|
||||
|
||||
function _values(obj) {
|
||||
var result = [];
|
||||
@@ -64,18 +64,18 @@ describe('iD.Features', function() {
|
||||
describe('#gatherStats', function() {
|
||||
it('counts features', function() {
|
||||
var graph = iD.coreGraph([
|
||||
iD.osmNode({id: 'point_bar', tags: {amenity: 'bar'}, version: 1}),
|
||||
iD.osmNode({id: 'point_dock', tags: {waterway: 'dock'}, version: 1}),
|
||||
iD.osmNode({id: 'point_rail_station', tags: {railway: 'station'}, version: 1}),
|
||||
iD.osmNode({id: 'point_generator', tags: {power: 'generator'}, version: 1}),
|
||||
iD.osmNode({id: 'point_old_rail_station', tags: {railway: 'station', disused: 'yes'}, version: 1}),
|
||||
iD.osmWay({id: 'motorway', tags: {highway: 'motorway'}, version: 1}),
|
||||
iD.osmWay({id: 'building_yes', tags: {area: 'yes', amenity: 'school', building: 'yes'}, version: 1}),
|
||||
iD.osmWay({id: 'boundary', tags: {boundary: 'administrative'}, version: 1}),
|
||||
iD.osmWay({id: 'fence', tags: {barrier: 'fence'}, version: 1})
|
||||
]),
|
||||
all = _values(graph.base().entities),
|
||||
stats;
|
||||
iD.osmNode({id: 'point_bar', tags: {amenity: 'bar'}, version: 1}),
|
||||
iD.osmNode({id: 'point_dock', tags: {waterway: 'dock'}, version: 1}),
|
||||
iD.osmNode({id: 'point_rail_station', tags: {railway: 'station'}, version: 1}),
|
||||
iD.osmNode({id: 'point_generator', tags: {power: 'generator'}, version: 1}),
|
||||
iD.osmNode({id: 'point_old_rail_station', tags: {railway: 'station', disused: 'yes'}, version: 1}),
|
||||
iD.osmWay({id: 'motorway', tags: {highway: 'motorway'}, version: 1}),
|
||||
iD.osmWay({id: 'building_yes', tags: {area: 'yes', amenity: 'school', building: 'yes'}, version: 1}),
|
||||
iD.osmWay({id: 'boundary', tags: {boundary: 'administrative'}, version: 1}),
|
||||
iD.osmWay({id: 'fence', tags: {barrier: 'fence'}, version: 1})
|
||||
]);
|
||||
var all = _values(graph.base().entities);
|
||||
var stats;
|
||||
|
||||
features.gatherStats(all, graph, dimensions);
|
||||
stats = features.stats();
|
||||
@@ -205,8 +205,8 @@ describe('iD.Features', function() {
|
||||
version: 1
|
||||
})
|
||||
|
||||
]),
|
||||
all = _values(graph.base().entities);
|
||||
]);
|
||||
var all = _values(graph.base().entities);
|
||||
|
||||
|
||||
function doMatch(ids) {
|
||||
@@ -435,12 +435,12 @@ describe('iD.Features', function() {
|
||||
|
||||
describe('hiding', function() {
|
||||
it('hides child vertices on a hidden way', function() {
|
||||
var a = iD.osmNode({id: 'a', version: 1}),
|
||||
b = iD.osmNode({id: 'b', version: 1}),
|
||||
w = iD.osmWay({id: 'w', nodes: [a.id, b.id], tags: {highway: 'path'}, version: 1}),
|
||||
graph = iD.coreGraph([a, b, w]),
|
||||
geometry = a.geometry(graph),
|
||||
all = _values(graph.base().entities);
|
||||
var a = iD.osmNode({id: 'a', version: 1});
|
||||
var b = iD.osmNode({id: 'b', version: 1});
|
||||
var w = iD.osmWay({id: 'w', nodes: [a.id, b.id], tags: {highway: 'path'}, version: 1});
|
||||
var graph = iD.coreGraph([a, b, w]);
|
||||
var geometry = a.geometry(graph);
|
||||
var all = _values(graph.base().entities);
|
||||
|
||||
features.disable('paths');
|
||||
features.gatherStats(all, graph, dimensions);
|
||||
@@ -452,23 +452,23 @@ describe('iD.Features', function() {
|
||||
});
|
||||
|
||||
it('hides uninteresting (e.g. untagged or "other") member ways on a hidden multipolygon relation', function() {
|
||||
var outer = iD.osmWay({id: 'outer', tags: {area: 'yes', natural: 'wood'}, version: 1}),
|
||||
inner1 = iD.osmWay({id: 'inner1', tags: {barrier: 'fence'}, version: 1}),
|
||||
inner2 = iD.osmWay({id: 'inner2', version: 1}),
|
||||
inner3 = iD.osmWay({id: 'inner3', tags: {highway: 'residential'}, version: 1}),
|
||||
r = iD.osmRelation({
|
||||
id: 'r',
|
||||
tags: {type: 'multipolygon'},
|
||||
members: [
|
||||
{id: outer.id, role: 'outer', type: 'way'},
|
||||
{id: inner1.id, role: 'inner', type: 'way'},
|
||||
{id: inner2.id, role: 'inner', type: 'way'},
|
||||
{id: inner3.id, role: 'inner', type: 'way'}
|
||||
],
|
||||
version: 1
|
||||
}),
|
||||
graph = iD.coreGraph([outer, inner1, inner2, inner3, r]),
|
||||
all = _values(graph.base().entities);
|
||||
var outer = iD.osmWay({id: 'outer', tags: {area: 'yes', natural: 'wood'}, version: 1});
|
||||
var inner1 = iD.osmWay({id: 'inner1', tags: {barrier: 'fence'}, version: 1});
|
||||
var inner2 = iD.osmWay({id: 'inner2', version: 1});
|
||||
var inner3 = iD.osmWay({id: 'inner3', tags: {highway: 'residential'}, version: 1});
|
||||
var r = iD.osmRelation({
|
||||
id: 'r',
|
||||
tags: {type: 'multipolygon'},
|
||||
members: [
|
||||
{id: outer.id, role: 'outer', type: 'way'},
|
||||
{id: inner1.id, role: 'inner', type: 'way'},
|
||||
{id: inner2.id, role: 'inner', type: 'way'},
|
||||
{id: inner3.id, role: 'inner', type: 'way'}
|
||||
],
|
||||
version: 1
|
||||
});
|
||||
var graph = iD.coreGraph([outer, inner1, inner2, inner3, r]);
|
||||
var all = _values(graph.base().entities);
|
||||
|
||||
features.disable('landuse');
|
||||
features.gatherStats(all, graph, dimensions);
|
||||
@@ -480,12 +480,12 @@ describe('iD.Features', function() {
|
||||
});
|
||||
|
||||
it('hides only versioned entities', function() {
|
||||
var a = iD.osmNode({id: 'a', version: 1}),
|
||||
b = iD.osmNode({id: 'b'}),
|
||||
graph = iD.coreGraph([a, b]),
|
||||
ageo = a.geometry(graph),
|
||||
bgeo = b.geometry(graph),
|
||||
all = _values(graph.base().entities);
|
||||
var a = iD.osmNode({id: 'a', version: 1});
|
||||
var b = iD.osmNode({id: 'b'});
|
||||
var graph = iD.coreGraph([a, b]);
|
||||
var ageo = a.geometry(graph);
|
||||
var bgeo = b.geometry(graph);
|
||||
var all = _values(graph.base().entities);
|
||||
|
||||
features.disable('points');
|
||||
features.gatherStats(all, graph, dimensions);
|
||||
@@ -494,10 +494,23 @@ describe('iD.Features', function() {
|
||||
expect(features.isHidden(b, graph, bgeo)).to.be.false;
|
||||
});
|
||||
|
||||
it('#forceVisible', function() {
|
||||
var a = iD.osmNode({id: 'a', version: 1});
|
||||
var graph = iD.coreGraph([a]);
|
||||
var ageo = a.geometry(graph);
|
||||
var all = _values(graph.base().entities);
|
||||
|
||||
features.disable('points');
|
||||
features.gatherStats(all, graph, dimensions);
|
||||
features.forceVisible(['a']);
|
||||
|
||||
expect(features.isHidden(a, graph, ageo)).to.be.false;
|
||||
});
|
||||
|
||||
it('auto-hides features', function() {
|
||||
var graph = iD.coreGraph([]),
|
||||
maxPoints = 200,
|
||||
all, hidden, autoHidden, i, msg;
|
||||
var graph = iD.coreGraph([]);
|
||||
var maxPoints = 200;
|
||||
var all, hidden, autoHidden, i, msg;
|
||||
|
||||
for (i = 0; i < maxPoints; i++) {
|
||||
graph.rebase([iD.osmNode({version: 1})], [graph]);
|
||||
@@ -525,10 +538,10 @@ describe('iD.Features', function() {
|
||||
});
|
||||
|
||||
it('doubles auto-hide threshold when doubling viewport size', function() {
|
||||
var graph = iD.coreGraph([]),
|
||||
maxPoints = 400,
|
||||
dimensions = [2000, 1000],
|
||||
all, hidden, autoHidden, i, msg;
|
||||
var graph = iD.coreGraph([]);
|
||||
var maxPoints = 400;
|
||||
var dimensions = [2000, 1000];
|
||||
var all, hidden, autoHidden, i, msg;
|
||||
|
||||
for (i = 0; i < maxPoints; i++) {
|
||||
graph.rebase([iD.osmNode({version: 1})], [graph]);
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('iD.uiRawTagEditor', function() {
|
||||
expect(tags).to.eql({highway: undefined});
|
||||
done();
|
||||
});
|
||||
iD.utilTriggerEvent(element.selectAll('button.remove'), 'click');
|
||||
iD.utilTriggerEvent(element.selectAll('button.remove'), 'mousedown');
|
||||
});
|
||||
|
||||
it('adds tags when pressing the TAB key on last input.value', function (done) {
|
||||
|
||||
Reference in New Issue
Block a user