| 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-present eyeo GmbH | 3 * Copyright (C) 2006-present 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 |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
| 13 * | 13 * |
| 14 * You should have received a copy of the GNU General Public License | 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/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| 16 */ | 16 */ |
| 17 | 17 |
| 18 "use strict"; | 18 "use strict"; |
| 19 | 19 |
| 20 const {checkCollapse, elemhide, | 20 const {checkCollapse, elemhide, |
| 21 getURLsFromElement, typeMap} = require("./include.preload"); | 21 getURLsFromElement, typeMap} = require("./include.preload"); |
| 22 const info = require("info"); |
| 22 | 23 |
| 23 // The page ID for the popup filter selection dialog (top frame only). | 24 // The page ID for the popup filter selection dialog (top frame only). |
| 24 let blockelementPopupId = null; | 25 let blockelementPopupId = null; |
| 25 | 26 |
| 26 // Element picking state (top frame only). | 27 // Element picking state (top frame only). |
| 27 let currentlyPickingElement = false; | 28 let currentlyPickingElement = false; |
| 28 let lastMouseOverEvent = null; | 29 let lastMouseOverEvent = null; |
| 29 | 30 |
| 30 // During element picking this is the currently highlighted element. When | 31 // During element picking this is the currently highlighted element. When |
| 31 // element has been picked this is the element that is due to be blocked. | 32 // element has been picked this is the element that is due to be blocked. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 58 baseURL: document.location.href | 59 baseURL: document.location.href |
| 59 }, | 60 }, |
| 60 response => | 61 response => |
| 61 { | 62 { |
| 62 callback(response.filters, response.selectors); | 63 callback(response.filters, response.selectors); |
| 63 }); | 64 }); |
| 64 } | 65 } |
| 65 | 66 |
| 66 function getBlockableElementOrAncestor(element, callback) | 67 function getBlockableElementOrAncestor(element, callback) |
| 67 { | 68 { |
| 69 // If we're offering to block the iframe element given by window.frameElement |
| 70 // we must use the context of the parent frame. |
| 71 let document = element.ownerDocument; |
| 72 let HTMLElement = document.defaultView.HTMLElement; |
| 73 |
| 68 // We assume that the user doesn't want to block the whole page. | 74 // We assume that the user doesn't want to block the whole page. |
| 69 // So we never consider the <html> or <body> element. | 75 // So we never consider the <html> or <body> element. |
| 70 while (element && element != document.documentElement && | 76 while (element && element != document.documentElement && |
| 71 element != document.body) | 77 element != document.body) |
| 72 { | 78 { |
| 73 // We can't handle non-HTML (like SVG) elements, as well as | 79 // We can't handle non-HTML (like SVG) elements, as well as |
| 74 // <area> elements (see below). So fall back to the parent element. | 80 // <area> elements (see below). So fall back to the parent element. |
| 75 if (!(element instanceof HTMLElement) || element.localName == "area") | 81 if (!(element instanceof HTMLElement) || element.localName == "area") |
| 76 element = element.parentElement; | 82 element = element.parentElement; |
| 77 | 83 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 // We reached the document root without finding a blockable element. | 122 // We reached the document root without finding a blockable element. |
| 117 callback(null); | 123 callback(null); |
| 118 } | 124 } |
| 119 | 125 |
| 120 | 126 |
| 121 /* Element highlighting */ | 127 /* Element highlighting */ |
| 122 | 128 |
| 123 // Adds an overlay to an element in order to highlight it. | 129 // Adds an overlay to an element in order to highlight it. |
| 124 function addElementOverlay(element) | 130 function addElementOverlay(element) |
| 125 { | 131 { |
| 132 let document = element.ownerDocument; |
| 133 |
| 126 let position = "absolute"; | 134 let position = "absolute"; |
| 127 let offsetX = window.scrollX; | 135 let offsetX = window.scrollX; |
| 128 let offsetY = window.scrollY; | 136 let offsetY = window.scrollY; |
| 129 | 137 |
| 130 for (let e = element; e; e = e.parentElement) | 138 for (let e = element; e; e = e.parentElement) |
| 131 { | 139 { |
| 132 let style = getComputedStyle(e); | 140 let style = getComputedStyle(e); |
| 133 | 141 |
| 134 // If the element isn't rendered (since its or one of its ancestor's | 142 // If the element isn't rendered (since its or one of its ancestor's |
| 135 // "display" property is "none"), the overlay wouldn't match the element. | 143 // "display" property is "none"), the overlay wouldn't match the element. |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 }); | 423 }); |
| 416 } | 424 } |
| 417 }); | 425 }); |
| 418 | 426 |
| 419 if (selectors.length > 0) | 427 if (selectors.length > 0) |
| 420 highlightElements(selectors.join(",")); | 428 highlightElements(selectors.join(",")); |
| 421 | 429 |
| 422 highlightElement(currentElement, "#fd1708", "#f6a1b5"); | 430 highlightElement(currentElement, "#fd1708", "#f6a1b5"); |
| 423 }); | 431 }); |
| 424 | 432 |
| 425 event.preventDefault(); | 433 if (event) |
| 426 event.stopPropagation(); | 434 { |
| 435 event.preventDefault(); |
| 436 event.stopPropagation(); |
| 437 } |
| 427 } | 438 } |
| 428 | 439 |
| 429 function stopPickingElement() | 440 function stopPickingElement() |
| 430 { | 441 { |
| 431 currentlyPickingElement = false; | 442 currentlyPickingElement = false; |
| 432 | 443 |
| 433 document.removeEventListener("mousedown", stopEventPropagation, true); | 444 document.removeEventListener("mousedown", stopEventPropagation, true); |
| 434 document.removeEventListener("mouseup", stopEventPropagation, true); | 445 document.removeEventListener("mouseup", stopEventPropagation, true); |
| 435 document.removeEventListener("mouseenter", stopEventPropagation, true); | 446 document.removeEventListener("mouseenter", stopEventPropagation, true); |
| 436 document.removeEventListener("mouseleave", stopEventPropagation, true); | 447 document.removeEventListener("mouseleave", stopEventPropagation, true); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 active: currentlyPickingElement || blockelementPopupId != null | 528 active: currentlyPickingElement || blockelementPopupId != null |
| 518 }); | 529 }); |
| 519 } | 530 } |
| 520 break; | 531 break; |
| 521 case "composer.content.startPickingElement": | 532 case "composer.content.startPickingElement": |
| 522 if (window == window.top) | 533 if (window == window.top) |
| 523 startPickingElement(); | 534 startPickingElement(); |
| 524 break; | 535 break; |
| 525 case "composer.content.contextMenuClicked": | 536 case "composer.content.contextMenuClicked": |
| 526 let event = lastRightClickEvent; | 537 let event = lastRightClickEvent; |
| 538 let target = event && event.target; |
| 539 |
| 540 // When the user attempts to block an element inside an iframe for which |
| 541 // our right click event listener was trashed the best we can do is to |
| 542 // offer to block the entire iframe. This doesn't work for cross origin |
| 543 // frames, neither on Edge where per-frame messaging isn't supported |
| 544 // yet[1], but it's the best we can do. |
| 545 // [1] - https://developer.microsoft.com/en-us/microsoft-edge/platform/d
ocumentation/extensions/api-support/supported-apis/ |
| 546 if (!target && window.frameElement && info.application != "edge") |
| 547 target = addElementOverlay(window.frameElement); |
| 548 |
| 527 deactivateBlockElement(); | 549 deactivateBlockElement(); |
| 528 if (event) | 550 if (target) |
| 529 { | 551 { |
| 530 getBlockableElementOrAncestor(event.target, element => | 552 getBlockableElementOrAncestor(target, element => |
| 531 { | 553 { |
| 532 if (element) | 554 if (element) |
| 533 { | 555 { |
| 534 currentElement = element; | 556 currentElement = element; |
| 535 elementPicked(event); | 557 elementPicked(event); |
| 536 } | 558 } |
| 537 }); | 559 }); |
| 538 } | 560 } |
| 539 break; | 561 break; |
| 540 case "composer.content.finished": | 562 case "composer.content.finished": |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 if (document instanceof HTMLDocument) | 609 if (document instanceof HTMLDocument) |
| 588 { | 610 { |
| 589 // There's a bug in Firefox that causes document_end content scripts to run | 611 // There's a bug in Firefox that causes document_end content scripts to run |
| 590 // before document_start content scripts on extension startup. In this case | 612 // before document_start content scripts on extension startup. In this case |
| 591 // the ext object is undefined, we fail to initialize, and initializeComposer | 613 // the ext object is undefined, we fail to initialize, and initializeComposer |
| 592 // returns false. As a workaround, try again after a timeout. | 614 // returns false. As a workaround, try again after a timeout. |
| 593 // https://bugzilla.mozilla.org/show_bug.cgi?id=1395287 | 615 // https://bugzilla.mozilla.org/show_bug.cgi?id=1395287 |
| 594 if (!initializeComposer()) | 616 if (!initializeComposer()) |
| 595 setTimeout(initializeComposer, 2000); | 617 setTimeout(initializeComposer, 2000); |
| 596 } | 618 } |
| OLD | NEW |