mirror of
https://github.com/gorhill/uBlock.git
synced 2024-10-04 16:47:15 +02:00
fix #3160
This commit is contained in:
parent
6112a68faf
commit
4f7aab695c
@ -32,11 +32,66 @@ if ( typeof vAPI === 'object' ) { // >>>>>>>> start of HUGE-IF-BLOCK
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
vAPI.userStylesheet = {
|
||||||
|
style: null,
|
||||||
|
css: new Map(),
|
||||||
|
disabled: false,
|
||||||
|
apply: function() {
|
||||||
|
},
|
||||||
|
add: function(cssText) {
|
||||||
|
if ( cssText === '' || this.css.has(cssText) ) { return; }
|
||||||
|
if ( this.style === null ) {
|
||||||
|
this.style = document.createElement('style');
|
||||||
|
this.style.disabled = this.disabled;
|
||||||
|
var parent = document.head || document.documentElement;
|
||||||
|
if ( parent !== null ) {
|
||||||
|
parent.appendChild(this.style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sheet = this.style.sheet,
|
||||||
|
i = sheet.cssRules.length;
|
||||||
|
if ( !sheet ) { return; }
|
||||||
|
sheet.insertRule(cssText, i);
|
||||||
|
this.css.set(cssText, sheet.cssRules[i]);
|
||||||
|
},
|
||||||
|
remove: function(cssText) {
|
||||||
|
if ( cssText === '' ) { return; }
|
||||||
|
var cssRule = this.css.get(cssText);
|
||||||
|
if ( cssRule === undefined ) { return; }
|
||||||
|
this.css.delete(cssText);
|
||||||
|
if ( this.style === null ) { return; }
|
||||||
|
var rules = this.style.sheet.cssRules,
|
||||||
|
i = rules.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
if ( rules[i] !== cssRule ) { continue; }
|
||||||
|
this.style.sheet.deleteRule(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( rules.length === 0 ) {
|
||||||
|
var parent = this.style.parentNode;
|
||||||
|
if ( parent !== null ) {
|
||||||
|
parent.removeChild(this.style);
|
||||||
|
}
|
||||||
|
this.style = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggle: function(state) {
|
||||||
|
if ( state === undefined ) { state = this.disabled; }
|
||||||
|
if ( state !== this.disabled ) { return; }
|
||||||
|
this.disabled = !state;
|
||||||
|
if ( this.style !== null ) {
|
||||||
|
this.style.disabled = this.disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.DOMFilterer = function() {
|
vAPI.DOMFilterer = function() {
|
||||||
this.commitTimer = new vAPI.SafeAnimationFrame(this.commitNow.bind(this));
|
this.commitTimer = new vAPI.SafeAnimationFrame(this.commitNow.bind(this));
|
||||||
this.domIsReady = document.readyState !== 'loading';
|
this.domIsReady = document.readyState !== 'loading';
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
this.hideNodeId = vAPI.randomToken();
|
this.hideNodeAttr = vAPI.randomToken();
|
||||||
this.hideNodeStylesheet = false;
|
this.hideNodeStylesheet = false;
|
||||||
this.excludedNodeSet = new WeakSet();
|
this.excludedNodeSet = new WeakSet();
|
||||||
this.addedNodes = new Set();
|
this.addedNodes = new Set();
|
||||||
@ -48,73 +103,10 @@ vAPI.DOMFilterer = function() {
|
|||||||
this.specificComplexHide = new Set();
|
this.specificComplexHide = new Set();
|
||||||
this.specificComplexHideAggregated = undefined;
|
this.specificComplexHideAggregated = undefined;
|
||||||
this.addedSpecificComplexHide = [];
|
this.addedSpecificComplexHide = [];
|
||||||
|
this.specificOthers = [];
|
||||||
this.genericSimpleHide = new Set();
|
this.genericSimpleHide = new Set();
|
||||||
this.genericComplexHide = new Set();
|
this.genericComplexHide = new Set();
|
||||||
|
|
||||||
this.userStylesheet = {
|
|
||||||
style: null,
|
|
||||||
css: new Map(),
|
|
||||||
disabled: false,
|
|
||||||
add: function(cssText) {
|
|
||||||
if ( cssText === '' || this.css.has(cssText) ) { return; }
|
|
||||||
if ( this.style === null ) {
|
|
||||||
this.style = document.createElement('style');
|
|
||||||
this.style.disabled = this.disabled;
|
|
||||||
var parent = document.head || document.documentElement;
|
|
||||||
if ( parent !== null ) {
|
|
||||||
parent.appendChild(this.style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var sheet = this.style.sheet,
|
|
||||||
i = sheet.cssRules.length;
|
|
||||||
if ( !sheet ) { return; }
|
|
||||||
sheet.insertRule(cssText, i);
|
|
||||||
this.css.set(cssText, sheet.cssRules[i]);
|
|
||||||
},
|
|
||||||
remove: function(cssText) {
|
|
||||||
if ( cssText === '' ) { return; }
|
|
||||||
var cssRule = this.css.get(cssText);
|
|
||||||
if ( cssRule === undefined ) { return; }
|
|
||||||
this.css.delete(cssText);
|
|
||||||
if ( this.style === null ) { return; }
|
|
||||||
var rules = this.style.sheet.cssRules,
|
|
||||||
i = rules.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
if ( rules[i] !== cssRule ) { continue; }
|
|
||||||
this.style.sheet.deleteRule(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ( rules.length === 0 ) {
|
|
||||||
var parent = this.style.parentNode;
|
|
||||||
if ( parent !== null ) {
|
|
||||||
parent.removeChild(this.style);
|
|
||||||
}
|
|
||||||
this.style = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggle: function(state) {
|
|
||||||
if ( state === undefined ) { state = this.disabled; }
|
|
||||||
if ( state !== this.disabled ) { return; }
|
|
||||||
this.disabled = !state;
|
|
||||||
if ( this.style !== null ) {
|
|
||||||
this.style.disabled = this.disabled;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getAllSelectors: function() {
|
|
||||||
var out = [];
|
|
||||||
var rules = this.style &&
|
|
||||||
this.style.sheet &&
|
|
||||||
this.style.sheet.cssRules;
|
|
||||||
if ( rules instanceof Object === false ) { return out; }
|
|
||||||
var i = rules.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
out.push(rules.item(i).selectorText);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.hideNodeExpando = undefined;
|
this.hideNodeExpando = undefined;
|
||||||
this.hideNodeBatchProcessTimer = undefined;
|
this.hideNodeBatchProcessTimer = undefined;
|
||||||
this.hiddenNodeObserver = undefined;
|
this.hiddenNodeObserver = undefined;
|
||||||
@ -135,7 +127,7 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
commitNow: function() {
|
commitNow: function() {
|
||||||
this.commitTimer.clear();
|
this.commitTimer.clear();
|
||||||
|
|
||||||
if ( this.domIsReady !== true || this.userStylesheet.disabled ) {
|
if ( this.domIsReady !== true || vAPI.userStylesheet.disabled ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,28 +219,31 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
|
|
||||||
if ( details === undefined ) { details = {}; }
|
if ( details === undefined ) { details = {}; }
|
||||||
|
|
||||||
var isGeneric= details.lazy === true,
|
|
||||||
isSimple = details.type === 'simple',
|
|
||||||
isComplex = details.type === 'complex',
|
|
||||||
selector;
|
|
||||||
|
|
||||||
var selectorsStr = Array.isArray(selectors) ?
|
var selectorsStr = Array.isArray(selectors) ?
|
||||||
selectors.join(',\n') :
|
selectors.join(',\n') :
|
||||||
selectors;
|
selectors;
|
||||||
if ( selectorsStr.length === 0 ) { return; }
|
if ( selectorsStr.length === 0 ) { return; }
|
||||||
|
|
||||||
this.userStylesheet.add(
|
vAPI.userStylesheet.add(selectorsStr + '\n{ ' + declarations + ' }');
|
||||||
selectorsStr +
|
|
||||||
'\n{ ' + declarations + ' }'
|
|
||||||
);
|
|
||||||
this.commit();
|
this.commit();
|
||||||
|
|
||||||
this.triggerListeners('declarative', selectorsStr);
|
this.triggerListeners('declarative', selectorsStr);
|
||||||
|
|
||||||
if ( this.reHideStyle.test(declarations) === false ) {
|
if ( this.reHideStyle.test(declarations) === false ) {
|
||||||
|
this.specificOthers.push({
|
||||||
|
selectors: selectorsStr,
|
||||||
|
declarations: declarations
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do not strongly enforce internal CSS rules.
|
||||||
|
if ( details.internal ) { return; }
|
||||||
|
|
||||||
|
var isGeneric= details.lazy === true,
|
||||||
|
isSimple = details.type === 'simple',
|
||||||
|
isComplex = details.type === 'complex',
|
||||||
|
selector;
|
||||||
|
|
||||||
if ( isGeneric ) {
|
if ( isGeneric ) {
|
||||||
if ( isSimple ) {
|
if ( isSimple ) {
|
||||||
this.genericSimpleHide.add(selectorsStr);
|
this.genericSimpleHide.add(selectorsStr);
|
||||||
@ -292,31 +287,6 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
removeCSSRule: function(selectors, declarations) {
|
|
||||||
var selectorsStr = Array.isArray(selectors)
|
|
||||||
? selectors.join(',\n')
|
|
||||||
: selectors;
|
|
||||||
if ( selectorsStr.length === 0 ) { return; }
|
|
||||||
this.userStylesheet.remove(
|
|
||||||
selectorsStr +
|
|
||||||
'\n{ ' + declarations + ' }'
|
|
||||||
);
|
|
||||||
if ( this.reHideStyle.test(declarations) === false ) { return; }
|
|
||||||
var selectorsArr = Array.isArray(selectors) ?
|
|
||||||
selectors :
|
|
||||||
selectors.split(',\n');
|
|
||||||
for ( var selector of selectorsArr ) {
|
|
||||||
if ( this.reCSSCombinators.test(selector) ) {
|
|
||||||
this.specificComplexHide.remove(selector);
|
|
||||||
this.genericComplexHide.remove(selector);
|
|
||||||
} else {
|
|
||||||
this.specificSimpleHide.remove(selector);
|
|
||||||
this.genericSimpleHide.remove(selector);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.commit();
|
|
||||||
},
|
|
||||||
|
|
||||||
onDOMCreated: function() {
|
onDOMCreated: function() {
|
||||||
this.domIsReady = true;
|
this.domIsReady = true;
|
||||||
this.addedNodes.clear();
|
this.addedNodes.clear();
|
||||||
@ -391,7 +361,7 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
hideNodeObserverHandler: function(mutations) {
|
hideNodeObserverHandler: function(mutations) {
|
||||||
if ( this.userStylesheet.disabled ) { return; }
|
if ( vAPI.userStylesheet.disabled ) { return; }
|
||||||
var i = mutations.length,
|
var i = mutations.length,
|
||||||
stagedNodes = this.hiddenNodesetToProcess;
|
stagedNodes = this.hiddenNodesetToProcess;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
@ -413,8 +383,8 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
new MutationObserver(this.hideNodeObserverHandler.bind(this));
|
new MutationObserver(this.hideNodeObserverHandler.bind(this));
|
||||||
if ( this.hideNodeStylesheet === false ) {
|
if ( this.hideNodeStylesheet === false ) {
|
||||||
this.hideNodeStylesheet = true;
|
this.hideNodeStylesheet = true;
|
||||||
this.userStylesheet.add(
|
vAPI.userStylesheet.add(
|
||||||
'[' + this.hideNodeId + ']\n{ display: none !important; }'
|
'[' + this.hideNodeAttr + ']\n{ display: none !important; }'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -424,12 +394,16 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
this.unhideNode(node);
|
this.unhideNode(node);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
unexcludeNode: function(node) {
|
||||||
|
this.excludedNodeSet.delete(node);
|
||||||
|
},
|
||||||
|
|
||||||
hideNode: function(node) {
|
hideNode: function(node) {
|
||||||
if ( this.excludedNodeSet.has(node) ) { return; }
|
if ( this.excludedNodeSet.has(node) ) { return; }
|
||||||
if ( this.hiddenNodeset.has(node) ) { return; }
|
if ( this.hiddenNodeset.has(node) ) { return; }
|
||||||
this.hiddenNodeset.add(node);
|
this.hiddenNodeset.add(node);
|
||||||
if ( this.hideNodeExpando === undefined ) { this.hideNodeInit(); }
|
if ( this.hideNodeExpando === undefined ) { this.hideNodeInit(); }
|
||||||
node.setAttribute(this.hideNodeId, '');
|
node.setAttribute(this.hideNodeAttr, '');
|
||||||
if ( node[this.hideNodeExpando] === undefined ) {
|
if ( node[this.hideNodeExpando] === undefined ) {
|
||||||
node[this.hideNodeExpando] =
|
node[this.hideNodeExpando] =
|
||||||
node.hasAttribute('style') &&
|
node.hasAttribute('style') &&
|
||||||
@ -442,7 +416,7 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
|
|
||||||
unhideNode: function(node) {
|
unhideNode: function(node) {
|
||||||
if ( this.hiddenNodeset.has(node) === false ) { return; }
|
if ( this.hiddenNodeset.has(node) === false ) { return; }
|
||||||
node.removeAttribute(this.hideNodeId);
|
node.removeAttribute(this.hideNodeAttr);
|
||||||
this.hiddenNodesetToProcess.delete(node);
|
this.hiddenNodesetToProcess.delete(node);
|
||||||
if ( this.hideNodeExpando === undefined ) { return; }
|
if ( this.hideNodeExpando === undefined ) { return; }
|
||||||
var attr = node[this.hideNodeExpando];
|
var attr = node[this.hideNodeExpando];
|
||||||
@ -469,9 +443,9 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
toggle: function(state) {
|
toggle: function(state) {
|
||||||
this.userStylesheet.toggle(state);
|
vAPI.userStylesheet.toggle(state);
|
||||||
var disabled = this.userStylesheet.disabled,
|
var disabled = vAPI.userStylesheet.disabled,
|
||||||
nodes = document.querySelectorAll('[' + this.hideNodeId + ']');
|
nodes = document.querySelectorAll('[' + this.hideNodeAttr + ']');
|
||||||
for ( var node of nodes ) {
|
for ( var node of nodes ) {
|
||||||
if ( disabled ) {
|
if ( disabled ) {
|
||||||
this.showNode(node);
|
this.showNode(node);
|
||||||
@ -484,19 +458,37 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getAllDeclarativeSelectors_: function(all) {
|
||||||
|
var out = [];
|
||||||
|
if ( this.specificSimpleHide.size !== 0 ) {
|
||||||
|
out.push(Array.from(this.specificSimpleHide).join(',\n'));
|
||||||
|
}
|
||||||
|
if ( this.specificComplexHide.size !== 0 ) {
|
||||||
|
out.push(Array.from(this.specificComplexHide).join(',\n'));
|
||||||
|
}
|
||||||
|
if ( this.genericSimpleHide.size !== 0 ) {
|
||||||
|
out.push(Array.from(this.genericSimpleHide).join(',\n'));
|
||||||
|
}
|
||||||
|
if ( this.genericComplexHide.size !== 0 ) {
|
||||||
|
out.push(Array.from(this.genericComplexHide).join(',\n'));
|
||||||
|
}
|
||||||
|
if ( all ) {
|
||||||
|
out.push('[' + this.hideNodeAttr + ']');
|
||||||
|
}
|
||||||
|
for ( var entry of this.specificOthers ) {
|
||||||
|
out.push(entry.selectors);
|
||||||
|
}
|
||||||
|
return out.join(',\n');
|
||||||
|
},
|
||||||
|
|
||||||
getFilteredElementCount: function() {
|
getFilteredElementCount: function() {
|
||||||
return document.querySelectorAll(
|
var selectors = this.getAllDeclarativeSelectors_(true);
|
||||||
this.userStylesheet.getAllSelectors().join(',\n')
|
if ( selectors.length === 0 ) { return 0; }
|
||||||
).length;
|
return document.querySelectorAll(selectors).length;
|
||||||
},
|
},
|
||||||
|
|
||||||
getAllDeclarativeSelectors: function() {
|
getAllDeclarativeSelectors: function() {
|
||||||
return [].concat(
|
return this.getAllDeclarativeSelectors_();
|
||||||
Array.from(this.specificSimpleHide),
|
|
||||||
Array.from(this.specificComplexHide),
|
|
||||||
Array.from(this.genericSimpleHide),
|
|
||||||
Array.from(this.genericComplexHide)
|
|
||||||
).join(',\n');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,75 +28,43 @@ if ( typeof vAPI === 'object' ) { // >>>>>>>> start of HUGE-IF-BLOCK
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
vAPI.userStylesheet = {
|
||||||
|
added: new Set(),
|
||||||
|
removed: new Set(),
|
||||||
|
apply: function() {
|
||||||
|
if ( this.added.size === 0 && this.removed.size === 0 ) { return; }
|
||||||
|
vAPI.messaging.send('vapi-background', {
|
||||||
|
what: 'userCSS',
|
||||||
|
add: Array.from(this.added),
|
||||||
|
remove: Array.from(this.removed)
|
||||||
|
});
|
||||||
|
this.added.clear();
|
||||||
|
this.removed.clear();
|
||||||
|
},
|
||||||
|
add: function(cssText, now) {
|
||||||
|
if ( cssText === '' ) { return; }
|
||||||
|
this.added.add(cssText);
|
||||||
|
if ( now ) { this.apply(); }
|
||||||
|
},
|
||||||
|
remove: function(cssText, now) {
|
||||||
|
if ( cssText === '' ) { return; }
|
||||||
|
this.removed.add(cssText);
|
||||||
|
if ( now ) { this.apply(); }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.DOMFilterer = function() {
|
vAPI.DOMFilterer = function() {
|
||||||
this.commitTimer = new vAPI.SafeAnimationFrame(this.commitNow.bind(this));
|
this.commitTimer = new vAPI.SafeAnimationFrame(this.commitNow.bind(this));
|
||||||
this.domIsReady = document.readyState !== 'loading';
|
this.domIsReady = document.readyState !== 'loading';
|
||||||
|
this.disabled = false;
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
|
this.filterset = new Set();
|
||||||
this.hideNodeId = vAPI.randomToken();
|
this.hideNodeId = vAPI.randomToken();
|
||||||
this.hideNodeStylesheet = false;
|
this.hideNodeStylesheet = false;
|
||||||
this.excludedNodeSet = new WeakSet();
|
this.excludedNodeSet = new WeakSet();
|
||||||
this.addedCSSRules = [];
|
this.addedCSSRules = new Set();
|
||||||
this.removedCSSRules = [];
|
|
||||||
this.internalRules = new Set();
|
|
||||||
|
|
||||||
this.userStylesheets = {
|
|
||||||
current: new Set(),
|
|
||||||
added: new Set(),
|
|
||||||
removed: new Set(),
|
|
||||||
disabled: false,
|
|
||||||
apply: function() {
|
|
||||||
for ( let cssText of this.added ) {
|
|
||||||
if ( this.current.has(cssText) || this.removed.has(cssText) ) {
|
|
||||||
this.added.delete(cssText);
|
|
||||||
} else {
|
|
||||||
this.current.add(cssText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for ( let cssText of this.removed ) {
|
|
||||||
if ( this.current.has(cssText) === false ) {
|
|
||||||
this.removed.delete(cssText);
|
|
||||||
} else {
|
|
||||||
this.current.delete(cssText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( this.added.size === 0 && this.removed.size === 0 ) { return; }
|
|
||||||
if ( this.disabled === false ) {
|
|
||||||
vAPI.messaging.send('vapi-background', {
|
|
||||||
what: 'userCSS',
|
|
||||||
add: Array.from(this.added),
|
|
||||||
remove: Array.from(this.removed)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.added.clear();
|
|
||||||
this.removed.clear();
|
|
||||||
},
|
|
||||||
add: function(cssText) {
|
|
||||||
if ( cssText === '' ) { return; }
|
|
||||||
this.added.add(cssText);
|
|
||||||
},
|
|
||||||
remove: function(cssText) {
|
|
||||||
if ( cssText === '' ) { return; }
|
|
||||||
this.removed.add(cssText);
|
|
||||||
},
|
|
||||||
toggle: function(state) {
|
|
||||||
if ( state === undefined ) { state = this.disabled; }
|
|
||||||
if ( state !== this.disabled ) { return; }
|
|
||||||
this.disabled = !state;
|
|
||||||
if ( this.current.size === 0 ) { return; }
|
|
||||||
var all = Array.from(this.current);
|
|
||||||
var toAdd = [], toRemove = [];
|
|
||||||
if ( this.disabled ) {
|
|
||||||
toRemove = all;
|
|
||||||
} else {
|
|
||||||
toAdd = all;
|
|
||||||
}
|
|
||||||
vAPI.messaging.send('vapi-background', {
|
|
||||||
what: 'userCSS',
|
|
||||||
add: toAdd,
|
|
||||||
remove: toRemove
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( this.domIsReady !== true ) {
|
if ( this.domIsReady !== true ) {
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
@ -108,30 +76,27 @@ vAPI.DOMFilterer = function() {
|
|||||||
|
|
||||||
vAPI.DOMFilterer.prototype = {
|
vAPI.DOMFilterer.prototype = {
|
||||||
reOnlySelectors: /\n\{[^\n]+/g,
|
reOnlySelectors: /\n\{[^\n]+/g,
|
||||||
|
|
||||||
|
// Here we will deal with:
|
||||||
|
// - Injecting low priority user styles;
|
||||||
|
// - Notifying listeners about changed filterset.
|
||||||
commitNow: function() {
|
commitNow: function() {
|
||||||
this.commitTimer.clear();
|
this.commitTimer.clear();
|
||||||
var i, entry, ruleText;
|
var userStylesheet = vAPI.userStylesheet,
|
||||||
i = this.addedCSSRules.length;
|
addedSelectors = [];
|
||||||
while ( i-- ) {
|
for ( var entry of this.addedCSSRules ) {
|
||||||
entry = this.addedCSSRules[i];
|
if ( this.disabled === false && entry.lazy ) {
|
||||||
if ( entry.lazy !== true || this.domIsReady ) {
|
userStylesheet.add(
|
||||||
ruleText = entry.selectors + '\n{ ' + entry.declarations + ' }';
|
entry.selectors + '\n{' + entry.declarations + '}'
|
||||||
this.userStylesheets.add(ruleText);
|
);
|
||||||
this.addedCSSRules.splice(i, 1);
|
|
||||||
if ( entry.internal ) {
|
|
||||||
this.internalRules.add(ruleText);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
addedSelectors.push(entry.selectors);
|
||||||
}
|
}
|
||||||
i = this.removedCSSRules.length;
|
this.addedCSSRules.clear();
|
||||||
while ( i-- ) {
|
userStylesheet.apply();
|
||||||
entry = this.removedCSSRules[i];
|
if ( addedSelectors.length !== 0 ) {
|
||||||
ruleText = entry.selectors + '\n{ ' + entry.declarations + ' }';
|
this.triggerListeners('declarative', addedSelectors.join(',\n'));
|
||||||
this.userStylesheets.remove(ruleText);
|
|
||||||
this.internalRules.delete(ruleText);
|
|
||||||
}
|
}
|
||||||
this.removedCSSRules = [];
|
|
||||||
this.userStylesheets.apply();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
commit: function(commitNow) {
|
commit: function(commitNow) {
|
||||||
@ -149,25 +114,17 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
? selectors.join(',\n')
|
? selectors.join(',\n')
|
||||||
: selectors;
|
: selectors;
|
||||||
if ( selectorsStr.length === 0 ) { return; }
|
if ( selectorsStr.length === 0 ) { return; }
|
||||||
this.addedCSSRules.push({
|
var entry = {
|
||||||
selectors: selectorsStr,
|
selectors: selectorsStr,
|
||||||
declarations,
|
declarations,
|
||||||
lazy: details && details.lazy === true,
|
lazy: details !== undefined && details.lazy === true,
|
||||||
internal: details && details.internal === true
|
internal: details && details.internal === true
|
||||||
});
|
};
|
||||||
this.commit();
|
this.addedCSSRules.add(entry);
|
||||||
this.triggerListeners('declarative', selectorsStr);
|
this.filterset.add(entry);
|
||||||
},
|
if ( this.disabled === false && entry.lazy !== true ) {
|
||||||
|
vAPI.userStylesheet.add(selectorsStr + '\n{' + declarations + '}');
|
||||||
removeCSSRule: function(selectors, declarations) {
|
}
|
||||||
var selectorsStr = Array.isArray(selectors)
|
|
||||||
? selectors.join(',\n')
|
|
||||||
: selectors;
|
|
||||||
if ( selectorsStr.length === 0 ) { return; }
|
|
||||||
this.removedCSSRules.push({
|
|
||||||
selectors: selectorsStr,
|
|
||||||
declarations,
|
|
||||||
});
|
|
||||||
this.commit();
|
this.commit();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -194,6 +151,10 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
this.unhideNode(node);
|
this.unhideNode(node);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
unexcludeNode: function(node) {
|
||||||
|
this.excludedNodeSet.delete(node);
|
||||||
|
},
|
||||||
|
|
||||||
hideNode: function(node) {
|
hideNode: function(node) {
|
||||||
if ( this.excludedNodeSet.has(node) ) { return; }
|
if ( this.excludedNodeSet.has(node) ) { return; }
|
||||||
node.setAttribute(this.hideNodeId, '');
|
node.setAttribute(this.hideNodeId, '');
|
||||||
@ -212,16 +173,26 @@ vAPI.DOMFilterer.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
toggle: function(state) {
|
toggle: function(state) {
|
||||||
this.userStylesheets.toggle(state);
|
if ( state === undefined ) { state = this.disabled; }
|
||||||
|
if ( state !== this.disabled ) { return; }
|
||||||
|
this.disabled = !state;
|
||||||
|
var userStylesheet = vAPI.userStylesheet;
|
||||||
|
for ( var entry of this.filterset ) {
|
||||||
|
var rule = entry.selectors + '\n{' + entry.declarations + '}';
|
||||||
|
if ( this.disabled ) {
|
||||||
|
userStylesheet.remove(rule);
|
||||||
|
} else {
|
||||||
|
userStylesheet.add(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userStylesheet.apply();
|
||||||
},
|
},
|
||||||
|
|
||||||
getAllDeclarativeSelectors_: function(all) {
|
getAllDeclarativeSelectors_: function(all) {
|
||||||
let selectors = [];
|
let selectors = [];
|
||||||
for ( var sheet of this.userStylesheets.current ) {
|
for ( var entry of this.filterset ) {
|
||||||
if ( all === false && this.internalRules.has(sheet) ) { continue; }
|
if ( all === false && entry.internal ) { continue; }
|
||||||
selectors.push(
|
selectors.push(entry.selectors);
|
||||||
sheet.replace(this.reOnlySelectors, ',').trim().slice(0, -1)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return selectors.join(',\n');
|
return selectors.join(',\n');
|
||||||
},
|
},
|
||||||
|
@ -774,7 +774,7 @@ vAPI.domCollapser = (function() {
|
|||||||
iframeLoadEventPatch(target);
|
iframeLoadEventPatch(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if ( selectors.length !== 0 ) {
|
if ( selectors.length !== 0 ) {
|
||||||
messaging.send(
|
messaging.send(
|
||||||
'contentscript',
|
'contentscript',
|
||||||
@ -786,7 +786,6 @@ vAPI.domCollapser = (function() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var send = function() {
|
var send = function() {
|
||||||
@ -1292,25 +1291,21 @@ vAPI.domSurveyor = (function() {
|
|||||||
domFilterer.addProceduralSelectors(cfeDetails.proceduralFilters);
|
domFilterer.addProceduralSelectors(cfeDetails.proceduralFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( cfeDetails.netFilters.length !== 0 ) {
|
||||||
|
vAPI.userStylesheet.add(
|
||||||
|
cfeDetails.netFilters + '\n{ display: none !important; }');
|
||||||
|
}
|
||||||
|
|
||||||
|
vAPI.userStylesheet.apply();
|
||||||
|
|
||||||
var parent = document.head || document.documentElement;
|
var parent = document.head || document.documentElement;
|
||||||
if ( parent ) {
|
if ( parent ) {
|
||||||
var elem, text;
|
|
||||||
if ( cfeDetails.netHide.length !== 0 ) {
|
|
||||||
elem = document.createElement('style');
|
|
||||||
elem.setAttribute('type', 'text/css');
|
|
||||||
text = cfeDetails.netHide.join(',\n');
|
|
||||||
text += response.collapseBlocked ?
|
|
||||||
'\n{ display:none !important; }' :
|
|
||||||
'\n{ visibility:hidden !important; }';
|
|
||||||
elem.appendChild(document.createTextNode(text));
|
|
||||||
parent.appendChild(elem);
|
|
||||||
}
|
|
||||||
// Library of resources is located at:
|
// Library of resources is located at:
|
||||||
// https://github.com/gorhill/uBlock/blob/master/assets/ublock/resources.txt
|
// https://github.com/gorhill/uBlock/blob/master/assets/ublock/resources.txt
|
||||||
if ( cfeDetails.scripts ) {
|
if ( cfeDetails.scripts ) {
|
||||||
// Have the injected script tag remove itself when execution completes:
|
// Have the injected script tag remove itself when execution completes:
|
||||||
// to keep DOM as clean as possible.
|
// to keep DOM as clean as possible.
|
||||||
text = cfeDetails.scripts +
|
var text = cfeDetails.scripts +
|
||||||
"\n" +
|
"\n" +
|
||||||
"(function() {\n" +
|
"(function() {\n" +
|
||||||
" var c = document.currentScript,\n" +
|
" var c = document.currentScript,\n" +
|
||||||
|
@ -408,7 +408,7 @@ SelectorCacheEntry.factory = function() {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// var netSelectorCacheLowWaterMark = 20;
|
var netSelectorCacheLowWaterMark = 20;
|
||||||
var netSelectorCacheHighWaterMark = 30;
|
var netSelectorCacheHighWaterMark = 30;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -451,8 +451,7 @@ SelectorCacheEntry.prototype.addCosmetic = function(details) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
SelectorCacheEntry.prototype.addNet = function(/* selectors */) {
|
SelectorCacheEntry.prototype.addNet = function(selectors) {
|
||||||
/*
|
|
||||||
if ( typeof selectors === 'string' ) {
|
if ( typeof selectors === 'string' ) {
|
||||||
this.addNetOne(selectors, Date.now());
|
this.addNetOne(selectors, Date.now());
|
||||||
} else {
|
} else {
|
||||||
@ -470,7 +469,6 @@ SelectorCacheEntry.prototype.addNet = function(/* selectors */) {
|
|||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
dict.delete(keys[i]);
|
dict.delete(keys[i]);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -515,11 +513,25 @@ SelectorCacheEntry.prototype.remove = function(type) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
SelectorCacheEntry.prototype.retrieveToArray = function(iterator, out) {
|
||||||
|
for ( var selector of iterator ) {
|
||||||
|
out.push(selector);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectorCacheEntry.prototype.retrieveToSet = function(iterator, out) {
|
||||||
|
for ( var selector of iterator ) {
|
||||||
|
out.add(selector);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
SelectorCacheEntry.prototype.retrieve = function(type, out) {
|
SelectorCacheEntry.prototype.retrieve = function(type, out) {
|
||||||
this.lastAccessTime = Date.now();
|
this.lastAccessTime = Date.now();
|
||||||
var dict = type === 'cosmetic' ? this.cosmetic : this.net;
|
var iterator = type === 'cosmetic' ? this.cosmetic : this.net.keys();
|
||||||
for ( var selector of dict ) {
|
if ( Array.isArray(out) ) {
|
||||||
out.add(selector);
|
this.retrieveToArray(iterator, out);
|
||||||
|
} else {
|
||||||
|
this.retrieveToSet(iterator, out);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1964,7 +1976,8 @@ FilterContainer.prototype.retrieveDomainSelectors = function(
|
|||||||
var hostname = this.µburi.hostnameFromURI(request.locationURL),
|
var hostname = this.µburi.hostnameFromURI(request.locationURL),
|
||||||
domain = this.µburi.domainFromHostname(hostname) || hostname,
|
domain = this.µburi.domainFromHostname(hostname) || hostname,
|
||||||
pos = domain.indexOf('.'),
|
pos = domain.indexOf('.'),
|
||||||
entity = pos === -1 ? '' : domain.slice(0, pos - domain.length) + '.*';
|
entity = pos === -1 ? '' : domain.slice(0, pos - domain.length) + '.*',
|
||||||
|
cacheEntry = this.selectorCache.get(hostname);
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/587
|
// https://github.com/chrisaljoudi/uBlock/issues/587
|
||||||
// r.ready will tell the content script the cosmetic filtering engine is
|
// r.ready will tell the content script the cosmetic filtering engine is
|
||||||
@ -1982,9 +1995,10 @@ FilterContainer.prototype.retrieveDomainSelectors = function(
|
|||||||
exceptionFilters: [],
|
exceptionFilters: [],
|
||||||
highGenericSimple: '',
|
highGenericSimple: '',
|
||||||
highGenericComplex: '',
|
highGenericComplex: '',
|
||||||
netHide: [],
|
netFilters: '',
|
||||||
proceduralFilters: [],
|
proceduralFilters: [],
|
||||||
scripts: undefined
|
scripts: undefined,
|
||||||
|
cssRulesInjected: false
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( options.noCosmeticFiltering !== true ) {
|
if ( options.noCosmeticFiltering !== true ) {
|
||||||
@ -2038,7 +2052,6 @@ FilterContainer.prototype.retrieveDomainSelectors = function(
|
|||||||
bucket.retrieve(hostname, specificSet);
|
bucket.retrieve(hostname, specificSet);
|
||||||
}
|
}
|
||||||
// Cached cosmetic filters: these are always declarative.
|
// Cached cosmetic filters: these are always declarative.
|
||||||
var cacheEntry = this.selectorCache.get(hostname);
|
|
||||||
if ( cacheEntry !== undefined ) {
|
if ( cacheEntry !== undefined ) {
|
||||||
cacheEntry.retrieve('cosmetic', specificSet);
|
cacheEntry.retrieve('cosmetic', specificSet);
|
||||||
if ( r.noDOMSurveying === false ) {
|
if ( r.noDOMSurveying === false ) {
|
||||||
@ -2107,13 +2120,11 @@ FilterContainer.prototype.retrieveDomainSelectors = function(
|
|||||||
// Scriptlet injection.
|
// Scriptlet injection.
|
||||||
r.scripts = this.retrieveUserScripts(domain, hostname);
|
r.scripts = this.retrieveUserScripts(domain, hostname);
|
||||||
|
|
||||||
// TODO: Is it *really* worth to cache selectors of collapsed resources?
|
if ( cacheEntry ) {
|
||||||
// This adds code complexity and I am having doubts about the
|
var netFilters = [];
|
||||||
// benefits. Investigate.
|
cacheEntry.retrieve('net', netFilters);
|
||||||
// Collapsible blocked resources.
|
r.netFilters = netFilters.join(',\n');
|
||||||
//if ( cacheEntry ) {
|
}
|
||||||
// cacheEntry.retrieve('net', r.netHide);
|
|
||||||
//}
|
|
||||||
|
|
||||||
console.timeEnd('cosmeticFilteringEngine.retrieveDomainSelectors');
|
console.timeEnd('cosmeticFilteringEngine.retrieveDomainSelectors');
|
||||||
|
|
||||||
|
@ -1400,9 +1400,11 @@ var stopPicker = function() {
|
|||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/2060
|
// https://github.com/gorhill/uBlock/issues/2060
|
||||||
if ( vAPI.domFilterer instanceof Object ) {
|
if ( vAPI.domFilterer instanceof Object ) {
|
||||||
vAPI.domFilterer.removeCSSRule(pickerCSSSelector1, pickerCSSDeclaration1);
|
vAPI.userStylesheet.remove(pickerCSS1);
|
||||||
vAPI.domFilterer.removeCSSRule(pickerCSSSelector2, pickerCSSDeclaration2);
|
vAPI.userStylesheet.remove(pickerCSS2);
|
||||||
|
vAPI.userStylesheet.apply();
|
||||||
}
|
}
|
||||||
|
vAPI.domFilterer.unexcludeNode(pickerRoot);
|
||||||
|
|
||||||
window.removeEventListener('scroll', onScrolled, true);
|
window.removeEventListener('scroll', onScrolled, true);
|
||||||
pickerRoot.contentWindow.removeEventListener('keydown', onKeyPressed, true);
|
pickerRoot.contentWindow.removeEventListener('keydown', onKeyPressed, true);
|
||||||
@ -1546,47 +1548,46 @@ var bootstrapPicker = function() {
|
|||||||
pickerRoot = document.createElement('iframe');
|
pickerRoot = document.createElement('iframe');
|
||||||
pickerRoot.id = vAPI.sessionId;
|
pickerRoot.id = vAPI.sessionId;
|
||||||
|
|
||||||
var pickerCSSSelector1 = '#' + pickerRoot.id;
|
var pickerCSSStyle = [
|
||||||
var pickerCSSDeclaration1 = [
|
'background: transparent',
|
||||||
'background: transparent',
|
'border: 0',
|
||||||
'border: 0',
|
'border-radius: 0',
|
||||||
'border-radius: 0',
|
'box-shadow: none',
|
||||||
'box-shadow: none',
|
'display: block',
|
||||||
'display: block',
|
'height: 100%',
|
||||||
'height: 100%',
|
'left: 0',
|
||||||
'left: 0',
|
'margin: 0',
|
||||||
'margin: 0',
|
'max-height: none',
|
||||||
'max-height: none',
|
'max-width: none',
|
||||||
'max-width: none',
|
'opacity: 1',
|
||||||
'opacity: 1',
|
'outline: 0',
|
||||||
'outline: 0',
|
'padding: 0',
|
||||||
'padding: 0',
|
'position: fixed',
|
||||||
'position: fixed',
|
'top: 0',
|
||||||
'top: 0',
|
'visibility: visible',
|
||||||
'visibility: visible',
|
'width: 100%',
|
||||||
'width: 100%',
|
'z-index: 2147483647',
|
||||||
'z-index: 2147483647',
|
''
|
||||||
''
|
].join(' !important;');
|
||||||
].join(' !important;');
|
pickerRoot.style.cssText = pickerCSSStyle;
|
||||||
var pickerCSSSelector2 = '[' + pickerRoot.id + '-clickblind]';
|
|
||||||
var pickerCSSDeclaration2 = 'pointer-events: none !important;';
|
|
||||||
|
|
||||||
|
var pickerCSS1 = [
|
||||||
pickerRoot.style.cssText = pickerCSSDeclaration1;
|
'#' + pickerRoot.id + ' {',
|
||||||
|
pickerCSSStyle,
|
||||||
|
'}'
|
||||||
|
].join('\n');
|
||||||
|
var pickerCSS2 = [
|
||||||
|
'[' + pickerRoot.id + '-clickblind] {',
|
||||||
|
'pointer-events: none !important;',
|
||||||
|
'}'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/1529
|
// https://github.com/gorhill/uBlock/issues/1529
|
||||||
// In addition to inline styles, harden the element picker styles by using
|
// In addition to inline styles, harden the element picker styles by using
|
||||||
// dedicated CSS rules.
|
// dedicated CSS rules.
|
||||||
vAPI.domFilterer.addCSSRule(
|
vAPI.userStylesheet.add(pickerCSS1);
|
||||||
pickerCSSSelector1,
|
vAPI.userStylesheet.add(pickerCSS2);
|
||||||
pickerCSSDeclaration1,
|
vAPI.userStylesheet.apply();
|
||||||
{ internal: true }
|
|
||||||
);
|
|
||||||
vAPI.domFilterer.addCSSRule(
|
|
||||||
pickerCSSSelector2,
|
|
||||||
pickerCSSDeclaration2,
|
|
||||||
{ internal: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/2060
|
// https://github.com/gorhill/uBlock/issues/2060
|
||||||
vAPI.domFilterer.excludeNode(pickerRoot);
|
vAPI.domFilterer.excludeNode(pickerRoot);
|
||||||
|
Loading…
Reference in New Issue
Block a user