+ }
+ if (cache.rtree) {
+ cache.rtree.load(features);
+ }
+ }
+ if (vectorTile.layers.hasOwnProperty("traffic_sign")) {
+ features = [];
+ cache = _mlyCache[which];
+ layer = vectorTile.layers.traffic_sign;
+ for (i2 = 0; i2 < layer.length; i2++) {
+ feature3 = layer.feature(i2).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+ loc = feature3.geometry.coordinates;
+ d = {
+ loc,
+ id: feature3.properties.id,
+ first_seen_at: feature3.properties.first_seen_at,
+ last_seen_at: feature3.properties.last_seen_at,
+ value: feature3.properties.value
+ };
+ features.push({
+ minX: loc[0],
+ minY: loc[1],
+ maxX: loc[0],
+ maxY: loc[1],
+ data: d
+ });
+ }
+ if (cache.rtree) {
+ cache.rtree.load(features);
+ }
+ }
+ }
+ function loadData(url) {
+ return fetch(url).then(function(response) {
+ if (!response.ok) {
+ throw new Error(response.status + " " + response.statusText);
+ }
+ return response.json();
+ }).then(function(result) {
+ if (!result) {
+ return [];
+ }
+ return result.data || [];
+ });
+ }
+ function partitionViewport(projection2) {
+ const z = geoScaleToZoom(projection2.scale());
+ const z2 = Math.ceil(z * 2) / 2 + 2.5;
+ const tiler8 = utilTiler().zoomExtent([z2, z2]);
+ return tiler8.getTiles(projection2).map(function(tile) {
+ return tile.extent;
+ });
+ }
+ function searchLimited(limit, projection2, rtree) {
+ limit = limit || 5;
+ return partitionViewport(projection2).reduce(function(result, extent) {
+ const found = rtree.search(extent.bbox()).slice(0, limit).map(function(d) {
+ return d.data;
+ });
+ return found.length ? result.concat(found) : result;
+ }, []);
+ }
+ var mapillary_default = {
+ // Initialize Mapillary
+ init: function() {
+ if (!_mlyCache) {
+ this.reset();
+ }
+ this.event = utilRebind(this, dispatch5, "on");
+ },
+ // Reset cache and state
+ reset: function() {
+ if (_mlyCache) {
+ Object.values(_mlyCache.requests.inflight).forEach(function(request3) {
+ request3.abort();
+ });
+ }
+ _mlyCache = {
+ images: { rtree: new import_rbush4.default(), forImageId: {} },
+ image_detections: { forImageId: {} },
+ signs: { rtree: new import_rbush4.default() },
+ points: { rtree: new import_rbush4.default() },
+ sequences: { rtree: new import_rbush4.default(), lineString: {} },
+ requests: { loaded: {}, inflight: {} }
+ };
+ _mlyActiveImage = null;
+ },
+ // Get visible images
+ images: function(projection2) {
+ const limit = 5;
+ return searchLimited(limit, projection2, _mlyCache.images.rtree);
+ },
+ // Get visible traffic signs
+ signs: function(projection2) {
+ const limit = 5;
+ return searchLimited(limit, projection2, _mlyCache.signs.rtree);
+ },
+ // Get visible map (point) features
+ mapFeatures: function(projection2) {
+ const limit = 5;
+ return searchLimited(limit, projection2, _mlyCache.points.rtree);
+ },
+ // Get cached image by id
+ cachedImage: function(imageId) {
+ return _mlyCache.images.forImageId[imageId];
+ },
+ // Get visible sequences
+ sequences: function(projection2) {
+ const viewport = projection2.clipExtent();
+ const min3 = [viewport[0][0], viewport[1][1]];
+ const max3 = [viewport[1][0], viewport[0][1]];
+ const bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
+ const sequenceIds = {};
+ let lineStrings = [];
+ _mlyCache.images.rtree.search(bbox2).forEach(function(d) {
+ if (d.data.sequence_id) {
+ sequenceIds[d.data.sequence_id] = true;
+ }
+ });
+ Object.keys(sequenceIds).forEach(function(sequenceId) {
+ if (_mlyCache.sequences.lineString[sequenceId]) {
+ lineStrings = lineStrings.concat(_mlyCache.sequences.lineString[sequenceId]);
+ }
+ });
+ return lineStrings;
+ },
+ // Load images in the visible area
+ loadImages: function(projection2) {
+ loadTiles("images", tileUrl, 14, projection2);
+ },
+ // Load traffic signs in the visible area
+ loadSigns: function(projection2) {
+ loadTiles("signs", trafficSignTileUrl, 14, projection2);
+ },
+ // Load map (point) features in the visible area
+ loadMapFeatures: function(projection2) {
+ loadTiles("points", mapFeatureTileUrl, 14, projection2);
+ },
+ // Return a promise that resolves when the image viewer (Mapillary JS) library has finished loading
+ ensureViewerLoaded: function(context) {
+ if (_loadViewerPromise)
+ return _loadViewerPromise;
+ const wrap2 = context.container().select(".photoviewer").selectAll(".mly-wrapper").data([0]);
+ wrap2.enter().append("div").attr("id", "ideditor-mly").attr("class", "photo-wrapper mly-wrapper").classed("hide", true);
+ const that = this;
+ _loadViewerPromise = new Promise((resolve, reject) => {
+ let loadedCount = 0;
+ function loaded() {
+ loadedCount += 1;
+ if (loadedCount === 2)
+ resolve();
+ }
+ const head = select_default2("head");
+ head.selectAll("#ideditor-mapillary-viewercss").data([0]).enter().append("link").attr("id", "ideditor-mapillary-viewercss").attr("rel", "stylesheet").attr("crossorigin", "anonymous").attr("href", context.asset(viewercss)).on("load.serviceMapillary", loaded).on("error.serviceMapillary", function() {
+ reject();
+ });
+ head.selectAll("#ideditor-mapillary-viewerjs").data([0]).enter().append("script").attr("id", "ideditor-mapillary-viewerjs").attr("crossorigin", "anonymous").attr("src", context.asset(viewerjs)).on("load.serviceMapillary", loaded).on("error.serviceMapillary", function() {
+ reject();
+ });
+ }).catch(function() {
+ _loadViewerPromise = null;
+ }).then(function() {
+ that.initViewer(context);
+ });
+ return _loadViewerPromise;
+ },
+ // Load traffic sign image sprites
+ loadSignResources: function(context) {
+ context.ui().svgDefs.addSprites(
+ ["mapillary-sprite"],
+ false
+ /* don't override colors */
+ );
+ return this;
+ },
+ // Load map (point) feature image sprites
+ loadObjectResources: function(context) {
+ context.ui().svgDefs.addSprites(
+ ["mapillary-object-sprite"],
+ false
+ /* don't override colors */
+ );
+ return this;
+ },
+ // Remove previous detections in image viewer
+ resetTags: function() {
+ if (_mlyViewer && !_mlyFallback) {
+ _mlyViewer.getComponent("tag").removeAll();
+ }
+ },
+ // Show map feature detections in image viewer
+ showFeatureDetections: function(value) {
+ _mlyShowFeatureDetections = value;
+ if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
+ this.resetTags();
+ }
+ },
+ // Show traffic sign detections in image viewer
+ showSignDetections: function(value) {
+ _mlyShowSignDetections = value;
+ if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
+ this.resetTags();
+ }
+ },
+ // Apply filter to image viewer
+ filterViewer: function(context) {
+ const showsPano = context.photos().showsPanoramic();
+ const showsFlat = context.photos().showsFlat();
+ const fromDate = context.photos().fromDate();
+ const toDate = context.photos().toDate();
+ const filter2 = ["all"];
+ if (!showsPano)
+ filter2.push(["!=", "cameraType", "spherical"]);
+ if (!showsFlat && showsPano)
+ filter2.push(["==", "pano", true]);
+ if (fromDate) {
+ filter2.push([">=", "capturedAt", new Date(fromDate).getTime()]);
+ }
+ if (toDate) {
+ filter2.push([">=", "capturedAt", new Date(toDate).getTime()]);
+ }
+ if (_mlyViewer) {
+ _mlyViewer.setFilter(filter2);
+ }
+ _mlyViewerFilter = filter2;
+ return filter2;
+ },
+ // Make the image viewer visible
+ showViewer: function(context) {
+ const wrap2 = context.container().select(".photoviewer").classed("hide", false);
+ const isHidden = wrap2.selectAll(".photo-wrapper.mly-wrapper.hide").size();
+ if (isHidden && _mlyViewer) {
+ wrap2.selectAll(".photo-wrapper:not(.mly-wrapper)").classed("hide", true);
+ wrap2.selectAll(".photo-wrapper.mly-wrapper").classed("hide", false);
+ _mlyViewer.resize();
+ }
+ return this;
+ },
+ // Hide the image viewer and resets map markers
+ hideViewer: function(context) {
+ _mlyActiveImage = null;
+ if (!_mlyFallback && _mlyViewer) {
+ _mlyViewer.getComponent("sequence").stop();
+ }
+ const viewer = context.container().select(".photoviewer");
+ if (!viewer.empty())
+ viewer.datum(null);
+ viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
+ this.updateUrlImage(null);
+ dispatch5.call("imageChanged");
+ dispatch5.call("loadedMapFeatures");
+ dispatch5.call("loadedSigns");
+ return this.setStyles(context, null);
+ },
+ // Update the URL with current image id
+ updateUrlImage: function(imageId) {
+ if (!window.mocha) {
+ const hash = utilStringQs(window.location.hash);
+ if (imageId) {
+ hash.photo = "mapillary/" + imageId;
+ } else {
+ delete hash.photo;
+ }
+ window.location.replace("#" + utilQsString(hash, true));
+ }
+ },
+ // Highlight the detection in the viewer that is related to the clicked map feature
+ highlightDetection: function(detection) {
+ if (detection) {
+ _mlyHighlightedDetection = detection.id;
+ }
+ return this;
+ },
+ // Initialize image viewer (Mapillar JS)
+ initViewer: function(context) {
+ const that = this;
+ if (!window.mapillary)
+ return;
+ const opts = {
+ accessToken,
+ component: {
+ cover: false,
+ keyboard: false,
+ tag: true
+ },
+ container: "ideditor-mly"
+ };
+ if (!mapillary.isSupported() && mapillary.isFallbackSupported()) {
+ _mlyFallback = true;
+ opts.component = {
+ cover: false,
+ direction: false,
+ imagePlane: false,
+ keyboard: false,
+ mouse: false,
+ sequence: false,
+ tag: false,
+ image: true,
+ // fallback
+ navigation: true
+ // fallback
+ };
+ }
+ _mlyViewer = new mapillary.Viewer(opts);
+ _mlyViewer.on("image", imageChanged);
+ _mlyViewer.on("bearing", bearingChanged);
+ if (_mlyViewerFilter) {
+ _mlyViewer.setFilter(_mlyViewerFilter);
+ }
+ context.ui().photoviewer.on("resize.mapillary", function() {
+ if (_mlyViewer)
+ _mlyViewer.resize();
+ });
+ function imageChanged(node) {
+ that.resetTags();
+ const image = node.image;
+ that.setActiveImage(image);
+ that.setStyles(context, null);
+ const loc = [image.originalLngLat.lng, image.originalLngLat.lat];
+ context.map().centerEase(loc);
+ that.updateUrlImage(image.id);
+ if (_mlyShowFeatureDetections || _mlyShowSignDetections) {
+ that.updateDetections(image.id, `${apiUrl}/${image.id}/detections?access_token=${accessToken}&fields=id,image,geometry,value`);
+ }
+ dispatch5.call("imageChanged");
+ }
+ function bearingChanged(e) {
+ dispatch5.call("bearingChanged", void 0, e);
+ }
+ },
+ // Move to an image
+ selectImage: function(context, imageId) {
+ if (_mlyViewer && imageId) {
+ _mlyViewer.moveTo(imageId).catch(function(e) {
+ console.error("mly3", e);
+ });
+ }
+ return this;
+ },
+ // Return the currently displayed image
+ getActiveImage: function() {
+ return _mlyActiveImage;
+ },
+ // Return a list of detection objects for the given id
+ getDetections: function(id2) {
+ return loadData(`${apiUrl}/${id2}/detections?access_token=${accessToken}&fields=id,value,image`);
+ },
+ // Set the currently visible image
+ setActiveImage: function(image) {
+ if (image) {
+ _mlyActiveImage = {
+ ca: image.originalCompassAngle,
+ id: image.id,
+ loc: [image.originalLngLat.lng, image.originalLngLat.lat],
+ is_pano: image.cameraType === "spherical",
+ sequence_id: image.sequenceId
+ };
+ } else {
+ _mlyActiveImage = null;
+ }
+ },
+ // Update the currently highlighted sequence and selected bubble.
+ setStyles: function(context, hovered) {
+ const hoveredImageId = hovered && hovered.id;
+ const hoveredSequenceId = hovered && hovered.sequence_id;
+ const selectedSequenceId = _mlyActiveImage && _mlyActiveImage.sequence_id;
+ context.container().selectAll(".layer-mapillary .viewfield-group").classed("highlighted", function(d) {
+ return d.sequence_id === selectedSequenceId || d.id === hoveredImageId;
+ }).classed("hovered", function(d) {
+ return d.id === hoveredImageId;
+ });
+ context.container().selectAll(".layer-mapillary .sequence").classed("highlighted", function(d) {
+ return d.properties.id === hoveredSequenceId;
+ }).classed("currentView", function(d) {
+ return d.properties.id === selectedSequenceId;
+ });
+ return this;
+ },
+ // Get detections for the current image and shows them in the image viewer
+ updateDetections: function(imageId, url) {
+ if (!_mlyViewer || _mlyFallback)
+ return;
+ if (!imageId)
+ return;
+ const cache = _mlyCache.image_detections;
+ if (cache.forImageId[imageId]) {
+ showDetections(_mlyCache.image_detections.forImageId[imageId]);
+ } else {
+ loadData(url).then((detections) => {
+ detections.forEach(function(detection) {
+ if (!cache.forImageId[imageId]) {
+ cache.forImageId[imageId] = [];
+ }
+ cache.forImageId[imageId].push({
+ geometry: detection.geometry,
+ id: detection.id,
+ image_id: imageId,
+ value: detection.value
+ });
+ });
+ showDetections(_mlyCache.image_detections.forImageId[imageId] || []);
+ });
+ }
+ function showDetections(detections) {
+ const tagComponent = _mlyViewer.getComponent("tag");
+ detections.forEach(function(data) {
+ const tag = makeTag(data);
+ if (tag) {
+ tagComponent.add([tag]);
+ }
+ });
+ }
+ function makeTag(data) {
+ const valueParts = data.value.split("--");
+ if (!valueParts.length)
+ return;
+ let tag;
+ let text2;
+ let color2 = 16777215;
+ if (_mlyHighlightedDetection === data.id) {
+ color2 = 16776960;
+ text2 = valueParts[1];
+ if (text2 === "flat" || text2 === "discrete" || text2 === "sign") {
+ text2 = valueParts[2];
+ }
+ text2 = text2.replace(/-/g, " ");
+ text2 = text2.charAt(0).toUpperCase() + text2.slice(1);
+ _mlyHighlightedDetection = null;
+ }
+ var decodedGeometry = window.atob(data.geometry);
+ var uintArray = new Uint8Array(decodedGeometry.length);
+ for (var i2 = 0; i2 < decodedGeometry.length; i2++) {
+ uintArray[i2] = decodedGeometry.charCodeAt(i2);
+ }
+ const tile = new import_vector_tile.VectorTile(new import_pbf.default(uintArray.buffer));
+ const layer = tile.layers["mpy-or"];
+ const geometries = layer.feature(0).loadGeometry();
+ const polygon2 = geometries.map((ring) => ring.map((point2) => [point2.x / layer.extent, point2.y / layer.extent]));
+ tag = new mapillary.OutlineTag(
+ data.id,
+ new mapillary.PolygonGeometry(polygon2[0]),
+ {
+ text: text2,
+ textColor: color2,
+ lineColor: color2,
+ lineWidth: 2,
+ fillColor: color2,
+ fillOpacity: 0.3
+ }
+ );
+ return tag;
+ }
+ },
+ // Return the current cache
+ cache: function() {
+ return _mlyCache;
+ }
+ };
+
+ // modules/core/validation/models.js
+ function validationIssue(attrs) {
+ this.type = attrs.type;
+ this.subtype = attrs.subtype;
+ this.severity = attrs.severity;
+ this.message = attrs.message;
+ this.reference = attrs.reference;
+ this.entityIds = attrs.entityIds;
+ this.loc = attrs.loc;
+ this.data = attrs.data;
+ this.dynamicFixes = attrs.dynamicFixes;
+ this.hash = attrs.hash;
+ this.id = generateID.apply(this);
+ this.key = generateKey.apply(this);
+ this.autoFix = null;
+ function generateID() {
+ var parts = [this.type];
+ if (this.hash) {
+ parts.push(this.hash);
+ }
+ if (this.subtype) {
+ parts.push(this.subtype);
+ }
+ if (this.entityIds) {
+ var entityKeys = this.entityIds.slice().sort();
+ parts.push.apply(parts, entityKeys);
+ }
+ return parts.join(":");
+ }
+ function generateKey() {
+ return this.id + ":" + Date.now().toString();
+ }
+ this.extent = function(resolver) {
+ if (this.loc) {
+ return geoExtent(this.loc);
+ }
+ if (this.entityIds && this.entityIds.length) {
+ return this.entityIds.reduce(function(extent, entityId) {
+ return extent.extend(resolver.entity(entityId).extent(resolver));
+ }, geoExtent());
+ }
+ return null;
+ };
+ this.fixes = function(context) {
+ var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
+ var issue = this;
+ if (issue.severity === "warning") {
+ fixes.push(new validationIssueFix({
+ title: _t.append("issues.fix.ignore_issue.title"),
+ icon: "iD-icon-close",
+ onClick: function() {
+ context.validator().ignoreIssue(this.issue.id);
+ }
+ }));
+ }
+ fixes.forEach(function(fix) {
+ fix.id = fix.title.stringId;
+ fix.issue = issue;
+ if (fix.autoArgs) {
+ issue.autoFix = fix;
+ }
+ });
+ return fixes;
+ };
+ }
+ function validationIssueFix(attrs) {
+ this.title = attrs.title;
+ this.onClick = attrs.onClick;
+ this.disabledReason = attrs.disabledReason;
+ this.icon = attrs.icon;
+ this.entityIds = attrs.entityIds || [];
+ this.autoArgs = attrs.autoArgs;
+ this.issue = null;
+ }
+
+ // modules/services/maprules.js
+ var buildRuleChecks = function() {
+ return {
+ equals: function(equals) {
+ return function(tags) {
+ return Object.keys(equals).every(function(k) {
+ return equals[k] === tags[k];
+ });
+ };
+ },
+ notEquals: function(notEquals) {
+ return function(tags) {
+ return Object.keys(notEquals).some(function(k) {
+ return notEquals[k] !== tags[k];
+ });
+ };
+ },
+ absence: function(absence) {
+ return function(tags) {
+ return Object.keys(tags).indexOf(absence) === -1;
+ };
+ },
+ presence: function(presence) {
+ return function(tags) {
+ return Object.keys(tags).indexOf(presence) > -1;
+ };
+ },
+ greaterThan: function(greaterThan) {
+ var key = Object.keys(greaterThan)[0];
+ var value = greaterThan[key];
+ return function(tags) {
+ return tags[key] > value;
+ };
+ },
+ greaterThanEqual: function(greaterThanEqual) {
+ var key = Object.keys(greaterThanEqual)[0];
+ var value = greaterThanEqual[key];
+ return function(tags) {
+ return tags[key] >= value;
+ };
+ },
+ lessThan: function(lessThan) {
+ var key = Object.keys(lessThan)[0];
+ var value = lessThan[key];
+ return function(tags) {
+ return tags[key] < value;
+ };
+ },
+ lessThanEqual: function(lessThanEqual) {
+ var key = Object.keys(lessThanEqual)[0];
+ var value = lessThanEqual[key];
+ return function(tags) {
+ return tags[key] <= value;
+ };
+ },
+ positiveRegex: function(positiveRegex) {
+ var tagKey = Object.keys(positiveRegex)[0];
+ var expression = positiveRegex[tagKey].join("|");
+ var regex = new RegExp(expression);
+ return function(tags) {
+ return regex.test(tags[tagKey]);
+ };
+ },
+ negativeRegex: function(negativeRegex) {
+ var tagKey = Object.keys(negativeRegex)[0];
+ var expression = negativeRegex[tagKey].join("|");
+ var regex = new RegExp(expression);
+ return function(tags) {
+ return !regex.test(tags[tagKey]);
+ };
+ }
+ };
+ };
+ var buildLineKeys = function() {
+ return {
+ highway: {
+ rest_area: true,
+ services: true
+ },
+ railway: {
+ roundhouse: true,
+ station: true,
+ traverser: true,
+ turntable: true,
+ wash: true
+ }
+ };
+ };
+ var maprules_default = {
+ init: function() {
+ this._ruleChecks = buildRuleChecks();
+ this._validationRules = [];
+ this._areaKeys = osmAreaKeys;
+ this._lineKeys = buildLineKeys();
+ },
+ // list of rules only relevant to tag checks...
+ filterRuleChecks: function(selector) {
+ var _ruleChecks = this._ruleChecks;
+ return Object.keys(selector).reduce(function(rules, key) {
+ if (["geometry", "error", "warning"].indexOf(key) === -1) {
+ rules.push(_ruleChecks[key](selector[key]));
+ }
+ return rules;
+ }, []);
+ },
+ // builds tagMap from mapcss-parse selector object...
+ buildTagMap: function(selector) {
+ var getRegexValues = function(regexes) {
+ return regexes.map(function(regex) {
+ return regex.replace(/\$|\^/g, "");
+ });
+ };
+ var tagMap = Object.keys(selector).reduce(function(expectedTags, key) {
+ var values;
+ var isRegex = /regex/gi.test(key);
+ var isEqual4 = /equals/gi.test(key);
+ if (isRegex || isEqual4) {
+ Object.keys(selector[key]).forEach(function(selectorKey) {
+ values = isEqual4 ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
+ if (expectedTags.hasOwnProperty(selectorKey)) {
+ values = values.concat(expectedTags[selectorKey]);
+ }
+ expectedTags[selectorKey] = values;
+ });
+ } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
+ var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
+ values = [selector[key][tagKey]];
+ if (expectedTags.hasOwnProperty(tagKey)) {
+ values = values.concat(expectedTags[tagKey]);
+ }
+ expectedTags[tagKey] = values;
+ }
+ return expectedTags;
+ }, {});
+ return tagMap;
+ },
+ // inspired by osmWay#isArea()
+ inferGeometry: function(tagMap) {
+ var _lineKeys = this._lineKeys;
+ var _areaKeys = this._areaKeys;
+ var keyValueDoesNotImplyArea = function(key2) {
+ return utilArrayIntersection(tagMap[key2], Object.keys(_areaKeys[key2])).length > 0;
+ };
+ var keyValueImpliesLine = function(key2) {
+ return utilArrayIntersection(tagMap[key2], Object.keys(_lineKeys[key2])).length > 0;
+ };
+ if (tagMap.hasOwnProperty("area")) {
+ if (tagMap.area.indexOf("yes") > -1) {
+ return "area";
+ }
+ if (tagMap.area.indexOf("no") > -1) {
+ return "line";
+ }
+ }
+ for (var key in tagMap) {
+ if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
+ return "area";
+ }
+ if (key in _lineKeys && keyValueImpliesLine(key)) {
+ return "area";
+ }
+ }
+ return "line";
+ },
+ // adds from mapcss-parse selector check...
+ addRule: function(selector) {
+ var rule = {
+ // checks relevant to mapcss-selector
+ checks: this.filterRuleChecks(selector),
+ // true if all conditions for a tag error are true..
+ matches: function(entity) {
+ return this.checks.every(function(check) {
+ return check(entity.tags);
+ });
+ },
+ // borrowed from Way#isArea()
+ inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
+ geometryMatches: function(entity, graph) {
+ if (entity.type === "node" || entity.type === "relation") {
+ return selector.geometry === entity.type;
+ } else if (entity.type === "way") {
+ return this.inferredGeometry === entity.geometry(graph);
+ }
+ },
+ // when geometries match and tag matches are present, return a warning...
+ findIssues: function(entity, graph, issues) {
+ if (this.geometryMatches(entity, graph) && this.matches(entity)) {
+ var severity = Object.keys(selector).indexOf("error") > -1 ? "error" : "warning";
+ var message = selector[severity];
+ issues.push(new validationIssue({
+ type: "maprules",
+ severity,
+ message: function() {
+ return message;
+ },
+ entityIds: [entity.id]
+ }));
+ }
+ }
+ };
+ this._validationRules.push(rule);
+ },
+ clearRules: function() {
+ this._validationRules = [];
+ },
+ // returns validationRules...
+ validationRules: function() {
+ return this._validationRules;
+ },
+ // returns ruleChecks
+ ruleChecks: function() {
+ return this._ruleChecks;
+ }
+ };
+
+ // modules/services/nominatim.js
+ var import_rbush7 = __toESM(require_rbush_min());
+
+ // modules/core/difference.js
+ var import_fast_deep_equal3 = __toESM(require_fast_deep_equal());
+ function coreDifference(base, head) {
+ var _changes = {};
+ var _didChange = {};
+ var _diff = {};
+ function checkEntityID(id2) {
+ var h = head.entities[id2];
+ var b = base.entities[id2];
+ if (h === b)
+ return;
+ if (_changes[id2])
+ return;
+ if (!h && b) {
+ _changes[id2] = { base: b, head: h };
+ _didChange.deletion = true;
+ return;
+ }
+ if (h && !b) {
+ _changes[id2] = { base: b, head: h };
+ _didChange.addition = true;
+ return;
+ }
+ if (h && b) {
+ if (h.members && b.members && !(0, import_fast_deep_equal3.default)(h.members, b.members)) {
+ _changes[id2] = { base: b, head: h };
+ _didChange.geometry = true;
+ _didChange.properties = true;
+ return;
+ }
+ if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
+ _changes[id2] = { base: b, head: h };
+ _didChange.geometry = true;
+ }
+ if (h.nodes && b.nodes && !(0, import_fast_deep_equal3.default)(h.nodes, b.nodes)) {
+ _changes[id2] = { base: b, head: h };
+ _didChange.geometry = true;
+ }
+ if (h.tags && b.tags && !(0, import_fast_deep_equal3.default)(h.tags, b.tags)) {
+ _changes[id2] = { base: b, head: h };
+ _didChange.properties = true;
+ }
+ }
+ }
+ function load() {
+ var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
+ for (var i2 = 0; i2 < ids.length; i2++) {
+ checkEntityID(ids[i2]);
+ }
+ }
+ load();
+ _diff.length = function length() {
+ return Object.keys(_changes).length;
+ };
+ _diff.changes = function changes() {
+ return _changes;
+ };
+ _diff.didChange = _didChange;
+ _diff.extantIDs = function extantIDs(includeRelMembers) {
+ var result = /* @__PURE__ */ new Set();
+ Object.keys(_changes).forEach(function(id2) {
+ if (_changes[id2].head) {
+ result.add(id2);
+ }
+ var h = _changes[id2].head;
+ var b = _changes[id2].base;
+ var entity = h || b;
+ if (includeRelMembers && entity.type === "relation") {
+ var mh = h ? h.members.map(function(m) {
+ return m.id;
+ }) : [];
+ var mb = b ? b.members.map(function(m) {
+ return m.id;
+ }) : [];
+ utilArrayUnion(mh, mb).forEach(function(memberID) {
+ if (head.hasEntity(memberID)) {
+ result.add(memberID);
+ }
+ });
+ }
+ });
+ return Array.from(result);
+ };
+ _diff.modified = function modified() {
+ var result = [];
+ Object.values(_changes).forEach(function(change) {
+ if (change.base && change.head) {
+ result.push(change.head);
+ }
+ });
+ return result;
+ };
+ _diff.created = function created() {
+ var result = [];
+ Object.values(_changes).forEach(function(change) {
+ if (!change.base && change.head) {
+ result.push(change.head);
+ }
+ });
+ return result;
+ };
+ _diff.deleted = function deleted() {
+ var result = [];
+ Object.values(_changes).forEach(function(change) {
+ if (change.base && !change.head) {
+ result.push(change.base);
+ }
+ });
+ return result;
+ };
+ _diff.summary = function summary() {
+ var relevant = {};
+ var keys2 = Object.keys(_changes);
+ for (var i2 = 0; i2 < keys2.length; i2++) {
+ var change = _changes[keys2[i2]];
+ if (change.head && change.head.geometry(head) !== "vertex") {
+ addEntity(change.head, head, change.base ? "modified" : "created");
+ } else if (change.base && change.base.geometry(base) !== "vertex") {
+ addEntity(change.base, base, "deleted");
+ } else if (change.base && change.head) {
+ var moved = !(0, import_fast_deep_equal3.default)(change.base.loc, change.head.loc);
+ var retagged = !(0, import_fast_deep_equal3.default)(change.base.tags, change.head.tags);
+ if (moved) {
+ addParents(change.head);
+ }
+ if (retagged || moved && change.head.hasInterestingTags()) {
+ addEntity(change.head, head, "modified");
+ }
+ } else if (change.head && change.head.hasInterestingTags()) {
+ addEntity(change.head, head, "created");
+ } else if (change.base && change.base.hasInterestingTags()) {
+ addEntity(change.base, base, "deleted");
+ }
+ }
+ return Object.values(relevant);
+ function addEntity(entity, graph, changeType) {
+ relevant[entity.id] = {
+ entity,
+ graph,
+ changeType
+ };
+ }
+ function addParents(entity) {
+ var parents = head.parentWays(entity);
+ for (var j2 = parents.length - 1; j2 >= 0; j2--) {
+ var parent = parents[j2];
+ if (!(parent.id in relevant)) {
+ addEntity(parent, head, "modified");
+ }
+ }
+ }
+ };
+ _diff.complete = function complete(extent) {
+ var result = {};
+ var id2, change;
+ for (id2 in _changes) {
+ change = _changes[id2];
+ var h = change.head;
+ var b = change.base;
+ var entity = h || b;
+ var i2;
+ if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) {
+ continue;
+ }
+ result[id2] = h;
+ if (entity.type === "way") {
+ var nh = h ? h.nodes : [];
+ var nb = b ? b.nodes : [];
+ var diff;
+ diff = utilArrayDifference(nh, nb);
+ for (i2 = 0; i2 < diff.length; i2++) {
+ result[diff[i2]] = head.hasEntity(diff[i2]);
+ }
+ diff = utilArrayDifference(nb, nh);
+ for (i2 = 0; i2 < diff.length; i2++) {
+ result[diff[i2]] = head.hasEntity(diff[i2]);
+ }
+ }
+ if (entity.type === "relation" && entity.isMultipolygon()) {
+ var mh = h ? h.members.map(function(m) {
+ return m.id;
+ }) : [];
+ var mb = b ? b.members.map(function(m) {
+ return m.id;
+ }) : [];
+ var ids = utilArrayUnion(mh, mb);
+ for (i2 = 0; i2 < ids.length; i2++) {
+ var member = head.hasEntity(ids[i2]);
+ if (!member)
+ continue;
+ if (extent && !member.intersects(extent, head))
+ continue;
+ result[ids[i2]] = member;
+ }
+ }
+ addParents(head.parentWays(entity), result);
+ addParents(head.parentRelations(entity), result);
+ }
+ return result;
+ function addParents(parents, result2) {
+ for (var i3 = 0; i3 < parents.length; i3++) {
+ var parent = parents[i3];
+ if (parent.id in result2)
+ continue;
+ result2[parent.id] = parent;
+ addParents(head.parentRelations(parent), result2);
+ }
+ }
+ };
+ return _diff;
+ }
+
+ // modules/core/tree.js
+ var import_rbush5 = __toESM(require_rbush_min());
+ function coreTree(head) {
+ var _rtree = new import_rbush5.default();
+ var _bboxes = {};
+ var _segmentsRTree = new import_rbush5.default();
+ var _segmentsBBoxes = {};
+ var _segmentsByWayId = {};
+ var tree = {};
+ function entityBBox(entity) {
+ var bbox2 = entity.extent(head).bbox();
+ bbox2.id = entity.id;
+ _bboxes[entity.id] = bbox2;
+ return bbox2;
+ }
+ function segmentBBox(segment) {
+ var extent = segment.extent(head);
+ if (!extent)
+ return null;
+ var bbox2 = extent.bbox();
+ bbox2.segment = segment;
+ _segmentsBBoxes[segment.id] = bbox2;
+ return bbox2;
+ }
+ function removeEntity(entity) {
+ _rtree.remove(_bboxes[entity.id]);
+ delete _bboxes[entity.id];
+ if (_segmentsByWayId[entity.id]) {
+ _segmentsByWayId[entity.id].forEach(function(segment) {
+ _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
+ delete _segmentsBBoxes[segment.id];
+ });
+ delete _segmentsByWayId[entity.id];
+ }
+ }
+ function loadEntities(entities) {
+ _rtree.load(entities.map(entityBBox));
+ var segments = [];
+ entities.forEach(function(entity) {
+ if (entity.segments) {
+ var entitySegments = entity.segments(head);
+ _segmentsByWayId[entity.id] = entitySegments;
+ segments = segments.concat(entitySegments);
+ }
+ });
+ if (segments.length)
+ _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
+ }
+ function updateParents(entity, insertions, memo) {
+ head.parentWays(entity).forEach(function(way) {
+ if (_bboxes[way.id]) {
+ removeEntity(way);
+ insertions[way.id] = way;
+ }
+ updateParents(way, insertions, memo);
+ });
+ head.parentRelations(entity).forEach(function(relation) {
+ if (memo[entity.id])
+ return;
+ memo[entity.id] = true;
+ if (_bboxes[relation.id]) {
+ removeEntity(relation);
+ insertions[relation.id] = relation;
+ }
+ updateParents(relation, insertions, memo);
+ });
+ }
+ tree.rebase = function(entities, force) {
+ var insertions = {};
+ for (var i2 = 0; i2 < entities.length; i2++) {
+ var entity = entities[i2];
+ if (!entity.visible)
+ continue;
+ if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
+ if (!force) {
+ continue;
+ } else if (_bboxes[entity.id]) {
+ removeEntity(entity);
+ }
+ }
+ insertions[entity.id] = entity;
+ updateParents(entity, insertions, {});
+ }
+ loadEntities(Object.values(insertions));
+ return tree;
+ };
+ function updateToGraph(graph) {
+ if (graph === head)
+ return;
+ var diff = coreDifference(head, graph);
+ head = graph;
+ var changed = diff.didChange;
+ if (!changed.addition && !changed.deletion && !changed.geometry)
+ return;
+ var insertions = {};
+ if (changed.deletion) {
+ diff.deleted().forEach(function(entity) {
+ removeEntity(entity);
+ });
+ }
+ if (changed.geometry) {
+ diff.modified().forEach(function(entity) {
+ removeEntity(entity);
+ insertions[entity.id] = entity;
+ updateParents(entity, insertions, {});
+ });
+ }
+ if (changed.addition) {
+ diff.created().forEach(function(entity) {
+ insertions[entity.id] = entity;
+ });
+ }
+ loadEntities(Object.values(insertions));
+ }
+ tree.intersects = function(extent, graph) {
+ updateToGraph(graph);
+ return _rtree.search(extent.bbox()).map(function(bbox2) {
+ return graph.entity(bbox2.id);
+ });
+ };
+ tree.waySegments = function(extent, graph) {
+ updateToGraph(graph);
+ return _segmentsRTree.search(extent.bbox()).map(function(bbox2) {
+ return bbox2.segment;
+ });
+ };
+ return tree;
+ }
+
+ // modules/svg/icon.js
+ function svgIcon(name, svgklass, useklass) {
+ return function drawIcon(selection2) {
+ selection2.selectAll("svg.icon" + (svgklass ? "." + svgklass.split(" ")[0] : "")).data([0]).enter().append("svg").attr("class", "icon " + (svgklass || "")).append("use").attr("xlink:href", name).attr("class", useklass);
+ };
+ }
+
+ // modules/ui/modal.js
+ function uiModal(selection2, blocking) {
+ let keybinding = utilKeybinding("modal");
+ let previous = selection2.select("div.modal");
+ let animate = previous.empty();
+ previous.transition().duration(200).style("opacity", 0).remove();
+ let shaded = selection2.append("div").attr("class", "shaded").style("opacity", 0);
+ shaded.close = () => {
+ shaded.transition().duration(200).style("opacity", 0).remove();
+ modal.transition().duration(200).style("top", "0px");
+ select_default2(document).call(keybinding.unbind);
+ };
+ let modal = shaded.append("div").attr("class", "modal fillL");
+ modal.append("input").attr("class", "keytrap keytrap-first").on("focus.keytrap", moveFocusToLast);
+ if (!blocking) {
+ shaded.on("click.remove-modal", (d3_event) => {
+ if (d3_event.target === this) {
+ shaded.close();
+ }
+ });
+ modal.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", shaded.close).call(svgIcon("#iD-icon-close"));
+ keybinding.on("\u232B", shaded.close).on("\u238B", shaded.close);
+ select_default2(document).call(keybinding);
+ }
+ modal.append("div").attr("class", "content");
+ modal.append("input").attr("class", "keytrap keytrap-last").on("focus.keytrap", moveFocusToFirst);
+ if (animate) {
+ shaded.transition().style("opacity", 1);
+ } else {
+ shaded.style("opacity", 1);
+ }
+ return shaded;
+ function moveFocusToFirst() {
+ let node = modal.select("a, button, input:not(.keytrap), select, textarea").node();
+ if (node) {
+ node.focus();
+ } else {
+ select_default2(this).node().blur();
+ }
+ }
+ function moveFocusToLast() {
+ let nodes = modal.selectAll("a, button, input:not(.keytrap), select, textarea").nodes();
+ if (nodes.length) {
+ nodes[nodes.length - 1].focus();
+ } else {
+ select_default2(this).node().blur();
+ }
+ }
+ }
+
+ // modules/ui/loading.js
+ function uiLoading(context) {
+ let _modalSelection = select_default2(null);
+ let _message = "";
+ let _blocking = false;
+ let loading = (selection2) => {
+ _modalSelection = uiModal(selection2, _blocking);
+ let loadertext = _modalSelection.select(".content").classed("loading-modal", true).append("div").attr("class", "modal-section fillL");
+ loadertext.append("img").attr("class", "loader").attr("src", context.imagePath("loader-white.gif"));
+ loadertext.append("h3").html(_message);
+ _modalSelection.select("button.close").attr("class", "hide");
+ return loading;
+ };
+ loading.message = function(val) {
+ if (!arguments.length)
+ return _message;
+ _message = val;
+ return loading;
+ };
+ loading.blocking = function(val) {
+ if (!arguments.length)
+ return _blocking;
+ _blocking = val;
+ return loading;
+ };
+ loading.close = () => {
+ _modalSelection.remove();
+ };
+ loading.isShown = () => {
+ return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
+ };
+ return loading;
+ }
+
+ // modules/core/history.js
+ function coreHistory(context) {
+ var dispatch10 = dispatch_default("reset", "change", "merge", "restore", "undone", "redone", "storage_error");
+ var lock = utilSessionMutex("lock");
+ var _hasUnresolvedRestorableChanges = lock.lock() && !!corePreferences(getKey("saved_history"));
+ var duration = 150;
+ var _imageryUsed = [];
+ var _photoOverlaysUsed = [];
+ var _checkpoints = {};
+ var _pausedGraph;
+ var _stack;
+ var _index;
+ var _tree;
+ function _act(actions, t) {
+ actions = Array.prototype.slice.call(actions);
+ var annotation;
+ if (typeof actions[actions.length - 1] !== "function") {
+ annotation = actions.pop();
+ }
+ var graph = _stack[_index].graph;
+ for (var i2 = 0; i2 < actions.length; i2++) {
+ graph = actions[i2](graph, t);
+ }
+ return {
+ graph,
+ annotation,
+ imageryUsed: _imageryUsed,
+ photoOverlaysUsed: _photoOverlaysUsed,
+ transform: context.projection.transform(),
+ selectedIDs: context.selectedIDs()
+ };
+ }
+ function _perform(args, t) {
+ var previous = _stack[_index].graph;
+ _stack = _stack.slice(0, _index + 1);
+ var actionResult = _act(args, t);
+ _stack.push(actionResult);
+ _index++;
+ return change(previous);
+ }
+ function _replace(args, t) {
+ var previous = _stack[_index].graph;
+ var actionResult = _act(args, t);
+ _stack[_index] = actionResult;
+ return change(previous);
+ }
+ function _overwrite(args, t) {
+ var previous = _stack[_index].graph;
+ if (_index > 0) {
+ _index--;
+ _stack.pop();
+ }
+ _stack = _stack.slice(0, _index + 1);
+ var actionResult = _act(args, t);
+ _stack.push(actionResult);
+ _index++;
+ return change(previous);
+ }
+ function change(previous) {
+ var difference = coreDifference(previous, history.graph());
+ if (!_pausedGraph) {
+ dispatch10.call("change", this, difference);
+ }
+ return difference;
+ }
+ function getKey(n2) {
+ return "iD_" + window.location.origin + "_" + n2;
+ }
+ var history = {
+ graph: function() {
+ return _stack[_index].graph;
+ },
+ tree: function() {
+ return _tree;
+ },
+ base: function() {
+ return _stack[0].graph;
+ },
+ merge: function(entities) {
+ var stack = _stack.map(function(state) {
+ return state.graph;
+ });
+ _stack[0].graph.rebase(entities, stack, false);
+ _tree.rebase(entities, false);
+ dispatch10.call("merge", this, entities);