| 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); | 
| +} | 
|  |