Merge branch 'master' of github.com:systemed/iD

This commit is contained in:
Saman Bemel-Benrud
2013-01-28 21:06:17 -05:00
20 changed files with 179 additions and 64 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
[![Build Status](https://secure.travis-ci.org/systemed/iD.png)](https://travis-ci.org/systemed/iD)
[![](https://raw.github.com/systemed/iD/master/screenshot.jpg)](http://geowiki.com/iD/)
[![](http://ideditor.com/img/editor.png)](http://geowiki.com/iD/)
[Try the online demo of the most recent code.](http://geowiki.com/iD/) and
[open issues for bugs and ideas!](https://github.com/systemed/iD/issues)
+33 -11
View File
@@ -256,6 +256,9 @@ button {
height:40px;
cursor:url(../img/cursor-pointer.png) 6 1, auto;
border-radius:4px;
-webkit-transition: background 100ms;
-moz-transition: background 100ms;
transition: background 100ms;
}
button:hover {
@@ -1023,6 +1026,14 @@ div.typeahead a:first-child {
text-align: center;
}
/* Success
------------------------------------------------------- */
a.success-action {
display:inline-block;
padding:10px;
margin:10px;
}
/* Notices
------------------------------------------------------- */
@@ -1085,17 +1096,17 @@ div.typeahead a:first-child {
}
.tooltip-inner {
text-align: left;
width: 200px;
font-size: 11px;
font-weight: bold;
line-height: 20px;
padding: 5px 10px;
color: #333;
background-color: white;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
text-align: left;
width: 200px;
font-size: 11px;
font-weight: bold;
line-height: 20px;
padding: 5px 10px;
color: #333;
background-color: white;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.tooltip-arrow {
@@ -1142,6 +1153,17 @@ div.typeahead a:first-child {
left: 30px;
}
.tooltip .keyhint {
float: right;
background: #eee;
font-size: 10px;
padding: 0 4px;
background:#aaa;
color:#fff;
border-radius: 2px;
margin-left: 4px;
}
.tail {
pointer-events:none;
position: absolute;
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 B

After

Width:  |  Height:  |  Size: 1.4 KiB

+29 -4
View File
@@ -23,7 +23,9 @@ iD.behavior.drag = function () {
var event = d3.dispatch("start", "move", "end"),
origin = null,
selector = '',
filter = null;
filter = null,
keybinding = d3.keybinding('drag'),
event_, target;
event.of = function(thiz, argumentz) {
return function(e1) {
@@ -39,9 +41,9 @@ iD.behavior.drag = function () {
};
function mousedown() {
var target = this,
event_ = event.of(target, arguments),
eventTarget = d3.event.target,
target = this,
event_ = event.of(target, arguments);
var eventTarget = d3.event.target,
touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
offset,
origin_ = point(),
@@ -135,6 +137,9 @@ iD.behavior.drag = function () {
drag.off = function(selection) {
selection.on("mousedown.drag" + selector, null)
.on("touchstart.drag" + selector, null);
keybinding
.on('⌘+Z', null)
.on('⌃+Z', null);
};
drag.delegate = function(_) {
@@ -155,5 +160,25 @@ iD.behavior.drag = function () {
return drag;
};
drag.cancel = function() {
d3.select(window)
.on("mousemove.drag", null)
.on("mouseup.drag", null);
return drag;
};
drag.target = function() {
if (!arguments.length) return target;
target = arguments[0];
event_ = event.of(target, Array.prototype.slice.call(arguments, 1));
return drag;
};
keybinding
.on('⌘+Z', drag.cancel)
.on('⌃+Z', drag.cancel);
d3.select(document).call(keybinding);
return d3.rebind(drag, event, "on");
};
+8 -4
View File
@@ -1,8 +1,7 @@
iD.behavior.DragMidpoint = function(mode) {
var history = mode.history,
projection = mode.map.projection;
return iD.behavior.drag()
projection = mode.map.projection,
behavior = iD.behavior.drag()
.delegate(".midpoint")
.origin(function(d) {
return projection(d.loc);
@@ -21,15 +20,20 @@ iD.behavior.DragMidpoint = function(mode) {
}
}
history.perform.apply(history, args);
var node = d3.selectAll('.node.vertex')
.filter(function(data) { return data.id === d.node.id; });
behavior.target(node.node(), node.datum());
})
.on('move', function(d) {
d3.event.sourceEvent.stopPropagation();
history.replace(
iD.actions.MoveNode(d.node.id, projection.invert(d3.event.point)));
iD.actions.MoveNode(d.id, projection.invert(d3.event.point)));
})
.on('end', function() {
history.replace(
iD.actions.Noop(),
'added a node to a way');
});
return behavior;
};
+2 -1
View File
@@ -14,7 +14,8 @@ iD.behavior.DragNode = function(mode) {
.on('move', function(entity) {
d3.event.sourceEvent.stopPropagation();
history.replace(
iD.actions.MoveNode(entity.id, projection.invert(d3.event.point)));
iD.actions.MoveNode(entity.id, projection.invert(d3.event.point)),
'moved a node');
})
.on('end', function() {
history.replace(
+2 -1
View File
@@ -17,7 +17,8 @@ iD.behavior.DragWay = function(mode) {
.on('move', function(entity) {
d3.event.sourceEvent.stopPropagation();
history.replace(
iD.actions.MoveWay(entity.id, d3.event.delta, projection));
iD.actions.MoveWay(entity.id, d3.event.delta, projection),
'moved a way');
})
.on('end', function() {
history.replace(
+14 -2
View File
@@ -1,9 +1,10 @@
iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode, baseGraph) {
var map = mode.map,
history = mode.history,
controller = mode.controller,
event = d3.dispatch('add', 'addHead', 'addTail', 'addNode', 'addWay'),
way = mode.history.graph().entity(wayId),
finished = false,
hover, draw;
var node = iD.Node({loc: map.mouseCoordinates()}),
@@ -56,6 +57,9 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
};
drawWay.off = function(surface) {
if (!finished)
history.pop();
map.fastEnable(true)
.minzoom(0)
.tail(false);
@@ -86,6 +90,7 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
ReplaceTemporaryNode(node),
annotation);
finished = true;
controller.enter(mode);
};
@@ -99,6 +104,7 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
ReplaceTemporaryNode(newNode),
annotation);
finished = true;
controller.enter(mode);
};
@@ -111,6 +117,7 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
ReplaceTemporaryNode(newNode),
annotation);
finished = true;
controller.enter(mode);
};
@@ -118,6 +125,7 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
// nodes to be valid, it's selected. Otherwise, return to browse mode.
drawWay.finish = function() {
history.pop();
finished = true;
var way = history.graph().entity(wayId);
if (way) {
@@ -129,7 +137,11 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
// Cancel the draw operation and return to browse, deleting everything drawn.
drawWay.cancel = function() {
history.perform(iD.actions.DeleteWay(wayId), 'cancelled drawing');
history.perform(
d3.functor(baseGraph),
'cancelled drawing');
finished = true;
controller.enter(iD.modes.Browse());
};
+5
View File
@@ -10,6 +10,10 @@ iD.Connection = function() {
loadedTiles = {},
oauth = iD.OAuth().url(url);
function changesetUrl(changesetId) {
return url + '/browse/changeset/' + changesetId;
}
function bboxUrl(b) {
return url + '/api/0.6/map?bbox=' + [b[0][0],b[1][1],b[1][0],b[0][1]];
}
@@ -325,6 +329,7 @@ iD.Connection = function() {
};
connection.bboxFromAPI = bboxFromAPI;
connection.changesetUrl = changesetUrl;
connection.loadFromURL = loadFromURL;
connection.loadTiles = _.debounce(loadTiles, 100);
connection.userDetails = userDetails;
+15 -9
View File
@@ -21,6 +21,10 @@ window.iD = function(container) {
return;
}
function hintprefix(x, y) {
return '<span class="keyhint">' + x + '</span> ' + y;
}
var m = container.append('div')
.attr('id', 'map')
.call(map);
@@ -40,8 +44,10 @@ window.iD = function(container) {
.enter().append('button')
.attr('tabindex', -1)
.attr('class', function (mode) { return mode.title + ' add-button col3'; })
.attr('data-original-title', function (mode) { return mode.description; })
.call(bootstrap.tooltip().placement('bottom'))
.attr('data-original-title', function (mode) {
return hintprefix(mode.key, mode.description);
})
.call(bootstrap.tooltip().placement('bottom').html(true))
.on('click.editor', function (mode) { controller.enter(mode); });
function disableTooHigh() {
@@ -82,7 +88,7 @@ window.iD = function(container) {
var undo_buttons = limiter.append('div')
.attr('class', 'button-wrap joined col1'),
undo_tooltip = bootstrap.tooltip().placement('bottom');
undo_tooltip = bootstrap.tooltip().placement('bottom').html(true);
undo_buttons.append('button')
.attr({ id: 'undo', 'class': 'col6' })
@@ -201,12 +207,12 @@ window.iD = function(container) {
limiter.select('#undo')
.property('disabled', !undo)
.attr('data-original-title', undo)
.attr('data-original-title', hintprefix('⌘Z', undo))
.call(refreshTooltip);
limiter.select('#redo')
.property('disabled', !redo)
.attr('data-original-title', redo)
.attr('data-original-title', hintprefix('⌘⇧Z', redo))
.call(refreshTooltip);
});
@@ -215,16 +221,16 @@ window.iD = function(container) {
});
var keybinding = d3.keybinding('main')
.on('M', function() { if (map.editable()) controller.enter(iD.modes.Browse()); })
.on('P', function() { if (map.editable()) controller.enter(iD.modes.AddPoint()); })
.on('L', function() { if (map.editable()) controller.enter(iD.modes.AddLine()); })
.on('A', function() { if (map.editable()) controller.enter(iD.modes.AddArea()); })
.on('⌘+Z', function() { history.undo(); })
.on('⌃+Z', function() { history.undo(); })
.on('⌘+⇧+Z', function() { history.redo(); })
.on('⌃+⇧+Z', function() { history.redo(); })
.on('⌫', function() { d3.event.preventDefault(); });
[iD.modes.Browse(), iD.modes.AddPoint(), iD.modes.AddLine(), iD.modes.AddArea()].forEach(function(m) {
keybinding.on(m.key, function() { if (map.editable()) controller.enter(m); });
});
d3.select(document)
.call(keybinding);
+11 -7
View File
@@ -3,7 +3,8 @@ iD.modes.AddArea = function() {
id: 'add-area',
button: 'area',
title: 'Area',
description: 'Add parks, buildings, lakes, or other areas to the map.'
description: 'Add parks, buildings, lakes, or other areas to the map.',
key: 'a'
};
var behavior,
@@ -15,18 +16,20 @@ iD.modes.AddArea = function() {
controller = mode.controller;
function startFromNode(node) {
var way = iD.Way({tags: defaultTags});
var graph = history.graph(),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawArea(way.id));
controller.enter(iD.modes.DrawArea(way.id, graph));
}
function startFromWay(other, loc, index) {
var node = iD.Node({loc: loc}),
var graph = history.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
@@ -36,11 +39,12 @@ iD.modes.AddArea = function() {
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(other.id, node.id, index));
controller.enter(iD.modes.DrawArea(way.id));
controller.enter(iD.modes.DrawArea(way.id, graph));
}
function start(loc) {
var node = iD.Node({loc: loc}),
var graph = history.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
@@ -49,7 +53,7 @@ iD.modes.AddArea = function() {
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawArea(way.id));
controller.enter(iD.modes.DrawArea(way.id, graph));
}
behavior = iD.behavior.AddWay(mode)
+11 -8
View File
@@ -3,7 +3,8 @@ iD.modes.AddLine = function() {
id: 'add-line',
button: 'line',
title: 'Line',
description: 'Lines can be highways, streets, pedestrian paths, or even canals.'
description: 'Lines can be highways, streets, pedestrian paths, or even canals.',
key: 'l'
};
var behavior,
@@ -20,10 +21,10 @@ iD.modes.AddLine = function() {
isLine = parent && parent.geometry(graph) === 'line';
if (isLine && parent.first() === node.id) {
controller.enter(iD.modes.DrawLine(parent.id, 'backward'));
controller.enter(iD.modes.DrawLine(parent.id, 'backward', graph));
} else if (isLine && parent.last() === node.id) {
controller.enter(iD.modes.DrawLine(parent.id, 'forward'));
controller.enter(iD.modes.DrawLine(parent.id, 'forward', graph));
} else {
var way = iD.Way({tags: defaultTags});
@@ -32,12 +33,13 @@ iD.modes.AddLine = function() {
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawLine(way.id, 'forward'));
controller.enter(iD.modes.DrawLine(way.id, 'forward', graph));
}
}
function startFromWay(other, loc, index) {
var node = iD.Node({loc: loc}),
var graph = history.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
@@ -46,11 +48,12 @@ iD.modes.AddLine = function() {
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(other.id, node.id, index));
controller.enter(iD.modes.DrawLine(way.id, 'forward'));
controller.enter(iD.modes.DrawLine(way.id, 'forward', graph));
}
function start(loc) {
var node = iD.Node({loc: loc}),
var graph = history.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
@@ -58,7 +61,7 @@ iD.modes.AddLine = function() {
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawLine(way.id, 'forward'));
controller.enter(iD.modes.DrawLine(way.id, 'forward', graph));
}
behavior = iD.behavior.AddWay(mode)
+2 -1
View File
@@ -2,7 +2,8 @@ iD.modes.AddPoint = function() {
var mode = {
id: 'add-point',
title: 'Point',
description: 'Restaurants, monuments, and postal boxes are points.'
description: 'Restaurants, monuments, and postal boxes are points.',
key: 'p'
};
var behavior;
+3 -2
View File
@@ -2,8 +2,9 @@ iD.modes.Browse = function() {
var mode = {
button: 'browse',
id: 'browse',
title: 'Move',
description: 'Pan and zoom the map'
title: 'Browse',
description: 'Pan and zoom the map',
key: 'b'
};
var behaviors;
+2 -2
View File
@@ -1,4 +1,4 @@
iD.modes.DrawArea = function(wayId) {
iD.modes.DrawArea = function(wayId, baseGraph) {
var mode = {
button: 'area',
id: 'draw-area'
@@ -29,7 +29,7 @@ iD.modes.DrawArea = function(wayId) {
behavior.add(loc, annotation);
}
behavior = iD.behavior.DrawWay(wayId, headId, tailId, index, mode)
behavior = iD.behavior.DrawWay(wayId, headId, tailId, index, mode, baseGraph)
.on('addHead', addHeadTail)
.on('addTail', addHeadTail)
.on('addNode', addNode)
+2 -2
View File
@@ -1,4 +1,4 @@
iD.modes.DrawLine = function(wayId, direction) {
iD.modes.DrawLine = function(wayId, direction, baseGraph) {
var mode = {
button: 'line',
id: 'draw-line'
@@ -38,7 +38,7 @@ iD.modes.DrawLine = function(wayId, direction) {
behavior.add(loc, annotation);
}
behavior = iD.behavior.DrawWay(wayId, headId, tailId, index, mode)
behavior = iD.behavior.DrawWay(wayId, headId, tailId, index, mode, baseGraph)
.on('addHead', addHead)
.on('addTail', addTail)
.on('addNode', addNode)
+11 -2
View File
@@ -165,24 +165,33 @@ iD.Map = function() {
}
function resetTransform() {
if (!surface.style(transformProp)) return;
if (!surface.style(transformProp)) return false;
surface.style(transformProp, '');
tilegroup.style(transformProp, '');
return true;
}
function redraw(difference) {
resetTransform();
// If we are in the middle of a zoom/pan, we can't do differenced redraws.
// It would result in artifacts where differenced entities are redrawn with
// one transform and unchanged entities with another.
if (resetTransform())
difference = undefined;
surface.attr('data-zoom', ~~map.zoom());
tilegroup.call(background);
if (map.editable()) {
connection.loadTiles(projection, dimensions);
drawVector(difference);
} else {
editOff();
}
transformStart = [
projection.scale(),
projection.translate().slice()];
return map;
}
+12
View File
@@ -1,6 +1,13 @@
iD.ui.modal = function(blocking) {
var animate = d3.select('div.modal').empty();
var keybinding = d3.keybinding('modal')
.on('⌫', close)
.on('⎋', close);
d3.select(document).call(keybinding);
d3.select('div.modal').transition()
.style('opacity', 0).remove();
@@ -30,5 +37,10 @@ iD.ui.modal = function(blocking) {
shaded.style('opacity', 1);
}
function close() {
shaded.remove();
keybinding.off();
}
return shaded;
};
+1 -1
View File
@@ -37,7 +37,7 @@ iD.ui.save = function() {
id: changeset_id,
comment: e.comment
})
.call(iD.ui.success()
.call(iD.ui.success(connection)
.on('cancel', function() {
modal.remove();
}));
+15 -6
View File
@@ -1,4 +1,4 @@
iD.ui.success = function() {
iD.ui.success = function(connection) {
var event = d3.dispatch('cancel', 'save');
function success(selection) {
@@ -9,22 +9,31 @@ iD.ui.success = function() {
var section = body.append('div').attr('class','modal-section fillD');
header.append('h2').text('You Just Edited OpenStreetMap!');
header.append('p').text('You just improved the world\'s best free map');
var m = '';
if (changeset.comment) {
m = '"' + changeset.comment.substring(0, 20) + '" ';
}
var message = 'Edited OpenStreetMap! ' + m +
'http://osm.org/browse/changeset/' + changeset.id;
var message = (m || 'Edited OSM!') +
connection.changesetUrl(changeset.id);
section.append('a')
header.append('a')
.attr('href', function(d) {
return connection.changesetUrl(changeset.id);
})
.attr('target', '_blank')
.attr('class', 'success-action')
.text('View on OSM');
header.append('a')
.attr('target', '_blank')
.attr('href', function(d) {
return 'https://twitter.com/intent/tweet?source=webclient&text=' +
encodeURIComponent(message);
})
.text('Tweet: ' + message);
.attr('class', 'success-action')
.text('Tweet');
var buttonwrap = section.append('div')
.attr('class', 'buttons cf');