| Index: include.preload.js |
| =================================================================== |
| --- a/include.preload.js |
| +++ b/include.preload.js |
| @@ -30,16 +30,18 @@ |
| ["audio", "MEDIA"], |
| ["video", "MEDIA"], |
| ["frame", "SUBDOCUMENT"], |
| ["iframe", "SUBDOCUMENT"], |
| ["object", "OBJECT"], |
| ["embed", "OBJECT"] |
| ]); |
| +let collapsingSelectors = new Set(); |
| + |
| function getURLsFromObjectElement(element) |
| { |
| let url = element.getAttribute("data"); |
| if (url) |
| return [url]; |
| for (let child of element.children) |
| { |
| @@ -123,16 +125,53 @@ |
| { |
| if (/^(?!https?:)[\w-]+:/i.test(urls[i])) |
| urls.splice(i--, 1); |
| } |
| return urls; |
| } |
| +function isCollapsibleMediaElement(element, mediatype) |
| +{ |
| + if (mediatype != "MEDIA") |
| + return false; |
| + |
| + if (!element.getAttribute("src")) |
| + return false; |
| + |
| + for (let child of element.children) |
| + { |
| + // If the <video> or <audio> element contains any <source> or <track> |
| + // children, we cannot address it in CSS by the source URL; in that case we |
| + // don't "collapse" it using a CSS selector but rather hide it directly by |
| + // setting the style="..." attribute. |
| + if (["source", "track"].includes(child.localName)) |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +function collapseMediaElement(element, srcValue) |
| +{ |
| + if (!srcValue) |
| + return; |
| + |
| + let selector = element.localName + "[src=" + CSS.escape(srcValue) + "]"; |
| + |
| + // Adding selectors is expensive so do it only if we really have a new |
| + // selector. |
| + if (!collapsingSelectors.has(selector)) |
| + { |
| + collapsingSelectors.add(selector); |
| + elemhide.addSelectors([selector], null, "collapsing", true); |
| + } |
| +} |
| + |
| function hideElement(element) |
| { |
| function doHide() |
| { |
| let propertyName = "display"; |
| let propertyValue = "none"; |
| if (element.localName == "frame") |
| { |
| @@ -160,29 +199,37 @@ |
| let mediatype = typeMap.get(element.localName); |
| if (!mediatype) |
| return; |
| let urls = getURLsFromElement(element); |
| if (urls.length == 0) |
| return; |
| + let collapsibleMediaElement = isCollapsibleMediaElement(element, mediatype); |
| + |
| + // Save the value of the src attribute because it can change between now and |
| + // when we get the response from the background page. |
| + let srcValue = collapsibleMediaElement ? element.getAttribute("src") : null; |
| + |
| browser.runtime.sendMessage( |
| { |
| type: "filters.collapse", |
| urls, |
| mediatype, |
| baseURL: document.location.href |
| }, |
| - |
| collapse => |
| { |
| if (collapse) |
| { |
| - hideElement(element); |
| + if (collapsibleMediaElement) |
| + collapseMediaElement(element, srcValue); |
| + else |
| + hideElement(element); |
| } |
| } |
| ); |
| } |
| function checkSitekey() |
| { |
| let attr = document.documentElement.getAttribute("data-adblockkey"); |
| @@ -375,21 +422,21 @@ |
| // avoid creating the shadowRoot twice. |
| let shadow = document.documentElement.shadowRoot || |
| document.documentElement.createShadowRoot(); |
| shadow.appendChild(document.createElement("shadow")); |
| return shadow; |
| }, |
| - addSelectorsInline(selectors, groupName) |
| + addSelectorsInline(selectors, groupName, appendOnly = false) |
| { |
| let style = this.styles.get(groupName); |
| - if (style) |
| + if (style && !appendOnly) |
| { |
| while (style.sheet.cssRules.length > 0) |
| style.sheet.deleteRule(0); |
| } |
| if (selectors.length == 0) |
| return; |
| @@ -447,41 +494,44 @@ |
| let selector = preparedSelectors.slice( |
| i, i + this.selectorGroupSize |
| ).join(", "); |
| style.sheet.insertRule(selector + "{display: none !important;}", |
| style.sheet.cssRules.length); |
| } |
| }, |
| - addSelectors(selectors, filters) |
| + addSelectors(selectors, filters, groupName = "emulated", appendOnly = false) |
| { |
| if (this.inline || this.inlineEmulated) |
| { |
| // 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 browser.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 |
| - this.addSelectorsInline(selectors, "emulated"); |
| + this.addSelectorsInline(selectors, groupName, appendOnly); |
| } |
| else |
| { |
| browser.runtime.sendMessage({ |
| type: "elemhide.injectSelectors", |
| selectors, |
| - groupName: "emulated" |
| + groupName, |
| + appendOnly |
| }); |
| } |
| - if (this.tracer) |
| + // Only trace selectors that are based directly on hiding filters |
|
Manish Jethani
2018/02/28 10:31:15
I forgot to add this. We do not want to trace coll
kzar
2018/03/02 09:37:28
You're right, but how about `groupName != "collaps
Manish Jethani
2018/03/02 11:09:36
Done.
|
| + // (i.e. leave out collapsing selectors). |
| + if (this.tracer && ["standard", "emulated"].includes(groupName)) |
| this.tracer.addSelectors(selectors, filters); |
| }, |
| hideElements(elements, filters) |
| { |
| for (let element of elements) |
| hideElement(element); |