| Left: | ||
| Right: |
| 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"); | |
| 93 | |
| 94 var boxShadow = "inset 0px 0px 5px " + shadowColor; | |
| 95 | |
| 96 var highlightWithShadowDOM = function() | |
| 97 { | 56 { |
| 98 var style = document.createElement("style"); | 57 highlightElement(overlay, shadowColor, backgroundColor); |
| 99 style.textContent = ":host {" + | 58 overlay.style.pointerEvents = "none"; |
| 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 | 59 |
| 108 element._unhighlight = function() | 60 element._unhighlight = function() |
|
kzar
2015/01/13 11:04:24
Could this cause a memory leak as _unhighlight fun
Sebastian Noack
2015/01/13 13:03:53
It is actually removed, see unhighlightElement().
| |
| 109 { | 61 { |
| 110 root.removeChild(style); | 62 overlay.parentNode.removeChild(overlay); |
| 111 }; | 63 }; |
| 112 }; | 64 }; |
| 113 | 65 |
| 114 var highlightWithStyleAttribute = function() | 66 var highlightWithStyleAttribute = function() |
| 115 { | 67 { |
| 116 var originalBoxShadow = element.style.getPropertyValue("box-shadow"); | 68 var originalBoxShadow = element.style.getPropertyValue ("box -shadow"); |
|
kzar
2015/01/13 11:04:24
Why extra spacing before opening bracket? (Maybe i
Sebastian Noack
2015/01/13 13:03:53
I find it more readable, when similar code is alig
| |
| 117 var originalBackgroundColor = element.style.getPropertyValue("background-col or"); | 69 var originalBoxShadowPriority = element.style.getPropertyPriority("box -shadow"); |
| 70 var originalBackgroundColor = element.style.getPropertyValue ("bac kground-color"); | |
| 71 var originalBackgroundColorPriority = element.style.getPropertyPriority("bac kground-color"); | |
| 118 | 72 |
| 119 element._originalStyle = getOriginalStyle(element); | 73 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"); | 74 element.style.setProperty("background-color", backgroundColor, "important"); |
| 123 | 75 |
| 124 element._unhighlight = function() | 76 element._unhighlight = function() |
| 125 { | 77 { |
| 126 this.style.removeProperty("box-shadow"); | 78 this.style.removeProperty("box-shadow"); |
| 127 this.style.setProperty( | 79 this.style.setProperty( |
| 128 "box-shadow", | 80 "box-shadow", |
| 129 originalBoxShadow, | 81 originalBoxShadow, |
| 130 originalBoxShadowPriority | 82 originalBoxShadowPriority |
| 131 ); | 83 ); |
| 132 | 84 |
| 133 this.style.removeProperty("background-color"); | 85 this.style.removeProperty("background-color"); |
| 134 this.style.setProperty( | 86 this.style.setProperty( |
| 135 "background-color", | 87 "background-color", |
| 136 originalBackgroundColor, | 88 originalBackgroundColor, |
| 137 originalBackgroundColorPriority | 89 originalBackgroundColorPriority |
| 138 ); | 90 ); |
| 139 }; | 91 }; |
| 140 }; | 92 }; |
| 141 | 93 |
| 142 // Use shadow DOM if posibble to avoid side effects when the | 94 var overlay; |
|
kzar
2015/01/13 11:04:24
Seems confusing to me that overlay is declared her
Sebastian Noack
2015/01/13 13:03:53
I moved the declaration into highlightWithOverlay(
| |
| 143 // web page updates style while highlighted. However, if the | 95 if (!("prisoner" in element) && (overlay = addElementOverlay(element))) |
|
kzar
2015/01/13 11:04:24
Could you add a comment before this if statement e
Sebastian Noack
2015/01/13 13:03:53
We only highlight elements with style attributes i
| |
| 144 // element has important styles we can't override them with shadow DOM. | 96 highlightWithOverlay(); |
| 145 if (supportsShadowRoot(element) && originalBoxShadowPriority != "importa nt" && | |
| 146 originalBackgroundColorPriority != "importa nt") | |
| 147 highlightWithShadowDOM(); | |
| 148 else | 97 else |
| 149 highlightWithStyleAttribute(); | 98 highlightWithStyleAttribute(); |
| 150 } | 99 } |
| 151 | 100 |
| 152 | 101 |
| 153 function unhighlightElement(element) | 102 function unhighlightElement(element) |
| 154 { | 103 { |
| 155 if ("_unhighlight" in element) | 104 if ("_unhighlight" in element) |
| 156 { | 105 { |
| 157 element._unhighlight(); | 106 element._unhighlight(); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 272 if (element.id) | 221 if (element.id) |
| 273 return true; | 222 return true; |
| 274 if (element.classList.length > 0) | 223 if (element.classList.length > 0) |
| 275 return true; | 224 return true; |
| 276 if (getURLsFromElement(element).length > 0) | 225 if (getURLsFromElement(element).length > 0) |
| 277 return true; | 226 return true; |
| 278 | 227 |
| 279 // We only generate filters based on the "style" attribute, | 228 // We only generate filters based on the "style" attribute, |
| 280 // if this is the only way we can generate a filter, and | 229 // if this is the only way we can generate a filter, and |
| 281 // only if there are at least two CSS properties defined. | 230 // only if there are at least two CSS properties defined. |
| 282 if (/:.+:/.test(getOriginalStyle(element))) | 231 if (/:.+:/.test(element.getAttribute("style"))) |
| 283 return true; | 232 return true; |
| 284 | 233 |
| 285 return false; | 234 return false; |
| 286 } | 235 } |
| 287 | 236 |
| 288 // Gets the absolute position of an element by walking up the DOM tree, | 237 // Gets the absolute position of an element by walking up the DOM tree, |
| 289 // adding up offsets. | 238 // adding up offsets. |
| 290 // I hope there's a better way because it just seems absolutely stupid | 239 // 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 | 240 // 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. | 241 // has hundreds and hundreds of other methods that do random junk. |
| 293 function getAbsolutePosition(elt) { | 242 function getAbsolutePosition(elt) { |
| 294 var l = 0; | 243 var l = 0; |
| 295 var t = 0; | 244 var t = 0; |
| 296 for(; elt; elt = elt.offsetParent) { | 245 for(; elt; elt = elt.offsetParent) { |
| 297 l += elt.offsetLeft; | 246 l += elt.offsetLeft; |
| 298 t += elt.offsetTop; | 247 t += elt.offsetTop; |
| 299 } | 248 } |
| 300 return [l, t]; | 249 return [l, t]; |
| 301 } | 250 } |
| 302 | 251 |
| 303 // Adds an overlay to an element, which is probably a Flash object | 252 // Adds an overlay to an element, which is probably a Flash object |
| 304 function addElementOverlay(elt) { | 253 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 | 254 // 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. | 255 // "display" property is "none"), the overlay wouldn't match the element. |
| 316 if (!elt.offsetParent) | 256 if (!elt.offsetParent) |
| 317 return; | 257 return; |
| 318 | 258 |
| 319 var thisStyle = getComputedStyle(elt, null); | 259 var thisStyle = getComputedStyle(elt, null); |
| 320 var overlay = document.createElement('div'); | 260 var overlay = document.createElement('div'); |
| 321 overlay.prisoner = elt; | 261 overlay.prisoner = elt; |
| 322 overlay.className = "__adblockplus__overlay"; | 262 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;'); | 263 overlay.setAttribute('style', 'opacity:0.4; display:inline-box; position:absol ute; overflow:hidden; box-sizing:border-box;'); |
|
kzar
2015/01/13 11:04:24
Are these changes relevant to the issue?
kzar
2015/01/13 13:26:34
What about these changes?
Sebastian Noack
2015/01/13 13:36:11
Kinda; it already prior to my changes here, it wer
| |
| 324 var pos = getAbsolutePosition(elt); | 264 var pos = getAbsolutePosition(elt); |
| 265 overlay.style.width = elt.offsetWidth + "px"; | |
| 266 overlay.style.height = elt.offsetHeight + "px"; | |
| 325 overlay.style.left = pos[0] + "px"; | 267 overlay.style.left = pos[0] + "px"; |
| 326 overlay.style.top = pos[1] + "px"; | 268 overlay.style.top = pos[1] + "px"; |
| 327 | 269 |
| 328 if (thisStyle.position != "static") | 270 if (thisStyle.position != "static") |
| 329 overlay.style.zIndex = thisStyle.zIndex; | 271 overlay.style.zIndex = thisStyle.zIndex; |
| 330 else | 272 else |
| 331 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; | 273 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; |
| 332 | 274 |
| 333 // elt.parentNode.appendChild(overlay, elt); | 275 // elt.parentNode.appendChild(overlay, elt); |
| 334 document.body.appendChild(overlay); | 276 document.body.appendChild(overlay); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 373 | 315 |
| 374 // Turn on the choose element to create filter thing | 316 // Turn on the choose element to create filter thing |
| 375 function clickHide_activate() { | 317 function clickHide_activate() { |
| 376 if(document == null) | 318 if(document == null) |
| 377 return; | 319 return; |
| 378 | 320 |
| 379 // If we are already selecting, abort now | 321 // If we are already selecting, abort now |
| 380 if (clickHide_activated || clickHideFiltersDialog) | 322 if (clickHide_activated || clickHideFiltersDialog) |
| 381 clickHide_deactivate(); | 323 clickHide_deactivate(); |
| 382 | 324 |
| 383 // Add overlays for elements with URLs so user can easily click them | 325 // 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'); | 326 var elts = document.querySelectorAll('object,embed,iframe'); |
| 385 for(var i=0; i<elts.length; i++) | 327 for(var i=0; i<elts.length; i++) |
| 386 addElementOverlay(elts[i]); | 328 { |
| 329 var element = elts[i]; | |
| 330 if (isBlockable(element)) | |
| 331 addElementOverlay(element); | |
| 332 } | |
| 387 | 333 |
| 388 clickHide_activated = true; | 334 clickHide_activated = true; |
| 389 document.addEventListener("mouseover", clickHide_mouseOver, true); | 335 document.addEventListener("mouseover", clickHide_mouseOver, true); |
| 390 document.addEventListener("mouseout", clickHide_mouseOut, true); | 336 document.addEventListener("mouseout", clickHide_mouseOut, true); |
| 391 document.addEventListener("click", clickHide_mouseClick, true); | 337 document.addEventListener("click", clickHide_mouseClick, true); |
| 392 document.addEventListener("keydown", clickHide_keyDown, true); | 338 document.addEventListener("keydown", clickHide_keyDown, true); |
| 393 } | 339 } |
| 394 | 340 |
| 395 // Called when user has clicked on something and we are waiting for confirmation | 341 // Called when user has clicked on something and we are waiting for confirmation |
| 396 // on whether the user actually wants these filters | 342 // on whether the user actually wants these filters |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 546 continue; | 492 continue; |
| 547 } | 493 } |
| 548 | 494 |
| 549 if (url == elt.src) | 495 if (url == elt.src) |
| 550 addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("s rc")) + ']'); | 496 addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("s rc")) + ']'); |
| 551 } | 497 } |
| 552 | 498 |
| 553 // as last resort, create a filter based on inline styles | 499 // as last resort, create a filter based on inline styles |
| 554 if (clickHideFilters.length == 0) | 500 if (clickHideFilters.length == 0) |
| 555 { | 501 { |
| 556 var style = getOriginalStyle(elt); | 502 var style = elt.getAttribute("style"); |
| 557 if (style) | 503 if (style) |
| 558 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']'); | 504 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']'); |
| 559 } | 505 } |
| 560 | 506 |
| 561 // Show popup | 507 // Show popup |
| 562 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); | 508 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); |
| 563 | 509 |
| 564 // Highlight the elements specified by selector in yellow | 510 // Highlight the elements specified by selector in yellow |
| 565 if (selectorList.length > 0) | 511 if (selectorList.length > 0) |
| 566 highlightElements(selectorList.join(",")); | 512 highlightElements(selectorList.join(",")); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 686 case "clickhide-activate": | 632 case "clickhide-activate": |
| 687 clickHide_activate(); | 633 clickHide_activate(); |
| 688 break; | 634 break; |
| 689 case "clickhide-deactivate": | 635 case "clickhide-deactivate": |
| 690 clickHide_deactivate(); | 636 clickHide_deactivate(); |
| 691 break; | 637 break; |
| 692 case "clickhide-new-filter": | 638 case "clickhide-new-filter": |
| 693 if(lastRightClickEvent) | 639 if(lastRightClickEvent) |
| 694 { | 640 { |
| 695 clickHide_activated = true; | 641 clickHide_activated = true; |
| 696 currentElement = addElementOverlay(lastRightClickEvent.target); | 642 currentElement = lastRightClickEvent.target; |
| 697 clickHide_mouseClick(lastRightClickEvent); | 643 clickHide_mouseClick(lastRightClickEvent); |
| 698 } | 644 } |
| 699 break; | 645 break; |
| 700 case "clickhide-init": | 646 case "clickhide-init": |
| 701 if (clickHideFiltersDialog) | 647 if (clickHideFiltersDialog) |
| 702 { | 648 { |
| 703 sendResponse({filters: clickHide_filters}); | 649 sendResponse({filters: clickHide_filters}); |
| 704 | 650 |
| 705 clickHideFiltersDialog.style.width = msg.width + "px"; | 651 clickHideFiltersDialog.style.width = msg.width + "px"; |
| 706 clickHideFiltersDialog.style.height = msg.height + "px"; | 652 clickHideFiltersDialog.style.height = msg.height + "px"; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 726 break; | 672 break; |
| 727 default: | 673 default: |
| 728 sendResponse({}); | 674 sendResponse({}); |
| 729 break; | 675 break; |
| 730 } | 676 } |
| 731 }); | 677 }); |
| 732 | 678 |
| 733 if (window == window.top) | 679 if (window == window.top) |
| 734 ext.backgroundPage.sendMessage({type: "report-html-page"}); | 680 ext.backgroundPage.sendMessage({type: "report-html-page"}); |
| 735 } | 681 } |
| OLD | NEW |