diff --git a/API.md b/API.md index f25d6c4e6..7d7b6b44a 100644 --- a/API.md +++ b/API.md @@ -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: diff --git a/dist/index.html b/dist/index.html index 480af8154..7e4cce361 100644 --- a/dist/index.html +++ b/dist/index.html @@ -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')); } diff --git a/index.html b/index.html index 37c391a5b..5de076250 100644 --- a/index.html +++ b/index.html @@ -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')); diff --git a/modules/core/context.js b/modules/core/context.js index 3be0be5c6..48b768692 100644 --- a/modules/core/context.js +++ b/modules/core/context.js @@ -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'); } diff --git a/modules/services/index.js b/modules/services/index.js index 2e9d38d30..5a5f1e0c6 100644 --- a/modules/services/index.js +++ b/modules/services/index.js @@ -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 }; diff --git a/modules/services/mapillary.js b/modules/services/mapillary.js index 2c1c68198..e30ccd34c 100644 --- a/modules/services/mapillary.js +++ b/modules/services/mapillary.js @@ -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; -} +}; diff --git a/modules/services/nominatim.js b/modules/services/nominatim.js index 950be8ab3..c1277f72a 100644 --- a/modules/services/nominatim.js +++ b/modules/services/nominatim.js @@ -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); - }); -} +}; diff --git a/modules/services/taginfo.js b/modules/services/taginfo.js index 5bb74b47e..0eb94d843 100644 --- a/modules/services/taginfo.js +++ b/modules/services/taginfo.js @@ -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; -} +}; diff --git a/modules/services/wikidata.js b/modules/services/wikidata.js index a1dfbe9cf..0cf5572db 100644 --- a/modules/services/wikidata.js +++ b/modules/services/wikidata.js @@ -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; -} +}; diff --git a/modules/services/wikipedia.js b/modules/services/wikipedia.js index 541800fb2..996650649 100644 --- a/modules/services/wikipedia.js +++ b/modules/services/wikipedia.js @@ -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; -} +}; diff --git a/modules/svg/mapillary_images.js b/modules/svg/mapillary_images.js index 7e716186c..653ac2410 100644 --- a/modules/svg/mapillary_images.js +++ b/modules/svg/mapillary_images.js @@ -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; }); diff --git a/modules/svg/mapillary_signs.js b/modules/svg/mapillary_signs.js index 9aa8b6f52..db2cf004e 100644 --- a/modules/svg/mapillary_signs.js +++ b/modules/svg/mapillary_signs.js @@ -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; }); diff --git a/modules/ui/fields/address.js b/modules/ui/fields/address.js index a100c98b9..0b4c90e1c 100644 --- a/modules/ui/fields/address.js +++ b/modules/ui/fields/address.js @@ -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); + } } diff --git a/modules/ui/fields/combo.js b/modules/ui/fields/combo.js index e7d2d81ad..669d40e4f 100644 --- a/modules/ui/fields/combo.js +++ b/modules/ui/fields/combo.js @@ -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; }); } diff --git a/modules/ui/fields/input.js b/modules/ui/fields/input.js index b181014fe..1b343de8c 100644 --- a/modules/ui/fields/input.js +++ b/modules/ui/fields/input.js @@ -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]); diff --git a/modules/ui/fields/localized.js b/modules/ui/fields/localized.js index 7a092efe0..8b9cd3e49 100644 --- a/modules/ui/fields/localized.js +++ b/modules/ui/fields/localized.js @@ -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, diff --git a/modules/ui/fields/wikipedia.js b/modules/ui/fields/wikipedia.js index ebcf29169..050914edb 100644 --- a/modules/ui/fields/wikipedia.js +++ b/modules/ui/fields/wikipedia.js @@ -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), diff --git a/modules/ui/raw_member_editor.js b/modules/ui/raw_member_editor.js index a706213db..be47cca2e 100644 --- a/modules/ui/raw_member_editor.js +++ b/modules/ui/raw_member_editor.js @@ -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), diff --git a/modules/ui/raw_membership_editor.js b/modules/ui/raw_membership_editor.js index 21368dd48..c46b8b864 100644 --- a/modules/ui/raw_membership_editor.js +++ b/modules/ui/raw_membership_editor.js @@ -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), diff --git a/modules/ui/raw_tag_editor.js b/modules/ui/raw_tag_editor.js index 65bf0df74..8ea806ef1 100644 --- a/modules/ui/raw_tag_editor.js +++ b/modules/ui/raw_tag_editor.js @@ -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), diff --git a/modules/ui/tag_reference.js b/modules/ui/tag_reference.js index ca8c1ab07..ff1d7d6ff 100644 --- a/modules/ui/tag_reference.js +++ b/modules/ui/tag_reference.js @@ -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') diff --git a/test/spec/services/mapillary.js b/test/spec/services/mapillary.js index 5120ef229..587c62554 100644 --- a/test/spec/services/mapillary.js +++ b/test/spec/services/mapillary.js @@ -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': '65'} - }; + }); 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'); }); }); diff --git a/test/spec/services/nominatim.js b/test/spec/services/nominatim.js index ffac1c186..a64d4ddb1 100644 --- a/test/spec/services/nominatim.js +++ b/test/spec/services/nominatim.js @@ -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); diff --git a/test/spec/services/taginfo.js b/test/spec/services/taginfo.js index 3f791e9c3..5e4630bd7 100644 --- a/test/spec/services/taginfo.js +++ b/test/spec/services/taginfo.js @@ -3,7 +3,7 @@ describe('iD.serviceTaginfo', function() { beforeEach(function() { server = sinon.fakeServer.create(); - taginfo = iD.serviceTaginfo.init(); + taginfo = iD.services.taginfo; taginfo.reset(); });