diff --git a/modules/core/node.js b/modules/core/node.js index 929769141..ea46a148d 100644 --- a/modules/core/node.js +++ b/modules/core/node.js @@ -51,6 +51,15 @@ _.extend(Node.prototype, { }); }, + isOnAddressLine: function(resolver) { + return resolver.transient(this, 'isOnAddressLine', function() { + return resolver.parentWays(this).filter(function(parent) { + return parent.tags.hasOwnProperty('addr:interpolation') && + parent.geometry(resolver) === 'line'; + }).length > 0; + }); + }, + asJXON: function(changeset_id) { var r = { node: { diff --git a/modules/presets/presets.js b/modules/presets/presets.js index cb90bea96..b6dd58ec9 100644 --- a/modules/presets/presets.js +++ b/modules/presets/presets.js @@ -23,8 +23,14 @@ export function presets() { }; all.match = function(entity, resolver) { - var geometry = entity.geometry(resolver), - geometryMatches = index[geometry], + var geometry = entity.geometry(resolver); + + // Treat entities on addr:interpolation lines as points, not vertices (#3241) + if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) { + geometry = 'point'; + } + + var geometryMatches = index[geometry], best = -1, match; diff --git a/modules/ui/preset_list.js b/modules/ui/preset_list.js index 974d6dba4..e2389007c 100644 --- a/modules/ui/preset_list.js +++ b/modules/ui/preset_list.js @@ -6,14 +6,21 @@ import { PresetIcon } from './preset_icon'; import { TagReference } from './tag_reference'; export function PresetList(context) { - var event = d3.dispatch('choose'), + var dispatch = d3.dispatch('choose'), id, currentPreset, autofocus = false; function presetList(selection) { - var geometry = context.geometry(id), - presets = context.presets().matchGeometry(geometry); + var entity = context.entity(id), + geometry = context.geometry(id); + + // Treat entities on addr:interpolation lines as points, not vertices (#3241) + if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) { + geometry = 'point'; + } + + var presets = context.presets().matchGeometry(geometry); selection.html(''); @@ -26,7 +33,7 @@ export function PresetList(context) { if (context.entity(id).isUsed(context.graph())) { messagewrap.append('button') .attr('class', 'preset-choose') - .on('click', function() { event.choose(currentPreset); }) + .on('click', function() { dispatch.choose(currentPreset); }) .append('span') .html('►'); } else { @@ -221,7 +228,7 @@ export function PresetList(context) { ChangePreset(id, currentPreset, preset), t('operations.change_tags.annotation')); - event.choose(preset); + dispatch.choose(preset); }; item.help = function() { @@ -254,5 +261,5 @@ export function PresetList(context) { return presetList; }; - return d3.rebind(presetList, event, 'on'); + return d3.rebind(presetList, dispatch, 'on'); } diff --git a/test/spec/presets/presets.js b/test/spec/presets/presets.js index 8e8be586e..572fb48b0 100644 --- a/test/spec/presets/presets.js +++ b/test/spec/presets/presets.js @@ -8,16 +8,16 @@ describe('iD.presets.presets', function() { tags: {}, geometry: ['line'] }, + vertex: { + tags: {}, + geometry: ['vertex'] + }, residential: { - tags: { - highway: 'residential' - }, + tags: { highway: 'residential' }, geometry: ['line'] }, park: { - tags: { - leisure: 'park' - }, + tags: { leisure: 'park' }, geometry: ['point', 'area'] } }; @@ -26,18 +26,36 @@ describe('iD.presets.presets', function() { describe('#match', function() { it('returns a collection containing presets matching a geometry and tags', function() { - var way = iD.Way({tags: { highway: 'residential'}}), + var way = iD.Way({ tags: { highway: 'residential' } }), graph = iD.Graph([way]); expect(c.match(way, graph).id).to.eql('residential'); }); it('returns the appropriate fallback preset when no tags match', function() { var point = iD.Node(), - line = iD.Way({tags: {foo: 'bar'}}), + line = iD.Way({ tags: { foo: 'bar' } }), graph = iD.Graph([point, line]); + expect(c.match(point, graph).id).to.eql('point'); expect(c.match(line, graph).id).to.eql('line'); }); + + it('matches vertices on a line as vertices', function() { + var point = iD.Node({ tags: { leisure: 'park' } }), + line = iD.Way({ nodes: [point.id], tags: { 'highway': 'residential' } }), + graph = iD.Graph([point, line]); + + expect(c.match(point, graph).id).to.eql('vertex'); + }); + + it('matches vertices on an addr:interpolation line as points', function() { + var point = iD.Node({ tags: { leisure: 'park' } }), + line = iD.Way({ nodes: [point.id], tags: { 'addr:interpolation': 'even' } }), + graph = iD.Graph([point, line]); + + expect(c.match(point, graph).id).to.eql('park'); + }); + }); describe('#areaKeys', function() {