diff --git a/js/id/behavior/hash.js b/js/id/behavior/hash.js index e017aabed..5e2edb860 100644 --- a/js/id/behavior/hash.js +++ b/js/id/behavior/hash.js @@ -41,6 +41,12 @@ iD.behavior.Hash = function(context) { // do so before any features are loaded. thus wait for the feature to // be loaded and then select function willselect(id) { + context.connection().loadEntity(id, function(error, entity) { + if (entity) { + context.map().zoomTo(entity); + } + }); + context.map().on('drawn.hash', function() { if (!context.entity(id)) return; selectoff(); diff --git a/js/id/core/connection.js b/js/id/core/connection.js index 8a58f97d0..4f07e6d85 100644 --- a/js/id/core/connection.js +++ b/js/id/core/connection.js @@ -40,6 +40,18 @@ iD.Connection = function() { return d3.xml(url).get().on('load', done); }; + connection.loadEntity = function(id, callback) { + var type = iD.Entity.id.type(id), + osmID = iD.Entity.id.toOSM(id); + + connection.loadFromURL( + url + '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''), + function(err, entities) { + event.load(err, entities); + if (callback) callback(err, entities && entities[id]); + }); + }; + function authenticating() { event.authenticating(); } diff --git a/js/id/core/entity.js b/js/id/core/entity.js index 71ac7c5cb..ab6f76bc6 100644 --- a/js/id/core/entity.js +++ b/js/id/core/entity.js @@ -25,6 +25,10 @@ iD.Entity.id.toOSM = function(id) { return id.slice(1); }; +iD.Entity.id.type = function(id) { + return {'n': 'node', 'w': 'way', 'r': 'relation'}[id[0]]; +}; + // A function suitable for use as the second argument to d3.selection#data(). iD.Entity.key = function(entity) { return entity.id; diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js index 2b301a502..ff50ee19a 100644 --- a/js/id/renderer/map.js +++ b/js/id/renderer/map.js @@ -322,6 +322,12 @@ iD.Map = function(context) { return redraw(); }; + map.zoomTo = function(entity) { + var extent = entity.extent(context.graph()), + zoom = map.extentZoom(extent); + map.centerZoom(extent.center(), zoom); + }; + map.centerZoom = function(loc, z) { var centered = setCenter(loc), zoomed = setZoom(z); diff --git a/test/spec/core/connection.js b/test/spec/core/connection.js index 541ba1783..830bc4247 100644 --- a/test/spec/core/connection.js +++ b/test/spec/core/connection.js @@ -79,6 +79,59 @@ describe('iD.Connection', function () { }); }); + describe('#loadEntity', function () { + var server, + nodeXML = '', + wayXML = '' + + '' + + '' + + ''; + + beforeEach(function() { + server = sinon.fakeServer.create(); + }); + + afterEach(function() { + server.restore(); + }); + + it('loads a node', function(done) { + c.loadEntity('n1', function(error, entity) { + expect(entity).to.be.an.instanceOf(iD.Node); + expect(entity.id).to.eql('n1'); + done(); + }); + + server.respondWith("GET", "http://www.openstreetmap.org/api/0.6/node/1", + [200, { "Content-Type": "text/xml" }, nodeXML]); + server.respond(); + }); + + it('loads a way', function(done) { + c.loadEntity('w1', function(error, entity) { + expect(entity).to.be.an.instanceOf(iD.Way); + expect(entity.id).to.eql('w1'); + done(); + }); + + server.respondWith("GET", "http://www.openstreetmap.org/api/0.6/way/1/full", + [200, { "Content-Type": "text/xml" }, wayXML]); + server.respond(); + }); + + it('emits a load event', function(done) { + c.loadEntity('n1'); + c.on('load', function(error, result) { + expect(result.n1).to.be.an.instanceOf(iD.Node); + done(); + }); + + server.respondWith("GET", "http://www.openstreetmap.org/api/0.6/node/1", + [200, { "Content-Type": "text/xml" }, nodeXML]); + server.respond(); + }); + }); + describe('#osmChangeJXON', function() { it('converts change data to JXON', function() { var jxon = c.osmChangeJXON('jfire', '1234', {created: [], modified: [], deleted: []});