From 48bda8ba678e90cdbe221e7c87ce41ae0c5fe8c8 Mon Sep 17 00:00:00 2001 From: Quincy Morgan Date: Mon, 20 Jan 2020 11:34:51 -0500 Subject: [PATCH] Move selected feature list to a collapsible inspector section (close #7273) --- css/80_app.css | 20 +++-- data/core.yaml | 1 + dist/locales/en.json | 1 + modules/ui/entity_editor.js | 2 +- modules/ui/selection_list.js | 160 +++++++++++++++++++---------------- 5 files changed, 104 insertions(+), 80 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index 2c0e773e9..1338af840 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -842,8 +842,7 @@ a.hide-toggle { .preset-list-pane .inspector-body { top: 120px; } -.entity-editor-pane .inspector-body, -.selection-list-pane .inspector-body { +.entity-editor-pane .inspector-body { top: 60px; } @@ -914,6 +913,7 @@ a.hide-toggle { font-weight: bold; height: 40px; line-height: 20px; + display: flex; } .feature-list-item:hover { background-color: #ececec; @@ -927,7 +927,7 @@ a.hide-toggle { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; - border-left: 1px solid rgba(0, 0, 0, .1); + flex: 1 1 auto; } [dir='rtl'] .feature-list-item .label { text-align: right; @@ -937,11 +937,11 @@ a.hide-toggle { opacity: .5; } .feature-list-item .close { - float: right; padding: 10px; + } .feature-list-item .close .icon { - opacity: 1; + opacity: 0.5; } .feature-list-item .entity-type { color: #7092ff; @@ -958,7 +958,15 @@ a.hide-toggle { padding-left: 0; padding-right: 10px; } - +.selected-features .feature-list { + border: 1px solid #ccc; + border-radius: 4px; + overflow: hidden; + margin-top: 5px; +} +.selected-features .feature-list-item:last-child { + border: none; +} /* Preset List and Icons ------------------------------------------------------- */ diff --git a/data/core.yaml b/data/core.yaml index 419697dbc..75b54f20e 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -548,6 +548,7 @@ en: all_tags: All tags all_members: All members all_relations: All relations + features_count: "Features ({count})" add_to_relation: Add to a relation new_relation: New relation... choose_relation: Choose a parent relation diff --git a/dist/locales/en.json b/dist/locales/en.json index 52c383dfb..d42670608 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -691,6 +691,7 @@ "all_tags": "All tags", "all_members": "All members", "all_relations": "All relations", + "features_count": "Features ({count})", "add_to_relation": "Add to a relation", "new_relation": "New relation...", "choose_relation": "Choose a parent relation", diff --git a/modules/ui/entity_editor.js b/modules/ui/entity_editor.js index ed7c01bef..5b23dffa9 100644 --- a/modules/ui/entity_editor.js +++ b/modules/ui/entity_editor.js @@ -95,7 +95,7 @@ export function uiEntityEditor(context) { var sectionInfos = [ { - klass: 'selection-list', + klass: 'selected-features inspector-inner', shouldHave: _entityIDs.length > 1, update: function(section) { section diff --git a/modules/ui/selection_list.js b/modules/ui/selection_list.js index 8f2f1ee63..773355d33 100644 --- a/modules/ui/selection_list.js +++ b/modules/ui/selection_list.js @@ -3,6 +3,7 @@ import { event as d3_event, select as d3_select } from 'd3-selection'; import { modeSelect } from '../modes/select'; import { osmEntity } from '../osm'; import { svgIcon } from '../svg/icon'; +import { uiDisclosure } from './disclosure'; import { t } from '../util/locale'; import { utilDisplayName, utilHighlightEntities } from '../util'; @@ -10,13 +11,39 @@ import { utilDisplayName, utilHighlightEntities } from '../util'; export function uiSelectionList(context) { var _selectedIDs = []; + var _selection = d3_select(null); + context.history() + .on('change.selectionList', function(difference) { + if (difference) { + _selection.selectAll('.disclosure-wrap') + .call(render); + + updateTitle(); + } + }); + + function selectionList(selection) { + _selection = selection; + + selection + .call(uiDisclosure(context, 'selected_features', true) + .content(render) + ); + + updateTitle(); + } + + selectionList.selectedIDs = function(val) { + if (!arguments.length) return _selectedIDs; + _selectedIDs = val; + return selectionList; + }; function selectEntity(entity) { context.enter(modeSelect(context, [entity.id])); } - function deselectEntity(entity) { d3_event.stopPropagation(); @@ -28,8 +55,7 @@ export function uiSelectionList(context) { } } - - function selectionList(selection) { + function render(selection) { var list = selection.selectAll('.feature-list') .data([0]); @@ -39,88 +65,76 @@ export function uiSelectionList(context) { .attr('class', 'feature-list') .merge(list); - context.history() - .on('change.selectionList', function(difference) { - if (difference) drawList(); + var entities = _selectedIDs + .map(function(id) { return context.hasEntity(id); }) + .filter(Boolean); + + var items = list.selectAll('.feature-list-item') + .data(entities, osmEntity.key); + + items.exit() + .remove(); + + // Enter + var enter = items.enter() + .append('div') + .attr('class', 'feature-list-item') + .on('click', selectEntity); + + enter + .each(function(d) { + d3_select(this).on('mouseover', function() { + utilHighlightEntities([d.id], true, context); + }); + d3_select(this).on('mouseout', function() { + utilHighlightEntities([d.id], false, context); + }); }); - drawList(); + var label = enter + .append('button') + .attr('class', 'label'); - function drawList() { - var entities = _selectedIDs - .map(function(id) { return context.hasEntity(id); }) - .filter(Boolean); + enter + .append('button') + .attr('class', 'close') + .attr('title', t('icons.deselect')) + .on('click', deselectEntity) + .call(svgIcon('#iD-icon-close')); - var items = list.selectAll('.feature-list-item') - .data(entities, osmEntity.key); + label + .append('span') + .attr('class', 'entity-geom-icon') + .call(svgIcon('', 'pre-text')); - items.exit() - .remove(); + label + .append('span') + .attr('class', 'entity-type'); - // Enter - var enter = items.enter() - .append('div') - .attr('class', 'feature-list-item') - .on('click', selectEntity); + label + .append('span') + .attr('class', 'entity-name'); - enter - .each(function(d) { - d3_select(this).on('mouseover', function() { - utilHighlightEntities([d.id], true, context); - }); - d3_select(this).on('mouseout', function() { - utilHighlightEntities([d.id], false, context); - }); - }); + // Update + items = items.merge(enter); - var label = enter - .append('button') - .attr('class', 'label'); + items.selectAll('.entity-geom-icon use') + .attr('href', function() { + var entity = this.parentNode.parentNode.__data__; + return '#iD-icon-' + context.geometry(entity.id); + }); - enter - .append('button') - .attr('class', 'close') - .attr('title', t('icons.deselect')) - .on('click', deselectEntity) - .call(svgIcon('#iD-icon-close')); + items.selectAll('.entity-type') + .text(function(entity) { return context.presets().match(entity, context.graph()).name(); }); - label - .append('span') - .attr('class', 'entity-geom-icon') - .call(svgIcon('', 'pre-text')); - - label - .append('span') - .attr('class', 'entity-type'); - - label - .append('span') - .attr('class', 'entity-name'); - - // Update - items = items.merge(enter); - - items.selectAll('.entity-geom-icon use') - .attr('href', function() { - var entity = this.parentNode.parentNode.__data__; - return '#iD-icon-' + context.geometry(entity.id); - }); - - items.selectAll('.entity-type') - .text(function(entity) { return context.presets().match(entity, context.graph()).name(); }); - - items.selectAll('.entity-name') - .text(function(entity) { return utilDisplayName(entity); }); - } + items.selectAll('.entity-name') + .text(function(entity) { return utilDisplayName(entity); }); } - - selectionList.selectedIDs = function(val) { - if (!arguments.length) return _selectedIDs; - _selectedIDs = val; - return selectionList; - }; - + function updateTitle() { + _selection.selectAll('.hide-toggle span') + .text(t('inspector.features_count', { count: _selectedIDs.length })); + } return selectionList; }