mirror of
https://github.com/gorhill/uBlock.git
synced 2024-10-04 16:47:15 +02:00
Add support to chain :style()
to procedural operators
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/382
Additionally, remnant code for pseudo-user stylesheets
has been removed. Related commit:
- 5c68867b92
This commit is contained in:
parent
3a51ca0002
commit
35aefed926
@ -56,6 +56,16 @@ window.addEventListener('webextFlavor', function() {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
vAPI.randomToken = function() {
|
||||||
|
const n = Math.random();
|
||||||
|
return String.fromCharCode(n * 26 + 97) +
|
||||||
|
Math.floor(
|
||||||
|
(0.25 + n * 0.75) * Number.MAX_SAFE_INTEGER
|
||||||
|
).toString(36).slice(-8);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.app = {
|
vAPI.app = {
|
||||||
name: manifest.name.replace(/ dev\w+ build/, ''),
|
name: manifest.name.replace(/ dev\w+ build/, ''),
|
||||||
version: (( ) => {
|
version: (( ) => {
|
||||||
@ -339,7 +349,10 @@ vAPI.Tabs = class {
|
|||||||
return tabs.length !== 0 ? tabs[0] : null;
|
return tabs.length !== 0 ? tabs[0] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async insertCSS() {
|
async insertCSS(tabId, details) {
|
||||||
|
if ( vAPI.supportsUserStylesheets ) {
|
||||||
|
details.cssOrigin = 'user';
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await webext.tabs.insertCSS(...arguments);
|
await webext.tabs.insertCSS(...arguments);
|
||||||
}
|
}
|
||||||
@ -357,7 +370,10 @@ vAPI.Tabs = class {
|
|||||||
return Array.isArray(tabs) ? tabs : [];
|
return Array.isArray(tabs) ? tabs : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeCSS() {
|
async removeCSS(tabId, details) {
|
||||||
|
if ( vAPI.supportsUserStylesheets ) {
|
||||||
|
details.cssOrigin = 'user';
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await webext.tabs.removeCSS(...arguments);
|
await webext.tabs.removeCSS(...arguments);
|
||||||
}
|
}
|
||||||
@ -1003,9 +1019,6 @@ vAPI.messaging = {
|
|||||||
frameId: sender.frameId,
|
frameId: sender.frameId,
|
||||||
matchAboutBlank: true
|
matchAboutBlank: true
|
||||||
};
|
};
|
||||||
if ( vAPI.supportsUserStylesheets ) {
|
|
||||||
details.cssOrigin = 'user';
|
|
||||||
}
|
|
||||||
if ( msg.add ) {
|
if ( msg.add ) {
|
||||||
details.runAt = 'document_start';
|
details.runAt = 'document_start';
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,11 @@ if (
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.randomToken = function() {
|
vAPI.randomToken = function() {
|
||||||
const now = Date.now();
|
const n = Math.random();
|
||||||
return String.fromCharCode(now % 26 + 97) +
|
return String.fromCharCode(n * 26 + 97) +
|
||||||
Math.floor((1 + Math.random()) * now).toString(36);
|
Math.floor(
|
||||||
|
(0.25 + n * 0.75) * Number.MAX_SAFE_INTEGER
|
||||||
|
).toString(36).slice(-8);
|
||||||
};
|
};
|
||||||
|
|
||||||
vAPI.sessionId = vAPI.randomToken();
|
vAPI.sessionId = vAPI.randomToken();
|
||||||
|
@ -138,8 +138,8 @@ const µBlock = (( ) => { // jshint ignore:line
|
|||||||
|
|
||||||
// Read-only
|
// Read-only
|
||||||
systemSettings: {
|
systemSettings: {
|
||||||
compiledMagic: 28, // Increase when compiled format changes
|
compiledMagic: 29, // Increase when compiled format changes
|
||||||
selfieMagic: 28, // Increase when selfie format changes
|
selfieMagic: 29, // Increase when selfie format changes
|
||||||
},
|
},
|
||||||
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501
|
||||||
|
@ -88,16 +88,8 @@
|
|||||||
|
|
||||||
The domFilterer makes use of platform-dependent user stylesheets[1].
|
The domFilterer makes use of platform-dependent user stylesheets[1].
|
||||||
|
|
||||||
At time of writing, only modern Firefox provides a custom implementation,
|
|
||||||
which makes for solid, reliable and low overhead cosmetic filtering on
|
|
||||||
Firefox.
|
|
||||||
|
|
||||||
The generic implementation[2] performs as best as can be, but won't ever be
|
|
||||||
as reliable and accurate as real user stylesheets.
|
|
||||||
|
|
||||||
[1] "user stylesheets" refer to local CSS rules which have priority over,
|
[1] "user stylesheets" refer to local CSS rules which have priority over,
|
||||||
and can't be overriden by a web page's own CSS rules.
|
and can't be overriden by a web page's own CSS rules.
|
||||||
[2] below, see platformUserCSS / platformHideNode / platformUnhideNode
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -492,6 +484,11 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
{
|
{
|
||||||
|
vAPI.hideStyle = 'display:none!important;';
|
||||||
|
|
||||||
|
// TODO: Experiment/evaluate loading procedural operator code using an
|
||||||
|
// on demand approach.
|
||||||
|
|
||||||
// 'P' stands for 'Procedural'
|
// 'P' stands for 'Procedural'
|
||||||
|
|
||||||
const PSelectorHasTextTask = class {
|
const PSelectorHasTextTask = class {
|
||||||
@ -562,14 +559,6 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const PSelectorPassthru = class {
|
|
||||||
constructor() {
|
|
||||||
}
|
|
||||||
transpose(node, output) {
|
|
||||||
output.push(node);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const PSelectorSpathTask = class {
|
const PSelectorSpathTask = class {
|
||||||
constructor(task) {
|
constructor(task) {
|
||||||
this.spath = task[1];
|
this.spath = task[1];
|
||||||
@ -701,17 +690,13 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
[ ':min-text-length', PSelectorMinTextLengthTask ],
|
[ ':min-text-length', PSelectorMinTextLengthTask ],
|
||||||
[ ':not', PSelectorIfNotTask ],
|
[ ':not', PSelectorIfNotTask ],
|
||||||
[ ':nth-ancestor', PSelectorUpwardTask ],
|
[ ':nth-ancestor', PSelectorUpwardTask ],
|
||||||
[ ':remove', PSelectorPassthru ],
|
|
||||||
[ ':spath', PSelectorSpathTask ],
|
[ ':spath', PSelectorSpathTask ],
|
||||||
[ ':upward', PSelectorUpwardTask ],
|
[ ':upward', PSelectorUpwardTask ],
|
||||||
[ ':watch-attr', PSelectorWatchAttrs ],
|
[ ':watch-attr', PSelectorWatchAttrs ],
|
||||||
[ ':xpath', PSelectorXpathTask ],
|
[ ':xpath', PSelectorXpathTask ],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
this.budget = 200; // I arbitrary picked a 1/5 second
|
|
||||||
this.raw = o.raw;
|
this.raw = o.raw;
|
||||||
this.cost = 0;
|
|
||||||
this.lastAllowanceTime = 0;
|
|
||||||
this.selector = o.selector;
|
this.selector = o.selector;
|
||||||
this.tasks = [];
|
this.tasks = [];
|
||||||
const tasks = o.tasks;
|
const tasks = o.tasks;
|
||||||
@ -722,9 +707,6 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( o.action !== undefined ) {
|
|
||||||
this.action = o.action;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
prime(input) {
|
prime(input) {
|
||||||
const root = input || document;
|
const root = input || document;
|
||||||
@ -760,10 +742,20 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
PSelector.prototype.action = undefined;
|
|
||||||
PSelector.prototype.hit = false;
|
|
||||||
PSelector.prototype.operatorToTaskMap = undefined;
|
PSelector.prototype.operatorToTaskMap = undefined;
|
||||||
|
|
||||||
|
const PSelectorRoot = class extends PSelector {
|
||||||
|
constructor(o, styleToken) {
|
||||||
|
super(o);
|
||||||
|
this.budget = 200; // I arbitrary picked a 1/5 second
|
||||||
|
this.raw = o.raw;
|
||||||
|
this.cost = 0;
|
||||||
|
this.lastAllowanceTime = 0;
|
||||||
|
this.styleToken = styleToken;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
PSelectorRoot.prototype.hit = false;
|
||||||
|
|
||||||
const DOMProceduralFilterer = class {
|
const DOMProceduralFilterer = class {
|
||||||
constructor(domFilterer) {
|
constructor(domFilterer) {
|
||||||
this.domFilterer = domFilterer;
|
this.domFilterer = domFilterer;
|
||||||
@ -771,41 +763,49 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
this.domIsWatched = false;
|
this.domIsWatched = false;
|
||||||
this.mustApplySelectors = false;
|
this.mustApplySelectors = false;
|
||||||
this.selectors = new Map();
|
this.selectors = new Map();
|
||||||
this.hiddenNodes = new Set();
|
this.masterToken = vAPI.randomToken();
|
||||||
|
this.styleTokenMap = new Map();
|
||||||
|
this.styledNodes = new Set();
|
||||||
if ( vAPI.domWatcher instanceof Object ) {
|
if ( vAPI.domWatcher instanceof Object ) {
|
||||||
vAPI.domWatcher.addListener(this);
|
vAPI.domWatcher.addListener(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addProceduralSelectors(aa) {
|
addProceduralSelectors(selectors) {
|
||||||
const addedSelectors = [];
|
const addedSelectors = [];
|
||||||
let mustCommit = this.domIsWatched;
|
let mustCommit = this.domIsWatched;
|
||||||
for ( let i = 0, n = aa.length; i < n; i++ ) {
|
for ( const raw of selectors ) {
|
||||||
const raw = aa[i];
|
if ( this.selectors.has(raw) ) { continue; }
|
||||||
const o = JSON.parse(raw);
|
const o = JSON.parse(raw);
|
||||||
if ( o.action === 'style' ) {
|
|
||||||
this.domFilterer.addCSSRule(o.selector, o.tasks[0][1]);
|
|
||||||
mustCommit = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ( o.pseudo !== undefined ) {
|
if ( o.pseudo !== undefined ) {
|
||||||
this.domFilterer.addCSSRule(
|
this.domFilterer.addCSSRule(o.selector, vAPI.hideStyle);
|
||||||
o.selector,
|
|
||||||
'display:none!important;'
|
|
||||||
);
|
|
||||||
mustCommit = true;
|
mustCommit = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( o.tasks !== undefined ) {
|
// CSS selector-based styles.
|
||||||
if ( this.selectors.has(raw) === false ) {
|
if (
|
||||||
const pselector = new PSelector(o);
|
o.action !== undefined &&
|
||||||
|
o.action[0] === ':style' &&
|
||||||
|
o.tasks === undefined
|
||||||
|
) {
|
||||||
|
this.domFilterer.addCSSRule(o.selector, o.action[1]);
|
||||||
|
mustCommit = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let style, styleToken;
|
||||||
|
if ( o.action === undefined ) {
|
||||||
|
style = vAPI.hideStyle;
|
||||||
|
} else if ( o.action[0] === ':style' ) {
|
||||||
|
style = o.action[1];
|
||||||
|
}
|
||||||
|
if ( style !== undefined ) {
|
||||||
|
styleToken = this.styleTokenFromStyle(style);
|
||||||
|
}
|
||||||
|
const pselector = new PSelectorRoot(o, styleToken);
|
||||||
this.selectors.set(raw, pselector);
|
this.selectors.set(raw, pselector);
|
||||||
addedSelectors.push(pselector);
|
addedSelectors.push(pselector);
|
||||||
mustCommit = true;
|
mustCommit = true;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( mustCommit === false ) { return; }
|
if ( mustCommit === false ) { return; }
|
||||||
this.mustApplySelectors = this.selectors.size !== 0;
|
this.mustApplySelectors = this.selectors.size !== 0;
|
||||||
this.domFilterer.commit();
|
this.domFilterer.commit();
|
||||||
@ -828,8 +828,8 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/341
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/341
|
||||||
// Be ready to unhide nodes which no longer matches any of
|
// Be ready to unhide nodes which no longer matches any of
|
||||||
// the procedural selectors.
|
// the procedural selectors.
|
||||||
const toRemove = this.hiddenNodes;
|
const toUnstyle = this.styledNodes;
|
||||||
this.hiddenNodes = new Set();
|
this.styledNodes = new Set();
|
||||||
|
|
||||||
let t0 = Date.now();
|
let t0 = Date.now();
|
||||||
|
|
||||||
@ -851,37 +851,54 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
t0 = t1;
|
t0 = t1;
|
||||||
if ( nodes.length === 0 ) { continue; }
|
if ( nodes.length === 0 ) { continue; }
|
||||||
pselector.hit = true;
|
pselector.hit = true;
|
||||||
if ( pselector.action === 'remove' ) {
|
this.styleNodes(nodes, pselector.styleToken);
|
||||||
this.removeNodes(nodes);
|
|
||||||
} else {
|
|
||||||
this.hideNodes(nodes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( const node of toRemove ) {
|
this.unstyleNodes(toUnstyle);
|
||||||
if ( this.hiddenNodes.has(node) ) { continue; }
|
|
||||||
this.domFilterer.unhideNode(node);
|
|
||||||
}
|
|
||||||
//console.timeEnd('procedural selectors/dom layout changed');
|
//console.timeEnd('procedural selectors/dom layout changed');
|
||||||
}
|
}
|
||||||
|
|
||||||
hideNodes(nodes) {
|
styleTokenFromStyle(style) {
|
||||||
for ( const node of nodes ) {
|
if ( style === undefined ) { return; }
|
||||||
if ( node.parentElement === null ) { continue; }
|
let styleToken = this.styleTokenMap.get(style);
|
||||||
this.domFilterer.hideNode(node);
|
if ( styleToken !== undefined ) { return styleToken; }
|
||||||
this.hiddenNodes.add(node);
|
styleToken = vAPI.randomToken();
|
||||||
}
|
this.styleTokenMap.set(style, styleToken);
|
||||||
|
this.domFilterer.addCSSRule(
|
||||||
|
`[${this.masterToken}][${styleToken}]`,
|
||||||
|
style,
|
||||||
|
{ silent: true }
|
||||||
|
);
|
||||||
|
return styleToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeNodes(nodes) {
|
styleNodes(nodes, styleToken) {
|
||||||
|
if ( styleToken === undefined ) {
|
||||||
for ( const node of nodes ) {
|
for ( const node of nodes ) {
|
||||||
node.textContent = '';
|
node.textContent = '';
|
||||||
node.remove();
|
node.remove();
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for ( const node of nodes ) {
|
||||||
|
if ( node.parentElement === null ) { continue; }
|
||||||
|
node.setAttribute(this.masterToken, '');
|
||||||
|
node.setAttribute(styleToken, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Current assumption is one style per hit element. Could be an
|
||||||
|
// issue if an element has multiple styling and one styling is
|
||||||
|
// brough back. Possibly too rare to care about this for now.
|
||||||
|
unstyleNodes(nodes) {
|
||||||
|
for ( const node of nodes ) {
|
||||||
|
if ( this.styledNodes.has(node) ) { continue; }
|
||||||
|
node.removeAttribute(this.masterToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createProceduralFilter(o) {
|
createProceduralFilter(o) {
|
||||||
return new PSelector(o);
|
return new PSelectorRoot(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDOMCreated() {
|
onDOMCreated() {
|
||||||
@ -908,14 +925,10 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
this.disabled = false;
|
this.disabled = false;
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
this.filterset = new Set();
|
this.filterset = new Set();
|
||||||
this.excludedNodeSet = new WeakSet();
|
|
||||||
this.addedCSSRules = new Set();
|
this.addedCSSRules = new Set();
|
||||||
this.exceptedCSSRules = [];
|
this.exceptedCSSRules = [];
|
||||||
this.reOnlySelectors = /\n\{[^\n]+/g;
|
|
||||||
this.exceptions = [];
|
this.exceptions = [];
|
||||||
this.proceduralFilterer = null;
|
this.proceduralFilterer = null;
|
||||||
this.hideNodeAttr = undefined;
|
|
||||||
this.hideNodeStyleSheetInjected = false;
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/167
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/167
|
||||||
// By the time the DOMContentLoaded is fired, the content script might
|
// By the time the DOMContentLoaded is fired, the content script might
|
||||||
// have been disconnected from the background page. Unclear why this
|
// have been disconnected from the background page. Unclear why this
|
||||||
@ -988,33 +1001,6 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
excludeNode(node) {
|
|
||||||
this.excludedNodeSet.add(node);
|
|
||||||
this.unhideNode(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
unexcludeNode(node) {
|
|
||||||
this.excludedNodeSet.delete(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
hideNode(node) {
|
|
||||||
if ( this.excludedNodeSet.has(node) ) { return; }
|
|
||||||
if ( this.hideNodeAttr === undefined ) { return; }
|
|
||||||
node.setAttribute(this.hideNodeAttr, '');
|
|
||||||
if ( this.hideNodeStyleSheetInjected ) { return; }
|
|
||||||
this.hideNodeStyleSheetInjected = true;
|
|
||||||
this.addCSSRule(
|
|
||||||
`[${this.hideNodeAttr}]`,
|
|
||||||
'display:none!important;',
|
|
||||||
{ silent: true }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
unhideNode(node) {
|
|
||||||
if ( this.hideNodeAttr === undefined ) { return; }
|
|
||||||
node.removeAttribute(this.hideNodeAttr);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle(state, callback) {
|
toggle(state, callback) {
|
||||||
if ( state === undefined ) { state = this.disabled; }
|
if ( state === undefined ) { state = this.disabled; }
|
||||||
if ( state !== this.disabled ) { return; }
|
if ( state !== this.disabled ) { return; }
|
||||||
@ -1031,24 +1017,6 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
userStylesheet.apply(callback);
|
userStylesheet.apply(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllSelectors_(all) {
|
|
||||||
const out = {
|
|
||||||
declarative: [],
|
|
||||||
exceptions: this.exceptedCSSRules,
|
|
||||||
};
|
|
||||||
for ( const entry of this.filterset ) {
|
|
||||||
let selectors = entry.selectors;
|
|
||||||
if ( all !== true && this.hideNodeAttr !== undefined ) {
|
|
||||||
selectors = selectors
|
|
||||||
.replace(`[${this.hideNodeAttr}]`, '')
|
|
||||||
.replace(/^,\n|,\n$/gm, '');
|
|
||||||
if ( selectors === '' ) { continue; }
|
|
||||||
}
|
|
||||||
out.declarative.push([ selectors, entry.declarations ]);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here we will deal with:
|
// Here we will deal with:
|
||||||
// - Injecting low priority user styles;
|
// - Injecting low priority user styles;
|
||||||
// - Notifying listeners about changed filterset.
|
// - Notifying listeners about changed filterset.
|
||||||
@ -1097,7 +1065,7 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addProceduralSelectors(aa) {
|
addProceduralSelectors(aa) {
|
||||||
if ( aa.length === 0 ) { return; }
|
if ( Array.isArray(aa) === false || aa.length === 0 ) { return; }
|
||||||
this.proceduralFiltererInstance().addProceduralSelectors(aa);
|
this.proceduralFiltererInstance().addProceduralSelectors(aa);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1105,25 +1073,39 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
return this.proceduralFiltererInstance().createProceduralFilter(o);
|
return this.proceduralFiltererInstance().createProceduralFilter(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllSelectors() {
|
getAllSelectors(bits = 0) {
|
||||||
const out = this.getAllSelectors_(false);
|
const out = {
|
||||||
out.procedural = this.proceduralFilterer instanceof Object
|
declarative: [],
|
||||||
|
exceptions: this.exceptedCSSRules,
|
||||||
|
};
|
||||||
|
const hasProcedural = this.proceduralFilterer instanceof Object;
|
||||||
|
const includePrivateSelectors = (bits & 0b01) !== 0;
|
||||||
|
const masterToken = hasProcedural
|
||||||
|
? `[${this.proceduralFilterer.masterToken}]`
|
||||||
|
: undefined;
|
||||||
|
for ( const entry of this.filterset ) {
|
||||||
|
const selectors = entry.selectors;
|
||||||
|
if (
|
||||||
|
includePrivateSelectors === false &&
|
||||||
|
masterToken !== undefined &&
|
||||||
|
selectors.startsWith(masterToken)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out.declarative.push([ selectors, entry.declarations ]);
|
||||||
|
}
|
||||||
|
const excludeProcedurals = (bits & 0b10) !== 0;
|
||||||
|
if ( excludeProcedurals !== true ) {
|
||||||
|
out.procedural = hasProcedural
|
||||||
? Array.from(this.proceduralFilterer.selectors.values())
|
? Array.from(this.proceduralFilterer.selectors.values())
|
||||||
: [];
|
: [];
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllExceptionSelectors() {
|
getAllExceptionSelectors() {
|
||||||
return this.exceptions.join(',\n');
|
return this.exceptions.join(',\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
getFilteredElementCount() {
|
|
||||||
const details = this.getAllSelectors_(true);
|
|
||||||
if ( Array.isArray(details.declarative) === false ) { return 0; }
|
|
||||||
const selectors = details.declarative.map(entry => entry[0]);
|
|
||||||
if ( selectors.length === 0 ) { return 0; }
|
|
||||||
return document.querySelectorAll(selectors.join(',\n')).length;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1548,29 +1530,11 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
let mustCommit = false;
|
let mustCommit = false;
|
||||||
|
|
||||||
if ( result ) {
|
if ( result ) {
|
||||||
let selectors = result.simple;
|
let selectors = result.injected;
|
||||||
if ( Array.isArray(selectors) && selectors.length !== 0 ) {
|
|
||||||
domFilterer.addCSSRule(
|
|
||||||
selectors,
|
|
||||||
'display:none!important;',
|
|
||||||
{ type: 'simple' }
|
|
||||||
);
|
|
||||||
mustCommit = true;
|
|
||||||
}
|
|
||||||
selectors = result.complex;
|
|
||||||
if ( Array.isArray(selectors) && selectors.length !== 0 ) {
|
|
||||||
domFilterer.addCSSRule(
|
|
||||||
selectors,
|
|
||||||
'display:none!important;',
|
|
||||||
{ type: 'complex' }
|
|
||||||
);
|
|
||||||
mustCommit = true;
|
|
||||||
}
|
|
||||||
selectors = result.injected;
|
|
||||||
if ( typeof selectors === 'string' && selectors.length !== 0 ) {
|
if ( typeof selectors === 'string' && selectors.length !== 0 ) {
|
||||||
domFilterer.addCSSRule(
|
domFilterer.addCSSRule(
|
||||||
selectors,
|
selectors,
|
||||||
'display:none!important;',
|
vAPI.hideStyle,
|
||||||
{ injected: true }
|
{ injected: true }
|
||||||
);
|
);
|
||||||
mustCommit = true;
|
mustCommit = true;
|
||||||
@ -1740,37 +1704,15 @@ vAPI.injectScriptlet = function(doc, text) {
|
|||||||
vAPI.domSurveyor = null;
|
vAPI.domSurveyor = null;
|
||||||
}
|
}
|
||||||
domFilterer.exceptions = cfeDetails.exceptionFilters;
|
domFilterer.exceptions = cfeDetails.exceptionFilters;
|
||||||
domFilterer.hideNodeAttr = cfeDetails.hideNodeAttr;
|
|
||||||
domFilterer.hideNodeStyleSheetInjected =
|
|
||||||
cfeDetails.hideNodeStyleSheetInjected === true;
|
|
||||||
domFilterer.addCSSRule(
|
|
||||||
cfeDetails.declarativeFilters,
|
|
||||||
'display:none!important;'
|
|
||||||
);
|
|
||||||
domFilterer.addCSSRule(
|
|
||||||
cfeDetails.highGenericHideSimple,
|
|
||||||
'display:none!important;',
|
|
||||||
{ type: 'simple', lazy: true }
|
|
||||||
);
|
|
||||||
domFilterer.addCSSRule(
|
|
||||||
cfeDetails.highGenericHideComplex,
|
|
||||||
'display:none!important;',
|
|
||||||
{ type: 'complex', lazy: true }
|
|
||||||
);
|
|
||||||
domFilterer.addCSSRule(
|
domFilterer.addCSSRule(
|
||||||
cfeDetails.injectedHideFilters,
|
cfeDetails.injectedHideFilters,
|
||||||
'display:none!important;',
|
vAPI.hideStyle,
|
||||||
{ injected: true }
|
{ injected: true }
|
||||||
);
|
);
|
||||||
domFilterer.addProceduralSelectors(cfeDetails.proceduralFilters);
|
domFilterer.addProceduralSelectors(cfeDetails.proceduralFilters);
|
||||||
domFilterer.exceptCSSRules(cfeDetails.exceptedFilters);
|
domFilterer.exceptCSSRules(cfeDetails.exceptedFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( cfeDetails.networkFilters.length !== 0 ) {
|
|
||||||
vAPI.userStylesheet.add(
|
|
||||||
cfeDetails.networkFilters + '\n{display:none!important;}');
|
|
||||||
}
|
|
||||||
|
|
||||||
vAPI.userStylesheet.apply();
|
vAPI.userStylesheet.apply();
|
||||||
|
|
||||||
// Library of resources is located at:
|
// Library of resources is located at:
|
||||||
|
@ -32,12 +32,6 @@ const cosmeticSurveyingMissCountMax =
|
|||||||
parseInt(vAPI.localStorage.getItem('cosmeticSurveyingMissCountMax'), 10) ||
|
parseInt(vAPI.localStorage.getItem('cosmeticSurveyingMissCountMax'), 10) ||
|
||||||
15;
|
15;
|
||||||
|
|
||||||
let supportsUserStylesheets = vAPI.webextFlavor.soup.has('user_stylesheet');
|
|
||||||
// https://www.reddit.com/r/uBlockOrigin/comments/8dkvqn/116_broken_loading_custom_filters_from_my_filters/
|
|
||||||
window.addEventListener('webextFlavor', function() {
|
|
||||||
supportsUserStylesheets = vAPI.webextFlavor.soup.has('user_stylesheet');
|
|
||||||
}, { once: true });
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@ -754,9 +748,9 @@ FilterContainer.prototype.triggerSelectorCachePruner = function() {
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
FilterContainer.prototype.addToSelectorCache = function(details) {
|
FilterContainer.prototype.addToSelectorCache = function(details) {
|
||||||
let hostname = details.hostname;
|
const hostname = details.hostname;
|
||||||
if ( typeof hostname !== 'string' || hostname === '' ) { return; }
|
if ( typeof hostname !== 'string' || hostname === '' ) { return; }
|
||||||
let selectors = details.selectors;
|
const selectors = details.selectors;
|
||||||
if ( Array.isArray(selectors) === false ) { return; }
|
if ( Array.isArray(selectors) === false ) { return; }
|
||||||
let entry = this.selectorCache.get(hostname);
|
let entry = this.selectorCache.get(hostname);
|
||||||
if ( entry === undefined ) {
|
if ( entry === undefined ) {
|
||||||
@ -838,14 +832,6 @@ FilterContainer.prototype.pruneSelectorCacheAsync = function() {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
FilterContainer.prototype.randomAlphaToken = function() {
|
|
||||||
const now = Date.now();
|
|
||||||
return String.fromCharCode(now % 26 + 97) +
|
|
||||||
Math.floor((1 + Math.random()) * now).toString(36);
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
FilterContainer.prototype.getSession = function() {
|
FilterContainer.prototype.getSession = function() {
|
||||||
return this.sessionFilterDB;
|
return this.sessionFilterDB;
|
||||||
};
|
};
|
||||||
@ -912,57 +898,38 @@ FilterContainer.prototype.retrieveGenericSelectors = function(request) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const out = {
|
const out = { injected: '', excepted, };
|
||||||
simple: Array.from(simpleSelectors),
|
|
||||||
complex: Array.from(complexSelectors),
|
|
||||||
injected: '',
|
|
||||||
excepted,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Important: always clear used registers before leaving.
|
const injected = [];
|
||||||
|
if ( simpleSelectors.size !== 0 ) {
|
||||||
|
injected.push(Array.from(simpleSelectors).join(',\n'));
|
||||||
simpleSelectors.clear();
|
simpleSelectors.clear();
|
||||||
|
}
|
||||||
|
if ( complexSelectors.size !== 0 ) {
|
||||||
|
injected.push(Array.from(complexSelectors).join(',\n'));
|
||||||
complexSelectors.clear();
|
complexSelectors.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Cache and inject (if user stylesheets supported) looked-up low generic
|
// Cache and inject looked-up low generic cosmetic filters.
|
||||||
// cosmetic filters.
|
if ( injected.length === 0 ) { return out; }
|
||||||
if (
|
|
||||||
(typeof request.hostname === 'string' && request.hostname !== '') &&
|
if ( typeof request.hostname === 'string' && request.hostname !== '' ) {
|
||||||
(out.simple.length !== 0 || out.complex.length !== 0)
|
|
||||||
) {
|
|
||||||
this.addToSelectorCache({
|
this.addToSelectorCache({
|
||||||
cost: request.surveyCost || 0,
|
cost: request.surveyCost || 0,
|
||||||
hostname: request.hostname,
|
hostname: request.hostname,
|
||||||
injectedHideFilters: '',
|
injectedHideFilters: '',
|
||||||
selectors: out.simple.concat(out.complex),
|
selectors: injected,
|
||||||
type: 'cosmetic'
|
type: 'cosmetic',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// If user stylesheets are supported in the current process, inject the
|
|
||||||
// cosmetic filters now.
|
|
||||||
if (
|
|
||||||
supportsUserStylesheets &&
|
|
||||||
request.tabId !== undefined &&
|
|
||||||
request.frameId !== undefined
|
|
||||||
) {
|
|
||||||
const injected = [];
|
|
||||||
if ( out.simple.length !== 0 ) {
|
|
||||||
injected.push(out.simple.join(',\n'));
|
|
||||||
out.simple = [];
|
|
||||||
}
|
|
||||||
if ( out.complex.length !== 0 ) {
|
|
||||||
injected.push(out.complex.join(',\n'));
|
|
||||||
out.complex = [];
|
|
||||||
}
|
|
||||||
out.injected = injected.join(',\n');
|
out.injected = injected.join(',\n');
|
||||||
vAPI.tabs.insertCSS(request.tabId, {
|
vAPI.tabs.insertCSS(request.tabId, {
|
||||||
code: out.injected + '\n{display:none!important;}',
|
code: out.injected + '\n{display:none!important;}',
|
||||||
cssOrigin: 'user',
|
|
||||||
frameId: request.frameId,
|
frameId: request.frameId,
|
||||||
matchAboutBlank: true,
|
matchAboutBlank: true,
|
||||||
runAt: 'document_start',
|
runAt: 'document_start',
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
//console.timeEnd('cosmeticFilteringEngine.retrieveGenericSelectors');
|
//console.timeEnd('cosmeticFilteringEngine.retrieveGenericSelectors');
|
||||||
|
|
||||||
@ -989,18 +956,11 @@ FilterContainer.prototype.retrieveSpecificSelectors = function(
|
|||||||
ready: this.frozen,
|
ready: this.frozen,
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
domain: request.domain,
|
domain: request.domain,
|
||||||
declarativeFilters: [],
|
|
||||||
exceptionFilters: [],
|
exceptionFilters: [],
|
||||||
exceptedFilters: [],
|
exceptedFilters: [],
|
||||||
hideNodeAttr: this.randomAlphaToken(),
|
|
||||||
hideNodeStyleSheetInjected: false,
|
|
||||||
highGenericHideSimple: '',
|
|
||||||
highGenericHideComplex: '',
|
|
||||||
injectedHideFilters: '',
|
|
||||||
networkFilters: '',
|
|
||||||
noDOMSurveying: this.needDOMSurveyor === false,
|
noDOMSurveying: this.needDOMSurveyor === false,
|
||||||
proceduralFilters: []
|
|
||||||
};
|
};
|
||||||
|
const injectedHideFilters = [];
|
||||||
|
|
||||||
if ( options.noCosmeticFiltering !== true ) {
|
if ( options.noCosmeticFiltering !== true ) {
|
||||||
const specificSet = this.$specificSet;
|
const specificSet = this.$specificSet;
|
||||||
@ -1063,7 +1023,7 @@ FilterContainer.prototype.retrieveSpecificSelectors = function(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( specificSet.size !== 0 ) {
|
if ( specificSet.size !== 0 ) {
|
||||||
out.declarativeFilters = Array.from(specificSet);
|
injectedHideFilters.push(Array.from(specificSet).join(',\n'));
|
||||||
}
|
}
|
||||||
if ( proceduralSet.size !== 0 ) {
|
if ( proceduralSet.size !== 0 ) {
|
||||||
out.proceduralFilters = Array.from(proceduralSet);
|
out.proceduralFilters = Array.from(proceduralSet);
|
||||||
@ -1078,10 +1038,10 @@ FilterContainer.prototype.retrieveSpecificSelectors = function(
|
|||||||
// string in memory, which I have observed occurs when the string is
|
// string in memory, which I have observed occurs when the string is
|
||||||
// stored directly as a value in a Map.
|
// stored directly as a value in a Map.
|
||||||
if ( options.noGenericCosmeticFiltering !== true ) {
|
if ( options.noGenericCosmeticFiltering !== true ) {
|
||||||
const exceptionHash = out.exceptionFilters.join();
|
const exceptionSetHash = out.exceptionFilters.join();
|
||||||
for ( const type in this.highlyGeneric ) {
|
for ( const key in this.highlyGeneric ) {
|
||||||
const entry = this.highlyGeneric[type];
|
const entry = this.highlyGeneric[key];
|
||||||
let str = entry.mru.lookup(exceptionHash);
|
let str = entry.mru.lookup(exceptionSetHash);
|
||||||
if ( str === undefined ) {
|
if ( str === undefined ) {
|
||||||
str = { s: entry.str, excepted: [] };
|
str = { s: entry.str, excepted: [] };
|
||||||
let genericSet = entry.dict;
|
let genericSet = entry.dict;
|
||||||
@ -1098,13 +1058,14 @@ FilterContainer.prototype.retrieveSpecificSelectors = function(
|
|||||||
}
|
}
|
||||||
str.s = Array.from(genericSet).join(',\n');
|
str.s = Array.from(genericSet).join(',\n');
|
||||||
}
|
}
|
||||||
entry.mru.add(exceptionHash, str);
|
entry.mru.add(exceptionSetHash, str);
|
||||||
}
|
}
|
||||||
out[entry.canonical] = str.s;
|
|
||||||
if ( str.excepted.length !== 0 ) {
|
if ( str.excepted.length !== 0 ) {
|
||||||
out.exceptedFilters.push(...str.excepted);
|
out.exceptedFilters.push(...str.excepted);
|
||||||
}
|
}
|
||||||
|
if ( str.s.length !== 0 ) {
|
||||||
|
injectedHideFilters.push(str.s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1115,54 +1076,26 @@ FilterContainer.prototype.retrieveSpecificSelectors = function(
|
|||||||
dummySet.clear();
|
dummySet.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// CSS selectors for collapsible blocked elements
|
|
||||||
if ( cacheEntry ) {
|
|
||||||
const networkFilters = [];
|
|
||||||
cacheEntry.retrieve('net', networkFilters);
|
|
||||||
out.networkFilters = networkFilters.join(',\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/3160
|
|
||||||
// If user stylesheets are supported in the current process, inject the
|
|
||||||
// cosmetic filters now.
|
|
||||||
if (
|
|
||||||
supportsUserStylesheets &&
|
|
||||||
request.tabId !== undefined &&
|
|
||||||
request.frameId !== undefined
|
|
||||||
) {
|
|
||||||
const injectedHideFilters = [];
|
|
||||||
if ( out.declarativeFilters.length !== 0 ) {
|
|
||||||
injectedHideFilters.push(out.declarativeFilters.join(',\n'));
|
|
||||||
out.declarativeFilters = [];
|
|
||||||
}
|
|
||||||
if ( out.proceduralFilters.length !== 0 ) {
|
|
||||||
injectedHideFilters.push('[' + out.hideNodeAttr + ']');
|
|
||||||
out.hideNodeStyleSheetInjected = true;
|
|
||||||
}
|
|
||||||
if ( out.highGenericHideSimple.length !== 0 ) {
|
|
||||||
injectedHideFilters.push(out.highGenericHideSimple);
|
|
||||||
out.highGenericHideSimple = '';
|
|
||||||
}
|
|
||||||
if ( out.highGenericHideComplex.length !== 0 ) {
|
|
||||||
injectedHideFilters.push(out.highGenericHideComplex);
|
|
||||||
out.highGenericHideComplex = '';
|
|
||||||
}
|
|
||||||
out.injectedHideFilters = injectedHideFilters.join(',\n');
|
|
||||||
const details = {
|
const details = {
|
||||||
code: '',
|
code: '',
|
||||||
cssOrigin: 'user',
|
|
||||||
frameId: request.frameId,
|
frameId: request.frameId,
|
||||||
matchAboutBlank: true,
|
matchAboutBlank: true,
|
||||||
runAt: 'document_start',
|
runAt: 'document_start',
|
||||||
};
|
};
|
||||||
if ( out.injectedHideFilters.length !== 0 ) {
|
|
||||||
|
if ( injectedHideFilters.length !== 0 ) {
|
||||||
|
out.injectedHideFilters = injectedHideFilters.join(',\n');
|
||||||
details.code = out.injectedHideFilters + '\n{display:none!important;}';
|
details.code = out.injectedHideFilters + '\n{display:none!important;}';
|
||||||
vAPI.tabs.insertCSS(request.tabId, details);
|
vAPI.tabs.insertCSS(request.tabId, details);
|
||||||
}
|
}
|
||||||
if ( out.networkFilters.length !== 0 ) {
|
|
||||||
details.code = out.networkFilters + '\n{display:none!important;}';
|
// CSS selectors for collapsible blocked elements
|
||||||
|
if ( cacheEntry ) {
|
||||||
|
const networkFilters = [];
|
||||||
|
cacheEntry.retrieve('net', networkFilters);
|
||||||
|
if ( networkFilters.length !== 0 ) {
|
||||||
|
details.code = networkFilters.join('\n') + '\n{display:none!important;}';
|
||||||
vAPI.tabs.insertCSS(request.tabId, details);
|
vAPI.tabs.insertCSS(request.tabId, details);
|
||||||
out.networkFilters = '';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ if ( epickerId === null ) { return; }
|
|||||||
let epickerConnectionId;
|
let epickerConnectionId;
|
||||||
let filterHostname = '';
|
let filterHostname = '';
|
||||||
let filterOrigin = '';
|
let filterOrigin = '';
|
||||||
let filterResultset = [];
|
let resultsetOpt;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@ -88,11 +88,8 @@ const userFilterFromCandidate = function(filter) {
|
|||||||
opts.push(`domain=${filterHostname}`);
|
opts.push(`domain=${filterHostname}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( filterResultset.length !== 0 ) {
|
if ( resultsetOpt !== undefined ) {
|
||||||
const item = filterResultset[0];
|
opts.push(resultsetOpt);
|
||||||
if ( item.opts ) {
|
|
||||||
opts.push(item.opts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( opts.length ) {
|
if ( opts.length ) {
|
||||||
@ -632,10 +629,10 @@ const onPickerMessage = function(msg) {
|
|||||||
case 'showDialog':
|
case 'showDialog':
|
||||||
showDialog(msg);
|
showDialog(msg);
|
||||||
break;
|
break;
|
||||||
case 'filterResultset': {
|
case 'resultsetDetails': {
|
||||||
filterResultset = msg.resultset;
|
resultsetOpt = msg.opt;
|
||||||
$id('resultsetCount').textContent = filterResultset.length;
|
$id('resultsetCount').textContent = msg.count;
|
||||||
if ( filterResultset.length !== 0 ) {
|
if ( msg.count !== 0 ) {
|
||||||
$id('create').removeAttribute('disabled');
|
$id('create').removeAttribute('disabled');
|
||||||
} else {
|
} else {
|
||||||
$id('create').setAttribute('disabled', '');
|
$id('create').setAttribute('disabled', '');
|
||||||
|
@ -278,7 +278,11 @@ const handlers = {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const details = JSON.parse(selector);
|
const details = JSON.parse(selector);
|
||||||
if ( details.action === 'style' ) {
|
if (
|
||||||
|
details.action !== undefined &&
|
||||||
|
details.tasks === undefined &&
|
||||||
|
details.action[0] === ':style'
|
||||||
|
) {
|
||||||
exceptionDict.set(details.selector, details.raw);
|
exceptionDict.set(details.selector, details.raw);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -501,16 +501,15 @@ const cosmeticFilterMapper = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nodesFromStyleTag = function(rootNode) {
|
const nodesFromStyleTag = function(rootNode) {
|
||||||
var filterMap = roRedNodes,
|
const filterMap = roRedNodes;
|
||||||
entry, selector, canonical, nodes, node;
|
const details = vAPI.domFilterer.getAllSelectors();
|
||||||
|
|
||||||
var details = vAPI.domFilterer.getAllSelectors();
|
|
||||||
|
|
||||||
// Declarative selectors.
|
// Declarative selectors.
|
||||||
for ( entry of (details.declarative || []) ) {
|
for ( const entry of (details.declarative || []) ) {
|
||||||
for ( selector of entry[0].split(',\n') ) {
|
for ( const selector of entry[0].split(',\n') ) {
|
||||||
canonical = selector;
|
let canonical = selector;
|
||||||
if ( entry[1] !== 'display:none!important;' ) {
|
let nodes;
|
||||||
|
if ( entry[1] !== vAPI.hideStyle ) {
|
||||||
canonical += ':style(' + entry[1] + ')';
|
canonical += ':style(' + entry[1] + ')';
|
||||||
}
|
}
|
||||||
if ( reHasCSSCombinators.test(selector) ) {
|
if ( reHasCSSCombinators.test(selector) ) {
|
||||||
@ -524,7 +523,7 @@ const cosmeticFilterMapper = (function() {
|
|||||||
}
|
}
|
||||||
nodes = rootNode.querySelectorAll(selector);
|
nodes = rootNode.querySelectorAll(selector);
|
||||||
}
|
}
|
||||||
for ( node of nodes ) {
|
for ( const node of nodes ) {
|
||||||
if ( filterMap.has(node) === false ) {
|
if ( filterMap.has(node) === false ) {
|
||||||
filterMap.set(node, canonical);
|
filterMap.set(node, canonical);
|
||||||
}
|
}
|
||||||
@ -533,9 +532,9 @@ const cosmeticFilterMapper = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Procedural selectors.
|
// Procedural selectors.
|
||||||
for ( entry of (details.procedural || []) ) {
|
for ( const entry of (details.procedural || []) ) {
|
||||||
nodes = entry.exec();
|
const nodes = entry.exec();
|
||||||
for ( node of nodes ) {
|
for ( const node of nodes ) {
|
||||||
// Upgrade declarative selector to procedural one
|
// Upgrade declarative selector to procedural one
|
||||||
filterMap.set(node, entry.raw);
|
filterMap.set(node, entry.raw);
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
if ( isNaN(surveyResults.hiddenElementCount) ) {
|
if ( isNaN(surveyResults.hiddenElementCount) ) {
|
||||||
surveyResults.hiddenElementCount = (( ) => {
|
surveyResults.hiddenElementCount = (( ) => {
|
||||||
if ( vAPI.domFilterer instanceof Object === false ) { return 0; }
|
if ( vAPI.domFilterer instanceof Object === false ) { return 0; }
|
||||||
const details = vAPI.domFilterer.getAllSelectors_(true);
|
const details = vAPI.domFilterer.getAllSelectors(0b11);
|
||||||
if (
|
if (
|
||||||
Array.isArray(details.declarative) === false ||
|
Array.isArray(details.declarative) === false ||
|
||||||
details.declarative.length === 0
|
details.declarative.length === 0
|
||||||
|
@ -49,6 +49,8 @@ const lastNetFilterSession = window.location.host + window.location.pathname;
|
|||||||
let lastNetFilterHostname = '';
|
let lastNetFilterHostname = '';
|
||||||
let lastNetFilterUnion = '';
|
let lastNetFilterUnion = '';
|
||||||
|
|
||||||
|
const hideBackgroundStyle = 'background-image:none!important;';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const safeQuerySelectorAll = function(node, selector) {
|
const safeQuerySelectorAll = function(node, selector) {
|
||||||
@ -645,10 +647,10 @@ const filterToDOMInterface = (( ) => {
|
|||||||
reFilter.test(elem.currentSrc)
|
reFilter.test(elem.currentSrc)
|
||||||
) {
|
) {
|
||||||
out.push({
|
out.push({
|
||||||
type: 'network',
|
elem,
|
||||||
elem: elem,
|
|
||||||
src: srcProp,
|
src: srcProp,
|
||||||
opts: filterTypes[elem.localName],
|
opt: filterTypes[elem.localName],
|
||||||
|
style: vAPI.hideStyle,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -657,10 +659,10 @@ const filterToDOMInterface = (( ) => {
|
|||||||
for ( const elem of candidateElements ) {
|
for ( const elem of candidateElements ) {
|
||||||
if ( reFilter.test(backgroundImageURLFromElement(elem)) ) {
|
if ( reFilter.test(backgroundImageURLFromElement(elem)) ) {
|
||||||
out.push({
|
out.push({
|
||||||
type: 'network',
|
elem,
|
||||||
elem: elem,
|
bg: true,
|
||||||
style: 'background-image',
|
opt: 'image',
|
||||||
opts: 'image',
|
style: hideBackgroundStyle,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -690,7 +692,7 @@ const filterToDOMInterface = (( ) => {
|
|||||||
const out = [];
|
const out = [];
|
||||||
for ( const elem of elems ) {
|
for ( const elem of elems ) {
|
||||||
if ( elem === pickerRoot ) { continue; }
|
if ( elem === pickerRoot ) { continue; }
|
||||||
out.push({ type: 'cosmetic', elem, raw });
|
out.push({ elem, raw, style: vAPI.hideStyle });
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
@ -702,33 +704,28 @@ const filterToDOMInterface = (( ) => {
|
|||||||
// Remove trailing pseudo-element when querying.
|
// Remove trailing pseudo-element when querying.
|
||||||
const fromCompiledCosmeticFilter = function(raw) {
|
const fromCompiledCosmeticFilter = function(raw) {
|
||||||
if ( typeof raw !== 'string' ) { return; }
|
if ( typeof raw !== 'string' ) { return; }
|
||||||
let elems;
|
let elems, style;
|
||||||
try {
|
try {
|
||||||
const o = JSON.parse(raw);
|
const o = JSON.parse(raw);
|
||||||
if ( o.action === 'style' ) {
|
|
||||||
elems = document.querySelectorAll(
|
|
||||||
o.selector.replace(rePseudoElements, '')
|
|
||||||
);
|
|
||||||
lastAction = o.selector + ' {' + o.tasks[0][1] + '}';
|
|
||||||
} else if ( o.tasks ) {
|
|
||||||
elems = vAPI.domFilterer.createProceduralFilter(o).exec();
|
elems = vAPI.domFilterer.createProceduralFilter(o).exec();
|
||||||
}
|
style = o.action === undefined || o.action[0] !== ':style'
|
||||||
|
? vAPI.hideStyle
|
||||||
|
: o.action[1];
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( !elems ) { return; }
|
if ( !elems ) { return; }
|
||||||
const out = [];
|
const out = [];
|
||||||
for ( const elem of elems ) {
|
for ( const elem of elems ) {
|
||||||
out.push({ type: 'cosmetic', elem, raw });
|
out.push({ elem, raw, style });
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vAPI.epickerStyleProxies = vAPI.epickerStyleProxies || new Map();
|
||||||
|
|
||||||
let lastFilter;
|
let lastFilter;
|
||||||
let lastResultset;
|
let lastResultset;
|
||||||
let lastAction;
|
|
||||||
let appliedStyleTag;
|
|
||||||
let applied = false;
|
|
||||||
let previewing = false;
|
let previewing = false;
|
||||||
|
|
||||||
const queryAll = function(details) {
|
const queryAll = function(details) {
|
||||||
@ -738,11 +735,10 @@ const filterToDOMInterface = (( ) => {
|
|||||||
unapply();
|
unapply();
|
||||||
if ( filter === '' || filter === '!' ) {
|
if ( filter === '' || filter === '!' ) {
|
||||||
lastFilter = '';
|
lastFilter = '';
|
||||||
lastResultset = [];
|
lastResultset = undefined;
|
||||||
return lastResultset;
|
return;
|
||||||
}
|
}
|
||||||
lastFilter = filter;
|
lastFilter = filter;
|
||||||
lastAction = undefined;
|
|
||||||
if ( filter.startsWith('##') === false ) {
|
if ( filter.startsWith('##') === false ) {
|
||||||
lastResultset = fromNetworkFilter(filter);
|
lastResultset = fromNetworkFilter(filter);
|
||||||
if ( previewing ) { apply(); }
|
if ( previewing ) { apply(); }
|
||||||
@ -759,86 +755,29 @@ const filterToDOMInterface = (( ) => {
|
|||||||
return lastResultset;
|
return lastResultset;
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/1629
|
|
||||||
// Avoid hiding the element picker's related elements.
|
|
||||||
const applyHide = function() {
|
|
||||||
const htmlElem = document.documentElement;
|
|
||||||
for ( const item of lastResultset ) {
|
|
||||||
const elem = item.elem;
|
|
||||||
if ( elem === pickerRoot ) { continue; }
|
|
||||||
if (
|
|
||||||
(elem !== htmlElem) &&
|
|
||||||
(item.type === 'cosmetic' || item.type === 'network' && item.src !== undefined)
|
|
||||||
) {
|
|
||||||
vAPI.domFilterer.hideNode(elem);
|
|
||||||
item.hidden = true;
|
|
||||||
}
|
|
||||||
if ( item.type === 'network' && item.style === 'background-image' ) {
|
|
||||||
const style = elem.style;
|
|
||||||
item.backgroundImage = style.getPropertyValue('background-image');
|
|
||||||
item.backgroundImagePriority = style.getPropertyPriority('background-image');
|
|
||||||
style.setProperty('background-image', 'none', 'important');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const unapplyHide = function() {
|
|
||||||
if ( lastResultset === undefined ) { return; }
|
|
||||||
for ( const item of lastResultset ) {
|
|
||||||
if ( item.hidden === true ) {
|
|
||||||
vAPI.domFilterer.unhideNode(item.elem);
|
|
||||||
item.hidden = false;
|
|
||||||
}
|
|
||||||
if ( item.hasOwnProperty('backgroundImage') ) {
|
|
||||||
item.elem.style.setProperty(
|
|
||||||
'background-image',
|
|
||||||
item.backgroundImage,
|
|
||||||
item.backgroundImagePriority
|
|
||||||
);
|
|
||||||
delete item.backgroundImage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const unapplyStyle = function() {
|
|
||||||
if ( !appliedStyleTag || appliedStyleTag.parentNode === null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
appliedStyleTag.parentNode.removeChild(appliedStyleTag);
|
|
||||||
};
|
|
||||||
|
|
||||||
const applyStyle = function() {
|
|
||||||
if ( !appliedStyleTag ) {
|
|
||||||
appliedStyleTag = document.createElement('style');
|
|
||||||
appliedStyleTag.setAttribute('type', 'text/css');
|
|
||||||
}
|
|
||||||
appliedStyleTag.textContent = lastAction;
|
|
||||||
if ( appliedStyleTag.parentNode === null ) {
|
|
||||||
document.head.appendChild(appliedStyleTag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const apply = function() {
|
const apply = function() {
|
||||||
if ( applied ) {
|
|
||||||
unapply();
|
unapply();
|
||||||
|
if ( Array.isArray(lastResultset) === false ) { return; }
|
||||||
|
const rootElem = document.documentElement;
|
||||||
|
for ( const { elem, style } of lastResultset ) {
|
||||||
|
if ( elem === pickerRoot ) { continue; }
|
||||||
|
if ( elem === rootElem && style === vAPI.hideStyle ) { continue; }
|
||||||
|
let styleToken = vAPI.epickerStyleProxies.get(style);
|
||||||
|
if ( styleToken === undefined ) {
|
||||||
|
styleToken = vAPI.randomToken();
|
||||||
|
vAPI.epickerStyleProxies.set(style, styleToken);
|
||||||
|
vAPI.userStylesheet.add(`[${styleToken}]\n{${style}}`, true);
|
||||||
}
|
}
|
||||||
if ( lastResultset === undefined ) { return; }
|
elem.setAttribute(styleToken, '');
|
||||||
if ( typeof lastAction === 'string' ) {
|
|
||||||
applyStyle();
|
|
||||||
} else {
|
|
||||||
applyHide();
|
|
||||||
}
|
}
|
||||||
applied = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const unapply = function() {
|
const unapply = function() {
|
||||||
if ( !applied ) { return; }
|
for ( const styleToken of vAPI.epickerStyleProxies.values() ) {
|
||||||
if ( typeof lastAction === 'string' ) {
|
for ( const elem of document.querySelectorAll(`[${styleToken}]`) ) {
|
||||||
unapplyStyle();
|
elem.removeAttribute(styleToken);
|
||||||
} else {
|
}
|
||||||
unapplyHide();
|
|
||||||
}
|
}
|
||||||
applied = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://www.reddit.com/r/uBlockOrigin/comments/c62irc/
|
// https://www.reddit.com/r/uBlockOrigin/comments/c62irc/
|
||||||
@ -849,24 +788,24 @@ const filterToDOMInterface = (( ) => {
|
|||||||
if ( previewing === false ) {
|
if ( previewing === false ) {
|
||||||
return unapply();
|
return unapply();
|
||||||
}
|
}
|
||||||
if ( lastResultset === undefined ) { return; }
|
if ( Array.isArray(lastResultset) === false ) { return; }
|
||||||
apply();
|
if ( permanent === false || lastFilter.startsWith('##') === false ) {
|
||||||
if ( permanent === false ) { return; }
|
return apply();
|
||||||
|
}
|
||||||
if ( vAPI.domFilterer instanceof Object === false ) { return; }
|
if ( vAPI.domFilterer instanceof Object === false ) { return; }
|
||||||
const cssSelectors = new Set();
|
const cssSelectors = new Set();
|
||||||
const proceduralSelectors = new Set();
|
const proceduralSelectors = new Set();
|
||||||
for ( const item of lastResultset ) {
|
for ( const { raw } of lastResultset ) {
|
||||||
if ( item.type !== 'cosmetic' ) { continue; }
|
if ( raw.startsWith('{') ) {
|
||||||
if ( item.raw.startsWith('{') ) {
|
proceduralSelectors.add(raw);
|
||||||
proceduralSelectors.add(item.raw);
|
|
||||||
} else {
|
} else {
|
||||||
cssSelectors.add(item.raw);
|
cssSelectors.add(raw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( cssSelectors.size !== 0 ) {
|
if ( cssSelectors.size !== 0 ) {
|
||||||
vAPI.domFilterer.addCSSRule(
|
vAPI.domFilterer.addCSSRule(
|
||||||
Array.from(cssSelectors),
|
Array.from(cssSelectors),
|
||||||
'display:none!important;'
|
vAPI.hideStyle
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( proceduralSelectors.size !== 0 ) {
|
if ( proceduralSelectors.size !== 0 ) {
|
||||||
@ -876,11 +815,7 @@ const filterToDOMInterface = (( ) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return { preview, queryAll };
|
||||||
get previewing() { return previewing; },
|
|
||||||
preview,
|
|
||||||
queryAll,
|
|
||||||
};
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -1091,11 +1026,6 @@ const quitPicker = function() {
|
|||||||
|
|
||||||
if ( pickerRoot === null ) { return; }
|
if ( pickerRoot === null ) { return; }
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/2060
|
|
||||||
if ( vAPI.domFilterer instanceof Object ) {
|
|
||||||
vAPI.domFilterer.unexcludeNode(pickerRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
pickerRoot.remove();
|
pickerRoot.remove();
|
||||||
pickerRoot = null;
|
pickerRoot = null;
|
||||||
|
|
||||||
@ -1118,16 +1048,13 @@ const onDialogMessage = function(msg) {
|
|||||||
quitPicker();
|
quitPicker();
|
||||||
break;
|
break;
|
||||||
case 'dialogSetFilter': {
|
case 'dialogSetFilter': {
|
||||||
const resultset = filterToDOMInterface.queryAll(msg);
|
const resultset = filterToDOMInterface.queryAll(msg) || [];
|
||||||
highlightElements(resultset.map(a => a.elem), true);
|
highlightElements(resultset.map(a => a.elem), true);
|
||||||
if ( msg.filter === '!' ) { break; }
|
if ( msg.filter === '!' ) { break; }
|
||||||
vAPI.MessagingConnection.sendTo(epickerConnectionId, {
|
vAPI.MessagingConnection.sendTo(epickerConnectionId, {
|
||||||
what: 'filterResultset',
|
what: 'resultsetDetails',
|
||||||
resultset: resultset.map(a => {
|
count: resultset.length,
|
||||||
const o = Object.assign({}, a);
|
opt: resultset.length !== 0 ? resultset[0].opt : undefined,
|
||||||
o.elem = undefined;
|
|
||||||
return o;
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1250,7 +1177,7 @@ const pickerCSSStyle = [
|
|||||||
].join(' !important;');
|
].join(' !important;');
|
||||||
|
|
||||||
const pickerCSS = `
|
const pickerCSS = `
|
||||||
:root [${vAPI.sessionId}] {
|
:root > [${vAPI.sessionId}] {
|
||||||
${pickerCSSStyle}
|
${pickerCSSStyle}
|
||||||
}
|
}
|
||||||
:root [${vAPI.sessionId}-clickblind] {
|
:root [${vAPI.sessionId}-clickblind] {
|
||||||
@ -1265,11 +1192,6 @@ pickerRoot = document.createElement('iframe');
|
|||||||
pickerRoot.setAttribute(vAPI.sessionId, '');
|
pickerRoot.setAttribute(vAPI.sessionId, '');
|
||||||
document.documentElement.append(pickerRoot);
|
document.documentElement.append(pickerRoot);
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/2060
|
|
||||||
if ( vAPI.domFilterer instanceof Object ) {
|
|
||||||
vAPI.domFilterer.excludeNode(pickerRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
vAPI.shutdown.add(quitPicker);
|
vAPI.shutdown.add(quitPicker);
|
||||||
|
|
||||||
vAPI.MessagingConnection.addListener(onConnectionMessage);
|
vAPI.MessagingConnection.addListener(onConnectionMessage);
|
||||||
|
@ -1177,7 +1177,7 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
]);
|
]);
|
||||||
this.reSimpleSelector = /^[#.][A-Za-z_][\w-]*$/;
|
this.reSimpleSelector = /^[#.][A-Za-z_][\w-]*$/;
|
||||||
this.div = document.createElement('div');
|
this.div = document.createElement('div');
|
||||||
this.rePseudoClass = /:(?::?after|:?before|:-?[a-z][a-z-]*[a-z])$/;
|
this.rePseudoElement = /:(?::?after|:?before|:-?[a-z][a-z-]*[a-z])$/;
|
||||||
this.reProceduralOperator = new RegExp([
|
this.reProceduralOperator = new RegExp([
|
||||||
'^(?:',
|
'^(?:',
|
||||||
Array.from(parser.proceduralOperatorTokens.keys()).join('|'),
|
Array.from(parser.proceduralOperatorTokens.keys()).join('|'),
|
||||||
@ -1296,7 +1296,7 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
// is fixed.
|
// is fixed.
|
||||||
cssSelectorType(s) {
|
cssSelectorType(s) {
|
||||||
if ( this.reSimpleSelector.test(s) ) { return 1; }
|
if ( this.reSimpleSelector.test(s) ) { return 1; }
|
||||||
const pos = this.cssPseudoSelector(s);
|
const pos = this.cssPseudoElement(s);
|
||||||
if ( pos !== -1 ) {
|
if ( pos !== -1 ) {
|
||||||
return this.cssSelectorType(s.slice(0, pos)) === 1 ? 3 : 0;
|
return this.cssSelectorType(s.slice(0, pos)) === 1 ? 3 : 0;
|
||||||
}
|
}
|
||||||
@ -1308,9 +1308,9 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cssPseudoSelector(s) {
|
cssPseudoElement(s) {
|
||||||
if ( s.lastIndexOf(':') === -1 ) { return -1; }
|
if ( s.lastIndexOf(':') === -1 ) { return -1; }
|
||||||
const match = this.rePseudoClass.exec(s);
|
const match = this.rePseudoElement.exec(s);
|
||||||
return match !== null ? match.index : -1;
|
return match !== null ? match.index : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1450,13 +1450,10 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
// The normalized string version is what is reported in the logger,
|
// The normalized string version is what is reported in the logger,
|
||||||
// by design.
|
// by design.
|
||||||
decompileProcedural(compiled) {
|
decompileProcedural(compiled) {
|
||||||
const tasks = compiled.tasks;
|
const tasks = compiled.tasks || [];
|
||||||
if ( Array.isArray(tasks) === false ) {
|
|
||||||
return compiled.selector;
|
|
||||||
}
|
|
||||||
const raw = [ compiled.selector ];
|
const raw = [ compiled.selector ];
|
||||||
let value;
|
|
||||||
for ( const task of tasks ) {
|
for ( const task of tasks ) {
|
||||||
|
let value;
|
||||||
switch ( task[0] ) {
|
switch ( task[0] ) {
|
||||||
case ':has':
|
case ':has':
|
||||||
case ':if':
|
case ':if':
|
||||||
@ -1494,8 +1491,6 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
raw.push(task[1]);
|
raw.push(task[1]);
|
||||||
break;
|
break;
|
||||||
case ':min-text-length':
|
case ':min-text-length':
|
||||||
case ':remove':
|
|
||||||
case ':style':
|
|
||||||
case ':upward':
|
case ':upward':
|
||||||
case ':watch-attr':
|
case ':watch-attr':
|
||||||
case ':xpath':
|
case ':xpath':
|
||||||
@ -1503,6 +1498,10 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( Array.isArray(compiled.action) ) {
|
||||||
|
const [ op, arg ] = compiled.action;
|
||||||
|
raw.push(`${op}(${arg})`);
|
||||||
|
}
|
||||||
return raw.join('');
|
return raw.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1578,10 +1577,12 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
tasks.push([ ':spath', spath ]);
|
tasks.push([ ':spath', spath ]);
|
||||||
}
|
}
|
||||||
if ( action !== undefined ) { return; }
|
if ( action !== undefined ) { return; }
|
||||||
tasks.push([ operator, args ]);
|
const task = [ operator, args ];
|
||||||
if ( this.actionOperators.has(operator) ) {
|
if ( this.actionOperators.has(operator) ) {
|
||||||
if ( root === false ) { return; }
|
if ( root === false ) { return; }
|
||||||
action = operator.slice(1);
|
action = task;
|
||||||
|
} else {
|
||||||
|
tasks.push(task);
|
||||||
}
|
}
|
||||||
opPrefixBeg = i;
|
opPrefixBeg = i;
|
||||||
if ( i === n ) { break; }
|
if ( i === n ) { break; }
|
||||||
@ -1589,7 +1590,7 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
|
|
||||||
// No task found: then we have a CSS selector.
|
// No task found: then we have a CSS selector.
|
||||||
// At least one task found: nothing should be left to parse.
|
// At least one task found: nothing should be left to parse.
|
||||||
if ( tasks.length === 0 ) {
|
if ( tasks.length === 0 && action === undefined ) {
|
||||||
prefix = raw;
|
prefix = raw;
|
||||||
} else if ( opPrefixBeg < n ) {
|
} else if ( opPrefixBeg < n ) {
|
||||||
if ( action !== undefined ) { return; }
|
if ( action !== undefined ) { return; }
|
||||||
@ -1626,21 +1627,17 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Expose action to take in root descriptor.
|
// Expose action to take in root descriptor.
|
||||||
//
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/961
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/382
|
|
||||||
// For the time being, `style` action can't be used in a
|
|
||||||
// procedural selector.
|
|
||||||
if ( action !== undefined ) {
|
if ( action !== undefined ) {
|
||||||
if ( tasks.length > 1 && action === 'style' ) { return; }
|
|
||||||
out.action = action;
|
out.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pseudo-selectors are valid only when used in a root task list.
|
// Pseudo elements are valid only when used in a root task list AND
|
||||||
|
// only when there are no procedural operators: pseudo elements can't
|
||||||
|
// be querySelectorAll-ed.
|
||||||
if ( prefix !== '' ) {
|
if ( prefix !== '' ) {
|
||||||
const pos = this.cssPseudoSelector(prefix);
|
const pos = this.cssPseudoElement(prefix);
|
||||||
if ( pos !== -1 ) {
|
if ( pos !== -1 ) {
|
||||||
if ( root === false ) { return; }
|
if ( root === false || tasks.length !== 0 ) { return; }
|
||||||
out.pseudo = pos;
|
out.pseudo = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user