mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-30 11:49:39 +02:00
Export live binding for services in iD.services, fix init/reset
(closes #3324) Previously we allowed devs to swap out services that they didn't need. This became difficult now that ES6 exports are immutable bindings. But we can wrap the immutable bindings themselves in a live object, to get back the flexibility that we used to have. This change also drops the `taginfo` accessor on Context, since devs who want to swap out taginfo service with something else can now do so through the live binding. `iD.services.taginfo = myTaginfo()`
This commit is contained in:
@@ -150,7 +150,6 @@ iD can use external presets exclusively or along with the default OpenStreetMap
|
||||
|
||||
var id = iD.Context(window)
|
||||
.presets(customPresets)
|
||||
.taginfo(iD.serviceTaginfo())
|
||||
.imagery(iD.dataImagery);
|
||||
|
||||
```
|
||||
@@ -165,7 +164,6 @@ Just like Presets, Imagery can be configured using the `context.imagery` accesso
|
||||
|
||||
var id = iD.Context(window)
|
||||
.presets(customPresets)
|
||||
.taginfo(iD.serviceTaginfo())
|
||||
.imagery(customImagery);
|
||||
|
||||
```
|
||||
@@ -173,19 +171,6 @@ var id = iD.Context(window)
|
||||
The Imagery object should follow the structure defined by [editor-layer-index](https://github.com/osmlab/editor-layer-index/blob/gh-pages/schema.json)
|
||||
|
||||
|
||||
### Taginfo
|
||||
|
||||
[Taginfo](http://taginfo.openstreetmap.org/) is a service that provides comprehensive documentation about the tags used in OpenStreetMap. iD uses Taginfo to display description and also autocomplete keys and values. This can be completely disabled by removing the `context.taginfo` accessor. To point iD to a different instance of Taginfo other than the default OpenStreetMap instance:
|
||||
|
||||
```js
|
||||
|
||||
var id = iD.Context(window)
|
||||
.presets(customPresets)
|
||||
.taginfo(iD.serviceTaginfo().endpoint('url'))
|
||||
.imagery(customImagery);
|
||||
|
||||
```
|
||||
|
||||
### Minimum Editable Zoom
|
||||
|
||||
The minimum zoom at which iD enters the edit mode is configured using the `context.minEditableZoom()` accessor. The default value is 16. To change this initialise the iD context as:
|
||||
|
||||
Vendored
+1
-2
@@ -39,8 +39,7 @@
|
||||
} else {
|
||||
var id = iD.Context(window)
|
||||
.presets(iD.dataPresets)
|
||||
.imagery(iD.dataImagery)
|
||||
.taginfo(iD.serviceTaginfo.init());
|
||||
.imagery(iD.dataImagery);
|
||||
|
||||
id.ui()(document.getElementById('id-container'));
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
id = iD.Context(window)
|
||||
.presets(iD.dataPresets)
|
||||
.imagery(iD.dataImagery)
|
||||
.taginfo(iD.serviceTaginfo.init())
|
||||
.assetPath('dist/');
|
||||
|
||||
id.ui()(document.getElementById('id-container'));
|
||||
|
||||
+23
-23
@@ -10,7 +10,7 @@ import { presetInit } from '../presets/init';
|
||||
import { rendererBackground } from '../renderer/background';
|
||||
import { rendererFeatures } from '../renderer/features';
|
||||
import { rendererMap } from '../renderer/map';
|
||||
import * as services from '../services/index';
|
||||
import { services } from '../services/index';
|
||||
import { uiInit } from '../ui/init';
|
||||
import { utilDetect } from '../util/detect';
|
||||
import { utilRebind } from '../util/rebind';
|
||||
@@ -142,19 +142,6 @@ export function coreContext(root) {
|
||||
if (history.hasChanges()) return t('save.unsaved_changes');
|
||||
};
|
||||
|
||||
context.flush = function() {
|
||||
context.debouncedSave.cancel();
|
||||
connection.flush();
|
||||
features.reset();
|
||||
history.reset();
|
||||
_.each(services, function(service) {
|
||||
// TODO: fix access to services #3324
|
||||
// var reset = service().reset;
|
||||
// if (reset) reset(context);
|
||||
});
|
||||
return context;
|
||||
};
|
||||
|
||||
|
||||
/* Graph */
|
||||
context.hasEntity = function(id) {
|
||||
@@ -300,15 +287,6 @@ export function coreContext(root) {
|
||||
};
|
||||
|
||||
|
||||
/* Taginfo */
|
||||
var taginfo;
|
||||
context.taginfo = function(_) {
|
||||
if (!arguments.length) return taginfo;
|
||||
taginfo = _;
|
||||
return context;
|
||||
};
|
||||
|
||||
|
||||
/* Assets */
|
||||
var assetPath = '';
|
||||
context.assetPath = function(_) {
|
||||
@@ -355,6 +333,21 @@ export function coreContext(root) {
|
||||
};
|
||||
|
||||
|
||||
/* reset (aka flush) */
|
||||
context.reset = context.flush = function() {
|
||||
context.debouncedSave.cancel();
|
||||
connection.flush();
|
||||
features.reset();
|
||||
history.reset();
|
||||
_.each(services, function(service) {
|
||||
if (typeof service.reset === 'function') {
|
||||
service.reset(context);
|
||||
}
|
||||
});
|
||||
return context;
|
||||
};
|
||||
|
||||
|
||||
/* Init */
|
||||
context.version = '2.0.0-alpha.2';
|
||||
|
||||
@@ -407,5 +400,12 @@ export function coreContext(root) {
|
||||
|
||||
presets = presetInit();
|
||||
|
||||
_.each(services, function(service) {
|
||||
if (typeof service.init === 'function') {
|
||||
service.init(context);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return utilRebind(context, dispatch, 'on');
|
||||
}
|
||||
|
||||
+11
-11
@@ -1,13 +1,13 @@
|
||||
import * as serviceMapillary from './mapillary';
|
||||
import * as serviceNominatim from './nominatim';
|
||||
import * as serviceTaginfo from './taginfo';
|
||||
import * as serviceWikidata from './wikidata';
|
||||
import * as serviceWikipedia from './wikipedia';
|
||||
import serviceMapillary from './mapillary';
|
||||
import serviceNominatim from './nominatim';
|
||||
import serviceTaginfo from './taginfo';
|
||||
import serviceWikidata from './wikidata';
|
||||
import serviceWikipedia from './wikipedia';
|
||||
|
||||
export {
|
||||
serviceMapillary,
|
||||
serviceTaginfo,
|
||||
serviceNominatim,
|
||||
serviceWikidata,
|
||||
serviceWikipedia
|
||||
export var services = {
|
||||
mapillary: serviceMapillary,
|
||||
nominatim: serviceNominatim,
|
||||
taginfo: serviceTaginfo,
|
||||
wikidata: serviceWikidata,
|
||||
wikipedia: serviceWikipedia
|
||||
};
|
||||
|
||||
+183
-185
@@ -10,15 +10,19 @@ import { svgIcon } from '../svg/index';
|
||||
import { utilQsString } from '../util/index';
|
||||
|
||||
|
||||
var mapillary = {},
|
||||
apibase = 'https://a.mapillary.com/v2/',
|
||||
var apibase = 'https://a.mapillary.com/v2/',
|
||||
viewercss = 'https://unpkg.com/mapillary-js@1.3.0/dist/mapillary-js.min.css',
|
||||
viewerjs = 'https://unpkg.com/mapillary-js@1.3.0/dist/mapillary-js.min.js',
|
||||
clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi',
|
||||
maxResults = 1000,
|
||||
maxPages = 10,
|
||||
tileZoom = 14,
|
||||
dispatch = d3.dispatch('loadedImages', 'loadedSigns');
|
||||
dispatch = d3.dispatch('loadedImages', 'loadedSigns'),
|
||||
mapillaryCache,
|
||||
mapillaryClicks,
|
||||
mapillaryImage,
|
||||
mapillarySignDefs,
|
||||
mapillaryViewer;
|
||||
|
||||
|
||||
function loadSignStyles(context) {
|
||||
@@ -33,95 +37,19 @@ function loadSignStyles(context) {
|
||||
|
||||
|
||||
function loadSignDefs(context) {
|
||||
if (mapillary.sign_defs) return;
|
||||
mapillary.sign_defs = {};
|
||||
if (mapillarySignDefs) return;
|
||||
mapillarySignDefs = {};
|
||||
|
||||
_.each(['au', 'br', 'ca', 'de', 'us'], function(region) {
|
||||
d3.json(context.asset('traffico/string-maps/' + region + '-map.json'), function(err, data) {
|
||||
if (err) return;
|
||||
if (region === 'de') region = 'eu';
|
||||
mapillary.sign_defs[region] = data;
|
||||
mapillarySignDefs[region] = data;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function loadViewer() {
|
||||
// mapillary-wrap
|
||||
var wrap = d3.select('#content').selectAll('.mapillary-wrap')
|
||||
.data([0]);
|
||||
|
||||
var enter = wrap.enter()
|
||||
.append('div')
|
||||
.attr('class', 'mapillary-wrap')
|
||||
.classed('al', true) // 'al'=left, 'ar'=right
|
||||
.classed('hidden', true);
|
||||
|
||||
enter
|
||||
.append('button')
|
||||
.attr('class', 'thumb-hide')
|
||||
.on('click', function () { mapillary.hideViewer(); })
|
||||
.append('div')
|
||||
.call(svgIcon('#icon-close'));
|
||||
|
||||
enter
|
||||
.append('div')
|
||||
.attr('id', 'mly')
|
||||
.attr('class', 'mly-wrapper')
|
||||
.classed('active', false);
|
||||
|
||||
// mapillary-viewercss
|
||||
d3.select('head').selectAll('#mapillary-viewercss')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('link')
|
||||
.attr('id', 'mapillary-viewercss')
|
||||
.attr('rel', 'stylesheet')
|
||||
.attr('href', viewercss);
|
||||
|
||||
// mapillary-viewerjs
|
||||
d3.select('head').selectAll('#mapillary-viewerjs')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('script')
|
||||
.attr('id', 'mapillary-viewerjs')
|
||||
.attr('src', viewerjs);
|
||||
}
|
||||
|
||||
|
||||
function initViewer(imageKey, context) {
|
||||
|
||||
function nodeChanged(d) {
|
||||
var clicks = mapillary.clicks;
|
||||
var index = clicks.indexOf(d.key);
|
||||
if (index > -1) { // nodechange initiated from clicking on a marker..
|
||||
clicks.splice(index, 1);
|
||||
} else { // nodechange initiated from the Mapillary viewer controls..
|
||||
var loc = d.apiNavImIm ? [d.apiNavImIm.lon, d.apiNavImIm.lat] : [d.latLon.lon, d.latLon.lat];
|
||||
context.map().centerEase(loc);
|
||||
mapillary.setSelectedImage(d.key, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (Mapillary && imageKey) {
|
||||
var opts = {
|
||||
baseImageSize: 320,
|
||||
cover: false,
|
||||
cache: true,
|
||||
debug: false,
|
||||
imagePlane: true,
|
||||
loading: true,
|
||||
sequence: true
|
||||
};
|
||||
|
||||
var viewer = new Mapillary.Viewer('mly', clientId, imageKey, opts);
|
||||
viewer.on('nodechanged', nodeChanged);
|
||||
viewer.on('loadingchanged', mapillary.setViewerLoading);
|
||||
mapillary.viewer = viewer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function abortRequest(i) {
|
||||
i.abort();
|
||||
}
|
||||
@@ -186,7 +114,7 @@ function loadTiles(which, url, projection, dimensions) {
|
||||
|
||||
|
||||
function loadTilePage(which, url, tile, page) {
|
||||
var cache = mapillary.cache[which],
|
||||
var cache = mapillaryCache[which],
|
||||
id = tile.id + ',' + String(page),
|
||||
rect = tile.extent.rectangle();
|
||||
|
||||
@@ -267,74 +195,137 @@ function searchLimited(psize, limit, projection, dimensions, rtree) {
|
||||
}
|
||||
|
||||
|
||||
// this function is only used by test cases
|
||||
export function getMapillary() {
|
||||
return mapillary;
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
init: function() {
|
||||
if (!mapillaryCache) {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
this.event = utilRebind(this, dispatch, 'on');
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
var cache = mapillaryCache;
|
||||
|
||||
if (cache) {
|
||||
if (cache.images && cache.images.inflight) {
|
||||
_.forEach(cache.images.inflight, abortRequest);
|
||||
}
|
||||
if (cache.signs && cache.signs.inflight) {
|
||||
_.forEach(cache.signs.inflight, abortRequest);
|
||||
}
|
||||
}
|
||||
|
||||
mapillaryCache = {
|
||||
images: { inflight: {}, loaded: {}, rtree: rbush() },
|
||||
signs: { inflight: {}, loaded: {}, rtree: rbush() }
|
||||
};
|
||||
|
||||
mapillaryImage = null;
|
||||
mapillaryClicks = [];
|
||||
},
|
||||
|
||||
|
||||
export function init() {
|
||||
|
||||
mapillary.loadImages = function(projection, dimensions) {
|
||||
loadImages: function(projection, dimensions) {
|
||||
var url = apibase + 'search/im/geojson?';
|
||||
loadTiles('images', url, projection, dimensions);
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
mapillary.loadSigns = function(context, projection, dimensions) {
|
||||
loadSigns: function(context, projection, dimensions) {
|
||||
var url = apibase + 'search/im/geojson/or?';
|
||||
loadSignStyles(context);
|
||||
loadSignDefs(context);
|
||||
loadTiles('signs', url, projection, dimensions);
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
mapillary.loadViewer = function() {
|
||||
loadViewer();
|
||||
};
|
||||
loadViewer: function() {
|
||||
var that = this;
|
||||
var wrap = d3.select('#content').selectAll('.mapillary-wrap')
|
||||
.data([0]);
|
||||
|
||||
var enter = wrap.enter()
|
||||
.append('div')
|
||||
.attr('class', 'mapillary-wrap')
|
||||
.classed('al', true) // 'al'=left, 'ar'=right
|
||||
.classed('hidden', true);
|
||||
|
||||
enter
|
||||
.append('button')
|
||||
.attr('class', 'thumb-hide')
|
||||
.on('click', function () { that.hideViewer(); })
|
||||
.append('div')
|
||||
.call(svgIcon('#icon-close'));
|
||||
|
||||
enter
|
||||
.append('div')
|
||||
.attr('id', 'mly')
|
||||
.attr('class', 'mly-wrapper')
|
||||
.classed('active', false);
|
||||
|
||||
// mapillary-viewercss
|
||||
d3.select('head').selectAll('#mapillary-viewercss')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('link')
|
||||
.attr('id', 'mapillary-viewercss')
|
||||
.attr('rel', 'stylesheet')
|
||||
.attr('href', viewercss);
|
||||
|
||||
// mapillary-viewerjs
|
||||
d3.select('head').selectAll('#mapillary-viewerjs')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('script')
|
||||
.attr('id', 'mapillary-viewerjs')
|
||||
.attr('src', viewerjs);
|
||||
},
|
||||
|
||||
|
||||
mapillary.images = function(projection, dimensions) {
|
||||
images: function(projection, dimensions) {
|
||||
var psize = 16, limit = 3;
|
||||
return searchLimited(psize, limit, projection, dimensions, mapillary.cache.images.rtree);
|
||||
};
|
||||
return searchLimited(psize, limit, projection, dimensions, mapillaryCache.images.rtree);
|
||||
},
|
||||
|
||||
|
||||
mapillary.signs = function(projection, dimensions) {
|
||||
signs: function(projection, dimensions) {
|
||||
var psize = 32, limit = 3;
|
||||
return searchLimited(psize, limit, projection, dimensions, mapillary.cache.signs.rtree);
|
||||
};
|
||||
return searchLimited(psize, limit, projection, dimensions, mapillaryCache.signs.rtree);
|
||||
},
|
||||
|
||||
|
||||
mapillary.signsSupported = function() {
|
||||
signsSupported: function() {
|
||||
var detected = utilDetect();
|
||||
return (!(detected.ie || detected.browser.toLowerCase() === 'safari'));
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
mapillary.signHTML = function(d) {
|
||||
if (!mapillary.sign_defs) return;
|
||||
signHTML: function(d) {
|
||||
if (!mapillarySignDefs) return;
|
||||
|
||||
var detectionPackage = d.signs[0].package,
|
||||
type = d.signs[0].type,
|
||||
country = detectionPackage.split('_')[1];
|
||||
|
||||
return mapillary.sign_defs[country][type];
|
||||
};
|
||||
return mapillarySignDefs[country][type];
|
||||
},
|
||||
|
||||
|
||||
mapillary.showViewer = function() {
|
||||
showViewer: function() {
|
||||
d3.select('#content')
|
||||
.selectAll('.mapillary-wrap')
|
||||
.classed('hidden', false)
|
||||
.selectAll('.mly-wrapper')
|
||||
.classed('active', true);
|
||||
|
||||
return mapillary;
|
||||
};
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
mapillary.hideViewer = function() {
|
||||
hideViewer: function() {
|
||||
d3.select('#content')
|
||||
.selectAll('.mapillary-wrap')
|
||||
.classed('hidden', true)
|
||||
@@ -344,100 +335,107 @@ export function init() {
|
||||
d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
|
||||
.classed('selected', false);
|
||||
|
||||
mapillary.image = null;
|
||||
return mapillary;
|
||||
};
|
||||
mapillaryImage = null;
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
mapillary.setViewerLoading = function(loading) {
|
||||
var canvas = d3.select('#content')
|
||||
.selectAll('.mly-wrapper canvas');
|
||||
|
||||
if (canvas.empty()) return; // viewer not loaded yet
|
||||
|
||||
var cover = d3.select('#content')
|
||||
.selectAll('.mly-wrapper .Cover');
|
||||
|
||||
cover.classed('CoverDone', !loading);
|
||||
|
||||
var button = cover.selectAll('.CoverButton')
|
||||
.data(loading ? [0] : []);
|
||||
|
||||
button.exit()
|
||||
.remove();
|
||||
|
||||
button.enter()
|
||||
.append('div')
|
||||
.attr('class', 'CoverButton')
|
||||
.append('div')
|
||||
.attr('class', 'uil-ripple-css')
|
||||
.append('div');
|
||||
|
||||
return mapillary;
|
||||
};
|
||||
|
||||
|
||||
mapillary.updateViewer = function(imageKey, context) {
|
||||
if (!mapillary) return;
|
||||
updateViewer: function(imageKey, context) {
|
||||
if (!imageKey) return;
|
||||
|
||||
if (!mapillary.viewer) {
|
||||
initViewer(imageKey, context);
|
||||
if (!mapillaryViewer) {
|
||||
this.initViewer(imageKey, context);
|
||||
} else {
|
||||
mapillary.viewer.moveToKey(imageKey);
|
||||
mapillaryViewer.moveToKey(imageKey);
|
||||
}
|
||||
|
||||
return mapillary;
|
||||
};
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
mapillary.getSelectedImage = function() {
|
||||
if (!mapillary) return null;
|
||||
return mapillary.image;
|
||||
};
|
||||
initViewer: function(imageKey, context) {
|
||||
var that = this;
|
||||
if (Mapillary && imageKey) {
|
||||
var opts = {
|
||||
baseImageSize: 320,
|
||||
cover: false,
|
||||
cache: true,
|
||||
debug: false,
|
||||
imagePlane: true,
|
||||
loading: true,
|
||||
sequence: true
|
||||
};
|
||||
|
||||
mapillaryViewer = new Mapillary.Viewer('mly', clientId, imageKey, opts);
|
||||
mapillaryViewer.on('nodechanged', nodeChanged);
|
||||
mapillaryViewer.on('loadingchanged', loadingChanged);
|
||||
}
|
||||
|
||||
function nodeChanged(node) {
|
||||
var clicks = mapillaryClicks;
|
||||
var index = clicks.indexOf(node.key);
|
||||
if (index > -1) { // nodechange initiated from clicking on a marker..
|
||||
clicks.splice(index, 1);
|
||||
} else { // nodechange initiated from the Mapillary viewer controls..
|
||||
var loc = node.apiNavImIm ? [node.apiNavImIm.lon, node.apiNavImIm.lat] : [node.latLon.lon, node.latLon.lat];
|
||||
context.map().centerEase(loc);
|
||||
that.selectedImage(node.key, false);
|
||||
}
|
||||
}
|
||||
|
||||
function loadingChanged(loading) {
|
||||
var canvas = d3.select('#content')
|
||||
.selectAll('.mly-wrapper canvas');
|
||||
|
||||
if (canvas.empty()) return; // viewer not loaded yet
|
||||
|
||||
var cover = d3.select('#content')
|
||||
.selectAll('.mly-wrapper .Cover');
|
||||
|
||||
cover.classed('CoverDone', !loading);
|
||||
|
||||
var button = cover.selectAll('.CoverButton')
|
||||
.data(loading ? [0] : []);
|
||||
|
||||
button.exit()
|
||||
.remove();
|
||||
|
||||
button.enter()
|
||||
.append('div')
|
||||
.attr('class', 'CoverButton')
|
||||
.append('div')
|
||||
.attr('class', 'uil-ripple-css')
|
||||
.append('div');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
mapillary.setSelectedImage = function(imageKey, fromClick) {
|
||||
if (!mapillary) return null;
|
||||
selectedImage: function(imageKey, fromClick) {
|
||||
if (!arguments.length) return mapillaryImage;
|
||||
|
||||
mapillary.image = imageKey;
|
||||
mapillaryImage = imageKey;
|
||||
if (fromClick) {
|
||||
mapillary.clicks.push(imageKey);
|
||||
mapillaryClicks.push(imageKey);
|
||||
}
|
||||
|
||||
d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
|
||||
.classed('selected', function(d) { return d.key === imageKey; });
|
||||
|
||||
return mapillary;
|
||||
};
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
mapillary.reset = function() {
|
||||
var cache = mapillary.cache;
|
||||
|
||||
if (cache) {
|
||||
_.forEach(cache.images.inflight, abortRequest);
|
||||
_.forEach(cache.signs.inflight, abortRequest);
|
||||
}
|
||||
|
||||
mapillary.cache = {
|
||||
images: { inflight: {}, loaded: {}, rtree: rbush() },
|
||||
signs: { inflight: {}, loaded: {}, rtree: rbush() }
|
||||
};
|
||||
|
||||
mapillary.image = null;
|
||||
mapillary.clicks = [];
|
||||
|
||||
return mapillary;
|
||||
};
|
||||
cache: function(_) {
|
||||
if (!arguments.length) return mapillaryCache;
|
||||
mapillaryCache = _;
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
if (!mapillary.cache) {
|
||||
mapillary.reset();
|
||||
signDefs: function(_) {
|
||||
if (!arguments.length) return mapillarySignDefs;
|
||||
mapillarySignDefs = _;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
mapillary.event = utilRebind(mapillary, dispatch, 'on');
|
||||
|
||||
return mapillary;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,45 +4,45 @@ import { geoExtent } from '../geo/index';
|
||||
import { utilQsString } from '../util/index';
|
||||
|
||||
|
||||
var endpoint, cache;
|
||||
var endpoint = 'https://nominatim.openstreetmap.org/reverse?',
|
||||
nominatimCache;
|
||||
|
||||
export function init() {
|
||||
endpoint = 'https://nominatim.openstreetmap.org/reverse?';
|
||||
if (!cache) {
|
||||
reset();
|
||||
|
||||
export default {
|
||||
|
||||
init: function() { nominatimCache = rbush(); },
|
||||
reset: function() { nominatimCache = rbush(); },
|
||||
|
||||
|
||||
countryCode: function (location, callback) {
|
||||
var countryCodes = nominatimCache.search(
|
||||
{ minX: location[0], minY: location[1], maxX: location[0], maxY: location[1] }
|
||||
);
|
||||
|
||||
if (countryCodes.length > 0) {
|
||||
return callback(null, countryCodes[0].data);
|
||||
}
|
||||
|
||||
d3.json(endpoint +
|
||||
utilQsString({
|
||||
format: 'json',
|
||||
addressdetails: 1,
|
||||
lat: location[1],
|
||||
lon: location[0]
|
||||
}), function(err, result) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
else if (result && result.error)
|
||||
return callback(result.error);
|
||||
|
||||
var extent = geoExtent(location).padByMeters(1000);
|
||||
nominatimCache.insert(Object.assign(extent.bbox(),
|
||||
{ data: result.address.country_code }
|
||||
));
|
||||
|
||||
callback(null, result.address.country_code);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function reset() {
|
||||
cache = rbush();
|
||||
}
|
||||
|
||||
|
||||
export function countryCode(location, callback) {
|
||||
var countryCodes = cache.search({
|
||||
minX: location[0], minY: location[1], maxX: location[0], maxY: location[1]
|
||||
});
|
||||
|
||||
if (countryCodes.length > 0)
|
||||
return callback(null, countryCodes[0].data);
|
||||
|
||||
d3.json(endpoint +
|
||||
utilQsString({
|
||||
format: 'json',
|
||||
addressdetails: 1,
|
||||
lat: location[1],
|
||||
lon: location[0]
|
||||
}), function(err, result) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
else if (result && result.error)
|
||||
return callback(result.error);
|
||||
|
||||
var extent = geoExtent(location).padByMeters(1000);
|
||||
|
||||
cache.insert(Object.assign(extent.bbox(), { data: result.address.country_code }));
|
||||
|
||||
callback(null, result.address.country_code);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
+74
-56
@@ -3,8 +3,8 @@ import _ from 'lodash';
|
||||
import { utilQsString } from '../util/index';
|
||||
|
||||
|
||||
var taginfo = {},
|
||||
endpoint = 'https://taginfo.openstreetmap.org/api/4/',
|
||||
var endpoint = 'https://taginfo.openstreetmap.org/api/4/',
|
||||
taginfoCache = {},
|
||||
tag_sorts = {
|
||||
point: 'count_nodes',
|
||||
vertex: 'count_nodes',
|
||||
@@ -130,10 +130,8 @@ var debounced = _.debounce(d3.json, 100, true);
|
||||
|
||||
|
||||
function request(url, debounce, callback) {
|
||||
var cache = taginfo.cache;
|
||||
|
||||
if (cache[url]) {
|
||||
callback(null, cache[url]);
|
||||
if (taginfoCache[url]) {
|
||||
callback(null, taginfoCache[url]);
|
||||
} else if (debounce) {
|
||||
debounced(url, done);
|
||||
} else {
|
||||
@@ -141,14 +139,21 @@ function request(url, debounce, callback) {
|
||||
}
|
||||
|
||||
function done(err, data) {
|
||||
if (!err) cache[url] = data;
|
||||
if (!err) {
|
||||
taginfoCache[url] = data;
|
||||
}
|
||||
callback(err, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function init() {
|
||||
taginfo.keys = function(parameters, callback) {
|
||||
export default {
|
||||
|
||||
init: function() { taginfoCache = {}; },
|
||||
reset: function() { taginfoCache = {}; },
|
||||
|
||||
|
||||
keys: function(parameters, callback) {
|
||||
var debounce = parameters.debounce;
|
||||
parameters = clean(setSort(parameters));
|
||||
request(endpoint + 'keys/all?' +
|
||||
@@ -158,13 +163,18 @@ export function init() {
|
||||
sortorder: 'desc',
|
||||
page: 1
|
||||
}, parameters)), debounce, function(err, d) {
|
||||
if (err) return callback(err);
|
||||
var f = filterKeys(parameters.filter);
|
||||
callback(null, d.data.filter(f).sort(sortKeys).map(valKey));
|
||||
});
|
||||
};
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
var f = filterKeys(parameters.filter);
|
||||
callback(null, d.data.filter(f).sort(sortKeys).map(valKey));
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
taginfo.multikeys = function(parameters, callback) {
|
||||
|
||||
multikeys: function(parameters, callback) {
|
||||
var debounce = parameters.debounce;
|
||||
parameters = clean(setSort(parameters));
|
||||
request(endpoint + 'keys/all?' +
|
||||
@@ -174,13 +184,18 @@ export function init() {
|
||||
sortorder: 'desc',
|
||||
page: 1
|
||||
}, parameters)), debounce, function(err, d) {
|
||||
if (err) return callback(err);
|
||||
var f = filterMultikeys();
|
||||
callback(null, d.data.filter(f).map(valKey));
|
||||
});
|
||||
};
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
var f = filterMultikeys();
|
||||
callback(null, d.data.filter(f).map(valKey));
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
taginfo.values = function(parameters, callback) {
|
||||
|
||||
values: function(parameters, callback) {
|
||||
var debounce = parameters.debounce;
|
||||
parameters = clean(setSort(setFilter(parameters)));
|
||||
request(endpoint + 'key/values?' +
|
||||
@@ -190,19 +205,24 @@ export function init() {
|
||||
sortorder: 'desc',
|
||||
page: 1
|
||||
}, parameters)), debounce, function(err, d) {
|
||||
if (err) return callback(err);
|
||||
// In most cases we prefer taginfo value results with lowercase letters.
|
||||
// A few OSM keys expect values to contain uppercase values (see #3377).
|
||||
// This is not an exhaustive list (e.g. `name` also has uppercase values)
|
||||
// but these are the fields where taginfo value lookup is most useful.
|
||||
var re = /network|taxon|genus|species/;
|
||||
var allowUpperCase = (parameters.key.match(re) !== null);
|
||||
var f = filterValues(allowUpperCase);
|
||||
callback(null, d.data.filter(f).map(valKeyDescription));
|
||||
});
|
||||
};
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
// In most cases we prefer taginfo value results with lowercase letters.
|
||||
// A few OSM keys expect values to contain uppercase values (see #3377).
|
||||
// This is not an exhaustive list (e.g. `name` also has uppercase values)
|
||||
// but these are the fields where taginfo value lookup is most useful.
|
||||
var re = /network|taxon|genus|species/;
|
||||
var allowUpperCase = (parameters.key.match(re) !== null);
|
||||
var f = filterValues(allowUpperCase);
|
||||
callback(null, d.data.filter(f).map(valKeyDescription));
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
taginfo.roles = function(parameters, callback) {
|
||||
|
||||
roles: function(parameters, callback) {
|
||||
var debounce = parameters.debounce;
|
||||
var geometry = parameters.geometry;
|
||||
parameters = clean(setSortMembers(parameters));
|
||||
@@ -213,13 +233,18 @@ export function init() {
|
||||
sortorder: 'desc',
|
||||
page: 1
|
||||
}, parameters)), debounce, function(err, d) {
|
||||
if (err) return callback(err);
|
||||
var f = filterRoles(geometry);
|
||||
callback(null, d.data.filter(f).map(roleKey));
|
||||
});
|
||||
};
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
var f = filterRoles(geometry);
|
||||
callback(null, d.data.filter(f).map(roleKey));
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
taginfo.docs = function(parameters, callback) {
|
||||
|
||||
docs: function(parameters, callback) {
|
||||
var debounce = parameters.debounce;
|
||||
parameters = clean(setSort(parameters));
|
||||
|
||||
@@ -228,26 +253,19 @@ export function init() {
|
||||
else if (parameters.rtype) path = 'relation/wiki_pages?';
|
||||
|
||||
request(endpoint + path + utilQsString(parameters), debounce, function(err, d) {
|
||||
if (err) return callback(err);
|
||||
callback(null, d.data);
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, d.data);
|
||||
}
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
taginfo.endpoint = function(_) {
|
||||
|
||||
endpoint: function(_) {
|
||||
if (!arguments.length) return endpoint;
|
||||
endpoint = _;
|
||||
return taginfo;
|
||||
};
|
||||
|
||||
taginfo.reset = function() {
|
||||
taginfo.cache = {};
|
||||
return taginfo;
|
||||
};
|
||||
|
||||
|
||||
if (!taginfo.cache) {
|
||||
taginfo.reset();
|
||||
return this;
|
||||
}
|
||||
|
||||
return taginfo;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,15 +2,17 @@ import { jsonpRequest } from '../util/jsonp_request';
|
||||
import { utilQsString } from '../util/index';
|
||||
|
||||
|
||||
var wikidata = {},
|
||||
endpoint = 'https://www.wikidata.org/w/api.php?';
|
||||
var endpoint = 'https://www.wikidata.org/w/api.php?';
|
||||
|
||||
export default {
|
||||
|
||||
init: function() {},
|
||||
reset: function() {},
|
||||
|
||||
export function init() {
|
||||
|
||||
// Given a Wikipedia language and article title, return an array of
|
||||
// corresponding Wikidata entities.
|
||||
wikidata.itemsByTitle = function(lang, title, callback) {
|
||||
itemsByTitle: function(lang, title, callback) {
|
||||
if (!title) {
|
||||
callback('', {});
|
||||
return;
|
||||
@@ -31,8 +33,6 @@ export function init() {
|
||||
callback(title, data.entities || {});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return wikidata;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,12 +2,15 @@ import { jsonpRequest } from '../util/jsonp_request';
|
||||
import { utilQsString } from '../util/index';
|
||||
|
||||
|
||||
var wikipedia = {},
|
||||
endpoint = 'https://en.wikipedia.org/w/api.php?';
|
||||
var endpoint = 'https://en.wikipedia.org/w/api.php?';
|
||||
|
||||
export default {
|
||||
|
||||
init: function() {},
|
||||
reset: function() {},
|
||||
|
||||
|
||||
export function init() {
|
||||
wikipedia.search = function(lang, query, callback) {
|
||||
search: function(lang, query, callback) {
|
||||
if (!query) {
|
||||
callback('', []);
|
||||
return;
|
||||
@@ -32,10 +35,10 @@ export function init() {
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
wikipedia.suggestions = function(lang, query, callback) {
|
||||
suggestions: function(lang, query, callback) {
|
||||
if (!query) {
|
||||
callback('', []);
|
||||
return;
|
||||
@@ -58,10 +61,10 @@ export function init() {
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
wikipedia.translations = function(lang, title, callback) {
|
||||
translations: function(lang, title, callback) {
|
||||
if (!title) {
|
||||
callback({});
|
||||
return;
|
||||
@@ -90,8 +93,6 @@ export function init() {
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return wikipedia;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as d3 from 'd3';
|
||||
import _ from 'lodash';
|
||||
import { svgPointTransform } from './point_transform';
|
||||
import { utilGetDimensions, utilSetDimensions } from '../util/dimensions';
|
||||
import { serviceMapillary } from '../services/index';
|
||||
import { services } from '../services/index';
|
||||
|
||||
|
||||
export function svgMapillaryImages(projection, context, dispatch) {
|
||||
@@ -20,10 +20,10 @@ export function svgMapillaryImages(projection, context, dispatch) {
|
||||
|
||||
|
||||
function getMapillary() {
|
||||
if (serviceMapillary && !_mapillary) {
|
||||
_mapillary = serviceMapillary.init();
|
||||
if (services.mapillary && !_mapillary) {
|
||||
_mapillary = services.mapillary;
|
||||
_mapillary.event.on('loadedImages', debouncedRedraw);
|
||||
} else if (!serviceMapillary && _mapillary) {
|
||||
} else if (!services.mapillary && _mapillary) {
|
||||
_mapillary = null;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export function svgMapillaryImages(projection, context, dispatch) {
|
||||
context.map().centerEase(d.loc);
|
||||
|
||||
mapillary
|
||||
.setSelectedImage(d.key, true)
|
||||
.selectedImage(d.key, true)
|
||||
.updateViewer(d.key, context)
|
||||
.showViewer();
|
||||
}
|
||||
@@ -97,7 +97,7 @@ export function svgMapillaryImages(projection, context, dispatch) {
|
||||
function update() {
|
||||
var mapillary = getMapillary(),
|
||||
data = (mapillary ? mapillary.images(projection, utilGetDimensions(layer)) : []),
|
||||
imageKey = mapillary ? mapillary.getSelectedImage() : null;
|
||||
imageKey = mapillary ? mapillary.selectedImage() : null;
|
||||
|
||||
var markers = layer.selectAll('.viewfield-group')
|
||||
.data(data, function(d) { return d.key; });
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as d3 from 'd3';
|
||||
import _ from 'lodash';
|
||||
import { utilGetDimensions, utilSetDimensions } from '../util/dimensions';
|
||||
import { svgPointTransform } from './point_transform';
|
||||
import { serviceMapillary } from '../services/index';
|
||||
import { services } from '../services/index';
|
||||
|
||||
|
||||
export function svgMapillarySigns(projection, context, dispatch) {
|
||||
@@ -20,10 +20,10 @@ export function svgMapillarySigns(projection, context, dispatch) {
|
||||
|
||||
|
||||
function getMapillary() {
|
||||
if (serviceMapillary && !_mapillary) {
|
||||
_mapillary = serviceMapillary.init();
|
||||
if (services.mapillary && !_mapillary) {
|
||||
_mapillary = services.mapillary;
|
||||
_mapillary.event.on('loadedSigns', debouncedRedraw);
|
||||
} else if (!serviceMapillary && _mapillary) {
|
||||
} else if (!services.mapillary && _mapillary) {
|
||||
_mapillary = null;
|
||||
}
|
||||
return _mapillary;
|
||||
@@ -60,7 +60,7 @@ export function svgMapillarySigns(projection, context, dispatch) {
|
||||
context.map().centerEase(d.loc);
|
||||
|
||||
mapillary
|
||||
.setSelectedImage(d.key, true)
|
||||
.selectedImage(d.key, true)
|
||||
.updateViewer(d.key, context)
|
||||
.showViewer();
|
||||
}
|
||||
@@ -69,7 +69,7 @@ export function svgMapillarySigns(projection, context, dispatch) {
|
||||
function update() {
|
||||
var mapillary = getMapillary(),
|
||||
data = (mapillary ? mapillary.signs(projection, utilGetDimensions(layer)) : []),
|
||||
imageKey = mapillary ? mapillary.getSelectedImage() : null;
|
||||
imageKey = mapillary ? mapillary.selectedImage() : null;
|
||||
|
||||
var signs = layer.selectAll('.icon-sign')
|
||||
.data(data, function(d) { return d.key; });
|
||||
|
||||
@@ -9,16 +9,17 @@ import {
|
||||
geoSphericalDistance
|
||||
} from '../../geo/index';
|
||||
|
||||
import { serviceNominatim } from '../../services/index';
|
||||
import { services } from '../../services/index';
|
||||
import { utilRebind } from '../../util/rebind';
|
||||
import { utilGetSetValue } from '../../util/get_set_value';
|
||||
|
||||
|
||||
export function uiFieldAddress(field, context) {
|
||||
var dispatch = d3.dispatch('init', 'change'),
|
||||
wrap,
|
||||
entity,
|
||||
isInitialized;
|
||||
nominatim = services.nominatim,
|
||||
wrap = d3.select(null),
|
||||
isInitialized = false,
|
||||
entity;
|
||||
|
||||
var widths = {
|
||||
housenumber: 1/3,
|
||||
@@ -114,6 +115,72 @@ export function uiFieldAddress(field, context) {
|
||||
}
|
||||
|
||||
|
||||
function initCallback(err, countryCode) {
|
||||
if (err) return;
|
||||
|
||||
var addressFormat = _.find(dataAddressFormats, function (a) {
|
||||
return a && a.countryCodes && _.includes(a.countryCodes, countryCode);
|
||||
}) || _.first(dataAddressFormats);
|
||||
|
||||
function row(r) {
|
||||
// Normalize widths.
|
||||
var total = _.reduce(r, function(sum, field) {
|
||||
return sum + (widths[field] || 0.5);
|
||||
}, 0);
|
||||
|
||||
return r.map(function (field) {
|
||||
return {
|
||||
id: field,
|
||||
width: (widths[field] || 0.5) / total
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
wrap.selectAll('div')
|
||||
.data(addressFormat.format)
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'addr-row')
|
||||
.selectAll('input')
|
||||
.data(row)
|
||||
.enter()
|
||||
.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
|
||||
.attr('class', function (d) { return 'addr-' + d.id; })
|
||||
.style('width', function (d) { return d.width * 100 + '%'; });
|
||||
|
||||
// Update
|
||||
wrap.selectAll('.addr-street')
|
||||
.call(d3combobox()
|
||||
.fetcher(function(value, callback) {
|
||||
callback(getStreets());
|
||||
}));
|
||||
|
||||
wrap.selectAll('.addr-city')
|
||||
.call(d3combobox()
|
||||
.fetcher(function(value, callback) {
|
||||
callback(getCities());
|
||||
}));
|
||||
|
||||
wrap.selectAll('.addr-postcode')
|
||||
.call(d3combobox()
|
||||
.fetcher(function(value, callback) {
|
||||
callback(getPostCodes());
|
||||
}));
|
||||
|
||||
wrap.selectAll('input')
|
||||
.on('blur', change())
|
||||
.on('change', change());
|
||||
|
||||
wrap.selectAll('input:not(.combobox-input)')
|
||||
.on('input', change(true));
|
||||
|
||||
dispatch.call('init');
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
|
||||
function address(selection) {
|
||||
isInitialized = false;
|
||||
|
||||
@@ -126,72 +193,10 @@ export function uiFieldAddress(field, context) {
|
||||
.merge(wrap);
|
||||
|
||||
|
||||
var center = entity.extent(context.graph()).center(),
|
||||
addressFormat;
|
||||
|
||||
serviceNominatim.init();
|
||||
serviceNominatim.countryCode(center, function (err, countryCode) {
|
||||
addressFormat = _.find(dataAddressFormats, function (a) {
|
||||
return a && a.countryCodes && _.includes(a.countryCodes, countryCode);
|
||||
}) || _.first(dataAddressFormats);
|
||||
|
||||
function row(r) {
|
||||
// Normalize widths.
|
||||
var total = _.reduce(r, function(sum, field) {
|
||||
return sum + (widths[field] || 0.5);
|
||||
}, 0);
|
||||
|
||||
return r.map(function (field) {
|
||||
return {
|
||||
id: field,
|
||||
width: (widths[field] || 0.5) / total
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
wrap.selectAll('div')
|
||||
.data(addressFormat.format)
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'addr-row')
|
||||
.selectAll('input')
|
||||
.data(row)
|
||||
.enter()
|
||||
.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
|
||||
.attr('class', function (d) { return 'addr-' + d.id; })
|
||||
.style('width', function (d) { return d.width * 100 + '%'; });
|
||||
|
||||
// Update
|
||||
wrap.selectAll('.addr-street')
|
||||
.call(d3combobox()
|
||||
.fetcher(function(value, callback) {
|
||||
callback(getStreets());
|
||||
}));
|
||||
|
||||
wrap.selectAll('.addr-city')
|
||||
.call(d3combobox()
|
||||
.fetcher(function(value, callback) {
|
||||
callback(getCities());
|
||||
}));
|
||||
|
||||
wrap.selectAll('.addr-postcode')
|
||||
.call(d3combobox()
|
||||
.fetcher(function(value, callback) {
|
||||
callback(getPostCodes());
|
||||
}));
|
||||
|
||||
wrap.selectAll('input')
|
||||
.on('blur', change())
|
||||
.on('change', change());
|
||||
|
||||
wrap.selectAll('input:not(.combobox-input)')
|
||||
.on('input', change(true));
|
||||
|
||||
dispatch.call('init');
|
||||
isInitialized = true;
|
||||
});
|
||||
if (nominatim && entity) {
|
||||
var center = entity.extent(context.graph()).center();
|
||||
nominatim.countryCode(center, initCallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as d3 from 'd3';
|
||||
import _ from 'lodash';
|
||||
import { t } from '../../util/locale';
|
||||
import { d3combobox } from '../../lib/d3.combobox.js';
|
||||
import { serviceNominatim } from '../../services/index';
|
||||
import { services } from '../../services/index';
|
||||
import { utilRebind } from '../../util/rebind';
|
||||
import { utilGetSetValue } from '../../util/get_set_value';
|
||||
|
||||
@@ -15,6 +15,8 @@ export {
|
||||
|
||||
export function uiFieldCombo(field, context) {
|
||||
var dispatch = d3.dispatch('change'),
|
||||
nominatim = services.nominatim,
|
||||
taginfo = services.taginfo,
|
||||
isMulti = (field.type === 'multiCombo'),
|
||||
isNetwork = (field.type === 'networkCombo'),
|
||||
optstrings = field.strings && field.strings.options,
|
||||
@@ -108,7 +110,7 @@ export function uiFieldCombo(field, context) {
|
||||
selection.call(combobox, attachTo);
|
||||
setStaticValues(setPlaceholder);
|
||||
|
||||
} else if (context.taginfo()) {
|
||||
} else if (taginfo) {
|
||||
selection.call(combobox.fetcher(setTaginfoValues), attachTo);
|
||||
setTaginfoValues('', setPlaceholder);
|
||||
}
|
||||
@@ -151,7 +153,7 @@ export function uiFieldCombo(field, context) {
|
||||
if (hasCountryPrefix) {
|
||||
query = country + ':';
|
||||
}
|
||||
context.taginfo()[fn]({
|
||||
taginfo[fn]({
|
||||
debounce: true,
|
||||
key: field.key,
|
||||
geometry: context.geometry(entity.id),
|
||||
@@ -248,10 +250,9 @@ export function uiFieldCombo(field, context) {
|
||||
.call(initCombo, selection)
|
||||
.merge(input);
|
||||
|
||||
if (isNetwork) {
|
||||
if (isNetwork && nominatim && entity) {
|
||||
var center = entity.extent(context.graph()).center();
|
||||
serviceNominatim.init();
|
||||
serviceNominatim.countryCode(center, function (err, code) {
|
||||
nominatim.countryCode(center, function (err, code) {
|
||||
country = code;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as d3 from 'd3';
|
||||
import { t } from '../../util/locale';
|
||||
import { serviceNominatim } from '../../services/index';
|
||||
import { dataPhoneFormats } from '../../../data/index';
|
||||
import { services } from '../../services/index';
|
||||
import { utilRebind } from '../../util/rebind';
|
||||
import { utilGetSetValue } from '../../util/get_set_value';
|
||||
|
||||
@@ -15,6 +15,7 @@ export {
|
||||
|
||||
export function uiFieldText(field, context) {
|
||||
var dispatch = d3.dispatch('change'),
|
||||
nominatim = services.nominatim,
|
||||
input,
|
||||
entity;
|
||||
|
||||
@@ -37,10 +38,9 @@ export function uiFieldText(field, context) {
|
||||
.on('blur', change())
|
||||
.on('change', change());
|
||||
|
||||
if (field.type === 'tel') {
|
||||
if (field.type === 'tel' && nominatim && entity) {
|
||||
var center = entity.extent(context.graph()).center();
|
||||
serviceNominatim.init();
|
||||
serviceNominatim.countryCode(center, function (err, countryCode) {
|
||||
nominatim.countryCode(center, function (err, countryCode) {
|
||||
if (err || !dataPhoneFormats[countryCode]) return;
|
||||
selection.selectAll('#' + fieldId)
|
||||
.attr('placeholder', dataPhoneFormats[countryCode]);
|
||||
|
||||
@@ -3,7 +3,7 @@ import _ from 'lodash';
|
||||
import { t } from '../../util/locale';
|
||||
import { d3combobox } from '../../lib/d3.combobox.js';
|
||||
import { dataSuggestions, dataWikipedia } from '../../../data/index';
|
||||
import { serviceWikipedia } from '../../services/index';
|
||||
import { services } from '../../services/index';
|
||||
import { svgIcon } from '../../svg/index';
|
||||
import { tooltip } from '../../util/tooltip';
|
||||
import { utilDetect } from '../../util/detect';
|
||||
@@ -14,7 +14,7 @@ import { utilSuggestNames } from '../../util/index';
|
||||
|
||||
export function uiFieldLocalized(field, context) {
|
||||
var dispatch = d3.dispatch('change', 'input'),
|
||||
wikipedia = serviceWikipedia.init(),
|
||||
wikipedia = services.wikipedia,
|
||||
input = d3.select(null),
|
||||
localizedInputs = d3.select(null),
|
||||
wikiTitles,
|
||||
|
||||
@@ -4,12 +4,7 @@ import { t } from '../../util/locale';
|
||||
import { actionChangeTags } from '../../actions/index';
|
||||
import { d3combobox } from '../../lib/d3.combobox.js';
|
||||
import { dataWikipedia } from '../../../data/index';
|
||||
|
||||
import {
|
||||
serviceWikipedia,
|
||||
serviceWikidata
|
||||
} from '../../services/index';
|
||||
|
||||
import { services } from '../../services/index';
|
||||
import { svgIcon } from '../../svg/index';
|
||||
import { utilDetect } from '../../util/detect';
|
||||
import { utilGetSetValue } from '../../util/get_set_value';
|
||||
@@ -18,8 +13,8 @@ import { utilRebind } from '../../util/rebind';
|
||||
|
||||
export function uiFieldWikipedia(field, context) {
|
||||
var dispatch = d3.dispatch('change'),
|
||||
wikipedia = serviceWikipedia.init(),
|
||||
wikidata = serviceWikidata.init(),
|
||||
wikipedia = services.wikipedia,
|
||||
wikidata = services.wikidata,
|
||||
link = d3.select(null),
|
||||
lang = d3.select(null),
|
||||
title = d3.select(null),
|
||||
|
||||
@@ -5,12 +5,14 @@ import { actionChangeMember, actionDeleteMember } from '../actions/index';
|
||||
import { modeBrowse, modeSelect } from '../modes/index';
|
||||
import { osmEntity } from '../osm/index';
|
||||
import { svgIcon } from '../svg/index';
|
||||
import { services } from '../services/index';
|
||||
import { uiDisclosure } from './disclosure';
|
||||
import { utilDisplayName } from '../util/index';
|
||||
|
||||
|
||||
export function uiRawMemberEditor(context) {
|
||||
var id;
|
||||
var id,
|
||||
taginfo = services.taginfo;
|
||||
|
||||
|
||||
function selectMember(d) {
|
||||
@@ -134,7 +136,7 @@ export function uiRawMemberEditor(context) {
|
||||
.on('click', deleteMember)
|
||||
.call(svgIcon('#operation-delete'));
|
||||
|
||||
if (context.taginfo()) {
|
||||
if (taginfo) {
|
||||
enter.each(bindTypeahead);
|
||||
}
|
||||
|
||||
@@ -159,7 +161,7 @@ export function uiRawMemberEditor(context) {
|
||||
role.call(d3combobox()
|
||||
.fetcher(function(role, callback) {
|
||||
var rtype = entity.tags.type;
|
||||
context.taginfo().roles({
|
||||
taginfo.roles({
|
||||
debounce: true,
|
||||
rtype: rtype || '',
|
||||
geometry: context.geometry(d.member.id),
|
||||
|
||||
@@ -12,13 +12,16 @@ import {
|
||||
|
||||
import { modeSelect } from '../modes/index';
|
||||
import { osmEntity, osmRelation } from '../osm/index';
|
||||
import { services } from '../services/index';
|
||||
import { svgIcon } from '../svg/index';
|
||||
import { uiDisclosure } from './disclosure';
|
||||
import { utilDisplayName } from '../util/index';
|
||||
|
||||
|
||||
export function uiRawMembershipEditor(context) {
|
||||
var id, showBlank;
|
||||
var taginfo = services.taginfo,
|
||||
id, showBlank;
|
||||
|
||||
|
||||
|
||||
function selectRelation(d) {
|
||||
@@ -197,7 +200,7 @@ export function uiRawMembershipEditor(context) {
|
||||
.on('click', deleteMembership)
|
||||
.call(svgIcon('#operation-delete'));
|
||||
|
||||
if (context.taginfo()) {
|
||||
if (taginfo) {
|
||||
enter.each(bindTypeahead);
|
||||
}
|
||||
|
||||
@@ -286,7 +289,7 @@ export function uiRawMembershipEditor(context) {
|
||||
role.call(d3combobox()
|
||||
.fetcher(function(role, callback) {
|
||||
var rtype = d.relation.tags.type;
|
||||
context.taginfo().roles({
|
||||
taginfo.roles({
|
||||
debounce: true,
|
||||
rtype: rtype || '',
|
||||
geometry: context.geometry(id),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as d3 from 'd3';
|
||||
import { d3combobox } from '../lib/d3.combobox.js';
|
||||
import { t } from '../util/locale';
|
||||
import { services } from '../services/index';
|
||||
import { svgIcon } from '../svg/index';
|
||||
import { uiDisclosure } from './disclosure';
|
||||
import { uiTagReference } from './tag_reference';
|
||||
@@ -9,7 +10,8 @@ import { utilRebind } from '../util/rebind';
|
||||
|
||||
|
||||
export function uiRawTagEditor(context) {
|
||||
var dispatch = d3.dispatch('change'),
|
||||
var taginfo = services.taginfo,
|
||||
dispatch = d3.dispatch('change'),
|
||||
showBlank = false,
|
||||
state,
|
||||
preset,
|
||||
@@ -118,7 +120,7 @@ export function uiRawTagEditor(context) {
|
||||
key = row.select('input.key'), // propagate bound data to child
|
||||
value = row.select('input.value'); // propagate bound data to child
|
||||
|
||||
if (context.taginfo()) {
|
||||
if (taginfo) {
|
||||
bindTypeahead(key, value);
|
||||
}
|
||||
|
||||
@@ -177,7 +179,7 @@ export function uiRawTagEditor(context) {
|
||||
|
||||
key.call(d3combobox()
|
||||
.fetcher(function(value, callback) {
|
||||
context.taginfo().keys({
|
||||
taginfo.keys({
|
||||
debounce: true,
|
||||
geometry: context.geometry(id),
|
||||
query: value
|
||||
@@ -188,7 +190,7 @@ export function uiRawTagEditor(context) {
|
||||
|
||||
value.call(d3combobox()
|
||||
.fetcher(function(value, callback) {
|
||||
context.taginfo().values({
|
||||
taginfo.values({
|
||||
debounce: true,
|
||||
key: utilGetSetValue(key),
|
||||
geometry: context.geometry(id),
|
||||
|
||||
@@ -2,11 +2,13 @@ import * as d3 from 'd3';
|
||||
import _ from 'lodash';
|
||||
import { t } from '../util/locale';
|
||||
import { utilDetect } from '../util/detect';
|
||||
import { services } from '../services/index';
|
||||
import { svgIcon } from '../svg/index';
|
||||
|
||||
|
||||
export function uiTagReference(tag, context) {
|
||||
var tagReference = {},
|
||||
var taginfo = services.taginfo,
|
||||
tagReference = {},
|
||||
button,
|
||||
body,
|
||||
loaded,
|
||||
@@ -40,9 +42,11 @@ export function uiTagReference(tag, context) {
|
||||
|
||||
|
||||
function load(param) {
|
||||
if (!taginfo) return;
|
||||
|
||||
button.classed('tag-reference-loading', true);
|
||||
|
||||
context.taginfo().docs(param, function show(err, data) {
|
||||
taginfo.docs(param, function show(err, data) {
|
||||
var docs;
|
||||
if (!err && data) {
|
||||
docs = findLocal(data);
|
||||
@@ -126,9 +130,7 @@ export function uiTagReference(tag, context) {
|
||||
} else if (loaded) {
|
||||
done();
|
||||
} else {
|
||||
if (context.taginfo()) {
|
||||
load(tag);
|
||||
}
|
||||
load(tag);
|
||||
}
|
||||
})
|
||||
.attr('class', 'tag-reference-button')
|
||||
|
||||
@@ -12,7 +12,7 @@ describe('iD.serviceMapillary', function() {
|
||||
context.projection.translate([-116508, 0]); // 10,0
|
||||
|
||||
server = sinon.fakeServer.create();
|
||||
mapillary = iD.serviceMapillary.init();
|
||||
mapillary = iD.services.mapillary;
|
||||
mapillary.reset();
|
||||
|
||||
/* eslint-disable no-native-reassign */
|
||||
@@ -39,18 +39,29 @@ describe('iD.serviceMapillary', function() {
|
||||
});
|
||||
|
||||
|
||||
describe('Mapillary service', function() {
|
||||
describe('#init', function() {
|
||||
it('Initializes cache one time', function() {
|
||||
var cache = iD.serviceMapillary.getMapillary().cache;
|
||||
var cache = mapillary.cache();
|
||||
expect(cache).to.have.property('images');
|
||||
expect(cache).to.have.property('signs');
|
||||
|
||||
iD.serviceMapillary.init();
|
||||
var cache2 = iD.serviceMapillary.getMapillary().cache;
|
||||
mapillary.init();
|
||||
var cache2 = mapillary.cache();
|
||||
expect(cache).to.equal(cache2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#reset', function() {
|
||||
it('resets cache and image', function() {
|
||||
mapillary.cache({foo: 'bar'});
|
||||
mapillary.selectedImage('baz');
|
||||
|
||||
mapillary.reset();
|
||||
expect(mapillary.cache()).to.not.have.property('foo');
|
||||
expect(mapillary.selectedImage()).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('#loadImages', function() {
|
||||
it('fires loadedImages when images are loaded', function() {
|
||||
var spy = sinon.spy();
|
||||
@@ -145,7 +156,7 @@ describe('iD.serviceMapillary', function() {
|
||||
});
|
||||
server.respond();
|
||||
|
||||
var sign_defs = iD.serviceMapillary.getMapillary().sign_defs;
|
||||
var sign_defs = mapillary.signDefs();
|
||||
|
||||
expect(sign_defs).to.have.property('au')
|
||||
.that.is.an('object')
|
||||
@@ -274,7 +285,7 @@ describe('iD.serviceMapillary', function() {
|
||||
{ minX: 10, minY: 1, maxX: 10, maxY: 1, data: { key: '2', loc: [10,1], ca: 90 } }
|
||||
];
|
||||
|
||||
iD.serviceMapillary.getMapillary().cache.images.rtree.load(features);
|
||||
mapillary.cache().images.rtree.load(features);
|
||||
var res = mapillary.images(context.projection, dimensions);
|
||||
|
||||
expect(res).to.deep.eql([
|
||||
@@ -292,7 +303,7 @@ describe('iD.serviceMapillary', function() {
|
||||
{ minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '4', loc: [10,0], ca: 90 } }
|
||||
];
|
||||
|
||||
iD.serviceMapillary.getMapillary().cache.images.rtree.load(features);
|
||||
mapillary.cache().images.rtree.load(features);
|
||||
var res = mapillary.images(context.projection, dimensions);
|
||||
expect(res).to.have.length.of.at.most(3);
|
||||
});
|
||||
@@ -313,7 +324,7 @@ describe('iD.serviceMapillary', function() {
|
||||
{ minX: 10, minY: 1, maxX: 10, maxY: 1, data: { key: '2', loc: [10,1], signs: signs } }
|
||||
];
|
||||
|
||||
iD.serviceMapillary.getMapillary().cache.signs.rtree.load(features);
|
||||
mapillary.cache().signs.rtree.load(features);
|
||||
var res = mapillary.signs(context.projection, dimensions);
|
||||
|
||||
expect(res).to.deep.eql([
|
||||
@@ -338,7 +349,7 @@ describe('iD.serviceMapillary', function() {
|
||||
{ minX: 10, minY: 0, maxX: 10, maxY: 0, data: { key: '4', loc: [10,0], signs: signs } }
|
||||
];
|
||||
|
||||
iD.serviceMapillary.getMapillary().cache.signs.rtree.load(features);
|
||||
mapillary.cache().signs.rtree.load(features);
|
||||
var res = mapillary.signs(context.projection, dimensions);
|
||||
expect(res).to.have.length.of.at.most(3);
|
||||
});
|
||||
@@ -358,9 +369,9 @@ describe('iD.serviceMapillary', function() {
|
||||
|
||||
describe('#signHTML', function() {
|
||||
it('returns sign HTML', function() {
|
||||
iD.serviceMapillary.getMapillary().sign_defs = {
|
||||
mapillary.signDefs({
|
||||
us: {'regulatory--maximum-speed-limit-65--us': '<span class="t">65</span>'}
|
||||
};
|
||||
});
|
||||
|
||||
var signdata = {
|
||||
key: '0',
|
||||
@@ -378,28 +389,10 @@ describe('iD.serviceMapillary', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setSelectedImage', function() {
|
||||
it('sets selected image', function() {
|
||||
mapillary.setSelectedImage('foo');
|
||||
expect(iD.serviceMapillary.getMapillary().image).to.eql('foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getSelectedImage', function() {
|
||||
it('gets selected image', function() {
|
||||
iD.serviceMapillary.getMapillary().image = 'bar';
|
||||
expect(mapillary.getSelectedImage()).to.eql('bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#reset', function() {
|
||||
it('resets cache and image', function() {
|
||||
iD.serviceMapillary.getMapillary().cache.foo = 'bar';
|
||||
iD.serviceMapillary.getMapillary().image = 'bar';
|
||||
|
||||
mapillary.reset();
|
||||
expect(iD.serviceMapillary.getMapillary().cache).to.not.have.property('foo');
|
||||
expect(iD.serviceMapillary.getMapillary().image).to.be.null;
|
||||
describe('#selectedImage', function() {
|
||||
it('sets and gets selected image', function() {
|
||||
mapillary.selectedImage('foo');
|
||||
expect(mapillary.selectedImage()).to.eql('foo');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,9 +3,8 @@ describe('iD.serviceNominatim', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
server = sinon.fakeServer.create();
|
||||
iD.serviceNominatim.init();
|
||||
nominatim = iD.serviceNominatim;
|
||||
iD.serviceNominatim.reset();
|
||||
nominatim = iD.services.nominatim;
|
||||
nominatim.reset();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
@@ -17,6 +16,7 @@ describe('iD.serviceNominatim', function() {
|
||||
}
|
||||
|
||||
describe.skip('#countryCode', function() {
|
||||
|
||||
it('calls the given callback with the results of the country code query', function() {
|
||||
var callback = sinon.spy();
|
||||
nominatim.countryCode([16, 48], callback);
|
||||
@@ -30,6 +30,7 @@ describe('iD.serviceNominatim', function() {
|
||||
{format: 'json', addressdetails: '1', lat: '48', lon: '16'});
|
||||
expect(callback).to.have.been.calledWith(null, 'at');
|
||||
});
|
||||
|
||||
it('should not cache the first country code result', function() {
|
||||
var callback = sinon.spy();
|
||||
nominatim.countryCode([16, 48], callback);
|
||||
@@ -57,6 +58,7 @@ describe('iD.serviceNominatim', function() {
|
||||
{format: 'json', addressdetails: '1', lat: '49', lon: '17'});
|
||||
expect(callback).to.have.been.calledWith(null, 'cz');
|
||||
});
|
||||
|
||||
it('should cache the first country code result', function() {
|
||||
var callback = sinon.spy();
|
||||
nominatim.countryCode([16, 48], callback);
|
||||
@@ -82,6 +84,7 @@ describe('iD.serviceNominatim', function() {
|
||||
|
||||
expect(callback).to.have.been.calledWith(null, 'at');
|
||||
});
|
||||
|
||||
it('calls the given callback with an error', function() {
|
||||
var callback = sinon.spy();
|
||||
nominatim.countryCode([1000, 1000], callback);
|
||||
|
||||
@@ -3,7 +3,7 @@ describe('iD.serviceTaginfo', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
server = sinon.fakeServer.create();
|
||||
taginfo = iD.serviceTaginfo.init();
|
||||
taginfo = iD.services.taginfo;
|
||||
taginfo.reset();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user