| Index: include.postload.js | 
| =================================================================== | 
| --- a/include.postload.js | 
| +++ b/include.postload.js | 
| @@ -267,24 +267,6 @@ | 
| return getURLsFromAttributes(element); | 
| } | 
|  | 
| -function isBlockable(element) | 
| -{ | 
| -  if (element.id) | 
| -    return true; | 
| -  if (element.classList.length > 0) | 
| -    return true; | 
| -  if (getURLsFromElement(element).length > 0) | 
| -    return true; | 
| - | 
| -  // We only generate filters based on the "style" attribute, | 
| -  // if this is the only way we can generate a filter, and | 
| -  // only if there are at least two CSS properties defined. | 
| -  if (/:.+:/.test(getOriginalStyle(element))) | 
| -    return true; | 
| - | 
| -  return false; | 
| -} | 
| - | 
| // Gets the absolute position of an element by walking up the DOM tree, | 
| // adding up offsets. | 
| // I hope there's a better way because it just seems absolutely stupid | 
| @@ -301,14 +283,9 @@ | 
| } | 
|  | 
| // Adds an overlay to an element, which is probably a Flash object | 
| -function addElementOverlay(elt) { | 
| +function addElementOverlay(elt, callback) { | 
| // If this element is enclosed in an object tag, we prefer to block that instead | 
| if(!elt) | 
| -    return null; | 
| - | 
| -  // If element doesn't have at least one of class name, ID or URL, give up | 
| -  // because we don't know how to construct a filter rule for it | 
| -  if(!isBlockable(elt)) | 
| return; | 
|  | 
| // If the element isn't rendered (since its or one of its ancestor's | 
| @@ -316,23 +293,30 @@ | 
| if (!elt.offsetParent) | 
| return; | 
|  | 
| -  var thisStyle = getComputedStyle(elt, null); | 
| -  var overlay = document.createElement('div'); | 
| -  overlay.prisoner = elt; | 
| -  overlay.className = "__adblockplus__overlay"; | 
| -  overlay.setAttribute('style', 'opacity:0.4; background-color:#ffffff; display:inline-box; ' + 'width:' + thisStyle.width + '; height:' + thisStyle.height + '; position:absolute; overflow:hidden; -webkit-box-sizing:border-box;'); | 
| -  var pos = getAbsolutePosition(elt); | 
| -  overlay.style.left = pos[0] + "px"; | 
| -  overlay.style.top = pos[1] + "px"; | 
| +  generateFilters(elt, function(filters) | 
| +  { | 
| +    if (filters.length == 0) | 
| +      return; | 
|  | 
| -  if (thisStyle.position != "static") | 
| -    overlay.style.zIndex = thisStyle.zIndex; | 
| -  else | 
| -    overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; | 
| +    var thisStyle = getComputedStyle(elt, null); | 
| +    var overlay = document.createElement('div'); | 
| +    overlay.prisoner = elt; | 
| +    overlay.className = "__adblockplus__overlay"; | 
| +    overlay.setAttribute('style', 'opacity:0.4; background-color:#ffffff; display:inline-box; ' + 'width:' + thisStyle.width + '; height:' + thisStyle.height + '; position:absolute; overflow:hidden; -webkit-box-sizing:border-box;'); | 
| +    var pos = getAbsolutePosition(elt); | 
| +    overlay.style.left = pos[0] + "px"; | 
| +    overlay.style.top = pos[1] + "px"; | 
|  | 
| -  // elt.parentNode.appendChild(overlay, elt); | 
| -  document.body.appendChild(overlay); | 
| -  return overlay; | 
| +    if (thisStyle.position != "static") | 
| +      overlay.style.zIndex = thisStyle.zIndex; | 
| +    else | 
| +      overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; | 
| + | 
| +    document.body.appendChild(overlay); | 
| + | 
| +    if (callback) | 
| +      callback(overlay); | 
| +  }); | 
| } | 
|  | 
| // Show dialog asking user whether she wants to add the proposed filters derived | 
| @@ -443,31 +427,50 @@ | 
| clickHide_mouseClick(ev); | 
| } | 
|  | 
| +function getBlockableElementOrAncestor(element, callback) | 
| +{ | 
| +  if (element && element != document.documentElement | 
| +              && element != document.body) | 
| +  { | 
| +    generateFilters(element, function(filters) | 
| +    { | 
| +      if (filters.length > 0) | 
| +        callback(element); | 
| +      else | 
| +        getBlockableElementOrAncestor(element.parentElement, callback); | 
| +    }); | 
| +  } | 
| +  else | 
| +  { | 
| +    callback(null); | 
| +  } | 
| +} | 
| + | 
| // Hovering over an element so highlight it | 
| function clickHide_mouseOver(e) | 
| { | 
| if (clickHide_activated == false) | 
| return; | 
|  | 
| -  var target = e.target; | 
| -  while (target.parentNode && !isBlockable(target)) | 
| -    target = target.parentNode; | 
| -  if (target == document.documentElement || target == document.body) | 
| -    target = null; | 
| +  getBlockableElementOrAncestor(e.target, function(element) | 
| +  { | 
| +    if (currentElement) | 
| +      unhighlightElement(currentElement); | 
|  | 
| -  if (target && target instanceof HTMLElement) | 
| -  { | 
| -    currentElement = target; | 
| +    if (element) | 
| +    { | 
| +      highlightElement(element, "#d6d84b", "#f8fa47"); | 
| +      element.addEventListener("contextmenu", clickHide_elementClickHandler, true); | 
| +    } | 
|  | 
| -    highlightElement(target, "#d6d84b", "#f8fa47"); | 
| -    target.addEventListener("contextmenu", clickHide_elementClickHandler, true); | 
| -  } | 
| +    currentElement = element; | 
| +  }); | 
| } | 
|  | 
| // No longer hovering over this element so unhighlight it | 
| function clickHide_mouseOut(e) | 
| { | 
| -  if (!clickHide_activated || !currentElement) | 
| +  if (!clickHide_activated || currentElement != e.target) | 
| return; | 
|  | 
| unhighlightElement(currentElement); | 
| @@ -494,6 +497,108 @@ | 
| } | 
| } | 
|  | 
| +function generateFilters(element, callback) | 
| +{ | 
| +  function addStyleAttributeFilter(filters, selectors) | 
| +  { | 
| +    var style = getOriginalStyle(element); | 
| +    if (style && filters.length == 0) | 
| +    { | 
| +      ext.backgroundPage.sendMessage( | 
| +        { | 
| +          type: "get-filters-from-selectors", | 
| +          selectors: [escapeCSS(element.localName) + '[style=' + quote(style) + ']'] | 
| +        }, | 
| + | 
| +        function(response) | 
| +        { | 
| +          callback(response.filters, response.selectors); | 
| +        } | 
| +      ); | 
| +    } | 
| +    else | 
| +      callback(filters, selectors); | 
| +  } | 
| + | 
| +  function addElemHideFilters(filters, selectors) | 
| +  { | 
| +    if (selectors.length > 0) | 
| +    { | 
| +      ext.backgroundPage.sendMessage( | 
| +        { | 
| +          type: "get-filters-from-selectors", | 
| +          selectors: selectors | 
| +        }, | 
| + | 
| +        function(response) | 
| +        { | 
| +          addStyleAttributeFilter(filters.concat(response.filters), response.selectors); | 
| +        } | 
| +      ); | 
| +    } | 
| +    else | 
| +      addStyleAttributeFilter(filters, selectors); | 
| +  } | 
| + | 
| +  var filters = []; | 
| +  var selectors = []; | 
| + | 
| +  if (element.id) | 
| +    selectors.push("#" + escapeCSS(element.id)); | 
| + | 
| +  if (element.classList.length > 0) | 
| +  { | 
| +    var selector = ""; | 
| + | 
| +    for (var i = 0; i < element.classList.length; i++) | 
| +      selector += "." + escapeCSS(element.classList[i]); | 
| + | 
| +    selectors.push(selector); | 
| +  } | 
| + | 
| +  var urls = getURLsFromElement(element); | 
| +  if (urls.length > 0) | 
| +  { | 
| +    ext.backgroundPage.sendMessage( | 
| +      { | 
| +        type: "check-whitelisted-urls", | 
| +        mediatype: typeMap[element.localName], | 
| +        urls: urls | 
| +      }, | 
| + | 
| +      function(whitelisted) | 
| +      { | 
| +        for (var i = 0; i < urls.length; i++) | 
| +        { | 
| +          var url = urls[i]; | 
| + | 
| +          if (!whitelisted[url] && /^https?:/i.test(url)) | 
| +          { | 
| +            var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||"); | 
| + | 
| +            if (filters.indexOf(filter) == -1) | 
| +              filters.push(filter); | 
| + | 
| +            continue; | 
| +          } | 
| + | 
| +          if (url == element.src) | 
| +          { | 
| +            var selector = escapeCSS(element.localName) + '[src=' + quote(element.getAttribute("src")) + ']'; | 
| + | 
| +            if (selectors.indexOf(selector) == -1) | 
| +              selectors.push(selector); | 
| +          } | 
| +        } | 
| + | 
| +        addElemHideFilters(filters, selectors); | 
| +      } | 
| +    ); | 
| +  } | 
| +  else | 
| +    addElemHideFilters(filters, selectors); | 
| +} | 
| + | 
| // When the user clicks, the currentElement is the one we want. | 
| // We should have ABP rules ready for when the | 
| // popup asks for them. | 
| @@ -506,66 +611,17 @@ | 
| if (currentElement.classList.contains("__adblockplus__overlay")) | 
| elt = currentElement.prisoner; | 
|  | 
| -  clickHideFilters = new Array(); | 
| -  selectorList = new Array(); | 
| +  generateFilters(elt, function(filters, selectors) | 
| +  { | 
| +    clickHide_showDialog(e.clientX, e.clientY, filters); | 
|  | 
| -  var addSelector = function(selector) | 
| -  { | 
| -    if (selectorList.indexOf(selector) != -1) | 
| -      return; | 
| +    // Highlight the elements specified by selector in yellow | 
| +    if (selectors.length > 0) | 
| +      highlightElements(selectors.join(",")); | 
|  | 
| -    clickHideFilters.push(document.domain + "##" + selector); | 
| -    selectorList.push(selector); | 
| -  }; | 
| - | 
| -  if (elt.id) | 
| -    addSelector("#" + escapeCSS(elt.id)); | 
| - | 
| -  if (elt.classList.length > 0) | 
| -  { | 
| -    var selector = ""; | 
| - | 
| -    for (var i = 0; i < elt.classList.length; i++) | 
| -      selector += "." + escapeCSS(elt.classList[i]); | 
| - | 
| -    addSelector(selector); | 
| -  } | 
| - | 
| -  var urls = getURLsFromElement(elt); | 
| -  for (var i = 0; i < urls.length; i++) | 
| -  { | 
| -    var url = urls[i]; | 
| - | 
| -    if (/^https?:/i.test(url)) | 
| -    { | 
| -      var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||"); | 
| - | 
| -      if (clickHideFilters.indexOf(filter) == -1) | 
| -        clickHideFilters.push(filter); | 
| - | 
| -      continue; | 
| -    } | 
| - | 
| -    if (url == elt.src) | 
| -      addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("src")) + ']'); | 
| -  } | 
| - | 
| -  // as last resort, create a filter based on inline styles | 
| -  if (clickHideFilters.length == 0) | 
| -  { | 
| -    var style = getOriginalStyle(elt); | 
| -    if (style) | 
| -      addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']'); | 
| -  } | 
| - | 
| -  // Show popup | 
| -  clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); | 
| - | 
| -  // Highlight the elements specified by selector in yellow | 
| -  if (selectorList.length > 0) | 
| -    highlightElements(selectorList.join(",")); | 
| -  // Now, actually highlight the element the user clicked on in red | 
| -  highlightElement(currentElement, "#fd1708", "#f6a1b5"); | 
| +    // Now, actually highlight the element the user clicked on in red | 
| +    highlightElement(currentElement, "#fd1708", "#f6a1b5"); | 
| +  }); | 
|  | 
| // Make sure the browser doesn't handle this click | 
| e.preventDefault(); | 
| @@ -692,9 +748,14 @@ | 
| case "clickhide-new-filter": | 
| if(lastRightClickEvent) | 
| { | 
| -          clickHide_activated = true; | 
| -          currentElement = addElementOverlay(lastRightClickEvent.target); | 
| -          clickHide_mouseClick(lastRightClickEvent); | 
| +          var event = lastRightClickEvent; | 
| + | 
| +          addElementOverlay(event.target, function(overlay) | 
| +          { | 
| +            clickHide_activated = true; | 
| +            currentElement = overlay; | 
| +            clickHide_mouseClick(event); | 
| +          }); | 
| } | 
| break; | 
| case "clickhide-init": | 
|  |