diff --git a/css/app.css b/css/app.css
index bc5c07269..39a6b2c76 100644
--- a/css/app.css
+++ b/css/app.css
@@ -1234,6 +1234,21 @@ a:hover .icon.out-link { background-position: -500px -14px;}
border-bottom-right-radius: 4px;
}
+/* preset form cycleway */
+
+.form-field-cycleway .preset-input-wrap li {
+ border-bottom: 1px solid #CCC;
+}
+.form-field-cycleway .preset-input-wrap li:last-child {
+ border-bottom: 0;
+}
+
+.preset-input-cycleway-wrap input {
+ border-radius: 0;
+ border-width: 0;
+ border-left-width: 1px;
+}
+
/* preset form numbers */
input[type=number] {
diff --git a/data/presets.yaml b/data/presets.yaml
index 1878cfe8f..edd40cebd 100644
--- a/data/presets.yaml
+++ b/data/presets.yaml
@@ -251,6 +251,43 @@ en:
cuisine:
# 'cuisine=*'
label: Cuisine
+ cycleway:
+ # 'cycleway:left=*, cycleway:right=*'
+ label: Bike Lanes
+ options:
+ # lane=yes
+ lane:
+ description: A bike lane separated from auto traffic by a painted line
+ title: Standard bike lane
+ # none=yes
+ none:
+ description: No bike lane
+ title: None
+ # opposite=yes
+ opposite:
+ description: A bike lane that travels in both directions on a one-way street
+ title: Contraflow bike lane
+ # opposite_lane=yes
+ opposite_lane:
+ description: A bike lane that travels in the opposite direction of traffic
+ title: Opposite bike lane
+ # share_busway=yes
+ share_busway:
+ description: A bike lane shared with a bus lane
+ title: Bike lane shared with bus
+ # shared_lane=yes
+ shared_lane:
+ description: A bike lane with no separation from auto traffic
+ title: Shared bike lane
+ # track=yes
+ track:
+ description: A bike lane separated from traffic by a physical barrier
+ title: Bike track
+ # cycleway field placeholder
+ placeholder: none
+ types:
+ 'cycleway:left': Left side
+ 'cycleway:right': Right side
delivery:
# 'delivery=*'
label: Delivery
diff --git a/data/presets/fields.json b/data/presets/fields.json
index 518aacbeb..4648669ad 100644
--- a/data/presets/fields.json
+++ b/data/presets/fields.json
@@ -321,6 +321,54 @@
"type": "combo",
"label": "Cuisine"
},
+ "cycleway": {
+ "keys": [
+ "cycleway:left",
+ "cycleway:right"
+ ],
+ "reference": {
+ "key": "cycleway"
+ },
+ "type": "cycleway",
+ "label": "Bike Lanes",
+ "placeholder": "none",
+ "strings": {
+ "types": {
+ "cycleway:left": "Left side",
+ "cycleway:right": "Right side"
+ },
+ "options": {
+ "none": {
+ "title": "None",
+ "description": "No bike lane"
+ },
+ "lane": {
+ "title": "Standard bike lane",
+ "description": "A bike lane separated from auto traffic by a painted line"
+ },
+ "shared_lane": {
+ "title": "Shared bike lane",
+ "description": "A bike lane with no separation from auto traffic"
+ },
+ "track": {
+ "title": "Bike track",
+ "description": "A bike lane separated from traffic by a physical barrier"
+ },
+ "share_busway": {
+ "title": "Bike lane shared with bus",
+ "description": "A bike lane shared with a bus lane"
+ },
+ "opposite_lane": {
+ "title": "Opposite bike lane",
+ "description": "A bike lane that travels in the opposite direction of traffic"
+ },
+ "opposite": {
+ "title": "Contraflow bike lane",
+ "description": "A bike lane that travels in both directions on a one-way street"
+ }
+ }
+ }
+ },
"delivery": {
"key": "delivery",
"type": "check",
diff --git a/data/presets/fields/cycleway.json b/data/presets/fields/cycleway.json
new file mode 100644
index 000000000..e011b0566
--- /dev/null
+++ b/data/presets/fields/cycleway.json
@@ -0,0 +1,43 @@
+{
+ "keys": ["cycleway:left", "cycleway:right"],
+ "reference": {"key": "cycleway"},
+ "type": "cycleway",
+ "label": "Bike Lanes",
+ "placeholder": "none",
+ "strings": {
+ "types": {
+ "cycleway:left": "Left side",
+ "cycleway:right": "Right side"
+ },
+ "options": {
+ "none": {
+ "title": "None",
+ "description": "No bike lane"
+ },
+ "lane": {
+ "title": "Standard bike lane",
+ "description": "A bike lane separated from auto traffic by a painted line"
+ },
+ "shared_lane": {
+ "title": "Shared bike lane",
+ "description": "A bike lane with no separation from auto traffic"
+ },
+ "track": {
+ "title": "Bike track",
+ "description": "A bike lane separated from traffic by a physical barrier"
+ },
+ "share_busway": {
+ "title": "Bike lane shared with bus",
+ "description": "A bike lane shared with a bus lane"
+ },
+ "opposite_lane": {
+ "title": "Opposite bike lane",
+ "description": "A bike lane that travels in the opposite direction of traffic"
+ },
+ "opposite": {
+ "title": "Contraflow bike lane",
+ "description": "A bike lane that travels in both directions on a one-way street"
+ }
+ }
+ }
+}
diff --git a/data/presets/presets.json b/data/presets/presets.json
index 09c1f3b4f..b01e1992f 100644
--- a/data/presets/presets.json
+++ b/data/presets/presets.json
@@ -3938,7 +3938,8 @@
"maxspeed",
"structure",
"access",
- "surface"
+ "surface",
+ "cycleway"
],
"geometry": [
"line"
@@ -4081,7 +4082,8 @@
"access",
"lanes",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
@@ -4100,7 +4102,8 @@
"structure",
"access",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
@@ -4147,7 +4150,8 @@
"maxspeed",
"structure",
"access",
- "surface"
+ "surface",
+ "cycleway"
],
"geometry": [
"line"
@@ -4199,7 +4203,8 @@
"access",
"lanes",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
@@ -4218,7 +4223,8 @@
"structure",
"access",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
@@ -4241,7 +4247,8 @@
"maxspeed",
"structure",
"access",
- "surface"
+ "surface",
+ "cycleway"
],
"geometry": [
"line"
@@ -4411,7 +4418,8 @@
"access",
"lanes",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
@@ -4430,7 +4438,8 @@
"structure",
"access",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
@@ -4548,7 +4557,8 @@
"maxspeed",
"structure",
"access",
- "surface"
+ "surface",
+ "cycleway"
],
"geometry": [
"line"
diff --git a/data/presets/presets/highway/living_street.json b/data/presets/presets/highway/living_street.json
index ac0202587..8a9b70aec 100644
--- a/data/presets/presets/highway/living_street.json
+++ b/data/presets/presets/highway/living_street.json
@@ -5,7 +5,8 @@
"maxspeed",
"structure",
"access",
- "surface"
+ "surface",
+ "cycleway"
],
"geometry": [
"line"
diff --git a/data/presets/presets/highway/primary.json b/data/presets/presets/highway/primary.json
index e09c87433..a9d54ac8c 100644
--- a/data/presets/presets/highway/primary.json
+++ b/data/presets/presets/highway/primary.json
@@ -7,7 +7,8 @@
"access",
"lanes",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
@@ -17,4 +18,4 @@
},
"terms": [],
"name": "Primary Road"
-}
\ No newline at end of file
+}
diff --git a/data/presets/presets/highway/primary_link.json b/data/presets/presets/highway/primary_link.json
index aeb87dd2c..3972c3aea 100644
--- a/data/presets/presets/highway/primary_link.json
+++ b/data/presets/presets/highway/primary_link.json
@@ -6,7 +6,8 @@
"structure",
"access",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
diff --git a/data/presets/presets/highway/residential.json b/data/presets/presets/highway/residential.json
index bca93dba5..f17d5e565 100644
--- a/data/presets/presets/highway/residential.json
+++ b/data/presets/presets/highway/residential.json
@@ -5,7 +5,8 @@
"maxspeed",
"structure",
"access",
- "surface"
+ "surface",
+ "cycleway"
],
"geometry": [
"line"
@@ -15,4 +16,4 @@
},
"terms": [],
"name": "Residential Road"
-}
\ No newline at end of file
+}
diff --git a/data/presets/presets/highway/secondary.json b/data/presets/presets/highway/secondary.json
index ed698a66f..244e3aaf9 100644
--- a/data/presets/presets/highway/secondary.json
+++ b/data/presets/presets/highway/secondary.json
@@ -7,7 +7,8 @@
"access",
"lanes",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
@@ -17,4 +18,4 @@
},
"terms": [],
"name": "Secondary Road"
-}
\ No newline at end of file
+}
diff --git a/data/presets/presets/highway/secondary_link.json b/data/presets/presets/highway/secondary_link.json
index ce24d2d3a..d791f3aec 100644
--- a/data/presets/presets/highway/secondary_link.json
+++ b/data/presets/presets/highway/secondary_link.json
@@ -6,7 +6,8 @@
"structure",
"access",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
diff --git a/data/presets/presets/highway/service.json b/data/presets/presets/highway/service.json
index c379d2997..46efb695a 100644
--- a/data/presets/presets/highway/service.json
+++ b/data/presets/presets/highway/service.json
@@ -6,7 +6,8 @@
"maxspeed",
"structure",
"access",
- "surface"
+ "surface",
+ "cycleway"
],
"geometry": [
"line"
@@ -16,4 +17,4 @@
},
"terms": [],
"name": "Service Road"
-}
\ No newline at end of file
+}
diff --git a/data/presets/presets/highway/tertiary.json b/data/presets/presets/highway/tertiary.json
index 2cdaa3800..42e4aa43b 100644
--- a/data/presets/presets/highway/tertiary.json
+++ b/data/presets/presets/highway/tertiary.json
@@ -7,7 +7,8 @@
"access",
"lanes",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
@@ -17,4 +18,4 @@
},
"terms": [],
"name": "Tertiary Road"
-}
\ No newline at end of file
+}
diff --git a/data/presets/presets/highway/tertiary_link.json b/data/presets/presets/highway/tertiary_link.json
index 4f2398285..8985e1336 100644
--- a/data/presets/presets/highway/tertiary_link.json
+++ b/data/presets/presets/highway/tertiary_link.json
@@ -6,7 +6,8 @@
"structure",
"access",
"surface",
- "ref"
+ "ref",
+ "cycleway"
],
"geometry": [
"line"
diff --git a/data/presets/presets/highway/unclassified.json b/data/presets/presets/highway/unclassified.json
index 8b49c9092..9ae82d8ae 100644
--- a/data/presets/presets/highway/unclassified.json
+++ b/data/presets/presets/highway/unclassified.json
@@ -5,7 +5,8 @@
"maxspeed",
"structure",
"access",
- "surface"
+ "surface",
+ "cycleway"
],
"geometry": [
"line"
@@ -15,4 +16,4 @@
},
"terms": [],
"name": "Unclassified Road"
-}
\ No newline at end of file
+}
diff --git a/data/presets/schema/field.json b/data/presets/schema/field.json
index c51c0cddd..b3733eaa2 100644
--- a/data/presets/schema/field.json
+++ b/data/presets/schema/field.json
@@ -52,6 +52,7 @@
"address",
"check",
"combo",
+ "cycleway",
"defaultcheck",
"text",
"maxspeed",
diff --git a/dist/img/line-presets.png b/dist/img/line-presets.png
index f27d52017..bc20ef448 100644
Binary files a/dist/img/line-presets.png and b/dist/img/line-presets.png differ
diff --git a/dist/img/relation-presets.png b/dist/img/relation-presets.png
index 47f1d6e30..ef444fb49 100644
Binary files a/dist/img/relation-presets.png and b/dist/img/relation-presets.png differ
diff --git a/dist/locales/en.json b/dist/locales/en.json
index d21a16cfb..f50c68a23 100644
--- a/dist/locales/en.json
+++ b/dist/locales/en.json
@@ -786,6 +786,44 @@
"cuisine": {
"label": "Cuisine"
},
+ "cycleway": {
+ "label": "Bike Lanes",
+ "placeholder": "none",
+ "types": {
+ "cycleway:left": "Left side",
+ "cycleway:right": "Right side"
+ },
+ "options": {
+ "none": {
+ "title": "None",
+ "description": "No bike lane"
+ },
+ "lane": {
+ "title": "Standard bike lane",
+ "description": "A bike lane separated from auto traffic by a painted line"
+ },
+ "shared_lane": {
+ "title": "Shared bike lane",
+ "description": "A bike lane with no separation from auto traffic"
+ },
+ "track": {
+ "title": "Bike track",
+ "description": "A bike lane separated from traffic by a physical barrier"
+ },
+ "share_busway": {
+ "title": "Bike lane shared with bus",
+ "description": "A bike lane shared with a bus lane"
+ },
+ "opposite_lane": {
+ "title": "Opposite bike lane",
+ "description": "A bike lane that travels in the opposite direction of traffic"
+ },
+ "opposite": {
+ "title": "Contraflow bike lane",
+ "description": "A bike lane that travels in both directions on a one-way street"
+ }
+ }
+ },
"delivery": {
"label": "Delivery"
},
diff --git a/index.html b/index.html
index ff5f84d8f..edf3987d9 100644
--- a/index.html
+++ b/index.html
@@ -127,6 +127,7 @@
+
diff --git a/js/id/ui/preset/cycleway.js b/js/id/ui/preset/cycleway.js
new file mode 100644
index 000000000..ebe28c147
--- /dev/null
+++ b/js/id/ui/preset/cycleway.js
@@ -0,0 +1,100 @@
+iD.ui.preset.cycleway = function(field) {
+ var event = d3.dispatch('change'),
+ items;
+
+ function cycleway(selection) {
+ var wrap = selection.selectAll('.preset-input-wrap')
+ .data([0]);
+
+ wrap.enter().append('div')
+ .attr('class', 'cf preset-input-wrap')
+ .append('ul');
+
+ items = wrap.select('ul').selectAll('li')
+ .data(field.keys);
+
+ // Enter
+
+ var enter = items.enter().append('li')
+ .attr('class', function(d) { return 'cf preset-cycleway-' + d; });
+
+ enter.append('span')
+ .attr('class', 'col6 label preset-label-cycleway')
+ .attr('for', function(d) { return 'preset-input-cycleway-' + d; })
+ .text(function(d) { return field.t('types.' + d); });
+
+ enter.append('div')
+ .attr('class', 'col6 preset-input-cycleway-wrap')
+ .append('input')
+ .attr('type', 'text')
+ .attr('class', 'preset-input-cycleway')
+ .attr('id', function(d) { return 'preset-input-cycleway-' + d; })
+ .each(function(d) {
+ d3.select(this)
+ .call(d3.combobox()
+ .data(cycleway.options(d)));
+ });
+
+ // Update
+
+ wrap.selectAll('.preset-input-cycleway')
+ .on('change', change)
+ .on('blur', change);
+ }
+
+ function change() {
+ var inputs = d3.selectAll('.preset-input-cycleway')[0],
+ left = d3.select(inputs[0]).value(),
+ right = d3.select(inputs[1]).value(),
+ tag = {};
+ if (left === 'none' || left === '') { left = undefined; }
+ if (right === 'none' || right === '') { right = undefined; }
+
+ // Always set both left and right as changing one can affect the other
+ tag = {
+ cycleway: undefined,
+ 'cycleway:left': left,
+ 'cycleway:right': right
+ };
+
+ // If the left and right tags match, use the cycleway tag to tag both
+ // sides the same way
+ if (left === right) {
+ tag = {
+ cycleway: left,
+ 'cycleway:left': undefined,
+ 'cycleway:right': undefined
+ };
+ }
+
+ event.change(tag);
+ }
+
+ cycleway.options = function() {
+ return d3.keys(field.strings.options).map(function(option) {
+ return {
+ title: field.t('options.' + option + '.description'),
+ value: option
+ };
+ });
+ };
+
+ cycleway.tags = function(tags) {
+ items.selectAll('.preset-input-cycleway')
+ .value(function(d) {
+ // If cycleway is set, always return that
+ if (tags.cycleway) {
+ return tags.cycleway;
+ }
+ return tags[d] || '';
+ })
+ .attr('placeholder', field.placeholder());
+ };
+
+ cycleway.focus = function() {
+ items.selectAll('.preset-input-cycleway')
+ .node().focus();
+ };
+
+ return d3.rebind(cycleway, event, 'on');
+};