| OLD | NEW |
| 1 /* | 1 /* |
| 2 * This file is part of Adblock Plus <http://adblockplus.org/>, | 2 * This file is part of Adblock Plus <http://adblockplus.org/>, |
| 3 * Copyright (C) 2006-2014 Eyeo GmbH | 3 * Copyright (C) 2006-2014 Eyeo GmbH |
| 4 * | 4 * |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | 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 | 6 * it under the terms of the GNU General Public License version 3 as |
| 7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
| 8 * | 8 * |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 function quote(value) | 41 function quote(value) |
| 42 { | 42 { |
| 43 return '"' + value.replace(/["\\\{\}\x00-\x1F\x7F]/g, escapeChar) + '"'; | 43 return '"' + value.replace(/["\\\{\}\x00-\x1F\x7F]/g, escapeChar) + '"'; |
| 44 } | 44 } |
| 45 | 45 |
| 46 function escapeCSS(s) | 46 function escapeCSS(s) |
| 47 { | 47 { |
| 48 return s.replace(/^[\d\-]|[^\w\-\u0080-\uFFFF]/g, escapeChar); | 48 return s.replace(/^[\d\-]|[^\w\-\u0080-\uFFFF]/g, escapeChar); |
| 49 } | 49 } |
| 50 | 50 |
| 51 function supportsShadowRoot(element) | |
| 52 { | |
| 53 if (!("createShadowRoot" in element)) | |
| 54 return false; | |
| 55 | |
| 56 // There are some elements (e.g. <textarea>), which don't | |
| 57 // support author created shadow roots and throw an exception. | |
| 58 var clone = element.cloneNode(false); | |
| 59 try | |
| 60 { | |
| 61 clone.createShadowRoot(); | |
| 62 } | |
| 63 catch (e) | |
| 64 { | |
| 65 return false; | |
| 66 } | |
| 67 | |
| 68 // There are some elements (e.g. <input>), which support | |
| 69 // author created shadow roots, but ignore insertion points. | |
| 70 var child = document.createTextNode(""); | |
| 71 clone.appendChild(child); | |
| 72 | |
| 73 var shadow = document.createElement("shadow"); | |
| 74 clone.shadowRoot.appendChild(shadow); | |
| 75 | |
| 76 return shadow.getDistributedNodes()[0] == child; | |
| 77 } | |
| 78 | |
| 79 function getOriginalStyle(element) | |
| 80 { | |
| 81 if ("_originalStyle" in element) | |
| 82 return element._originalStyle; | |
| 83 | |
| 84 return element.getAttribute("style"); | |
| 85 } | |
| 86 | |
| 87 function highlightElement(element, shadowColor, backgroundColor) | 51 function highlightElement(element, shadowColor, backgroundColor) |
| 88 { | 52 { |
| 89 unhighlightElement(element); | 53 unhighlightElement(element); |
| 90 | 54 |
| 91 var originalBoxShadowPriority = element.style.getPropertyPriority("box-shadow"
); | 55 var highlightWithOverlay = function() |
| 92 var originalBackgroundColorPriority = element.style.getPropertyPriority("backg
round-color"); | 56 { |
| 57 var overlay = addElementOverlay(element); |
| 93 | 58 |
| 94 var boxShadow = "inset 0px 0px 5px " + shadowColor; | 59 highlightElement(overlay, shadowColor, backgroundColor); |
| 95 | 60 overlay.style.pointerEvents = "none"; |
| 96 var highlightWithShadowDOM = function() | |
| 97 { | |
| 98 var style = document.createElement("style"); | |
| 99 style.textContent = ":host {" + | |
| 100 "box-shadow:" + boxShadow + " !important;" + | |
| 101 "background-color:" + backgroundColor + " !important;" + | |
| 102 "}"; | |
| 103 | |
| 104 var root = element.createShadowRoot(); | |
| 105 root.appendChild(document.createElement("shadow")); | |
| 106 root.appendChild(style); | |
| 107 | 61 |
| 108 element._unhighlight = function() | 62 element._unhighlight = function() |
| 109 { | 63 { |
| 110 root.removeChild(style); | 64 overlay.parentNode.removeChild(overlay); |
| 111 }; | 65 }; |
| 112 }; | 66 }; |
| 113 | 67 |
| 114 var highlightWithStyleAttribute = function() | 68 var highlightWithStyleAttribute = function() |
| 115 { | 69 { |
| 116 var originalBoxShadow = element.style.getPropertyValue("box-shadow"); | 70 var originalBoxShadow = element.style.getPropertyValue("box-shadow"); |
| 71 var originalBoxShadowPriority = element.style.getPropertyPriority("box-shado
w"); |
| 117 var originalBackgroundColor = element.style.getPropertyValue("background-col
or"); | 72 var originalBackgroundColor = element.style.getPropertyValue("background-col
or"); |
| 73 var originalBackgroundColorPriority = element.style.getPropertyPriority("bac
kground-color"); |
| 118 | 74 |
| 119 element._originalStyle = getOriginalStyle(element); | 75 element.style.setProperty("box-shadow", "inset 0px 0px 5px " + shadowColor,
"important"); |
| 120 | |
| 121 element.style.setProperty("box-shadow", boxShadow, "important"); | |
| 122 element.style.setProperty("background-color", backgroundColor, "important"); | 76 element.style.setProperty("background-color", backgroundColor, "important"); |
| 123 | 77 |
| 124 element._unhighlight = function() | 78 element._unhighlight = function() |
| 125 { | 79 { |
| 126 this.style.removeProperty("box-shadow"); | 80 this.style.removeProperty("box-shadow"); |
| 127 this.style.setProperty( | 81 this.style.setProperty( |
| 128 "box-shadow", | 82 "box-shadow", |
| 129 originalBoxShadow, | 83 originalBoxShadow, |
| 130 originalBoxShadowPriority | 84 originalBoxShadowPriority |
| 131 ); | 85 ); |
| 132 | 86 |
| 133 this.style.removeProperty("background-color"); | 87 this.style.removeProperty("background-color"); |
| 134 this.style.setProperty( | 88 this.style.setProperty( |
| 135 "background-color", | 89 "background-color", |
| 136 originalBackgroundColor, | 90 originalBackgroundColor, |
| 137 originalBackgroundColorPriority | 91 originalBackgroundColorPriority |
| 138 ); | 92 ); |
| 139 }; | 93 }; |
| 140 }; | 94 }; |
| 141 | 95 |
| 142 // Use shadow DOM if posibble to avoid side effects when the | 96 if ("prisoner" in element) |
| 143 // web page updates style while highlighted. However, if the | 97 highlightWithStyleAttribute(); |
| 144 // element has important styles we can't override them with shadow DOM. | |
| 145 if (supportsShadowRoot(element) && originalBoxShadowPriority != "importa
nt" && | |
| 146 originalBackgroundColorPriority != "importa
nt") | |
| 147 highlightWithShadowDOM(); | |
| 148 else | 98 else |
| 149 highlightWithStyleAttribute(); | 99 highlightWithOverlay(); |
| 150 } | 100 } |
| 151 | 101 |
| 152 | 102 |
| 153 function unhighlightElement(element) | 103 function unhighlightElement(element) |
| 154 { | 104 { |
| 155 if ("_unhighlight" in element) | 105 if ("_unhighlight" in element) |
| 156 { | 106 { |
| 157 element._unhighlight(); | 107 element._unhighlight(); |
| 158 delete element._unhighlight; | 108 delete element._unhighlight; |
| 159 } | 109 } |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 if (element.id) | 222 if (element.id) |
| 273 return true; | 223 return true; |
| 274 if (element.classList.length > 0) | 224 if (element.classList.length > 0) |
| 275 return true; | 225 return true; |
| 276 if (getURLsFromElement(element).length > 0) | 226 if (getURLsFromElement(element).length > 0) |
| 277 return true; | 227 return true; |
| 278 | 228 |
| 279 // We only generate filters based on the "style" attribute, | 229 // We only generate filters based on the "style" attribute, |
| 280 // if this is the only way we can generate a filter, and | 230 // if this is the only way we can generate a filter, and |
| 281 // only if there are at least two CSS properties defined. | 231 // only if there are at least two CSS properties defined. |
| 282 if (/:.+:/.test(getOriginalStyle(element))) | 232 if (/:.+:/.test(element.getAttribute("style"))) |
| 283 return true; | 233 return true; |
| 284 | 234 |
| 285 return false; | 235 return false; |
| 286 } | 236 } |
| 287 | 237 |
| 288 // Gets the absolute position of an element by walking up the DOM tree, | 238 // Gets the absolute position of an element by walking up the DOM tree, |
| 289 // adding up offsets. | 239 // adding up offsets. |
| 290 // I hope there's a better way because it just seems absolutely stupid | 240 // I hope there's a better way because it just seems absolutely stupid |
| 291 // that the DOM wouldn't have a direct way to get this, given that it | 241 // that the DOM wouldn't have a direct way to get this, given that it |
| 292 // has hundreds and hundreds of other methods that do random junk. | 242 // has hundreds and hundreds of other methods that do random junk. |
| 293 function getAbsolutePosition(elt) { | 243 function getAbsolutePosition(elt) { |
| 294 var l = 0; | 244 var l = 0; |
| 295 var t = 0; | 245 var t = 0; |
| 296 for(; elt; elt = elt.offsetParent) { | 246 for(; elt; elt = elt.offsetParent) { |
| 297 l += elt.offsetLeft; | 247 l += elt.offsetLeft; |
| 298 t += elt.offsetTop; | 248 t += elt.offsetTop; |
| 299 } | 249 } |
| 300 return [l, t]; | 250 return [l, t]; |
| 301 } | 251 } |
| 302 | 252 |
| 303 // Adds an overlay to an element, which is probably a Flash object | 253 // Adds an overlay to an element, which is probably a Flash object |
| 304 function addElementOverlay(elt) { | 254 function addElementOverlay(elt) { |
| 305 // If this element is enclosed in an object tag, we prefer to block that inste
ad | |
| 306 if(!elt) | |
| 307 return null; | |
| 308 | |
| 309 // If element doesn't have at least one of class name, ID or URL, give up | |
| 310 // because we don't know how to construct a filter rule for it | |
| 311 if(!isBlockable(elt)) | |
| 312 return; | |
| 313 | |
| 314 // If the element isn't rendered (since its or one of its ancestor's | 255 // If the element isn't rendered (since its or one of its ancestor's |
| 315 // "display" property is "none"), the overlay wouldn't match the element. | 256 // "display" property is "none"), the overlay wouldn't match the element. |
| 316 if (!elt.offsetParent) | 257 if (!elt.offsetParent) |
| 317 return; | 258 return; |
| 318 | 259 |
| 319 var thisStyle = getComputedStyle(elt, null); | 260 var thisStyle = getComputedStyle(elt, null); |
| 320 var overlay = document.createElement('div'); | 261 var overlay = document.createElement('div'); |
| 321 overlay.prisoner = elt; | 262 overlay.prisoner = elt; |
| 322 overlay.className = "__adblockplus__overlay"; | 263 overlay.className = "__adblockplus__overlay"; |
| 323 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;'); | 264 overlay.setAttribute('style', 'opacity:0.4; display:inline-box; position:absol
ute; overflow:hidden; box-sizing:border-box;'); |
| 324 var pos = getAbsolutePosition(elt); | 265 var pos = getAbsolutePosition(elt); |
| 266 overlay.style.width = elt.offsetWidth + "px"; |
| 267 overlay.style.height = elt.offsetHeight + "px"; |
| 325 overlay.style.left = pos[0] + "px"; | 268 overlay.style.left = pos[0] + "px"; |
| 326 overlay.style.top = pos[1] + "px"; | 269 overlay.style.top = pos[1] + "px"; |
| 327 | 270 |
| 328 if (thisStyle.position != "static") | 271 if (thisStyle.position != "static") |
| 329 overlay.style.zIndex = thisStyle.zIndex; | 272 overlay.style.zIndex = thisStyle.zIndex; |
| 330 else | 273 else |
| 331 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; | 274 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; |
| 332 | 275 |
| 333 // elt.parentNode.appendChild(overlay, elt); | 276 // elt.parentNode.appendChild(overlay, elt); |
| 334 document.body.appendChild(overlay); | 277 document.body.appendChild(overlay); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 | 316 |
| 374 // Turn on the choose element to create filter thing | 317 // Turn on the choose element to create filter thing |
| 375 function clickHide_activate() { | 318 function clickHide_activate() { |
| 376 if(document == null) | 319 if(document == null) |
| 377 return; | 320 return; |
| 378 | 321 |
| 379 // If we are already selecting, abort now | 322 // If we are already selecting, abort now |
| 380 if (clickHide_activated || clickHideFiltersDialog) | 323 if (clickHide_activated || clickHideFiltersDialog) |
| 381 clickHide_deactivate(); | 324 clickHide_deactivate(); |
| 382 | 325 |
| 383 // Add overlays for elements with URLs so user can easily click them | 326 // Add overlays for blockable elements that don't emit mouse events that they
can still be selected |
| 384 var elts = document.querySelectorAll('object,embed,img,iframe,video,audio,pict
ure'); | 327 var elts = document.querySelectorAll('object,embed,iframe'); |
| 385 for(var i=0; i<elts.length; i++) | 328 for(var i=0; i<elts.length; i++) |
| 386 addElementOverlay(elts[i]); | 329 { |
| 330 var element = elts[i]; |
| 331 if (isBlockable(element)) |
| 332 addElementOverlay(element); |
| 333 } |
| 387 | 334 |
| 388 clickHide_activated = true; | 335 clickHide_activated = true; |
| 389 document.addEventListener("mouseover", clickHide_mouseOver, true); | 336 document.addEventListener("mouseover", clickHide_mouseOver, true); |
| 390 document.addEventListener("mouseout", clickHide_mouseOut, true); | 337 document.addEventListener("mouseout", clickHide_mouseOut, true); |
| 391 document.addEventListener("click", clickHide_mouseClick, true); | 338 document.addEventListener("click", clickHide_mouseClick, true); |
| 392 document.addEventListener("keydown", clickHide_keyDown, true); | 339 document.addEventListener("keydown", clickHide_keyDown, true); |
| 393 } | 340 } |
| 394 | 341 |
| 395 // Called when user has clicked on something and we are waiting for confirmation | 342 // Called when user has clicked on something and we are waiting for confirmation |
| 396 // on whether the user actually wants these filters | 343 // on whether the user actually wants these filters |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 546 continue; | 493 continue; |
| 547 } | 494 } |
| 548 | 495 |
| 549 if (url == elt.src) | 496 if (url == elt.src) |
| 550 addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("s
rc")) + ']'); | 497 addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("s
rc")) + ']'); |
| 551 } | 498 } |
| 552 | 499 |
| 553 // as last resort, create a filter based on inline styles | 500 // as last resort, create a filter based on inline styles |
| 554 if (clickHideFilters.length == 0) | 501 if (clickHideFilters.length == 0) |
| 555 { | 502 { |
| 556 var style = getOriginalStyle(elt); | 503 var style = elt.getAttribute("style"); |
| 557 if (style) | 504 if (style) |
| 558 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']'); | 505 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']'); |
| 559 } | 506 } |
| 560 | 507 |
| 561 // Show popup | 508 // Show popup |
| 562 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); | 509 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); |
| 563 | 510 |
| 564 // Highlight the elements specified by selector in yellow | 511 // Highlight the elements specified by selector in yellow |
| 565 if (selectorList.length > 0) | 512 if (selectorList.length > 0) |
| 566 highlightElements(selectorList.join(",")); | 513 highlightElements(selectorList.join(",")); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 686 case "clickhide-activate": | 633 case "clickhide-activate": |
| 687 clickHide_activate(); | 634 clickHide_activate(); |
| 688 break; | 635 break; |
| 689 case "clickhide-deactivate": | 636 case "clickhide-deactivate": |
| 690 clickHide_deactivate(); | 637 clickHide_deactivate(); |
| 691 break; | 638 break; |
| 692 case "clickhide-new-filter": | 639 case "clickhide-new-filter": |
| 693 if(lastRightClickEvent) | 640 if(lastRightClickEvent) |
| 694 { | 641 { |
| 695 clickHide_activated = true; | 642 clickHide_activated = true; |
| 696 currentElement = addElementOverlay(lastRightClickEvent.target); | 643 currentElement = lastRightClickEvent.target; |
| 697 clickHide_mouseClick(lastRightClickEvent); | 644 clickHide_mouseClick(lastRightClickEvent); |
| 698 } | 645 } |
| 699 break; | 646 break; |
| 700 case "clickhide-init": | 647 case "clickhide-init": |
| 701 if (clickHideFiltersDialog) | 648 if (clickHideFiltersDialog) |
| 702 { | 649 { |
| 703 sendResponse({filters: clickHide_filters}); | 650 sendResponse({filters: clickHide_filters}); |
| 704 | 651 |
| 705 clickHideFiltersDialog.style.width = msg.width + "px"; | 652 clickHideFiltersDialog.style.width = msg.width + "px"; |
| 706 clickHideFiltersDialog.style.height = msg.height + "px"; | 653 clickHideFiltersDialog.style.height = msg.height + "px"; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 723 element.parentNode.removeChild(element); | 670 element.parentNode.removeChild(element); |
| 724 } | 671 } |
| 725 clickHide_deactivate(); | 672 clickHide_deactivate(); |
| 726 break; | 673 break; |
| 727 } | 674 } |
| 728 }); | 675 }); |
| 729 | 676 |
| 730 if (window == window.top) | 677 if (window == window.top) |
| 731 ext.backgroundPage.sendMessage({type: "report-html-page"}); | 678 ext.backgroundPage.sendMessage({type: "report-html-page"}); |
| 732 } | 679 } |
| OLD | NEW |