diff --git a/css/80_app.css b/css/80_app.css index 64246010c..d5a647638 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -308,29 +308,29 @@ button.disabled { cursor: not-allowed; } -.joined button { +.joined > * { border-radius: 0; border-right: 1px solid rgba(0,0,0,.5); } -[dir='rtl'] .joined button { +[dir='rtl'] .joined > * { border-left: 1px solid rgba(0,0,0,.5); border-right: none; } -.fillL .joined button { +.fillL .joined > * { border-right: 1px solid #fff; } -.joined button:first-child { +.joined > *:first-child { border-radius: 4px 0 0 4px; } -[dir='rtl'] .joined button:first-child { +[dir='rtl'] .joined > *:first-child { border-radius: 0 4px 4px 0; } -.joined button:last-child { +.joined > *:last-child { border-right-width: 0; border-radius: 0 4px 4px 0; } -[dir='rtl'] .joined button:last-child { +[dir='rtl'] .joined > *.bar-button:last-child { border-radius: 4px 0 0 4px; } @@ -451,22 +451,25 @@ button[disabled].action:hover { width: 100%; } .tool-group.leading-area { - flex-shrink: 2; justify-content: flex-start; } +.tool-group.leading-area, +.tool-group.trailing-area { + flex-shrink: 2; +} .tool-group.center-area { justify-content: center; } .tool-group.trailing-area { - justify-content: flex-start; + justify-content: flex-end; } -.tool-group > div { +.tool-group > div:not(:empty) { display: flex; margin: 0 5px; } -.tool-group button { - flex: 1 1 auto; +.tool-group button.bar-button { + flex: 0 0 auto; flex-flow: row nowrap; align-items: center; padding: 0 10px; @@ -474,38 +477,31 @@ button[disabled].action:hover { white-space: nowrap; display: flex; } -[dir='ltr'] .tool-group button.add-preset.add-point, -[dir='ltr'] .tool-group button.add-preset.add-point .label { - padding-left: 0px; +.tool-group button.add-preset:not(.add-generic-preset) { + padding: 0; } -[dir='ltr'] .tool-group button.add-preset:not(.add-point) { - padding-left: 5px; +.tool-group button.add-preset.disabled .preset-icon-container { + opacity: 0.5; } -[dir='ltr'] .tool-group button.add-preset:not(.add-point) .label { - padding-left: 3px; -} -[dir='rtl'] .tool-group button.add-preset.add-point, -[dir='rtl'] .tool-group button.add-preset.add-point .label { - padding-right: 0px; -} -[dir='rtl'] .tool-group button.add-preset:not(.add-point) { - padding-right: 5px; -} -[dir='rtl'] .tool-group button.add-preset:not(.add-point) .label { - padding-right: 3px; -} -.narrow .tool-group button.add-preset { - padding-right: 0 !important; - padding-left: 0 !important; -} -.tool-group button > .icon { +.tool-group button.bar-button .icon { flex: 0 0 20px; } -.tool-group button .label { +.tool-group button.bar-button .label { flex: 0 1 auto; padding: 0 5px; } +.tool-group button.dragging { + opacity: 0.75; + z-index: 200; +} +.tool-group button.dragging .tooltip { + display: none; +} +.tool-group button.dragging.removing { + cursor: url(img/cursor-select-remove.png), pointer; +} + button.save .count { display: inline-block; border: 0px solid #ccc; @@ -565,15 +561,15 @@ button.add-note svg.icon { .spinner { opacity: .5; - display: flex; - flex-shrink: 2; - justify-content: flex-end; + position: absolute; + right: 4px; + bottom: 26px; } .spinner img { - height: 40px; - width: 40px; - border-radius: 4px; - background: black; + height: 20px; + width: 20px; + background: transparent; + border-radius: 100%; } [dir='rtl'] .spinner img { -moz-transform: scaleX(-1); @@ -589,7 +585,7 @@ button.add-note svg.icon { width: unset; } #bar.narrow .spinner, -#bar.narrow button .label { +#bar.narrow button.bar-button .label { display: none; } #bar.narrow button .count { @@ -597,7 +593,148 @@ button.add-note svg.icon { border-right-width: 0; } +/* Add a feature search bar +------------------------------------------------------- */ +.search-add { + width: 100%; + justify-content: center; + position: relative; +} +.search-add .search-wrap { + position: relative; + width: 100%; + min-width: 200px; + max-width: 250px; + border-radius: 20px 0 0 20px; + background: #fff; +} +.search-add .search-wrap.focused .tooltip { + display: none; +} +.search-add .search-wrap:nth-last-child(2) { + border-radius: 20px; + border: none; +} +.search-add input[type='search'] { + position: relative; + width: 100%; + height: 100%; + border: none; + font-size: 14px; + text-indent: 25px; + padding: 5px 10px; + border-radius: inherit; +} +.search-add .search-icon { + color: #333; + display: block; + position: absolute; + left: 10px; + top: 10px; + pointer-events: none; +} +[dir='rtl'] .search-add .search-icon { + left: auto; + right: 10px; +} +.search-add .popover { + max-height: 250px; + width: 100%; + position: absolute; + top: 44px; + border: none; + border-radius: 6px; + overflow-y: auto; + max-width: 350px; + /* ensure corners are rounded in Chrome */ + -webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC); +} +.search-add .popover::-webkit-scrollbar { + /* don't overlap rounded corners */ + background: transparent; +} +.search-add .popover .list { + max-height: 70vh; +} +.search-add .list-item { + display: flex; + position: relative; + padding: 2px; +} +.search-add .list-item:not(:last-of-type), +.search-add .subsection .list-item { + border-bottom: 1px solid #DCDCDC; +} +.search-add .list-item .label { + font-weight: bold; + font-size: 12px; + padding-left: 2px; + top: 0; + bottom: 0; + position: relative; + display: flex; + align-items: center; + line-height: 1.3em; + width: 100%; +} +.search-add .list-item .label .namepart:nth-child(2) { + font-weight: normal; +} +.search-add .list-item.disabled .preset-icon-container, +.search-add .list-item.disabled .label { + opacity: 0.55; +} +[dir='ltr'] .search-add .list-item .label .icon.inline { + margin-left: 0; +} +[dir='rtl'] .search-add .list-item .label .icon.inline { + margin-right: 0; +} +.search-add .list-item > *:not(button) { + pointer-events: none; +} +.search-add .list-item button.choose { + position: absolute; + border-radius: 0; + height: 100%; + width: 100%; + top: 0; + left: 0; +} +.search-add .list-item button.choose:hover, +.search-add .list-item button.choose:focus { + background: #fff; +} +.search-add .list-item.focused:not(.disabled) button.choose { + background: #e8ebff; +} +.search-add .list-item button.choose.disabled { + background-color: #ececec; +} +.search-add .subsection .list-item button.choose { + opacity: 0.85; +} +.search-add .list-item button.accessory { + position: relative; + flex: 0 0 auto; + color: #808080; + background: transparent; + padding-right: 3px; + padding-left: 3px; +} +.search-add .list-item button.accessory:hover { + color: #666; +} +.search-add .subsection { + background-color: #CBCBCB; +} +[dir='ltr'] .search-add .subsection { + padding-left: 6px; +} +[dir='rtl'] .search-add .subsection { + padding-right: 6px; +} /* Header for modals / panes ------------------------------------------------------- */ .header { @@ -995,9 +1132,16 @@ a.hide-toggle { height: 60px; text-align: center; } -#bar .preset-icon-container { +.preset-icon-container.small { width: 40px; height: 40px; + flex: 0 0 auto; +} + +.preset-icon-point-border path { + stroke: #333; + stroke-width: 1.2; + fill: transparent; } .preset-icon-line { @@ -1034,7 +1178,6 @@ a.hide-toggle { } .preset-icon-fill { - cursor: inherit; margin: auto; position: absolute; width: 100%; @@ -1042,6 +1185,10 @@ a.hide-toggle { left: 0; top: 0; } +.preset-icon-container svg, +.preset-icon-container svg > * { + cursor: inherit !important; +} .preset-icon-fill path.area.stroke { fill: transparent; } @@ -1058,41 +1205,34 @@ a.hide-toggle { height:100%; position: absolute; z-index: 1; + transform: scale(0.48); } .preset-icon .icon { position: absolute; margin: auto; - top: 26%; - left: 26%; - width: 48%; - height: 48%; -} - -.preset-icon.framed .icon { - top: 30%; - left: 30%; - width: 40%; - height: 40%; -} -.preset-icon.framed.line-geom .icon { - top: 20%; -} - -.preset-icon-iD .icon { - top: 0; left: 0; - height: 100%; + right: 0; width: 100%; + height: 100%; } - -.preset-icon-iD.framed .icon { - top: 13%; - left: 13%; - width: 74%; - height: 74%; +.preset-icon-container.small .preset-icon.point-geom { + transform: translateY(-7%) scale(0.27); } -.preset-icon-iD.framed.line-geom .icon { - top: 3%; +.preset-icon.framed { + transform: scale(0.4); +} +.preset-icon.framed.line-geom { + top: 20%; + transform: translateY(-30%) scale(0.4); +} +.preset-icon-iD { + transform: scale(1); +} +.preset-icon-iD.framed { + transform: scale(0.74); +} +.preset-icon-iD.framed.line-geom { + transform: translateY(-30%) scale(0.74); } .preset-list-button .label { @@ -1144,7 +1284,8 @@ a.hide-toggle { .preset-list-item button.tag-reference-button { height: 100%; border: 1px solid #ccc; - flex: 32px; + width: 32px; + flex: 0 0 auto; background: #f6f6f6; } [dir='ltr'] .preset-list-item button.preset-favorite-button, @@ -1173,11 +1314,11 @@ a.hide-toggle { opacity: .5; } -.preset-list-item button.preset-favorite-button .icon { +button.preset-favorite-button .icon { fill-opacity: 0; - stroke-width: 1.6; + stroke-width: 1; } -.preset-list-item button.preset-favorite-button.active .icon { +button.preset-favorite-button.active .icon { fill-opacity: inherit; } @@ -4775,22 +4916,29 @@ svg.mouseclick use.right { } /* dark tooltips for sidebar / panels */ +.tooltip.dark.top .tooltip-arrow, .map-pane .tooltip.top .tooltip-arrow, #sidebar .tooltip.top .tooltip-arrow { border-top-color: #000; } +.tooltip.dark.bottom .tooltip-arrow, .map-pane .tooltip.bottom .tooltip-arrow, #sidebar .tooltip.bottom .tooltip-arrow { border-bottom-color: #000; } +.tooltip.dark.left .tooltip-arrow, .map-pane .tooltip.left .tooltip-arrow, #sidebar .tooltip.left .tooltip-arrow { border-left-color: #000; } +.tooltip.dark.right .tooltip-arrow, .map-pane .tooltip.right .tooltip-arrow, #sidebar .tooltip.right .tooltip-arrow { border-right-color: #000; } +.tooltip.dark .tooltip-inner, +.tooltip.dark .tooltip-heading, +.tooltip.dark .keyhint-wrap, .map-pane .tooltip-inner, .map-pane .tooltip-heading, .map-pane .keyhint-wrap, diff --git a/data/core.yaml b/data/core.yaml index 2f49c4a37..954249d4d 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -9,6 +9,10 @@ en: open_wikidata: open on wikidata.org favorite: favorite modes: + add_feature: + title: Add a feature + description: "Search for features to add to the map." + key: Tab add_area: title: Area description: "Add parks, buildings, lakes or other areas to the map." @@ -21,10 +25,13 @@ en: title: Point description: "Add restaurants, monuments, postal boxes or other points to the map." tail: Click on the map to add a point. + add_vertex: + title: Vertex add_note: title: Note description: "Spotted an issue? Let other mappers know." tail: Click on the map to add a note. + key: N add_preset: title: "Add {feature}" point: @@ -33,6 +40,10 @@ en: title: "Add {feature} as a line" area: title: "Add {feature} as an area" + building: + title: "Add {feature} as a building" + vertex: + title: "Add {feature} as a vertex" browse: title: Browse description: Pan and zoom the map. @@ -1643,10 +1654,12 @@ en: title: "Editing" drawing: title: "Drawing" + focus_add_feature: "Focus the feature search field" add_point: "'Add point' mode" add_line: "'Add line' mode" add_area: "'Add area' mode" add_note: "'Add note' mode" + add_favorite: "Add a favorite feature" place_point: "Place a point or note" disable_snap: "Hold to disable point snapping" stop_line: "Finish drawing a line or area" diff --git a/data/presets.yaml b/data/presets.yaml index b03a03de5..02ff12baa 100644 --- a/data/presets.yaml +++ b/data/presets.yaml @@ -5,34 +5,32 @@ en: name: Barrier Features category-building: name: Building Features - category-golf-area: - name: Golf Features - category-golf-line: + category-golf: name: Golf Features category-landuse: name: Land Use Features - category-natural-area: - name: Natural Features - category-natural-line: - name: Natural Features - category-natural-point: + category-natural: name: Natural Features category-path: - name: Path Features + name: Paths category-rail: - name: Rail Features + name: Rails category-restriction: name: Restriction Features - category-road: - name: Road Features + category-road_major: + name: Major Roads + category-road_minor: + name: Minor Roads + category-road_service: + name: Service Roads category-route: name: Route Features category-utility: name: Utility Features - category-water-area: - name: Water Features - category-water-line: - name: Water Features + category-water: + name: Water Bodies + category-waterway: + name: Waterways fields: access: # 'access=*, foot=*, motor_vehicle=*, bicycle=*, horse=*' @@ -3518,6 +3516,9 @@ en: # building=warehouse name: Warehouse terms: '' + building_point: + # building=* + name: Building camp_site/camp_pitch: # camp_site=camp_pitch name: Camp Pitch @@ -6953,8 +6954,9 @@ en: name: Waterway terms: '' vertex: - name: Other - terms: '' + name: Vertex + # 'terms: other' + terms: '' waterway: # waterway=* name: Waterway diff --git a/data/presets/categories.json b/data/presets/categories.json index b4343a4a2..b7ecc20dc 100644 --- a/data/presets/categories.json +++ b/data/presets/categories.json @@ -2,7 +2,6 @@ "categories": { "category-barrier": { "icon": "maki-roadblock", - "geometry": "line", "name": "Barrier Features", "members": [ "barrier/fence", @@ -16,7 +15,6 @@ }, "category-building": { "icon": "maki-building", - "geometry": "area", "name": "Building Features", "members": [ "building", @@ -29,9 +27,8 @@ "building/residential" ] }, - "category-golf-area": { + "category-golf": { "icon": "maki-golf", - "geometry": "area", "name": "Golf Features", "members": [ "golf/fairway", @@ -41,14 +38,7 @@ "golf/bunker", "golf/tee", "golf/water_hazard", - "golf/driving_range" - ] - }, - "category-golf-line": { - "icon": "maki-golf", - "geometry": "line", - "name": "Golf Features", - "members": [ + "golf/driving_range", "golf/hole", "golf/cartpath", "golf/cartpath_service", @@ -57,7 +47,6 @@ }, "category-landuse": { "icon": "maki-landuse", - "geometry": "area", "name": "Land Use Features", "members": [ "landuse/residential", @@ -74,9 +63,8 @@ "landuse/religious" ] }, - "category-natural-area": { + "category-natural": { "icon": "maki-natural", - "geometry": "area", "name": "Natural Features", "members": [ "natural/water", @@ -88,20 +76,9 @@ "natural/bare_rock", "natural/beach", "natural/cave_entrance", - "natural/glacier" - ] - }, - "category-natural-line": { - "icon": "maki-natural", - "geometry": "line", - "name": "Natural Features", - "members": ["natural/coastline", "natural/tree_row"] - }, - "category-natural-point": { - "icon": "maki-natural", - "geometry": "point", - "name": "Natural Features", - "members": [ + "natural/glacier", + "natural/coastline", + "natural/tree_row", "natural/peak", "natural/cliff", "natural/beach", @@ -109,36 +86,35 @@ ] }, "category-path": { - "icon": "iD-category-path", - "geometry": "line", - "name": "Path Features", + "icon": "temaki-pedestrian", + "name": "Paths", "members": [ + "highway/path", + "highway/footway", "highway/footway/marked", "highway/footway/sidewalk", "highway/steps", - "highway/path", - "highway/footway", "highway/cycleway", "highway/bridleway", "highway/pedestrian_line" ] }, "category-rail": { - "icon": "iD-category-rail", - "geometry": "line", - "name": "Rail Features", + "icon": "iD-railway-rail", + "name": "Rails", "members": [ "railway/rail", - "railway/subway", - "railway/tram", - "railway/monorail", "railway/disused", - "railway/abandoned" + "railway/tram", + "railway/subway", + "railway/narrow_gauge", + "railway/light_rail", + "railway/monorail", + "railway/funicular" ] }, "category-restriction": { "icon": "iD-restriction", - "geometry": "relation", "name": "Restriction Features", "members": [ "type/restriction/no_left_turn", @@ -152,32 +128,48 @@ "type/restriction" ] }, - "category-road": { - "icon": "iD-category-roads", - "geometry": "line", - "name": "Road Features", + "category-road_major": { + "icon": "iD-highway-unclassified", + "name": "Major Roads", "members": [ - "highway/residential", "highway/motorway", "highway/trunk", "highway/primary", "highway/secondary", "highway/tertiary", - "highway/living_street", - "highway/unclassified", - "highway/service", - "highway/track", "highway/motorway_link", "highway/trunk_link", "highway/primary_link", "highway/secondary_link", - "highway/tertiary_link", + "highway/tertiary_link" + ] + }, + "category-road_minor": { + "icon": "iD-highway-unclassified", + "name": "Minor Roads", + "members": [ + "highway/unclassified", + "highway/residential", + "highway/living_street", + "highway/service", + "highway/track", "highway/road" ] }, + "category-road_service": { + "icon": "iD-highway-service", + "name": "Service Roads", + "members": [ + "highway/service", + "highway/service/parking_aisle", + "highway/service/driveway", + "highway/service/alley", + "highway/service/emergency_access", + "highway/service/drive-through" + ] + }, "category-route": { "icon": "iD-route", - "geometry": "relation", "name": "Route Features", "members": [ "type/route/road", @@ -200,8 +192,7 @@ ] }, "category-utility": { - "icon": "iD-category-utility", - "geometry": "line", + "icon": "iD-power-line", "name": "Utility Features", "members": [ "power/line", @@ -210,27 +201,30 @@ "power/cable/underground" ] }, - "category-water-area": { + "category-water": { "icon": "maki-water", - "geometry": "area", - "name": "Water Features", + "name": "Water Bodies", "members": [ - "natural/water/lake", + "natural/water", "natural/water/pond", + "natural/water/basin", + "natural/water/lake", "natural/water/reservoir", - "natural/water" + "natural/bay" ] }, - "category-water-line": { - "icon": "iD-category-water", - "geometry": "line", - "name": "Water Features", + "category-waterway": { + "icon": "iD-waterway-stream", + "name": "Waterways", "members": [ - "waterway/river", "waterway/stream", + "waterway/drain", + "waterway/river", "waterway/canal", "waterway/ditch", - "waterway/drain" + "natural/water/stream", + "natural/water/river", + "natural/water/canal" ] } } diff --git a/data/presets/categories/barrier.json b/data/presets/categories/barrier.json index e3fb9e5fe..752db1d27 100644 --- a/data/presets/categories/barrier.json +++ b/data/presets/categories/barrier.json @@ -1,6 +1,5 @@ { "icon": "maki-roadblock", - "geometry": "line", "name": "Barrier Features", "members": [ "barrier/fence", diff --git a/data/presets/categories/building.json b/data/presets/categories/building.json index 05a116721..0b020a285 100644 --- a/data/presets/categories/building.json +++ b/data/presets/categories/building.json @@ -1,6 +1,5 @@ { "icon": "maki-building", - "geometry": "area", "name": "Building Features", "members": [ "building", diff --git a/data/presets/categories/golf-line.json b/data/presets/categories/golf-line.json deleted file mode 100644 index f108f968d..000000000 --- a/data/presets/categories/golf-line.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "icon": "maki-golf", - "geometry": "line", - "name": "Golf Features", - "members": [ - "golf/hole", - "golf/cartpath", - "golf/cartpath_service", - "golf/path" - ] -} diff --git a/data/presets/categories/golf-area.json b/data/presets/categories/golf.json similarity index 66% rename from data/presets/categories/golf-area.json rename to data/presets/categories/golf.json index 4e43047b9..8b175b4ed 100644 --- a/data/presets/categories/golf-area.json +++ b/data/presets/categories/golf.json @@ -1,6 +1,5 @@ { "icon": "maki-golf", - "geometry": "area", "name": "Golf Features", "members": [ "golf/fairway", @@ -10,6 +9,10 @@ "golf/bunker", "golf/tee", "golf/water_hazard", - "golf/driving_range" + "golf/driving_range", + "golf/hole", + "golf/cartpath", + "golf/cartpath_service", + "golf/path" ] } diff --git a/data/presets/categories/landuse.json b/data/presets/categories/landuse.json index 7d92de866..e4e6ed9c5 100644 --- a/data/presets/categories/landuse.json +++ b/data/presets/categories/landuse.json @@ -1,6 +1,5 @@ { "icon": "maki-landuse", - "geometry": "area", "name": "Land Use Features", "members": [ "landuse/residential", diff --git a/data/presets/categories/natural-line.json b/data/presets/categories/natural-line.json deleted file mode 100644 index 12f1b1705..000000000 --- a/data/presets/categories/natural-line.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "icon": "maki-natural", - "geometry": "line", - "name": "Natural Features", - "members": [ - "natural/coastline", - "natural/tree_row" - ] -} diff --git a/data/presets/categories/natural-point.json b/data/presets/categories/natural-point.json deleted file mode 100644 index e10d5a1ef..000000000 --- a/data/presets/categories/natural-point.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "icon": "maki-natural", - "geometry": "point", - "name": "Natural Features", - "members": [ - "natural/peak", - "natural/cliff", - "natural/beach", - "natural/cave_entrance" - ] -} diff --git a/data/presets/categories/natural-area.json b/data/presets/categories/natural.json similarity index 63% rename from data/presets/categories/natural-area.json rename to data/presets/categories/natural.json index 607f3b11d..020c8e9ae 100644 --- a/data/presets/categories/natural-area.json +++ b/data/presets/categories/natural.json @@ -1,6 +1,5 @@ { "icon": "maki-natural", - "geometry": "area", "name": "Natural Features", "members": [ "natural/water", @@ -12,6 +11,12 @@ "natural/bare_rock", "natural/beach", "natural/cave_entrance", - "natural/glacier" + "natural/glacier", + "natural/coastline", + "natural/tree_row", + "natural/peak", + "natural/cliff", + "natural/beach", + "natural/cave_entrance" ] } diff --git a/data/presets/categories/path.json b/data/presets/categories/path.json index 275e726f3..d48958cde 100644 --- a/data/presets/categories/path.json +++ b/data/presets/categories/path.json @@ -1,13 +1,12 @@ { - "icon": "iD-category-path", - "geometry": "line", - "name": "Path Features", + "icon": "temaki-pedestrian", + "name": "Paths", "members": [ + "highway/path", + "highway/footway", "highway/footway/marked", "highway/footway/sidewalk", "highway/steps", - "highway/path", - "highway/footway", "highway/cycleway", "highway/bridleway", "highway/pedestrian_line" diff --git a/data/presets/categories/rail.json b/data/presets/categories/rail.json index f7489a689..89b226b35 100644 --- a/data/presets/categories/rail.json +++ b/data/presets/categories/rail.json @@ -1,13 +1,14 @@ { - "icon": "iD-category-rail", - "geometry": "line", - "name": "Rail Features", + "icon": "iD-railway-rail", + "name": "Rails", "members": [ "railway/rail", - "railway/subway", - "railway/tram", - "railway/monorail", "railway/disused", - "railway/abandoned" + "railway/tram", + "railway/subway", + "railway/narrow_gauge", + "railway/light_rail", + "railway/monorail", + "railway/funicular" ] } diff --git a/data/presets/categories/restriction.json b/data/presets/categories/restriction.json index bf5bb5d06..52d52f2f3 100644 --- a/data/presets/categories/restriction.json +++ b/data/presets/categories/restriction.json @@ -1,6 +1,5 @@ { "icon": "iD-restriction", - "geometry": "relation", "name": "Restriction Features", "members": [ "type/restriction/no_left_turn", diff --git a/data/presets/categories/road.json b/data/presets/categories/road_major.json similarity index 50% rename from data/presets/categories/road.json rename to data/presets/categories/road_major.json index eaabdf505..0a0d912a1 100644 --- a/data/presets/categories/road.json +++ b/data/presets/categories/road_major.json @@ -1,23 +1,16 @@ { - "icon": "iD-category-roads", - "geometry": "line", - "name": "Road Features", + "icon": "iD-highway-unclassified", + "name": "Major Roads", "members": [ - "highway/residential", "highway/motorway", "highway/trunk", "highway/primary", "highway/secondary", "highway/tertiary", - "highway/living_street", - "highway/unclassified", - "highway/service", - "highway/track", "highway/motorway_link", "highway/trunk_link", "highway/primary_link", "highway/secondary_link", - "highway/tertiary_link", - "highway/road" + "highway/tertiary_link" ] } diff --git a/data/presets/categories/road_minor.json b/data/presets/categories/road_minor.json new file mode 100644 index 000000000..5b7d5aeaa --- /dev/null +++ b/data/presets/categories/road_minor.json @@ -0,0 +1,12 @@ +{ + "icon": "iD-highway-unclassified", + "name": "Minor Roads", + "members": [ + "highway/unclassified", + "highway/residential", + "highway/living_street", + "highway/service", + "highway/track", + "highway/road" + ] +} diff --git a/data/presets/categories/road_service.json b/data/presets/categories/road_service.json new file mode 100644 index 000000000..632345405 --- /dev/null +++ b/data/presets/categories/road_service.json @@ -0,0 +1,12 @@ +{ + "icon": "iD-highway-service", + "name": "Service Roads", + "members": [ + "highway/service", + "highway/service/parking_aisle", + "highway/service/driveway", + "highway/service/alley", + "highway/service/emergency_access", + "highway/service/drive-through" + ] +} diff --git a/data/presets/categories/route.json b/data/presets/categories/route.json index 6c05b0b03..35a16337f 100644 --- a/data/presets/categories/route.json +++ b/data/presets/categories/route.json @@ -1,6 +1,5 @@ { "icon": "iD-route", - "geometry": "relation", "name": "Route Features", "members": [ "type/route/road", diff --git a/data/presets/categories/utility.json b/data/presets/categories/utility.json index 63aae92d0..215e331fb 100644 --- a/data/presets/categories/utility.json +++ b/data/presets/categories/utility.json @@ -1,6 +1,5 @@ { - "icon": "iD-category-utility", - "geometry": "line", + "icon": "iD-power-line", "name": "Utility Features", "members": [ "power/line", diff --git a/data/presets/categories/water-line.json b/data/presets/categories/water-line.json deleted file mode 100644 index 7a7c8c3ff..000000000 --- a/data/presets/categories/water-line.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "icon": "iD-category-water", - "geometry": "line", - "name": "Water Features", - "members": [ - "waterway/river", - "waterway/stream", - "waterway/canal", - "waterway/ditch", - "waterway/drain" - ] -} diff --git a/data/presets/categories/water-area.json b/data/presets/categories/water.json similarity index 58% rename from data/presets/categories/water-area.json rename to data/presets/categories/water.json index 99c83125a..1a4eda92a 100644 --- a/data/presets/categories/water-area.json +++ b/data/presets/categories/water.json @@ -1,11 +1,12 @@ { "icon": "maki-water", - "geometry": "area", - "name": "Water Features", + "name": "Water Bodies", "members": [ - "natural/water/lake", + "natural/water", "natural/water/pond", + "natural/water/basin", + "natural/water/lake", "natural/water/reservoir", - "natural/water" + "natural/bay" ] } diff --git a/data/presets/categories/waterway.json b/data/presets/categories/waterway.json new file mode 100644 index 000000000..0b531eb4d --- /dev/null +++ b/data/presets/categories/waterway.json @@ -0,0 +1,14 @@ +{ + "icon": "iD-waterway-stream", + "name": "Waterways", + "members": [ + "waterway/stream", + "waterway/drain", + "waterway/river", + "waterway/canal", + "waterway/ditch", + "natural/water/stream", + "natural/water/river", + "natural/water/canal" + ] +} diff --git a/data/presets/defaults.json b/data/presets/defaults.json index 71247c4da..7668b15c2 100644 --- a/data/presets/defaults.json +++ b/data/presets/defaults.json @@ -3,8 +3,8 @@ "area": [ "category-landuse", "category-building", - "category-water-area", - "category-natural-area", + "category-water", + "category-natural", "leisure/park", "amenity/hospital", "amenity/place_of_worship", @@ -13,17 +13,18 @@ "area" ], "line": [ - "category-road", + "category-road_major", + "category-road_minor", "category-rail", "category-path", - "category-water-line", + "category-waterway", "category-barrier", - "category-natural-line", + "category-natural", "category-utility", "line" ], "point": [ - "category-natural-point", + "category-natural", "leisure/park", "amenity/hospital", "amenity/place_of_worship", diff --git a/data/presets/presets.json b/data/presets/presets.json index 39cbe3530..dca17b874 100644 --- a/data/presets/presets.json +++ b/data/presets/presets.json @@ -5,6 +5,7 @@ "amenity": {"fields": ["amenity"], "geometry": ["point", "vertex", "line", "area"], "tags": {"amenity": "*"}, "searchable": false, "name": "Amenity"}, "attraction": {"icon": "maki-star", "fields": ["name", "attraction", "operator", "opening_hours"], "moreFields": ["opening_hours", "fee", "payment_multi", "address", "website", "phone", "email", "fax"], "geometry": ["point", "vertex", "line", "area"], "tags": {"attraction": "*"}, "searchable": false, "name": "Attraction"}, "boundary": {"fields": ["boundary"], "geometry": ["line"], "tags": {"boundary": "*"}, "searchable": false, "name": "Boundary"}, + "building_point": {"icon": "maki-home", "fields": ["{building}"], "moreFields": ["{building}"], "geometry": ["point"], "tags": {"building": "*"}, "matchScore": 0.6, "searchable": false, "terms": [], "name": "Building"}, "circular": {"geometry": ["vertex", "line"], "fields": ["name"], "tags": {"junction": "circular"}, "name": "Traffic Circle", "searchable": false}, "embankment": {"geometry": ["line"], "tags": {"embankment": "yes"}, "name": "Embankment", "matchScore": 0.2, "searchable": false}, "highway": {"fields": ["name", "highway"], "geometry": ["point", "vertex", "line", "area"], "tags": {"highway": "*"}, "searchable": false, "name": "Highway"}, @@ -264,7 +265,7 @@ "boundary/administrative": {"name": "Administrative Boundary", "geometry": ["line"], "tags": {"boundary": "administrative"}, "fields": ["name", "admin_level"]}, "bridge/support": {"icon": "fas-archway", "fields": ["bridge/support"], "moreFields": ["material", "seamark/type"], "geometry": ["point", "vertex", "area"], "tags": {"bridge:support": "*"}, "name": "Bridge Support"}, "bridge/support/pier": {"icon": "fas-archway", "fields": ["bridge/support"], "moreFields": ["material", "seamark/type"], "geometry": ["point", "vertex", "area"], "tags": {"bridge:support": "pier"}, "name": "Bridge Pier"}, - "building": {"icon": "maki-home", "fields": ["name", "building", "levels", "height", "address"], "moreFields": ["architect", "building/material", "layer", "roof/colour", "smoking", "wheelchair"], "geometry": ["point", "area"], "tags": {"building": "*"}, "matchScore": 0.6, "terms": [], "name": "Building"}, + "building": {"icon": "maki-home", "fields": ["name", "building", "levels", "height", "address"], "moreFields": ["architect", "building/material", "layer", "roof/colour", "smoking", "wheelchair"], "geometry": ["area"], "tags": {"building": "*"}, "matchScore": 0.6, "terms": [], "name": "Building"}, "building/bunker": {"geometry": ["area"], "tags": {"building": "bunker"}, "matchScore": 0.5, "name": "Bunker", "searchable": false}, "building/entrance": {"icon": "maki-entrance-alt1", "fields": [], "moreFields": [], "geometry": ["vertex"], "tags": {"building": "entrance"}, "name": "Entrance/Exit", "searchable": false}, "building/train_station": {"icon": "maki-building", "geometry": ["point", "vertex", "area"], "tags": {"building": "train_station"}, "matchScore": 0.5, "name": "Train Station Building", "searchable": false}, @@ -677,12 +678,12 @@ "natural/volcano": {"icon": "maki-volcano", "fields": ["name", "elevation", "volcano/status", "volcano/type"], "geometry": ["point", "vertex"], "tags": {"natural": "volcano"}, "terms": ["mountain", "crater"], "name": "Volcano"}, "natural/water": {"icon": "maki-water", "fields": ["name", "water", "intermittent"], "moreFields": ["salt", "tidal"], "geometry": ["area"], "tags": {"natural": "water"}, "name": "Water"}, "natural/water/basin": {"icon": "maki-water", "fields": ["name", "basin", "intermittent_yes"], "geometry": ["area"], "tags": {"natural": "water", "water": "basin"}, "reference": {"key": "water", "value": "basin"}, "terms": ["detention", "drain", "overflow", "rain", "retention"], "name": "Basin"}, - "natural/water/canal": {"icon": "maki-water", "fields": ["{natural/water}", "salt"], "geometry": ["area"], "tags": {"natural": "water", "water": "canal"}, "reference": {"key": "water", "value": "canal"}, "name": "Canal"}, + "natural/water/canal": {"icon": "iD-waterway-canal", "fields": ["{natural/water}", "salt"], "geometry": ["area"], "tags": {"natural": "water", "water": "canal"}, "reference": {"key": "water", "value": "canal"}, "name": "Canal"}, "natural/water/lake": {"icon": "maki-water", "fields": ["{natural/water}", "salt", "tidal"], "geometry": ["area"], "tags": {"natural": "water", "water": "lake"}, "reference": {"key": "water", "value": "lake"}, "terms": ["lakelet", "loch", "mere"], "name": "Lake"}, "natural/water/pond": {"icon": "maki-water", "fields": ["{natural/water}", "salt"], "geometry": ["area"], "tags": {"natural": "water", "water": "pond"}, "reference": {"key": "water", "value": "pond"}, "terms": ["lakelet", "millpond", "tarn", "pool", "mere"], "name": "Pond"}, "natural/water/reservoir": {"icon": "maki-water", "geometry": ["area"], "tags": {"natural": "water", "water": "reservoir"}, "reference": {"key": "water", "value": "reservoir"}, "name": "Reservoir"}, - "natural/water/river": {"icon": "maki-water", "fields": ["{natural/water}", "tidal"], "geometry": ["area"], "tags": {"natural": "water", "water": "river"}, "reference": {"key": "water", "value": "river"}, "terms": ["beck", "branch", "brook", "course", "creek", "estuary", "rill", "riverbank", "rivulet", "run", "runnel", "stream", "tributary", "watercourse"], "name": "River"}, - "natural/water/stream": {"icon": "maki-water", "fields": ["{natural/water}"], "geometry": ["area"], "tags": {"natural": "water", "water": "stream"}, "reference": {"key": "water", "value": "stream"}, "terms": ["beck", "branch", "brook", "burn", "course", "creek", "current", "drift", "flood", "flow", "freshet", "race", "rill", "rindle", "rivulet", "run", "runnel", "rush", "spate", "spritz", "surge", "tide", "torrent", "tributary", "watercourse"], "name": "Stream"}, + "natural/water/river": {"icon": "iD-waterway-river", "fields": ["{natural/water}", "tidal"], "geometry": ["area"], "tags": {"natural": "water", "water": "river"}, "reference": {"key": "water", "value": "river"}, "terms": ["beck", "branch", "brook", "course", "creek", "estuary", "rill", "riverbank", "rivulet", "run", "runnel", "stream", "tributary", "watercourse"], "name": "River"}, + "natural/water/stream": {"icon": "iD-waterway-stream", "fields": ["{natural/water}"], "geometry": ["area"], "tags": {"natural": "water", "water": "stream"}, "reference": {"key": "water", "value": "stream"}, "terms": ["beck", "branch", "brook", "burn", "course", "creek", "current", "drift", "flood", "flow", "freshet", "race", "rill", "rindle", "rivulet", "run", "runnel", "rush", "spate", "spritz", "surge", "tide", "torrent", "tributary", "watercourse"], "name": "Stream"}, "natural/wetland": {"icon": "maki-wetland", "fields": ["wetland"], "geometry": ["point", "area"], "tags": {"natural": "wetland"}, "terms": ["bog", "marsh", "reedbed", "swamp", "tidalflat"], "name": "Wetland"}, "natural/wood": {"icon": "maki-park-alt1", "fields": ["name", "leaf_type", "leaf_cycle"], "geometry": ["point", "area"], "tags": {"natural": "wood"}, "terms": ["tree"], "name": "Wood"}, "noexit/yes": {"icon": "maki-barrier", "geometry": ["vertex"], "terms": ["no exit", "road end", "dead end"], "tags": {"noexit": "yes"}, "reference": {"key": "noexit", "value": "*"}, "name": "No Exit"}, @@ -1060,7 +1061,7 @@ "type/route/tram": {"icon": "iD-route-tram", "fields": ["name", "ref_route", "operator", "network", "to", "from"], "geometry": ["relation"], "tags": {"type": "route", "route": "tram"}, "name": "Tram Route"}, "type/site": {"icon": "iD-relation", "fields": ["name", "site"], "geometry": ["relation"], "tags": {"type": "site"}, "name": "Site"}, "type/waterway": {"icon": "iD-route-water", "fields": ["name", "waterway", "ref"], "geometry": ["relation"], "tags": {"type": "waterway"}, "name": "Waterway"}, - "vertex": {"moreFields": ["name"], "geometry": ["vertex"], "tags": {}, "name": "Other", "matchScore": 0.1}, + "vertex": {"moreFields": ["name"], "geometry": ["vertex"], "terms": ["other"], "tags": {}, "name": "Vertex", "matchScore": 0.1}, "waterway/riverbank": {"icon": "maki-water", "geometry": ["area"], "tags": {"waterway": "riverbank"}, "name": "Riverbank", "searchable": false}, "waterway/boatyard": {"icon": "maki-harbor", "fields": ["name", "operator"], "moreFields": ["address", "website", "phone", "email", "fax", "wheelchair"], "geometry": ["area", "vertex", "point"], "tags": {"waterway": "boatyard"}, "name": "Boatyard"}, "waterway/canal": {"icon": "iD-waterway-canal", "fields": ["name", "width", "intermittent"], "moreFields": ["salt"], "geometry": ["line"], "tags": {"waterway": "canal"}, "name": "Canal"}, diff --git a/data/presets/presets/_building_point.json b/data/presets/presets/_building_point.json new file mode 100644 index 000000000..0cce45b4f --- /dev/null +++ b/data/presets/presets/_building_point.json @@ -0,0 +1,19 @@ +{ + "icon": "maki-home", + "fields": [ + "{building}" + ], + "moreFields": [ + "{building}" + ], + "geometry": [ + "point" + ], + "tags": { + "building": "*" + }, + "matchScore": 0.6, + "searchable": false, + "terms": [], + "name": "Building" +} diff --git a/data/presets/presets/building.json b/data/presets/presets/building.json index 771e7129c..7484840cd 100644 --- a/data/presets/presets/building.json +++ b/data/presets/presets/building.json @@ -16,7 +16,6 @@ "wheelchair" ], "geometry": [ - "point", "area" ], "tags": { diff --git a/data/presets/presets/natural/water/canal.json b/data/presets/presets/natural/water/canal.json index 510d4fb6b..96505bb92 100644 --- a/data/presets/presets/natural/water/canal.json +++ b/data/presets/presets/natural/water/canal.json @@ -1,5 +1,5 @@ { - "icon": "maki-water", + "icon": "iD-waterway-canal", "fields": [ "{natural/water}", "salt" diff --git a/data/presets/presets/natural/water/river.json b/data/presets/presets/natural/water/river.json index 3847098a0..5909ba6d6 100644 --- a/data/presets/presets/natural/water/river.json +++ b/data/presets/presets/natural/water/river.json @@ -1,5 +1,5 @@ { - "icon": "maki-water", + "icon": "iD-waterway-river", "fields": [ "{natural/water}", "tidal" diff --git a/data/presets/presets/natural/water/stream.json b/data/presets/presets/natural/water/stream.json index 2f57eda40..a7b9425f8 100644 --- a/data/presets/presets/natural/water/stream.json +++ b/data/presets/presets/natural/water/stream.json @@ -1,5 +1,5 @@ { - "icon": "maki-water", + "icon": "iD-waterway-stream", "fields": [ "{natural/water}" ], diff --git a/data/presets/presets/vertex.json b/data/presets/presets/vertex.json index 85c3ddbc6..228e00fd3 100644 --- a/data/presets/presets/vertex.json +++ b/data/presets/presets/vertex.json @@ -5,7 +5,10 @@ "geometry": [ "vertex" ], + "terms": [ + "other" + ], "tags": {}, - "name": "Other", + "name": "Vertex", "matchScore": 0.1 } diff --git a/data/shortcuts.json b/data/shortcuts.json index 6c80699a1..cdda16290 100644 --- a/data/shortcuts.json +++ b/data/shortcuts.json @@ -157,19 +157,17 @@ "text": "shortcuts.editing.drawing.title" }, { - "shortcuts": ["1"], - "text": "shortcuts.editing.drawing.add_point" + "shortcuts": ["modes.add_feature.key"], + "text": "shortcuts.editing.drawing.focus_add_feature" }, { - "shortcuts": ["2"], - "text": "shortcuts.editing.drawing.add_line" + "shortcuts": ["1", "2", "3"], + "text": "shortcuts.editing.drawing.add_favorite", + "separator": ",", + "suffix": "…" }, { - "shortcuts": ["3"], - "text": "shortcuts.editing.drawing.add_area" - }, - { - "shortcuts": ["4"], + "shortcuts": ["modes.add_note.key"], "text": "shortcuts.editing.drawing.add_note" }, { diff --git a/data/taginfo.json b/data/taginfo.json index 7048c75fb..1f11b3ffe 100644 --- a/data/taginfo.json +++ b/data/taginfo.json @@ -8,6 +8,7 @@ {"key": "amenity", "description": "🄿 Amenity (unsearchable), 🄵 Type", "object_types": ["node", "way", "area"]}, {"key": "attraction", "description": "🄿 Attraction (unsearchable), 🄵 Type", "object_types": ["node", "way", "area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/star-15.svg?sanitize=true"}, {"key": "boundary", "description": "🄿 Boundary (unsearchable), 🄵 Type", "object_types": ["way"]}, + {"key": "building", "description": "🄿 Building (unsearchable), 🄿 Building, 🄵 Building", "object_types": ["node"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/home-15.svg?sanitize=true"}, {"key": "junction", "value": "circular", "description": "🄿 Traffic Circle (unsearchable), 🄵 Junction", "object_types": ["node", "way"]}, {"key": "embankment", "value": "yes", "description": "🄿 Embankment (unsearchable)", "object_types": ["way"]}, {"key": "highway", "description": "🄿 Highway (unsearchable), 🄵 Type", "object_types": ["node", "way", "area"]}, @@ -261,7 +262,6 @@ {"key": "boundary", "value": "administrative", "description": "🄿 Administrative Boundary", "object_types": ["way"]}, {"key": "bridge:support", "description": "🄿 Bridge Support, 🄵 Type", "object_types": ["node", "area"], "icon_url": "https://raw.githubusercontent.com/openstreetmap/iD/master/svg/fontawesome/fas-archway.svg?sanitize=true"}, {"key": "bridge:support", "value": "pier", "description": "🄿 Bridge Pier", "object_types": ["node", "area"], "icon_url": "https://raw.githubusercontent.com/openstreetmap/iD/master/svg/fontawesome/fas-archway.svg?sanitize=true"}, - {"key": "building", "description": "🄿 Building, 🄵 Building", "object_types": ["node", "area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/home-15.svg?sanitize=true"}, {"key": "building", "value": "bunker", "description": "🄿 Bunker (unsearchable)", "object_types": ["area"]}, {"key": "building", "value": "entrance", "description": "🄿 Entrance/Exit (unsearchable)", "object_types": ["node"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/entrance-alt1-15.svg?sanitize=true"}, {"key": "building", "value": "train_station", "description": "🄿 Train Station Building (unsearchable)", "object_types": ["node", "area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/building-15.svg?sanitize=true"}, @@ -655,12 +655,12 @@ {"key": "natural", "value": "tree", "description": "🄿 Tree", "object_types": ["node"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/park-15.svg?sanitize=true"}, {"key": "natural", "value": "volcano", "description": "🄿 Volcano", "object_types": ["node"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/volcano-15.svg?sanitize=true"}, {"key": "water", "value": "basin", "description": "🄿 Basin", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/water-15.svg?sanitize=true"}, - {"key": "water", "value": "canal", "description": "🄿 Canal", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/water-15.svg?sanitize=true"}, + {"key": "water", "value": "canal", "description": "🄿 Canal", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/openstreetmap/iD/master/svg/iD-sprite/presets/waterway-canal.svg?sanitize=true"}, {"key": "water", "value": "lake", "description": "🄿 Lake", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/water-15.svg?sanitize=true"}, {"key": "water", "value": "pond", "description": "🄿 Pond", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/water-15.svg?sanitize=true"}, {"key": "water", "value": "reservoir", "description": "🄿 Reservoir", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/water-15.svg?sanitize=true"}, - {"key": "water", "value": "river", "description": "🄿 River", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/water-15.svg?sanitize=true"}, - {"key": "water", "value": "stream", "description": "🄿 Stream", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/water-15.svg?sanitize=true"}, + {"key": "water", "value": "river", "description": "🄿 River", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/openstreetmap/iD/master/svg/iD-sprite/presets/waterway-river.svg?sanitize=true"}, + {"key": "water", "value": "stream", "description": "🄿 Stream", "object_types": ["area"], "icon_url": "https://raw.githubusercontent.com/openstreetmap/iD/master/svg/iD-sprite/presets/waterway-stream.svg?sanitize=true"}, {"key": "natural", "value": "wetland", "description": "🄿 Wetland", "object_types": ["node", "area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/wetland-15.svg?sanitize=true"}, {"key": "natural", "value": "wood", "description": "🄿 Wood", "object_types": ["node", "area"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/park-alt1-15.svg?sanitize=true"}, {"key": "noexit", "value": "yes", "description": "🄿 No Exit", "object_types": ["node"], "icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/barrier-15.svg?sanitize=true"}, diff --git a/dist/locales/en.json b/dist/locales/en.json index 9cccb0f90..4ff7c9bc6 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -11,6 +11,11 @@ "favorite": "favorite" }, "modes": { + "add_feature": { + "title": "Add a feature", + "description": "Search for features to add to the map.", + "key": "Tab" + }, "add_area": { "title": "Area", "description": "Add parks, buildings, lakes or other areas to the map.", @@ -26,10 +31,14 @@ "description": "Add restaurants, monuments, postal boxes or other points to the map.", "tail": "Click on the map to add a point." }, + "add_vertex": { + "title": "Vertex" + }, "add_note": { "title": "Note", "description": "Spotted an issue? Let other mappers know.", - "tail": "Click on the map to add a note." + "tail": "Click on the map to add a note.", + "key": "N" }, "add_preset": { "title": "Add {feature}", @@ -41,6 +50,12 @@ }, "area": { "title": "Add {feature} as an area" + }, + "building": { + "title": "Add {feature} as a building" + }, + "vertex": { + "title": "Add {feature} as a vertex" } }, "browse": { @@ -1982,10 +1997,12 @@ "title": "Editing", "drawing": { "title": "Drawing", + "focus_add_feature": "Focus the feature search field", "add_point": "'Add point' mode", "add_line": "'Add line' mode", "add_area": "'Add area' mode", "add_note": "'Add note' mode", + "add_favorite": "Add a favorite feature", "place_point": "Place a point or note", "disable_snap": "Hold to disable point snapping", "stop_line": "Finish drawing a line or area" @@ -2063,35 +2080,32 @@ "category-building": { "name": "Building Features" }, - "category-golf-area": { - "name": "Golf Features" - }, - "category-golf-line": { + "category-golf": { "name": "Golf Features" }, "category-landuse": { "name": "Land Use Features" }, - "category-natural-area": { - "name": "Natural Features" - }, - "category-natural-line": { - "name": "Natural Features" - }, - "category-natural-point": { + "category-natural": { "name": "Natural Features" }, "category-path": { - "name": "Path Features" + "name": "Paths" }, "category-rail": { - "name": "Rail Features" + "name": "Rails" }, "category-restriction": { "name": "Restriction Features" }, - "category-road": { - "name": "Road Features" + "category-road_major": { + "name": "Major Roads" + }, + "category-road_minor": { + "name": "Minor Roads" + }, + "category-road_service": { + "name": "Service Roads" }, "category-route": { "name": "Route Features" @@ -2099,11 +2113,11 @@ "category-utility": { "name": "Utility Features" }, - "category-water-area": { - "name": "Water Features" + "category-water": { + "name": "Water Bodies" }, - "category-water-line": { - "name": "Water Features" + "category-waterway": { + "name": "Waterways" } }, "fields": { @@ -3916,6 +3930,10 @@ "name": "Boundary", "terms": "" }, + "building_point": { + "name": "Building", + "terms": "" + }, "circular": { "name": "Traffic Circle", "terms": "" @@ -8137,8 +8155,8 @@ "terms": "" }, "vertex": { - "name": "Other", - "terms": "" + "name": "Vertex", + "terms": "other" }, "waterway/riverbank": { "name": "Riverbank", diff --git a/modules/behavior/draw.js b/modules/behavior/draw.js index d12eaadd0..8959569f4 100644 --- a/modules/behavior/draw.js +++ b/modules/behavior/draw.js @@ -127,11 +127,13 @@ export function behaviorDraw(context) { var d = datum(); var target = d && d.properties && d.properties.entity; + var mode = context.mode(); + if (target && target.type === 'node' && allowsVertex(target)) { // Snap to a node dispatch.call('clickNode', this, target, d); return; - } else if (target && target.type === 'way') { // Snap to a way + } else if (target && target.type === 'way' && (mode.id !== 'add-point' || mode.preset.matchGeometry('vertex'))) { // Snap to a way var choice = geoChooseEdge( context.childNodes(target), context.mouse(), context.projection, context.activeID() ); @@ -140,8 +142,10 @@ export function behaviorDraw(context) { dispatch.call('clickWay', this, choice.loc, edge, d); return; } + } else if (mode.id !== 'add-point' || mode.preset.matchGeometry('point')) { + dispatch.call('click', this, context.map().mouseCoordinates(), d); } - dispatch.call('click', this, context.map().mouseCoordinates(), d); + } diff --git a/modules/behavior/draw_way.js b/modules/behavior/draw_way.js index db3a80a79..e11f7fc80 100644 --- a/modules/behavior/draw_way.js +++ b/modules/behavior/draw_way.js @@ -350,7 +350,8 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin window.setTimeout(function() { context.map().dblclickEnable(true); }, 1000); - var isNewFeature = !mode.isContinuing && mode.button.indexOf('add-preset-') === -1; + + var isNewFeature = !mode.isContinuing && context.presets().match(origWay, context.graph()).isFallback(); context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature)); if (isNewFeature) { context.validator().validate(); diff --git a/modules/behavior/hover.js b/modules/behavior/hover.js index 63b26751b..6cc286b93 100644 --- a/modules/behavior/hover.js +++ b/modules/behavior/hover.js @@ -107,6 +107,15 @@ export function behaviorHover(context) { return d.geometry(context.graph()) === 'vertex' || context.presets().allowsVertex(d, context.graph()); } + function modeAllowsHover(target) { + var mode = context.mode(); + if (mode.id === 'add-point') { + return mode.preset.matchGeometry('vertex') || + (target.type !== 'way' && target.geometry(context.graph()) !== 'vertex'); + } + return true; + } + function enter(datum) { if (datum === _target) return; _target = datum; @@ -144,17 +153,20 @@ export function behaviorHover(context) { } } + var mode = context.mode(); + // Update hover state and dispatch event if (entity && entity.id !== _newNodeId) { // If drawing a way, don't hover on a node that was just placed. #3974 - var mode = context.mode() && context.mode().id; - if ((mode === 'draw-line' || mode === 'draw-area') && !_newNodeId && entity.type === 'node') { + + if ((mode.id === 'draw-line' || mode.id === 'draw-area') && !_newNodeId && entity.type === 'node') { _newNodeId = entity.id; return; } var suppressed = (_altDisables && d3_event && d3_event.altKey) || - (entity.type === 'node' && _ignoreVertex && !allowsVertex(entity)); + (entity.type === 'node' && _ignoreVertex && !allowsVertex(entity)) || + !modeAllowsHover(entity); _selection.selectAll(selector) .classed(suppressed ? 'hover-suppressed' : 'hover', true); diff --git a/modules/core/context.js b/modules/core/context.js index 9e730711a..7f6820c68 100644 --- a/modules/core/context.js +++ b/modules/core/context.js @@ -316,6 +316,12 @@ export function coreContext() { context.getFavoritePresets = function() { return JSON.parse(context.storage('favorite_presets')) || []; }; + function setFavoritePresets(favs) { + context.storage('favorite_presets', JSON.stringify(favs)); + + //and call update on modes + dispatch.call('favoritePreset'); + } context.favoritePreset = function(preset, geom) { var favs = context.getFavoritePresets(); @@ -325,26 +331,28 @@ export function coreContext() { return !(d.id === preset.id && d.geom === geom); }); } else { - // only allow 3 favorites - if (favs.length === 3) { - // remove the last favorite (first in, first out) + // only allow 10 favorites + if (favs.length === 10) { + // remove the last favorite (last in, first out) favs.pop(); } - // prepend array - favs.unshift({id: preset.id, geom: geom}); + // append array + favs.push({id: preset.id, geom: geom}); } - - context.storage('favorite_presets', JSON.stringify(favs)); - - //and call update on modes - dispatch.call('favoritePreset'); + setFavoritePresets(favs); }; + context.isFavoritePreset = function(preset, geom) { var favs = context.getFavoritePresets(); return favs.some(function(d) { return d.id === preset.id && d.geom === geom; }); }; + context.moveFavoritePreset = function(fromIndex, toIndex) { + var favs = context.getFavoritePresets(); + favs.splice(toIndex, 0, favs.splice(fromIndex, 1)[0]); + setFavoritePresets(favs); + }; /* Map */ var map; diff --git a/modules/modes/add_area.js b/modules/modes/add_area.js index 55b344943..891cd0631 100644 --- a/modules/modes/add_area.js +++ b/modules/modes/add_area.js @@ -10,14 +10,8 @@ import { modeDrawArea } from './index'; import { osmNode, osmWay } from '../osm'; -export function modeAddArea(context, customMode) { - var mode = customMode || { - id: 'add-area', - button: 'area', - title: t('modes.add_area.title'), - description: t('modes.add_area.description'), - key: '3' - }; +export function modeAddArea(context, mode) { + mode.id = 'add-area'; var behavior = behaviorAddWay(context) .tail(t('modes.add_area.tail')) diff --git a/modules/modes/add_line.js b/modules/modes/add_line.js index 82f4578ae..c4e6801f1 100644 --- a/modules/modes/add_line.js +++ b/modules/modes/add_line.js @@ -10,14 +10,8 @@ import { modeDrawLine } from './index'; import { osmNode, osmWay } from '../osm'; -export function modeAddLine(context, customMode) { - var mode = customMode || { - id: 'add-line', - button: 'line', - title: t('modes.add_line.title'), - description: t('modes.add_line.description'), - key: '2' - }; +export function modeAddLine(context, mode) { + mode.id = 'add-line'; var behavior = behaviorAddWay(context) .tail(t('modes.add_line.tail')) diff --git a/modules/modes/add_note.js b/modules/modes/add_note.js index 8f7f065a0..d7e105113 100644 --- a/modules/modes/add_note.js +++ b/modules/modes/add_note.js @@ -11,7 +11,7 @@ export function modeAddNote(context) { button: 'note', title: t('modes.add_note.title'), description: t('modes.add_note.description'), - key: '4' + key: t('modes.add_note.key') }; var behavior = behaviorDraw(context) diff --git a/modules/modes/add_point.js b/modules/modes/add_point.js index 3b79f86b6..d3c490d72 100644 --- a/modules/modes/add_point.js +++ b/modules/modes/add_point.js @@ -1,19 +1,16 @@ +import _clone from 'lodash-es/clone'; + import { t } from '../util/locale'; -import { actionAddEntity } from '../actions'; +import { actionAddEntity, actionChangeTags } from '../actions'; import { behaviorDraw } from '../behavior'; import { modeBrowse, modeSelect } from './index'; import { osmNode } from '../osm'; import { actionAddMidpoint } from '../actions'; -export function modeAddPoint(context, customMode) { - var mode = customMode || { - id: 'add-point', - button: 'point', - title: t('modes.add_point.title'), - description: t('modes.add_point.description'), - key: '1' - }; +export function modeAddPoint(context, mode) { + + mode.id = 'add-point'; var behavior = behaviorDraw(context) .tail(t('modes.add_point.tail')) @@ -35,9 +32,7 @@ export function modeAddPoint(context, customMode) { t('operations.add.annotation.point') ); - context.enter( - modeSelect(context, [node.id]).newFeature(!mode.preset) - ); + enterSelectMode(node); } @@ -49,14 +44,34 @@ export function modeAddPoint(context, customMode) { t('operations.add.annotation.vertex') ); + enterSelectMode(node); + } + + function enterSelectMode(node) { context.enter( - modeSelect(context, [node.id]).newFeature(!mode.preset) + modeSelect(context, [node.id]).newFeature(mode.preset.isFallback()) ); } function addNode(node) { - add(node.loc); + + if (Object.keys(defaultTags).length === 0) { + enterSelectMode(node); + return; + } + + var tags = _clone(node.tags); + for (var key in defaultTags) { + tags[key] = defaultTags[key]; + } + + context.perform( + actionChangeTags(node.id, tags), + t('operations.add.annotation.point') + ); + + enterSelectMode(node); } diff --git a/modules/presets/category.js b/modules/presets/category.js index 3a538aae0..582ef71ca 100644 --- a/modules/presets/category.js +++ b/modules/presets/category.js @@ -14,6 +14,17 @@ export function presetCategory(id, category, all) { })); + category.geometry = category.members.collection.reduce(function(geometries, preset) { + for (var index in preset.geometry) { + var geometry = preset.geometry[index]; + if (geometries.indexOf(geometry) === -1) { + geometries.push(geometry); + } + } + return geometries; + }, []); + + category.matchGeometry = function(geometry) { return category.geometry.indexOf(geometry) >= 0; }; diff --git a/modules/presets/collection.js b/modules/presets/collection.js index d110ee059..08a3b65e2 100644 --- a/modules/presets/collection.js +++ b/modules/presets/collection.js @@ -34,6 +34,14 @@ export function presetCollection(collection) { })); }, + matchAnyGeometry: function(geometries) { + return presetCollection(this.collection.filter(function(d) { + return geometries.some(function(geometry) { + return d.matchGeometry(geometry); + }); + })); + }, + search: function(value, geometry) { if (!value) return this; @@ -134,8 +142,6 @@ export function presetCollection(collection) { return a.preset; }); - var other = presets.item(geometry); - var results = leading_name.concat( leading_suggestions, leading_terms, @@ -145,7 +151,17 @@ export function presetCollection(collection) { similar_terms ).slice(0, maxSearchResults - 1); - return presetCollection(_uniq(results.concat(other))); + if (geometry) { + if (typeof geometry === 'string') { + results.push(presets.item(geometry)); + } else { + geometry.forEach(function(geom) { + results.push(presets.item(geom)); + }); + } + } + + return presetCollection(_uniq(results)); } }; diff --git a/modules/presets/index.js b/modules/presets/index.js index 44a3694d6..37a8b9338 100644 --- a/modules/presets/index.js +++ b/modules/presets/index.js @@ -268,6 +268,10 @@ export function presetIndex() { return presetCollection(_uniq(rec.concat(def).concat(all.item(geometry)))); }; + all.recent = function(geometries, n) { + return presetCollection(_recent.matchAnyGeometry(geometries).collection.slice(0, n - 1)); + }; + all.choose = function(preset) { if (preset.searchable !== false) { _recent = presetCollection(_uniq([preset].concat(_recent.collection))); diff --git a/modules/presets/preset.js b/modules/presets/preset.js index 33e67fb55..ed1cb5c82 100644 --- a/modules/presets/preset.js +++ b/modules/presets/preset.js @@ -249,11 +249,12 @@ export function presetPreset(id, preset, fields, visible, rawPresets) { } } } - - for (var f in preset.fields) { - var field = preset.fields[f]; - if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) { - tags[field.key] = field.default; + if (geometry) { + for (var f in preset.fields) { + var field = preset.fields[f]; + if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) { + tags[field.key] = field.default; + } } } diff --git a/modules/ui/init.js b/modules/ui/init.js index d1d962658..942f0be84 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -26,6 +26,7 @@ import { uiLoading } from './loading'; import { uiMapData } from './map_data'; import { uiMapInMap } from './map_in_map'; import { uiModes } from './modes'; +import { uiNotes } from './notes'; import { uiNotice } from './notice'; import { uiPhotoviewer } from './photoviewer'; import { uiRestore } from './restore'; @@ -36,6 +37,7 @@ import { uiSidebar } from './sidebar'; import { uiSpinner } from './spinner'; import { uiSplash } from './splash'; import { uiStatus } from './status'; +import { uiSearchAdd } from './search_add'; import { uiTooltipHtml } from './tooltipHtml'; import { uiUndoRedo } from './undo_redo'; import { uiVersion } from './version'; @@ -90,7 +92,7 @@ export function uiInit(context) { var sidebarButton = leadingArea .append('div') .append('button') - .attr('class', 'sidebar-toggle') + .attr('class', 'sidebar-toggle bar-button') .attr('tabindex', -1) .on('click', ui.sidebar.toggle) .call(tooltip() @@ -110,12 +112,19 @@ export function uiInit(context) { // Center area button group (Point/Line/Area/Note mode buttons) - bar + var centerArea = bar .append('div') - .attr('class', 'tool-group center-area') - .append('div') - .attr('class', 'modes joined') - .call(uiModes(context), bar); + .attr('class', 'tool-group center-area'); + + var addArea = centerArea.append('div') + .attr('class', 'search-add joined'); + + addArea.call(uiSearchAdd(context), bar); + addArea.call(uiModes(context), bar); + + centerArea.append('div') + .attr('class', 'notes') + .call(uiNotes(context), bar); // Trailing area button group (Undo/Redo save buttons) @@ -134,13 +143,6 @@ export function uiInit(context) { .call(uiSave(context)); - // For now, just put spinner at the end of the #bar - bar - .append('div') - .attr('class', 'spinner') - .call(uiSpinner(context)); - - // Map controls (appended to #bar, but absolutely positioned) var controls = content .append('div') @@ -184,6 +186,10 @@ export function uiInit(context) { .call(help.renderToggleButton); content.call(help.renderPane); + content + .append('div') + .attr('class', 'spinner') + .call(uiSpinner(context)); // Add attribution and footer var about = content diff --git a/modules/ui/modes.js b/modules/ui/modes.js index ea15f1199..238581e8e 100644 --- a/modules/ui/modes.js +++ b/modules/ui/modes.js @@ -1,36 +1,26 @@ import _debounce from 'lodash-es/debounce'; -import { select as d3_select } from 'd3-selection'; +import { drag as d3_drag } from 'd3-drag'; +import { event as d3_event, select as d3_select } from 'd3-selection'; import { modeAddArea, modeAddLine, modeAddPoint, - modeAddNote, modeBrowse } from '../modes'; import { svgIcon } from '../svg'; -import { t } from '../util/locale'; +import { t, textDirection } from '../util/locale'; import { tooltip } from '../util/tooltip'; import { uiPresetIcon } from './preset_icon'; import { uiTooltipHtml } from './tooltipHtml'; export function uiModes(context) { - var modes = [ - modeAddPoint(context), - modeAddLine(context), - modeAddArea(context), - modeAddNote(context) - ]; - function enabled(d) { - if (d.id === 'add-note') { - return notesEnabled() && notesEditable(); - } else { - return osmEditable(); - } + function enabled() { + return osmEditable(); } function osmEditable() { @@ -38,16 +28,6 @@ export function uiModes(context) { return context.editable() && mode && mode.id !== 'save'; } - function notesEnabled() { - var noteLayer = context.layers().layer('notes'); - return noteLayer && noteLayer.enabled(); - } - - function notesEditable() { - var mode = context.mode(); - return context.map().notesEditable() && mode && mode.id !== 'save'; - } - return function(selection) { context @@ -64,19 +44,6 @@ export function uiModes(context) { .classed('mode-' + exited.id, false); }); - modes.forEach(function(mode) { - context.keybinding().on(mode.key, function() { - if (!enabled(mode)) return; - - if (mode.id === context.mode().id) { - context.enter(modeBrowse(context)); - } else { - context.enter(mode); - } - }); - }); - - var debouncedUpdate = _debounce(update, 500, { leading: true, trailing: true }); context.map() @@ -91,51 +58,96 @@ export function uiModes(context) { function update() { - var showNotes = notesEnabled(); - var data = showNotes ? modes : modes.slice(0, 3); - // add favorite presets to modes + for (var i = 0; i <= 9; i++) { + context.keybinding().off(i.toString()); + } + var favoritePresets = context.getFavoritePresets(); - var favoriteModes = favoritePresets.map(function(d) { + var favoriteModes = favoritePresets.map(function(d, index) { var preset = context.presets().item(d.id); - var isMaki = /^maki-/.test(preset.icon); - var icon = '#' + preset.icon + (isMaki ? '-11' : ''); - var markerClass = 'add-preset add-' + d.geom + ' add-preset-' + preset.name() - .replace(/\s+/g, '_') - + '-' + d.geom; //replace spaces with underscores to avoid css interpretation - var presetName = t('presets.presets.' + preset.id + '.name'); - var relevantMatchingGeometry = preset.geometry.filter(function(geometry) { - return ['point', 'line', 'area'].indexOf(geometry) !== -1; + var presetName = preset.name().split(' – ')[0]; + var markerClass = 'add-preset add-' + d.geom + ' add-preset-' + presetName.replace(/\s+/g, '_') + + '-' + d.geom; // replace spaces with underscores to avoid css interpretation + if (preset.isFallback()) { + markerClass += ' add-generic-preset'; + } + + var supportedGeometry = preset.geometry.filter(function(geometry) { + return ['vertex', 'point', 'line', 'area'].indexOf(geometry) !== -1; }); + var vertexIndex = supportedGeometry.indexOf('vertex'); + if (vertexIndex !== -1 && supportedGeometry.indexOf('point') !== -1) { + // both point and vertex allowed, just combine them + supportedGeometry.splice(vertexIndex, 1); + } var tooltipTitleID = 'modes.add_preset.title'; - if (relevantMatchingGeometry.length !== 1) { - tooltipTitleID = 'modes.add_preset.' + d.geom + '.title'; + if (supportedGeometry.length !== 1) { + if (preset.setTags({}, d.geom).building) { + tooltipTitleID = 'modes.add_preset.building.title'; + } else { + tooltipTitleID = 'modes.add_preset.' + d.geom + '.title'; + } } var favoriteMode = { - id: markerClass, button: markerClass, title: presetName, - description: t(tooltipTitleID, { feature: presetName }), - key: '', - icon: icon, + description: t(tooltipTitleID, { feature: '' + presetName + '' }), preset: preset, geometry: d.geom }; + var keyCode; + if (textDirection === 'ltr') { + // use number row order: 1 2 3 4 5 6 7 8 9 0 + if (index === 9) { + keyCode = 0; + } else if (index < 10) { + keyCode = index + 1; + } + } else { + // use number row order from right to left + if (index === 0) { + keyCode = 0; + } else if (index < 10) { + keyCode = 10 - index; + } + } + if (keyCode !== null) { + favoriteMode.key = keyCode.toString(); + } + + var mode; switch (d.geom) { case 'point': case 'vertex': - return modeAddPoint(context, favoriteMode); + mode = modeAddPoint(context, favoriteMode); + break; case 'line': - return modeAddLine(context, favoriteMode); + mode = modeAddLine(context, favoriteMode); + break; case 'area': - return modeAddArea(context, favoriteMode); + mode = modeAddArea(context, favoriteMode); } + + if (mode.key) { + context.keybinding().on(mode.key, function() { + if (!enabled(mode)) return; + + if (mode.button === context.mode().button) { + context.enter(modeBrowse(context)); + } else { + context.enter(mode); + } + }); + } + + return mode; }); - data = data.concat(favoriteModes); + var data = favoriteModes; var buttons = selection.selectAll('button.add-button') - .data(data, function(d) { return d.id; }); + .data(data, function(d, index) { return d.button + index; }); // exit buttons.exit() @@ -145,7 +157,7 @@ export function uiModes(context) { var buttonsEnter = buttons.enter() .append('button') .attr('tabindex', -1) - .attr('class', function(d) { return d.id + ' add-button'; }) + .attr('class', function(d) { return d.button + ' add-button bar-button'; }) .on('click.mode-buttons', function(d) { if (!enabled(d)) return; @@ -167,33 +179,95 @@ export function uiModes(context) { buttonsEnter .each(function(d) { - if (d.preset) { + if (d.preset.isFallback()) { + d3_select(this) + .call(svgIcon('#iD-icon-' + d.preset.id)); + } else { d3_select(this) .call(uiPresetIcon() .geometry(d.geometry) .preset(d.preset) .sizeClass('small') ); - } else { - d3_select(this) - .call(svgIcon(d.icon || '#iD-icon-' + d.button)); } }); - buttonsEnter - .append('span') - .attr('class', 'label') - .text(function(mode) { return mode.title; }); + var dragOrigin, targetIndex; - // if we are adding/removing the buttons, check if toolbar has overflowed - if (buttons.enter().size() || buttons.exit().size()) { - context.ui().checkOverflow('#bar', true); - } + buttonsEnter.call(d3_drag() + .on('start', function() { + dragOrigin = { + x: d3_event.x, + y: d3_event.y + }; + targetIndex = null; + }) + .on('drag', function(d, index) { + var x = d3_event.x - dragOrigin.x, + y = d3_event.y - dragOrigin.y; + + d3_select(this) + .classed('dragging', true) + .classed('removing', y > 50); + + targetIndex = null; + + selection.selectAll('button.add-preset') + .style('transform', function(d2, index2) { + var node = d3_select(this).node(); + if (index === index2) { + return 'translate(' + x + 'px, ' + y + 'px)'; + } else if (y > 50) { + if (index2 > index) { + return 'translateX(' + (textDirection === 'rtl' ? '' : '-') + '100%)'; + } + } else if (index2 > index && ( + (d3_event.x > node.offsetLeft && textDirection === 'ltr') || + (d3_event.x < node.offsetLeft + node.offsetWidth && textDirection === 'rtl') + )) { + if (targetIndex === null || index2 > targetIndex) { + targetIndex = index2; + } + return 'translateX(' + (textDirection === 'rtl' ? '' : '-') + '100%)'; + } else if (index2 < index && ( + (d3_event.x < node.offsetLeft + node.offsetWidth && textDirection === 'ltr') || + (d3_event.x > node.offsetLeft && textDirection === 'rtl') + )) { + if (targetIndex === null || index2 < targetIndex) { + targetIndex = index2; + } + return 'translateX(' + (textDirection === 'rtl' ? '-' : '') + '100%)'; + } + return null; + }); + }) + .on('end', function(d, index) { + + d3_select(this) + .classed('dragging', false) + .classed('removing', false); + + selection.selectAll('button.add-preset') + .style('transform', null); + + var y = d3_event.y - dragOrigin.y; + if (y > 50) { + // dragged out of the top bar, remove the favorite + context.favoritePreset(d.preset, d.geometry); + } else if (targetIndex !== null) { + // dragged to a new position, reorder + context.moveFavoritePreset(index, targetIndex); + } + }) + ); // update buttons = buttons .merge(buttonsEnter) .classed('disabled', function(d) { return !enabled(d); }); + + // check if toolbar has overflowed + context.ui().checkOverflow('#bar', true); } }; } diff --git a/modules/ui/notes.js b/modules/ui/notes.js new file mode 100644 index 000000000..45a2d62be --- /dev/null +++ b/modules/ui/notes.js @@ -0,0 +1,128 @@ +import _debounce from 'lodash-es/debounce'; + +import { select as d3_select } from 'd3-selection'; + +import { + modeAddNote, + modeBrowse +} from '../modes'; + +import { svgIcon } from '../svg'; +import { tooltip } from '../util/tooltip'; +import { uiTooltipHtml } from './tooltipHtml'; + +export function uiNotes(context) { + + var mode = modeAddNote(context); + + function enabled() { + return notesEnabled() && notesEditable(); + } + + function notesEnabled() { + var noteLayer = context.layers().layer('notes'); + return noteLayer && noteLayer.enabled(); + } + + function notesEditable() { + var mode = context.mode(); + return context.map().notesEditable() && mode && mode.id !== 'save'; + } + + + return function(selection) { + context + .on('enter.editor.notes', function(entered) { + selection.selectAll('button.add-button') + .classed('active', function(mode) { return entered.button === mode.button; }); + context.container() + .classed('mode-' + entered.id, true); + }); + + context + .on('exit.editor.notes', function(exited) { + context.container() + .classed('mode-' + exited.id, false); + }); + + context.keybinding().on(mode.key, function() { + if (!enabled(mode)) return; + + if (mode.id === context.mode().id) { + context.enter(modeBrowse(context)); + } else { + context.enter(mode); + } + }); + + + var debouncedUpdate = _debounce(update, 500, { leading: true, trailing: true }); + + context.map() + .on('move.notes', debouncedUpdate) + .on('drawn.notes', debouncedUpdate); + + context + .on('enter.notes', update); + + update(); + + + function update() { + var showNotes = notesEnabled(); + var data = showNotes ? [mode] : []; + + var buttons = selection.selectAll('button.add-button') + .data(data, function(d) { return d.id; }); + + // exit + buttons.exit() + .remove(); + + // enter + var buttonsEnter = buttons.enter() + .append('button') + .attr('tabindex', -1) + .attr('class', function(d) { return d.id + ' add-button bar-button'; }) + .on('click.notes', function(d) { + if (!enabled(d)) return; + + // When drawing, ignore accidental clicks on mode buttons - #4042 + var currMode = context.mode().id; + if (/^draw/.test(currMode)) return; + + if (d.id === currMode) { + context.enter(modeBrowse(context)); + } else { + context.enter(d); + } + }) + .call(tooltip() + .placement('bottom') + .html(true) + .title(function(d) { return uiTooltipHtml(d.description, d.key); }) + ); + + buttonsEnter + .each(function(d) { + d3_select(this) + .call(svgIcon(d.icon || '#iD-icon-' + d.button)); + }); + + buttonsEnter + .append('span') + .attr('class', 'label') + .text(function(mode) { return mode.title; }); + + // if we are adding/removing the buttons, check if toolbar has overflowed + if (buttons.enter().size() || buttons.exit().size()) { + context.ui().checkOverflow('#bar', true); + } + + // update + buttons = buttons + .merge(buttonsEnter) + .classed('disabled', function(d) { return !enabled(d); }); + } + }; +} diff --git a/modules/ui/preset_favorite.js b/modules/ui/preset_favorite.js index ef43ee338..2cc7b43b4 100644 --- a/modules/ui/preset_favorite.js +++ b/modules/ui/preset_favorite.js @@ -6,7 +6,7 @@ import { import { t } from '../util/locale'; import { svgIcon } from '../svg'; -export function uiPresetFavorite(preset, geom, context) { +export function uiPresetFavorite(preset, geom, context, klass) { var presetFavorite = {}; @@ -15,7 +15,7 @@ export function uiPresetFavorite(preset, geom, context) { presetFavorite.button = function(selection) { - var canFavorite = geom !== 'vertex' && geom !== 'relation' && !preset.isFallback(); + var canFavorite = geom !== 'relation'; _button = selection.selectAll('.preset-favorite-button') .data(canFavorite ? [0] : []); @@ -24,31 +24,31 @@ export function uiPresetFavorite(preset, geom, context) { _button = _button.enter() .insert('button', '.tag-reference-button') - .attr('class', 'preset-favorite-button') + .attr('class', 'preset-favorite-button ' + klass) .attr('title', t('icons.favorite')) .attr('tabindex', -1) .call(svgIcon('#iD-icon-favorite')) .merge(_button); _button - .classed('active', function() { - return context.isFavoritePreset(preset, geom); - }) .on('click', function () { d3_event.stopPropagation(); d3_event.preventDefault(); - //update state of favorite icon - d3_select(this) - .classed('active', function() { - return !d3_select(this).classed('active'); - }); - - context.favoritePreset(preset, geom); + context.favoritePreset(preset, geom); + update(); }); + update(); }; + function update() { + _button + .classed('active', context.isFavoritePreset(preset, geom)); + } + + context.on('favoritePreset.button-' + preset.id.replace(/[^a-zA-Z\d:]/g, '-') + '-' + geom, update); + return presetFavorite; } diff --git a/modules/ui/preset_icon.js b/modules/ui/preset_icon.js index f699272e2..bad8214fe 100644 --- a/modules/ui/preset_icon.js +++ b/modules/ui/preset_icon.js @@ -23,10 +23,26 @@ export function uiPresetIcon() { return 'iD-other-line'; else if (geom === 'vertex') return p.isFallback() ? '' : 'temaki-vertex'; + else if (isSmall() && geom === 'point') + return ''; else return 'maki-marker-stroked'; } + function renderPointBorder(enter) { + var w = 40, h = 40; + enter = enter + .append('svg') + .attr('class', 'preset-icon-fill preset-icon-point-border') + .attr('width', w) + .attr('height', h) + .attr('viewBox', '0 0 ' + w + ' ' + h); + + enter.append('path') + .attr('transform', 'translate(11.5, 8)') + .attr('d', 'M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z'); + } + function renderCircleFill(fillEnter) { var w = 60, h = 60, d = 40; fillEnter = fillEnter @@ -128,11 +144,11 @@ export function uiPresetIcon() { container = container.enter() .append('div') - .attr('class', 'preset-icon-container') + .attr('class', 'preset-icon-container ' + sizeClass) .merge(container); var p = preset.apply(this, arguments); - var geom = geometry.apply(this, arguments); + var geom = geometry ? geometry.apply(this, arguments) : null; var picon = getIcon(p, geom); var isMaki = /^maki-/.test(picon); var isTemaki = /^temaki-/.test(picon); @@ -151,6 +167,16 @@ export function uiPresetIcon() { } var tagClasses = svgTagClasses().getClassesString(tags, ''); + var pointBorder = container.selectAll('.preset-icon-point-border') + .data(geom === 'point' && isSmall() ? [0] : []); + + pointBorder.exit() + .remove(); + + var pointBorderEnter = pointBorder.enter(); + renderPointBorder(pointBorderEnter); + pointBorder = pointBorderEnter.merge(pointBorder); + var vertexFill = container.selectAll('.preset-icon-fill-vertex') .data(geom === 'vertex' ? [0] : []); @@ -206,7 +232,7 @@ export function uiPresetIcon() { .merge(icon); icon - .attr('class', 'preset-icon ' + geom + '-geom') + .attr('class', 'preset-icon ' + (geom ? geom + '-geom' : '')) .classed('framed', isFramed) .classed('preset-icon-iD', isiDIcon); @@ -216,7 +242,8 @@ export function uiPresetIcon() { }); icon.selectAll('use') - .attr('href', '#' + picon + (isMaki ? '-15' : '')); + .attr('href', '#' + picon + (isMaki ? (isSmall() && geom === 'point' ? '-11' : '-15') : '')); + } diff --git a/modules/ui/preset_list.js b/modules/ui/preset_list.js index 51c9f3a09..1e8ab2d46 100644 --- a/modules/ui/preset_list.js +++ b/modules/ui/preset_list.js @@ -91,7 +91,7 @@ export function uiPresetList(context) { var value = search.property('value'); if (d3_event.keyCode === 13 && value.length) { list.selectAll('.preset-list-item:first-child') - .each(function(d) { d.choose.call(d3_select(this).node()); }); + .each(function(d) { d.choose.call(this); }); } } @@ -339,11 +339,12 @@ export function uiPresetList(context) { .style('padding-bottom', '0px'); } else { shown = true; - sublist.call(drawList, preset.members); + var members = preset.members.matchGeometry(context.geometry(_entityID)); + sublist.call(drawList, members); box.transition() .duration(200) .style('opacity', '1') - .style('max-height', 200 + preset.members.collection.length * 190 + 'px') + .style('max-height', 200 + members.collection.length * 190 + 'px') .style('padding-bottom', '10px'); } }; diff --git a/modules/ui/save.js b/modules/ui/save.js index a818941f7..7bb972914 100644 --- a/modules/ui/save.js +++ b/modules/ui/save.js @@ -77,7 +77,7 @@ export function uiSave(context) { var button = selection .append('button') - .attr('class', 'save disabled') + .attr('class', 'save disabled bar-button') .attr('tabindex', -1) .on('click', save) .call(tooltipBehavior); diff --git a/modules/ui/search_add.js b/modules/ui/search_add.js new file mode 100644 index 000000000..24d45d503 --- /dev/null +++ b/modules/ui/search_add.js @@ -0,0 +1,469 @@ +import { dispatch as d3_dispatch } from 'd3-dispatch'; + +import { + event as d3_event, + select as d3_select, + selectAll as d3_selectAll +} from 'd3-selection'; + +import { + modeAddArea, + modeAddLine, + modeAddPoint +} from '../modes'; + +import { t, textDirection } from '../util/locale'; +import { svgIcon } from '../svg/index'; +import { tooltip } from '../util/tooltip'; +import { uiTooltipHtml } from './tooltipHtml'; +import { uiPresetFavorite } from './preset_favorite'; +import { uiPresetIcon } from './preset_icon'; +import { utilKeybinding, utilNoAuto, utilRebind } from '../util'; + + +export function uiSearchAdd(context) { + var dispatch = d3_dispatch('choose'); + var presets; + var search = d3_select(null), popover = d3_select(null), list = d3_select(null); + + var shownGeometry = ['area', 'line', 'point', 'vertex']; + + function searchAdd(selection) { + + presets = context.presets().matchAnyGeometry(shownGeometry); + + var key = t('modes.add_feature.key'); + + var searchWrap = selection + .append('div') + .attr('class', 'search-wrap') + .call(tooltip() + .placement('bottom') + .html(true) + .title(function() { return uiTooltipHtml(t('modes.add_feature.description'), key); }) + ); + + search = searchWrap + .append('input') + .attr('class', 'search-input') + .attr('placeholder', t('modes.add_feature.title')) + .attr('type', 'search') + .call(utilNoAuto) + .on('mousedown', function() { + search.attr('clicking', true); + }) + .on('mouseup', function() { + search.attr('clicking', null); + }) + .on('focus', function() { + searchWrap.classed('focused', true); + if (search.attr('clicking')) { + search.attr('focusing', true); + search.attr('clicking', null); + } else { + search.node().setSelectionRange(0, search.property('value').length); + } + popover.classed('hide', false); + }) + .on('blur', function() { + searchWrap.classed('focused', false); + popover.classed('hide', true); + }) + .on('click', function() { + if (search.attr('focusing')) { + search.node().setSelectionRange(0, search.property('value').length); + search.attr('focusing', null); + } + }) + .on('keypress', keypress) + .on('keydown', keydown) + .on('input', searchInput); + + searchWrap + .call(svgIcon('#iD-icon-search', 'search-icon pre-text')); + + popover = selection + .append('div') + .attr('class', 'popover fillL hide') + .on('mousedown', function() { + // don't blur the search input (and thus close results) + d3_event.preventDefault(); + d3_event.stopPropagation(); + }); + + list = popover + .append('div') + .attr('class', 'list');// + //.call(drawList, context.presets().defaults(geometry, 36)); + + context.features().on('change.search-add', updateForFeatureHiddenState); + + context.keybinding().on(key, function() { + search.node().focus(); + d3_event.preventDefault(); + d3_event.stopPropagation(); + }); + } + + function keypress() { + if (d3_event.keyCode === utilKeybinding.keyCodes.enter) { + popover.selectAll('.list .list-item.focused button.choose') + .each(function(d) { d.choose.call(this); }); + d3_event.preventDefault(); + d3_event.stopPropagation(); + } + } + + function keydown() { + + var nextFocus, + priorFocus, + parentSubsection; + if (d3_event.keyCode === utilKeybinding.keyCodes['↓'] || + d3_event.keyCode === utilKeybinding.keyCodes.tab && !d3_event.shiftKey) { + d3_event.preventDefault(); + d3_event.stopPropagation(); + + priorFocus = popover.selectAll('.list .list-item.focused'); + if (priorFocus.empty()) { + nextFocus = popover.selectAll('.list > .list-item:first-child'); + } else { + nextFocus = popover.selectAll('.list .list-item.focused + .list-item'); + if (nextFocus.empty()) { + nextFocus = d3_select(priorFocus.nodes()[0].nextElementSibling) + .selectAll('.list-item:first-child'); + } + if (nextFocus.empty()) { + parentSubsection = priorFocus.nodes()[0].closest('.list .subsection'); + if (parentSubsection && parentSubsection.nextElementSibling) { + nextFocus = d3_select(parentSubsection.nextElementSibling); + } + } + } + if (!nextFocus.empty()) { + focusListItem(nextFocus); + priorFocus.classed('focused', false); + } + + } else if (d3_event.keyCode === utilKeybinding.keyCodes['↑'] || + d3_event.keyCode === utilKeybinding.keyCodes.tab && d3_event.shiftKey) { + d3_event.preventDefault(); + d3_event.stopPropagation(); + + priorFocus = popover.selectAll('.list .list-item.focused'); + if (!priorFocus.empty()) { + + nextFocus = d3_select(priorFocus.nodes()[0].previousElementSibling); + if (!nextFocus.empty() && !nextFocus.classed('list-item')) { + nextFocus = nextFocus.selectAll('.list-item:last-child'); + } + if (nextFocus.empty()) { + parentSubsection = priorFocus.nodes()[0].closest('.list .subsection'); + if (parentSubsection && parentSubsection.previousElementSibling) { + nextFocus = d3_select(parentSubsection.previousElementSibling); + } + } + if (!nextFocus.empty()) { + focusListItem(nextFocus); + priorFocus.classed('focused', false); + } + } + } else if (d3_event.keyCode === utilKeybinding.keyCodes.esc) { + search.node().blur(); + d3_event.preventDefault(); + d3_event.stopPropagation(); + } + } + + function searchInput() { + + popover.selectAll('.subsection').remove(); + + var value = search.property('value'); + var results; + if (value.length) { + results = presets.search(value, shownGeometry); + } else { + results = context.presets().recent(shownGeometry, 36); + } + + list.call(drawList, results); + + popover.selectAll('.list .list-item.focused') + .classed('focused', false); + focusListItem(popover.selectAll('.list > .list-item:first-child')); + } + + function focusListItem(selection) { + if (!selection.empty()) { + selection.classed('focused', true); + // scroll to keep the focused item visible + scrollPopoverToShow(selection); + } + } + + function scrollPopoverToShow(selection) { + if (selection.empty()) return; + + var node = selection.nodes()[0]; + var popoverNode = popover.node(); + + if (node.offsetTop < popoverNode.scrollTop) { + popoverNode.scrollTop = node.offsetTop; + + } else if (node.offsetTop + node.offsetHeight > popoverNode.scrollTop + popoverNode.offsetHeight && + node.offsetHeight < popoverNode.offsetHeight) { + popoverNode.scrollTop = node.offsetTop + node.offsetHeight - popoverNode.offsetHeight; + } + } + + function itemForPreset(preset) { + if (preset.members) { + return CategoryItem(preset); + } + var supportedGeometry = preset.geometry.filter(function(geometry) { + return shownGeometry.indexOf(geometry) !== -1; + }).sort(); + var vertexIndex = supportedGeometry.indexOf('vertex'); + if (vertexIndex !== -1 && supportedGeometry.indexOf('point') !== -1) { + // both point and vertex allowed, just show point + supportedGeometry.splice(vertexIndex, 1); + } + if (supportedGeometry.length === 1) { + return AddablePresetItem(preset, supportedGeometry[0]); + } + return MultiGeometryPresetItem(preset, supportedGeometry); + } + + function drawList(list, presets) { + + var collection = presets.collection.map(function(preset) { + return itemForPreset(preset); + }); + + var items = list.selectAll('.list-item') + .data(collection, function(d) { return d.preset.id; }); + + items.order(); + + items.exit() + .remove(); + + items.enter(); + drawItems(items.enter()); + + updateForFeatureHiddenState(); + } + + function drawItems(selection) { + + var row = selection + .append('div') + .attr('class', 'list-item') + .attr('id', function(d) { + var id = 'search-add-list-item-preset-' + d.preset.id.replace(/[^a-zA-Z\d:]/g, '-'); + if (d.geometry) { + id += '-' + d.geometry; + } + return id; + }) + .on('mouseover', function() { + list.selectAll('.list-item.focused') + .classed('focused', false); + d3_select(this) + .classed('focused', true); + }) + .on('mouseout', function() { + d3_select(this) + .classed('focused', false); + }); + + row.append('button') + .attr('class', 'choose') + .on('click', function(d) { + d.choose.call(this); + }); + + row.each(function(d) { + d3_select(this).call( + uiPresetIcon() + .geometry(d.geometry) + .preset(d.preset) + .sizeClass('small') + ); + }); + var label = row.append('div') + .attr('class', 'label'); + + label.each(function(d) { + if (!d.geometry) { + d3_select(this) + .call(svgIcon((textDirection === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'), 'inline')); + } + }); + + label.each(function(d) { + + if ((d.geometry && !d.isSubitem) || d.geometries) { + // NOTE: split/join on en-dash, not a hypen (to avoid conflict with fr - nl names in Brussels etc) + d3_select(this) + .append('div') + .attr('class', 'label-inner') + .selectAll('.namepart') + .data(d.preset.name().split(' – ')) + .enter() + .append('div') + .attr('class', 'namepart') + .text(function(d) { return d; }); + } else { + d3_select(this).append('span') + .text(function(d) { + if (d.isSubitem) { + if (d.preset.setTags({}, d.geometry).building) { + return t('presets.presets.building.name'); + } + return t('modes.add_' + d.geometry + '.title'); + } + return d.preset.name(); + }); + } + }); + + row.each(function(d) { + if (d.geometry) { + var presetFavorite = uiPresetFavorite(d.preset, d.geometry, context, 'accessory'); + d3_select(this).call(presetFavorite.button); + } + }); + } + + function updateForFeatureHiddenState() { + + var listItem = d3_selectAll('.search-add .popover .list-item'); + + // remove existing tooltips + listItem.selectAll('button.choose').call(tooltip().destroyAny); + + listItem.each(function(item, index) { + if (!item.geometry) return; + + var hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, item.geometry); + var isHiddenPreset = !!hiddenPresetFeaturesId; + + var button = d3_select(this).selectAll('button.choose'); + + d3_select(this).classed('disabled', isHiddenPreset); + button.classed('disabled', isHiddenPreset); + + if (isHiddenPreset) { + var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId); + var tooltipIdSuffix = isAutoHidden ? 'zoom' : 'manual'; + var tooltipObj = { features: t('feature.' + hiddenPresetFeaturesId + '.description') }; + button.call(tooltip('dark') + .html(true) + .title(t('inspector.hidden_preset.' + tooltipIdSuffix, tooltipObj)) + .placement(index < 2 ? 'bottom' : 'top') + ); + } + }); + } + + function chooseExpandable(item, itemSelection) { + + var shouldExpand = !itemSelection.classed('expanded'); + + itemSelection.classed('expanded', shouldExpand); + + var iconName = shouldExpand ? + '#iD-icon-down' : (textDirection === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'); + itemSelection.selectAll('.label svg.icon use') + .attr('href', iconName); + + if (shouldExpand) { + var subitems = item.subitems(); + var selector = '#' + itemSelection.node().id + ' + *'; + item.subsection = d3_select(itemSelection.node().parentElement).insert('div', selector) + .attr('class', 'subsection'); + var subitemsEnter = item.subsection.selectAll('.list-item') + .data(subitems) + .enter(); + drawItems(subitemsEnter); + updateForFeatureHiddenState(); + scrollPopoverToShow(item.subsection); + } else { + item.subsection.remove(); + } + } + + function CategoryItem(preset) { + var item = {}; + item.subsection = d3_select(null); + item.preset = preset; + item.choose = function() { + var selection = d3_select(this); + if (selection.classed('disabled')) return; + chooseExpandable(item, d3_select(selection.node().closest('.list-item'))); + }; + item.subitems = function() { + return preset.members.matchAnyGeometry(shownGeometry).collection.map(function(preset) { + return itemForPreset(preset); + }); + }; + return item; + } + + function MultiGeometryPresetItem(preset, geometries) { + + var item = {}; + item.subsection = d3_select(null); + item.preset = preset; + item.geometries = geometries; + item.choose = function() { + var selection = d3_select(this); + if (selection.classed('disabled')) return; + chooseExpandable(item, d3_select(selection.node().closest('.list-item'))); + }; + item.subitems = function() { + return geometries.map(function(geometry) { + return AddablePresetItem(preset, geometry, true); + }); + }; + return item; + } + + function AddablePresetItem(preset, geometry, isSubitem) { + var item = {}; + item.isSubitem = isSubitem; + item.preset = preset; + item.geometry = geometry; + item.choose = function() { + if (d3_select(this).classed('disabled')) return; + + var markerClass = 'add-preset add-' + geometry + + ' add-preset-' + preset.name().replace(/\s+/g, '_') + '-' + geometry; + var modeInfo = { + button: markerClass, + preset: preset, + geometry: geometry + }; + var mode; + switch (geometry) { + case 'point': + case 'vertex': + mode = modeAddPoint(context, modeInfo); + break; + case 'line': + mode = modeAddLine(context, modeInfo); + break; + case 'area': + mode = modeAddArea(context, modeInfo); + } + search.node().blur(); + context.presets().choose(preset); + context.enter(mode); + }; + return item; + } + + return utilRebind(searchAdd, dispatch, 'on'); +} diff --git a/modules/ui/shortcuts.js b/modules/ui/shortcuts.js index 252375c4b..8842d96b8 100644 --- a/modules/ui/shortcuts.js +++ b/modules/ui/shortcuts.js @@ -189,7 +189,8 @@ export function uiShortcuts(context) { return _uniq(arr).map(function(s) { return { shortcut: s, - separator: d.separator + separator: d.separator, + suffix: d.suffix }; }); }) @@ -212,6 +213,10 @@ export function uiShortcuts(context) { selection .append('span') .text(d.separator || '\u00a0' + t('shortcuts.or') + '\u00a0'); + } else if (i === nodes.length - 1 && d.suffix) { + selection + .append('span') + .text(d.suffix); } }); diff --git a/modules/ui/undo_redo.js b/modules/ui/undo_redo.js index eef37b5d2..7222396b9 100644 --- a/modules/ui/undo_redo.js +++ b/modules/ui/undo_redo.js @@ -46,7 +46,7 @@ export function uiUndoRedo(context) { .data(commands) .enter() .append('button') - .attr('class', function(d) { return 'disabled ' + d.id + '-button'; }) + .attr('class', function(d) { return 'disabled ' + d.id + '-button bar-button'; }) .on('click', function(d) { return d.action(); }) .call(tooltipBehavior); diff --git a/modules/util/tooltip.js b/modules/util/tooltip.js index 637229aee..bdb15b3a7 100644 --- a/modules/util/tooltip.js +++ b/modules/util/tooltip.js @@ -3,7 +3,7 @@ import { utilFunctor } from './index'; var _tooltipID = 0; -export function tooltip() { +export function tooltip(klass) { var _id = _tooltipID++; var tooltip = function(selection) { selection.each(setup); @@ -98,7 +98,7 @@ export function tooltip() { var enter = tip.enter() .append('div') - .attr('class', 'tooltip tooltip-' + _id); + .attr('class', 'tooltip tooltip-' + _id + ' ' + (klass ? klass : '')); enter .append('div') diff --git a/svg/iD-sprite/presets/category-path.svg b/svg/iD-sprite/presets/category-path.svg deleted file mode 100644 index 8d4070adf..000000000 --- a/svg/iD-sprite/presets/category-path.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/svg/iD-sprite/presets/category-rail.svg b/svg/iD-sprite/presets/category-rail.svg deleted file mode 100644 index b9369f2a2..000000000 --- a/svg/iD-sprite/presets/category-rail.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/svg/iD-sprite/presets/category-roads.svg b/svg/iD-sprite/presets/category-roads.svg deleted file mode 100644 index e298e81a2..000000000 --- a/svg/iD-sprite/presets/category-roads.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/svg/iD-sprite/presets/category-utility.svg b/svg/iD-sprite/presets/category-utility.svg deleted file mode 100644 index e819114fc..000000000 --- a/svg/iD-sprite/presets/category-utility.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/svg/iD-sprite/presets/category-water.svg b/svg/iD-sprite/presets/category-water.svg deleted file mode 100644 index 47da3fd11..000000000 --- a/svg/iD-sprite/presets/category-water.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file