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

This commit is contained in:
Saman Bemel-Benrud
2013-01-04 19:28:27 -05:00
33 changed files with 739 additions and 352 deletions
+17 -14
View File
@@ -14,17 +14,19 @@ iD.Connection = function() {
}
function bboxFromAPI(box, tile, callback) {
loadFromURL(bboxUrl(box), function(err, parsed) {
function done(err, parsed) {
loadedTiles[tile.toString()] = true;
callback(err, parsed);
});
}
loadFromURL(bboxUrl(box), done);
}
function loadFromURL(url, callback) {
function done(dom) {
return callback(null, parse(dom));
}
inflight.push(d3.xml(url).get()
.on('load', function(dom) {
return callback(null, parse(dom));
}));
.on('load', done));
}
function getNodes(obj) {
@@ -67,9 +69,7 @@ iD.Connection = function() {
tags: getTags(obj)
};
for (var i = 0, l = obj.attributes.length; i < l; i++) {
var n = obj.attributes[i].nodeName;
var v = obj.attributes[i].nodeValue;
o[n] = v;
o[obj.attributes[i].nodeName] = obj.attributes[i].nodeValue;
}
if (o.lon && o.lat) {
o.loc = [parseFloat(o.lon), parseFloat(o.lat)];
@@ -129,13 +129,14 @@ iD.Connection = function() {
};
function userDetails(callback) {
oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, function(err, user_details) {
function done(err, user_details) {
var u = user_details.getElementsByTagName('user')[0];
callback(connection.user({
display_name: u.attributes.display_name.nodeValue,
id: u.attributes.id.nodeValue
}).user());
});
}
oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
}
function tileAlreadyLoaded(c) { return !loadedTiles[c.toString()]; }
@@ -143,9 +144,10 @@ iD.Connection = function() {
function abortRequest(i) { i.abort(); }
function loadTile(e) {
bboxFromAPI(e.box, e.tile, function(err, g) {
function done(err, g) {
event.load(err, g);
});
}
bboxFromAPI(e.box, e.tile, done);
}
function loadTiles(projection) {
@@ -211,10 +213,11 @@ iD.Connection = function() {
};
connection.authenticate = function(callback) {
return oauth.authenticate(function(err, res) {
function done(err, res) {
event.auth();
if (callback) callback(err, res);
});
}
return oauth.authenticate(done);
};
connection.bboxFromAPI = bboxFromAPI;
+22
View File
@@ -84,6 +84,28 @@ iD.Entity.prototype = {
key != 'odbl' &&
key.indexOf('tiger:') !== 0;
});
},
friendlyName: function() {
// Generate a string such as 'river' or 'Fred's House' for an entity.
if (!this.tags || !Object.keys(this.tags).length) { return ''; }
var mainkeys = ['highway','amenity','railway','waterway','natural'],
n = [];
if (this.tags.name) n.push(this.tags.name);
if (this.tags.ref) n.push(this.tags.ref);
if (!n.length) {
for (var k in this.tags) {
if (mainkeys.indexOf(k) !== -1) {
n.push(this.tags[k]);
break;
}
}
}
return n.length === 0 ? 'unknown' : n.join('; ');
}
};
+4
View File
@@ -3,5 +3,9 @@ iD.Node = iD.Entity.extend({
extent: function() {
return [this.loc, this.loc];
},
geometry: function() {
return this._poi ? 'point' : 'vertex';
}
});
+4
View File
@@ -36,5 +36,9 @@ iD.Way = iD.Entity.extend({
this.tags.area !== 'no' &&
!this.tags.highway &&
!this.tags.barrier);
},
geometry: function() {
return this.isArea() ? 'area' : 'line';
}
});
+46 -1
View File
@@ -107,10 +107,11 @@ window.iD = function(container) {
.append('div')
.attr('class', 'hello');
bar.append('button')
var save_button = bar.append('button')
.attr('class', 'save action wide')
.html("<span class='icon icon-pre-text save'></span><span class='label'>Save</span><small id='as-username'></small>")
.attr('title', 'Save changes to OpenStreetMap, making them visible to other users')
.property('disabled', true)
.call(bootstrap.tooltip()
.placement('bottom'))
.on('click', function() {
@@ -121,6 +122,17 @@ window.iD = function(container) {
l.remove();
history.reset();
map.flush().redraw();
var modal = iD.modal();
modal.select('.content')
.classed('success-modal', true)
.datum({
id: changeset_id,
comment: e.comment
})
.call(iD.success()
.on('cancel', function() {
modal.remove();
}));
});
}
var changes = history.changes();
@@ -146,6 +158,24 @@ window.iD = function(container) {
}
});
save_button.append('span')
.attr('class', 'count');
history.on('change.save-button', function() {
var changes = history.changes(),
num_changes = d3.sum(d3.values(changes).map(function(c) {
return c.length;
}));
save_button.property('disabled', num_changes === 0);
save_button
.classed('has-count', num_changes > 0);
save_button.select('span.count')
.text(num_changes);
});
bar.append('div')
.attr('class', 'messages');
@@ -160,6 +190,21 @@ window.iD = function(container) {
return d[0] + ' icon';
});
function geolocateSuccess(position) {
map.center([position.coords.longitude, position.coords.latitude]);
}
function geolocateError() { }
if (navigator.geolocation) {
container.append('div')
.attr('class', 'geolocate-control map-control')
.append('button')
.attr('class', 'narrow')
.text('G')
.on('click', function() {
navigator.geolocation.getCurrentPosition(geolocateSuccess, geolocateError);
});
}
var gc = container.append('div').attr('class', 'geocode-control map-control')
.call(iD.geocoder().map(map));
-1
View File
@@ -13,7 +13,6 @@ iD.modes.AddLine = function() {
controller = mode.controller;
map.dblclickEnable(false)
.hoverEnable(false)
.hoverEnable(false)
.hint('Click on the map to start drawing an road, path, or route.');
+1 -1
View File
@@ -30,7 +30,7 @@ iD.modes.AddPoint = function() {
};
mode.exit = function() {
map.hoverEnable(true);
mode.map.hoverEnable(true);
mode.map.hint(false);
mode.map.surface.on('click.addpoint', null);
mode.map.keybinding().on('⎋.addpoint', null);
+23 -2
View File
@@ -66,14 +66,35 @@ iD.modes.Select = function (entity) {
mode.controller.exit();
});
surface.on('click.select', function () {
function click() {
var datum = d3.select(d3.event.target).datum();
if (datum instanceof iD.Entity) {
mode.controller.enter(iD.modes.Select(datum));
} else {
mode.controller.enter(iD.modes.Browse());
}
});
}
function dblclick() {
var datum = d3.select(d3.event.target).datum();
if (datum instanceof iD.Entity &&
(datum.geometry() === 'area' || datum.geometry() === 'line')) {
var choice = iD.util.geo.chooseIndex(datum,
d3.mouse(mode.map.surface.node()), mode.map),
node = iD.Node({ loc: choice.loc });
mode.history.perform(
iD.actions.AddNode(node),
iD.actions.AddWayNode(datum.id, node.id, choice.index),
'added a point to a road');
d3.event.preventDefault();
d3.event.stopPropagation();
}
}
surface.on('click.select', click)
.on('dblclick.browse', dblclick);
mode.map.keybinding().on('⌫.select', function(e) {
remove();
+4
View File
@@ -66,6 +66,10 @@ iD.OAuth = function() {
var l = iD.loading('contacting openstreetmap...');
// it would make more sense to have this code within the callback
// to oauth.xhr below. however, it needs to be directly within a
// browser event handler in order to open a popup without it being
// blocked.
var w = 600, h = 550,
settings = [
['width', w], ['height', h],
+20 -7
View File
@@ -2,6 +2,7 @@ iD.Background = function() {
var tile = d3.geo.tile(),
projection,
cache = {},
offset = [0, 0],
transformProp = iD.util.prefixCSSProperty('Transform'),
source = d3.functor('');
@@ -27,6 +28,10 @@ iD.Background = function() {
return tiles;
}
function tileSize(d, z) {
return Math.ceil(256 * Math.pow(2, z - d[2])) / 256;
}
// derive the tiles onscreen, remove those offscreen and position tiles
// correctly for the currentstate of `projection`
function background() {
@@ -82,21 +87,29 @@ iD.Background = function() {
.on('error', error)
.on('load', load);
function tileSize(d) {
return Math.ceil(256 * Math.pow(2, z - d[2])) / 256;
}
image.style(transformProp, function(d) {
var _ts = 256 * Math.pow(2, z - d[2]);
var scale = tileSize(d);
var scale = tileSize(d, z);
return 'translate(' +
Math.round((d[0] * _ts) - tile_origin[0]) + 'px,' +
Math.round((d[1] * _ts) - tile_origin[1]) + 'px) scale(' + scale + ',' + scale + ')';
(Math.round((d[0] * _ts) - tile_origin[0]) + offset[0]) + 'px,' +
(Math.round((d[1] * _ts) - tile_origin[1]) + offset[1]) + 'px) scale(' + scale + ',' + scale + ')';
});
if (Object.keys(cache).length > 100) cache = {};
}
background.offset = function(_) {
if (!arguments.length) return offset;
offset = _;
return background;
};
background.nudge = function(_) {
offset[0] += _[0];
offset[1] += _[1];
return background;
};
background.projection = function(_) {
if (!arguments.length) return projection;
projection = _;
+4
View File
@@ -45,3 +45,7 @@ iD.BackgroundSource.Tiger2012 = iD.BackgroundSource.template(
iD.BackgroundSource.OSM = iD.BackgroundSource.template(
'http://{t}.tile.openstreetmap.org/{z}/{x}/{y}.png',
['a', 'b', 'c'], [0, 18]);
iD.BackgroundSource.MapBox = iD.BackgroundSource.template(
'http://{t}.tiles.mapbox.com/v3/openstreetmap.map-4wvf9l0l/{z}/{x}/{y}.jpg70',
['a', 'b', 'c'], [0, 16]);
+46 -35
View File
@@ -84,9 +84,9 @@ iD.Map = function() {
filter = d3.functor(true);
} else {
var only = {};
difference.forEach(function (id) {
difference.forEach(function buildDifference(id) {
only[id] = graph.fetch(id);
graph.parentWays(id).forEach(function (parent) {
graph.parentWays(id).forEach(function buildOnly(parent) {
only[parent.id] = graph.fetch(parent.id);
});
});
@@ -94,7 +94,6 @@ iD.Map = function() {
filter = function(d) { return d.accuracy ? d.way in only : d.id in only; };
}
if (all.length > 10000) return editOff();
else editOn();
@@ -112,9 +111,10 @@ iD.Map = function() {
}
}
var parentStructure = graph.parentStructure(ways);
var wayAccuracyHandles = ways.reduce(function(mem, w) {
return mem.concat(accuracyHandles(w));
}, []);
var wayAccuracyHandles = [];
for (i = 0; i < ways.length; i++) {
accuracyHandles(ways[i], wayAccuracyHandles);
}
drawVertices(vertices, parentStructure, filter);
drawAccuracyHandles(wayAccuracyHandles, filter);
drawCasings(lines, filter);
@@ -123,8 +123,8 @@ iD.Map = function() {
drawPoints(points, filter);
}
function accuracyHandles(way) {
var handles = [];
// updates handles by reference
function accuracyHandles(way, handles) {
for (var i = 0; i < way.nodes.length - 1; i++) {
if (iD.util.geo.dist(way.nodes[i].loc, way.nodes[i + 1].loc) > 0.0001) {
handles.push({
@@ -135,32 +135,36 @@ iD.Map = function() {
});
}
}
return handles;
}
function pointTransform(entity) {
return 'translate(' + iD.util.geo.roundCoords(projection(entity.loc)) + ')';
}
function drawVertices(vertices, parentStructure, filter) {
function shared(d) { return parentStructure[d.id] > 1; }
var circles = g.hit.selectAll('circle.vertex')
var circles = g.hit.selectAll('g.vertex')
.filter(filter)
.data(vertices, key);
circles.exit().remove();
circles.enter().insert('circle', ':first-child')
var cg = circles.enter()
.insert('g', ':first-child')
.attr('class', 'node vertex');
circles.attr('transform', function(entity) {
var p = projection(entity.loc);
return 'translate(' + [~~p[0], ~~p[1]] +
')';
})
cg.append('circle')
.attr('class', 'stroke')
.attr('r', 6);
cg.append('circle')
.attr('class', 'fill')
.attr('r', 4);
circles.attr('transform', pointTransform)
.classed('shared', shared)
.classed('hover', classHover);
circles.transition().duration(50).attr('r', function(d) {
return d.id === hover ? 8: 4;
});
}
function drawAccuracyHandles(waynodes, filter) {
@@ -170,10 +174,7 @@ iD.Map = function() {
handles.exit().remove();
handles.enter().append('circle')
.attr({ r: 3, 'class': 'accuracy-handle' });
handles.attr('transform', function(entity) {
var p = projection(entity.loc);
return 'translate(' + [~~p[0], ~~p[1]] + ')';
});
handles.attr('transform', pointTransform);
}
function editOff() {
@@ -209,20 +210,30 @@ iD.Map = function() {
}
function drawPoints(points, filter) {
var groups = g.hit.selectAll('g.point')
.filter(filter)
.data(points, key);
groups.exit().remove();
var group = groups.enter().append('g')
.attr('class', 'node point');
group.append('circle')
.attr({ r: 10, cx: 8, cy: 8 });
.attr('class', 'stroke')
.attr({ r: 10 });
group.append('circle')
.attr('class', 'fill')
.attr({ r: 10 });
group.append('image')
.attr({ width: 16, height: 16 });
groups.attr('transform', function(d) {
var pt = projection(d.loc);
return 'translate(' + [~~pt[0], ~~pt[1]] + ') translate(-8, -8)';
});
.attr({ width: 16, height: 16 })
.attr('transform', 'translate(-8, -8)');
groups.attr('transform', pointTransform);
groups.classed('hover', classHover);
groups.select('image').attr('xlink:href', iD.Style.pointImage);
}
@@ -299,11 +310,11 @@ iD.Map = function() {
if (fast) {
if (!translateStart) translateStart = d3.event.translate.slice();
var a = d3.event.translate,
b = translateStart;
tilegroup.style(transformProp,
'translate(' + ~~(a[0] - b[0]) + 'px,' + ~~(a[1] - b[1]) + 'px)');
surface.style(transformProp,
'translate(' + ~~(a[0] - b[0]) + 'px,' + ~~(a[1] - b[1]) + 'px)');
b = translateStart,
translate = 'translate(' + ~~(a[0] - b[0]) + 'px,' +
~~(a[1] - b[1]) + 'px)';
tilegroup.style(transformProp, translate);
surface.style(transformProp, translate);
} else {
redraw();
translateStart = null;
+1 -1
View File
@@ -5,7 +5,7 @@ iD.taginfo = function() {
taginfo.keys = function(parameters, callback) {
d3.json(endpoint + 'db/keys?' +
iD.util.qsString(_.extend({
rp: 20,
rp: 6,
sortname: 'count_all',
sortorder: 'desc',
page: 1
+54 -28
View File
@@ -14,51 +14,77 @@ iD.commit = function() {
.attr('class', 'changeset-comment')
.attr('placeholder', 'Brief Description of your contributions');
var buttonwrap = commit.append('div')
.attr('class', 'buttons');
var buttonwrap = commit.append('div')
.attr('class', 'buttons');
var savebutton = buttonwrap.append('button')
.attr('class', 'action wide')
.on('click.save', function() {
event.save({
comment: d3.select('textarea.changeset-comment').node().value
});
});
savebutton.append('span').attr('class','icon save icon-pre-text');
savebutton.append('span').attr('class','label').text('Save');
var cancelbutton = buttonwrap.append('button')
.attr('class', 'cancel wide')
.on('click.cancel', function() {
event.cancel();
});
cancelbutton.append('span').attr('class','icon close icon-pre-text');
cancelbutton.append('span').attr('class','label').text('Cancel');
var savebutton = buttonwrap.append('button')
.attr('class', 'action wide')
.on('click.save', function() {
event.save({
comment: d3.select('textarea.changeset-comment').node().value
});
});
savebutton.append('span').attr('class','icon save icon-pre-text');
savebutton.append('span').attr('class','label').text('Save');
var cancelbutton = buttonwrap.append('button')
.attr('class', 'cancel wide')
.on('click.cancel', function() {
event.cancel();
});
cancelbutton.append('span').attr('class','icon close icon-pre-text');
cancelbutton.append('span').attr('class','label').text('Cancel');
function changesLength(d) { return changes[d].length; }
var section = body.selectAll('div.commit-section')
.data(['modified', 'deleted', 'created'].filter(function(d) {
return changes[d].length;
}))
.data(['modified', 'deleted', 'created'].filter(changesLength))
.enter()
.append('div').attr('class', 'commit-section modal-section fillL2');
section.append('h3').text(String)
.append('small')
.attr('class', 'count')
.text(function(d) { return changes[d].length; });
.text(changesLength);
function zipSame(d) {
var c = [], n = -1;
for (var i = 0; i < d.length; i++) {
var desc = {
name: d[i].friendlyName(),
type: d[i].type,
count: 1,
tagText: iD.util.tagText(d[i])
};
if (c[n] &&
c[n].name == desc.name &&
c[n].tagText == desc.tagText) {
c[n].count++;
} else {
c[++n] = desc;
}
}
return c;
}
var li = section.append('ul')
.attr('class','changeset-list')
.selectAll('li')
.data(function(d) { return changes[d]; })
.data(function(d) { return zipSame(changes[d]); })
.enter()
.append('li');
li.append('strong').text(function(d) { return d.type + ' '; });
li.append('strong').text(function(d) {
return (d.count > 1) ? d.type + 's ' : d.type + ' ';
});
li.append('span')
.text(function(d) {
return iD.util.friendlyName(d);
})
.attr('title', iD.util.tagText);
.text(function(d) { return d.name; })
.attr('title', function(d) { return d.tagText; });
li.filter(function(d) { return d.count > 1; })
.append('span')
.attr('class', 'count')
.text(function(d) { return d.count; });
}
return d3.rebind(commit, event, 'on');
+190 -173
View File
@@ -2,220 +2,237 @@ iD.Inspector = function() {
var event = d3.dispatch('changeTags', 'changeWayDirection',
'update', 'remove', 'close', 'splitWay'),
taginfo = iD.taginfo(),
inspectorwrap;
tagList;
function inspector(selection) {
var entity = selection.datum();
selection.html("").append('button')
.attr('class', 'narrow close')
.html("<span class='icon close'></span>")
.on('click', function() {
event.close(entity);
});
selection.append('div')
.attr('class', 'head inspector-inner')
.call(drawHead);
var inspectorbody = selection.append('div')
.attr('class', 'inspector-body');
var inspectorwrap = inspectorbody.append('div')
.attr('class', 'inspector-inner tag-wrap fillL2');
inspectorwrap.append('h4')
.text('Edit tags');
tagList = inspectorwrap.append('ul');
inspectorwrap.append('div').attr('class', 'add-tag-row').append('button')
.attr('class', 'add-tag')
.text('+ Add New Tag')
.on('click', function() {
addTag();
tagList.selectAll('li:last-child input.key').node().focus();
});
var formsel = drawTags(entity.tags);
inspectorbody.append('div')
.attr('class', 'inspector-buttons')
.call(drawButtons);
var inHeight = inspectorbody.node().offsetHeight;
inspectorbody.style('display', 'none')
.style('margin-top', (-inHeight) + 'px');
var inspectortoggle = selection.append('button')
.attr('class', 'inspector-toggle action')
.on('click', function() {
inspectortoggle.style('display', 'none');
inspectorbody
.style('display', 'block')
.transition()
.style('margin-top', '0px');
});
formsel.selectAll('input').node().focus();
inspectortoggle.append('span')
.text('Details')
.attr('class','label');
}
function drawHead(selection) {
var entity = selection.datum();
function drawhead(selection) {
function osmLink(d) {
return 'http://www.openstreetmap.org/browse/' + d.type + '/' + d.osmId();
}
function emitChangeDirection(d) { event.changeWayDirection(d); }
function emitSplitWay(d) { event.splitWay(d); }
selection.html('');
var h2 = selection.append('h2');
h2.append('span').attr('class', function(d) {
var icons = { way: 'line', node: 'point' };
return 'icon big icon-pre-text big-' + icons[d.type];
});
h2.append('span').text(iD.util.friendlyName(selection.datum()));
h2.append('span')
.attr('class', 'icon big icon-pre-text big-' + entity.geometry());
h2.append('span')
.text(entity.friendlyName());
selection.append('a')
.attr('class', 'permalink')
.attr('href', osmLink)
.attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId())
.text('View on OSM');
if (selection.datum().type === 'way') {
if (entity.type === 'way') {
selection.append('a')
.attr('class', 'permalink')
.attr('href', '#')
.text('Reverse Direction')
.on('click', emitChangeDirection);
.on('click', function() { event.changeWayDirection(entity); });
}
if (selection.datum().type === 'node' && !selection.datum()._poi) {
if (entity.geometry() === 'vertex') {
selection.append('a')
.attr('class', 'permalink')
.attr('href', '#')
.text('Split Way')
.on('click', emitSplitWay);
.on('click', function() { event.splitWay(entity); });
}
}
function inspector(selection) {
selection.each(function(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', apply);
function draw(tags) {
selection.append('button')
.attr('class', 'delete wide action')
.html("<span class='icon icon-pre-text delete'></span><span class='label'>Delete</span>")
.on('click', function(entity) { event.remove(entity); });
}
function emptyTag(d) {
return d.key === '';
}
function drawTags(tags) {
tags = d3.entries(tags);
function pushMore() {
if (d3.event.keyCode === 9) {
draw(inspector.tags());
}
}
if (!tags.length) {
tags = [{key: '', value: ''}];
}
function bindTypeahead() {
var row = d3.select(this),
key = row.selectAll('.key'),
value = row.selectAll('.value');
var li = tagList.selectAll('li')
.data(tags, function(d) { return d.key; });
key.call(d3.typeahead()
.data(function(_, callback) {
taginfo.keys({query: key.property('value')}, function(err, data) {
callback(data.data.map(function (d) {
return {value: d.key};
}));
});
}));
li.exit().remove();
value.call(d3.typeahead()
.data(function(_, callback) {
taginfo.values({key: key.property('value'), query: value.property('value')}, function(err, data) {
callback(data.data.map(function (d) {
return {value: d.value, title: d.description};
}));
});
}));
}
var row = li.enter().append('li')
.attr('class', 'tag-row');
tags = d3.entries(tags);
tags.push({ key: '', value: ''});
var inputs = row.append('div')
.attr('class', 'input-wrap');
var li = inspectorwrap.selectAll('li')
.data(tags, function(d) { return d.key; });
inputs.append('input')
.property('type', 'text')
.attr('class', 'key')
.property('value', function(d) { return d.key; })
.on('change', function(d) { d.key = this.value; });
li.exit().remove();
inputs.append('input')
.property('type', 'text')
.attr('class', 'value')
.property('value', function(d) { return d.value; })
.on('change', function(d) { d.value = this.value; })
.on('keydown.push-more', pushMore);
var row = li.enter().append('li').attr('class','tag-row');
var inputs = row.append('div').attr('class','input-wrap');
inputs.each(bindTypeahead);
li.classed('tag-row-empty', emptyTag);
var removeBtn = row.append('button')
.attr('tabindex', -1)
.attr('class','remove minor')
.on('click', removeTag);
inputs.append('input')
.property('type', 'text')
.attr('class', 'key')
.property('value', function(d) { return d.key; });
removeBtn.append('span')
.attr('class', 'icon remove');
inputs.append('input')
.property('type', 'text')
.attr('class', 'value')
.property('value', function(d) { return d.value; })
.on('keydown.push-more', pushMore);
inputs.each(bindTypeahead);
var removeBtn = row.append('button')
.attr('tabindex', -1)
.attr('class','remove minor')
.on('click', removeTag);
removeBtn.append('span').attr('class', 'icon remove');
var helpBtn = row.append('button')
.attr('tabindex', -1)
.attr('class', 'tag-help minor')
.append('a')
.attr('tabindex', -1)
.attr('target', '_blank')
.on('click', function(d) {
taginfo.docs(d, function(err, docs) {
var en = _.find(docs, function(d) {
return d.lang == 'en';
});
if (en) {
var types = [];
if (en.on_area) types.push('area');
if (en.on_node) types.push('point');
if (en.on_way) types.push('line');
en.types = types;
var mod = iD.modal();
mod.select('.content')
.datum(en)
.call(iD.tagReference);
}
});
d3.event.preventDefault();
})
.attr('href', function(d) {
return 'http://taginfo.openstreetmap.org/keys/' + d.key;
var helpBtn = row.append('button')
.attr('tabindex', -1)
.attr('class', 'tag-help minor')
.append('a')
.attr('tabindex', -1)
.attr('target', '_blank')
.on('click', function(d) {
taginfo.docs(d, function(err, docs) {
var en = _.find(docs, function(d) {
return d.lang == 'en';
});
helpBtn.append('span').attr('class', 'icon inspect');
return li;
}
function removeTag(d) {
var tags = inspector.tags();
delete tags[d.key];
draw(tags);
}
function apply(entity) {
event.changeTags(entity, inspector.tags());
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', apply);
selection.append('button')
.attr('class', 'delete wide action')
.html("<span class='icon icon-pre-text delete'></span><span class='label'>Delete</span>")
.on('click', function(entity) { event.remove(entity); });
}
selection.html("").append('button')
.attr('class', 'narrow close')
.html("<span class='icon close'></span>")
.on('click', function() {
event.close(entity);
if (en) {
var types = [];
if (en.on_area) types.push('area');
if (en.on_node) types.push('point');
if (en.on_way) types.push('line');
en.types = types;
var mod = iD.modal();
mod.select('.content')
.datum(en)
.call(iD.tagReference);
}
});
d3.event.preventDefault();
})
.attr('href', function(d) {
return 'http://taginfo.openstreetmap.org/keys/' + d.key;
});
selection.append('div')
.attr('class', 'head inspector-inner')
.call(drawhead);
helpBtn.append('span')
.attr('class', 'icon inspect');
var inspectorbody = selection.append('div')
.attr('class', 'inspector-body');
return li;
}
inspectorwrap = inspectorbody
.append('ul').attr('class', 'inspector-inner tag-wrap fillL2');
function pushMore() {
if (d3.event.keyCode === 9 && tagList.selectAll('li:last-child input.value').node() === this) {
addTag();
}
}
inspectorwrap.append('h4').text('Edit tags');
function bindTypeahead() {
var row = d3.select(this),
key = row.selectAll('.key'),
value = row.selectAll('.value');
var formsel = draw(entity.tags);
inspectorbody.append('div')
.attr('class', 'inspector-buttons').call(drawbuttons);
var inHeight = inspectorbody.node().offsetHeight;
inspectorbody.style('display', 'none')
.style('margin-top', (-inHeight) + 'px');
var inspectortoggle = selection.append('button')
.attr('class', 'inspector-toggle action')
.on('click', function() {
inspectortoggle.style('display', 'none');
inspectorbody
.style('display', 'block')
.transition()
.style('margin-top', '0px');
key.call(d3.typeahead()
.data(function(_, callback) {
taginfo.keys({query: key.property('value')}, function(err, data) {
callback(data.data.map(function (d) {
return {value: d.key};
}));
});
}));
formsel.select('input').node().focus();
value.call(d3.typeahead()
.data(function(_, callback) {
taginfo.values({key: key.property('value'), query: value.property('value')}, function(err, data) {
callback(data.data.map(function (d) {
return {value: d.value, title: d.description};
}));
});
}));
}
inspectortoggle.append('span')
.text('Details')
.attr('class','label');
});
function addTag() {
var tags = inspector.tags();
tags[''] = '';
drawTags(tags);
}
function removeTag(d) {
var tags = inspector.tags();
delete tags[d.key];
drawTags(tags);
}
function apply(entity) {
event.changeTags(entity, inspector.tags());
event.close(entity);
}
inspector.tags = function () {
var tags = {};
inspectorwrap.selectAll('li').each(function() {
tagList.selectAll('li').each(function() {
var row = d3.select(this),
key = row.selectAll('.key').property('value'),
value = row.selectAll('.value').property('value');
+34
View File
@@ -12,6 +12,10 @@ iD.layerswitcher = function(map) {
name: 'OSM',
source: iD.BackgroundSource.OSM,
description: 'The default OpenStreetMap layer.'
}, {
name: 'MapBox',
source: iD.BackgroundSource.MapBox,
description: 'Satellite and Aerial Imagery'
}, {
name: 'Custom',
source: iD.BackgroundSource.Custom,
@@ -121,6 +125,36 @@ iD.layerswitcher = function(map) {
.insert('span')
.attr('class','icon toggle');
var adjustments = content
.append('div')
.attr('class', 'adjustments');
var directions = [
['←', [-1, 0]],
['↑', [0, -1]],
['→', [1, 0]],
['↓', [0, 1]]];
function nudge(d) {
map.background.nudge(d[1]);
map.redraw();
}
adjustments.selectAll('button')
.data(directions).enter()
.append('button')
.attr('class', 'nudge')
.text(function(d) { return d[0]; })
.on('click', nudge);
adjustments.append('button')
.text('reset')
.attr('class', 'reset')
.on('click', function() {
map.background.offset([0, 0]);
map.redraw();
});
selection.call(clickoutside);
selectLayer(map.background.source());
+1 -1
View File
@@ -3,7 +3,7 @@ iD.notice = function(selection) {
notice = {};
notice.message = function(_) {
selection.attr('class','inner');
selection.attr('class', 'notice inner');
if (!arguments.length) return _;
if (!message && _) {
selection
+43
View File
@@ -0,0 +1,43 @@
iD.success = function() {
var event = d3.dispatch('cancel', 'save');
function success(selection) {
var changeset = selection.datum(),
header = selection.append('div').attr('class', 'header modal-section'),
body = selection.append('div').attr('class', 'body');
var section = body.append('div').attr('class','modal-section');
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;
section.append('a')
.attr('href', function(d) {
return 'https://twitter.com/intent/tweet?source=webclient&text=' +
encodeURIComponent(message);
})
.text('Tweet: ' + message);
var buttonwrap = section.append('div')
.attr('class', 'buttons');
var okbutton = buttonwrap.append('button')
.attr('class', 'action wide')
.on('click.save', function() {
event.cancel();
});
okbutton.append('span').attr('class','icon apply icon-pre-text');
okbutton.append('span').attr('class','label').text('OK');
}
return d3.rebind(success, event, 'on');
};
-22
View File
@@ -6,28 +6,6 @@ iD.util.trueObj = function(arr) {
return o;
};
iD.util.friendlyName = function(entity) {
// Generate a string such as 'river' or 'Fred's House' for an entity.
if (!entity.tags || !Object.keys(entity.tags).length) { return ''; }
var mainkeys = ['highway','amenity','railway','waterway','natural'],
n = [];
if (entity.tags.name) n.push(entity.tags.name);
if (entity.tags.ref) n.push(entity.tags.ref);
if (!n.length) {
for (var k in entity.tags) {
if (mainkeys.indexOf(k) !== -1) {
n.push(entity.tags[k]);
break;
}
}
}
return n.length === 0 ? 'unknown' : n.join('; ');
};
iD.util.codeWindow = function(content) {
top.win = window.open('','contentWindow',
'width=350,height=350,menubar=0' +
+7
View File
@@ -0,0 +1,7 @@
d3.selection.prototype.trigger = function (type) {
this.each(function() {
var evt = document.createEvent('HTMLEvents');
evt.initEvent(type, true, true);
this.dispatchEvent(evt);
});
};
+39 -17
View File
@@ -14,35 +14,47 @@ d3.typeahead = function() {
top: rect.bottom + 'px'
});
selection
.on('keyup.typeahead', update);
.on('keyup.typeahead', key);
hidden = false;
}
function hide() {
window.setTimeout(function() {
container.remove();
idx = 0;
hidden = true;
}, 500);
container.remove();
idx = 0;
hidden = true;
}
function slowHide() {
window.setTimeout(hide, 150);
}
selection
.on('focus.typeahead', setup)
.on('blur.typeahead', hide);
.on('blur.typeahead', slowHide);
function update() {
if (hidden) setup();
if (d3.event.keyCode === 40) idx++;
if (d3.event.keyCode === 38) idx--;
if (d3.event.keyCode === 13) {
selection.property('value', container.select('a.selected').datum().value);
hide();
}
function key() {
if (d3.event.keyCode === 40) {
idx++;
return highlight();
} else if (d3.event.keyCode === 38) {
idx--;
return highlight();
} else if (d3.event.keyCode === 13) {
select(container.select('a.selected').datum());
hide();
} else {
update();
}
}
function highlight() {
container
.selectAll('a')
.classed('selected', function(d, i) { return i == idx; });
}
function update() {
if (hidden) setup();
data(selection, function(data) {
container.style('display', function() {
@@ -57,11 +69,21 @@ d3.typeahead = function() {
.append('a')
.text(function(d) { return d.value; })
.attr('title', function(d) { return d.title; })
.on('click', function(d) { selection.property('value', d.value); });
.on('click', select);
options.exit().remove();
options
.classed('selected', function(d, i) { return i == idx; });
});
}
function select(d) {
selection
.property('value', d.value)
.trigger('change');
}
};
typeahead.data = function(_) {