From d8169ddb1473cfc7f757c9a1b1927ab6ef611c70 Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Thu, 18 Oct 2012 16:13:57 -0400 Subject: [PATCH] Use scope and don't bind in connection. --- index.html | 1 - js/iD/Connection.js | 320 +++++++++++++++++++----------------------- js/iD/renderer/Map.js | 8 +- 3 files changed, 151 insertions(+), 178 deletions(-) diff --git a/index.html b/index.html index 3e69ec52d..23ac6da76 100755 --- a/index.html +++ b/index.html @@ -53,7 +53,6 @@ require(["dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/dom","dojo/Evented width: dom.byId('map').offsetWidth, height: dom.byId('map').offsetHeight }); - conn.registerMap(map); map.ruleset = ruleset; // Initialise controller diff --git a/js/iD/Connection.js b/js/iD/Connection.js index bbeac1d63..e055ef982 100755 --- a/js/iD/Connection.js +++ b/js/iD/Connection.js @@ -7,68 +7,65 @@ if (typeof iD === 'undefined') iD = {}; iD.Connection = function(apiURL) { - // summary: The data store, including methods to fetch data from (and, eventually, save data to) - // an OSM API server. - this.nextNode = -1; // next negative ids - this.nextWay = -1; // | - this.nextRelation = -1; // | - this.nodes={}; - this.ways={}; - this.relations= {}; - this.pois = {}; - this.maps=[]; - this.modified=false; - this.apiBaseURL=apiURL; - this.callback = null; -}; + // summary: The data store, including methods to fetch data from (and, eventually, save data to) + // an OSM API server. + var nextNode = -1, // next negative ids + nextWay = -1, // | + nextRelation = -1, // | + nodes = {}, + ways = {}, + relations = {}, + pois = {}, + modified = false, + apiBaseURL = apiURL; -iD.Connection.prototype = { - _assign:function(obj) { - // summary: Save an entity to the data store. - switch (obj.entityType) { - case "node": this.nodes[obj.id]=obj; break; - case "way": this.ways[obj.id]=obj; break; - case "relation": this.relations[obj.id]=obj; break; - } - }, + var connection = {}; - _getOrCreate:function(id,type) { - // summary: Return an entity if it exists: if not, create an empty one with the given id, and return that. - switch (type) { - case "node": - if (!this.nodes[id]) this._assign(new iD.Node(this, id, NaN, NaN, {}, false)); - return this.nodes[id]; - case "way": - if (!this.ways[id]) this._assign(new iD.Way(this, id, [], {}, false)); - return this.ways[id]; - case "relation": - if (!this.relations[id]) this._assign(new iD.Relation(this, id, [], {}, false)); - return this.relations[id]; - } - }, + function assign(obj) { + // summary: Save an entity to the data store. + switch (obj.entityType) { + case "node": nodes[obj.id]=obj; break; + case "way": ways[obj.id]=obj; break; + case "relation": relations[obj.id]=obj; break; + } + } - doCreateNode:function(tags, lat, lon, perform) { - // summary: Create a new node and save it in the data store, using an undo stack. - var node = new iD.Node(this, this.nextNode--, lat, lon, tags, true); - perform(new iD.actions.CreateEntityAction(node, _.bind(this._assign, this) )); - return node; // iD.Node - }, + function getOrCreate(id, type) { + // summary: Return an entity if it exists: if not, create an empty one with the given id, and return that. + if (type === 'node') { + if (!nodes[id]) assign(new iD.Node(connection, id, NaN, NaN, {}, false)); + return nodes[id]; + } else if (type === 'way') { + if (!ways[id]) assign(new iD.Way(connection, id, [], {}, false)); + return ways[id]; + } else if (type === 'relation') { + if (!relations[id]) assign(new iD.Relation(connection, id, [], {}, false)); + return relations[id]; + } + } - doCreateWay:function(tags, nodes, perform) { - // summary: Create a new way and save it in the data store, using an undo stack. - var way = new iD.Way(this, this.nextWay--, nodes.concat(), tags, true); - perform(new iD.actions.CreateEntityAction(way, _.bind(this._assign, this) )); - return way; - }, + function doCreateNode(tags, lat, lon, perform) { + // summary: Create a new node and save it in the data store, using an undo stack. + var node = new iD.Node(connection, nextNode--, lat, lon, tags, true); + perform(new iD.actions.CreateEntityAction(node, assign)); + return node; // iD.Node + } - doCreateRelation:function(tags, members, perform) { - // summary: Create a new relation and save it in the data store, using an undo stack. - var relation = new iD.Relation(this, this.nextRelation--, members.concat(), tags, true); - perform(new iD.actions.CreateEntityAction(relation, _.bind(this._assign, this) )); - return relation; - }, + function doCreateWay(tags, nodes, perform) { + // summary: Create a new way and save it in the data store, using an undo stack. + var way = new iD.Way(connection, nextWay--, nodes.concat(), tags, true); + perform(new iD.actions.CreateEntityAction(way, assign)); + return way; + } - getObjectsByBbox:function(left,right,top,bottom) { + function doCreateRelation(tags, members, perform) { + // summary: Create a new relation and save it in the data store, using an undo stack. + var relation = new iD.Relation(connection, nextRelation--, members.concat(), tags, true); + perform(new iD.actions.CreateEntityAction(relation, assign)); + return relation; + } + + function getObjectsByBbox(left,right,top,bottom) { // summary: Find all drawable entities that are within a given bounding box. // returns: Object An object with four properties: .poisInside, .poisOutside, .waysInside, .waysOutside. // Each one is an array of entities. @@ -78,162 +75,139 @@ iD.Connection.prototype = { waysInside: [], waysOutside: [] }; - for (var id in this.ways) { - var way = this.ways[id]; + for (var id in ways) { + var way = ways[id]; if (way.within(left,right,top,bottom)) { o.waysInside.push(way); } else { o.waysOutside.push(way); } } - _.each(this.pois, function(node) { + _.each(pois, function(node) { if (node.within(left,right,top,bottom)) { o.poisInside.push(node); } else { o.poisOutside.push(node); } }); return o; - }, + } - // --------------- - // Redraw handling + // ------------ + // POI handling + function updatePOIs(nodelist) { + // summary: Update the list of POIs (nodes not in ways) from a supplied array of nodes. + _.each(nodelist, function(node) { + if (node.entity.hasParentWays()) { + delete pois[node._id]; + } else { + pois[node._id] = node; + } + }); + } - registerMap:function(map) { - // summary: Record that a Map object wants updates from this Connection. - this.maps.push(map); - }, + function getPOIs() { + // summary: Return a list of all the POIs in connection Connection. + return _.values(pois); + } - refreshMaps:function() { - // summary: Redraw all the Map objects that take data from this Connection. - _.each(this.maps, function(map) { - map.updateUIs(false,true); - }); - }, + function registerPOI(node) { + // summary: Register a node as a POI (not in a way). + pois[node._id] = node; + } - refreshEntity: function(entity) { - // summary: Redraw a particular entity on all the Map objects that take data from this Connection. - _.each(this.maps, function(map) { - map.refreshUI(entity); - }); - }, + function unregisterPOI(node) { + // summary: Mark a node as no longer being a POI (it's now in a way). + delete pois[node._id]; + } - // ------------ - // POI handling - updatePOIs:function(nodelist) { - // summary: Update the list of POIs (nodes not in ways) from a supplied array of nodes. - for (var i in nodelist) { - if (nodelist[i].entity.hasParentWays()) { - delete this.pois[nodelist[i]._id]; - } else { - this.pois[nodelist[i]._id] = nodelist[i]; - } - } - }, + // ---------- + // OSM parser - getPOIs:function() { - // summary: Return a list of all the POIs in this Connection. - return _.values(this.pois); - }, - - registerPOI:function(node) { - // summary: Register a node as a POI (not in a way). - this.pois[node._id] = node; - }, - - unregisterPOI:function(node) { - // summary: Mark a node as no longer being a POI (it's now in a way). - delete this.pois[node._id]; - }, - - // ---------- - // OSM parser - - loadFromAPI: function(box) { + function loadFromAPI(box, callback) { // summary: Request data within the bbox from an external OSM server. Currently hardcoded // to use Overpass API (which has the relevant CORS headers). - this.loadFromURL("http://www.overpass-api.de/api/xapi?map?bbox=" + [box.west, box.south, box.east, box.north]); - }, + loadFromURL("http://www.overpass-api.de/api/xapi?map?bbox=" + + [box.west, box.south, box.east, box.north], callback); + } - loadFromURL: function(url) { - // summary: Load all data from a given URL. - $.ajax({ + function loadFromURL(url, callback) { + // summary: Load all data from a given URL. + $.ajax({ url: url, - context: this, headers: { "X-Requested-With": null }, - success: this._processOSM + success: parse(callback) }); - }, + } - _processOSM:function(dom) { - var nodelist = []; - for (var i in dom.childNodes[0].childNodes) { - var obj = dom.childNodes[0].childNodes[i]; - switch(obj.nodeName) { - - case "node": - var node = new iD.Node(this, + function parse(callback) { + return function(dom) { + var nodelist = _.compact(_.map(dom.childNodes[0].childNodes, function(obj) { + if (obj.nodeName === 'node') { + var node = new iD.Node(connection, +getAttribute(obj, 'id'), +getAttribute(obj, 'lat'), +getAttribute(obj, 'lon'), getTags(obj)); - this._assign(node); - nodelist.push(node); - break; - - case "way": - var way = new iD.Way(this, - getAttribute(obj,'id'), - getNodes(obj, this), + assign(node); + return node; + } else if (obj.nodeName === 'way') { + var way = new iD.Way(connection, + getAttribute(obj, 'id'), + getNodes(obj, connection), getTags(obj)); - this._assign(way); - break; - - case "relation": - var relation = new iD.Relation(this, - getAttribute(obj,'id'), - getMembers(obj, this), + assign(way); + } else if (obj.nodeName === 'relation') { + var relation = new iD.Relation(connection, + getAttribute(obj, 'id'), + getMembers(obj, connection), getTags(obj)); - this._assign(relation); - break; - } - } - this.updatePOIs(nodelist); - this.refreshMaps(); - if (this.callback) { this.callback(); } + assign(relation); + } + })); + updatePOIs(nodelist); + if (callback) { callback(nodelist); } - // Private functions to parse DOM created from XML file - function filterNodeName(n) { - return function(item) { - return item.nodeName === n; - }; - } + // Private functions to parse DOM created from XML file + function filterNodeName(n) { + return function(item) { return item.nodeName === n; }; + } - function getAttribute(obj, name) { - return _.find(obj.attributes, filterNodeName(name)).nodeValue; - } + function getAttribute(obj, name) { + return _.find(obj.attributes, filterNodeName(name)).nodeValue; + } - function getTags(obj) { - return _(obj.childNodes).chain() + function getTags(obj) { + return _(obj.childNodes).chain() .filter(filterNodeName('tag')) .map(function(item) { return [getAttribute(item,'k'), getAttribute(item,'v')]; }).object().value(); - } + } - function getNodes(obj,conn) { - return _(obj.childNodes).chain() + function getNodes(obj,conn) { + return _(obj.childNodes).chain() .filter(filterNodeName('nd')) .map(function(item) { - return conn.nodes[getAttribute(item,'ref')]; + return nodes[getAttribute(item,'ref')]; }).value(); - } + } - function getMembers(obj,conn) { - return _(obj.childNodes).chain() - .filter(filterNodeName('member')) - .map(function(item) { - var id = getAttribute(item,'ref'), + function getMembers(obj,conn) { + return _(obj.childNodes).chain() + .filter(filterNodeName('member')) + .map(function(item) { + var id = getAttribute(item,'ref'), type = getAttribute(item,'type'), role = getAttribute(item,'role'); - var obj = conn._getOrCreate(id,type); - return new iD.RelationMember(obj,role); - }).value(); - } - } + var obj = getOrCreate(id,type); + return new iD.RelationMember(obj,role); + }).value(); + } + }; + } + + connection.nodes = nodes; + connection.ways = ways; + connection.relations = relations; + connection.loadFromAPI = loadFromAPI; + connection.loadFromURL = loadFromURL; + connection.getObjectsByBbox = getObjectsByBbox; + + return connection; }; diff --git a/js/iD/renderer/Map.js b/js/iD/renderer/Map.js index 2ad184980..0245b175c 100755 --- a/js/iD/renderer/Map.js +++ b/js/iD/renderer/Map.js @@ -224,10 +224,10 @@ declare("iD.renderer.Map", null, { download:function() { // summary: Ask the connection to download data for the current viewport. - this.conn.loadFromAPI(this.extent); + this.conn.loadFromAPI(this.extent, _.bind(this.updateUIs, this)); }, - updateUIs:function(redraw,remove) { + updateUIs: function(redraw, remove) { // summary: Draw/refresh all EntityUIs within the bbox, and remove any others. // redraw: Boolean Should we redraw any UIs that are already present? // remove: Boolean Should we delete any UIs that are no longer in the bbox? @@ -243,7 +243,7 @@ declare("iD.renderer.Map", null, { else if (redraw) { m.wayuis[way.id].recalculate(); m.wayuis[way.id].redraw(); } }); - if (remove) { + if (remove !== false) { array.forEach(o.waysOutside, function(way) { if (m.wayuis[way.id]) { // && !m.wayuis[way.id].purgable if (redraw) { m.wayuis[way.id].recalculate(); m.wayuis[way.id].redraw(); } @@ -257,7 +257,7 @@ declare("iD.renderer.Map", null, { else if (redraw) { m.nodeuis[poi.id].redraw(); } }); - if (remove) { + if (remove !== false) { array.forEach(o.poisOutside, function(poi) { if (m.nodeuis[poi.id]) { // && !m.nodeuis[poi.id].purgable if (redraw) { m.nodeuis[poi.id].redraw(); }