From f247bd1e66e4c0145eb9c9d23a162b1c7ab6ec1a Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 5 Dec 2017 23:41:34 -0500 Subject: [PATCH] Move icon code into uiFlash, default flash icon to icon-no Previously it was up to the caller to draw whatever they want into the footer flash. With this change, uiFlash creates an icon and a text, so the caller doesn't need to do as much work. --- css/80_app.css | 35 ++++++++-- modules/behavior/operation.js | 69 +++++++------------ modules/renderer/map.js | 4 +- modules/ui/flash.js | 124 +++++++++++++++++++++++++++------- test/spec/ui/flash.js | 10 +-- 5 files changed, 159 insertions(+), 83 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index b8662d899..4f9be5651 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -3052,13 +3052,13 @@ img.tile-removing { margin: 0 3px; } - #footer { pointer-events: all; display: block; height: 30px; } +/* footer flash message */ #flash-wrap { display: flex; @@ -3071,7 +3071,7 @@ img.tile-removing { left: 0; } -#flash-wrap .content { +.flash-content { display: flex; flex: 1 0 auto; flex-flow: row nowrap; @@ -3080,15 +3080,38 @@ img.tile-removing { height: 30px; } - -#flash-wrap svg.operation-icon { +.flash-icon { flex: 0 0 auto; width: 20px; height: 20px; margin: 0 8px; } -#flash-wrap div.operation-tip { +.flash-icon circle { + fill: #eee; +} +.flash-icon.disabled circle { + cursor: auto; + fill: rgba(255,255,255,0.7); +} + +.flash-icon use { + color: #222; +} +.flash-icon.disabled use { + color: rgba(32,32,32,0.7); +} + +.flash-icon.operation use { + fill: #222; + color: #79f; +} +.flash-icon.operation.disabled use { + fill: rgba(32,32,32,0.7); + color: rgba(40,40,40,0.7); +} + +.flash-text { flex: 1 1 auto; } @@ -3118,6 +3141,8 @@ img.tile-removing { } +/* footer scale */ + #scale-block { vertical-align: bottom; width: 250px; diff --git a/modules/behavior/operation.js b/modules/behavior/operation.js index 9dfb8502d..88bc96e8b 100644 --- a/modules/behavior/operation.js +++ b/modules/behavior/operation.js @@ -9,61 +9,40 @@ import { uiFlash } from '../ui'; /* Creates a keybinding behavior for an operation */ export function behaviorOperation() { - var which, keybinding; - - - function drawIcon(selection) { - var button = selection - .append('svg') - .attr('class', 'operation-icon') - .append('g') - .attr('class', 'radial-menu-item radial-menu-item-' + which.id) - .attr('transform', 'translate(10,10)') - .classed('disabled', which.disabled()); - - button - .append('circle') - .attr('r', 9); - - button - .append('use') - .attr('transform', 'translate(-7,-7)') - .attr('width', '14') - .attr('height', '14') - .attr('xlink:href', '#operation-' + which.id); - - return selection; - } - + var _operation, keybinding; var behavior = function () { - if (which && which.available()) { - keybinding = d3_keybinding('behavior.key.' + which.id); - keybinding.on(which.keys, function() { + if (_operation && _operation.available()) { + keybinding = d3_keybinding('behavior.key.' + _operation.id); + keybinding.on(_operation.keys, function() { d3_event.preventDefault(); - var disabled = which.disabled(); + var disabled = _operation.disabled(); + var flash; if (disabled) { - uiFlash(3000) - .html('') - .call(drawIcon) - .append('div') - .attr('class', 'operation-tip') - .text(which.tooltip); + flash = uiFlash() + .duration(4000) + .iconName('#operation-' + _operation.id) + .iconClass('operation disabled') + .text(_operation.tooltip); + + flash(); } else { - uiFlash(1500) - .html('') - .call(drawIcon) - .append('div') - .attr('class', 'operation-tip') - .text(which.annotation() || which.title); + flash = uiFlash() + .duration(2000) + .iconName('#operation-' + _operation.id) + .iconClass('operation') + .text(_operation.annotation() || _operation.title); - which(); + flash(); + _operation(); } }); + d3_select(document).call(keybinding); } + return behavior; }; @@ -76,8 +55,8 @@ export function behaviorOperation() { behavior.which = function (_) { - if (!arguments.length) return which; - which = _; + if (!arguments.length) return _operation; + _operation = _; return behavior; }; diff --git a/modules/renderer/map.js b/modules/renderer/map.js index 93cc7bdd0..e53297ff4 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -359,7 +359,7 @@ export function rendererMap(context) { if (ktoz(eventTransform.k * 2 * Math.PI) < minzoom) { surface.interrupt(); - uiFlash().text(t('cannot_zoom')); + uiFlash().text(t('cannot_zoom'))(); setZoom(context.minEditableZoom(), true); scheduleRedraw(); dispatch.call('move', this, map); @@ -653,7 +653,7 @@ export function rendererMap(context) { if (z2 < minzoom) { surface.interrupt(); - uiFlash().text(t('cannot_zoom')); + uiFlash().text(t('cannot_zoom'))(); z2 = context.minEditableZoom(); } diff --git a/modules/ui/flash.js b/modules/ui/flash.js index 27a5d759e..8540c706a 100644 --- a/modules/ui/flash.js +++ b/modules/ui/flash.js @@ -1,37 +1,115 @@ import { select as d3_select } from 'd3-selection'; import { timeout as d3_timeout } from 'd3-timer'; -var timer; +var _flashTimer; -export function uiFlash(showDuration) { - showDuration = showDuration || 1500; +export function uiFlash() { + var _duration = 2000; + var _iconName = '#icon-no'; + var _iconClass = 'disabled'; + var _text = ''; + var _textClass; - if (timer) { - timer.stop(); + + function flash() { + if (_flashTimer) { + _flashTimer.stop(); + } + + d3_select('#footer-wrap') + .attr('class', 'footer-hide'); + d3_select('#flash-wrap') + .attr('class', 'footer-show'); + + var content = d3_select('#flash-wrap').selectAll('.flash-content') + .data([0]); + + // Enter + var contentEnter = content.enter() + .append('div') + .attr('class', 'flash-content'); + + var iconEnter = contentEnter + .append('svg') + .attr('class', 'flash-icon') + .append('g') + .attr('transform', 'translate(10,10)'); + + iconEnter + .append('circle') + .attr('r', 9); + + iconEnter + .append('use') + .attr('transform', 'translate(-7,-7)') + .attr('width', '14') + .attr('height', '14'); + + contentEnter + .append('div') + .attr('class', 'flash-text'); + + + // Update + content = content + .merge(contentEnter); + + content + .selectAll('.flash-icon') + .attr('class', 'flash-icon ' + (_iconClass || '')); + + content + .selectAll('.flash-icon use') + .attr('xlink:href', _iconName); + + content + .selectAll('.flash-text') + .attr('class', 'flash-text ' + (_textClass || '')) + .text(_text); + + + _flashTimer = d3_timeout(function() { + _flashTimer = null; + d3_select('#footer-wrap') + .attr('class', 'footer-show'); + d3_select('#flash-wrap') + .attr('class', 'footer-hide'); + }, _duration); + + return content; } - d3_select('#footer-wrap') - .attr('class', 'footer-hide'); - d3_select('#flash-wrap') - .attr('class', 'footer-show'); - var content = d3_select('#flash-wrap').selectAll('.content') - .data([0]); + flash.duration = function(_) { + if (!arguments.length) return _duration; + _duration = _; + return flash; + }; - content = content.enter() - .append('div') - .attr('class', 'content') - .merge(content); + flash.text = function(_) { + if (!arguments.length) return _text; + _text = _; + return flash; + }; - timer = d3_timeout(function() { - timer = null; - d3_select('#footer-wrap') - .attr('class', 'footer-show'); - d3_select('#flash-wrap') - .attr('class', 'footer-hide'); - }, showDuration); + flash.textClass = function(_) { + if (!arguments.length) return _textClass; + _textClass = _; + return flash; + }; + flash.iconName = function(_) { + if (!arguments.length) return _iconName; + _iconName = _; + return flash; + }; - return content; + flash.iconClass = function(_) { + if (!arguments.length) return _iconClass; + _iconClass = _; + return flash; + }; + + return flash; } diff --git a/test/spec/ui/flash.js b/test/spec/ui/flash.js index 3fa10b0d1..d19970396 100644 --- a/test/spec/ui/flash.js +++ b/test/spec/ui/flash.js @@ -13,14 +13,8 @@ describe('iD.uiFlash', function () { .remove(); }); - it('returns a selection', function () { - var content = iD.uiFlash(200); - expect(content.size()).to.eql(1); - expect(content.classed('content')).to.be.ok; - }); - it('flash is shown', function() { - iD.uiFlash(200); + iD.uiFlash().duration(200)(); var flashWrap = d3.selectAll('#flash-wrap'); var footerWrap = d3.selectAll('#footer-wrap'); expect(flashWrap.classed('footer-show')).to.be.ok; @@ -28,7 +22,7 @@ describe('iD.uiFlash', function () { }); it('flash goes away', function(done) { - iD.uiFlash(200); + iD.uiFlash().duration(200)(); window.setTimeout(function() { d3.timerFlush(); var flashWrap = d3.selectAll('#flash-wrap');