Add support for `nth-ancestor` operator in HTML filtering

Also opportunitisically converted some code to
ES6's `class`.
This commit is contained in:
Raymond Hill 2019-05-11 13:21:23 -04:00
parent d42d86dd12
commit 8a7e704080
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
1 changed files with 134 additions and 109 deletions

View File

@ -42,14 +42,15 @@
}
};
const PSelectorHasTextTask = function(task) {
const PSelectorHasTextTask = class {
constructor(task) {
let arg0 = task[1], arg1;
if ( Array.isArray(task[1]) ) {
arg1 = arg0[1]; arg0 = arg0[0];
}
this.needle = new RegExp(arg0, arg1);
};
PSelectorHasTextTask.prototype.exec = function(input) {
}
exec(input) {
const output = [];
for ( const node of input ) {
if ( this.needle.test(node.textContent) ) {
@ -57,18 +58,14 @@
}
}
return output;
}
};
const PSelectorIfTask = function(task) {
const PSelectorIfTask = class {
constructor(task) {
this.pselector = new PSelector(task[1]);
};
PSelectorIfTask.prototype.target = true;
Object.defineProperty(PSelectorIfTask.prototype, 'invalid', {
get: function() {
return this.pselector.invalid;
}
});
PSelectorIfTask.prototype.exec = function(input) {
exec(input) {
const output = [];
for ( const node of input ) {
if ( this.pselector.test(node) === this.target ) {
@ -76,19 +73,46 @@
}
}
return output;
}
get invalid() {
return this.pselector.invalid;
}
};
PSelectorIfTask.prototype.target = true;
const PSelectorIfNotTask = function(task) {
PSelectorIfTask.call(this, task);
const PSelectorIfNotTask = class extends PSelectorIfTask {
constructor(task) {
super.call(task);
this.target = false;
}
};
PSelectorIfNotTask.prototype = Object.create(PSelectorIfTask.prototype);
PSelectorIfNotTask.prototype.constructor = PSelectorIfNotTask;
const PSelectorXpathTask = function(task) {
this.xpe = task[1];
const PSelectorNthAncestorTask = class {
constructor(task) {
this.nth = task[1];
}
exec(input) {
const output = [];
for ( let node of input ) {
let nth = this.nth;
for (;;) {
node = node.parentElement;
if ( node === null ) { break; }
nth -= 1;
if ( nth !== 0 ) { continue; }
output.push(node);
break;
}
}
return output;
}
};
PSelectorXpathTask.prototype.exec = function(input) {
const PSelectorXpathTask = class {
constructor(task) {
this.xpe = task[1];
}
exec(input) {
const output = [];
const xpe = docRegister.createExpression(this.xpe, null);
let xpr = null;
@ -107,19 +131,11 @@
}
}
return output;
}
};
const PSelector = function(o) {
if ( PSelector.prototype.operatorToTaskMap === undefined ) {
PSelector.prototype.operatorToTaskMap = new Map([
[ ':has', PSelectorIfTask ],
[ ':has-text', PSelectorHasTextTask ],
[ ':if', PSelectorIfTask ],
[ ':if-not', PSelectorIfNotTask ],
[ ':not', PSelectorIfNotTask ],
[ ':xpath', PSelectorXpathTask ]
]);
}
const PSelector = class {
constructor(o) {
this.raw = o.raw;
this.selector = o.selector;
this.tasks = [];
@ -137,17 +153,15 @@
}
this.tasks.push(pselector);
}
};
PSelector.prototype.operatorToTaskMap = undefined;
PSelector.prototype.invalid = false;
PSelector.prototype.prime = function(input) {
}
prime(input) {
const root = input || docRegister;
if ( this.selector !== '' ) {
return root.querySelectorAll(this.selector);
}
return [ root ];
};
PSelector.prototype.exec = function(input) {
}
exec(input) {
if ( this.invalid ) { return []; }
let nodes = this.prime(input);
for ( const task of this.tasks ) {
@ -155,8 +169,8 @@
nodes = task.exec(nodes);
}
return nodes;
};
PSelector.prototype.test = function(input) {
}
test(input) {
if ( this.invalid ) { return false; }
const nodes = this.prime(input);
const AA = [ null ];
@ -170,7 +184,18 @@
if ( aa.length !== 0 ) { return true; }
}
return false;
}
};
PSelector.prototype.operatorToTaskMap = new Map([
[ ':has', PSelectorIfTask ],
[ ':has-text', PSelectorHasTextTask ],
[ ':if', PSelectorIfTask ],
[ ':if-not', PSelectorIfNotTask ],
[ ':not', PSelectorIfNotTask ],
[ ':nth-ancestor', PSelectorNthAncestorTask ],
[ ':xpath', PSelectorXpathTask ]
]);
PSelector.prototype.invalid = false;
const logOne = function(details, exception, selector) {
µBlock.filteringContext