From 005c6595006d945497e7eb8eb5e38ca876ef84ca Mon Sep 17 00:00:00 2001 From: gorhill Date: Sat, 28 Oct 2017 09:07:41 -0400 Subject: [PATCH] code review: improve element picker for touch-only devices --- src/epicker.html | 10 +++- src/js/scriptlets/element-picker.js | 71 +++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/epicker.html b/src/epicker.html index d2b764349..33a402eb7 100644 --- a/src/epicker.html +++ b/src/epicker.html @@ -74,6 +74,7 @@ section > div:first-child > textarea { height: 8em; margin: 0; overflow: hidden; + overflow-y: auto; padding: 2px; resize: none; width: 100%; @@ -165,10 +166,11 @@ aside { border: 1px solid #aaa; bottom: 4px; box-sizing: border-box; - visibility: hidden; + min-width: 24em; padding: 4px; position: fixed; right: 4px; + visibility: hidden; width: calc(40% - 4px); } body.paused > aside { @@ -179,6 +181,12 @@ body.paused > aside { body.paused > aside:hover { opacity: 1; } +body.paused > aside.show { + opacity: 1; +} +body.paused > aside.hide { + opacity: 0.1; +} diff --git a/src/js/scriptlets/element-picker.js b/src/js/scriptlets/element-picker.js index 9b7abaa2b..ca275f08c 100644 --- a/src/js/scriptlets/element-picker.js +++ b/src/js/scriptlets/element-picker.js @@ -1,7 +1,7 @@ /******************************************************************************* uBlock Origin - a browser extension to block requests. - Copyright (C) 2014-2016 Raymond Hill + Copyright (C) 2014-2017 Raymond Hill This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1092,7 +1092,14 @@ var filterChoiceFromEvent = function(ev) { /******************************************************************************/ var onDialogClicked = function(ev) { - if ( ev.target === null ) { + + // If the dialog is hidden, clicking on it force it to become visible. + if ( dialog.classList.contains('hide') ) { + dialog.classList.add('show'); + dialog.classList.remove('hide'); + } + + else if ( ev.target === null ) { /* do nothing */ } @@ -1161,6 +1168,11 @@ var showDialog = function(options) { options = options || {}; + // Typically the dialog will be forced to be visible when using a + // touch-aware device. + dialog.classList.toggle('show', options.show === true); + dialog.classList.remove('hide'); + // Create lists of candidate filters var populate = function(src, des) { var root = dialog.querySelector(des); @@ -1262,7 +1274,17 @@ var onSvgHovered = (function() { }; })(); -/******************************************************************************/ +/******************************************************************************* + + Swipe right: + If picker not paused: quit picker + If picker paused and dialog visible: hide dialog + If picker paused and dialog not visible: quit picker + + Swipe left: + If picker paused and dialog not visible: show dialog + +*/ var onSvgTouchStartStop = (function() { var startX, @@ -1277,22 +1299,43 @@ var onSvgTouchStartStop = (function() { if ( startX === undefined ) { return; } var stopX = ev.changedTouches[0].pageX, stopY = ev.changedTouches[0].pageY, + angle = Math.abs(Math.atan2(stopY - startY, stopX - startX)), distance = Math.sqrt( Math.pow(stopX - startX, 2), Math.pow(stopY - startY, 2) ); - // Swipe = exit element zapper/picker. - if ( distance > 32 ) { - stopPicker(); + var angleUpperBound = Math.PI * 0.25 * 0.5, + swipeRight = angle < angleUpperBound, + swipeInvalid = swipeRight === false && + angle < Math.PI - angleUpperBound; + // Interpret touch events as a click events if swipe is not valid. + if ( distance < 64 || swipeInvalid ) { + onSvgClicked({ + type: 'touch', + target: ev.target, + clientX: startX, + clientY: startY + }); return; } - // Interpret touch event as a click. - onSvgClicked({ - type: 'click', - target: ev.target, - clientX: startX, - clientY: startY - }); + // Swipe left. + if ( swipeRight === false ) { + if ( pickerBody.classList.contains('paused') ) { + dialog.classList.remove('hide'); + dialog.classList.add('show'); + } + return; + } + // Swipe right. + if ( + pickerBody.classList.contains('paused') && + dialog.classList.contains('show') + ) { + dialog.classList.remove('show'); + dialog.classList.add('hide'); + return; + } + stopPicker(); }; })(); @@ -1329,7 +1372,7 @@ var onSvgClicked = function(ev) { if ( filtersFrom(ev.clientX, ev.clientY) === 0 ) { return; } - showDialog(); + showDialog({ show: ev.type === 'touch' }); }; /******************************************************************************/