mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-16 13:59:27 +02:00
+30
@@ -1,3 +1,33 @@
|
||||
/* Additional CSS rules will go here */
|
||||
|
||||
.currentMode { font-weight: bold; }
|
||||
|
||||
#zoombuttons {
|
||||
position:absolute;
|
||||
right:20px;
|
||||
top:20px;
|
||||
}
|
||||
|
||||
#zoombuttons button {
|
||||
width:30px;
|
||||
height:30px;
|
||||
text-align:center;
|
||||
margin:0;
|
||||
background:#fff;
|
||||
color:#555;
|
||||
font:bold 20px/20px 'Helvetica';
|
||||
border:1px solid #888;
|
||||
}
|
||||
|
||||
#zoombuttons button:active {
|
||||
background:#eee;
|
||||
}
|
||||
|
||||
#zoombuttons #zoomIn {
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
#zoombuttons #zoomOut {
|
||||
border-left:0;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
+30
-25
@@ -8,7 +8,6 @@
|
||||
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojox/layout/resources/FloatingPane.css">
|
||||
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojox/layout/resources/ResizeHandle.css">
|
||||
<link rel="stylesheet" href="css/app.css">
|
||||
<script src="js/lib/jshashtable.js"></script>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true, baseUrl: 'js/iD/'"></script>
|
||||
<style type="text/css">
|
||||
:focus { outline-color: transparent; outline-style: none; }
|
||||
@@ -19,23 +18,31 @@
|
||||
</head>
|
||||
<body class="claro">
|
||||
<div id="appLayout" class="demoLayout">
|
||||
|
||||
<script>
|
||||
<script type="text/javascript" src="js/lib/underscore-min.js"></script>
|
||||
<script type="text/javascript" src="js/lib/jquery-1.8.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/iD/Util.js"></script>
|
||||
<script type="text/javascript" src="js/iD/Node.js"></script>
|
||||
<script type="text/javascript" src="js/iD/Relation.js"></script>
|
||||
<script type="text/javascript" src="js/iD/Entity.js"></script>
|
||||
<script type="text/javascript" src="js/iD/Way.js"></script>
|
||||
<script type="text/javascript" src="js/iD/Connection.js"></script>
|
||||
<script>
|
||||
|
||||
require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/dom",
|
||||
"dijit/form/Button","dijit/form/ToggleButton",
|
||||
"dojox/layout/FloatingPane",
|
||||
"iD/actions/UndoStack","iD/actions/CreatePOIAction",
|
||||
"iD/Connection",
|
||||
"iD/Controller",
|
||||
"iD/controller/edit/NoSelection","iD/controller/shape/NoSelection",
|
||||
"iD/actions/CreateEntityAction",
|
||||
"iD/controller/edit/NoSelection",
|
||||
"iD/controller/shape/NoSelection",
|
||||
"iD/renderer/Map","iD/styleparser/RuleSet",
|
||||
"iD/ui/DragAndDrop","iD/ui/StepPane",
|
||||
"dojo/domReady!"], function(lang,domGeom,domClass,on,dom){
|
||||
"dojo/domReady!"], function(lang,domGeom,domClass,on,dom) {
|
||||
|
||||
var ruleset=new iD.styleparser.RuleSet();
|
||||
var conn=new iD.Connection("http://www.overpass-api.de/api/xapi?");
|
||||
|
||||
|
||||
// Load styles
|
||||
ruleset.registerCallback(styleLoaded);
|
||||
ruleset.loadFromCSS("potlatch.css",styleLoaded);
|
||||
@@ -56,7 +63,7 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
|
||||
// Initialise controller
|
||||
var controller=new iD.Controller(map);
|
||||
map.setController(controller);
|
||||
|
||||
|
||||
// Initialise event listeners
|
||||
on(window, "enterState", enterStateListener);
|
||||
on(window, "exitState", exitStateListener);
|
||||
@@ -77,10 +84,10 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
|
||||
// Load data
|
||||
map.download();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
// State event listeners
|
||||
|
||||
|
||||
function enterStateListener(event) {
|
||||
domClass.add(event.state[0]+"Button","currentMode");
|
||||
};
|
||||
@@ -88,7 +95,7 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
|
||||
function exitStateListener(event) {
|
||||
domClass.remove(event.state[0]+"Button","currentMode");
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Mode button handlers
|
||||
|
||||
@@ -98,7 +105,7 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
|
||||
|
||||
enterEditMode=function() {
|
||||
};
|
||||
|
||||
|
||||
finishClicked=function() {
|
||||
controller.stepper.hide();
|
||||
};
|
||||
@@ -106,12 +113,17 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
|
||||
cancelClicked=function() {
|
||||
controller.stepper.hide();
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Map control handlers
|
||||
|
||||
zoomInClicked =function() { map.zoomIn(); };
|
||||
zoomOutClicked=function() { map.zoomOut(); };
|
||||
|
||||
$('#zoomIn').click(function() {
|
||||
map.zoomIn();
|
||||
});
|
||||
|
||||
$('#zoomOut').click(function() {
|
||||
map.zoomOut();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -139,14 +151,7 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
|
||||
</div>
|
||||
|
||||
<div id="zoombuttons">
|
||||
<button style="position: absolute; left: 10px; top: 40px;"
|
||||
id="zoomIn" data-dojo-type="dijit.form.Button" data-dojo-props="onClick:zoomInClicked">
|
||||
+
|
||||
</button>
|
||||
<button style="position: absolute; left: 10px; top: 70px;"
|
||||
id="zoomOut" data-dojo-type="dijit.form.Button" data-dojo-props="onClick:zoomOutClicked">
|
||||
–
|
||||
</button>
|
||||
<button id="zoomIn">+</button><button id="zoomOut">–</button>
|
||||
</div>
|
||||
|
||||
<!-- Map div -->
|
||||
@@ -158,7 +163,7 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
|
||||
|
||||
<!-- Floating help window -->
|
||||
|
||||
<div id="helpPane" data-dojo-type="dojox.layout.FloatingPane"
|
||||
<div id="helpPane" data-dojo-type="dojox.layout.FloatingPane"
|
||||
data-dojo-props="resizable:true, closable:false, dockable:false, title: 'Step by step'"
|
||||
style="position:absolute; top:45px; left:50px; width:200px; height:200px; visibility: hidden;" >
|
||||
<ol id="helpSteps">
|
||||
|
||||
+118
-162
@@ -1,61 +1,36 @@
|
||||
// iD/Connection.js
|
||||
|
||||
define(["dojo/_base/xhr","dojo/_base/lang","dojox/xml/DomParser","dojo/_base/array",'dojo/_base/declare',
|
||||
"iD/Entity","iD/Node","iD/Way","iD/Relation","iD/actions/CreateEntityAction"],
|
||||
function(xhr,lang,DomParser,array,declare,Entity){
|
||||
// define(["dojo/_base/xhr","dojo/_base/lang","dojox/xml/DomParser","dojo/_base/array",'dojo/_base/declare',
|
||||
// "iD/Entity","iD/Node","iD/Way","iD/Relation","iD/actions/CreateEntityAction"],
|
||||
// function(xhr,lang,DomParser,array,declare,Entity){
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Connection base class
|
||||
|
||||
declare("iD.Connection", null, {
|
||||
|
||||
nodes: {}, // hash of node objects
|
||||
ways: {}, // hash of way objects
|
||||
relations: {}, // hash of relation objects
|
||||
pois: null, // list of nodes which are POIs
|
||||
maps: [], // list of Map objects listening to this
|
||||
callback: null, // callback once .osm is parsed
|
||||
modified: false, // data has been changed
|
||||
|
||||
nextNode: -1, // next negative ids
|
||||
nextWay: -1, // |
|
||||
nextRelation: -1, // |
|
||||
|
||||
apiBaseURL: '', // root API address
|
||||
|
||||
constructor:function(apiURL) {
|
||||
// summary: The data store, including methods to fetch data from (and, eventually, save data to)
|
||||
// an OSM API server.
|
||||
this.nodes={};
|
||||
this.ways={};
|
||||
this.relations={};
|
||||
this.pois=new Hashtable();
|
||||
this.maps=[];
|
||||
this.modified=false;
|
||||
this.apiBaseURL=apiURL;
|
||||
},
|
||||
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;
|
||||
};
|
||||
|
||||
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;
|
||||
case "node": this.nodes[obj.id]=obj; break;
|
||||
case "way": this.ways[obj.id]=obj; break;
|
||||
case "relation": this.relations[obj.id]=obj; break;
|
||||
}
|
||||
},
|
||||
|
||||
getNode:function(id) {
|
||||
// summary: Return a node by id.
|
||||
return this.nodes[id]; // iD.Node
|
||||
},
|
||||
getWay:function(id) {
|
||||
// summary: Return a way by id.
|
||||
return this.ways[id]; // iD.Way
|
||||
},
|
||||
getRelation:function(id) {
|
||||
// summary: Return a relation by id.
|
||||
return this.relations[id]; // iD.Relation
|
||||
},
|
||||
|
||||
_getOrCreate:function(id,type) {
|
||||
// summary: Return an entity if it exists: if not, create an empty one with the given id, and return that.
|
||||
@@ -75,52 +50,45 @@ declare("iD.Connection", null, {
|
||||
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, lang.hitch(this,this._assign) ));
|
||||
perform(new iD.actions.CreateEntityAction(node, _.bind(this._assign, this) ));
|
||||
return node; // iD.Node
|
||||
},
|
||||
|
||||
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, lang.hitch(this,this._assign) ));
|
||||
perform(new iD.actions.CreateEntityAction(way, _.bind(this._assign, this) ));
|
||||
return way;
|
||||
},
|
||||
|
||||
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, lang.hitch(this,this._assign) ));
|
||||
perform(new iD.actions.CreateEntityAction(relation, _.bind(this._assign, this) ));
|
||||
return relation;
|
||||
},
|
||||
|
||||
markClean:function() {
|
||||
// summary: Mark the connection as clean (i.e. there's no new data to be saved).
|
||||
this.modified=false;
|
||||
},
|
||||
markDirty:function() {
|
||||
// summary: Mark the connection as dirty (i.e. there's data to be saved).
|
||||
this.modified=true;
|
||||
},
|
||||
isDirty:function() {
|
||||
// summary: Is the connection dirty?
|
||||
return this.modified;
|
||||
},
|
||||
|
||||
getObjectsByBbox:function(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.
|
||||
var o={ poisInside: [], poisOutside: [],
|
||||
waysInside: [], waysOutside: [] };
|
||||
for (var id in this.ways) {
|
||||
var way=this.ways[id];
|
||||
if (way.within(left,right,top,bottom)) { o.waysInside.push(way); }
|
||||
else { o.waysOutside.push(way); }
|
||||
}
|
||||
this.pois.each(function(node,v) {
|
||||
if (node.within(left,right,top,bottom)) { o.poisInside.push(node); }
|
||||
else { o.poisOutside.push(node); }
|
||||
});
|
||||
return o;
|
||||
},
|
||||
getObjectsByBbox:function(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.
|
||||
var o = {
|
||||
poisInside: [],
|
||||
poisOutside: [],
|
||||
waysInside: [],
|
||||
waysOutside: []
|
||||
};
|
||||
for (var id in this.ways) {
|
||||
var way = this.ways[id];
|
||||
if (way.within(left,right,top,bottom)) { o.waysInside.push(way); }
|
||||
else { o.waysOutside.push(way); }
|
||||
}
|
||||
_.each(this.pois, function(node) {
|
||||
if (node.within(left,right,top,bottom)) { o.poisInside.push(node); }
|
||||
else { o.poisOutside.push(node); }
|
||||
});
|
||||
return o;
|
||||
},
|
||||
|
||||
// ---------------
|
||||
// Redraw handling
|
||||
@@ -132,94 +100,95 @@ declare("iD.Connection", null, {
|
||||
|
||||
refreshMaps:function() {
|
||||
// summary: Redraw all the Map objects that take data from this Connection.
|
||||
array.forEach(this.maps, function(map) {
|
||||
_.each(this.maps, function(map) {
|
||||
map.updateUIs(false,true);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
refreshEntity:function(_entity) {
|
||||
// summary: Redraw a particular entity on all the Map objects that take data from this Connection.
|
||||
array.forEach(this.maps, function(map) {
|
||||
_.each(this.maps, function(map) {
|
||||
map.refreshUI(_entity);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// ------------
|
||||
// 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].hasParentWays()) {
|
||||
this.pois.remove(nodelist[i]);
|
||||
if (nodelist[i].entity.hasParentWays()) {
|
||||
delete this.pois[nodelist[i]._id];
|
||||
} else {
|
||||
this.pois.put(nodelist[i],true);
|
||||
this.pois[nodelist[i]._id] = nodelist[i];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
getPOIs:function() {
|
||||
// summary: Return a list of all the POIs in this Connection.
|
||||
return this.pois.keys(); // Array
|
||||
return _.values(this.pois);
|
||||
},
|
||||
|
||||
|
||||
registerPOI:function(node) {
|
||||
// summary: Register a node as a POI (not in a way).
|
||||
this.pois.put(node,true);
|
||||
this.pois[node._id] = node;
|
||||
},
|
||||
|
||||
|
||||
unregisterPOI:function(node) {
|
||||
// summary: Mark a node as no longer being a POI (it's now in a way).
|
||||
this.pois.remove(node);
|
||||
delete this.pois[node._id];
|
||||
},
|
||||
|
||||
// ----------
|
||||
// OSM parser
|
||||
|
||||
loadFromAPI:function(left,right,top,bottom) {
|
||||
// summary: Request data within the bbox from an external OSM server. Currently hardcoded
|
||||
// to use Overpass API (which has the relevant CORS headers).
|
||||
var url="http://www.overpass-api.de/api/xapi?map?bbox="+left+","+bottom+","+right+","+top;
|
||||
xhr.get({ url: url,
|
||||
headers: { "X-Requested-With": null },
|
||||
load: lang.hitch(this, "_processOSM") });
|
||||
},
|
||||
loadFromAPI:function(left,right,top,bottom) {
|
||||
// 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]);
|
||||
},
|
||||
|
||||
loadFromURL:function(url) {
|
||||
// summary: Load all data from a given URL.
|
||||
xhr.get({ url: url, load: lang.hitch(this, "_processOSM") });
|
||||
$.ajax({
|
||||
url: url,
|
||||
context: this,
|
||||
headers: { "X-Requested-With": null },
|
||||
success: this._processOSM
|
||||
});
|
||||
},
|
||||
|
||||
_processOSM:function(result) {
|
||||
var jsdom = DomParser.parse(result).childNodes[1];
|
||||
_processOSM:function(dom) {
|
||||
// var jsdom = $.parseXML(result).childNodes[1];
|
||||
var nodelist = [];
|
||||
for (var i in jsdom.childNodes) {
|
||||
var obj=jsdom.childNodes[i];
|
||||
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,
|
||||
getAttribute(obj,'id'),
|
||||
getAttribute(obj,'lat'),
|
||||
getAttribute(obj,'lon'),
|
||||
getTags(obj));
|
||||
this._assign(node);
|
||||
case "node":
|
||||
var node = new iD.Node(this,
|
||||
+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),
|
||||
getTags(obj));
|
||||
var way = new iD.Way(this,
|
||||
getAttribute(obj,'id'),
|
||||
getNodes(obj,this),
|
||||
getTags(obj));
|
||||
this._assign(way);
|
||||
break;
|
||||
|
||||
case "relation":
|
||||
var relation = new iD.Relation(this,
|
||||
getAttribute(obj,'id'),
|
||||
getMembers(obj,this),
|
||||
getTags(obj));
|
||||
var relation = new iD.Relation(this,
|
||||
getAttribute(obj,'id'),
|
||||
getMembers(obj,this),
|
||||
getTags(obj));
|
||||
this._assign(relation);
|
||||
break;
|
||||
}
|
||||
@@ -229,56 +198,43 @@ declare("iD.Connection", null, {
|
||||
if (this.callback) { this.callback(); }
|
||||
|
||||
// Private functions to parse DOM created from XML file
|
||||
function filterNodeName(n) {
|
||||
return function(item) {
|
||||
return item.nodeName === n;
|
||||
};
|
||||
}
|
||||
|
||||
function getAttribute(obj,name) {
|
||||
var result=array.filter(obj.attributes,function(item) {
|
||||
return item.nodeName==name;
|
||||
});
|
||||
return result[0].nodeValue;
|
||||
return _.find(obj.attributes, filterNodeName(name)).nodeValue;
|
||||
}
|
||||
|
||||
function getTags(obj) {
|
||||
var tags={};
|
||||
array.forEach(obj.childNodes,function(item) {
|
||||
if (item.nodeName=='tag') {
|
||||
tags[getAttribute(item,'k')]=getAttribute(item,'v');
|
||||
}
|
||||
});
|
||||
return tags;
|
||||
return _(obj.childNodes).chain()
|
||||
.filter(filterNodeName('tag'))
|
||||
.map(function(item) {
|
||||
return [getAttribute(item,'k'), getAttribute(item,'v')];
|
||||
}).object().value();
|
||||
}
|
||||
|
||||
function getNodes(obj,conn) {
|
||||
var nodes=[];
|
||||
array.forEach(obj.childNodes,function(item) {
|
||||
if (item.nodeName=='nd') {
|
||||
var id=getAttribute(item,'ref');
|
||||
nodes.push(conn.getNode(id));
|
||||
}
|
||||
});
|
||||
return nodes;
|
||||
return _(obj.childNodes).chain()
|
||||
.filter(filterNodeName('nd'))
|
||||
.map(function(item) {
|
||||
return conn.nodes[getAttribute(item,'ref')];
|
||||
}).value();
|
||||
}
|
||||
|
||||
function getMembers(obj,conn) {
|
||||
var members=[];
|
||||
array.forEach(obj.childNodes,function(item) {
|
||||
if (item.nodeName=='member') {
|
||||
var id =getAttribute(item,'ref');
|
||||
var type=getAttribute(item,'type');
|
||||
var role=getAttribute(item,'role');
|
||||
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);
|
||||
members.push(new iD.RelationMember(obj,role));
|
||||
}
|
||||
});
|
||||
return members;
|
||||
var obj = conn._getOrCreate(id,type);
|
||||
return new iD.RelationMember(obj,role);
|
||||
}).value();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// End of module
|
||||
});
|
||||
};
|
||||
|
||||
+3
-5
@@ -1,5 +1,3 @@
|
||||
// iD/Controller.js
|
||||
|
||||
define(['dojo/_base/declare','dojo/on','iD/actions/UndoStack'], function(declare,on){
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
@@ -10,7 +8,7 @@ declare("iD.Controller", null, {
|
||||
map: null, // current Map
|
||||
stepper: null, // current StepPane
|
||||
undoStack: null, // main undoStack
|
||||
|
||||
|
||||
constructor:function(_map) {
|
||||
// summary: The Controller marshalls ControllerStates and passes events to them.
|
||||
this.map=_map;
|
||||
@@ -21,7 +19,7 @@ declare("iD.Controller", null, {
|
||||
// summary: Set reference for the singleton-like class for the step-by-step instruction panel.
|
||||
this.stepper=_stepper;
|
||||
},
|
||||
|
||||
|
||||
setState:function(newState) {
|
||||
// summary: Enter a new ControllerState, firing exitState on the old one, and enterState on the new one.
|
||||
if (newState==this.state) { return; }
|
||||
@@ -34,7 +32,7 @@ declare("iD.Controller", null, {
|
||||
newState.enterState();
|
||||
on.emit(window, "enterState", { bubbles: true, cancelable: true, state: this.state.stateNameAsArray() });
|
||||
},
|
||||
|
||||
|
||||
entityMouseEvent:function(event,entityUI) {
|
||||
// summary: Pass a MouseEvent on an EntityUI (e.g. clicking a way) to the current ControllerState.
|
||||
if (!this.state) { return; }
|
||||
|
||||
+36
-120
@@ -1,164 +1,80 @@
|
||||
// iD/Entity.js
|
||||
// Entity classes for iD
|
||||
if (typeof iD === 'undefined') iD = {};
|
||||
|
||||
define(['dojo/_base/declare','dojo/_base/array','dojo/_base/lang',
|
||||
'iD/actions/AddNodeToWayAction','iD/actions/MoveNodeAction'
|
||||
], function(declare,array,lang){
|
||||
iD.Entity = function() {
|
||||
this.parents = {};
|
||||
// The ID locally
|
||||
this._id = iD.Util.id();
|
||||
this.connection = null;
|
||||
// The ID in OSM terms
|
||||
this.id = NaN;
|
||||
this.loaded = false;
|
||||
this.entityType = '';
|
||||
this.modified = false;
|
||||
this.deleted = false;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Entity base class
|
||||
|
||||
declare("iD.Entity", null, {
|
||||
|
||||
connection: null,
|
||||
id: NaN,
|
||||
loaded: false,
|
||||
tags: null,
|
||||
entityType: '',
|
||||
parents: null,
|
||||
modified: false,
|
||||
deleted: false,
|
||||
MAINKEYS: ['highway','amenity','railway','waterway'],
|
||||
|
||||
constructor:function() {
|
||||
// summary: The base class for an entity (way, node or relation).
|
||||
this.tags={};
|
||||
this.parents=new Hashtable();
|
||||
},
|
||||
|
||||
iD.Entity.prototype = {
|
||||
isType:function(type) {
|
||||
// summary: Is this entity of the specified type ('node','way','relation')?
|
||||
return this.entityType==type; // Boolean
|
||||
return this.entityType === type;
|
||||
},
|
||||
|
||||
toString:function() {
|
||||
return this.entityType+"."+this.id;
|
||||
return this.entityType + " . " + this.id;
|
||||
},
|
||||
|
||||
// --------------------------------
|
||||
// Provoke redraw and other changes
|
||||
|
||||
refresh:function() {
|
||||
// summary: Ask the connection to provoke redraw and other changes.
|
||||
this.connection.refreshEntity(this);
|
||||
},
|
||||
|
||||
// ---------------
|
||||
// Clean and dirty
|
||||
|
||||
_markClean:function() {
|
||||
// summary: Mark entity as clean. Should only be called from UndoableEntityAction.
|
||||
this.modified=false;
|
||||
},
|
||||
_markDirty:function() {
|
||||
// summary: Mark entity as dirty. Should only be called from UndoableEntityAction.
|
||||
this.modified=true;
|
||||
},
|
||||
isDirty:function() {
|
||||
// summary: Is the entity dirty?
|
||||
return this.modified; // Boolean
|
||||
},
|
||||
|
||||
// --------
|
||||
// Deletion
|
||||
|
||||
setDeletedState:function(isDeleted) {
|
||||
// summary: Mark entity as deleted or not.
|
||||
this.deleted=isDeleted;
|
||||
},
|
||||
|
||||
// -------------------------------------
|
||||
// Bounding box check (to be overridden)
|
||||
|
||||
within:function(left,right,top,bottom) {
|
||||
within:function(left, right, top, bottom) {
|
||||
// summary: Is the entity within the specified bbox?
|
||||
return !this.deleted; // Boolean
|
||||
},
|
||||
|
||||
// -------------
|
||||
// Tag functions
|
||||
|
||||
getTagsHash:function() {
|
||||
// summary: Tag getter.
|
||||
// returns: The tags hash (reference to the actual object property, not a copy).
|
||||
return this.tags; // Object
|
||||
},
|
||||
|
||||
numTags:function() {
|
||||
// summary: Count how many tags this entity has.
|
||||
var c=0;
|
||||
for (var i in this.tags) { c++; }
|
||||
return c; // int
|
||||
},
|
||||
|
||||
friendlyName:function() {
|
||||
// summary: Rough-and-ready function to return a human-friendly name
|
||||
// for the object. Really just a placeholder for something better.
|
||||
// returns: A string such as 'river' or 'Fred's House'.
|
||||
if (this.numTags()===0) { return ''; }
|
||||
var n=[];
|
||||
if (this.tags.name) { n.push(this.tags.name); }
|
||||
if (this.tags.ref) { n.push(this.tags.ref); }
|
||||
if (n.length===0) {
|
||||
for (var i=0; i<this.MAINKEYS.length; i++) {
|
||||
if (this.tags[this.MAINKEYS[i]]) { n.push(this.tags[this.MAINKEYS[i]]); break; }
|
||||
}
|
||||
}
|
||||
return n.length===0 ? 'unknown' : n.join('; '); // String
|
||||
},
|
||||
|
||||
// ---------------
|
||||
// Parent-handling
|
||||
|
||||
addParent:function(entity) {
|
||||
addParent: function(entity) {
|
||||
// summary: Record a parent (a relation or way which contains this entity).
|
||||
this.parents.put(entity,true);
|
||||
this.parents[entity._id] = entity;
|
||||
},
|
||||
removeParent:function(entity) {
|
||||
removeParent: function(entity) {
|
||||
// summary: Remove a parent (e.g. when node removed from a way).
|
||||
this.parents.remove(_entity);
|
||||
delete this.parents[entity._id];
|
||||
},
|
||||
hasParent:function(entity) {
|
||||
hasParent: function(entity) {
|
||||
// summary: Does this entity have the specified parent (e.g. is it in a certain relation)?
|
||||
return this.parents.containsKey(entity); // Boolean
|
||||
return !!this.parents[entity._id];
|
||||
},
|
||||
parentObjects:function() {
|
||||
parentObjects: function() {
|
||||
// summary: List of all parents of this entity.
|
||||
return this.parents.keys(); // Boolean
|
||||
return _.values(this.parents);
|
||||
},
|
||||
hasParentWays:function() {
|
||||
hasParentWays: function() {
|
||||
// summary: Does this entity have any parents which are ways?
|
||||
var p=this.parentObjects();
|
||||
for (var i in p) {
|
||||
if (p[i].entityType=='way') { return true; }
|
||||
}
|
||||
return false; // Boolean
|
||||
return !!_.find(this.parentObjects(), function(p) {
|
||||
return p.entityType === 'way';
|
||||
});
|
||||
},
|
||||
parentWays:function() {
|
||||
parentWays: function() {
|
||||
// summary: Return an array of all ways that this entity is a member of.
|
||||
return this._parentObjectsOfClass('way'); // Array
|
||||
},
|
||||
parentRelations:function() {
|
||||
parentRelations: function() {
|
||||
// summary: Return an array of all relations that this entity is a member of.
|
||||
return this._parentObjectsOfClass('relation'); // Array
|
||||
},
|
||||
_parentObjectsOfClass:function(_class) {
|
||||
var p=this.parentObjects(), c=[];
|
||||
for (var i in p) {
|
||||
if (p[i].entityType==_class) { c.push(p[i]); }
|
||||
}
|
||||
return c;
|
||||
_parentObjectsOfClass: function(_class) {
|
||||
return _.filter(this.parentObjects(), function(p) {
|
||||
return p.entityType === _class;
|
||||
});
|
||||
}
|
||||
// Halcyon also implements:
|
||||
// removeFromParents()
|
||||
// hasParents()
|
||||
// findParentRelationsOfType(type,role)
|
||||
// getRelationMemberships()
|
||||
// countParentObjects(within)
|
||||
// memberships()
|
||||
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// End of module
|
||||
});
|
||||
};
|
||||
|
||||
+41
-45
@@ -1,64 +1,60 @@
|
||||
// iD/Node.js
|
||||
if (typeof iD === 'undefined') iD = {};
|
||||
|
||||
define(['dojo/_base/declare','dojo/_base/array','dojo/_base/lang',
|
||||
'iD/Entity','iD/actions/AddNodeToWayAction','iD/actions/MoveNodeAction'
|
||||
], function(declare,array,lang){
|
||||
iD.Node = function(conn, id, lat, lon, tags, loaded) {
|
||||
// summary: An OSM node.
|
||||
this.entityType = 'node';
|
||||
this.connection = conn;
|
||||
this.id = id;
|
||||
this._id = iD.Util.id();
|
||||
this.entity = new iD.Entity();
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.tags = tags;
|
||||
this.loaded = (loaded === undefined) ? true : loaded;
|
||||
this.project();
|
||||
this.modified = this.id < 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Node class
|
||||
|
||||
declare("iD.Node", [iD.Entity], {
|
||||
lat:NaN,
|
||||
latp:NaN,
|
||||
lon:NaN,
|
||||
entityType:"node",
|
||||
|
||||
constructor:function(conn,id,lat,lon,tags,loaded) {
|
||||
// summary: An OSM node.
|
||||
this.connection=conn;
|
||||
this.id=Number(id);
|
||||
this.lat=Number(lat);
|
||||
this.lon=Number(lon);
|
||||
this.tags=tags;
|
||||
this.loaded=(loaded===undefined) ? true : loaded;
|
||||
this.project();
|
||||
this.modified=this.id<0;
|
||||
},
|
||||
|
||||
project:function() {
|
||||
iD.Node.prototype = {
|
||||
project: function() {
|
||||
// summary: Update the projected latitude value (this.latp) from the latitude (this.lat).
|
||||
this.latp=180/Math.PI * Math.log(Math.tan(Math.PI/4+this.lat*(Math.PI/180)/2));
|
||||
this.latp = 180/Math.PI *
|
||||
Math.log(Math.tan(Math.PI/4+this.lat*(Math.PI/180)/2));
|
||||
},
|
||||
latp2lat:function(a) {
|
||||
latp2lat: function(a) {
|
||||
// summary: Get a latitude from a projected latitude.
|
||||
// returns: Latitude.
|
||||
return 180/Math.PI * (2 * Math.atan(Math.exp(a*Math.PI/180)) - Math.PI/2); // Number
|
||||
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) && !this.deleted; },
|
||||
within: function(left, right, top, bottom) {
|
||||
return (this.lon >= left) &&
|
||||
(this.lon <= right) &&
|
||||
(this.lat >= bottom) &&
|
||||
(this.lat <= top);
|
||||
},
|
||||
|
||||
refresh:function() {
|
||||
var ways=this.parentWays();
|
||||
var conn=this.connection;
|
||||
array.forEach(ways,function(way) { conn.refreshEntity(way); });
|
||||
refresh: function() {
|
||||
var ways = this.parentWays();
|
||||
_.each(ways, _.bind(function(way) { this.connection.refreshEntity(way); }, this));
|
||||
this.connection.refreshEntity(this);
|
||||
},
|
||||
|
||||
doSetLonLatp:function(lon,latproj,performAction) {
|
||||
doSetLonLatp: function(lon,latproj,performAction) {
|
||||
// summary: Change the position of a node, using an undo stack.
|
||||
performAction(new iD.actions.MoveNodeAction(this, this.latp2lat(latproj), lon, lang.hitch(this,this._setLatLonImmediate) ));
|
||||
performAction(new iD.actions.MoveNodeAction(this,
|
||||
this.latp2lat(latproj),
|
||||
lon,
|
||||
lang.hitch(this,this._setLatLonImmediate)));
|
||||
},
|
||||
|
||||
_setLatLonImmediate:function(lat,lon) {
|
||||
_setLatLonImmediate: function(lat,lon) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.project();
|
||||
var ways = this.parentWays();
|
||||
for (var i=0; i<ways.length; i++) { ways[i].expandBbox(this); }
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// End of module
|
||||
});
|
||||
_.each(ways, _.bind(function(way) {
|
||||
way.expandBbox(this);
|
||||
}, this));
|
||||
}
|
||||
};
|
||||
|
||||
+18
-41
@@ -1,43 +1,20 @@
|
||||
// iD/Relation.js
|
||||
if (typeof iD === 'undefined') iD = {};
|
||||
|
||||
define(['dojo/_base/declare','dojo/_base/array','dojo/_base/lang',
|
||||
'iD/Entity','iD/actions/AddNodeToWayAction','iD/actions/MoveNodeAction'
|
||||
], function(declare,array,lang){
|
||||
iD.Relation = function(conn, id, members, tags, loaded) {
|
||||
this.entityType = 'relation';
|
||||
this.connection = conn;
|
||||
this.id = id;
|
||||
this._id = iD.Util.id();
|
||||
this.members = members;
|
||||
this.tags = tags;
|
||||
this.modified = this.id < 0;
|
||||
this.loaded = (loaded === undefined) ? true : loaded;
|
||||
_.each(members, _.bind(function(member) {
|
||||
member.entity.entity.addParent(this);
|
||||
}, this));
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Relation class
|
||||
|
||||
declare("iD.Relation", [iD.Entity], {
|
||||
members:null,
|
||||
entityType:"relation",
|
||||
|
||||
constructor:function(conn,id,members,tags,loaded) {
|
||||
// summary: An OSM relation.
|
||||
this.connection=conn;
|
||||
this.id=Number(id);
|
||||
this.members=members;
|
||||
this.tags=tags;
|
||||
this.modified=this.id<0;
|
||||
this.loaded=(loaded===undefined) ? true : loaded;
|
||||
var r=this; array.forEach(members,function(member) {
|
||||
member.entity.addParent(r);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// RelationMember class
|
||||
|
||||
declare("iD.RelationMember", [], {
|
||||
entity:null,
|
||||
role:"",
|
||||
constructor:function(entity,role) {
|
||||
// summary: An object containing both the entity that is in the relation, and its role.
|
||||
this.entity=entity;
|
||||
this.role=role;
|
||||
}
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// End of module
|
||||
});
|
||||
iD.RelationMember = function(entity, role) {
|
||||
this.entity = entity;
|
||||
this.role = role;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
if (typeof iD === 'undefined') iD = {};
|
||||
|
||||
iD.Util = {};
|
||||
|
||||
iD.Util._id = 0;
|
||||
|
||||
iD.Util.id = function() {
|
||||
return iD.Util._id++;
|
||||
};
|
||||
|
||||
iD.Util.friendlyName = function(entity) {
|
||||
// summary: Rough-and-ready function to return a human-friendly name
|
||||
// for the object. Really just a placeholder for something better.
|
||||
// returns: A string such as 'river' or 'Fred's House'.
|
||||
if (_.isEmpty(entity.tags)) { return ''; }
|
||||
|
||||
var mainkeys = ['highway','amenity','railway','waterway'];
|
||||
var n = _.compact([entity.tags.name, entity.tags.ref]);
|
||||
|
||||
if (!n.length) {
|
||||
var k = _.find(mainkeys, function(m) {
|
||||
return !!entity.tags[m];
|
||||
});
|
||||
if (k) n.push(entity.tags[k]);
|
||||
}
|
||||
|
||||
return n.length === 0 ? 'unknown' : n.join('; ');
|
||||
};
|
||||
+113
-138
@@ -1,153 +1,128 @@
|
||||
// iD/Way.js
|
||||
if (typeof iD === 'undefined') iD = {};
|
||||
|
||||
define(['dojo/_base/declare','dojo/_base/array','dojo/_base/lang',
|
||||
'iD/Entity','iD/actions/AddNodeToWayAction','iD/actions/MoveNodeAction'
|
||||
], function(declare,array,lang){
|
||||
iD.Way = function(conn, id, nodes, tags, loaded) {
|
||||
// summary: An OSM way.
|
||||
this.connection = conn;
|
||||
this.entityType = 'way';
|
||||
this.id = id;
|
||||
this._id = iD.Util.id();
|
||||
this.nodes = nodes || [];
|
||||
this.deleted = false;
|
||||
this.entity = new iD.Entity();
|
||||
this.tags = tags || {};
|
||||
this.loaded = (loaded === undefined) ? true : loaded;
|
||||
this.modified = this.id < 0;
|
||||
_.each(nodes, _.bind(function(node) {
|
||||
node.entity.addParent(this);
|
||||
}, this));
|
||||
this._calculateBbox();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Way class
|
||||
iD.Way.prototype = {
|
||||
isClosed:function() {
|
||||
// summary: Is this a closed way (first and last nodes the same)?
|
||||
return this.nodes[this.nodes.length - 1] === this.nodes[0]; // Boolean
|
||||
},
|
||||
|
||||
declare("iD.Way", [iD.Entity], {
|
||||
nodes: null,
|
||||
entityType: "way",
|
||||
edgel: NaN,
|
||||
edger: NaN,
|
||||
edget: NaN,
|
||||
edgeb: NaN,
|
||||
isType:function(type) {
|
||||
// summary: Is this a 'way' (always true), an 'area' (closed) or a 'line' (unclosed)?
|
||||
if (type === 'way') return true;
|
||||
if (type === 'area') return this.isClosed();
|
||||
if (type === 'line') return !(this.isClosed());
|
||||
return false; // Boolean
|
||||
},
|
||||
|
||||
constructor:function(conn,id,nodes,tags,loaded) {
|
||||
// summary: An OSM way.
|
||||
this.connection=conn;
|
||||
this.id=Number(id);
|
||||
this.nodes=nodes;
|
||||
this.tags=tags;
|
||||
this.loaded=(loaded==undefined) ? true : loaded;
|
||||
this.modified=this.id<0;
|
||||
var w=this; array.forEach(nodes,function(node) {
|
||||
node.addParent(w);
|
||||
});
|
||||
this._calculateBbox();
|
||||
},
|
||||
|
||||
length:function() {
|
||||
// summary: Return the number of nodes in the way.
|
||||
return this.nodes.length; // int
|
||||
},
|
||||
|
||||
isClosed:function() {
|
||||
// summary: Is this a closed way (first and last nodes the same)?
|
||||
return this.nodes[this.nodes.length-1]==this.nodes[0]; // Boolean
|
||||
},
|
||||
// ---------------------
|
||||
// Bounding-box handling
|
||||
within:function(left,right,top,bottom) {
|
||||
// TODO invert and just return
|
||||
if (!this.edgel ||
|
||||
(this.edgel<left && this.edger<left ) ||
|
||||
(this.edgel>right && this.edger>right ) ||
|
||||
(this.edgeb<bottom && this.edget<bottom) ||
|
||||
(this.edgeb>top && this.edgeb>top )) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
isType:function(_type) {
|
||||
// summary: Is this a 'way' (always true), an 'area' (closed) or a 'line' (unclosed)?
|
||||
switch (_type) {
|
||||
case 'way': return true;
|
||||
case 'area': return this.isClosed;
|
||||
case 'line': return !(this.isClosed);
|
||||
}
|
||||
return false; // Boolean
|
||||
},
|
||||
_calculateBbox:function() {
|
||||
this.edgel = 999999; this.edger = -999999;
|
||||
this.edgeb = 999999; this.edget = -999999;
|
||||
_.each(this.nodes, _.bind(function(n) { this.expandBbox(n); }, this));
|
||||
},
|
||||
|
||||
getNode:function(index) {
|
||||
// summary: Return the node at the given position.
|
||||
return this.nodes[index]; // iD.Node
|
||||
},
|
||||
getFirstNode:function() {
|
||||
// summary: Return the first node in the way.
|
||||
return this.nodes[0]; // iD.Node
|
||||
},
|
||||
getLastNode:function() {
|
||||
// summary: Return the last node in the way.
|
||||
return this.nodes[this.nodes.length-1]; // iD.Node
|
||||
},
|
||||
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);
|
||||
},
|
||||
|
||||
// ---------------------
|
||||
// Bounding-box handling
|
||||
// --------------
|
||||
// Action callers
|
||||
|
||||
within:function(left,right,top,bottom) {
|
||||
if (!this.edgel ||
|
||||
(this.edgel<left && this.edger<left ) ||
|
||||
(this.edgel>right && this.edger>right ) ||
|
||||
(this.edgeb<bottom && this.edget<bottom) ||
|
||||
(this.edgeb>top && this.edgeb>top ) || this.deleted) { return false; }
|
||||
return true;
|
||||
},
|
||||
doAppendNode:function(node, performAction) {
|
||||
// summary: Add a node to the end of the way, using an undo stack.
|
||||
// returns: New length of the way.
|
||||
if (node!=this.getLastNode()) performAction(new iD.actions.AddNodeToWayAction(this, node, this.nodes, -1, true));
|
||||
return this.nodes.length + 1; // int
|
||||
},
|
||||
|
||||
_calculateBbox:function() {
|
||||
this.edgel=999999; this.edger=-999999;
|
||||
this.edgeb=999999; this.edget=-999999;
|
||||
for (var i in this.nodes) { this.expandBbox(this.nodes[i]); }
|
||||
},
|
||||
|
||||
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);
|
||||
},
|
||||
doPrependNode:function(node, performAction) {
|
||||
// summary: Add a node to the start of the way, using an undo stack.
|
||||
// returns: New length of the way.
|
||||
if (node!=this.nodes[0]) performAction(new iD.actions.AddNodeToWayAction(this, node, this.nodes, 0, true));
|
||||
return this.nodes.length + 1; // int
|
||||
},
|
||||
|
||||
// --------------
|
||||
// Action callers
|
||||
doInsertNode:function(index, node, performAction) {
|
||||
// summary: Add a node at a given index within the way, using an undo stack.
|
||||
if (index > 0 && this.nodes[index - 1]==node) return;
|
||||
if (index < this.nodes.length - 1 && this.nodes[index]==node) return;
|
||||
performAction(new iD.actions.AddNodeToWayAction(this, node, this.nodes, index, false));
|
||||
},
|
||||
|
||||
doAppendNode:function(node, performAction) {
|
||||
// summary: Add a node to the end of the way, using an undo stack.
|
||||
// returns: New length of the way.
|
||||
if (node!=this.getLastNode()) performAction(new iD.actions.AddNodeToWayAction(this, node, this.nodes, -1, true));
|
||||
return this.nodes.length + 1; // int
|
||||
},
|
||||
doInsertNodeAtClosestPosition:function(newNode, isSnap, performAction) {
|
||||
// summary: Add a node into whichever segment of the way is nearest, using an undo stack.
|
||||
// isSnap: Boolean Should the node position be snapped to be exactly on the segment?
|
||||
// returns: The index at which the node was inserted.
|
||||
var closestProportion = 1,
|
||||
newIndex = 0,
|
||||
snapped;
|
||||
|
||||
doPrependNode:function(node, performAction) {
|
||||
// summary: Add a node to the start of the way, using an undo stack.
|
||||
// returns: New length of the way.
|
||||
if (node!=this.getFirstNode()) performAction(new iD.actions.AddNodeToWayAction(this, node, this.nodes, 0, true));
|
||||
return this.nodes.length + 1; // int
|
||||
},
|
||||
for (var i = 0; i < this.nodes.length - 1; i++) {
|
||||
var node1 = this.nodes[i];
|
||||
var node2 = this.nodes[i + 1];
|
||||
var directDist = this._pythagoras(node1, node2);
|
||||
var viaNewDist = this._pythagoras(node1, newNode) +
|
||||
this._pythagoras(node2, newNode);
|
||||
var proportion = Math.abs(viaNewDist/directDist - 1);
|
||||
if (proportion < closestProportion) {
|
||||
newIndex = i+1;
|
||||
closestProportion = proportion;
|
||||
snapped = this._calculateSnappedPoint(node1, node2, newNode);
|
||||
}
|
||||
}
|
||||
|
||||
doInsertNode:function(index, node, performAction) {
|
||||
// summary: Add a node at a given index within the way, using an undo stack.
|
||||
if (index>0 && this.getNode(index-1)==node) return;
|
||||
if (index<this.nodes.length-1 && this.getNode(index)==node) return;
|
||||
performAction(new iD.actions.AddNodeToWayAction(this, node, this.nodes, index, false));
|
||||
},
|
||||
|
||||
doInsertNodeAtClosestPosition:function(newNode, isSnap, performAction) {
|
||||
// summary: Add a node into whichever segment of the way is nearest, using an undo stack.
|
||||
// isSnap: Boolean Should the node position be snapped to be exactly on the segment?
|
||||
// returns: The index at which the node was inserted.
|
||||
var closestProportion = 1;
|
||||
var newIndex = 0;
|
||||
var snapped;
|
||||
// splice in new node
|
||||
if (isSnap) { newNode.doSetLonLatp(snapped.x, snapped.y, performAction); }
|
||||
this.doInsertNode(newIndex, newNode, performAction);
|
||||
return newIndex; // int
|
||||
},
|
||||
|
||||
for (var i=0; i<this.nodes.length-1; i++) {
|
||||
var node1 = this.getNode(i);
|
||||
var node2 = this.getNode(i+1);
|
||||
var directDist = this._pythagoras(node1, node2);
|
||||
var viaNewDist = this._pythagoras(node1, newNode) + this._pythagoras(node2, newNode);
|
||||
var proportion = Math.abs(viaNewDist/directDist - 1);
|
||||
if (proportion < closestProportion) {
|
||||
newIndex = i+1;
|
||||
closestProportion = proportion;
|
||||
snapped = this._calculateSnappedPoint(node1, node2, newNode);
|
||||
}
|
||||
}
|
||||
_pythagoras:function(node1, node2) {
|
||||
return (Math.sqrt(Math.pow(node1.lon-node2.lon,2) +
|
||||
Math.pow(node1.latp-node2.latp,2)));
|
||||
},
|
||||
|
||||
// splice in new node
|
||||
if (isSnap) { newNode.doSetLonLatp(snapped.x, snapped.y, performAction); }
|
||||
this.doInsertNode(newIndex, newNode, performAction);
|
||||
return newIndex; // int
|
||||
},
|
||||
|
||||
_pythagoras:function(node1, node2) { return (Math.sqrt(Math.pow(node1.lon-node2.lon,2)+Math.pow(node1.latp-node2.latp,2))); },
|
||||
_calculateSnappedPoint:function(node1, node2, newNode) {
|
||||
var w = node2.lon - node1.lon;
|
||||
var h = node2.latp - node1.latp;
|
||||
var u = ((newNode.lon-node1.lon) * w + (newNode.latp-node1.latp) * h) / (w*w + h*h);
|
||||
return { x: node1.lon + u*w, y: node1.latp + u*h };
|
||||
},
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// End of module
|
||||
});
|
||||
_calculateSnappedPoint:function(node1, node2, newNode) {
|
||||
var w = node2.lon - node1.lon;
|
||||
var h = node2.latp - node1.latp;
|
||||
var u = ((newNode.lon-node1.lon) * w + (newNode.latp-node1.latp) * h) / (w*w + h*h);
|
||||
return { x: node1.lon + u*w, y: node1.latp + u*h };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -66,20 +66,20 @@ declare("iD.actions.UndoableEntityAction", [iD.actions.UndoableAction], {
|
||||
// summary: Mark a change to the entity ('dirtying' it).
|
||||
if (!this.initialised) this.init();
|
||||
if (!this.wasDirty) this.entity._markDirty();
|
||||
if (!this.connectionWasDirty) this.entity.connection.markDirty();
|
||||
if (!this.connectionWasDirty) this.entity.connection.modified = true;
|
||||
},
|
||||
|
||||
markClean:function() {
|
||||
// summary: If the entity was clean before, revert the dirty flag to that state.
|
||||
if (!this.initialised) this.init();
|
||||
if (!this.wasDirty) this.entity._markClean();
|
||||
if (!this.connectionWasDirty) this.entity.connection.markClean();
|
||||
if (!this.connectionWasDirty) this.entity.connection.modified = false;
|
||||
},
|
||||
|
||||
init:function() {
|
||||
// summary: Record whether or not the entity and connection were clean before this action started
|
||||
this.wasDirty = this.entity.isDirty();
|
||||
this.connectionWasDirty = this.entity.connection.isDirty();
|
||||
this.wasDirty = this.entity.modified;
|
||||
this.connectionWasDirty = this.entity.connection.modified;
|
||||
this.initialised = true;
|
||||
},
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ declare("iD.controller.edit.EditBaseState", [iD.controller.ControllerState], {
|
||||
// x: Number Screen co-ordinate.
|
||||
// y: Number Screen co-ordinate.
|
||||
// entity: iD.Entity The entity to be edited.
|
||||
var h=entity.friendlyName();
|
||||
var h = iD.Util.friendlyName(entity);
|
||||
if (h !== '') h = h + "<br/>";
|
||||
this.editortooltip = new dijit.TooltipDialog({
|
||||
content: h+"<button data-dojo-type='dijit.form.Button' type='submit'>Edit tags</button> " +
|
||||
|
||||
@@ -15,28 +15,28 @@ declare("iD.controller.edit.NoSelection", [iD.controller.edit.EditBaseState], {
|
||||
constructor:function() {
|
||||
// summary: In 'Edit object' mode but nothing selected.
|
||||
},
|
||||
|
||||
|
||||
enterState:function() {
|
||||
this.controller.stepper.hide();
|
||||
},
|
||||
|
||||
|
||||
processMouseEvent:function(event,entityUI) {
|
||||
this.inherited(arguments);
|
||||
if (!entityUI) { return this; }
|
||||
var entity=entityUI.entity;
|
||||
var entity = entityUI.entity;
|
||||
if (event.type=='click') {
|
||||
this.inherited(arguments);
|
||||
switch (entity.entityType) {
|
||||
case 'node':
|
||||
var ways=entity.parentWays();
|
||||
if (ways.length==0) { return new iD.controller.edit.SelectedPOINode(entity); }
|
||||
if (!ways.length) { return new iD.controller.edit.SelectedPOINode(entity); }
|
||||
else { return new iD.controller.edit.SelectedWayNode(entity,ways[0]); }
|
||||
break;
|
||||
case 'way':
|
||||
return new iD.controller.edit.SelectedWay(entityUI.entity, event);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Add road or shape -> DrawWay
|
||||
|
||||
The user is drawing a way.
|
||||
|
||||
|
||||
Goes to:
|
||||
-> click empty area: adds point, continues
|
||||
-> click way: adds junction, continues
|
||||
@@ -26,8 +26,8 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
|
||||
wayUI: null,
|
||||
editEnd: false,
|
||||
|
||||
constructor:function(_way) {
|
||||
this.way=_way;
|
||||
constructor: function(way) {
|
||||
this.way = way;
|
||||
},
|
||||
enterState:function() {
|
||||
this.wayUI=this.controller.map.getUI(this.way);
|
||||
@@ -42,14 +42,14 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
|
||||
this.wayUI.resetStateClass('shownodes');
|
||||
this.wayUI.redraw();
|
||||
},
|
||||
|
||||
|
||||
processMouseEvent:function(event,entityUI) {
|
||||
var entity=entityUI ? entityUI.entity : null;
|
||||
var entityType=entity ? entity.entityType : null;
|
||||
var map=this.controller.map;
|
||||
var ways;
|
||||
|
||||
if (event.type=='mouseover' && entityType=='way' && entityUI!=this.wayUI) {
|
||||
if (event.type=='mouseover' && entityType=='way' && entityUI!=this.wayUI) {
|
||||
// Mouse over way, show hover highlight
|
||||
entityUI.setStateClass('shownodeshover');
|
||||
entityUI.redraw();
|
||||
@@ -57,7 +57,7 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
|
||||
this.updateElastic(event);
|
||||
return this;
|
||||
|
||||
} else if (event.type=='mouseout' && entityType=='way' && entityUI!=this.wayUI) {
|
||||
} else if (event.type=='mouseout' && entityType=='way' && entityUI!=this.wayUI) {
|
||||
// Mouse left way, remove hover highlight
|
||||
// Find what object we're moving into
|
||||
var into=shape.byId((event.hasOwnProperty('toElement') ? event.toElement : event.relatedTarget).__gfxObject__);
|
||||
@@ -117,7 +117,7 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
|
||||
var action=this.undoAdder(); action(undo);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
} else if (event.type=='click') {
|
||||
// Click on empty space, add new node to way
|
||||
var undo=new iD.actions.CompositeUndoableAction();
|
||||
@@ -137,15 +137,15 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
|
||||
map.mouseX(event), map.mouseY(event)
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
getDrawingNode:function() {
|
||||
return (this.editEnd ? this.way.nodes[this.way.length()-1] : this.way.nodes[0]);
|
||||
},
|
||||
|
||||
|
||||
getStartNode:function() {
|
||||
return (this.editEnd ? this.way.nodes[0] : this.way.nodes[this.way.length()-1]);
|
||||
},
|
||||
|
||||
|
||||
appendNode:function(node, performAction) {
|
||||
if (this.editEnd) { this.way.doAppendNode(node, performAction); }
|
||||
else { this.way.doPrependNode(node, performAction); }
|
||||
@@ -154,13 +154,13 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
|
||||
appendNewNode:function(event, undo) {
|
||||
var map=this.controller.map;
|
||||
var node=this.getConnection().doCreateNode(
|
||||
{},
|
||||
{},
|
||||
map.coord2lat(map.mouseY(event)),
|
||||
map.coord2lon(map.mouseX(event)), lang.hitch(undo,undo.push) );
|
||||
this.appendNode(node, lang.hitch(undo,undo.push));
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Add road or shape -> NoSelection
|
||||
|
||||
The user has clicked 'Add road or shape', but hasn't yet started drawing.
|
||||
|
||||
|
||||
Goes to:
|
||||
-> click empty area: goes to shape/DrawWay
|
||||
-> click way: goes to shape/SelectedWay
|
||||
@@ -37,7 +37,7 @@ declare("iD.controller.shape.NoSelection", [iD.controller.ControllerState], {
|
||||
tag: "Set the type of the road or shape"
|
||||
},['begin','draw','tag']).highlight('begin');
|
||||
},
|
||||
|
||||
|
||||
processMouseEvent:function(event,entityUI) {
|
||||
var entity=entityUI ? entityUI.entity : null;
|
||||
var entityType=entity ? entity.entityType : null;
|
||||
@@ -70,7 +70,6 @@ declare("iD.controller.shape.NoSelection", [iD.controller.ControllerState], {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -50,13 +50,13 @@ declare("iD.renderer.EntityUI", null, {
|
||||
},
|
||||
refreshStyleList:function(tags) {
|
||||
// summary: Calculate the list of styles that apply to this UI at this zoom level.
|
||||
if (!this.styleList || !this.styleList.isValidAt(this.map.scale)) {
|
||||
if (!this.styleList || !this.styleList.isValidAt(this.map.scale)) {
|
||||
this.styleList=this.map.ruleset.getStyles(this.entity,tags,this.map.scale);
|
||||
}
|
||||
this.layer=this.styleList.layerOverride();
|
||||
if (isNaN(this.layer)) {
|
||||
this.layer=0;
|
||||
if (tags['layer']) { this.layer=Number(tags['layer']); }
|
||||
if (tags.layer) { this.layer = +tags.layer; }
|
||||
}
|
||||
|
||||
// Iterate through each subpart, drawing any styles on that layer
|
||||
@@ -78,7 +78,7 @@ declare("iD.renderer.EntityUI", null, {
|
||||
|
||||
// --------------------
|
||||
// State class handling
|
||||
|
||||
|
||||
setStateClasses:function(stateClasses) {
|
||||
// summary: Set all state classes at once, and prompt a redraw if they're different to previously,
|
||||
if (stateClasses && this.stateClasses.join(',')!=stateClasses.join(',')) {
|
||||
@@ -87,7 +87,7 @@ declare("iD.renderer.EntityUI", null, {
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
setStateClass:function(sc) {
|
||||
// summary: Set a single state class, and prompt a redraw if it wasn't set previously.
|
||||
if (this.stateClasses.indexOf(sc)==-1) {
|
||||
@@ -122,7 +122,7 @@ declare("iD.renderer.EntityUI", null, {
|
||||
// summary: Receive a mouse event (e.g. clicking on the UI), and forward it to the Controller.
|
||||
this.map.controller.entityMouseEvent(event, event.gfxTarget.source);
|
||||
event.stopPropagation();
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
+88
-77
@@ -53,7 +53,7 @@ declare("iD.renderer.Map", null, {
|
||||
edgeb: NaN, // |
|
||||
mapheight: NaN, // size of map object in pixels
|
||||
mapwidth: NaN, // |
|
||||
|
||||
|
||||
layers: null, // array-like object of Groups, one for each OSM layer
|
||||
minlayer: -5, // minimum OSM layer supported
|
||||
maxlayer: 5, // maximum OSM layer supported
|
||||
@@ -61,7 +61,7 @@ declare("iD.renderer.Map", null, {
|
||||
elastic: null, // Group for drawing elastic band
|
||||
|
||||
ruleset: null, // map style
|
||||
|
||||
|
||||
constructor:function(obj) {
|
||||
// summary: The main map display, containing the individual sprites (UIs) for each entity.
|
||||
// obj: Object An object containing .lat, .lon, .scale, .div (the name of the <div> to be used),
|
||||
@@ -75,7 +75,12 @@ declare("iD.renderer.Map", null, {
|
||||
this.wayuis={},
|
||||
this.div=document.getElementById(obj.div);
|
||||
this.surface=Gfx.createSurface(obj.div, this.mapwidth, this.mapheight);
|
||||
this.backdrop=this.surface.createRect( { x:0, y:0, width: this.mapwidth, height: this.mapheight }).setFill(new dojo.Color([255,255,245,1]));
|
||||
this.backdrop=this.surface.createRect({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.mapwidth,
|
||||
height: this.mapheight
|
||||
}).setFill(new dojo.Color([255,255,245,1]));
|
||||
this.tilegroup=this.surface.createGroup();
|
||||
this.container=this.surface.createGroup();
|
||||
this.conn=obj.connection;
|
||||
@@ -111,7 +116,7 @@ declare("iD.renderer.Map", null, {
|
||||
this.surface.connect("onmousedown", lang.hitch(this,"_mouseEvent"));
|
||||
this.surface.connect("onmouseup", lang.hitch(this,"_mouseEvent"));
|
||||
},
|
||||
|
||||
|
||||
setController:function(controller) {
|
||||
// summary: Set the controller that will handle events on the map (e.g. mouse clicks).
|
||||
this.controller=controller;
|
||||
@@ -145,9 +150,9 @@ 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];
|
||||
var collection=this.layers[layer][groupType], sub;
|
||||
switch (groupType) {
|
||||
case 'casing':
|
||||
case 'text':
|
||||
@@ -157,7 +162,7 @@ declare("iD.renderer.Map", null, {
|
||||
// Find correct sublayer, inserting if necessary
|
||||
var insertAt=collection.children.length;
|
||||
for (var i=0; i<collection.children.length; i++) {
|
||||
var sub=collection.children[i];
|
||||
sub=collection.children[i];
|
||||
if (sub.sublayer==sublayer) { return sub; }
|
||||
else if (sub.sublayer>sublayer) {
|
||||
sub=collection.createGroup();
|
||||
@@ -168,50 +173,56 @@ declare("iD.renderer.Map", null, {
|
||||
}
|
||||
sub=collection.createGroup().moveToFront();
|
||||
sub.sublayer=sublayer;
|
||||
return sub; // dojox.gfx.Group
|
||||
return sub; // dojox.gfx.Group
|
||||
},
|
||||
|
||||
|
||||
createUI:function(entity,stateClasses) {
|
||||
// summary: Create a UI (sprite) for an entity, assigning any specified state classes
|
||||
// (temporary attributes such as ':hover' or ':selected')
|
||||
var id=entity.id;
|
||||
switch (entity.entityType) {
|
||||
case 'node':
|
||||
if (!this.nodeuis[id]) { this.nodeuis[id]=new iD.renderer.NodeUI(entity,this,stateClasses); }
|
||||
else { this.nodeuis[id].setStateClasses(stateClasses).redraw(); }
|
||||
return this.nodeuis[id]; // iD.renderer.EntityUI
|
||||
case 'way':
|
||||
if (!this.wayuis[id]) { this.wayuis[id]=new iD.renderer.WayUI(entity,this,stateClasses); }
|
||||
else { this.wayuis[id].setStateClasses(stateClasses).redraw(); }
|
||||
return this.wayuis[id]; // iD.renderer.EntityUI
|
||||
}
|
||||
var id = entity.id;
|
||||
if (entity.entityType === 'node') {
|
||||
if (!this.nodeuis[id]) {
|
||||
this.nodeuis[id] = new iD.renderer.NodeUI(entity,this,stateClasses);
|
||||
} else {
|
||||
this.nodeuis[id].setStateClasses(stateClasses).redraw();
|
||||
}
|
||||
return this.nodeuis[id]; // iD.renderer.EntityUI
|
||||
} else if (entity.entityType === 'way') {
|
||||
if (!this.wayuis[id]) {
|
||||
this.wayuis[id] = new iD.renderer.WayUI(entity,this,stateClasses);
|
||||
} else {
|
||||
this.wayuis[id].setStateClasses(stateClasses).redraw();
|
||||
}
|
||||
return this.wayuis[id]; // iD.renderer.EntityUI
|
||||
}
|
||||
},
|
||||
|
||||
getUI:function(entity) {
|
||||
// summary: Return the UI for an entity, if it exists.
|
||||
switch (entity.entityType) {
|
||||
case 'node': return this.nodeuis[entity.id]; // iD.renderer.EntityUI
|
||||
case 'way': return this.wayuis[entity.id]; // iD.renderer.EntityUI
|
||||
// summary: Return the UI for an entity, if it exists.
|
||||
if (entity.entityType === 'node') {
|
||||
return this.nodeuis[entity.id]; // iD.renderer.EntityUI
|
||||
} else if (entity.entityType === 'way') {
|
||||
return this.wayuis[entity.id]; // iD.renderer.EntityUI
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
|
||||
refreshUI:function(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;
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
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 'way': if (this.wayuis[entity.id] ) { this.wayuis[entity.id].removeSprites(); delete this.wayuis[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);
|
||||
@@ -226,11 +237,12 @@ declare("iD.renderer.Map", null, {
|
||||
var way, poi;
|
||||
var o = this.conn.getObjectsByBbox(this.edgel,this.edger,this.edget,this.edgeb);
|
||||
|
||||
array.forEach(o.waysInside, function(way) {
|
||||
if (!way.loaded) return;
|
||||
if (!m.wayuis[way.id]) { m.createUI(way); }
|
||||
else if (redraw) { m.wayuis[way.id].recalculate(); m.wayuis[way.id].redraw(); }
|
||||
});
|
||||
_(o.waysInside).chain()
|
||||
.filter(function(w) { return w.loaded; })
|
||||
.each(function(way) {
|
||||
if (!m.wayuis[way.id]) { m.createUI(way); }
|
||||
else if (redraw) { m.wayuis[way.id].recalculate(); m.wayuis[way.id].redraw(); }
|
||||
});
|
||||
|
||||
if (remove) {
|
||||
array.forEach(o.waysOutside, function(way) {
|
||||
@@ -257,12 +269,12 @@ declare("iD.renderer.Map", null, {
|
||||
|
||||
// -------------
|
||||
// Zoom handling
|
||||
|
||||
|
||||
zoomIn:function() {
|
||||
// summary: Zoom in by one level (unless maximum reached).
|
||||
if (this.scale!=this.MAXSCALE) { this.changeScale(this.scale+1); }
|
||||
},
|
||||
|
||||
|
||||
zoomOut:function() {
|
||||
// summary: Zoom out by one level (unless minimum reached).
|
||||
if (this.scale!=this.MINSCALE) { this.changeScale(this.scale-1); }
|
||||
@@ -277,7 +289,7 @@ declare("iD.renderer.Map", null, {
|
||||
this.updateCoordsFromLatLon(this.centrelat,this.centrelon); // recentre
|
||||
this.updateUIs(true,true);
|
||||
},
|
||||
|
||||
|
||||
_setScaleFactor:function() {
|
||||
// summary: Calculate the scaling factor for this zoom level.
|
||||
this.scalefactor=this.MASTERSCALE/Math.pow(2,13-this.scale);
|
||||
@@ -285,12 +297,12 @@ declare("iD.renderer.Map", null, {
|
||||
|
||||
// ----------------------
|
||||
// Elastic band redrawing
|
||||
|
||||
|
||||
clearElastic:function() {
|
||||
// summary: Remove the elastic band used to draw new ways.
|
||||
this.elastic.clear();
|
||||
},
|
||||
|
||||
|
||||
drawElastic:function(x1,y1,x2,y2) {
|
||||
// summary: Draw the elastic band (for new ways) between two points.
|
||||
this.elastic.clear();
|
||||
@@ -305,7 +317,7 @@ declare("iD.renderer.Map", null, {
|
||||
// -------------
|
||||
// Tile handling
|
||||
// ** FIXME: see docs
|
||||
|
||||
|
||||
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
|
||||
@@ -320,49 +332,49 @@ declare("iD.renderer.Map", null, {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
_fetchTile:function(z,x,y) {
|
||||
// summary: Load a tile image at the given tile co-ordinates.
|
||||
var t=this.tilegroup.createImage({
|
||||
x: this.lon2coord(this.tile2lon(x)),
|
||||
y: this.lat2coord(this.tile2lat(y)),
|
||||
x: Math.floor(this.lon2coord(this.tile2lon(x))),
|
||||
y: Math.floor(this.lat2coord(this.tile2lat(y))),
|
||||
width: 256, height: 256,
|
||||
src: this._tileURL(z,x,y)
|
||||
});
|
||||
this._assignTile(z,x,y,t);
|
||||
},
|
||||
|
||||
|
||||
_getTile:function(z,x,y) {
|
||||
// summary: See if this tile is already loaded.
|
||||
if (this.tiles[z]==undefined) { return undefined; }
|
||||
if (this.tiles[z][x]==undefined) { return undefined; }
|
||||
return this.tiles[z][x][y];
|
||||
var k = z + ',' + x + ',' + y;
|
||||
return this.tiles[k];
|
||||
},
|
||||
|
||||
_assignTile:function(z,x,y,t) {
|
||||
// summary: Store a reference to the tile so we know it's loaded.
|
||||
if (this.tiles[z]==undefined) { this.tiles[z]=[]; }
|
||||
if (this.tiles[z][x]==undefined) { this.tiles[z][x]=[]; }
|
||||
this.tiles[z][x][y]=t;
|
||||
var k = z + ',' + x + ',' + y;
|
||||
if (!this.tiles[k]) {
|
||||
this.tiles[z + ',' + x + ',' + y] = t;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
_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--) {
|
||||
var byte=0;
|
||||
var mask=1<<(zoom-1);
|
||||
if ((x & mask)!=0) byte++;
|
||||
if ((y & mask)!=0) byte+=2;
|
||||
if ((x & mask) !== 0) byte++;
|
||||
if ((y & mask) !== 0) byte += 2;
|
||||
u=u+byte.toString();
|
||||
}
|
||||
return this.tilebaseURL.replace('$z',z).replace('$x',x).replace('$y',y).replace('$quadkey',u);
|
||||
},
|
||||
|
||||
|
||||
_blankTiles:function() {
|
||||
// summary: Unload all tiles and remove from the display.
|
||||
this.tilegroup.clear();
|
||||
this.tiles=[];
|
||||
this.tiles = {};
|
||||
},
|
||||
|
||||
// -------------------------------------------
|
||||
@@ -396,12 +408,12 @@ declare("iD.renderer.Map", null, {
|
||||
processMove:function(e) {
|
||||
// summary: Drag the map to a new origin.
|
||||
// e: MouseEvent The mouse-move event that triggered it.
|
||||
var x=e.clientX;
|
||||
var y=e.clientY;
|
||||
var x = e.clientX;
|
||||
var y = e.clientY;
|
||||
if (this.dragging) {
|
||||
if (this.dragx) {
|
||||
this.containerx+=(x-this.dragx);
|
||||
this.containery+=(y-this.dragy);
|
||||
this.containerx += (x - this.dragx);
|
||||
this.containery += (y - this.dragy);
|
||||
this.updateOrigin();
|
||||
this.dragged=true;
|
||||
}
|
||||
@@ -411,31 +423,31 @@ declare("iD.renderer.Map", null, {
|
||||
this.controller.entityMouseEvent(e,null);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
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) {
|
||||
// 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); }
|
||||
// ** FIXME: we may want to reinstate this at some point...
|
||||
// this.controller.entityMouseEvent(e,null);
|
||||
},
|
||||
|
||||
// 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); }
|
||||
// ** FIXME: we may want to reinstate this at some point...
|
||||
// this.controller.entityMouseEvent(e,null);
|
||||
},
|
||||
|
||||
updateCoordsFromViewportPosition:function(e) {
|
||||
// summary: Update centre and bbox from the current viewport origin.
|
||||
this._updateCoords(this.containerx,this.containery);
|
||||
},
|
||||
|
||||
|
||||
updateCoordsFromLatLon:function(lat,lon) {
|
||||
// summary: Update centre and bbox to a specified lat/lon.
|
||||
this._updateCoords(-(this.lon2coord(lon)-this.mapwidth/2),
|
||||
-(this.lat2coord(lat)-this.mapheight/2));
|
||||
},
|
||||
// summary: Update centre and bbox to a specified lat/lon.
|
||||
this._updateCoords(-(this.lon2coord(lon)-this.mapwidth/2),
|
||||
-(this.lat2coord(lat)-this.mapheight/2));
|
||||
},
|
||||
|
||||
_updateCoords:function(x,y) {
|
||||
// summary: Set centre and bbox.
|
||||
@@ -481,8 +493,7 @@ declare("iD.renderer.Map", null, {
|
||||
// Turn event co-ordinates into map co-ordinates
|
||||
|
||||
mouseX:function(e) { return e.clientX - domGeom.getMarginBox(this.div).l - this.containerx; },
|
||||
mouseY:function(e) { return e.clientY - domGeom.getMarginBox(this.div).t - this.containery; },
|
||||
|
||||
mouseY:function(e) { return e.clientY - domGeom.getMarginBox(this.div).t - this.containery; }
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
+12
-14
@@ -1,7 +1,7 @@
|
||||
// iD/renderer/NodeUI.js
|
||||
// NodeUI classes for iD
|
||||
|
||||
define(['dojo/_base/declare','dojo/_base/lang','dojo/_base/array','dojox/gfx/_base','iD/renderer/EntityUI'],
|
||||
define(['dojo/_base/declare','dojo/_base/lang','dojo/_base/array','dojox/gfx/_base','iD/renderer/EntityUI'],
|
||||
function(declare,lang,array,g){
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
@@ -14,25 +14,25 @@ declare("iD.renderer.NodeUI", [iD.renderer.EntityUI], {
|
||||
},
|
||||
getEnhancedTags:function() {
|
||||
var tags=this.inherited(arguments);
|
||||
if (!this.entity.hasParentWays()) { tags[':poi']='yes'; }
|
||||
if (!this.entity.entity.hasParentWays()) { tags[':poi']='yes'; }
|
||||
// add junction and dupe
|
||||
return tags;
|
||||
},
|
||||
redraw:function() {
|
||||
// summary: Draw the object (mostly icons) and add hitzone sprites.
|
||||
var node=this.entity;
|
||||
var node = this.entity;
|
||||
this.removeSprites();
|
||||
|
||||
// Tags, position and styleList
|
||||
var x=this.map.lon2coord(this.entity.lon);
|
||||
var y=this.map.latp2coord(this.entity.latp);
|
||||
var tags=this.getEnhancedTags();
|
||||
var x = Math.floor(this.map.lon2coord(this.entity.lon));
|
||||
var y = Math.floor(this.map.latp2coord(this.entity.latp));
|
||||
var tags = this.getEnhancedTags();
|
||||
this.refreshStyleList(tags);
|
||||
|
||||
// Iterate through each subpart, drawing any styles on that layer
|
||||
var drawn=false;
|
||||
var s,p,t,w,h;
|
||||
for (i=0; i<this.styleList.subparts.length; i++) {
|
||||
for (i = 0; i < this.styleList.subparts.length; i++) {
|
||||
var subpart=this.styleList.subparts[i];
|
||||
p = this.styleList.pointStyles[subpart];
|
||||
if (!p || !p.drawn()) { continue; }
|
||||
@@ -44,9 +44,9 @@ declare("iD.renderer.NodeUI", [iD.renderer.EntityUI], {
|
||||
// Draw icon
|
||||
var shape;
|
||||
switch (p.icon_image) {
|
||||
case 'square': shape=this.targetGroup('stroke',p.sublayer).createRect({ x:x-w/2, y:y-h/2, width:w, height:h }); break;
|
||||
case 'circle': shape=this.targetGroup('stroke',p.sublayer).createCircle({ cx:x, cy:y, r:w }); break;
|
||||
default: shape=this.targetGroup('stroke',p.sublayer).createImage({ width:w, height:h, x: x-w/2, y: y-h/2, src:p.icon_image }); break;
|
||||
case 'square':shape=this.targetGroup('stroke',p.sublayer).createRect({ x:x-w/2, y:y-h/2, width:w, height:h }); break;
|
||||
case 'circle':shape=this.targetGroup('stroke',p.sublayer).createCircle({ cx:x, cy:y, r:w }); break;
|
||||
default:shape=this.targetGroup('stroke',p.sublayer).createImage({ width:w, height:h, x: x-w/2, y: y-h/2, src:p.icon_image }); break;
|
||||
}
|
||||
switch (p.icon_image) {
|
||||
case 'square':
|
||||
@@ -55,7 +55,6 @@ declare("iD.renderer.NodeUI", [iD.renderer.EntityUI], {
|
||||
this.recordSprite(shape);
|
||||
|
||||
// Add text label
|
||||
|
||||
// Add hit-zone
|
||||
var hit;
|
||||
switch (p.icon_image) {
|
||||
@@ -64,15 +63,14 @@ declare("iD.renderer.NodeUI", [iD.renderer.EntityUI], {
|
||||
}
|
||||
hit.setFill([0,1,0,0]).setStroke( { width:2, color:[0,0,0,0] } );
|
||||
this.recordSprite(hit);
|
||||
hit.source=this;
|
||||
hit.source= this;
|
||||
hit.connect("onclick" , lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmousedown" , lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmouseup" , lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmouseenter", lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmouseleave", lang.hitch(this,this.entityMouseEvent));
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
+22
-18
@@ -28,11 +28,12 @@ declare("iD.renderer.WayUI", [iD.renderer.EntityUI], {
|
||||
},
|
||||
redraw:function() {
|
||||
// summary: Draw the object and add hitzone sprites.
|
||||
var way=this.entity;
|
||||
var maxwidth=4;
|
||||
var i;
|
||||
var way = this.entity,
|
||||
maxwidth=4,
|
||||
i;
|
||||
|
||||
this.removeSprites();
|
||||
if (way.length()==0) { return; }
|
||||
if (!way.nodes.length) { return; }
|
||||
|
||||
// Create tags and calculate styleList
|
||||
var tags=this.getEnhancedTags();
|
||||
@@ -40,14 +41,17 @@ declare("iD.renderer.WayUI", [iD.renderer.EntityUI], {
|
||||
|
||||
// List of co-ordinates
|
||||
var coords=[];
|
||||
for (i=0; i<way.nodes.length; i++) {
|
||||
var node=way.nodes[i];
|
||||
coords.push( { x: this.map.lon2coord(node.lon), y: this.map.latp2coord(node.latp) } );
|
||||
for (i = 0; i < way.nodes.length; i++) {
|
||||
var node = way.nodes[i];
|
||||
coords.push({
|
||||
x: this.map.lon2coord(node.lon),
|
||||
y: this.map.latp2coord(node.latp)
|
||||
});
|
||||
}
|
||||
|
||||
// Iterate through each subpart, drawing any styles on that layer
|
||||
var drawn=false;
|
||||
for (i=0; i<this.styleList.subparts.length; i++) {
|
||||
var drawn = false;
|
||||
for (i = 0; i < this.styleList.subparts.length; i++) {
|
||||
var subpart=this.styleList.subparts[i];
|
||||
if (this.styleList.shapeStyles[subpart]) {
|
||||
var s=this.styleList.shapeStyles[subpart];
|
||||
@@ -66,13 +70,13 @@ declare("iD.renderer.WayUI", [iD.renderer.EntityUI], {
|
||||
}
|
||||
|
||||
// Casing
|
||||
if (s.casing_width) {
|
||||
if (s.casing_width) {
|
||||
this.recordSprite(this.targetGroup('casing').createPolyline(coords).setStroke(s.casingStyler()));
|
||||
maxwidth=Math.max(maxwidth,s.width+s.casing_width*2);
|
||||
drawn=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Text label on path
|
||||
if (this.styleList.textStyles[subpart]) {
|
||||
var t=this.styleList.textStyles[subpart];
|
||||
@@ -96,26 +100,26 @@ declare("iD.renderer.WayUI", [iD.renderer.EntityUI], {
|
||||
if (drawn) {
|
||||
var hit=this.recordSprite(this.targetGroup('hit').createPolyline(coords).setStroke( { width:maxwidth+8, color: [0,0,0,0] } ));
|
||||
hit.source=this;
|
||||
hit.connect("onclick" , lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmousedown" , lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmouseup" , lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onclick", lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmousedown", lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmouseup", lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmouseenter", lang.hitch(this,this.entityMouseEvent));
|
||||
hit.connect("onmouseleave", lang.hitch(this,this.entityMouseEvent));
|
||||
}
|
||||
// Draw nodes
|
||||
for (i=0; i<way.length(); i++) {
|
||||
for (i=0; i<way.nodes.length; i++) {
|
||||
var node=way.nodes[i];
|
||||
var sc=[];
|
||||
if (tags[':shownodes']) { sc.push('selectedway'); }
|
||||
if (tags[':shownodeshover']) { sc.push('hoverway'); }
|
||||
if (node.parentWays().length>1) { sc.push('junction'); }
|
||||
if (node.entity.parentWays().length>1) { sc.push('junction'); }
|
||||
this.map.createUI(node,sc);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
entityMouseEvent:function(event) {
|
||||
this.inherited(arguments);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -29,13 +29,15 @@ declare("iD.styleparser.Rule", null, {
|
||||
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.isType(this.subject)) { return false; }
|
||||
if ((this.subject !== '') && (entity.entityType !== this.subject)) {
|
||||
return false;
|
||||
}
|
||||
if (zoom<this.minZoom || zoom>this.maxZoom) { return false; }
|
||||
|
||||
|
||||
var v=true; var i=0; var isAnd=this.isAnd;
|
||||
array.forEach(this.conditions, function(condition) {
|
||||
var r=condition.test(tags);
|
||||
if (i==0) { v=r; }
|
||||
if (i === 0) { v=r; }
|
||||
else if (isAnd) { v=v && r; }
|
||||
else { v = v || r; }
|
||||
i++;
|
||||
|
||||
@@ -62,20 +62,20 @@ declare("iD.styleparser.RuleChain", null, {
|
||||
|
||||
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 (this.rules.length === 0) { return false; }
|
||||
if (pos==-1) { pos=this.rules.length-1; }
|
||||
|
||||
var r=this.rules[pos];
|
||||
|
||||
var r = this.rules[pos];
|
||||
if (!r.test(entity, tags, zoom)) { return false; }
|
||||
if (pos==0) { return true; }
|
||||
|
||||
var o=entity.parentObjects();
|
||||
for (var i=0; i<o.length; i++) {
|
||||
if (pos === 0) { return true; }
|
||||
|
||||
var o = entity.entity.parentObjects();
|
||||
for (var i = 0; i < o.length; i++) {
|
||||
var p=o[i];
|
||||
if (this.test(pos-1, p, p.getTagsHash(), zoom)) { return true; }
|
||||
if (this.test(pos-1, p, p.tags, zoom)) { return true; }
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@ declare("iD.styleparser.RuleSet", null, {
|
||||
// summary: An entire stylesheet in parsed form.
|
||||
this.choosers=[];
|
||||
},
|
||||
|
||||
|
||||
registerCallback:function(callback) {
|
||||
// summary: Set a callback function to be called when the CSS is loaded and parsed.
|
||||
this.callback=callback;
|
||||
},
|
||||
|
||||
|
||||
getStyles:function(entity, tags, zoom) {
|
||||
// summary: Find the styles for a given entity.
|
||||
var sl=new iD.styleparser.StyleList();
|
||||
@@ -35,13 +35,13 @@ declare("iD.styleparser.RuleSet", null, {
|
||||
// summary: Load a MapCSS file from a URL, then throw it at the parser when it's loaded.
|
||||
xhr.get({ url: url, load: lang.hitch(this, "parseCSS") });
|
||||
},
|
||||
|
||||
|
||||
parseCSS:function(css) {
|
||||
// summary: Parse a CSS document into a set of StyleChoosers.
|
||||
var previous=0; // what was the previous CSS word?
|
||||
var sc=new iD.styleparser.StyleChooser(); // currently being assembled
|
||||
this.choosers=[];
|
||||
css=css.replace(/[\r\n]/g,""); // strip linebreaks because JavaScript doesn't have the /s modifier
|
||||
css = css.replace(/[\r\n]/g,""); // strip linebreaks because JavaScript doesn't have the /s modifier
|
||||
|
||||
var o={};
|
||||
while (css.length>0) {
|
||||
@@ -139,12 +139,12 @@ declare("iD.styleparser.RuleSet", null, {
|
||||
var o={};
|
||||
var k, v;
|
||||
|
||||
// Create styles
|
||||
var ss=new iD.styleparser.ShapeStyle() ;
|
||||
var ps=new iD.styleparser.PointStyle() ;
|
||||
var ts=new iD.styleparser.TextStyle() ;
|
||||
var hs=new iD.styleparser.ShieldStyle();
|
||||
var xs=new iD.styleparser.InstructionStyle();
|
||||
// Create styles
|
||||
var ss = new iD.styleparser.ShapeStyle();
|
||||
var ps = new iD.styleparser.PointStyle();
|
||||
var ts = new iD.styleparser.TextStyle();
|
||||
var hs = new iD.styleparser.ShieldStyle();
|
||||
var xs = new iD.styleparser.InstructionStyle();
|
||||
|
||||
var r=s.split(';');
|
||||
var isEval={};
|
||||
@@ -163,39 +163,39 @@ declare("iD.styleparser.RuleSet", null, {
|
||||
if (t['z_index']) { sub=Number(t['z_index']); delete t['z_index']; }
|
||||
ss.sublayer=ps.sublayer=ts.sublayer=hs.sublayer=sub;
|
||||
xs.sublayer=10;
|
||||
|
||||
|
||||
// Find "interactive" property - it's true unless explicitly set false
|
||||
var inter=true;
|
||||
if (t['interactive']) { inter=t['interactive'].match(this.FALSE) ? false : true; delete t['interactive']; }
|
||||
ss.interactive=ps.interactive=ts.interactive=hs.interactive=xs.interactive=inter;
|
||||
|
||||
// Munge special values
|
||||
// (we should stop doing this and do it in the style instead)
|
||||
if (t['font_weight'] ) { t['font_bold' ] = t['font_weight' ].match(this.BOLD ) ? true : false; delete t['font_weight']; }
|
||||
if (t['font_style'] ) { t['font_italic'] = t['font_style' ].match(this.ITALIC) ? true : false; delete t['font_style']; }
|
||||
if (t['text_decoration']) { t['font_underline'] = t['text_decoration'].match(this.UNDERLINE) ? true : false; delete t['text_decoration']; }
|
||||
if (t['text_position'] ) { t['text_center'] = t['text_position' ].match(this.CENTER) ? true : false; delete t['text_position']; }
|
||||
if (t['text_transform']) {
|
||||
if (t['text_transform'].match(this.CAPS)) { t['font_caps']=true; } else { t['font_caps']=false; }
|
||||
delete t['text_transform'];
|
||||
}
|
||||
// Munge special values
|
||||
// (we should stop doing this and do it in the style instead)
|
||||
if (t['font_weight'] ) { t['font_bold' ] = t['font_weight' ].match(this.BOLD ) ? true : false; delete t['font_weight']; }
|
||||
if (t['font_style'] ) { t['font_italic'] = t['font_style' ].match(this.ITALIC) ? true : false; delete t['font_style']; }
|
||||
if (t['text_decoration']) { t['font_underline'] = t['text_decoration'].match(this.UNDERLINE) ? true : false; delete t['text_decoration']; }
|
||||
if (t['text_position'] ) { t['text_center'] = t['text_position' ].match(this.CENTER) ? true : false; delete t['text_position']; }
|
||||
if (t['text_transform']) {
|
||||
if (t['text_transform'].match(this.CAPS)) { t['font_caps']=true; } else { t['font_caps']=false; }
|
||||
delete t['text_transform'];
|
||||
}
|
||||
|
||||
// Assign each property to the appropriate style
|
||||
for (a in t) {
|
||||
// Parse properties
|
||||
// ** also do units, e.g. px/pt/m
|
||||
if (a.match(this.COLOR)) { v = this.parseCSSColor(t[a]); }
|
||||
else { v = t[a]; }
|
||||
|
||||
// Set in styles
|
||||
if (ss.has(a)) { ss.setPropertyFromString(a,v,isEval[a]); }
|
||||
else if (ps.has(a)) { ps.setPropertyFromString(a,v,isEval[a]); }
|
||||
else if (ts.has(a)) { ts.setPropertyFromString(a,v,isEval[a]); }
|
||||
else if (hs.has(a)) { hs.setPropertyFromString(a,v,isEval[a]); }
|
||||
else { console.log(a+" not found"); }
|
||||
}
|
||||
// Assign each property to the appropriate style
|
||||
for (a in t) {
|
||||
// Parse properties
|
||||
// ** also do units, e.g. px/pt/m
|
||||
if (a.match(this.COLOR)) { v = this.parseCSSColor(t[a]); }
|
||||
else { v = t[a]; }
|
||||
|
||||
// Add each style to list
|
||||
// Set in styles
|
||||
if (ss.has(a)) { ss.setPropertyFromString(a,v,isEval[a]); }
|
||||
else if (ps.has(a)) { ps.setPropertyFromString(a,v,isEval[a]); }
|
||||
else if (ts.has(a)) { ts.setPropertyFromString(a,v,isEval[a]); }
|
||||
else if (hs.has(a)) { hs.setPropertyFromString(a,v,isEval[a]); }
|
||||
else { console.log(a+" not found"); }
|
||||
}
|
||||
|
||||
// Add each style to list
|
||||
if (ss.edited) { styles.push(ss); }
|
||||
if (ps.edited) { styles.push(ps); }
|
||||
if (ts.edited) { styles.push(ts); }
|
||||
@@ -203,7 +203,7 @@ declare("iD.styleparser.RuleSet", null, {
|
||||
if (xs.edited) { styles.push(xs); }
|
||||
return styles;
|
||||
},
|
||||
|
||||
|
||||
parseZoom:function(s) {
|
||||
var o={};
|
||||
if ((o=this.ZOOM_MINMAX.exec(s))) { return [o[1],o[2]]; }
|
||||
@@ -250,7 +250,7 @@ declare("iD.styleparser.RuleSet", null, {
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
|
||||
// Regular expression tests and other constants
|
||||
|
||||
WHITESPACE :/^\s+/,
|
||||
@@ -287,16 +287,16 @@ declare("iD.styleparser.RuleSet", null, {
|
||||
SET_TAG_EVAL :/^\s*set\s+(\S+)\s*=\s*eval\s*\(\s*'(.+?)'\s*\)\s*$/i,
|
||||
SET_TAG :/^\s*set\s+(\S+)\s*=\s*(.+?)\s*$/i,
|
||||
SET_TAG_TRUE :/^\s*set\s+(\S+)\s*$/i,
|
||||
EXIT :/^\s*exit\s*$/i,
|
||||
EXIT :/^\s*exit\s*$/i,
|
||||
|
||||
oZOOM: 2,
|
||||
oGROUP: 3,
|
||||
oCONDITION: 4,
|
||||
oOBJECT: 5,
|
||||
oDECLARATION: 6,
|
||||
oSUBPART: 7,
|
||||
oZOOM: 2,
|
||||
oGROUP: 3,
|
||||
oCONDITION: 4,
|
||||
oOBJECT: 5,
|
||||
oDECLARATION: 6,
|
||||
oSUBPART: 7,
|
||||
|
||||
DASH: /\-/g,
|
||||
DASH: /\-/g,
|
||||
COLOR: /color$/,
|
||||
BOLD: /^bold$/i,
|
||||
ITALIC: /^italic|oblique$/i,
|
||||
|
||||
@@ -211,13 +211,13 @@ declare("iD.styleparser.TextStyle", [iD.styleparser.Style], {
|
||||
return {
|
||||
decoration: this.font_underline ? 'underline' : 'none',
|
||||
align: 'middle',
|
||||
text: _text,
|
||||
text: _text
|
||||
};
|
||||
},
|
||||
fillStyler:function() {
|
||||
// not implemented yet
|
||||
return this.dojoColor(0,1);
|
||||
},
|
||||
}
|
||||
|
||||
// getTextFormat, getHaloFilter, writeNameLabel
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ declare("iD.styleparser.StyleChooser", null, {
|
||||
this.ruleChains=[new iD.styleparser.RuleChain()];
|
||||
this.styles=[];
|
||||
},
|
||||
|
||||
|
||||
currentChain:function() {
|
||||
return this.ruleChains[this.ruleChains.length-1];
|
||||
},
|
||||
|
||||
@@ -8,32 +8,31 @@ define(['dojo/_base/declare'], function(declare){
|
||||
|
||||
declare("iD.styleparser.StyleList", null, {
|
||||
|
||||
shapeStyles:{},
|
||||
textStyles:{},
|
||||
pointStyles:{},
|
||||
shieldStyles:{},
|
||||
maxwidth:0,
|
||||
subparts:[], // List of subparts used in this StyleList
|
||||
validAt:-1, // Zoom level this is valid at (or -1 at all levels - saves recomputing)
|
||||
|
||||
shapeStyles: {},
|
||||
textStyles: {},
|
||||
pointStyles: {},
|
||||
shieldStyles: {},
|
||||
maxwidth: 0,
|
||||
subparts: [], // List of subparts used in this StyleList
|
||||
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.
|
||||
|
||||
this.shapeStyles={};
|
||||
this.textStyles={};
|
||||
this.pointStyles={};
|
||||
this.shieldStyles={};
|
||||
this.subparts=[];
|
||||
},
|
||||
|
||||
|
||||
hasStyles:function() {
|
||||
// summary: Does this StyleList contain any styles?
|
||||
return ( this.hasShapeStyles() || this.hasTextStyles() || this.hasPointStyles() || this.hasShieldStyles() );
|
||||
},
|
||||
|
||||
|
||||
hasFills:function() {
|
||||
// summary: Does this StyleList contain any styles with a fill?
|
||||
for (var s in this.shapeStyles) {
|
||||
@@ -71,11 +70,10 @@ declare("iD.styleparser.StyleList", null, {
|
||||
return str;
|
||||
},
|
||||
|
||||
hasShapeStyles:function() { for (var a in shapeStyles ) { return true; }; return false; },
|
||||
hasTextStyles:function() { for (var a in textStyles ) { return true; }; return false; },
|
||||
hasPointStyles:function() { for (var a in pointStyles ) { return true; }; return false; },
|
||||
hasShieldStyles:function() { for (var a in shieldStyles) { return true; }; return false; },
|
||||
|
||||
hasShapeStyles:function() { for (var a in shapeStyles ) { return true; } return false; },
|
||||
hasTextStyles:function() { for (var a in textStyles ) { return true; } return false; },
|
||||
hasPointStyles:function() { for (var a in pointStyles ) { return true; } return false; },
|
||||
hasShieldStyles:function() { for (var a in shieldStyles) { return true; } return false; }
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Vendored
+2
File diff suppressed because one or more lines are too long
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Copyright 2010 Tim Down.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
var Hashtable=(function(){var p="function";var n=(typeof Array.prototype.splice==p)?function(s,r){s.splice(r,1)}:function(u,t){var s,v,r;if(t===u.length-1){u.length=t}else{s=u.slice(t+1);u.length=t;for(v=0,r=s.length;v<r;++v){u[t+v]=s[v]}}};function a(t){var r;if(typeof t=="string"){return t}else{if(typeof t.hashCode==p){r=t.hashCode();return(typeof r=="string")?r:a(r)}else{if(typeof t.toString==p){return t.toString()}else{try{return String(t)}catch(s){return Object.prototype.toString.call(t)}}}}}function g(r,s){return r.equals(s)}function e(r,s){return(typeof s.equals==p)?s.equals(r):(r===s)}function c(r){return function(s){if(s===null){throw new Error("null is not a valid "+r)}else{if(typeof s=="undefined"){throw new Error(r+" must not be undefined")}}}}var q=c("key"),l=c("value");function d(u,s,t,r){this[0]=u;this.entries=[];this.addEntry(s,t);if(r!==null){this.getEqualityFunction=function(){return r}}}var h=0,j=1,f=2;function o(r){return function(t){var s=this.entries.length,v,u=this.getEqualityFunction(t);while(s--){v=this.entries[s];if(u(t,v[0])){switch(r){case h:return true;case j:return v;case f:return[s,v[1]]}}}return false}}function k(r){return function(u){var v=u.length;for(var t=0,s=this.entries.length;t<s;++t){u[v+t]=this.entries[t][r]}}}d.prototype={getEqualityFunction:function(r){return(typeof r.equals==p)?g:e},getEntryForKey:o(j),getEntryAndIndexForKey:o(f),removeEntryForKey:function(s){var r=this.getEntryAndIndexForKey(s);if(r){n(this.entries,r[0]);return r[1]}return null},addEntry:function(r,s){this.entries[this.entries.length]=[r,s]},keys:k(0),values:k(1),getEntries:function(s){var u=s.length;for(var t=0,r=this.entries.length;t<r;++t){s[u+t]=this.entries[t].slice(0)}},containsKey:o(h),containsValue:function(s){var r=this.entries.length;while(r--){if(s===this.entries[r][1]){return true}}return false}};function m(s,t){var r=s.length,u;while(r--){u=s[r];if(t===u[0]){return r}}return null}function i(r,s){var t=r[s];return(t&&(t instanceof d))?t:null}function b(t,r){var w=this;var v=[];var u={};var x=(typeof t==p)?t:a;var s=(typeof r==p)?r:null;this.put=function(B,C){q(B);l(C);var D=x(B),E,A,z=null;E=i(u,D);if(E){A=E.getEntryForKey(B);if(A){z=A[1];A[1]=C}else{E.addEntry(B,C)}}else{E=new d(D,B,C,s);v[v.length]=E;u[D]=E}return z};this.get=function(A){q(A);var B=x(A);var C=i(u,B);if(C){var z=C.getEntryForKey(A);if(z){return z[1]}}return null};this.containsKey=function(A){q(A);var z=x(A);var B=i(u,z);return B?B.containsKey(A):false};this.containsValue=function(A){l(A);var z=v.length;while(z--){if(v[z].containsValue(A)){return true}}return false};this.clear=function(){v.length=0;u={}};this.isEmpty=function(){return !v.length};var y=function(z){return function(){var A=[],B=v.length;while(B--){v[B][z](A)}return A}};this.keys=y("keys");this.values=y("values");this.entries=y("getEntries");this.remove=function(B){q(B);var C=x(B),z,A=null;var D=i(u,C);if(D){A=D.removeEntryForKey(B);if(A!==null){if(!D.entries.length){z=m(v,C);n(v,z);delete u[C]}}}return A};this.size=function(){var A=0,z=v.length;while(z--){A+=v[z].entries.length}return A};this.each=function(C){var z=w.entries(),A=z.length,B;while(A--){B=z[A];C(B[0],B[1])}};this.putAll=function(H,C){var B=H.entries();var E,F,D,z,A=B.length;var G=(typeof C==p);while(A--){E=B[A];F=E[0];D=E[1];if(G&&(z=w.get(F))){D=C(F,z,D)}w.put(F,D)}};this.clone=function(){var z=new b(t,r);z.putAll(w);return z}}return b})();
|
||||
Vendored
+5
File diff suppressed because one or more lines are too long
+17
-9
@@ -6,7 +6,6 @@
|
||||
Based heavily on:
|
||||
MapCSS demonstration stylesheet
|
||||
Richard Fairhurst, October 2009
|
||||
|
||||
*/
|
||||
|
||||
/* A set of fairly standard rules.
|
||||
@@ -20,13 +19,13 @@ way[highway=primary],way[highway=primary_link],
|
||||
way[highway=secondary],way[highway=secondary_link],
|
||||
way[highway=tertiary],way[highway=tertiary_link],
|
||||
way[highway=unclassified],
|
||||
way[highway=residential] { text: name; text-color: black; font-size: 7; text-position: line;}
|
||||
way[highway=residential] { text: name; text-color: black; font-size: 6; text-position: line;}
|
||||
way[highway=motorway],way[highway=motorway_link] { z-index: 9; color: #809BC0; width: 7; casing-color: black; casing-width: 1; }
|
||||
way[highway=trunk],way[highway=trunk_link] { z-index: 9; color: #7FC97F; width: 7; casing-color: black; casing-width: 1; }
|
||||
way[highway=primary],way[highway=primary_link] { z-index: 8; color: #E46D71; width: 7; casing-color: black; casing-width: 1; }
|
||||
way[highway=primary],way[highway=primary_link] { z-index: 8; color: #E46D71; width: 9; casing-color: black; casing-width: 1; }
|
||||
way[highway=secondary],way[highway=secondary_link] { z-index: 7; color: #FDBF6F; width: 7; casing-width: 1; }
|
||||
way[highway=tertiary],way[highway=unclassified] { z-index: 6; color: #FEFECB; width: 5; casing-width: 1; }
|
||||
way[highway=residential] { z-index: 5; color: #E8E8E8; width: 5; casing-color: gray; casing-width: 1; }
|
||||
way[highway=residential] { z-index: 5; color: #E8E8E8; width: 6; casing-color: gray; casing-width: 1; }
|
||||
way[highway=service] { color: white; width: 3; casing-width: 1; }
|
||||
|
||||
/* Pedestrian precincts need to be treated carefully. Only closed-loops with an explicit
|
||||
@@ -40,13 +39,22 @@ way[highway=bridleway] { z-index:9; color: #996644; width: 2; dashes: 4, 2, 2, 2
|
||||
way[highway=track] { color: #996644; width: 2; dashes: 4, 2; }
|
||||
way[highway=path] { color: lightgreen; width: 2; dashes: 2, 2; }
|
||||
|
||||
way[waterway=river], way[waterway=canal] { color: blue; width: 2; text:name; text-color:blue; font-size:9; text-position: offset; text-offset: 7;}
|
||||
way[waterway=river], way[waterway=canal] {
|
||||
casing-width: 1;
|
||||
casing-color: #6eafd4;
|
||||
color: #10539a;
|
||||
width: 3;
|
||||
text:name;
|
||||
text-color:blue;
|
||||
font-size:7;
|
||||
text-position: offset;
|
||||
text-offset: -5;
|
||||
}
|
||||
|
||||
way[barrier] {color: #000000; width: 1}
|
||||
|
||||
/* Fills can be solid colour or bitmap images */
|
||||
|
||||
|
||||
way[natural] :area { color: #ADD6A5; width: 1; fill-color: #ADD6A5; fill-opacity: 0.2; }
|
||||
way[landuse] :area { color: #444444; width: 2; fill-color: #444444; fill-opacity: 0.3; }
|
||||
way[amenity],way[shop] :area { color: #ADCEB5; width: 1; fill-color: #ADCEB5; fill-opacity: 0.2; }
|
||||
@@ -96,7 +104,7 @@ node[amenity=school] { icon-image: icons/school.png; icon-width: 16; }
|
||||
node[amenity=taxi] { icon-image: icons/taxi.png; icon-width: 16; }
|
||||
node[amenity=telephone] { icon-image: icons/telephone.png; icon-width: 16; }
|
||||
way node[barrier=gate], way node[highway=gate] { icon-image: icons/gate.png; icon-width: 7; }
|
||||
|
||||
|
||||
/* We can stack styles at different z-index (depth) */
|
||||
|
||||
way[railway=rail]
|
||||
@@ -110,7 +118,7 @@ way[railway=subway]
|
||||
way[bridge=yes]
|
||||
{ z-index: 4; color: white; width: eval('_width+3'); }
|
||||
{ z-index: 3; color: black; width: eval('_width+6'); }
|
||||
|
||||
|
||||
/* Tunnel */
|
||||
way[tunnel=yes]
|
||||
{ z-index: 4; color: white; width: eval('_width+2'); }
|
||||
@@ -138,7 +146,7 @@ node !:drawn :poi { z-index: 2; icon-image: circle; icon-width: 4; color: green;
|
||||
|
||||
node :hoverway { z-index: 9; icon-image: square; icon-width: 7; color: blue; layer: 5; }
|
||||
node::highlight :selected { z-index: 1; icon-image: square; icon-width: eval('_width+10'); color: yellow; }
|
||||
|
||||
|
||||
/* Descendant selectors provide an easy way to style relations: this example means "any way
|
||||
which is part of a relation whose type=route". */
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Jasmine Spec Runner</title>
|
||||
|
||||
<link rel="shortcut icon" type="image/png" href="lib/jasmine-1.2.0/jasmine_favicon.png">
|
||||
<link rel="stylesheet" type="text/css" href="lib/jasmine-1.2.0/jasmine.css">
|
||||
<script type="text/javascript" src="lib/jasmine-1.2.0/jasmine.js"></script>
|
||||
<script type="text/javascript" src="lib/jasmine-1.2.0/jasmine-html.js"></script>
|
||||
|
||||
<!-- include source files here... -->
|
||||
<script type="text/javascript" src="../js/lib/underscore-min.js"></script>
|
||||
<script type="text/javascript" src="../js/lib/jquery-1.8.2.min.js"></script>
|
||||
<script type="text/javascript" src="../js/iD/Util.js"></script>
|
||||
<script type="text/javascript" src="../js/iD/Node.js"></script>
|
||||
<script type="text/javascript" src="../js/iD/Relation.js"></script>
|
||||
<script type="text/javascript" src="../js/iD/Entity.js"></script>
|
||||
<script type="text/javascript" src="../js/iD/Way.js"></script>
|
||||
<script type="text/javascript" src="../js/iD/Connection.js"></script>
|
||||
|
||||
<!-- include spec files here... -->
|
||||
<script type="text/javascript" src="spec/Util.js"></script>
|
||||
<script type="text/javascript" src="spec/Node.js"></script>
|
||||
<script type="text/javascript" src="spec/Entity.js"></script>
|
||||
<script type="text/javascript" src="spec/Relation.js"></script>
|
||||
<script type="text/javascript" src="spec/Way.js"></script>
|
||||
<script type="text/javascript" src="spec/Connection.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var jasmineEnv = jasmine.getEnv();
|
||||
jasmineEnv.updateInterval = 1000;
|
||||
|
||||
var htmlReporter = new jasmine.HtmlReporter();
|
||||
|
||||
jasmineEnv.addReporter(htmlReporter);
|
||||
|
||||
jasmineEnv.specFilter = function(spec) {
|
||||
return htmlReporter.specFilter(spec);
|
||||
};
|
||||
|
||||
var currentWindowOnload = window.onload;
|
||||
|
||||
window.onload = function() {
|
||||
if (currentWindowOnload) {
|
||||
currentWindowOnload();
|
||||
}
|
||||
execJasmine();
|
||||
};
|
||||
|
||||
function execJasmine() {
|
||||
jasmineEnv.execute();
|
||||
}
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2008-2011 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,616 @@
|
||||
jasmine.HtmlReporterHelpers = {};
|
||||
|
||||
jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
|
||||
var el = document.createElement(type);
|
||||
|
||||
for (var i = 2; i < arguments.length; i++) {
|
||||
var child = arguments[i];
|
||||
|
||||
if (typeof child === 'string') {
|
||||
el.appendChild(document.createTextNode(child));
|
||||
} else {
|
||||
if (child) {
|
||||
el.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var attr in attrs) {
|
||||
if (attr == "className") {
|
||||
el[attr] = attrs[attr];
|
||||
} else {
|
||||
el.setAttribute(attr, attrs[attr]);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
};
|
||||
|
||||
jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
|
||||
var results = child.results();
|
||||
var status = results.passed() ? 'passed' : 'failed';
|
||||
if (results.skipped) {
|
||||
status = 'skipped';
|
||||
}
|
||||
|
||||
return status;
|
||||
};
|
||||
|
||||
jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
|
||||
var parentDiv = this.dom.summary;
|
||||
var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
|
||||
var parent = child[parentSuite];
|
||||
|
||||
if (parent) {
|
||||
if (typeof this.views.suites[parent.id] == 'undefined') {
|
||||
this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
|
||||
}
|
||||
parentDiv = this.views.suites[parent.id].element;
|
||||
}
|
||||
|
||||
parentDiv.appendChild(childElement);
|
||||
};
|
||||
|
||||
|
||||
jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
|
||||
for(var fn in jasmine.HtmlReporterHelpers) {
|
||||
ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
|
||||
}
|
||||
};
|
||||
|
||||
jasmine.HtmlReporter = function(_doc) {
|
||||
var self = this;
|
||||
var doc = _doc || window.document;
|
||||
|
||||
var reporterView;
|
||||
|
||||
var dom = {};
|
||||
|
||||
// Jasmine Reporter Public Interface
|
||||
self.logRunningSpecs = false;
|
||||
|
||||
self.reportRunnerStarting = function(runner) {
|
||||
var specs = runner.specs() || [];
|
||||
|
||||
if (specs.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
createReporterDom(runner.env.versionString());
|
||||
doc.body.appendChild(dom.reporter);
|
||||
|
||||
reporterView = new jasmine.HtmlReporter.ReporterView(dom);
|
||||
reporterView.addSpecs(specs, self.specFilter);
|
||||
};
|
||||
|
||||
self.reportRunnerResults = function(runner) {
|
||||
reporterView && reporterView.complete();
|
||||
};
|
||||
|
||||
self.reportSuiteResults = function(suite) {
|
||||
reporterView.suiteComplete(suite);
|
||||
};
|
||||
|
||||
self.reportSpecStarting = function(spec) {
|
||||
if (self.logRunningSpecs) {
|
||||
self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
|
||||
}
|
||||
};
|
||||
|
||||
self.reportSpecResults = function(spec) {
|
||||
reporterView.specComplete(spec);
|
||||
};
|
||||
|
||||
self.log = function() {
|
||||
var console = jasmine.getGlobal().console;
|
||||
if (console && console.log) {
|
||||
if (console.log.apply) {
|
||||
console.log.apply(console, arguments);
|
||||
} else {
|
||||
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.specFilter = function(spec) {
|
||||
if (!focusedSpecName()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return spec.getFullName().indexOf(focusedSpecName()) === 0;
|
||||
};
|
||||
|
||||
return self;
|
||||
|
||||
function focusedSpecName() {
|
||||
var specName;
|
||||
|
||||
(function memoizeFocusedSpec() {
|
||||
if (specName) {
|
||||
return;
|
||||
}
|
||||
|
||||
var paramMap = [];
|
||||
var params = doc.location.search.substring(1).split('&');
|
||||
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
|
||||
}
|
||||
|
||||
specName = paramMap.spec;
|
||||
})();
|
||||
|
||||
return specName;
|
||||
}
|
||||
|
||||
function createReporterDom(version) {
|
||||
dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
|
||||
dom.banner = self.createDom('div', { className: 'banner' },
|
||||
self.createDom('span', { className: 'title' }, "Jasmine "),
|
||||
self.createDom('span', { className: 'version' }, version)),
|
||||
|
||||
dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
|
||||
dom.alert = self.createDom('div', {className: 'alert'}),
|
||||
dom.results = self.createDom('div', {className: 'results'},
|
||||
dom.summary = self.createDom('div', { className: 'summary' }),
|
||||
dom.details = self.createDom('div', { id: 'details' }))
|
||||
);
|
||||
}
|
||||
};
|
||||
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
|
||||
this.startedAt = new Date();
|
||||
this.runningSpecCount = 0;
|
||||
this.completeSpecCount = 0;
|
||||
this.passedCount = 0;
|
||||
this.failedCount = 0;
|
||||
this.skippedCount = 0;
|
||||
|
||||
this.createResultsMenu = function() {
|
||||
this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
|
||||
this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
|
||||
' | ',
|
||||
this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
|
||||
|
||||
this.summaryMenuItem.onclick = function() {
|
||||
dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
|
||||
};
|
||||
|
||||
this.detailsMenuItem.onclick = function() {
|
||||
showDetails();
|
||||
};
|
||||
};
|
||||
|
||||
this.addSpecs = function(specs, specFilter) {
|
||||
this.totalSpecCount = specs.length;
|
||||
|
||||
this.views = {
|
||||
specs: {},
|
||||
suites: {}
|
||||
};
|
||||
|
||||
for (var i = 0; i < specs.length; i++) {
|
||||
var spec = specs[i];
|
||||
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
|
||||
if (specFilter(spec)) {
|
||||
this.runningSpecCount++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.specComplete = function(spec) {
|
||||
this.completeSpecCount++;
|
||||
|
||||
if (isUndefined(this.views.specs[spec.id])) {
|
||||
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
|
||||
}
|
||||
|
||||
var specView = this.views.specs[spec.id];
|
||||
|
||||
switch (specView.status()) {
|
||||
case 'passed':
|
||||
this.passedCount++;
|
||||
break;
|
||||
|
||||
case 'failed':
|
||||
this.failedCount++;
|
||||
break;
|
||||
|
||||
case 'skipped':
|
||||
this.skippedCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
specView.refresh();
|
||||
this.refresh();
|
||||
};
|
||||
|
||||
this.suiteComplete = function(suite) {
|
||||
var suiteView = this.views.suites[suite.id];
|
||||
if (isUndefined(suiteView)) {
|
||||
return;
|
||||
}
|
||||
suiteView.refresh();
|
||||
};
|
||||
|
||||
this.refresh = function() {
|
||||
|
||||
if (isUndefined(this.resultsMenu)) {
|
||||
this.createResultsMenu();
|
||||
}
|
||||
|
||||
// currently running UI
|
||||
if (isUndefined(this.runningAlert)) {
|
||||
this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
|
||||
dom.alert.appendChild(this.runningAlert);
|
||||
}
|
||||
this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
|
||||
|
||||
// skipped specs UI
|
||||
if (isUndefined(this.skippedAlert)) {
|
||||
this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
|
||||
}
|
||||
|
||||
this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
|
||||
|
||||
if (this.skippedCount === 1 && isDefined(dom.alert)) {
|
||||
dom.alert.appendChild(this.skippedAlert);
|
||||
}
|
||||
|
||||
// passing specs UI
|
||||
if (isUndefined(this.passedAlert)) {
|
||||
this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
|
||||
}
|
||||
this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
|
||||
|
||||
// failing specs UI
|
||||
if (isUndefined(this.failedAlert)) {
|
||||
this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
|
||||
}
|
||||
this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
|
||||
|
||||
if (this.failedCount === 1 && isDefined(dom.alert)) {
|
||||
dom.alert.appendChild(this.failedAlert);
|
||||
dom.alert.appendChild(this.resultsMenu);
|
||||
}
|
||||
|
||||
// summary info
|
||||
this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
|
||||
this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
|
||||
};
|
||||
|
||||
this.complete = function() {
|
||||
dom.alert.removeChild(this.runningAlert);
|
||||
|
||||
this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
|
||||
|
||||
if (this.failedCount === 0) {
|
||||
dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
|
||||
} else {
|
||||
showDetails();
|
||||
}
|
||||
|
||||
dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
function showDetails() {
|
||||
if (dom.reporter.className.search(/showDetails/) === -1) {
|
||||
dom.reporter.className += " showDetails";
|
||||
}
|
||||
}
|
||||
|
||||
function isUndefined(obj) {
|
||||
return typeof obj === 'undefined';
|
||||
}
|
||||
|
||||
function isDefined(obj) {
|
||||
return !isUndefined(obj);
|
||||
}
|
||||
|
||||
function specPluralizedFor(count) {
|
||||
var str = count + " spec";
|
||||
if (count > 1) {
|
||||
str += "s"
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
|
||||
|
||||
|
||||
jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
|
||||
this.spec = spec;
|
||||
this.dom = dom;
|
||||
this.views = views;
|
||||
|
||||
this.symbol = this.createDom('li', { className: 'pending' });
|
||||
this.dom.symbolSummary.appendChild(this.symbol);
|
||||
|
||||
this.summary = this.createDom('div', { className: 'specSummary' },
|
||||
this.createDom('a', {
|
||||
className: 'description',
|
||||
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
|
||||
title: this.spec.getFullName()
|
||||
}, this.spec.description)
|
||||
);
|
||||
|
||||
this.detail = this.createDom('div', { className: 'specDetail' },
|
||||
this.createDom('a', {
|
||||
className: 'description',
|
||||
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
|
||||
title: this.spec.getFullName()
|
||||
}, this.spec.getFullName())
|
||||
);
|
||||
};
|
||||
|
||||
jasmine.HtmlReporter.SpecView.prototype.status = function() {
|
||||
return this.getSpecStatus(this.spec);
|
||||
};
|
||||
|
||||
jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
|
||||
this.symbol.className = this.status();
|
||||
|
||||
switch (this.status()) {
|
||||
case 'skipped':
|
||||
break;
|
||||
|
||||
case 'passed':
|
||||
this.appendSummaryToSuiteDiv();
|
||||
break;
|
||||
|
||||
case 'failed':
|
||||
this.appendSummaryToSuiteDiv();
|
||||
this.appendFailureDetail();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
|
||||
this.summary.className += ' ' + this.status();
|
||||
this.appendToSummary(this.spec, this.summary);
|
||||
};
|
||||
|
||||
jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
|
||||
this.detail.className += ' ' + this.status();
|
||||
|
||||
var resultItems = this.spec.results().getItems();
|
||||
var messagesDiv = this.createDom('div', { className: 'messages' });
|
||||
|
||||
for (var i = 0; i < resultItems.length; i++) {
|
||||
var result = resultItems[i];
|
||||
|
||||
if (result.type == 'log') {
|
||||
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
|
||||
} else if (result.type == 'expect' && result.passed && !result.passed()) {
|
||||
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
|
||||
|
||||
if (result.trace.stack) {
|
||||
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (messagesDiv.childNodes.length > 0) {
|
||||
this.detail.appendChild(messagesDiv);
|
||||
this.dom.details.appendChild(this.detail);
|
||||
}
|
||||
};
|
||||
|
||||
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
|
||||
this.suite = suite;
|
||||
this.dom = dom;
|
||||
this.views = views;
|
||||
|
||||
this.element = this.createDom('div', { className: 'suite' },
|
||||
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
|
||||
);
|
||||
|
||||
this.appendToSummary(this.suite, this.element);
|
||||
};
|
||||
|
||||
jasmine.HtmlReporter.SuiteView.prototype.status = function() {
|
||||
return this.getSpecStatus(this.suite);
|
||||
};
|
||||
|
||||
jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
|
||||
this.element.className += " " + this.status();
|
||||
};
|
||||
|
||||
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
|
||||
|
||||
/* @deprecated Use jasmine.HtmlReporter instead
|
||||
*/
|
||||
jasmine.TrivialReporter = function(doc) {
|
||||
this.document = doc || document;
|
||||
this.suiteDivs = {};
|
||||
this.logRunningSpecs = false;
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
|
||||
var el = document.createElement(type);
|
||||
|
||||
for (var i = 2; i < arguments.length; i++) {
|
||||
var child = arguments[i];
|
||||
|
||||
if (typeof child === 'string') {
|
||||
el.appendChild(document.createTextNode(child));
|
||||
} else {
|
||||
if (child) { el.appendChild(child); }
|
||||
}
|
||||
}
|
||||
|
||||
for (var attr in attrs) {
|
||||
if (attr == "className") {
|
||||
el[attr] = attrs[attr];
|
||||
} else {
|
||||
el.setAttribute(attr, attrs[attr]);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
|
||||
var showPassed, showSkipped;
|
||||
|
||||
this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
|
||||
this.createDom('div', { className: 'banner' },
|
||||
this.createDom('div', { className: 'logo' },
|
||||
this.createDom('span', { className: 'title' }, "Jasmine"),
|
||||
this.createDom('span', { className: 'version' }, runner.env.versionString())),
|
||||
this.createDom('div', { className: 'options' },
|
||||
"Show ",
|
||||
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
|
||||
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
|
||||
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
|
||||
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
|
||||
)
|
||||
),
|
||||
|
||||
this.runnerDiv = this.createDom('div', { className: 'runner running' },
|
||||
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
|
||||
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
|
||||
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
|
||||
);
|
||||
|
||||
this.document.body.appendChild(this.outerDiv);
|
||||
|
||||
var suites = runner.suites();
|
||||
for (var i = 0; i < suites.length; i++) {
|
||||
var suite = suites[i];
|
||||
var suiteDiv = this.createDom('div', { className: 'suite' },
|
||||
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
|
||||
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
|
||||
this.suiteDivs[suite.id] = suiteDiv;
|
||||
var parentDiv = this.outerDiv;
|
||||
if (suite.parentSuite) {
|
||||
parentDiv = this.suiteDivs[suite.parentSuite.id];
|
||||
}
|
||||
parentDiv.appendChild(suiteDiv);
|
||||
}
|
||||
|
||||
this.startedAt = new Date();
|
||||
|
||||
var self = this;
|
||||
showPassed.onclick = function(evt) {
|
||||
if (showPassed.checked) {
|
||||
self.outerDiv.className += ' show-passed';
|
||||
} else {
|
||||
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
|
||||
}
|
||||
};
|
||||
|
||||
showSkipped.onclick = function(evt) {
|
||||
if (showSkipped.checked) {
|
||||
self.outerDiv.className += ' show-skipped';
|
||||
} else {
|
||||
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
|
||||
var results = runner.results();
|
||||
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
|
||||
this.runnerDiv.setAttribute("class", className);
|
||||
//do it twice for IE
|
||||
this.runnerDiv.setAttribute("className", className);
|
||||
var specs = runner.specs();
|
||||
var specCount = 0;
|
||||
for (var i = 0; i < specs.length; i++) {
|
||||
if (this.specFilter(specs[i])) {
|
||||
specCount++;
|
||||
}
|
||||
}
|
||||
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
|
||||
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
|
||||
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
|
||||
|
||||
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
|
||||
var results = suite.results();
|
||||
var status = results.passed() ? 'passed' : 'failed';
|
||||
if (results.totalCount === 0) { // todo: change this to check results.skipped
|
||||
status = 'skipped';
|
||||
}
|
||||
this.suiteDivs[suite.id].className += " " + status;
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
|
||||
if (this.logRunningSpecs) {
|
||||
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
|
||||
}
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
|
||||
var results = spec.results();
|
||||
var status = results.passed() ? 'passed' : 'failed';
|
||||
if (results.skipped) {
|
||||
status = 'skipped';
|
||||
}
|
||||
var specDiv = this.createDom('div', { className: 'spec ' + status },
|
||||
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
|
||||
this.createDom('a', {
|
||||
className: 'description',
|
||||
href: '?spec=' + encodeURIComponent(spec.getFullName()),
|
||||
title: spec.getFullName()
|
||||
}, spec.description));
|
||||
|
||||
|
||||
var resultItems = results.getItems();
|
||||
var messagesDiv = this.createDom('div', { className: 'messages' });
|
||||
for (var i = 0; i < resultItems.length; i++) {
|
||||
var result = resultItems[i];
|
||||
|
||||
if (result.type == 'log') {
|
||||
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
|
||||
} else if (result.type == 'expect' && result.passed && !result.passed()) {
|
||||
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
|
||||
|
||||
if (result.trace.stack) {
|
||||
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (messagesDiv.childNodes.length > 0) {
|
||||
specDiv.appendChild(messagesDiv);
|
||||
}
|
||||
|
||||
this.suiteDivs[spec.suite.id].appendChild(specDiv);
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.log = function() {
|
||||
var console = jasmine.getGlobal().console;
|
||||
if (console && console.log) {
|
||||
if (console.log.apply) {
|
||||
console.log.apply(console, arguments);
|
||||
} else {
|
||||
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.getLocation = function() {
|
||||
return this.document.location;
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
|
||||
var paramMap = {};
|
||||
var params = this.getLocation().search.substring(1).split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
|
||||
}
|
||||
|
||||
if (!paramMap.spec) {
|
||||
return true;
|
||||
}
|
||||
return spec.getFullName().indexOf(paramMap.spec) === 0;
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
|
||||
|
||||
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
|
||||
#HTMLReporter a { text-decoration: none; }
|
||||
#HTMLReporter a:hover { text-decoration: underline; }
|
||||
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
|
||||
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
|
||||
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
|
||||
#HTMLReporter .version { color: #aaaaaa; }
|
||||
#HTMLReporter .banner { margin-top: 14px; }
|
||||
#HTMLReporter .duration { color: #aaaaaa; float: right; }
|
||||
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
|
||||
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
|
||||
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
|
||||
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
|
||||
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
|
||||
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
|
||||
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
|
||||
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
|
||||
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
|
||||
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
|
||||
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
|
||||
#HTMLReporter .runningAlert { background-color: #666666; }
|
||||
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
|
||||
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
|
||||
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
|
||||
#HTMLReporter .passingAlert { background-color: #a6b779; }
|
||||
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
|
||||
#HTMLReporter .failingAlert { background-color: #cf867e; }
|
||||
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
|
||||
#HTMLReporter .results { margin-top: 14px; }
|
||||
#HTMLReporter #details { display: none; }
|
||||
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
|
||||
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
|
||||
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
|
||||
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
|
||||
#HTMLReporter.showDetails .summary { display: none; }
|
||||
#HTMLReporter.showDetails #details { display: block; }
|
||||
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
|
||||
#HTMLReporter .summary { margin-top: 14px; }
|
||||
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
|
||||
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
|
||||
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
|
||||
#HTMLReporter .description + .suite { margin-top: 0; }
|
||||
#HTMLReporter .suite { margin-top: 14px; }
|
||||
#HTMLReporter .suite a { color: #333333; }
|
||||
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
|
||||
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
|
||||
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
|
||||
#HTMLReporter .resultMessage span.result { display: block; }
|
||||
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
|
||||
|
||||
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
|
||||
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
|
||||
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
|
||||
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
|
||||
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
|
||||
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
|
||||
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
|
||||
#TrivialReporter .runner.running { background-color: yellow; }
|
||||
#TrivialReporter .options { text-align: right; font-size: .8em; }
|
||||
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
|
||||
#TrivialReporter .suite .suite { margin: 5px; }
|
||||
#TrivialReporter .suite.passed { background-color: #dfd; }
|
||||
#TrivialReporter .suite.failed { background-color: #fdd; }
|
||||
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
|
||||
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
|
||||
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
|
||||
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
|
||||
#TrivialReporter .spec.skipped { background-color: #bbb; }
|
||||
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
|
||||
#TrivialReporter .passed { background-color: #cfc; display: none; }
|
||||
#TrivialReporter .failed { background-color: #fbb; }
|
||||
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
|
||||
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
|
||||
#TrivialReporter .resultMessage .mismatch { color: black; }
|
||||
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
|
||||
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
|
||||
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
|
||||
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
|
||||
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
describe('Connection', function() {
|
||||
var c;
|
||||
|
||||
beforeEach(function() {
|
||||
c = new iD.Connection();
|
||||
});
|
||||
|
||||
it('is instantiated', function() {
|
||||
expect(c).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
describe('Entity', function() {
|
||||
var entity;
|
||||
|
||||
beforeEach(function() {
|
||||
entity = new iD.Entity();
|
||||
});
|
||||
|
||||
it('has no entity type', function() {
|
||||
expect(entity.entityType).toEqual('');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
describe('Node', function() {
|
||||
var node;
|
||||
|
||||
beforeEach(function() {
|
||||
node = new iD.Node(null, 10, 38, -77);
|
||||
});
|
||||
|
||||
it('is a node entity', function() {
|
||||
expect(node.entityType).toEqual('node');
|
||||
});
|
||||
|
||||
it('should be initialized with a proper ID, lat, and lon', function() {
|
||||
expect(node.id).toEqual(10);
|
||||
expect(node.lat).toEqual(38);
|
||||
expect(node.lon).toEqual(-77);
|
||||
});
|
||||
|
||||
it('reprojects a latp parameter', function() {
|
||||
expect(node.latp).toBeCloseTo(41.1376);
|
||||
node.project();
|
||||
expect(node.latp).toBeCloseTo(41.1376);
|
||||
});
|
||||
|
||||
it('knows if it is within a bounding box', function() {
|
||||
expect(node.within(-90, 90, 90, -90)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('knows if it is without a bounding box', function() {
|
||||
expect(node.within(-90, -85, 90, -90)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
describe('Relation Member', function() {
|
||||
var rm;
|
||||
|
||||
beforeEach(function() {
|
||||
rm = new iD.RelationMember();
|
||||
});
|
||||
|
||||
it('is instantiated', function() {
|
||||
expect(rm).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
describe('Util', function() {
|
||||
var util;
|
||||
|
||||
it('gives unique ids', function() {
|
||||
var a = iD.Util.id(),
|
||||
b = iD.Util.id(),
|
||||
c = iD.Util.id(),
|
||||
d = iD.Util.id();
|
||||
expect(a === b).toEqual(false);
|
||||
expect(b === c).toEqual(false);
|
||||
expect(c === d).toEqual(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
describe('Way', function() {
|
||||
var way;
|
||||
|
||||
beforeEach(function() {
|
||||
way = new iD.Way();
|
||||
});
|
||||
|
||||
it('is a way', function() {
|
||||
expect(way.entityType).toEqual('way');
|
||||
});
|
||||
|
||||
it('has zero nodes by default', function() {
|
||||
expect(way.nodes.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('is closed by default', function() {
|
||||
expect(way.isClosed()).toEqual(true);
|
||||
});
|
||||
|
||||
it('is a way when it has no nodes', function() {
|
||||
expect(way.isType('way')).toEqual(true);
|
||||
});
|
||||
|
||||
it('is also an area when it has no nodes', function() {
|
||||
expect(way.isType('area')).toEqual(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user