diff --git a/modules/ui/raw_member_editor.js b/modules/ui/raw_member_editor.js index a371534644..0d1080dca3 100644 --- a/modules/ui/raw_member_editor.js +++ b/modules/ui/raw_member_editor.js @@ -15,7 +15,8 @@ import { uiDisclosure } from './disclosure'; import { utilDisplayName, utilDisplayType, - utilNoAuto + utilNoAuto, + utilHighlightEntity } from '../util'; @@ -37,8 +38,7 @@ export function uiRawMemberEditor(context) { context.map().zoomTo(entity); // highlight the feature in case it wasn't previously on-screen - var selectorPrefix = d.type === 'node' ? 'g.' : 'path.'; - context.surface().selectAll(selectorPrefix+d.id).classed('highlighted', true); + utilHighlightEntity(d.id, true, context); } @@ -135,12 +135,11 @@ export function uiRawMemberEditor(context) { if (d.member) { // highlight the member feature in the map while hovering on the list item - var selectorPrefix = d.type === 'node' ? 'g.' : 'path.'; d3_select(this).on('mouseover', function() { - context.surface().selectAll(selectorPrefix+d.id).classed('highlighted', true); + utilHighlightEntity(d.id, true, context); }); d3_select(this).on('mouseout', function() { - context.surface().selectAll(selectorPrefix+d.id).classed('highlighted', false); + utilHighlightEntity(d.id, false, context); }); var label = d3_select(this).append('label') diff --git a/modules/ui/raw_membership_editor.js b/modules/ui/raw_membership_editor.js index 0fadc1b7bf..f856cd7ab5 100644 --- a/modules/ui/raw_membership_editor.js +++ b/modules/ui/raw_membership_editor.js @@ -24,7 +24,7 @@ import { osmEntity, osmRelation } from '../osm'; import { services } from '../services'; import { svgIcon } from '../svg'; import { uiDisclosure } from './disclosure'; -import { utilDisplayName, utilNoAuto } from '../util'; +import { utilDisplayName, utilNoAuto, utilHighlightEntity } from '../util'; export function uiRawMembershipEditor(context) { @@ -173,6 +173,16 @@ export function uiRawMembershipEditor(context) { .append('li') .attr('class', 'member-row member-row-normal form-field'); + enter.each(function(d){ + // highlight the relation in the map while hovering on the list item + d3_select(this).on('mouseover', function() { + utilHighlightEntity(d.relation.id, true, context); + }); + d3_select(this).on('mouseout', function() { + utilHighlightEntity(d.relation.id, false, context); + }); + }); + var label = enter .append('label') .attr('class', 'form-label') diff --git a/modules/ui/selection_list.js b/modules/ui/selection_list.js index 6362a7cead..f7f3a3ee7b 100644 --- a/modules/ui/selection_list.js +++ b/modules/ui/selection_list.js @@ -7,7 +7,7 @@ import { t } from '../util/locale'; import { modeSelect } from '../modes'; import { osmEntity } from '../osm'; import { svgIcon } from '../svg'; -import { utilDisplayName } from '../util'; +import { utilDisplayName, utilHighlightEntity } from '../util'; export function uiSelectionList(context, selectedIDs) { @@ -70,12 +70,11 @@ export function uiSelectionList(context, selectedIDs) { enter .each(function(d) { // highlight the feature in the map while hovering on the list item - var selectorPrefix = d.type === 'node' ? 'g.' : 'path.'; d3_select(this).on('mouseover', function() { - context.surface().selectAll(selectorPrefix+d.id).classed('highlighted', true); + utilHighlightEntity(d.id, true, context); }); d3_select(this).on('mouseout', function() { - context.surface().selectAll(selectorPrefix+d.id).classed('highlighted', false); + utilHighlightEntity(d.id, false, context); }); }); diff --git a/modules/util/index.js b/modules/util/index.js index 16460cd148..a0269240ff 100644 --- a/modules/util/index.js +++ b/modules/util/index.js @@ -7,12 +7,14 @@ export { utilDisplayType } from './util'; export { utilEditDistance } from './util'; export { utilEntitySelector } from './util'; export { utilEntityOrMemberSelector } from './util'; +export { utilEntityOrDeepMemberSelector } from './util'; export { utilFastMouse } from './util'; export { utilFunctor } from './util'; export { utilGetAllNodes } from './util'; export { utilGetPrototypeOf } from './util'; export { utilGetSetValue } from './get_set_value'; export { utilHashcode } from './util'; +export { utilHighlightEntity } from './util'; export { utilIdleWorker } from './idle_worker'; export { utilNoAuto } from './util'; export { utilPrefixCSSProperty } from './util'; diff --git a/modules/util/util.js b/modules/util/util.js index 6b03c9f4cd..5eb821ced1 100644 --- a/modules/util/util.js +++ b/modules/util/util.js @@ -34,6 +34,32 @@ export function utilEntityOrMemberSelector(ids, graph) { } +export function utilEntityOrDeepMemberSelector(ids, graph) { + var seen = {}; + var allIDs = []; + function addEntityAndMembersIfNotYetSeen(id) { + // avoid infinite recursion for circular relations by skipping seen entities + if (seen[id]) return; + // mark the entity as seen + seen[id] = true; + // add the id; + allIDs.push(id); + if (graph.hasEntity(id)) { + var entity = graph.entity(id); + if (entity.type === 'relation' && entity.members) { + entity.members.forEach(function(member){ + addEntityAndMembersIfNotYetSeen(member.id); + }); + } + } + } + ids.forEach(function(id) { + addEntityAndMembersIfNotYetSeen(id); + }); + return utilEntitySelector(allIDs); +} + + export function utilGetAllNodes(ids, graph) { var seen = {}; var nodes = []; @@ -282,3 +308,10 @@ export function utilHashcode(str) { } return hash; } + +// Adds or removes highlight styling for the specified entity's SVG elements in the map. +export function utilHighlightEntity(id, highlighted, context) { + context.surface() + .selectAll(utilEntityOrDeepMemberSelector([id], context.graph())) + .classed('highlighted', highlighted); +}