| 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-2016 Eyeo GmbH | 3 * Copyright (C) 2006-2016 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 /* globals checkCollapse, elemhide, getURLsFromElement, typeMap */ | |
|
Sebastian Noack
2017/02/09 01:04:50
As mentioned in the other review for the base ESLi
kzar
2017/02/20 10:27:30
We're not making the situation worse by documentin
Sebastian Noack
2017/03/29 17:14:07
JavaScript is a dynamic language, which comes with
kzar
2017/03/30 07:20:39
As discussed in IRC sounds good. I've opened https
| |
| 19 | |
| 18 "use strict"; | 20 "use strict"; |
| 19 | 21 |
| 20 // The page ID for the popup filter selection dialog (top frame only). | 22 // The page ID for the popup filter selection dialog (top frame only). |
| 21 let blockelementPopupId = null; | 23 let blockelementPopupId = null; |
| 22 | 24 |
| 23 // Element picking state (top frame only). | 25 // Element picking state (top frame only). |
| 24 let currentlyPickingElement = false; | 26 let currentlyPickingElement = false; |
| 25 let lastMouseOverEvent = null; | 27 let lastMouseOverEvent = null; |
| 26 | 28 |
| 27 // During element picking this is the currently highlighted element. When | 29 // During element picking this is the currently highlighted element. When |
| 28 // element has been picked this is the element that is due to be blocked. | 30 // element has been picked this is the element that is due to be blocked. |
| 29 let currentElement = null; | 31 let currentElement = null; |
| 30 | 32 |
| 31 // Highlighting state, used by the top frame during element picking and all | 33 // Highlighting state, used by the top frame during element picking and all |
| 32 // frames when the chosen element is highlighted red. | 34 // frames when the chosen element is highlighted red. |
| 33 let highlightedElementsSelector = null; | 35 let highlightedElementsSelector = null; |
| 34 let highlightedElementsInterval = null; | 36 let highlightedElementsInterval = null; |
| 35 | 37 |
| 36 // Last right click state stored for element blocking via the context menu. | 38 // Last right click state stored for element blocking via the context menu. |
| 37 let lastRightClickEvent = null; | 39 let lastRightClickEvent = null; |
| 38 let lastRightClickEventIsMostRecent = false; | 40 let lastRightClickEventIsMostRecent = false; |
| 39 | 41 |
| 40 | 42 |
| 41 /* Utilities */ | 43 /* Utilities */ |
| 42 | 44 |
| 43 function getFiltersForElement(element, callback) | 45 function getFiltersForElement(element, callback) |
| 44 { | 46 { |
| 45 let src = element.getAttribute("src"); | 47 let src = element.getAttribute("src"); |
| 46 ext.backgroundPage.sendMessage( | 48 ext.backgroundPage.sendMessage({ |
| 47 { | |
| 48 type: "composer.getFilters", | 49 type: "composer.getFilters", |
| 49 tagName: element.localName, | 50 tagName: element.localName, |
| 50 id: element.id, | 51 id: element.id, |
| 51 src: src && src.length <= 1000 ? src : null, | 52 src: src && src.length <= 1000 ? src : null, |
| 52 style: element.getAttribute("style"), | 53 style: element.getAttribute("style"), |
| 53 classes: Array.prototype.slice.call(element.classList), | 54 classes: Array.prototype.slice.call(element.classList), |
| 54 urls: getURLsFromElement(element), | 55 urls: getURLsFromElement(element), |
| 55 mediatype: typeMap[element.localName], | 56 mediatype: typeMap.get(element.localName), |
| 56 baseURL: document.location.href | 57 baseURL: document.location.href |
| 57 }, | 58 }, |
| 58 response => | 59 response => |
| 59 { | 60 { |
| 60 callback(response.filters, response.selectors); | 61 callback(response.filters, response.selectors); |
| 61 }); | 62 }); |
| 62 } | 63 } |
| 63 | 64 |
| 64 function getBlockableElementOrAncestor(element, callback) | 65 function getBlockableElementOrAncestor(element, callback) |
| 65 { | 66 { |
| 66 // We assume that the user doesn't want to block the whole page. | 67 // We assume that the user doesn't want to block the whole page. |
| 67 // So we never consider the <html> or <body> element. | 68 // So we never consider the <html> or <body> element. |
| 68 while (element && element != document.documentElement && | 69 while (element && element != document.documentElement && |
| 69 element != document.body) | 70 element != document.body) |
| 70 { | 71 { |
| 71 // We can't handle non-HTML (like SVG) elements, as well as | 72 // We can't handle non-HTML (like SVG) elements, as well as |
| 72 // <area> elements (see below). So fall back to the parent element. | 73 // <area> elements (see below). So fall back to the parent element. |
| 73 if (!(element instanceof HTMLElement) || element.localName == "area") | 74 if (!(element instanceof HTMLElement) || element.localName == "area") |
| 75 { | |
| 74 element = element.parentElement; | 76 element = element.parentElement; |
| 75 | 77 } |
| 76 // If image maps are used mouse events occur for the <area> element. | 78 // If image maps are used mouse events occur for the <area> element. |
| 77 // But we have to block the image associated with the <map> element. | 79 // But we have to block the image associated with the <map> element. |
| 78 else if (element.localName == "map") | 80 else if (element.localName == "map") |
| 79 { | 81 { |
| 80 let images = document.querySelectorAll("img[usemap]"); | 82 let images = document.querySelectorAll("img[usemap]"); |
| 81 let image = null; | 83 let image = null; |
| 82 | 84 |
| 83 for (let currentImage of images) | 85 for (let currentImage of images) |
| 84 { | 86 { |
| 85 let usemap = currentImage.getAttribute("usemap"); | 87 let usemap = currentImage.getAttribute("usemap"); |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 381 { | 383 { |
| 382 if (!currentElement) | 384 if (!currentElement) |
| 383 return; | 385 return; |
| 384 | 386 |
| 385 let element = currentElement.prisoner || currentElement; | 387 let element = currentElement.prisoner || currentElement; |
| 386 getFiltersForElement(element, (filters, selectors) => | 388 getFiltersForElement(element, (filters, selectors) => |
| 387 { | 389 { |
| 388 if (currentlyPickingElement) | 390 if (currentlyPickingElement) |
| 389 stopPickingElement(); | 391 stopPickingElement(); |
| 390 | 392 |
| 391 ext.backgroundPage.sendMessage( | 393 ext.backgroundPage.sendMessage({ |
| 392 { | |
| 393 type: "composer.openDialog" | 394 type: "composer.openDialog" |
| 394 }, | 395 }, |
| 395 popupId => | 396 popupId => |
| 396 { | 397 { |
| 397 ext.backgroundPage.sendMessage( | 398 ext.backgroundPage.sendMessage({ |
| 398 { | |
| 399 type: "forward", | 399 type: "forward", |
| 400 targetPageId: popupId, | 400 targetPageId: popupId, |
| 401 payload: | 401 payload: {type: "composer.dialog.init", filters} |
| 402 { | |
| 403 type: "composer.dialog.init", | |
| 404 filters: filters | |
| 405 } | |
| 406 }); | 402 }); |
| 407 | 403 |
| 408 // Only the top frame keeps a record of the popup window's ID, | 404 // Only the top frame keeps a record of the popup window's ID, |
| 409 // so if this isn't the top frame we need to pass the ID on. | 405 // so if this isn't the top frame we need to pass the ID on. |
| 410 if (window == window.top) | 406 if (window == window.top) |
| 411 { | 407 { |
| 412 blockelementPopupId = popupId; | 408 blockelementPopupId = popupId; |
| 413 } | 409 } |
| 414 else | 410 else |
| 415 { | 411 { |
| 416 ext.backgroundPage.sendMessage( | 412 ext.backgroundPage.sendMessage({ |
| 417 { | |
| 418 type: "forward", | 413 type: "forward", |
| 419 payload: | 414 payload: {type: "composer.content.dialogOpened", popupId} |
| 420 { | |
| 421 type: "composer.content.dialogOpened", | |
| 422 popupId: popupId | |
| 423 } | |
| 424 }); | 415 }); |
| 425 } | 416 } |
| 426 }); | 417 }); |
| 427 | 418 |
| 428 if (selectors.length > 0) | 419 if (selectors.length > 0) |
| 429 highlightElements(selectors.join(",")); | 420 highlightElements(selectors.join(",")); |
| 430 | 421 |
| 431 highlightElement(currentElement, "#fd1708", "#f6a1b5"); | 422 highlightElement(currentElement, "#fd1708", "#f6a1b5"); |
| 432 }); | 423 }); |
| 433 | 424 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 454 /* Core logic */ | 445 /* Core logic */ |
| 455 | 446 |
| 456 // We're done with the block element feature for now, tidy everything up. | 447 // We're done with the block element feature for now, tidy everything up. |
| 457 function deactivateBlockElement() | 448 function deactivateBlockElement() |
| 458 { | 449 { |
| 459 if (currentlyPickingElement) | 450 if (currentlyPickingElement) |
| 460 stopPickingElement(); | 451 stopPickingElement(); |
| 461 | 452 |
| 462 if (blockelementPopupId != null) | 453 if (blockelementPopupId != null) |
| 463 { | 454 { |
| 464 ext.backgroundPage.sendMessage( | 455 ext.backgroundPage.sendMessage({ |
| 465 { | |
| 466 type: "forward", | 456 type: "forward", |
| 467 targetPageId: blockelementPopupId, | 457 targetPageId: blockelementPopupId, |
| 468 payload: | 458 payload: |
| 469 { | 459 { |
| 470 type: "composer.dialog.close" | 460 type: "composer.dialog.close" |
| 471 } | 461 } |
| 472 }); | 462 }); |
| 473 | 463 |
| 474 blockelementPopupId = null; | 464 blockelementPopupId = null; |
| 475 } | 465 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 497 // this because the contextMenu API only provides a URL, not the actual DOM | 487 // this because the contextMenu API only provides a URL, not the actual DOM |
| 498 // element. | 488 // element. |
| 499 // We also need to make sure that the previous right click event, | 489 // We also need to make sure that the previous right click event, |
| 500 // if there is one, is removed. We don't know which frame it is in so we must | 490 // if there is one, is removed. We don't know which frame it is in so we must |
| 501 // send a message to the other frames to clear their old right click events. | 491 // send a message to the other frames to clear their old right click events. |
| 502 document.addEventListener("contextmenu", event => | 492 document.addEventListener("contextmenu", event => |
| 503 { | 493 { |
| 504 lastRightClickEvent = event; | 494 lastRightClickEvent = event; |
| 505 lastRightClickEventIsMostRecent = true; | 495 lastRightClickEventIsMostRecent = true; |
| 506 | 496 |
| 507 ext.backgroundPage.sendMessage( | 497 ext.backgroundPage.sendMessage({ |
| 508 { | |
| 509 type: "forward", | 498 type: "forward", |
| 510 payload: | 499 payload: |
| 511 { | 500 { |
| 512 type: "composer.content.clearPreviousRightClickEvent" | 501 type: "composer.content.clearPreviousRightClickEvent" |
| 513 } | 502 } |
| 514 }); | 503 }); |
| 515 }, true); | 504 }, true); |
| 516 | 505 |
| 517 ext.onMessage.addListener((msg, sender, sendResponse) => | 506 ext.onMessage.addListener((msg, sender, sendResponse) => |
| 518 { | 507 { |
| 519 switch (msg.type) | 508 switch (msg.type) |
| 520 { | 509 { |
| 521 case "composer.content.getState": | 510 case "composer.content.getState": |
| 522 if (window == window.top) | 511 if (window == window.top) |
| 512 { | |
| 523 sendResponse({ | 513 sendResponse({ |
| 524 active: currentlyPickingElement || blockelementPopupId != null | 514 active: currentlyPickingElement || blockelementPopupId != null |
| 525 }); | 515 }); |
| 516 } | |
| 526 break; | 517 break; |
| 527 case "composer.content.startPickingElement": | 518 case "composer.content.startPickingElement": |
| 528 if (window == window.top) | 519 if (window == window.top) |
| 529 startPickingElement(); | 520 startPickingElement(); |
| 530 break; | 521 break; |
| 531 case "composer.content.contextMenuClicked": | 522 case "composer.content.contextMenuClicked": |
| 532 let event = lastRightClickEvent; | 523 let event = lastRightClickEvent; |
| 533 deactivateBlockElement(); | 524 deactivateBlockElement(); |
| 534 if (event) | 525 if (event) |
| 535 { | 526 { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 565 break; | 556 break; |
| 566 case "composer.content.dialogOpened": | 557 case "composer.content.dialogOpened": |
| 567 if (window == window.top) | 558 if (window == window.top) |
| 568 blockelementPopupId = msg.popupId; | 559 blockelementPopupId = msg.popupId; |
| 569 break; | 560 break; |
| 570 case "composer.content.dialogClosed": | 561 case "composer.content.dialogClosed": |
| 571 // The onRemoved hook for the popup can create a race condition, so we | 562 // The onRemoved hook for the popup can create a race condition, so we |
| 572 // to be careful here. (This is not perfect, but best we can do.) | 563 // to be careful here. (This is not perfect, but best we can do.) |
| 573 if (window == window.top && blockelementPopupId == msg.popupId) | 564 if (window == window.top && blockelementPopupId == msg.popupId) |
| 574 { | 565 { |
| 575 ext.backgroundPage.sendMessage( | 566 ext.backgroundPage.sendMessage({ |
| 576 { | |
| 577 type: "forward", | 567 type: "forward", |
| 578 payload: | 568 payload: |
| 579 { | 569 { |
| 580 type: "composer.content.finished" | 570 type: "composer.content.finished" |
| 581 } | 571 } |
| 582 }); | 572 }); |
| 583 } | 573 } |
| 584 break; | 574 break; |
| 585 } | 575 } |
| 586 }); | 576 }); |
| 587 | 577 |
| 588 if (window == window.top) | 578 if (window == window.top) |
| 589 ext.backgroundPage.sendMessage({type: "composer.ready"}); | 579 ext.backgroundPage.sendMessage({type: "composer.ready"}); |
| 590 } | 580 } |
| OLD | NEW |