mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-15 13:38:26 +02:00
pulled updates from remote
This commit is contained in:
+1
-1
@@ -15,7 +15,7 @@
|
||||
color: #ff3300;
|
||||
}
|
||||
.layer-notes .note.closed .note-fill {
|
||||
color: #00bb33;
|
||||
color: #55dd00;
|
||||
}
|
||||
.layer-notes .note.hovered .note-fill {
|
||||
color: #eebb00;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import serviceMapillary from './mapillary';
|
||||
import serviceNominatim from './nominatim';
|
||||
import serviceNotes from './notes';
|
||||
import serviceOpenstreetcam from './openstreetcam';
|
||||
import serviceOsm from './osm';
|
||||
import serviceStreetside from './streetside';
|
||||
@@ -11,7 +10,6 @@ import serviceWikipedia from './wikipedia';
|
||||
export var services = {
|
||||
geocoder: serviceNominatim,
|
||||
mapillary: serviceMapillary,
|
||||
notes: serviceNotes,
|
||||
openstreetcam: serviceOpenstreetcam,
|
||||
osm: serviceOsm,
|
||||
streetside: serviceStreetside,
|
||||
@@ -23,7 +21,6 @@ export var services = {
|
||||
export {
|
||||
serviceMapillary,
|
||||
serviceNominatim,
|
||||
serviceNotes,
|
||||
serviceOpenstreetcam,
|
||||
serviceOsm,
|
||||
serviceStreetside,
|
||||
|
||||
@@ -1,298 +0,0 @@
|
||||
import _extend from 'lodash-es/extend';
|
||||
import _filter from 'lodash-es/filter';
|
||||
import _find from 'lodash-es/find';
|
||||
import _forEach from 'lodash-es/forEach';
|
||||
import _isEmpty from 'lodash-es/isEmpty';
|
||||
|
||||
import osmAuth from 'osm-auth';
|
||||
|
||||
import rbush from 'rbush';
|
||||
|
||||
var _entityCache = {};
|
||||
|
||||
import { dispatch as d3_dispatch } from 'd3-dispatch';
|
||||
import { xml as d3_xml } from 'd3-request';
|
||||
|
||||
import { d3geoTile as d3_geoTile } from '../lib/d3.geo.tile';
|
||||
import { geoExtent } from '../geo';
|
||||
|
||||
import {
|
||||
utilRebind,
|
||||
utilIdleWorker
|
||||
} from '../util';
|
||||
|
||||
import {
|
||||
osmNote
|
||||
} from '../osm';
|
||||
import { actionRestrictTurn } from '../actions';
|
||||
|
||||
var urlroot = 'https://api.openstreetmap.org',
|
||||
_notesCache,
|
||||
dispatch = d3_dispatch('loadedNotes', 'loading'),
|
||||
tileZoom = 14;
|
||||
|
||||
// TODO: complete authentication
|
||||
var oauth = osmAuth({
|
||||
url: urlroot,
|
||||
oauth_consumer_key: '',
|
||||
oauth_secret: '',
|
||||
loading: authLoading,
|
||||
done: authDone
|
||||
});
|
||||
|
||||
function authLoading() {
|
||||
dispatch.call('authLoading');
|
||||
}
|
||||
|
||||
function authDone() {
|
||||
dispatch.call('authDone');
|
||||
}
|
||||
|
||||
function authenticated() {
|
||||
return oauth.authenticated();
|
||||
}
|
||||
|
||||
function abortRequest(i) {
|
||||
i.abort();
|
||||
}
|
||||
|
||||
function getTiles(projection) {
|
||||
var s = projection.scale() * 2 * Math.PI,
|
||||
z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
|
||||
ts = 256 * Math.pow(2, z - tileZoom),
|
||||
origin = [
|
||||
s / 2 - projection.translate()[0],
|
||||
s / 2 - projection.translate()[1]];
|
||||
|
||||
var tiles = d3_geoTile()
|
||||
.scaleExtent([tileZoom, tileZoom])
|
||||
.scale(s)
|
||||
.size(projection.clipExtent()[1])
|
||||
.translate(projection.translate())()
|
||||
.map(function(tile) {
|
||||
var x = tile[0] * ts - origin[0],
|
||||
y = tile[1] * ts - origin[1];
|
||||
|
||||
return {
|
||||
id: tile.toString(),
|
||||
xyz: tile,
|
||||
extent: geoExtent(
|
||||
projection.invert([x, y + ts]),
|
||||
projection.invert([x + ts, y])
|
||||
)
|
||||
};
|
||||
});
|
||||
|
||||
return tiles;
|
||||
}
|
||||
|
||||
function getLoc(attrs) {
|
||||
var lon = attrs.lon && attrs.lon.value;
|
||||
var lat = attrs.lat && attrs.lat.value;
|
||||
return [parseFloat(lon), parseFloat(lat)];
|
||||
}
|
||||
|
||||
function parseComments(comments) {
|
||||
var parsedComments = [];
|
||||
|
||||
// for each comment
|
||||
_forEach(comments, function(comment) {
|
||||
if (comment.nodeName === 'comment') {
|
||||
var childNodes = comment.childNodes;
|
||||
var parsedComment = {};
|
||||
|
||||
_forEach(childNodes, function(node) {
|
||||
if (node.nodeName !== '#text') {
|
||||
var nodeName = node.nodeName;
|
||||
parsedComment[nodeName] = node.innerHTML;
|
||||
}
|
||||
});
|
||||
if (parsedComment) { parsedComments.push(parsedComment); }
|
||||
}
|
||||
});
|
||||
return parsedComments;
|
||||
}
|
||||
|
||||
var parsers = {
|
||||
note: function parseNote(obj, uid) {
|
||||
var attrs = obj.attributes;
|
||||
var childNodes = obj.childNodes;
|
||||
var parsedNote = {};
|
||||
|
||||
parsedNote.loc = getLoc(attrs);
|
||||
|
||||
_forEach(childNodes, function(node) {
|
||||
if (node.nodeName !== '#text') {
|
||||
var nodeName = node.nodeName;
|
||||
// if the element is comments, parse the comments
|
||||
if (nodeName === 'comments') {
|
||||
parsedNote[nodeName] = parseComments(node.childNodes);
|
||||
} else {
|
||||
parsedNote[nodeName] = node.innerHTML;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
parsedNote.id = uid;
|
||||
parsedNote.type = 'note';
|
||||
|
||||
return {
|
||||
minX: parsedNote.loc[0],
|
||||
minY: parsedNote.loc[1],
|
||||
maxX: parsedNote.loc[0],
|
||||
maxY: parsedNote.loc[1],
|
||||
data: new osmNote(parsedNote)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function parse(xml, callback, options) {
|
||||
options = _extend({ cache: true }, options);
|
||||
if (!xml || !xml.childNodes) return;
|
||||
|
||||
var root = xml.childNodes[0];
|
||||
var children = root.childNodes;
|
||||
|
||||
function parseChild(child) {
|
||||
var parser = parsers[child.nodeName];
|
||||
if (parser) {
|
||||
|
||||
var childNodes = child.childNodes;
|
||||
|
||||
var uid;
|
||||
_forEach(childNodes, function(node) {
|
||||
if (node.nodeName === 'id') {
|
||||
uid = child.nodeName + node.innerHTML;
|
||||
}
|
||||
});
|
||||
|
||||
if (options.cache && _entityCache[uid]) {
|
||||
return null;
|
||||
}
|
||||
return parser(child, uid);
|
||||
}
|
||||
}
|
||||
utilIdleWorker(children, parseChild, callback);
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
init: function() {
|
||||
if (!_notesCache) {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
this.event = utilRebind(this, dispatch, 'on');
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
var cache = _notesCache;
|
||||
|
||||
if (cache) {
|
||||
if (cache.notes && cache.notes.inflight) {
|
||||
_forEach(cache.notes.inflight, abortRequest);
|
||||
}
|
||||
}
|
||||
|
||||
_notesCache = { notes: { inflight: {}, loaded: {}, rtree: rbush() } };
|
||||
},
|
||||
|
||||
loadFromAPI: function(path, callback, options) {
|
||||
options = _extend({ cache: true }, options);
|
||||
|
||||
function done(err, xml) {
|
||||
if (err) {
|
||||
callback(err, xml);
|
||||
}
|
||||
parse(
|
||||
xml,
|
||||
function(entities) {
|
||||
if (options.cache) {
|
||||
for (var i in entities) {
|
||||
_entityCache[entities[i].id] = true;
|
||||
}
|
||||
}
|
||||
callback(null, entities);
|
||||
},
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
if (authenticated()) {
|
||||
return oauth.xhr({ method: 'GET', path: path }, done);
|
||||
} else {
|
||||
return d3_xml(path).get(done);
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: refactor /services for consistency by splitting or joining loadTiles & loadTile
|
||||
loadTile: function(which, currZoom, url, tile) {
|
||||
var that = this;
|
||||
var cache = _notesCache[which];
|
||||
var bbox = tile.extent.toParam();
|
||||
var fullUrl = url + bbox;
|
||||
|
||||
var id = tile.id;
|
||||
|
||||
if (cache.loaded[id] || cache.inflight[id]) return;
|
||||
|
||||
if (_isEmpty(cache.inflight)) {
|
||||
dispatch.call('loading');
|
||||
}
|
||||
|
||||
cache.inflight[id] = that.loadFromAPI(
|
||||
fullUrl,
|
||||
function (err, parsed) {
|
||||
delete cache.inflight[id];
|
||||
if (!err) {
|
||||
cache.loaded[id] = true;
|
||||
}
|
||||
|
||||
cache.rtree.load(parsed);
|
||||
|
||||
if (_isEmpty(cache.inflight)) {
|
||||
dispatch.call('loadedNotes');
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
},
|
||||
|
||||
loadTiles: function(which, url, projection) {
|
||||
var that = this;
|
||||
var s = projection.scale() * 2 * Math.PI,
|
||||
currZoom = Math.floor(Math.max(Math.log(s) / Math.log(2) - 8, 0));
|
||||
|
||||
var tiles = getTiles(projection);
|
||||
|
||||
_filter(which.inflight, function(v, k) {
|
||||
var wanted = _find(tiles, function(tile) { return k === (tile.id + ',0'); });
|
||||
if (!wanted) delete which.inflight[k];
|
||||
return !wanted;
|
||||
}).map(abortRequest);
|
||||
|
||||
tiles.forEach(function(tile) {
|
||||
that.loadTile(which, currZoom, url, tile);
|
||||
});
|
||||
},
|
||||
|
||||
loadNotes: function(projection) {
|
||||
var that = this;
|
||||
var url = urlroot + '/api/0.6/notes?bbox=';
|
||||
that.loadTiles('notes', url, projection);
|
||||
},
|
||||
|
||||
notes: 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 _notesCache.notes.rtree.search(bbox)
|
||||
.map(function(d) { return d.data; });
|
||||
},
|
||||
|
||||
cache: function() {
|
||||
return _notesCache;
|
||||
}
|
||||
};
|
||||
@@ -237,11 +237,11 @@ function parse(xml, callback, options) {
|
||||
uid = child.getElementsByTagName('id')[0].textContent;
|
||||
} else {
|
||||
uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
|
||||
if (options.cache && _seenEntity[uid]) {
|
||||
return null; // avoid reparsing a "seen" entity
|
||||
}
|
||||
}
|
||||
|
||||
if (options.cache && _seenEntity[uid]) {
|
||||
return null;
|
||||
}
|
||||
return parser(child, uid);
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ export default {
|
||||
// Logout and retry the request..
|
||||
if (isAuthenticated && err && (err.status === 400 || err.status === 401 || err.status === 403)) {
|
||||
that.logout();
|
||||
that.loadFromAPI(path, callback);
|
||||
that.loadFromAPI(path, callback, options);
|
||||
|
||||
// else, no retry..
|
||||
} else {
|
||||
@@ -343,7 +343,7 @@ export default {
|
||||
parse(xml, function (entities) {
|
||||
if (options.cache) {
|
||||
for (var i in entities) {
|
||||
_seenEntity[entities[i].id] = true;
|
||||
_seenEntity[entities[i].id] = true; // avoid re-parsing again later
|
||||
}
|
||||
}
|
||||
callback(null, entities);
|
||||
@@ -707,6 +707,7 @@ export default {
|
||||
dispatch.call('loading'); // start the spinner
|
||||
}
|
||||
|
||||
var options = { cache: !loadingNotes };
|
||||
cache.inflight[id] = that.loadFromAPI(
|
||||
path + tile.extent.toParam(),
|
||||
function(err, parsed) {
|
||||
@@ -726,8 +727,8 @@ export default {
|
||||
dispatch.call('loaded'); // stop the spinner
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
options
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -129,6 +129,18 @@ export function svgNotes(projection, context, dispatch) {
|
||||
.attr('y', '-22px')
|
||||
.attr('xlink:href', '#fas-comment-alt');
|
||||
|
||||
// add dots if there's a comment thread
|
||||
notesEnter.selectAll('.thread')
|
||||
.data(function(d) { return d.comments.length > 1 ? [0] : []; })
|
||||
.enter()
|
||||
.append('use')
|
||||
.attr('class', 'note-shadow thread')
|
||||
.attr('width', '18px')
|
||||
.attr('height', '18px')
|
||||
.attr('x', '-9px')
|
||||
.attr('y', '-22px')
|
||||
.attr('xlink:href', '#iD-icon-more');
|
||||
|
||||
// update
|
||||
notes
|
||||
.merge(notesEnter)
|
||||
|
||||
@@ -104,7 +104,6 @@
|
||||
|
||||
<script src='spec/services/mapillary.js'></script>
|
||||
<script src='spec/services/nominatim.js'></script>
|
||||
<script src='spec/services/notes.js'></script>
|
||||
<script src='spec/services/openstreetcam.js'></script>
|
||||
<script src='spec/services/osm.js'></script>
|
||||
<script src='spec/services/streetside.js'></script>
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
describe('iD.serviceNotes', function () {
|
||||
var dimensions = [64, 64],
|
||||
context, server, notes;
|
||||
|
||||
|
||||
before(function() {
|
||||
iD.services.notes = iD.serviceNotes;
|
||||
});
|
||||
|
||||
after(function() {
|
||||
delete iD.services.notes;
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
context = iD.Context().assetPath('../dist/');
|
||||
context.projection
|
||||
.scale(667544.214430109) // z14
|
||||
.translate([-116508, 0]) // 10,0
|
||||
.clipExtent([[0,0], dimensions]);
|
||||
|
||||
server = sinon.fakeServer.create();
|
||||
notes = iD.services.notes;
|
||||
notes.reset();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
server.restore();
|
||||
});
|
||||
|
||||
describe('#init', function () {
|
||||
it('Initializes cache one time', function () {
|
||||
var cache = notes.cache();
|
||||
expect(cache).to.have.property('notes');
|
||||
|
||||
notes.init();
|
||||
var cache2 = notes.cache();
|
||||
expect(cache).to.equal(cache2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#reset', function () {
|
||||
it('resets cache', function () {
|
||||
notes.cache.foo = 'bar';
|
||||
notes.reset();
|
||||
expect(notes.cache()).to.not.have.property('foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#loadFromAPI', function () {
|
||||
var path = '/api/0.6/notes?bbox=-0.65094,51.312159,0.374908,51.3125',
|
||||
response = '<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
'<osm version="0.6" generator="OpenStreetMap server">' +
|
||||
'<note lon="0.1979819" lat="51.3122986">' +
|
||||
'<id>814798</id>' +
|
||||
'<url>https://api.openstreetmap.org/api/0.6/notes/814798</url>' +
|
||||
'<comment_url>https://api.openstreetmap.org/api/0.6/notes/814798/comment</comment_url>' +
|
||||
'<close_url>https://api.openstreetmap.org/api/0.6/notes/814798/close</close_url>' +
|
||||
'<date_created>2016-12-13 11:02:44 UTC</date_created>' +
|
||||
'<status>open</status>' +
|
||||
'<comments>' +
|
||||
'<comment>' +
|
||||
'<date>2016-12-13 11:02:44 UTC</date>' +
|
||||
'<action>opened</action>' +
|
||||
'<text>Otford Scout Hut</text>' +
|
||||
'<html><p>Otford Scout Hut</p></html>' +
|
||||
'</comment>' +
|
||||
'</comments>' +
|
||||
'</note>' +
|
||||
'</osm>';
|
||||
|
||||
it('returns an object', function (done) {
|
||||
var result = notes.loadFromAPI(
|
||||
'https://www.openstreetmap.org' + path,
|
||||
function (err, xml) {
|
||||
expect(err).to.not.be.ok;
|
||||
expect(typeof xml).to.eql('object');
|
||||
done();
|
||||
},
|
||||
[]);
|
||||
|
||||
// TODO: clarify why this throws an error
|
||||
// server.respondWith('GET', 'http://www.openstreetmap.org' + path,
|
||||
// [200, { 'Content-Type': 'text/xml' }, response]);
|
||||
// server.respond();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -137,8 +137,8 @@ describe('iD.serviceOsm', function () {
|
||||
});
|
||||
|
||||
describe('#loadFromAPI', function () {
|
||||
var path = '/api/0.6/map?bbox=-74.542,40.655,-74.541,40.656',
|
||||
response = '<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
var path = '/api/0.6/map?bbox=-74.542,40.655,-74.541,40.656';
|
||||
var response = '<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
'<osm version="0.6">' +
|
||||
' <bounds minlat="40.655" minlon="-74.542" maxlat="40.656" maxlon="-74.541' +
|
||||
' <node id="105340439" visible="true" version="2" changeset="2880013" timestamp="2009-10-18T07:47:39Z" user="woodpeck_fixbot" uid="147510" lat="40.6555" lon="-74.5415"/>' +
|
||||
@@ -293,11 +293,58 @@ describe('iD.serviceOsm', function () {
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('#loadNotes', function () {
|
||||
var path = '/api/0.6/notes?bbox=-0.65094,51.312159,0.374908,51.3125';
|
||||
var response = '<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
'<osm version="0.6" generator="OpenStreetMap server">' +
|
||||
'<note lon="0.1979819" lat="51.3122986">' +
|
||||
'<id>814798</id>' +
|
||||
'<url>https://api.openstreetmap.org/api/0.6/notes/814798</url>' +
|
||||
'<comment_url>https://api.openstreetmap.org/api/0.6/notes/814798/comment</comment_url>' +
|
||||
'<close_url>https://api.openstreetmap.org/api/0.6/notes/814798/close</close_url>' +
|
||||
'<date_created>2016-12-13 11:02:44 UTC</date_created>' +
|
||||
'<status>open</status>' +
|
||||
'<comments>' +
|
||||
'<comment>' +
|
||||
'<date>2016-12-13 11:02:44 UTC</date>' +
|
||||
'<action>opened</action>' +
|
||||
'<text>Otford Scout Hut</text>' +
|
||||
'<html><p>Otford Scout Hut</p></html>' +
|
||||
'</comment>' +
|
||||
'</comments>' +
|
||||
'</note>' +
|
||||
'</osm>';
|
||||
|
||||
beforeEach(function() {
|
||||
connection.reset();
|
||||
server = sinon.fakeServer.create();
|
||||
spy = sinon.spy();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
server.restore();
|
||||
});
|
||||
|
||||
it('returns an object', function (done) {
|
||||
connection.loadFromAPI(path, function (err, xml) {
|
||||
expect(err).to.not.be.ok;
|
||||
expect(typeof xml).to.eql('object');
|
||||
done();
|
||||
});
|
||||
|
||||
server.respondWith('GET', 'http://www.openstreetmap.org' + path,
|
||||
[200, { 'Content-Type': 'text/xml' }, response]);
|
||||
server.respond();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#loadEntity', function () {
|
||||
var nodeXML = '<?xml version="1.0" encoding="UTF-8"?><osm>' +
|
||||
'<node id="1" version="1" changeset="1" lat="0" lon="0" visible="true" timestamp="2009-03-07T03:26:33Z"></node>' +
|
||||
'</osm>',
|
||||
wayXML = '<?xml version="1.0" encoding="UTF-8"?><osm>' +
|
||||
'</osm>';
|
||||
var wayXML = '<?xml version="1.0" encoding="UTF-8"?><osm>' +
|
||||
'<node id="1" version="1" changeset="2817006" lat="0" lon="0" visible="true" timestamp="2009-10-11T18:03:23Z"/>' +
|
||||
'<way id="1" visible="true" timestamp="2008-01-03T05:24:43Z" version="1" changeset="522559"><nd ref="1"/></way>' +
|
||||
'</osm>';
|
||||
@@ -355,11 +402,12 @@ describe('iD.serviceOsm', function () {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#loadEntityVersion', function () {
|
||||
var nodeXML = '<?xml version="1.0" encoding="UTF-8"?><osm>' +
|
||||
'<node id="1" version="1" changeset="1" lat="0" lon="0" visible="true" timestamp="2009-03-07T03:26:33Z"></node>' +
|
||||
'</osm>',
|
||||
wayXML = '<?xml version="1.0" encoding="UTF-8"?><osm>' +
|
||||
'</osm>';
|
||||
var wayXML = '<?xml version="1.0" encoding="UTF-8"?><osm>' +
|
||||
'<way id="1" visible="true" timestamp="2008-01-03T05:24:43Z" version="1" changeset="522559"><nd ref="1"/></way>' +
|
||||
'</osm>';
|
||||
|
||||
@@ -416,6 +464,7 @@ describe('iD.serviceOsm', function () {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#loadMultiple', function () {
|
||||
beforeEach(function() {
|
||||
server = sinon.fakeServer.create();
|
||||
@@ -428,7 +477,6 @@ describe('iD.serviceOsm', function () {
|
||||
it('loads nodes');
|
||||
it('loads ways');
|
||||
it('does not ignore repeat requests');
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user