diff options
-rw-r--r-- | src/js/element-picker.js | 48 |
1 files changed, 43 insertions, 5 deletions
diff --git a/src/js/element-picker.js b/src/js/element-picker.js index 20eeff0..6d06c6b 100644 --- a/src/js/element-picker.js +++ b/src/js/element-picker.js @@ -19,8 +19,7 @@ Home: https://github.com/gorhill/uBlock */ -/* global CSS */ -'use strict'; +/* global self, vAPI, CSS */ /******************************************************************************/ /******************************************************************************/ @@ -28,6 +27,8 @@ /*! http://mths.be/cssescape v0.2.1 by @mathias | MIT license */ ;(function(root) { + 'use strict'; + if (!root.CSS) { root.CSS = {}; } @@ -118,6 +119,8 @@ (function() { +'use strict'; + /******************************************************************************/ // don't run in frames @@ -158,6 +161,19 @@ var onSvgHoveredTimer = null; /******************************************************************************/ +// For browsers not supporting `:scope`, it's not the end of the world: the +// suggested CSS selectors may just end up being more verbose. + +var cssScope = ':scope > '; + +try { + document.querySelector(':scope *'); +} catch (e) { + cssScope = ''; +} + +/******************************************************************************/ + var pickerPaused = function() { return pickerRoot.classList.contains('paused'); }; @@ -295,7 +311,7 @@ var cosmeticFilterFromElement = function(elem, out) { var tagName = elem.tagName.toLowerCase(); var prefix = ''; var suffix = []; - var v; + var v, i; // Id v = typeof elem.id === 'string' && CSS.escape(elem.id); @@ -307,7 +323,7 @@ var cosmeticFilterFromElement = function(elem, out) { v = typeof elem.className === 'string' && elem.className.trim(); if ( v.length ) { v = v.split(/\s+/); - var i = v.length; + i = v.length; while ( i-- ) { v[i] = CSS.escape(v[i]); } @@ -353,7 +369,29 @@ var cosmeticFilterFromElement = function(elem, out) { } } - out.push('##' + prefix + suffix.join('')); + var selector = prefix + suffix.join(''); + + // https://github.com/gorhill/uBlock/issues/637 + // If the selector is still ambiguous at this point, further narrow using + // `nth-of-type`. It is preferable to use `nth-of-type` as opposed to + // `nth-child`, as `nth-of-type` is less volatile. + var parentNode = elem.parentNode; + if ( parentNode !== null && parentNode.querySelectorAll(cssScope + selector).length > 1 ) { + i = 1; + while ( elem.previousSibling !== null ) { + elem = elem.previousSibling; + if ( typeof elem.tagName !== 'string' ) { + continue; + } + if ( elem.tagName.toLowerCase() !== tagName ) { + continue; + } + i++; + } + selector += ':nth-of-type(' + i + ')'; + } + + out.push('##' + selector); }; /******************************************************************************/ |