| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-2015 Eyeo GmbH | 3 * Copyright (C) 2006-2015 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 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 | 191 |
| 192 case "video": | 192 case "video": |
| 193 case "audio": | 193 case "audio": |
| 194 case "picture": | 194 case "picture": |
| 195 return getURLsFromMediaElement(element); | 195 return getURLsFromMediaElement(element); |
| 196 } | 196 } |
| 197 | 197 |
| 198 return getURLsFromAttributes(element); | 198 return getURLsFromAttributes(element); |
| 199 } | 199 } |
| 200 | 200 |
| 201 function isBlockable(element) | |
| 202 { | |
| 203 if (element.id) | |
| 204 return true; | |
| 205 if (element.classList.length > 0) | |
| 206 return true; | |
| 207 if (getURLsFromElement(element).length > 0) | |
| 208 return true; | |
| 209 | |
| 210 // We only generate filters based on the "style" attribute, | |
| 211 // if this is the only way we can generate a filter, and | |
| 212 // only if there are at least two CSS properties defined. | |
| 213 if (/:.+:/.test(element.getAttribute("style"))) | |
| 214 return true; | |
| 215 | |
| 216 return false; | |
| 217 } | |
| 218 | |
| 219 // Adds an overlay to an element, which is probably a Flash object | 201 // Adds an overlay to an element, which is probably a Flash object |
| 220 function addElementOverlay(elt) { | 202 function addElementOverlay(elt) { |
| 221 var zIndex = "auto"; | 203 var zIndex = "auto"; |
| 222 var position = "absolute"; | 204 var position = "absolute"; |
| 223 | 205 |
| 224 for (var e = elt; e; e = e.parentElement) | 206 for (var e = elt; e; e = e.parentElement) |
| 225 { | 207 { |
| 226 var style = getComputedStyle(e); | 208 var style = getComputedStyle(e); |
| 227 | 209 |
| 228 // If the element isn't rendered (since its or one of its ancestor's | 210 // If the element isn't rendered (since its or one of its ancestor's |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 305 function clickHide_activate() { | 287 function clickHide_activate() { |
| 306 if(document == null) | 288 if(document == null) |
| 307 return; | 289 return; |
| 308 | 290 |
| 309 // If we are already selecting, abort now | 291 // If we are already selecting, abort now |
| 310 if (clickHide_activated || clickHideFiltersDialog) | 292 if (clickHide_activated || clickHideFiltersDialog) |
| 311 clickHide_deactivate(); | 293 clickHide_deactivate(); |
| 312 | 294 |
| 313 // Add overlays for blockable elements that don't emit mouse events, | 295 // Add overlays for blockable elements that don't emit mouse events, |
| 314 // so that they can still be selected. | 296 // so that they can still be selected. |
| 315 var elts = document.querySelectorAll('object,embed,iframe,frame'); | 297 [].forEach.call( |
| 316 for(var i=0; i<elts.length; i++) | 298 document.querySelectorAll('object,embed,iframe,frame'), |
| 317 { | 299 function(element) |
| 318 var element = elts[i]; | 300 { |
| 319 if (isBlockable(element)) | 301 getFiltersForElement(element, function(filters) |
| 320 addElementOverlay(element); | 302 { |
| 321 } | 303 if (filters.length > 0) |
| 304 addElementOverlay(element); | |
| 305 }); | |
| 306 } | |
| 307 ); | |
| 322 | 308 |
| 323 clickHide_activated = true; | 309 clickHide_activated = true; |
| 324 document.addEventListener("mousedown", clickHide_stopPropagation, true); | 310 document.addEventListener("mousedown", clickHide_stopPropagation, true); |
| 325 document.addEventListener("mouseup", clickHide_stopPropagation, true); | 311 document.addEventListener("mouseup", clickHide_stopPropagation, true); |
| 326 document.addEventListener("mouseenter", clickHide_stopPropagation, true); | 312 document.addEventListener("mouseenter", clickHide_stopPropagation, true); |
| 327 document.addEventListener("mouseleave", clickHide_stopPropagation, true); | 313 document.addEventListener("mouseleave", clickHide_stopPropagation, true); |
| 328 document.addEventListener("mouseover", clickHide_mouseOver, true); | 314 document.addEventListener("mouseover", clickHide_mouseOver, true); |
| 329 document.addEventListener("mouseout", clickHide_mouseOut, true); | 315 document.addEventListener("mouseout", clickHide_mouseOut, true); |
| 330 document.addEventListener("click", clickHide_mouseClick, true); | 316 document.addEventListener("click", clickHide_mouseClick, true); |
| 331 document.addEventListener("keydown", clickHide_keyDown, true); | 317 document.addEventListener("keydown", clickHide_keyDown, true); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 394 { | 380 { |
| 395 e.stopPropagation(); | 381 e.stopPropagation(); |
| 396 } | 382 } |
| 397 | 383 |
| 398 function clickHide_elementClickHandler(e) { | 384 function clickHide_elementClickHandler(e) { |
| 399 e.preventDefault(); | 385 e.preventDefault(); |
| 400 e.stopPropagation(); | 386 e.stopPropagation(); |
| 401 clickHide_mouseClick(e); | 387 clickHide_mouseClick(e); |
| 402 } | 388 } |
| 403 | 389 |
| 404 function getBlockableElementOrAncestor(element) | 390 function getBlockableElementOrAncestor(element, callback) |
| 405 { | 391 { |
| 406 while (element && element != document.documentElement | 392 // We reached the document root without finding a blockable element. |
| 407 && element != document.body) | 393 // We also assume that the user doesn't want to block the whole page. |
| 394 // So we never consider the <html> or <body> element. | |
| 395 if (!element || element == document.documentElement || element == document.bod y) | |
| 396 callback(null); | |
| 397 | |
| 398 // We can't handle non-HTML (like SVG) elements, as well as | |
| 399 // <area> elements (see below). So fall back to the parent element. | |
| 400 else if (!(element instanceof HTMLElement) || element.localName == "area") | |
| 401 getBlockableElementOrAncestor(element.parentElement, callback); | |
|
Wladimir Palant
2015/03/02 20:14:19
This seems to be the right recipe to error out wit
Sebastian Noack
2015/03/03 14:29:00
Done.
| |
| 402 | |
| 403 // If image maps are used mouse events occur for the <area> element. | |
| 404 // But we have to block the image associated with the <map> element. | |
| 405 else if (element.localName == "map") | |
| 408 { | 406 { |
| 409 if (element instanceof HTMLElement && element.localName != "area") | 407 var images = document.querySelectorAll("img[usemap]"); |
| 408 var image = null; | |
| 409 | |
| 410 for (var i = 0; i < images.length; i++) | |
| 410 { | 411 { |
| 411 // Handle <area> and their <map> elements specially, | 412 var usemap = images[i].getAttribute("usemap"); |
| 412 // blocking the image they are associated with | 413 var index = usemap.indexOf("#"); |
| 413 if (element.localName == "map") | 414 |
| 415 if (index != -1 && usemap.substr(index + 1) == element.name) | |
| 414 { | 416 { |
| 415 var images = document.querySelectorAll("img[usemap]"); | 417 image = images[i]; |
| 416 for (var i = 0; i < images.length; i++) | 418 break; |
| 417 { | |
| 418 var image = images[i]; | |
| 419 var usemap = image.getAttribute("usemap"); | |
| 420 var index = usemap.indexOf("#"); | |
| 421 | |
| 422 if (index != -1 && usemap.substr(index + 1) == element.name) | |
| 423 return getBlockableElementOrAncestor(image); | |
| 424 } | |
| 425 | |
| 426 return null; | |
| 427 } | 419 } |
| 428 | |
| 429 if (isBlockable(element)) | |
| 430 return element; | |
| 431 } | 420 } |
| 432 | 421 |
| 433 element = element.parentElement; | 422 getBlockableElementOrAncestor(image, callback); |
| 434 } | 423 } |
| 435 | 424 |
| 436 return null; | 425 // Finally, if none of the above is true, check whether we can generate |
| 426 // any filters for this element. Otherwise fall back to its parent element. | |
| 427 else | |
| 428 { | |
| 429 getFiltersForElement(element, function(filters) | |
| 430 { | |
| 431 if (filters.length > 0) | |
| 432 callback(element); | |
| 433 else | |
| 434 getBlockableElementOrAncestor(element.parentElement, callback); | |
| 435 }); | |
| 436 } | |
| 437 } | 437 } |
| 438 | 438 |
| 439 // Hovering over an element so highlight it | 439 // Hovering over an element so highlight it |
| 440 function clickHide_mouseOver(e) | 440 function clickHide_mouseOver(e) |
| 441 { | 441 { |
| 442 if (clickHide_activated == false) | 442 if (clickHide_activated == false) |
| 443 return; | 443 return; |
| 444 | 444 |
| 445 var target = getBlockableElementOrAncestor(e.target); | 445 getBlockableElementOrAncestor(e.target, function(element) |
| 446 { | |
| 447 if (currentElement) | |
| 448 unhighlightElement(currentElement); | |
|
Wladimir Palant
2015/03/02 20:14:19
I don't think it is that simple. Mouse events can
Sebastian Noack
2015/03/03 14:29:00
I have a hard time verifying that the suggested lo
| |
| 446 | 449 |
| 447 if (target) | 450 if (element) |
| 448 { | 451 { |
| 449 currentElement = target; | 452 highlightElement(element, "#d6d84b", "#f8fa47"); |
| 453 element.addEventListener("contextmenu", clickHide_elementClickHandler, tru e); | |
| 454 } | |
| 450 | 455 |
| 451 highlightElement(target, "#d6d84b", "#f8fa47"); | 456 currentElement = element; |
| 452 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); | 457 }); |
| 453 } | 458 |
| 454 e.stopPropagation(); | 459 e.stopPropagation(); |
| 455 } | 460 } |
| 456 | 461 |
| 457 // No longer hovering over this element so unhighlight it | 462 // No longer hovering over this element so unhighlight it |
| 458 function clickHide_mouseOut(e) | 463 function clickHide_mouseOut(e) |
| 459 { | 464 { |
| 460 if (!clickHide_activated || !currentElement) | 465 if (!clickHide_activated || currentElement != e.target) |
|
kzar
2015/03/02 18:30:08
Wouldn't e.target not match for image maps where t
Sebastian Noack
2015/03/02 18:40:48
currentElement is the element we are highlighting
kzar
2015/03/02 18:42:29
Whoops missed the return there, OK.
| |
| 461 return; | 466 return; |
| 462 | 467 |
| 463 unhighlightElement(currentElement); | 468 unhighlightElement(currentElement); |
| 464 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, true); | 469 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, true); |
| 465 e.stopPropagation(); | 470 e.stopPropagation(); |
| 466 } | 471 } |
| 467 | 472 |
| 468 // Selects the currently hovered-over filter or cancels selection | 473 // Selects the currently hovered-over filter or cancels selection |
| 469 function clickHide_keyDown(e) | 474 function clickHide_keyDown(e) |
| 470 { | 475 { |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 489 { | 494 { |
| 490 ext.backgroundPage.sendMessage( | 495 ext.backgroundPage.sendMessage( |
| 491 { | 496 { |
| 492 type: "compose-filters", | 497 type: "compose-filters", |
| 493 tagName: element.localName, | 498 tagName: element.localName, |
| 494 id: element.id, | 499 id: element.id, |
| 495 src: element.getAttribute("src"), | 500 src: element.getAttribute("src"), |
| 496 style: element.getAttribute("style"), | 501 style: element.getAttribute("style"), |
| 497 classes: [].slice.call(element.classList), | 502 classes: [].slice.call(element.classList), |
| 498 urls: getURLsFromElement(element), | 503 urls: getURLsFromElement(element), |
| 504 mediatype: typeMap[element.localName], | |
| 499 baseURL: document.location.href | 505 baseURL: document.location.href |
| 500 }, | 506 }, |
| 501 function(response) | 507 function(response) |
| 502 { | 508 { |
| 503 callback(response.filters, response.selectors); | 509 callback(response.filters, response.selectors); |
| 504 } | 510 } |
| 505 ); | 511 ); |
| 506 } | 512 } |
| 507 | 513 |
| 508 // When the user clicks, the currentElement is the one we want. | 514 // When the user clicks, the currentElement is the one we want. |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 667 break; | 673 break; |
| 668 case "clickhide-activate": | 674 case "clickhide-activate": |
| 669 clickHide_activate(); | 675 clickHide_activate(); |
| 670 break; | 676 break; |
| 671 case "clickhide-deactivate": | 677 case "clickhide-deactivate": |
| 672 clickHide_deactivate(); | 678 clickHide_deactivate(); |
| 673 break; | 679 break; |
| 674 case "clickhide-new-filter": | 680 case "clickhide-new-filter": |
| 675 if(lastRightClickEvent) | 681 if(lastRightClickEvent) |
| 676 { | 682 { |
| 677 clickHide_activated = true; | 683 getBlockableElementOrAncestor(lastRightClickEvent.target, function(ele ment) |
| 678 currentElement = getBlockableElementOrAncestor(lastRightClickEvent.tar get); | 684 { |
| 679 clickHide_mouseClick(lastRightClickEvent); | 685 clickHide_activated = true; |
| 686 currentElement = element; | |
| 687 clickHide_mouseClick(lastRightClickEvent); | |
| 688 }); | |
| 680 } | 689 } |
| 681 break; | 690 break; |
| 682 case "clickhide-init": | 691 case "clickhide-init": |
| 683 if (clickHideFiltersDialog) | 692 if (clickHideFiltersDialog) |
| 684 { | 693 { |
| 685 sendResponse({filters: clickHide_filters}); | 694 sendResponse({filters: clickHide_filters}); |
| 686 | 695 |
| 687 clickHideFiltersDialog.style.width = msg.width + "px"; | 696 clickHideFiltersDialog.style.width = msg.width + "px"; |
| 688 clickHideFiltersDialog.style.height = msg.height + "px"; | 697 clickHideFiltersDialog.style.height = msg.height + "px"; |
| 689 clickHideFiltersDialog.style.visibility = "visible"; | 698 clickHideFiltersDialog.style.visibility = "visible"; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 717 lastRightClickEventValid = false; | 726 lastRightClickEventValid = false; |
| 718 else | 727 else |
| 719 lastRightClickEvent = null; | 728 lastRightClickEvent = null; |
| 720 break; | 729 break; |
| 721 } | 730 } |
| 722 }); | 731 }); |
| 723 | 732 |
| 724 if (window == window.top) | 733 if (window == window.top) |
| 725 ext.backgroundPage.sendMessage({type: "report-html-page"}); | 734 ext.backgroundPage.sendMessage({type: "report-html-page"}); |
| 726 } | 735 } |
| OLD | NEW |