From 4182cc1240be2684ae41bfd85ee4075ea8571095 Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Thu, 18 Oct 2012 12:37:01 -0400 Subject: [PATCH] Start UI refactor --- css/app.css | 56 ++++++++++++- index.html | 114 ++++++++++---------------- js/iD/Connection.js | 21 +++-- js/iD/Controller.js | 2 +- js/iD/Node.js | 10 +-- js/iD/Way.js | 27 +++--- js/iD/controller/shape/DrawWay.js | 38 ++++----- js/iD/controller/shape/NoSelection.js | 12 +-- js/iD/renderer/Map.js | 114 +++++++++++++------------- js/iD/renderer/WayUI.js | 2 + js/iD/styleparser/Condition.js | 27 +++--- js/iD/styleparser/Rule.js | 6 +- js/iD/styleparser/RuleChain.js | 7 +- js/iD/styleparser/RuleSet.js | 12 +-- js/iD/styleparser/Style.js | 55 ++++++------- js/iD/styleparser/StyleChooser.js | 5 +- js/iD/styleparser/StyleList.js | 12 +-- js/iD/ui/StepPane.js | 82 +++--------------- 18 files changed, 286 insertions(+), 316 deletions(-) diff --git a/css/app.css b/css/app.css index 464996632..13338406b 100644 --- a/css/app.css +++ b/css/app.css @@ -1,6 +1,8 @@ body { font:normal 13px/20px Helvetica, Arial, sans-serif; background:#e4e4e4; + margin:0; + text-rendering: optimizeLegibility; } :focus { outline-color: transparent; @@ -24,6 +26,30 @@ text { -moz-user-select: none; } +#map { + height: 600px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.help-pane { + position:absolute; + left:0; + width:300px; + opacity:0.9; + top:40px; + background:#FFFBD3; +} + +.help-pane div { + padding:10px; + font-style:italic; +} + #map.state-drawing { cursor: pointer; } @@ -32,13 +58,41 @@ text { font-weight: bold; } -/* Zoom controls */ +#modebuttons { + width:300px; + position:absolute; + left:0px; + top:0px; +} + #zoombuttons { position:absolute; right:20px; top:20px; } +#addPOI { + display:none; +} + +#modebuttons button { + width:100px; + cursor:pointer; + background:#fff; + color:#555; + font:bold 19px/35px 'Helvetica Neue'; + border:0; + border-right:1px solid #222; + border-bottom:1px solid #222; + padding:0 10px; + height:40px; + margin:0; +} + +#modebuttons button:hover { + background:#eee; +} + #zoombuttons button { cursor:pointer; width:30px; diff --git a/index.html b/index.html index 6f4b59816..5629d892b 100755 --- a/index.html +++ b/index.html @@ -24,7 +24,6 @@ + - - -
-
- Add point -
-

Drag points onto the map

- -
-
-
- - - - +
+ +
+

Drag points onto the map

+ +
+
- + +
+ + +
+
Click on the map to start a road
+
Draw the road by clicking on points along its path
+
Choose a road type
-
-
+

Work in progress: introduction, code, docs. Imagery © 2012 Bing, GeoEye, Getmapping, Intermap, Microsoft.

- - - -
diff --git a/js/iD/Connection.js b/js/iD/Connection.js index af6ef99ea..bbeac1d63 100755 --- a/js/iD/Connection.js +++ b/js/iD/Connection.js @@ -143,13 +143,13 @@ iD.Connection.prototype = { // ---------- // OSM parser - loadFromAPI:function(left,right,top,bottom) { + loadFromAPI: function(box) { // 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=" + [left,bottom,right,top]); + this.loadFromURL("http://www.overpass-api.de/api/xapi?map?bbox=" + [box.west, box.south, box.east, box.north]); }, - loadFromURL:function(url) { + loadFromURL: function(url) { // summary: Load all data from a given URL. $.ajax({ url: url, @@ -160,17 +160,16 @@ iD.Connection.prototype = { }, _processOSM:function(dom) { - // var jsdom = $.parseXML(result).childNodes[1]; var nodelist = []; for (var i in dom.childNodes[0].childNodes) { - var obj=dom.childNodes[0].childNodes[i]; + var obj = dom.childNodes[0].childNodes[i]; switch(obj.nodeName) { case "node": var node = new iD.Node(this, - +getAttribute(obj,'id'), - +getAttribute(obj,'lat'), - +getAttribute(obj,'lon'), + +getAttribute(obj, 'id'), + +getAttribute(obj, 'lat'), + +getAttribute(obj, 'lon'), getTags(obj)); this._assign(node); nodelist.push(node); @@ -179,7 +178,7 @@ iD.Connection.prototype = { case "way": var way = new iD.Way(this, getAttribute(obj,'id'), - getNodes(obj,this), + getNodes(obj, this), getTags(obj)); this._assign(way); break; @@ -187,7 +186,7 @@ iD.Connection.prototype = { case "relation": var relation = new iD.Relation(this, getAttribute(obj,'id'), - getMembers(obj,this), + getMembers(obj, this), getTags(obj)); this._assign(relation); break; @@ -204,7 +203,7 @@ iD.Connection.prototype = { }; } - function getAttribute(obj,name) { + function getAttribute(obj, name) { return _.find(obj.attributes, filterNodeName(name)).nodeValue; } diff --git a/js/iD/Controller.js b/js/iD/Controller.js index eb1257333..db7a2f2da 100755 --- a/js/iD/Controller.js +++ b/js/iD/Controller.js @@ -20,7 +20,7 @@ declare("iD.Controller", [Evented], { this.editorCache = {}; }, - setStepper:function(stepper) { + setStepper: function(stepper) { // summary: Set reference for the singleton-like class for the step-by-step instruction panel. this.stepper = stepper; }, diff --git a/js/iD/Node.js b/js/iD/Node.js index 3d379a001..4f509afe6 100644 --- a/js/iD/Node.js +++ b/js/iD/Node.js @@ -39,11 +39,11 @@ iD.Node.prototype = { return 180/Math.PI * (2 * Math.atan(Math.exp(a*Math.PI/180)) - Math.PI/2); }, - within: function(left, right, top, bottom) { - return (this.lon >= left) && - (this.lon <= right) && - (this.lat >= bottom) && - (this.lat <= top); + within: function(extent) { + return (this.lon >= extent.west) && + (this.lon <= extent.east) && + (this.lat >= extent.south) && + (this.lat <= extent.north); }, refresh: function() { diff --git a/js/iD/Way.js b/js/iD/Way.js index 7cba274af..240970467 100644 --- a/js/iD/Way.js +++ b/js/iD/Way.js @@ -12,6 +12,7 @@ iD.Way = function(conn, id, nodes, tags, loaded) { this.loaded = (loaded === undefined) ? true : loaded; this.modified = this.id < 0; this.nodes = nodes || []; + this.extent = {}; _.each(nodes, _.bind(function(node) { node.entity.addParent(this); }, this)); @@ -49,11 +50,11 @@ iD.Way.prototype = { // Bounding-box handling within:function(left,right,top,bottom) { // TODO invert and just return - if (!this.edgel || - (this.edgelright && this.edger>right ) || - (this.edgebtop && this.edgeb>top )) { + if (!this.extent.west || + (this.extent.west < left && this.extent.east < left ) || + (this.extent.west > right && this.extent.east > right ) || + (this.extent.south < bottom && this.extent.north < bottom) || + (this.extent.south > top && this.extent.south > top)) { return false; } else { return true; @@ -61,18 +62,22 @@ iD.Way.prototype = { }, _calculateBbox:function() { - this.edgel = 999999; this.edger = -999999; - this.edgeb = 999999; this.edget = -999999; + this.extent = { + west: Infinity, + east: -Infinity, + south: Infinity, + north: -Infinity + }; _.each(this.nodes, _.bind(function(n) { this.expandBbox(n); }, this)); }, expandBbox:function(node) { // summary: Enlarge the way's bounding box to make sure it // includes the co-ordinates of a supplied node. - this.edgel=Math.min(this.edgel,node.lon); - this.edger=Math.max(this.edger,node.lon); - this.edgeb=Math.min(this.edgeb,node.lat); - this.edget=Math.max(this.edget,node.lat); + this.extent.west = Math.min(this.extent.west, node.lon); + this.extent.east = Math.max(this.extent.east, node.lon); + this.extent.south = Math.min(this.extent.south, node.lat); + this.extent.north = Math.max(this.extent.north, node.lat); }, // -------------- diff --git a/js/iD/controller/shape/DrawWay.js b/js/iD/controller/shape/DrawWay.js index b3a246e29..f38b8c526 100644 --- a/js/iD/controller/shape/DrawWay.js +++ b/js/iD/controller/shape/DrawWay.js @@ -28,20 +28,21 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], { constructor: function(way) { this.way = way; - }, - enterState: function() { - this.wayUI = this.controller.map.getUI(this.way); - this.wayUI.setStateClass('selected'); - this.wayUI.setStateClass('shownodes'); - this.wayUI.redraw(); - this.controller.stepper.highlight('draw'); - }, - exitState: function() { - this.controller.map.clearElastic(); - this.wayUI.resetStateClass('selected'); - this.wayUI.resetStateClass('shownodes'); - this.wayUI.redraw(); - }, + }, + enterState: function() { + this.wayUI = this.controller.map.getUI(this.way); + this.wayUI.setStateClass('selected') + .setStateClass('shownodes') + .redraw(); + this.controller.stepper.step(1); + }, + exitState: function() { + this.controller.map.clearElastic(); + this.wayUI + .resetStateClass('selected') + .resetStateClass('shownodes') + .redraw(); + }, processMouseEvent:function(event,entityUI) { var entity=entityUI ? entityUI.entity : null; @@ -99,12 +100,12 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], { // Click on node if (entity === this.getDrawingNode()) { // Double-click, so complete drawing - this.controller.stepper.highlight('tag'); + this.controller.stepper.step(2); return new iD.controller.edit.SelectedWay(this.way, null); } else if (entity === this.getStartNode()) { // Start of this way, so complete drawing this.appendNode(entity, this.undoAdder() ); - this.controller.stepper.highlight('tag'); + this.controller.stepper.step(2); return new iD.controller.edit.SelectedWay(this.way, null); } else { // Add to way @@ -147,11 +148,11 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], { }, getDrawingNode:function() { - return (this.editEnd ? this.way.nodes[this.way.length()-1] : this.way.nodes[0]); + return (this.editEnd ? this.way.nodes[this.way.nodes.length - 1] : this.way.nodes[0]); }, getStartNode:function() { - return (this.editEnd ? this.way.nodes[0] : this.way.nodes[this.way.length()-1]); + return (this.editEnd ? this.way.nodes[0] : this.way.nodes[this.way.node.length - 1]); }, appendNode:function(node, performAction) { @@ -168,7 +169,6 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], { this.appendNode(node, lang.hitch(undo,undo.push)); return node; } - }); // ---------------------------------------------------------------------- diff --git a/js/iD/controller/shape/NoSelection.js b/js/iD/controller/shape/NoSelection.js index 1e9eb8301..9f3edbfa5 100644 --- a/js/iD/controller/shape/NoSelection.js +++ b/js/iD/controller/shape/NoSelection.js @@ -36,11 +36,7 @@ declare("iD.controller.shape.NoSelection", [iD.controller.ControllerState], { enterState: function() { this.controller.map.div.className = 'state-drawing'; - this.controller.stepper.setSteps({ - begin: "Click anywhere on the map to start drawing", - draw: "Keep clicking to add each point then double-click when you're done", - tag: "Set the type of the road or shape" - }, ['begin', 'draw', 'tag']).highlight('begin'); + this.controller.stepper.show().step(0); }, processMouseEvent:function(event,entityUI) { @@ -53,9 +49,9 @@ declare("iD.controller.shape.NoSelection", [iD.controller.ControllerState], { case 'node': // Click to select a node var ways=entity.parentWays(); - if (ways.length==0) { return new iD.controller.shape.SelectedPOINode(entity); } - // else { return new iD.controller.shape.SelectedWayNode(entity,ways[0]); } - // ** FIXME: ^^^ the above should start a new branching way, not select the node + if (!ways.length) { return new iD.controller.shape.SelectedPOINode(entity); } + // else { return new iD.controller.shape.SelectedWayNode(entity,ways[0]); } + // ** FIXME: ^^^ the above should start a new branching way, not select the node return this; case 'way': // Click to select a way diff --git a/js/iD/renderer/Map.js b/js/iD/renderer/Map.js index b083a2372..9b35ff2d9 100755 --- a/js/iD/renderer/Map.js +++ b/js/iD/renderer/Map.js @@ -5,7 +5,7 @@ define(['dojo/_base/declare','dojo/_base/array','dojo/_base/event','dojo/_base/l 'dojo/dom-geometry', 'dojox/gfx','dojox/gfx/matrix', 'iD/Connection','iD/Entity','iD/renderer/EntityUI','iD/renderer/WayUI','iD/renderer/NodeUI'], - function(declare,array,Event,lang,domGeom,Gfx,Matrix){ + function(declare, array, Event, lang, domGeom, Gfx, Matrix){ // ---------------------------------------------------------------------- // Connection base class @@ -47,10 +47,7 @@ declare("iD.renderer.Map", null, { containery: 0, // | centrelat: NaN, // lat/long and bounding box of map centrelon: NaN, // | - edgel: NaN, // | - edger: NaN, // | - edget: NaN, // | - edgeb: NaN, // | + extent: {}, // | mapheight: NaN, // size of map object in pixels mapwidth: NaN, // | @@ -109,22 +106,22 @@ declare("iD.renderer.Map", null, { this.elastic = this.container.createGroup(); // Make draggable - this.backdrop.connect("onmousedown", lang.hitch(this,"startDrag")); - this.tilegroup.connect("onmousedown", lang.hitch(this,"startDrag")); - this.surface.connect("onclick", lang.hitch(this,"clickSurface")); - this.surface.connect("onmousemove", lang.hitch(this,"processMove")); - this.surface.connect("onmousedown", lang.hitch(this,"_mouseEvent")); - this.surface.connect("onmouseup", lang.hitch(this,"_mouseEvent")); + this.backdrop.connect("onmousedown", _.bind(this.startDrag, this)); + this.tilegroup.connect("onmousedown", _.bind(this.startDrag, this)); + this.surface.connect("onclick", _.bind(this.clickSurface, this)); + this.surface.connect("onmousemove", _.bind(this.processMove, this)); + this.surface.connect("onmousedown", _.bind(this._mouseEvent, this)); + this.surface.connect("onmouseup", _.bind(this._mouseEvent, this)); }, setController:function(controller) { // summary: Set the controller that will handle events on the map (e.g. mouse clicks). - this.controller=controller; + this.controller = controller; }, - _moveToPosition:function(group,position) { + _moveToPosition:function(group, position) { // summary: Supplementary method for dojox.gfx. - // This should ideally be core Dojo stuff: see http://bugs.dojotoolkit.org/ticket/15296 + // This should ideally be core Dojo stuff: see http://bugs.dojotoolkit.org/ticket/15296 var parent=group.getParent(); if (!parent) { return; } this._moveChildToPosition(parent,group,position); @@ -135,9 +132,9 @@ declare("iD.renderer.Map", null, { } }, - _moveChildToPosition: function(parent,child,position) { - for(var i = 0; i < parent.children.length; ++i){ - if(parent.children[i] == child){ + _moveChildToPosition: function(parent, child, position) { + for (var i = 0; i < parent.children.length; ++i){ + if (parent.children[i] === child){ parent.children.splice(i, 1); parent.children.splice(position, 0, child); break; @@ -150,7 +147,7 @@ declare("iD.renderer.Map", null, { sublayer:function(layer,groupType,sublayer) { // summary: Find the gfx.Group for a given OSM layer and rendering sublayer, creating it - // if necessary. Note that sublayers are only implemented for stroke and fill. + // if necessary. Note that sublayers are only implemented for stroke and fill. // groupType: String 'casing','text','hit','stroke', or 'fill' var collection=this.layers[layer][groupType], sub; switch (groupType) { @@ -165,7 +162,7 @@ declare("iD.renderer.Map", null, { sub=collection.children[i]; if (sub.sublayer==sublayer) { return sub; } else if (sub.sublayer>sublayer) { - sub=collection.createGroup(); + sub = collection.createGroup(); this._moveToPosition(sub,i); sub.sublayer=sublayer; return sub; @@ -208,7 +205,7 @@ declare("iD.renderer.Map", null, { }, refreshUI:function(entity) { - // summary: Redraw the UI for an entity. + // summary: Redraw the UI for an entity. switch (entity.entityType) { case 'node': if (this.nodeuis[entity.id]) { this.nodeuis[entity.id].redraw(); } break; case 'way': if (this.wayuis[entity.id] ) { this.wayuis[entity.id].redraw(); } break; @@ -218,14 +215,14 @@ declare("iD.renderer.Map", null, { deleteUI:function(entity) { // summary: Delete the UI for an entity. switch (entity.entityType) { - case 'node':if (this.nodeuis[entity.id]) { this.nodeuis[entity.id].removeSprites(); delete this.nodeuis[entity.id]; } break; + case 'node': if (this.nodeuis[entity.id]) { this.nodeuis[entity.id].removeSprites(); delete this.nodeuis[entity.id]; } break; case 'way': if (this.wayuis[entity.id] ) { this.wayuis[entity.id].removeSprites(); delete this.wayuis[entity.id]; } break; } }, download:function() { // summary: Ask the connection to download data for the current viewport. - this.conn.loadFromAPI(this.edgel, this.edger, this.edget, this.edgeb); + this.conn.loadFromAPI(this.extent); }, updateUIs:function(redraw,remove) { @@ -235,7 +232,7 @@ declare("iD.renderer.Map", null, { var m = this; var way, poi; - var o = this.conn.getObjectsByBbox(this.edgel,this.edger,this.edget,this.edgeb); + var o = this.conn.getObjectsByBbox(this.extent); _(o.waysInside).chain() .filter(function(w) { return w.loaded; }) @@ -270,18 +267,18 @@ declare("iD.renderer.Map", null, { // ------------- // Zoom handling - zoomIn:function() { + zoomIn: function() { // summary: Zoom in by one level (unless maximum reached). - if (this.scale!=this.MAXSCALE) { this.changeScale(this.scale+1); } + if (this.scale !== this.MAXSCALE) { this.changeScale(this.scale+1); } }, - zoomOut:function() { + zoomOut: function() { // summary: Zoom out by one level (unless minimum reached). - if (this.scale!=this.MINSCALE) { this.changeScale(this.scale-1); } + if (this.scale !== this.MINSCALE) { this.changeScale(this.scale-1); } this.download(); }, - changeScale:function(scale) { + changeScale: function(scale) { // summary: Redraw the map at a new zoom level. this.scale=scale; this._setScaleFactor(); @@ -290,7 +287,7 @@ declare("iD.renderer.Map", null, { this.updateUIs(true,true); }, - _setScaleFactor:function() { + _setScaleFactor: function() { // summary: Calculate the scaling factor for this zoom level. this.scalefactor=this.MASTERSCALE/Math.pow(2,13-this.scale); }, @@ -298,42 +295,45 @@ declare("iD.renderer.Map", null, { // ---------------------- // Elastic band redrawing - clearElastic:function() { + clearElastic: function() { // summary: Remove the elastic band used to draw new ways. this.elastic.clear(); }, - drawElastic:function(x1,y1,x2,y2) { + drawElastic: function(x1,y1,x2,y2) { // summary: Draw the elastic band (for new ways) between two points. this.elastic.clear(); // **** Next line is SVG-specific this.elastic.rawNode.setAttribute("pointer-events","none"); this.elastic.createPolyline( [{ x:x1, y:y1 }, { x:x2, y:y2 }] ).setStroke( { - color: [0,0,0,1], + color: [0, 0, 0, 1], style: 'Solid', - width: 1 }); + width: 1 + }); }, // ------------- // Tile handling // ** FIXME: see docs - - loadTiles:function() { + loadTiles: function() { // summary: Load all tiles for the current viewport. This is a bare-bones function // at present: it needs configurable URLs (not just Bing), attribution/logo // support, and to be 'nudgable' (i.e. adjust the offset). - var tile_l=this.lon2tile(this.edgel); - var tile_r=this.lon2tile(this.edger); - var tile_t=this.lat2tile(this.edget); - var tile_b=this.lat2tile(this.edgeb); + var tile_l=this.lon2tile(this.extent.west); + var tile_r=this.lon2tile(this.extent.east); + var tile_t=this.lat2tile(this.extent.north); + var tile_b=this.lat2tile(this.extent.south); + for (var x=tile_l; x<=tile_r; x++) { for (var y=tile_t; y<=tile_b; y++) { - if (!this._getTile(this.scale,x,y)) { this._fetchTile(this.scale,x,y); } + if (!this._getTile(this.scale,x,y)) { + this._fetchTile(this.scale,x,y); + } } } }, - _fetchTile:function(z,x,y) { + _fetchTile: function(z,x,y) { // summary: Load a tile image at the given tile co-ordinates. var t=this.tilegroup.createImage({ x: Math.floor(this.lon2coord(this.tile2lon(x))), @@ -344,13 +344,13 @@ declare("iD.renderer.Map", null, { this._assignTile(z,x,y,t); }, - _getTile:function(z,x,y) { + _getTile: function(z,x,y) { // summary: See if this tile is already loaded. var k = z + ',' + x + ',' + y; return this.tiles[k]; }, - _assignTile:function(z,x,y,t) { + _assignTile: function(z,x,y,t) { // summary: Store a reference to the tile so we know it's loaded. var k = z + ',' + x + ',' + y; if (!this.tiles[k]) { @@ -358,7 +358,7 @@ declare("iD.renderer.Map", null, { } }, - _tileURL:function(z,x,y) { + _tileURL: function(z,x,y) { // summary: Calculate the URL for a tile at the given co-ordinates. var u=''; for (var zoom=z; zoom>0; zoom--) { @@ -371,7 +371,7 @@ declare("iD.renderer.Map", null, { return this.tilebaseURL.replace('$z',z).replace('$x',x).replace('$y',y).replace('$quadkey',u); }, - _blankTiles:function() { + _blankTiles: function() { // summary: Unload all tiles and remove from the display. this.tilegroup.clear(); this.tiles = {}; @@ -380,7 +380,7 @@ declare("iD.renderer.Map", null, { // ------------------------------------------- // Co-ordinate management, dragging and redraw - startDrag:function(e) { + startDrag: function(e) { // summary: Start dragging the map in response to a mouse-down. // e: MouseEvent The mouse-down event that triggered it. var srcElement = (e.gfxTarget==this.backdrop) ? e.gfxTarget : e.gfxTarget.parent; @@ -393,7 +393,7 @@ declare("iD.renderer.Map", null, { this.dragconnect=srcElement.connect("onmouseup", lang.hitch(this,"endDrag")); }, - endDrag:function(e) { + endDrag: function(e) { // summary: Stop dragging the map in response to a mouse-up. // e: MouseEvent The mouse-up event that triggered it. Event.stop(e); @@ -405,7 +405,7 @@ declare("iD.renderer.Map", null, { this.download(); }, - processMove:function(e) { + processMove: function(e) { // summary: Drag the map to a new origin. // e: MouseEvent The mouse-move event that triggered it. var x = e.clientX; @@ -424,13 +424,13 @@ declare("iD.renderer.Map", null, { } }, - updateOrigin:function() { + updateOrigin: function() { // summary: Tell Dojo to update the viewport origin. this.container.setTransform([Matrix.translate(this.containerx,this.containery)]); this.tilegroup.setTransform([Matrix.translate(this.containerx,this.containery)]); }, - _mouseEvent:function(e) { + _mouseEvent: function(e) { // summary: Catch mouse events on the surface but not the tiles - in other words, // on drawn items that don't have their own hitzones, like the fill of a shape. if (e.type=='mousedown') { this.startDrag(e); } @@ -449,15 +449,19 @@ declare("iD.renderer.Map", null, { -(this.lat2coord(lat)-this.mapheight/2)); }, - _updateCoords:function(x,y) { + _updateCoords:function(x, y) { // summary: Set centre and bbox. this.containerx=x; this.containery=y; this.updateOrigin(); this.centrelon=this.coord2lon(-x + this.mapwidth/2); this.centrelat=this.coord2lat(-y + this.mapheight/2); - this.edget=this.coord2lat(-y); - this.edgeb=this.coord2lat(-y + this.mapheight); - this.edgel=this.coord2lon(-x); - this.edger=this.coord2lon(-x + this.mapwidth); + + this.extent = { + north: this.coord2lat(-y), + south: this.coord2lat(-y + this.mapheight), + west: this.coord2lon(-x), + east: this.coord2lon(-x + this.mapwidth) + }; + this.loadTiles(); }, diff --git a/js/iD/renderer/WayUI.js b/js/iD/renderer/WayUI.js index dfcb1c695..a44b5b4b0 100755 --- a/js/iD/renderer/WayUI.js +++ b/js/iD/renderer/WayUI.js @@ -131,6 +131,8 @@ declare("iD.renderer.WayUI", [iD.renderer.EntityUI], { if (node.entity.parentWays().length>1) { sc.push('junction'); } this.map.createUI(node,sc); } + + return this; }, entityMouseEvent:function(event) { diff --git a/js/iD/styleparser/Condition.js b/js/iD/styleparser/Condition.js index 85f08babf..6c509b6f4 100755 --- a/js/iD/styleparser/Condition.js +++ b/js/iD/styleparser/Condition.js @@ -19,28 +19,27 @@ declare("iD.styleparser.Condition", null, { // summary: Run the condition against the supplied tags. var p=this.params; switch (this.type) { - case 'eq': return (tags[p[0]]==p[1]); break; - case 'ne': return (tags[p[0]]!=p[1]); break; + case 'eq': return (tags[p[0]]==p[1]); + case 'ne': return (tags[p[0]]!=p[1]); case 'regex': var r=new RegExp(p[1],"i"); - return (r.test(tags[p[0]])); break; - case 'true': return (tags[p[0]]=='true' || tags[p[0]]=='yes' || tags[p[0]]=='1'); break; - case 'false': return (tags[p[0]]=='false' || tags[p[0]]=='no' || tags[p[0]]=='0'); break; - case 'set': return (tags[p[0]]!=undefined && tags[p[0]]!=''); break; - case 'unset': return (tags[p[0]]==undefined || tags[p[0]]==''); break; - case '<': return (Number(tags[p[0]])< Number(p[1])); break; - case '<=': return (Number(tags[p[0]])<=Number(p[1])); break; - case '>': return (Number(tags[p[0]])> Number(p[1])); break; - case '>=': return (Number(tags[p[0]])>=Number(p[1])); break; + return (r.test(tags[p[0]])); + case 'true': return (tags[p[0]]=='true' || tags[p[0]]=='yes' || tags[p[0]]=='1'); + case 'false': return (tags[p[0]]=='false' || tags[p[0]]=='no' || tags[p[0]]=='0'); + case 'set': return (tags[p[0]] !== undefined && tags[p[0]]!==''); + case 'unset': return (tags[p[0]] === undefined || tags[p[0]]===''); + case '<': return (Number(tags[p[0]])< Number(p[1])); + case '<=': return (Number(tags[p[0]])<=Number(p[1])); + case '>': return (Number(tags[p[0]])> Number(p[1])); + case '>=': return (Number(tags[p[0]])>=Number(p[1])); } return false; }, toString:function() { return "["+this.type+": "+this.params+"]"; - }, - + } }); // ---------------------------------------------------------------------- // End of module -}); \ No newline at end of file +}); diff --git a/js/iD/styleparser/Rule.js b/js/iD/styleparser/Rule.js index 6cf8f7b25..5fffb211f 100755 --- a/js/iD/styleparser/Rule.js +++ b/js/iD/styleparser/Rule.js @@ -13,7 +13,7 @@ declare("iD.styleparser.Rule", null, { maxZoom: 255, // maximum zoom level at which the Rule is fulfilled subject: '', // entity type to which the Rule applies: 'way', 'node', 'relation', 'area' (closed way) or 'line' (unclosed way) - constructor:function(_subject) { + constructor: function(_subject) { // summary: A MapCSS selector. Contains a list of Conditions; the entity type to which the selector applies; // and the zoom levels at which it is true. way[waterway=river][boat=yes] would be parsed into one Rule. // The selectors and declaration together form a StyleChooser. @@ -21,12 +21,12 @@ declare("iD.styleparser.Rule", null, { this.conditions=[]; }, - addCondition:function(_condition) { + addCondition: function(_condition) { // summary: Add a condition to this rule. this.conditions.push(_condition); }, - test:function(entity,tags,zoom) { + test: function(entity,tags,zoom) { // summary: Evaluate the Rule on the given entity, tags and zoom level. // returns: true if the Rule passes, false if the conditions aren't fulfilled. if ((this.subject !== '') && (entity.entityType !== this.subject)) { diff --git a/js/iD/styleparser/RuleChain.js b/js/iD/styleparser/RuleChain.js index 19a070364..96b1658c0 100755 --- a/js/iD/styleparser/RuleChain.js +++ b/js/iD/styleparser/RuleChain.js @@ -48,8 +48,8 @@ declare("iD.styleparser.RuleChain", null, { return this.rules.length; }, - setSubpart:function(_subpart) { - this.subpart = _subpart=='' ? 'default' : _subpart; + setSubpart:function(subpart) { + this.subpart = subpart || 'default'; }, // Test a ruleChain @@ -60,7 +60,7 @@ declare("iD.styleparser.RuleChain", null, { // - if they succeed, and it's the last in the chain, return happily // - if they succeed, and there's more in the chain, rerun this for each parent until success - test:function(pos, entity, tags, zoom) { + test: function(pos, entity, tags, zoom) { // summary: Test a rule chain by running all the tests in reverse order. if (this.rules.length === 0) { return false; } if (pos==-1) { pos=this.rules.length-1; } @@ -76,7 +76,6 @@ declare("iD.styleparser.RuleChain", null, { } return false; } - }); // ---------------------------------------------------------------------- diff --git a/js/iD/styleparser/RuleSet.js b/js/iD/styleparser/RuleSet.js index 790d56ccb..c0e540e1a 100755 --- a/js/iD/styleparser/RuleSet.js +++ b/js/iD/styleparser/RuleSet.js @@ -238,12 +238,12 @@ declare("iD.styleparser.RuleSet", null, { } else { var match = this.HEX.exec(colorStr); if ( match ) { - if ( match[1].length == 3) { - // repeat digits. #abc => 0xaabbcc - return Number("0x"+match[1].charAt(0)+match[1].charAt(0)+ - match[1].charAt(1)+match[1].charAt(1)+ - match[1].charAt(2)+match[1].charAt(2)); - } else if ( match[1].length == 6) { + if ( match[1].length == 3) { + // repeat digits. #abc => 0xaabbcc + return Number("0x"+match[1].charAt(0)+match[1].charAt(0)+ + match[1].charAt(1)+match[1].charAt(1)+ + match[1].charAt(2)+match[1].charAt(2)); + } else if ( match[1].length == 6) { return Number("0x"+match[1]); } else { return Number("0x000000"); //as good as any diff --git a/js/iD/styleparser/Style.js b/js/iD/styleparser/Style.js index 542b9d74e..4bde63d76 100755 --- a/js/iD/styleparser/Style.js +++ b/js/iD/styleparser/Style.js @@ -15,16 +15,16 @@ declare("iD.styleparser.Style", null, { styleType: 'Style', evals: null, - constructor: function(){ + constructor: function() { // summary: Base class for a set of painting attributes, into which the CSS declaration is parsed. - this.evals={}; + this.evals = {}; }, - drawn: function(){ + drawn: function() { return false; }, - has: function(k){ + has: function(k) { return this.properties.indexOf(k)>-1; }, @@ -46,7 +46,7 @@ declare("iD.styleparser.Style", null, { } else if (typeof(this[k])=='number') { v=Number(v); } else if (this[k] && this[k].constructor==Array) { - v=v.split(',').map(function(a) { return Number(a); }); + v = v.split(',').map(function(a) { return Number(a); }); } this[k]=v; return true; @@ -66,12 +66,12 @@ declare("iD.styleparser.Style", null, { }, toString: function() { - var str=''; + var str = ''; for (var k in this.properties) { if (this.hasOwnProperty(k)) { str+=k+"="+this[k]+"; "; } } return str; - }, + } }); @@ -79,14 +79,14 @@ declare("iD.styleparser.Style", null, { // InstructionStyle class declare("iD.styleparser.InstructionStyle", [iD.styleparser.Style], { - set_tags:null, - breaker:false, + set_tags: null, + breaker: false, styleType: 'InstructionStyle', - addSetTag:function(k,v) { + addSetTag: function(k,v) { this.edited=true; if (!this.set_tags) this.set_tags={}; this.set_tags[k]=v; - }, + } }); // ---------------------------------------------------------------------- @@ -100,19 +100,19 @@ declare("iD.styleparser.PointStyle", [iD.styleparser.Style], { rotation: NaN, styleType: 'PointStyle', drawn:function() { - return (this.icon_image!=null); + return (this.icon_image !== null); }, maxwidth:function() { - return this.evals['icon_width'] ? 0 : this.icon_width; - }, + return this.evals.icon_width ? 0 : this.icon_width; + } }); // ---------------------------------------------------------------------- // ShapeStyle class declare("iD.styleparser.ShapeStyle", [iD.styleparser.Style], { - properties: ['width','color','opacity','dashes','linecap','linejoin','line_style', - 'fill_image','fill_color','fill_opacity','casing_width','casing_color','casing_opacity','casing_dashes','layer'], + properties: ['width','color','opacity','dashes','linecap','linejoin','line_style', + 'fill_image','fill_color','fill_opacity','casing_width','casing_color','casing_opacity','casing_dashes','layer'], width:0, color:NaN, opacity:NaN, dashes:[], linecap:null, linejoin:null, line_style:null, @@ -127,7 +127,7 @@ declare("iD.styleparser.ShapeStyle", [iD.styleparser.Style], { }, maxwidth:function() { // If width is set by an eval, then we can't use it to calculate maxwidth, or it'll just grow on each invocation... - if (this.evals['width'] || this.evals['casing_width']) { return 0; } + if (this.evals.width || this.evals.casing_width) { return 0; } return (this.width + (this.casing_width ? this.casing_width*2 : 0)); }, strokeStyler:function() { @@ -167,7 +167,7 @@ declare("iD.styleparser.ShapeStyle", [iD.styleparser.Style], { cap: cap, join: join }; - }, + } }); // ---------------------------------------------------------------------- @@ -175,13 +175,13 @@ declare("iD.styleparser.ShapeStyle", [iD.styleparser.Style], { declare("iD.styleparser.TextStyle", [iD.styleparser.Style], { - properties: ['font_family','font_bold','font_italic','font_caps','font_underline','font_size', - 'text_color','text_offset','max_width', - 'text','text_halo_color','text_halo_radius','text_center', - 'letter_spacing'], + properties: ['font_family','font_bold','font_italic','font_caps','font_underline','font_size', + 'text_color','text_offset','max_width', + 'text','text_halo_color','text_halo_radius','text_center', + 'letter_spacing'], - font_family: null, - font_bold: false, + font_family: null, + font_bold: false, font_italic: false, font_underline: false, font_caps: false, @@ -197,7 +197,7 @@ declare("iD.styleparser.TextStyle", [iD.styleparser.Style], { styleType: 'TextStyle', drawn: function() { - return (this.text!=null); + return (this.text !== null); }, fontStyler:function() { return { @@ -218,7 +218,6 @@ declare("iD.styleparser.TextStyle", [iD.styleparser.Style], { // not implemented yet return this.dojoColor(0,1); } - // getTextFormat, getHaloFilter, writeNameLabel }); @@ -232,8 +231,8 @@ declare("iD.styleparser.ShieldStyle", [iD.styleparser.Style], { shield_height: NaN, styleType: 'ShieldStyle', drawn:function() { - return (shield_image!=null); - }, + return (shield_image !== null); + } }); // ---------------------------------------------------------------------- diff --git a/js/iD/styleparser/StyleChooser.js b/js/iD/styleparser/StyleChooser.js index 7d4ddf478..8b856f2b8 100755 --- a/js/iD/styleparser/StyleChooser.js +++ b/js/iD/styleparser/StyleChooser.js @@ -64,7 +64,7 @@ declare("iD.styleparser.StyleChooser", null, { break; } if (r.drawn) { tags[':drawn']='yes'; } - tags['_width']=sl.maxwidth; + tags._width = sl.maxwidth; r.runEvals(tags); if (a[c.subpart]) { @@ -79,8 +79,7 @@ declare("iD.styleparser.StyleChooser", null, { } } } - }, - + } }); // ---------------------------------------------------------------------- diff --git a/js/iD/styleparser/StyleList.js b/js/iD/styleparser/StyleList.js index 0db3a58de..e9bc441b7 100755 --- a/js/iD/styleparser/StyleList.js +++ b/js/iD/styleparser/StyleList.js @@ -17,10 +17,10 @@ declare("iD.styleparser.StyleList", null, { validAt: -1, // Zoom level this is valid at (or -1 at all levels - saves recomputing) constructor:function() { - // summary: A StyleList object is the full list of all styles applied to - // a drawn entity (i.e. node/way). Each array element applies to that - // sublayer (z-index). If there is no element, nothing is drawn on that sublayer. - // StyleLists are created by StyleChooser.getStyles. + // summary: A StyleList object is the full list of all styles applied to + // a drawn entity (i.e. node/way). Each array element applies to that + // sublayer (z-index). If there is no element, nothing is drawn on that sublayer. + // StyleLists are created by StyleChooser.getStyles. this.shapeStyles={}; this.textStyles={}; this.pointStyles={}; @@ -30,7 +30,7 @@ declare("iD.styleparser.StyleList", null, { hasStyles:function() { // summary: Does this StyleList contain any styles? - return ( this.hasShapeStyles() || this.hasTextStyles() || this.hasPointStyles() || this.hasShieldStyles() ); + return (this.hasShapeStyles() || this.hasTextStyles() || this.hasPointStyles() || this.hasShieldStyles()); }, hasFills:function() { @@ -61,7 +61,7 @@ declare("iD.styleparser.StyleList", null, { toString:function() { // summary: Summarise StyleList as String - for debugging - var str=''; + var str = ''; var k; for (k in this.shapeStyles ) { str+="- SS "+k+"="+this.shapeStyles[k]+"\n"; } for (k in this.textStyles ) { str+="- TS "+k+"="+this.textStyles[k]+"\n"; } diff --git a/js/iD/ui/StepPane.js b/js/iD/ui/StepPane.js index 3c27d596b..eb4841140 100644 --- a/js/iD/ui/StepPane.js +++ b/js/iD/ui/StepPane.js @@ -11,90 +11,32 @@ define(['dojo/_base/declare','dojo/_base/lang'], function(declare,lang){ declare("iD.ui.StepPane", null, { - divname: null, - stepsname: null, // we probably don't want to have this currentStep: 0, - order: null, - - constructor:function(_divname,_stepsdivname) { - // summary: Populates and creates the 'Step by step' how-to panel. - // This is a bit messy at present - it shouldn't take stepsname or similar, it should just - // create the pane programmatically. We should also be able to set the title of the pane. - this.divname=_divname; - this.stepsname=_stepsdivname; - this.order=[]; + constructor:function() { }, - - stepsDiv:function() { - // summary: Getter for the
containing the steps. - return document.getElementById(this.stepsname); - }, - stepsNodes:function() { - // summary: Getter for the nodes of the
containing the steps. - return this.stepsDiv().childNodes; - }, - - // ---------------- - // Add/remove steps - - addStep:function(name,text) { - // summary: Add a step to the end of the list. - // name: String A reference to this step (for example, 'start'). - // text: String The text of the step. - this.order.push(name); - this.stepsDiv().appendChild(document.createElement('li')).innerHTML=text; - }, - insertStep:function(pos,name,text) { - // summary: Insert a step at a position within the list. - // pos: Number The index at which to insert the step. - // name: String A reference to this step (for example, 'start'). - // text: String The text of the step. - this.order.splice(pos,0,name); - this.stepsNodes()[pos+1].insertBefore(document.createElement('li')).innerHTML=text; - }, - setSteps:function(steps,order) { - // summary: Set the entire list of steps. - // steps: Object A hash of each step, keyed by reference name. For example: { start: 'Click to begin', ... } - // order: String An array of the step names, in the desired order. For example: ['start','add','finish'] - this.clear(); - for (var i=0; i=1; i--) { - this.stepsDiv().removeChild(this.stepsNodes()[i]); - } - this.order=[]; - }, - // --------------------------- // Change the highlighted step - highlight:function(stepname) { + step: function(x) { // summary: Highlight the step with the specified name, and dim all others. this.show(); - this.currentStep=stepname; - for (var i=1; i