From 12206c68e6143ac01778b3b188b702ad619c90fd Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Mon, 30 Dec 2019 19:07:12 +0000 Subject: [PATCH] Convert Osmsoe service to ES6 syntax --- modules/services/osmose.js | 445 +++++++++++++++++------------------- modules/ui/osmose_editor.js | 4 +- 2 files changed, 218 insertions(+), 231 deletions(-) diff --git a/modules/services/osmose.js b/modules/services/osmose.js index 46f498ecf..d42994e5a 100644 --- a/modules/services/osmose.js +++ b/modules/services/osmose.js @@ -9,280 +9,267 @@ import { qaError } from '../osm'; import { utilRebind, utilTiler, utilQsString } from '../util'; import { services } from '../../data/qa_errors.json'; -var tiler = utilTiler(); -var dispatch = d3_dispatch('loaded'); +const tiler = utilTiler(); +const dispatch = d3_dispatch('loaded'); +const _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/'; +const _erZoom = 14; -var _erCache; -var _erZoom = 14; - -var _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/'; +// This gets reassigned if reset +let _erCache; function abortRequest(controller) { - if (controller) { - controller.abort(); - } + if (controller) { + controller.abort(); + } } function abortUnwantedRequests(cache, tiles) { - Object.keys(cache.inflightTile).forEach(function(k) { - var wanted = tiles.find(function(tile) { return k === tile.id; }); - if (!wanted) { - abortRequest(cache.inflightTile[k]); - delete cache.inflightTile[k]; - } - }); + Object.keys(cache.inflightTile).forEach(k => { + let wanted = tiles.find(tile => k === tile.id); + if (!wanted) { + abortRequest(cache.inflightTile[k]); + delete cache.inflightTile[k]; + } + }); } - function encodeErrorRtree(d) { - return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d }; + return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d }; } - // replace or remove error from rtree function updateRtree(item, replace) { - _erCache.rtree.remove(item, function isEql(a, b) { - return a.data.id === b.data.id; - }); + _erCache.rtree.remove(item, (a, b) => a.data.id === b.data.id); - if (replace) { - _erCache.rtree.insert(item); - } + if (replace) { + _erCache.rtree.insert(item); + } } function linkEntity(d) { - return '' + d + ''; + return `${d}`; } // Errors shouldn't obscure eachother -function preventCoincident(loc, bumpUp) { - var coincident = false; - do { - // first time, move marker up. after that, move marker right. - var delta = coincident ? [0.00001, 0] : (bumpUp ? [0, 0.00001] : [0, 0]); - loc = geoVecAdd(loc, delta); - var bbox = geoExtent(loc).bbox(); - coincident = _erCache.rtree.search(bbox).length; - } while (coincident); +function preventCoincident(loc) { + let coincident = false; + do { + // first time, move marker up. after that, move marker right. + let delta = coincident ? [0.00001, 0] : [0, 0.00001]; + loc = geoVecAdd(loc, delta); + let bbox = geoExtent(loc).bbox(); + coincident = _erCache.rtree.search(bbox).length; + } while (coincident); - return loc; + return loc; } export default { - init: function() { - if (!_erCache) { - this.reset(); - } + init() { + if (!_erCache) { + this.reset(); + } - this.event = utilRebind(this, dispatch, 'on'); - }, + this.event = utilRebind(this, dispatch, 'on'); + }, - reset: function() { - if (_erCache) { - Object.values(_erCache.inflightTile).forEach(abortRequest); - } - _erCache = { - data: {}, - loadedTile: {}, - inflightTile: {}, - inflightPost: {}, - closed: {}, - rtree: new RBush() - }; - }, + reset() { + if (_erCache) { + Object.values(_erCache.inflightTile).forEach(abortRequest); + } + _erCache = { + data: {}, + loadedTile: {}, + inflightTile: {}, + inflightPost: {}, + closed: {}, + rtree: new RBush() + }; + }, - loadErrors: function(projection) { - var params = { - item: services.osmose.items.join() // only interested in certain errors - }; + loadErrors(projection) { + let params = { + // Tiles return a maximum # of errors + // So we want to filter our request for only types iD supports + item: services.osmose.items.join() + }; - // determine the needed tiles to cover the view - var tiles = tiler - .zoomExtent([_erZoom, _erZoom]) - .getTiles(projection); + // determine the needed tiles to cover the view + let tiles = tiler + .zoomExtent([_erZoom, _erZoom]) + .getTiles(projection); - // abort inflight requests that are no longer needed - abortUnwantedRequests(_erCache, tiles); + // abort inflight requests that are no longer needed + abortUnwantedRequests(_erCache, tiles); - // issue new requests.. - tiles.forEach(function(tile) { - if (_erCache.loadedTile[tile.id] || _erCache.inflightTile[tile.id]) return; + // issue new requests.. + tiles.forEach(tile => { + if (_erCache.loadedTile[tile.id] || _erCache.inflightTile[tile.id]) return; - var lang = 'en'; // todo: may want to use provided translations - var path = [tile.xyz[2], tile.xyz[0], tile.xyz[1]].join('/'); - var url = _osmoseUrlRoot + lang + '/map/issues/' + path + '.json?' + utilQsString(params); + let lang = 'en'; // todo: may want to use provided translations + let [ x, y, z ] = tile.xyz; + let url = _osmoseUrlRoot + `${lang}/map/issues/${z}/${x}/${y}.json?` + utilQsString(params); - var controller = new AbortController(); - _erCache.inflightTile[tile.id] = controller; + let controller = new AbortController(); + _erCache.inflightTile[tile.id] = controller; - d3_json(url, { signal: controller.signal }) - .then(function(data) { - delete _erCache.inflightTile[tile.id]; - _erCache.loadedTile[tile.id] = true; + d3_json(url, { signal: controller.signal }) + .then(data => { + delete _erCache.inflightTile[tile.id]; + _erCache.loadedTile[tile.id] = true; - if (data.features) { - data.features.forEach(function(issue) { - var loc = issue.geometry.coordinates; // lon, lat - var props = issue.properties; - // Item is the type of error, w/ class tells us the sub-type - var type = [props.item, props.class].join('-'); + if (data.features) { + data.features.forEach(issue => { + const { item, class: error_class, issue_id: identifier } = issue.properties; + // Item is the type of error, w/ class tells us the sub-type + const error_type = [item, error_class].join('-'); - // Filter out unsupported error types (some are too specific or advanced) - if (type in services.osmose.errorTypes) { - loc = preventCoincident(loc, true); + // Filter out unsupported error types (some are too specific or advanced) + if (error_type in services.osmose.errorTypes) { + let loc = issue.geometry.coordinates; // lon, lat + loc = preventCoincident(loc); - var d = new qaError({ - // Info required for every error - loc: loc, - service: 'osmose', - error_type: type, - // Extra details needed for this service - identifier: props.issue_id, // needed to query and update the error - item: props.item, // category of the issue for styling - class: props.class - }); - - // Special handling for some error types - // Setting elems here prevents UI error detail requests - switch (d.item) { - case 8300: - case 8360: - mapillaryError(d); - break; - } - - _erCache.data[d.id] = d; - _erCache.rtree.insert(encodeErrorRtree(d)); - } - }); - } - - dispatch.call('loaded'); - }) - .catch(function() { - delete _erCache.inflightTile[tile.id]; - _erCache.loadedTile[tile.id] = true; - }); - }); - - function mapillaryError(d) { - // Parts only exists for these error types - var parts = dataEn.QA.osmose.error_types[d.item].parts; - d.replacements = [parts[d.class]]; - d.elems = []; - } - }, - - loadErrorDetail: function(d, callback) { - // Error details only need to be fetched once - if (d.elems !== undefined) { - if (callback) callback(null, d); - return; - } - - var url = _osmoseUrlRoot + 'en/api/0.3beta/issue/' + d.identifier; - - var that = this; - d3_json(url) - .then(function(data) { - // Associated elements used for highlighting - // Assign directly for immediate use in the callback - d.elems = data.elems.map(function(e) { - return e.type.substring(0,1) + e.id; - }); - - // Element links used in the error description - d.replacements = d.elems.map(function(i) { - return linkEntity(i); + let d = new qaError({ + // Info required for every error + loc, + service: 'osmose', + error_type, + // Extra details needed for this service + identifier, // needed to query and update the error + item // category of the issue for styling }); // Special handling for some error types + // Setting elems here prevents UI error detail requests switch (d.item) { - case 3040: - d.replacements.push(/Bad value for (.+)/i - .exec(data.subtitle)[1] - ); - break; + case 8300: + case 8360: { + // Parts only exists for these error types + let { parts } = dataEn.QA.osmose.error_types[d.item]; + d.replacements = [parts[error_class]]; + d.elems = []; + break; + } } - that.replaceError(d); - if (callback) callback(null, d); - }) - .catch(function(err) { - if (callback) callback(err.message); + _erCache.data[d.id] = d; + _erCache.rtree.insert(encodeErrorRtree(d)); + } }); - }, + } - postUpdate: function(d, callback) { - if (_erCache.inflightPost[d.id]) { - return callback({ message: 'Error update already inflight', status: -2 }, d); + dispatch.call('loaded'); + }) + .catch(() => { + delete _erCache.inflightTile[tile.id]; + _erCache.loadedTile[tile.id] = true; + }); + }); + }, + + loadErrorDetail(d, callback) { + // Error details only need to be fetched once + if (d.elems !== undefined) { + if (callback) callback(null, d); + return; + } + + let url = _osmoseUrlRoot + `en/api/0.3beta/issue/${d.identifier}`; + + d3_json(url) + .then(data => { + // Associated elements used for highlighting + // Assign directly for immediate use in the callback + d.elems = data.elems.map(e => e.type.substring(0,1) + e.id); + + // Element links used in the error description + d.replacements = d.elems.map(linkEntity); + + // Special handling for some error types + switch (d.item) { + case 3040: { + let [, key_value] = /Bad value for (.+)/i.exec(data.subtitle); + d.replacements.push(key_value); + break; + } } - var that = this; + this.replaceError(d); + if (callback) callback(null, d); + }) + .catch(err => { + if (callback) callback(err.message); + }); + }, - // UI sets the status to either '/done' or '/false' - var url = _osmoseUrlRoot + 'en/api/0.3beta/issue/' + d.identifier + d.newStatus; - - var controller = new AbortController(); - _erCache.inflightPost[d.id] = controller; - - fetch(url, { signal: controller.signal }) - .then(function() { - delete _erCache.inflightPost[d.id]; - - that.removeError(d); - if (d.newStatus === '/done') { - // No error identifier, so we give a count of each category - if (!(d.item in _erCache.closed)) { - _erCache.closed[d.item] = 0; - } - _erCache.closed[d.item] += 1; - } - if (callback) callback(null, d); - }) - .catch(function(err) { - delete _erCache.inflightPost[d.id]; - if (callback) callback(err.message); - }); - }, - - - // get all cached errors covering the viewport - getErrors: function(projection) { - var viewport = projection.clipExtent(); - var min = [viewport[0][0], viewport[1][1]]; - var max = [viewport[1][0], viewport[0][1]]; - var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox(); - - return _erCache.rtree.search(bbox).map(function(d) { - return d.data; - }); - }, - - // get a single error from the cache - getError: function(id) { - return _erCache.data[id]; - }, - - // replace a single error in the cache - replaceError: function(error) { - if (!(error instanceof qaError) || !error.id) return; - - _erCache.data[error.id] = error; - updateRtree(encodeErrorRtree(error), true); // true = replace - return error; - }, - - // remove a single error from the cache - removeError: function(error) { - if (!(error instanceof qaError) || !error.id) return; - - delete _erCache.data[error.id]; - updateRtree(encodeErrorRtree(error), false); // false = remove - }, - - // Used to populate `closed:osmose:*` changeset tags - getClosedCounts: function() { - return _erCache.closed; + postUpdate(d, callback) { + if (_erCache.inflightPost[d.id]) { + return callback({ message: 'Error update already inflight', status: -2 }, d); } -}; \ No newline at end of file + + // UI sets the status to either 'done' or 'false' + let url = _osmoseUrlRoot + `en/api/0.3beta/issue/${d.identifier}/${d.newStatus}`; + + let controller = new AbortController(); + _erCache.inflightPost[d.id] = controller; + + fetch(url, { signal: controller.signal }) + .then(() => { + delete _erCache.inflightPost[d.id]; + + this.removeError(d); + if (d.newStatus === 'done') { + // No error identifier, so we give a count of each category + if (!(d.item in _erCache.closed)) { + _erCache.closed[d.item] = 0; + } + _erCache.closed[d.item] += 1; + } + if (callback) callback(null, d); + }) + .catch(err => { + delete _erCache.inflightPost[d.id]; + if (callback) callback(err.message); + }); + }, + + + // get all cached errors covering the viewport + getErrors(projection) { + let viewport = projection.clipExtent(); + let min = [viewport[0][0], viewport[1][1]]; + let max = [viewport[1][0], viewport[0][1]]; + let bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox(); + + return _erCache.rtree.search(bbox).map(d => { + return d.data; + }); + }, + + // get a single error from the cache + getError(id) { + return _erCache.data[id]; + }, + + // replace a single error in the cache + replaceError(error) { + if (!(error instanceof qaError) || !error.id) return; + + _erCache.data[error.id] = error; + updateRtree(encodeErrorRtree(error), true); // true = replace + return error; + }, + + // remove a single error from the cache + removeError(error) { + if (!(error instanceof qaError) || !error.id) return; + + delete _erCache.data[error.id]; + updateRtree(encodeErrorRtree(error), false); // false = remove + }, + + // Used to populate `closed:osmose:*` changeset tags + getClosedCounts() { + return _erCache.closed; + } +}; diff --git a/modules/ui/osmose_editor.js b/modules/ui/osmose_editor.js index 38cbc42fa..4571eeb56 100644 --- a/modules/ui/osmose_editor.js +++ b/modules/ui/osmose_editor.js @@ -136,7 +136,7 @@ export function uiOsmoseEditor(context) { this.blur(); // avoid keeping focus on the button - #4641 var errorService = services.osmose; if (errorService) { - d.newStatus = '/done'; + d.newStatus = 'done'; errorService.postUpdate(d, function(err, error) { dispatch.call('change', error); }); @@ -151,7 +151,7 @@ export function uiOsmoseEditor(context) { this.blur(); // avoid keeping focus on the button - #4641 var errorService = services.osmose; if (errorService) { - d.newStatus = '/false'; + d.newStatus = 'false'; errorService.postUpdate(d, function(err, error) { dispatch.call('change', error); });