resolved conflict.

This commit is contained in:
Saman Bemel-Benrud
2012-12-14 12:17:49 -05:00
24 changed files with 442 additions and 5657 deletions

View File

@@ -53,7 +53,8 @@
<script src='js/id/actions/change_entity_tags.js'></script>
<script src="js/id/actions/delete_node.js"></script>
<script src="js/id/actions/delete_way.js"></script>
<script src='js/id/actions/move.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/noop.js'></script>
<script src='js/id/actions/remove_relation_member.js'></script>
<script src='js/id/actions/remove_way_node.js'></script>

View File

@@ -1,8 +1,8 @@
// 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(entityId, loc) {
iD.actions.MoveNode = function(nodeId, loc) {
return function(graph) {
var entity = graph.entity(entityId);
return graph.replace(entity.update({loc: loc}));
var node = graph.entity(nodeId);
return graph.replace(node.update({loc: loc}));
};
};

14
js/id/actions/move_way.js Normal file
View File

@@ -0,0 +1,14 @@
iD.actions.MoveWay = function(wayId, dxdy, projection) {
return 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] + dxdy[0], start[1] + dxdy[1]]);
graph = iD.actions.MoveNode(id, end)(graph);
});
return graph;
};
};

View File

@@ -36,14 +36,36 @@ window.iD = function(container) {
.call(bootstrap.tooltip().placement('bottom'))
.on('click', function (mode) { controller.enter(mode); });
map.on('move.disable-buttons', function() {
function disableTooHigh() {
if (map.zoom() < 16) {
buttons.attr('disabled', 'disabled');
controller.enter(iD.modes.Browse());
} else {
buttons.attr('disabled', null);
}
});
}
var showUsers = _.debounce(function() {
var users = {},
entities = map.history().graph().entities;
for (var i in entities) {
users[entities[i].user] = true;
if (Object.keys(users).length > 10) break;
}
var u = Object.keys(users);
var l = d3.select('#user-list')
.selectAll('a.user-link').data(u);
l.enter().append('a')
.attr('class', 'user-link')
.attr('href', function(d) {
return 'http://api06.dev.openstreetmap.org/user/' + d;
})
.text(String);
l.exit().remove();
}, 1000);
map.on('move.disable-buttons', disableTooHigh)
.on('move.show-users', showUsers);
buttons.append('span')
.attr('class', function(d) {
@@ -143,12 +165,15 @@ window.iD = function(container) {
.attr('class', 'inspector-wrap fillL')
.style('display', 'none');
this.append('div')
var about = this.append('div')
.attr('id', 'about')
.html("<a href='http://github.com/systemed/iD'>code</a> " +
"<a href='http://github.com/systemed/iD/issues'>report a bug</a>" +
" <a href='http://opengeodata.org/microsoft-imagery-details'><img src='img/bing.png' /></a>");
about.append('div')
.attr('id', 'user-list');
history.on('change.buttons', function() {
var undo = history.undoAnnotation(),
redo = history.redoAnnotation();
@@ -166,7 +191,7 @@ window.iD = function(container) {
map.size(m.size());
};
var keybinding = d3.keybinding()
map.keybinding()
.on('a', function(evt, mods) {
controller.enter(iD.modes.AddArea());
})
@@ -180,8 +205,6 @@ window.iD = function(container) {
if (mods === '⇧⌘') history.redo();
if (mods === '⌘') history.undo();
});
d3.select(document).call(keybinding);
map.keybinding(keybinding);
var hash = iD.Hash().map(map);

View File

@@ -15,7 +15,7 @@ iD.modes.AddLine = function() {
map.dblclickEnable(false)
.hint('Click on the map to start drawing an road, path, or route.');
map.surface.on('click.addroad', function() {
map.surface.on('click.addline', function() {
var datum = d3.select(d3.event.target).datum() || {},
way = iD.Way({ tags: { highway: 'residential' } }),
direction = 'forward';
@@ -62,7 +62,7 @@ iD.modes.AddLine = function() {
controller.enter(iD.modes.DrawLine(way.id, direction));
});
map.keybinding().on('⎋.addroad', function() {
map.keybinding().on('⎋.addline', function() {
controller.exit();
});
};
@@ -70,8 +70,8 @@ iD.modes.AddLine = function() {
mode.exit = function() {
mode.map.dblclickEnable(true);
mode.map.hint(false);
mode.map.surface.on('click.addroad', null);
mode.map.keybinding().on('⎋.addroad', null);
mode.map.surface.on('click.addline', null);
mode.map.keybinding().on('⎋.addline', null);
};
return mode;

View File

@@ -4,6 +4,7 @@ iD.modes._dragFeatures = function(mode) {
var dragbehavior = d3.behavior.drag()
.origin(function(entity) {
var p = mode.map.projection(entity.loc);
d3.event.sourceEvent.stopPropagation();
return { x: p[0], y: p[1] };
})
.on('drag', function(entity) {
@@ -20,11 +21,11 @@ iD.modes._dragFeatures = function(mode) {
} else {
dragging = entity;
mode.history.perform(
iD.actions.Move(dragging.id, loc));
iD.actions.MoveNode(dragging.id, loc));
}
}
mode.history.replace(iD.actions.Move(dragging.id, loc));
mode.history.replace(iD.actions.MoveNode(dragging.id, loc));
})
.on('dragend', function (entity) {
if (!dragging) return;

View File

@@ -24,7 +24,7 @@ iD.modes.DrawArea = function(wayId) {
iD.actions.AddWayNode(way.id, node.id, -1));
function mousemove() {
history.replace(iD.actions.Move(node.id, map.mouseCoordinates()));
history.replace(iD.actions.MoveNode(node.id, map.mouseCoordinates()));
}
function click() {
@@ -95,24 +95,32 @@ iD.modes.DrawArea = function(wayId) {
controller.enter(iD.modes.Browse());
}
map.surface.on('mousemove.drawarea', mousemove);
map.surface.on('click.drawarea', click);
map.keybinding().on('.drawarea', esc)
map.surface
.on('mousemove.drawarea', mousemove)
.on('click.drawarea', click);
map.keybinding()
.on('⎋.drawarea', esc)
.on('⌫.drawarea', backspace)
.on('delete.drawarea', del)
.on('.drawarea', del)
.on('↩.drawarea', ret);
};
mode.exit = function() {
mode.map.hint(false);
mode.map.fastEnable(true);
mode.map
.hint(false)
.fastEnable(true);
mode.map.surface
.on('mousemove.drawarea', null)
.on('click.drawarea', null);
mode.map.keybinding().on('⎋.drawarea', null)
mode.map.keybinding()
.on('⎋.drawarea', null)
.on('⌫.drawarea', null)
.on('delete.drawarea', null)
.on('.drawarea', null)
.on('↩.drawarea', null);
window.setTimeout(function() {
mode.map.dblclickEnable(true);
}, 1000);

View File

@@ -24,11 +24,11 @@ iD.modes.DrawLine = function(wayId, direction) {
iD.actions.AddNode(node),
iD.actions.AddWayNode(wayId, node.id, index));
map.surface.on('mousemove.drawline', function() {
history.replace(iD.actions.Move(node.id, map.mouseCoordinates()));
});
function mousemove() {
history.replace(iD.actions.MoveNode(node.id, map.mouseCoordinates()));
}
map.surface.on('click.drawline', function() {
function click() {
var datum = d3.select(d3.event.target).datum() || {};
if (datum.id === tailId) {
@@ -72,7 +72,7 @@ iD.modes.DrawLine = function(wayId, direction) {
controller.enter(iD.modes.DrawLine(wayId, direction));
}
});
}
function esc() {
history.replace(
@@ -108,23 +108,32 @@ iD.modes.DrawLine = function(wayId, direction) {
controller.enter(iD.modes.Browse());
}
map.keybinding().on('⎋.drawline', esc)
map.surface
.on('mousemove.drawline', mousemove)
.on('click.drawline', click);
map.keybinding()
.on('⎋.drawline', esc)
.on('⌫.drawline', backspace)
.on('delete.drawline', del)
.on('.drawline', del)
.on('↩.drawline', ret);
};
mode.exit = function() {
mode.map.hint(false);
mode.map.fastEnable(true);
mode.map
.hint(false)
.fastEnable(true);
mode.map.surface
.on('mousemove.drawline', null)
.on('click.drawline', null);
mode.map.keybinding().on('⎋.drawline', null)
mode.map.keybinding()
.on('⎋.drawline', null)
.on('⌫.drawline', null)
.on('delete.drawline', null)
.on('.drawline', null)
.on('↩.drawline', null);
window.setTimeout(function() {
mode.map.dblclickEnable(true);
}, 1000);

View File

@@ -1,8 +1,11 @@
iD.modes.Select = function (entity) {
var mode = {
button: ''
},
inspector = iD.Inspector(),
id: 'select',
button: 'browse',
entity: entity
};
var inspector = iD.Inspector(),
dragging, target;
var dragWay = d3.behavior.drag()
@@ -11,48 +14,45 @@ iD.modes.Select = function (entity) {
return { x: p[0], y: p[1] };
})
.on('drag', function(entity) {
if (!mode.map.dragEnable()) return;
d3.event.sourceEvent.stopPropagation();
if (!dragging) {
dragging = iD.util.trueObj([entity.id].concat(
_.pluck(mode.history.graph().parentWays(entity.id), 'id')));
dragging = true;
mode.history.perform(iD.actions.Noop());
}
_.uniq(_.pluck(entity.nodes, 'id'))
.forEach(function(id) {
var node = mode.history.graph().entity(id),
start = mode.map.projection(node.loc),
end = mode.map.projection.invert([
start[0] + d3.event.dx,
start[1] + d3.event.dy]);
mode.history.replace(iD.actions.Move(id, end));
});
mode.history.replace(iD.actions.MoveWay(entity.id, [d3.event.dx, d3.event.dy], mode.map.projection));
})
.on('dragend', function () {
if (!mode.map.dragEnable() || !dragging) return;
if (!dragging) return;
dragging = undefined;
mode.map.redraw();
});
function remove() {
switch (entity.type) {
case 'way':
mode.history.perform(iD.actions.DeleteWay(entity.id));
break;
case 'node':
mode.history.perform(iD.actions.DeleteNode(entity.id));
if (entity.type === 'way') {
mode.history.perform(
iD.actions.DeleteWay(entity.id),
'deleted a way');
} else if (entity.type === 'node') {
var parents = mode.history.graph().parentWays(entity.id),
operations = [iD.actions.DeleteNode(entity.id)];
parents.forEach(function(parent) {
if (_.uniq(parent.nodes).length === 1) operations.push(iD.actions.DeleteWay(parent.id));
});
mode.history.perform.apply(mode.history,
operations.concat(['deleted a node']));
}
mode.controller.exit();
}
mode.enter = function () {
target = mode.map.surface.selectAll("*")
target = mode.map.surface.selectAll('*')
.filter(function (d) { return d === entity; });
iD.modes._dragFeatures(mode);
d3.select('.inspector-wrap')
.style('display', 'block')
.style('opacity', 1)
@@ -60,11 +60,23 @@ iD.modes.Select = function (entity) {
.call(inspector);
inspector.on('changeTags', function(d, tags) {
mode.history.perform(iD.actions.ChangeEntityTags(d.id, tags));
mode.history.perform(
iD.actions.ChangeEntityTags(d.id, tags),
'changed tags');
}).on('changeWayDirection', function(d) {
mode.history.perform(iD.actions.ReverseWay(d));
mode.history.perform(
iD.actions.ReverseWay(d.id),
'reversed a way');
}).on('splitWay', function(d) {
mode.history.perform(
iD.actions.SplitWay(d.id),
'split a way on a node');
}).on('remove', function() {
remove();
}).on('close', function() {
mode.controller.exit();
});
@@ -73,7 +85,7 @@ iD.modes.Select = function (entity) {
target.call(dragWay);
}
mode.map.surface.on("click.browse", function () {
mode.map.surface.on('click.browse', function () {
var datum = d3.select(d3.event.target).datum();
if (datum instanceof iD.Entity) {
mode.controller.enter(iD.modes.Select(datum));
@@ -100,6 +112,7 @@ iD.modes.Select = function (entity) {
}
mode.map.surface.on("click.browse", null);
mode.map.surface.on('mousedown.latedrag', null);
mode.map.keybinding().on('⌫.browse', null);
mode.map.selection(null);

View File

@@ -4,7 +4,7 @@ iD.Map = function() {
dispatch = d3.dispatch('move'),
selection = null, hover = null,
translateStart,
keybinding,
keybinding = d3.keybinding(),
projection = d3.geo.mercator().scale(1024),
zoom = d3.behavior.zoom()
.translate(projection.translate())
@@ -12,7 +12,6 @@ iD.Map = function() {
.scaleExtent([1024, 256 * Math.pow(2, 24)])
.on('zoom', zoomPan),
dblclickEnabled = true,
dragging = false,
fastEnabled = true,
notice,
background = iD.Background()
@@ -63,6 +62,8 @@ iD.Map = function() {
map.size(this.size());
map.surface = surface;
d3.select(document).call(keybinding);
}
function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }

View File

@@ -48,103 +48,109 @@ iD.Inspector = function() {
var inspectorwrap = selection
.append('ul').attr('class', 'inspector-inner tag-wrap fillL2');
inspectorwrap.append('h4').text('Edit tags')
inspectorwrap.append('h4').text('Edit tags');
inspectorwrap
.data(['tag', 'value', ''])
.enter();
function removeTag(d) {
var tags = pad(grabtags());
delete tags[d.key];
draw(tags);
draw(grabtags().filter(function(t) { return t.key !== d.key; }));
}
function draw(data) {
var tr = inspectorwrap.selectAll('li')
.data(d3.entries(data), function(d) { return [d.key, d.value]; });
tr.exit().remove();
var row = tr.enter().append('li').attr('class','tag-row');
var inputs = row.append('div').attr('class','input-wrap').selectAll('input')
.data(function(d) { return [d, d]; });
inputs.enter().append('input')
var li = inspectorwrap.selectAll('li')
.data(data, function(d) { return [d.key, d.value]; });
li.exit().remove();
var row = li.enter().append('li').attr('class','tag-row');
var inputs = row.append('div').attr('class','input-wrap');
function setValue(d, i) { d.value = this.value; }
function emptyTag(d) { return d.key === ''; }
function pushMore(d, i) {
if (d3.event.keyCode === 9) {
var tags = grabtags();
if (i == tags.length - 1 && !tags.filter(emptyTag).length) {
draw(tags.concat([{ key: '', value: '' }]));
}
}
}
function bindTypeahead(d, i) {
var selection = d3.select(this);
selection.call(d3.typeahead()
.data(function(selection, callback) {
taginfo.values(selection.datum().key, function(err, data) {
callback(data.data);
});
}));
}
inputs.append('input')
.property('type', 'text')
.attr('class', function(d, i) {
return i ? 'value' : 'key';
})
.property('value', function(d, i) { return d[i ? 'value' : 'key']; })
.on('keyup.update', function(d, i) {
d[i ? 'value' : 'key'] = this.value;
update();
})
.each(function(d, i) {
if (!i) return;
var selection = d3.select(this);
selection.call(d3.typeahead()
.data(function(selection, callback) {
update();
taginfo.values(selection.datum().key, function(err, data) {
callback(data.data);
});
}));
});
row.append('button')
.html("<span class='icon remove'></span>")
.attr('class', 'key')
.property('value', function(d, i) { return d.key; })
.on('keyup.update', setValue);
inputs.append('input')
.property('type', 'text')
.attr('class', 'value')
.property('value', function(d, i) { return d.value; })
.on('keyup.update', setValue)
.on('keydown.push-more', pushMore)
.each(bindTypeahead);
removeBtn = row.append('button')
.attr('class','remove minor')
.on('click', removeTag);
row.append('button').attr('class', 'tag-help minor').append('a')
.html("<span class='icon inspect'></span>")
removeBtn.append('span').attr('class', 'icon remove')
helpBtn = row.append('button').attr('class', 'tag-help minor').append('a')
.attr('target', '_blank')
.attr('tabindex', -1)
.attr('href', function(d) {
return 'http://taginfo.openstreetmap.org/keys/' + d.key;
});
}
// Remove any blank key-values
function clean(x) {
for (var i in x) {
// undefined is cast to a string as an object key
if (!i || i === 'undefined') delete x[i];
}
return x;
}
// Add a blank row for new tags
function pad(x) {
if (!x['']) x[''] = '';
return x;
helpBtn.append('span').attr('class', 'icon inspect')
}
function grabtags() {
var grabbed = {};
function grab(d) { if (d.key !== undefined) grabbed[d.key] = d.value; }
inspectorwrap.selectAll('input').each(grab);
var grabbed = [];
function grab(d) { grabbed.push(d); }
inspectorwrap.selectAll('li').each(grab);
return grabbed;
}
// fill values and add blank field if necessary
function update() {
draw(pad(grabtags()));
function unentries(entries) {
return d3.nest()
.key(function(d) { return d.key; })
.rollup(function(v) { return v[0].value; })
.map(entries);
}
var data = _.clone(entity.tags);
draw(data);
update();
draw(d3.entries(_.clone(entity.tags)));
selection.select('input').node().focus();
selection.append('div')
.attr('class', 'inspector-buttons').call(drawbuttons);
function apply(entity) {
event.changeTags(entity, unentries(grabtags()));
event.close(entity);
}
function drawbuttons(selection) {
selection.append('button')
.attr('class', 'apply wide action')
.html("<span class='icon icon-pre-text apply'></span><span class='label'>Apply</span>")
.on('click', function(entity) {
event.changeTags(entity, clean(grabtags()));
event.close(entity);
});
.on('click', apply);
selection.append('button')
.attr('class', 'delete wide action fr')
.html("<span class='icon icon-pre-text delete'></span><span class='label'>Delete</span>")

View File

@@ -48,36 +48,36 @@ iD.layerswitcher = function(map) {
var opa = content
.append('div')
.attr('class', 'opacity-options-wrapper fillL2')
.attr('class', 'opacity-options-wrapper fillL2');
opa.append('h4').text('Layers')
opa.append('h4').text('Layers');
opa.append('ul')
.attr('class', 'opacity-options')
.selectAll('div.opacity')
.data(opacities)
.enter()
.append('li')
.attr('data-original-title', function(d) {
return (d * 100) + "% opacity";
})
.on('click.set-opacity', function(d) {
d3.select('#tile-g')
.transition()
.style('opacity', d)
.attr('data-opacity', d);
d3.selectAll('.opacity-options li')
.classed('selected', false);
d3.select(this)
.classed('selected', true);
})
.html("<div class='select-box'></div>")
.call(bootstrap.tooltip().placement('top'))
.append('div')
.attr('class', 'opacity')
.style('opacity', function(d) {
return d;
});
opa.append('ul')
.attr('class', 'opacity-options')
.selectAll('div.opacity')
.data(opacities)
.enter()
.append('li')
.attr('data-original-title', function(d) {
return (d * 100) + "% opacity";
})
.on('click.set-opacity', function(d) {
d3.select('#tile-g')
.transition()
.style('opacity', d)
.attr('data-opacity', d);
d3.selectAll('.opacity-options li')
.classed('selected', false);
d3.select(this)
.classed('selected', true);
})
.html("<div class='select-box'></div>")
.call(bootstrap.tooltip().placement('top'))
.append('div')
.attr('class', 'opacity')
.style('opacity', function(d) {
return d;
});
// Make sure there is an active selection by default
d3.select('.opacity-options li').classed('selected', true);

View File

@@ -39,8 +39,8 @@ d3.keybinding = function() {
'⇞': 36, home: 36,
// Insert key, or ins
ins: 45, insert: 45,
// Delete key, on Mac: (Delete)
del: 46, 'delete': 46,
// Delete key, on Mac: (Delete)
'⌦': 46, del: 46, 'delete': 46,
// Left Arrow Key, or ←
'←': 37, left: 37, 'arrow-left': 37,
// Up Arrow Key, or ↑
@@ -93,42 +93,27 @@ d3.keybinding = function() {
while(++i < 91) _keys.keys[String.fromCharCode(i).toLowerCase()] = i;
var pairs = d3.entries(_keys.keys),
key_shortcuts = pairs.map(function(d) {
return d.key;
}),
mods = d3.entries(_keys.mods),
mod_shortcuts = mods.map(function(d) {
return d.key;
}),
event = d3.dispatch.apply(d3, key_shortcuts),
modifiers = [];
function keydown() {
var tagName = d3.select(d3.event.target).node().tagName;
if (tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA') {
return;
}
modifiers = modifiers.concat(mods.filter(function(d) {
return d.value === d3.event.keyCode;
}).map(function(d) { return d.key; }));
pairs.filter(function(d) {
return d.value === d3.event.keyCode;
}).forEach(function(d) {
event[d.key](d3.event, modifiers.slice().sort().join(''));
});
}
function keyup() {
modifiers = [];
}
event = d3.dispatch.apply(d3, d3.keys(_keys.keys));
function keys(selection) {
d3.select(window).on('focus', keyup);
selection
.on('keyup', keyup)
.on('keydown', keydown);
selection.on('keydown', function () {
var tagName = d3.select(d3.event.target).node().tagName;
if (tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA') {
return;
}
var modifiers = '';
if (d3.event.shiftKey) modifiers += '⇧';
if (d3.event.ctrlKey) modifiers += '⌃';
if (d3.event.altKey) modifiers += '⌥';
if (d3.event.metaKey) modifiers += '⌘';
pairs.filter(function(d) {
return d.value === d3.event.keyCode;
}).forEach(function(d) {
event[d.key](d3.event, modifiers);
});
});
}
return d3.rebind(keys, event, 'on');

26
package.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "iD",
"version": "0.0.0",
"description": "a new editor for openstreetmap",
"main": "iD.js",
"directories": {
"doc": "docs",
"test": "test"
},
"scripts": {
"test": "mocha-phantomjs test/index.html"
},
"repository": {
"type": "git",
"url": "git://github.com/systemed/iD.git"
},
"keywords": [
"editor",
"openstreetmap"
],
"license": "BSD",
"devDependencies": {
"uglify-js": "~2.2.2",
"mocha-phantomjs": "~1.1.1"
}
}

File diff suppressed because it is too large Load Diff

13
test/data/node.xml Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="OpenStreetMap server" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
<node id="356552551" version="1" changeset="747176" lat="44.6636172" lon="-73.0132525" user="iandees" uid="4732" visible="true" timestamp="2009-03-07T03:26:33Z">
<tag k="ele" v="114"/>
<tag k="gnis:edited" v="05/27/2008"/>
<tag k="gnis:state_id" v="50"/>
<tag k="gnis:feature_id" v="1456383"/>
<tag k="amenity" v="school"/>
<tag k="name" v="Bellows Free Academy"/>
<tag k="gnis:county_id" v="011"/>
<tag k="gnis:created" v="10/29/1980"/>
</node>
</osm>

58
test/data/way.xml Normal file
View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="OpenStreetMap server" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
<node id="204595896" version="2" changeset="2817006" lat="44.665883" lon="-72.923053" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595901" version="2" changeset="2817006" lat="44.66597" lon="-72.922201" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595904" version="2" changeset="2817006" lat="44.665989" lon="-72.921986" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595911" version="2" changeset="3138486" lat="44.666015" lon="-72.921474" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-11-17T05:45:06Z"/>
<node id="204595915" version="2" changeset="2817006" lat="44.666015" lon="-72.921254" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595919" version="2" changeset="2817006" lat="44.666007" lon="-72.921033" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204587613" version="2" changeset="2817006" lat="44.665983" lon="-72.920587" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:01:27Z"/>
<node id="204595923" version="2" changeset="2817006" lat="44.665938" lon="-72.920089" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595927" version="2" changeset="2817006" lat="44.665901" lon="-72.919727" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595932" version="2" changeset="3138486" lat="44.665837" lon="-72.919284" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-11-17T05:45:06Z"/>
<node id="204595935" version="2" changeset="2817006" lat="44.665821" lon="-72.91914" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595939" version="2" changeset="2817006" lat="44.66581" lon="-72.918999" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595943" version="2" changeset="2817006" lat="44.665814" lon="-72.918855" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595947" version="2" changeset="3346870" lat="44.665823" lon="-72.918783" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-12-11T06:32:30Z"/>
<node id="204595950" version="2" changeset="2817006" lat="44.665839" lon="-72.91871" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595953" version="2" changeset="2817006" lat="44.66587" lon="-72.918641" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595955" version="2" changeset="2817006" lat="44.665923" lon="-72.918586" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595957" version="2" changeset="2817006" lat="44.665985" lon="-72.918559" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<node id="204595961" version="2" changeset="3138486" lat="44.666193" lon="-72.918523" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-11-17T05:45:06Z"/>
<node id="204595963" version="2" changeset="2817006" lat="44.666342" lon="-72.918513" user="woodpeck_fixbot" uid="147510" visible="true" timestamp="2009-10-11T18:03:23Z"/>
<way id="19698713" visible="true" timestamp="2008-01-03T05:24:43Z" version="1" changeset="522559" user="DaveHansenTiger" uid="7168">
<nd ref="204595896"/>
<nd ref="204595901"/>
<nd ref="204595904"/>
<nd ref="204595911"/>
<nd ref="204595915"/>
<nd ref="204595919"/>
<nd ref="204587613"/>
<nd ref="204595923"/>
<nd ref="204595927"/>
<nd ref="204595932"/>
<nd ref="204595935"/>
<nd ref="204595939"/>
<nd ref="204595943"/>
<nd ref="204595947"/>
<nd ref="204595950"/>
<nd ref="204595953"/>
<nd ref="204595955"/>
<nd ref="204595957"/>
<nd ref="204595961"/>
<nd ref="204595963"/>
<tag k="highway" v="residential"/>
<tag k="name" v="Oustinoff Rd"/>
<tag k="tiger:cfcc" v="A41"/>
<tag k="tiger:county" v="Franklin, VT"/>
<tag k="tiger:name_base" v="Oustinoff"/>
<tag k="tiger:name_type" v="Rd"/>
<tag k="tiger:reviewed" v="no"/>
<tag k="tiger:separated" v="no"/>
<tag k="tiger:source" v="tiger_import_dch_v0.6_20070830"/>
<tag k="tiger:tlid" v="136533324:136533325"/>
<tag k="tiger:upload_uuid" v="bulk_upload.pl-62def9fe-abee-42f3-ac1f-9d9f4b4ee78b"/>
<tag k="tiger:zip_left" v="05444"/>
<tag k="tiger:zip_right" v="05444"/>
</way>
</osm>

View File

@@ -20,6 +20,8 @@
<script src='../js/lib/d3.v3.js'></script>
<script src='../js/lib/sha.js'></script>
<script src='../js/lib/d3.geo.tile.js'></script>
<script src='../js/lib/d3.keybinding.js'></script>
<script src='../js/lib/d3.latedrag.js'></script>
<script src='../js/lib/d3.size.js'></script>
<script src='../js/lib/d3.typeahead.js'></script>
<script src='../js/lib/d3.one.js'></script>
@@ -52,7 +54,8 @@
<script src='../js/id/actions/change_entity_tags.js'></script>
<script src="../js/id/actions/delete_node.js"></script>
<script src="../js/id/actions/delete_way.js"></script>
<script src='../js/id/actions/move.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/noop.js'></script>
<script src='../js/id/actions/remove_relation_member.js'></script>
<script src='../js/id/actions/remove_way_node.js'></script>
@@ -63,6 +66,7 @@
<script src='../js/id/modes/add_place.js'></script>
<script src='../js/id/modes/add_line.js'></script>
<script src='../js/id/modes/browse.js'></script>
<script src='../js/id/modes/drag_features.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/select.js'></script>
@@ -91,7 +95,8 @@
<script src="spec/actions/change_entity_tags.js"></script>
<script src="spec/actions/delete_node.js"></script>
<script src="spec/actions/delete_way.js"></script>
<script src="spec/actions/move.js"></script>
<script src="spec/actions/move_node.js"></script>
<script src="spec/actions/move_way.js"></script>
<script src="spec/actions/noop.js"></script>
<script src="spec/actions/remove_way_node.js"></script>
<script src="spec/actions/remove_relation_member.js"></script>
@@ -99,14 +104,19 @@
<script src="spec/format/geojson.js"></script>
<script src="spec/format/xml.js"></script>
<script src="spec/graph/graph.js"></script>
<script src="spec/graph/entity.js"></script>
<script src="spec/graph/history.js"></script>
<script src="spec/graph/way.js"></script>
<script src="spec/modes/add_place.js"></script>
<script src="spec/renderer/background.js"></script>
<script src="spec/renderer/hash.js"></script>
<script src="spec/renderer/map.js"></script>
<script src="spec/renderer/style.js"></script>
<script src="spec/ui/inspector.js"></script>
<script src="spec/ui/geocoder.js"></script>
<script src="spec/connection.js"></script>

View File

@@ -31,7 +31,8 @@
<script src="spec/actions/change_entity_tags.js"></script>
<script src="spec/actions/delete_node.js"></script>
<script src="spec/actions/delete_way.js"></script>
<script src="spec/actions/move.js"></script>
<script src="spec/actions/move_node.js"></script>
<script src="spec/actions/move_way.js"></script>
<script src="spec/actions/noop.js"></script>
<script src="spec/actions/remove_way_node.js"></script>
<script src="spec/actions/remove_relation_member.js"></script>
@@ -39,14 +40,19 @@
<script src="spec/format/geojson.js"></script>
<script src="spec/format/xml.js"></script>
<script src="spec/graph/graph.js"></script>
<script src="spec/graph/entity.js"></script>
<script src="spec/graph/history.js"></script>
<script src="spec/graph/way.js"></script>
<script src="spec/modes/add_place.js"></script>
<script src="spec/renderer/background.js"></script>
<script src="spec/renderer/hash.js"></script>
<script src="spec/renderer/map.js"></script>
<script src="spec/renderer/style.js"></script>
<script src="spec/ui/inspector.js"></script>
<script src="spec/connection.js"></script>
<script src="spec/oauth.js"></script>

View File

@@ -1,8 +0,0 @@
describe("iD.actions.Move", function () {
it("changes an entity's location", function () {
var entity = iD.Entity(),
loc = [2, 3],
graph = iD.actions.Move(entity.id, loc)(iD.Graph([entity]));
expect(graph.entity(entity.id).loc).to.eql(loc);
});
});

View File

@@ -0,0 +1,8 @@
describe("iD.actions.MoveNode", function () {
it("changes a node's location", function () {
var node = iD.Node(),
loc = [2, 3],
graph = iD.actions.MoveNode(node.id, loc)(iD.Graph([node]));
expect(graph.entity(node.id).loc).to.eql(loc);
});
});

View File

@@ -0,0 +1,21 @@
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]}),
dxdy = [2, 3],
projection = d3.geo.mercator(),
graph = iD.actions.MoveWay(way.id, dxdy, projection)(iD.Graph([node1, node2, way]));
expect(graph.entity(node1.id).loc).to.eql([1.4400000000000002, -2.1594885414215783]);
expect(graph.entity(node2.id).loc).to.eql([6.440000000000008, 7.866329874099955]);
});
it("moves repeated nodes only once", function () {
var node = iD.Node({loc: [0, 0]}),
way = iD.Way({nodes: [node.id, node.id]}),
dxdy = [2, 3],
projection = d3.geo.mercator(),
graph = iD.actions.MoveWay(way.id, dxdy, projection)(iD.Graph([node, way]));
expect(graph.entity(node.id).loc).to.eql([1.4400000000000002, -2.1594885414215783]);
});
});

View File

@@ -24,11 +24,11 @@ describe('Connection', function() {
describe('#loadFromURL', function() {
it('loads test data', function(done) {
c.loadFromURL('data/map.xml', done);
c.loadFromURL('data/node.xml', done);
});
it('returns a graph', function(done) {
c.loadFromURL('data/map.xml', function(err, graph) {
c.loadFromURL('data/node.xml', function(err, graph) {
expect(err).to.not.be.ok;
expect(graph).to.be.instanceOf(iD.Graph);
done();
@@ -36,15 +36,15 @@ describe('Connection', function() {
});
it('parses a node', function(done) {
c.loadFromURL('data/map.xml', function(err, graph) {
expect(graph.entity('n1193811')).to.be.instanceOf(iD.Entity);
c.loadFromURL('data/node.xml', function(err, graph) {
expect(graph.entity('n356552551')).to.be.instanceOf(iD.Entity);
done();
});
});
it('parses a way', function(done) {
c.loadFromURL('data/map.xml', function(err, graph) {
expect(graph.entity('w53471')).to.be.instanceOf(iD.Entity);
c.loadFromURL('data/way.xml', function(err, graph) {
expect(graph.entity('w19698713')).to.be.instanceOf(iD.Entity);
done();
});
});

View File

@@ -0,0 +1,39 @@
describe("iD.modes.AddPlace", function () {
var container, map, history, controller, mode;
beforeEach(function () {
container = d3.select('body').append('div');
map = iD.Map();
history = iD.History();
controller = iD.Controller(map, history);
container.call(map);
mode = iD.modes.AddPlace();
controller.enter(mode);
});
afterEach(function() {
container.remove();
});
describe("clicking the map", function () {
it("adds a node", function () {
happen.click(map.surface.node(), {});
expect(history.changes().created).to.have.length(1);
});
it("selects the node", function () {
happen.click(map.surface.node(), {});
expect(controller.mode.id).to.equal('select');
expect(controller.mode.entity).to.equal(history.changes().created[0]);
});
});
describe("pressing ⎋", function () {
it("exits to browse mode", function () {
happen.keydown(document, {keyCode: 27});
expect(controller.mode.id).to.equal('browse');
});
});
});