mirror of https://github.com/gorhill/uBlock.git
#435: using shadow nodes instead of modifying directly nodes' style attr
This commit is contained in:
parent
c11421d574
commit
febb18147a
|
@ -446,12 +446,34 @@ var uBlockCollapser = (function() {
|
|||
if ( document.body === null ) {
|
||||
return;
|
||||
}
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/158
|
||||
// Using CSSStyleDeclaration.setProperty is more reliable
|
||||
var elems = document.querySelectorAll(selectors);
|
||||
var i = elems.length;
|
||||
if ( i === 0 ) {
|
||||
return;
|
||||
}
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/158
|
||||
// Using CSSStyleDeclaration.setProperty is more reliable
|
||||
var template = vAPI.perNodeShadowTemplate;
|
||||
if ( template === null ) {
|
||||
while ( i-- ) {
|
||||
elems[i].style.setProperty('display', 'none', 'important');
|
||||
}
|
||||
return;
|
||||
}
|
||||
// https://github.com/gorhill/uBlock/issues/435
|
||||
// Using shadow content so that we do not have to modify style
|
||||
// attribute.
|
||||
var sessionId = vAPI.sessionId;
|
||||
var elem, shadow;
|
||||
while ( i-- ) {
|
||||
elems[i].style.setProperty('display', 'none', 'important');
|
||||
elem = elems[i];
|
||||
shadow = elem.shadowRoot;
|
||||
if ( shadow !== null && shadow.className === sessionId ) {
|
||||
continue;
|
||||
}
|
||||
shadow = elem.createShadowRoot();
|
||||
shadow.className = sessionId;
|
||||
shadow.appendChild(template.cloneNode(true));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -54,6 +54,14 @@ if ( vAPI.contentscriptStartInjected ) {
|
|||
}
|
||||
vAPI.contentscriptStartInjected = true;
|
||||
vAPI.styles = vAPI.styles || [];
|
||||
vAPI.perNodeShadowTemplate = (function() {
|
||||
if ( typeof document.documentElement.createShadowRoot !== 'function' ) {
|
||||
return null;
|
||||
}
|
||||
var content = document.createElement('content');
|
||||
content.select = '#' + vAPI.sessionId;
|
||||
return content;
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -157,12 +165,34 @@ var hideElements = function(selectors) {
|
|||
if ( document.body === null ) {
|
||||
return;
|
||||
}
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/158
|
||||
// Using CSSStyleDeclaration.setProperty is more reliable
|
||||
var elems = document.querySelectorAll(selectors);
|
||||
var i = elems.length;
|
||||
if ( i === 0 ) {
|
||||
return;
|
||||
}
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/158
|
||||
// Using CSSStyleDeclaration.setProperty is more reliable
|
||||
var template = vAPI.perNodeShadowTemplate;
|
||||
if ( template === null ) {
|
||||
while ( i-- ) {
|
||||
elems[i].style.setProperty('display', 'none', 'important');
|
||||
}
|
||||
return;
|
||||
}
|
||||
// https://github.com/gorhill/uBlock/issues/435
|
||||
// Using shadow content so that we do not have to modify style
|
||||
// attribute.
|
||||
var sessionId = vAPI.sessionId;
|
||||
var elem, shadow;
|
||||
while ( i-- ) {
|
||||
elems[i].style.setProperty('display', 'none', 'important');
|
||||
elem = elems[i];
|
||||
shadow = elem.shadowRoot;
|
||||
if ( shadow !== null && shadow.className === sessionId ) {
|
||||
continue;
|
||||
}
|
||||
shadow = elem.createShadowRoot();
|
||||
shadow.className = sessionId;
|
||||
shadow.appendChild(template.cloneNode(true));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -29,8 +29,11 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var showdomButton = uDom.nodeFromId('showdom');
|
||||
|
||||
// Don't bother if the browser is not modern enough.
|
||||
if ( typeof Map === undefined || typeof WeakMap === undefined ) {
|
||||
showdomButton.classList.add('disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -44,7 +47,6 @@ var inspectedURL = '';
|
|||
var inspectedHostname = '';
|
||||
var pollTimer = null;
|
||||
var fingerprint = null;
|
||||
var showdomButton = uDom.nodeFromId('showdom');
|
||||
var inspector = uDom.nodeFromId('domInspector');
|
||||
var domTree = uDom.nodeFromId('domTree');
|
||||
var tabSelector = uDom.nodeFromId('pageSelector');
|
||||
|
|
|
@ -49,6 +49,8 @@ if ( Array.isArray(styles) === false ) {
|
|||
return;
|
||||
}
|
||||
|
||||
var sessionId = vAPI.sessionId;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Remove all cosmetic filtering-related styles from the DOM
|
||||
|
@ -60,15 +62,12 @@ var style, i;
|
|||
i = styles.length;
|
||||
while ( i-- ) {
|
||||
style = styles[i];
|
||||
if ( style.parentElement === null ) {
|
||||
continue;
|
||||
}
|
||||
style.parentElement.removeChild(style);
|
||||
selectors.push(style.textContent.replace(reProperties, ''));
|
||||
if ( style.sheet !== null ) {
|
||||
style.sheet.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove `display: none !important` attribute
|
||||
|
||||
if ( selectors.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
@ -78,13 +77,23 @@ try {
|
|||
elems = document.querySelectorAll(selectors.join(','));
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
i = elems.length;
|
||||
|
||||
var elem, shadow;
|
||||
while ( i-- ) {
|
||||
style = elems[i].style;
|
||||
if ( typeof style === 'object' || typeof style.removeProperty === 'function' ) {
|
||||
style.removeProperty('display');
|
||||
elem = elems[i];
|
||||
shadow = elem.shadowRoot;
|
||||
if ( shadow === undefined ) {
|
||||
style = elem.style;
|
||||
if ( typeof style === 'object' || typeof style.removeProperty === 'function' ) {
|
||||
style.removeProperty('display');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ( shadow === null || shadow.className !== sessionId ) {
|
||||
continue;
|
||||
}
|
||||
shadow.children[0].select = '';
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -49,6 +49,8 @@ if ( Array.isArray(styles) === false ) {
|
|||
return;
|
||||
}
|
||||
|
||||
var sessionId = vAPI.sessionId;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Insert all cosmetic filtering-related style tags in the DOM
|
||||
|
@ -56,23 +58,16 @@ if ( Array.isArray(styles) === false ) {
|
|||
var selectors = [];
|
||||
var reProperties = /\s*\{[^}]+\}\s*/;
|
||||
var style, i;
|
||||
var parent = document.head || document.body || document.documentElement;
|
||||
|
||||
i = styles.length;
|
||||
while ( i-- ) {
|
||||
style = styles[i];
|
||||
if ( style.parentElement !== null ) {
|
||||
continue;
|
||||
}
|
||||
if ( parent === null ) {
|
||||
continue;
|
||||
}
|
||||
selectors.push(style.textContent.replace(reProperties, ''));
|
||||
parent.appendChild(style);
|
||||
if ( style.sheet !== null ) {
|
||||
style.sheet.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Add `display: none !important` attribute
|
||||
|
||||
if ( selectors.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
@ -83,12 +78,22 @@ try {
|
|||
} catch (e) {
|
||||
}
|
||||
|
||||
var elem, shadow, selector = '#' + sessionId;
|
||||
i = elems.length;
|
||||
while ( i-- ) {
|
||||
style = elems[i].style;
|
||||
if ( typeof style === 'object' || typeof style.removeProperty === 'function' ) {
|
||||
style.setProperty('display', 'none', 'important');
|
||||
elem = elems[i];
|
||||
shadow = elem.shadowRoot;
|
||||
if ( shadow === undefined ) {
|
||||
style = elems[i].style;
|
||||
if ( typeof style === 'object' || typeof style.removeProperty === 'function' ) {
|
||||
style.setProperty('display', 'none', 'important');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ( shadow === null || shadow.className !== sessionId ) {
|
||||
continue;
|
||||
}
|
||||
shadow.children[0].select = selector;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -42,7 +42,9 @@ if ( typeof vAPI !== 'object' ) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
if ( document.querySelector('iframe.dom-inspector.' + vAPI.sessionId) !== null ) {
|
||||
var sessionId = vAPI.sessionId;
|
||||
|
||||
if ( document.querySelector('iframe.dom-inspector.' + sessionId) !== null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -159,7 +161,7 @@ var toggledNodes = new Map();
|
|||
// Some kind of fingerprint for the DOM, without incurring too much overhead.
|
||||
|
||||
var domFingerprint = function() {
|
||||
return vAPI.sessionId;
|
||||
return sessionId;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -274,7 +276,7 @@ var domLayout = (function() {
|
|||
return null;
|
||||
}
|
||||
// skip uBlock's own nodes
|
||||
if ( node.classList.contains(vAPI.sessionId) ) {
|
||||
if ( node.classList.contains(sessionId) ) {
|
||||
return null;
|
||||
}
|
||||
if ( level === 0 && localName === 'body' ) {
|
||||
|
@ -807,14 +809,14 @@ var onScrolled = function() {
|
|||
/******************************************************************************/
|
||||
|
||||
var resetToggledNodes = function() {
|
||||
var value;
|
||||
var details;
|
||||
// Chromium does not support destructuring as of v43.
|
||||
for ( var node of toggledNodes.keys() ) {
|
||||
value = toggledNodes.get(node);
|
||||
if ( value !== null ) {
|
||||
node.style.removeProperty('display');
|
||||
details = toggledNodes.get(node);
|
||||
if ( details.show ) {
|
||||
showNode(node, details.v1, details.v2);
|
||||
} else {
|
||||
node.style.setProperty('display', value);
|
||||
hideNode(node);
|
||||
}
|
||||
}
|
||||
toggledNodes.clear();
|
||||
|
@ -845,6 +847,7 @@ var selectNodes = function(selector, nid) {
|
|||
/******************************************************************************/
|
||||
|
||||
var shutdown = function() {
|
||||
toggleStylesVisibility(true);
|
||||
resetToggledNodes();
|
||||
domLayout.shutdown();
|
||||
localMessager.removeAllListeners();
|
||||
|
@ -869,32 +872,38 @@ var toggleNodes = function(nodes, originalState, targetState) {
|
|||
if ( i === 0 ) {
|
||||
return;
|
||||
}
|
||||
var node, value;
|
||||
var node, details;
|
||||
while ( i-- ) {
|
||||
node = nodes[i];
|
||||
if ( originalState ) { // any, ?
|
||||
if ( targetState ) { // any, any
|
||||
value = toggledNodes.get(node);
|
||||
if ( value === undefined ) {
|
||||
continue;
|
||||
}
|
||||
if ( value !== null ) {
|
||||
node.style.removeProperty('display');
|
||||
} else {
|
||||
node.style.setProperty('display', value);
|
||||
}
|
||||
// originally visible node
|
||||
if ( originalState ) {
|
||||
// unhide visible node
|
||||
if ( targetState ) {
|
||||
details = toggledNodes.get(node) || {};
|
||||
showNode(node, details.v1, details.v2);
|
||||
toggledNodes.delete(node);
|
||||
} else { // any, hidden
|
||||
toggledNodes.set(node, node.style.getPropertyValue('display') || null);
|
||||
node.style.setProperty('display', 'none');
|
||||
}
|
||||
} else { // hidden, ?
|
||||
if ( targetState ) { // hidden, any
|
||||
toggledNodes.set(node, 'none');
|
||||
node.style.setProperty('display', 'initial', 'important');
|
||||
} else { // hidden, hidden
|
||||
// hide visible node
|
||||
else {
|
||||
toggledNodes.set(node, {
|
||||
show: true,
|
||||
v1: node.style.getPropertyValue('display') || '',
|
||||
v2: node.style.getPropertyPriority('display') || ''
|
||||
});
|
||||
hideNode(node);
|
||||
}
|
||||
}
|
||||
// originally hidden node
|
||||
else {
|
||||
// show hidden node
|
||||
if ( targetState ) {
|
||||
toggledNodes.set(node, { show: false });
|
||||
showNode(node, 'initial', 'important');
|
||||
}
|
||||
// hide hidden node
|
||||
else {
|
||||
hideNode(node);
|
||||
toggledNodes.delete(node);
|
||||
node.style.setProperty('display', 'none', 'important');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -902,6 +911,56 @@ var toggleNodes = function(nodes, originalState, targetState) {
|
|||
|
||||
// https://www.youtube.com/watch?v=L5jRewnxSBY
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var showNode = function(node, v1, v2) {
|
||||
var shadow = node.shadowRoot;
|
||||
if ( shadow === undefined ) {
|
||||
if ( !v1 ) {
|
||||
node.style.removeProperty('display');
|
||||
} else {
|
||||
node.style.setProperty('display', v1, v2);
|
||||
}
|
||||
} else if ( shadow !== null && shadow.className === sessionId ) {
|
||||
shadow.children[0].select = '';
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var hideNode = function(node) {
|
||||
var shadow = node.shadowRoot;
|
||||
if ( shadow === undefined ) {
|
||||
node.style.setProperty('display', 'none', 'important');
|
||||
return;
|
||||
}
|
||||
if ( shadow !== null && shadow.className === sessionId ) {
|
||||
shadow.children[0].select = '#' + sessionId;
|
||||
return;
|
||||
}
|
||||
// not all node can be shadowed
|
||||
try {
|
||||
shadow = node.createShadowRoot();
|
||||
} catch (ex) {
|
||||
return;
|
||||
}
|
||||
shadow.className = sessionId;
|
||||
shadow.appendChild(vAPI.perNodeShadowTemplate.cloneNode(true));
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var toggleStylesVisibility = function(state) {
|
||||
var styleTags = vAPI.styles || [];
|
||||
var i = styleTags.length, sheet;
|
||||
while ( i-- ) {
|
||||
sheet = styleTags[i].sheet;
|
||||
if ( sheet !== null ) {
|
||||
sheet.disabled = !state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -978,7 +1037,7 @@ var onMessage = function(request) {
|
|||
// Install DOM inspector widget
|
||||
|
||||
pickerRoot = document.createElement('iframe');
|
||||
pickerRoot.classList.add(vAPI.sessionId);
|
||||
pickerRoot.classList.add(sessionId);
|
||||
pickerRoot.classList.add('dom-inspector');
|
||||
pickerRoot.style.cssText = [
|
||||
'background: transparent',
|
||||
|
@ -1048,6 +1107,7 @@ pickerRoot.onload = function() {
|
|||
window.addEventListener('scroll', onScrolled, true);
|
||||
|
||||
highlightElements();
|
||||
toggleStylesVisibility(false);
|
||||
|
||||
localMessager.addListener(onMessage);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue