| LEFT | RIGHT |
| 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-2017 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 * |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 chrome.tabs.onRemoved.addListener(forgetTab); | 310 chrome.tabs.onRemoved.addListener(forgetTab); |
| 311 | 311 |
| 312 chrome.tabs.onActivated.addListener(details => | 312 chrome.tabs.onActivated.addListener(details => |
| 313 { | 313 { |
| 314 ext.pages.onActivated._dispatch(new Page({id: details.tabId})); | 314 ext.pages.onActivated._dispatch(new Page({id: details.tabId})); |
| 315 }); | 315 }); |
| 316 | 316 |
| 317 | 317 |
| 318 /* Browser actions */ | 318 /* Browser actions */ |
| 319 | 319 |
| 320 // On Firefox for Android, open the options page directly when the browser |
| 321 // action is clicked. |
| 322 if (!("getPopup" in chrome.browserAction)) |
| 323 { |
| 324 chrome.browserAction.onClicked.addListener(() => |
| 325 { |
| 326 ext.showOptions(); |
| 327 }); |
| 328 } |
| 329 |
| 320 let BrowserAction = function(tabId) | 330 let BrowserAction = function(tabId) |
| 321 { | 331 { |
| 322 this._tabId = tabId; | 332 this._tabId = tabId; |
| 323 this._changes = null; | 333 this._changes = null; |
| 324 }; | 334 }; |
| 325 BrowserAction.prototype = { | 335 BrowserAction.prototype = { |
| 326 _applyChanges() | 336 _applyChanges() |
| 327 { | 337 { |
| 328 if ("iconPath" in this._changes) | 338 if ("iconPath" in this._changes) |
| 329 { | 339 { |
| 330 chrome.browserAction.setIcon({ | 340 // Firefox for Android displays the browser action not as an icon but |
| 331 tabId: this._tabId, | 341 // as a menu item. There is no icon, but such an option may be added in |
| 332 path: { | 342 // the future. |
| 333 16: this._changes.iconPath.replace("$size", "16"), | 343 // https://bugzilla.mozilla.org/show_bug.cgi?id=1331746 |
| 334 19: this._changes.iconPath.replace("$size", "19"), | 344 if ("setIcon" in chrome.browserAction) |
| 335 20: this._changes.iconPath.replace("$size", "20"), | 345 { |
| 336 32: this._changes.iconPath.replace("$size", "32"), | 346 chrome.browserAction.setIcon({ |
| 337 38: this._changes.iconPath.replace("$size", "38"), | 347 tabId: this._tabId, |
| 338 40: this._changes.iconPath.replace("$size", "40") | 348 path: { |
| 339 } | 349 16: this._changes.iconPath.replace("$size", "16"), |
| 340 }); | 350 19: this._changes.iconPath.replace("$size", "19"), |
| 351 20: this._changes.iconPath.replace("$size", "20"), |
| 352 32: this._changes.iconPath.replace("$size", "32"), |
| 353 38: this._changes.iconPath.replace("$size", "38"), |
| 354 40: this._changes.iconPath.replace("$size", "40") |
| 355 } |
| 356 }); |
| 357 } |
| 341 } | 358 } |
| 342 | 359 |
| 343 if ("badgeText" in this._changes) | 360 if ("badgeText" in this._changes) |
| 344 { | 361 { |
| 345 chrome.browserAction.setBadgeText({ | 362 // There is no badge on Firefox for Android; the browser action is |
| 346 tabId: this._tabId, | 363 // simply a menu item. |
| 347 text: this._changes.badgeText | 364 if ("setBadgeText" in chrome.browserAction) |
| 348 }); | 365 { |
| 366 chrome.browserAction.setBadgeText({ |
| 367 tabId: this._tabId, |
| 368 text: this._changes.badgeText |
| 369 }); |
| 370 } |
| 349 } | 371 } |
| 350 | 372 |
| 351 if ("badgeColor" in this._changes) | 373 if ("badgeColor" in this._changes) |
| 352 { | 374 { |
| 353 chrome.browserAction.setBadgeBackgroundColor({ | 375 // There is no badge on Firefox for Android; the browser action is |
| 354 tabId: this._tabId, | 376 // simply a menu item. |
| 355 color: this._changes.badgeColor | 377 if ("setBadgeBackgroundColor" in chrome.browserAction) |
| 356 }); | 378 { |
| 379 chrome.browserAction.setBadgeBackgroundColor({ |
| 380 tabId: this._tabId, |
| 381 color: this._changes.badgeColor |
| 382 }); |
| 383 } |
| 357 } | 384 } |
| 358 | 385 |
| 359 this._changes = null; | 386 this._changes = null; |
| 360 }, | 387 }, |
| 361 _queueChanges() | 388 _queueChanges() |
| 362 { | 389 { |
| 363 chrome.tabs.get(this._tabId, () => | 390 chrome.tabs.get(this._tabId, () => |
| 364 { | 391 { |
| 365 // If the tab is prerendered, chrome.tabs.get() sets | 392 // If the tab is prerendered, chrome.tabs.get() sets |
| 366 // chrome.runtime.lastError and we have to delay our changes | 393 // chrome.runtime.lastError and we have to delay our changes |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 416 }; | 443 }; |
| 417 | 444 |
| 418 | 445 |
| 419 /* Context menus */ | 446 /* Context menus */ |
| 420 | 447 |
| 421 let contextMenuItems = new ext.PageMap(); | 448 let contextMenuItems = new ext.PageMap(); |
| 422 let contextMenuUpdating = false; | 449 let contextMenuUpdating = false; |
| 423 | 450 |
| 424 let updateContextMenu = () => | 451 let updateContextMenu = () => |
| 425 { | 452 { |
| 426 if (contextMenuUpdating) | 453 // Firefox for Android does not support context menus. |
| 454 // https://bugzilla.mozilla.org/show_bug.cgi?id=1269062 |
| 455 if (!("contextMenus" in chrome) || contextMenuUpdating) |
| 427 return; | 456 return; |
| 428 | 457 |
| 429 contextMenuUpdating = true; | 458 contextMenuUpdating = true; |
| 430 | 459 |
| 431 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => | 460 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => |
| 432 { | 461 { |
| 433 chrome.contextMenus.removeAll(() => | 462 chrome.contextMenus.removeAll(() => |
| 434 { | 463 { |
| 435 contextMenuUpdating = false; | 464 contextMenuUpdating = false; |
| 436 | 465 |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 if (frame) | 664 if (frame) |
| 636 return frame.parent || null; | 665 return frame.parent || null; |
| 637 | 666 |
| 638 return frames.get(0) || null; | 667 return frames.get(0) || null; |
| 639 } | 668 } |
| 640 }; | 669 }; |
| 641 } | 670 } |
| 642 | 671 |
| 643 return ext.onMessage._dispatch( | 672 return ext.onMessage._dispatch( |
| 644 message, sender, sendResponse | 673 message, sender, sendResponse |
| 645 ).indexOf(true) != -1; | 674 ).includes(true); |
| 646 }); | 675 }); |
| 647 | 676 |
| 648 | 677 |
| 649 /* Storage */ | 678 /* Storage */ |
| 650 | 679 |
| 651 ext.storage = { | 680 ext.storage = { |
| 652 get(keys, callback) | 681 get(keys, callback) |
| 653 { | 682 { |
| 654 chrome.storage.local.get(keys, callback); | 683 chrome.storage.local.get(keys, callback); |
| 655 }, | 684 }, |
| 656 set(key, value, callback) | 685 set(key, value, callback) |
| 657 { | 686 { |
| 658 let items = {}; | 687 let items = {}; |
| 659 items[key] = value; | 688 items[key] = value; |
| 660 chrome.storage.local.set(items, callback); | 689 chrome.storage.local.set(items, callback); |
| 661 }, | 690 }, |
| 662 remove(key, callback) | 691 remove(key, callback) |
| 663 { | 692 { |
| 664 chrome.storage.local.remove(key, callback); | 693 chrome.storage.local.remove(key, callback); |
| 665 }, | 694 }, |
| 666 onChanged: chrome.storage.onChanged | 695 onChanged: chrome.storage.onChanged |
| 667 }; | 696 }; |
| 668 | 697 |
| 669 /* Options */ | 698 /* Options */ |
| 670 | 699 |
| 671 if ("openOptionsPage" in chrome.runtime) | 700 ext.showOptions = callback => |
| 672 { | 701 { |
| 673 ext.showOptions = callback => | 702 if ("openOptionsPage" in chrome.runtime && |
| 703 // Firefox for Android does have a runtime.openOptionsPage but it |
| 704 // doesn't do anything. |
| 705 // https://bugzilla.mozilla.org/show_bug.cgi?id=1364945 |
| 706 require("info").application != "fennec") |
| 674 { | 707 { |
| 675 if (!callback) | 708 if (!callback) |
| 676 { | 709 { |
| 677 chrome.runtime.openOptionsPage(); | 710 chrome.runtime.openOptionsPage(); |
| 678 } | 711 } |
| 679 else | 712 else |
| 680 { | 713 { |
| 681 chrome.runtime.openOptionsPage(() => | 714 chrome.runtime.openOptionsPage(() => |
| 682 { | 715 { |
| 683 if (chrome.runtime.lastError) | 716 if (chrome.runtime.lastError) |
| 684 return; | 717 return; |
| 685 | 718 |
| 686 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => | 719 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => |
| 687 { | 720 { |
| 688 if (tabs.length > 0) | 721 if (tabs.length > 0) |
| 689 { | 722 { |
| 690 if (tabs[0].status == "complete") | 723 if (tabs[0].status == "complete") |
| 691 callback(new Page(tabs[0])); | 724 callback(new Page(tabs[0])); |
| 692 else | 725 else |
| 693 afterTabLoaded(callback)(tabs[0]); | 726 afterTabLoaded(callback)(tabs[0]); |
| 694 } | 727 } |
| 695 }); | 728 }); |
| 696 }); | 729 }); |
| 697 } | 730 } |
| 698 }; | 731 } |
| 699 } | 732 else |
| 700 else | 733 { |
| 701 { | 734 // Edge does not yet support runtime.openOptionsPage (tested version 38) |
| 702 // Edge does not yet support runtime.openOptionsPage (tested version 38) | 735 // nor does Firefox for Android, |
| 703 // and so this workaround needs to stay for now. | 736 // and so this workaround needs to stay for now. |
| 704 // We are not using extension.getURL to get the absolute path here | 737 // We are not using extension.getURL to get the absolute path here |
| 705 // because of the Edge issue: | 738 // because of the Edge issue: |
| 706 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/1027
6332/ | 739 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10
276332/ |
| 707 ext.showOptions = callback => | |
| 708 { | |
| 709 let optionsUrl = "options.html"; | |
| 710 let queryInfo = {url: optionsUrl}; | |
| 711 | |
| 712 let open = win => | 740 let open = win => |
| 713 { | 741 { |
| 742 let optionsUrl = "options.html"; |
| 743 let queryInfo = {url: optionsUrl}; |
| 744 |
| 714 // extension pages can't be accessed in incognito windows. In order to | 745 // extension pages can't be accessed in incognito windows. In order to |
| 715 // correctly mimic the way in which Chrome opens extension options, | 746 // correctly mimic the way in which Chrome opens extension options, |
| 716 // we have to focus the options page in any other window. | 747 // we have to focus the options page in any other window. |
| 717 if (win && !win.incognito) | 748 if (win && !win.incognito) |
| 718 queryInfo.windowId = win.id; | 749 queryInfo.windowId = win.id; |
| 719 | 750 |
| 720 chrome.tabs.query(queryInfo, tabs => | 751 chrome.tabs.query(queryInfo, tabs => |
| 721 { | 752 { |
| 722 if (tabs.length > 0) | 753 if (tabs && tabs.length > 0) |
| 723 { | 754 { |
| 724 let tab = tabs[0]; | 755 let tab = tabs[0]; |
| 725 | 756 |
| 726 if ("windows" in chrome) | 757 if ("windows" in chrome) |
| 727 chrome.windows.update(tab.windowId, {focused: true}); | 758 chrome.windows.update(tab.windowId, {focused: true}); |
| 728 | 759 |
| 729 chrome.tabs.update(tab.id, {active: true}); | 760 chrome.tabs.update(tab.id, {active: true}); |
| 730 | 761 |
| 731 if (callback) | 762 if (callback) |
| 732 callback(new Page(tab)); | 763 callback(new Page(tab)); |
| 733 } | 764 } |
| 734 else | 765 else |
| 735 { | 766 { |
| 736 ext.pages.open(optionsUrl, callback); | 767 ext.pages.open(optionsUrl, callback); |
| 737 } | 768 } |
| 738 }); | 769 }); |
| 739 }; | 770 }; |
| 740 | 771 |
| 741 if ("windows" in chrome) | 772 if ("windows" in chrome) |
| 773 { |
| 742 chrome.windows.getLastFocused(open); | 774 chrome.windows.getLastFocused(open); |
| 775 } |
| 743 else | 776 else |
| 777 { |
| 778 // Firefox for Android does not support the windows API. Since there is |
| 779 // effectively only one window on the mobile browser, there's no need |
| 780 // to bring it into focus. |
| 744 open(); | 781 open(); |
| 745 }; | 782 } |
| 746 } | 783 } |
| 784 }; |
| 747 | 785 |
| 748 /* Windows */ | 786 /* Windows */ |
| 749 ext.windows = { | 787 ext.windows = { |
| 750 create(createData, callback) | 788 create(createData, callback) |
| 751 { | 789 { |
| 752 chrome.windows.create(createData, createdWindow => | 790 chrome.windows.create(createData, createdWindow => |
| 753 { | 791 { |
| 754 afterTabLoaded(callback)(createdWindow.tabs[0]); | 792 afterTabLoaded(callback)(createdWindow.tabs[0]); |
| 755 }); | 793 }); |
| 756 } | 794 } |
| 757 }; | 795 }; |
| 758 }()); | 796 }()); |
| LEFT | RIGHT |