| 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 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 | 33 |
| 34 // Highlighting state, used by the top frame during element picking and all | 34 // Highlighting state, used by the top frame during element picking and all |
| 35 // frames when the chosen element is highlighted red. | 35 // frames when the chosen element is highlighted red. |
| 36 let highlightedElementsSelector = null; | 36 let highlightedElementsSelector = null; |
| 37 let highlightedElementsInterval = null; | 37 let highlightedElementsInterval = null; |
| 38 | 38 |
| 39 // Last right click state stored for element blocking via the context menu. | 39 // Last right click state stored for element blocking via the context menu. |
| 40 let lastRightClickEvent = null; | 40 let lastRightClickEvent = null; |
| 41 let lastRightClickEventIsMostRecent = false; | 41 let lastRightClickEventIsMostRecent = false; |
| 42 | 42 |
| 43 let perFrameMessagingSupported = false; |
| 44 browser.runtime.sendMessage( |
| 45 {type: "app.get", what: "application"}, |
| 46 application => { perFrameMessagingSupported = application != "edge"; } |
| 47 ); |
| 43 | 48 |
| 44 /* Utilities */ | 49 /* Utilities */ |
| 45 | 50 |
| 46 function getFiltersForElement(element, callback) | 51 function getFiltersForElement(element, callback) |
| 47 { | 52 { |
| 48 let src = element.getAttribute("src"); | 53 let src = element.getAttribute("src"); |
| 49 browser.runtime.sendMessage({ | 54 browser.runtime.sendMessage({ |
| 50 type: "composer.getFilters", | 55 type: "composer.getFilters", |
| 51 tagName: element.localName, | 56 tagName: element.localName, |
| 52 id: element.id, | 57 id: element.id, |
| 53 src: src && src.length <= 1000 ? src : null, | 58 src: src && src.length <= 1000 ? src : null, |
| 54 style: element.getAttribute("style"), | 59 style: element.getAttribute("style"), |
| 55 classes: Array.prototype.slice.call(element.classList), | 60 classes: Array.prototype.slice.call(element.classList), |
| 56 urls: getURLsFromElement(element), | 61 urls: getURLsFromElement(element), |
| 57 mediatype: typeMap.get(element.localName), | 62 mediatype: typeMap.get(element.localName), |
| 58 baseURL: document.location.href | 63 baseURL: document.location.href |
| 59 }, | 64 }, |
| 60 response => | 65 response => |
| 61 { | 66 { |
| 62 callback(response.filters, response.selectors); | 67 callback(response.filters, response.selectors); |
| 63 }); | 68 }); |
| 64 } | 69 } |
| 65 | 70 |
| 66 function getBlockableElementOrAncestor(element, callback) | 71 function getBlockableElementOrAncestor(element, callback) |
| 67 { | 72 { |
| 73 // If we're offering to block the iframe element given by window.frameElement |
| 74 // we must use the context of the parent frame. |
| 75 let document = element.ownerDocument; |
| 76 let HTMLElement = document.defaultView.HTMLElement; |
| 77 |
| 68 // We assume that the user doesn't want to block the whole page. | 78 // We assume that the user doesn't want to block the whole page. |
| 69 // So we never consider the <html> or <body> element. | 79 // So we never consider the <html> or <body> element. |
| 70 while (element && element != document.documentElement && | 80 while (element && element != document.documentElement && |
| 71 element != document.body) | 81 element != document.body) |
| 72 { | 82 { |
| 73 // We can't handle non-HTML (like SVG) elements, as well as | 83 // We can't handle non-HTML (like SVG) elements, as well as |
| 74 // <area> elements (see below). So fall back to the parent element. | 84 // <area> elements (see below). So fall back to the parent element. |
| 75 if (!(element instanceof HTMLElement) || element.localName == "area") | 85 if (!(element instanceof HTMLElement) || element.localName == "area") |
| 76 element = element.parentElement; | 86 element = element.parentElement; |
| 77 | 87 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 // We reached the document root without finding a blockable element. | 126 // We reached the document root without finding a blockable element. |
| 117 callback(null); | 127 callback(null); |
| 118 } | 128 } |
| 119 | 129 |
| 120 | 130 |
| 121 /* Element highlighting */ | 131 /* Element highlighting */ |
| 122 | 132 |
| 123 // Adds an overlay to an element in order to highlight it. | 133 // Adds an overlay to an element in order to highlight it. |
| 124 function addElementOverlay(element) | 134 function addElementOverlay(element) |
| 125 { | 135 { |
| 136 let document = element.ownerDocument; |
| 137 |
| 126 let position = "absolute"; | 138 let position = "absolute"; |
| 127 let offsetX = window.scrollX; | 139 let offsetX = window.scrollX; |
| 128 let offsetY = window.scrollY; | 140 let offsetY = window.scrollY; |
| 129 | 141 |
| 130 for (let e = element; e; e = e.parentElement) | 142 for (let e = element; e; e = e.parentElement) |
| 131 { | 143 { |
| 132 let style = getComputedStyle(e); | 144 let style = getComputedStyle(e); |
| 133 | 145 |
| 134 // If the element isn't rendered (since its or one of its ancestor's | 146 // 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. | 147 // "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 }); | 427 }); |
| 416 } | 428 } |
| 417 }); | 429 }); |
| 418 | 430 |
| 419 if (selectors.length > 0) | 431 if (selectors.length > 0) |
| 420 highlightElements(selectors.join(",")); | 432 highlightElements(selectors.join(",")); |
| 421 | 433 |
| 422 highlightElement(currentElement, "#fd1708", "#f6a1b5"); | 434 highlightElement(currentElement, "#fd1708", "#f6a1b5"); |
| 423 }); | 435 }); |
| 424 | 436 |
| 425 event.preventDefault(); | 437 if (event) |
| 426 event.stopPropagation(); | 438 { |
| 439 event.preventDefault(); |
| 440 event.stopPropagation(); |
| 441 } |
| 427 } | 442 } |
| 428 | 443 |
| 429 function stopPickingElement() | 444 function stopPickingElement() |
| 430 { | 445 { |
| 431 currentlyPickingElement = false; | 446 currentlyPickingElement = false; |
| 432 | 447 |
| 433 document.removeEventListener("mousedown", stopEventPropagation, true); | 448 document.removeEventListener("mousedown", stopEventPropagation, true); |
| 434 document.removeEventListener("mouseup", stopEventPropagation, true); | 449 document.removeEventListener("mouseup", stopEventPropagation, true); |
| 435 document.removeEventListener("mouseenter", stopEventPropagation, true); | 450 document.removeEventListener("mouseenter", stopEventPropagation, true); |
| 436 document.removeEventListener("mouseleave", stopEventPropagation, true); | 451 document.removeEventListener("mouseleave", stopEventPropagation, true); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 active: currentlyPickingElement || blockelementPopupId != null | 532 active: currentlyPickingElement || blockelementPopupId != null |
| 518 }); | 533 }); |
| 519 } | 534 } |
| 520 break; | 535 break; |
| 521 case "composer.content.startPickingElement": | 536 case "composer.content.startPickingElement": |
| 522 if (window == window.top) | 537 if (window == window.top) |
| 523 startPickingElement(); | 538 startPickingElement(); |
| 524 break; | 539 break; |
| 525 case "composer.content.contextMenuClicked": | 540 case "composer.content.contextMenuClicked": |
| 526 let event = lastRightClickEvent; | 541 let event = lastRightClickEvent; |
| 542 let target = event && event.target; |
| 543 |
| 544 // When the user attempts to block an element inside an iframe for which |
| 545 // our right click event listener was trashed the best we can do is to |
| 546 // offer to block the entire iframe. This doesn't work for cross origin |
| 547 // frames, neither on Edge where per-frame messaging isn't supported |
| 548 // yet[1], but it's the best we can do. |
| 549 // [1] - https://developer.microsoft.com/en-us/microsoft-edge/platform/d
ocumentation/extensions/api-support/supported-apis/ |
| 550 if (!target && window.frameElement && perFrameMessagingSupported) |
| 551 target = addElementOverlay(window.frameElement); |
| 552 |
| 527 deactivateBlockElement(); | 553 deactivateBlockElement(); |
| 528 if (event) | 554 if (target) |
| 529 { | 555 { |
| 530 getBlockableElementOrAncestor(event.target, element => | 556 getBlockableElementOrAncestor(target, element => |
| 531 { | 557 { |
| 532 if (element) | 558 if (element) |
| 533 { | 559 { |
| 534 currentElement = element; | 560 currentElement = element; |
| 535 elementPicked(event); | 561 elementPicked(event); |
| 536 } | 562 } |
| 537 }); | 563 }); |
| 538 } | 564 } |
| 539 break; | 565 break; |
| 540 case "composer.content.finished": | 566 case "composer.content.finished": |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 if (document instanceof HTMLDocument) | 613 if (document instanceof HTMLDocument) |
| 588 { | 614 { |
| 589 // There's a bug in Firefox that causes document_end content scripts to run | 615 // 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 | 616 // before document_start content scripts on extension startup. In this case |
| 591 // the ext object is undefined, we fail to initialize, and initializeComposer | 617 // the ext object is undefined, we fail to initialize, and initializeComposer |
| 592 // returns false. As a workaround, try again after a timeout. | 618 // returns false. As a workaround, try again after a timeout. |
| 593 // https://bugzilla.mozilla.org/show_bug.cgi?id=1395287 | 619 // https://bugzilla.mozilla.org/show_bug.cgi?id=1395287 |
| 594 if (!initializeComposer()) | 620 if (!initializeComposer()) |
| 595 setTimeout(initializeComposer, 2000); | 621 setTimeout(initializeComposer, 2000); |
| 596 } | 622 } |
| OLD | NEW |