mirror of https://github.com/gorhill/uBlock.git
Element picker tweaks
- Indentation whitespace fixes. - Use built-in getBoundingClientRect() function instead of self-made. - Use built-in DOM API for manipulating the class attributes instead of altering the className property. - Add pointer-events: none to the svgRoot when using document.elementFromPoint(), but if the browser (older Safari for example) doesn't take the pointer-events into account, then fall back to display: none. - Initiate every part of the picker at the same time; when the message is received from the background. This way the selected element will have the red overlay immediately, instead of showing first the black overlay, then a few milliseconds later the red.
This commit is contained in:
parent
6d49ef0dac
commit
cc27193147
|
@ -120,16 +120,21 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var localMessager = vAPI.messaging.channel('element-picker.js');
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/314#issuecomment-58878112
|
||||
// Using an id makes uBlock's CSS rules more specific, thus prevents
|
||||
// surrounding external rules from winning over own rules.
|
||||
var µBlockId = CSS.escape('µBlock');
|
||||
|
||||
var pickerRoot = document.getElementById(µBlockId);
|
||||
|
||||
if ( pickerRoot ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var localMessager = vAPI.messaging.channel('element-picker.js');
|
||||
|
||||
var svgns = 'http://www.w3.org/2000/svg';
|
||||
|
||||
var pickerRoot = null;
|
||||
var svgRoot = null;
|
||||
var svgOcean = null;
|
||||
var svgIslands = null;
|
||||
|
@ -143,23 +148,25 @@ var cosmeticFilterCandidates = [];
|
|||
var targetElements = [];
|
||||
var svgWidth = 0;
|
||||
var svgHeight = 0;
|
||||
var elementFromPointCSSProperty = 'pointerEvents';
|
||||
var onSvgHoveredTimer = null;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var pickerPaused = function() {
|
||||
return /(^| )paused( |$)/.test(pickerRoot.className);
|
||||
return pickerRoot.classList.contains('paused');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var pausePicker = function() {
|
||||
pickerRoot.className += ' paused';
|
||||
pickerRoot.classList.add('paused');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var unpausePicker = function() {
|
||||
pickerRoot.className = pickerRoot.className.replace(/(^| )paused( |$)/g, '').trim();
|
||||
pickerRoot.classList.remove('paused');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -178,24 +185,6 @@ var pickerRootDistance = function(elem) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/210
|
||||
|
||||
// HTMLElement.getBoundingClientRect() is unreliable (or I misunderstand what
|
||||
// it does). I will just compute it myself.
|
||||
|
||||
var getBoundingClientRect = function(elem, r) {
|
||||
r.w = elem.offsetWidth;
|
||||
r.h = elem.offsetHeight;
|
||||
r.x = elem.offsetLeft - elem.scrollLeft;
|
||||
r.y = elem.offsetTop - elem.scrollTop;
|
||||
while ( elem = elem.offsetParent ) {
|
||||
r.x += elem.offsetLeft - elem.scrollLeft;
|
||||
r.y += elem.offsetTop - elem.scrollTop;
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var highlightElements = function(elems, force) {
|
||||
// To make mouse move handler more efficient
|
||||
if ( !force && elems.length === targetElements.length ) {
|
||||
|
@ -216,7 +205,6 @@ var highlightElements = function(elems, force) {
|
|||
var offx = window.pageXOffset;
|
||||
var offy = window.pageYOffset;
|
||||
var islands = [];
|
||||
// To avoid memory churning, reuse object
|
||||
var elem, rect, poly;
|
||||
for ( var i = 0; i < elems.length; i++ ) {
|
||||
elem = elems[i];
|
||||
|
@ -233,7 +221,7 @@ var highlightElements = function(elems, force) {
|
|||
islands.push(poly);
|
||||
}
|
||||
svgOcean.setAttribute('d', ocean.join(''));
|
||||
svgIslands.setAttribute('d', islands.join('') || 'M 0 0');
|
||||
svgIslands.setAttribute('d', islands.join('') || 'M0 0');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -590,23 +578,27 @@ var showDialog = function(options) {
|
|||
/******************************************************************************/
|
||||
|
||||
var elementFromPoint = function(x, y) {
|
||||
svgRoot.style.display = 'none';
|
||||
svgRoot.style[elementFromPointCSSProperty] = 'none';
|
||||
var elem = document.elementFromPoint(x, y);
|
||||
if ( elem === document.body || elem === document.documentElement ) {
|
||||
elem = null;
|
||||
}
|
||||
svgRoot.style.display = '';
|
||||
svgRoot.style[elementFromPointCSSProperty] = '';
|
||||
return elem;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onSvgHovered = function(ev) {
|
||||
if ( pickerPaused() ) {
|
||||
if ( pickerPaused() || onSvgHoveredTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
onSvgHoveredTimer = setTimeout(function() {
|
||||
var elem = elementFromPoint(ev.clientX, ev.clientY);
|
||||
highlightElements(elem ? [elem] : []);
|
||||
onSvgHoveredTimer = null;
|
||||
}, 50);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -675,11 +667,7 @@ var stopPicker = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var startPicker = function() {
|
||||
pickerRoot = document.getElementById(µBlockId);
|
||||
if ( pickerRoot !== null ) {
|
||||
return;
|
||||
}
|
||||
var startPicker = function(details) {
|
||||
pickerRoot = document.createElement('div');
|
||||
pickerRoot.id = µBlockId;
|
||||
|
||||
|
@ -742,6 +730,7 @@ var startPicker = function() {
|
|||
'position: absolute;',
|
||||
'top: 0;',
|
||||
'left: 0;',
|
||||
'pointer-events: auto;',
|
||||
'cursor: crosshair;',
|
||||
'z-index: 4999999999;',
|
||||
'}',
|
||||
|
@ -899,7 +888,6 @@ var startPicker = function() {
|
|||
|
||||
highlightElements([], true);
|
||||
|
||||
var initPicker = function(details) {
|
||||
var i18nMap = {
|
||||
'#µBlock > div': '@@bidi_dir',
|
||||
'#create': 'create',
|
||||
|
@ -922,8 +910,16 @@ var startPicker = function() {
|
|||
divDialog.querySelector(k).firstChild.nodeValue = details.i18n[i18nMap[k]];
|
||||
}
|
||||
|
||||
// First we test if pointer-events are hadnled in Node.elementFromPoint().
|
||||
// If the browser ignores pointer-events in Node.elementFromPoint(),
|
||||
// then use the display property instead (e.g., for older Safari).
|
||||
var elem = elementFromPoint(0, 0);
|
||||
|
||||
if ( elem === svgRoot ) {
|
||||
elementFromPointCSSProperty = 'display';
|
||||
}
|
||||
|
||||
// Auto-select a specific target, if any, and if possible
|
||||
var elem;
|
||||
|
||||
// Try using mouse position
|
||||
if ( details.clientX !== -1 ) {
|
||||
|
@ -970,14 +966,11 @@ var startPicker = function() {
|
|||
showDialog({ modifier: true });
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
localMessager.send({ what: 'elementPickerArguments' }, initPicker);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
startPicker();
|
||||
localMessager.send({ what: 'elementPickerArguments' }, startPicker);
|
||||
|
||||
// This triggers the hiding of the popover in Safari
|
||||
window.focus();
|
||||
|
|
|
@ -38,7 +38,7 @@ var messagingConnector = function(response) {
|
|||
// Safari bug
|
||||
// Deleting the response.requestId below (only in some cases, probably
|
||||
// when frames are present on the page) will remove it from all the
|
||||
// following messages too, however with the following line it won't.
|
||||
// future messages too, however with the following line it won't.
|
||||
vAPI.safari && console.log;
|
||||
|
||||
delete vAPI.messaging.listeners[response.requestId];
|
||||
|
|
Loading…
Reference in New Issue