refactor: tab features

* support for `browser.newtab.url`
This commit is contained in:
Alex Kontos
2025-08-05 13:34:42 +01:00
parent cf8a14469b
commit 2a33ecf02a
8 changed files with 375 additions and 219 deletions

View File

@@ -22,7 +22,7 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
PrefUtils: "resource:///modules/PrefUtils.jsm",
PrivateTab: "resource:///modules/PrivateTab.sys.mjs",
StatusBar: "resource:///modules/StatusBar.sys.mjs",
TabFeatures: "resource:///modules/TabFeatures.jsm",
TabFeatures: "resource:///modules/TabFeatures.sys.mjs",
UICustomizations: "resource:///modules/UICustomizations.jsm",
});

View File

@@ -1,156 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* global */
const EXPORTED_SYMBOLS = ["TabFeatures"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const TabFeatures = {
PREF_ACTIVETAB: "browser.tabs.copyurl.activetab",
PREF_REQUIRECONFIRM: "browser.restart_menu.requireconfirm",
PREF_PURGECACHE: "browser.restart_menu.purgecache",
init(window) {
window.TabFeatures = this;
this.initListeners(window);
},
initListeners(aWindow) {
aWindow.document
.getElementById("tabContextMenu")
?.addEventListener("popupshowing", this.tabContext);
if (AppConstants.platform == "macosx") {
aWindow.document
.getElementById("file-menu")
?.addEventListener("popupshowing", this.tabContext);
} else {
aWindow.document
.getElementById("appMenu-popup")
?.addEventListener("popupshowing", this.tabContext);
}
},
tabContext(aEvent) {
let win = aEvent.view;
if (!win) {
win = Services.wm.getMostRecentWindow("navigator:browser");
}
let { document } = win;
let elements = document.getElementsByClassName("tabFeature");
for (let i = 0; i < elements.length; i++) {
let el = elements[i];
let pref = el.getAttribute("preference");
if (pref) {
let visible = Services.prefs.getBoolPref(pref);
el.hidden = !visible;
}
}
// Can't unload selected tab, so don't show menu item in that case
if (win.TabContextMenu.contextTab === win.gBrowser.selectedTab) {
const el = document.getElementById("context_unloadTab");
el.hidden = true;
}
},
// Copies current tab url to clipboard
copyTabUrl(aUri, aWindow) {
const gClipboardHelper = Cc[
"@mozilla.org/widget/clipboardhelper;1"
].getService(Ci.nsIClipboardHelper);
try {
Services.prefs.getBoolPref(this.PREF_ACTIVETAB)
? gClipboardHelper.copyString(aWindow.gBrowser.currentURI.spec)
: gClipboardHelper.copyString(aUri);
} catch (e) {
throw new Error(
"We're sorry but something has gone wrong with 'CopyTabUrl' " + e
);
}
},
// Copies all tab urls to clipboard
copyAllTabUrls(aWindow) {
const gClipboardHelper = Cc[
"@mozilla.org/widget/clipboardhelper;1"
].getService(Ci.nsIClipboardHelper);
//Get all urls
let urlArr = this._getAllUrls(aWindow);
try {
// Enumerate all urls in to a list.
let urlList = urlArr.join("\n");
// Send list to clipboard.
gClipboardHelper.copyString(urlList.trim());
// Clear url list after clipboard event
urlList = "";
} catch (e) {
throw new Error(
"We're sorry but something has gone wrong with 'copyAllTabUrls' " + e
);
}
},
// Get all the tab urls into an array.
_getAllUrls(aWindow) {
// We don't want to copy about uri's
let blocklist = /^about:.*/i;
let urlArr = [];
let tabCount = aWindow.gBrowser.browsers.length;
Array(tabCount)
.fill()
.map((_, i) => {
let spec = aWindow.gBrowser.getBrowserAtIndex(i).currentURI.spec;
if (!blocklist.test(spec)) {
urlArr.push(spec);
}
});
return urlArr;
},
async restartBrowser() {
try {
if (Services.prefs.getBoolPref(this.PREF_REQUIRECONFIRM)) {
// Need brand in here to be able to expand { -brand-short-name }
let l10n = new Localization([
"branding/brand.ftl",
"browser/waterfox.ftl",
]);
let [title, question] = (
await l10n.formatMessages([
{ id: "restart-prompt-title" },
{ id: "restart-prompt-question" },
])
).map(({ value }) => value);
if (Services.prompt.confirm(null, title, question)) {
// only restart if confirmation given
this._attemptRestart();
}
} else {
this._attemptRestart();
}
} catch (e) {
Cu.reportError(
"We're sorry but something has gone wrong with 'restartBrowser' " + e
);
}
},
_attemptRestart() {
// Purge cache if required
if (Services.prefs.getBoolPref(this.PREF_PURGECACHE)) {
Services.appinfo.invalidateCachesOnRestart();
}
// Initiate the restart
Services.startup.quit(
Services.startup.eRestart | Services.startup.eAttemptQuit
);
},
};

View File

@@ -0,0 +1,322 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { AppConstants } = ChromeUtils.importESModule(
"resource://gre/modules/AppConstants.sys.mjs"
);
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs",
setTimeout: "resource://gre/modules/Timer.sys.mjs",
});
export const TabFeatures = {
NEW_TAB_CONFIG_PATH: "browser.newtab.url",
newTabURL: null,
prefListener: null,
PREF_ACTIVETAB: "browser.tabs.copyurl.activetab",
PREF_REQUIRECONFIRM: "browser.restart_menu.requireconfirm",
PREF_PURGECACHE: "browser.restart_menu.purgecache",
init(aWindow) {
// Wait for XUL elements to be available before initializing listeners.
// 'context_copyTabUrl' is an element from our associated XUL, which we will now wait for.
if (!aWindow.document.getElementById("context_copyTabUrl")) {
lazy.setTimeout(() => {
this.init(aWindow);
}, 50); // Retry after 50ms
return;
}
aWindow.TabFeatures = this;
this.initListeners(aWindow);
this.initNewTabConfig(); // Does not require aWindow
this.initNewTabFocus(aWindow);
},
destroy() {
this.destroyNewTabConfig();
},
initListeners(aWindow) {
const doc = aWindow.document;
doc
.getElementById("tabContextMenu")
?.addEventListener("popupshowing", this.tabContext.bind(this));
if (AppConstants.platform === "macosx") {
doc
.getElementById("file-menu")
?.addEventListener("popupshowing", this.tabContext.bind(this));
} else {
doc
.getElementById("appMenu-popup")
?.addEventListener("popupshowing", this.tabContext.bind(this));
}
const copyTabUrlElement = doc.getElementById("context_copyTabUrl");
if (copyTabUrlElement) {
copyTabUrlElement.addEventListener("command", (_event) => {
if (aWindow.TabContextMenu?.contextTab?.linkedBrowser) {
try {
this.copyTabUrl(
aWindow.TabContextMenu.contextTab.linkedBrowser.currentURI.spec,
aWindow
);
} catch (e) {
console.error(
"TabFeatures: Error inside copyTabUrl listener execution:",
e
);
}
} else {
// console.warn("TabFeatures: copyTabUrl not called, context or linkedBrowser not available.");
}
});
} else {
console.error(
"TabFeatures: FAILED to find element 'context_copyTabUrl'. Listener NOT attached."
);
}
doc
.getElementById("context_copyAllTabUrls")
?.addEventListener("command", (_event) => {
this.copyAllTabUrls(aWindow);
});
doc
.getElementById("context_unloadTab")
?.addEventListener("command", (_event) => {
if (
aWindow.gBrowser &&
aWindow.TabContextMenu &&
aWindow.TabContextMenu.contextTab
) {
// Prevent unloading if it's the last tab or the only non-pinned tab in the window
if (
aWindow.gBrowser.tabs.length > 1 &&
(Array.from(aWindow.gBrowser.tabs).filter((t) => !t.pinned).length >
1 ||
!aWindow.TabContextMenu.contextTab.pinned)
) {
aWindow.gBrowser.discardBrowser(aWindow.TabContextMenu.contextTab);
} else {
// console.log("TabFeatures: discardBrowser not called, conditions not met (e.g., last tab).");
}
} else {
// console.warn("TabFeatures: discardBrowser not called, context not available.");
}
});
const restartMac = doc.getElementById("app_restartBrowser");
if (restartMac) {
restartMac.addEventListener("command", (_event) => {
this.restartBrowser();
});
}
const restartOther = doc.getElementById("appMenu-restart-button");
if (restartOther && restartOther.getAttribute("data-tabfeatures-handler-attached") !== "true") {
restartOther.addEventListener("command", (_event) => {
this.restartBrowser();
});
restartOther.setAttribute("data-tabfeatures-handler-attached", "true");
}
},
initNewTabConfig() {
// Fetch pref if it exists
this.newTabURL = Services.prefs.getStringPref(this.NEW_TAB_CONFIG_PATH, "");
// Only proceed if a value is actually set
if (this.newTabURL) {
try {
lazy.AboutNewTab.newTabURL = this.newTabURL;
this.prefListener = Services.prefs.addObserver(
this.NEW_TAB_CONFIG_PATH,
(_subject, _topic, _data) => {
const newURL = Services.prefs.getStringPref(
this.NEW_TAB_CONFIG_PATH,
""
);
if (newURL) {
lazy.AboutNewTab.newTabURL = newURL;
} else {
// If the pref is cleared, revert to default behavior
lazy.AboutNewTab.resetNewTabURL();
}
}
);
} catch (e) {
console.error("Error initializing new tab config:", e);
}
}
},
initNewTabFocus(window) {
window.gBrowser.tabContainer.addEventListener("TabOpen", (event) => {
const tab = event.target;
const browser = window.gBrowser.getBrowserForTab(tab);
browser.addEventListener(
"load",
function onLoad() {
browser.removeEventListener("load", onLoad);
window.setTimeout(() => {
browser.contentWindow.focus();
}, 0);
},
{ once: true }
);
});
},
destroyNewTabConfig() {
if (this.prefListener) {
Services.prefs.removeObserver(
this.NEW_TAB_CONFIG_PATH,
this.prefListener
);
this.prefListener = null;
}
},
tabContext(aEvent) {
let win = aEvent.view;
if (!win) {
win = Services.wm.getMostRecentWindow("navigator:browser");
}
const { document } = win;
const elements = document.getElementsByClassName("tabFeature");
for (let i = 0; i < elements.length; i++) {
const el = elements[i];
const pref = el.getAttribute("preference");
if (pref) {
const visible = Services.prefs.getBoolPref(pref);
el.hidden = !visible;
}
}
// Can't unload selected tab, so don't show menu item in that case
if (win.TabContextMenu.contextTab === win.gBrowser.selectedTab) {
const el = document.getElementById("context_unloadTab");
el.hidden = true;
}
// Ensure restart button in App Menu (Windows/Linux) has its handler after template instantiation
const restartBtn = document.getElementById("appMenu-restart-button");
if (restartBtn) {
// Toggle iconic styling to match icon prefs so alignment matches Exit when icons are disabled
const iconsDisabled = Services.prefs.getBoolPref("userChrome.icon.disabled", false);
const iconsInPanel = Services.prefs.getBoolPref("userChrome.icon.panel", false);
const shouldIconic = iconsInPanel && !iconsDisabled;
restartBtn.classList.toggle("subviewbutton-iconic", shouldIconic);
if (restartBtn.getAttribute("data-tabfeatures-handler-attached") !== "true") {
restartBtn.addEventListener("command", (_event) => {
this.restartBrowser();
});
restartBtn.setAttribute("data-tabfeatures-handler-attached", "true");
}
}
},
// Copies current tab url to clipboard
copyTabUrl(aUri, aWindow) {
const gClipboardHelper = Cc[
"@mozilla.org/widget/clipboardhelper;1"
].getService(Ci.nsIClipboardHelper);
try {
Services.prefs.getBoolPref(this.PREF_ACTIVETAB)
? gClipboardHelper.copyString(aWindow.gBrowser.currentURI.spec)
: gClipboardHelper.copyString(aUri);
} catch (e) {
throw new Error(
`We're sorry but something has gone wrong with 'CopyTabUrl' ${e}`
);
}
},
// Copies all tab urls to clipboard
copyAllTabUrls(aWindow) {
const gClipboardHelper = Cc[
"@mozilla.org/widget/clipboardhelper;1"
].getService(Ci.nsIClipboardHelper);
//Get all urls
const urlArr = this._getAllUrls(aWindow);
try {
// Enumerate all urls in to a list.
let urlList = urlArr.join("\n");
// Send list to clipboard.
gClipboardHelper.copyString(urlList.trim());
// Clear url list after clipboard event
urlList = "";
} catch (e) {
throw new Error(
`We're sorry but something has gone wrong with 'copyAllTabUrls' ${e}`
);
}
},
// Get all the tab urls into an array.
_getAllUrls(aWindow) {
// We don't want to copy about uri's
const blocklist = /^about:.*/i;
const urlArr = [];
const tabCount = aWindow.gBrowser.browsers.length;
Array(tabCount)
.fill()
.map((_, i) => {
const spec = aWindow.gBrowser.getBrowserAtIndex(i).currentURI.spec;
if (!blocklist.test(spec)) {
urlArr.push(spec);
}
});
return urlArr;
},
async restartBrowser() {
try {
if (Services.prefs.getBoolPref(this.PREF_REQUIRECONFIRM)) {
// Need brand in here to be able to expand { -brand-short-name }
const l10n = new Localization([
"branding/brand.ftl",
"browser/waterfox.ftl",
]);
const [title, question] = (
await l10n.formatMessages([
{ id: "restart-prompt-title" },
{ id: "restart-prompt-question" },
])
).map(({ value }) => value);
if (Services.prompt.confirm(null, title, question)) {
// only restart if confirmation given
this._attemptRestart();
}
} else {
this._attemptRestart();
}
} catch (e) {
console.error(
"We're sorry but something has gone wrong with 'restartBrowser' ",
e
);
}
},
_attemptRestart() {
// Purge cache if required
if (Services.prefs.getBoolPref(this.PREF_PURGECACHE)) {
Services.appinfo.invalidateCachesOnRestart();
}
// Initiate the restart
Services.startup.quit(
Services.startup.eRestart | Services.startup.eAttemptQuit
);
},
};

