Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: include.preload.js

Issue 29410607: Issue 5090 - Use user stylesheets for element hiding if possible (Closed)
Patch Set: Make hideElements return a promise Created May 24, 2017, 5:07 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: include.preload.js
===================================================================
--- a/include.preload.js
+++ b/include.preload.js
@@ -529,16 +529,17 @@
}, randomEventName);
}
function ElemHide()
{
this.shadow = this.createShadowTree();
this.style = null;
this.tracer = null;
+ this.inject = true;
this.elemHideEmulation = new ElemHideEmulation(
window,
callback =>
{
ext.backgroundPage.sendMessage({
type: "filters.get",
what: "elemhideemulation"
@@ -591,73 +592,111 @@
}
});
}, null);
}
return shadow;
},
- addSelectors(selectors, filters)
+ addSelectors(selectors, filters, {inject, traceOnly} = {})
{
- if (selectors.length == 0)
+ if (!selectors || selectors.length == 0)
return;
- if (!this.style)
+ if (traceOnly)
{
- // Create <style> element lazily, only if we add styles. Add it to
- // the shadow DOM if possible. Otherwise fallback to the <head> or
- // <html> element. If we have injected a style element before that
- // has been removed (the sheet property is null), create a new one.
- this.style = document.createElement("style");
- (this.shadow || document.head ||
- document.documentElement).appendChild(this.style);
-
- // It can happen that the frame already navigated to a different
- // document while we were waiting for the background page to respond.
- // In that case the sheet property will stay null, after addind the
- // <style> element to the shadow DOM.
- if (!this.style.sheet)
- return;
+ if (this.tracer)
+ this.tracer.addSelectors(selectors, filters);
+ return;
}
- // If using shadow DOM, we have to add the ::content pseudo-element
- // before each selector, in order to match elements within the
- // insertion point.
- let preparedSelectors = [];
- if (this.shadow)
+ inject = this.inject && inject == null || !!inject;
+
+ // Insert the style rules inline if we have been instructed by the
+ // background page to do so. This is usually the case, except on platforms
+ // that do support user stylesheets via the chrome.tabs.insertCSS API
+ // (Firefox 53 onwards for now and possibly Chrome in the near future).
+ // Once all supported platforms have implemented this API, we can remove
+ // the code below.
+ // See issue #5090.
+ // Related Chrome and Firefox issues:
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=632009
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1310026
+ if (inject)
{
- for (let selector of selectors)
+ if (!this.style)
+ {
+ // Create <style> element lazily, only if we add styles. Add it to
+ // the shadow DOM if possible. Otherwise fallback to the <head> or
+ // <html> element. If we have injected a style element before that
+ // has been removed (the sheet property is null), create a new one.
+ this.style = document.createElement("style");
+ (this.shadow || document.head ||
+ document.documentElement).appendChild(this.style);
+
+ // It can happen that the frame already navigated to a different
+ // document while we were waiting for the background page to respond.
+ // In that case the sheet property will stay null, after addind the
+ // <style> element to the shadow DOM.
+ if (!this.style.sheet)
+ return;
+ }
+
+ // If using shadow DOM, we have to add the ::content pseudo-element
+ // before each selector, in order to match elements within the
+ // insertion point.
+ let preparedSelectors = [];
+ if (this.shadow)
{
- let subSelectors = splitSelector(selector);
- for (let subSelector of subSelectors)
- preparedSelectors.push("::content " + subSelector);
+ for (let selector of selectors)
+ {
+ let subSelectors = splitSelector(selector);
+ for (let subSelector of subSelectors)
+ preparedSelectors.push("::content " + subSelector);
+ }
+ }
+ else
+ {
+ preparedSelectors = selectors;
}
+
+ // Safari only allows 8192 primitive selectors to be injected at once[1],
+ // we therefore chunk the inserted selectors into groups of 200 to be
+ // safe.
+ // (Chrome also has a limit, larger... but we're not certain exactly what
+ // it is! Edge apparently has no such limit.)
+ // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69debb75fc1de/Source/WebCore/css/RuleSet.h#L68
+ for (let i = 0; i < preparedSelectors.length; i += this.selectorGroupSize)
+ {
+ let selector = preparedSelectors.slice(
+ i, i + this.selectorGroupSize
+ ).join(", ");
+ this.style.sheet.insertRule(selector + "{display: none !important;}",
+ this.style.sheet.cssRules.length);
+ }
+
+ if (this.tracer)
+ this.tracer.addSelectors(selectors, filters);
}
else
{
- preparedSelectors = selectors;
- }
+ ext.backgroundPage.sendMessage({type: "hide-elements", selectors},
+ success =>
+ {
+ let options = {};
- // Safari only allows 8192 primitive selectors to be injected at once[1], we
- // therefore chunk the inserted selectors into groups of 200 to be safe.
- // (Chrome also has a limit, larger... but we're not certain exactly what it
- // is! Edge apparently has no such limit.)
- // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69debb75fc1de/Source/WebCore/css/RuleSet.h#L68
- for (let i = 0; i < preparedSelectors.length; i += this.selectorGroupSize)
- {
- let selector = preparedSelectors.slice(
- i, i + this.selectorGroupSize
- ).join(", ");
- this.style.sheet.insertRule(selector + "{display: none !important;}",
- this.style.sheet.cssRules.length);
+ if (!success)
+ options.inject = true;
+ else
+ options.traceOnly = true;
+
+ this.addSelectors(selectors, filters, options);
+ });
}
-
- if (this.tracer)
- this.tracer.addSelectors(selectors, filters);
},
apply()
{
ext.backgroundPage.sendMessage({type: "get-selectors"}, response =>
{
if (this.tracer)
this.tracer.disconnect();
@@ -665,17 +704,19 @@
if (this.style && this.style.parentElement)
this.style.parentElement.removeChild(this.style);
this.style = null;
if (response.trace)
this.tracer = new ElementHidingTracer();
- this.addSelectors(response.selectors);
+ this.inject = response.inject;
+
+ this.addSelectors(response.selectors, null, {traceOnly: !this.inject});
this.elemHideEmulation.apply();
});
}
};
if (document instanceof HTMLDocument)
{
checkSitekey();
« no previous file with comments | « ext/background.js ('k') | lib/elemHideHelper.js » ('j') | lib/elemHideHelper.js » ('J')

Powered by Google App Engine
This is Rietveld