diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 000000000..03cee0067 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,11 @@ +# Development Roadmap + +iD is a sizable project with many types of changes happening concurrently. In the past, it's been difficult to tell at a glance what to expect next and what we're broadly working toward. The [iD Blog](https://ideditor.blog/) is one place to get information, but the format doesn't lend itself to dynamic technical content. + +This roadmap aims to get everyone on the same page by outlining the general initiatives and specific goals for iD over the short, intermediate, and long terms. These should be considered only as guidelines, not a strict set of deliverables. + +The roadmap should be kept aligned with the needs of the OpenStreetMap database itself, its ecosystem of software, and the supporting community. + +--- + +_More details coming "soon"._ diff --git a/css/80_app.css b/css/80_app.css index a0b59583f..d4e99ea4d 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1426,7 +1426,6 @@ a.hide-toggle { flex: 0 0 32px; border-left: 1px solid #ccc; width: 32px; - height: 100%; border-radius: 0; background: #f6f6f6; } diff --git a/data/deprecated.json b/data/deprecated.json index 273752dd5..bce2e0f6d 100644 --- a/data/deprecated.json +++ b/data/deprecated.json @@ -115,6 +115,10 @@ "old": {"amenity": "kiosk"}, "replace": {"shop": "kiosk"} }, + { + "old": {"amenity": "notice_board"}, + "replace": {"advertising": "board"} + }, { "old": {"amenity": "nursery"}, "replace": {"amenity": "kindergarten"} diff --git a/data/presets.yaml b/data/presets.yaml index 328930e83..f389f06e7 100644 --- a/data/presets.yaml +++ b/data/presets.yaml @@ -765,6 +765,11 @@ en: anticlockwise: Counterclockwise # direction=clockwise clockwise: Clockwise + direction_point: + # direction=* + label: Direction (Degrees Clockwise) + # direction_point field placeholder + placeholder: '45, 90, 180, 270' direction_vertex: # direction=* label: Direction Affected @@ -2772,6 +2777,26 @@ en: valve: # valve=* label: Type + vehicles: + # 'bus=*, trolleybus=*, tram=*, train=*, subway=*, light_rail=*, monorail=*, ferry=*' + label: Vehicles + options: + # bus=yes + bus: Bus + # ferry=yes + ferry: Ferry + # light_rail=yes + light_rail: Light Rail + # monorail=yes + monorail: Monorail + # subway=yes + subway: Subway + # train=yes + train: Train + # tram=yes + tram: Tram + # trolleybus=yes + trolleybus: Trolleybus vending: # vending=* label: Types of Goods @@ -8739,6 +8764,11 @@ en: # 'tourism=information, information=board' name: Information Board terms: '' + tourism/information/board/welcome_sign: + # 'tourism=information, information=board, board_type=welcome_sign' + name: Welcome Sign + # 'terms: new location' + terms: '' tourism/information/guidepost: # 'tourism=information, information=guidepost' name: Guidepost @@ -8879,26 +8909,11 @@ en: name: City Limit Sign # 'terms: town,village,hamlet,boundary,edge,border,road,highway' terms: '' - traffic_sign/city_limit_vertex: - # traffic_sign=city_limit - name: City Limit Sign - # 'terms: town,village,hamlet,boundary,edge,border,road,highway' - terms: '' traffic_sign/maxspeed: # traffic_sign=maxspeed name: Speed Limit Sign # 'terms: max speed,maximum speed,road,highway' terms: '' - traffic_sign/maxspeed_vertex: - # traffic_sign=maxspeed - name: Speed Limit Sign - # 'terms: max speed,maximum speed,road,highway' - terms: '' - traffic_sign_vertex: - # traffic_sign=* - name: Traffic Sign - # 'terms: road,highway' - terms: '' type/boundary: # type=boundary name: Boundary diff --git a/data/presets/fields.json b/data/presets/fields.json index d33568097..62f05183e 100644 --- a/data/presets/fields.json +++ b/data/presets/fields.json @@ -131,6 +131,7 @@ "diplomatic/services": {"key": "diplomatic:services:", "type": "multiCombo", "label": "Services"}, "direction_cardinal": {"key": "direction", "type": "combo", "label": "Direction", "strings": {"options": {"N": "North", "E": "East", "S": "South", "W": "West", "NE": "Northeast", "SE": "Southeast", "SW": "Southwest", "NW": "Northwest", "NNE": "North-northeast", "ENE": "East-northeast", "ESE": "East-southeast", "SSE": "South-southeast", "SSW": "South-southwest", "WSW": "West-southwest", "WNW": "West-northwest", "NNW": "North-northwest"}}}, "direction_clock": {"key": "direction", "type": "combo", "label": "Direction", "strings": {"options": {"clockwise": "Clockwise", "anticlockwise": "Counterclockwise"}}}, + "direction_point": {"key": "direction", "type": "number", "label": "Direction (Degrees Clockwise)", "placeholder": "45, 90, 180, 270", "geometry": ["point"]}, "direction_vertex_dual": {"key": "direction", "type": "combo", "label": "Direction Affected", "strings": {"options": {"forward": "Forward", "backward": "Backward"}}}, "direction_vertex": {"key": "direction", "type": "combo", "label": "Direction Affected", "strings": {"options": {"forward": "Forward", "backward": "Backward", "both": "Both / All"}}}, "direction": {"key": "direction", "type": "number", "label": "Direction (Degrees Clockwise)", "placeholder": "45, 90, 180, 270"}, @@ -471,7 +472,7 @@ "trade": {"key": "trade", "type": "typeCombo", "label": "Type"}, "traffic_calming": {"key": "traffic_calming", "type": "typeCombo", "label": "Type"}, "traffic_sign": {"key": "traffic_sign", "type": "typeCombo", "label": "Traffic Sign"}, - "traffic_sign/direction": {"key": "traffic_sign:direction", "type": "combo", "label": "Direction Affected", "strings": {"options": {"forward": "Forward", "backward": "Backward", "both": "Both / All"}}}, + "traffic_sign/direction": {"key": "traffic_sign:direction", "type": "combo", "label": "Direction Affected", "strings": {"options": {"forward": "Forward", "backward": "Backward", "both": "Both / All"}}, "geometry": ["vertex"]}, "traffic_signals": {"key": "traffic_signals", "type": "combo", "label": "Type", "default": "signal"}, "traffic_signals/direction": {"key": "traffic_signals:direction", "type": "combo", "label": "Direction Affected", "strings": {"options": {"forward": "Forward", "backward": "Backward", "both": "Both / All"}}}, "trail_visibility": {"key": "trail_visibility", "type": "combo", "label": "Trail Visibility", "placeholder": "Excellent, Good, Bad...", "strings": {"options": {"excellent": "Excellent: unambiguous path or markers everywhere", "good": "Good: markers visible, sometimes require searching", "intermediate": "Intermediate: few markers, path mostly visible", "bad": "Bad: no markers, path sometimes invisible/pathless", "horrible": "Horrible: often pathless, some orientation skills required", "no": "No: pathless, excellent orientation skills required"}}}, @@ -485,6 +486,7 @@ "utility_semi": {"key": "utility", "type": "semiCombo", "label": "Utilities"}, "utility": {"key": "utility", "type": "typeCombo", "label": "Utility"}, "valve": {"key": "valve", "type": "combo", "label": "Type"}, + "vehicles": {"keys": ["bus", "trolleybus", "tram", "train", "subway", "light_rail", "monorail", "ferry"], "type": "multiCombo", "label": "Vehicles", "strings": {"options": {"bus": "Bus", "trolleybus": "Trolleybus", "tram": "Tram", "train": "Train", "subway": "Subway", "light_rail": "Light Rail", "monorail": "Monorail", "ferry": "Ferry"}}, "reference": {"key": "public_transport"}, "prerequisiteTag": {"keyNot": "aerialway"}}, "vending": {"key": "vending", "type": "semiCombo", "label": "Types of Goods"}, "vhf": {"key": "vhf", "type": "text", "label": "VHF Channel", "terms": ["call sign", "very high frequency"]}, "video_calls": {"key": "video", "type": "check", "label": "Video Calls"}, diff --git a/data/presets/fields/direction_point.json b/data/presets/fields/direction_point.json new file mode 100644 index 000000000..23100bb2d --- /dev/null +++ b/data/presets/fields/direction_point.json @@ -0,0 +1,9 @@ +{ + "key": "direction", + "type": "number", + "label": "Direction (Degrees Clockwise)", + "placeholder": "45, 90, 180, 270", + "geometry": [ + "point" + ] +} diff --git a/data/presets/fields/traffic_sign/direction.json b/data/presets/fields/traffic_sign/direction.json index c8e06eca5..d6d417cc2 100644 --- a/data/presets/fields/traffic_sign/direction.json +++ b/data/presets/fields/traffic_sign/direction.json @@ -8,5 +8,8 @@ "backward": "Backward", "both": "Both / All" } - } + }, + "geometry": [ + "vertex" + ] } diff --git a/data/presets/fields/vehicles.json b/data/presets/fields/vehicles.json new file mode 100644 index 000000000..65c93d4f8 --- /dev/null +++ b/data/presets/fields/vehicles.json @@ -0,0 +1,32 @@ +{ + "keys": [ + "bus", + "trolleybus", + "tram", + "train", + "subway", + "light_rail", + "monorail", + "ferry" + ], + "type": "multiCombo", + "label": "Vehicles", + "strings": { + "options": { + "bus": "Bus", + "trolleybus": "Trolleybus", + "tram": "Tram", + "train": "Train", + "subway": "Subway", + "light_rail": "Light Rail", + "monorail": "Monorail", + "ferry": "Ferry" + } + }, + "reference": { + "key": "public_transport" + }, + "prerequisiteTag": { + "keyNot": "aerialway" + } +} diff --git a/data/presets/presets.json b/data/presets/presets.json index 0d05f8509..df70e888a 100644 --- a/data/presets/presets.json +++ b/data/presets/presets.json @@ -976,8 +976,8 @@ "power/switch": {"icon": "temaki-power_switch", "fields": ["switch", "operator", "location", "cables", "voltage", "ref"], "geometry": ["point", "vertex"], "tags": {"power": "switch"}, "name": "Power Switch"}, "power/tower": {"icon": "temaki-power_tower", "fields": ["ref", "operator", "design", "height", "material", "line_attachment"], "moreFields": ["line_management", "manufacturer"], "geometry": ["point", "vertex"], "terms": ["power"], "tags": {"power": "tower"}, "matchScore": 1.05, "name": "High-Voltage Tower"}, "power/transformer": {"icon": "temaki-power_transformer", "fields": ["ref", "operator", "transformer", "location", "rating", "devices", "phases"], "moreFields": ["frequency", "manufacturer", "voltage/primary", "voltage/secondary", "voltage/tertiary", "windings", "windings/configuration"], "geometry": ["point", "vertex"], "tags": {"power": "transformer"}, "name": "Transformer"}, - "public_transport/platform_point": {"icon": "temaki-sign_and_bench", "fields": ["name", "ref_stop_position", "network", "operator", "departures_board", "shelter"], "moreFields": ["bench", "bin", "gnis/feature_id", "level", "lit", "tactile_paving", "wheelchair"], "geometry": ["point"], "tags": {"public_transport": "platform"}, "terms": ["platform", "public transit", "public transportation", "transit", "transportation"], "name": "Transit Stop / Platform", "matchScore": 0.6}, - "public_transport/platform": {"icon": "temaki-board_transit", "fields": ["ref_platform", "network", "operator", "departures_board", "surface"], "moreFields": ["access", "covered", "indoor", "layer", "level", "lit", "wheelchair"], "geometry": ["line", "area"], "tags": {"public_transport": "platform"}, "terms": ["platform", "public transit", "public transportation", "transit", "transportation"], "name": "Transit Platform", "matchScore": 0.6}, + "public_transport/platform_point": {"icon": "temaki-sign_and_bench", "fields": ["name", "ref_stop_position", "network", "operator", "vehicles", "departures_board", "shelter"], "moreFields": ["bench", "bin", "gnis/feature_id", "level", "lit", "tactile_paving", "wheelchair"], "geometry": ["point"], "tags": {"public_transport": "platform"}, "terms": ["platform", "public transit", "public transportation", "transit", "transportation"], "name": "Transit Stop / Platform", "matchScore": 0.6}, + "public_transport/platform": {"icon": "temaki-board_transit", "fields": ["ref_platform", "network", "operator", "vehicles", "departures_board", "surface"], "moreFields": ["access", "covered", "indoor", "layer", "level", "lit", "wheelchair"], "geometry": ["line", "area"], "tags": {"public_transport": "platform"}, "terms": ["platform", "public transit", "public transportation", "transit", "transportation"], "name": "Transit Platform", "matchScore": 0.6}, "public_transport/platform/aerialway_point": {"icon": "temaki-gondola_lift", "fields": ["{public_transport/platform_point}"], "moreFields": ["{public_transport/platform_point}"], "geometry": ["point"], "tags": {"public_transport": "platform", "aerialway": "yes"}, "reference": {"key": "public_transport", "value": "platform"}, "searchable": false, "name": "Aerialway Stop / Platform"}, "public_transport/platform/ferry_point": {"icon": "temaki-ferry", "fields": ["{public_transport/platform_point}"], "moreFields": ["{public_transport/platform_point}"], "geometry": ["point"], "tags": {"public_transport": "platform", "ferry": "yes"}, "reference": {"key": "public_transport", "value": "platform"}, "searchable": false, "name": "Ferry Stop / Platform"}, "public_transport/platform/light_rail_point": {"icon": "temaki-light_rail", "fields": ["{public_transport/platform_point}"], "moreFields": ["{public_transport/platform_point}"], "geometry": ["point"], "tags": {"public_transport": "platform", "light_rail": "yes"}, "reference": {"key": "railway", "value": "platform"}, "searchable": false, "name": "Light Rail Stop / Platform"}, @@ -1006,7 +1006,7 @@ "public_transport/station_train": {"icon": "temaki-train", "fields": ["{public_transport/station}"], "moreFields": ["{public_transport/station}"], "geometry": ["vertex", "point", "area"], "tags": {"public_transport": "station", "train": "yes"}, "addTags": {"public_transport": "station", "train": "yes", "railway": "station"}, "reference": {"key": "railway", "value": "station"}, "terms": ["public transit", "public transportation", "rail", "station", "terminal", "track", "train", "transit", "transportation"], "name": "Train Station"}, "public_transport/station_tram": {"icon": "temaki-tram", "fields": ["{public_transport/station}"], "moreFields": ["{public_transport/station}"], "geometry": ["point", "area"], "tags": {"public_transport": "station", "tram": "yes"}, "reference": {"key": "public_transport", "value": "station"}, "terms": ["electric", "light rail", "public transit", "public transportation", "rail", "station", "streetcar", "terminal", "track", "tram", "trolley", "transit", "transportation"], "name": "Tram Station"}, "public_transport/station_trolleybus": {"icon": "temaki-trolleybus", "fields": ["{public_transport/station}"], "moreFields": ["{public_transport/station}"], "geometry": ["point", "area"], "tags": {"public_transport": "station", "trolleybus": "yes"}, "addTags": {"public_transport": "station", "trolleybus": "yes", "amenity": "bus_station"}, "reference": {"key": "amenity", "value": "bus_station"}, "terms": ["bus", "electric", "public transit", "public transportation", "station", "streetcar", "terminal", "trackless", "tram", "trolley", "transit", "transportation"], "name": "Trolleybus Station / Terminal"}, - "public_transport/station": {"icon": "temaki-transit", "fields": ["name", "network", "operator", "address", "building_area", "internet_access"], "moreFields": ["air_conditioning", "baby_feeding", "email", "fax", "gnis/feature_id", "internet_access/fee", "internet_access/ssid", "level", "phone", "website", "wheelchair"], "geometry": ["point", "area"], "tags": {"public_transport": "station"}, "terms": ["public transit", "public transportation", "station", "terminal", "transit", "transportation"], "name": "Transit Station", "matchScore": 0.2}, + "public_transport/station": {"icon": "temaki-transit", "fields": ["name", "network", "operator", "vehicles", "address", "building_area", "internet_access"], "moreFields": ["air_conditioning", "baby_feeding", "email", "fax", "gnis/feature_id", "internet_access/fee", "internet_access/ssid", "level", "phone", "website", "wheelchair"], "geometry": ["point", "area"], "tags": {"public_transport": "station"}, "terms": ["public transit", "public transportation", "station", "terminal", "transit", "transportation"], "name": "Transit Station", "matchScore": 0.2}, "public_transport/stop_area": {"icon": "iD-relation", "fields": ["name", "ref", "network", "operator"], "geometry": ["relation"], "tags": {"type": "public_transport", "public_transport": "stop_area"}, "reference": {"key": "public_transport", "value": "stop_area"}, "name": "Transit Stop Area"}, "public_transport/stop_position_aerialway": {"icon": "temaki-gondola_lift", "fields": ["{public_transport/stop_position}"], "moreFields": ["{public_transport/stop_position}"], "geometry": ["vertex"], "tags": {"public_transport": "stop_position", "aerialway": "yes"}, "reference": {"key": "public_transport", "value": "stop_position"}, "terms": ["aerialway", "cable car", "public transit", "public transportation", "transit", "transportation"], "name": "Aerialway Stopping Location"}, "public_transport/stop_position_bus": {"icon": "temaki-bus", "fields": ["{public_transport/stop_position}"], "moreFields": ["{public_transport/stop_position}"], "geometry": ["vertex"], "tags": {"public_transport": "stop_position", "bus": "yes"}, "reference": {"key": "public_transport", "value": "stop_position"}, "terms": ["bus", "public transit", "public transportation", "transit", "transportation"], "name": "Bus Stopping Location"}, @@ -1017,7 +1017,7 @@ "public_transport/stop_position_train": {"icon": "temaki-train", "fields": ["{public_transport/stop_position}"], "moreFields": ["{public_transport/stop_position}"], "geometry": ["vertex"], "tags": {"public_transport": "stop_position", "train": "yes"}, "addTags": {"public_transport": "stop_position", "train": "yes", "railway": "stop"}, "reference": {"key": "railway", "value": "stop"}, "terms": ["public transit", "public transportation", "rail", "track", "train", "transit", "transportation"], "name": "Train Stopping Location"}, "public_transport/stop_position_tram": {"icon": "temaki-tram", "fields": ["{public_transport/stop_position}"], "moreFields": ["{public_transport/stop_position}"], "geometry": ["vertex"], "tags": {"public_transport": "stop_position", "tram": "yes"}, "addTags": {"public_transport": "stop_position", "tram": "yes", "railway": "tram_stop"}, "reference": {"key": "public_transport", "value": "stop_position"}, "terms": ["electric", "light rail", "public transit", "public transportation", "rail", "streetcar", "track", "tram", "trolley", "transit", "transportation"], "name": "Tram Stopping Location"}, "public_transport/stop_position_trolleybus": {"icon": "temaki-trolleybus", "fields": ["{public_transport/stop_position}"], "moreFields": ["{public_transport/stop_position}"], "geometry": ["vertex"], "tags": {"public_transport": "stop_position", "trolleybus": "yes"}, "reference": {"key": "public_transport", "value": "stop_position"}, "terms": ["bus", "electric", "public transit", "public transportation", "streetcar", "trackless", "tram", "trolley", "transit", "transportation"], "name": "Trolleybus Stopping Location"}, - "public_transport/stop_position": {"icon": "temaki-transit", "fields": ["name", "ref_stop_position", "network", "operator"], "moreFields": [], "geometry": ["vertex"], "tags": {"public_transport": "stop_position"}, "terms": ["public transit", "public transportation", "transit", "transportation"], "name": "Transit Stopping Location", "matchScore": 0.2}, + "public_transport/stop_position": {"icon": "temaki-transit", "fields": ["name", "ref_stop_position", "network", "operator", "vehicles"], "moreFields": [], "geometry": ["vertex"], "tags": {"public_transport": "stop_position"}, "terms": ["public transit", "public transportation", "transit", "transportation"], "name": "Transit Stopping Location", "matchScore": 0.2}, "railway/halt": {"icon": "temaki-rail_flag", "geometry": ["point", "vertex"], "tags": {"railway": "halt"}, "name": "Train Station (Halt / Request)", "searchable": false}, "railway/platform": {"icon": "temaki-board_train", "fields": ["{public_transport/platform}"], "moreFields": ["{public_transport/platform}"], "geometry": ["line", "area"], "tags": {"railway": "platform"}, "name": "Train Platform", "searchable": false}, "railway/station": {"icon": "temaki-train", "fields": ["{public_transport/station}"], "moreFields": ["{public_transport/station}"], "geometry": ["point", "vertex", "area"], "tags": {"railway": "station"}, "matchScore": 0.95, "name": "Train Station", "searchable": false}, @@ -1254,6 +1254,7 @@ "tourism/hotel": {"icon": "fas-concierge-bell", "fields": ["{tourism/motel}"], "moreFields": ["{tourism/motel}", "bar", "stars"], "geometry": ["point", "area"], "tags": {"tourism": "hotel"}, "terms": ["concierge", "lodge", "lodging", "overnight accommodations"], "name": "Hotel"}, "tourism/information": {"icon": "maki-information", "fields": ["information", "operator", "address", "building_area"], "moreFields": ["level"], "geometry": ["point", "vertex", "area"], "tags": {"tourism": "information"}, "name": "Information"}, "tourism/information/board": {"icon": "temaki-info_board", "fields": ["name", "operator", "board_type", "direction"], "geometry": ["point", "vertex"], "tags": {"tourism": "information", "information": "board"}, "reference": {"key": "information", "value": "board"}, "name": "Information Board"}, + "tourism/information/board/welcome_sign": {"icon": "maki-embassy", "geometry": ["point"], "terms": ["new location"], "tags": {"tourism": "information", "information": "board", "board_type": "welcome_sign"}, "name": "Welcome Sign"}, "tourism/information/guidepost": {"icon": "fas-map-signs", "fields": ["name", "ele_node", "operator", "ref"], "moreFields": ["material"], "geometry": ["point", "vertex"], "terms": ["signpost"], "tags": {"tourism": "information", "information": "guidepost"}, "reference": {"key": "information", "value": "guidepost"}, "name": "Guidepost"}, "tourism/information/map": {"icon": "fas-map", "fields": ["operator", "map_type", "map_size", "direction"], "geometry": ["point", "vertex"], "tags": {"tourism": "information", "information": "map"}, "reference": {"key": "information", "value": "map"}, "name": "Map"}, "tourism/information/office": {"icon": "maki-information", "fields": ["name", "operator", "address", "building_area", "internet_access", "internet_access/fee"], "moreFields": ["building/levels_building", "email", "fax", "gnis/feature_id", "height_building", "internet_access/ssid", "phone", "website", "wheelchair"], "geometry": ["point", "vertex", "area"], "tags": {"tourism": "information", "information": "office"}, "reference": {"key": "information", "value": "office"}, "terms": ["information office", "tour guide", "tourism office", "tourist information center", "visitors center", "visitors information center", "welcome center"], "name": "Visitor Center"}, @@ -1281,12 +1282,9 @@ "traffic_calming/island": {"icon": "temaki-diamond", "fields": ["surface"], "geometry": ["vertex", "line", "area"], "terms": ["circle", "roundabout", "slow"], "tags": {"traffic_calming": "island"}, "name": "Traffic Island"}, "traffic_calming/rumble_strip": {"icon": "temaki-rumble_strip", "fields": ["direction_vertex"], "geometry": ["vertex", "line"], "terms": ["audible lines", "sleeper lines", "growlers"], "tags": {"traffic_calming": "rumble_strip"}, "name": "Rumble Strip"}, "traffic_calming/table": {"icon": "temaki-speed_table", "fields": ["surface", "direction_vertex"], "geometry": ["vertex"], "tags": {"traffic_calming": "table"}, "terms": ["flat top", "hump", "speed", "slow"], "name": "Speed Table"}, - "traffic_sign_vertex": {"icon": "maki-square-stroked", "fields": ["traffic_sign", "traffic_sign/direction"], "geometry": ["vertex"], "tags": {"traffic_sign": "*"}, "terms": ["road", "highway"], "name": "Traffic Sign"}, - "traffic_sign": {"icon": "fas-directions", "fields": ["traffic_sign", "direction"], "geometry": ["point"], "tags": {"traffic_sign": "*"}, "terms": ["road", "highway"], "name": "Traffic Sign"}, - "traffic_sign/city_limit_vertex": {"icon": "maki-square-stroked", "fields": ["traffic_sign", "traffic_sign/direction", "name"], "geometry": ["vertex"], "tags": {"traffic_sign": "city_limit"}, "terms": ["town", "village", "hamlet", "boundary", "edge", "border", "road", "highway"], "name": "City Limit Sign"}, - "traffic_sign/city_limit": {"icon": "maki-square-stroked", "fields": ["traffic_sign", "direction", "name"], "geometry": ["point"], "tags": {"traffic_sign": "city_limit"}, "terms": ["town", "village", "hamlet", "boundary", "edge", "border", "road", "highway"], "name": "City Limit Sign"}, - "traffic_sign/maxspeed_vertex": {"icon": "maki-square-stroked", "fields": ["traffic_sign", "traffic_sign/direction", "maxspeed"], "geometry": ["vertex"], "tags": {"traffic_sign": "maxspeed"}, "terms": ["max speed", "maximum speed", "road", "highway"], "name": "Speed Limit Sign"}, - "traffic_sign/maxspeed": {"icon": "maki-square-stroked", "fields": ["traffic_sign", "direction", "maxspeed"], "geometry": ["point"], "tags": {"traffic_sign": "maxspeed"}, "terms": ["max speed", "maximum speed", "road", "highway"], "name": "Speed Limit Sign"}, + "traffic_sign": {"icon": "fas-directions", "fields": ["traffic_sign", "traffic_sign/direction", "direction_point"], "geometry": ["point", "vertex"], "tags": {"traffic_sign": "*"}, "terms": ["road", "highway"], "name": "Traffic Sign"}, + "traffic_sign/city_limit": {"icon": "maki-square-stroked", "fields": ["{traffic_sign}", "name"], "geometry": ["point", "vertex"], "tags": {"traffic_sign": "city_limit"}, "terms": ["town", "village", "hamlet", "boundary", "edge", "border", "road", "highway"], "name": "City Limit Sign"}, + "traffic_sign/maxspeed": {"icon": "maki-square-stroked", "fields": ["{traffic_sign}", "maxspeed"], "geometry": ["point", "vertex"], "tags": {"traffic_sign": "maxspeed"}, "terms": ["max speed", "maximum speed", "road", "highway"], "name": "Speed Limit Sign"}, "type/multipolygon": {"icon": "iD-multipolygon", "geometry": ["area", "relation"], "tags": {"type": "multipolygon"}, "removeTags": {}, "name": "Multipolygon", "searchable": false, "matchScore": 0.1}, "type/boundary": {"icon": "iD-boundary", "fields": ["name", "boundary"], "geometry": ["relation"], "tags": {"type": "boundary"}, "name": "Boundary"}, "type/boundary/administrative": {"icon": "iD-boundary", "fields": ["name", "admin_level"], "moreFields": ["gnis/feature_id"], "geometry": ["relation"], "tags": {"type": "boundary", "boundary": "administrative"}, "reference": {"key": "boundary", "value": "administrative"}, "name": "Administrative Boundary"}, diff --git a/data/presets/presets/public_transport/platform.json b/data/presets/presets/public_transport/platform.json index cadd65ece..c9ef76187 100644 --- a/data/presets/presets/public_transport/platform.json +++ b/data/presets/presets/public_transport/platform.json @@ -4,6 +4,7 @@ "ref_platform", "network", "operator", + "vehicles", "departures_board", "surface" ], diff --git a/data/presets/presets/public_transport/platform_point.json b/data/presets/presets/public_transport/platform_point.json index ce252eddc..3ec88363e 100644 --- a/data/presets/presets/public_transport/platform_point.json +++ b/data/presets/presets/public_transport/platform_point.json @@ -5,6 +5,7 @@ "ref_stop_position", "network", "operator", + "vehicles", "departures_board", "shelter" ], diff --git a/data/presets/presets/public_transport/station.json b/data/presets/presets/public_transport/station.json index 6412deac5..184a215dc 100644 --- a/data/presets/presets/public_transport/station.json +++ b/data/presets/presets/public_transport/station.json @@ -4,6 +4,7 @@ "name", "network", "operator", + "vehicles", "address", "building_area", "internet_access" diff --git a/data/presets/presets/public_transport/stop_position.json b/data/presets/presets/public_transport/stop_position.json index 3da48b655..69cde81d0 100644 --- a/data/presets/presets/public_transport/stop_position.json +++ b/data/presets/presets/public_transport/stop_position.json @@ -4,7 +4,8 @@ "name", "ref_stop_position", "network", - "operator" + "operator", + "vehicles" ], "moreFields": [], "geometry": [ diff --git a/data/presets/presets/tourism/information/board/welcome_sign.json b/data/presets/presets/tourism/information/board/welcome_sign.json new file mode 100644 index 000000000..e3aa872b0 --- /dev/null +++ b/data/presets/presets/tourism/information/board/welcome_sign.json @@ -0,0 +1,15 @@ +{ + "icon": "maki-embassy", + "geometry": [ + "point" + ], + "terms": [ + "new location" + ], + "tags": { + "tourism": "information", + "information": "board", + "board_type": "welcome_sign" + }, + "name": "Welcome Sign" +} \ No newline at end of file diff --git a/data/presets/presets/traffic_sign.json b/data/presets/presets/traffic_sign.json index 423d66e76..60d848853 100644 --- a/data/presets/presets/traffic_sign.json +++ b/data/presets/presets/traffic_sign.json @@ -2,10 +2,12 @@ "icon": "fas-directions", "fields": [ "traffic_sign", - "direction" + "traffic_sign/direction", + "direction_point" ], "geometry": [ - "point" + "point", + "vertex" ], "tags": { "traffic_sign": "*" diff --git a/data/presets/presets/traffic_sign/city_limit.json b/data/presets/presets/traffic_sign/city_limit.json index bf32228f6..1175311b5 100644 --- a/data/presets/presets/traffic_sign/city_limit.json +++ b/data/presets/presets/traffic_sign/city_limit.json @@ -1,12 +1,12 @@ { "icon": "maki-square-stroked", "fields": [ - "traffic_sign", - "direction", + "{traffic_sign}", "name" ], "geometry": [ - "point" + "point", + "vertex" ], "tags": { "traffic_sign": "city_limit" diff --git a/data/presets/presets/traffic_sign/city_limit_vertex.json b/data/presets/presets/traffic_sign/city_limit_vertex.json deleted file mode 100644 index 11c71e054..000000000 --- a/data/presets/presets/traffic_sign/city_limit_vertex.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "icon": "maki-square-stroked", - "fields": [ - "traffic_sign", - "traffic_sign/direction", - "name" - ], - "geometry": [ - "vertex" - ], - "tags": { - "traffic_sign": "city_limit" - }, - "terms": [ - "town", - "village", - "hamlet", - "boundary", - "edge", - "border", - "road", - "highway" - ], - "name": "City Limit Sign" -} diff --git a/data/presets/presets/traffic_sign/maxspeed.json b/data/presets/presets/traffic_sign/maxspeed.json index 1845a779d..b5179284a 100644 --- a/data/presets/presets/traffic_sign/maxspeed.json +++ b/data/presets/presets/traffic_sign/maxspeed.json @@ -1,12 +1,12 @@ { "icon": "maki-square-stroked", "fields": [ - "traffic_sign", - "direction", + "{traffic_sign}", "maxspeed" ], "geometry": [ - "point" + "point", + "vertex" ], "tags": { "traffic_sign": "maxspeed" diff --git a/data/presets/presets/traffic_sign/maxspeed_vertex.json b/data/presets/presets/traffic_sign/maxspeed_vertex.json deleted file mode 100644 index 667d3c7d9..000000000 --- a/data/presets/presets/traffic_sign/maxspeed_vertex.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "icon": "maki-square-stroked", - "fields": [ - "traffic_sign", - "traffic_sign/direction", - "maxspeed" - ], - "geometry": [ - "vertex" - ], - "tags": { - "traffic_sign": "maxspeed" - }, - "terms": [ - "max speed", - "maximum speed", - "road", - "highway" - ], - "name": "Speed Limit Sign" -} diff --git a/data/presets/presets/traffic_sign_vertex.json b/data/presets/presets/traffic_sign_vertex.json deleted file mode 100644 index 67edd21d8..000000000 --- a/data/presets/presets/traffic_sign_vertex.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "icon": "maki-square-stroked", - "fields": [ - "traffic_sign", - "traffic_sign/direction" - ], - "geometry": [ - "vertex" - ], - "tags": { - "traffic_sign": "*" - }, - "terms": [ - "road", - "highway" - ], - "name": "Traffic Sign" -} diff --git a/data/taginfo.json b/data/taginfo.json index 861dae55f..d83d820b0 100644 --- a/data/taginfo.json +++ b/data/taginfo.json @@ -1199,6 +1199,7 @@ {"key": "tourism", "value": "hotel", "description": "🄿 Hotel", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/openstreetmap/iD@develop/svg/fontawesome/fas-concierge-bell.svg"}, {"key": "tourism", "value": "information", "description": "🄿 Information", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/mapbox/maki/icons/information-15.svg"}, {"key": "information", "value": "board", "description": "🄿 Information Board", "object_types": ["node"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/info_board.svg"}, + {"key": "board_type", "value": "welcome_sign", "description": "🄿 Welcome Sign", "object_types": ["node"], "icon_url": "https://cdn.jsdelivr.net/gh/mapbox/maki/icons/embassy-15.svg"}, {"key": "information", "value": "guidepost", "description": "🄿 Guidepost", "object_types": ["node"], "icon_url": "https://cdn.jsdelivr.net/gh/openstreetmap/iD@develop/svg/fontawesome/fas-map-signs.svg"}, {"key": "information", "value": "map", "description": "🄿 Map", "object_types": ["node"], "icon_url": "https://cdn.jsdelivr.net/gh/openstreetmap/iD@develop/svg/fontawesome/fas-map.svg"}, {"key": "information", "value": "office", "description": "🄿 Visitor Center", "object_types": ["node", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/mapbox/maki/icons/information-15.svg"}, @@ -1225,7 +1226,7 @@ {"key": "traffic_calming", "value": "hump", "description": "🄿 Speed Hump", "object_types": ["node", "way"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/speed_hump.svg"}, {"key": "traffic_calming", "value": "island", "description": "🄿 Traffic Island", "object_types": ["node", "way", "area"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/diamond.svg"}, {"key": "traffic_calming", "value": "rumble_strip", "description": "🄿 Rumble Strip", "object_types": ["node", "way"], "icon_url": "https://cdn.jsdelivr.net/gh/ideditor/temaki/icons/rumble_strip.svg"}, - {"key": "traffic_sign", "description": "🄿 Traffic Sign, 🄵 Traffic Sign", "object_types": ["node"], "icon_url": "https://cdn.jsdelivr.net/gh/mapbox/maki/icons/square-stroked-15.svg"}, + {"key": "traffic_sign", "description": "🄿 Traffic Sign, 🄵 Traffic Sign", "object_types": ["node"], "icon_url": "https://cdn.jsdelivr.net/gh/openstreetmap/iD@develop/svg/fontawesome/fas-directions.svg"}, {"key": "traffic_sign", "value": "city_limit", "description": "🄿 City Limit Sign", "object_types": ["node"], "icon_url": "https://cdn.jsdelivr.net/gh/mapbox/maki/icons/square-stroked-15.svg"}, {"key": "traffic_sign", "value": "maxspeed", "description": "🄿 Speed Limit Sign", "object_types": ["node"], "icon_url": "https://cdn.jsdelivr.net/gh/mapbox/maki/icons/square-stroked-15.svg"}, {"key": "type", "value": "multipolygon", "description": "🄿 Multipolygon (unsearchable)", "object_types": ["area", "relation"], "icon_url": "https://cdn.jsdelivr.net/gh/openstreetmap/iD@develop/svg/iD-sprite/presets/multipolygon.svg"}, @@ -1387,10 +1388,10 @@ {"key": "bicycle_parking", "description": "🄵 Type"}, {"key": "bin", "description": "🄵 Waste Bin"}, {"key": "blind", "description": "🄵 Blind Person Access"}, - {"key": "blood:", "value": "whole", "description": "🄵 Blood Components"}, - {"key": "blood:", "value": "plasma", "description": "🄵 Blood Components"}, - {"key": "blood:", "value": "platelets", "description": "🄵 Blood Components"}, - {"key": "blood:", "value": "stemcells", "description": "🄵 Blood Components"}, + {"key": "blood:whole", "description": "🄵 Blood Components"}, + {"key": "blood:plasma", "description": "🄵 Blood Components"}, + {"key": "blood:platelets", "description": "🄵 Blood Components"}, + {"key": "blood:stemcells", "description": "🄵 Blood Components"}, {"key": "board_type", "description": "🄵 Type"}, {"key": "bollard", "description": "🄵 Type"}, {"key": "booth", "description": "🄵 Booth"}, @@ -1506,10 +1507,10 @@ {"key": "direction", "value": "NNW", "description": "🄵 Direction"}, {"key": "direction", "value": "clockwise", "description": "🄵 Direction"}, {"key": "direction", "value": "anticlockwise", "description": "🄵 Direction"}, + {"key": "direction", "description": "🄵 Direction (Degrees Clockwise)"}, {"key": "direction", "value": "forward", "description": "🄵 Direction Affected"}, {"key": "direction", "value": "backward", "description": "🄵 Direction Affected"}, {"key": "direction", "value": "both", "description": "🄵 Direction Affected"}, - {"key": "direction", "description": "🄵 Direction (Degrees Clockwise)"}, {"key": "dispensing", "description": "🄵 Dispenses Prescriptions"}, {"key": "display", "description": "🄵 Display"}, {"key": "distance", "description": "🄵 Distance"}, @@ -1980,6 +1981,14 @@ {"key": "usage", "value": "test", "description": "🄵 Usage Type"}, {"key": "usage", "value": "tourism", "description": "🄵 Usage Type"}, {"key": "valve", "description": "🄵 Type"}, + {"key": "bus", "description": "🄵 Vehicles"}, + {"key": "trolleybus", "description": "🄵 Vehicles"}, + {"key": "tram", "description": "🄵 Vehicles"}, + {"key": "train", "description": "🄵 Vehicles"}, + {"key": "subway", "description": "🄵 Vehicles"}, + {"key": "light_rail", "description": "🄵 Vehicles"}, + {"key": "monorail", "description": "🄵 Vehicles"}, + {"key": "ferry", "description": "🄵 Vehicles"}, {"key": "vending", "description": "🄵 Types of Goods"}, {"key": "vhf", "description": "🄵 VHF Channel"}, {"key": "video", "description": "🄵 Video Calls"}, @@ -2046,6 +2055,7 @@ {"key": "amenity", "value": "gym", "description": "🄳 ➜ leisure=fitness_centre"}, {"key": "amenity", "value": "hotel", "description": "🄳 ➜ tourism=hotel"}, {"key": "amenity", "value": "kiosk", "description": "🄳 ➜ shop=kiosk"}, + {"key": "amenity", "value": "notice_board", "description": "🄳 ➜ advertising=board"}, {"key": "amenity", "value": "nursery", "description": "🄳 ➜ amenity=kindergarten"}, {"key": "amenity", "value": "preschool", "description": "🄳 ➜ amenity=kindergarten + preschool=yes"}, {"key": "amenity", "value": "public_building", "description": "🄳 ➜ building=public"}, diff --git a/dist/locales/en.json b/dist/locales/en.json index c5abe8aa4..4f2c141ca 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -3422,6 +3422,10 @@ "anticlockwise": "Counterclockwise" } }, + "direction_point": { + "label": "Direction (Degrees Clockwise)", + "placeholder": "45, 90, 180, 270" + }, "direction_vertex_dual": { "label": "Direction Affected", "options": { @@ -5105,6 +5109,19 @@ "valve": { "label": "Type" }, + "vehicles": { + "label": "Vehicles", + "options": { + "bus": "Bus", + "trolleybus": "Trolleybus", + "tram": "Tram", + "train": "Train", + "subway": "Subway", + "light_rail": "Light Rail", + "monorail": "Monorail", + "ferry": "Ferry" + } + }, "vending": { "label": "Types of Goods" }, @@ -10183,6 +10200,10 @@ "name": "Information Board", "terms": "" }, + "tourism/information/board/welcome_sign": { + "name": "Welcome Sign", + "terms": "new location" + }, "tourism/information/guidepost": { "name": "Guidepost", "terms": "signpost" @@ -10291,26 +10312,14 @@ "name": "Speed Table", "terms": "flat top,hump,speed,slow" }, - "traffic_sign_vertex": { - "name": "Traffic Sign", - "terms": "road,highway" - }, "traffic_sign": { "name": "Traffic Sign", "terms": "road,highway" }, - "traffic_sign/city_limit_vertex": { - "name": "City Limit Sign", - "terms": "town,village,hamlet,boundary,edge,border,road,highway" - }, "traffic_sign/city_limit": { "name": "City Limit Sign", "terms": "town,village,hamlet,boundary,edge,border,road,highway" }, - "traffic_sign/maxspeed_vertex": { - "name": "Speed Limit Sign", - "terms": "max speed,maximum speed,road,highway" - }, "traffic_sign/maxspeed": { "name": "Speed Limit Sign", "terms": "max speed,maximum speed,road,highway" diff --git a/modules/ui/field.js b/modules/ui/field.js index 9d92eb873..d25df54a5 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -185,7 +185,7 @@ export function uiField(context, presetField, entityIDs, options) { // instantiate tag reference if (options.wrap && options.info) { - var referenceKey = d.key; + var referenceKey = d.key || ''; if (d.type === 'multiCombo') { // lookup key without the trailing ':' referenceKey = referenceKey.replace(/:$/, ''); } diff --git a/modules/ui/fields/combo.js b/modules/ui/fields/combo.js index 1c0733d8f..4ba8ecafd 100644 --- a/modules/ui/fields/combo.js +++ b/modules/ui/fields/combo.js @@ -20,20 +20,18 @@ export { export function uiFieldCombo(field, context) { var dispatch = d3_dispatch('change'); - var taginfo = services.taginfo; - var isMulti = (field.type === 'multiCombo'); - var isNetwork = (field.type === 'networkCombo'); - var isSemi = (field.type === 'semiCombo'); - var optstrings = field.strings && field.strings.options; - var optarray = field.options; - var snake_case = (field.snake_case || (field.snake_case === undefined)); - var caseSensitive = field.caseSensitive; - var combobox = uiCombobox(context, 'combo-' + field.safeid) - .caseSensitive(caseSensitive) - .minItems(isMulti || isSemi ? 1 : 2); - var container = d3_select(null); - var inputWrap = d3_select(null); - var input = d3_select(null); + var _isMulti = (field.type === 'multiCombo'); + var _isNetwork = (field.type === 'networkCombo'); + var _isSemi = (field.type === 'semiCombo'); + var _optstrings = field.strings && field.strings.options; + var _optarray = field.options; + var _snake_case = (field.snake_case || (field.snake_case === undefined)); + var _combobox = uiCombobox(context, 'combo-' + field.safeid) + .caseSensitive(field.caseSensitive) + .minItems(_isMulti || _isSemi ? 1 : 2); + var _container = d3_select(null); + var _inputWrap = d3_select(null); + var _input = d3_select(null); var _comboData = []; var _multiData = []; var _entityIDs = []; @@ -49,7 +47,7 @@ export function uiFieldCombo(field, context) { // ensure multiCombo field.key ends with a ':' - if (isMulti && /[^:]$/.test(field.key)) { + if (_isMulti && field.key && /[^:]$/.test(field.key)) { field.key += ':'; } @@ -74,7 +72,7 @@ export function uiFieldCombo(field, context) { function tagValue(dval) { dval = clean(dval || ''); - if (optstrings) { + if (_optstrings) { var found = _comboData.find(function(o) { return o.key && clean(o.value) === dval; }); @@ -87,7 +85,7 @@ export function uiFieldCombo(field, context) { return 'yes'; } - return (snake_case ? snake(dval) : dval) || undefined; + return (_snake_case ? snake(dval) : dval) || undefined; } @@ -96,7 +94,7 @@ export function uiFieldCombo(field, context) { function displayValue(tval) { tval = tval || ''; - if (optstrings) { + if (_optstrings) { var found = _comboData.find(function(o) { return o.key === tval && o.value; }); @@ -109,7 +107,7 @@ export function uiFieldCombo(field, context) { return ''; } - return snake_case ? unsnake(tval) : tval; + return _snake_case ? unsnake(tval) : tval; } @@ -128,28 +126,28 @@ export function uiFieldCombo(field, context) { function initCombo(selection, attachTo) { - if (optstrings) { + if (_optstrings) { selection.attr('readonly', 'readonly'); - selection.call(combobox, attachTo); + selection.call(_combobox, attachTo); setStaticValues(setPlaceholder); - } else if (optarray) { - selection.call(combobox, attachTo); + } else if (_optarray) { + selection.call(_combobox, attachTo); setStaticValues(setPlaceholder); - } else if (taginfo) { - selection.call(combobox.fetcher(setTaginfoValues), attachTo); + } else if (services.taginfo) { + selection.call(_combobox.fetcher(setTaginfoValues), attachTo); setTaginfoValues('', setPlaceholder); } } function setStaticValues(callback) { - if (!(optstrings || optarray)) return; + if (!(_optstrings || _optarray)) return; - if (optstrings) { - _comboData = Object.keys(optstrings).map(function(k) { - var v = field.t('options.' + k, { 'default': optstrings[k], html: false }); + if (_optstrings) { + _comboData = Object.keys(_optstrings).map(function(k) { + var v = field.t('options.' + k, { 'default': _optstrings[k], html: false }); return { key: k, value: v, @@ -157,9 +155,9 @@ export function uiFieldCombo(field, context) { }; }); - } else if (optarray) { - _comboData = optarray.map(function(k) { - var v = snake_case ? unsnake(k) : k; + } else if (_optarray) { + _comboData = _optarray.map(function(k) { + var v = _snake_case ? unsnake(k) : k; return { key: k, value: v, @@ -168,15 +166,15 @@ export function uiFieldCombo(field, context) { }); } - combobox.data(objectDifference(_comboData, _multiData)); + _combobox.data(objectDifference(_comboData, _multiData)); if (callback) callback(_comboData); } function setTaginfoValues(q, callback) { - var fn = isMulti ? 'multikeys' : 'values'; - var query = (isMulti ? field.key : '') + q; - var hasCountryPrefix = isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0; + var fn = _isMulti ? 'multikeys' : 'values'; + var query = (_isMulti ? field.key : '') + q; + var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0; if (hasCountryPrefix) { query = _countryCode + ':'; } @@ -191,7 +189,7 @@ export function uiFieldCombo(field, context) { params.geometry = context.graph().geometry(_entityIDs[0]); } - taginfo[fn](params, function(err, data) { + services.taginfo[fn](params, function(err, data) { if (err) return; data = data.filter(function(d) { @@ -220,16 +218,16 @@ export function uiFieldCombo(field, context) { } // hide the caret if there are no suggestions - container.classed('empty-combobox', data.length === 0); + _container.classed('empty-combobox', data.length === 0); _comboData = data.map(function(d) { var k = d.value; - if (isMulti) k = k.replace(field.key, ''); - var v = snake_case ? unsnake(k) : k; + if (_isMulti) k = k.replace(field.key, ''); + var v = _snake_case ? unsnake(k) : k; return { key: k, value: v, - title: isMulti ? v : d.title + title: _isMulti ? v : d.title }; }); @@ -241,7 +239,7 @@ export function uiFieldCombo(field, context) { function setPlaceholder(values) { - if (isMulti || isSemi) { + if (_isMulti || _isSemi) { _staticPlaceholder = field.placeholder() || t('inspector.add', { html: false }); } else { var vals = values @@ -257,13 +255,13 @@ export function uiFieldCombo(field, context) { } var ph; - if (!isMulti && !isSemi && _tags && Array.isArray(_tags[field.key])) { + if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) { ph = t('inspector.multiple_values', { html: false }); } else { ph = _staticPlaceholder; } - container.selectAll('input') + _container.selectAll('input') .attr('placeholder', ph); } @@ -272,17 +270,17 @@ export function uiFieldCombo(field, context) { var t = {}; var val; - if (isMulti || isSemi) { - val = tagValue(utilGetSetValue(input).replace(/,/g, ';')) || ''; - container.classed('active', false); - utilGetSetValue(input, ''); + if (_isMulti || _isSemi) { + val = tagValue(utilGetSetValue(_input).replace(/,/g, ';')) || ''; + _container.classed('active', false); + utilGetSetValue(_input, ''); var vals = val.split(';').filter(Boolean); if (!vals.length) return; - if (isMulti) { + if (_isMulti) { utilArrayUniq(vals).forEach(function(v) { - var key = field.key + v; + var key = (field.key || '') + v; if (_tags) { // don't set a multicombo value to 'yes' if it already has a non-'no' value // e.g. `language:de=main` @@ -294,16 +292,16 @@ export function uiFieldCombo(field, context) { t[key] = 'yes'; }); - } else if (isSemi) { + } else if (_isSemi) { var arr = _multiData.map(function(d) { return d.key; }); arr = arr.concat(vals); t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';')); } - window.setTimeout(function() { input.node().focus(); }, 10); + window.setTimeout(function() { _input.node().focus(); }, 10); } else { - var rawValue = utilGetSetValue(input); + var rawValue = utilGetSetValue(_input); // don't override multiple values with blank string if (!rawValue && Array.isArray(_tags[field.key])) return; @@ -319,9 +317,9 @@ export function uiFieldCombo(field, context) { function removeMultikey(d) { d3_event.stopPropagation(); var t = {}; - if (isMulti) { + if (_isMulti) { t[d.key] = undefined; - } else if (isSemi) { + } else if (_isSemi) { var arr = _multiData.map(function(md) { return md.key === d.key ? null : md.key; }).filter(Boolean); @@ -334,17 +332,17 @@ export function uiFieldCombo(field, context) { function combo(selection) { - container = selection.selectAll('.form-field-input-wrap') + _container = selection.selectAll('.form-field-input-wrap') .data([0]); - var type = (isMulti || isSemi) ? 'multicombo': 'combo'; - container = container.enter() + var type = (_isMulti || _isSemi) ? 'multicombo': 'combo'; + _container = _container.enter() .append('div') .attr('class', 'form-field-input-wrap form-field-input-' + type) - .merge(container); + .merge(_container); - if (isMulti || isSemi) { - container = container.selectAll('.chiplist') + if (_isMulti || _isSemi) { + _container = _container.selectAll('.chiplist') .data([0]); var listClass = 'chiplist'; @@ -355,67 +353,67 @@ export function uiFieldCombo(field, context) { listClass += ' full-line-chips'; } - container = container.enter() + _container = _container.enter() .append('ul') .attr('class', listClass) .on('click', function() { - window.setTimeout(function() { input.node().focus(); }, 10); + window.setTimeout(function() { _input.node().focus(); }, 10); }) - .merge(container); + .merge(_container); - inputWrap = container.selectAll('.input-wrap') + _inputWrap = _container.selectAll('.input-wrap') .data([0]); - inputWrap = inputWrap.enter() + _inputWrap = _inputWrap.enter() .append('li') .attr('class', 'input-wrap') - .merge(inputWrap); + .merge(_inputWrap); - input = inputWrap.selectAll('input') + _input = _inputWrap.selectAll('input') .data([0]); } else { - input = container.selectAll('input') + _input = _container.selectAll('input') .data([0]); } - input = input.enter() + _input = _input.enter() .append('input') .attr('type', 'text') .attr('id', field.domId) .call(utilNoAuto) .call(initCombo, selection) - .merge(input); + .merge(_input); - if (isNetwork) { + if (_isNetwork) { var extent = combinedEntityExtent(); var countryCode = extent && countryCoder.iso1A2Code(extent.center()); _countryCode = countryCode && countryCode.toLowerCase(); } - input + _input .on('change', change) .on('blur', change); - input + _input .on('keydown.field', function() { switch (d3_event.keyCode) { case 13: // ↩ Return - input.node().blur(); // blurring also enters the value + _input.node().blur(); // blurring also enters the value d3_event.stopPropagation(); break; } }); - if (isMulti || isSemi) { - combobox + if (_isMulti || _isSemi) { + _combobox .on('accept', function() { - input.node().blur(); - input.node().focus(); + _input.node().blur(); + _input.node().focus(); }); - input - .on('focus', function() { container.classed('active', true); }); + _input + .on('focus', function() { _container.classed('active', true); }); } } @@ -423,19 +421,19 @@ export function uiFieldCombo(field, context) { combo.tags = function(tags) { _tags = tags; - if (isMulti || isSemi) { + if (_isMulti || _isSemi) { _multiData = []; var maxLength; - if (isMulti) { + if (_isMulti) { // Build _multiData array containing keys already set.. for (var k in tags) { - if (k.indexOf(field.key) !== 0) continue; + if ((field.key && k.indexOf(field.key) !== 0) || field.keys.indexOf(k) === -1) continue; var v = tags[k]; if (!v || (typeof v === 'string' && v.toLowerCase() === 'no')) continue; - var suffix = k.substring(field.key.length); + var suffix = field.key ? k.substring(field.key.length) : k; _multiData.push({ key: k, value: displayValue(suffix), @@ -443,13 +441,17 @@ export function uiFieldCombo(field, context) { }); } - // Set keys for form-field modified (needed for undo and reset buttons).. - field.keys = _multiData.map(function(d) { return d.key; }); + if (field.key) { + // Set keys for form-field modified (needed for undo and reset buttons).. + field.keys = _multiData.map(function(d) { return d.key; }); - // limit the input length so it fits after prepending the key prefix - maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key); + // limit the input length so it fits after prepending the key prefix + maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key); + } else { + maxLength = context.maxCharsForTagKey(); + } - } else if (isSemi) { + } else if (_isSemi) { var allValues = []; var commonValues; @@ -492,23 +494,23 @@ export function uiFieldCombo(field, context) { // a negative maxlength doesn't make sense maxLength = Math.max(0, maxLength); - var allowDragAndDrop = isSemi // only semiCombo values are ordered + var allowDragAndDrop = _isSemi // only semiCombo values are ordered && !Array.isArray(tags[field.key]); // Exclude existing multikeys from combo options.. var available = objectDifference(_comboData, _multiData); - combobox.data(available); + _combobox.data(available); // Hide 'Add' button if this field uses fixed set of - // translateable optstrings and they're all currently used, + // translateable _optstrings and they're all currently used, // or if the field is already at its character limit - var hideAdd = (optstrings && !available.length) || maxLength <= 0; - container.selectAll('.chiplist .input-wrap') + var hideAdd = (_optstrings && !available.length) || maxLength <= 0; + _container.selectAll('.chiplist .input-wrap') .style('display', hideAdd ? 'none' : null); // Render chips - var chips = container.selectAll('.chip') + var chips = _container.selectAll('.chip') .data(_multiData); chips.exit() @@ -550,7 +552,7 @@ export function uiFieldCombo(field, context) { return displayValue(val); }).filter(Boolean); - utilGetSetValue(input, !isMixed ? displayValue(tags[field.key]) : '') + utilGetSetValue(_input, !isMixed ? displayValue(tags[field.key]) : '') .attr('title', isMixed ? mixedValues.join('\n') : undefined) .attr('placeholder', isMixed ? t('inspector.multiple_values', { html: false }) : _staticPlaceholder || '') .classed('mixed', isMixed); @@ -585,7 +587,7 @@ export function uiFieldCombo(field, context) { var draggedTagWidth = d3_select(this).node().offsetWidth; if (field.key === 'destination') { // meaning tags are full width - container.selectAll('.chip') + _container.selectAll('.chip') .style('transform', function(d2, index2) { var node = d3_select(this).node(); @@ -607,7 +609,7 @@ export function uiFieldCombo(field, context) { return null; }); } else { - container.selectAll('.chip') + _container.selectAll('.chip') .each(function(d2, index2) { var node = d3_select(this).node(); @@ -650,7 +652,7 @@ export function uiFieldCombo(field, context) { d3_select(this) .classed('dragging', false); - container.selectAll('.chip') + _container.selectAll('.chip') .style('transform', null); if (typeof targetIndex === 'number') { @@ -678,7 +680,7 @@ export function uiFieldCombo(field, context) { combo.focus = function() { - input.node().focus(); + _input.node().focus(); }; diff --git a/scripts/build_data.js b/scripts/build_data.js index bdd98a13f..e272b92c7 100644 --- a/scripts/build_data.js +++ b/scripts/build_data.js @@ -537,13 +537,19 @@ function generateTaginfo(presets, fields) { const field = fields[id]; const keys = field.keys || [ field.key ] || []; const isRadio = (field.type === 'radio' || field.type === 'structureRadio'); + const isMulticombo = field.type === 'multiCombo'; keys.forEach(key => { - if (field.strings && field.strings.options && !isRadio) { + if (field.strings && field.strings.options && !isRadio && (!isMulticombo || field.key)) { let values = Object.keys(field.strings.options); values.forEach(value => { if (value === 'undefined' || value === '*' || value === '') return; - let tag = { key: key, value: value }; + let tag; + if (isMulticombo) { + tag = { key: key + value }; + } else { + tag = { key: key, value: value }; + } if (field.label) { tag.description = [ `🄵 ${field.label}` ]; }