Merge branch 'master' into quick-translate

This commit is contained in:
Bryan Housel
2017-01-17 18:39:49 +05:30
21 changed files with 851 additions and 149 deletions
+77 -13
View File
@@ -1,51 +1,115 @@
{
"dataAddressFormats": [
{
"format": [["housenumber", "street"], ["city", "postcode"]]
"format": [
["housenumber", "street"],
["city", "postcode"]
]
},
{
"countryCodes": ["gb"],
"format": [["housename"], ["housenumber", "street"], ["city", "postcode"]]
"format": [
["housename"],
["housenumber", "street"],
["city", "postcode"]
]
},
{
"countryCodes": ["ie"],
"format": [["housename"], ["housenumber", "street"], ["city"], ["postcode"]]
"format": [
["housename"],
["housenumber", "street"],
["city"],
["postcode"]
]
},
{
"countryCodes": ["ad", "at", "ba", "be", "ch", "cz", "de", "dk", "es", "fi", "gr", "hr", "is", "it", "li", "nl", "no", "pl", "pt", "se", "si", "sk", "sm", "va"],
"format": [["street", "housenumber"], ["postcode", "city"]]
"countryCodes": [
"ad", "at", "ba", "be", "ch", "cz",
"de", "dk", "es", "fi", "gr", "hr",
"is", "it", "li", "nl", "no", "pl",
"pt", "se", "si", "sk", "sm", "va"
],
"format": [
["street", "housenumber"],
["postcode", "city"]
]
},
{
"countryCodes": ["fr", "lu", "mo"],
"format": [["housenumber", "street"], ["postcode", "city"]]
"format": [
["housenumber", "street"],
["postcode", "city"]
]
},
{
"countryCodes": ["br"],
"format": [["street"], ["housenumber", "suburb"], ["city", "postcode"]]
"format": [
["street"],
["housenumber", "suburb"],
["city", "postcode"]
]
},
{
"countryCodes": ["vn"],
"format": [["housenumber", "street"], ["subdistrict"], ["district"], ["city"], ["province", "postcode"]]
"format": [
["housenumber", "street"],
["subdistrict"],
["district"],
["city"],
["province", "postcode"]
]
},
{
"countryCodes": ["us"],
"format": [["housenumber", "street"], ["city", "state", "postcode"]]
"format": [
["housenumber", "street"],
["city", "state", "postcode"]
]
},
{
"countryCodes": ["ca"],
"format": [["housenumber", "street"], ["city", "province", "postcode"]]
"format": [
["housenumber", "street"],
["city", "province", "postcode"]
]
},
{
"countryCodes": ["tw"],
"format": [["postcode", "city", "district"], ["place", "street"], ["housenumber", "floor"]]
"format": [
["postcode", "city", "district"],
["place", "street"],
["housenumber", "floor"]
]
},
{
"countryCodes": ["jp"],
"format": [["postcode", "province", "county"], ["city", "suburb", "quarter"], ["neighbourhood", "block_number", "housenumber"]]
"format": [
["postcode", "province", "county"],
["city", "suburb"],
["quarter", "neighbourhood"],
["block_number", "housenumber"]
],
"dropdowns": [
"postcode", "province", "county",
"city", "suburb",
"quarter", "neighbourhood",
"block_number"
],
"widths": {
"postcode": 0.3, "province": 0.35, "county": 0.35,
"city": 0.65, "suburb": 0.35,
"quarter": 0.5, "neighbourhood": 0.5,
"block_number": 0.5, "housenumber": 0.5
}
},
{
"countryCodes": ["tr"],
"format": [["neighbourhood"], ["street", "housenumber"], ["postcode", "district", "city"]]
"format": [
["neighbourhood"],
["street", "housenumber"],
["postcode", "district", "city"]
]
}
]
}
+13 -2
View File
@@ -84,28 +84,39 @@ en:
# access=*
label: Access
address:
# 'addr:block_number=*, addr:city=*, addr:conscriptionnumber=*, addr:county=*, addr:country=*, addr:district=*, addr:floor=*, addr:hamlet=*, addr:housename=*, addr:housenumber=*, addr:neighbourhood=*, addr:place=*, addr:postcode=*, addr:province=*, addr:quarter=*, addr:state=*, addr:street=*, addr:subdistrict=*, addr:suburb=*'
# 'addr:block_number=*, addr:city=*, addr:block_number=*, addr:conscriptionnumber=*, addr:county=*, addr:country=*, addr:county=*, addr:district=*, addr:floor=*, addr:hamlet=*, addr:housename=*, addr:housenumber=*, addr:neighbourhood=*, addr:place=*, addr:postcode=*, addr:province=*, addr:quarter=*, addr:state=*, addr:street=*, addr:subdistrict=*, addr:suburb=*'
label: Address
placeholders:
block_number: Block number
block_number: Block Number
block_number!jp: Block No.
city: City
city!jp: City/Town/Village/Tokyo Special Ward
city!vn: City/Town
conscriptionnumber: '123'
country: Country
county: County
county!jp: District
district: District
district!vn: Arrondissement/Town/District
floor: Floor
hamlet: Hamlet
housename: Housename
housenumber: '123'
housenumber!jp: Building No./Lot No.
neighbourhood: Neighbourhood
neighbourhood!jp: Chōme/Aza/Koaza
place: Place
postcode: Postcode
province: Province
province!jp: Prefecture
quarter: Quarter
quarter!jp: Ōaza/Machi
state: State
street: Street
subdistrict: Subdistrict
subdistrict!vn: Ward/Commune/Townlet
suburb: Suburb
suburb!jp: Ward
admin_level:
# admin_level=*
label: Admin Level
+16 -3
View File
@@ -81,9 +81,11 @@
"keys": [
"addr:block_number",
"addr:city",
"addr:block_number",
"addr:conscriptionnumber",
"addr:county",
"addr:country",
"addr:county",
"addr:district",
"addr:floor",
"addr:hamlet",
@@ -107,25 +109,36 @@
"label": "Address",
"strings": {
"placeholders": {
"block_number": "Block number",
"block_number": "Block Number",
"block_number!jp": "Block No.",
"city": "City",
"city!jp": "City/Town/Village/Tokyo Special Ward",
"city!vn": "City/Town",
"conscriptionnumber": "123",
"county": "County",
"country": "Country",
"county": "County",
"county!jp": "District",
"district": "District",
"district!vn": "Arrondissement/Town/District",
"floor": "Floor",
"hamlet": "Hamlet",
"housename": "Housename",
"housenumber": "123",
"housenumber!jp": "Building No./Lot No.",
"neighbourhood": "Neighbourhood",
"neighbourhood!jp": "Chōme/Aza/Koaza",
"place": "Place",
"postcode": "Postcode",
"province": "Province",
"province!jp": "Prefecture",
"quarter": "Quarter",
"quarter!jp": "Ōaza/Machi",
"state": "State",
"street": "Street",
"subdistrict": "Subdistrict",
"suburb": "Suburb"
"subdistrict!vn": "Ward/Commune/Townlet",
"suburb": "Suburb",
"suburb!jp": "Ward"
}
}
},
+16 -3
View File
@@ -3,9 +3,11 @@
"keys": [
"addr:block_number",
"addr:city",
"addr:block_number",
"addr:conscriptionnumber",
"addr:county",
"addr:country",
"addr:county",
"addr:district",
"addr:floor",
"addr:hamlet",
@@ -27,25 +29,36 @@
"label": "Address",
"strings": {
"placeholders": {
"block_number": "Block number",
"block_number": "Block Number",
"block_number!jp": "Block No.",
"city": "City",
"city!jp": "City/Town/Village/Tokyo Special Ward",
"city!vn": "City/Town",
"conscriptionnumber": "123",
"county": "County",
"country": "Country",
"county": "County",
"county!jp": "District",
"district": "District",
"district!vn": "Arrondissement/Town/District",
"floor": "Floor",
"hamlet": "Hamlet",
"housename": "Housename",
"housenumber": "123",
"housenumber!jp": "Building No./Lot No.",
"neighbourhood": "Neighbourhood",
"neighbourhood!jp": "Chōme/Aza/Koaza",
"place": "Place",
"postcode": "Postcode",
"province": "Province",
"province!jp": "Prefecture",
"quarter": "Quarter",
"quarter!jp": "Ōaza/Machi",
"state": "State",
"street": "Street",
"subdistrict": "Subdistrict",
"suburb": "Suburb"
"subdistrict!vn": "Ward/Commune/Townlet",
"suburb": "Suburb",
"suburb!jp": "Ward"
}
}
}
+14 -3
View File
@@ -789,25 +789,36 @@
"address": {
"label": "Address",
"placeholders": {
"block_number": "Block number",
"block_number": "Block Number",
"block_number!jp": "Block No.",
"city": "City",
"city!jp": "City/Town/Village/Tokyo Special Ward",
"city!vn": "City/Town",
"conscriptionnumber": "123",
"county": "County",
"country": "Country",
"county": "County",
"county!jp": "District",
"district": "District",
"district!vn": "Arrondissement/Town/District",
"floor": "Floor",
"hamlet": "Hamlet",
"housename": "Housename",
"housenumber": "123",
"housenumber!jp": "Building No./Lot No.",
"neighbourhood": "Neighbourhood",
"neighbourhood!jp": "Chōme/Aza/Koaza",
"place": "Place",
"postcode": "Postcode",
"province": "Province",
"province!jp": "Prefecture",
"quarter": "Quarter",
"quarter!jp": "Ōaza/Machi",
"state": "State",
"street": "Street",
"subdistrict": "Subdistrict",
"suburb": "Suburb"
"subdistrict!vn": "Ward/Commune/Townlet",
"suburb": "Suburb",
"suburb!jp": "Ward"
}
},
"admin_level": {
+5 -2
View File
@@ -31,6 +31,9 @@ export function actionDisconnect(nodeId, newNodeId) {
if (connection.index === 0 && way.isArea()) {
// replace shared node with shared node..
graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
} else if (way.isClosed() && connection.index === way.nodes.length - 1) {
// replace closing node with new new node..
graph = graph.replace(way.unclose().addNode(newNode.id));
} else {
// replace shared node with multiple new nodes..
graph = graph.replace(way.updateNode(newNode.id, connection.index));
@@ -52,11 +55,11 @@ export function actionDisconnect(nodeId, newNodeId) {
return;
}
if (way.isArea() && (way.nodes[0] === nodeId)) {
candidates.push({wayID: way.id, index: 0});
candidates.push({ wayID: way.id, index: 0 });
} else {
way.nodes.forEach(function(waynode, index) {
if (waynode === nodeId) {
candidates.push({wayID: way.id, index: index});
candidates.push({ wayID: way.id, index: index });
}
});
}
+47 -28
View File
@@ -41,20 +41,27 @@ export function behaviorDrawWay(context, wayId, index, mode, baseGraph) {
annotation = t((way.isDegenerate() ?
'operations.start.annotation.' :
'operations.continue.annotation.') + context.geometry(wayId)),
draw = behaviorDraw(context);
draw = behaviorDraw(context),
startIndex, start, end, segment;
var startIndex = typeof index === 'undefined' ? way.nodes.length - 1 : 0,
start = osmNode({loc: context.graph().entity(way.nodes[startIndex]).loc}),
end = osmNode({loc: context.map().mouseCoordinates()}),
segment = osmWay({
if (!isArea) {
startIndex = typeof index === 'undefined' ? way.nodes.length - 1 : 0;
start = osmNode({ id: 'nStart', loc: context.entity(way.nodes[startIndex]).loc });
end = osmNode({ id: 'nEnd', loc: context.map().mouseCoordinates() });
segment = osmWay({ id: 'wTemp',
nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
tags: _.clone(way.tags)
});
} else {
end = osmNode({ loc: context.map().mouseCoordinates() });
}
var fn = context[way.isDegenerate() ? 'replace' : 'perform'];
if (isArea) {
fn(actionAddEntity(end),
actionAddVertex(wayId, end.id, index)
actionAddVertex(wayId, end.id)
);
} else {
fn(actionAddEntity(start),
@@ -70,7 +77,7 @@ export function behaviorDrawWay(context, wayId, index, mode, baseGraph) {
if (datum.type === 'node' && datum.id !== end.id) {
loc = datum.loc;
} else if (datum.type === 'way' && datum.id !== segment.id) {
} else if (datum.type === 'way') { // && (segment || datum.id !== segment.id)) {
var dims = context.map().dimensions(),
mouse = context.mouse(),
pad = 5,
@@ -145,9 +152,8 @@ export function behaviorDrawWay(context, wayId, index, mode, baseGraph) {
return function(graph) {
if (isArea) {
return graph
.replace(way.addNode(newNode.id, index))
.replace(way.addNode(newNode.id))
.remove(end);
} else {
return graph
.replace(graph.entity(wayId).addNode(newNode.id, index))
@@ -165,13 +171,19 @@ export function behaviorDrawWay(context, wayId, index, mode, baseGraph) {
var last = context.hasEntity(way.nodes[way.nodes.length - (isArea ? 2 : 1)]);
if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
var newNode = osmNode({loc: loc});
context.replace(
actionAddEntity(newNode),
ReplaceTemporaryNode(newNode),
annotation
);
if (isArea) {
context.replace(
actionMoveNode(end.id, loc),
annotation
);
} else {
var newNode = osmNode({loc: loc});
context.replace(
actionAddEntity(newNode),
ReplaceTemporaryNode(newNode),
annotation
);
}
finished = true;
context.enter(mode);
@@ -180,21 +192,28 @@ export function behaviorDrawWay(context, wayId, index, mode, baseGraph) {
// Connect the way to an existing way.
drawWay.addWay = function(loc, edge) {
var previousEdge = startIndex ?
[way.nodes[startIndex], way.nodes[startIndex - 1]] :
[way.nodes[0], way.nodes[1]];
// Avoid creating duplicate segments
if (!isArea && geoEdgeEqual(edge, previousEdge))
return;
if (isArea) {
context.perform(
actionAddMidpoint({ loc: loc, edge: edge}, end),
annotation
);
} else {
var previousEdge = startIndex ?
[way.nodes[startIndex], way.nodes[startIndex - 1]] :
[way.nodes[0], way.nodes[1]];
var newNode = osmNode({ loc: loc });
// Avoid creating duplicate segments
if (geoEdgeEqual(edge, previousEdge))
return;
context.perform(
actionAddMidpoint({ loc: loc, edge: edge}, newNode),
ReplaceTemporaryNode(newNode),
annotation
);
var newNode = osmNode({ loc: loc });
context.perform(
actionAddMidpoint({ loc: loc, edge: edge}, newNode),
ReplaceTemporaryNode(newNode),
annotation
);
}
finished = true;
context.enter(mode);
+10 -3
View File
@@ -27,6 +27,13 @@ export function modeAddArea(context) {
defaultTags = { area: 'yes' };
function actionClose(wayId) {
return function (graph) {
return graph.replace(graph.entity(wayId).close());
};
}
function start(loc) {
var graph = context.graph(),
node = osmNode({ loc: loc }),
@@ -36,7 +43,7 @@ export function modeAddArea(context) {
actionAddEntity(node),
actionAddEntity(way),
actionAddVertex(way.id, node.id),
actionAddVertex(way.id, node.id)
actionClose(way.id)
);
context.enter(modeDrawArea(context, way.id, graph));
@@ -52,7 +59,7 @@ export function modeAddArea(context) {
actionAddEntity(node),
actionAddEntity(way),
actionAddVertex(way.id, node.id),
actionAddVertex(way.id, node.id),
actionClose(way.id),
actionAddMidpoint({ loc: loc, edge: edge }, node)
);
@@ -67,7 +74,7 @@ export function modeAddArea(context) {
context.perform(
actionAddEntity(way),
actionAddVertex(way.id, node.id),
actionAddVertex(way.id, node.id)
actionClose(way.id)
);
context.enter(modeDrawArea(context, way.id, graph));
+1 -4
View File
@@ -7,8 +7,6 @@ import {
behaviorSelect
} from '../behavior/index';
import { modeDragNode } from './index';
export function modeBrowse(context) {
var mode = {
@@ -22,8 +20,7 @@ export function modeBrowse(context) {
behaviorPaste(context),
behaviorHover(context).on('hover', context.ui().sidebar.hover),
behaviorSelect(context),
behaviorLasso(context),
modeDragNode(context).behavior
behaviorLasso(context)
];
+9 -3
View File
@@ -79,12 +79,16 @@ export function modeDragNode(context) {
function start(entity) {
activeIDs = _.map(context.graph().parentWays(entity), 'id');
activeIDs.push(entity.id);
wasMidpoint = entity.type === 'midpoint';
isCancelled = d3.event.sourceEvent.shiftKey ||
!(wasMidpoint || _.some(activeIDs, function (activeID) { return selectedIDs.indexOf(activeID) !== -1; })) ||
context.features().hasHiddenConnections(entity, context.graph());
if (isCancelled) return behavior.cancel();
wasMidpoint = entity.type === 'midpoint';
if (wasMidpoint) {
var midpoint = entity;
entity = osmNode();
@@ -93,12 +97,14 @@ export function modeDragNode(context) {
var vertex = context.surface().selectAll('.' + entity.id);
behavior.target(vertex.node(), entity);
activeIDs = _.map(context.graph().parentWays(entity), 'id');
activeIDs.push(entity.id);
} else {
context.perform(actionNoop());
}
activeIDs = _.map(context.graph().parentWays(entity), 'id');
activeIDs.push(entity.id);
setActiveElements();
context.enter(mode);
}
+6 -5
View File
@@ -11,17 +11,18 @@ export function modeDrawArea(context, wayId, baseGraph) {
mode.enter = function() {
var way = context.entity(wayId),
headId = way.nodes[way.nodes.length - 2],
tailId = way.first();
var way = context.entity(wayId);
behavior = behaviorDrawWay(context, wayId, -1, mode, baseGraph)
behavior = behaviorDrawWay(context, wayId, undefined, mode, baseGraph)
.tail(t('modes.draw_area.tail'));
var addNode = behavior.addNode;
behavior.addNode = function(node) {
if (node.id === headId || node.id === tailId) {
var length = way.nodes.length,
penultimate = length > 2 ? way.nodes[length - 2] : null;
if (node.id === way.first() || node.id === penultimate) {
behavior.finish();
} else {
addNode(node);
+1
View File
@@ -15,6 +15,7 @@ export function operationContinue(selectedIDs, context) {
function candidateWays() {
return graph.parentWays(vertex).filter(function(parent) {
return parent.geometry(graph) === 'line' &&
!parent.isClosed() &&
parent.affix(vertex.id) &&
(geometries.line.length === 0 || geometries.line[0] === parent);
});
+149 -18
View File
@@ -122,7 +122,7 @@ _.extend(osmWay.prototype, {
isClosed: function() {
return this.nodes.length > 0 && this.first() === this.last();
return this.nodes.length > 1 && this.first() === this.last();
},
@@ -188,46 +188,169 @@ _.extend(osmWay.prototype, {
},
// If this way is not closed, append the beginning node to the end of the nodelist to close it.
close: function() {
if (this.isClosed() || !this.nodes.length) return this;
var nodes = this.nodes.slice();
nodes = nodes.filter(noRepeatNodes);
nodes.push(nodes[0]);
return this.update({ nodes: nodes });
},
// If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
unclose: function() {
if (!this.isClosed()) return this;
var nodes = this.nodes.slice(),
connector = this.first(),
i = nodes.length - 1;
// remove trailing connectors..
while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
nodes.splice(i, 1);
i = nodes.length - 1;
}
nodes = nodes.filter(noRepeatNodes);
return this.update({ nodes: nodes });
},
// Adds a node (id) in front of the node which is currently at position index.
// If index is undefined, the node will be added to the end of the way for linear ways,
// or just before the final connecting node for circular ways.
// Consecutive duplicates are eliminated including existing ones.
// Circularity is always preserved when adding a node.
addNode: function(id, index) {
var nodes = this.nodes.slice();
nodes.splice(index === undefined ? nodes.length : index, 0, id);
return this.update({nodes: nodes});
var nodes = this.nodes.slice(),
isClosed = this.isClosed(),
max = isClosed ? nodes.length - 1 : nodes.length;
if (index === undefined) {
index = max;
}
if (index < 0 || index > max) {
throw new RangeError('index ' + index + ' out of range 0..' + max);
}
// If this is a closed way, remove all connector nodes except the first one
// (there may be duplicates) and adjust index if necessary..
if (isClosed) {
var connector = this.first();
// leading connectors..
var i = 1;
while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
nodes.splice(i, 1);
if (index > i) index--;
}
// trailing connectors..
i = nodes.length - 1;
while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
nodes.splice(i, 1);
if (index > i) index--;
i = nodes.length - 1;
}
}
nodes.splice(index, 0, id);
nodes = nodes.filter(noRepeatNodes);
// If the way was closed before, append a connector node to keep it closed..
if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
nodes.push(nodes[0]);
}
return this.update({ nodes: nodes });
},
// Replaces the node which is currently at position index with the given node (id).
// Consecutive duplicates are eliminated including existing ones.
// Circularity is preserved when updating a node.
updateNode: function(id, index) {
var nodes = this.nodes.slice();
var nodes = this.nodes.slice(),
isClosed = this.isClosed(),
max = nodes.length - 1;
if (index === undefined || index < 0 || index > max) {
throw new RangeError('index ' + index + ' out of range 0..' + max);
}
// If this is a closed way, remove all connector nodes except the first one
// (there may be duplicates) and adjust index if necessary..
if (isClosed) {
var connector = this.first();
// leading connectors..
var i = 1;
while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
nodes.splice(i, 1);
if (index > i) index--;
}
// trailing connectors..
i = nodes.length - 1;
while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
nodes.splice(i, 1);
if (index === i) index = 0; // update leading connector instead
i = nodes.length - 1;
}
}
nodes.splice(index, 1, id);
nodes = nodes.filter(noRepeatNodes);
// If the way was closed before, append a connector node to keep it closed..
if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
nodes.push(nodes[0]);
}
return this.update({nodes: nodes});
},
// Replaces each occurrence of node id needle with replacement.
// Consecutive duplicates are eliminated including existing ones.
// Circularity is preserved.
replaceNode: function(needle, replacement) {
if (this.nodes.indexOf(needle) < 0)
return this;
var nodes = this.nodes.slice(),
isClosed = this.isClosed();
var nodes = this.nodes.slice();
for (var i = 0; i < nodes.length; i++) {
if (nodes[i] === needle) {
nodes[i] = replacement;
}
}
nodes = nodes.filter(noRepeatNodes);
// If the way was closed before, append a connector node to keep it closed..
if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
nodes.push(nodes[0]);
}
return this.update({nodes: nodes});
},
// Removes each occurrence of node id needle with replacement.
// Consecutive duplicates are eliminated including existing ones.
// Circularity is preserved.
removeNode: function(id) {
var nodes = [];
var nodes = this.nodes.slice(),
isClosed = this.isClosed();
for (var i = 0; i < this.nodes.length; i++) {
var node = this.nodes[i];
if (node !== id && nodes[nodes.length - 1] !== node) {
nodes.push(node);
}
}
nodes = nodes
.filter(function(node) { return node !== id; })
.filter(noRepeatNodes);
// Preserve circularity
if (this.nodes.length > 1 && this.first() === id && this.last() === id && nodes[nodes.length - 1] !== nodes[0]) {
// If the way was closed before, append a connector node to keep it closed..
if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
nodes.push(nodes[0]);
}
@@ -248,7 +371,9 @@ _.extend(osmWay.prototype, {
})
}
};
if (changeset_id) r.way['@changeset'] = changeset_id;
if (changeset_id) {
r.way['@changeset'] = changeset_id;
}
return r;
},
@@ -297,3 +422,9 @@ _.extend(osmWay.prototype, {
});
}
});
// Filter function to eliminate consecutive duplicates.
function noRepeatNodes(node, i, arr) {
return i === 0 || node !== arr[i - 1];
}
+10 -11
View File
@@ -58,19 +58,18 @@ export function uiCommit(context) {
context.connection().userChangesets(function (err, changesets) {
if (err) return;
var comments = [];
for (var i = 0; i < changesets.length; i++) {
if (changesets[i].tags.comment) {
comments.push({
title: changesets[i].tags.comment,
value: changesets[i].tags.comment
});
}
}
var comments = changesets.map(function(changeset) {
return {
title: changeset.tags.comment,
value: changeset.tags.comment
};
});
commentField
.call(d3combobox().caseSensitive(true).data(comments));
.call(d3combobox()
.caseSensitive(true)
.data(_.uniqBy(comments, 'title'))
);
});
var clippyArea = commentSection.append('div')
+15 -15
View File
@@ -16,20 +16,11 @@ import { utilGetSetValue } from '../../util/get_set_value';
export function uiFieldAddress(field, context) {
var dispatch = d3.dispatch('init', 'change'),
nominatim = services.nominatim,
nominatim = services.geocoder,
wrap = d3.select(null),
isInitialized = false,
entity;
var widths = {
housenumber: 1/3,
street: 2/3,
city: 2/3,
state: 1/4,
postcode: 1/3
};
function getNearStreets() {
var extent = entity.extent(context.graph()),
l = extent.center(),
@@ -98,7 +89,6 @@ export function uiFieldAddress(field, context) {
}
}
function getNearValues(key) {
var extent = entity.extent(context.graph()),
l = extent.center(),
@@ -130,6 +120,11 @@ export function uiFieldAddress(field, context) {
return a && a.countryCodes && _.includes(a.countryCodes, countryCode);
}) || _.first(dataAddressFormats);
var widths = addressFormat.widths || {
housenumber: 1/3, street: 2/3,
city: 2/3, state: 1/4, postcode: 1/3
};
function row(r) {
// Normalize widths.
var total = _.reduce(r, function(sum, field) {
@@ -154,19 +149,25 @@ export function uiFieldAddress(field, context) {
.enter()
.append('input')
.property('type', 'text')
.attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
.attr('placeholder', function (d) {
var localkey = d.id + '!' + countryCode,
tkey = field.strings.placeholders[localkey] ? localkey : d.id;
return field.t('placeholders.' + tkey);
})
.attr('class', function (d) { return 'addr-' + d.id; })
.style('width', function (d) { return d.width * 100 + '%'; });
// Update
var addrTags = [
// setup dropdowns for common address tags
var dropdowns = addressFormat.dropdowns || [
'city', 'county', 'country', 'district', 'hamlet',
'neighbourhood', 'place', 'postcode', 'province',
'quarter', 'state', 'street', 'subdistrict', 'suburb'
];
// If fields exist for any of these tags, create dropdowns to pick nearby values..
addrTags.forEach(function(tag) {
dropdowns.forEach(function(tag) {
var nearValues = (tag === 'street') ? getNearStreets
: (tag === 'city') ? getNearCities
: getNearValues;
@@ -202,7 +203,6 @@ export function uiFieldAddress(field, context) {
.attr('class', 'preset-input-wrap')
.merge(wrap);
if (nominatim && entity) {
var center = entity.extent(context.graph()).center();
nominatim.countryCode(center, initCallback);
+1 -1
View File
@@ -15,7 +15,7 @@ export {
export function uiFieldCombo(field, context) {
var dispatch = d3.dispatch('change'),
nominatim = services.nominatim,
nominatim = services.geocoder,
taginfo = services.taginfo,
isMulti = (field.type === 'multiCombo'),
isNetwork = (field.type === 'networkCombo'),
+1 -1
View File
@@ -15,7 +15,7 @@ export {
export function uiFieldText(field, context) {
var dispatch = d3.dispatch('change'),
nominatim = services.nominatim,
nominatim = services.geocoder,
input,
entity;
-2
View File
@@ -1,5 +1,4 @@
export { uiInit } from './init';
export { uiFields } from './fields/index';
export { uiAccount } from './account';
export { uiAttribution } from './attribution';
export { uiBackground } from './background';
@@ -18,7 +17,6 @@ export { uiGeolocate } from './geolocate';
export { uiHelp } from './help';
export { uiInfo } from './info';
export { uiInspector } from './inspector';
export { uiIntro } from './intro';
export { uiLasso } from './lasso';
export { uiLoading } from './loading';
export { uiMapData } from './map_data';
+2 -2
View File
@@ -51,7 +51,7 @@
"js-yaml": "~3.7.0",
"jsonschema": "~1.1.0",
"json-stable-stringify": "~1.0.1",
"mapillary-js": "2.2.0",
"mapillary-js": "2.3.0",
"minimist": "~1.2.0",
"mocha": "~3.2.0",
"mocha-phantomjs-core": "~2.1.0",
@@ -59,7 +59,7 @@
"npm-run-all": "~4.0.0",
"phantomjs-prebuilt": "~2.1.11",
"request": "~2.79.0",
"rollup": "0.41.1",
"rollup": "0.41.4",
"rollup-plugin-commonjs": "7.0.0",
"rollup-plugin-json": "2.0.2",
"rollup-plugin-node-resolve": "2.0.0",
+457 -29
View File
@@ -127,16 +127,24 @@ describe('iD.osmWay', function() {
});
describe('#isClosed', function() {
it('returns false when the way has no nodes', function() {
expect(iD.Way().isClosed()).to.equal(false);
it('returns false when the way contains no nodes', function() {
expect(iD.Way().isClosed()).to.be.false;
});
it('returns false when the way contains a single node', function() {
expect(iD.Way({ nodes: 'a'.split('') }).isClosed()).to.be.false;
});
it('returns false when the way ends are not equal', function() {
expect(iD.Way({nodes: ['n1', 'n2']}).isClosed()).to.equal(false);
expect(iD.Way({ nodes: 'abc'.split('') }).isClosed()).to.be.false;
});
it('returns true when the way ends are equal', function() {
expect(iD.Way({nodes: ['n1', 'n2', 'n1']}).isClosed()).to.equal(true);
expect(iD.Way({ nodes: 'aba'.split('') }).isClosed()).to.be.true;
});
it('returns true when the way contains two of the same node', function() {
expect(iD.Way({ nodes: 'aa'.split('') }).isClosed()).to.be.true;
});
});
@@ -409,54 +417,474 @@ describe('iD.osmWay', function() {
});
});
describe('#close', function () {
it('returns self for empty way', function () {
var w = iD.Way();
expect(w.close()).to.deep.equal(w);
});
it('returns self for already closed way', function () {
var w1 = iD.Way({ nodes: 'aba'.split('') });
expect(w1.close()).to.deep.equal(w1);
var w2 = iD.Way({ nodes: 'aa'.split('') });
expect(w2.close()).to.deep.equal(w2);
});
it('closes a way', function () {
var w1 = iD.Way({ nodes: 'ab'.split('') });
expect(w1.close().nodes.join('')).to.eql('aba', 'multiple');
var w2 = iD.Way({ nodes: 'a'.split('') });
expect(w2.close().nodes.join('')).to.eql('aa', 'single');
});
it('eliminates duplicate consecutive nodes when closing a linear way', function () {
var w1 = iD.Way({ nodes: 'abb'.split('') });
expect(w1.close().nodes.join('')).to.eql('aba', 'duplicate at end');
var w2 = iD.Way({ nodes: 'abbc'.split('') });
expect(w2.close().nodes.join('')).to.eql('abca', 'duplicate in middle');
var w3 = iD.Way({ nodes: 'aabc'.split('') });
expect(w3.close().nodes.join('')).to.eql('abca', 'duplicate at beginning');
var w4 = iD.Way({ nodes: 'abbbcbb'.split('') });
expect(w4.close().nodes.join('')).to.eql('abcba', 'duplicates multiple places');
});
});
describe('#unclose', function () {
it('returns self for empty way', function () {
var w = iD.Way();
expect(w.unclose()).to.deep.equal(w);
});
it('returns self for already unclosed way', function () {
var w1 = iD.Way({ nodes: 'a'.split('') });
expect(w1.unclose()).to.deep.equal(w1);
var w2 = iD.Way({ nodes: 'ab'.split('') });
expect(w2.unclose()).to.deep.equal(w2);
});
it('uncloses a circular way', function () {
var w1 = iD.Way({ nodes: 'aba'.split('') });
expect(w1.unclose().nodes.join('')).to.eql('ab', 'multiple');
var w2 = iD.Way({ nodes: 'aa'.split('') });
expect(w2.unclose().nodes.join('')).to.eql('a', 'single');
});
it('eliminates duplicate consecutive nodes when unclosing a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.unclose().nodes.join('')).to.eql('abc', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.unclose().nodes.join('')).to.eql('abc', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.unclose().nodes.join('')).to.eql('abc', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.unclose().nodes.join('')).to.eql('abc', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.unclose().nodes.join('')).to.eql('abcb', 'duplicates multiple places');
var w6 = iD.Way({ nodes: 'aa'.split('') });
expect(w6.unclose().nodes.join('')).to.eql('a', 'single node circular');
var w7 = iD.Way({ nodes: 'aaa'.split('') });
expect(w7.unclose().nodes.join('')).to.eql('a', 'single node circular with duplicates');
});
});
describe('#addNode', function () {
it('adds a node to the end of a way', function () {
it('adds a node to an empty way', function () {
var w = iD.Way();
expect(w.addNode('a').nodes).to.eql(['a']);
});
it('adds a node to a way at index 0', function () {
var w = iD.Way({nodes: ['a', 'b']});
expect(w.addNode('c', 0).nodes).to.eql(['c', 'a', 'b']);
it('adds a node to the end of a linear way when index is undefined', function () {
var w = iD.Way({ nodes: 'ab'.split('') });
expect(w.addNode('c').nodes.join('')).to.eql('abc');
});
it('adds a node to a way at a positive index', function () {
var w = iD.Way({nodes: ['a', 'b']});
expect(w.addNode('c', 1).nodes).to.eql(['a', 'c', 'b']);
it('adds a node before the end connector of a circular way when index is undefined', function () {
var w1 = iD.Way({ nodes: 'aba'.split('') });
expect(w1.addNode('c').nodes.join('')).to.eql('abca', 'circular');
var w2 = iD.Way({ nodes: 'aa'.split('') });
expect(w2.addNode('c').nodes.join('')).to.eql('aca', 'single node circular');
});
it('adds a node to a way at a negative index', function () {
var w = iD.Way({nodes: ['a', 'b']});
expect(w.addNode('c', -1).nodes).to.eql(['a', 'c', 'b']);
it('adds an internal node to a linear way at a positive index', function () {
var w = iD.Way({ nodes: 'ab'.split('') });
expect(w.addNode('c', 1).nodes.join('')).to.eql('acb');
});
it('adds an internal node to a circular way at a positive index', function () {
var w1 = iD.Way({ nodes: 'aba'.split('') });
expect(w1.addNode('c', 1).nodes.join('')).to.eql('acba', 'circular');
var w2 = iD.Way({ nodes: 'aa'.split('') });
expect(w2.addNode('c', 1).nodes.join('')).to.eql('aca', 'single node circular');
});
it('adds a leading node to a linear way at index 0', function () {
var w = iD.Way({ nodes: 'ab'.split('') });
expect(w.addNode('c', 0).nodes.join('')).to.eql('cab');
});
it('adds a leading node to a circular way at index 0, preserving circularity', function () {
var w1 = iD.Way({ nodes: 'aba'.split('') });
expect(w1.addNode('c', 0).nodes.join('')).to.eql('cabc', 'circular');
var w2 = iD.Way({ nodes: 'aa'.split('') });
expect(w2.addNode('c', 0).nodes.join('')).to.eql('cac', 'single node circular');
});
it('throws RangeError if index outside of array range for linear way', function () {
var w = iD.Way({ nodes: 'ab'.split('') });
expect(w.addNode.bind(w, 'c', 3)).to.throw(RangeError, /out of range 0\.\.2/, 'over range');
expect(w.addNode.bind(w, 'c', -1)).to.throw(RangeError, /out of range 0\.\.2/, 'under range');
});
it('throws RangeError if index outside of array range for circular way', function () {
var w = iD.Way({ nodes: 'aba'.split('') });
expect(w.addNode.bind(w, 'c', 3)).to.throw(RangeError, /out of range 0\.\.2/, 'over range');
expect(w.addNode.bind(w, 'c', -1)).to.throw(RangeError, /out of range 0\.\.2/, 'under range');
});
it('eliminates duplicate consecutive nodes when adding to the end of a linear way', function () {
var w1 = iD.Way({ nodes: 'abb'.split('') });
expect(w1.addNode('b').nodes.join('')).to.eql('ab', 'duplicate at end');
var w2 = iD.Way({ nodes: 'abbc'.split('') });
expect(w2.addNode('c').nodes.join('')).to.eql('abc', 'duplicate in middle');
var w3 = iD.Way({ nodes: 'aabc'.split('') });
expect(w3.addNode('c').nodes.join('')).to.eql('abc', 'duplicate at beginning');
var w4 = iD.Way({ nodes: 'abbbcbb'.split('') });
expect(w4.addNode('b').nodes.join('')).to.eql('abcb', 'duplicates multiple places');
});
it('eliminates duplicate consecutive nodes when adding same node before the end connector of a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.addNode('c').nodes.join('')).to.eql('abca', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.addNode('c').nodes.join('')).to.eql('abca', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.addNode('c').nodes.join('')).to.eql('abca', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.addNode('a').nodes.join('')).to.eql('abca', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.addNode('b').nodes.join('')).to.eql('abcba', 'duplicates multiple places');
var w6 = iD.Way({ nodes: 'aa'.split('') });
expect(w6.addNode('a').nodes.join('')).to.eql('aa', 'single node circular');
var w7 = iD.Way({ nodes: 'aaa'.split('') });
expect(w7.addNode('a').nodes.join('')).to.eql('aa', 'single node circular with duplicates');
});
it('eliminates duplicate consecutive nodes when adding different node before the end connector of a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.addNode('d').nodes.join('')).to.eql('abcda', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.addNode('d').nodes.join('')).to.eql('abcda', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.addNode('d').nodes.join('')).to.eql('abcda', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.addNode('d').nodes.join('')).to.eql('abcda', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.addNode('d').nodes.join('')).to.eql('abcbda', 'duplicates multiple places');
var w6 = iD.Way({ nodes: 'aa'.split('') });
expect(w6.addNode('d').nodes.join('')).to.eql('ada', 'single node circular');
var w7 = iD.Way({ nodes: 'aaa'.split('') });
expect(w7.addNode('d').nodes.join('')).to.eql('ada', 'single node circular with duplicates');
});
it('eliminates duplicate consecutive nodes when adding to the beginning of a linear way', function () {
var w1 = iD.Way({ nodes: 'abb'.split('') });
expect(w1.addNode('a', 0).nodes.join('')).to.eql('ab', 'duplicate at end');
var w2 = iD.Way({ nodes: 'abbc'.split('') });
expect(w2.addNode('a', 0).nodes.join('')).to.eql('abc', 'duplicate in middle');
var w3 = iD.Way({ nodes: 'aabc'.split('') });
expect(w3.addNode('a', 0).nodes.join('')).to.eql('abc', 'duplicate at beginning');
var w4 = iD.Way({ nodes: 'abbbcbb'.split('') });
expect(w4.addNode('a', 0).nodes.join('')).to.eql('abcb', 'duplicates multiple places');
});
it('eliminates duplicate consecutive nodes when adding same node as beginning connector a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.addNode('a', 0).nodes.join('')).to.eql('abca', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.addNode('a', 0).nodes.join('')).to.eql('abca', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.addNode('a', 0).nodes.join('')).to.eql('abca', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.addNode('a', 0).nodes.join('')).to.eql('abca', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.addNode('a', 0).nodes.join('')).to.eql('abcba', 'duplicates multiple places');
var w6 = iD.Way({ nodes: 'aa'.split('') });
expect(w6.addNode('a', 0).nodes.join('')).to.eql('aa', 'single node circular');
var w7 = iD.Way({ nodes: 'aaa'.split('') });
expect(w7.addNode('a', 0).nodes.join('')).to.eql('aa', 'single node circular with duplicates');
});
it('eliminates duplicate consecutive nodes when adding different node as beginning connector of a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.addNode('d', 0).nodes.join('')).to.eql('dabcd', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.addNode('d', 0).nodes.join('')).to.eql('dabcd', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.addNode('d', 0).nodes.join('')).to.eql('dabcd', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.addNode('d', 0).nodes.join('')).to.eql('dabcd', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.addNode('d', 0).nodes.join('')).to.eql('dabcbd', 'duplicates multiple places');
var w6 = iD.Way({ nodes: 'aa'.split('') });
expect(w6.addNode('d', 0).nodes.join('')).to.eql('dad', 'single node circular');
var w7 = iD.Way({ nodes: 'aaa'.split('') });
expect(w7.addNode('d', 0).nodes.join('')).to.eql('dad', 'single node circular with duplicates');
});
});
describe('#updateNode', function () {
it('updates the node id at the specified index', function () {
var w = iD.Way({nodes: ['a', 'b', 'c']});
expect(w.updateNode('d', 1).nodes).to.eql(['a', 'd', 'c']);
it('throws RangeError if empty way', function () {
var w = iD.Way();
expect(w.updateNode.bind(w, 'd', 0)).to.throw(RangeError, /out of range 0\.\.-1/);
});
it('updates an internal node on a linear way at a positive index', function () {
var w = iD.Way({ nodes: 'ab'.split('') });
expect(w.updateNode('d', 1).nodes.join('')).to.eql('ad');
});
it('updates an internal node on a circular way at a positive index', function () {
var w = iD.Way({ nodes: 'aba'.split('') });
expect(w.updateNode('d', 1).nodes.join('')).to.eql('ada', 'circular');
});
it('updates a leading node on a linear way at index 0', function () {
var w = iD.Way({ nodes: 'ab'.split('') });
expect(w.updateNode('d', 0).nodes.join('')).to.eql('db');
});
it('updates a leading node on a circular way at index 0, preserving circularity', function () {
var w1 = iD.Way({ nodes: 'aba'.split('') });
expect(w1.updateNode('d', 0).nodes.join('')).to.eql('dbd', 'circular');
var w2 = iD.Way({ nodes: 'aa'.split('') });
expect(w2.updateNode('d', 0).nodes.join('')).to.eql('dd', 'single node circular');
});
it('throws RangeError if index outside of array range for linear way', function () {
var w = iD.Way({ nodes: 'ab'.split('') });
expect(w.updateNode.bind(w, 'd', 2)).to.throw(RangeError, /out of range 0\.\.1/, 'over range');
expect(w.updateNode.bind(w, 'd', -1)).to.throw(RangeError, /out of range 0\.\.1/, 'under range');
});
it('throws RangeError if index outside of array range for circular way', function () {
var w = iD.Way({ nodes: 'aba'.split('') });
expect(w.updateNode.bind(w, 'd', 3)).to.throw(RangeError, /out of range 0\.\.2/, 'over range');
expect(w.updateNode.bind(w, 'd', -1)).to.throw(RangeError, /out of range 0\.\.2/, 'under range');
});
it('eliminates duplicate consecutive nodes when updating the end of a linear way', function () {
var w1 = iD.Way({ nodes: 'abcc'.split('') });
expect(w1.updateNode('c', 3).nodes.join('')).to.eql('abc', 'duplicate at end');
var w2 = iD.Way({ nodes: 'abbc'.split('') });
expect(w2.updateNode('c', 3).nodes.join('')).to.eql('abc', 'duplicate in middle');
var w3 = iD.Way({ nodes: 'aabc'.split('') });
expect(w3.updateNode('c', 3).nodes.join('')).to.eql('abc', 'duplicate at beginning');
var w4 = iD.Way({ nodes: 'abbbcbb'.split('') });
expect(w4.updateNode('b', 6).nodes.join('')).to.eql('abcb', 'duplicates multiple places');
});
it('eliminates duplicate consecutive nodes when updating same node before the end connector of a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.updateNode('c', 3).nodes.join('')).to.eql('abca', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.updateNode('c', 3).nodes.join('')).to.eql('abca', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.updateNode('c', 3).nodes.join('')).to.eql('abca', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.updateNode('a', 3).nodes.join('')).to.eql('abca', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.updateNode('b', 6).nodes.join('')).to.eql('abcba', 'duplicates multiple places');
});
it('eliminates duplicate consecutive nodes when updating different node before the end connector of a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.updateNode('d', 3).nodes.join('')).to.eql('abcda', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.updateNode('d', 3).nodes.join('')).to.eql('abda', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.updateNode('d', 3).nodes.join('')).to.eql('abda', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.updateNode('d', 3).nodes.join('')).to.eql('dbcd', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.updateNode('d', 6).nodes.join('')).to.eql('abcbda', 'duplicates multiple places');
});
it('eliminates duplicate consecutive nodes when updating the beginning of a linear way', function () {
var w1 = iD.Way({ nodes: 'abb'.split('') });
expect(w1.updateNode('b', 0).nodes.join('')).to.eql('b', 'duplicate at end');
var w2 = iD.Way({ nodes: 'abbc'.split('') });
expect(w2.updateNode('b', 0).nodes.join('')).to.eql('bc', 'duplicate in middle');
var w3 = iD.Way({ nodes: 'aabc'.split('') });
expect(w3.updateNode('a', 0).nodes.join('')).to.eql('abc', 'duplicate at beginning');
var w4 = iD.Way({ nodes: 'abbbcbb'.split('') });
expect(w4.updateNode('a', 0).nodes.join('')).to.eql('abcb', 'duplicates multiple places');
});
it('eliminates duplicate consecutive nodes when updating same node as beginning connector a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.updateNode('a', 0).nodes.join('')).to.eql('abca', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.updateNode('a', 0).nodes.join('')).to.eql('abca', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.updateNode('a', 0).nodes.join('')).to.eql('abca', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.updateNode('a', 0).nodes.join('')).to.eql('abca', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.updateNode('a', 0).nodes.join('')).to.eql('abcba', 'duplicates multiple places');
var w6 = iD.Way({ nodes: 'aa'.split('') });
expect(w6.updateNode('a', 0).nodes.join('')).to.eql('aa', 'single node circular');
var w7 = iD.Way({ nodes: 'aaa'.split('') });
expect(w7.updateNode('a', 0).nodes.join('')).to.eql('aa', 'single node circular with duplicates');
});
it('eliminates duplicate consecutive nodes when updating different node as beginning connector of a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.updateNode('d', 0).nodes.join('')).to.eql('dbcd', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.updateNode('d', 0).nodes.join('')).to.eql('dbcd', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.updateNode('d', 0).nodes.join('')).to.eql('dbcd', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.updateNode('d', 0).nodes.join('')).to.eql('dbcd', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.updateNode('d', 0).nodes.join('')).to.eql('dbcbd', 'duplicates multiple places');
var w6 = iD.Way({ nodes: 'aa'.split('') });
expect(w6.updateNode('d', 0).nodes.join('')).to.eql('dd', 'single node circular');
var w7 = iD.Way({ nodes: 'aaa'.split('') });
expect(w7.updateNode('d', 0).nodes.join('')).to.eql('dd', 'single node circular with duplicates');
});
it('eliminates duplicate consecutive nodes when updating different node as ending connector of a circular way', function () {
var w1 = iD.Way({ nodes: 'abcca'.split('') });
expect(w1.updateNode('d', 4).nodes.join('')).to.eql('dbcd', 'duplicate internal node at end');
var w2 = iD.Way({ nodes: 'abbca'.split('') });
expect(w2.updateNode('d', 4).nodes.join('')).to.eql('dbcd', 'duplicate internal node in middle');
var w3 = iD.Way({ nodes: 'aabca'.split('') });
expect(w3.updateNode('d', 4).nodes.join('')).to.eql('dbcd', 'duplicate connector node at beginning');
var w4 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w4.updateNode('d', 4).nodes.join('')).to.eql('dbcd', 'duplicate connector node at end');
var w5 = iD.Way({ nodes: 'abbbcbba'.split('') });
expect(w5.updateNode('d', 7).nodes.join('')).to.eql('dbcbd', 'duplicates multiple places');
var w6 = iD.Way({ nodes: 'aa'.split('') });
expect(w6.updateNode('d', 1).nodes.join('')).to.eql('dd', 'single node circular');
var w7 = iD.Way({ nodes: 'aaa'.split('') });
expect(w7.updateNode('d', 2).nodes.join('')).to.eql('dd', 'single node circular with duplicates');
});
});
describe('#replaceNode', function () {
it('replaces a node', function () {
var w1 = iD.Way({ nodes: 'a'.split('') });
expect(w1.replaceNode('a','b').nodes.join('')).to.eql('b', 'single replace, single node');
var w2 = iD.Way({ nodes: 'abc'.split('') });
expect(w2.replaceNode('b','d').nodes.join('')).to.eql('adc', 'single replace, linear');
var w4 = iD.Way({ nodes: 'abca'.split('') });
expect(w4.replaceNode('b','d').nodes.join('')).to.eql('adca', 'single replace, circular');
});
it('replaces multiply occurring nodes', function () {
var w1 = iD.Way({ nodes: 'abcb'.split('') });
expect(w1.replaceNode('b','d').nodes.join('')).to.eql('adcd', 'multiple replace, linear');
var w2 = iD.Way({ nodes: 'abca'.split('') });
expect(w2.replaceNode('a','d').nodes.join('')).to.eql('dbcd', 'multiple replace, circular');
var w3 = iD.Way({ nodes: 'aa'.split('') });
expect(w3.replaceNode('a','d').nodes.join('')).to.eql('dd', 'multiple replace, single node circular');
});
it('eliminates duplicate consecutive nodes when replacing along a linear way', function () {
var w1 = iD.Way({ nodes: 'abbcd'.split('') });
expect(w1.replaceNode('c','b').nodes.join('')).to.eql('abd', 'duplicate before');
var w2 = iD.Way({ nodes: 'abcdd'.split('') });
expect(w2.replaceNode('c','d').nodes.join('')).to.eql('abd', 'duplicate after');
var w3 = iD.Way({ nodes: 'abbcbb'.split('')});
expect(w3.replaceNode('c','b').nodes.join('')).to.eql('ab', 'duplicate before and after');
});
it('eliminates duplicate consecutive nodes when replacing internal nodes along a circular way', function () {
var w1 = iD.Way({ nodes: 'abbcda'.split('') });
expect(w1.replaceNode('c','b').nodes.join('')).to.eql('abda', 'duplicate before');
var w2 = iD.Way({ nodes: 'abcdda'.split('') });
expect(w2.replaceNode('c','d').nodes.join('')).to.eql('abda', 'duplicate after');
var w3 = iD.Way({ nodes: 'abbcbba'.split('')});
expect(w3.replaceNode('c','b').nodes.join('')).to.eql('aba', 'duplicate before and after');
});
it('eliminates duplicate consecutive nodes when replacing adjacent to connecting nodes along a circular way', function () {
var w1 = iD.Way({ nodes: 'abcda'.split('') });
expect(w1.replaceNode('d','a').nodes.join('')).to.eql('abca', 'before single end connector');
var w2 = iD.Way({ nodes: 'abcda'.split('') });
expect(w2.replaceNode('b','a').nodes.join('')).to.eql('acda', 'after single beginning connector');
var w3 = iD.Way({ nodes: 'abcdaa'.split('') });
expect(w3.replaceNode('d','a').nodes.join('')).to.eql('abca', 'before duplicate end connector');
var w4 = iD.Way({ nodes: 'aabcda'.split('') });
expect(w4.replaceNode('b','a').nodes.join('')).to.eql('acda', 'after duplicate beginning connector');
});
it('eliminates duplicate consecutive nodes when replacing connecting nodes along a circular way', function () {
var w1 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w1.replaceNode('a','d').nodes.join('')).to.eql('dbcd', 'duplicate end connector');
var w2 = iD.Way({ nodes: 'aabca'.split('') });
expect(w2.replaceNode('a','d').nodes.join('')).to.eql('dbcd', 'duplicate beginning connector');
var w3 = iD.Way({ nodes: 'aabcaa'.split('') });
expect(w3.replaceNode('a','d').nodes.join('')).to.eql('dbcd', 'duplicate beginning and end connectors');
var w4 = iD.Way({ nodes: 'aabaacaa'.split('') });
expect(w4.replaceNode('a','d').nodes.join('')).to.eql('dbdcd', 'duplicates multiple places');
});
});
describe('#removeNode', function () {
it('removes the node', function () {
var w = iD.Way({nodes: ['a']});
expect(w.removeNode('a').nodes).to.eql([]);
it('removes a node', function () {
var w1 = iD.Way({ nodes: 'a'.split('') });
expect(w1.removeNode('a').nodes.join('')).to.eql('', 'single remove, single node');
var w2 = iD.Way({ nodes: 'abc'.split('') });
expect(w2.removeNode('b').nodes.join('')).to.eql('ac', 'single remove, linear');
var w3 = iD.Way({ nodes: 'abca'.split('') });
expect(w3.removeNode('b').nodes.join('')).to.eql('aca', 'single remove, circular');
var w4 = iD.Way({ nodes: 'aa'.split('') });
expect(w4.removeNode('a').nodes.join('')).to.eql('', 'multiple remove, single node circular');
});
it('prevents duplicate consecutive nodes', function () {
var w = iD.Way({nodes: ['a', 'b', 'c', 'b']});
expect(w.removeNode('c').nodes).to.eql(['a', 'b']);
it('removes multiply occurring nodes', function () {
var w1 = iD.Way({ nodes: 'abcb'.split('') });
expect(w1.removeNode('b').nodes.join('')).to.eql('ac', 'multiple remove, linear');
var w2 = iD.Way({ nodes: 'abcba'.split('') });
expect(w2.removeNode('b').nodes.join('')).to.eql('aca', 'multiple remove, circular');
});
it('preserves circularity', function () {
var w = iD.Way({nodes: ['a', 'b', 'c', 'd', 'a']});
expect(w.removeNode('a').nodes).to.eql(['b', 'c', 'd', 'b']);
it('eliminates duplicate consecutive nodes when removing along a linear way', function () {
var w1 = iD.Way({ nodes: 'abbcd'.split('') });
expect(w1.removeNode('c').nodes.join('')).to.eql('abd', 'duplicate before');
var w2 = iD.Way({ nodes: 'abcdd'.split('') });
expect(w2.removeNode('c').nodes.join('')).to.eql('abd', 'duplicate after');
var w3 = iD.Way({ nodes: 'abbcbb'.split('')});
expect(w3.removeNode('c').nodes.join('')).to.eql('ab', 'duplicate before and after');
});
it('prevents duplicate consecutive nodes when preserving circularity', function () {
var w = iD.Way({nodes: ['a', 'b', 'c', 'd', 'b', 'a']});
expect(w.removeNode('a').nodes).to.eql(['b', 'c', 'd', 'b']);
it('eliminates duplicate consecutive nodes when removing internal nodes along a circular way', function () {
var w1 = iD.Way({ nodes: 'abbcda'.split('') });
expect(w1.removeNode('c').nodes.join('')).to.eql('abda', 'duplicate before');
var w2 = iD.Way({ nodes: 'abcdda'.split('') });
expect(w2.removeNode('c').nodes.join('')).to.eql('abda', 'duplicate after');
var w3 = iD.Way({ nodes: 'abbcbba'.split('')});
expect(w3.removeNode('c').nodes.join('')).to.eql('aba', 'duplicate before and after');
});
it('eliminates duplicate consecutive nodes when removing adjacent to connecting nodes along a circular way', function () {
var w1 = iD.Way({ nodes: 'abcdaa'.split('') });
expect(w1.removeNode('d').nodes.join('')).to.eql('abca', 'duplicate end connector');
var w2 = iD.Way({ nodes: 'aabcda'.split('') });
expect(w2.removeNode('b').nodes.join('')).to.eql('acda', 'duplicate beginning connector');
});
it('eliminates duplicate consecutive nodes when removing connecting nodes along a circular way', function () {
var w1 = iD.Way({ nodes: 'abcaa'.split('') });
expect(w1.removeNode('a').nodes.join('')).to.eql('bcb', 'duplicate end connector');
var w2 = iD.Way({ nodes: 'aabca'.split('') });
expect(w2.removeNode('a').nodes.join('')).to.eql('bcb', 'duplicate beginning connector');
var w3 = iD.Way({ nodes: 'aabcaa'.split('') });
expect(w3.removeNode('a').nodes.join('')).to.eql('bcb', 'duplicate beginning and end connectors');
var w4 = iD.Way({ nodes: 'aabaacaa'.split('') });
expect(w4.removeNode('a').nodes.join('')).to.eql('bcb', 'duplicates multiple places');
});
});
+1 -1
View File
@@ -3,7 +3,7 @@ describe('iD.serviceNominatim', function() {
beforeEach(function() {
server = sinon.fakeServer.create();
nominatim = iD.services.nominatim;
nominatim = iD.services.geocoder;
nominatim.reset();
});