| Index: include.preload.js |
| =================================================================== |
| --- a/include.preload.js |
| +++ b/include.preload.js |
| @@ -1,6 +1,6 @@ |
| /* |
| * This file is part of Adblock Plus <http://adblockplus.org/>, |
| - * Copyright (C) 2006-2013 Eyeo GmbH |
| + * Copyright (C) 2006-2014 Eyeo GmbH |
| * |
| * Adblock Plus is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 3 as |
| @@ -17,46 +17,6 @@ |
| var SELECTOR_GROUP_SIZE = 20; |
| -var elemhideElt = null; |
| - |
| -// Sets the currently used CSS rules for elemhide filters |
| -function setElemhideCSSRules(selectors) |
| -{ |
| - if (elemhideElt && elemhideElt.parentNode) |
| - elemhideElt.parentNode.removeChild(elemhideElt); |
| - |
| - if (!selectors) |
| - return; |
| - |
| - elemhideElt = document.createElement("style"); |
| - elemhideElt.setAttribute("type", "text/css"); |
| - |
| - // Try to insert the style into the <head> tag, inserting directly under the |
| - // document root breaks dev tools functionality: |
| - // http://code.google.com/p/chromium/issues/detail?id=178109 |
| - (document.head || document.documentElement).appendChild(elemhideElt); |
| - |
| - var elt = elemhideElt; // Use a local variable to avoid racing conditions |
| - function setRules() |
| - { |
| - if (!elt.sheet) |
| - { |
| - // Stylesheet didn't initialize yet, wait a little longer |
| - window.setTimeout(setRules, 0); |
| - return; |
| - } |
| - |
| - // WebKit apparently chokes when the selector list in a CSS rule is huge. |
| - // So we split the elemhide selectors into groups. |
| - for (var i = 0, j = 0; i < selectors.length; i += SELECTOR_GROUP_SIZE, j++) |
| - { |
| - var selector = selectors.slice(i, i + SELECTOR_GROUP_SIZE).join(", "); |
| - elt.sheet.insertRule(selector + " { display: none !important; }", j); |
| - } |
| - } |
| - setRules(); |
| -} |
| - |
| var typeMap = { |
| "img": "IMAGE", |
| "input": "IMAGE", |
| @@ -66,15 +26,13 @@ |
| "iframe": "SUBDOCUMENT" |
| }; |
| -function checkCollapse(event) |
| +function checkCollapse(element) |
| { |
| - var target = event.target; |
| - var tag = target.localName; |
| - var expectedEvent = (tag == "iframe" || tag == "frame" ? "load" : "error"); |
| - if (tag in typeMap && event.type == expectedEvent) |
| + var tag = element.localName; |
| + if (tag in typeMap) |
| { |
| // This element failed loading, did we block it? |
| - var url = target.src; |
| + var url = element.src; |
| if (!url) |
| return; |
| @@ -82,45 +40,193 @@ |
| { |
| type: "should-collapse", |
| url: url, |
| - documentUrl: document.URL, |
| mediatype: typeMap[tag] |
| }, |
| function(response) |
| { |
| - if (response && target.parentNode) |
| + if (response && element.parentNode) |
| { |
| // <frame> cannot be removed, doing that will mess up the frameset |
| if (tag == "frame") |
| - target.style.setProperty("visibility", "hidden", "!important"); |
| + element.style.setProperty("visibility", "hidden", "important"); |
| else |
| - target.parentNode.removeChild(target); |
| + element.style.setProperty("display", "none", "important"); |
| } |
| } |
| ); |
| } |
| } |
| -function init() |
| +function checkExceptionKey() |
| { |
| - // Make sure this is really an HTML page, as Chrome runs these scripts on just about everything |
| - if (!(document.documentElement instanceof HTMLElement)) |
| - return; |
| - |
| - document.addEventListener("error", checkCollapse, true); |
| - document.addEventListener("load", checkCollapse, true); |
| - |
| - ext.backgroundPage.sendMessage( |
| - { |
| - type: "get-selectors", |
| - frameUrl: window.location.href |
| - }, |
| - setElemhideCSSRules |
| - ); |
| + var attr = document.documentElement.getAttribute("data-adblockkey"); |
| + if (attr) |
| + ext.backgroundPage.sendMessage({type: "add-key-exception", token: attr}); |
| } |
| -// In Chrome 18 the document might not be initialized yet |
| -if (document.documentElement) |
| - init(); |
| -else |
| - window.setTimeout(init, 0); |
| +function hasInlineURL(element, attribute) |
| +{ |
| + var value = element.getAttribute(attribute); |
| + return value == null || /^\s*(javascript:|about:|$)/i.test(value); |
| +} |
| + |
| +function isInlineFrame(element) |
| +{ |
| + switch (element.localName) |
| + { |
| + case "iframe": |
| + return hasInlineURL(element, "src") || element.hasAttribute("srcdoc"); |
| + case "frame": |
| + return hasInlineURL(element, "src"); |
| + case "object": |
| + return hasInlineURL(element, "data") && element.contentDocument; |
| + default: |
| + return false; |
| + } |
| +} |
| + |
| +// Converts relative to absolute URL |
| +// e.g.: foo.swf on http://example.com/whatever/bar.html |
| +// -> http://example.com/whatever/foo.swf |
| +function relativeToAbsoluteUrl(url) |
| +{ |
| + // If URL is already absolute, don't mess with it |
| + if (!url || /^[\w\-]+:/i.test(url)) |
| + return url; |
| + |
| + // Leading / means absolute path |
| + // Leading // means network path |
| + if (url[0] == '/') |
| + { |
| + if (url[1] == '/') |
| + return document.location.protocol + url; |
| + else |
| + return document.location.protocol + "//" + document.location.host + url; |
| + } |
| + |
| + // Remove filename and add relative URL to it |
| + var base = document.baseURI.match(/.+\//); |
| + if (!base) |
| + return document.baseURI + "/" + url; |
| + return base[0] + url; |
| +} |
| + |
| +function init(document) |
| +{ |
| + var canUseShadow = "webkitCreateShadowRoot" in document.documentElement; |
| + var fixInlineFrames = false; |
| + |
| + var match = navigator.userAgent.match(/\bChrome\/(\d+)/); |
| + if (match) |
| + { |
| + var chromeVersion = parseInt(match[1]); |
| + |
| + // the <shadow> element is ignored in Chrome 32 (#309). Also Chrome 31-33 |
| + // crashes in some situations on some pages when using shadow DOM (#498). |
| + // So we must not use Shadow DOM on those versions of Chrome. |
| + if (chromeVersion >= 31 && chromeVersion <= 33) |
| + canUseShadow = false; |
| + |
| + // prior to Chrome 37, content scripts don't run on about:blank |
| + // and about:srcdoc. So we have to apply element hiding and collapsing |
| + // from the parent frame, when inline frames are loaded. |
| + if (chromeVersion < 37) |
| + fixInlineFrames = true; |
| + } |
| + |
| + // use Shadow DOM if available to don't mess with web pages that |
| + // rely on the order of their own <style> tags (#309). However we |
| + // must not create the shadow root in the response callback passed |
| + // to sendMessage(), otherwise Chrome breaks some websites (#450). |
| + if (canUseShadow) |
| + { |
| + var shadow = document.documentElement.webkitCreateShadowRoot(); |
| + shadow.appendChild(document.createElement("shadow")); |
| + } |
| + |
| + // Sets the currently used CSS rules for elemhide filters |
| + var setElemhideCSSRules = function(selectors) |
| + { |
| + if (selectors.length == 0) |
| + return; |
| + |
| + var style = document.createElement("style"); |
| + style.setAttribute("type", "text/css"); |
| + |
| + if (canUseShadow) |
| + { |
| + shadow.appendChild(style); |
| + |
| + try |
| + { |
| + document.querySelector("::content"); |
| + |
| + for (var i = 0; i < selectors.length; i++) |
| + selectors[i] = "::content " + selectors[i]; |
| + } |
| + catch (e) |
| + { |
| + for (var i = 0; i < selectors.length; i++) |
| + selectors[i] = "::-webkit-distributed(" + selectors[i] + ")"; |
| + } |
| + } |
| + else |
| + { |
| + // Try to insert the style into the <head> tag, inserting directly under the |
| + // document root breaks dev tools functionality: |
| + // http://code.google.com/p/chromium/issues/detail?id=178109 |
| + (document.head || document.documentElement).appendChild(style); |
| + } |
| + |
| + var setRules = function() |
| + { |
| + // The sheet property might not exist yet if the |
| + // <style> element was created for a sub frame |
| + if (!style.sheet) |
| + { |
| + setTimeout(setRules, 0); |
| + return; |
| + } |
| + |
| + // WebKit apparently chokes when the selector list in a CSS rule is huge. |
| + // So we split the elemhide selectors into groups. |
| + for (var i = 0; selectors.length > 0; i++) |
| + { |
| + var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", "); |
| + style.sheet.insertRule(selector + " { display: none !important; }", i); |
| + } |
| + }; |
| + |
| + setRules(); |
| + }; |
| + |
| + document.addEventListener("error", function(event) |
| + { |
| + checkCollapse(event.target); |
| + }, true); |
| + |
| + document.addEventListener("load", function(event) |
| + { |
| + var element = event.target; |
| + |
| + if (/^i?frame$/.test(element.localName)) |
| + checkCollapse(element); |
| + |
| + if (fixInlineFrames && isInlineFrame(element)) |
| + { |
| + init(element.contentDocument); |
| + |
| + for (var tagName in typeMap) |
| + Array.prototype.forEach.call(element.contentDocument.getElementsByTagName(tagName), checkCollapse); |
| + } |
| + }, true); |
| + |
| + ext.backgroundPage.sendMessage({type: "get-selectors"}, setElemhideCSSRules); |
| +} |
| + |
| +if (document instanceof HTMLDocument) |
| +{ |
| + checkExceptionKey(); |
| + init(document); |
| +} |