@@ -36,9 +36,6 @@ const nonVisualElements = {
36
36
37
37
const regexFromString = (s, exact = false) => {
38
38
if ( s === '' ) { return /^/; }
39
-
if ( /^".+"$/.test(s) ) {
40
-
s = s.slice(1,-1).replace(/\\(\\|")/g, '$1');
41
-
}
42
39
const match = /^\/(.+)\/([i]?)$/.exec(s);
43
40
if ( match !== null ) {
44
41
return new RegExp(match[1], match[2] || undefined);
@@ -68,11 +65,7 @@ class PSelectorVoidTask extends PSelectorTask {
68
65
class PSelectorHasTextTask extends PSelectorTask {
69
66
constructor(task) {
70
67
super();
71
-
let arg0 = task[1], arg1;
72
-
if ( Array.isArray(task[1]) ) {
73
-
arg1 = arg0[1]; arg0 = arg0[0];
74
-
}
75
-
this.needle = new RegExp(arg0, arg1);
68
+
this.needle = regexFromString(task[1]);
76
69
}
77
70
transpose(node, output) {
78
71
if ( this.needle.test(node.textContent) ) {
@@ -168,11 +161,7 @@ class PSelectorMatchesMediaTask extends PSelectorTask {
168
161
class PSelectorMatchesPathTask extends PSelectorTask {
169
162
constructor(task) {
170
163
super();
171
-
let arg0 = task[1], arg1;
172
-
if ( Array.isArray(task[1]) ) {
173
-
arg1 = arg0[1]; arg0 = arg0[0];
174
-
}
175
-
this.needle = new RegExp(arg0, arg1);
164
+
this.needle = regexFromString(task[1]);
176
165
}
177
166
transpose(node, output) {
178
167
if ( this.needle.test(self.location.pathname + self.location.search) ) {
@@ -450,13 +439,13 @@ class PSelector {
450
439
PSelector.prototype.operatorToTaskMap = undefined;
451
440
452
441
class PSelectorRoot extends PSelector {
453
-
constructor(o, styleToken) {
442
+
constructor(o) {
454
443
super(o);
455
444
this.budget = 200; // I arbitrary picked a 1/5 second
456
445
this.raw = o.raw;
457
446
this.cost = 0;
458
447
this.lastAllowanceTime = 0;
459
-
this.styleToken = styleToken;
448
+
this.action = o.action;
460
449
}
461
450
prime(input) {
462
451
try {
@@ -486,16 +475,8 @@ class ProceduralFilterer {
486
475
let mustCommit = false;
487
476
for ( const selector of selectors ) {
488
477
if ( this.selectors.has(selector.raw) ) { continue; }
489
-
let style, styleToken;
490
-
if ( selector.action === undefined ) {
491
-
style = vAPI.hideStyle;
492
-
} else if ( selector.action[0] === 'style' ) {
493
-
style = selector.action[1];
494
-
}
495
-
if ( style !== undefined ) {
496
-
styleToken = this.styleTokenFromStyle(style);
497
-
}
498
-
const pselector = new PSelectorRoot(selector, styleToken);
478
+
const pselector = new PSelectorRoot(selector);
479
+
this.primeProceduralSelector(pselector);
499
480
this.selectors.set(selector.raw, pselector);
500
481
addedSelectors.push(pselector);
501
482
mustCommit = true;
@@ -510,13 +491,22 @@ class ProceduralFilterer {
510
491
}
511
492
}
512
493
494
+
// This allows to perform potentially expensive initialization steps
495
+
// before the filters are ready to be applied.
496
+
primeProceduralSelector(pselector) {
497
+
if ( pselector.action === undefined ) {
498
+
this.styleTokenFromStyle(vAPI.hideStyle);
499
+
} else if ( pselector.action[0] === 'style' ) {
500
+
this.styleTokenFromStyle(pselector.action[1]);
501
+
}
502
+
return pselector;
503
+
}
504
+
513
505
commitNow() {
514
506
if ( this.selectors.size === 0 ) { return; }
515
507
516
508
this.mustApplySelectors = false;
517
509
518
-
//console.time('procedural selectors/dom layout changed');
519
-
520
510
// https://github.com/uBlockOrigin/uBlock-issues/issues/341
521
511
// Be ready to unhide nodes which no longer matches any of
522
512
// the procedural selectors.
@@ -543,16 +533,15 @@ class ProceduralFilterer {
543
533
t0 = t1;
544
534
if ( nodes.length === 0 ) { continue; }
545
535
pselector.hit = true;
546
-
this.styleNodes(nodes, pselector.styleToken);
536
+
this.processNodes(nodes, pselector.action);
547
537
}
548
538
549
-
this.unstyleNodes(toUnstyle);
550
-
//console.timeEnd('procedural selectors/dom layout changed');
539
+
this.unprocessNodes(toUnstyle);
551
540
}
552
541
553
542
styleTokenFromStyle(style) {
554
543
if ( style === undefined ) { return; }
555
-
let styleToken = this.styleTokenMap.get(style);
544
+
let styleToken = this.styleTokenMap.get(vAPI.hideStyle);
556
545
if ( styleToken !== undefined ) { return styleToken; }
557
546
styleToken = vAPI.randomToken();
558
547
this.styleTokenMap.set(style, styleToken);
@@ -563,33 +552,70 @@ class ProceduralFilterer {
563
552
return styleToken;
564
553
}
565
554
566
-
styleNodes(nodes, styleToken) {
567
-
if ( styleToken === undefined ) {
555
+
processNodes(nodes, action) {
556
+
const op = action && action[0] || '';
557
+
const arg = op !== '' ? action[1] : '';
558
+
switch ( op ) {
559
+
case '':
560
+
/* fall through */
561
+
case 'style': {
562
+
const styleToken = this.styleTokenFromStyle(
563
+
arg === '' ? vAPI.hideStyle : arg
564
+
);
565
+
for ( const node of nodes ) {
566
+
node.setAttribute(this.masterToken, '');
567
+
node.setAttribute(styleToken, '');
568
+
this.styledNodes.add(node);
569
+
}
570
+
break;
571
+
}
572
+
case 'remove': {
568
573
for ( const node of nodes ) {
569
-
node.textContent = '';
570
574
node.remove();
575
+
node.textContent = '';
571
576
}
572
-
return;
577
+
break;
573
578
}
574
-
for ( const node of nodes ) {
575
-
node.setAttribute(this.masterToken, '');
576
-
node.setAttribute(styleToken, '');
577
-
this.styledNodes.add(node);
579
+
case 'remove-attr': {
580
+
const reAttr = regexFromString(arg, true);
581
+
for ( const node of nodes ) {
582
+
for ( const name of node.getAttributeNames() ) {
583
+
if ( reAttr.test(name) === false ) { continue; }
584
+
node.removeAttribute(name);
585
+
}
586
+
}
587
+
break;
588
+
}
589
+
case 'remove-class': {
590
+
const reClass = regexFromString(arg, true);
591
+
for ( const node of nodes ) {
592
+
const cl = node.classList;
593
+
for ( const name of cl.values() ) {
594
+
if ( reClass.test(name) === false ) { continue; }
595
+
cl.remove(name);
596
+
}
597
+
}
598
+
break;
599
+
}
600
+
default:
601
+
break;
578
602
}
579
603
}
580
604
581
605
// TODO: Current assumption is one style per hit element. Could be an
582
606
// issue if an element has multiple styling and one styling is
583
607
// brought back. Possibly too rare to care about this for now.
584
-
unstyleNodes(nodes) {
608
+
unprocessNodes(nodes) {
585
609
for ( const node of nodes ) {
586
610
if ( this.styledNodes.has(node) ) { continue; }
587
611
node.removeAttribute(this.masterToken);
588
612
}
589
613
}
590
614
591
615
createProceduralFilter(o) {
592
-
return new PSelectorRoot(typeof o === 'string' ? JSON.parse(o) : o);
616
+
return this.primeProceduralSelector(
617
+
new PSelectorRoot(typeof o === 'string' ? JSON.parse(o) : o)
618
+
);
593
619
}
594
620
595
621
onDOMCreated() {
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4