refactor: tab features
* support for `browser.newtab.url`
This commit is contained in:
@@ -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",
|
||||
});
|
||||
|
||||
|
||||
@@ -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
|
||||
);
|
||||
},
|
||||
};
|
||||
322
waterfox/browser/components/tabfeatures/TabFeatures.sys.mjs
Normal file
322
waterfox/browser/components/tabfeatures/TabFeatures.sys.mjs
Normal 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
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 }
|
||||
|
||||
Reference in New Issue
Block a user