mirror of
https://github.com/FoggedLens/iD.git
synced 2026-04-21 19:26:41 +02:00
Merge branch 'master' of git://github.com/systemed/iD into rotate2
Conflicts: index.html test/index.html
This commit is contained in:
+191
-45
@@ -19,35 +19,41 @@ which implements map panning and zooming.
|
||||
|
||||
## Core
|
||||
|
||||
The iD *core* implements the OSM data types, a graph of OSM object's
|
||||
relationships to each other, and an undo/redo history for changes made during
|
||||
editing. It aims to be generic enough to be used by other JavaScript-based
|
||||
The iD *core* implements OSM data types, a graph of OSM objects'
|
||||
relationships to one another, an undo/redo history for changes made during
|
||||
editing, and a couple of important auxiliary classes. It eventually aims
|
||||
to be a reusable, modular library to kickstart other JavaScript-based
|
||||
tools for OpenStreetMap.
|
||||
|
||||
Briefly, the OSM data model includes three basic data types: nodes, ways, and
|
||||
relations. A _node_ is a point type, having a single geographic coordinate. A
|
||||
_way_ is an ordered list of nodes. And a _relation_ groups together nodes,
|
||||
ways, and other relations to provide free-form higher-level structures. Each
|
||||
of these three types has _tags_: an associative array of key-value pairs which
|
||||
The OSM data model includes three basic data types: nodes, ways, and
|
||||
relations.
|
||||
|
||||
* A _node_ is a point type, having a single geographic coordinate.
|
||||
* A _way_ is an ordered list of nodes.
|
||||
* A _relation_ groups together nodes, ways, and other relations to provide
|
||||
free-form higher-level structures.
|
||||
|
||||
Each of these three types has _tags_: an associative array of key-value pairs which
|
||||
describe the object.
|
||||
|
||||
In iD, these three types are implemented by `iD.Node`, `iD.Way` and
|
||||
`iD.Relation`. These three classes inherit from a common base, `iD.Entity`
|
||||
(the only use of classical inheritance in iD). Generically, we refer to a
|
||||
`iD.Relation`. These three classes inherit from a common base, `iD.Entity`.
|
||||
This is the only use of classical inheritance in iD, but it's justified
|
||||
by the common functionality of the types. Generically, we refer to a
|
||||
node, way or relation as an _entity_.
|
||||
|
||||
Every entity has an _ID_ either assigned by the OSM database, or, for an
|
||||
entity that is newly created, constructed as a proxy consisting of a negative
|
||||
numeral. IDs from the OSM database as treated as opaque strings; no
|
||||
Every entity has an _ID_ either assigned by the OSM database or
|
||||
a negative, local identifier assigned by iD for newly-created objects.
|
||||
IDs from the OSM database as treated as opaque strings; no
|
||||
[assumptions](http://lists.openstreetmap.org/pipermail/dev/2013-February/026495.html)
|
||||
are made of them other than that they can be compared for identity and do not
|
||||
begin with a minus sign (and thus will not conflict with proxy IDs). In fact,
|
||||
in the OSM database the three types of entities have separate ID spaces; a
|
||||
node can have the same ID as a way, for instance. Because it is useful to
|
||||
store heterogeneous entities in the same datastructure, iD ensures that every
|
||||
entity has a fully-unique ID by prefixing each OSM ID with the first letter of
|
||||
the entity type. For example, a way with OSM ID 123456 is represented as
|
||||
'w123456' within iD.
|
||||
begin with a minus sign (and thus will not conflict with proxy IDs). The three
|
||||
types of entities have separate ID spaces: a
|
||||
node can have the same numeric ID as a way or a relation. Instead of segregating
|
||||
ways, nodes, and other entities into different datastructures,
|
||||
iD internally uses fully-unique IDs generated by prefixing
|
||||
each OSM ID with the first letter of the entity type. For example, a way
|
||||
with OSM ID 123456 is represented as 'w123456' within iD.
|
||||
|
||||
iD entities are *immutable*: once constructed, an `Entity` object cannot
|
||||
change. Tags cannot be updated; nodes cannot be added or removed from ways,
|
||||
@@ -56,8 +62,9 @@ entity: if your code has a reference to one, it is safe to store it and use it
|
||||
later, knowing that it cannot have been changed outside of your control. It
|
||||
also makes it possible to implement the entity graph (described below) as an
|
||||
efficient [persistent data
|
||||
structure](http://en.wikipedia.org/wiki/Persistent_data_structure). But
|
||||
obviously, iD is an editor, and must allow entities to change somehow. The
|
||||
structure](http://en.wikipedia.org/wiki/Persistent_data_structure).
|
||||
|
||||
Since iD is an editor, it must allow for new versions of entities. The
|
||||
solution is that all edits produce new copies of anything that changes. At the
|
||||
entity level, this takes the form of methods such as `iD.Node#move`, which
|
||||
returns a new node object that has the same ID and tags as the original, but a
|
||||
@@ -65,39 +72,82 @@ different coordinate. More generically, `iD.Entity#update` returns a new
|
||||
entity of the same type and ID as the original but with specified properties
|
||||
such as `nodes`, `tags`, or `members` replaced.
|
||||
|
||||

|
||||
|
||||
Entities are related to one another: ways have many nodes and relations have
|
||||
many members. In order to render a map of a certain area, iD needs a
|
||||
many members. To render a map of a certain area, iD needs a
|
||||
datastructure to hold all the entities in that area and traverse these
|
||||
relationships. `iD.Graph` provides this functionality. The core of a graph is
|
||||
a map between IDs and the associated entities; given an ID, the graph can give
|
||||
you the entity. Like entities, a graph is immutable: adding, replacing, or
|
||||
removing an entity produces a new graph, and the original is unchanged.
|
||||
Because entities are immutable, the original and new graphs can share
|
||||
references to entities that have not changed, keeping memory use to a minimum.
|
||||
If you are familiar with how git works internally, this persistent data
|
||||
structure approach is very similar.
|
||||
Because entities are immutable, the original and new graphs can minimize
|
||||
memory use by sharing references to entities that have not changed instead of
|
||||
copying the entire graph.
|
||||
This persistent data structure approach is similar to the internals of
|
||||
the [git](http://git-scm.com/) revision control system.
|
||||
|
||||
The final component of the core is comprised of `iD.History` and
|
||||
`iD.Difference`, which track the changes made in an editing session and
|
||||
provide undo/redo capabilities. Here, the immutable nature of the core types
|
||||
really pays off: the history is a simple stack of graphs, each representing
|
||||
the state of the data at a particular point in editing. The graph at the top
|
||||
of the stack is the current state, off which all rendering is based. To undo
|
||||
the last change, this graph is popped off the stack, and the map is
|
||||
re-rendered based on the new top of the stack. Contrast this to a mutable
|
||||
graph as used in JOSM and Potlatch: every command that changes the graph must
|
||||
implement an equal and opposite undo command that restores the graph to the
|
||||
previous state.
|
||||
The final major component of the core is `iD.History`, which tracks the changes
|
||||
made in an editing session and provides undo/redo capabilities. Here, the
|
||||
immutable nature of the core types really pays off: the history is a simple
|
||||
stack of graphs, each representing the state of the data at a particular point
|
||||
in editing. The graph at the top of the stack is the current state, off which
|
||||
all rendering is based. To undo the last change, this graph is popped off the
|
||||
stack, and the map is re-rendered based on the new top of the stack.
|
||||
|
||||
This approach constitutes one of the main differences between iD's approach
|
||||
to data and that of [JOSM](http://josm.openstreetmap.de/) and
|
||||
[Potlatch 2](http://wiki.openstreetmap.org/wiki/Potlatch_2).
|
||||
Instead of changing a single copy of local data and having to implement
|
||||
an 'undo' for each specific action, actions in iD do not need to be aware
|
||||
of history and the undo system.
|
||||
|
||||
Finally, we have the auxiliary classes `iD.Difference` and `iD.Tree`.
|
||||
|
||||
`iD.Difference` encapsulates the difference between two graphs, and knows how to calculate the
|
||||
set of entities that were created, modified, or deleted, and need to be redrawn.
|
||||
|
||||
```js
|
||||
var a = iD.Graph(), b = iD.Graph();
|
||||
// (fill a & b with data)
|
||||
var difference = iD.Difference(a, b);
|
||||
|
||||
// returns entities created between and b
|
||||
difference.created();
|
||||
```
|
||||
|
||||
`iD.Tree` calculates the set of downloaded entities that are visible in the
|
||||
current map view. To calculate this quickly during map
|
||||
interaction, it uses an [R-tree](http://en.wikipedia.org/wiki/R-tree).
|
||||
|
||||
```js
|
||||
var graph = iD.Graph();
|
||||
// (load OSM data into graph)
|
||||
|
||||
// this tree indexes the contents of the graph
|
||||
var tree = iD.Tree(graph);
|
||||
|
||||
// quickly pull all features that intersect with an extent
|
||||
var features = tree.intersects(
|
||||
iD.geo.Extent([0, 0], [2, 2]), tree.graph());
|
||||
```
|
||||
|
||||
## Actions
|
||||
|
||||
In iD, an _action_ is a function that accepts a graph as input and returns a
|
||||
modified graph as output. Actions typically need other inputs as well; for
|
||||
new, modified graph as output. Actions typically need other inputs as well; for
|
||||
example, `iD.actions.DeleteNode` also requires the ID of a node to delete. The
|
||||
additional input is passed to the action's constructor:
|
||||
|
||||
``` var action = iD.actions.DeleteNode('n123456'); // construct the action var
|
||||
newGraph = action(oldGraph); // apply the action ```
|
||||
```js
|
||||
// construct the action: this returns a function that remembers the
|
||||
// value `n123456` in a closure so that when it's called, it runs
|
||||
// the specified action on the graph
|
||||
var action = iD.actions.DeleteNode('n123456');
|
||||
|
||||
// apply the action, yielding a new graph. oldGraph is untouched.
|
||||
newGraph = action(oldGraph);
|
||||
```
|
||||
|
||||
iD provides actions for all the typical things an editor needs to do: add a
|
||||
new entity, split a way in two, connect the vertices of two ways together, and
|
||||
@@ -112,9 +162,8 @@ is a member.
|
||||
|
||||
As you can imagine, implementing all these details requires an expert
|
||||
knowledge of the OpenStreetMap data model. It is our hope that JavaScript
|
||||
based tools for OpenStreetMap can reuse the implementations provided by iD in
|
||||
other contexts, significantly reducing the work necessary to create a robust
|
||||
tool.
|
||||
based tools for OpenStreetMap can reuse the iD's core implementation,
|
||||
significantly reducing the work necessary to create a robust tool.
|
||||
|
||||
## Modes
|
||||
|
||||
@@ -200,4 +249,101 @@ the history, and then enter the appropriate mode. For example,
|
||||
`iD.operations.Split` performs `iD.actions.Split`, then enters
|
||||
`iD.modes.Select` with the resulting ways selected.
|
||||
|
||||
## Rendering and other UI
|
||||
## Map Rendering
|
||||
|
||||
Finally, we get to the parts of iD that actually draw and manipulate the map
|
||||
entities on screen. The rendering is coordinated by `iD.Map`, which takes care
|
||||
of setting up a [Spherical Mercator](http://bl.ocks.org/mbostock/3757132)
|
||||
projection and the [zoom
|
||||
behavior](https://github.com/mbostock/d3/wiki/Zoom-Behavior), and provides
|
||||
accessors for such things as the current zoom level and map center.
|
||||
|
||||
For rendering entities on screen, we found it convenient to adopt a geometric
|
||||
vocabulary that provides a slightly higher-level representation than the basic
|
||||
entity types of the OSM data model:
|
||||
|
||||
* A _point_ is a node that is not a member of any way.
|
||||
* A _vertex_ is a node that is a member of one or more ways.
|
||||
* A _line_ is a way that is not an area.
|
||||
* An _area_ is a way that is circular and has certain tags, or a series of one
|
||||
or more ways grouped in a multipolygon relation.
|
||||
|
||||
For each of these geometric types, `iD.svg` has a corresponding module:
|
||||
`iD.svg.Points`, `iD.svg.Vertices`, `iD.svg.Lines`, and `iD.svg.Areas`. To
|
||||
render entities on screen, `iD.Map` delegates to these modules. Internally,
|
||||
they make heavy use of [d3 joins](http://bost.ocks.org/mike/join/) to
|
||||
manipulate the SVG elements that visually represent the map entities. When an
|
||||
entity is rendered for the first time, it is part of the _enter_ selection,
|
||||
and the SVG elements needed to represent it are created. When an entity is
|
||||
modified, it is part of the _update_ selection, and the appropriate attributes
|
||||
of the SVG element (for example, those that specify the location on screen)
|
||||
are updated. And when an entity is deleted (or simply moves offscreen), the
|
||||
corresponding SVG element is in the _exit_ selection, and will be removed.
|
||||
|
||||
The `iD.svg` modules apply classes to the SVG elements based on the entity
|
||||
tags, via `iD.svg.TagClasses`. For example, an entity tagged with
|
||||
`highway=residential` gets two classes: `tag-highway` and
|
||||
`tag-highway-residential`. This allows distinct visual styles to be applied
|
||||
via CSS at either the key or key-value levels. SVG elements also receive a
|
||||
class corresponding to their entity type (`node`, `way`, or `relation`) and
|
||||
one corresponding to their geometry type (`point`, `line`, or `area`).
|
||||
|
||||
The `iD.svg` namespace has a few other modules that don't have a one-to-one
|
||||
correspondence with entities:
|
||||
|
||||
* `iD.svg.Midpoints` renders the small "virtual node" at the midpoint between
|
||||
two vertices.
|
||||
* `iD.svg.Labels` renders the textual
|
||||
[labels](http://mapbox.com/osmdev/2013/02/12/labeling-id/).
|
||||
* `iD.svg.Surface` sets up a number of layers that ensure that map elements
|
||||
appear in an appropriate z-order.
|
||||
|
||||
## Other UI
|
||||
|
||||
iD provides a lot of user interface elements other than the core map component:
|
||||
the page footer, the interface for saving changes, the splash screen you see
|
||||
the first time you use iD, the geocoding and background layer controls, and the
|
||||
tag/preset editor, for example.
|
||||
|
||||

|
||||
|
||||
The implementations for all non-map UI components live in the `iD.ui` namespace.
|
||||
Many of the modules in this namespace follow a pattern for reusable d3
|
||||
components [originally suggested](http://bost.ocks.org/mike/chart/) by Mike
|
||||
Bostock in the context of charts. The entry point to a UI element is a
|
||||
constructor function, e.g. `iD.ui.Geocoder()`. The constructor function may
|
||||
require a set of mandatory arguments; for most UI components exactly one
|
||||
argument is required, a `context` object produced by the top-level `iD()`
|
||||
function.
|
||||
|
||||
A component needs some way to be rendered on screen by creating new DOM
|
||||
elements or manipulating existing elements. This is done by calling the
|
||||
component as a function, and passing a d3 selection where the component should
|
||||
render itself:
|
||||
|
||||
```
|
||||
var container = d3.select('body').append('div')
|
||||
.attr('class', 'map-control geocode-control');
|
||||
|
||||
var geocoder = iD.ui.Geocoder(context)(container);
|
||||
```
|
||||
|
||||
Alternatively, and more commonly, the same result is accomplished with
|
||||
[d3.selection#call](https://github.com/mbostock/d3/wiki/Selections#wiki-call):
|
||||
|
||||
```
|
||||
d3.select('body').append('div')
|
||||
.attr('class', 'map-control geocode-control')
|
||||
.call(iD.ui.Geocoder(context));
|
||||
```
|
||||
|
||||
Some components are reconfigurable, and some provide functionality beyond
|
||||
basic rendering. Both reconfiguration and extended functionality are exposed
|
||||
via module functions:
|
||||
|
||||
```
|
||||
var inspector = iD.ui.Inspector();
|
||||
inspector(container); // render the inspector
|
||||
inspector.tags(); // retrieve the current tags
|
||||
inspector.on('change', callback); // get notified when a tag change is made
|
||||
```
|
||||
|
||||
@@ -18,7 +18,6 @@ all: \
|
||||
js/lib/d3.keybinding.js \
|
||||
js/lib/d3.one.js \
|
||||
js/lib/d3.size.js \
|
||||
js/lib/d3.tail.js \
|
||||
js/lib/d3.trigger.js \
|
||||
js/lib/d3.typeahead.js \
|
||||
js/lib/jxon.js \
|
||||
@@ -51,6 +50,7 @@ all: \
|
||||
js/id/svg/*.js \
|
||||
js/id/ui.js \
|
||||
js/id/ui/*.js \
|
||||
js/id/ui/preset/*.js \
|
||||
js/id/presetdata.js \
|
||||
js/id/validate.js \
|
||||
js/id/end.js \
|
||||
@@ -63,7 +63,7 @@ iD.js: Makefile
|
||||
|
||||
%.min.js: %.js Makefile
|
||||
@rm -f $@
|
||||
$(JS_COMPILER) $< -o $@
|
||||
$(JS_COMPILER) $< -c -m -o $@
|
||||
|
||||
clean:
|
||||
rm -f iD*.js
|
||||
|
||||
+3
-3
@@ -23,7 +23,6 @@
|
||||
<script src='js/lib/d3.size.js'></script>
|
||||
<script src='js/lib/d3.trigger.js'></script>
|
||||
<script src='js/lib/d3.keybinding.js'></script>
|
||||
<script src='js/lib/d3.tail.js'></script>
|
||||
<script src='js/lib/d3-compat.js'></script>
|
||||
<script src='js/lib/bootstrap-tooltip.js'></script>
|
||||
<script src='js/lib/rtree.js'></script>
|
||||
@@ -70,6 +69,7 @@
|
||||
<script src='js/id/ui/flash.js'></script>
|
||||
<script src='js/id/ui/save.js'></script>
|
||||
<script src='js/id/ui/tag_reference.js'></script>
|
||||
<script src='js/id/ui/tail.js'></script>
|
||||
<script src='js/id/ui/key_reference.js'></script>
|
||||
|
||||
<script src='js/id/actions.js'></script>
|
||||
@@ -81,7 +81,7 @@
|
||||
<script src="js/id/actions/delete_way.js"></script>
|
||||
<script src='js/id/actions/disconnect.js'></script>
|
||||
<script src='js/id/actions/move_node.js'></script>
|
||||
<script src='js/id/actions/move_way.js'></script>
|
||||
<script src='js/id/actions/move.js'></script>
|
||||
<script src='js/id/actions/circularize.js'></script>
|
||||
<script src='js/id/actions/noop.js'></script>
|
||||
<script src='js/id/actions/reverse.js'></script>
|
||||
@@ -103,7 +103,7 @@
|
||||
<script src='js/id/modes/browse.js'></script>
|
||||
<script src='js/id/modes/draw_area.js'></script>
|
||||
<script src='js/id/modes/draw_line.js'></script>
|
||||
<script src='js/id/modes/move_way.js'></script>
|
||||
<script src='js/id/modes/move.js'></script>
|
||||
<script src='js/id/modes/select.js'></script>
|
||||
|
||||
<script src='js/id/operations.js'></script>
|
||||
|
||||
+40
-7
@@ -278,6 +278,7 @@ button {
|
||||
transition: background 100ms;
|
||||
}
|
||||
|
||||
button:focus,
|
||||
button:hover {
|
||||
background-color: #ececec;
|
||||
}
|
||||
@@ -641,6 +642,26 @@ div.combobox {
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
|
||||
.rowselect .item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.rowselect .item label:hover{
|
||||
background-color: #ececec;
|
||||
}
|
||||
|
||||
.rowselect .item label {
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.rowselect .item div {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Address input */
|
||||
|
||||
.preset-input .addr-housename {
|
||||
@@ -653,7 +674,7 @@ div.combobox {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.preset-input .addr-streetname {
|
||||
.preset-input .addr-street {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
@@ -756,17 +777,25 @@ div.combobox {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.preset-grid.filtered .grid-entry:first-child,
|
||||
.preset-grid .grid-entry .grid-inner:hover {
|
||||
.preset-grid.filtered .grid-entry:first-child {
|
||||
background: #ececec;
|
||||
}
|
||||
|
||||
.preset-grid .grid-entry .grid-inner:hover {
|
||||
background: inherit;
|
||||
.grid-entry .preset-help {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: black;
|
||||
}
|
||||
|
||||
.grid-entry .grid-inner {
|
||||
position: absolute;
|
||||
.grid-entry .preset-help:hover {
|
||||
background: grey;
|
||||
}
|
||||
|
||||
.preset-inspect {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.grid-entry .preset-icon-fill.area {
|
||||
@@ -1099,6 +1128,10 @@ img.tile {
|
||||
-webkit-transform-origin:0 0;
|
||||
-moz-transform-origin:0 0;
|
||||
-o-transform-origin:0 0;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#surface {
|
||||
|
||||
+11
-6
@@ -229,6 +229,11 @@ path.area.fill {
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
|
||||
path.line.stroke {
|
||||
stroke: white;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
path.stroke.tag-natural {
|
||||
stroke: #b6e199;
|
||||
stroke-width:1;
|
||||
@@ -507,28 +512,28 @@ svg[data-zoom="16"] path.casing.tag-highway-construction {
|
||||
|
||||
/* railways */
|
||||
|
||||
path.stroke.tag-railway {
|
||||
.line.stroke.tag-railway {
|
||||
stroke: #eee;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: butt;
|
||||
stroke-dasharray: 12,12;
|
||||
}
|
||||
path.casing.tag-railway {
|
||||
.line.casing.tag-railway {
|
||||
stroke: #555;
|
||||
stroke-width: 4;
|
||||
}
|
||||
|
||||
path.stroke.tag-railway-abandoned {
|
||||
.line.stroke.tag-railway-abandoned {
|
||||
stroke: #eee;
|
||||
}
|
||||
path.casing.tag-railway-abandoned {
|
||||
.line.casing.tag-railway-abandoned {
|
||||
stroke: #999;
|
||||
}
|
||||
|
||||
path.stroke.tag-railway-subway {
|
||||
.line.stroke.tag-railway-subway {
|
||||
stroke: #666;
|
||||
}
|
||||
path.casing.tag-railway-subway {
|
||||
.line.casing.tag-railway-subway {
|
||||
stroke: #222;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,16 +15,6 @@ In order to unify the construction interface for these two styles, classical cla
|
||||
[instanceof trick](http://ejohn.org/blog/simple-class-instantiation/). This allows instantiation
|
||||
of both module pattern classes and classical classes to be done without using `new`.
|
||||
|
||||
Function names
|
||||
--------------
|
||||
Anything that creates and calls an Action should be prefixed with do:
|
||||
doSetLatLon(lat,lon)
|
||||
|
||||
Anything that is called by an Action, to do the actual work, should be prefixed with an underscore:
|
||||
_setLatLon(lat,lon)
|
||||
|
||||
and commented as such. Underscores are also used to prefix private methods.
|
||||
|
||||
File naming
|
||||
-----------
|
||||
The filename should be the name of the base class. You can add subclasses within
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 96 KiB |
+4
-3
@@ -20,11 +20,11 @@
|
||||
<script src='js/lib/jxon.js'></script>
|
||||
<script src='js/lib/d3.typeahead.js'></script>
|
||||
<script src='js/lib/d3.combobox.js'></script>
|
||||
<script src='js/lib/d3.rowselect.js'></script>
|
||||
<script src='js/lib/d3.geo.tile.js'></script>
|
||||
<script src='js/lib/d3.size.js'></script>
|
||||
<script src='js/lib/d3.trigger.js'></script>
|
||||
<script src='js/lib/d3.keybinding.js'></script>
|
||||
<script src='js/lib/d3.tail.js'></script>
|
||||
<script src='js/lib/d3-compat.js'></script>
|
||||
<script src='js/lib/bootstrap-tooltip.js'></script>
|
||||
<script src='js/lib/rtree.js'></script>
|
||||
@@ -91,7 +91,8 @@
|
||||
<script src='js/id/ui/taglist.js'></script>
|
||||
<script src='js/id/ui/presetgrid.js'></script>
|
||||
<script src='js/id/ui/tageditor.js'></script>
|
||||
<script src='js/id/ui/address.js'></script>
|
||||
<script src='js/id/ui/tail.js'></script>
|
||||
<script src='js/id/ui/preset/address.js'></script>
|
||||
|
||||
<script src='js/id/actions.js'></script>
|
||||
<script src="js/id/actions/add_midpoint.js"></script>
|
||||
@@ -107,7 +108,7 @@
|
||||
<script src='js/id/actions/join.js'></script>
|
||||
<script src='js/id/actions/merge.js'></script>
|
||||
<script src='js/id/actions/move_node.js'></script>
|
||||
<script src='js/id/actions/move_way.js'></script>
|
||||
<script src='js/id/actions/move.js'></script>
|
||||
<script src='js/id/actions/rotate_way.js'></script>
|
||||
<script src='js/id/actions/circularize.js'></script>
|
||||
<script src='js/id/actions/orthogonalize.js'></script>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
|
||||
iD.actions.DeleteRelation = function(relationId) {
|
||||
function deleteEntity(entity, graph) {
|
||||
return !graph.parentWays(entity).length &&
|
||||
!graph.parentRelations(entity).length &&
|
||||
!entity.hasInterestingTags();
|
||||
}
|
||||
|
||||
return function(graph) {
|
||||
var relation = graph.entity(relationId);
|
||||
|
||||
@@ -8,6 +14,15 @@ iD.actions.DeleteRelation = function(relationId) {
|
||||
graph = graph.replace(parent.removeMember(relationId));
|
||||
});
|
||||
|
||||
_.uniq(_.pluck(relation.members, 'id')).forEach(function(memberId) {
|
||||
graph = graph.replace(relation.removeMember(memberId));
|
||||
|
||||
var entity = graph.entity(memberId);
|
||||
if (deleteEntity(entity, graph)) {
|
||||
graph = iD.actions.DeleteMultiple([memberId])(graph);
|
||||
}
|
||||
});
|
||||
|
||||
return graph.remove(relation);
|
||||
};
|
||||
};
|
||||
|
||||
+10
-12
@@ -1,5 +1,11 @@
|
||||
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
|
||||
iD.actions.DeleteWay = function(wayId) {
|
||||
function deleteNode(node, graph) {
|
||||
return !graph.parentWays(node).length &&
|
||||
!graph.parentRelations(node).length &&
|
||||
!node.hasInterestingTags();
|
||||
}
|
||||
|
||||
return function(graph) {
|
||||
var way = graph.entity(wayId);
|
||||
|
||||
@@ -8,20 +14,12 @@ iD.actions.DeleteWay = function(wayId) {
|
||||
graph = graph.replace(parent.removeMember(wayId));
|
||||
});
|
||||
|
||||
way.nodes.forEach(function(nodeId) {
|
||||
var node = graph.entity(nodeId);
|
||||
|
||||
// Circular ways include nodes more than once, so they
|
||||
// can be deleted on earlier iterations of this loop.
|
||||
if (!node) return;
|
||||
|
||||
_.uniq(way.nodes).forEach(function(nodeId) {
|
||||
graph = graph.replace(way.removeNode(nodeId));
|
||||
|
||||
if (!graph.parentWays(node).length &&
|
||||
!graph.parentRelations(node).length) {
|
||||
if (!node.hasInterestingTags()) {
|
||||
graph = graph.remove(node);
|
||||
}
|
||||
var node = graph.entity(nodeId);
|
||||
if (deleteNode(node, graph)) {
|
||||
graph = graph.remove(node);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
|
||||
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
|
||||
iD.actions.Move = function(ids, delta, projection) {
|
||||
function addNodes(ids, nodes, graph) {
|
||||
ids.forEach(function(id) {
|
||||
var entity = graph.entity(id);
|
||||
if (entity.type === 'node') {
|
||||
nodes.push(id);
|
||||
} else if (entity.type === 'way') {
|
||||
nodes.push.apply(nodes, entity.nodes);
|
||||
} else {
|
||||
addNodes(_.pluck(entity.members, 'id'), nodes, graph);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return function(graph) {
|
||||
var nodes = [];
|
||||
|
||||
addNodes(ids, nodes, graph);
|
||||
|
||||
_.uniq(nodes).forEach(function(id) {
|
||||
var node = graph.entity(id),
|
||||
start = projection(node.loc),
|
||||
end = projection.invert([start[0] + delta[0], start[1] + delta[1]]);
|
||||
graph = graph.replace(node.move(end));
|
||||
});
|
||||
|
||||
return graph;
|
||||
};
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
iD.actions.MoveWay = function(wayId, delta, projection) {
|
||||
return function(graph) {
|
||||
return graph.update(function(graph) {
|
||||
var way = graph.entity(wayId);
|
||||
|
||||
_.uniq(way.nodes).forEach(function(id) {
|
||||
var node = graph.entity(id),
|
||||
start = projection(node.loc),
|
||||
end = projection.invert([start[0] + delta[0], start[1] + delta[1]]);
|
||||
graph = graph.replace(node.move(end));
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -98,7 +98,8 @@ iD.behavior.DragNode = function(context) {
|
||||
}
|
||||
}
|
||||
|
||||
context.replace(iD.actions.MoveNode(entity.id, loc));
|
||||
context.replace(iD.actions.MoveNode(entity.id, loc),
|
||||
t('operations.move.annotation.' + entity.geometry(context.graph())));
|
||||
}
|
||||
|
||||
function end(entity) {
|
||||
|
||||
@@ -240,7 +240,7 @@ iD.History = function(context) {
|
||||
context.storage(getKey('nextIDs', null));
|
||||
context.storage(getKey('index', null));
|
||||
|
||||
stack = JSON.parse(json).map(function(d, i) {
|
||||
stack = JSON.parse(json).map(function(d) {
|
||||
d.graph = iD.Graph(stack[0].graph).load(d.entities);
|
||||
return d;
|
||||
});
|
||||
|
||||
+4
-3
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
iD.Tree = function(graph) {
|
||||
|
||||
var rtree = new RTree(),
|
||||
@@ -58,7 +56,10 @@ iD.Tree = function(graph) {
|
||||
});
|
||||
|
||||
var created = diff.created().concat(queuedCreated);
|
||||
modified = d3.values(diff.addParents(modified)).concat(queuedModified);
|
||||
modified = d3.values(diff.addParents(modified))
|
||||
// some parents might be created, not modified
|
||||
.filter(function(d) { return !!graph.entity(d.id); })
|
||||
.concat(queuedModified);
|
||||
queuedCreated = [];
|
||||
queuedModified = [];
|
||||
|
||||
|
||||
+3
-2
@@ -4,7 +4,7 @@ window.iD = function () {
|
||||
|
||||
// https://github.com/systemed/iD/issues/772
|
||||
// http://mathiasbynens.be/notes/localstorage-pattern#comment-9
|
||||
try { storage = localStorage } catch (e) {}
|
||||
try { storage = localStorage; } catch (e) {}
|
||||
storage = storage || {};
|
||||
|
||||
context.storage = function(k, v) {
|
||||
@@ -106,7 +106,8 @@ window.iD = function () {
|
||||
context.background()
|
||||
.source(_.find(iD.layers, function(l) {
|
||||
if (l.data.sourcetag === q.layer) {
|
||||
return (detected = true);
|
||||
detected = true;
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -10,13 +10,12 @@ iD.modes.AddLine = function(context) {
|
||||
var behavior = iD.behavior.AddWay(context)
|
||||
.on('start', start)
|
||||
.on('startFromWay', startFromWay)
|
||||
.on('startFromNode', startFromNode),
|
||||
defaultTags = {highway: 'residential'};
|
||||
.on('startFromNode', startFromNode);
|
||||
|
||||
function start(loc) {
|
||||
var graph = context.graph(),
|
||||
node = iD.Node({loc: loc}),
|
||||
way = iD.Way({tags: defaultTags});
|
||||
way = iD.Way();
|
||||
|
||||
context.perform(
|
||||
iD.actions.AddEntity(node),
|
||||
@@ -29,7 +28,7 @@ iD.modes.AddLine = function(context) {
|
||||
function startFromWay(other, loc, index) {
|
||||
var graph = context.graph(),
|
||||
node = iD.Node({loc: loc}),
|
||||
way = iD.Way({tags: defaultTags});
|
||||
way = iD.Way();
|
||||
|
||||
context.perform(
|
||||
iD.actions.AddEntity(node),
|
||||
@@ -52,7 +51,7 @@ iD.modes.AddLine = function(context) {
|
||||
context.enter(iD.modes.DrawLine(context, parent.id, 'forward', graph));
|
||||
|
||||
} else {
|
||||
var way = iD.Way({tags: defaultTags});
|
||||
var way = iD.Way();
|
||||
|
||||
context.perform(
|
||||
iD.actions.AddEntity(way),
|
||||
|
||||
+8
-19
@@ -4,14 +4,13 @@ iD.modes.Move = function(context, entityIDs) {
|
||||
button: 'browse'
|
||||
};
|
||||
|
||||
var keybinding = d3.keybinding('move'),
|
||||
entities = entityIDs.map(context.entity);
|
||||
var keybinding = d3.keybinding('move');
|
||||
|
||||
mode.enter = function() {
|
||||
var origin,
|
||||
nudgeInterval,
|
||||
annotation = entities.length === 1 ?
|
||||
t('operations.move.annotation.' + context.geometry(entities[0].id)) :
|
||||
annotation = entityIDs.length === 1 ?
|
||||
t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
|
||||
t('operations.move.annotation.multiple');
|
||||
|
||||
context.perform(
|
||||
@@ -57,29 +56,19 @@ iD.modes.Move = function(context, entityIDs) {
|
||||
|
||||
origin = context.map().mouseCoordinates();
|
||||
|
||||
entities.forEach(function(entity) {
|
||||
if (entity.type === 'way') {
|
||||
context.replace(
|
||||
iD.actions.MoveWay(entity.id, delta, context.projection));
|
||||
} else if (entity.type === 'node') {
|
||||
var start = context.projection(context.entity(entity.id).loc),
|
||||
end = [start[0] + delta[0], start[1] + delta[1]],
|
||||
loc = context.projection.invert(end);
|
||||
context.replace(iD.actions.MoveNode(entity.id, loc));
|
||||
}
|
||||
});
|
||||
|
||||
context.replace(iD.actions.Noop(), annotation);
|
||||
context.replace(
|
||||
iD.actions.Move(entityIDs, delta, context.projection),
|
||||
annotation);
|
||||
}
|
||||
|
||||
function finish() {
|
||||
d3.event.stopPropagation();
|
||||
context.enter(iD.modes.Select(context, entityIDs, true));
|
||||
context.enter(iD.modes.Select(context, entityIDs));
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
context.pop();
|
||||
context.enter(iD.modes.Select(context, entityIDs, true));
|
||||
context.enter(iD.modes.Select(context, entityIDs));
|
||||
}
|
||||
|
||||
function undone() {
|
||||
|
||||
@@ -4,7 +4,7 @@ iD.modes.Select = function(context, selection, initial) {
|
||||
button: 'browse'
|
||||
};
|
||||
|
||||
var inspector = iD.ui.Inspector().initial(!!initial),
|
||||
var inspector = iD.ui.Inspector(context).initial(!!initial),
|
||||
keybinding = d3.keybinding('select'),
|
||||
timeout = null,
|
||||
behaviors = [
|
||||
@@ -84,7 +84,6 @@ iD.modes.Select = function(context, selection, initial) {
|
||||
|
||||
if (entity) {
|
||||
inspector
|
||||
.context(context)
|
||||
.presetData(context.connection().presetData());
|
||||
|
||||
context.container()
|
||||
|
||||
+7
-13
@@ -4,8 +4,6 @@ iD.OAuth = function(context) {
|
||||
keys,
|
||||
oauth = {};
|
||||
|
||||
function keyclean(x) { return x.replace(/\W/g, ''); }
|
||||
|
||||
function timenonce(o) {
|
||||
o.oauth_timestamp = ohauth.timestamp();
|
||||
o.oauth_nonce = ohauth.nonce();
|
||||
@@ -73,17 +71,13 @@ iD.OAuth = function(context) {
|
||||
['top', screen.height / 2 - h / 2]].map(function(x) {
|
||||
return x.join('=');
|
||||
}).join(','),
|
||||
popup = window.open("about:blank", 'oauth_window', settings),
|
||||
locationCheck = window.setInterval(function() {
|
||||
if (popup.closed) return window.clearInterval(locationCheck);
|
||||
if (popup.location.search) {
|
||||
var search = popup.location.search,
|
||||
oauth_token = ohauth.stringQs(search.slice(1));
|
||||
popup.close();
|
||||
get_access_token(oauth_token);
|
||||
window.clearInterval(locationCheck);
|
||||
}
|
||||
}, 100);
|
||||
popup = window.open("about:blank", 'oauth_window', settings);
|
||||
|
||||
window.authComplete = function(token) {
|
||||
var oauth_token = ohauth.stringQs(token);
|
||||
get_access_token(oauth_token);
|
||||
delete window.authComplete;
|
||||
};
|
||||
|
||||
function reqTokenDone(err, xhr) {
|
||||
if (err) callback(err);
|
||||
|
||||
@@ -11,6 +11,8 @@ iD.operations.Delete = function(selection, context) {
|
||||
context.perform(
|
||||
iD.actions.DeleteMultiple(selection),
|
||||
annotation);
|
||||
|
||||
context.enter(iD.modes.Browse(context));
|
||||
};
|
||||
|
||||
operation.available = function() {
|
||||
|
||||
@@ -6,7 +6,7 @@ iD.operations.Move = function(selection, context) {
|
||||
|
||||
operation.available = function() {
|
||||
return selection.length > 1 ||
|
||||
context.entity(selection[0]).type === 'way';
|
||||
context.entity(selection[0]).type !== 'node';
|
||||
};
|
||||
|
||||
operation.enabled = function() {
|
||||
|
||||
+15
-3
@@ -1,7 +1,19 @@
|
||||
iD.presetData = function() {
|
||||
|
||||
var other = {
|
||||
name: 'other',
|
||||
title: 'Other',
|
||||
icon: 'marker-stroked',
|
||||
match: {
|
||||
tags: {},
|
||||
type: ['node', 'line', 'area']
|
||||
},
|
||||
form: []
|
||||
};
|
||||
|
||||
var presets = {},
|
||||
data = [],
|
||||
categories = {},
|
||||
data = [other],
|
||||
categories = [],
|
||||
defaults = {
|
||||
node: [],
|
||||
area: [],
|
||||
@@ -16,7 +28,7 @@ iD.presetData = function() {
|
||||
|
||||
presets.data = function(_) {
|
||||
if (!arguments.length) return data;
|
||||
data = _.presets;
|
||||
data = _.presets.concat([other]);
|
||||
categories = _.categories;
|
||||
defaults = _.defaults;
|
||||
return presets;
|
||||
|
||||
@@ -21,7 +21,7 @@ iD.Map = function(context) {
|
||||
areas = iD.svg.Areas(roundedProjection),
|
||||
midpoints = iD.svg.Midpoints(roundedProjection),
|
||||
labels = iD.svg.Labels(roundedProjection),
|
||||
tail = d3.tail(),
|
||||
tail = iD.ui.Tail(),
|
||||
surface, tilegroup;
|
||||
|
||||
function map(selection) {
|
||||
|
||||
+45
-14
@@ -14,6 +14,8 @@ iD.taginfo = function() {
|
||||
line: 'ways'
|
||||
};
|
||||
|
||||
var cache = this.cache = {};
|
||||
|
||||
function sets(parameters, n, o) {
|
||||
if (parameters.geometry && o[parameters.geometry]) {
|
||||
parameters[n] = o[parameters.geometry];
|
||||
@@ -30,16 +32,25 @@ iD.taginfo = function() {
|
||||
}
|
||||
|
||||
function clean(parameters) {
|
||||
return _.omit(parameters, 'geometry');
|
||||
return _.omit(parameters, 'geometry', 'debounce');
|
||||
}
|
||||
|
||||
function shorten(parameters) {
|
||||
if (!parameters.query) {
|
||||
delete parameters.query;
|
||||
} else {
|
||||
parameters.query = parameters.query.slice(0, 3);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
function popularKeys(parameters) {
|
||||
var pop_field = 'count_all_fraction';
|
||||
if (parameters.filter) pop_field = 'count_' + parameters.filter + '_fraction';
|
||||
return function(d) { return parseFloat(d[pop_field]) > 0.01; };
|
||||
var pop_field = 'count_all';
|
||||
if (parameters.filter) pop_field = 'count_' + parameters.filter;
|
||||
return function(d) { return parseFloat(d[pop_field]) > 10000; };
|
||||
}
|
||||
|
||||
function popularValues(parameters) {
|
||||
function popularValues() {
|
||||
return function(d) { return parseFloat(d.fraction) > 0.01; };
|
||||
}
|
||||
|
||||
@@ -52,38 +63,58 @@ iD.taginfo = function() {
|
||||
};
|
||||
}
|
||||
|
||||
var debounced = _.debounce(d3.json, 100, true);
|
||||
|
||||
function request(url, debounce, callback) {
|
||||
if (cache[url]) {
|
||||
callback(null, cache[url]);
|
||||
} else if (debounce) {
|
||||
debounced(url, done);
|
||||
} else {
|
||||
d3.json(url, done);
|
||||
}
|
||||
|
||||
function done(err, data) {
|
||||
if (!err) cache[url] = data;
|
||||
callback(err, data);
|
||||
}
|
||||
}
|
||||
|
||||
taginfo.keys = function(parameters, callback) {
|
||||
parameters = clean(setSort(setFilter(parameters)));
|
||||
d3.json(endpoint + 'keys/all?' +
|
||||
var debounce = parameters.debounce;
|
||||
parameters = clean(shorten(setSort(setFilter(parameters))));
|
||||
request(endpoint + 'keys/all?' +
|
||||
iD.util.qsString(_.extend({
|
||||
rp: 6,
|
||||
rp: 10,
|
||||
sortname: 'count_all',
|
||||
sortorder: 'desc',
|
||||
page: 1
|
||||
}, parameters)), function(err, d) {
|
||||
}, parameters)), debounce, function(err, d) {
|
||||
if (err) return callback(err);
|
||||
callback(null, d.data.filter(popularKeys(parameters)).map(valKey));
|
||||
});
|
||||
};
|
||||
|
||||
taginfo.values = function(parameters, callback) {
|
||||
parameters = clean(setSort(setFilter(parameters)));
|
||||
d3.json(endpoint + 'key/values?' +
|
||||
var debounce = parameters.debounce;
|
||||
parameters = clean(shorten(setSort(setFilter(parameters))));
|
||||
request(endpoint + 'key/values?' +
|
||||
iD.util.qsString(_.extend({
|
||||
rp: 20,
|
||||
sortname: 'count_all',
|
||||
sortorder: 'desc',
|
||||
page: 1
|
||||
}, parameters)), function(err, d) {
|
||||
}, parameters)), debounce, function(err, d) {
|
||||
if (err) return callback(err);
|
||||
callback(null, d.data.filter(popularValues()).map(valKeyDescription), parameters);
|
||||
});
|
||||
};
|
||||
|
||||
taginfo.docs = function(parameters, callback) {
|
||||
var debounce = parameters.debounce;
|
||||
parameters = clean(setSort(parameters));
|
||||
d3.json(endpoint + 'tag/wiki_pages?' +
|
||||
iD.util.qsString(parameters), callback);
|
||||
request(endpoint + (parameters.value ? 'tag/wiki_pages?' : 'key/wiki_pages?') +
|
||||
iD.util.qsString(parameters), debounce, callback);
|
||||
};
|
||||
|
||||
taginfo.endpoint = function(_) {
|
||||
|
||||
+3
-3
@@ -80,9 +80,9 @@ iD.svg.Labels = function(projection) {
|
||||
.data(entities, iD.Entity.key)
|
||||
.attr({
|
||||
'startOffset': '50%',
|
||||
'xlink:href': function(d, i) { return '#halo-' + d.id; }
|
||||
'xlink:href': function(d) { return '#halo-' + d.id; }
|
||||
})
|
||||
.text(function(d, i) { return name(d); });
|
||||
.text(function(d) { return name(d); });
|
||||
|
||||
texts.exit().remove();
|
||||
|
||||
@@ -97,7 +97,7 @@ iD.svg.Labels = function(projection) {
|
||||
halos.enter()
|
||||
.append('path')
|
||||
.style('stroke-width', get(labels, 'font-size'))
|
||||
.attr('id', function(d, i) { return 'halo-' + d.id; })
|
||||
.attr('id', function(d) { return 'halo-' + d.id; })
|
||||
.attr('class', classes);
|
||||
|
||||
halos.attr('d', get(labels, 'lineString'));
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ iD.svg.Lines = function(projection) {
|
||||
|
||||
text.selectAll('.textpath')
|
||||
.filter(filter)
|
||||
.attr('xlink:href', function(d, i) { return '#shadow-' + d.id; })
|
||||
.attr('xlink:href', function(d) { return '#shadow-' + d.id; })
|
||||
.text(function(d) {
|
||||
// adding longer text than necessary, since overflow is hidden
|
||||
return (new Array(Math.floor(lengths[d.id] * 1.1))).join(arrowtext);
|
||||
|
||||
@@ -2,7 +2,7 @@ iD.svg.MemberClasses = function(graph) {
|
||||
var tagClassRe = /^member-?/;
|
||||
|
||||
return function memberClassesSelection(selection) {
|
||||
selection.each(function memberClassesEach(d, i) {
|
||||
selection.each(function memberClassesEach(d) {
|
||||
var classes, value = this.className;
|
||||
|
||||
if (value.baseVal !== undefined) value = value.baseVal;
|
||||
|
||||
@@ -6,5 +6,5 @@ iD.ui.Attribution = function(context) {
|
||||
selection
|
||||
.append('span')
|
||||
.attr('class', 'provided-by');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
+9
-7
@@ -46,18 +46,18 @@ iD.ui.Commit = function(context) {
|
||||
|
||||
var userLink = d3.select(document.createElement('div'));
|
||||
|
||||
userLink.append('a')
|
||||
.attr('class','user-info')
|
||||
.text(user.display_name)
|
||||
.attr('href', connection.url() + '/user/' + user.display_name)
|
||||
.attr('target', '_blank');
|
||||
|
||||
if (user.image_url) {
|
||||
userLink.append('img')
|
||||
.attr('src', user.image_url)
|
||||
.attr('class', 'icon icon-pre-text user-icon');
|
||||
}
|
||||
|
||||
userLink.append('a')
|
||||
.attr('class','user-info')
|
||||
.text(user.display_name)
|
||||
.attr('href', connection.url() + '/user/' + user.display_name)
|
||||
.attr('target', '_blank');
|
||||
|
||||
commentSection.append('p')
|
||||
.attr('class', 'commit-info')
|
||||
.html(t('commit.upload_explanation', {user: userLink.html()}));
|
||||
@@ -108,7 +108,9 @@ iD.ui.Commit = function(context) {
|
||||
.enter()
|
||||
.append('li');
|
||||
|
||||
warningLi.append('button')
|
||||
// only show the fix icon when an entity is given
|
||||
warningLi.filter(function(d) { return d.entity; })
|
||||
.append('button')
|
||||
.attr('class', 'minor')
|
||||
.on('click', event.fix)
|
||||
.append('span')
|
||||
|
||||
@@ -4,9 +4,9 @@ iD.ui.Contributors = function(context) {
|
||||
limit = 4,
|
||||
entities = context.intersects(context.map().extent());
|
||||
|
||||
for (var i in entities) {
|
||||
if (entities[i].user) users[entities[i].user] = true;
|
||||
}
|
||||
entities.forEach(function(entity) {
|
||||
if (entity && entity.user) users[entity.user] = true;
|
||||
});
|
||||
|
||||
var u = Object.keys(users),
|
||||
subset = u.slice(0, u.length > limit ? limit - 1 : limit);
|
||||
|
||||
@@ -59,7 +59,7 @@ iD.ui.Geocoder = function(context) {
|
||||
}
|
||||
|
||||
function hide() { setVisible(false); }
|
||||
function toggle() { setVisible(gcForm.classed('hide')); }
|
||||
function toggle() { tooltip.hide(button); setVisible(gcForm.classed('hide')); }
|
||||
|
||||
function setVisible(show) {
|
||||
if (show !== shown) {
|
||||
@@ -71,13 +71,13 @@ iD.ui.Geocoder = function(context) {
|
||||
shown = show;
|
||||
}
|
||||
}
|
||||
var tooltip = bootstrap.tooltip().placement('right');
|
||||
|
||||
var button = selection.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.attr('title', t('geocoder.title'))
|
||||
.on('click', toggle)
|
||||
.call(bootstrap.tooltip()
|
||||
.placement('right'));
|
||||
.call(tooltip);
|
||||
|
||||
button.append('span')
|
||||
.attr('class', 'icon geocode');
|
||||
|
||||
+10
-46
@@ -1,15 +1,11 @@
|
||||
iD.ui.Inspector = function() {
|
||||
iD.ui.Inspector = function(context) {
|
||||
var event = d3.dispatch('changeTags', 'close', 'change'),
|
||||
taginfo = iD.taginfo(),
|
||||
presetData = iD.presetData(),
|
||||
initial = false,
|
||||
inspectorbody,
|
||||
entity,
|
||||
presetUI,
|
||||
presetGrid,
|
||||
tagList,
|
||||
tagEditor,
|
||||
context;
|
||||
tagEditor;
|
||||
|
||||
function inspector(selection) {
|
||||
|
||||
@@ -21,29 +17,27 @@ iD.ui.Inspector = function() {
|
||||
|
||||
inspectorbody = selection.append('div')
|
||||
.attr('class', 'fillL'),
|
||||
selection.append('div')
|
||||
.attr('class', 'inspector-actions pad1 fillD col12')
|
||||
.call(drawButtons);
|
||||
|
||||
presetGrid = iD.ui.PresetGrid()
|
||||
presetGrid = iD.ui.PresetGrid(context)
|
||||
.presetData(presetData)
|
||||
.entity(entity)
|
||||
.context(context)
|
||||
.on('message', changeMessage)
|
||||
.on('choose', function(preset) {
|
||||
inspectorbody.call(tagEditor, preset);
|
||||
});
|
||||
|
||||
tagEditor = iD.ui.TagEditor()
|
||||
tagEditor = iD.ui.TagEditor(context)
|
||||
.presetData(presetData)
|
||||
.tags(entity.tags)
|
||||
.context(context)
|
||||
.on('message', changeMessage)
|
||||
.on('change', function() {
|
||||
.on('changeTags', function() {
|
||||
event.changeTags(entity, inspector.tags());
|
||||
})
|
||||
.on('close', function() {
|
||||
event.close(entity);
|
||||
})
|
||||
.on('choose', function() {
|
||||
inspectorbody.call(presetGrid);
|
||||
inspectorbody.call(presetGrid, true);
|
||||
});
|
||||
|
||||
function changeMessage(msg) { message.text(msg);}
|
||||
@@ -58,32 +52,7 @@ iD.ui.Inspector = function() {
|
||||
selection.call(iD.ui.Toggle(true));
|
||||
}
|
||||
|
||||
function drawButtons(selection) {
|
||||
var entity = selection.datum();
|
||||
|
||||
var inspectorButton = selection.append('button')
|
||||
.attr('class', 'apply action')
|
||||
.on('click', apply);
|
||||
|
||||
inspectorButton.append('span')
|
||||
.attr('class','label')
|
||||
.text(t('inspector.okay'));
|
||||
|
||||
var minorButtons = selection.append('div')
|
||||
.attr('class','minor-buttons fl');
|
||||
|
||||
minorButtons.append('a')
|
||||
.attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId())
|
||||
.attr('target', '_blank')
|
||||
.text(t('inspector.view_on_osm'));
|
||||
}
|
||||
|
||||
function apply(entity) {
|
||||
event.changeTags(entity, inspector.tags());
|
||||
event.close(entity);
|
||||
}
|
||||
|
||||
inspector.tags = function(tags) {
|
||||
inspector.tags = function() {
|
||||
if (!arguments.length) {
|
||||
return tagEditor.tags();
|
||||
} else {
|
||||
@@ -102,10 +71,5 @@ iD.ui.Inspector = function() {
|
||||
return inspector;
|
||||
};
|
||||
|
||||
inspector.context = function(_) {
|
||||
context = _;
|
||||
return inspector;
|
||||
};
|
||||
|
||||
return d3.rebind(inspector, event, 'on');
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ iD.ui.keyReference = function(selection) {
|
||||
.append('tr');
|
||||
|
||||
var cols = rows.selectAll('td')
|
||||
.data(function(d, i) {
|
||||
.data(function(d) {
|
||||
return [d.value, d.description || "", d.count];
|
||||
})
|
||||
.enter()
|
||||
|
||||
+2
-3
@@ -1,7 +1,6 @@
|
||||
iD.ui.Lasso = function() {
|
||||
|
||||
var center, box,
|
||||
group,
|
||||
var box, group,
|
||||
a = [0, 0],
|
||||
b = [0, 0];
|
||||
|
||||
@@ -50,7 +49,7 @@ iD.ui.Lasso = function() {
|
||||
return lasso;
|
||||
};
|
||||
|
||||
lasso.close = function(selection) {
|
||||
lasso.close = function() {
|
||||
if (group) {
|
||||
group.call(iD.ui.Toggle(false, function() {
|
||||
d3.select(this).remove();
|
||||
|
||||
@@ -18,20 +18,21 @@ iD.ui.LayerSwitcher = function(context) {
|
||||
.append('div').attr('class', 'content fillD map-overlay hide'),
|
||||
shown = false;
|
||||
|
||||
var tooltip = bootstrap.tooltip().placement('right');
|
||||
|
||||
var button = selection
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.attr('class', 'fillD')
|
||||
.attr('title', t('layerswitcher.description'))
|
||||
.on('click.layerswitcher-toggle', toggle)
|
||||
.call(bootstrap.tooltip()
|
||||
.placement('right'));
|
||||
.call(tooltip);
|
||||
|
||||
button.append('span')
|
||||
.attr('class', 'layers icon');
|
||||
|
||||
function hide() { setVisible(false); }
|
||||
function toggle() { setVisible(content.classed('hide')); }
|
||||
function toggle() { tooltip.hide(button); setVisible(content.classed('hide')); }
|
||||
|
||||
function setVisible(show) {
|
||||
if (show !== shown) {
|
||||
|
||||
+33
-25
@@ -1,7 +1,6 @@
|
||||
iD.ui.preset = function() {
|
||||
var event = d3.dispatch('change'),
|
||||
iD.ui.preset = function(context) {
|
||||
var event = d3.dispatch('change', 'setTags'),
|
||||
taginfo = iD.taginfo(),
|
||||
context,
|
||||
entity,
|
||||
type,
|
||||
hidden,
|
||||
@@ -13,7 +12,11 @@ iD.ui.preset = function() {
|
||||
var tags = _.clone(preset.match.tags);
|
||||
sections.selectAll('input,select')
|
||||
.each(function(d) {
|
||||
tags[d.key] = this.value;
|
||||
if (d && d.key) {
|
||||
tags[d.key] = d.type === 'combo' || d.type === 'select' ?
|
||||
this.value.replace(' ', '_') :
|
||||
this.value;
|
||||
}
|
||||
});
|
||||
return tags;
|
||||
}
|
||||
@@ -22,8 +25,15 @@ iD.ui.preset = function() {
|
||||
if (!sections) return;
|
||||
sections.selectAll('input,select')
|
||||
.each(function(d) {
|
||||
this.value = tags[d.key] || '';
|
||||
if (d && d.key) {
|
||||
this.value = tags[d.key] || '';
|
||||
if (d.type === 'combo' || d.type === 'select') {
|
||||
this.value = this.value.replace('_', ' ');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
event.setTags();
|
||||
}
|
||||
|
||||
function clean(o) {
|
||||
@@ -66,20 +76,25 @@ iD.ui.preset = function() {
|
||||
.attr('id', 'input-' + d.key)
|
||||
.attr('placeholder', 'http://example.com/');
|
||||
break;
|
||||
case 'check':
|
||||
i = this.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.attr('id', 'input-' + d.key);
|
||||
break;
|
||||
case 'select':
|
||||
wrap = this.append('span').attr('class', 'input-wrap-position'),
|
||||
i = wrap.append('input').attr('type', 'text');
|
||||
wrap.call(d3.combobox().data(d.options.map(function(d) {
|
||||
return {
|
||||
title: d,
|
||||
value: d
|
||||
};
|
||||
})));
|
||||
|
||||
if (d.options.length <= 5) {
|
||||
var select = d3.rowselect()
|
||||
.data(d.options)
|
||||
.on('change', key);
|
||||
i.datum(d);
|
||||
wrap.call(select);
|
||||
event.on('setTags.' + d.key, select.update);
|
||||
|
||||
} else {
|
||||
wrap.call(d3.combobox().data(d.options.map(function(d) {
|
||||
var o = {};
|
||||
o.title = o.value = d.replace('_', ' ');
|
||||
return o;
|
||||
})));
|
||||
}
|
||||
break;
|
||||
case 'combo':
|
||||
var combobox = d3.combobox();
|
||||
@@ -90,7 +105,7 @@ iD.ui.preset = function() {
|
||||
key: d.key
|
||||
}, function(err, data) {
|
||||
if (!err) combobox.data(data.map(function(d) {
|
||||
d.title = d.value;
|
||||
d.title = d.value = d.value.replace('_', ' ');
|
||||
return d;
|
||||
}));
|
||||
});
|
||||
@@ -130,8 +145,7 @@ iD.ui.preset = function() {
|
||||
if (d.type === 'address') {
|
||||
wrap.append('div')
|
||||
.attr('class', 'col9 preset-input', d)
|
||||
.call(iD.ui.preset.address()
|
||||
.context(context)
|
||||
.call(iD.ui.preset.address(context)
|
||||
.on('change', key)
|
||||
.entity(entity));
|
||||
}
|
||||
@@ -157,12 +171,6 @@ iD.ui.preset = function() {
|
||||
return clean(getTags());
|
||||
};
|
||||
|
||||
presets.context = function(_) {
|
||||
if (!arguments.length) return context;
|
||||
context = _;
|
||||
return presets;
|
||||
};
|
||||
|
||||
presets.entity = function(_) {
|
||||
if (!arguments.length) return entity;
|
||||
entity = _;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
iD.ui.preset.address = function() {
|
||||
iD.ui.preset.address = function(context) {
|
||||
|
||||
var event = d3.dispatch('change'),
|
||||
context,
|
||||
entity;
|
||||
|
||||
function getStreets() {
|
||||
|
||||
var l = entity.loc || context.entity(entity.nodes[0]).loc,
|
||||
var extent = entity.extent(context.graph()),
|
||||
l = extent.center(),
|
||||
dist = iD.geo.metresToCoordinates(l, [200, 200]),
|
||||
extent = entity.extent(context.graph()),
|
||||
box = iD.geo.Extent(
|
||||
[extent[0][0] - dist[0], extent[0][1] - dist[1]],
|
||||
[extent[1][0] + dist[0], extent[1][1] + dist[1]]);
|
||||
@@ -56,12 +55,12 @@ iD.ui.preset.address = function() {
|
||||
|
||||
var streetwrap = selection.append('span')
|
||||
.attr('class', 'input-wrap-position')
|
||||
.datum({ 'key': 'addr:streetname' });
|
||||
.datum({ 'key': 'addr:street' });
|
||||
|
||||
streetwrap.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', 'Oak Street')
|
||||
.attr('class', 'addr-streetname')
|
||||
.attr('class', 'addr-street')
|
||||
.on('blur', change)
|
||||
.on('change', change);
|
||||
|
||||
@@ -74,11 +73,5 @@ iD.ui.preset.address = function() {
|
||||
return address;
|
||||
};
|
||||
|
||||
address.context = function(_) {
|
||||
if (!arguments.length) return context;
|
||||
context = _;
|
||||
return address;
|
||||
};
|
||||
|
||||
return d3.rebind(address, event, 'on');
|
||||
};
|
||||
+125
-55
@@ -1,15 +1,15 @@
|
||||
iD.ui.PresetGrid = function() {
|
||||
iD.ui.PresetGrid = function(context) {
|
||||
var event = d3.dispatch('choose', 'message'),
|
||||
entity,
|
||||
context,
|
||||
presetData;
|
||||
presetData,
|
||||
taginfo = iD.taginfo();
|
||||
|
||||
function presetgrid(selection) {
|
||||
function presetgrid(selection, preset) {
|
||||
|
||||
selection.html('');
|
||||
|
||||
var viable = presetData.match(entity);
|
||||
event.message('What kind of ' + entity.geometry(context.graph()) + ' are you adding?');
|
||||
event.message(t('inspector.choose'));
|
||||
|
||||
var searchwrap = selection.append('div')
|
||||
.attr('class', 'preset-grid-search-wrap inspector-inner');
|
||||
@@ -24,8 +24,7 @@ iD.ui.PresetGrid = function() {
|
||||
.on('keyup', function() {
|
||||
// enter
|
||||
if (d3.event.keyCode === 13) {
|
||||
var chosen = grid.selectAll('.grid-entry:first-child').datum();
|
||||
if (chosen) event.choose(chosen);
|
||||
choose(grid.selectAll('.grid-entry:first-child').datum());
|
||||
} else {
|
||||
var value = search.property('value'),
|
||||
presets = filter(value);
|
||||
@@ -36,6 +35,11 @@ iD.ui.PresetGrid = function() {
|
||||
});
|
||||
search.node().focus();
|
||||
|
||||
if (preset) {
|
||||
selection.append('div')
|
||||
.attr('class', 'inspector-actions pad1 fillD col12')
|
||||
.call(drawButtons);
|
||||
}
|
||||
|
||||
function filter(value) {
|
||||
if (!value) return presetData.defaults(entity);
|
||||
@@ -56,54 +60,128 @@ iD.ui.PresetGrid = function() {
|
||||
|
||||
return iD.util.editDistance(value, a.name) - iD.util.editDistance(value, b.name);
|
||||
}).filter(function(d) {
|
||||
return iD.util.editDistance(value, d.name) - d.name.length + value.length < 3;
|
||||
return iD.util.editDistance(value, d.name) - d.name.length + value.length < 3 ||
|
||||
d.name === 'other';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function choose(d) {
|
||||
// Category
|
||||
if (d.members) {
|
||||
search.property('value', '');
|
||||
viable = presetData.categories(d.name);
|
||||
drawGrid(selection, viable);
|
||||
|
||||
// Preset
|
||||
} else {
|
||||
event.choose(d);
|
||||
}
|
||||
}
|
||||
|
||||
function name(d) { return d.name; }
|
||||
|
||||
function drawGrid(selection, presets) {
|
||||
|
||||
var entries = selection
|
||||
.selectAll('button.grid-entry')
|
||||
.data(presets.slice(0, 12), name);
|
||||
|
||||
var entered = entries.enter()
|
||||
.append('button')
|
||||
.attr('class', 'grid-entry col3')
|
||||
.on('click', choose);
|
||||
|
||||
entered.append('div')
|
||||
.attr('class', function(d) {
|
||||
var s = 'preset-icon-fill ' + entity.geometry(context.graph());
|
||||
if (d.members) {
|
||||
s += 'category';
|
||||
} else {
|
||||
for (var i in d.match.tags) {
|
||||
s += ' tag-' + i + ' tag-' + i + '-' + d.match.tags[i];
|
||||
}
|
||||
}
|
||||
return s;
|
||||
});
|
||||
|
||||
entered.append('div')
|
||||
.attr('class', function(d) { return 'preset-' + d.icon + ' icon'; });
|
||||
|
||||
var presetinspect;
|
||||
|
||||
entered.append('span').attr('class','label').text(name);
|
||||
|
||||
entered.append('div')
|
||||
.attr('tabindex', -1)
|
||||
.attr('class', 'preset-help')
|
||||
.on('click', function(d) {
|
||||
|
||||
// Display description box inline
|
||||
|
||||
d3.event.stopPropagation();
|
||||
|
||||
var entry = this.parentNode,
|
||||
index,
|
||||
entries = selection.selectAll('button.grid-entry');
|
||||
|
||||
if (presetinspect && presetinspect.remove().datum() === d) {
|
||||
presetinspect = null;
|
||||
return;
|
||||
}
|
||||
|
||||
entries.each(function(d, i) {
|
||||
if (this === entry) index = i;
|
||||
});
|
||||
|
||||
var selector = '.grid-entry:nth-child(' + (Math.floor(index/4) * 4 + 5 ) + ')';
|
||||
|
||||
presetinspect = selection.insert('div', selector)
|
||||
.attr('class', 'preset-inspect col12')
|
||||
.datum(d);
|
||||
|
||||
presetinspect.append('h2').text(d.title || d.name);
|
||||
|
||||
var description = presetinspect.append('p');
|
||||
var link = presetinspect.append('a');
|
||||
|
||||
var params = {},
|
||||
locale = iD.detect().locale.split('-')[0] || 'en';
|
||||
|
||||
params.key = Object.keys(d.match.tags)[0];
|
||||
if (d.match.tags[params.key] !== '*') {
|
||||
params.value = d.match.tags[params.key];
|
||||
}
|
||||
|
||||
taginfo.docs(params, function(err, data) {
|
||||
var doc = _.find(data, function(d) { return d.lang === locale; }) ||
|
||||
_.find(data, function(d) { return d.lang === 'en'; });
|
||||
description.text(doc.description);
|
||||
link.attr('href', 'http://wiki.openstreetmap.org/wiki/' + encodeURIComponent(doc.title));
|
||||
link.text(doc.title);
|
||||
});
|
||||
})
|
||||
.append('span')
|
||||
.attr('class', 'icon inspect');
|
||||
|
||||
entries.exit().remove();
|
||||
entries.order();
|
||||
}
|
||||
}
|
||||
|
||||
function name(d) { return d.name; }
|
||||
function cancel() {
|
||||
event.choose();
|
||||
}
|
||||
|
||||
function drawGrid(selection, presets) {
|
||||
function drawButtons(selection) {
|
||||
|
||||
var entries = selection
|
||||
.selectAll('button.grid-entry')
|
||||
.data(presets.slice(0, 12), name);
|
||||
var inspectorButton = selection.append('button')
|
||||
.attr('class', 'apply action')
|
||||
.on('click', cancel);
|
||||
|
||||
var entered = entries.enter()
|
||||
.append('button')
|
||||
.attr('class', 'grid-entry col3')
|
||||
.on('click', function(d) {
|
||||
// Category
|
||||
if (d.members) {
|
||||
drawGrid(selection, presetData.categories(d.name));
|
||||
|
||||
// Preset
|
||||
} else {
|
||||
event.choose(d);
|
||||
}
|
||||
});
|
||||
|
||||
entered.append('div')
|
||||
.attr('class', function(d) {
|
||||
var s = 'preset-icon-fill ' + entity.geometry(context.graph());
|
||||
if (d.members) {
|
||||
s += 'category';
|
||||
} else {
|
||||
for (var i in d.match.tags) {
|
||||
s += ' tag-' + i + ' tag-' + i + '-' + d.match.tags[i];
|
||||
}
|
||||
}
|
||||
return s;
|
||||
});
|
||||
|
||||
entered.append('div')
|
||||
.attr('class', function(d) { return 'preset-' + d.icon + ' icon'; });
|
||||
|
||||
entered.append('span').attr('class','label').text(name);
|
||||
|
||||
entries.exit().remove();
|
||||
entries.order();
|
||||
inspectorButton.append('span')
|
||||
.attr('class','label')
|
||||
.text(t('commit.cancel'));
|
||||
}
|
||||
|
||||
presetgrid.presetData = function(_) {
|
||||
@@ -112,19 +190,11 @@ iD.ui.PresetGrid = function() {
|
||||
return presetgrid;
|
||||
};
|
||||
|
||||
presetgrid.context = function(_) {
|
||||
if (!arguments.length) return context;
|
||||
context = _;
|
||||
return presetgrid;
|
||||
};
|
||||
|
||||
presetgrid.entity = function(_) {
|
||||
if (!arguments.length) return entity;
|
||||
entity = _;
|
||||
return presetgrid;
|
||||
};
|
||||
|
||||
|
||||
|
||||
return d3.rebind(presetgrid, event, 'on');
|
||||
};
|
||||
|
||||
@@ -6,6 +6,8 @@ iD.ui.RadialMenu = function(operations) {
|
||||
if (!operations.length)
|
||||
return;
|
||||
|
||||
selection.node().focus();
|
||||
|
||||
function click(operation) {
|
||||
d3.event.stopPropagation();
|
||||
operation();
|
||||
|
||||
+1
-1
@@ -28,5 +28,5 @@ iD.ui.Splash = function(context) {
|
||||
website: '<a href="http://ideditor.com/">ideditor.com</a>',
|
||||
github: '<a href="https://github.com/systemed/iD">github.com</a>'
|
||||
}));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ iD.ui.Success = function(connection) {
|
||||
connection.changesetUrl(changeset.id);
|
||||
|
||||
header.append('a')
|
||||
.attr('href', function(d) {
|
||||
.attr('href', function() {
|
||||
return connection.changesetUrl(changeset.id);
|
||||
})
|
||||
.attr('target', '_blank')
|
||||
@@ -28,7 +28,7 @@ iD.ui.Success = function(connection) {
|
||||
|
||||
header.append('a')
|
||||
.attr('target', '_blank')
|
||||
.attr('href', function(d) {
|
||||
.attr('href', function() {
|
||||
return 'https://twitter.com/intent/tweet?source=webclient&text=' +
|
||||
encodeURIComponent(message);
|
||||
})
|
||||
|
||||
+59
-40
@@ -1,20 +1,18 @@
|
||||
iD.ui.TagEditor = function() {
|
||||
var event = d3.dispatch('changeTags', 'choose', 'close', 'change', 'message'),
|
||||
taginfo = iD.taginfo(),
|
||||
iD.ui.TagEditor = function(context) {
|
||||
var event = d3.dispatch('changeTags', 'choose', 'close', 'message'),
|
||||
presetData = iD.presetData(),
|
||||
inspectorbody,
|
||||
entity,
|
||||
tags,
|
||||
name,
|
||||
presetMatch,
|
||||
selection_,
|
||||
presetUI,
|
||||
presetGrid,
|
||||
tagList,
|
||||
context;
|
||||
tagList;
|
||||
|
||||
function tageditor(selection, preset) {
|
||||
|
||||
entity = selection.datum();
|
||||
selection_ = selection;
|
||||
var type = entity.type === 'node' ? entity.type : entity.geometry();
|
||||
|
||||
// preset was explicitly chosen
|
||||
@@ -60,44 +58,44 @@ iD.ui.TagEditor = function() {
|
||||
|
||||
typewrap.append('h4').text('Type');
|
||||
|
||||
var typelabel = typewrap.append('button')
|
||||
var typebutton = typewrap.append('button')
|
||||
.attr('class','col12')
|
||||
.on('click', function() {
|
||||
event.choose();
|
||||
});
|
||||
|
||||
typelabel.append('div')
|
||||
typebutton.append('div')
|
||||
.attr('class', 'icon icon-pre-text' + (presetMatch ? ' preset-' + presetMatch.icon : ''));
|
||||
|
||||
typebutton.node().focus();
|
||||
|
||||
var namewrap = headerwrap.append('div')
|
||||
.attr('class', 'name col9 inspector-inner');
|
||||
.attr('class', 'name col9 inspector-inner');
|
||||
|
||||
typelabel.append('span')
|
||||
.attr('class','label')
|
||||
.text(presetMatch ? presetMatch.name : 'Other');
|
||||
typebutton.append('span')
|
||||
.attr('class','label')
|
||||
.text(presetMatch.name);
|
||||
|
||||
namewrap.append('h4').text('Name');
|
||||
namewrap.append('h4').text(t('inspector.name'));
|
||||
|
||||
name = namewrap.append('input')
|
||||
.attr('placeholder', 'unknown')
|
||||
.attr('class', 'major')
|
||||
.attr('type', 'text')
|
||||
.property('value', entity.tags.name || 'this')
|
||||
.property('value', entity.tags.name || '')
|
||||
.on('blur', function() {
|
||||
event.change();
|
||||
event.changeTags();
|
||||
});
|
||||
|
||||
presetUI = iD.ui.preset()
|
||||
.context(context)
|
||||
presetUI = iD.ui.preset(context)
|
||||
.entity(entity)
|
||||
.on('change', function(tags) {
|
||||
event.change(tags);
|
||||
.on('change', function() {
|
||||
event.changeTags();
|
||||
});
|
||||
|
||||
tagList = iD.ui.Taglist()
|
||||
.context(context)
|
||||
.on('change', function(tags) {
|
||||
event.change(tags);
|
||||
tagList = iD.ui.Taglist(context)
|
||||
.on('change', function() {
|
||||
event.changeTags();
|
||||
});
|
||||
|
||||
var tageditorpreset = editorwrap.append('div')
|
||||
@@ -105,26 +103,45 @@ iD.ui.TagEditor = function() {
|
||||
|
||||
if (presetMatch) {
|
||||
tageditorpreset.call(presetUI
|
||||
.preset(presetMatch));
|
||||
.preset(presetMatch));
|
||||
}
|
||||
|
||||
event.message('Edit ' + (presetMatch && presetMatch.name || ''));
|
||||
event.message(t('inspector.editing', { type: presetMatch.name }));
|
||||
|
||||
var taglistwrap = editorwrap.append('div')
|
||||
.attr('class','inspector-inner col12 fillL2').call(tagList);
|
||||
editorwrap.append('div')
|
||||
.attr('class','inspector-inner col12 fillL2').call(tagList, presetMatch.name === 'other');
|
||||
|
||||
selection.append('div')
|
||||
.attr('class', 'inspector-actions pad1 fillD col12')
|
||||
.call(drawButtons);
|
||||
|
||||
tageditor.tags(tags);
|
||||
event.change(tags);
|
||||
|
||||
event.changeTags();
|
||||
}
|
||||
|
||||
function drawHead(selection) {
|
||||
var h2 = selection.append('h2');
|
||||
function apply() {
|
||||
event.changeTags();
|
||||
event.close();
|
||||
}
|
||||
|
||||
h2.append('span')
|
||||
.attr('class', 'icon big icon-pre-text big-' + entity.geometry(context.graph()));
|
||||
function drawButtons(selection) {
|
||||
|
||||
h2.append('span')
|
||||
.text(entity.friendlyName());
|
||||
var inspectorButton = selection.append('button')
|
||||
.attr('class', 'apply action')
|
||||
.on('click', apply);
|
||||
|
||||
inspectorButton.append('span')
|
||||
.attr('class','label')
|
||||
.text(t('inspector.okay'));
|
||||
|
||||
var minorButtons = selection.append('div')
|
||||
.attr('class','minor-buttons fl');
|
||||
|
||||
minorButtons.append('a')
|
||||
.attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId())
|
||||
.attr('target', '_blank')
|
||||
.text(t('inspector.view_on_osm'));
|
||||
}
|
||||
|
||||
tageditor.tags = function(newtags) {
|
||||
@@ -135,6 +152,13 @@ iD.ui.TagEditor = function() {
|
||||
} else {
|
||||
tags = _.clone(newtags);
|
||||
if (presetUI && tagList) {
|
||||
|
||||
// change preset if necessary (undos/redos)
|
||||
var newmatch = presetData.matchTags(entity.update({ tags: tags }));
|
||||
if (newmatch !== presetMatch) {
|
||||
return tageditor(selection_, newmatch);
|
||||
}
|
||||
|
||||
name.property('value', tags.name || '');
|
||||
presetUI.change(tags);
|
||||
tagList.tags(_.omit(tags, _.keys(presetUI.tags() || {}).concat(['name'])));
|
||||
@@ -148,10 +172,5 @@ iD.ui.TagEditor = function() {
|
||||
return tageditor;
|
||||
};
|
||||
|
||||
tageditor.context = function(_) {
|
||||
context = _;
|
||||
return tageditor;
|
||||
};
|
||||
|
||||
return d3.rebind(tageditor, event, 'on');
|
||||
};
|
||||
|
||||
+17
-17
@@ -1,24 +1,25 @@
|
||||
iD.ui.Taglist = function() {
|
||||
iD.ui.Taglist = function(context) {
|
||||
var event = d3.dispatch('change'),
|
||||
taginfo = iD.taginfo(),
|
||||
initial = false,
|
||||
list,
|
||||
context;
|
||||
collapsebutton,
|
||||
list;
|
||||
|
||||
function taglist(selection) {
|
||||
function taglist(selection, expanded) {
|
||||
|
||||
var collapsebutton = selection.append('a')
|
||||
collapsebutton = selection.append('a')
|
||||
.attr('href','#')
|
||||
.attr('class','hide-toggle')
|
||||
.text('Additional tags')
|
||||
.text(t('inspector.additional'))
|
||||
.on('click', function() {
|
||||
collapsebutton.classed('expanded', wrap.classed('hide'));
|
||||
wrap.call(iD.ui.Toggle(wrap.classed('hide')));
|
||||
selection.node().parentNode.scrollTop += 200;
|
||||
});
|
||||
})
|
||||
.classed('expanded', expanded);
|
||||
|
||||
var wrap = selection.append('div')
|
||||
.attr('class', 'hide');
|
||||
.classed('hide', !expanded);
|
||||
|
||||
list = wrap.append('ul')
|
||||
.attr('class', 'tag-list');
|
||||
@@ -42,6 +43,8 @@ iD.ui.Taglist = function() {
|
||||
function drawTags(tags) {
|
||||
var entity = list.datum();
|
||||
|
||||
collapsebutton.text(t('inspector.additional') + ' (' + Object.keys(tags).length + ')');
|
||||
|
||||
tags = d3.entries(tags);
|
||||
|
||||
if (!tags.length) {
|
||||
@@ -212,26 +215,28 @@ iD.ui.Taglist = function() {
|
||||
|
||||
var keyinput = key.select('input');
|
||||
key.call(d3.combobox()
|
||||
.fetcher(_.debounce(function(_, __, callback) {
|
||||
.fetcher(function(_, __, callback) {
|
||||
taginfo.keys({
|
||||
debounce: true,
|
||||
geometry: geometry,
|
||||
query: keyinput.property('value')
|
||||
}, function(err, data) {
|
||||
if (!err) callback(sort(keyinput.property('value'), data));
|
||||
});
|
||||
}, 500)));
|
||||
}));
|
||||
|
||||
var valueinput = value.select('input');
|
||||
value.call(d3.combobox()
|
||||
.fetcher(_.debounce(function(_, __, callback) {
|
||||
.fetcher(function(_, __, callback) {
|
||||
taginfo.values({
|
||||
debounce: true,
|
||||
key: keyinput.property('value'),
|
||||
geometry: geometry,
|
||||
query: valueinput.property('value')
|
||||
}, function(err, data) {
|
||||
if (!err) callback(sort(valueinput.property('value'), data));
|
||||
});
|
||||
}, 500)));
|
||||
}));
|
||||
}
|
||||
|
||||
function focusNewKey() {
|
||||
@@ -265,10 +270,5 @@ iD.ui.Taglist = function() {
|
||||
}
|
||||
};
|
||||
|
||||
taglist.context = function(_) {
|
||||
context = _;
|
||||
return taglist;
|
||||
};
|
||||
|
||||
return d3.rebind(taglist, event, 'on');
|
||||
};
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
d3.tail = function() {
|
||||
iD.ui.Tail = function() {
|
||||
var text = false,
|
||||
container,
|
||||
inner,
|
||||
xmargin = 25,
|
||||
tooltip_size = [0, 0],
|
||||
selection_size = [0, 0],
|
||||
transformProp = iD.util.prefixCSSProperty('Transform');
|
||||
|
||||
var tail = function(selection) {
|
||||
|
||||
function tail(selection) {
|
||||
d3.select(window).on('resize.tail-size', function() {
|
||||
selection_size = selection.size();
|
||||
});
|
||||
|
||||
function setup() {
|
||||
|
||||
container = d3.select(document.body)
|
||||
.append('div').attr('class', 'tail tooltip-inner');
|
||||
.append('div')
|
||||
.style('display', 'none')
|
||||
.attr('class', 'tail tooltip-inner');
|
||||
|
||||
inner = container.append('div');
|
||||
|
||||
selection
|
||||
.on('mousemove.tail', mousemove)
|
||||
@@ -26,11 +29,16 @@ d3.tail = function() {
|
||||
.on('mousemove.tail', mousemove);
|
||||
|
||||
selection_size = selection.size();
|
||||
}
|
||||
|
||||
function show() {
|
||||
container.style('display', 'block');
|
||||
tooltip_size = container.size();
|
||||
}
|
||||
|
||||
function mousemove() {
|
||||
if (text === false) return;
|
||||
if (container.style('display') === 'none') show();
|
||||
var xoffset = ((d3.event.clientX + tooltip_size[0] + xmargin) > selection_size[0]) ?
|
||||
-tooltip_size[0] - xmargin : xmargin;
|
||||
container.classed('left', xoffset > 0);
|
||||
@@ -46,12 +54,11 @@ d3.tail = function() {
|
||||
|
||||
function mouseover() {
|
||||
if (d3.event.relatedTarget !== container.node() &&
|
||||
text !== false) container.style('display', 'block');
|
||||
text !== false) show();
|
||||
}
|
||||
|
||||
if (!container) setup();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
tail.text = function(_) {
|
||||
if (!arguments.length) return text;
|
||||
@@ -59,11 +66,9 @@ d3.tail = function() {
|
||||
text = _;
|
||||
container.style('display', 'none');
|
||||
return tail;
|
||||
} else if (container.style('display') == 'none') {
|
||||
container.style('display', 'block');
|
||||
}
|
||||
text = _;
|
||||
container.text(text);
|
||||
inner.text(text);
|
||||
tooltip_size = container.size();
|
||||
return tail;
|
||||
};
|
||||
+1
-1
@@ -36,5 +36,5 @@ iD.ui.Zoom = function(context) {
|
||||
|
||||
d3.select(document)
|
||||
.call(keybinding);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,6 +15,12 @@ iD.validate = function(changes, graph) {
|
||||
if (tags.building && tags.building === 'yes') return 'building=yes';
|
||||
}
|
||||
|
||||
if (changes.deleted.length > 100) {
|
||||
warnings.push({
|
||||
message: t('validations.many_deletions', { n: changes.deleted.length })
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = 0; i < changes.created.length; i++) {
|
||||
change = changes.created[i];
|
||||
|
||||
|
||||
+20
-15
@@ -15,15 +15,6 @@ d3.combobox = function() {
|
||||
var idx = -1;
|
||||
input = selection.select('input');
|
||||
|
||||
container = d3.select(document.body)
|
||||
.insert('div', ':first-child')
|
||||
.attr('class', 'combobox')
|
||||
.style({
|
||||
position: 'absolute',
|
||||
display: 'none',
|
||||
left: '0px'
|
||||
});
|
||||
|
||||
selection.append('a', selection.select('input'))
|
||||
.attr('class', 'combobox-carat')
|
||||
.on('mousedown', stop)
|
||||
@@ -64,14 +55,26 @@ d3.combobox = function() {
|
||||
}
|
||||
|
||||
function show() {
|
||||
container.style('display', 'block');
|
||||
shown = true;
|
||||
if (!shown) {
|
||||
container = d3.select(document.body)
|
||||
.insert('div', ':first-child')
|
||||
.attr('class', 'combobox')
|
||||
.style({
|
||||
position: 'absolute',
|
||||
display: 'block',
|
||||
left: '0px'
|
||||
});
|
||||
|
||||
shown = true;
|
||||
}
|
||||
}
|
||||
|
||||
function hide() {
|
||||
idx = -1;
|
||||
container.style('display', 'none');
|
||||
shown = false;
|
||||
if (shown) {
|
||||
idx = -1;
|
||||
container.remove();
|
||||
shown = false;
|
||||
}
|
||||
}
|
||||
|
||||
function slowHide() {
|
||||
@@ -189,7 +192,7 @@ d3.combobox = function() {
|
||||
|
||||
if (data.length &&
|
||||
document.activeElement === input.node()) show();
|
||||
else hide();
|
||||
else return hide();
|
||||
|
||||
autocomplete(e, data);
|
||||
|
||||
@@ -230,6 +233,8 @@ d3.combobox = function() {
|
||||
input.node().focus();
|
||||
update('');
|
||||
|
||||
if (!container) return;
|
||||
|
||||
var entries = container.selectAll('a'),
|
||||
height = container.node().scrollHeight / entries[0].length,
|
||||
w = d3.select(window);
|
||||
|
||||
@@ -2,7 +2,8 @@ d3.geo.tile = function() {
|
||||
var size = [960, 500],
|
||||
scale = 256,
|
||||
scaleExtent = [0, 20],
|
||||
translate = [size[0] / 2, size[1] / 2];
|
||||
translate = [size[0] / 2, size[1] / 2],
|
||||
zoomDelta = 0;
|
||||
|
||||
function bound(_) {
|
||||
return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
|
||||
@@ -10,7 +11,7 @@ d3.geo.tile = function() {
|
||||
|
||||
function tile() {
|
||||
var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
|
||||
z0 = bound(z | 0),
|
||||
z0 = bound(Math.round(z + zoomDelta)),
|
||||
k = Math.pow(2, z - z0 + 8),
|
||||
origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
|
||||
tiles = [],
|
||||
@@ -53,5 +54,11 @@ d3.geo.tile = function() {
|
||||
return tile;
|
||||
};
|
||||
|
||||
tile.zoomDelta = function(_) {
|
||||
if (!arguments.length) return zoomDelta;
|
||||
zoomDelta = +_;
|
||||
return tile;
|
||||
};
|
||||
|
||||
return tile;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
d3.rowselect = function() {
|
||||
|
||||
var input, data, wrap,
|
||||
event = d3.dispatch('change');
|
||||
|
||||
var select = function(selection) {
|
||||
|
||||
input = selection.select('input')
|
||||
.style('display', 'none');
|
||||
|
||||
wrap = selection.append('div')
|
||||
.attr('class', 'rowselect');
|
||||
|
||||
var labels = wrap.selectAll('div')
|
||||
.data(data)
|
||||
.enter()
|
||||
.append('div')
|
||||
.style('display', 'inline-block')
|
||||
.style('width', ~~(100 / data.length) + '%')
|
||||
.attr('class', 'item')
|
||||
.append('label')
|
||||
.on('click', function() {
|
||||
var checkbox = d3.select(this).select('input'),
|
||||
val = !!checkbox.property('checked');
|
||||
wrap.selectAll('input').property('checked', false);
|
||||
checkbox.property('checked', val);
|
||||
input.property('value', val ? checkbox.datum() : '');
|
||||
|
||||
event.change();
|
||||
d3.event.stopPropagation();
|
||||
});
|
||||
|
||||
var value = input.property('value');
|
||||
|
||||
labels.append('div')
|
||||
.append('input')
|
||||
.attr('type', 'checkbox');
|
||||
|
||||
labels.append('span').text(function(d) { return d; });
|
||||
|
||||
input.on('change.select', update);
|
||||
|
||||
};
|
||||
|
||||
function update() {
|
||||
var value = input.property('value');
|
||||
|
||||
wrap.selectAll('input')
|
||||
.property('checked', function(d) {
|
||||
return d === value;
|
||||
});
|
||||
}
|
||||
|
||||
select.data = function(_) {
|
||||
if (!arguments.length) return data;
|
||||
data = _;
|
||||
return select;
|
||||
};
|
||||
|
||||
select.update = update;
|
||||
|
||||
return d3.rebind(select, event, 'on');
|
||||
};
|
||||
Vendored
+76
-1484
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>iD</title>
|
||||
<style>
|
||||
body {
|
||||
font:normal 20px/30px 'Helvetica Neue';
|
||||
text-align:center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<html><head></head>
|
||||
<body>
|
||||
<h1 id='land'></h1>
|
||||
<script>
|
||||
var i = 2;
|
||||
window.setInterval(function() {
|
||||
document.getElementById('land').innerHTML = (new Array(i++)).join('.');
|
||||
i = (i > 8) ? 2 : i;
|
||||
}, 200);
|
||||
opener.authComplete(window.location.search.slice(1));
|
||||
window.close();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-1
@@ -179,7 +179,11 @@ locale.da = {
|
||||
new_tag: "Nyt tag",
|
||||
edit_tags: "Ret tags",
|
||||
okay: "Ok",
|
||||
view_on_osm: "Vis på OSM"
|
||||
view_on_osm: "Vis på OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
restore: {
|
||||
@@ -221,6 +225,7 @@ locale.da = {
|
||||
untagged_point: "Mangler et tag på punkt som ikke er del af en linje eller område",
|
||||
untagged_line: "Mangler tag på linje",
|
||||
untagged_area: "Mangler tag på område",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "Dette tag {tag} mener denne linje skule være et område, men dette er ikke et område",
|
||||
deprecated_tags: "Uønskede tags: {tags}"
|
||||
}
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.de = {
|
||||
new_tag: "Neues Attribut",
|
||||
edit_tags: "Attribute bearbeiten",
|
||||
okay: "OK",
|
||||
view_on_osm: "auf OpenStreetMap ansehen"
|
||||
view_on_osm: "auf OpenStreetMap ansehen",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.de = {
|
||||
untagged_point: "Punkt ohne Attribute, der kein Teil einer Linie oder Fläche ist",
|
||||
untagged_line: "Linie ohne Attribute",
|
||||
untagged_area: "Fläche ohne Attribute",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "Das Attribut {tag} suggeriert eine Fläche, ist aber keine Fläche",
|
||||
deprecated_tags: "Veraltete Attribute: {tags}"
|
||||
},
|
||||
|
||||
+7
-2
@@ -112,7 +112,7 @@ locale.en = {
|
||||
vertex: "Moved a node in a way.",
|
||||
line: "Moved a line.",
|
||||
area: "Moved an area.",
|
||||
multiple: "Moved multiple objects"
|
||||
multiple: "Moved multiple objects."
|
||||
}
|
||||
},
|
||||
rotate: {
|
||||
@@ -181,7 +181,11 @@ locale.en = {
|
||||
new_tag: "New Tag",
|
||||
edit_tags: "Edit tags",
|
||||
okay: "Okay",
|
||||
view_on_osm: "View on OSM"
|
||||
view_on_osm: "View on OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -226,6 +230,7 @@ locale.en = {
|
||||
untagged_point: "Untagged point which is not part of a line or area",
|
||||
untagged_line: "Untagged line",
|
||||
untagged_area: "Untagged area",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "The tag {tag} suggests line should be area, but it is not an area",
|
||||
deprecated_tags: "Deprecated tags: {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.es = {
|
||||
new_tag: "Nueva etiqueta", //"New Tag"
|
||||
edit_tags: "Editar etiquetas", //"Edit tags",
|
||||
okay: "OK",
|
||||
view_on_osm: "Ver en OSM" //"View on OSM"
|
||||
view_on_osm: "Ver en OSM", //"View on OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.es = {
|
||||
untagged_point: "Punto sin etiquetar que no es parte de una línea ni de un área.", //"Untagged point which is not part of a line or area",
|
||||
untagged_line: "Línea sin etiquetar", //"Untagged line",
|
||||
untagged_area: "Área sin etiquetar", //"Untagged area",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "La etiqueta {tag} sugiere que esta línea debería ser una área, pero no lo es.", //"The tag {tag} suggests line should be area, but it is not an area",
|
||||
deprecated_tags: "Etiquetas obsoletas: {tags}" //"Deprecated tags: {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.fr = {
|
||||
new_tag: "Nouveau tag",
|
||||
edit_tags: "Editer les tags",
|
||||
okay: "Okay",
|
||||
view_on_osm: "Visualiser sur OSM"
|
||||
view_on_osm: "Visualiser sur OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.fr = {
|
||||
untagged_point: "Point sans aucun tag ne faisant partie ni d'une ligne, ni d'un polygone",
|
||||
untagged_line: "Ligne sans aucun tag",
|
||||
untagged_area: "Polygone sans aucun tag",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "Ce tag {tag} suppose que cette ligne devrait être un polygone, or ce n'est pas le cas",
|
||||
deprecated_tags: "Tags obsolètes : {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.it = {
|
||||
new_tag: "Nuovo Tag",
|
||||
edit_tags: "Modifica i tag",
|
||||
okay: "Ok",
|
||||
view_on_osm: "Mostra su OSM"
|
||||
view_on_osm: "Mostra su OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.it = {
|
||||
untagged_point: "Punto senza tag che non è parte di una linea o di un'area",
|
||||
untagged_line: "Linea senza tag",
|
||||
untagged_area: "Area senza tag",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "Il tag {tag} fa pensare che la linea sia un'area, ma non rappresenta un'area",
|
||||
deprecated_tags: "Tag deprecati: {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.ja = {
|
||||
new_tag: "新規タグ",
|
||||
edit_tags: "タグ編集",
|
||||
okay: "OK",
|
||||
view_on_osm: "詳細情報確認"
|
||||
view_on_osm: "詳細情報確認",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.ja = {
|
||||
untagged_point: "ポイントにタグが付与されておらず、ラインやエリアの一部でもありません",
|
||||
untagged_line: "ラインにタグが付与されていません",
|
||||
untagged_area: "エリアにタグが付与されていません",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "ラインに {tag} タグが付与されています。エリアで描かれるべきです",
|
||||
deprecated_tags: "タグの重複: {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.lv = {
|
||||
new_tag: "Jauns apzīmējums",
|
||||
edit_tags: "Labot apzīmējumus",
|
||||
okay: "Labi",
|
||||
view_on_osm: "Apskatīt OSM"
|
||||
view_on_osm: "Apskatīt OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.lv = {
|
||||
untagged_point: "Neapzīmēts punkts",
|
||||
untagged_line: "Neapzīmēta līnija",
|
||||
untagged_area: "Neapzīmēts apgabals",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "Apzīmējums {tag} parasti tiek lietots apgabaliem, bet objekts nav apgabals",
|
||||
deprecated_tags: "Novecojuši apzīmējumi: {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.nl = {
|
||||
new_tag: "Nieuwe tag",
|
||||
edit_tags: "Tags aanpassen",
|
||||
okay: "OK",
|
||||
view_on_osm: "Bekijk op OSM"
|
||||
view_on_osm: "Bekijk op OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.nl = {
|
||||
untagged_point: "Punt zonder tags, dat geen onderdeel is van een lijn of vlak",
|
||||
untagged_line: "Lijn zonder tags",
|
||||
untagged_area: "Vlak zonder tags",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "De tag {tag} suggereert dat de lijn een vlak is, maar het is geen vlak",
|
||||
deprecated_tags: "Afgeschafte tags: {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.pl = {
|
||||
new_tag: "Nowy tag",
|
||||
edit_tags: "Edytuj tagi",
|
||||
okay: "Okej",
|
||||
view_on_osm: "Zobacz w OSM"
|
||||
view_on_osm: "Zobacz w OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.pl = {
|
||||
untagged_point: "Nieopisany punkt, który nie jest częścią linii lub obszaru.",
|
||||
untagged_line: "Nieopisana linia.",
|
||||
untagged_area: "Nieopisany obszar.",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "Tag {tag} sugeruje, że linia powinna być obszarem, ale nim nie jest.",
|
||||
deprecated_tags: "Przestarzałe tagi: {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.ru = {
|
||||
new_tag: "Новый тег",
|
||||
edit_tags: "Править теги",
|
||||
okay: "Готово",
|
||||
view_on_osm: "Посмотреть в OSM"
|
||||
view_on_osm: "Посмотреть в OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.ru = {
|
||||
untagged_point: "Точка без тегов и не в составе линии или контура",
|
||||
untagged_line: "Линия без тегов",
|
||||
untagged_area: "Контур без тегов",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "Тег {tag} обычно ставится на замкнутые контуры, но это не контур",
|
||||
deprecated_tags: "Теги устарели: {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.tr = {
|
||||
new_tag: "Yeni Etiket",
|
||||
edit_tags: "Etiketleri güncelle",
|
||||
okay: "Tamam",
|
||||
view_on_osm: "View on OSM"
|
||||
view_on_osm: "View on OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.tr = {
|
||||
untagged_point: "Herhangi bir çizgi ya da alana bağlantısı olmayan ve etiketlenmemiş bir nokta.",
|
||||
untagged_line: "Etiketlenmemiş çizgi",
|
||||
untagged_area: "Etiketlenmemiş alan",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "{tag} etiketi buranın alan olmasını tavsiye ediyor ama alan değil.",
|
||||
deprecated_tags: "Kullanımdan kaldırılmış etiket : {tags}"
|
||||
},
|
||||
|
||||
+6
-1
@@ -171,7 +171,11 @@ locale.uk = {
|
||||
new_tag: "Новий теґ",
|
||||
edit_tags: "Редагувати теґи",
|
||||
okay: "Готово",
|
||||
view_on_osm: "Подивтись в ОСМ"
|
||||
view_on_osm: "Подивтись в ОСМ",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -216,6 +220,7 @@ locale.uk = {
|
||||
untagged_point: "Точка без теґів, що не є частиною лінію чи полігону",
|
||||
untagged_line: "Лінія без теґів",
|
||||
untagged_area: "Полігон без теґів",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "Теґ {tag} зазвичай ставться на полігони, але об’єкт ним не є",
|
||||
deprecated_tags: "Застарілі теґи: {tags}"
|
||||
},
|
||||
|
||||
+7
-2
@@ -112,7 +112,7 @@ locale.vi = {
|
||||
vertex: "Di chuyển nốt trong lối.",
|
||||
line: "Di chuyển đường kẻ.",
|
||||
area: "Di chuyển vùng.",
|
||||
multiple: "Di chuyển hơn một đối tượng"
|
||||
multiple: "Di chuyển hơn một đối tượng."
|
||||
}
|
||||
},
|
||||
reverse: {
|
||||
@@ -172,7 +172,11 @@ locale.vi = {
|
||||
new_tag: "Thẻ Mới",
|
||||
edit_tags: "Sửa đổi các thẻ",
|
||||
okay: "OK",
|
||||
view_on_osm: "Xem tại OSM"
|
||||
view_on_osm: "Xem tại OSM",
|
||||
name: "Name",
|
||||
editing: "Editing {type}",
|
||||
additional: "Additional tags",
|
||||
choose: "What are you adding?"
|
||||
},
|
||||
|
||||
layerswitcher: {
|
||||
@@ -217,6 +221,7 @@ locale.vi = {
|
||||
untagged_point: "Địa điểm không có thẻ mà không trực thuộc đường kẻ hoặc vùng",
|
||||
untagged_line: "Đường kẻ không có thẻ",
|
||||
untagged_area: "Vùng không có thẻ",
|
||||
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
|
||||
tag_suggests_area: "Thẻ {tag} có lẽ dành cho vùng nhưng được gắn vào đường kẻ",
|
||||
deprecated_tags: "Thẻ bị phản đối: {tags}"
|
||||
},
|
||||
|
||||
+2
-21
@@ -13,7 +13,8 @@
|
||||
"form": [
|
||||
{
|
||||
"key": "cuisine",
|
||||
"type": "combo"
|
||||
"type": "combo",
|
||||
"indexed": true
|
||||
},
|
||||
{
|
||||
"key": "internet_access",
|
||||
@@ -645,26 +646,6 @@
|
||||
"title": "Address"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Other",
|
||||
"name": "other",
|
||||
"match": {
|
||||
"type": ["line", "area"],
|
||||
"tags": {}
|
||||
},
|
||||
"icon": "square-stroked",
|
||||
"form": []
|
||||
},
|
||||
{
|
||||
"title": "Other",
|
||||
"name": "other",
|
||||
"match": {
|
||||
"type": ["node"],
|
||||
"tags": {}
|
||||
},
|
||||
"icon": "marker-stroked",
|
||||
"form": []
|
||||
}
|
||||
],
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 162 KiB |
+3
-3
@@ -26,7 +26,6 @@
|
||||
<script src='../js/lib/d3.trigger.js'></script>
|
||||
<script src='../js/lib/d3.typeahead.js'></script>
|
||||
<script src='../js/lib/d3.one.js'></script>
|
||||
<script src='../js/lib/d3.tail.js'></script>
|
||||
<script src='../js/lib/ohauth.js'></script>
|
||||
<script src='../js/lib/jxon.js'></script>
|
||||
<script src="../js/lib/rtree.js"></script>
|
||||
@@ -78,6 +77,7 @@
|
||||
<script src='../js/id/ui/source_switch.js'></script>
|
||||
<script src='../js/id/ui/tageditor.js'></script>
|
||||
<script src='../js/id/ui/taglist.js'></script>
|
||||
<script src='../js/id/ui/tail.js'></script>
|
||||
<script src='../js/id/ui/toggle.js'></script>
|
||||
|
||||
<script src='../js/id/actions.js'></script>
|
||||
@@ -96,7 +96,7 @@
|
||||
<script src='../js/id/actions/join.js'></script>
|
||||
<script src='../js/id/actions/merge.js'></script>
|
||||
<script src='../js/id/actions/move_node.js'></script>
|
||||
<script src='../js/id/actions/move_way.js'></script>
|
||||
<script src='../js/id/actions/move.js'></script>
|
||||
<script src='../js/id/actions/rotate_way.js'></script>
|
||||
<script src='../js/id/actions/noop.js'></script>
|
||||
<script src='../js/id/actions/reverse.js'></script>
|
||||
@@ -180,7 +180,7 @@
|
||||
<script src="spec/actions/join.js"></script>
|
||||
<script src='spec/actions/merge.js'></script>
|
||||
<script src="spec/actions/move_node.js"></script>
|
||||
<script src="spec/actions/move_way.js"></script>
|
||||
<script src="spec/actions/move.js"></script>
|
||||
<script src="spec/actions/noop.js"></script>
|
||||
<script src="spec/actions/reverse.js"></script>
|
||||
<script src="spec/actions/split.js"></script>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<script src="spec/actions/join.js"></script>
|
||||
<script src='spec/actions/merge.js'></script>
|
||||
<script src="spec/actions/move_node.js"></script>
|
||||
<script src="spec/actions/move_way.js"></script>
|
||||
<script src="spec/actions/move.js"></script>
|
||||
<script src="spec/actions/noop.js"></script>
|
||||
<script src="spec/actions/reverse.js"></script>
|
||||
<script src="spec/actions/split.js"></script>
|
||||
|
||||
@@ -14,4 +14,63 @@ describe("iD.actions.DeleteRelation", function () {
|
||||
graph = action(iD.Graph([a, b, parent]));
|
||||
expect(graph.entity(parent.id).members).to.eql([{ id: b.id }]);
|
||||
});
|
||||
|
||||
it("deletes member nodes not referenced by another parent", function() {
|
||||
var node = iD.Node(),
|
||||
relation = iD.Relation({members: [{id: node.id}]}),
|
||||
action = iD.actions.DeleteRelation(relation.id),
|
||||
graph = action(iD.Graph([node, relation]));
|
||||
expect(graph.entity(node.id)).to.be.undefined;
|
||||
});
|
||||
|
||||
it("does not delete member nodes referenced by another parent", function() {
|
||||
var node = iD.Node(),
|
||||
way = iD.Way({nodes: [node.id]}),
|
||||
relation = iD.Relation({members: [{id: node.id}]}),
|
||||
action = iD.actions.DeleteRelation(relation.id),
|
||||
graph = action(iD.Graph([node, way, relation]));
|
||||
expect(graph.entity(node.id)).not.to.be.undefined;
|
||||
});
|
||||
|
||||
it("does not delete member nodes with interesting tags", function() {
|
||||
var node = iD.Node({tags: {highway: 'traffic_signals'}}),
|
||||
relation = iD.Relation({members: [{id: node.id}]}),
|
||||
action = iD.actions.DeleteRelation(relation.id),
|
||||
graph = action(iD.Graph([node, relation]));
|
||||
expect(graph.entity(node.id)).not.to.be.undefined;
|
||||
});
|
||||
|
||||
it("deletes member ways not referenced by another parent", function() {
|
||||
var way = iD.Way(),
|
||||
relation = iD.Relation({members: [{id: way.id}]}),
|
||||
action = iD.actions.DeleteRelation(relation.id),
|
||||
graph = action(iD.Graph([way, relation]));
|
||||
expect(graph.entity(way.id)).to.be.undefined;
|
||||
});
|
||||
|
||||
it("does not delete member ways referenced by another parent", function() {
|
||||
var way = iD.Way(),
|
||||
relation1 = iD.Relation({members: [{id: way.id}]}),
|
||||
relation2 = iD.Relation({members: [{id: way.id}]}),
|
||||
action = iD.actions.DeleteRelation(relation1.id),
|
||||
graph = action(iD.Graph([way, relation1, relation2]));
|
||||
expect(graph.entity(way.id)).not.to.be.undefined;
|
||||
});
|
||||
|
||||
it("does not delete member ways with interesting tags", function() {
|
||||
var way = iD.Node({tags: {highway: 'residential'}}),
|
||||
relation = iD.Relation({members: [{id: way.id}]}),
|
||||
action = iD.actions.DeleteRelation(relation.id),
|
||||
graph = action(iD.Graph([way, relation]));
|
||||
expect(graph.entity(way.id)).not.to.be.undefined;
|
||||
});
|
||||
|
||||
it("deletes nodes of deleted member ways", function() {
|
||||
var node = iD.Node(),
|
||||
way = iD.Way({nodes: [node.id]}),
|
||||
relation = iD.Relation({members: [{id: way.id}]}),
|
||||
action = iD.actions.DeleteRelation(relation.id),
|
||||
graph = action(iD.Graph([node, way, relation]));
|
||||
expect(graph.entity(node.id)).to.be.undefined;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,7 +47,7 @@ describe("iD.actions.DeleteWay", function() {
|
||||
c = iD.Node(),
|
||||
way = iD.Way({nodes: [a.id, b.id, c.id, a.id]}),
|
||||
action = iD.actions.DeleteWay(way.id),
|
||||
graph = iD.Graph([a, b, way]).update(action);
|
||||
graph = iD.Graph([a, b, c, way]).update(action);
|
||||
expect(graph.entity(a.id)).to.be.undefined;
|
||||
expect(graph.entity(b.id)).to.be.undefined;
|
||||
expect(graph.entity(c.id)).to.be.undefined;
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
describe("iD.actions.Move", function() {
|
||||
it("moves all nodes in a way by the given amount", function() {
|
||||
var node1 = iD.Node({loc: [0, 0]}),
|
||||
node2 = iD.Node({loc: [5, 10]}),
|
||||
way = iD.Way({nodes: [node1.id, node2.id]}),
|
||||
delta = [2, 3],
|
||||
projection = d3.geo.mercator(),
|
||||
graph = iD.actions.Move([way.id], delta, projection)(iD.Graph([node1, node2, way])),
|
||||
loc1 = graph.entity(node1.id).loc,
|
||||
loc2 = graph.entity(node2.id).loc;
|
||||
expect(loc1[0]).to.be.closeTo( 1.440, 0.001);
|
||||
expect(loc1[1]).to.be.closeTo(-2.159, 0.001);
|
||||
expect(loc2[0]).to.be.closeTo( 6.440, 0.001);
|
||||
expect(loc2[1]).to.be.closeTo( 7.866, 0.001);
|
||||
});
|
||||
|
||||
it("moves repeated nodes only once", function() {
|
||||
var node = iD.Node({loc: [0, 0]}),
|
||||
way = iD.Way({nodes: [node.id, node.id]}),
|
||||
delta = [2, 3],
|
||||
projection = d3.geo.mercator(),
|
||||
graph = iD.actions.Move([way.id], delta, projection)(iD.Graph([node, way])),
|
||||
loc = graph.entity(node.id).loc;
|
||||
expect(loc[0]).to.be.closeTo( 1.440, 0.001);
|
||||
expect(loc[1]).to.be.closeTo(-2.159, 0.001);
|
||||
});
|
||||
|
||||
it("moves multiple ways", function() {
|
||||
var node = iD.Node({loc: [0, 0]}),
|
||||
way1 = iD.Way({nodes: [node.id]}),
|
||||
way2 = iD.Way({nodes: [node.id]}),
|
||||
delta = [2, 3],
|
||||
projection = d3.geo.mercator(),
|
||||
graph = iD.actions.Move([way1.id, way2.id], delta, projection)(iD.Graph([node, way1, way2])),
|
||||
loc = graph.entity(node.id).loc;
|
||||
expect(loc[0]).to.be.closeTo( 1.440, 0.001);
|
||||
expect(loc[1]).to.be.closeTo(-2.159, 0.001);
|
||||
});
|
||||
|
||||
it("moves leaf nodes of a relation", function() {
|
||||
var node = iD.Node({loc: [0, 0]}),
|
||||
way = iD.Way({nodes: [node.id]}),
|
||||
relation = iD.Relation({members: [{id: way.id}]}),
|
||||
delta = [2, 3],
|
||||
projection = d3.geo.mercator(),
|
||||
graph = iD.actions.Move([relation.id], delta, projection)(iD.Graph([node, way, relation])),
|
||||
loc = graph.entity(node.id).loc;
|
||||
expect(loc[0]).to.be.closeTo( 1.440, 0.001);
|
||||
expect(loc[1]).to.be.closeTo(-2.159, 0.001);
|
||||
});
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
describe("iD.actions.MoveWay", function() {
|
||||
it("moves all nodes in a way by the given amount", function() {
|
||||
var node1 = iD.Node({loc: [0, 0]}),
|
||||
node2 = iD.Node({loc: [5, 10]}),
|
||||
way = iD.Way({nodes: [node1.id, node2.id]}),
|
||||
delta = [2, 3],
|
||||
projection = d3.geo.mercator(),
|
||||
graph = iD.actions.MoveWay(way.id, delta, projection)(iD.Graph([node1, node2, way])),
|
||||
loc1 = graph.entity(node1.id).loc,
|
||||
loc2 = graph.entity(node2.id).loc;
|
||||
expect(loc1[0]).to.be.closeTo( 1.440, 0.001);
|
||||
expect(loc1[1]).to.be.closeTo(-2.159, 0.001);
|
||||
expect(loc2[0]).to.be.closeTo( 6.440, 0.001);
|
||||
expect(loc2[1]).to.be.closeTo( 7.866, 0.001);
|
||||
});
|
||||
|
||||
it("moves repeated nodes only once", function() {
|
||||
var node = iD.Node({loc: [0, 0]}),
|
||||
way = iD.Way({nodes: [node.id, node.id]}),
|
||||
delta = [2, 3],
|
||||
projection = d3.geo.mercator(),
|
||||
graph = iD.actions.MoveWay(way.id, delta, projection)(iD.Graph([node, way])),
|
||||
loc = graph.entity(node.id).loc;
|
||||
expect(loc[0]).to.be.closeTo( 1.440, 0.001);
|
||||
expect(loc[1]).to.be.closeTo(-2.159, 0.001);
|
||||
});
|
||||
});
|
||||
@@ -25,7 +25,7 @@ describe("iD.taginfo", function() {
|
||||
server.respond();
|
||||
|
||||
expect(query(server.requests[0].url)).to.eql(
|
||||
{query: "amen", page: "1", rp: "6", sortname: "count_all", sortorder: "desc"});
|
||||
{query: "ame", page: "1", rp: "10", sortname: "count_all", sortorder: "desc"});
|
||||
expect(callback).to.have.been.calledWith(null, [{"value":"amenity"}]);
|
||||
});
|
||||
|
||||
@@ -49,11 +49,11 @@ describe("iD.taginfo", function() {
|
||||
|
||||
server.respondWith("GET", new RegExp("http://taginfo.openstreetmap.org/api/4/keys/all"),
|
||||
[200, { "Content-Type": "application/json" },
|
||||
'{"data":[{"count_all":5190337,"key":"amenity","count_all_fraction":1.0, "count_nodes_fraction":1.0},\
|
||||
{"count_all":1,"key":"amenityother","count_all_fraction":0.0, "count_nodes_fraction":1.0}]}']);
|
||||
'{"data":[{"count_all":5190337,"count_nodes":500000,"key":"amenity","count_all_fraction":1.0, "count_nodes_fraction":1.0},\
|
||||
{"count_all":1,"key":"amenityother","count_all_fraction":0.0, "count_nodes":100}]}']);
|
||||
server.respond();
|
||||
|
||||
expect(callback).to.have.been.calledWith(null, [{"value":"amenity"},{"value":"amenityother"}]);
|
||||
expect(callback).to.have.been.calledWith(null, [{"value":"amenity"}]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ describe("iD.ui.Inspector", function () {
|
||||
entity, graph, context;
|
||||
|
||||
function render() {
|
||||
inspector = iD.ui.Inspector().context(context);
|
||||
inspector = iD.ui.Inspector(context);
|
||||
element = d3.select('body')
|
||||
.append('div')
|
||||
.attr('id', 'inspector-wrap')
|
||||
|
||||
Reference in New Issue
Block a user