- return parseXML(xml, function (err, results) {
- if (err) {
- return callback(err);
- } else {
- return callback(undefined, results[0]);
- }
- }, options);
- }
- },
- // Load the details of the logged-in user
- // GET /api/0.6/user/details
- userDetails: function userDetails(callback) {
- if (_userDetails) {
- // retrieve cached
- return callback(undefined, _userDetails);
- }
-
- oauth.xhr({
- method: 'GET',
- path: '/api/0.6/user/details'
- }, wrapcb(this, done, _connectionID));
-
- function done(err, xml) {
- if (err) {
- return callback(err);
- }
-
- var options = {
- skipSeen: false
- };
- return parseXML(xml, function (err, results) {
- if (err) {
- return callback(err);
- } else {
- _userDetails = results[0];
- return callback(undefined, _userDetails);
- }
- }, options);
- }
- },
- // Load previous changesets for the logged in user
- // GET /api/0.6/changesets?user=#id
- userChangesets: function userChangesets(callback) {
- if (_userChangesets) {
- // retrieve cached
- return callback(undefined, _userChangesets);
- }
-
- this.userDetails(wrapcb(this, gotDetails, _connectionID));
-
- function gotDetails(err, user) {
- if (err) {
- return callback(err);
- }
-
- oauth.xhr({
- method: 'GET',
- path: '/api/0.6/changesets?user=' + user.id
- }, wrapcb(this, done, _connectionID));
- }
-
- function done(err, xml) {
- if (err) {
- return callback(err);
- }
-
- _userChangesets = Array.prototype.map.call(xml.getElementsByTagName('changeset'), function (changeset) {
- return {
- tags: getTags(changeset)
- };
- }).filter(function (changeset) {
- var comment = changeset.tags.comment;
- return comment && comment !== '';
- });
- return callback(undefined, _userChangesets);
- }
- },
- // Fetch the status of the OSM API
- // GET /api/capabilities
- status: function status(callback) {
- var url = urlroot + '/api/capabilities';
- var errback = wrapcb(this, done, _connectionID);
- d3_xml(url).then(function (data) {
- errback(null, data);
- })["catch"](function (err) {
- errback(err.message);
- });
-
- function done(err, xml) {
- if (err) {
- // the status is null if no response could be retrieved
- return callback(err, null);
- } // update blocklists
-
-
- var elements = xml.getElementsByTagName('blacklist');
- var regexes = [];
-
- for (var i = 0; i < elements.length; i++) {
- var regexString = elements[i].getAttribute('regex'); // needs unencode?
-
- if (regexString) {
- try {
- var regex = new RegExp(regexString);
- regexes.push(regex);
- } catch (e) {
- /* noop */
- }
- }
- }
-
- if (regexes.length) {
- _imageryBlocklists = regexes;
- }
-
- if (_rateLimitError) {
- return callback(_rateLimitError, 'rateLimited');
- } else {
- var waynodes = xml.getElementsByTagName('waynodes');
- var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute('maximum'), 10);
- if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
- var apiStatus = xml.getElementsByTagName('status');
- var val = apiStatus[0].getAttribute('api');
- return callback(undefined, val);
- }
- }
- },
- // Calls `status` and dispatches an `apiStatusChange` event if the returned
- // status differs from the cached status.
- reloadApiStatus: function reloadApiStatus() {
- // throttle to avoid unnecessary API calls
- if (!this.throttledReloadApiStatus) {
- var that = this;
- this.throttledReloadApiStatus = throttle(function () {
- that.status(function (err, status) {
- if (status !== _cachedApiStatus) {
- _cachedApiStatus = status;
- dispatch$6.call('apiStatusChange', that, err, status);
- }
- });
- }, 500);
- }
-
- this.throttledReloadApiStatus();
- },
- // Returns the maximum number of nodes a single way can have
- maxWayNodes: function maxWayNodes() {
- return _maxWayNodes;
- },
- // Load data (entities) from the API in tiles
- // GET /api/0.6/map?bbox=
- loadTiles: function loadTiles(projection, callback) {
- if (_off) return; // determine the needed tiles to cover the view
-
- var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection); // abort inflight requests that are no longer needed
-
- var hadRequests = hasInflightRequests(_tileCache);
- abortUnwantedRequests$3(_tileCache, tiles);
-
- if (hadRequests && !hasInflightRequests(_tileCache)) {
- dispatch$6.call('loaded'); // stop the spinner
- } // issue new requests..
-
-
- tiles.forEach(function (tile) {
- this.loadTile(tile, callback);
- }, this);
- },
- // Load a single data tile
- // GET /api/0.6/map?bbox=
- loadTile: function loadTile(tile, callback) {
- if (_off) return;
- if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
-
- if (!hasInflightRequests(_tileCache)) {
- dispatch$6.call('loading'); // start the spinner
- }
-
- var path = '/api/0.6/map.json?bbox=';
- var options = {
- skipSeen: true
- };
- _tileCache.inflight[tile.id] = this.loadFromAPI(path + tile.extent.toParam(), tileCallback, options);
-
- function tileCallback(err, parsed) {
- delete _tileCache.inflight[tile.id];
-
- if (!err) {
- delete _tileCache.toLoad[tile.id];
- _tileCache.loaded[tile.id] = true;
- var bbox = tile.extent.bbox();
- bbox.id = tile.id;
-
- _tileCache.rtree.insert(bbox);
- }
-
- if (callback) {
- callback(err, Object.assign({
- data: parsed
- }, tile));
- }
-
- if (!hasInflightRequests(_tileCache)) {
- dispatch$6.call('loaded'); // stop the spinner
- }
- }
- },
- isDataLoaded: function isDataLoaded(loc) {
- var bbox = {
- minX: loc[0],
- minY: loc[1],
- maxX: loc[0],
- maxY: loc[1]
- };
- return _tileCache.rtree.collides(bbox);
- },
- // load the tile that covers the given `loc`
- loadTileAtLoc: function loadTileAtLoc(loc, callback) {
- // Back off if the toLoad queue is filling up.. re #6417
- // (Currently `loadTileAtLoc` requests are considered low priority - used by operations to
- // let users safely edit geometries which extend to unloaded tiles. We can drop some.)
- if (Object.keys(_tileCache.toLoad).length > 50) return;
- var k = geoZoomToScale(_tileZoom$3 + 1);
- var offset = geoRawMercator().scale(k)(loc);
- var projection = geoRawMercator().transform({
- k: k,
- x: -offset[0],
- y: -offset[1]
- });
- var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection);
- tiles.forEach(function (tile) {
- if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
- _tileCache.toLoad[tile.id] = true;
- this.loadTile(tile, callback);
- }, this);
- },
- // Load notes from the API in tiles
- // GET /api/0.6/notes?bbox=
- loadNotes: function loadNotes(projection, noteOptions) {
- noteOptions = Object.assign({
- limit: 10000,
- closed: 7
- }, noteOptions);
- if (_off) return;
- var that = this;
- var path = '/api/0.6/notes?limit=' + noteOptions.limit + '&closed=' + noteOptions.closed + '&bbox=';
-
- var throttleLoadUsers = throttle(function () {
- var uids = Object.keys(_userCache.toLoad);
- if (!uids.length) return;
- that.loadUsers(uids, function () {}); // eagerly load user details
- }, 750); // determine the needed tiles to cover the view
-
-
- var tiles = tiler$5.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection); // abort inflight requests that are no longer needed
-
- abortUnwantedRequests$3(_noteCache, tiles); // issue new requests..
-
- tiles.forEach(function (tile) {
- if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
- var options = {
- skipSeen: false
- };
- _noteCache.inflight[tile.id] = that.loadFromAPI(path + tile.extent.toParam(), function (err) {
- delete _noteCache.inflight[tile.id];
-
- if (!err) {
- _noteCache.loaded[tile.id] = true;
- }
-
- throttleLoadUsers();
- dispatch$6.call('loadedNotes');
- }, options);
- });
- },
- // Create a note
- // POST /api/0.6/notes?params
- postNoteCreate: function postNoteCreate(note, callback) {
- if (!this.authenticated()) {
- return callback({
- message: 'Not Authenticated',
- status: -3
- }, note);
- }
-
- if (_noteCache.inflightPost[note.id]) {
- return callback({
- message: 'Note update already inflight',
- status: -2
- }, note);
- }
-
- if (!note.loc[0] || !note.loc[1] || !note.newComment) return; // location & description required
-
- var comment = note.newComment;
-
- if (note.newCategory && note.newCategory !== 'None') {
- comment += ' #' + note.newCategory;
- }
-
- var path = '/api/0.6/notes?' + utilQsString({
- lon: note.loc[0],
- lat: note.loc[1],
- text: comment
- });
- _noteCache.inflightPost[note.id] = oauth.xhr({
- method: 'POST',
- path: path
- }, wrapcb(this, done, _connectionID));
-
- function done(err, xml) {
- delete _noteCache.inflightPost[note.id];
-
- if (err) {
- return callback(err);
- } // we get the updated note back, remove from caches and reparse..
-
-
- this.removeNote(note);
- var options = {
- skipSeen: false
- };
- return parseXML(xml, function (err, results) {
- if (err) {
- return callback(err);
- } else {
- return callback(undefined, results[0]);
- }
- }, options);
- }
- },
- // Update a note
- // POST /api/0.6/notes/#id/comment?text=comment
- // POST /api/0.6/notes/#id/close?text=comment
- // POST /api/0.6/notes/#id/reopen?text=comment
- postNoteUpdate: function postNoteUpdate(note, newStatus, callback) {
- if (!this.authenticated()) {
- return callback({
- message: 'Not Authenticated',
- status: -3
- }, note);
- }
-
- if (_noteCache.inflightPost[note.id]) {
- return callback({
- message: 'Note update already inflight',
- status: -2
- }, note);
- }
-
- var action;
-
- if (note.status !== 'closed' && newStatus === 'closed') {
- action = 'close';
- } else if (note.status !== 'open' && newStatus === 'open') {
- action = 'reopen';
- } else {
- action = 'comment';
- if (!note.newComment) return; // when commenting, comment required
- }
-
- var path = '/api/0.6/notes/' + note.id + '/' + action;
-
- if (note.newComment) {
- path += '?' + utilQsString({
- text: note.newComment
- });
- }
-
- _noteCache.inflightPost[note.id] = oauth.xhr({
- method: 'POST',
- path: path
- }, wrapcb(this, done, _connectionID));
-
- function done(err, xml) {
- delete _noteCache.inflightPost[note.id];
-
- if (err) {
- return callback(err);
- } // we get the updated note back, remove from caches and reparse..
-
-
- this.removeNote(note); // update closed note cache - used to populate `closed:note` changeset tag
-
- if (action === 'close') {
- _noteCache.closed[note.id] = true;
- } else if (action === 'reopen') {
- delete _noteCache.closed[note.id];
- }
-
- var options = {
- skipSeen: false
- };
- return parseXML(xml, function (err, results) {
- if (err) {
- return callback(err);
- } else {
- return callback(undefined, results[0]);
- }
- }, options);
- }
- },
- "switch": function _switch(options) {
- urlroot = options.urlroot;
- oauth.options(Object.assign({
- url: urlroot,
- loading: authLoading,
- done: authDone
- }, options));
- this.reset();
- this.userChangesets(function () {}); // eagerly load user details/changesets
-
- dispatch$6.call('change');
- return this;
- },
- toggle: function toggle(val) {
- _off = !val;
- return this;
- },
- isChangesetInflight: function isChangesetInflight() {
- return !!_changeset.inflight;
- },
- // get/set cached data
- // This is used to save/restore the state when entering/exiting the walkthrough
- // Also used for testing purposes.
- caches: function caches(obj) {
- function cloneCache(source) {
- var target = {};
- Object.keys(source).forEach(function (k) {
- if (k === 'rtree') {
- target.rtree = new RBush().fromJSON(source.rtree.toJSON()); // clone rbush
- } else if (k === 'note') {
- target.note = {};
- Object.keys(source.note).forEach(function (id) {
- target.note[id] = osmNote(source.note[id]); // copy notes
- });
- } else {
- target[k] = JSON.parse(JSON.stringify(source[k])); // clone deep
- }
- });
- return target;
- }
-
- if (!arguments.length) {
- return {
- tile: cloneCache(_tileCache),
- note: cloneCache(_noteCache),
- user: cloneCache(_userCache)
- };
- } // access caches directly for testing (e.g., loading notes rtree)
-
-
- if (obj === 'get') {
- return {
- tile: _tileCache,
- note: _noteCache,
- user: _userCache
- };
- }
-
- if (obj.tile) {
- _tileCache = obj.tile;
- _tileCache.inflight = {};
- }
-
- if (obj.note) {
- _noteCache = obj.note;
- _noteCache.inflight = {};
- _noteCache.inflightPost = {};
- }
-
- if (obj.user) {
- _userCache = obj.user;
- }
-
- return this;
- },
- logout: function logout() {
- _userChangesets = undefined;
- _userDetails = undefined;
- oauth.logout();
- dispatch$6.call('change');
- return this;
- },
- authenticated: function authenticated() {
- return oauth.authenticated();
- },
- authenticate: function authenticate(callback) {
- var that = this;
- var cid = _connectionID;
- _userChangesets = undefined;
- _userDetails = undefined;
-
- function done(err, res) {
- if (err) {
- if (callback) callback(err);
- return;
- }
-
- if (that.getConnectionId() !== cid) {
- if (callback) callback({
- message: 'Connection Switched',
- status: -1
- });
- return;
- }
-
- _rateLimitError = undefined;
- dispatch$6.call('change');
- if (callback) callback(err, res);
- that.userChangesets(function () {}); // eagerly load user details/changesets
- }
-
- return oauth.authenticate(done);
- },
- imageryBlocklists: function imageryBlocklists() {
- return _imageryBlocklists;
- },
- tileZoom: function tileZoom(val) {
- if (!arguments.length) return _tileZoom$3;
- _tileZoom$3 = val;
- return this;
- },
- // get all cached notes covering the viewport
- notes: function notes(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 _noteCache.rtree.search(bbox).map(function (d) {
- return d.data;
- });
- },
- // get a single note from the cache
- getNote: function getNote(id) {
- return _noteCache.note[id];
- },
- // remove a single note from the cache
- removeNote: function removeNote(note) {
- if (!(note instanceof osmNote) || !note.id) return;
- delete _noteCache.note[note.id];
- updateRtree$3(encodeNoteRtree(note), false); // false = remove
- },
- // replace a single note in the cache
- replaceNote: function replaceNote(note) {
- if (!(note instanceof osmNote) || !note.id) return;
- _noteCache.note[note.id] = note;
- updateRtree$3(encodeNoteRtree(note), true); // true = replace
-
- return note;
- },
- // Get an array of note IDs closed during this session.
- // Used to populate `closed:note` changeset tag
- getClosedIDs: function getClosedIDs() {
- return Object.keys(_noteCache.closed).sort();
- }
- };
-
- var _apibase = 'https://wiki.openstreetmap.org/w/api.php';
- var _inflight$1 = {};
- var _wikibaseCache = {};
- var _localeIDs = {
- en: false
- };
-
- var debouncedRequest = debounce(request, 500, {
- leading: false
- });
-
- function request(url, callback) {
- if (_inflight$1[url]) return;
- var controller = new AbortController();
- _inflight$1[url] = controller;
- d3_json(url, {
- signal: controller.signal
- }).then(function (result) {
- delete _inflight$1[url];
- if (callback) callback(null, result);
- })["catch"](function (err) {
- delete _inflight$1[url];
- if (err.name === 'AbortError') return;
- if (callback) callback(err.message);
- });
- }
-
- var serviceOsmWikibase = {
- init: function init() {
- _inflight$1 = {};
- _wikibaseCache = {};
- _localeIDs = {};
- },
- reset: function reset() {
- Object.values(_inflight$1).forEach(function (controller) {
- controller.abort();
- });
- _inflight$1 = {};
- },
-
- /**
- * Get the best value for the property, or undefined if not found
- * @param entity object from wikibase
- * @param property string e.g. 'P4' for image
- * @param langCode string e.g. 'fr' for French
- */
- claimToValue: function claimToValue(entity, property, langCode) {
- if (!entity.claims[property]) return undefined;
- var locale = _localeIDs[langCode];
- var preferredPick, localePick;
- entity.claims[property].forEach(function (stmt) {
- // If exists, use value limited to the needed language (has a qualifier P26 = locale)
- // Or if not found, use the first value with the "preferred" rank
- if (!preferredPick && stmt.rank === 'preferred') {
- preferredPick = stmt;
- }
-
- if (locale && stmt.qualifiers && stmt.qualifiers.P26 && stmt.qualifiers.P26[0].datavalue.value.id === locale) {
- localePick = stmt;
- }
- });
- var result = localePick || preferredPick;
-
- if (result) {
- var datavalue = result.mainsnak.datavalue;
- return datavalue.type === 'wikibase-entityid' ? datavalue.value.id : datavalue.value;
- } else {
- return undefined;
- }
- },
-
- /**
- * Convert monolingual property into a key-value object (language -> value)
- * @param entity object from wikibase
- * @param property string e.g. 'P31' for monolingual wiki page title
- */
- monolingualClaimToValueObj: function monolingualClaimToValueObj(entity, property) {
- if (!entity || !entity.claims[property]) return undefined;
- return entity.claims[property].reduce(function (acc, obj) {
- var value = obj.mainsnak.datavalue.value;
- acc[value.language] = value.text;
- return acc;
- }, {});
- },
- toSitelink: function toSitelink(key, value) {
- var result = value ? 'Tag:' + key + '=' + value : 'Key:' + key;
- return result.replace(/_/g, ' ').trim();
- },
- //
- // Pass params object of the form:
- // {
- // key: 'string',
- // value: 'string',
- // langCode: 'string'
- // }
- //
- getEntity: function getEntity(params, callback) {
- var doRequest = params.debounce ? debouncedRequest : request;
- var that = this;
- var titles = [];
- var result = {};
- var rtypeSitelink = params.key === 'type' && params.value ? ('Relation:' + params.value).replace(/_/g, ' ').trim() : false;
- var keySitelink = params.key ? this.toSitelink(params.key) : false;
- var tagSitelink = params.key && params.value ? this.toSitelink(params.key, params.value) : false;
- var localeSitelink;
-
- if (params.langCodes) {
- params.langCodes.forEach(function (langCode) {
- if (_localeIDs[langCode] === undefined) {
- // If this is the first time we are asking about this locale,
- // fetch corresponding entity (if it exists), and cache it.
- // If there is no such entry, cache `false` value to avoid re-requesting it.
- localeSitelink = ('Locale:' + langCode).replace(/_/g, ' ').trim();
- titles.push(localeSitelink);
- }
- });
- }
-
- if (rtypeSitelink) {
- if (_wikibaseCache[rtypeSitelink]) {
- result.rtype = _wikibaseCache[rtypeSitelink];
- } else {
- titles.push(rtypeSitelink);
- }
- }
-
- if (keySitelink) {
- if (_wikibaseCache[keySitelink]) {
- result.key = _wikibaseCache[keySitelink];
- } else {
- titles.push(keySitelink);
- }
- }
-
- if (tagSitelink) {
- if (_wikibaseCache[tagSitelink]) {
- result.tag = _wikibaseCache[tagSitelink];
- } else {
- titles.push(tagSitelink);
- }
- }
-
- if (!titles.length) {
- // Nothing to do, we already had everything in the cache
- return callback(null, result);
- } // Requesting just the user language code
- // If backend recognizes the code, it will perform proper fallbacks,
- // and the result will contain the requested code. If not, all values are returned:
- // {"zh-tw":{"value":"...","language":"zh-tw","source-language":"zh-hant"}
- // {"pt-br":{"value":"...","language":"pt","for-language":"pt-br"}}
-
-
- var obj = {
- action: 'wbgetentities',
- sites: 'wiki',
- titles: titles.join('|'),
- languages: params.langCodes.join('|'),
- languagefallback: 1,
- origin: '*',
- format: 'json' // There is an MW Wikibase API bug https://phabricator.wikimedia.org/T212069
- // We shouldn't use v1 until it gets fixed, but should switch to it afterwards
- // formatversion: 2,
-
- };
- var url = _apibase + '?' + utilQsString(obj);
- doRequest(url, function (err, d) {
- if (err) {
- callback(err);
- } else if (!d.success || d.error) {
- callback(d.error.messages.map(function (v) {
- return v.html['*'];
- }).join('<br>'));
- } else {
- var localeID = false;
- Object.values(d.entities).forEach(function (res) {
- if (res.missing !== '') {
- var title = res.sitelinks.wiki.title;
-
- if (title === rtypeSitelink) {
- _wikibaseCache[rtypeSitelink] = res;
- result.rtype = res;
- } else if (title === keySitelink) {
- _wikibaseCache[keySitelink] = res;
- result.key = res;
- } else if (title === tagSitelink) {
- _wikibaseCache[tagSitelink] = res;
- result.tag = res;
- } else if (title === localeSitelink) {
- localeID = res.id;
- } else {
- console.log('Unexpected title ' + title); // eslint-disable-line no-console
- }
- }
- });
-
- if (localeSitelink) {
- // If locale ID is not found, store false to prevent repeated queries
- that.addLocale(params.langCodes[0], localeID);
- }
-
- callback(null, result);
- }
- });
- },
- //
- // Pass params object of the form:
- // {
- // key: 'string', // required
- // value: 'string' // optional
- // }
- //
- // Get an result object used to display tag documentation
- // {
- // title: 'string',
- // description: 'string',
- // editURL: 'string',
- // imageURL: 'string',
- // wiki: { title: 'string', text: 'string', url: 'string' }
- // }
- //
- getDocs: function getDocs(params, callback) {
- var that = this;
- var langCodes = _mainLocalizer.localeCodes().map(function (code) {
- return code.toLowerCase();
- });
- params.langCodes = langCodes;
- this.getEntity(params, function (err, data) {
- if (err) {
- callback(err);
- return;
- }
-
- var entity = data.rtype || data.tag || data.key;
-
- if (!entity) {
- callback('No entity');
- return;
- }
-
- var i;
- var description;
-
- for (i in langCodes) {
- var _code = langCodes[i];
-
- if (entity.descriptions[_code] && entity.descriptions[_code].language === _code) {
- description = entity.descriptions[_code];
- break;
- }
- }
-
- if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
-
- var result = {
- title: entity.title,
- description: description ? description.value : '',
- descriptionLocaleCode: description ? description.language : '',
- editURL: 'https://wiki.openstreetmap.org/wiki/' + entity.title
- }; // add image
-
- if (entity.claims) {
- var imageroot;
- var image = that.claimToValue(entity, 'P4', langCodes[0]);
-
- if (image) {
- imageroot = 'https://commons.wikimedia.org/w/index.php';
- } else {
- image = that.claimToValue(entity, 'P28', langCodes[0]);
-
- if (image) {
- imageroot = 'https://wiki.openstreetmap.org/w/index.php';
- }
- }
-
- if (imageroot && image) {
- result.imageURL = imageroot + '?' + utilQsString({
- title: 'Special:Redirect/file/' + image,
- width: 400
- });
- }
- } // Try to get a wiki page from tag data item first, followed by the corresponding key data item.
- // If neither tag nor key data item contain a wiki page in the needed language nor English,
- // get the first found wiki page from either the tag or the key item.
-
-
- var rtypeWiki = that.monolingualClaimToValueObj(data.rtype, 'P31');
- var tagWiki = that.monolingualClaimToValueObj(data.tag, 'P31');
- var keyWiki = that.monolingualClaimToValueObj(data.key, 'P31');
- var wikis = [rtypeWiki, tagWiki, keyWiki];
-
- for (i in wikis) {
- var wiki = wikis[i];
-
- for (var j in langCodes) {
- var code = langCodes[j];
- var referenceId = langCodes[0].split('-')[0] !== 'en' && code.split('-')[0] === 'en' ? 'inspector.wiki_en_reference' : 'inspector.wiki_reference';
- var info = getWikiInfo(wiki, code, referenceId);
-
- if (info) {
- result.wiki = info;
- break;
- }
- }
-
- if (result.wiki) break;
- }
-
- callback(null, result); // Helper method to get wiki info if a given language exists
-
- function getWikiInfo(wiki, langCode, tKey) {
- if (wiki && wiki[langCode]) {
- return {
- title: wiki[langCode],
- text: tKey,
- url: 'https://wiki.openstreetmap.org/wiki/' + wiki[langCode]
- };
- }
- }
- });
- },
- addLocale: function addLocale(langCode, qid) {
- // Makes it easier to unit test
- _localeIDs[langCode] = qid;
- },
- apibase: function apibase(val) {
- if (!arguments.length) return _apibase;
- _apibase = val;
- return this;
- }
- };
-
- var jsonpCache = {};
- window.jsonpCache = jsonpCache;
- function jsonpRequest(url, callback) {
- var request = {
- abort: function abort() {}
- };
-
- if (window.JSONP_FIX) {
- if (window.JSONP_DELAY === 0) {
- callback(window.JSONP_FIX);
- } else {
- var t = window.setTimeout(function () {
- callback(window.JSONP_FIX);
- }, window.JSONP_DELAY || 0);
-
- request.abort = function () {
- window.clearTimeout(t);
- };