| Index: include.postload.js | 
| =================================================================== | 
| --- a/include.postload.js | 
| +++ b/include.postload.js | 
| @@ -198,24 +198,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(element.getAttribute("style"))) | 
| -    return true; | 
| - | 
| -  return false; | 
| -} | 
| - | 
| // Adds an overlay to an element, which is probably a Flash object | 
| function addElementOverlay(elt) { | 
| var zIndex = "auto"; | 
| @@ -312,13 +294,17 @@ | 
|  | 
| // Add overlays for blockable elements that don't emit mouse events, | 
| // so that they can still be selected. | 
| -  var elts = document.querySelectorAll('object,embed,iframe,frame'); | 
| -  for(var i=0; i<elts.length; i++) | 
| -  { | 
| -    var element = elts[i]; | 
| -    if (isBlockable(element)) | 
| -      addElementOverlay(element); | 
| -  } | 
| +  [].forEach.call( | 
| +    document.querySelectorAll('object,embed,iframe,frame'), | 
| +    function(element) | 
| +    { | 
| +      getFiltersForElement(element, function(filters) | 
| +      { | 
| +        if (filters.length > 0) | 
| +          addElementOverlay(element); | 
| +      }); | 
| +    } | 
| +  ); | 
|  | 
| clickHide_activated = true; | 
| document.addEventListener("mousedown", clickHide_stopPropagation, true); | 
| @@ -401,39 +387,53 @@ | 
| clickHide_mouseClick(e); | 
| } | 
|  | 
| -function getBlockableElementOrAncestor(element) | 
| +function getBlockableElementOrAncestor(element, callback) | 
| { | 
| -  while (element && element != document.documentElement | 
| -                 && element != document.body) | 
| +  // We reached the document root without finding a blockable element. | 
| +  // We also assume that the user doesn't want to block the whole page. | 
| +  // So we never consider the <html> or <body> element. | 
| +  if (!element || element == document.documentElement || element == document.body) | 
| +    callback(null); | 
| + | 
| +  // We can't handle non-HTML (like SVG) elements, as well as | 
| +  // <area> elements (see below). So fall back to the parent element. | 
| +  else if (!(element instanceof HTMLElement) || element.localName == "area") | 
| +    getBlockableElementOrAncestor(element.parentElement, callback); | 
| + | 
| +  // If image maps are used mouse events occur for the <area> element. | 
| +  // But we have to block the image associated with the <map> element. | 
| +  else if (element.localName == "map") | 
| { | 
| -    if (element instanceof HTMLElement && element.localName != "area") | 
| +    var images = document.querySelectorAll("img[usemap]"); | 
| +    var image = null; | 
| + | 
| +    for (var i = 0; i < images.length; i++) | 
| { | 
| -      // Handle <area> and their <map> elements specially, | 
| -      // blocking the image they are associated with | 
| -      if (element.localName == "map") | 
| +      var usemap = images[i].getAttribute("usemap"); | 
| +      var index = usemap.indexOf("#"); | 
| + | 
| +      if (index != -1 && usemap.substr(index + 1) == element.name) | 
| { | 
| -        var images = document.querySelectorAll("img[usemap]"); | 
| -        for (var i = 0; i < images.length; i++) | 
| -        { | 
| -          var image = images[i]; | 
| -          var usemap = image.getAttribute("usemap"); | 
| -          var index = usemap.indexOf("#"); | 
| - | 
| -          if (index != -1 && usemap.substr(index + 1) == element.name) | 
| -            return getBlockableElementOrAncestor(image); | 
| -        } | 
| - | 
| -        return null; | 
| +        image = images[i]; | 
| +        break; | 
| } | 
| - | 
| -      if (isBlockable(element)) | 
| -        return element; | 
| } | 
|  | 
| -    element = element.parentElement; | 
| +    getBlockableElementOrAncestor(image, callback); | 
| } | 
|  | 
| -  return null; | 
| +  // Finally, if none of the above is true, check whether we can generate | 
| +  // any filters for this element. Otherwise fall back to its parent element. | 
| +  else | 
| +  { | 
| +    getFiltersForElement(element, function(filters) | 
| +    { | 
| +      if (filters.length > 0) | 
| +        callback(element); | 
| +      else | 
| +        getBlockableElementOrAncestor(element.parentElement, callback); | 
| +    }); | 
| +  } | 
| } | 
|  | 
| // Hovering over an element so highlight it | 
| @@ -442,22 +442,27 @@ | 
| if (clickHide_activated == false) | 
| return; | 
|  | 
| -  var target = getBlockableElementOrAncestor(e.target); | 
| +  getBlockableElementOrAncestor(e.target, function(element) | 
| +  { | 
| +    if (currentElement) | 
| +      unhighlightElement(currentElement); | 
|  | 
| -  if (target) | 
| -  { | 
| -    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; | 
| +  }); | 
| + | 
| e.stopPropagation(); | 
| } | 
|  | 
| // 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); | 
| @@ -496,6 +501,7 @@ | 
| style: element.getAttribute("style"), | 
| classes: [].slice.call(element.classList), | 
| urls: getURLsFromElement(element), | 
| +      mediatype: typeMap[element.localName], | 
| baseURL: document.location.href | 
| }, | 
| function(response) | 
| @@ -674,9 +680,12 @@ | 
| case "clickhide-new-filter": | 
| if(lastRightClickEvent) | 
| { | 
| -          clickHide_activated = true; | 
| -          currentElement = getBlockableElementOrAncestor(lastRightClickEvent.target); | 
| -          clickHide_mouseClick(lastRightClickEvent); | 
| +          getBlockableElementOrAncestor(lastRightClickEvent.target, function(element) | 
| +          { | 
| +            clickHide_activated = true; | 
| +            currentElement = element; | 
| +            clickHide_mouseClick(lastRightClickEvent); | 
| +          }); | 
| } | 
| break; | 
| case "clickhide-init": | 
|  |