X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/76d8bed5d12fc10a785366bfa1a411aa4e0c39d8..3ba036045bc43031475eb29ca0663d33c80e1b32:/vendor/assets/iD/iD.js diff --git a/vendor/assets/iD/iD.js b/vendor/assets/iD/iD.js index d4a8ffdef..6c0845b7c 100644 --- a/vendor/assets/iD/iD.js +++ b/vendor/assets/iD/iD.js @@ -5665,7 +5665,7 @@ d3.combobox = function() { var fetcher = function(val, cb) { cb(data.filter(function(d) { - return d.title + return d.value .toString() .toLowerCase() .indexOf(val.toLowerCase()) !== -1; @@ -15199,11 +15199,6 @@ window.iD = function () { /* History */ context.graph = history.graph; - context.perform = history.perform; - context.replace = history.replace; - context.pop = history.pop; - context.undo = history.undo; - context.redo = history.redo; context.changes = history.changes; context.intersects = history.intersects; @@ -15227,6 +15222,23 @@ window.iD = function () { return context; }; + // Debounce save, since it's a synchronous localStorage write, + // and history changes can happen frequently (e.g. when dragging). + var debouncedSave = _.debounce(context.save, 350); + function withDebouncedSave(fn) { + return function() { + var result = fn.apply(history, arguments); + debouncedSave(); + return result; + } + } + + context.perform = withDebouncedSave(history.perform); + context.replace = withDebouncedSave(history.replace); + context.pop = withDebouncedSave(history.pop); + context.undo = withDebouncedSave(history.undo); + context.redo = withDebouncedSave(history.redo); + /* Graph */ context.hasEntity = function(id) { return history.graph().hasEntity(id); @@ -15376,7 +15388,7 @@ window.iD = function () { return d3.rebind(context, dispatch, 'on'); }; -iD.version = '1.2.0'; +iD.version = '1.2.1'; (function() { var detected = {}; @@ -15529,7 +15541,12 @@ iD.taginfo = function() { taginfo.docs = function(parameters, callback) { var debounce = parameters.debounce; parameters = clean(setSort(parameters)); - request(endpoint + (parameters.value ? 'tag/wiki_pages?' : 'key/wiki_pages?') + + + var path = 'key/wiki_pages?'; + if (parameters.value) path = 'tag/wiki_pages?'; + else if (parameters.rtype) path = 'relation/wiki_pages?'; + + request(endpoint + path + iD.util.qsString(parameters), debounce, callback); }; @@ -15750,6 +15767,13 @@ iD.util.asyncMap = function(inputs, func, callback) { }); }); }; + +// wraps an index to an interval [0..length-1] +iD.util.wrap = function(index, length) { + if (index < 0) + index += Math.ceil(-index/length)*length; + return index % length; +}; iD.geo = {}; iD.geo.roundCoords = function(c) { @@ -15762,17 +15786,23 @@ iD.geo.interp = function(p1, p2, t) { }; // http://jsperf.com/id-dist-optimization -iD.geo.dist = function(a, b) { +iD.geo.euclideanDistance = function(a, b) { var x = a[0] - b[0], y = a[1] - b[1]; return Math.sqrt((x * x) + (y * y)); }; +// Equirectangular approximation of spherical distances on Earth +iD.geo.sphericalDistance = function(a, b) { + var x = Math.cos(a[1]*Math.PI/180) * (a[0] - b[0]), + y = a[1] - b[1]; + return 6.3710E6 * Math.sqrt((x * x) + (y * y)) * Math.PI/180; +}; // Choose the edge with the minimal distance from `point` to its orthogonal // projection onto that edge, if such a projection exists, or the distance to // the closest vertex on that edge. Returns an object with the `index` of the // chosen edge, the chosen `loc` on that edge, and the `distance` to to it. iD.geo.chooseEdge = function(nodes, point, projection) { - var dist = iD.geo.dist, + var dist = iD.geo.euclideanDistance, points = nodes.map(function(n) { return projection(n.loc); }), min = Infinity, idx, loc; @@ -16215,63 +16245,105 @@ iD.actions.ChangeTags = function(entityId, tags) { return graph.replace(entity.update({tags: tags})); }; }; -iD.actions.Circularize = function(wayId, projection, count) { - count = count || 12; - - function closestIndex(nodes, loc) { - var idx, min = Infinity, dist; - for (var i = 0; i < nodes.length; i++) { - dist = iD.geo.dist(nodes[i].loc, loc); - if (dist < min) { - min = dist; - idx = i; - } - } - return idx; - } +iD.actions.Circularize = function(wayId, projection, maxAngle) { + maxAngle = (maxAngle || 20) * Math.PI / 180; var action = function(graph) { var way = graph.entity(wayId), nodes = _.uniq(graph.childNodes(way)), + keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length != 1; }), points = nodes.map(function(n) { return projection(n.loc); }), + keyPoints = keyNodes.map(function(n) { return projection(n.loc); }), centroid = d3.geom.polygon(points).centroid(), - radius = d3.median(points, function(p) { - return iD.geo.dist(centroid, p); - }), - ids = [], - sign = d3.geom.polygon(points).area() > 0 ? -1 : 1; - - for (var i = 0; i < count; i++) { - var node, + radius = d3.median(points, function(p) { return iD.geo.euclideanDistance(centroid, p); }), + sign = d3.geom.polygon(points).area() > 0 ? 1 : -1, + ids; + + // we need atleast two key nodes for the algorithm to work + if (!keyNodes.length) { + keyNodes = [nodes[0]]; + keyPoints = [points[0]]; + } + + if (keyNodes.length == 1) { + var index = nodes.indexOf(keyNodes[0]), + oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length); + + keyNodes.push(nodes[oppositeIndex]); + keyPoints.push(points[oppositeIndex]); + } + + // key points and nodes are those connected to the ways, + // they are projected onto the circle, inbetween nodes are moved + // to constant internals between key nodes, extra inbetween nodes are + // added if necessary. + for (var i = 0; i < keyPoints.length; i++) { + var nextKeyNodeIndex = (i + 1) % keyNodes.length, + startNodeIndex = nodes.indexOf(keyNodes[i]), + endNodeIndex = nodes.indexOf(keyNodes[nextKeyNodeIndex]), + numberNewPoints = -1, + indexRange = endNodeIndex - startNodeIndex, + distance, totalAngle, eachAngle, startAngle, endAngle, + angle, loc, node, j; + + if (indexRange < 0) { + indexRange += nodes.length; + } + + // position this key node + distance = iD.geo.euclideanDistance(centroid, keyPoints[i]); + keyPoints[i] = [ + centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius, + centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius]; + graph = graph.replace(keyNodes[i].move(projection.invert(keyPoints[i]))); + + // figure out the between delta angle we want to match to + startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]); + endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]); + totalAngle = endAngle - startAngle; + + // detects looping around -pi/pi + if (totalAngle*sign > 0) { + totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle)); + } + + do { + numberNewPoints++; + eachAngle = totalAngle / (indexRange + numberNewPoints); + } while (Math.abs(eachAngle) > maxAngle); + + // move existing points + for (j = 1; j < indexRange; j++) { + angle = startAngle + j * eachAngle; loc = projection.invert([ - centroid[0] + Math.cos(sign * (i / 12) * Math.PI * 2) * radius, - centroid[1] + Math.sin(sign * (i / 12) * Math.PI * 2) * radius]); + centroid[0] + Math.cos(angle)*radius, + centroid[1] + Math.sin(angle)*radius]); - if (nodes.length) { - var idx = closestIndex(nodes, loc); - node = nodes[idx]; - nodes.splice(idx, 1); - } else { - node = iD.Node(); + node = nodes[(j + startNodeIndex) % nodes.length].move(loc); + graph = graph.replace(node); } - ids.push(node.id); - graph = graph.replace(node.move(loc)); + // add new inbetween nodes if necessary + for (j = 0; j < numberNewPoints; j++) { + angle = startAngle + (indexRange + j) * eachAngle; + loc = projection.invert([ + centroid[0] + Math.cos(angle) * radius, + centroid[1] + Math.sin(angle) * radius]); + + node = iD.Node({loc: loc}); + graph = graph.replace(node); + + nodes.splice(endNodeIndex + j, 0, node); + } } + // update the way to have all the new nodes + ids = nodes.map(function(n) { return n.id; }); ids.push(ids[0]); + way = way.update({nodes: ids}); graph = graph.replace(way); - for (i = 0; i < nodes.length; i++) { - graph.parentWays(nodes[i]).forEach(function(parent) { - graph = graph.replace(parent.replaceNode(nodes[i].id, - ids[closestIndex(graph.childNodes(way), nodes[i].loc)])); - }); - - graph = iD.actions.DeleteNode(nodes[i].id)(graph); - } - return graph; }; @@ -16865,20 +16937,24 @@ iD.actions.Noop = function() { */ iD.actions.Orthogonalize = function(wayId, projection) { + var threshold = 7, // degrees within right or straight to alter + lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180), + upperThreshold = Math.cos(threshold * Math.PI / 180); + var action = function(graph) { var way = graph.entity(wayId), nodes = graph.childNodes(way), + points = _.uniq(nodes).map(function(n) { return projection(n.loc); }), corner = {i: 0, dotp: 1}, - points, i, j, score, motions; + epsilon = 1e-4, + i, j, score, motions; if (nodes.length === 4) { - points = _.uniq(nodes).map(function(n) { return projection(n.loc); }); - for (i = 0; i < 1000; i++) { motions = points.map(calcMotion); points[corner.i] = addPoints(points[corner.i],motions[corner.i]); score = corner.dotp; - if (score < 1.0e-8) { + if (score < epsilon) { break; } } @@ -16886,21 +16962,21 @@ iD.actions.Orthogonalize = function(wayId, projection) { graph = graph.replace(graph.entity(nodes[corner.i].id) .move(projection.invert(points[corner.i]))); } else { - var best; - points = _.uniq(nodes).map(function(n) { return projection(n.loc); }); - score = squareness(); + var best, + originalPoints = _.clone(points); + score = Infinity; for (i = 0; i < 1000; i++) { motions = points.map(calcMotion); for (j = 0; j < motions.length; j++) { points[j] = addPoints(points[j],motions[j]); } - var newScore = squareness(); + var newScore = squareness(points); if (newScore < score) { best = _.clone(points); score = newScore; } - if (score < 1.0e-8) { + if (score < epsilon) { break; } } @@ -16908,8 +16984,28 @@ iD.actions.Orthogonalize = function(wayId, projection) { points = best; for (i = 0; i < points.length; i++) { - graph = graph.replace(graph.entity(nodes[i].id) - .move(projection.invert(points[i]))); + // only move the points that actually moved + if (originalPoints[i][0] != points[i][0] || originalPoints[i][1] != points[i][1]) { + graph = graph.replace(graph.entity(nodes[i].id) + .move(projection.invert(points[i]))); + } + } + + // remove empty nodes on straight sections + for (i = 0; i < points.length; i++) { + var node = nodes[i]; + + if (graph.parentWays(node).length > 1 || + graph.parentRelations(node).length || + node.hasInterestingTags()) { + + continue; + } + + var dotp = normalizedDotProduct(i, points); + if (dotp < -1 + epsilon) { + graph = iD.actions.DeleteNode(nodes[i].id)(graph); + } } } @@ -16919,78 +17015,91 @@ iD.actions.Orthogonalize = function(wayId, projection) { var a = array[(i - 1 + array.length) % array.length], c = array[(i + 1) % array.length], p = subtractPoints(a, b), - q = subtractPoints(c, b); + q = subtractPoints(c, b), + scale, dotp; - var scale = 2*Math.min(iD.geo.dist(p, [0, 0]), iD.geo.dist(q, [0, 0])); + scale = 2 * Math.min(iD.geo.euclideanDistance(p, [0, 0]), iD.geo.euclideanDistance(q, [0, 0])); p = normalizePoint(p, 1.0); q = normalizePoint(q, 1.0); - var dotp = p[0] * q[0] + p[1] * q[1]; + dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]); // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270). if (array.length > 3) { if (dotp < -0.707106781186547) { dotp += 1.0; } - } else if (Math.abs(dotp) < corner.dotp) { + } else if (dotp && Math.abs(dotp) < corner.dotp) { corner.i = i; corner.dotp = Math.abs(dotp); } return normalizePoint(addPoints(p, q), 0.1 * dotp * scale); } + }; - function squareness() { - var g = 0.0; - for (var i = 1; i < points.length - 1; i++) { - var score = scoreOfPoints(points[i - 1], points[i], points[i + 1]); - g += score; - } - var startScore = scoreOfPoints(points[points.length - 1], points[0], points[1]); - var endScore = scoreOfPoints(points[points.length - 2], points[points.length - 1], points[0]); - g += startScore; - g += endScore; - return g; - } + function squareness(points) { + return points.reduce(function(sum, val, i, array) { + var dotp = normalizedDotProduct(i, array); - function scoreOfPoints(a, b, c) { - var p = subtractPoints(a, b), - q = subtractPoints(c, b); + dotp = filterDotProduct(dotp); + return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1))); + }, 0); + } - p = normalizePoint(p, 1.0); - q = normalizePoint(q, 1.0); + function normalizedDotProduct(i, points) { + var a = points[(i - 1 + points.length) % points.length], + b = points[i], + c = points[(i + 1) % points.length], + p = subtractPoints(a, b), + q = subtractPoints(c, b); - var dotp = p[0] * q[0] + p[1] * q[1]; - // score is constructed so that +1, -1 and 0 are all scored 0, any other angle - // is scored higher. - return 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1))); - } + p = normalizePoint(p, 1.0); + q = normalizePoint(q, 1.0); - function subtractPoints(a, b) { - return [a[0] - b[0], a[1] - b[1]]; - } + return p[0] * q[0] + p[1] * q[1]; + } - function addPoints(a, b) { - return [a[0] + b[0], a[1] + b[1]]; + function subtractPoints(a, b) { + return [a[0] - b[0], a[1] - b[1]]; + } + + function addPoints(a, b) { + return [a[0] + b[0], a[1] + b[1]]; + } + + function normalizePoint(point, scale) { + var vector = [0, 0]; + var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]); + if (length !== 0) { + vector[0] = point[0] / length; + vector[1] = point[1] / length; } - function normalizePoint(point, scale) { - var vector = [0, 0]; - var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]); - if (length !== 0) { - vector[0] = point[0] / length; - vector[1] = point[1] / length; - } + vector[0] *= scale; + vector[1] *= scale; - vector[0] *= scale; - vector[1] *= scale; + return vector; + } - return vector; + function filterDotProduct(dotp) { + if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) { + return dotp; } - }; + + return 0; + } action.disabled = function(graph) { - return false; + var way = graph.entity(wayId), + nodes = graph.childNodes(way), + points = _.uniq(nodes).map(function(n) { return projection(n.loc); }); + + if (squareness(points)) { + return false; + } + + return 'not_squarish'; }; return action; @@ -17114,19 +17223,70 @@ iD.actions.RotateWay = function(wayId, pivot, angle, projection) { iD.actions.Split = function(nodeId, newWayIds) { var wayIds; + // if the way is closed, we need to search for a partner node + // to split the way at. + // + // The following looks for a node that is both far away from + // the initial node in terms of way segment length and nearby + // in terms of beeline-distance. This assures that areas get + // split on the most "natural" points (independent of the number + // of nodes). + // For example: bone-shaped areas get split across their waist + // line, circles across the diameter. + function splitArea(nodes, idxA, graph) { + var lengths = new Array(nodes.length), + length, + i, + best = 0, + idxB; + + function wrap(index) { + return iD.util.wrap(index, nodes.length); + } + + function dist(nA, nB) { + return iD.geo.sphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc); + } + + // calculate lengths + length = 0; + for (i = wrap(idxA+1); i != idxA; i = wrap(i+1)) { + length += dist(nodes[i], nodes[wrap(i-1)]); + lengths[i] = length; + } + + length = 0; + for (i = wrap(idxA-1); i != idxA; i = wrap(i-1)) { + length += dist(nodes[i], nodes[wrap(i+1)]); + if (length < lengths[i]) + lengths[i] = length; + } + + // determine best opposite node to split + for (i = 0; i < nodes.length; i++) { + var cost = lengths[i] / dist(nodes[idxA], nodes[i]); + if (cost > best) { + idxB = i; + best = cost; + } + } + + return idxB; + } + function split(graph, wayA, newWayId) { var wayB = iD.Way({id: newWayId, tags: wayA.tags}), nodesA, nodesB, - isArea = wayA.isArea(); + isArea = wayA.isArea(), + isOuter = iD.geo.isSimpleMultipolygonOuterMember(wayA, graph); if (wayA.isClosed()) { var nodes = wayA.nodes.slice(0, -1), idxA = _.indexOf(nodes, nodeId), - idxB = idxA + Math.floor(nodes.length / 2); + idxB = splitArea(nodes, idxA, graph); - if (idxB >= nodes.length) { - idxB %= nodes.length; + if (idxB < idxA) { nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1)); nodesB = nodes.slice(idxB, idxA + 1); } else { @@ -17153,24 +17313,23 @@ iD.actions.Split = function(nodeId, newWayIds) { graph = graph.replace(relation); } } else { - var role = relation.memberById(wayA.id).role, - last = wayB.last(), - i = relation.memberById(wayA.id).index, - j; - - for (j = 0; j < relation.members.length; j++) { - var entity = graph.hasEntity(relation.members[j].id); - if (entity && entity.type === 'way' && entity.contains(last)) { - break; - } + if (relation === isOuter) { + graph = graph.replace(relation.mergeTags(wayA.tags)); + graph = graph.replace(wayA.update({tags: {}})); + graph = graph.replace(wayB.update({tags: {}})); } - relation = relation.addMember({id: wayB.id, type: 'way', role: role}, i <= j ? i + 1 : i); - graph = graph.replace(relation); + var member = { + id: wayB.id, + type: 'way', + role: relation.memberById(wayA.id).role + }; + + graph = iD.actions.AddMember(relation.id, member)(graph); } }); - if (isArea) { + if (!isOuter && isArea) { var multipolygon = iD.Relation({ tags: _.extend({}, wayA.tags, {type: 'multipolygon'}), members: [ @@ -17196,12 +17355,16 @@ iD.actions.Split = function(nodeId, newWayIds) { action.ways = function(graph) { var node = graph.entity(nodeId), - parents = graph.parentWays(node); + parents = graph.parentWays(node), + hasLines = _.any(parents, function(parent) { return parent.geometry(graph) === 'line'; }); return parents.filter(function(parent) { if (wayIds && wayIds.indexOf(parent.id) === -1) return false; + if (!wayIds && hasLines && parent.geometry(graph) !== 'line') + return false; + if (parent.isClosed()) { return true; } @@ -17253,7 +17416,10 @@ iD.actions.Straighten = function(wayId, projection) { var node = nodes[i], point = points[i]; - if (graph.parentWays(node).length > 1 || (node.tags && Object.keys(node.tags).length)) { + if (graph.parentWays(node).length > 1 || + graph.parentRelations(node).length || + node.hasInterestingTags()) { + var u = positionAlongWay(point, startPoint, endPoint), p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]), p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]), @@ -17572,8 +17738,8 @@ iD.behavior.Draw = function(context) { d3.select(window).on('mouseup.draw', function() { element.on('mousemove.draw', mousemove); - if (iD.geo.dist(pos, point()) < closeTolerance || - (iD.geo.dist(pos, point()) < tolerance && + if (iD.geo.euclideanDistance(pos, point()) < closeTolerance || + (iD.geo.euclideanDistance(pos, point()) < tolerance && (+new Date() - time) < 500)) { // Prevent a quick second click @@ -18501,8 +18667,6 @@ iD.modes.Browse = function(context) { iD.modes.DragNode(context).behavior]; mode.enter = function() { - context.save(); - behaviors.forEach(function(behavior) { context.install(behavior); }); @@ -18578,8 +18742,8 @@ iD.modes.DragNode = function(context) { return t('operations.move.annotation.' + entity.geometry(context.graph())); } - function connectAnnotation(datum) { - return t('operations.connect.annotation.' + datum.geometry(context.graph())); + function connectAnnotation(entity) { + return t('operations.connect.annotation.' + entity.geometry(context.graph())); } function origin(entity) { @@ -18648,7 +18812,7 @@ iD.modes.DragNode = function(context) { context.replace( iD.actions.MoveNode(entity.id, loc), - t('operations.move.annotation.' + entity.geometry(context.graph()))); + moveAnnotation(entity)); } function end(entity) { @@ -19186,8 +19350,6 @@ iD.modes.Select = function(context, selectedIDs) { }; mode.enter = function() { - context.save(); - behaviors.forEach(function(behavior) { context.install(behavior); }); @@ -19431,8 +19593,8 @@ iD.operations.Delete = function(selectedIDs, context) { } else if (i === nodes.length - 1) { i--; } else { - var a = iD.geo.dist(entity.loc, context.entity(nodes[i - 1]).loc), - b = iD.geo.dist(entity.loc, context.entity(nodes[i + 1]).loc); + var a = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc), + b = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc); i = a < b ? i - 1 : i + 1; } @@ -21636,23 +21798,26 @@ _.extend(iD.Way.prototype, { // of the following keys, and the value is _not_ one of the associated // values for the respective key. iD.Way.areaKeys = { + aeroway: { taxiway: true}, + amenity: {}, area: {}, + 'area:highway': {}, building: {}, - leisure: {}, - tourism: {}, - ruins: {}, + 'building:part': {}, historic: {}, landuse: {}, + leisure: {}, + man_made: { cutline: true, embankment: true, pipeline: true}, military: {}, natural: { coastline: true }, - amenity: {}, - shop: {}, - man_made: {}, - public_transport: {}, + office: {}, place: {}, - aeroway: {}, - waterway: {}, - power: {} + power: {}, + public_transport: {}, + ruins: {}, + shop: {}, + tourism: {}, + waterway: {} }; iD.Background = function(context) { var dispatch = d3.dispatch('change'), @@ -22750,7 +22915,7 @@ iD.svg = { b = [x, y]; if (a) { - var span = iD.geo.dist(a, b) - offset; + var span = iD.geo.euclideanDistance(a, b) - offset; if (span >= 0) { var angle = Math.atan2(b[1] - a[1], b[0] - a[0]), @@ -23468,7 +23633,7 @@ iD.svg.Midpoints = function(projection, context) { // If neither of the nodes changed, no need to redraw midpoint if (!midpoints[id] && (filter(a) || filter(b))) { var loc = iD.geo.interp(a.loc, b.loc, 0.5); - if (extent.intersects(loc) && iD.geo.dist(projection(a.loc), projection(b.loc)) > 40) { + if (extent.intersects(loc) && iD.geo.euclideanDistance(projection(a.loc), projection(b.loc)) > 40) { midpoints[id] = { type: 'midpoint', id: id, @@ -25097,7 +25262,7 @@ iD.ui.EntityEditor = function(context) { if (!arguments.length) return preset; if (_ !== preset) { preset = _; - reference = iD.ui.TagReference(preset.reference()) + reference = iD.ui.TagReference(preset.reference(context.geometry(id))) .showing(false); } return entityEditor; @@ -26477,7 +26642,7 @@ iD.ui.PresetList = function(context) { }; item.preset = preset; - item.reference = iD.ui.TagReference(preset.reference()); + item.reference = iD.ui.TagReference(preset.reference(context.geometry(id))); return item; } @@ -26787,7 +26952,7 @@ iD.ui.RawMembershipEditor = function(context) { graph = context.graph(); context.intersects(context.extent()).forEach(function(entity) { - if (entity.type !== 'relation') + if (entity.type !== 'relation' || entity.id === id) return; var presetName = context.presets().match(entity, graph).name(), @@ -27175,12 +27340,12 @@ iD.ui.Restore = function(context) { introModal.append('div') .attr('class', 'modal-section') .append('h3') - .text(t('restore.heading')); + .text(t('restore.heading')); introModal.append('div') .attr('class','modal-section') .append('p') - .text(t('restore.description')); + .text(t('restore.description')); var buttonWrap = introModal.append('div') .attr('class', 'modal-actions cf'); @@ -27203,8 +27368,6 @@ iD.ui.Restore = function(context) { restore.node().focus(); }; - modal.select('button.close').attr('class','hide'); - }; iD.ui.Save = function(context) { var history = context.history(), @@ -27877,7 +28040,6 @@ iD.ui.preset.access = function(field, context) { .attr('class', 'col6 preset-input-access-wrap') .append('input') .attr('type', 'text') - .attr('placeholder', field.placeholder()) .attr('class', 'preset-input-access') .attr('id', function(d) { return 'preset-input-access-' + d; }) .each(function(d) { @@ -27922,7 +28084,10 @@ iD.ui.preset.access = function(field, context) { access.tags = function(tags) { items.selectAll('.preset-input-access') - .value(function(d) { return tags[d] || ''; }); + .value(function(d) { return tags[d] || ''; }) + .attr('placeholder', function(d) { + return d !== 'access' && tags.access ? tags.access : field.placeholder(); + }); }; access.focus = function() { @@ -29651,14 +29816,17 @@ iD.presets.Preset = function(id, preset, fields) { return Object.keys(preset.tags).length === 0; }; - preset.reference = function() { - var reference = {key: Object.keys(preset.tags)[0]}; + preset.reference = function(geometry) { + var key = Object.keys(preset.tags)[0], + value = preset.tags[key]; - if (preset.tags[reference.key] !== '*') { - reference.value = preset.tags[reference.key]; + if (geometry === 'relation' && key === 'type') { + return { rtype: value }; + } else if (value === '*') { + return { key: key }; + } else { + return { key: key, value: value }; } - - return reference; }; var removeTags = preset.removeTags || preset.tags; @@ -58743,7 +58911,6 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081]," "icon": "shop", "fields": [ "address", - "building_area", "opening_hours" ], "geometry": [ @@ -72767,7 +72934,8 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081]," "annotation": { "line": "Squared the corners of a line.", "area": "Squared the corners of an area." - } + }, + "not_squarish": "This can't be made square because it is not squarish." }, "straighten": { "title": "Straighten",