View File

@@ -4,8 +4,9 @@
max-width: 225px;
min-width: var(--tab-min-width);
width: 0;
transition: min-width 100ms ease-out,
max-width 100ms ease-out;
transition:
min-width 100ms ease-out,
max-width 100ms ease-out;
}
.tabbrowser-tab:is([pinned]):not([fadein]) {

View File

@@ -8,35 +8,32 @@
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<popupset id="mainPopupSet">
<menupopup id="tabContextMenu">
<menuitem id="context_duplicateTab" data-lazy-l10n-id="duplicate-tab"
oncommand="duplicateTabIn(TabContextMenu.contextTab, 'tab');" class="tabFeature"
preference="browser.tabs.duplicateTab" />
<menuitem id="context_copyTabUrl" class="tabFeature"
oncommand="TabFeatures.copyTabUrl(TabContextMenu.contextTab.linkedBrowser.currentURI.spec, window);"
data-lazy-l10n-id="copy-url" preference="browser.tabs.copyurl" insertafter="context_duplicateTab" />
<menuitem id="context_copyAllTabUrls" class="tabFeature" oncommand="TabFeatures.copyAllTabUrls(window);"
data-lazy-l10n-id="copy-url" preference="browser.tabs.copyurl" />
<menuitem id="context_copyAllTabUrls" class="tabFeature"
data-lazy-l10n-id="copy-all-urls" preference="browser.tabs.copyallurls"
insertafter="context_copyTabUrl" />
<menuitem id="context_unloadTab" class="tabFeature"
oncommand="gBrowser.discardBrowser(TabContextMenu.contextTab);" data-lazy-l10n-id="unload-tab"
data-lazy-l10n-id="unload-tab"
preference="browser.tabs.unloadTab" insertafter="context_copyAllTabUrls" />
</menupopup>
</popupset>
#ifdef XP_MACOSX
<menubar id="main-menubar">
<menuitem id="app_restartBrowser" class="tabFeature" oncommand="TabFeatures.restartBrowser();"
<menuitem id="app_restartBrowser" class="tabFeature"
data-l10n-id="appmenuitem-restart-browser" preference="browser.restart_menu.showpanelmenubtn" hidden="true"
insertafter="goOfflineMenuitem" />
</menubar>
#else
<html:template id="appMenu-viewCache">
<panelview id="appMenu-protonMainView">
<vbox id="appMenu-subview-body" class="panel-subview-body">
<toolbarbutton id="appMenu-restart-button" class="subviewbutton subviewbutton-iconic tabFeature"
oncommand="TabFeatures.restartBrowser();" data-l10n-id="appmenuitem-restart-browser"
preference="browser.restart_menu.showpanelmenubtn" hidden="true" />
</vbox>
</panelview>
</html:template>
<html:template id="appMenu-viewCache">
<panelview id="appMenu-mainView">
<vbox class="panel-subview-body">
<toolbarbutton id="appMenu-restart-button" class="subviewbutton subviewbutton-iconic tabFeature"
data-l10n-id="appmenuitem-restart-browser"
preference="browser.restart_menu.showpanelmenubtn" hidden="true"
insertbefore="appMenu-quit-button2" />
</vbox>
</panelview>
</html:template>
#endif
</overlay>

View File

@@ -5,7 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXTRA_JS_MODULES += [
"TabFeatures.jsm",
"TabFeatures.sys.mjs",
]
BROWSER_CHROME_MANIFESTS += ["test/browser/browser.ini"]

View File

@@ -1,9 +1,7 @@
"use strict";
add_task(async function testCopyTabUrls() {
// Make sure elements are present
let copyTabUrl = document.getElementById("context_copyTabUrl");
let copyAllTabUrls = document.getElementById("context_copyAllTabUrls");
const copyTabUrl = document.getElementById("context_copyTabUrl");
const copyAllTabUrls = document.getElementById("context_copyAllTabUrls");
ok(copyTabUrl, "Copy tab URL is included");
ok(copyAllTabUrls, "Copy all tab URLs is included");
// Make sure that defaults are set correctly
@@ -27,7 +25,7 @@ add_task(async function testCopyTabUrls() {
add_task(async function testHideDuplicateTab() {
// Setting duplicateTab pref to false should hide element in all windows
let duplicateTab = document.getElementById("context_duplicateTab");
const duplicateTab = document.getElementById("context_duplicateTab");
Services.prefs.setBoolPref(DUPLICATE_TAB_PREF, false);
await openAndCloseTabContextMenu(gBrowser.selectedTab);
is(duplicateTab.hidden, true, "Duplicate tab hidden");
@@ -40,13 +38,13 @@ add_task(async function testHideDuplicateTab() {
add_task(async function testRestartItem() {
// Make sure element is present
let restartBrowserMenu = document.getElementById("app_restartBrowser");
const restartBrowserMenu = document.getElementById("app_restartBrowser");
// Need to use PanelMultiView to get PanelUI elements
let restartBrowserApp = PanelMultiView.getViewNode(
const restartBrowserApp = PanelMultiView.getViewNode(
document,
"appMenu-restart-button"
);
if (OS == "macosx") {
if (OS === "macosx") {
ok(restartBrowserMenu, "Restart browser menu bar item is included");
is(restartBrowserApp, null, "Restart browser appMenu item not included");
await openAndCloseFileMenu();
@@ -65,7 +63,7 @@ add_task(async function testRestartItem() {
}
// Make sure element is hidden
Services.prefs.setBoolPref(RESTART_PREF, false);
if (OS == "macosx") {
if (OS === "macosx") {
await openAndCloseFileMenu();
is(
restartBrowserMenu.hidden,
@@ -77,22 +75,22 @@ add_task(async function testRestartItem() {
});
add_task(async function testCopyUrlFunctionality() {
let copyTabUrl = document.getElementById("context_copyTabUrl");
let copyAllTabUrls = document.getElementById("context_copyAllTabUrls");
const copyTabUrl = document.getElementById("context_copyTabUrl");
const copyAllTabUrls = document.getElementById("context_copyAllTabUrls");
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URI1);
let browser = tab.linkedBrowser;
const browser = tab.linkedBrowser;
// Test copy tab url copies URL
await openTabContextMenu(tab);
EventUtils.synthesizeMouseAtCenter(copyTabUrl, {});
let tabURI = await pasteFromClipboard(browser);
const tabURI = await pasteFromClipboard(browser);
is(tabURI, URI1);
// Test copy all tab urls
Services.prefs.setBoolPref(COPY_ALL_URLS_PREF, true);
const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, URI2);
await openTabContextMenu(tab);
EventUtils.synthesizeMouseAtCenter(copyAllTabUrls, {});
let tabURIs = await pasteFromClipboard(browser);
is(tabURIs, URI1 + "\n" + URI2);
const tabURIs = await pasteFromClipboard(browser);
is(tabURIs, `${URI1}\n${URI2}`);
// Test copy active tab pref
Services.prefs.setBoolPref(COPY_ACTIVE_URL_PREF, true);
await openTabContextMenu(tab);

View File

@@ -1,28 +1,22 @@
"use strict";
const { synthesizeDrop, synthesizeMouseAtCenter } = EventUtils;
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const _COPY_URL_PREF = "browser.tabs.copyurl";
const _COPY_ALL_URLS_PREF = "browser.tabs.copyallurls";
const _COPY_ACTIVE_URL_PREF = "browser.tabs.copyurl.activetab";
const _DUPLICATE_TAB_PREF = "browser.tabs.duplicateTab";
const _RESTART_PREF = "browser.restart_menu.showpanelmenubtn";
var { synthesizeDrop, synthesizeMouseAtCenter } = EventUtils;
const _URI1 = "https://test1.example.com/";
const _URI2 = "https://example.com/";
const COPY_URL_PREF = "browser.tabs.copyurl";
const COPY_ALL_URLS_PREF = "browser.tabs.copyallurls";
const COPY_ACTIVE_URL_PREF = "browser.tabs.copyurl.activetab";
const DUPLICATE_TAB_PREF = "browser.tabs.duplicateTab";
const RESTART_PREF = "browser.restart_menu.showpanelmenubtn";
const URI1 = "https://test1.example.com/";
const URI2 = "https://example.com/";
let OS = AppConstants.platform;
const _OS = AppConstants.platform;
/**
* Helper for opening the toolbar context menu.
*/
async function openTabContextMenu(tab) {
info("Opening tab context menu");
let contextMenu = document.getElementById("tabContextMenu");
let openTabContextMenuPromise = BrowserTestUtils.waitForPopupEvent(
const contextMenu = document.getElementById("tabContextMenu");
const openTabContextMenuPromise = BrowserTestUtils.waitForPopupEvent(
contextMenu,
"shown"
);
@@ -32,7 +26,7 @@ async function openTabContextMenu(tab) {
return contextMenu;
}
async function openAndCloseTabContextMenu(tab) {
async function _openAndCloseTabContextMenu(tab) {
await openTabContextMenu(tab);
info("Opened tab context menu");
await EventUtils.synthesizeKey("VK_ESCAPE", {});
@@ -44,8 +38,8 @@ async function openAndCloseTabContextMenu(tab) {
*/
async function openFileMenu() {
info("Opening file menu");
let fileMenu = document.getElementById("file-menu");
let openFileMenuPromise = BrowserTestUtils.waitForPopupEvent(
const fileMenu = document.getElementById("file-menu");
const openFileMenuPromise = BrowserTestUtils.waitForPopupEvent(
fileMenu,
"shown"
);
@@ -54,7 +48,7 @@ async function openFileMenu() {
return fileMenu;
}
async function openAndCloseFileMenu() {
async function _openAndCloseFileMenu() {
await openFileMenu();
await EventUtils.synthesizeKey("VK_ESCAPE", {});
info("Closed file menu");
@@ -63,8 +57,8 @@ async function openAndCloseFileMenu() {
/**
* Helper for opening toolbar context menu.
*/
async function openToolbarContextMenu(contextMenu, target) {
let popupshown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
async function _openToolbarContextMenu(contextMenu, target) {
const popupshown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(target, { type: "contextmenu" });
await popupshown;
}
@@ -73,15 +67,15 @@ async function openToolbarContextMenu(contextMenu, target) {
* Helper to paste from clipboard
*/
async function pasteFromClipboard(browser) {
async function _pasteFromClipboard(browser) {
return SpecialPowers.spawn(browser, [], () => {
let { document } = content;
const { document } = content;
document.body.contentEditable = true;
document.body.focus();
let pastePromise = new Promise(resolve => {
const pastePromise = new Promise((resolve) => {
document.addEventListener(
"paste",
e => {
(e) => {
resolve(e.clipboardData.getData("text/plain"));
},
{ once: true }