| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 /* |  | 
| 2  * This file is part of Adblock Plus <https://adblockplus.org/>, |  | 
| 3  * Copyright (C) 2006-2016 Eyeo GmbH |  | 
| 4  * |  | 
| 5  * Adblock Plus is free software: you can redistribute it and/or modify |  | 
| 6  * it under the terms of the GNU General Public License version 3 as |  | 
| 7  * published by the Free Software Foundation. |  | 
| 8  * |  | 
| 9  * Adblock Plus is distributed in the hope that it will be useful, |  | 
| 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | 
| 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | 
| 12  * GNU General Public License for more details. |  | 
| 13  * |  | 
| 14  * You should have received a copy of the GNU General Public License |  | 
| 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. |  | 
| 16  */ |  | 
| 17 |  | 
| 18 // Click-to-hide stuff |  | 
| 19 var clickHide_activated = false; |  | 
| 20 var clickHide_filters = null; |  | 
| 21 var currentElement = null; |  | 
| 22 var highlightedElementsSelector = null; |  | 
| 23 var highlightedElementsInterval = null; |  | 
| 24 var clickHideFiltersDialog = null; |  | 
| 25 var lastRightClickEvent = null; |  | 
| 26 var lastRightClickEventValid = false; |  | 
| 27 var lastMouseOverEvent = null; |  | 
| 28 |  | 
| 29 function highlightElement(element, shadowColor, backgroundColor) |  | 
| 30 { |  | 
| 31   unhighlightElement(element); |  | 
| 32 |  | 
| 33   var highlightWithOverlay = function() |  | 
| 34   { |  | 
| 35     var overlay = addElementOverlay(element); |  | 
| 36 |  | 
| 37     // If the element isn't displayed no overlay will be added. |  | 
| 38     // Moreover, we don't need to highlight anything then. |  | 
| 39     if (!overlay) |  | 
| 40       return; |  | 
| 41 |  | 
| 42     highlightElement(overlay, shadowColor, backgroundColor); |  | 
| 43     overlay.style.pointerEvents = "none"; |  | 
| 44 |  | 
| 45     element._unhighlight = function() |  | 
| 46     { |  | 
| 47       overlay.parentNode.removeChild(overlay); |  | 
| 48     }; |  | 
| 49   }; |  | 
| 50 |  | 
| 51   var highlightWithStyleAttribute = function() |  | 
| 52   { |  | 
| 53     var originalBoxShadow = element.style.getPropertyValue("box-shadow"); |  | 
| 54     var originalBoxShadowPriority = element.style.getPropertyPriority("box-shado
     w"); |  | 
| 55     var originalBackgroundColor = element.style.getPropertyValue("background-col
     or"); |  | 
| 56     var originalBackgroundColorPriority = element.style.getPropertyPriority("bac
     kground-color"); |  | 
| 57 |  | 
| 58     element.style.setProperty("box-shadow", "inset 0px 0px 5px " + shadowColor, 
     "important"); |  | 
| 59     element.style.setProperty("background-color", backgroundColor, "important"); |  | 
| 60 |  | 
| 61     element._unhighlight = function() |  | 
| 62     { |  | 
| 63       this.style.removeProperty("box-shadow"); |  | 
| 64       this.style.setProperty( |  | 
| 65         "box-shadow", |  | 
| 66         originalBoxShadow, |  | 
| 67         originalBoxShadowPriority |  | 
| 68       ); |  | 
| 69 |  | 
| 70       this.style.removeProperty("background-color"); |  | 
| 71       this.style.setProperty( |  | 
| 72         "background-color", |  | 
| 73         originalBackgroundColor, |  | 
| 74         originalBackgroundColorPriority |  | 
| 75       ); |  | 
| 76     }; |  | 
| 77   }; |  | 
| 78 |  | 
| 79   if ("prisoner" in element) |  | 
| 80     highlightWithStyleAttribute(); |  | 
| 81   else |  | 
| 82     highlightWithOverlay(); |  | 
| 83 } |  | 
| 84 |  | 
| 85 |  | 
| 86 function unhighlightElement(element) |  | 
| 87 { |  | 
| 88   if ("_unhighlight" in element) |  | 
| 89   { |  | 
| 90     element._unhighlight(); |  | 
| 91     delete element._unhighlight; |  | 
| 92   } |  | 
| 93 } |  | 
| 94 |  | 
| 95 // Highlight elements according to selector string. This would include |  | 
| 96 // all elements that would be affected by proposed filters. |  | 
| 97 function highlightElements(selectorString) { |  | 
| 98   unhighlightElements(); |  | 
| 99 |  | 
| 100   var elements = Array.prototype.slice.call(document.querySelectorAll(selectorSt
     ring)); |  | 
| 101   highlightedElementsSelector = selectorString; |  | 
| 102 |  | 
| 103   // Highlight elements progressively. Otherwise the page freezes |  | 
| 104   // when a lot of elements get highlighted at the same time. |  | 
| 105   highlightedElementsInterval = setInterval(function() |  | 
| 106   { |  | 
| 107     if (elements.length > 0) |  | 
| 108     { |  | 
| 109       var element = elements.shift(); |  | 
| 110       if (element != currentElement) |  | 
| 111         highlightElement(element, "#fd6738", "#f6e1e5"); |  | 
| 112     } |  | 
| 113     else |  | 
| 114     { |  | 
| 115       clearInterval(highlightedElementsInterval); |  | 
| 116       highlightedElementsInterval = null; |  | 
| 117     } |  | 
| 118   }, 0); |  | 
| 119 } |  | 
| 120 |  | 
| 121 // Unhighlight all elements, including those that would be affected by |  | 
| 122 // the proposed filters |  | 
| 123 function unhighlightElements() { |  | 
| 124   if (highlightedElementsInterval) |  | 
| 125   { |  | 
| 126     clearInterval(highlightedElementsInterval) |  | 
| 127     highlightedElementsInterval = null; |  | 
| 128   } |  | 
| 129 |  | 
| 130   if (highlightedElementsSelector) |  | 
| 131   { |  | 
| 132     Array.prototype.forEach.call( |  | 
| 133       document.querySelectorAll(highlightedElementsSelector), |  | 
| 134       unhighlightElement |  | 
| 135     ); |  | 
| 136 |  | 
| 137     highlightedElementsSelector = null; |  | 
| 138   } |  | 
| 139 } |  | 
| 140 |  | 
| 141 // Adds an overlay to an element, which is probably a Flash object |  | 
| 142 function addElementOverlay(elt) { |  | 
| 143   var position = "absolute"; |  | 
| 144   var offsetX = window.scrollX; |  | 
| 145   var offsetY = window.scrollY; |  | 
| 146 |  | 
| 147   for (var e = elt; e; e = e.parentElement) |  | 
| 148   { |  | 
| 149     var style = getComputedStyle(e); |  | 
| 150 |  | 
| 151     // If the element isn't rendered (since its or one of its ancestor's |  | 
| 152     // "display" property is "none"), the overlay wouldn't match the element. |  | 
| 153     if (style.display == "none") |  | 
| 154       return null; |  | 
| 155 |  | 
| 156     // If the element or one of its ancestors uses fixed postioning, the overlay |  | 
| 157     // has to use fixed postioning too. Otherwise it might not match the element
     . |  | 
| 158     if (style.position == "fixed") |  | 
| 159     { |  | 
| 160       position = "fixed"; |  | 
| 161       offsetX = offsetY = 0; |  | 
| 162     } |  | 
| 163   } |  | 
| 164 |  | 
| 165   var overlay = document.createElement('div'); |  | 
| 166   overlay.prisoner = elt; |  | 
| 167   overlay.className = "__adblockplus__overlay"; |  | 
| 168   overlay.setAttribute('style', 'opacity:0.4; display:inline-box; overflow:hidde
     n; box-sizing:border-box;'); |  | 
| 169   var rect = elt.getBoundingClientRect(); |  | 
| 170   overlay.style.width = rect.width + "px"; |  | 
| 171   overlay.style.height = rect.height + "px"; |  | 
| 172   overlay.style.left = (rect.left + offsetX) + "px"; |  | 
| 173   overlay.style.top = (rect.top + offsetY) + "px"; |  | 
| 174   overlay.style.position = position; |  | 
| 175   overlay.style.zIndex = 0x7FFFFFFE; |  | 
| 176 |  | 
| 177   // elt.parentNode.appendChild(overlay, elt); |  | 
| 178   document.documentElement.appendChild(overlay); |  | 
| 179   return overlay; |  | 
| 180 } |  | 
| 181 |  | 
| 182 // Show dialog asking user whether she wants to add the proposed filters derived |  | 
| 183 // from selected page element |  | 
| 184 function clickHide_showDialog(filters) |  | 
| 185 { |  | 
| 186   clickHide_filters = filters; |  | 
| 187 |  | 
| 188   clickHideFiltersDialog = document.createElement("iframe"); |  | 
| 189   clickHideFiltersDialog.src = ext.getURL("block.html"); |  | 
| 190   clickHideFiltersDialog.setAttribute("style", "position: fixed !important; visi
     bility: hidden; display: block !important; border: 0px !important;"); |  | 
| 191   clickHideFiltersDialog.style.WebkitBoxShadow = "5px 5px 20px rgba(0,0,0,0.5)"; |  | 
| 192   clickHideFiltersDialog.style.zIndex = 0x7FFFFFFF; |  | 
| 193 |  | 
| 194   // Position in upper-left all the time |  | 
| 195   clickHideFiltersDialog.style.left = "50px"; |  | 
| 196   clickHideFiltersDialog.style.top = "50px"; |  | 
| 197 |  | 
| 198   // Make dialog partly transparent when mouse isn't over it so user has a bette
     r |  | 
| 199   // view of what's going to be blocked |  | 
| 200   clickHideFiltersDialog.onmouseout = function() |  | 
| 201   { |  | 
| 202     if (clickHideFiltersDialog) |  | 
| 203       clickHideFiltersDialog.style.setProperty("opacity", "0.7"); |  | 
| 204   }; |  | 
| 205   clickHideFiltersDialog.onmouseover = function() |  | 
| 206   { |  | 
| 207     if (clickHideFiltersDialog) |  | 
| 208       clickHideFiltersDialog.style.setProperty("opacity", "1.0"); |  | 
| 209   }; |  | 
| 210 |  | 
| 211   document.documentElement.appendChild(clickHideFiltersDialog); |  | 
| 212 } |  | 
| 213 |  | 
| 214 // Turn on the choose element to create filter thing |  | 
| 215 function clickHide_activate() { |  | 
| 216   if(document == null) |  | 
| 217     return; |  | 
| 218 |  | 
| 219   // If we are already selecting, abort now |  | 
| 220   if (clickHide_activated || clickHideFiltersDialog) |  | 
| 221     clickHide_deactivate(); |  | 
| 222 |  | 
| 223   // Add overlays for blockable elements that don't emit mouse events, |  | 
| 224   // so that they can still be selected. |  | 
| 225   [].forEach.call( |  | 
| 226     document.querySelectorAll('object,embed,iframe,frame'), |  | 
| 227     function(element) |  | 
| 228     { |  | 
| 229       getFiltersForElement(element, function(filters) |  | 
| 230       { |  | 
| 231         if (filters.length > 0) |  | 
| 232           addElementOverlay(element); |  | 
| 233       }); |  | 
| 234     } |  | 
| 235   ); |  | 
| 236 |  | 
| 237   clickHide_activated = true; |  | 
| 238   document.addEventListener("mousedown", clickHide_stopPropagation, true); |  | 
| 239   document.addEventListener("mouseup", clickHide_stopPropagation, true); |  | 
| 240   document.addEventListener("mouseenter", clickHide_stopPropagation, true); |  | 
| 241   document.addEventListener("mouseleave", clickHide_stopPropagation, true); |  | 
| 242   document.addEventListener("mouseover", clickHide_mouseOver, true); |  | 
| 243   document.addEventListener("mouseout", clickHide_mouseOut, true); |  | 
| 244   document.addEventListener("click", clickHide_mouseClick, true); |  | 
| 245   document.addEventListener("keydown", clickHide_keyDown, true); |  | 
| 246 |  | 
| 247   ext.onExtensionUnloaded.addListener(clickHide_deactivate); |  | 
| 248 } |  | 
| 249 |  | 
| 250 // Called when user has clicked on something and we are waiting for confirmation |  | 
| 251 // on whether the user actually wants these filters |  | 
| 252 function clickHide_rulesPending() { |  | 
| 253   clickHide_activated = false; |  | 
| 254 |  | 
| 255   if (clickHideFiltersDialog) |  | 
| 256   { |  | 
| 257     document.documentElement.removeChild(clickHideFiltersDialog); |  | 
| 258     clickHideFiltersDialog = null; |  | 
| 259   } |  | 
| 260 |  | 
| 261   document.removeEventListener("mousedown", clickHide_stopPropagation, true); |  | 
| 262   document.removeEventListener("mouseup", clickHide_stopPropagation, true); |  | 
| 263   document.removeEventListener("mouseenter", clickHide_stopPropagation, true); |  | 
| 264   document.removeEventListener("mouseleave", clickHide_stopPropagation, true); |  | 
| 265   document.removeEventListener("mouseover", clickHide_mouseOver, true); |  | 
| 266   document.removeEventListener("mouseout", clickHide_mouseOut, true); |  | 
| 267   document.removeEventListener("click", clickHide_mouseClick, true); |  | 
| 268   document.removeEventListener("keydown", clickHide_keyDown, true); |  | 
| 269 } |  | 
| 270 |  | 
| 271 function clickHide_deactivate() |  | 
| 272 { |  | 
| 273   clickHide_rulesPending(); |  | 
| 274 |  | 
| 275   clickHide_filters = null; |  | 
| 276   lastRightClickEvent = null; |  | 
| 277 |  | 
| 278   if (currentElement) |  | 
| 279   { |  | 
| 280     currentElement.removeEventListener("contextmenu",  clickHide_elementClickHan
     dler, true); |  | 
| 281     unhighlightElement(currentElement); |  | 
| 282     currentElement = null; |  | 
| 283   } |  | 
| 284   unhighlightElements(); |  | 
| 285 |  | 
| 286   var overlays = document.getElementsByClassName("__adblockplus__overlay"); |  | 
| 287   while (overlays.length > 0) |  | 
| 288     overlays[0].parentNode.removeChild(overlays[0]); |  | 
| 289 |  | 
| 290   ext.onExtensionUnloaded.removeListener(clickHide_deactivate); |  | 
| 291 } |  | 
| 292 |  | 
| 293 function clickHide_stopPropagation(e) |  | 
| 294 { |  | 
| 295   e.stopPropagation(); |  | 
| 296 } |  | 
| 297 |  | 
| 298 function clickHide_elementClickHandler(e) { |  | 
| 299   e.preventDefault(); |  | 
| 300   e.stopPropagation(); |  | 
| 301   clickHide_mouseClick(e); |  | 
| 302 } |  | 
| 303 |  | 
| 304 function getBlockableElementOrAncestor(element, callback) |  | 
| 305 { |  | 
| 306   // We assume that the user doesn't want to block the whole page. |  | 
| 307   // So we never consider the <html> or <body> element. |  | 
| 308   while (element && element != document.documentElement |  | 
| 309                  && element != document.body) |  | 
| 310   { |  | 
| 311     // We can't handle non-HTML (like SVG) elements, as well as |  | 
| 312     // <area> elements (see below). So fall back to the parent element. |  | 
| 313     if (!(element instanceof HTMLElement) || element.localName == "area") |  | 
| 314       element = element.parentElement; |  | 
| 315 |  | 
| 316     // If image maps are used mouse events occur for the <area> element. |  | 
| 317     // But we have to block the image associated with the <map> element. |  | 
| 318     else if (element.localName == "map") |  | 
| 319     { |  | 
| 320       var images = document.querySelectorAll("img[usemap]"); |  | 
| 321       var image = null; |  | 
| 322 |  | 
| 323       for (var i = 0; i < images.length; i++) |  | 
| 324       { |  | 
| 325         var usemap = images[i].getAttribute("usemap"); |  | 
| 326         var index = usemap.indexOf("#"); |  | 
| 327 |  | 
| 328         if (index != -1 && usemap.substr(index + 1) == element.name) |  | 
| 329         { |  | 
| 330           image = images[i]; |  | 
| 331           break; |  | 
| 332         } |  | 
| 333       } |  | 
| 334 |  | 
| 335       element = image; |  | 
| 336     } |  | 
| 337 |  | 
| 338     // Finally, if none of the above is true, check whether we can generate |  | 
| 339     // any filters for this element. Otherwise fall back to its parent element. |  | 
| 340     else |  | 
| 341     { |  | 
| 342       getFiltersForElement(element, function(filters) |  | 
| 343       { |  | 
| 344         if (filters.length > 0) |  | 
| 345           callback(element); |  | 
| 346         else |  | 
| 347           getBlockableElementOrAncestor(element.parentElement, callback); |  | 
| 348       }); |  | 
| 349 |  | 
| 350       return; |  | 
| 351     } |  | 
| 352   } |  | 
| 353 |  | 
| 354   // We reached the document root without finding a blockable element. |  | 
| 355   callback(null); |  | 
| 356 } |  | 
| 357 |  | 
| 358 // Hovering over an element so highlight it |  | 
| 359 function clickHide_mouseOver(e) |  | 
| 360 { |  | 
| 361   lastMouseOverEvent = e; |  | 
| 362 |  | 
| 363   getBlockableElementOrAncestor(e.target, function(element) |  | 
| 364   { |  | 
| 365     if (e == lastMouseOverEvent) |  | 
| 366     { |  | 
| 367       lastMouseOverEvent = null; |  | 
| 368 |  | 
| 369       if (clickHide_activated) |  | 
| 370       { |  | 
| 371         if (currentElement) |  | 
| 372           unhighlightElement(currentElement); |  | 
| 373 |  | 
| 374         if (element) |  | 
| 375         { |  | 
| 376           highlightElement(element, "#d6d84b", "#f8fa47"); |  | 
| 377           element.addEventListener("contextmenu", clickHide_elementClickHandler,
      true); |  | 
| 378         } |  | 
| 379 |  | 
| 380         currentElement = element; |  | 
| 381       } |  | 
| 382     } |  | 
| 383   }); |  | 
| 384 |  | 
| 385   e.stopPropagation(); |  | 
| 386 } |  | 
| 387 |  | 
| 388 // No longer hovering over this element so unhighlight it |  | 
| 389 function clickHide_mouseOut(e) |  | 
| 390 { |  | 
| 391   if (!clickHide_activated || currentElement != e.target) |  | 
| 392     return; |  | 
| 393 |  | 
| 394   unhighlightElement(currentElement); |  | 
| 395   currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle
     r, true); |  | 
| 396   e.stopPropagation(); |  | 
| 397 } |  | 
| 398 |  | 
| 399 // Selects the currently hovered-over filter or cancels selection |  | 
| 400 function clickHide_keyDown(e) |  | 
| 401 { |  | 
| 402   if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 13 /*DOM_VK_RETURN*
     /) |  | 
| 403      clickHide_mouseClick(e); |  | 
| 404   else if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 27 /*DOM_VK_ES
     CAPE*/) |  | 
| 405   { |  | 
| 406     ext.backgroundPage.sendMessage( |  | 
| 407     { |  | 
| 408       type: "forward", |  | 
| 409       payload: |  | 
| 410       { |  | 
| 411         type: "clickhide-deactivate" |  | 
| 412       } |  | 
| 413     }); |  | 
| 414     e.preventDefault(); |  | 
| 415     e.stopPropagation(); |  | 
| 416   } |  | 
| 417 } |  | 
| 418 |  | 
| 419 function getFiltersForElement(element, callback) |  | 
| 420 { |  | 
| 421   ext.backgroundPage.sendMessage( |  | 
| 422     { |  | 
| 423       type: "compose-filters", |  | 
| 424       tagName: element.localName, |  | 
| 425       id: element.id, |  | 
| 426       src: element.getAttribute("src"), |  | 
| 427       style: element.getAttribute("style"), |  | 
| 428       classes: [].slice.call(element.classList), |  | 
| 429       urls: getURLsFromElement(element), |  | 
| 430       mediatype: typeMap[element.localName], |  | 
| 431       baseURL: document.location.href |  | 
| 432     }, |  | 
| 433     function(response) |  | 
| 434     { |  | 
| 435       callback(response.filters, response.selectors); |  | 
| 436     } |  | 
| 437   ); |  | 
| 438 } |  | 
| 439 |  | 
| 440 // When the user clicks, the currentElement is the one we want. |  | 
| 441 // We should have ABP rules ready for when the |  | 
| 442 // popup asks for them. |  | 
| 443 function clickHide_mouseClick(e) |  | 
| 444 { |  | 
| 445   if (!currentElement || !clickHide_activated) |  | 
| 446     return; |  | 
| 447 |  | 
| 448   var elt = currentElement; |  | 
| 449   if (currentElement.classList.contains("__adblockplus__overlay")) |  | 
| 450     elt = currentElement.prisoner; |  | 
| 451 |  | 
| 452   getFiltersForElement(elt, function(filters, selectors) |  | 
| 453   { |  | 
| 454     ext.backgroundPage.sendMessage( |  | 
| 455     { |  | 
| 456       type: "forward", |  | 
| 457       payload: |  | 
| 458       { |  | 
| 459         type: "clickhide-show-dialog", |  | 
| 460         clickHideFilters: filters |  | 
| 461       } |  | 
| 462     }); |  | 
| 463 |  | 
| 464     if (selectors.length > 0) |  | 
| 465       highlightElements(selectors.join(",")); |  | 
| 466 |  | 
| 467     highlightElement(currentElement, "#fd1708", "#f6a1b5"); |  | 
| 468   }); |  | 
| 469 |  | 
| 470   // Make sure the browser doesn't handle this click |  | 
| 471   e.preventDefault(); |  | 
| 472   e.stopPropagation(); |  | 
| 473 } |  | 
| 474 |  | 
| 475 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js |  | 
| 476 // and licensed under the MIT license. See jquery-*.min.js for details. |  | 
| 477 function removeDotSegments(u) { |  | 
| 478   var r = '', m = []; |  | 
| 479   if (/\./.test(u)) { |  | 
| 480     while (u !== undefined && u !== '') { |  | 
| 481       if (u === '.' || u === '..') { |  | 
| 482         u = ''; |  | 
| 483       } else if (/^\.\.\//.test(u)) { // starts with ../ |  | 
| 484         u = u.substring(3); |  | 
| 485       } else if (/^\.\//.test(u)) { // starts with ./ |  | 
| 486         u = u.substring(2); |  | 
| 487       } else if (/^\/\.(\/|$)/.test(u)) { // starts with /./ or consists of /. |  | 
| 488         u = '/' + u.substring(3); |  | 
| 489       } else if (/^\/\.\.(\/|$)/.test(u)) { // starts with /../ or consists of /
     .. |  | 
| 490         u = '/' + u.substring(4); |  | 
| 491         r = r.replace(/\/?[^\/]+$/, ''); |  | 
| 492       } else { |  | 
| 493         m = u.match(/^(\/?[^\/]*)(\/.*)?$/); |  | 
| 494         u = m[2]; |  | 
| 495         r = r + m[1]; |  | 
| 496       } |  | 
| 497     } |  | 
| 498     return r; |  | 
| 499   } else { |  | 
| 500     return u; |  | 
| 501   } |  | 
| 502 } |  | 
| 503 |  | 
| 504 // In Chrome 37-40, the document_end content script (this one) runs properly, wh
     ile the |  | 
| 505 // document_start content scripts (that defines ext) might not. Check whether va
     riable ext |  | 
| 506 // exists before continuing to avoid "Uncaught ReferenceError: ext is not define
     d". |  | 
| 507 // See https://crbug.com/416907 |  | 
| 508 if ("ext" in window && document instanceof HTMLDocument) |  | 
| 509 { |  | 
| 510   // Use a contextmenu handler to save the last element the user right-clicked o
     n. |  | 
| 511   // To make things easier, we actually save the DOM event. |  | 
| 512   // We have to do this because the contextMenu API only provides a URL, not the
      actual |  | 
| 513   // DOM element. |  | 
| 514   document.addEventListener('contextmenu', function(e) |  | 
| 515   { |  | 
| 516     lastRightClickEvent = e; |  | 
| 517     // We also need to ensure any old lastRightClickEvent variables in other |  | 
| 518     // frames are cleared. |  | 
| 519     lastRightClickEventValid = true; |  | 
| 520     ext.backgroundPage.sendMessage( |  | 
| 521     { |  | 
| 522       type: "forward", |  | 
| 523       payload: |  | 
| 524       { |  | 
| 525         type: "clickhide-clear-last-right-click-event" |  | 
| 526       } |  | 
| 527     }); |  | 
| 528   }, true); |  | 
| 529 |  | 
| 530   document.addEventListener("click", function(event) |  | 
| 531   { |  | 
| 532     // Ignore right-clicks |  | 
| 533     if (event.button == 2) |  | 
| 534       return; |  | 
| 535 |  | 
| 536     // Search the link associated with the click |  | 
| 537     var link = event.target; |  | 
| 538     while (!(link instanceof HTMLAnchorElement)) |  | 
| 539     { |  | 
| 540       link = link.parentNode; |  | 
| 541 |  | 
| 542       if (!link) |  | 
| 543         return; |  | 
| 544     } |  | 
| 545 |  | 
| 546     if (link.protocol == "http:" || link.protocol == "https:") |  | 
| 547     { |  | 
| 548       if (link.host != "subscribe.adblockplus.org" || link.pathname != "/") |  | 
| 549         return; |  | 
| 550     } |  | 
| 551     else if (!/^abp:\/*subscribe\/*\?/i.test(link.href)) |  | 
| 552       return; |  | 
| 553 |  | 
| 554     // This is our link - make sure the browser doesn't handle it |  | 
| 555     event.preventDefault(); |  | 
| 556     event.stopPropagation(); |  | 
| 557 |  | 
| 558     // Decode URL parameters |  | 
| 559     var params = link.search.substr(1).split("&"); |  | 
| 560     var title = null; |  | 
| 561     var url = null; |  | 
| 562     for (var i = 0; i < params.length; i++) |  | 
| 563     { |  | 
| 564       var parts = params[i].split("=", 2); |  | 
| 565       if (parts.length != 2 || !/\S/.test(parts[1])) |  | 
| 566         continue; |  | 
| 567       switch (parts[0]) |  | 
| 568       { |  | 
| 569         case "title": |  | 
| 570           title = decodeURIComponent(parts[1]); |  | 
| 571           break; |  | 
| 572         case "location": |  | 
| 573           url = decodeURIComponent(parts[1]); |  | 
| 574           break; |  | 
| 575       } |  | 
| 576     } |  | 
| 577     if (!url) |  | 
| 578       return; |  | 
| 579 |  | 
| 580     // Default title to the URL |  | 
| 581     if (!title) |  | 
| 582       title = url; |  | 
| 583 |  | 
| 584     // Trim spaces in title and URL |  | 
| 585     title = title.trim(); |  | 
| 586     url = url.trim(); |  | 
| 587     if (!/^(https?|ftp):/.test(url)) |  | 
| 588       return; |  | 
| 589 |  | 
| 590     ext.backgroundPage.sendMessage({ |  | 
| 591       type: "add-subscription", |  | 
| 592       title: title, |  | 
| 593       url: url |  | 
| 594     }); |  | 
| 595   }, true); |  | 
| 596 |  | 
| 597   ext.onMessage.addListener(function(msg, sender, sendResponse) |  | 
| 598   { |  | 
| 599     switch (msg.type) |  | 
| 600     { |  | 
| 601       case "get-clickhide-state": |  | 
| 602         sendResponse({active: clickHide_activated}); |  | 
| 603         break; |  | 
| 604       case "clickhide-activate": |  | 
| 605         clickHide_activate(); |  | 
| 606         break; |  | 
| 607       case "clickhide-deactivate": |  | 
| 608         clickHide_deactivate(); |  | 
| 609         break; |  | 
| 610       case "clickhide-new-filter": |  | 
| 611         if(lastRightClickEvent) |  | 
| 612         { |  | 
| 613           var event = lastRightClickEvent; |  | 
| 614           getBlockableElementOrAncestor(event.target, function(element) |  | 
| 615           { |  | 
| 616             clickHide_activate(); |  | 
| 617             currentElement = element; |  | 
| 618             clickHide_mouseClick(event); |  | 
| 619           }); |  | 
| 620         } |  | 
| 621         break; |  | 
| 622       case "clickhide-init": |  | 
| 623         if (clickHideFiltersDialog) |  | 
| 624         { |  | 
| 625           sendResponse({filters: clickHide_filters}); |  | 
| 626 |  | 
| 627           clickHideFiltersDialog.style.width = msg.width + "px"; |  | 
| 628           clickHideFiltersDialog.style.height = msg.height + "px"; |  | 
| 629           clickHideFiltersDialog.style.visibility = "visible"; |  | 
| 630         } |  | 
| 631         break; |  | 
| 632       case "clickhide-move": |  | 
| 633         if (clickHideFiltersDialog) |  | 
| 634         { |  | 
| 635           var rect = clickHideFiltersDialog.getBoundingClientRect(); |  | 
| 636           var x = Math.max(0, Math.min(rect.left + msg.x, window.innerWidth - re
     ct.width)); |  | 
| 637           var y = Math.max(0, Math.min(rect.top + msg.y, window.innerHeight - re
     ct.height)); |  | 
| 638 |  | 
| 639           clickHideFiltersDialog.style.left = x + "px"; |  | 
| 640           clickHideFiltersDialog.style.top = y + "px"; |  | 
| 641         } |  | 
| 642         break; |  | 
| 643       case "clickhide-close": |  | 
| 644         if (currentElement && msg.remove) |  | 
| 645         { |  | 
| 646           // Hide the selected element itself if an added blocking |  | 
| 647           // filter is causing it to collapse. Note that this |  | 
| 648           // behavior is incomplete, but the best we can do here, |  | 
| 649           // e.g. if an added blocking filter matches other elements, |  | 
| 650           // the effect won't be visible until the page is is reloaded. |  | 
| 651           checkCollapse(currentElement.prisoner || currentElement); |  | 
| 652 |  | 
| 653           // Apply added element hiding filters. |  | 
| 654           updateStylesheet(); |  | 
| 655         } |  | 
| 656         clickHide_deactivate(); |  | 
| 657         break; |  | 
| 658       case "clickhide-show-dialog": |  | 
| 659         clickHide_rulesPending(); |  | 
| 660         if (window.self == window.top) |  | 
| 661           clickHide_showDialog(msg.clickHideFilters); |  | 
| 662         break; |  | 
| 663       case "clickhide-clear-last-right-click-event": |  | 
| 664         if (lastRightClickEventValid) |  | 
| 665           lastRightClickEventValid = false; |  | 
| 666         else |  | 
| 667           lastRightClickEvent = null; |  | 
| 668         break; |  | 
| 669     } |  | 
| 670   }); |  | 
| 671 |  | 
| 672   if (window == window.top) |  | 
| 673     ext.backgroundPage.sendMessage({type: "report-html-page"}); |  | 
| 674 } |  | 
| OLD | NEW | 
|---|