]> git.openstreetmap.org Git - rails.git/blobdiff - vendor/assets/iD/iD.js
Merge remote-tracking branch 'osmlab/id-default'
[rails.git] / vendor / assets / iD / iD.js
index 3cb6da7cca5e96c53ba22e00a79845b122d13887..aeb16e7a4d968f7d6de52252bc37fe19447bbb40 100644 (file)
@@ -5725,6 +5725,10 @@ d3.combobox = function() {
                         position: 'absolute',
                         display: 'block',
                         left: '0px'
+                    })
+                    .on('mousedown', function () {
+                        // prevent moving focus out of the text field
+                        d3.event.preventDefault();
                     });
 
                 d3.select(document.body)
@@ -15024,12 +15028,19 @@ window.iD = function () {
     // https://github.com/systemed/iD/issues/772
     // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
     try { storage = localStorage; } catch (e) {}
-    storage = storage || {};
+    storage = storage || (function() {
+        var s = {};
+        return {
+            getItem: function(k) { return s[k]; },
+            setItem: function(k, v) { s[k] = v; },
+            removeItem: function(k) { delete s[k] }
+        };
+    })();
 
     context.storage = function(k, v) {
-        if (arguments.length === 1) return storage[k];
-        else if (v === null) delete storage[k];
-        else storage[k] = v;
+        if (arguments.length === 1) return storage.getItem(k);
+        else if (v === null) storage.removeItem(k);
+        else storage.setItem(k, v);
     };
 
     var history = iD.History(context),
@@ -15232,7 +15243,7 @@ window.iD = function () {
     return d3.rebind(context, dispatch, 'on');
 };
 
-iD.version = '1.1.0';
+iD.version = '1.1.4';
 
 (function() {
     var detected = {};
@@ -15323,7 +15334,7 @@ iD.taginfo = function() {
     }
 
     function popularValues() {
-        return function(d) { return parseFloat(d.fraction) > 0.01; };
+        return function(d) { return parseFloat(d.fraction) > 0.01 || d.in_wiki; };
     }
 
     function valKey(d) { return { value: d.key }; }
@@ -17324,9 +17335,12 @@ iD.behavior.Draw = function(context) {
 
     function draw(selection) {
         context.install(hover);
-        context.install(tail);
         context.install(edit);
 
+        if (!iD.behavior.Draw.usedTails[tail.text()]) {
+            context.install(tail);
+        }
+
         keybinding
             .on('⌫', backspace)
             .on('⌦', del)
@@ -17345,9 +17359,13 @@ iD.behavior.Draw = function(context) {
 
     draw.off = function(selection) {
         context.uninstall(hover);
-        context.uninstall(tail);
         context.uninstall(edit);
 
+        if (!iD.behavior.Draw.usedTails[tail.text()]) {
+            context.uninstall(tail);
+            iD.behavior.Draw.usedTails[tail.text()] = true;
+        }
+
         selection
             .on('mousedown.draw', null)
             .on('mousemove.draw', null);
@@ -17360,10 +17378,7 @@ iD.behavior.Draw = function(context) {
     };
 
     draw.tail = function(_) {
-        if (!_ || iD.behavior.Draw.usedTails[_] === undefined) {
-            tail.text(_);
-            iD.behavior.Draw.usedTails[_] = true;
-        }
+        tail.text(_);
         return draw;
     };
 
@@ -18204,12 +18219,16 @@ iD.modes.Browse = function(context) {
         iD.modes.DragNode(context).behavior];
 
     mode.enter = function() {
+        context.history().save();
+
         behaviors.forEach(function(behavior) {
             context.install(behavior);
         });
 
         // Get focus on the body.
-        document.activeElement.blur();
+        if (document.activeElement) {
+            document.activeElement.blur();
+        }
 
         if (sidebar) {
             context.ui().sidebar.show(sidebar);
@@ -18880,6 +18899,8 @@ iD.modes.Select = function(context, selectedIDs) {
     };
 
     mode.enter = function() {
+        context.history().save();
+
         behaviors.forEach(function(behavior) {
             context.install(behavior);
         });
@@ -19914,6 +19935,8 @@ iD.Entity = function(attrs) {
     // Create the appropriate subtype.
     if (attrs && attrs.type) {
         return iD.Entity[attrs.type].apply(this, arguments);
+    } else if (attrs && attrs.id) {
+        return iD.Entity[iD.Entity.id.type(attrs.id)].apply(this, arguments);
     }
 
     // Initialize a generic Entity (used only in tests).
@@ -19940,7 +19963,7 @@ iD.Entity.id.type = function(id) {
 
 // A function suitable for use as the second argument to d3.selection#data().
 iD.Entity.key = function(entity) {
-    return entity.id + ',' + entity.v;
+    return entity.id + 'v' + (entity.v || 0);
 };
 
 iD.Entity.areaPath = d3.geo.path()
@@ -20315,28 +20338,14 @@ iD.Graph.prototype = {
 
     // Obliterates any existing entities
     load: function(entities) {
-
-        var base = this.base(),
-            i, entity, prefix;
+        var base = this.base();
         this.entities = Object.create(base.entities);
 
-        for (i in entities) {
-            entity = entities[i];
-            prefix = i[0];
-
-            if (entity === 'undefined') {
-                this.entities[i] = undefined;
-            } else if (prefix == 'n') {
-                this.entities[i] = new iD.Node(entity);
-
-            } else if (prefix == 'w') {
-                this.entities[i] = new iD.Way(entity);
-
-            } else if (prefix == 'r') {
-                this.entities[i] = new iD.Relation(entity);
-            }
+        for (var i in entities) {
+            this.entities[i] = entities[i];
             this._updateCalculated(base.entities[i], this.entities[i]);
         }
+
         return this;
     }
 };
@@ -20529,33 +20538,85 @@ iD.History = function(context) {
         toJSON: function() {
             if (stack.length <= 1) return;
 
+            var allEntities = {};
+
             var s = stack.map(function(i) {
-                var x = { entities: i.graph.entities };
+                var modified = [], deleted = [];
+
+                _.forEach(i.graph.entities, function(entity, id) {
+                    if (entity) {
+                        var key = iD.Entity.key(entity);
+                        allEntities[key] = entity;
+                        modified.push(key);
+                    } else {
+                        deleted.push(id);
+                    }
+                });
+
+                var x = {};
+
+                if (modified.length) x.modified = modified;
+                if (deleted.length) x.deleted = deleted;
                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
                 if (i.annotation) x.annotation = i.annotation;
+
                 return x;
             });
 
             return JSON.stringify({
+                version: 2,
+                entities: _.values(allEntities),
                 stack: s,
                 nextIDs: iD.Entity.id.next,
                 index: index
-            }, function includeUndefined(key, value) {
-                if (typeof value === 'undefined') return 'undefined';
-                return value;
             });
         },
 
         fromJSON: function(json) {
-
             var h = JSON.parse(json);
 
             iD.Entity.id.next = h.nextIDs;
             index = h.index;
-            stack = h.stack.map(function(d) {
-                d.graph = iD.Graph(stack[0].graph).load(d.entities);
-                return d;
-            });
+
+            if (h.version === 2) {
+                var allEntities = {};
+
+                h.entities.forEach(function(entity) {
+                    allEntities[iD.Entity.key(entity)] = iD.Entity(entity);
+                });
+
+                stack = h.stack.map(function(d) {
+                    var entities = {}, entity;
+
+                    d.modified && d.modified.forEach(function(key) {
+                        entity = allEntities[key];
+                        entities[entity.id] = entity;
+                    });
+
+                    d.deleted && d.deleted.forEach(function(id) {
+                        entities[id] = undefined;
+                    });
+
+                    return {
+                        graph: iD.Graph(stack[0].graph).load(entities),
+                        annotation: d.annotation,
+                        imageryUsed: d.imageryUsed
+                    };
+                });
+            } else { // original version
+                stack = h.stack.map(function(d) {
+                    var entities = {};
+
+                    for (var i in d.entities) {
+                        var entity = d.entities[i];
+                        entities[i] = entity === 'undefined' ? undefined : iD.Entity(entity);
+                    }
+
+                    d.graph = iD.Graph(stack[0].graph).load(entities);
+                    return d;
+                });
+            }
+
             stack[0].graph.inherited = false;
             dispatch.change();
 
@@ -21669,7 +21730,6 @@ iD.Map = function(context) {
         map.dimensions(selection.dimensions());
 
         labels.supersurface(supersurface);
-        mouse = iD.util.fastMouse(supersurface.node());
     }
 
     function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
@@ -21899,6 +21959,7 @@ iD.Map = function(context) {
         surface.dimensions(dimensions);
         context.background().dimensions(dimensions);
         projection.clipExtent([[0, 0], dimensions]);
+        mouse = iD.util.fastMouse(supersurface.node());
         setCenter(center);
         return redraw();
     };
@@ -23676,7 +23737,7 @@ iD.ui.Background = function(context) {
             ['top', [0, -1]],
             ['right', [-1, 0]],
             ['bottom', [0, 1]]],
-        opacityDefault = (context.storage('background-opacity') !== undefined) ?
+        opacityDefault = (context.storage('background-opacity') != undefined) ?
             (+context.storage('background-opacity')) : 0.5;
 
     function background(selection) {
@@ -24443,6 +24504,7 @@ iD.ui.EntityEditor = function(context) {
                 .entityID(id));
 
         function historyChanged() {
+            if (state === 'hide') return;
             var entity = context.hasEntity(id);
             if (!entity) return;
             entityEditor.preset(context.presets().match(entity, context.graph()));
@@ -24510,9 +24572,10 @@ iD.ui.FeatureList = function(context) {
             .text(t('inspector.feature_list'));
 
         function keypress() {
-            var q = search.property('value');
-            if (d3.event.keyCode === 13 && q.length) {
-                click(list.selectAll('.feature-list-item:first-child').datum().entity);
+            var q = search.property('value'),
+                items = list.selectAll('.feature-list-item');
+            if (d3.event.keyCode === 13 && q.length && items.size()) {
+                click(items.datum().entity);
             }
         }
 
@@ -24985,6 +25048,7 @@ iD.ui.Inspector = function(context) {
     inspector.state = function(_) {
         if (!arguments.length) return state;
         state = _;
+        entityEditor.state(state);
         return inspector;
     };
 
@@ -25468,10 +25532,10 @@ iD.ui.preset = function(context) {
         var shown = fields.filter(function(field) { return field.shown(); }),
             notShown = fields.filter(function(field) { return !field.shown(); });
 
-        var $form = selection.selectAll('form')
+        var $form = selection.selectAll('.preset-form')
             .data([0]);
 
-        $form.enter().append('form')
+        $form.enter().append('div')
             .attr('class', 'preset-form inspector-inner fillL3');
 
         var $fields = $form.selectAll('.form-field')
@@ -25667,7 +25731,7 @@ iD.ui.PresetList = function(context) {
         var message = messagewrap.append('h3')
             .text(t('inspector.choose'));
 
-        if (currentPreset) {
+        if (context.entity(id).isUsed(context.graph())) {
             messagewrap.append('button')
                 .attr('class', 'preset-choose')
                 .on('click', function() { event.choose(currentPreset); })
@@ -25877,6 +25941,7 @@ iD.ui.PresetList = function(context) {
     presetList.entityID = function(_) {
         if (!arguments.length) return id;
         id = _;
+        presetList.preset(context.presets().match(context.entity(id), context.graph()));
         return presetList;
     };
 
@@ -25956,7 +26021,9 @@ iD.ui.RadialMenu = function(context, operations) {
             .attr('class', 'tooltip-inner radial-menu-tooltip');
 
         function mouseover(d, i) {
-            var rect = context.surface().node().getBoundingClientRect(),
+            // Avoid getBoundingClientRect on SVG element; browser implementations
+            // differ: http://stackoverflow.com/questions/18153989/
+            var rect = context.surface().node().parentNode.getBoundingClientRect(),
                 angle = a0 + i * a,
                 dx = rect.left - (angle < 0 ? 200 : 0),
                 dy = rect.top;
@@ -26669,6 +26736,7 @@ iD.ui.Sidebar = function(context) {
             } else if (!current) {
                 featureListWrap.classed('inspector-hidden', false);
                 inspectorWrap.classed('inspector-hidden', true);
+                inspector.state('hide');
             }
         };
 
@@ -26689,6 +26757,7 @@ iD.ui.Sidebar = function(context) {
             } else if (!current) {
                 featureListWrap.classed('inspector-hidden', false);
                 inspectorWrap.classed('inspector-hidden', true);
+                inspector.state('hide');
             }
         };
 
@@ -26874,21 +26943,24 @@ iD.ui.Success = function(context) {
             .on('click', function() { event.cancel(success) });
 
         header.append('h3')
-            .text(t('just_edited'));
+            .text(t('success.just_edited'));
 
         var body = selection.append('div')
             .attr('class', 'body save-success');
 
+        body.append('p')
+            .html(t('success.help_html'));
+
         body.append('a')
-            .attr('class', 'col12 osm')
+            .attr('class', 'button col12 osm')
             .attr('target', '_blank')
             .attr('href', function() {
                 return context.connection().changesetURL(changeset.id);
             })
-            .text(t('view_on_osm'));
+            .text(t('success.view_on_osm'));
 
         body.append('a')
-            .attr('class', 'col12 twitter')
+            .attr('class', 'button col12 twitter')
             .attr('target', '_blank')
             .attr('href', function() {
                 return 'https://twitter.com/intent/tweet?source=webclient&text=' +
@@ -26897,7 +26969,7 @@ iD.ui.Success = function(context) {
             .text(t('success.tweet'));
 
         body.append('a')
-            .attr('class', 'col12 facebook')
+            .attr('class', 'button col12 facebook')
             .attr('target', '_blank')
             .attr('href', function() {
                 return 'https://facebook.com/sharer/sharer.php?u=' +
@@ -27098,7 +27170,9 @@ iD.ui.UndoRedo = function(context) {
             .placement('bottom')
             .html(true)
             .title(function (d) {
-                return iD.ui.tooltipHtml(d.annotation() || t('nothing_to_' + d.id), d.cmd);
+                return iD.ui.tooltipHtml(d.annotation() ?
+                    t(d.id + '.tooltip', {action: d.annotation()}) :
+                    t(d.id + '.nothing'), d.cmd);
             });
 
         var buttons = selection.selectAll('button')
@@ -27477,7 +27551,11 @@ iD.ui.preset.combo = function(field) {
 
         input.enter().append('input')
             .attr('type', 'text')
-            .attr('id', 'preset-input-' + field.id)
+            .attr('id', 'preset-input-' + field.id);
+
+        input
+            .on('change', change)
+            .on('blur', change)
             .each(function() {
                 if (field.options) {
                     options(field.options);
@@ -27488,11 +27566,7 @@ iD.ui.preset.combo = function(field) {
                         if (!err) options(_.pluck(data, 'value'));
                     });
                 }
-            });
-
-        input
-            .on('change', change)
-            .on('blur', change)
+            })
             .call(combobox);
 
         function options(opts) {
@@ -27686,7 +27760,9 @@ iD.ui.preset.localized = function(field, context) {
 
         if (language) value = language[2];
 
-        t[key(d.lang)] = '';
+        if (d.lang) {
+            t[key(d.lang)] = '';
+        }
 
         if (d.value) {
             t[key(value)] = d.value;
@@ -32475,7 +32551,9 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
             },
             "area": {
                 "name": "Area",
-                "tags": {},
+                "tags": {
+                    "area": "yes"
+                },
                 "geometry": [
                     "area"
                 ]
@@ -32826,6 +32904,19 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                 },
                 "name": "Ambulance Station"
             },
+            "emergency/fire_hydrant": {
+                "fields": [
+                    "fire_hydrant/type"
+                ],
+                "geometry": [
+                    "point",
+                    "vertex"
+                ],
+                "tags": {
+                    "emergency": "fire_hydrant"
+                },
+                "name": "Fire Hydrant"
+            },
             "emergency/phone": {
                 "icon": "emergency-telephone",
                 "fields": [
@@ -34048,6 +34139,21 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                 "icon": "swimming",
                 "name": "Swimming Pool"
             },
+            "leisure/track": {
+                "icon": "pitch",
+                "fields": [
+                    "surface"
+                ],
+                "geometry": [
+                    "point",
+                    "line",
+                    "area"
+                ],
+                "tags": {
+                    "leisure": "track"
+                },
+                "name": "Race Track"
+            },
             "line": {
                 "name": "Line",
                 "tags": {},
@@ -34587,6 +34693,7 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                 "name": "Power"
             },
             "power/generator": {
+                "name": "Power Generator",
                 "geometry": [
                     "point",
                     "vertex",
@@ -34595,7 +34702,11 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                 "tags": {
                     "power": "generator"
                 },
-                "name": "Power Plant"
+                "fields": [
+                    "generator/source",
+                    "generator/method",
+                    "generator/type"
+                ]
             },
             "power/line": {
                 "geometry": [
@@ -36821,11 +36932,37 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                 "type": "check",
                 "label": "Fee"
             },
+            "fire_hydrant/type": {
+                "key": "fire_hydrant:type",
+                "type": "combo",
+                "options": [
+                    "pillar",
+                    "pond",
+                    "underground",
+                    "wall"
+                ],
+                "label": "Type"
+            },
             "fixme": {
                 "key": "fixme",
                 "type": "textarea",
                 "label": "Fix Me"
             },
+            "generator/method": {
+                "key": "generator:method",
+                "type": "combo",
+                "label": "Method"
+            },
+            "generator/source": {
+                "key": "generator:source",
+                "type": "combo",
+                "label": "Source"
+            },
+            "generator/type": {
+                "key": "generator:type",
+                "type": "combo",
+                "label": "Type"
+            },
             "highway": {
                 "key": "highway",
                 "type": "combo",
@@ -48804,6 +48941,7 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
         "fi",
         "fr",
         "de",
+        "el",
         "hu",
         "is",
         "id",
@@ -48996,12 +49134,16 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                 "multiple_ways": "There are too many lines here to split."
             }
         },
-        "nothing_to_undo": "Nothing to undo.",
-        "nothing_to_redo": "Nothing to redo.",
+        "undo": {
+            "tooltip": "Undo: {action}",
+            "nothing": "Nothing to undo."
+        },
+        "redo": {
+            "tooltip": "Redo: {action}",
+            "nothing": "Nothing to redo."
+        },
         "tooltip_keyhint": "Shortcut:",
-        "just_edited": "You just edited OpenStreetMap!",
         "browser_notice": "This editor is supported in Firefox, Chrome, Safari, Opera, and Internet Explorer 9 and above. Please upgrade your browser or use Potlatch 2 to edit the map.",
-        "view_on_osm": "View on OSM",
         "translate": {
             "translate": "Translate",
             "localized_translation_label": "Multilingual name",
@@ -49086,9 +49228,11 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
         },
         "success": {
             "edited_osm": "Edited OSM!",
+            "just_edited": "You just edited OpenStreetMap!",
+            "view_on_osm": "View on OSM",
             "facebook": "Share on Facebook",
             "tweet": "Tweet",
-            "okay": "Okay"
+            "help_html": "Your changes should appear in the \"Standard\" layer in a few minutes. Other layers, and certain features, may take longer\n(<a href='https://help.openstreetmap.org/questions/4705/why-havent-my-changes-appeared-on-the-map'>details</a>).\n"
         },
         "confirm": {
             "okay": "Okay"
@@ -49344,9 +49488,21 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                 "fee": {
                     "label": "Fee"
                 },
+                "fire_hydrant/type": {
+                    "label": "Type"
+                },
                 "fixme": {
                     "label": "Fix Me"
                 },
+                "generator/method": {
+                    "label": "Method"
+                },
+                "generator/source": {
+                    "label": "Source"
+                },
+                "generator/type": {
+                    "label": "Type"
+                },
                 "highway": {
                     "label": "Type"
                 },
@@ -49887,6 +50043,10 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                     "name": "Ambulance Station",
                     "terms": ""
                 },
+                "emergency/fire_hydrant": {
+                    "name": "Fire Hydrant",
+                    "terms": ""
+                },
                 "emergency/phone": {
                     "name": "Emergency Phone",
                     "terms": ""
@@ -50203,6 +50363,10 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                     "name": "Swimming Pool",
                     "terms": ""
                 },
+                "leisure/track": {
+                    "name": "Race Track",
+                    "terms": ""
+                },
                 "line": {
                     "name": "Line",
                     "terms": ""
@@ -50372,7 +50536,7 @@ iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081],"
                     "terms": ""
                 },
                 "power/generator": {
-                    "name": "Power Plant",
+                    "name": "Power Generator",
                     "terms": ""
                 },
                 "power/line": {