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'); +};