diff --git a/src/js/contentscript-end.js b/src/js/contentscript-end.js index 092768b2c..1f41b8f8c 100644 --- a/src/js/contentscript-end.js +++ b/src/js/contentscript-end.js @@ -291,6 +291,63 @@ var uBlockCollapser = (function() { //var timer = window.performance || Date; //var tStart = timer.now(); + var hideElements = (function() { + if ( document.body === null ) { + return function() {}; + } + if ( document.body.shadowRoot === undefined ) { + return function(selectors) { + // https://github.com/chrisaljoudi/uBlock/issues/207 + // Do not call querySelectorAll() using invalid CSS selectors + if ( selectors.length === 0 ) { return; } + 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 + while ( i-- ) { + elems[i].style.setProperty('display', 'none', 'important'); + } + }; + } + return function(selectors) { + if ( selectors.length === 0 ) { return; } + var elems = document.querySelectorAll(selectors); + var i = elems.length; + if ( i === 0 ) { 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-- ) { + elem = elems[i]; + shadow = elem.shadowRoot; + // https://www.chromestatus.com/features/4668884095336448 + // "Multiple shadow roots is being deprecated." + if ( shadow !== null ) { + if ( shadow.className !== sessionId ) { + elem.style.setProperty('display', 'none', 'important'); + } + continue; + } + // https://github.com/gorhill/uBlock/pull/555 + // Not all nodes can be shadowed: + // https://github.com/w3c/webcomponents/issues/102 + // https://github.com/gorhill/uBlock/issues/762 + // Remove display style that might get in the way of the shadow + // node doing its magic. + try { + shadow = elem.createShadowRoot(); + shadow.className = sessionId; + elem.style.removeProperty('display'); + } catch (ex) { + elem.style.setProperty('display', 'none', 'important'); + } + } + }; + })(); + // https://github.com/chrisaljoudi/uBlock/issues/789 // https://github.com/gorhill/uBlock/issues/873 // Be sure that our style tags used for cosmetic filtering are still applied. @@ -298,7 +355,7 @@ var uBlockCollapser = (function() { var doc = document, html = doc.documentElement, head = doc.head, - newParent = html || head; + newParent = head || html; if ( newParent === null ) { return; } @@ -307,9 +364,24 @@ var uBlockCollapser = (function() { for ( var i = 0; i < styles.length; i++ ) { style = styles[i]; oldParent = style.parentNode; - if ( oldParent !== head && oldParent !== html ) { - newParent.appendChild(style); + // https://github.com/gorhill/uBlock/issues/1031 + // If our style tag was disabled, force a re-insert into the page. + if ( + style.disabled && + oldParent !== null && + style[vAPI.sessionId] === undefined + ) { + oldParent.removeChild(style); + oldParent = null; } + if ( oldParent === head || oldParent === html ) { + continue; + } + style.disabled = false; + newParent.appendChild(style); + // The page tried to get rid of us: reapply inline styles to + // blocked elements. + hideElements(style.textContent.slice(0, style.textContent.lastIndexOf('\n'))); } }; checkStyleTags(); @@ -427,6 +499,7 @@ var uBlockCollapser = (function() { // Boost specificity of our CSS rules. var styleText = ':root ' + selectors.join(',\n:root '); var style = document.createElement('style'); + style.setAttribute('type', 'text/css'); // The linefeed before the style block is very important: do no remove! style.appendChild(document.createTextNode(styleText + '\n{display:none !important;}')); var parent = document.head || document.documentElement; @@ -444,63 +517,6 @@ var uBlockCollapser = (function() { //console.debug('µBlock> generic cosmetic filters: injecting %d CSS rules:', selectors.length, text); }; - var hideElements = (function() { - if ( document.body === null ) { - return function() {}; - } - if ( document.body.shadowRoot === undefined ) { - return function(selectors) { - // https://github.com/chrisaljoudi/uBlock/issues/207 - // Do not call querySelectorAll() using invalid CSS selectors - if ( selectors.length === 0 ) { return; } - 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 - while ( i-- ) { - elems[i].style.setProperty('display', 'none', 'important'); - } - }; - } - return function(selectors) { - if ( selectors.length === 0 ) { return; } - var elems = document.querySelectorAll(selectors); - var i = elems.length; - if ( i === 0 ) { 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-- ) { - elem = elems[i]; - shadow = elem.shadowRoot; - // https://www.chromestatus.com/features/4668884095336448 - // "Multiple shadow roots is being deprecated." - if ( shadow !== null ) { - if ( shadow.className !== sessionId ) { - elem.style.setProperty('display', 'none', 'important'); - } - continue; - } - // https://github.com/gorhill/uBlock/pull/555 - // Not all nodes can be shadowed: - // https://github.com/w3c/webcomponents/issues/102 - // https://github.com/gorhill/uBlock/issues/762 - // Remove display style that might get in the way of the shadow - // node doing its magic. - try { - shadow = elem.createShadowRoot(); - shadow.className = sessionId; - elem.style.removeProperty('display'); - } catch (ex) { - elem.style.setProperty('display', 'none', 'important'); - } - } - }; - })(); - // Extract and return the staged nodes which (may) match the selectors. var selectNodes = function(selector) { diff --git a/src/js/contentscript-start.js b/src/js/contentscript-start.js index a84f6ee4d..bf1da5839 100644 --- a/src/js/contentscript-start.js +++ b/src/js/contentscript-start.js @@ -101,6 +101,7 @@ var cosmeticFilters = function(details) { // Boost specificity of our CSS rules. var styleText = ':root ' + hide.join(',\n:root '); var style = document.createElement('style'); + style.setAttribute('type', 'text/css'); // The linefeed before the style block is very important: do not remove! style.appendChild(document.createTextNode(styleText + '\n{display:none !important;}')); //console.debug('µBlock> "%s" cosmetic filters: injecting %d CSS rules:', details.domain, details.hide.length, hideStyleText); diff --git a/src/js/scriptlets/cosmetic-off.js b/src/js/scriptlets/cosmetic-off.js index 4079269ed..b94cfe6cc 100644 --- a/src/js/scriptlets/cosmetic-off.js +++ b/src/js/scriptlets/cosmetic-off.js @@ -71,6 +71,7 @@ while ( i-- ) { selectors.push(style.textContent.replace(reProperties, '')); if ( style.sheet !== null ) { style.sheet.disabled = true; + style[vAPI.sessionId] = true; } } diff --git a/src/js/scriptlets/cosmetic-on.js b/src/js/scriptlets/cosmetic-on.js index 2c9472189..affe19172 100644 --- a/src/js/scriptlets/cosmetic-on.js +++ b/src/js/scriptlets/cosmetic-on.js @@ -71,6 +71,7 @@ while ( i-- ) { selectors.push(style.textContent.replace(reProperties, '')); if ( style.sheet !== null ) { style.sheet.disabled = false; + style[vAPI.sessionId] = undefined; } } diff --git a/src/js/scriptlets/dom-inspector.js b/src/js/scriptlets/dom-inspector.js index 2ae60a15a..e2352d0e9 100644 --- a/src/js/scriptlets/dom-inspector.js +++ b/src/js/scriptlets/dom-inspector.js @@ -742,6 +742,7 @@ var cosmeticFilterMapper = (function() { nodesFromStyleTag(styleTag, rootNode); if ( styleTag.sheet !== null ) { styleTag.sheet.disabled = true; + styleTag[vAPI.sessionId] = true; } } }; @@ -759,9 +760,9 @@ var cosmeticFilterMapper = (function() { styleTag = styleTags[i]; if ( styleTag.sheet !== null ) { styleTag.sheet.disabled = false; + styleTag[vAPI.sessionId] = undefined; } } - reset(); }; return {