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 |