code review: improve element picker for touch-only devices

This commit is contained in:
gorhill 2017-10-28 09:07:41 -04:00
parent bbda2a9086
commit 005c659500
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 66 additions and 15 deletions

View File

@ -74,6 +74,7 @@ section > div:first-child > textarea {
height: 8em; height: 8em;
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
overflow-y: auto;
padding: 2px; padding: 2px;
resize: none; resize: none;
width: 100%; width: 100%;
@ -165,10 +166,11 @@ aside {
border: 1px solid #aaa; border: 1px solid #aaa;
bottom: 4px; bottom: 4px;
box-sizing: border-box; box-sizing: border-box;
visibility: hidden; min-width: 24em;
padding: 4px; padding: 4px;
position: fixed; position: fixed;
right: 4px; right: 4px;
visibility: hidden;
width: calc(40% - 4px); width: calc(40% - 4px);
} }
body.paused > aside { body.paused > aside {
@ -179,6 +181,12 @@ body.paused > aside {
body.paused > aside:hover { body.paused > aside:hover {
opacity: 1; opacity: 1;
} }
body.paused > aside.show {
opacity: 1;
}
body.paused > aside.hide {
opacity: 0.1;
}
</style> </style>
</head> </head>

View File

@ -1,7 +1,7 @@
/******************************************************************************* /*******************************************************************************
uBlock Origin - a browser extension to block requests. 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 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 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) { 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 */ /* do nothing */
} }
@ -1161,6 +1168,11 @@ var showDialog = function(options) {
options = 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 // Create lists of candidate filters
var populate = function(src, des) { var populate = function(src, des) {
var root = dialog.querySelector(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 onSvgTouchStartStop = (function() {
var startX, var startX,
@ -1277,22 +1299,43 @@ var onSvgTouchStartStop = (function() {
if ( startX === undefined ) { return; } if ( startX === undefined ) { return; }
var stopX = ev.changedTouches[0].pageX, var stopX = ev.changedTouches[0].pageX,
stopY = ev.changedTouches[0].pageY, stopY = ev.changedTouches[0].pageY,
angle = Math.abs(Math.atan2(stopY - startY, stopX - startX)),
distance = Math.sqrt( distance = Math.sqrt(
Math.pow(stopX - startX, 2), Math.pow(stopX - startX, 2),
Math.pow(stopY - startY, 2) Math.pow(stopY - startY, 2)
); );
// Swipe = exit element zapper/picker. var angleUpperBound = Math.PI * 0.25 * 0.5,
if ( distance > 32 ) { swipeRight = angle < angleUpperBound,
stopPicker(); swipeInvalid = swipeRight === false &&
return; angle < Math.PI - angleUpperBound;
} // Interpret touch events as a click events if swipe is not valid.
// Interpret touch event as a click. if ( distance < 64 || swipeInvalid ) {
onSvgClicked({ onSvgClicked({
type: 'click', type: 'touch',
target: ev.target, target: ev.target,
clientX: startX, clientX: startX,
clientY: startY clientY: startY
}); });
return;
}
// 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 ) { if ( filtersFrom(ev.clientX, ev.clientY) === 0 ) {
return; return;
} }
showDialog(); showDialog({ show: ev.type === 'touch' });
}; };
/******************************************************************************/ /******************************************************************************/