mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-14 21:28:11 +02:00
Merge branch 'develop' into touch-walkthrough-update
This commit is contained in:
+90
-28
@@ -7,14 +7,16 @@ fail to serve some proportion of mappers. Broadly speaking, iD should strive to
|
||||
follow [universal design](https://en.wikipedia.org/wiki/Universal_design) principles.
|
||||
|
||||
This is a living document that details the usability of iD across a number of dimensions,
|
||||
with the intent of identifying and addressing problem areas.
|
||||
with the intent of identifying and addressing problem areas. Since there are always more
|
||||
factors to consider, no part of this document should be considered "complete".
|
||||
|
||||
Symbols used in this document:
|
||||
|
||||
- ✅ Full support
|
||||
- 🟩 Full support assumed but unverified
|
||||
- 🟩 Full support assumed, but not sufficiently tested
|
||||
- 🟠 Partial support
|
||||
- ❌ No appreciable support
|
||||
- 🤷 Unknown support, none is assumed
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
@@ -26,18 +28,78 @@ should fallback gracefully without breaking other aspects of the app.
|
||||
This table covers high-level compatibility, with individual features to be detailed
|
||||
elsewhere in this document.
|
||||
|
||||
| | Browser | Notes |
|
||||
|---|---|---|
|
||||
| ✅ | Chrome | |
|
||||
| ✅* | Firefox | *Minor known issues ([#7132]) |
|
||||
| ✅ | Safari | |
|
||||
| 🟩 | Opera | Infrequently tested |
|
||||
| 🟩 | Edge | Infrequently tested |
|
||||
| 🟠 | Internet Explorer | Infrequently tested. IE has been discontinued, but IE 11 is still maintained. iD polyfills ES6 features on IE 11, with varying success. |
|
||||
| 🟠 | Mobile browsers | iD has not yet been fully optimized for mobile devices, but some editing is usually possible. |
|
||||
| | | Browser | Notes | Issues |
|
||||
|---|---|---|---|---|
|
||||
| ✅ | ![chrome logo] | Chrome | |
|
||||
| ✅* | ![firefox logo] | Firefox | \*Minor known issues | [#7132] |
|
||||
| ✅ | ![safari logo] | Safari | |
|
||||
| 🟩 | ![opera logo] | Opera | |
|
||||
| 🟩 | ![edge logo] | Edge | |
|
||||
| 🟠 | ![ie logo] | Internet Explorer | IE has been discontinued, but IE 11 is still maintained. iD polyfills ES6 features on IE 11, with varying success. |
|
||||
| 🟩 | 🌐 | Others | iD should run without issue on any desktop browser implementing modern web standards. |
|
||||
| 🟠 | 📱 | Mobile browsers | iD has not yet been fully optimized for mobile devices, but some editing is usually possible. |
|
||||
|
||||
[safari logo]: https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Safari_browser_logo.svg/30px-Safari_browser_logo.svg.png
|
||||
[opera logo]: https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Opera_browser_logo_2013_vector.svg/30px-Opera_browser_logo_2013_vector.svg.png
|
||||
[chrome logo]: https://upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Google_Chrome_icon_%28September_2014%29.svg/30px-Google_Chrome_icon_%28September_2014%29.svg.png
|
||||
[firefox logo]: https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Firefox_logo%2C_2019.svg/30px-Firefox_logo%2C_2019.svg.png
|
||||
[edge logo]: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Microsoft_Edge_logo_%282015%E2%80%932019%29.svg/30px-Microsoft_Edge_logo_%282015%E2%80%932019%29.svg.png
|
||||
[ie logo]: https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/Internet_Explorer_10%2B11_logo.svg/30px-Internet_Explorer_10%2B11_logo.svg.png
|
||||
|
||||
[#7132]: https://github.com/openstreetmap/iD/issues/7132
|
||||
|
||||
## Input Device Support
|
||||
|
||||
iD has traditionally assumed the mapper will be interacting via a mouse and keyboard,
|
||||
but realistically people want or need to use various other [input devices](https://en.wikipedia.org/wiki/Input_device).
|
||||
|
||||
iD relies on modern [pointer events](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events) for some interactions, so
|
||||
some devices may see degraded functionality on older browsers.
|
||||
|
||||
### Setups
|
||||
|
||||
The following table lists iD's usability for different setups. A setup is where
|
||||
a mapper is using only the device(s) given in the row.
|
||||
|
||||
A setup with "full support" offers functionality equivalent to that of the
|
||||
highest-functioning setup (generally mouse and keyboard).
|
||||
Certain functions may be accessed differently on different setups,
|
||||
such as opening the edit menu via long-pressing instead of right-clicking.
|
||||
|
||||
| | | Input Setup | Notes |
|
||||
|---|---|---|---|
|
||||
| ✅ | 🖱⌨️ | [Mouse](https://en.wikipedia.org/wiki/Computer_mouse) + [keyboard](https://en.wikipedia.org/wiki/Computer_keyboard) | iD's original input paradigm. Any mouse-like device such as a [trackpad](https://en.wikipedia.org/wiki/Touchpad), [trackball](https://en.wikipedia.org/wiki/Trackball), or [pointing stick](https://en.wikipedia.org/wiki/Pointing_stick) is grouped into "mouse" for this table |
|
||||
| ❌ | ⌨️ | Keyboard only | Not all elements can necessarily be keyed to. Key traps may exists. Geometry editing isn't possible |
|
||||
| 🟠 | 🖱 | Mouse only | The primary [mouse button](https://en.wikipedia.org/wiki/Mouse_button) (e.g. left click) alone is sufficient. Multiselection and disabling of node-snapping aren't possible |
|
||||
| 🟠 | 🖐 | [Multi-touch](https://en.wikipedia.org/wiki/Multi-touch) on a [touchscreen](https://en.wikipedia.org/wiki/Touchscreen) | Move and rotate aren't possible |
|
||||
| 🟠 | ✍️ | [Stylus](https://en.wikipedia.org/wiki/Stylus_(computing)) on a touchscreen | Move, rotate, and multiselection aren't possible |
|
||||
| 🤷 | ✍️🔲 | Stylus on a [graphics tablet](https://en.wikipedia.org/wiki/Graphics_tablet) | |
|
||||
| 🤷 | 🎮 | [Gamepad](https://en.wikipedia.org/wiki/Gamepad) | |
|
||||
| 🤷 | 🗣 | [Voice](https://en.wikipedia.org/wiki/Voice_user_interface) | Tools like [Voice Control on macOS](https://support.apple.com/en-us/HT210539) and [Windows Speech Recognition](https://en.wikipedia.org/wiki/Windows_Speech_Recognition) allow navigating webpages with voice commands to some degree |
|
||||
| 🤷 | 🔘 | [Switch](https://en.wikipedia.org/wiki/Switch_access) | Tools like [Switch Control on macOS](https://support.apple.com/en-us/HT202865) can theoretically replicate mouse and keyboard interactions in most apps |
|
||||
|
||||
### Devices
|
||||
|
||||
This table details iD's support for specific classes of input devices.
|
||||
|
||||
"Full support" for a device means that iD reasonably handles its entire range of input on supported platforms. But unlike the "setups" table above, a given device is not necessarily expected to perform all of iD's functions.
|
||||
|
||||
It's impractical to ensure every single input device works as expected, so the table only reflects the support status to the best of our knowledge.
|
||||
|
||||
| | Input Device | Notes | Issues |
|
||||
|---|---|---|---|
|
||||
| ✅ | Single-button mouse | E.g. [Chester Mouse](https://duckduckgo.com/?q=chester+one+button+mouse&iar=images&iax=images&ia=images). Primary click (e.g. left-click) can be used for all pointer interactions. A long-click on map features opens the edit menu |
|
||||
| ✅ | Multi-button mouse | Secondary click (e.g. right-click) can be used on map features to open the edit menu. Middle click, etc., are not needed by iD but are passed through to the browser |
|
||||
| ✅ | Multi-touch mouse | E.g. [Magic Mouse](https://en.wikipedia.org/wiki/Magic_Mouse). 2D scrolling in the map is treated as panning, not zooming |
|
||||
| 🟠 | Vertical [scroll wheel](https://en.wikipedia.org/wiki/Scroll_wheel) | Should zoom the map in and out | [#5550](https://github.com/openstreetmap/iD/issues/5550) |
|
||||
| ❌ | Horizontal scroll wheel | Currently does nothing in the map | [#7134](https://github.com/openstreetmap/iD/issues/7134) |
|
||||
| 🤷 | Scroll ball | E.g. in [Apple Mighty Mouse](https://en.wikipedia.org/wiki/Apple_Mighty_Mouse) |
|
||||
| 🟩 | Trackball | |
|
||||
| 🟩 | Trackpad | |
|
||||
| ✅ | Multi-touch trackpad | E.g. [Magic Trackpad](https://en.wikipedia.org/wiki/Magic_Trackpad). Pinch-to-zoom and scroll-to-pan are supported in the map |
|
||||
| 🟩 | Pointing stick | |
|
||||
| ✅ | Keyboard | |
|
||||
|
||||
## Language Support
|
||||
|
||||
English is the language of tags and relation roles in the OpenStreetMap database.
|
||||
@@ -56,7 +118,7 @@ for more info.
|
||||
| ❌ | Base language fallback | E.g. if `pt_BR` is incomplete, `pt` should be tried before `en` |
|
||||
| ❌ | Custom fallback language | If the preferred language is incomplete, a user-specified one should be tried before `en` (e.g. `kk` → `ru`) |
|
||||
| ✅ | Locale URL parameters | `locale` and `rtl` can be used to manually set iD's locale preferences. See the [API](API.md#url-parameters) |
|
||||
| 🟩 | Right-to-left layouts | Infrequently tested. Used for languages like Hebrew and Arabic |
|
||||
| 🟩 | Right-to-left layouts | Used for languages like Hebrew and Arabic |
|
||||
|
||||
### Translatability
|
||||
|
||||
@@ -64,22 +126,22 @@ The following table details which interface elements can adapt to the mapper's
|
||||
language preferences. This doesn't account for whether they've actually been
|
||||
translated to one or more languages.
|
||||
|
||||
| | Interface Element | Notes |
|
||||
|---|---|---|
|
||||
| ✅ | Labels and descriptions | |
|
||||
| ✅ | Help docs and walkthrough | |
|
||||
| ✅ | Letter hotkeys | E.g. <kbd>S</kbd> for Straighten makes sense in English, but not every language |
|
||||
| ✅ | Preset names and search terms | |
|
||||
| 🟠 | Fields | Combo fields may show raw tag values. The Wikipedia field lists Wiki names in their native languages |
|
||||
| ❌ | Tags | OpenStreetMap tags are English-only as a limitation of the database |
|
||||
| ❌ | Relation member roles | OpenStreetMap roles are also limited to English |
|
||||
| ✅ | Imagery metadata | |
|
||||
| 🟠 | Locator overlay | This layer shows feature labels in their local languages |
|
||||
| ✅ | OSM community index | |
|
||||
| ✅ | iD validation issues | |
|
||||
| ✅ | KeepRight issues | |
|
||||
| ✅ | ImproveOSM issues | |
|
||||
| ✅ | Osmose issues | Translated strings are [provided by Osmose](https://www.transifex.com/openstreetmap-france/osmose/) itself, not iD |
|
||||
| | Interface Element | Notes | Issues |
|
||||
|---|---|---|---|
|
||||
| ✅ | Labels and descriptions | | |
|
||||
| ✅ | Help docs and walkthrough | | |
|
||||
| ✅ | Letter hotkeys | E.g. <kbd>S</kbd> for Straighten makes sense in English, but not every language | |
|
||||
| ✅ | Preset names and search terms | | |
|
||||
| 🟠 | Fields | Combo fields may show raw tag values. The Wikipedia field lists Wiki names in their native languages | [#2708](https://github.com/openstreetmap/iD/issues/2708) |
|
||||
| ❌ | Tags | OpenStreetMap tags are English-only as a limitation of the database | |
|
||||
| ❌ | Relation member roles | OpenStreetMap roles are also limited to English | |
|
||||
| ✅ | Imagery metadata | | |
|
||||
| 🟠 | Locator overlay | This layer shows feature labels in their local languages | [#7737](https://github.com/openstreetmap/iD/issues/7737) |
|
||||
| ✅ | OSM community index | | |
|
||||
| ✅ | iD validation issues | | |
|
||||
| ✅ | KeepRight issues | | |
|
||||
| ✅ | ImproveOSM issues | | |
|
||||
| ✅ | Osmose issues | Translated strings are [provided by Osmose](https://www.transifex.com/openstreetmap-france/osmose/) itself, not iD | |
|
||||
|
||||
### Language Coverage
|
||||
|
||||
|
||||
@@ -2583,21 +2583,9 @@ img.tag-reference-wiki-image {
|
||||
}
|
||||
|
||||
.form-field-input-member > input.member-role {
|
||||
border-radius: 0 0 0 4px;
|
||||
}
|
||||
.ideditor[dir='rtl'] .form-field-input-member > input.member-role {
|
||||
border-radius: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.member-incomplete .form-field-input-member > input.member-role,
|
||||
.ideditor[dir='rtl'] .member-incomplete .form-field-input-member > input.member-role {
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
.member-incomplete .member-delete {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.member-row-new .member-entity-input {
|
||||
flex: 1 1 100%;
|
||||
border-radius: 4px 4px 0 0;
|
||||
|
||||
@@ -315,6 +315,7 @@ en:
|
||||
vertex: Moved a node in a way.
|
||||
line: Moved a line.
|
||||
area: Moved an area.
|
||||
relation: Moved a relation.
|
||||
multiple: Moved multiple features.
|
||||
incomplete_relation:
|
||||
single: This feature can't be moved because it hasn't been fully downloaded.
|
||||
@@ -371,6 +372,7 @@ en:
|
||||
line: Rotated a line.
|
||||
area: Rotated an area.
|
||||
multiple: Rotated multiple features.
|
||||
relation: Rotated a relation.
|
||||
incomplete_relation:
|
||||
single: This feature can't be rotated because it hasn't been fully downloaded.
|
||||
multiple: These features can't be rotated because they haven't been fully downloaded.
|
||||
|
||||
@@ -247,6 +247,10 @@
|
||||
"old": {"building": "household"},
|
||||
"replace": {"building": "house"}
|
||||
},
|
||||
{
|
||||
"old": {"building": "pavillion"},
|
||||
"replace": {"building": "pavilion"}
|
||||
},
|
||||
{
|
||||
"old": {"building:color": "*"},
|
||||
"replace": {"building:colour": "$1"}
|
||||
|
||||
+3
-2
@@ -4664,8 +4664,9 @@ en:
|
||||
terms: '<translate with synonyms or related terms for ''Craft'', separated by commas>'
|
||||
craft/agricultural_engines:
|
||||
# craft=agricultural_engines
|
||||
name: Argricultural Engines Mechanic
|
||||
terms: '<translate with synonyms or related terms for ''Argricultural Engines Mechanic'', separated by commas>'
|
||||
name: Agricultural Engines Mechanic
|
||||
# 'terms: combines,farm equipment,harvesters,tractors'
|
||||
terms: '<translate with synonyms or related terms for ''Agricultural Engines Mechanic'', separated by commas>'
|
||||
craft/basket_maker:
|
||||
# craft=basket_maker
|
||||
name: Basket Maker
|
||||
|
||||
@@ -395,7 +395,7 @@
|
||||
"craft": {"icon": "temaki-tools", "fields": ["name", "craft", "operator", "address", "building_area", "opening_hours", "opening_hours/covid19"], "moreFields": ["air_conditioning", "building/levels_building", "ele", "email", "fax", "gnis/feature_id", "height_building", "internet_access", "internet_access/fee", "internet_access/ssid", "level", "phone", "product", "ref/vatin", "website", "wheelchair"], "geometry": ["point", "area"], "tags": {"craft": "*"}, "terms": [], "name": "Craft"},
|
||||
"craft/locksmith": {"icon": "maki-marker-stroked", "geometry": ["point", "area"], "tags": {"craft": "locksmith"}, "reference": {"key": "shop", "value": "locksmith"}, "name": "Locksmith", "searchable": false},
|
||||
"craft/tailor": {"icon": "temaki-needle_and_spool", "geometry": ["point", "area"], "tags": {"craft": "tailor"}, "reference": {"key": "shop", "value": "tailor"}, "name": "Tailor", "searchable": false},
|
||||
"craft/agricultural_engines": {"icon": "temaki-tools", "geometry": ["point", "area"], "tags": {"craft": "agricultural_engines"}, "name": "Argricultural Engines Mechanic"},
|
||||
"craft/agricultural_engines": {"icon": "temaki-tools", "geometry": ["point", "area"], "tags": {"craft": "agricultural_engines"}, "terms": ["combines", "farm equipment", "harvesters", "tractors"], "name": "Agricultural Engines Mechanic"},
|
||||
"craft/basket_maker": {"icon": "temaki-vase", "geometry": ["point", "area"], "tags": {"craft": "basket_maker"}, "name": "Basket Maker"},
|
||||
"craft/beekeeper": {"icon": "maki-farm", "geometry": ["point", "area"], "tags": {"craft": "beekeeper"}, "name": "Beekeeper"},
|
||||
"craft/blacksmith": {"icon": "temaki-anvil_and_hammer", "geometry": ["point", "area"], "tags": {"craft": "blacksmith"}, "name": "Blacksmith"},
|
||||
|
||||
@@ -7,5 +7,11 @@
|
||||
"tags": {
|
||||
"craft": "agricultural_engines"
|
||||
},
|
||||
"name": "Argricultural Engines Mechanic"
|
||||
"terms": [
|
||||
"combines",
|
||||
"farm equipment",
|
||||
"harvesters",
|
||||
"tractors"
|
||||
],
|
||||
"name": "Agricultural Engines Mechanic"
|
||||
}
|
||||
|
||||
+2
-1
@@ -391,7 +391,7 @@
|
||||
{"key": "craft", "description": "🄿 Craft, 🄵 Type", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/tools.svg"},
|
||||
{"key": "craft", "value": "locksmith", "description": "🄿 Locksmith (unsearchable)", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/mapbox/maki/icons/marker-stroked-15.svg"},
|
||||
{"key": "craft", "value": "tailor", "description": "🄿 Tailor (unsearchable)", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/needle_and_spool.svg"},
|
||||
{"key": "craft", "value": "agricultural_engines", "description": "🄿 Argricultural Engines Mechanic", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/tools.svg"},
|
||||
{"key": "craft", "value": "agricultural_engines", "description": "🄿 Agricultural Engines Mechanic", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/tools.svg"},
|
||||
{"key": "craft", "value": "basket_maker", "description": "🄿 Basket Maker", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/vase.svg"},
|
||||
{"key": "craft", "value": "beekeeper", "description": "🄿 Beekeeper", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/mapbox/maki/icons/farm-15.svg"},
|
||||
{"key": "craft", "value": "blacksmith", "description": "🄿 Blacksmith", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/anvil_and_hammer.svg"},
|
||||
@@ -2060,6 +2060,7 @@
|
||||
{"key": "building", "value": "family_house", "description": "🄳 ➜ building=house"},
|
||||
{"key": "building", "value": "home", "description": "🄳 ➜ building=house"},
|
||||
{"key": "building", "value": "household", "description": "🄳 ➜ building=house"},
|
||||
{"key": "building", "value": "pavillion", "description": "🄳 ➜ building=pavilion"},
|
||||
{"key": "building:color", "description": "🄳 ➜ building:colour=*"},
|
||||
{"key": "building:height", "description": "🄳 ➜ height=*"},
|
||||
{"key": "building:material", "value": "Brick", "description": "🄳 ➜ building:material=brick"},
|
||||
|
||||
Vendored
+5
-3
@@ -411,6 +411,7 @@
|
||||
"vertex": "Moved a node in a way.",
|
||||
"line": "Moved a line.",
|
||||
"area": "Moved an area.",
|
||||
"relation": "Moved a relation.",
|
||||
"multiple": "Moved multiple features."
|
||||
},
|
||||
"incomplete_relation": {
|
||||
@@ -486,7 +487,8 @@
|
||||
"annotation": {
|
||||
"line": "Rotated a line.",
|
||||
"area": "Rotated an area.",
|
||||
"multiple": "Rotated multiple features."
|
||||
"multiple": "Rotated multiple features.",
|
||||
"relation": "Rotated a relation."
|
||||
},
|
||||
"incomplete_relation": {
|
||||
"single": "This feature can't be rotated because it hasn't been fully downloaded.",
|
||||
@@ -6711,8 +6713,8 @@
|
||||
"name": "Tailor"
|
||||
},
|
||||
"craft/agricultural_engines": {
|
||||
"name": "Argricultural Engines Mechanic",
|
||||
"terms": ""
|
||||
"name": "Agricultural Engines Mechanic",
|
||||
"terms": "combines,farm equipment,harvesters,tractors"
|
||||
},
|
||||
"craft/basket_maker": {
|
||||
"name": "Basket Maker",
|
||||
|
||||
@@ -45,7 +45,10 @@ export function actionExtract(entityID) {
|
||||
var keysToRetain = ['area'];
|
||||
var buildingKeysToRetain = ['architect', 'building', 'height', 'layer'];
|
||||
|
||||
var centroid = d3_geoCentroid(entity.asGeoJSON(graph));
|
||||
var extractedLoc = d3_geoCentroid(entity.asGeoJSON(graph));
|
||||
if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
|
||||
extractedLoc = entity.extent(graph).center();
|
||||
}
|
||||
|
||||
var isBuilding = entity.tags.building && entity.tags.building !== 'no';
|
||||
|
||||
@@ -87,7 +90,7 @@ export function actionExtract(entityID) {
|
||||
entityTags.area = 'yes';
|
||||
}
|
||||
|
||||
var replacement = osmNode({ loc: centroid, tags: pointTags });
|
||||
var replacement = osmNode({ loc: extractedLoc, tags: pointTags });
|
||||
graph = graph.replace(replacement);
|
||||
|
||||
extractedNodeID = replacement.id;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { geoPolygonContainsPolygon } from '../geo';
|
||||
import { osmJoinWays, osmRelation } from '../osm';
|
||||
import { utilArrayGroupBy, utilObjectOmit } from '../util';
|
||||
import { utilArrayGroupBy, utilArrayIntersection, utilObjectOmit } from '../util';
|
||||
|
||||
|
||||
export function actionMergePolygon(ids, newRelationId) {
|
||||
@@ -114,10 +114,35 @@ export function actionMergePolygon(ids, newRelationId) {
|
||||
action.disabled = function(graph) {
|
||||
var entities = groupEntities(graph);
|
||||
if (entities.other.length > 0 ||
|
||||
entities.closedWay.length + entities.multipolygon.length < 2)
|
||||
entities.closedWay.length + entities.multipolygon.length < 2) {
|
||||
return 'not_eligible';
|
||||
if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
|
||||
}
|
||||
if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); })) {
|
||||
return 'incomplete_relation';
|
||||
}
|
||||
|
||||
if (!entities.multipolygon.length) {
|
||||
var sharedMultipolygons = [];
|
||||
entities.closedWay.forEach(function(way, i) {
|
||||
if (i === 0) {
|
||||
sharedMultipolygons = graph.parentMultipolygons(way);
|
||||
} else {
|
||||
sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
|
||||
}
|
||||
});
|
||||
sharedMultipolygons = sharedMultipolygons.filter(function(relation) {
|
||||
return relation.members.length === entities.closedWay.length;
|
||||
});
|
||||
if (sharedMultipolygons.length) {
|
||||
// don't create a new multipolygon if it'd be redundant
|
||||
return 'not_eligible';
|
||||
}
|
||||
} else if (entities.closedWay.some(function(way) {
|
||||
return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
|
||||
})) {
|
||||
// don't add a way to a multipolygon again if it's already a member
|
||||
return 'not_eligible';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -21,10 +21,9 @@ export function operationExtract(context, selectedIDs) {
|
||||
|
||||
if (entity.type === 'node' && graph.parentWays(entity).length === 0) return;
|
||||
|
||||
var geometry = graph.geometry(entityID);
|
||||
if (geometry === 'area' || geometry === 'line') {
|
||||
if (entity.type !== 'node') {
|
||||
var preset = presetManager.match(entity, graph);
|
||||
// only allow extraction from ways/multipolygons if the preset supports points
|
||||
// only allow extraction from ways/relations if the preset supports points
|
||||
if (preset.geometry.indexOf('point') === -1) return;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,19 +14,24 @@ export function operationMerge(context, selectedIDs) {
|
||||
var _action = getAction();
|
||||
|
||||
function getAction() {
|
||||
// prefer a non-disabled action first
|
||||
var join = actionJoin(selectedIDs);
|
||||
if (join.disabled(context.graph()) !== 'not_eligible') {
|
||||
return join;
|
||||
}
|
||||
if (!join.disabled(context.graph())) return join;
|
||||
|
||||
var merge = actionMerge(selectedIDs);
|
||||
if (merge.disabled(context.graph()) !== 'not_eligible') {
|
||||
return merge;
|
||||
}
|
||||
if (!merge.disabled(context.graph())) return merge;
|
||||
|
||||
var mergePolygon = actionMergePolygon(selectedIDs);
|
||||
if (mergePolygon.disabled(context.graph()) !== 'not_eligible') {
|
||||
return mergePolygon;
|
||||
}
|
||||
if (!mergePolygon.disabled(context.graph())) return mergePolygon;
|
||||
|
||||
var mergeNodes = actionMergeNodes(selectedIDs);
|
||||
if (!mergeNodes.disabled(context.graph())) return mergeNodes;
|
||||
|
||||
// otherwise prefer an action with an interesting disabled reason
|
||||
if (join.disabled(context.graph()) !== 'not_eligible') return join;
|
||||
if (merge.disabled(context.graph()) !== 'not_eligible') return merge;
|
||||
if (mergePolygon.disabled(context.graph()) !== 'not_eligible') return mergePolygon;
|
||||
|
||||
return mergeNodes;
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -48,7 +48,16 @@ export function uiEditMenu(context) {
|
||||
var showLabels = isTouchMenu;
|
||||
|
||||
var buttonHeight = showLabels ? 32 : 34;
|
||||
var menuWidth = showLabels ? 172 : 44;
|
||||
var menuWidth;
|
||||
if (showLabels) {
|
||||
// Get a general idea of the width based on the length of the label
|
||||
menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function(op) {
|
||||
return op.title.length;
|
||||
})));
|
||||
} else {
|
||||
menuWidth = 44;
|
||||
}
|
||||
|
||||
var menuLeft = displayOnLeft(viewport);
|
||||
|
||||
offset[0] = menuLeft ? -1 * (_menuSideMargin + menuWidth) : _menuSideMargin;
|
||||
|
||||
@@ -59,6 +59,9 @@ export function uiInit(context) {
|
||||
|
||||
container
|
||||
.on('click.ui', function() {
|
||||
// we're only concerned with the primary mouse button
|
||||
if (d3_event.button !== 0) return;
|
||||
|
||||
if (!d3_event.composedPath) return;
|
||||
|
||||
// some targets have default click events we don't want to override
|
||||
|
||||
@@ -189,6 +189,13 @@ export function uiSectionRawMemberEditor(context) {
|
||||
.attr('class', 'member-entity-name')
|
||||
.text(function(d) { return utilDisplayName(d.member); });
|
||||
|
||||
label
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.attr('title', t('icons.remove'))
|
||||
.attr('class', 'remove member-delete')
|
||||
.call(svgIcon('#iD-operation-delete'));
|
||||
|
||||
label
|
||||
.append('button')
|
||||
.attr('class', 'member-zoom')
|
||||
@@ -235,13 +242,6 @@ export function uiSectionRawMemberEditor(context) {
|
||||
.attr('placeholder', t('inspector.role'))
|
||||
.call(utilNoAuto);
|
||||
|
||||
wrapEnter
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.attr('title', t('icons.remove'))
|
||||
.attr('class', 'remove form-field-button member-delete')
|
||||
.call(svgIcon('#iD-operation-delete'));
|
||||
|
||||
if (taginfo) {
|
||||
wrapEnter.each(bindTypeahead);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,16 @@ export function uiSectionRawMembershipEditor(context) {
|
||||
context.enter(modeSelect(context, [d.relation.id]));
|
||||
}
|
||||
|
||||
function zoomToRelation(d) {
|
||||
d3_event.preventDefault();
|
||||
|
||||
var entity = context.entity(d.relation.id);
|
||||
context.map().zoomToEase(entity);
|
||||
|
||||
// highlight the relation in case it wasn't previously on-screen
|
||||
utilHighlightEntities([d.relation.id], true, context);
|
||||
}
|
||||
|
||||
|
||||
function changeRole(d) {
|
||||
if (d === 0) return; // called on newrow (shoudn't happen)
|
||||
@@ -236,14 +246,16 @@ export function uiSectionRawMembershipEditor(context) {
|
||||
.attr('class', 'field-label')
|
||||
.attr('for', function(d) {
|
||||
return d.domId;
|
||||
})
|
||||
});
|
||||
|
||||
var labelLink = labelEnter
|
||||
.append('span')
|
||||
.attr('class', 'label-text')
|
||||
.append('a')
|
||||
.attr('href', '#')
|
||||
.on('click', selectRelation);
|
||||
|
||||
labelEnter
|
||||
labelLink
|
||||
.append('span')
|
||||
.attr('class', 'member-entity-type')
|
||||
.text(function(d) {
|
||||
@@ -251,11 +263,25 @@ export function uiSectionRawMembershipEditor(context) {
|
||||
return (matched && matched.name()) || t('inspector.relation');
|
||||
});
|
||||
|
||||
labelEnter
|
||||
labelLink
|
||||
.append('span')
|
||||
.attr('class', 'member-entity-name')
|
||||
.text(function(d) { return utilDisplayName(d.relation); });
|
||||
|
||||
labelEnter
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.attr('class', 'remove member-delete')
|
||||
.call(svgIcon('#iD-operation-delete'))
|
||||
.on('click', deleteMembership);
|
||||
|
||||
labelEnter
|
||||
.append('button')
|
||||
.attr('class', 'member-zoom')
|
||||
.attr('title', t('icons.zoom_to'))
|
||||
.call(svgIcon('#iD-icon-framed-dot', 'monochrome'))
|
||||
.on('click', zoomToRelation);
|
||||
|
||||
var wrapEnter = itemsEnter
|
||||
.append('div')
|
||||
.attr('class', 'form-field-input-wrap form-field-input-member');
|
||||
@@ -273,13 +299,6 @@ export function uiSectionRawMembershipEditor(context) {
|
||||
.on('blur', changeRole)
|
||||
.on('change', changeRole);
|
||||
|
||||
wrapEnter
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.attr('class', 'remove form-field-button member-delete')
|
||||
.call(svgIcon('#iD-operation-delete'))
|
||||
.on('click', deleteMembership);
|
||||
|
||||
if (taginfo) {
|
||||
wrapEnter.each(bindTypeahead);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user