TaskbarTabsPageAction.sys.mjs (5421B)
1 /* vim: se cin sw=2 ts=2 et filetype=javascript : 2 * This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 const kWidgetId = "taskbar-tabs-button"; 7 8 import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; 9 10 let lazy = {}; 11 12 ChromeUtils.defineESModuleGetters(lazy, { 13 PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", 14 TaskbarTabs: "resource:///modules/taskbartabs/TaskbarTabs.sys.mjs", 15 TaskbarTabsUtils: "resource:///modules/taskbartabs/TaskbarTabsUtils.sys.mjs", 16 }); 17 18 ChromeUtils.defineLazyGetter(lazy, "logConsole", () => { 19 return console.createInstance({ 20 prefix: "TaskbarTabs", 21 maxLogLevel: "Warn", 22 }); 23 }); 24 25 /** 26 * Object which handles Taskbar Tabs page actions. 27 */ 28 export const TaskbarTabsPageAction = { 29 // Set of tabs currently being processed due to a page action event. 30 _processingTabs: new Set(), 31 32 /** 33 * Connects a listener to the Taskbar Tabs page action. 34 * 35 * @param {DOMWindow} aWindow - The browser window. 36 */ 37 init(aWindow) { 38 let isPopupWindow = !aWindow.toolbar.visible; 39 let isPrivate = lazy.PrivateBrowsingUtils.isWindowPrivate(aWindow); 40 let isWin32 = AppConstants.platform === "win"; 41 let isMsix = 42 isWin32 && Services.sysinfo.getProperty("hasWinPackageId", false); // Bug 1979190 43 44 if (isPopupWindow || isPrivate || !isWin32 || isMsix) { 45 lazy.logConsole.info("Not initializing Taskbar Tabs Page Action."); 46 return; 47 } 48 49 lazy.logConsole.info("Initializing Taskbar Tabs Page Action."); 50 51 let taskbarTabsButton = aWindow.document.getElementById(kWidgetId); 52 taskbarTabsButton.addEventListener("click", this, true); 53 54 if (lazy.TaskbarTabsUtils.isTaskbarTabWindow(aWindow)) { 55 taskbarTabsButton.setAttribute( 56 "data-l10n-id", 57 "taskbar-tab-urlbar-button-close" 58 ); 59 } 60 61 initVisibilityChanges(aWindow, taskbarTabsButton); 62 }, 63 64 /** 65 * Handles the clicking of the page action button associated with Taskbar 66 * Tabs. 67 * 68 * @param {Event} aEvent - The event triggered by the Taskbar Tabs page 69 * action. 70 * @returns {Promise} Resolves once the event has been handled. 71 */ 72 async handleEvent(aEvent) { 73 if (aEvent.button != 0) { 74 // Only handle left-click events. 75 return; 76 } 77 78 let window = aEvent.target.ownerGlobal; 79 let currentTab = window.gBrowser.selectedTab; 80 81 if (this._processingTabs.has(currentTab)) { 82 // Button was clicked before last input finished processing for the tab, 83 // discard to avoid racing. Don't bother buffering input - clicking 84 // repeatedly before input is processed is not meaningful. 85 lazy.logConsole.debug( 86 `Page Action still processing for tab, dropping input.` 87 ); 88 return; 89 } 90 lazy.logConsole.debug(`Blocking Page Action input for tab.`); 91 this._processingTabs.add(currentTab); 92 93 try { 94 let isTaskbarTabWindow = lazy.TaskbarTabsUtils.isTaskbarTabWindow(window); 95 96 if (!isTaskbarTabWindow) { 97 lazy.logConsole.info("Opening new Taskbar Tab via Page Action."); 98 await lazy.TaskbarTabs.moveTabIntoTaskbarTab(currentTab); 99 } else { 100 lazy.logConsole.info("Closing Taskbar Tab via Page Action."); 101 102 // Move tab to a regular browser window. 103 let id = lazy.TaskbarTabsUtils.getTaskbarTabIdFromWindow(window); 104 105 await lazy.TaskbarTabs.ejectWindow(window); 106 107 if (!(await lazy.TaskbarTabs.getCountForId(id))) { 108 lazy.logConsole.info("Uninstalling Taskbar Tab via Page Action."); 109 await lazy.TaskbarTabs.removeTaskbarTab(id); 110 } 111 } 112 } finally { 113 lazy.logConsole.debug(`Unblocking Page Action input for tab.`); 114 this._processingTabs.delete(currentTab); 115 } 116 }, 117 }; 118 119 /** 120 * Shows or hides the page action as the user navigates. 121 * 122 * @param {Window} aWindow - The window that contains the page action. 123 * @param {Element} aElement - The element that makes up the page action. 124 */ 125 function initVisibilityChanges(aWindow, aElement) { 126 // Filled in at the end; memoized to avoid performance failures. 127 let isTaskbarTabsEnabled = false; 128 129 const shouldHide = aLocation => { 130 if (!isTaskbarTabsEnabled) { 131 return true; 132 } 133 134 // Forcefully initialize Taskbar Tabs. At some point, this will also affect 135 // the page action; in the meantime, ensures that telemetry info is 136 // prepared whenever the pref is enabled. 137 // 138 // This is a promise, but we don't care when it finishes. It's a no-op if 139 // TaskbarTabs already initialized. 140 lazy.TaskbarTabs.waitUntilReady(); 141 142 return ( 143 !(aLocation instanceof Ci.nsIURL) && !aLocation.scheme.startsWith("http") 144 ); 145 }; 146 147 aWindow.gBrowser.addProgressListener({ 148 onLocationChange(aWebProgress, aRequest, aLocation) { 149 if (aWebProgress.isTopLevel) { 150 aElement.hidden = shouldHide(aLocation); 151 } 152 }, 153 }); 154 155 const observer = () => { 156 isTaskbarTabsEnabled = lazy.TaskbarTabsUtils.isEnabled(); 157 aElement.hidden = shouldHide(aWindow.gBrowser.currentURI); 158 }; 159 160 Services.prefs.addObserver("browser.taskbarTabs.enabled", observer); 161 aWindow.addEventListener("unload", function () { 162 Services.prefs.removeObserver("browser.taskbarTabs.enabled", observer); 163 }); 164 165 observer(); 166 }