refactor: private tab
This commit is contained in:
@@ -29,7 +29,10 @@ export var PrivateBrowsingUtils = {
|
||||
|
||||
// This should be used only in frame scripts.
|
||||
isContentWindowPrivate: function pbu_isWindowPrivate(aWindow) {
|
||||
return this.privacyContextFromWindow(aWindow).usePrivateBrowsing;
|
||||
// Waterfox: Essential to prevent form data from being saved.
|
||||
return this.privacyContextFromWindow(aWindow).usePrivateBrowsing
|
||||
? true
|
||||
: Services.prefs.getBoolPref("browser.tabs.selectedTabPrivate", false);
|
||||
},
|
||||
|
||||
isBrowserPrivate(aBrowser) {
|
||||
|
||||
@@ -20,7 +20,7 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
ChromeManifest: "resource:///modules/ChromeManifest.sys.mjs",
|
||||
Overlays: "resource:///modules/Overlays.sys.mjs",
|
||||
PrefUtils: "resource:///modules/PrefUtils.jsm",
|
||||
PrivateTab: "resource:///modules/PrivateTab.jsm",
|
||||
PrivateTab: "resource:///modules/PrivateTab.sys.mjs",
|
||||
StatusBar: "resource:///modules/StatusBar.jsm",
|
||||
TabFeatures: "resource:///modules/TabFeatures.jsm",
|
||||
UICustomizations: "resource:///modules/UICustomizations.jsm",
|
||||
|
||||
@@ -1,503 +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/. */
|
||||
|
||||
const EXPORTED_SYMBOLS = ["PrivateTab"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const { ContextualIdentityService } = ChromeUtils.import(
|
||||
"resource://gre/modules/ContextualIdentityService.jsm"
|
||||
);
|
||||
|
||||
const { PlacesUIUtils } = ChromeUtils.import(
|
||||
"resource:///modules/PlacesUIUtils.jsm"
|
||||
);
|
||||
|
||||
const { TabStateCache } = ChromeUtils.import(
|
||||
"resource:///modules/sessionstore/TabStateCache.jsm"
|
||||
);
|
||||
|
||||
const { TabStateFlusher } = ChromeUtils.import(
|
||||
"resource:///modules/sessionstore/TabStateFlusher.jsm"
|
||||
);
|
||||
|
||||
const { BrowserUtils } = ChromeUtils.import(
|
||||
"resource:///modules/BrowserUtils.jsm"
|
||||
);
|
||||
|
||||
const { PrefUtils } = ChromeUtils.import("resource:///modules/PrefUtils.jsm");
|
||||
|
||||
const PrivateTab = {
|
||||
config: {
|
||||
neverClearData: false, // TODO: change to pref controlled value; if you want to not record history but don"t care about other data, maybe even want to keep private logins
|
||||
restoreTabsOnRestart: true,
|
||||
doNotClearDataUntilFxIsClosed: false,
|
||||
},
|
||||
|
||||
openTabs: new Set(),
|
||||
|
||||
BTN_ID: "privateTab-button",
|
||||
BTN2_ID: "newPrivateTab-button",
|
||||
|
||||
get style() {
|
||||
return `
|
||||
@-moz-document url('chrome://browser/content/browser.xhtml') {
|
||||
#private-mask[enabled="true"] {
|
||||
display: block !important;
|
||||
}
|
||||
#${this.BTN_ID}, #${this.BTN2_ID} {
|
||||
list-style-image: url(chrome://browser/skin/privateBrowsing.svg);
|
||||
}
|
||||
#tabbrowser-tabs[hasadjacentnewprivatetabbutton]:not([overflow="true"]) ~ #${this.BTN_ID},
|
||||
#tabbrowser-tabs[overflow="true"] > #tabbrowser-arrowscrollbox > #${this.BTN2_ID},
|
||||
#tabbrowser-tabs:not([hasadjacentnewprivatetabbutton]) > #tabbrowser-arrowscrollbox > #${this.BTN2_ID},
|
||||
#TabsToolbar[customizing="true"] #${this.BTN2_ID} {
|
||||
display: none;
|
||||
}
|
||||
.tabbrowser-tab[usercontextid="${this.container.userContextId}"] .tab-label {
|
||||
text-decoration: underline !important;
|
||||
text-decoration-color: -moz-nativehyperlinktext !important;
|
||||
text-decoration-style: dashed !important;
|
||||
}
|
||||
.tabbrowser-tab[usercontextid="${this.container.userContextId}"][pinned] .tab-icon-image,
|
||||
.tabbrowser-tab[usercontextid="${this.container.userContextId}"][pinned] .tab-throbber {
|
||||
border-bottom: 1px dashed -moz-nativehyperlinktext !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
},
|
||||
|
||||
init(window) {
|
||||
// Only init in a non-private window
|
||||
if (!window.PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
window.PrivateTab = this;
|
||||
this.initContainer("Private");
|
||||
this.initObservers(window);
|
||||
this.initListeners(window);
|
||||
this.initCustomFunctions(window);
|
||||
this.overridePlacesUIUtils();
|
||||
this.updatePrivateMaskId(window);
|
||||
BrowserUtils.setStyle(this.style);
|
||||
}
|
||||
},
|
||||
|
||||
initContainer(aName) {
|
||||
ContextualIdentityService.ensureDataReady();
|
||||
this.container = ContextualIdentityService._identities.find(
|
||||
container => container.name == aName
|
||||
);
|
||||
if (this.container && this.container.icon == "private") {
|
||||
ContextualIdentityService.remove(this.container.userContextId);
|
||||
this.container = undefined;
|
||||
}
|
||||
if (!this.container) {
|
||||
ContextualIdentityService.create(aName, "fingerprint", "purple");
|
||||
this.container = ContextualIdentityService._identities.find(
|
||||
container => container.name == aName
|
||||
);
|
||||
} else if (!this.config.neverClearData) {
|
||||
this.clearData();
|
||||
}
|
||||
return this.container;
|
||||
},
|
||||
|
||||
clearData() {
|
||||
Services.clearData.deleteDataFromOriginAttributesPattern({
|
||||
userContextId: this.container.userContextId,
|
||||
});
|
||||
},
|
||||
|
||||
initObservers(aWindow) {
|
||||
this.setPrivateObserver();
|
||||
},
|
||||
|
||||
initListeners(aWindow) {
|
||||
this.initPrivateTabListeners(aWindow);
|
||||
aWindow.document
|
||||
.getElementById("placesContext")
|
||||
?.addEventListener("popupshowing", this.placesContext);
|
||||
aWindow.document
|
||||
.getElementById("contentAreaContextMenu")
|
||||
?.addEventListener("popupshowing", this.contentContext);
|
||||
aWindow.document
|
||||
.getElementById("contentAreaContextMenu")
|
||||
?.addEventListener("popuphidden", this.hideContext);
|
||||
aWindow.document
|
||||
.getElementById("tabContextMenu")
|
||||
?.addEventListener("popupshowing", this.tabContext);
|
||||
aWindow.document
|
||||
.getElementById("newPrivateTab-button")
|
||||
?.addEventListener("click", this.toolbarClick);
|
||||
},
|
||||
|
||||
async updatePrivateMaskId(aWindow) {
|
||||
let privateMask = aWindow.document.getElementsByClassName(
|
||||
"private-browsing-indicator"
|
||||
)[0];
|
||||
privateMask.id = "private-mask";
|
||||
},
|
||||
|
||||
setPrivateObserver() {
|
||||
if (!this.config.neverClearData) {
|
||||
let observe = () => {
|
||||
this.clearData();
|
||||
if (!this.config.restoreTabsOnRestart) {
|
||||
this.closeTabs();
|
||||
}
|
||||
};
|
||||
Services.obs.addObserver(observe, "quit-application-granted");
|
||||
}
|
||||
},
|
||||
|
||||
closeTabs() {
|
||||
ContextualIdentityService._forEachContainerTab((tab, tabbrowser) => {
|
||||
if (tab.userContextId == this.container.userContextId) {
|
||||
tabbrowser.removeTab(tab);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
placesContext(aEvent) {
|
||||
let win = aEvent.view;
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
let { document } = win;
|
||||
let openAll = "placesContext_openBookmarkContainer:tabs";
|
||||
let openAllLinks = "placesContext_openLinks:tabs";
|
||||
let openTab = "placesContext_open:newtab";
|
||||
// let document = event.target.ownerDocument;
|
||||
document.getElementById("openPrivate").disabled = document.getElementById(
|
||||
openTab
|
||||
).disabled;
|
||||
document.getElementById("openPrivate").hidden = document.getElementById(
|
||||
openTab
|
||||
).hidden;
|
||||
document.getElementById(
|
||||
"openAllPrivate"
|
||||
).disabled = document.getElementById(openAll).disabled;
|
||||
document.getElementById("openAllPrivate").hidden = document.getElementById(
|
||||
openAll
|
||||
).hidden;
|
||||
document.getElementById(
|
||||
"openAllLinksPrivate"
|
||||
).disabled = document.getElementById(openAllLinks).disabled;
|
||||
document.getElementById(
|
||||
"openAllLinksPrivate"
|
||||
).hidden = document.getElementById(openAllLinks).hidden;
|
||||
},
|
||||
|
||||
isPrivate(aTab) {
|
||||
return aTab.getAttribute("usercontextid") == this.container.userContextId;
|
||||
},
|
||||
|
||||
contentContext(aEvent) {
|
||||
let win = aEvent.view;
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
let { gContextMenu, gBrowser, PrivateTab } = win;
|
||||
let tab = gBrowser.getTabForBrowser(gContextMenu.browser);
|
||||
gContextMenu.showItem(
|
||||
"openLinkInPrivateTab",
|
||||
gContextMenu.onSaveableLink || gContextMenu.onPlainTextLink
|
||||
);
|
||||
let isPrivate = PrivateTab.isPrivate(tab);
|
||||
if (isPrivate) {
|
||||
gContextMenu.showItem("context-openlinkincontainertab", false);
|
||||
}
|
||||
},
|
||||
|
||||
hideContext(aEvent) {
|
||||
if (!aEvent.view) {
|
||||
return;
|
||||
}
|
||||
if (aEvent.target == this) {
|
||||
aEvent.view.document.getElementById("openLinkInPrivateTab").hidden = true;
|
||||
}
|
||||
},
|
||||
|
||||
tabContext(aEvent) {
|
||||
let win = aEvent.view;
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
let { document, PrivateTab } = win;
|
||||
const isPrivate =
|
||||
win.TabContextMenu.contextTab.userContextId ===
|
||||
PrivateTab.container.userContextId;
|
||||
document
|
||||
.getElementById("toggleTabPrivateState")
|
||||
.setAttribute("data-l10n-args", JSON.stringify({ isPrivate }));
|
||||
},
|
||||
|
||||
openLink(aEvent) {
|
||||
let win = aEvent.view;
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
let { gContextMenu, PrivateTab, document } = win;
|
||||
win.openLinkIn(
|
||||
gContextMenu.linkURL,
|
||||
"tab",
|
||||
gContextMenu._openLinkInParameters({
|
||||
userContextId: PrivateTab.container.userContextId,
|
||||
triggeringPrincipal: document.nodePrincipal,
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
toolbarClick(aEvent) {
|
||||
let win = aEvent.view;
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
let { PrivateTab, document } = win;
|
||||
if (aEvent.button == 0) {
|
||||
PrivateTab.browserOpenTabPrivate(win);
|
||||
} else if (aEvent.button == 2) {
|
||||
document.popupNode = document.getElementById(PrivateTab.BTN_ID);
|
||||
document
|
||||
.getElementById("toolbar-context-menu")
|
||||
.openPopup(this, "after_start", 14, -10, false, false);
|
||||
document.getElementsByClassName(
|
||||
"customize-context-removeFromToolbar"
|
||||
)[0].disabled = false;
|
||||
document.getElementsByClassName(
|
||||
"customize-context-moveToPanel"
|
||||
)[0].disabled = false;
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
overridePlacesUIUtils() {
|
||||
/* globals BrowserWindowTracker */
|
||||
// Unused vars required for eval to execute
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { PlacesUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/PlacesUtils.jsm"
|
||||
);
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { PrivateBrowsingUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm"
|
||||
);
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function getBrowserWindow(aWindow) {
|
||||
// Prefer the caller window if it's a browser window, otherwise use
|
||||
// the top browser window.
|
||||
return aWindow &&
|
||||
aWindow.document.documentElement.getAttribute("windowtype") ==
|
||||
"navigator:browser"
|
||||
? aWindow
|
||||
: BrowserWindowTracker.getTopWindow();
|
||||
}
|
||||
|
||||
// TODO: replace eval with new Function()();
|
||||
try {
|
||||
// eslint-disable-next-line no-eval
|
||||
eval(
|
||||
"PlacesUIUtils.openTabset = function " +
|
||||
PlacesUIUtils.openTabset
|
||||
.toString()
|
||||
.replace(
|
||||
/(\s+)(inBackground: loadInBackground,)/,
|
||||
"$1$2$1userContextId: aEvent.userContextId || 0,"
|
||||
)
|
||||
);
|
||||
} catch (ex) {}
|
||||
},
|
||||
|
||||
openAllPrivate(event) {
|
||||
event.userContextId = this.container.userContextId;
|
||||
PlacesUIUtils.openSelectionInTabs(event);
|
||||
},
|
||||
|
||||
openPrivateTab(event) {
|
||||
let view = event.target.parentElement._view;
|
||||
PlacesUIUtils._openNodeIn(view.selectedNode, "tab", view.ownerWindow, {
|
||||
aPrivate: false,
|
||||
userContextId: this.container.userContextId,
|
||||
});
|
||||
},
|
||||
|
||||
togglePrivate(aWindow, aTab = aWindow.gBrowser.selectedTab) {
|
||||
let newTab;
|
||||
const { gBrowser, gURLBar } = aWindow;
|
||||
aTab.setAttribute("isToggling", true);
|
||||
const shouldSelect = aTab == aWindow.gBrowser.selectedTab;
|
||||
try {
|
||||
newTab = gBrowser.duplicateTab(aTab);
|
||||
if (shouldSelect) {
|
||||
gBrowser.selectedTab = newTab;
|
||||
const focusUrlbar = gURLBar.focused;
|
||||
if (focusUrlbar) {
|
||||
gURLBar.focus();
|
||||
}
|
||||
}
|
||||
gBrowser.removeTab(aTab);
|
||||
} catch (ex) {
|
||||
// Can use this to pop up failure message
|
||||
}
|
||||
return newTab;
|
||||
},
|
||||
|
||||
browserOpenTabPrivate(aWindow) {
|
||||
aWindow.openTrustedLinkIn(aWindow.BROWSER_NEW_TAB_URL, "tab", {
|
||||
userContextId: this.container.userContextId,
|
||||
});
|
||||
},
|
||||
|
||||
initPrivateTabListeners(aWindow) {
|
||||
let { gBrowser } = aWindow;
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", this.onTabSelect);
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", this.onTabOpen);
|
||||
|
||||
gBrowser.privateListener = e => {
|
||||
let browser = e.target;
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (!tab) {
|
||||
return;
|
||||
}
|
||||
let isPrivate = this.isPrivate(tab);
|
||||
|
||||
if (!isPrivate) {
|
||||
if (this.observePrivateTabs) {
|
||||
this.openTabs.delete(tab);
|
||||
if (!this.openTabs.size) {
|
||||
this.clearData();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.observePrivateTabs) {
|
||||
this.openTabs.add(tab);
|
||||
}
|
||||
|
||||
browser.browsingContext.useGlobalHistory = false;
|
||||
};
|
||||
|
||||
aWindow.addEventListener("XULFrameLoaderCreated", gBrowser.privateListener);
|
||||
|
||||
if (this.observePrivateTabs) {
|
||||
gBrowser.tabContainer.addEventListener("TabClose", this.onTabClose);
|
||||
}
|
||||
},
|
||||
|
||||
onTabSelect(aEvent) {
|
||||
let tab = aEvent.target;
|
||||
if (!tab) {
|
||||
return;
|
||||
}
|
||||
let win = tab.ownerGlobal;
|
||||
let { PrivateTab } = win;
|
||||
let prevTab = aEvent.detail.previousTab;
|
||||
let isPrivate = PrivateTab.isPrivate(tab);
|
||||
|
||||
if (tab.userContextId != prevTab.userContextId) {
|
||||
// Show/hide private mask on browser window
|
||||
PrivateTab.toggleMask(win);
|
||||
// Ensure we don't save search suggestions for PrivateTab
|
||||
win.gURLBar.isPrivate = isPrivate;
|
||||
// Update selected tab private status for autofill
|
||||
PrefUtils.set("browser.tabs.selectedTabPrivate", isPrivate);
|
||||
}
|
||||
},
|
||||
|
||||
async onTabOpen(aEvent) {
|
||||
// Update tab state cache
|
||||
let tab = aEvent.target;
|
||||
if (!tab) {
|
||||
return;
|
||||
}
|
||||
let { PrivateTab } = tab.ownerGlobal;
|
||||
let isPrivate = PrivateTab.isPrivate(tab);
|
||||
// if statement is temp solution to prevent containers being dropped on restart.
|
||||
// The flushing and cache updating should only occur if the parent tab was
|
||||
// private and the new tab is non-private OR the parent tab was non-private
|
||||
// and the new tab is private. Otherwise we should rely on default behaviour.
|
||||
// We also need to be wary of pinned state of tabs, as that may also have been
|
||||
// affected in the same case.
|
||||
if (isPrivate) {
|
||||
let userContextId = isPrivate ? PrivateTab.container.userContextId : 0;
|
||||
// Duplicating a tab copies the tab state cache from the parent tab.
|
||||
// Therefore we need to flush the tab state to ensure it's updated,
|
||||
// then overwrite the tab usercontextid so that any restored tabs
|
||||
// are opened in the correct container, rather than that of their
|
||||
// parent tab.
|
||||
let browser = tab.linkedBrowser;
|
||||
// Can't update tab state if we can't get the browser
|
||||
if (browser) {
|
||||
TabStateFlusher.flush(browser)
|
||||
.then(() => {
|
||||
TabStateCache.update(tab.linkedBrowser.permanentKey, {
|
||||
isPrivate,
|
||||
userContextId,
|
||||
});
|
||||
})
|
||||
.catch(ex => {
|
||||
// Sometimes tests fail here
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onTabClose(aEvent) {
|
||||
let tab = aEvent.target;
|
||||
if (!tab) {
|
||||
return;
|
||||
}
|
||||
let { PrivateTab } = tab.ownerGlobal;
|
||||
if (PrivateTab.isPrivate(tab)) {
|
||||
PrivateTab.openTabs.delete(tab);
|
||||
if (!PrivateTab.openTabs.size) {
|
||||
PrivateTab.clearData();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toggleMask(aWindow) {
|
||||
let { gBrowser } = aWindow;
|
||||
let privateMask = aWindow.document.getElementById("private-mask");
|
||||
if (gBrowser.selectedTab.isToggling) {
|
||||
privateMask.setAttribute(
|
||||
"enabled",
|
||||
gBrowser.selectedTab.userContextId == this.container.userContextId
|
||||
? "false"
|
||||
: "true"
|
||||
);
|
||||
} else {
|
||||
privateMask.setAttribute(
|
||||
"enabled",
|
||||
gBrowser.selectedTab.userContextId == this.container.userContextId
|
||||
? "true"
|
||||
: "false"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
get observePrivateTabs() {
|
||||
return (
|
||||
!this.config.neverClearData && !this.config.doNotClearDataUntilFxIsClosed
|
||||
);
|
||||
},
|
||||
|
||||
initCustomFunctions(aWindow) {
|
||||
let { MozElements, PrivateTab } = aWindow;
|
||||
MozElements.MozTab.prototype.getAttribute = function(att) {
|
||||
if (att == "usercontextid" && this.getAttribute("isToggling", false)) {
|
||||
this.removeAttribute("isToggling");
|
||||
// If in private tab and we attempt to toggle, remove container, else convert to private tab
|
||||
return PrivateTab.orig_getAttribute.call(this, att) ==
|
||||
PrivateTab.container.userContextId
|
||||
? 0
|
||||
: PrivateTab.container.userContextId;
|
||||
}
|
||||
return PrivateTab.orig_getAttribute.call(this, att);
|
||||
};
|
||||
},
|
||||
|
||||
orig_getAttribute: Services.wm.getMostRecentBrowserWindow("navigator:browser")
|
||||
.MozElements.MozTab.prototype.getAttribute,
|
||||
};
|
||||
1250
waterfox/browser/components/privatetab/PrivateTab.sys.mjs
Normal file
1250
waterfox/browser/components/privatetab/PrivateTab.sys.mjs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,35 +8,34 @@
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<keyset id="privateTab-keyset" insertbefore="mainPopupSet">
|
||||
<key id="togglePrivateTab-key" modifiers="alt control" key="T" oncommand="PrivateTab.togglePrivate(window)" />
|
||||
<key id="newPrivateTab-key" modifiers="alt control" key="P"
|
||||
oncommand="PrivateTab.browserOpenTabPrivate(window)" />
|
||||
<key id="togglePrivateTab-key" modifiers="alt control" key="T" />
|
||||
<key id="newPrivateTab-key" modifiers="alt control" key="P" />
|
||||
</keyset>
|
||||
|
||||
<popupset id="mainPopupSet">
|
||||
<menupopup id="tabContextMenu">
|
||||
<menuitem id="toggleTabPrivateState" data-l10n-id="private-tab"
|
||||
data-l10n-args="{"isPrivate":false}" class="privatetab-icon" acceltext="Ctrl+Alt+T"
|
||||
oncommand="PrivateTab.togglePrivate(window, TabContextMenu.contextTab)" insertafter="context_pinTab" />
|
||||
insertafter="context_pinTab" />
|
||||
</menupopup>
|
||||
<menupopup id="placesContext">
|
||||
<menuitem id="openAllPrivate" data-l10n-id="open-all-private" class="privatetab-icon"
|
||||
oncommand="PrivateTab.openAllPrivate(event);" insertafter="placesContext_openBookmarkLinks:tabs" />
|
||||
insertafter="placesContext_openBookmarkLinks:tabs" />
|
||||
<menuitem id="openPrivate" data-l10n-id="open-private-tab" class="privatetab-icon"
|
||||
oncommand="PrivateTab.openPrivateTab(event);" insertafter="placesContext_open:newtab" />
|
||||
insertafter="placesContext_open:newtab" />
|
||||
<menuitem id="openAllLinksPrivate" data-l10n-id="open-all-links-private" class="privatetab-icon"
|
||||
oncommand="PrivateTab.openAllPrivate(event);" insertafter="placesContext_openLinks:tabs" />
|
||||
insertafter="placesContext_openLinks:tabs" />
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
<menupopup id="menu_FilePopup">
|
||||
<menuitem id="menu_newPrivateTab" data-l10n-id="new-private-tab" acceltext="Ctrl+Alt+P"
|
||||
oncommand="PrivateTab.browserOpenTabPrivate(window)" insertafter="menu_newNavigatorTab" />
|
||||
insertafter="menu_newNavigatorTab" />
|
||||
</menupopup>
|
||||
|
||||
<menupopup id="contentAreaContextMenu">
|
||||
<menuitem id="openLinkInPrivateTab" data-l10n-id="open-link-private" class="privatetab-icon"
|
||||
oncommand="PrivateTab.openLink(event);" insertafter="context-openlinkintab" />
|
||||
insertafter="context-openlinkintab" />
|
||||
</menupopup>
|
||||
|
||||
</overlay>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
"PrivateTab.jsm",
|
||||
"PrivateTab.sys.mjs",
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ["test/browser/browser.ini"]
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
async function togglePrivate(tab, skip = false) {
|
||||
@@ -7,32 +5,32 @@ async function togglePrivate(tab, skip = false) {
|
||||
return PrivateTab.togglePrivate(window, tab);
|
||||
}
|
||||
await openTabContextMenu(tab);
|
||||
let openPrivate = document.getElementById("toggleTabPrivateState");
|
||||
const openPrivate = document.getElementById("toggleTabPrivateState");
|
||||
openPrivate.click();
|
||||
return gBrowser.selectedTab;
|
||||
}
|
||||
|
||||
// Test elements exist in correct locations
|
||||
add_task(async function testButtonsExist() {
|
||||
let b1 = document.getElementById("openAllPrivate");
|
||||
const b1 = document.getElementById("openAllPrivate");
|
||||
ok(b1, "Multiple bookmark context menu item added.");
|
||||
let b2 = document.getElementById("openAllLinksPrivate");
|
||||
const b2 = document.getElementById("openAllLinksPrivate");
|
||||
ok(b2, "Multiple link context menu item added.");
|
||||
let b3 = document.getElementById("openPrivate");
|
||||
const b3 = document.getElementById("openPrivate");
|
||||
ok(b3, "New private tab item added.");
|
||||
let b4 = document.getElementById("menu_newPrivateTab");
|
||||
const b4 = document.getElementById("menu_newPrivateTab");
|
||||
ok(b4, "Menu item added.");
|
||||
let b5 = document.getElementById("openLinkInPrivateTab");
|
||||
const b5 = document.getElementById("openLinkInPrivateTab");
|
||||
ok(b5, "Link context menu item added.");
|
||||
let b6 = document.getElementById("toggleTabPrivateState");
|
||||
const b6 = document.getElementById("toggleTabPrivateState");
|
||||
ok(b6, "Tab context menu item added.");
|
||||
});
|
||||
|
||||
// Test container exists
|
||||
add_task(async function testContainer() {
|
||||
ContextualIdentityService.ensureDataReady();
|
||||
let container = ContextualIdentityService._identities.find(
|
||||
c => c.name == "Private"
|
||||
const container = ContextualIdentityService._identities.find(
|
||||
(c) => c.name === "Private"
|
||||
);
|
||||
ok(container, "Found Private container.");
|
||||
});
|
||||
@@ -58,8 +56,8 @@ add_task(async function testAutofillNotStored() {
|
||||
"http://mochi.test:8888/browser/browser/components/" +
|
||||
"sessionstore/test/browser_formdata_sample.html";
|
||||
|
||||
const OUTER_VALUE = "browser_formdata_" + Math.random();
|
||||
const INNER_VALUE = "browser_formdata_" + Math.random();
|
||||
const OUTER_VALUE = `browser_formdata_${Math.random()}`;
|
||||
const INNER_VALUE = `browser_formdata_${Math.random()}`;
|
||||
|
||||
// Creates a tab, loads a page with some form fields,
|
||||
// modifies their values and closes the tab.
|
||||
@@ -68,7 +66,7 @@ add_task(async function testAutofillNotStored() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
||||
// Toggle to a private tab
|
||||
tab = await togglePrivate(tab, true);
|
||||
let browser = tab.linkedBrowser;
|
||||
const browser = tab.linkedBrowser;
|
||||
await promiseBrowserLoaded(browser);
|
||||
|
||||
// Modify form data.
|
||||
@@ -85,7 +83,7 @@ add_task(async function testAutofillNotStored() {
|
||||
}
|
||||
|
||||
await createAndRemoveTab();
|
||||
let [
|
||||
const [
|
||||
{
|
||||
state: { formdata },
|
||||
},
|
||||
@@ -99,7 +97,7 @@ add_task(async function testTabHistoryNotStored() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URI1);
|
||||
// Make it private
|
||||
tab = await togglePrivate(tab, true);
|
||||
let browser = tab.linkedBrowser;
|
||||
const browser = tab.linkedBrowser;
|
||||
await promiseBrowserLoaded(browser);
|
||||
// Open a new URL
|
||||
BrowserTestUtils.loadURI(browser, URI2);
|
||||
@@ -107,14 +105,14 @@ add_task(async function testTabHistoryNotStored() {
|
||||
// Remove tab to save state
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
// Verify only non-private data stored
|
||||
let closedTabData = JSON.parse(SessionStore.getClosedTabData(window)).filter(
|
||||
data => {
|
||||
const closedTabData = JSON.parse(SessionStore.getClosedTabData(window)).filter(
|
||||
(data) => {
|
||||
return (
|
||||
data.state.entries[0].url === URI1 || data.state.entries[0].url === URI2
|
||||
);
|
||||
}
|
||||
);
|
||||
let privateData = closedTabData.filter(data => {
|
||||
const privateData = closedTabData.filter((data) => {
|
||||
return data.state.isPrivate === true;
|
||||
});
|
||||
const oneClosedTabWithNoPrivateData =
|
||||
@@ -140,12 +138,12 @@ const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
|
||||
async function getSuggestionResults() {
|
||||
await UrlbarTestUtils.promiseSearchComplete(window);
|
||||
|
||||
let results = [];
|
||||
let matchCount = UrlbarTestUtils.getResultCount(window);
|
||||
const results = [];
|
||||
const matchCount = UrlbarTestUtils.getResultCount(window);
|
||||
for (let i = 0; i < matchCount; i++) {
|
||||
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
|
||||
const result = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
|
||||
if (
|
||||
result.type == UrlbarUtils.RESULT_TYPE.SEARCH &&
|
||||
result.type === UrlbarUtils.RESULT_TYPE.SEARCH &&
|
||||
result.searchParams.suggestion
|
||||
) {
|
||||
result.index = i;
|
||||
@@ -157,15 +155,15 @@ async function getSuggestionResults() {
|
||||
|
||||
// Must run first.
|
||||
add_task(async function prepare() {
|
||||
let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
const suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
let engine = await SearchTestUtils.promiseNewSearchEngine(
|
||||
const engine = await SearchTestUtils.promiseNewSearchEngine(
|
||||
getRootDirectory(gTestPath) + TEST_ENGINE_BASENAME
|
||||
);
|
||||
let oldDefaultEngine = await Services.search.getDefault();
|
||||
const oldDefaultEngine = await Services.search.getDefault();
|
||||
await Services.search.setDefault(engine);
|
||||
await UrlbarTestUtils.formHistory.clear();
|
||||
registerCleanupFunction(async function() {
|
||||
registerCleanupFunction(async () => {
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
|
||||
await Services.search.setDefault(oldDefaultEngine);
|
||||
|
||||
@@ -184,7 +182,7 @@ add_task(async function testSearchSuggestionsNotStored() {
|
||||
window,
|
||||
value: "foo",
|
||||
});
|
||||
let results = await getSuggestionResults();
|
||||
const results = await getSuggestionResults();
|
||||
ok(!results.length, "Suggestion not be stored in private tab");
|
||||
// Cleanup
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
@@ -1,37 +1,33 @@
|
||||
"use strict";
|
||||
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
const { TabStateFlusher } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
|
||||
);
|
||||
|
||||
const { TabStateFlusher } = ChromeUtils.import(
|
||||
"resource:///modules/sessionstore/TabStateFlusher.jsm"
|
||||
const { TabStateCache } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/TabStateCache.sys.mjs"
|
||||
);
|
||||
|
||||
const { TabStateCache } = ChromeUtils.import(
|
||||
"resource:///modules/sessionstore/TabStateCache.jsm"
|
||||
);
|
||||
|
||||
const { SearchTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/SearchTestUtils.jsm"
|
||||
const { SearchTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/SearchTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
SearchTestUtils.init(this);
|
||||
|
||||
const { UrlbarTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/UrlbarTestUtils.jsm"
|
||||
const { UrlbarTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/UrlbarTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
UrlbarTestUtils.init(this);
|
||||
|
||||
const { PrivateTab } = ChromeUtils.import("resource:///modules/PrivateTab.jsm");
|
||||
const { PrivateTab } = ChromeUtils.importESModule(
|
||||
"resource:///modules/PrivateTab.sys.mjs"
|
||||
);
|
||||
|
||||
const URI1 = "https://test1.example.com/";
|
||||
const URI2 = "https://example.com/";
|
||||
const _URI1 = "https://test1.example.com/";
|
||||
const _URI2 = "https://example.com/";
|
||||
|
||||
let OS = AppConstants.platform;
|
||||
const _OS = AppConstants.platform;
|
||||
|
||||
function promiseBrowserLoaded(
|
||||
function _promiseBrowserLoaded(
|
||||
aBrowser,
|
||||
ignoreSubFrames = true,
|
||||
wantLoad = null
|
||||
@@ -41,21 +37,21 @@ function promiseBrowserLoaded(
|
||||
|
||||
// Removes the given tab immediately and returns a promise that resolves when
|
||||
// all pending status updates (messages) of the closing tab have been received.
|
||||
function promiseRemoveTabAndSessionState(tab) {
|
||||
let sessionUpdatePromise = BrowserTestUtils.waitForSessionStoreUpdate(tab);
|
||||
function _promiseRemoveTabAndSessionState(tab) {
|
||||
const sessionUpdatePromise = BrowserTestUtils.waitForSessionStoreUpdate(tab);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
return sessionUpdatePromise;
|
||||
}
|
||||
|
||||
function setPropertyOfFormField(browserContext, selector, propName, newValue) {
|
||||
function _setPropertyOfFormField(browserContext, selector, propName, newValue) {
|
||||
return SpecialPowers.spawn(
|
||||
browserContext,
|
||||
[selector, propName, newValue],
|
||||
(selectorChild, propNameChild, newValueChild) => {
|
||||
let node = content.document.querySelector(selectorChild);
|
||||
const node = content.document.querySelector(selectorChild);
|
||||
node[propNameChild] = newValueChild;
|
||||
|
||||
let event = node.ownerDocument.createEvent("UIEvents");
|
||||
const event = node.ownerDocument.createEvent("UIEvents");
|
||||
event.initUIEvent("input", true, true, node.ownerGlobal, 0);
|
||||
node.dispatchEvent(event);
|
||||
}
|
||||
@@ -65,10 +61,10 @@ function setPropertyOfFormField(browserContext, selector, propName, newValue) {
|
||||
/**
|
||||
* Helper for opening the toolbar context menu.
|
||||
*/
|
||||
async function openTabContextMenu(tab) {
|
||||
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"
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user