зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1561435 - Format browser/components/, a=automatic-formatting
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D36042 --HG-- extra : source : d3afcafdce650a6f36cebbc126ee93b17f13cf52
This commit is contained in:
Родитель
f9f5914039
Коммит
1f830c96da
|
@ -2,11 +2,18 @@
|
|||
* 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/. */
|
||||
|
||||
var EXPORTED_SYMBOLS = ["nsBrowserContentHandler", "nsDefaultCommandLineHandler"];
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"nsBrowserContentHandler",
|
||||
"nsDefaultCommandLineHandler",
|
||||
];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
|
@ -17,20 +24,27 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
SessionStartup: "resource:///modules/sessionstore/SessionStartup.jsm",
|
||||
ShellService: "resource:///modules/ShellService.jsm",
|
||||
UpdatePing: "resource://gre/modules/UpdatePing.jsm",
|
||||
RemotePages: "resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm",
|
||||
RemotePages:
|
||||
"resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm",
|
||||
});
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils",
|
||||
"@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"WindowsUIUtils",
|
||||
"@mozilla.org/windows-ui-utils;1",
|
||||
"nsIWindowsUIUtils"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gSystemPrincipal",
|
||||
() => Services.scriptSecurityManager.getSystemPrincipal());
|
||||
XPCOMUtils.defineLazyGetter(this, "gSystemPrincipal", () =>
|
||||
Services.scriptSecurityManager.getSystemPrincipal()
|
||||
);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, [URL]);
|
||||
|
||||
const NEWINSTALL_PAGE = "about:newinstall";
|
||||
|
||||
function shouldLoadURI(aURI) {
|
||||
if (aURI && !aURI.schemeIs("chrome"))
|
||||
if (aURI && !aURI.schemeIs("chrome")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dump("*** Preventing external load of chrome: URI into browser window\n");
|
||||
dump(" Use --chrome <uri> instead\n");
|
||||
|
@ -42,13 +56,16 @@ function resolveURIInternal(aCmdLine, aArgument) {
|
|||
var uriFixup = Services.uriFixup;
|
||||
|
||||
if (!(uri instanceof Ci.nsIFileURL)) {
|
||||
return uriFixup.createFixupURI(aArgument,
|
||||
uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS);
|
||||
return uriFixup.createFixupURI(
|
||||
aArgument,
|
||||
uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
if (uri.file.exists())
|
||||
if (uri.file.exists()) {
|
||||
return uri;
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
|
@ -77,9 +94,9 @@ function getNewInstallPage() {
|
|||
|
||||
var gFirstWindow = false;
|
||||
|
||||
const OVERRIDE_NONE = 0;
|
||||
const OVERRIDE_NONE = 0;
|
||||
const OVERRIDE_NEW_PROFILE = 1;
|
||||
const OVERRIDE_NEW_MSTONE = 2;
|
||||
const OVERRIDE_NEW_MSTONE = 2;
|
||||
const OVERRIDE_NEW_BUILD_ID = 3;
|
||||
const OVERRIDE_ALTERNATE_PROFILE = 4;
|
||||
/**
|
||||
|
@ -93,19 +110,27 @@ const OVERRIDE_ALTERNATE_PROFILE = 4;
|
|||
* OVERRIDE_NONE otherwise.
|
||||
*/
|
||||
function needHomepageOverride(prefb) {
|
||||
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].
|
||||
getService(Ci.nsIToolkitProfileService);
|
||||
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
|
||||
Ci.nsIToolkitProfileService
|
||||
);
|
||||
if (pService.createdAlternateProfile) {
|
||||
return OVERRIDE_ALTERNATE_PROFILE;
|
||||
}
|
||||
var savedmstone = prefb.getCharPref("browser.startup.homepage_override.mstone", "");
|
||||
var savedmstone = prefb.getCharPref(
|
||||
"browser.startup.homepage_override.mstone",
|
||||
""
|
||||
);
|
||||
|
||||
if (savedmstone == "ignore")
|
||||
if (savedmstone == "ignore") {
|
||||
return OVERRIDE_NONE;
|
||||
}
|
||||
|
||||
var mstone = Services.appinfo.platformVersion;
|
||||
|
||||
var savedBuildID = prefb.getCharPref("browser.startup.homepage_override.buildID", "");
|
||||
var savedBuildID = prefb.getCharPref(
|
||||
"browser.startup.homepage_override.buildID",
|
||||
""
|
||||
);
|
||||
|
||||
var buildID = Services.appinfo.platformBuildID;
|
||||
|
||||
|
@ -114,12 +139,13 @@ function needHomepageOverride(prefb) {
|
|||
// agreement if the platform's installer had already shown one. Now with
|
||||
// about:rights we've removed the EULA stuff and default pref, but we need
|
||||
// a way to make existing profiles retain the default that we removed.
|
||||
if (savedmstone)
|
||||
if (savedmstone) {
|
||||
prefb.setBoolPref("browser.rights.3.shown", true);
|
||||
}
|
||||
|
||||
prefb.setCharPref("browser.startup.homepage_override.mstone", mstone);
|
||||
prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
|
||||
return (savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE);
|
||||
return savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE;
|
||||
}
|
||||
|
||||
if (buildID != savedBuildID) {
|
||||
|
@ -138,19 +164,18 @@ function needHomepageOverride(prefb) {
|
|||
* @return The override page.
|
||||
*/
|
||||
function getPostUpdateOverridePage(defaultOverridePage) {
|
||||
var um = Cc["@mozilla.org/updates/update-manager;1"]
|
||||
.getService(Ci.nsIUpdateManager);
|
||||
var um = Cc["@mozilla.org/updates/update-manager;1"].getService(
|
||||
Ci.nsIUpdateManager
|
||||
);
|
||||
// The active update should be present when this code is called. If for
|
||||
// whatever reason it isn't fallback to the latest update in the update
|
||||
// history.
|
||||
if (um.activeUpdate) {
|
||||
var update = um.activeUpdate
|
||||
.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
var update = um.activeUpdate.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
} else {
|
||||
// If the updates.xml file is deleted then getUpdateAt will throw.
|
||||
try {
|
||||
update = um.getUpdateAt(0)
|
||||
.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
update = um.getUpdateAt(0).QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
} catch (e) {
|
||||
Cu.reportError("Unable to find update: " + e);
|
||||
return defaultOverridePage;
|
||||
|
@ -160,13 +185,15 @@ function getPostUpdateOverridePage(defaultOverridePage) {
|
|||
let actions = update.getProperty("actions");
|
||||
// When the update doesn't specify actions fallback to the original behavior
|
||||
// of displaying the default override page.
|
||||
if (!actions)
|
||||
if (!actions) {
|
||||
return defaultOverridePage;
|
||||
}
|
||||
|
||||
// The existence of silent or the non-existence of showURL in the actions both
|
||||
// mean that an override page should not be displayed.
|
||||
if (actions.includes("silent") || !actions.includes("showURL"))
|
||||
if (actions.includes("silent") || !actions.includes("showURL")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// If a policy was set to not allow the update.xml-provided
|
||||
// URL to be used, use the default fallback (which will also
|
||||
|
@ -202,8 +229,13 @@ function getPostUpdateOverridePage(defaultOverridePage) {
|
|||
* @param forcePrivate (optional)
|
||||
* Boolean. If set to true, the new window will be a private browsing one.
|
||||
*/
|
||||
function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData = null,
|
||||
forcePrivate = false) {
|
||||
function openBrowserWindow(
|
||||
cmdLine,
|
||||
triggeringPrincipal,
|
||||
urlOrUrlList,
|
||||
postData = null,
|
||||
forcePrivate = false
|
||||
) {
|
||||
let chromeURL = AppConstants.BROWSER_CHROME_URL;
|
||||
|
||||
let args;
|
||||
|
@ -211,10 +243,14 @@ function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData
|
|||
// Just pass in the defaultArgs directly. We'll use system principal on the other end.
|
||||
args = [gBrowserContentHandler.defaultArgs];
|
||||
} else {
|
||||
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].
|
||||
getService(Ci.nsIToolkitProfileService);
|
||||
if (cmdLine && cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
|
||||
pService.createdAlternateProfile) {
|
||||
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
|
||||
Ci.nsIToolkitProfileService
|
||||
);
|
||||
if (
|
||||
cmdLine &&
|
||||
cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
|
||||
pService.createdAlternateProfile
|
||||
) {
|
||||
let url = getNewInstallPage();
|
||||
if (Array.isArray(urlOrUrlList)) {
|
||||
urlOrUrlList.unshift(url);
|
||||
|
@ -226,15 +262,22 @@ function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData
|
|||
if (Array.isArray(urlOrUrlList)) {
|
||||
// There isn't an explicit way to pass a principal here, so we load multiple URLs
|
||||
// with system principal when we get to actually loading them.
|
||||
if (!triggeringPrincipal || !triggeringPrincipal.equals(gSystemPrincipal)) {
|
||||
throw new Error("Can't open multiple URLs with something other than system principal.");
|
||||
if (
|
||||
!triggeringPrincipal ||
|
||||
!triggeringPrincipal.equals(gSystemPrincipal)
|
||||
) {
|
||||
throw new Error(
|
||||
"Can't open multiple URLs with something other than system principal."
|
||||
);
|
||||
}
|
||||
// Passing an nsIArray for the url disables the "|"-splitting behavior.
|
||||
let uriArray = Cc["@mozilla.org/array;1"]
|
||||
.createInstance(Ci.nsIMutableArray);
|
||||
let uriArray = Cc["@mozilla.org/array;1"].createInstance(
|
||||
Ci.nsIMutableArray
|
||||
);
|
||||
urlOrUrlList.forEach(function(uri) {
|
||||
var sstring = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
var sstring = Cc["@mozilla.org/supports-string;1"].createInstance(
|
||||
Ci.nsISupportsString
|
||||
);
|
||||
sstring.data = uri;
|
||||
uriArray.appendElement(sstring);
|
||||
});
|
||||
|
@ -243,16 +286,18 @@ function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData
|
|||
// Always pass at least 3 arguments to avoid the "|"-splitting behavior,
|
||||
// ie. avoid the loadOneOrMoreURIs function.
|
||||
// Also, we need to pass the triggering principal.
|
||||
args = [urlOrUrlList,
|
||||
null, // charset
|
||||
null, // refererInfo
|
||||
postData,
|
||||
undefined, // allowThirdPartyFixup; this would be `false` but that
|
||||
// needs a conversion. Hopefully bug 1485961 will fix.
|
||||
undefined, // user context id
|
||||
null, // origin principal
|
||||
null, // origin storage principal
|
||||
triggeringPrincipal];
|
||||
args = [
|
||||
urlOrUrlList,
|
||||
null, // charset
|
||||
null, // refererInfo
|
||||
postData,
|
||||
undefined, // allowThirdPartyFixup; this would be `false` but that
|
||||
// needs a conversion. Hopefully bug 1485961 will fix.
|
||||
undefined, // user context id
|
||||
null, // origin principal
|
||||
null, // origin storage principal
|
||||
triggeringPrincipal,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,9 +309,9 @@ function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData
|
|||
win.document.documentElement.removeAttribute("windowtype");
|
||||
|
||||
if (forcePrivate) {
|
||||
win.docShell
|
||||
.QueryInterface(Ci.nsILoadContext)
|
||||
.usePrivateBrowsing = true;
|
||||
win.docShell.QueryInterface(
|
||||
Ci.nsILoadContext
|
||||
).usePrivateBrowsing = true;
|
||||
}
|
||||
|
||||
win.location = chromeURL;
|
||||
|
@ -281,25 +326,31 @@ function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData
|
|||
// If we have a single string guaranteed to not contain '|' we can simply
|
||||
// wrap it in an nsISupportsString object.
|
||||
let [url] = args;
|
||||
args = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
args = Cc["@mozilla.org/supports-string;1"].createInstance(
|
||||
Ci.nsISupportsString
|
||||
);
|
||||
args.data = url;
|
||||
} else {
|
||||
// Otherwise, pass an nsIArray.
|
||||
if (args.length > 1) {
|
||||
let string = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
let string = Cc["@mozilla.org/supports-string;1"].createInstance(
|
||||
Ci.nsISupportsString
|
||||
);
|
||||
string.data = args[0];
|
||||
args[0] = string;
|
||||
}
|
||||
let array = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
args.forEach(a => { array.appendElement(a); });
|
||||
args.forEach(a => {
|
||||
array.appendElement(a);
|
||||
});
|
||||
args = array;
|
||||
}
|
||||
|
||||
let features = "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine);
|
||||
if (forcePrivate)
|
||||
let features =
|
||||
"chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine);
|
||||
if (forcePrivate) {
|
||||
features += ",private";
|
||||
}
|
||||
|
||||
Services.ww.openWindow(null, chromeURL, "_blank", features, args);
|
||||
}
|
||||
|
@ -310,7 +361,7 @@ function openPreferences(cmdLine, extraArgs) {
|
|||
|
||||
function doSearch(searchTerm, cmdLine) {
|
||||
var engine = Services.search.defaultEngine;
|
||||
var countId = (engine.identifier || ("other-" + engine.name)) + ".system";
|
||||
var countId = (engine.identifier || "other-" + engine.name) + ".system";
|
||||
var count = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
|
||||
count.add(countId);
|
||||
|
||||
|
@ -318,7 +369,12 @@ function doSearch(searchTerm, cmdLine) {
|
|||
|
||||
// XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing
|
||||
// preferences, but need nsIBrowserDOMWindow extensions
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal, submission.uri.spec, submission.postData);
|
||||
openBrowserWindow(
|
||||
cmdLine,
|
||||
gSystemPrincipal,
|
||||
submission.uri.spec,
|
||||
submission.postData
|
||||
);
|
||||
}
|
||||
|
||||
function nsBrowserContentHandler() {
|
||||
|
@ -329,10 +385,12 @@ function nsBrowserContentHandler() {
|
|||
}
|
||||
nsBrowserContentHandler.prototype = {
|
||||
/* nsISupports */
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsICommandLineHandler,
|
||||
Ci.nsIBrowserHandler,
|
||||
Ci.nsIContentHandler,
|
||||
Ci.nsICommandLineValidator]),
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsICommandLineHandler,
|
||||
Ci.nsIBrowserHandler,
|
||||
Ci.nsIContentHandler,
|
||||
Ci.nsICommandLineValidator,
|
||||
]),
|
||||
|
||||
/* nsICommandLineHandler */
|
||||
handle: function bch_handle(cmdLine) {
|
||||
|
@ -356,8 +414,9 @@ nsBrowserContentHandler.prototype = {
|
|||
try {
|
||||
while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) {
|
||||
let uri = resolveURIInternal(cmdLine, uriparam);
|
||||
if (!shouldLoadURI(uri))
|
||||
if (!shouldLoadURI(uri)) {
|
||||
continue;
|
||||
}
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal, uri.spec);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
|
@ -368,9 +427,13 @@ nsBrowserContentHandler.prototype = {
|
|||
try {
|
||||
while ((uriparam = cmdLine.handleFlagWithParam("new-tab", false))) {
|
||||
let uri = resolveURIInternal(cmdLine, uriparam);
|
||||
handURIToExistingBrowser(uri, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
cmdLine, false,
|
||||
gSystemPrincipal);
|
||||
handURIToExistingBrowser(
|
||||
uri,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
cmdLine,
|
||||
false,
|
||||
gSystemPrincipal
|
||||
);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -380,8 +443,10 @@ nsBrowserContentHandler.prototype = {
|
|||
var chromeParam = cmdLine.handleFlagWithParam("chrome", false);
|
||||
if (chromeParam) {
|
||||
// Handle old preference dialog URLs.
|
||||
if (chromeParam == "chrome://browser/content/pref/pref.xul" ||
|
||||
chromeParam == "chrome://browser/content/preferences/preferences.xul") {
|
||||
if (
|
||||
chromeParam == "chrome://browser/content/pref/pref.xul" ||
|
||||
chromeParam == "chrome://browser/content/preferences/preferences.xul"
|
||||
) {
|
||||
openPreferences(cmdLine);
|
||||
cmdLine.preventDefault = true;
|
||||
} else {
|
||||
|
@ -399,14 +464,23 @@ nsBrowserContentHandler.prototype = {
|
|||
let features = "chrome,dialog=no,all" + this.getFeatures(cmdLine);
|
||||
// Provide 1 null argument, as openWindow has a different behavior
|
||||
// when the arg count is 0.
|
||||
let argArray = Cc["@mozilla.org/array;1"]
|
||||
.createInstance(Ci.nsIMutableArray);
|
||||
let argArray = Cc["@mozilla.org/array;1"].createInstance(
|
||||
Ci.nsIMutableArray
|
||||
);
|
||||
argArray.appendElement(null);
|
||||
Services.ww.openWindow(null, resolvedURI.spec, "_blank", features, argArray);
|
||||
Services.ww.openWindow(
|
||||
null,
|
||||
resolvedURI.spec,
|
||||
"_blank",
|
||||
features,
|
||||
argArray
|
||||
);
|
||||
cmdLine.preventDefault = true;
|
||||
} else {
|
||||
dump("*** Preventing load of web URI as chrome\n");
|
||||
dump(" If you're trying to load a webpage, do not pass --chrome.\n");
|
||||
dump(
|
||||
" If you're trying to load a webpage, do not pass --chrome.\n"
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
|
@ -417,11 +491,15 @@ nsBrowserContentHandler.prototype = {
|
|||
openPreferences(cmdLine);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
if (cmdLine.handleFlag("silent", false))
|
||||
if (cmdLine.handleFlag("silent", false)) {
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
|
||||
try {
|
||||
var privateWindowParam = cmdLine.handleFlagWithParam("private-window", false);
|
||||
var privateWindowParam = cmdLine.handleFlagWithParam(
|
||||
"private-window",
|
||||
false
|
||||
);
|
||||
if (privateWindowParam) {
|
||||
let forcePrivate = true;
|
||||
let resolvedURI;
|
||||
|
@ -433,8 +511,13 @@ nsBrowserContentHandler.prototype = {
|
|||
} else {
|
||||
resolvedURI = resolveURIInternal(cmdLine, privateWindowParam);
|
||||
}
|
||||
handURIToExistingBrowser(resolvedURI, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
cmdLine, forcePrivate, gSystemPrincipal);
|
||||
handURIToExistingBrowser(
|
||||
resolvedURI,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
cmdLine,
|
||||
forcePrivate,
|
||||
gSystemPrincipal
|
||||
);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -443,8 +526,13 @@ nsBrowserContentHandler.prototype = {
|
|||
}
|
||||
// NS_ERROR_INVALID_ARG is thrown when flag exists, but has no param.
|
||||
if (cmdLine.handleFlag("private-window", false)) {
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal, "about:privatebrowsing", null,
|
||||
PrivateBrowsingUtils.enabled);
|
||||
openBrowserWindow(
|
||||
cmdLine,
|
||||
gSystemPrincipal,
|
||||
"about:privatebrowsing",
|
||||
null,
|
||||
PrivateBrowsingUtils.enabled
|
||||
);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
}
|
||||
|
@ -462,9 +550,9 @@ nsBrowserContentHandler.prototype = {
|
|||
if (cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH) {
|
||||
let win = Services.wm.getMostRecentWindow("navigator:blank");
|
||||
if (win) {
|
||||
win.docShell
|
||||
.QueryInterface(Ci.nsILoadContext)
|
||||
.usePrivateBrowsing = true;
|
||||
win.docShell.QueryInterface(
|
||||
Ci.nsILoadContext
|
||||
).usePrivateBrowsing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -497,18 +585,21 @@ nsBrowserContentHandler.prototype = {
|
|||
|
||||
get helpInfo() {
|
||||
let info =
|
||||
" --browser Open a browser window.\n" +
|
||||
" --new-window <url> Open <url> in a new window.\n" +
|
||||
" --new-tab <url> Open <url> in a new tab.\n" +
|
||||
" --private-window <url> Open <url> in a new private window.\n";
|
||||
" --browser Open a browser window.\n" +
|
||||
" --new-window <url> Open <url> in a new window.\n" +
|
||||
" --new-tab <url> Open <url> in a new tab.\n" +
|
||||
" --private-window <url> Open <url> in a new private window.\n";
|
||||
if (AppConstants.platform == "win") {
|
||||
info += " --preferences Open Options dialog.\n";
|
||||
} else {
|
||||
info += " --preferences Open Preferences dialog.\n";
|
||||
}
|
||||
info += " --screenshot [<path>] Save screenshot to <path> or in working directory.\n";
|
||||
info += " --window-size width[,height] Width and optionally height of screenshot.\n";
|
||||
info += " --search <term> Search <term> with your default search engine.\n";
|
||||
info +=
|
||||
" --screenshot [<path>] Save screenshot to <path> or in working directory.\n";
|
||||
info +=
|
||||
" --window-size width[,height] Width and optionally height of screenshot.\n";
|
||||
info +=
|
||||
" --search <term> Search <term> with your default search engine.\n";
|
||||
info += " --setDefaultBrowser Set this app as the default browser.\n";
|
||||
return info;
|
||||
},
|
||||
|
@ -535,8 +626,14 @@ nsBrowserContentHandler.prototype = {
|
|||
// URL if we do end up showing an overridePage. This makes it possible
|
||||
// to have the overridePage's content vary depending on the version we're
|
||||
// upgrading from.
|
||||
let old_mstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone", "unknown");
|
||||
let old_buildId = Services.prefs.getCharPref("browser.startup.homepage_override.buildID", "unknown");
|
||||
let old_mstone = Services.prefs.getCharPref(
|
||||
"browser.startup.homepage_override.mstone",
|
||||
"unknown"
|
||||
);
|
||||
let old_buildId = Services.prefs.getCharPref(
|
||||
"browser.startup.homepage_override.buildID",
|
||||
"unknown"
|
||||
);
|
||||
override = needHomepageOverride(prefb);
|
||||
if (override != OVERRIDE_NONE) {
|
||||
switch (override) {
|
||||
|
@ -548,8 +645,12 @@ nsBrowserContentHandler.prototype = {
|
|||
break;
|
||||
case OVERRIDE_NEW_PROFILE:
|
||||
// New profile.
|
||||
overridePage = Services.urlFormatter.formatURLPref("startup.homepage_welcome_url");
|
||||
additionalPage = Services.urlFormatter.formatURLPref("startup.homepage_welcome_url.additional");
|
||||
overridePage = Services.urlFormatter.formatURLPref(
|
||||
"startup.homepage_welcome_url"
|
||||
);
|
||||
additionalPage = Services.urlFormatter.formatURLPref(
|
||||
"startup.homepage_welcome_url.additional"
|
||||
);
|
||||
// Turn on 'later run' pages for new profiles.
|
||||
LaterRun.enabled = true;
|
||||
break;
|
||||
|
@ -561,7 +662,9 @@ nsBrowserContentHandler.prototype = {
|
|||
// we may open the startPage in addition to restoring the session.
|
||||
willRestoreSession = SessionStartup.isAutomaticRestoreEnabled();
|
||||
|
||||
overridePage = Services.urlFormatter.formatURLPref("startup.homepage_override_url");
|
||||
overridePage = Services.urlFormatter.formatURLPref(
|
||||
"startup.homepage_override_url"
|
||||
);
|
||||
if (prefb.prefHasUserValue("app.update.postupdate")) {
|
||||
prefb.clearUserPref("app.update.postupdate");
|
||||
overridePage = getPostUpdateOverridePage(overridePage);
|
||||
|
@ -583,8 +686,9 @@ nsBrowserContentHandler.prototype = {
|
|||
} catch (ex) {}
|
||||
|
||||
// formatURLPref might return "about:blank" if getting the pref fails
|
||||
if (overridePage == "about:blank")
|
||||
if (overridePage == "about:blank") {
|
||||
overridePage = "";
|
||||
}
|
||||
|
||||
if (!additionalPage) {
|
||||
additionalPage = LaterRun.getURL() || "";
|
||||
|
@ -601,21 +705,26 @@ nsBrowserContentHandler.prototype = {
|
|||
var startPage = "";
|
||||
try {
|
||||
var choice = prefb.getIntPref("browser.startup.page");
|
||||
if (choice == 1 || choice == 3)
|
||||
if (choice == 1 || choice == 3) {
|
||||
startPage = HomePage.get();
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
|
||||
if (startPage == "about:blank")
|
||||
if (startPage == "about:blank") {
|
||||
startPage = "";
|
||||
}
|
||||
|
||||
let skipStartPage = ((override == OVERRIDE_NEW_PROFILE) || (override == OVERRIDE_ALTERNATE_PROFILE)) &&
|
||||
let skipStartPage =
|
||||
(override == OVERRIDE_NEW_PROFILE ||
|
||||
override == OVERRIDE_ALTERNATE_PROFILE) &&
|
||||
prefb.getBoolPref("browser.startup.firstrunSkipsHomepage");
|
||||
// Only show the startPage if we're not restoring an update session and are
|
||||
// not set to skip the start page on this profile
|
||||
if (overridePage && startPage && !willRestoreSession && !skipStartPage)
|
||||
if (overridePage && startPage && !willRestoreSession && !skipStartPage) {
|
||||
return overridePage + "|" + startPage;
|
||||
}
|
||||
|
||||
return overridePage || startPage || "about:blank";
|
||||
},
|
||||
|
@ -631,12 +740,13 @@ nsBrowserContentHandler.prototype = {
|
|||
var width = cmdLine.handleFlagWithParam("width", false);
|
||||
var height = cmdLine.handleFlagWithParam("height", false);
|
||||
|
||||
if (width)
|
||||
if (width) {
|
||||
this.mFeatures += ",width=" + width;
|
||||
if (height)
|
||||
}
|
||||
if (height) {
|
||||
this.mFeatures += ",height=" + height;
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// The global PB Service consumes this flag, so only eat it in per-window
|
||||
|
@ -645,8 +755,10 @@ nsBrowserContentHandler.prototype = {
|
|||
this.mFeatures += ",private";
|
||||
}
|
||||
|
||||
if (Services.prefs.getBoolPref("browser.suppress_first_window_animation") &&
|
||||
!Services.wm.getMostRecentWindow("navigator:browser")) {
|
||||
if (
|
||||
Services.prefs.getBoolPref("browser.suppress_first_window_animation") &&
|
||||
!Services.wm.getMostRecentWindow("navigator:browser")
|
||||
) {
|
||||
this.mFeatures += ",suppressanimation";
|
||||
}
|
||||
}
|
||||
|
@ -660,8 +772,9 @@ nsBrowserContentHandler.prototype = {
|
|||
const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
|
||||
|
||||
try {
|
||||
var webNavInfo = Cc["@mozilla.org/webnavigation-info;1"]
|
||||
.getService(Ci.nsIWebNavigationInfo);
|
||||
var webNavInfo = Cc["@mozilla.org/webnavigation-info;1"].getService(
|
||||
Ci.nsIWebNavigationInfo
|
||||
);
|
||||
if (!webNavInfo.isTypeSupported(contentType, null)) {
|
||||
throw NS_ERROR_WONT_HANDLE_CONTENT;
|
||||
}
|
||||
|
@ -670,8 +783,13 @@ nsBrowserContentHandler.prototype = {
|
|||
}
|
||||
|
||||
request.QueryInterface(Ci.nsIChannel);
|
||||
handURIToExistingBrowser(request.URI, Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW,
|
||||
null, false, request.loadInfo.triggeringPrincipal);
|
||||
handURIToExistingBrowser(
|
||||
request.URI,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW,
|
||||
null,
|
||||
false,
|
||||
request.loadInfo.triggeringPrincipal
|
||||
);
|
||||
request.cancel(Cr.NS_BINDING_ABORTED);
|
||||
},
|
||||
|
||||
|
@ -681,15 +799,20 @@ nsBrowserContentHandler.prototype = {
|
|||
// flag is also present and the command line is valid.
|
||||
var osintFlagIdx = cmdLine.findFlag("osint", false);
|
||||
var urlFlagIdx = cmdLine.findFlag("url", false);
|
||||
if (urlFlagIdx > -1 && (osintFlagIdx > -1 ||
|
||||
cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_EXPLICIT)) {
|
||||
if (
|
||||
urlFlagIdx > -1 &&
|
||||
(osintFlagIdx > -1 ||
|
||||
cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_EXPLICIT)
|
||||
) {
|
||||
var urlParam = cmdLine.getArgument(urlFlagIdx + 1);
|
||||
if (cmdLine.length != urlFlagIdx + 2 || /firefoxurl:/i.test(urlParam))
|
||||
if (cmdLine.length != urlFlagIdx + 2 || /firefoxurl:/i.test(urlParam)) {
|
||||
throw Cr.NS_ERROR_ABORT;
|
||||
}
|
||||
var isDefault = false;
|
||||
try {
|
||||
var url = Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
||||
"win10-default-browser";
|
||||
var url =
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
||||
"win10-default-browser";
|
||||
if (urlParam == url) {
|
||||
isDefault = ShellService.isDefaultBrowser(false, false);
|
||||
}
|
||||
|
@ -705,27 +828,45 @@ nsBrowserContentHandler.prototype = {
|
|||
};
|
||||
var gBrowserContentHandler = new nsBrowserContentHandler();
|
||||
|
||||
function handURIToExistingBrowser(uri, location, cmdLine, forcePrivate, triggeringPrincipal) {
|
||||
if (!shouldLoadURI(uri))
|
||||
function handURIToExistingBrowser(
|
||||
uri,
|
||||
location,
|
||||
cmdLine,
|
||||
forcePrivate,
|
||||
triggeringPrincipal
|
||||
) {
|
||||
if (!shouldLoadURI(uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unless using a private window is forced, open external links in private
|
||||
// windows only if we're in perma-private mode.
|
||||
var allowPrivate = forcePrivate || PrivateBrowsingUtils.permanentPrivateBrowsing;
|
||||
var navWin = BrowserWindowTracker.getTopWindow({private: allowPrivate});
|
||||
var allowPrivate =
|
||||
forcePrivate || PrivateBrowsingUtils.permanentPrivateBrowsing;
|
||||
var navWin = BrowserWindowTracker.getTopWindow({ private: allowPrivate });
|
||||
if (!navWin) {
|
||||
// if we couldn't load it in an existing window, open a new one
|
||||
openBrowserWindow(cmdLine, triggeringPrincipal, uri.spec, null, forcePrivate);
|
||||
openBrowserWindow(
|
||||
cmdLine,
|
||||
triggeringPrincipal,
|
||||
uri.spec,
|
||||
null,
|
||||
forcePrivate
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var bwin = navWin.browserDOMWindow;
|
||||
bwin.openURI(uri, null, location,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL, triggeringPrincipal);
|
||||
bwin.openURI(
|
||||
uri,
|
||||
null,
|
||||
location,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL,
|
||||
triggeringPrincipal
|
||||
);
|
||||
}
|
||||
|
||||
function nsDefaultCommandLineHandler() {
|
||||
}
|
||||
function nsDefaultCommandLineHandler() {}
|
||||
|
||||
nsDefaultCommandLineHandler.prototype = {
|
||||
/* nsISupports */
|
||||
|
@ -750,7 +891,7 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
this._haveProfile = true;
|
||||
} catch (e) {
|
||||
while ((ar = cmdLine.handleFlagWithParam("url", false)));
|
||||
while ((ar = cmdLine.handleFlagWithParam("url", false))) {}
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
}
|
||||
|
@ -767,14 +908,19 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
}
|
||||
|
||||
if (cmdLine.findFlag("screenshot", true) != -1) {
|
||||
HeadlessShell.handleCmdLineArgs(cmdLine, urilist.filter(shouldLoadURI).map(u => u.spec));
|
||||
HeadlessShell.handleCmdLineArgs(
|
||||
cmdLine,
|
||||
urilist.filter(shouldLoadURI).map(u => u.spec)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < cmdLine.length; ++i) {
|
||||
var curarg = cmdLine.getArgument(i);
|
||||
if (curarg.match(/^-/)) {
|
||||
Cu.reportError("Warning: unrecognized command line flag " + curarg + "\n");
|
||||
Cu.reportError(
|
||||
"Warning: unrecognized command line flag " + curarg + "\n"
|
||||
);
|
||||
// To emulate the pre-nsICommandLine behavior, we ignore
|
||||
// the argument after an unrecognized flag.
|
||||
++i;
|
||||
|
@ -782,22 +928,34 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
try {
|
||||
urilist.push(resolveURIInternal(cmdLine, curarg));
|
||||
} catch (e) {
|
||||
Cu.reportError("Error opening URI '" + curarg + "' from the command line: " + e + "\n");
|
||||
Cu.reportError(
|
||||
"Error opening URI '" +
|
||||
curarg +
|
||||
"' from the command line: " +
|
||||
e +
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (urilist.length) {
|
||||
if (cmdLine.state != Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
|
||||
urilist.length == 1) {
|
||||
if (
|
||||
cmdLine.state != Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
|
||||
urilist.length == 1
|
||||
) {
|
||||
// Try to find an existing window and load our URI into the
|
||||
// current tab, new tab, or new window as prefs determine.
|
||||
try {
|
||||
handURIToExistingBrowser(urilist[0], Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW,
|
||||
cmdLine, false, gSystemPrincipal);
|
||||
handURIToExistingBrowser(
|
||||
urilist[0],
|
||||
Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW,
|
||||
cmdLine,
|
||||
false,
|
||||
gSystemPrincipal
|
||||
);
|
||||
return;
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
var URLlist = urilist.filter(shouldLoadURI).map(u => u.spec);
|
||||
|
@ -805,9 +963,11 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
openBrowserWindow(cmdLine, gSystemPrincipal, URLlist);
|
||||
}
|
||||
} else if (!cmdLine.preventDefault) {
|
||||
if (AppConstants.isPlatformAndVersionAtLeast("win", "10") &&
|
||||
cmdLine.state != Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
|
||||
WindowsUIUtils.inTabletMode) {
|
||||
if (
|
||||
AppConstants.isPlatformAndVersionAtLeast("win", "10") &&
|
||||
cmdLine.state != Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
|
||||
WindowsUIUtils.inTabletMode
|
||||
) {
|
||||
// In windows 10 tablet mode, do not create a new window, but reuse the existing one.
|
||||
let win = BrowserWindowTracker.getTopWindow();
|
||||
if (win) {
|
||||
|
@ -822,8 +982,9 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
// window, but for now the blank window getting closed quickly (and
|
||||
// causing only a slight flicker) is better than leaving it open.
|
||||
let win = Services.wm.getMostRecentWindow("navigator:blank");
|
||||
if (win)
|
||||
if (win) {
|
||||
win.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6,9 +6,15 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["AboutNetErrorHandler"];
|
||||
|
||||
const {RemotePages} = ChromeUtils.import("resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm");
|
||||
const { RemotePages } = ChromeUtils.import(
|
||||
"resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"BrowserUtils",
|
||||
"resource://gre/modules/BrowserUtils.jsm"
|
||||
);
|
||||
|
||||
var AboutNetErrorHandler = {
|
||||
_inited: false,
|
||||
|
@ -52,7 +58,7 @@ var AboutNetErrorHandler = {
|
|||
// Send a message to the content when a captive portal is freed
|
||||
// so that error pages can refresh themselves.
|
||||
this.pageListener.sendAsyncMessage("AboutNetErrorCaptivePortalFreed");
|
||||
break;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -60,20 +66,26 @@ var AboutNetErrorHandler = {
|
|||
switch (msg.name) {
|
||||
case "Browser:OpenCaptivePortalPage":
|
||||
Services.obs.notifyObservers(null, "ensure-captive-portal-tab");
|
||||
break;
|
||||
break;
|
||||
case "Browser:PrimeMitm":
|
||||
this.primeMitm(msg.target.browser);
|
||||
break;
|
||||
break;
|
||||
case "Browser:ResetEnterpriseRootsPref":
|
||||
Services.prefs.clearUserPref("security.enterprise_roots.enabled");
|
||||
Services.prefs.clearUserPref("security.enterprise_roots.auto-enabled");
|
||||
break;
|
||||
break;
|
||||
case "RecordCertErrorLoad":
|
||||
Services.telemetry.recordEvent("security.ui.certerror", "load", "aboutcerterror", msg.data.errorCode, {
|
||||
has_sts: msg.data.has_sts.toString(),
|
||||
is_frame: msg.data.is_frame.toString(),
|
||||
});
|
||||
break;
|
||||
Services.telemetry.recordEvent(
|
||||
"security.ui.certerror",
|
||||
"load",
|
||||
"aboutcerterror",
|
||||
msg.data.errorCode,
|
||||
{
|
||||
has_sts: msg.data.has_sts.toString(),
|
||||
is_frame: msg.data.is_frame.toString(),
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -88,8 +100,10 @@ var AboutNetErrorHandler = {
|
|||
return;
|
||||
}
|
||||
|
||||
let url = Services.prefs.getStringPref("security.certerrors.mitm.priming.endpoint");
|
||||
let request = new XMLHttpRequest({mozAnon: true});
|
||||
let url = Services.prefs.getStringPref(
|
||||
"security.certerrors.mitm.priming.endpoint"
|
||||
);
|
||||
let request = new XMLHttpRequest({ mozAnon: true });
|
||||
request.open("HEAD", url);
|
||||
request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
|
||||
|
@ -100,7 +114,9 @@ var AboutNetErrorHandler = {
|
|||
return;
|
||||
}
|
||||
|
||||
let secInfo = request.channel.securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
let secInfo = request.channel.securityInfo.QueryInterface(
|
||||
Ci.nsITransportSecurityInfo
|
||||
);
|
||||
if (secInfo.errorCodeString != "SEC_ERROR_UNKNOWN_ISSUER") {
|
||||
return;
|
||||
}
|
||||
|
@ -110,22 +126,39 @@ var AboutNetErrorHandler = {
|
|||
if (secInfo.serverCert && secInfo.serverCert.issuerName) {
|
||||
// Grab the issuer of the certificate used in the exchange and store it so that our
|
||||
// network-level MitM detection code has a comparison baseline.
|
||||
Services.prefs.setStringPref("security.pki.mitm_canary_issuer", secInfo.serverCert.issuerName);
|
||||
Services.prefs.setStringPref(
|
||||
"security.pki.mitm_canary_issuer",
|
||||
secInfo.serverCert.issuerName
|
||||
);
|
||||
|
||||
// MitM issues are sometimes caused by software not registering their root certs in the
|
||||
// Firefox root store. We might opt for using third party roots from the system root store.
|
||||
if (Services.prefs.getBoolPref("security.certerrors.mitm.auto_enable_enterprise_roots")) {
|
||||
if (!Services.prefs.getBoolPref("security.enterprise_roots.enabled")) {
|
||||
if (
|
||||
Services.prefs.getBoolPref(
|
||||
"security.certerrors.mitm.auto_enable_enterprise_roots"
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!Services.prefs.getBoolPref("security.enterprise_roots.enabled")
|
||||
) {
|
||||
// Loading enterprise roots happens on a background thread, so wait for import to finish.
|
||||
BrowserUtils.promiseObserved("psm:enterprise-certs-imported").then(() => {
|
||||
if (browser.documentURI.spec.startsWith("about:certerror")) {
|
||||
browser.reload();
|
||||
BrowserUtils.promiseObserved("psm:enterprise-certs-imported").then(
|
||||
() => {
|
||||
if (browser.documentURI.spec.startsWith("about:certerror")) {
|
||||
browser.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
Services.prefs.setBoolPref("security.enterprise_roots.enabled", true);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.enterprise_roots.enabled",
|
||||
true
|
||||
);
|
||||
// Record that this pref was automatically set.
|
||||
Services.prefs.setBoolPref("security.enterprise_roots.auto-enabled", true);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.enterprise_roots.auto-enabled",
|
||||
true
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Need to reload the page to make sure network code picks up the canary issuer pref.
|
||||
|
|
|
@ -6,20 +6,22 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["AboutPrivateBrowsingHandler"];
|
||||
|
||||
const {RemotePages} = ChromeUtils.import("resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { RemotePages } = ChromeUtils.import(
|
||||
"resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var AboutPrivateBrowsingHandler = {
|
||||
_inited: false,
|
||||
_topics: [
|
||||
"OpenPrivateWindow",
|
||||
"SearchHandoff",
|
||||
],
|
||||
_topics: ["OpenPrivateWindow", "SearchHandoff"],
|
||||
|
||||
init() {
|
||||
this.pageListener = new RemotePages("about:privatebrowsing");
|
||||
for (let topic of this._topics) {
|
||||
this.pageListener.addMessageListener(topic, this.receiveMessage.bind(this));
|
||||
this.pageListener.addMessageListener(
|
||||
topic,
|
||||
this.receiveMessage.bind(this)
|
||||
);
|
||||
}
|
||||
this._inited = true;
|
||||
},
|
||||
|
@ -38,12 +40,13 @@ var AboutPrivateBrowsingHandler = {
|
|||
switch (aMessage.name) {
|
||||
case "OpenPrivateWindow": {
|
||||
let win = aMessage.target.browser.ownerGlobal;
|
||||
win.OpenBrowserWindow({private: true});
|
||||
win.OpenBrowserWindow({ private: true });
|
||||
break;
|
||||
}
|
||||
case "SearchHandoff": {
|
||||
let searchAlias = "";
|
||||
let searchAliases = Services.search.defaultEngine.wrappedJSObject.__internalAliases;
|
||||
let searchAliases =
|
||||
Services.search.defaultEngine.wrappedJSObject.__internalAliases;
|
||||
if (searchAliases && searchAliases.length > 0) {
|
||||
searchAlias = `${searchAliases[0]} `;
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["AboutProtectionsHandler"];
|
||||
|
||||
const {RemotePages} = ChromeUtils.import("resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm");
|
||||
const { RemotePages } = ChromeUtils.import(
|
||||
"resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm"
|
||||
);
|
||||
|
||||
var AboutProtectionsHandler = {
|
||||
_inited: false,
|
||||
_topics: [
|
||||
"openContentBlockingPreferences",
|
||||
],
|
||||
_topics: ["openContentBlockingPreferences"],
|
||||
|
||||
init() {
|
||||
this.pageListener = new RemotePages("about:protections");
|
||||
|
@ -36,7 +36,9 @@ var AboutProtectionsHandler = {
|
|||
let win = aMessage.target.browser.ownerGlobal;
|
||||
switch (aMessage.name) {
|
||||
case "openContentBlockingPreferences":
|
||||
win.openPreferences("privacy-trackingprotection", {origin: "about-protections"});
|
||||
win.openPreferences("privacy-trackingprotection", {
|
||||
origin: "about-protections",
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const contract = "@mozilla.org/network/protocol/about;1?what=newtab";
|
||||
const am = Cc[contract].getService(Ci.nsIAboutModule);
|
||||
|
|
|
@ -2,9 +2,13 @@
|
|||
* 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 {DeferredTask} = ChromeUtils.import("resource://gre/modules/DeferredTask.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
const { DeferredTask } = ChromeUtils.import(
|
||||
"resource://gre/modules/DeferredTask.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Preferences } = ChromeUtils.import(
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
);
|
||||
|
||||
const SEARCH_TIMEOUT_MS = 100;
|
||||
const SEARCH_AUTO_MIN_CRARACTERS = 3;
|
||||
|
@ -22,7 +26,11 @@ const STRINGS_ADD_BY_TYPE = {
|
|||
};
|
||||
|
||||
let gDefaultBranch = Services.prefs.getDefaultBranch("");
|
||||
let gFilterPrefsTask = new DeferredTask(() => filterPrefs(), SEARCH_TIMEOUT_MS, 0);
|
||||
let gFilterPrefsTask = new DeferredTask(
|
||||
() => filterPrefs(),
|
||||
SEARCH_TIMEOUT_MS,
|
||||
0
|
||||
);
|
||||
|
||||
/**
|
||||
* Maps the name of each preference in the back-end to its PrefRow object,
|
||||
|
@ -108,8 +116,10 @@ class PrefRow {
|
|||
// We don't know which preferences should be read using getComplexValue,
|
||||
// so we use a heuristic to determine if this is a localized preference.
|
||||
// This can throw if there is no value in the localized files.
|
||||
this.value = Services.prefs.getComplexValue(this.name,
|
||||
Ci.nsIPrefLocalizedString).data;
|
||||
this.value = Services.prefs.getComplexValue(
|
||||
this.name,
|
||||
Ci.nsIPrefLocalizedString
|
||||
).data;
|
||||
}
|
||||
} catch (ex) {
|
||||
this.value = "";
|
||||
|
@ -125,9 +135,11 @@ class PrefRow {
|
|||
}
|
||||
|
||||
get matchesFilter() {
|
||||
return gFilterShowAll ||
|
||||
(gFilterPattern && gFilterPattern.test(this.name)) ||
|
||||
(gFilterString && this.name.toLowerCase().includes(gFilterString));
|
||||
return (
|
||||
gFilterShowAll ||
|
||||
(gFilterPattern && gFilterPattern.test(this.name)) ||
|
||||
(gFilterString && this.name.toLowerCase().includes(gFilterString))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,12 +157,12 @@ class PrefRow {
|
|||
let nameCell = document.createElement("th");
|
||||
this._element.append(
|
||||
nameCell,
|
||||
this.valueCell = document.createElement("td"),
|
||||
this.editCell = document.createElement("td"),
|
||||
this.resetCell = document.createElement("td")
|
||||
(this.valueCell = document.createElement("td")),
|
||||
(this.editCell = document.createElement("td")),
|
||||
(this.resetCell = document.createElement("td"))
|
||||
);
|
||||
this.editCell.appendChild(
|
||||
this.editButton = document.createElement("button")
|
||||
(this.editButton = document.createElement("button"))
|
||||
);
|
||||
delete this.resetButton;
|
||||
|
||||
|
@ -187,15 +199,19 @@ class PrefRow {
|
|||
span.setAttribute("aria-hidden", "true");
|
||||
let outerSpan = document.createElement("span");
|
||||
let spanL10nId = this.hasUserValue
|
||||
? "about-config-pref-accessible-value-custom"
|
||||
: "about-config-pref-accessible-value-default";
|
||||
document.l10n.setAttributes(outerSpan, spanL10nId,
|
||||
{ value: "" + this.value });
|
||||
? "about-config-pref-accessible-value-custom"
|
||||
: "about-config-pref-accessible-value-default";
|
||||
document.l10n.setAttributes(outerSpan, spanL10nId, {
|
||||
value: "" + this.value,
|
||||
});
|
||||
outerSpan.appendChild(span);
|
||||
this.valueCell.textContent = "";
|
||||
this.valueCell.append(outerSpan);
|
||||
if (this.type == "Boolean") {
|
||||
document.l10n.setAttributes(this.editButton, "about-config-pref-toggle");
|
||||
document.l10n.setAttributes(
|
||||
this.editButton,
|
||||
"about-config-pref-toggle"
|
||||
);
|
||||
this.editButton.className = "button-toggle";
|
||||
} else {
|
||||
document.l10n.setAttributes(this.editButton, "about-config-pref-edit");
|
||||
|
@ -265,12 +281,16 @@ class PrefRow {
|
|||
this.resetCell.appendChild(this.resetButton);
|
||||
}
|
||||
if (!this.hasDefaultValue) {
|
||||
document.l10n.setAttributes(this.resetButton,
|
||||
"about-config-pref-delete");
|
||||
document.l10n.setAttributes(
|
||||
this.resetButton,
|
||||
"about-config-pref-delete"
|
||||
);
|
||||
this.resetButton.className = "";
|
||||
} else {
|
||||
document.l10n.setAttributes(this.resetButton,
|
||||
"about-config-pref-reset");
|
||||
document.l10n.setAttributes(
|
||||
this.resetButton,
|
||||
"about-config-pref-reset"
|
||||
);
|
||||
this.resetButton.className = "button-reset";
|
||||
}
|
||||
} else if (this.resetButton) {
|
||||
|
@ -291,10 +311,11 @@ class PrefRow {
|
|||
if (this.hidden) {
|
||||
className = "hidden";
|
||||
} else {
|
||||
className = (this.hasUserValue ? "has-user-value " : "") +
|
||||
(this.isLocked ? "locked " : "") +
|
||||
(this.exists ? "" : "deleted ") +
|
||||
(this.odd ? "odd " : "");
|
||||
className =
|
||||
(this.hasUserValue ? "has-user-value " : "") +
|
||||
(this.isLocked ? "locked " : "") +
|
||||
(this.exists ? "" : "deleted ") +
|
||||
(this.odd ? "odd " : "");
|
||||
}
|
||||
|
||||
if (this._lastClassName !== className) {
|
||||
|
@ -357,16 +378,22 @@ if (!Preferences.get("browser.aboutConfig.showWarning")) {
|
|||
// immediately to prevent flickering, but wait to filter the preferences until
|
||||
// the value of the textbox has been restored from previous sessions.
|
||||
document.addEventListener("DOMContentLoaded", loadPrefs, { once: true });
|
||||
window.addEventListener("load", () => {
|
||||
if (document.getElementById("about-config-search").value) {
|
||||
filterPrefs();
|
||||
}
|
||||
}, { once: true });
|
||||
window.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
if (document.getElementById("about-config-search").value) {
|
||||
filterPrefs();
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
function onWarningButtonClick() {
|
||||
Services.prefs.setBoolPref("browser.aboutConfig.showWarning",
|
||||
document.getElementById("showWarningNextTime").checked);
|
||||
Services.prefs.setBoolPref(
|
||||
"browser.aboutConfig.showWarning",
|
||||
document.getElementById("showWarningNextTime").checked
|
||||
);
|
||||
loadPrefs();
|
||||
}
|
||||
|
||||
|
@ -378,8 +405,8 @@ function loadPrefs() {
|
|||
document.body.textContent = "";
|
||||
document.body.appendChild(content);
|
||||
|
||||
let search = gSearchInput = document.getElementById("about-config-search");
|
||||
let prefs = gPrefsTable = document.getElementById("prefs");
|
||||
let search = (gSearchInput = document.getElementById("about-config-search"));
|
||||
let prefs = (gPrefsTable = document.getElementById("prefs"));
|
||||
let showAll = document.getElementById("show-all");
|
||||
search.focus();
|
||||
|
||||
|
@ -539,7 +566,7 @@ function filterPrefs(options = {}) {
|
|||
}
|
||||
|
||||
if (searchName && !gExistingPrefs.has(searchName)) {
|
||||
gPrefsTable.appendChild((new PrefRow(searchName)).getElement());
|
||||
gPrefsTable.appendChild(new PrefRow(searchName).getElement());
|
||||
}
|
||||
|
||||
// We only start observing preference changes after the first search is done,
|
||||
|
@ -547,11 +574,17 @@ function filterPrefs(options = {}) {
|
|||
if (!gPrefObserverRegistered) {
|
||||
gPrefObserverRegistered = true;
|
||||
Services.prefs.addObserver("", gPrefObserver);
|
||||
window.addEventListener("unload", () => {
|
||||
Services.prefs.removeObserver("", gPrefObserver);
|
||||
}, { once: true });
|
||||
window.addEventListener(
|
||||
"unload",
|
||||
() => {
|
||||
Services.prefs.removeObserver("", gPrefObserver);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
document.body.classList.toggle("config-warning",
|
||||
location.href.split(":").every(l => gFilterString.includes(l)));
|
||||
document.body.classList.toggle(
|
||||
"config-warning",
|
||||
location.href.split(":").every(l => gFilterString.includes(l))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
* be resolved in bug 1539000.
|
||||
*/
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Too many characters in placeable/);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(
|
||||
/Too many characters in placeable/
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["test.aboutconfig.added", true],
|
||||
],
|
||||
set: [["test.aboutconfig.added", true]],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -25,8 +25,8 @@ add_task(async function test_accessible_value() {
|
|||
]) {
|
||||
let span = this.getRow(name).valueCell.querySelector("span");
|
||||
let expectedL10nId = expectHasUserValue
|
||||
? "about-config-pref-accessible-value-custom"
|
||||
: "about-config-pref-accessible-value-default";
|
||||
? "about-config-pref-accessible-value-custom"
|
||||
: "about-config-pref-accessible-value-default";
|
||||
Assert.equal(span.getAttribute("data-l10n-id"), expectedL10nId);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,13 +6,17 @@
|
|||
* be resolved in bug 1539000.
|
||||
*/
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Too many characters in placeable/);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(
|
||||
/Too many characters in placeable/
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["test.aboutconfig.userValueLikeLocalized",
|
||||
"chrome://test/locale/testing.properties"],
|
||||
[
|
||||
"test.aboutconfig.userValueLikeLocalized",
|
||||
"chrome://test/locale/testing.properties",
|
||||
],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
@ -30,10 +34,12 @@ add_task(async function test_load_settings() {
|
|||
Assert.equal(this.getRow(PREF_STRING_DEFAULT_EMPTY).value, "");
|
||||
|
||||
// Test if the modified state is displayed for the right prefs.
|
||||
Assert.ok(!this.getRow(PREF_BOOLEAN_DEFAULT_TRUE)
|
||||
.hasClass("has-user-value"));
|
||||
Assert.ok(this.getRow(PREF_BOOLEAN_USERVALUE_TRUE)
|
||||
.hasClass("has-user-value"));
|
||||
Assert.ok(
|
||||
!this.getRow(PREF_BOOLEAN_DEFAULT_TRUE).hasClass("has-user-value")
|
||||
);
|
||||
Assert.ok(
|
||||
this.getRow(PREF_BOOLEAN_USERVALUE_TRUE).hasClass("has-user-value")
|
||||
);
|
||||
|
||||
// Test to see if values are localized, sampling from different files. If
|
||||
// any of these are removed or their value changes, just update the value
|
||||
|
@ -42,12 +48,15 @@ add_task(async function test_load_settings() {
|
|||
Assert.equal(this.getRow("intl.ellipsis").value, "\u2026");
|
||||
Assert.equal(
|
||||
this.getRow("gecko.handlerService.schemes.mailto.1.uriTemplate").value,
|
||||
"https://mail.google.com/mail/?extsrc=mailto&url=%s");
|
||||
"https://mail.google.com/mail/?extsrc=mailto&url=%s"
|
||||
);
|
||||
|
||||
// Test to see if user created value is not empty string when it matches
|
||||
// /^chrome:\/\/.+\/locale\/.+\.properties/.
|
||||
Assert.equal(this.getRow("test.aboutconfig.userValueLikeLocalized").value,
|
||||
"chrome://test/locale/testing.properties");
|
||||
Assert.equal(
|
||||
this.getRow("test.aboutconfig.userValueLikeLocalized").value,
|
||||
"chrome://test/locale/testing.properties"
|
||||
);
|
||||
|
||||
// Test to see if empty string when value matches
|
||||
// /^chrome:\/\/.+\/locale\/.+\.properties/ and an exception is thrown.
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
* be resolved in bug 1539000.
|
||||
*/
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Too many characters in placeable/);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(
|
||||
/Too many characters in placeable/
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
|
@ -39,19 +41,26 @@ add_task(async function test_copy() {
|
|||
let row = this.getRow(name);
|
||||
|
||||
// Triple click at any location in the name cell should select the name.
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(row.nameCell,
|
||||
{ clickCount: 3 },
|
||||
this.browser);
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
row.nameCell,
|
||||
{ clickCount: 3 },
|
||||
this.browser
|
||||
);
|
||||
Assert.ok(row.nameCell.contains(this.window.getSelection().anchorNode));
|
||||
await SimpleTest.promiseClipboardChange(name, async () => {
|
||||
await BrowserTestUtils.synthesizeKey("c", { accelKey: true },
|
||||
this.browser);
|
||||
await BrowserTestUtils.synthesizeKey(
|
||||
"c",
|
||||
{ accelKey: true },
|
||||
this.browser
|
||||
);
|
||||
});
|
||||
|
||||
// Triple click at any location in the value cell should select the value.
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(row.valueCell,
|
||||
{ clickCount: 3 },
|
||||
this.browser);
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
row.valueCell,
|
||||
{ clickCount: 3 },
|
||||
this.browser
|
||||
);
|
||||
let selection = this.window.getSelection();
|
||||
Assert.ok(row.valueCell.contains(selection.anchorNode));
|
||||
|
||||
|
@ -59,8 +68,11 @@ add_task(async function test_copy() {
|
|||
// this makes sure that an empty string can be copied.
|
||||
Assert.ok(!selection.isCollapsed);
|
||||
await SimpleTest.promiseClipboardChange(expectedString, async () => {
|
||||
await BrowserTestUtils.synthesizeKey("c", { accelKey: true },
|
||||
this.browser);
|
||||
await BrowserTestUtils.synthesizeKey(
|
||||
"c",
|
||||
{ accelKey: true },
|
||||
this.browser
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -69,12 +81,13 @@ add_task(async function test_copy() {
|
|||
add_task(async function test_copy_multiple() {
|
||||
await AboutConfigTest.withNewTab(async function() {
|
||||
// Lines are separated by a single LF character on all platforms.
|
||||
let expectedString = "test.aboutconfig.copy.false\tfalse\t\n" +
|
||||
"test.aboutconfig.copy.number\t10\t\n" +
|
||||
"test.aboutconfig.copy.spaces.1\t \t\n" +
|
||||
"test.aboutconfig.copy.spaces.2\t \t\n" +
|
||||
"test.aboutconfig.copy.spaces.3\t \t\n" +
|
||||
"test.aboutconfig.copy.string\t010.5";
|
||||
let expectedString =
|
||||
"test.aboutconfig.copy.false\tfalse\t\n" +
|
||||
"test.aboutconfig.copy.number\t10\t\n" +
|
||||
"test.aboutconfig.copy.spaces.1\t \t\n" +
|
||||
"test.aboutconfig.copy.spaces.2\t \t\n" +
|
||||
"test.aboutconfig.copy.spaces.3\t \t\n" +
|
||||
"test.aboutconfig.copy.string\t010.5";
|
||||
|
||||
this.search("test.aboutconfig.copy.");
|
||||
let startRow = this.getRow("test.aboutconfig.copy.false");
|
||||
|
@ -82,18 +95,34 @@ add_task(async function test_copy_multiple() {
|
|||
let { width, height } = endRow.valueCell.getBoundingClientRect();
|
||||
|
||||
// Drag from the top left of the first row to the bottom right of the last.
|
||||
await BrowserTestUtils.synthesizeMouse(startRow.nameCell, 1, 1,
|
||||
{ type: "mousedown" }, this.browser);
|
||||
await BrowserTestUtils.synthesizeMouse(endRow.valueCell,
|
||||
width - 1, height - 1,
|
||||
{ type: "mousemove" }, this.browser);
|
||||
await BrowserTestUtils.synthesizeMouse(endRow.valueCell,
|
||||
width - 1, height - 1,
|
||||
{ type: "mouseup" }, this.browser);
|
||||
await BrowserTestUtils.synthesizeMouse(
|
||||
startRow.nameCell,
|
||||
1,
|
||||
1,
|
||||
{ type: "mousedown" },
|
||||
this.browser
|
||||
);
|
||||
await BrowserTestUtils.synthesizeMouse(
|
||||
endRow.valueCell,
|
||||
width - 1,
|
||||
height - 1,
|
||||
{ type: "mousemove" },
|
||||
this.browser
|
||||
);
|
||||
await BrowserTestUtils.synthesizeMouse(
|
||||
endRow.valueCell,
|
||||
width - 1,
|
||||
height - 1,
|
||||
{ type: "mouseup" },
|
||||
this.browser
|
||||
);
|
||||
|
||||
await SimpleTest.promiseClipboardChange(expectedString, async () => {
|
||||
await BrowserTestUtils.synthesizeKey("c", { accelKey: true },
|
||||
this.browser);
|
||||
await BrowserTestUtils.synthesizeKey(
|
||||
"c",
|
||||
{ accelKey: true },
|
||||
this.browser
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,14 +6,19 @@
|
|||
* be resolved in bug 1539000.
|
||||
*/
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Too many characters in placeable/);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(
|
||||
/Too many characters in placeable/
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["test.aboutconfig.modify.boolean", true],
|
||||
["test.aboutconfig.modify.number", 1337],
|
||||
["test.aboutconfig.modify.string", "the answer to the life the universe and everything"],
|
||||
[
|
||||
"test.aboutconfig.modify.string",
|
||||
"the answer to the life the universe and everything",
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -25,8 +30,10 @@ add_task(async function setup() {
|
|||
});
|
||||
|
||||
add_task(async function test_add_user_pref() {
|
||||
Assert.equal(Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID);
|
||||
Assert.equal(
|
||||
Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID
|
||||
);
|
||||
|
||||
await AboutConfigTest.withNewTab(async function() {
|
||||
// The row for a new preference appears when searching for its name.
|
||||
|
@ -57,26 +64,26 @@ add_task(async function test_add_user_pref() {
|
|||
|
||||
// Reset the preference, then continue by adding a different type.
|
||||
row.resetColumnButton.click();
|
||||
Assert.equal(Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID);
|
||||
Assert.equal(
|
||||
Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_delete_user_pref() {
|
||||
for (let [radioIndex, testValue] of [
|
||||
[0, false],
|
||||
[1, -1],
|
||||
[2, "value"],
|
||||
]) {
|
||||
for (let [radioIndex, testValue] of [[0, false], [1, -1], [2, "value"]]) {
|
||||
Preferences.set(PREF_NEW, testValue);
|
||||
await AboutConfigTest.withNewTab(async function() {
|
||||
// Deleting the preference should keep the row.
|
||||
let row = this.getRow(PREF_NEW);
|
||||
row.resetColumnButton.click();
|
||||
Assert.ok(row.hasClass("deleted"));
|
||||
Assert.equal(Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID);
|
||||
Assert.equal(
|
||||
Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID
|
||||
);
|
||||
|
||||
// Re-adding the preference should keep the same value.
|
||||
Assert.ok(row.element.querySelectorAll("input")[radioIndex].checked);
|
||||
|
@ -94,7 +101,7 @@ add_task(async function test_delete_user_pref() {
|
|||
|
||||
add_task(async function test_reset_user_pref() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
set: [
|
||||
[PREF_BOOLEAN_DEFAULT_TRUE, false],
|
||||
[PREF_STRING_LOCALIZED_MISSING, "user-value"],
|
||||
],
|
||||
|
@ -141,8 +148,10 @@ add_task(async function test_modify() {
|
|||
for (let i = 0; i < 2; i++) {
|
||||
row.editColumnButton.click();
|
||||
// Check new layout and saving in backend.
|
||||
Assert.equal(this.getRow(nameOfBoolPref).value,
|
||||
"" + Preferences.get(nameOfBoolPref));
|
||||
Assert.equal(
|
||||
this.getRow(nameOfBoolPref).value,
|
||||
"" + Preferences.get(nameOfBoolPref)
|
||||
);
|
||||
let prefHasUserValue = Services.prefs.prefHasUserValue(nameOfBoolPref);
|
||||
Assert.equal(row.hasClass("has-user-value"), prefHasUserValue);
|
||||
Assert.equal(!!row.resetColumnButton, prefHasUserValue);
|
||||
|
@ -155,14 +164,22 @@ add_task(async function test_modify() {
|
|||
row.valueInput.value = "test";
|
||||
let intRow = this.getRow("test.aboutconfig.modify.number");
|
||||
intRow.editColumnButton.click();
|
||||
Assert.equal(intRow.valueInput.value,
|
||||
Preferences.get("test.aboutconfig.modify.number"));
|
||||
Assert.equal(
|
||||
intRow.valueInput.value,
|
||||
Preferences.get("test.aboutconfig.modify.number")
|
||||
);
|
||||
Assert.ok(!row.valueInput);
|
||||
Assert.equal(row.value, Preferences.get("test.aboutconfig.modify.string"));
|
||||
|
||||
// Test validation of integer values.
|
||||
for (let invalidValue of
|
||||
["", " ", "a", "1.5", "-2147483649", "2147483648"]) {
|
||||
for (let invalidValue of [
|
||||
"",
|
||||
" ",
|
||||
"a",
|
||||
"1.5",
|
||||
"-2147483649",
|
||||
"2147483648",
|
||||
]) {
|
||||
intRow.valueInput.value = invalidValue;
|
||||
intRow.editColumnButton.click();
|
||||
// We should still be in edit mode.
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
* be resolved in bug 1539000.
|
||||
*/
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Too many characters in placeable/);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(
|
||||
/Too many characters in placeable/
|
||||
);
|
||||
|
||||
const PREF_STRING_NO_DEFAULT = "test.aboutconfig.a";
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_STRING_NO_DEFAULT, "some value"],
|
||||
],
|
||||
set: [[PREF_STRING_NO_DEFAULT, "some value"]],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -55,7 +55,9 @@ add_task(async function test_locked() {
|
|||
let unlockedPref = this.getRow(PREF_BOOLEAN_USERVALUE_TRUE);
|
||||
Assert.ok(!unlockedPref.hasClass("locked"));
|
||||
Assert.equal(unlockedPref.value, "true");
|
||||
Assert.ok(unlockedPref.editColumnButton.classList.contains("button-toggle"));
|
||||
Assert.ok(
|
||||
unlockedPref.editColumnButton.classList.contains("button-toggle")
|
||||
);
|
||||
Assert.ok(!unlockedPref.editColumnButton.disabled);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,14 +6,19 @@
|
|||
* be resolved in bug 1539000.
|
||||
*/
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Too many characters in placeable/);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(
|
||||
/Too many characters in placeable/
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["test.aboutconfig.modify.boolean", true],
|
||||
["test.aboutconfig.modify.number", 1337],
|
||||
["test.aboutconfig.modify.string", "the answer to the life the universe and everything"],
|
||||
[
|
||||
"test.aboutconfig.modify.string",
|
||||
"the answer to the life the universe and everything",
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -25,23 +30,30 @@ add_task(async function setup() {
|
|||
});
|
||||
|
||||
add_task(async function test_observe_add_user_pref_before_search() {
|
||||
Assert.equal(Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID);
|
||||
Assert.equal(
|
||||
Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID
|
||||
);
|
||||
|
||||
await AboutConfigTest.withNewTab(async function() {
|
||||
this.bypassWarningButton.click();
|
||||
await AboutConfigTest.withNewTab(
|
||||
async function() {
|
||||
this.bypassWarningButton.click();
|
||||
|
||||
// No results are shown after the warning page is dismissed or bypassed,
|
||||
// and newly added preferences should not be displayed.
|
||||
Preferences.set(PREF_NEW, true);
|
||||
Assert.ok(!this.prefsTable.firstElementChild);
|
||||
Preferences.reset(PREF_NEW);
|
||||
}, { dontBypassWarning: true });
|
||||
// No results are shown after the warning page is dismissed or bypassed,
|
||||
// and newly added preferences should not be displayed.
|
||||
Preferences.set(PREF_NEW, true);
|
||||
Assert.ok(!this.prefsTable.firstElementChild);
|
||||
Preferences.reset(PREF_NEW);
|
||||
},
|
||||
{ dontBypassWarning: true }
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_observe_add_user_pref() {
|
||||
Assert.equal(Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID);
|
||||
Assert.equal(
|
||||
Services.prefs.getPrefType(PREF_NEW),
|
||||
Ci.nsIPrefBranch.PREF_INVALID
|
||||
);
|
||||
|
||||
await AboutConfigTest.withNewTab(async function() {
|
||||
for (let value of [false, true, "", "value", 0, -10]) {
|
||||
|
@ -114,9 +126,7 @@ add_task(async function test_observe_delete_user_pref() {
|
|||
|
||||
add_task(async function test_observe_reset_user_pref() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
[PREF_BOOLEAN_DEFAULT_TRUE, false],
|
||||
],
|
||||
set: [[PREF_BOOLEAN_DEFAULT_TRUE, false]],
|
||||
});
|
||||
|
||||
await AboutConfigTest.withNewTab(async function() {
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
* be resolved in bug 1539000.
|
||||
*/
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Too many characters in placeable/);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(
|
||||
/Too many characters in placeable/
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
|
@ -34,8 +36,9 @@ add_task(async function test_search() {
|
|||
// modified by other code during the execution of this test.
|
||||
this.search("Wser.down ");
|
||||
|
||||
let filteredPrefArray =
|
||||
prefArray.filter(pref => pref.includes("wser.down"));
|
||||
let filteredPrefArray = prefArray.filter(pref =>
|
||||
pref.includes("wser.down")
|
||||
);
|
||||
// Adding +1 to the list since button does not match an exact
|
||||
// preference name then a row is added for the user to add a
|
||||
// new button preference if desired
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
* be resolved in bug 1539000.
|
||||
*/
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Too many characters in placeable/);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(
|
||||
/Too many characters in placeable/
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.aboutConfig.showWarning", true],
|
||||
],
|
||||
set: [["browser.aboutConfig.showWarning", true]],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -22,24 +22,29 @@ add_task(async function test_showWarningNextTime() {
|
|||
{ expectWarningPage: true, disableShowWarningNextTime: true },
|
||||
{ expectWarningPage: false },
|
||||
]) {
|
||||
await AboutConfigTest.withNewTab(async function() {
|
||||
if (test.expectWarningPage) {
|
||||
this.assertWarningPage(true);
|
||||
Assert.ok(this.document.getElementById("showWarningNextTime").checked);
|
||||
if (test.disableShowWarningNextTime) {
|
||||
this.document.getElementById("showWarningNextTime").click();
|
||||
await AboutConfigTest.withNewTab(
|
||||
async function() {
|
||||
if (test.expectWarningPage) {
|
||||
this.assertWarningPage(true);
|
||||
Assert.ok(
|
||||
this.document.getElementById("showWarningNextTime").checked
|
||||
);
|
||||
if (test.disableShowWarningNextTime) {
|
||||
this.document.getElementById("showWarningNextTime").click();
|
||||
}
|
||||
this.bypassWarningButton.click();
|
||||
}
|
||||
this.bypassWarningButton.click();
|
||||
}
|
||||
|
||||
// No results are shown after the warning page is dismissed or bypassed.
|
||||
this.assertWarningPage(false);
|
||||
Assert.ok(!this.prefsTable.firstElementChild);
|
||||
Assert.equal(this.document.activeElement, this.searchInput);
|
||||
// No results are shown after the warning page is dismissed or bypassed.
|
||||
this.assertWarningPage(false);
|
||||
Assert.ok(!this.prefsTable.firstElementChild);
|
||||
Assert.equal(this.document.activeElement, this.searchInput);
|
||||
|
||||
// The show all button should be present and show all results immediately.
|
||||
this.showAll();
|
||||
Assert.ok(this.prefsTable.firstElementChild);
|
||||
}, { dontBypassWarning: true });
|
||||
// The show all button should be present and show all results immediately.
|
||||
this.showAll();
|
||||
Assert.ok(this.prefsTable.firstElementChild);
|
||||
},
|
||||
{ dontBypassWarning: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -78,14 +78,17 @@ class AboutConfigRowTest {
|
|||
|
||||
class AboutConfigTest {
|
||||
static withNewTab(testFn, options = {}) {
|
||||
return BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: "chrome://browser/content/aboutconfig/aboutconfig.html",
|
||||
}, async browser => {
|
||||
let scope = new this(browser);
|
||||
await scope.setupNewTab(options);
|
||||
await testFn.call(scope);
|
||||
});
|
||||
return BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: "chrome://browser/content/aboutconfig/aboutconfig.html",
|
||||
},
|
||||
async browser => {
|
||||
let scope = new this(browser);
|
||||
await scope.setupNewTab(options);
|
||||
await testFn.call(scope);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
constructor(browser) {
|
||||
|
|
|
@ -6,12 +6,19 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["AboutLoginsChild"];
|
||||
|
||||
const {ActorChild} = ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
|
||||
const {LoginHelper} = ChromeUtils.import("resource://gre/modules/LoginHelper.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { ActorChild } = ChromeUtils.import(
|
||||
"resource://gre/modules/ActorChild.jsm"
|
||||
);
|
||||
const { LoginHelper } = ChromeUtils.import(
|
||||
"resource://gre/modules/LoginHelper.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const TELEMETRY_EVENT_CATEGORY = "pwmgr";
|
||||
|
||||
class AboutLoginsChild extends ActorChild {
|
||||
|
@ -21,7 +28,10 @@ class AboutLoginsChild extends ActorChild {
|
|||
this.mm.sendAsyncMessage("AboutLogins:Subscribe");
|
||||
|
||||
let documentElement = this.content.document.documentElement;
|
||||
documentElement.classList.toggle("official-branding", AppConstants.MOZILLA_OFFICIAL);
|
||||
documentElement.classList.toggle(
|
||||
"official-branding",
|
||||
AppConstants.MOZILLA_OFFICIAL
|
||||
);
|
||||
|
||||
let waivedContent = Cu.waiveXrays(this.content);
|
||||
let AboutLoginsUtils = {
|
||||
|
@ -29,17 +39,25 @@ class AboutLoginsChild extends ActorChild {
|
|||
return LoginHelper.doLoginsMatch(loginA, loginB, {});
|
||||
},
|
||||
};
|
||||
waivedContent.AboutLoginsUtils = Cu.cloneInto(AboutLoginsUtils, waivedContent, {
|
||||
cloneFunctions: true,
|
||||
});
|
||||
waivedContent.AboutLoginsUtils = Cu.cloneInto(
|
||||
AboutLoginsUtils,
|
||||
waivedContent,
|
||||
{
|
||||
cloneFunctions: true,
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsCreateLogin": {
|
||||
this.mm.sendAsyncMessage("AboutLogins:CreateLogin", {login: event.detail});
|
||||
this.mm.sendAsyncMessage("AboutLogins:CreateLogin", {
|
||||
login: event.detail,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsDeleteLogin": {
|
||||
this.mm.sendAsyncMessage("AboutLogins:DeleteLogin", {login: event.detail});
|
||||
this.mm.sendAsyncMessage("AboutLogins:DeleteLogin", {
|
||||
login: event.detail,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsImport": {
|
||||
|
@ -59,23 +77,30 @@ class AboutLoginsChild extends ActorChild {
|
|||
break;
|
||||
}
|
||||
case "AboutLoginsOpenSite": {
|
||||
this.mm.sendAsyncMessage("AboutLogins:OpenSite", {login: event.detail});
|
||||
this.mm.sendAsyncMessage("AboutLogins:OpenSite", {
|
||||
login: event.detail,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsRecordTelemetryEvent": {
|
||||
let {method, object} = event.detail;
|
||||
let { method, object } = event.detail;
|
||||
try {
|
||||
Services.telemetry.recordEvent(
|
||||
TELEMETRY_EVENT_CATEGORY,
|
||||
method,
|
||||
object);
|
||||
object
|
||||
);
|
||||
} catch (ex) {
|
||||
Cu.reportError("AboutLoginsChild: error recording telemetry event: " + ex.message);
|
||||
Cu.reportError(
|
||||
"AboutLoginsChild: error recording telemetry event: " + ex.message
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsUpdateLogin": {
|
||||
this.mm.sendAsyncMessage("AboutLogins:UpdateLogin", {login: event.detail});
|
||||
this.mm.sendAsyncMessage("AboutLogins:UpdateLogin", {
|
||||
login: event.detail,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +124,7 @@ class AboutLoginsChild extends ActorChild {
|
|||
}
|
||||
|
||||
sendToContent(messageType, detail) {
|
||||
let message = Object.assign({messageType}, {value: detail});
|
||||
let message = Object.assign({ messageType }, { value: detail });
|
||||
let event = new this.content.CustomEvent("AboutLoginsChromeToContent", {
|
||||
detail: Cu.cloneInto(message, this.content),
|
||||
});
|
||||
|
|
|
@ -6,15 +6,29 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["AboutLoginsParent"];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "E10SUtils",
|
||||
"resource://gre/modules/E10SUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "LoginHelper",
|
||||
"resource://gre/modules/LoginHelper.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "MigrationUtils",
|
||||
"resource:///modules/MigrationUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"E10SUtils",
|
||||
"resource://gre/modules/E10SUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"LoginHelper",
|
||||
"resource://gre/modules/LoginHelper.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"MigrationUtils",
|
||||
"resource:///modules/MigrationUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Services",
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
||||
return LoginHelper.createLogger("AboutLoginsParent");
|
||||
|
@ -25,9 +39,10 @@ const MASTER_PASSWORD_NOTIFICATION_ID = "master-password-login-required";
|
|||
|
||||
const PRIVILEGEDABOUT_PROCESS_PREF =
|
||||
"browser.tabs.remote.separatePrivilegedContentProcess";
|
||||
const PRIVILEGEDABOUT_PROCESS_ENABLED =
|
||||
Services.prefs.getBoolPref(PRIVILEGEDABOUT_PROCESS_PREF, false);
|
||||
|
||||
const PRIVILEGEDABOUT_PROCESS_ENABLED = Services.prefs.getBoolPref(
|
||||
PRIVILEGEDABOUT_PROCESS_PREF,
|
||||
false
|
||||
);
|
||||
|
||||
const FEEDBACK_URL_PREF = "signon.management.page.feedbackURL";
|
||||
const FEEDBACK_URL = Services.urlFormatter.formatURLPref(FEEDBACK_URL_PREF);
|
||||
|
@ -37,9 +52,9 @@ const FAQ_URL = Services.prefs.getStringPref(FAQ_URL_PREF);
|
|||
|
||||
// When the privileged content process is enabled, we expect about:logins
|
||||
// to load in it. Otherwise, it's in a normal web content process.
|
||||
const EXPECTED_ABOUTLOGINS_REMOTE_TYPE =
|
||||
PRIVILEGEDABOUT_PROCESS_ENABLED ? E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE
|
||||
: E10SUtils.DEFAULT_REMOTE_TYPE;
|
||||
const EXPECTED_ABOUTLOGINS_REMOTE_TYPE = PRIVILEGEDABOUT_PROCESS_ENABLED
|
||||
? E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE
|
||||
: E10SUtils.DEFAULT_REMOTE_TYPE;
|
||||
|
||||
const isValidLogin = login => {
|
||||
return !(login.origin || "").startsWith("chrome://");
|
||||
|
@ -57,12 +72,11 @@ const convertSubjectToLogin = subject => {
|
|||
const augmentVanillaLoginObject = login => {
|
||||
let title;
|
||||
try {
|
||||
title = (new URL(login.origin)).host;
|
||||
title = new URL(login.origin).host;
|
||||
} catch (ex) {
|
||||
title = login.origin;
|
||||
}
|
||||
title = title.replace(/^http(s)?:\/\//, "").
|
||||
replace(/^www\d*\./, "");
|
||||
title = title.replace(/^http(s)?:\/\//, "").replace(/^www\d*\./, "");
|
||||
return Object.assign({}, login, {
|
||||
title,
|
||||
});
|
||||
|
@ -75,8 +89,10 @@ var AboutLoginsParent = {
|
|||
// Listeners are added in BrowserGlue.jsm
|
||||
async receiveMessage(message) {
|
||||
// Only respond to messages sent from about:logins.
|
||||
if (message.target.remoteType != EXPECTED_ABOUTLOGINS_REMOTE_TYPE ||
|
||||
message.target.contentPrincipal.originNoSuffix != ABOUT_LOGINS_ORIGIN) {
|
||||
if (
|
||||
message.target.remoteType != EXPECTED_ABOUTLOGINS_REMOTE_TYPE ||
|
||||
message.target.contentPrincipal.originNoSuffix != ABOUT_LOGINS_ORIGIN
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -86,7 +102,9 @@ var AboutLoginsParent = {
|
|||
// Remove the path from the origin, if it was provided.
|
||||
let origin = LoginHelper.getLoginOrigin(newLogin.origin);
|
||||
if (!origin) {
|
||||
Cu.reportError("AboutLogins:CreateLogin: Unable to get an origin from the login details.");
|
||||
Cu.reportError(
|
||||
"AboutLogins:CreateLogin: Unable to get an origin from the login details."
|
||||
);
|
||||
return;
|
||||
}
|
||||
newLogin.origin = origin;
|
||||
|
@ -105,19 +123,24 @@ var AboutLoginsParent = {
|
|||
}
|
||||
case "AboutLogins:Import": {
|
||||
try {
|
||||
MigrationUtils.showMigrationWizard(message.target.ownerGlobal,
|
||||
[MigrationUtils.MIGRATION_ENTRYPOINT_PASSWORDS]);
|
||||
MigrationUtils.showMigrationWizard(message.target.ownerGlobal, [
|
||||
MigrationUtils.MIGRATION_ENTRYPOINT_PASSWORDS,
|
||||
]);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "AboutLogins:OpenFeedback": {
|
||||
message.target.ownerGlobal.openWebLinkIn(FEEDBACK_URL, "tab", {relatedToCurrent: true});
|
||||
message.target.ownerGlobal.openWebLinkIn(FEEDBACK_URL, "tab", {
|
||||
relatedToCurrent: true,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "AboutLogins:OpenFAQ": {
|
||||
message.target.ownerGlobal.openWebLinkIn(FAQ_URL, "tab", {relatedToCurrent: true});
|
||||
message.target.ownerGlobal.openWebLinkIn(FAQ_URL, "tab", {
|
||||
relatedToCurrent: true,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "AboutLogins:OpenPreferences": {
|
||||
|
@ -126,17 +149,25 @@ var AboutLoginsParent = {
|
|||
}
|
||||
case "AboutLogins:OpenSite": {
|
||||
let guid = message.data.login.guid;
|
||||
let logins = LoginHelper.searchLoginsWithObject({guid});
|
||||
let logins = LoginHelper.searchLoginsWithObject({ guid });
|
||||
if (logins.length != 1) {
|
||||
log.warn(`AboutLogins:OpenSite: expected to find a login for guid: ${guid} but found ${logins.length}`);
|
||||
log.warn(
|
||||
`AboutLogins:OpenSite: expected to find a login for guid: ${guid} but found ${
|
||||
logins.length
|
||||
}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
message.target.ownerGlobal.openWebLinkIn(logins[0].origin, "tab", {relatedToCurrent: true});
|
||||
message.target.ownerGlobal.openWebLinkIn(logins[0].origin, "tab", {
|
||||
relatedToCurrent: true,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "AboutLogins:Subscribe": {
|
||||
if (!ChromeUtils.nondeterministicGetWeakSetKeys(this._subscribers).length) {
|
||||
if (
|
||||
!ChromeUtils.nondeterministicGetWeakSetKeys(this._subscribers).length
|
||||
) {
|
||||
Services.obs.addObserver(this, "passwordmgr-crypto-login");
|
||||
Services.obs.addObserver(this, "passwordmgr-crypto-loginCanceled");
|
||||
Services.obs.addObserver(this, "passwordmgr-storage-changed");
|
||||
|
@ -144,14 +175,23 @@ var AboutLoginsParent = {
|
|||
this._subscribers.add(message.target);
|
||||
|
||||
let messageManager = message.target.messageManager;
|
||||
messageManager.sendAsyncMessage("AboutLogins:AllLogins", await this.getAllLogins());
|
||||
messageManager.sendAsyncMessage(
|
||||
"AboutLogins:AllLogins",
|
||||
await this.getAllLogins()
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "AboutLogins:UpdateLogin": {
|
||||
let loginUpdates = message.data.login;
|
||||
let logins = LoginHelper.searchLoginsWithObject({guid: loginUpdates.guid});
|
||||
let logins = LoginHelper.searchLoginsWithObject({
|
||||
guid: loginUpdates.guid,
|
||||
});
|
||||
if (logins.length != 1) {
|
||||
log.warn(`AboutLogins:UpdateLogin: expected to find a login for guid: ${loginUpdates.guid} but found ${logins.length}`);
|
||||
log.warn(
|
||||
`AboutLogins:UpdateLogin: expected to find a login for guid: ${
|
||||
loginUpdates.guid
|
||||
} but found ${logins.length}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -179,7 +219,10 @@ var AboutLoginsParent = {
|
|||
|
||||
if (topic == "passwordmgr-crypto-login") {
|
||||
this.removeMasterPasswordLoginNotifications();
|
||||
this.messageSubscribers("AboutLogins:AllLogins", await this.getAllLogins());
|
||||
this.messageSubscribers(
|
||||
"AboutLogins:AllLogins",
|
||||
await this.getAllLogins()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -225,10 +268,12 @@ var AboutLoginsParent = {
|
|||
MozXULElement.insertFTLIfNeeded("browser/aboutLogins.ftl");
|
||||
|
||||
// If there's already an existing notification bar, don't do anything.
|
||||
let {gBrowser} = subscriber.ownerGlobal;
|
||||
let { gBrowser } = subscriber.ownerGlobal;
|
||||
let browser = subscriber;
|
||||
let notificationBox = gBrowser.getNotificationBox(browser);
|
||||
let notification = notificationBox.getNotificationWithValue(MASTER_PASSWORD_NOTIFICATION_ID);
|
||||
let notification = notificationBox.getNotificationWithValue(
|
||||
MASTER_PASSWORD_NOTIFICATION_ID
|
||||
);
|
||||
if (notification) {
|
||||
continue;
|
||||
}
|
||||
|
@ -243,23 +288,34 @@ var AboutLoginsParent = {
|
|||
doc.l10n.setAttributes(message, "master-password-notification-message");
|
||||
messageFragment.appendChild(message);
|
||||
|
||||
let buttons = [{
|
||||
"l10n-id": "master-password-reload-button",
|
||||
popup: null,
|
||||
callback() { browser.reload(); },
|
||||
}];
|
||||
let buttons = [
|
||||
{
|
||||
"l10n-id": "master-password-reload-button",
|
||||
popup: null,
|
||||
callback() {
|
||||
browser.reload();
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
notification = notificationBox.appendNotification(messageFragment, MASTER_PASSWORD_NOTIFICATION_ID,
|
||||
iconURL, priority, buttons);
|
||||
notification = notificationBox.appendNotification(
|
||||
messageFragment,
|
||||
MASTER_PASSWORD_NOTIFICATION_ID,
|
||||
iconURL,
|
||||
priority,
|
||||
buttons
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
removeMasterPasswordLoginNotifications() {
|
||||
for (let subscriber of this._subscriberIterator()) {
|
||||
let {gBrowser} = subscriber.ownerGlobal;
|
||||
let { gBrowser } = subscriber.ownerGlobal;
|
||||
let browser = subscriber;
|
||||
let notificationBox = gBrowser.getNotificationBox(browser);
|
||||
let notification = notificationBox.getNotificationWithValue(MASTER_PASSWORD_NOTIFICATION_ID);
|
||||
let notification = notificationBox.getNotificationWithValue(
|
||||
MASTER_PASSWORD_NOTIFICATION_ID
|
||||
);
|
||||
if (!notification) {
|
||||
continue;
|
||||
}
|
||||
|
@ -267,12 +323,16 @@ var AboutLoginsParent = {
|
|||
}
|
||||
},
|
||||
|
||||
* _subscriberIterator() {
|
||||
let subscribers = ChromeUtils.nondeterministicGetWeakSetKeys(this._subscribers);
|
||||
*_subscriberIterator() {
|
||||
let subscribers = ChromeUtils.nondeterministicGetWeakSetKeys(
|
||||
this._subscribers
|
||||
);
|
||||
for (let subscriber of subscribers) {
|
||||
if (subscriber.remoteType != EXPECTED_ABOUTLOGINS_REMOTE_TYPE ||
|
||||
!subscriber.contentPrincipal ||
|
||||
subscriber.contentPrincipal.originNoSuffix != ABOUT_LOGINS_ORIGIN) {
|
||||
if (
|
||||
subscriber.remoteType != EXPECTED_ABOUTLOGINS_REMOTE_TYPE ||
|
||||
!subscriber.contentPrincipal ||
|
||||
subscriber.contentPrincipal.originNoSuffix != ABOUT_LOGINS_ORIGIN
|
||||
) {
|
||||
this._subscribers.delete(subscriber);
|
||||
continue;
|
||||
}
|
||||
|
@ -291,9 +351,10 @@ var AboutLoginsParent = {
|
|||
async getAllLogins() {
|
||||
try {
|
||||
let logins = await Services.logins.getAllLoginsAsync();
|
||||
return logins.filter(isValidLogin)
|
||||
.map(LoginHelper.loginToVanillaObject)
|
||||
.map(augmentVanillaLoginObject);
|
||||
return logins
|
||||
.filter(isValidLogin)
|
||||
.map(LoginHelper.loginToVanillaObject)
|
||||
.map(augmentVanillaLoginObject);
|
||||
} catch (e) {
|
||||
if (e.result == Cr.NS_ERROR_ABORT) {
|
||||
// If the user cancels the MP prompt then return no logins.
|
||||
|
|
|
@ -2,30 +2,36 @@
|
|||
* 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/. */
|
||||
|
||||
import {recordTelemetryEvent} from "./aboutLoginsUtils.js";
|
||||
import { recordTelemetryEvent } from "./aboutLoginsUtils.js";
|
||||
|
||||
let gElements = {};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
gElements.loginList = document.querySelector("login-list");
|
||||
gElements.loginItem = document.querySelector("login-item");
|
||||
gElements.loginFilter = document.querySelector("login-filter");
|
||||
gElements.newLoginButton = document.querySelector("#create-login-button");
|
||||
document.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
() => {
|
||||
gElements.loginList = document.querySelector("login-list");
|
||||
gElements.loginItem = document.querySelector("login-item");
|
||||
gElements.loginFilter = document.querySelector("login-filter");
|
||||
gElements.newLoginButton = document.querySelector("#create-login-button");
|
||||
|
||||
let {searchParams} = new URL(document.location);
|
||||
if (searchParams.get("filter")) {
|
||||
gElements.loginFilter.value = searchParams.get("filter");
|
||||
}
|
||||
let { searchParams } = new URL(document.location);
|
||||
if (searchParams.get("filter")) {
|
||||
gElements.loginFilter.value = searchParams.get("filter");
|
||||
}
|
||||
|
||||
gElements.newLoginButton.addEventListener("click", () => {
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsCreateLogin"));
|
||||
recordTelemetryEvent({object: "new_login", method: "new"});
|
||||
});
|
||||
gElements.newLoginButton.addEventListener("click", () => {
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsCreateLogin"));
|
||||
recordTelemetryEvent({ object: "new_login", method: "new" });
|
||||
});
|
||||
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsInit", {bubbles: true}));
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsInit", { bubbles: true })
|
||||
);
|
||||
|
||||
gElements.loginFilter.focus();
|
||||
}, {once: true});
|
||||
gElements.loginFilter.focus();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
window.addEventListener("AboutLoginsChromeToContent", event => {
|
||||
switch (event.detail.messageType) {
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
* @params {object} event.value [optional] The telemety event value
|
||||
*/
|
||||
export function recordTelemetryEvent(event) {
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsRecordTelemetryEvent", {
|
||||
bubbles: true,
|
||||
detail: event,
|
||||
}));
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsRecordTelemetryEvent", {
|
||||
bubbles: true,
|
||||
detail: event,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export default class ConfirmDeleteDialog extends HTMLElement {
|
|||
return;
|
||||
}
|
||||
let template = document.querySelector("#confirm-delete-dialog-template");
|
||||
let shadowRoot = this.attachShadow({mode: "open"});
|
||||
let shadowRoot = this.attachShadow({ mode: "open" });
|
||||
document.l10n.connectRoot(shadowRoot);
|
||||
shadowRoot.appendChild(template.content.cloneNode(true));
|
||||
|
||||
|
@ -33,9 +33,11 @@ export default class ConfirmDeleteDialog extends HTMLElement {
|
|||
}
|
||||
break;
|
||||
case "click":
|
||||
if (event.target.classList.contains("cancel-button") ||
|
||||
event.target.classList.contains("dismiss-button") ||
|
||||
event.target.classList.contains("overlay")) {
|
||||
if (
|
||||
event.target.classList.contains("cancel-button") ||
|
||||
event.target.classList.contains("dismiss-button") ||
|
||||
event.target.classList.contains("overlay")
|
||||
) {
|
||||
this.onCancel();
|
||||
} else if (event.target.classList.contains("confirm-button")) {
|
||||
this.onConfirm();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
import {recordTelemetryEvent} from "../aboutLoginsUtils.js";
|
||||
import { recordTelemetryEvent } from "../aboutLoginsUtils.js";
|
||||
|
||||
export default class LoginFilter extends HTMLElement {
|
||||
connectedCallback() {
|
||||
|
@ -11,7 +11,7 @@ export default class LoginFilter extends HTMLElement {
|
|||
}
|
||||
|
||||
let loginFilterTemplate = document.querySelector("#login-filter-template");
|
||||
let shadowRoot = this.attachShadow({mode: "open"});
|
||||
let shadowRoot = this.attachShadow({ mode: "open" });
|
||||
document.l10n.connectRoot(shadowRoot);
|
||||
shadowRoot.appendChild(loginFilterTemplate.content.cloneNode(true));
|
||||
|
||||
|
@ -43,13 +43,15 @@ export default class LoginFilter extends HTMLElement {
|
|||
}
|
||||
|
||||
_dispatchFilterEvent(value) {
|
||||
this.dispatchEvent(new CustomEvent("AboutLoginsFilterLogins", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: value,
|
||||
}));
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsFilterLogins", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: value,
|
||||
})
|
||||
);
|
||||
|
||||
recordTelemetryEvent({object: "list", method: "filter"});
|
||||
recordTelemetryEvent({ object: "list", method: "filter" });
|
||||
}
|
||||
}
|
||||
customElements.define("login-filter", LoginFilter);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
import {recordTelemetryEvent} from "../aboutLoginsUtils.js";
|
||||
import { recordTelemetryEvent } from "../aboutLoginsUtils.js";
|
||||
|
||||
export default class LoginItem extends HTMLElement {
|
||||
/**
|
||||
|
@ -25,23 +25,35 @@ export default class LoginItem extends HTMLElement {
|
|||
}
|
||||
|
||||
let loginItemTemplate = document.querySelector("#login-item-template");
|
||||
let shadowRoot = this.attachShadow({mode: "open"});
|
||||
let shadowRoot = this.attachShadow({ mode: "open" });
|
||||
document.l10n.connectRoot(shadowRoot);
|
||||
shadowRoot.appendChild(loginItemTemplate.content.cloneNode(true));
|
||||
|
||||
this._cancelButton = this.shadowRoot.querySelector(".cancel-button");
|
||||
this._confirmDeleteDialog = document.querySelector("confirm-delete-dialog");
|
||||
this._copyPasswordButton = this.shadowRoot.querySelector(".copy-password-button");
|
||||
this._copyUsernameButton = this.shadowRoot.querySelector(".copy-username-button");
|
||||
this._copyPasswordButton = this.shadowRoot.querySelector(
|
||||
".copy-password-button"
|
||||
);
|
||||
this._copyUsernameButton = this.shadowRoot.querySelector(
|
||||
".copy-username-button"
|
||||
);
|
||||
this._deleteButton = this.shadowRoot.querySelector(".delete-button");
|
||||
this._editButton = this.shadowRoot.querySelector(".edit-button");
|
||||
this._form = this.shadowRoot.querySelector("form");
|
||||
this._openSiteButton = this.shadowRoot.querySelector(".open-site-button");
|
||||
this._originInput = this.shadowRoot.querySelector("input[name='origin']");
|
||||
this._usernameInput = this.shadowRoot.querySelector("input[name='username']");
|
||||
this._passwordInput = this.shadowRoot.querySelector("input[name='password']");
|
||||
this._revealCheckbox = this.shadowRoot.querySelector(".reveal-password-checkbox");
|
||||
this._saveChangesButton = this.shadowRoot.querySelector(".save-changes-button");
|
||||
this._usernameInput = this.shadowRoot.querySelector(
|
||||
"input[name='username']"
|
||||
);
|
||||
this._passwordInput = this.shadowRoot.querySelector(
|
||||
"input[name='password']"
|
||||
);
|
||||
this._revealCheckbox = this.shadowRoot.querySelector(
|
||||
".reveal-password-checkbox"
|
||||
);
|
||||
this._saveChangesButton = this.shadowRoot.querySelector(
|
||||
".save-changes-button"
|
||||
);
|
||||
this._title = this.shadowRoot.querySelector(".login-item-title");
|
||||
this._timeCreated = this.shadowRoot.querySelector(".time-created");
|
||||
this._timeChanged = this.shadowRoot.querySelector(".time-changed");
|
||||
|
@ -64,9 +76,15 @@ export default class LoginItem extends HTMLElement {
|
|||
}
|
||||
|
||||
render() {
|
||||
document.l10n.setAttributes(this._timeCreated, "login-item-time-created", {timeCreated: this._login.timeCreated || ""});
|
||||
document.l10n.setAttributes(this._timeChanged, "login-item-time-changed", {timeChanged: this._login.timePasswordChanged || ""});
|
||||
document.l10n.setAttributes(this._timeUsed, "login-item-time-used", {timeUsed: this._login.timeLastUsed || ""});
|
||||
document.l10n.setAttributes(this._timeCreated, "login-item-time-created", {
|
||||
timeCreated: this._login.timeCreated || "",
|
||||
});
|
||||
document.l10n.setAttributes(this._timeChanged, "login-item-time-changed", {
|
||||
timeChanged: this._login.timePasswordChanged || "",
|
||||
});
|
||||
document.l10n.setAttributes(this._timeUsed, "login-item-time-used", {
|
||||
timeUsed: this._login.timeLastUsed || "",
|
||||
});
|
||||
|
||||
this._title.textContent = this._login.title;
|
||||
this._originInput.defaultValue = this._login.origin || "";
|
||||
|
@ -82,7 +100,7 @@ export default class LoginItem extends HTMLElement {
|
|||
break;
|
||||
}
|
||||
case "AboutLoginsInitialLoginSelected": {
|
||||
this.setLogin(event.detail, {skipFocusChange: true});
|
||||
this.setLogin(event.detail, { skipFocusChange: true });
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsLoginSelected": {
|
||||
|
@ -106,7 +124,7 @@ export default class LoginItem extends HTMLElement {
|
|||
this._updatePasswordRevealState();
|
||||
|
||||
let method = this._revealCheckbox.checked ? "show" : "hide";
|
||||
recordTelemetryEvent({object: "password", method});
|
||||
recordTelemetryEvent({ object: "password", method });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -126,20 +144,28 @@ export default class LoginItem extends HTMLElement {
|
|||
});
|
||||
return;
|
||||
}
|
||||
if (classList.contains("copy-password-button") ||
|
||||
classList.contains("copy-username-button")) {
|
||||
if (
|
||||
classList.contains("copy-password-button") ||
|
||||
classList.contains("copy-username-button")
|
||||
) {
|
||||
let copyButton = event.currentTarget;
|
||||
copyButton.disabled = true;
|
||||
let propertyToCopy = copyButton.dataset.copyLoginProperty;
|
||||
navigator.clipboard.writeText(this._login[propertyToCopy]).then(() => {
|
||||
copyButton.dataset.copied = true;
|
||||
setTimeout(() => {
|
||||
copyButton.disabled = false;
|
||||
delete copyButton.dataset.copied;
|
||||
}, LoginItem.COPY_BUTTON_RESET_TIMEOUT);
|
||||
}, () => copyButton.disabled = false);
|
||||
navigator.clipboard.writeText(this._login[propertyToCopy]).then(
|
||||
() => {
|
||||
copyButton.dataset.copied = true;
|
||||
setTimeout(() => {
|
||||
copyButton.disabled = false;
|
||||
delete copyButton.dataset.copied;
|
||||
}, LoginItem.COPY_BUTTON_RESET_TIMEOUT);
|
||||
},
|
||||
() => (copyButton.disabled = false)
|
||||
);
|
||||
|
||||
recordTelemetryEvent({object: copyButton.dataset.telemetryObject, method: "copy"});
|
||||
recordTelemetryEvent({
|
||||
object: copyButton.dataset.telemetryObject,
|
||||
method: "copy",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (classList.contains("delete-button")) {
|
||||
|
@ -149,39 +175,50 @@ export default class LoginItem extends HTMLElement {
|
|||
if (classList.contains("edit-button")) {
|
||||
this._toggleEditing();
|
||||
|
||||
recordTelemetryEvent({object: "existing_login", method: "edit"});
|
||||
recordTelemetryEvent({ object: "existing_login", method: "edit" });
|
||||
return;
|
||||
}
|
||||
if (classList.contains("open-site-button") ||
|
||||
(classList.contains("origin-input") && !this.dataset.editing)) {
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsOpenSite", {
|
||||
bubbles: true,
|
||||
detail: this._login,
|
||||
}));
|
||||
if (
|
||||
classList.contains("open-site-button") ||
|
||||
(classList.contains("origin-input") && !this.dataset.editing)
|
||||
) {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsOpenSite", {
|
||||
bubbles: true,
|
||||
detail: this._login,
|
||||
})
|
||||
);
|
||||
|
||||
recordTelemetryEvent({object: "existing_login", method: "open_site"});
|
||||
recordTelemetryEvent({
|
||||
object: "existing_login",
|
||||
method: "open_site",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (classList.contains("save-changes-button")) {
|
||||
if (!this._isFormValid({reportErrors: true})) {
|
||||
if (!this._isFormValid({ reportErrors: true })) {
|
||||
return;
|
||||
}
|
||||
let loginUpdates = this._loginFromForm();
|
||||
if (this._login.guid) {
|
||||
loginUpdates.guid = this._login.guid;
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsUpdateLogin", {
|
||||
bubbles: true,
|
||||
detail: loginUpdates,
|
||||
}));
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsUpdateLogin", {
|
||||
bubbles: true,
|
||||
detail: loginUpdates,
|
||||
})
|
||||
);
|
||||
|
||||
recordTelemetryEvent({object: "existing_login", method: "save"});
|
||||
recordTelemetryEvent({ object: "existing_login", method: "save" });
|
||||
} else {
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsCreateLogin", {
|
||||
bubbles: true,
|
||||
detail: loginUpdates,
|
||||
}));
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsCreateLogin", {
|
||||
bubbles: true,
|
||||
detail: loginUpdates,
|
||||
})
|
||||
);
|
||||
|
||||
recordTelemetryEvent({object: "new_login", method: "save"});
|
||||
recordTelemetryEvent({ object: "new_login", method: "save" });
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -195,13 +232,18 @@ export default class LoginItem extends HTMLElement {
|
|||
*/
|
||||
confirmDelete() {
|
||||
const dialog = document.querySelector("confirm-delete-dialog");
|
||||
dialog.show().then(() => {
|
||||
document.dispatchEvent(new CustomEvent("AboutLoginsDeleteLogin", {
|
||||
bubbles: true,
|
||||
detail: this._login,
|
||||
}));
|
||||
recordTelemetryEvent({object: "existing_login", method: "delete"});
|
||||
}, () => {});
|
||||
dialog.show().then(
|
||||
() => {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsDeleteLogin", {
|
||||
bubbles: true,
|
||||
detail: this._login,
|
||||
})
|
||||
);
|
||||
recordTelemetryEvent({ object: "existing_login", method: "delete" });
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,7 +253,7 @@ export default class LoginItem extends HTMLElement {
|
|||
* login will not get focus automatically. This is used to prevent
|
||||
* stealing focus from the search filter upon page load.
|
||||
*/
|
||||
setLogin(login, {skipFocusChange} = {}) {
|
||||
setLogin(login, { skipFocusChange } = {}) {
|
||||
this._login = login;
|
||||
|
||||
this._form.reset();
|
||||
|
@ -239,8 +281,10 @@ export default class LoginItem extends HTMLElement {
|
|||
* a plain JS object representation of nsILoginInfo/nsILoginMetaInfo.
|
||||
*/
|
||||
loginAdded(login) {
|
||||
if (this._login.guid ||
|
||||
!window.AboutLoginsUtils.doLoginsMatch(login, this._loginFromForm())) {
|
||||
if (
|
||||
this._login.guid ||
|
||||
!window.AboutLoginsUtils.doLoginsMatch(login, this._loginFromForm())
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -290,7 +334,7 @@ export default class LoginItem extends HTMLElement {
|
|||
* @param {boolean} reportErrors If true, validation errors will be reported
|
||||
* to the user.
|
||||
*/
|
||||
_isFormValid({reportErrors} = {}) {
|
||||
_isFormValid({ reportErrors } = {}) {
|
||||
let fields = [this._passwordInput];
|
||||
if (this.dataset.isNewLogin) {
|
||||
fields.push(this._originInput);
|
||||
|
@ -334,7 +378,8 @@ export default class LoginItem extends HTMLElement {
|
|||
} else {
|
||||
// Need to set a shorter width than -moz-available so the reveal checkbox
|
||||
// will still appear next to the password.
|
||||
this._passwordInput.style.width = (this._login.password || "").length + "ch";
|
||||
this._passwordInput.style.width =
|
||||
(this._login.password || "").length + "ch";
|
||||
}
|
||||
|
||||
this._deleteButton.disabled = this.dataset.isNewLogin;
|
||||
|
@ -355,11 +400,12 @@ export default class LoginItem extends HTMLElement {
|
|||
}
|
||||
|
||||
_updatePasswordRevealState() {
|
||||
let titleId = this._revealCheckbox.checked ? "login-item-password-reveal-checkbox-hide"
|
||||
: "login-item-password-reveal-checkbox-show";
|
||||
let titleId = this._revealCheckbox.checked
|
||||
? "login-item-password-reveal-checkbox-hide"
|
||||
: "login-item-password-reveal-checkbox-show";
|
||||
document.l10n.setAttributes(this._revealCheckbox, titleId);
|
||||
|
||||
let {checked} = this._revealCheckbox;
|
||||
let { checked } = this._revealCheckbox;
|
||||
let inputType = checked ? "text" : "password";
|
||||
this._passwordInput.setAttribute("type", inputType);
|
||||
}
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
* 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/. */
|
||||
|
||||
import {recordTelemetryEvent} from "../aboutLoginsUtils.js";
|
||||
import { recordTelemetryEvent } from "../aboutLoginsUtils.js";
|
||||
|
||||
export default class LoginListItem extends HTMLElement {
|
||||
constructor(login) {
|
||||
super();
|
||||
this._login = login;
|
||||
this.id = login.guid ?
|
||||
// Prepend the ID with a string since IDs must not begin with a number.
|
||||
"lli-" + this._login.guid :
|
||||
"new-login-list-item";
|
||||
this.id = login.guid
|
||||
? // Prepend the ID with a string since IDs must not begin with a number.
|
||||
"lli-" + this._login.guid
|
||||
: "new-login-list-item";
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
@ -20,8 +20,10 @@ export default class LoginListItem extends HTMLElement {
|
|||
return;
|
||||
}
|
||||
|
||||
let loginListItemTemplate = document.querySelector("#login-list-item-template");
|
||||
let shadowRoot = this.attachShadow({mode: "open"});
|
||||
let loginListItemTemplate = document.querySelector(
|
||||
"#login-list-item-template"
|
||||
);
|
||||
let shadowRoot = this.attachShadow({ mode: "open" });
|
||||
document.l10n.connectRoot(shadowRoot);
|
||||
shadowRoot.appendChild(loginListItemTemplate.content.cloneNode(true));
|
||||
|
||||
|
@ -37,8 +39,14 @@ export default class LoginListItem extends HTMLElement {
|
|||
render() {
|
||||
if (!this._login.guid) {
|
||||
delete this.dataset.guid;
|
||||
document.l10n.setAttributes(this._title, "login-list-item-title-new-login");
|
||||
document.l10n.setAttributes(this._username, "login-list-item-subtitle-new-login");
|
||||
document.l10n.setAttributes(
|
||||
this._title,
|
||||
"login-list-item-title-new-login"
|
||||
);
|
||||
document.l10n.setAttributes(
|
||||
this._username,
|
||||
"login-list-item-subtitle-new-login"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -48,7 +56,10 @@ export default class LoginListItem extends HTMLElement {
|
|||
this._username.removeAttribute("data-l10n-id");
|
||||
this._username.textContent = this._login.username.trim();
|
||||
} else {
|
||||
document.l10n.setAttributes(this._username, "login-list-item-subtitle-missing-username");
|
||||
document.l10n.setAttributes(
|
||||
this._username,
|
||||
"login-list-item-subtitle-missing-username"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,13 +70,15 @@ export default class LoginListItem extends HTMLElement {
|
|||
return;
|
||||
}
|
||||
|
||||
this.dispatchEvent(new CustomEvent("AboutLoginsLoginSelected", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: this._login,
|
||||
}));
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsLoginSelected", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: this._login,
|
||||
})
|
||||
);
|
||||
|
||||
recordTelemetryEvent({object: "existing_login", method: "select"});
|
||||
recordTelemetryEvent({ object: "existing_login", method: "select" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import LoginListItem from "./login-list-item.js";
|
|||
const collator = new Intl.Collator();
|
||||
const sortFnOptions = {
|
||||
name: (a, b) => collator.compare(a.title, b.title),
|
||||
"last-used": (a, b) => (a.timeLastUsed < b.timeLastUsed),
|
||||
"last-changed": (a, b) => (a.timePasswordChanged < b.timePasswordChanged),
|
||||
"last-used": (a, b) => a.timeLastUsed < b.timeLastUsed,
|
||||
"last-changed": (a, b) => a.timePasswordChanged < b.timePasswordChanged,
|
||||
};
|
||||
|
||||
export default class LoginList extends HTMLElement {
|
||||
|
@ -25,7 +25,7 @@ export default class LoginList extends HTMLElement {
|
|||
return;
|
||||
}
|
||||
let loginListTemplate = document.querySelector("#login-list-template");
|
||||
let shadowRoot = this.attachShadow({mode: "open"});
|
||||
let shadowRoot = this.attachShadow({ mode: "open" });
|
||||
document.l10n.connectRoot(shadowRoot);
|
||||
shadowRoot.appendChild(loginListTemplate.content.cloneNode(true));
|
||||
|
||||
|
@ -35,8 +35,9 @@ export default class LoginList extends HTMLElement {
|
|||
|
||||
this.render();
|
||||
|
||||
this.shadowRoot.getElementById("login-sort")
|
||||
.addEventListener("change", this);
|
||||
this.shadowRoot
|
||||
.getElementById("login-sort")
|
||||
.addEventListener("change", this);
|
||||
window.addEventListener("AboutLoginsClearSelection", this);
|
||||
window.addEventListener("AboutLoginsCreateLogin", this);
|
||||
window.addEventListener("AboutLoginsInitialLoginSelected", this);
|
||||
|
@ -57,12 +58,17 @@ export default class LoginList extends HTMLElement {
|
|||
if (options.createLogin) {
|
||||
this._blankLoginListItem.classList.add("selected");
|
||||
this._blankLoginListItem.setAttribute("aria-selected", "true");
|
||||
this._list.setAttribute("aria-activedescendant", this._blankLoginListItem.id);
|
||||
this._list.setAttribute(
|
||||
"aria-activedescendant",
|
||||
this._blankLoginListItem.id
|
||||
);
|
||||
this._list.append(this._blankLoginListItem);
|
||||
}
|
||||
|
||||
if (!this._logins.length) {
|
||||
document.l10n.setAttributes(this._count, "login-list-count", {count: 0});
|
||||
document.l10n.setAttributes(this._count, "login-list-count", {
|
||||
count: 0,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -77,7 +83,9 @@ export default class LoginList extends HTMLElement {
|
|||
}
|
||||
|
||||
let visibleLoginCount = this._applyFilter();
|
||||
document.l10n.setAttributes(this._count, "login-list-count", {count: visibleLoginCount});
|
||||
document.l10n.setAttributes(this._count, "login-list-count", {
|
||||
count: visibleLoginCount,
|
||||
});
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
|
@ -92,14 +100,16 @@ export default class LoginList extends HTMLElement {
|
|||
if (!this._logins.length) {
|
||||
return;
|
||||
}
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsLoginSelected", {
|
||||
detail: this._logins[0],
|
||||
}));
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsLoginSelected", {
|
||||
detail: this._logins[0],
|
||||
})
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsCreateLogin": {
|
||||
this._selectedGuid = null;
|
||||
this.render({createLogin: true});
|
||||
this.render({ createLogin: true });
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsFilterLogins": {
|
||||
|
@ -134,14 +144,20 @@ export default class LoginList extends HTMLElement {
|
|||
|
||||
this.render();
|
||||
|
||||
if (!this._selectedGuid ||
|
||||
!this._logins.findIndex(login => login.guid == this._selectedGuid) != -1) {
|
||||
if (
|
||||
!this._selectedGuid ||
|
||||
!this._logins.findIndex(login => login.guid == this._selectedGuid) != -1
|
||||
) {
|
||||
// Select the first visible login after any possible filter is applied.
|
||||
let firstVisibleLogin = this._list.querySelector("login-list-item[data-guid]:not([hidden])");
|
||||
let firstVisibleLogin = this._list.querySelector(
|
||||
"login-list-item[data-guid]:not([hidden])"
|
||||
);
|
||||
if (firstVisibleLogin) {
|
||||
window.dispatchEvent(new CustomEvent("AboutLoginsInitialLoginSelected", {
|
||||
detail: firstVisibleLogin._login,
|
||||
}));
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("AboutLoginsInitialLoginSelected", {
|
||||
detail: firstVisibleLogin._login,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,10 +201,14 @@ export default class LoginList extends HTMLElement {
|
|||
_applyFilter() {
|
||||
let matchingLoginGuids;
|
||||
if (this._filter) {
|
||||
matchingLoginGuids = this._logins.filter(login => {
|
||||
return login.origin.toLocaleLowerCase().includes(this._filter) ||
|
||||
login.username.toLocaleLowerCase().includes(this._filter);
|
||||
}).map(login => login.guid);
|
||||
matchingLoginGuids = this._logins
|
||||
.filter(login => {
|
||||
return (
|
||||
login.origin.toLocaleLowerCase().includes(this._filter) ||
|
||||
login.username.toLocaleLowerCase().includes(this._filter)
|
||||
);
|
||||
})
|
||||
.map(login => login.guid);
|
||||
} else {
|
||||
matchingLoginGuids = this._logins.map(login => login.guid);
|
||||
}
|
||||
|
@ -217,9 +237,9 @@ export default class LoginList extends HTMLElement {
|
|||
|
||||
let isLTR = document.dir == "ltr";
|
||||
let activeDescendantId = this._list.getAttribute("aria-activedescendant");
|
||||
let activeDescendant = activeDescendantId ?
|
||||
this.shadowRoot.getElementById(activeDescendantId) :
|
||||
this._list.firstElementChild;
|
||||
let activeDescendant = activeDescendantId
|
||||
? this.shadowRoot.getElementById(activeDescendantId)
|
||||
: this._list.firstElementChild;
|
||||
let newlyFocusedItem = null;
|
||||
switch (event.key) {
|
||||
case "ArrowDown": {
|
||||
|
@ -231,9 +251,9 @@ export default class LoginList extends HTMLElement {
|
|||
break;
|
||||
}
|
||||
case "ArrowLeft": {
|
||||
let item = isLTR ?
|
||||
activeDescendant.previousElementSibling :
|
||||
activeDescendant.nextElementSibling;
|
||||
let item = isLTR
|
||||
? activeDescendant.previousElementSibling
|
||||
: activeDescendant.nextElementSibling;
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
@ -241,9 +261,9 @@ export default class LoginList extends HTMLElement {
|
|||
break;
|
||||
}
|
||||
case "ArrowRight": {
|
||||
let item = isLTR ?
|
||||
activeDescendant.nextElementSibling :
|
||||
activeDescendant.previousElementSibling;
|
||||
let item = isLTR
|
||||
? activeDescendant.nextElementSibling
|
||||
: activeDescendant.previousElementSibling;
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -9,12 +9,16 @@ export default class MenuButton extends HTMLElement {
|
|||
}
|
||||
|
||||
let MenuButtonTemplate = document.querySelector("#menu-button-template");
|
||||
let shadowRoot = this.attachShadow({mode: "open"});
|
||||
let shadowRoot = this.attachShadow({ mode: "open" });
|
||||
document.l10n.connectRoot(shadowRoot);
|
||||
shadowRoot.appendChild(MenuButtonTemplate.content.cloneNode(true));
|
||||
|
||||
for (let menuitem of this.shadowRoot.querySelectorAll(".menuitem-button[data-supported-platforms]")) {
|
||||
let supportedPlatforms = menuitem.dataset.supportedPlatforms.split(",").map(platform => platform.trim());
|
||||
for (let menuitem of this.shadowRoot.querySelectorAll(
|
||||
".menuitem-button[data-supported-platforms]"
|
||||
)) {
|
||||
let supportedPlatforms = menuitem.dataset.supportedPlatforms
|
||||
.split(",")
|
||||
.map(platform => platform.trim());
|
||||
if (supportedPlatforms.includes(navigator.platform)) {
|
||||
menuitem.hidden = false;
|
||||
}
|
||||
|
@ -31,8 +35,10 @@ export default class MenuButton extends HTMLElement {
|
|||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "blur": {
|
||||
if (event.relatedTarget &&
|
||||
event.relatedTarget.closest(".menu") == this._menu) {
|
||||
if (
|
||||
event.relatedTarget &&
|
||||
event.relatedTarget.closest(".menu") == this._menu
|
||||
) {
|
||||
// Only hide the menu if focus has left the menu-button.
|
||||
return;
|
||||
}
|
||||
|
@ -42,20 +48,26 @@ export default class MenuButton extends HTMLElement {
|
|||
case "click": {
|
||||
// Skip the catch-all event listener if it was the menu-button
|
||||
// that was clicked on.
|
||||
if (event.currentTarget == document.documentElement &&
|
||||
event.target == this &&
|
||||
event.originalTarget == this._menuButton) {
|
||||
if (
|
||||
event.currentTarget == document.documentElement &&
|
||||
event.target == this &&
|
||||
event.originalTarget == this._menuButton
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let classList = event.originalTarget.classList;
|
||||
if (classList.contains("menuitem-import") ||
|
||||
classList.contains("menuitem-faq") ||
|
||||
classList.contains("menuitem-feedback") ||
|
||||
classList.contains("menuitem-preferences")) {
|
||||
if (
|
||||
classList.contains("menuitem-import") ||
|
||||
classList.contains("menuitem-faq") ||
|
||||
classList.contains("menuitem-feedback") ||
|
||||
classList.contains("menuitem-preferences")
|
||||
) {
|
||||
let eventName = event.originalTarget.dataset.eventName;
|
||||
document.dispatchEvent(new CustomEvent(eventName, {
|
||||
bubbles: true,
|
||||
}));
|
||||
document.dispatchEvent(
|
||||
new CustomEvent(eventName, {
|
||||
bubbles: true,
|
||||
})
|
||||
);
|
||||
this._hideMenu();
|
||||
break;
|
||||
}
|
||||
|
@ -81,8 +93,9 @@ export default class MenuButton extends HTMLElement {
|
|||
return;
|
||||
}
|
||||
|
||||
let activeMenuitem = this.shadowRoot.activeElement ||
|
||||
this._menu.querySelector(".menuitem-button:not([hidden])");
|
||||
let activeMenuitem =
|
||||
this.shadowRoot.activeElement ||
|
||||
this._menu.querySelector(".menuitem-button:not([hidden])");
|
||||
|
||||
let newlyFocusedItem = null;
|
||||
if (event.key == "ArrowDown") {
|
||||
|
|
|
@ -8,21 +8,30 @@ ChromeUtils.import("resource://testing-common/TelemetryTestUtils.jsm", this);
|
|||
function waitForTelemetryEventCount(count) {
|
||||
return TestUtils.waitForCondition(() => {
|
||||
let events = Services.telemetry.snapshotEvents(
|
||||
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, false).content;
|
||||
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
|
||||
false
|
||||
).content;
|
||||
return events && events.length == count;
|
||||
}, "waiting for telemetry event count of: " + count);
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
let storageChangedPromised = TestUtils.topicObserved("passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin");
|
||||
let storageChangedPromised = TestUtils.topicObserved(
|
||||
"passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin"
|
||||
);
|
||||
TEST_LOGIN1 = Services.logins.addLogin(TEST_LOGIN1);
|
||||
await storageChangedPromised;
|
||||
storageChangedPromised = TestUtils.topicObserved("passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin");
|
||||
storageChangedPromised = TestUtils.topicObserved(
|
||||
"passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin"
|
||||
);
|
||||
TEST_LOGIN2 = Services.logins.addLogin(TEST_LOGIN2);
|
||||
await storageChangedPromised;
|
||||
await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
|
@ -33,35 +42,48 @@ add_task(async function test_telemetry_events() {
|
|||
await TestUtils.waitForCondition(() => {
|
||||
Services.telemetry.clearEvents();
|
||||
let events = Services.telemetry.snapshotEvents(
|
||||
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).content;
|
||||
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
|
||||
true
|
||||
).content;
|
||||
return !events || !events.length;
|
||||
}, "Waiting for telemetry events to get cleared");
|
||||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
|
||||
let loginList = content.document.querySelector("login-list");
|
||||
let loginListItem = loginList.shadowRoot.querySelector("login-list-item:nth-child(2)");
|
||||
let loginListItem = loginList.shadowRoot.querySelector(
|
||||
"login-list-item:nth-child(2)"
|
||||
);
|
||||
loginListItem.click();
|
||||
});
|
||||
await waitForTelemetryEventCount(1);
|
||||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
|
||||
let loginItem = content.document.querySelector("login-item");
|
||||
let copyButton = loginItem.shadowRoot.querySelector(".copy-username-button");
|
||||
let copyButton = loginItem.shadowRoot.querySelector(
|
||||
".copy-username-button"
|
||||
);
|
||||
copyButton.click();
|
||||
});
|
||||
await waitForTelemetryEventCount(2);
|
||||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
|
||||
let loginItem = content.document.querySelector("login-item");
|
||||
let copyButton = loginItem.shadowRoot.querySelector(".copy-password-button");
|
||||
let copyButton = loginItem.shadowRoot.querySelector(
|
||||
".copy-password-button"
|
||||
);
|
||||
copyButton.click();
|
||||
});
|
||||
await waitForTelemetryEventCount(3);
|
||||
|
||||
let promiseNewTab = BrowserTestUtils.waitForNewTab(gBrowser, TEST_LOGIN1.origin);
|
||||
let promiseNewTab = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
TEST_LOGIN1.origin
|
||||
);
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
|
||||
let loginItem = content.document.querySelector("login-item");
|
||||
let openSiteButton = loginItem.shadowRoot.querySelector(".open-site-button");
|
||||
let openSiteButton = loginItem.shadowRoot.querySelector(
|
||||
".open-site-button"
|
||||
);
|
||||
openSiteButton.click();
|
||||
});
|
||||
let newTab = await promiseNewTab;
|
||||
|
@ -78,7 +100,9 @@ add_task(async function test_telemetry_events() {
|
|||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
|
||||
let loginItem = content.document.querySelector("login-item");
|
||||
let originField = loginItem.shadowRoot.querySelector('input[name="origin"]');
|
||||
let originField = loginItem.shadowRoot.querySelector(
|
||||
'input[name="origin"]'
|
||||
);
|
||||
originField.value = "https://www.example.com";
|
||||
|
||||
let saveButton = loginItem.shadowRoot.querySelector(".save-changes-button");
|
||||
|
@ -101,7 +125,9 @@ add_task(async function test_telemetry_events() {
|
|||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
|
||||
let loginList = content.document.querySelector("login-list");
|
||||
let loginListItem = loginList.shadowRoot.querySelector("login-list-item[data-guid]");
|
||||
let loginListItem = loginList.shadowRoot.querySelector(
|
||||
"login-list-item[data-guid]"
|
||||
);
|
||||
loginListItem.click();
|
||||
});
|
||||
await waitForTelemetryEventCount(9);
|
||||
|
@ -110,8 +136,12 @@ add_task(async function test_telemetry_events() {
|
|||
let loginItem = content.document.querySelector("login-item");
|
||||
let deleteButton = loginItem.shadowRoot.querySelector(".delete-button");
|
||||
deleteButton.click();
|
||||
let confirmDeleteDialog = content.document.querySelector("confirm-delete-dialog");
|
||||
let confirmDeleteButton = confirmDeleteDialog.shadowRoot.querySelector(".confirm-button");
|
||||
let confirmDeleteDialog = content.document.querySelector(
|
||||
"confirm-delete-dialog"
|
||||
);
|
||||
let confirmDeleteButton = confirmDeleteDialog.shadowRoot.querySelector(
|
||||
".confirm-button"
|
||||
);
|
||||
confirmDeleteButton.click();
|
||||
});
|
||||
await waitForTelemetryEventCount(10);
|
||||
|
@ -139,6 +169,7 @@ add_task(async function test_telemetry_events() {
|
|||
|
||||
TelemetryTestUtils.assertEvents(
|
||||
expectedEvents,
|
||||
{category: "pwmgr"},
|
||||
{process: "content"});
|
||||
{ category: "pwmgr" },
|
||||
{ process: "content" }
|
||||
);
|
||||
});
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function setup() {
|
||||
await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
@ -12,57 +15,97 @@ add_task(async function test() {
|
|||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
await ContentTask.spawn(browser, null, async () => {
|
||||
let dialog = Cu.waiveXrays(content.document.querySelector("confirm-delete-dialog"));
|
||||
let dialog = Cu.waiveXrays(
|
||||
content.document.querySelector("confirm-delete-dialog")
|
||||
);
|
||||
|
||||
let cancelButton = dialog.shadowRoot.querySelector(".cancel-button");
|
||||
let confirmDeleteButton = dialog.shadowRoot.querySelector(".confirm-button");
|
||||
let confirmDeleteButton = dialog.shadowRoot.querySelector(
|
||||
".confirm-button"
|
||||
);
|
||||
let dismissButton = dialog.shadowRoot.querySelector(".dismiss-button");
|
||||
let message = dialog.shadowRoot.querySelector(".message");
|
||||
let title = dialog.shadowRoot.querySelector(".title");
|
||||
|
||||
is(title.textContent, "Confirm Deletion",
|
||||
"Title contents should match l10n attribute set on outer element");
|
||||
is(message.textContent, "Are you sure you want to delete this login?",
|
||||
"Message contents should match l10n attribute set on outer element");
|
||||
is(cancelButton.textContent, "Cancel",
|
||||
"Cancel button contents should match l10n attribute set on outer element");
|
||||
is(confirmDeleteButton.textContent, "Delete login",
|
||||
"Delete button contents should match l10n attribute set on outer element");
|
||||
is(
|
||||
title.textContent,
|
||||
"Confirm Deletion",
|
||||
"Title contents should match l10n attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
message.textContent,
|
||||
"Are you sure you want to delete this login?",
|
||||
"Message contents should match l10n attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
cancelButton.textContent,
|
||||
"Cancel",
|
||||
"Cancel button contents should match l10n attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
confirmDeleteButton.textContent,
|
||||
"Delete login",
|
||||
"Delete button contents should match l10n attribute set on outer element"
|
||||
);
|
||||
|
||||
let showPromise = dialog.show();
|
||||
cancelButton.click();
|
||||
try {
|
||||
await showPromise;
|
||||
ok(false, "Promise returned by show() should not resolve after clicking cancel button");
|
||||
ok(
|
||||
false,
|
||||
"Promise returned by show() should not resolve after clicking cancel button"
|
||||
);
|
||||
} catch (ex) {
|
||||
ok(true, "Promise returned by show() should reject after clicking cancel button");
|
||||
ok(
|
||||
true,
|
||||
"Promise returned by show() should reject after clicking cancel button"
|
||||
);
|
||||
}
|
||||
await ContentTaskUtils.waitForCondition(() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden");
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden"
|
||||
);
|
||||
ok(dialog.hidden, "Dialog should be hidden after clicking cancel button");
|
||||
|
||||
showPromise = dialog.show();
|
||||
dismissButton.click();
|
||||
try {
|
||||
await showPromise;
|
||||
ok(false, "Promise returned by show() should not resolve after clicking dismiss button");
|
||||
ok(
|
||||
false,
|
||||
"Promise returned by show() should not resolve after clicking dismiss button"
|
||||
);
|
||||
} catch (ex) {
|
||||
ok(true, "Promise returned by show() should reject after clicking dismiss button");
|
||||
ok(
|
||||
true,
|
||||
"Promise returned by show() should reject after clicking dismiss button"
|
||||
);
|
||||
}
|
||||
await ContentTaskUtils.waitForCondition(() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden");
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden"
|
||||
);
|
||||
ok(dialog.hidden, "Dialog should be hidden after clicking dismiss button");
|
||||
|
||||
showPromise = dialog.show();
|
||||
confirmDeleteButton.click();
|
||||
try {
|
||||
await showPromise;
|
||||
ok(true, "Promise returned by show() should resolve after clicking confirm button");
|
||||
ok(
|
||||
true,
|
||||
"Promise returned by show() should resolve after clicking confirm button"
|
||||
);
|
||||
} catch (ex) {
|
||||
ok(false, "Promise returned by show() should not reject after clicking confirm button");
|
||||
ok(
|
||||
false,
|
||||
"Promise returned by show() should not reject after clicking confirm button"
|
||||
);
|
||||
}
|
||||
await ContentTaskUtils.waitForCondition(() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden");
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden"
|
||||
);
|
||||
ok(dialog.hidden, "Dialog should be hidden after clicking confirm button");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,56 +2,78 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [["dom.events.testing.asyncClipboard", true]] });
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.events.testing.asyncClipboard", true]],
|
||||
});
|
||||
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: "about:logins"}, async function(browser) {
|
||||
let TEST_LOGIN = {
|
||||
guid: "70a",
|
||||
username: "jared",
|
||||
password: "deraj",
|
||||
origin: "https://www.example.com",
|
||||
};
|
||||
|
||||
await ContentTask.spawn(browser, TEST_LOGIN, async function(login) {
|
||||
let loginItem = Cu.waiveXrays(content.document.querySelector("login-item"));
|
||||
|
||||
// The login object needs to be cloned into the content global.
|
||||
loginItem.setLogin(Cu.cloneInto(login, content));
|
||||
|
||||
// Lower the timeout for the test.
|
||||
Object.defineProperty(loginItem.constructor, "COPY_BUTTON_RESET_TIMEOUT", {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 1000,
|
||||
});
|
||||
});
|
||||
|
||||
for (let testCase of [
|
||||
[TEST_LOGIN.username, ".copy-username-button"],
|
||||
[TEST_LOGIN.password, ".copy-password-button"],
|
||||
]) {
|
||||
let testObj = {
|
||||
expectedValue: testCase[0],
|
||||
copyButtonSelector: testCase[1],
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: "about:logins" },
|
||||
async function(browser) {
|
||||
let TEST_LOGIN = {
|
||||
guid: "70a",
|
||||
username: "jared",
|
||||
password: "deraj",
|
||||
origin: "https://www.example.com",
|
||||
};
|
||||
info("waiting for " + testObj.expectedValue + " to be placed on clipboard");
|
||||
await SimpleTest.promiseClipboardChange(testObj.expectedValue, async () => {
|
||||
|
||||
await ContentTask.spawn(browser, TEST_LOGIN, async function(login) {
|
||||
let loginItem = Cu.waiveXrays(
|
||||
content.document.querySelector("login-item")
|
||||
);
|
||||
|
||||
// The login object needs to be cloned into the content global.
|
||||
loginItem.setLogin(Cu.cloneInto(login, content));
|
||||
|
||||
// Lower the timeout for the test.
|
||||
Object.defineProperty(
|
||||
loginItem.constructor,
|
||||
"COPY_BUTTON_RESET_TIMEOUT",
|
||||
{
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 1000,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
for (let testCase of [
|
||||
[TEST_LOGIN.username, ".copy-username-button"],
|
||||
[TEST_LOGIN.password, ".copy-password-button"],
|
||||
]) {
|
||||
let testObj = {
|
||||
expectedValue: testCase[0],
|
||||
copyButtonSelector: testCase[1],
|
||||
};
|
||||
info(
|
||||
"waiting for " + testObj.expectedValue + " to be placed on clipboard"
|
||||
);
|
||||
await SimpleTest.promiseClipboardChange(
|
||||
testObj.expectedValue,
|
||||
async () => {
|
||||
await ContentTask.spawn(browser, testObj, async function(aTestObj) {
|
||||
let loginItem = content.document.querySelector("login-item");
|
||||
let copyButton = loginItem.shadowRoot.querySelector(
|
||||
aTestObj.copyButtonSelector
|
||||
);
|
||||
info("Clicking 'copy' button");
|
||||
copyButton.click();
|
||||
});
|
||||
}
|
||||
);
|
||||
ok(true, testObj.expectedValue + " is on clipboard now");
|
||||
|
||||
await ContentTask.spawn(browser, testObj, async function(aTestObj) {
|
||||
let loginItem = content.document.querySelector("login-item");
|
||||
let copyButton = loginItem.shadowRoot.querySelector(aTestObj.copyButtonSelector);
|
||||
info("Clicking 'copy' button");
|
||||
copyButton.click();
|
||||
let copyButton = loginItem.shadowRoot.querySelector(
|
||||
aTestObj.copyButtonSelector
|
||||
);
|
||||
ok(copyButton.dataset.copied, "Success message should be shown");
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => !copyButton.dataset.copied,
|
||||
"'copied' attribute should be removed after a timeout"
|
||||
);
|
||||
});
|
||||
});
|
||||
ok(true, testObj.expectedValue + " is on clipboard now");
|
||||
|
||||
await ContentTask.spawn(browser, testObj, async function(aTestObj) {
|
||||
let loginItem = content.document.querySelector("login-item");
|
||||
let copyButton = loginItem.shadowRoot.querySelector(aTestObj.copyButtonSelector);
|
||||
ok(copyButton.dataset.copied, "Success message should be shown");
|
||||
await ContentTaskUtils.waitForCondition(() => !copyButton.dataset.copied,
|
||||
"'copied' attribute should be removed after a timeout");
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function setup() {
|
||||
let aboutLoginsTab = await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
let aboutLoginsTab = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(aboutLoginsTab);
|
||||
Services.logins.removeAllLogins();
|
||||
|
@ -14,33 +17,48 @@ add_task(async function test_create_login() {
|
|||
["ftp://ftp.example.com/", "ftp://ftp.example.com"],
|
||||
["https://example.com/foo", "https://example.com"],
|
||||
["http://example.com/", "http://example.com"],
|
||||
["https://testuser1:testpass1@bugzilla.mozilla.org/show_bug.cgi?id=1556934", "https://bugzilla.mozilla.org"],
|
||||
[
|
||||
"https://testuser1:testpass1@bugzilla.mozilla.org/show_bug.cgi?id=1556934",
|
||||
"https://bugzilla.mozilla.org",
|
||||
],
|
||||
["https://www.example.com/bar", "https://www.example.com"],
|
||||
];
|
||||
|
||||
for (let i = 0; i < testCases.length; i++) {
|
||||
let originTuple = testCases[i];
|
||||
info("Testcase " + i);
|
||||
let storageChangedPromised = TestUtils.topicObserved("passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin");
|
||||
let storageChangedPromised = TestUtils.topicObserved(
|
||||
"passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin"
|
||||
);
|
||||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
await ContentTask.spawn(browser, originTuple, async (aOriginTuple) => {
|
||||
await ContentTask.spawn(browser, originTuple, async aOriginTuple => {
|
||||
let createButton = content.document.querySelector("#create-login-button");
|
||||
createButton.click();
|
||||
await Promise.resolve();
|
||||
|
||||
let loginItem = Cu.waiveXrays(content.document.querySelector("login-item"));
|
||||
let loginItem = Cu.waiveXrays(
|
||||
content.document.querySelector("login-item")
|
||||
);
|
||||
|
||||
let originInput = loginItem.shadowRoot.querySelector("input[name='origin']");
|
||||
let usernameInput = loginItem.shadowRoot.querySelector("input[name='username']");
|
||||
let passwordInput = loginItem.shadowRoot.querySelector("input[name='password']");
|
||||
let originInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='origin']"
|
||||
);
|
||||
let usernameInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='username']"
|
||||
);
|
||||
let passwordInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='password']"
|
||||
);
|
||||
|
||||
originInput.value = aOriginTuple[0];
|
||||
usernameInput.value = "testuser1";
|
||||
passwordInput.value = "testpass1";
|
||||
|
||||
let saveChangesButton = loginItem.shadowRoot.querySelector(".save-changes-button");
|
||||
let saveChangesButton = loginItem.shadowRoot.querySelector(
|
||||
".save-changes-button"
|
||||
);
|
||||
saveChangesButton.click();
|
||||
});
|
||||
|
||||
|
@ -48,51 +66,94 @@ add_task(async function test_create_login() {
|
|||
await storageChangedPromised;
|
||||
info("login added to storage");
|
||||
|
||||
storageChangedPromised = TestUtils.topicObserved("passwordmgr-storage-changed",
|
||||
(_, data) => data == "modifyLogin");
|
||||
storageChangedPromised = TestUtils.topicObserved(
|
||||
"passwordmgr-storage-changed",
|
||||
(_, data) => data == "modifyLogin"
|
||||
);
|
||||
let expectedCount = i + 1;
|
||||
await ContentTask.spawn(browser, {expectedCount, originTuple}, async ({expectedCount: aExpectedCount, originTuple: aOriginTuple}) => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
let loginFound = await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginList._logins.length == aExpectedCount;
|
||||
}, "Waiting for login to be displayed");
|
||||
ok(loginFound, "Expected number of logins found in login-list");
|
||||
await ContentTask.spawn(
|
||||
browser,
|
||||
{ expectedCount, originTuple },
|
||||
async ({ expectedCount: aExpectedCount, originTuple: aOriginTuple }) => {
|
||||
let loginList = Cu.waiveXrays(
|
||||
content.document.querySelector("login-list")
|
||||
);
|
||||
let loginFound = await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginList._logins.length == aExpectedCount;
|
||||
}, "Waiting for login to be displayed");
|
||||
ok(loginFound, "Expected number of logins found in login-list");
|
||||
|
||||
let loginListItem = [...loginList.shadowRoot.querySelectorAll("login-list-item")]
|
||||
.find(l => l._login.origin == aOriginTuple[1]);
|
||||
ok(!!loginListItem, `Stored login should only include the origin of the URL provided during creation (${aOriginTuple[1]})`);
|
||||
is(loginListItem._login.username, "testuser1",
|
||||
"Stored login should have username provided during creation");
|
||||
is(loginListItem._login.password, "testpass1",
|
||||
"Stored login should have password provided during creation");
|
||||
loginListItem.click();
|
||||
let loginListItem = [
|
||||
...loginList.shadowRoot.querySelectorAll("login-list-item"),
|
||||
].find(l => l._login.origin == aOriginTuple[1]);
|
||||
ok(
|
||||
!!loginListItem,
|
||||
`Stored login should only include the origin of the URL provided during creation (${
|
||||
aOriginTuple[1]
|
||||
})`
|
||||
);
|
||||
is(
|
||||
loginListItem._login.username,
|
||||
"testuser1",
|
||||
"Stored login should have username provided during creation"
|
||||
);
|
||||
is(
|
||||
loginListItem._login.password,
|
||||
"testpass1",
|
||||
"Stored login should have password provided during creation"
|
||||
);
|
||||
loginListItem.click();
|
||||
|
||||
let loginItem = Cu.waiveXrays(content.document.querySelector("login-item"));
|
||||
is(loginItem._login.guid, loginListItem._login.guid, "Login should be selected");
|
||||
let editButton = loginItem.shadowRoot.querySelector(".edit-button");
|
||||
editButton.click();
|
||||
let loginItem = Cu.waiveXrays(
|
||||
content.document.querySelector("login-item")
|
||||
);
|
||||
is(
|
||||
loginItem._login.guid,
|
||||
loginListItem._login.guid,
|
||||
"Login should be selected"
|
||||
);
|
||||
let editButton = loginItem.shadowRoot.querySelector(".edit-button");
|
||||
editButton.click();
|
||||
|
||||
let usernameInput = loginItem.shadowRoot.querySelector("input[name='username']");
|
||||
let passwordInput = loginItem.shadowRoot.querySelector("input[name='password']");
|
||||
usernameInput.value = "testuser2";
|
||||
passwordInput.value = "testpass2";
|
||||
let usernameInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='username']"
|
||||
);
|
||||
let passwordInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='password']"
|
||||
);
|
||||
usernameInput.value = "testuser2";
|
||||
passwordInput.value = "testpass2";
|
||||
|
||||
let saveChangesButton = loginItem.shadowRoot.querySelector(".save-changes-button");
|
||||
saveChangesButton.click();
|
||||
});
|
||||
let saveChangesButton = loginItem.shadowRoot.querySelector(
|
||||
".save-changes-button"
|
||||
);
|
||||
saveChangesButton.click();
|
||||
}
|
||||
);
|
||||
|
||||
info("waiting for login to get modified in storage");
|
||||
await storageChangedPromised;
|
||||
info("login modified in storage");
|
||||
|
||||
await ContentTask.spawn(browser, originTuple, async (aOriginTuple) => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
await ContentTask.spawn(browser, originTuple, async aOriginTuple => {
|
||||
let loginList = Cu.waiveXrays(
|
||||
content.document.querySelector("login-list")
|
||||
);
|
||||
let login = loginList._logins.find(l => l.origin == aOriginTuple[1]);
|
||||
ok(!!login, "Stored login should only include the origin of the URL provided during creation");
|
||||
is(login.username, "testuser2",
|
||||
"Stored login should have modified username");
|
||||
is(login.password, "testpass2",
|
||||
"Stored login should have modified password");
|
||||
ok(
|
||||
!!login,
|
||||
"Stored login should only include the origin of the URL provided during creation"
|
||||
);
|
||||
is(
|
||||
login.username,
|
||||
"testuser2",
|
||||
"Stored login should have modified username"
|
||||
);
|
||||
is(
|
||||
login.password,
|
||||
"testpass2",
|
||||
"Stored login should have modified password"
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function setup() {
|
||||
await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
@ -13,12 +16,14 @@ add_task(async function setup() {
|
|||
add_task(async function test_show_logins() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
await ContentTask.spawn(browser, [TEST_LOGIN1, TEST_LOGIN2], async (logins) => {
|
||||
await ContentTask.spawn(browser, [TEST_LOGIN1, TEST_LOGIN2], async logins => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
let loginFound = await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginList._logins.length == 2 &&
|
||||
loginList._logins[0].guid == logins[0].guid &&
|
||||
loginList._logins[1].guid == logins[1].guid;
|
||||
return (
|
||||
loginList._logins.length == 2 &&
|
||||
loginList._logins[0].guid == logins[0].guid &&
|
||||
loginList._logins[1].guid == logins[1].guid
|
||||
);
|
||||
}, "Waiting for logins to be displayed");
|
||||
ok(loginFound, "Newly added logins should be added to the page");
|
||||
});
|
||||
|
@ -27,13 +32,21 @@ add_task(async function test_show_logins() {
|
|||
add_task(async function test_login_item() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let deleteLoginMessageReceived = false;
|
||||
browser.messageManager.addMessageListener("AboutLogins:DeleteLogin", function onMsg() {
|
||||
deleteLoginMessageReceived = true;
|
||||
browser.messageManager.removeMessageListener("AboutLogins:DeleteLogin", onMsg);
|
||||
});
|
||||
await ContentTask.spawn(browser, [TEST_LOGIN1, TEST_LOGIN2], async (logins) => {
|
||||
browser.messageManager.addMessageListener(
|
||||
"AboutLogins:DeleteLogin",
|
||||
function onMsg() {
|
||||
deleteLoginMessageReceived = true;
|
||||
browser.messageManager.removeMessageListener(
|
||||
"AboutLogins:DeleteLogin",
|
||||
onMsg
|
||||
);
|
||||
}
|
||||
);
|
||||
await ContentTask.spawn(browser, [TEST_LOGIN1, TEST_LOGIN2], async logins => {
|
||||
let loginList = content.document.querySelector("login-list");
|
||||
let loginListItem = loginList.shadowRoot.querySelector("login-list-item[data-guid]");
|
||||
let loginListItem = loginList.shadowRoot.querySelector(
|
||||
"login-list-item[data-guid]"
|
||||
);
|
||||
info("Clicking on the first login");
|
||||
loginListItem.click();
|
||||
|
||||
|
@ -46,10 +59,16 @@ add_task(async function test_login_item() {
|
|||
let deleteButton = loginItem.shadowRoot.querySelector(".delete-button");
|
||||
deleteButton.click();
|
||||
|
||||
let confirmDeleteDialog = Cu.waiveXrays(content.document.querySelector("confirm-delete-dialog"));
|
||||
let confirmButton = confirmDeleteDialog.shadowRoot.querySelector(".confirm-button");
|
||||
let confirmDeleteDialog = Cu.waiveXrays(
|
||||
content.document.querySelector("confirm-delete-dialog")
|
||||
);
|
||||
let confirmButton = confirmDeleteDialog.shadowRoot.querySelector(
|
||||
".confirm-button"
|
||||
);
|
||||
confirmButton.click();
|
||||
});
|
||||
ok(deleteLoginMessageReceived,
|
||||
"Clicking the delete button should send the AboutLogins:DeleteLogin messsage");
|
||||
ok(
|
||||
deleteLoginMessageReceived,
|
||||
"Clicking the delete button should send the AboutLogins:DeleteLogin messsage"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function setup() {
|
||||
await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
@ -18,11 +21,13 @@ add_task(async function test_login_added() {
|
|||
let browser = gBrowser.selectedBrowser;
|
||||
browser.messageManager.sendAsyncMessage("AboutLogins:LoginAdded", login);
|
||||
|
||||
await ContentTask.spawn(browser, login, async (addedLogin) => {
|
||||
await ContentTask.spawn(browser, login, async addedLogin => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
let loginFound = await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginList._logins.length == 1 &&
|
||||
loginList._logins[0].guid == addedLogin.guid;
|
||||
return (
|
||||
loginList._logins.length == 1 &&
|
||||
loginList._logins[0].guid == addedLogin.guid
|
||||
);
|
||||
}, "Waiting for login to be added");
|
||||
ok(loginFound, "Newly added logins should be added to the page");
|
||||
});
|
||||
|
@ -38,12 +43,14 @@ add_task(async function test_login_modified() {
|
|||
let browser = gBrowser.selectedBrowser;
|
||||
browser.messageManager.sendAsyncMessage("AboutLogins:LoginModified", login);
|
||||
|
||||
await ContentTask.spawn(browser, login, async (modifiedLogin) => {
|
||||
await ContentTask.spawn(browser, login, async modifiedLogin => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
let loginFound = await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginList._logins.length == 1 &&
|
||||
loginList._logins[0].guid == modifiedLogin.guid &&
|
||||
loginList._logins[0].username == modifiedLogin.username;
|
||||
return (
|
||||
loginList._logins.length == 1 &&
|
||||
loginList._logins[0].guid == modifiedLogin.guid &&
|
||||
loginList._logins[0].username == modifiedLogin.username
|
||||
);
|
||||
}, "Waiting for username to get updated");
|
||||
ok(loginFound, "The login should get updated on the page");
|
||||
});
|
||||
|
@ -59,7 +66,7 @@ add_task(async function test_login_removed() {
|
|||
let browser = gBrowser.selectedBrowser;
|
||||
browser.messageManager.sendAsyncMessage("AboutLogins:LoginRemoved", login);
|
||||
|
||||
await ContentTask.spawn(browser, login, async (removedLogin) => {
|
||||
await ContentTask.spawn(browser, login, async removedLogin => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
let loginRemoved = await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginList._logins.length == 0;
|
||||
|
|
|
@ -12,10 +12,15 @@ function waitForMPDialog(action) {
|
|||
let dialogShown = TestUtils.topicObserved("common-dialog-loaded");
|
||||
return dialogShown.then(function([subject]) {
|
||||
let dialog = subject.Dialog;
|
||||
is(dialog.args.title, "Password Required", "Dialog is the Master Password dialog");
|
||||
is(
|
||||
dialog.args.title,
|
||||
"Password Required",
|
||||
"Dialog is the Master Password dialog"
|
||||
);
|
||||
if (action == "authenticate") {
|
||||
SpecialPowers.wrap(dialog.ui.password1Textbox)
|
||||
.setUserInput(LoginTestUtils.masterPassword.masterPassword);
|
||||
SpecialPowers.wrap(dialog.ui.password1Textbox).setUserInput(
|
||||
LoginTestUtils.masterPassword.masterPassword
|
||||
);
|
||||
dialog.ui.button0.click();
|
||||
} else if (action == "cancel") {
|
||||
dialog.ui.button1.click();
|
||||
|
@ -25,10 +30,10 @@ function waitForMPDialog(action) {
|
|||
}
|
||||
|
||||
function waitForLoginCountToReach(browser, loginCount) {
|
||||
return ContentTask.spawn(browser, loginCount, async (expectedLoginCount) => {
|
||||
return ContentTask.spawn(browser, loginCount, async expectedLoginCount => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginList._logins.length == expectedLoginCount;
|
||||
return loginList._logins.length == expectedLoginCount;
|
||||
});
|
||||
return loginList._logins.length;
|
||||
});
|
||||
|
@ -39,7 +44,10 @@ add_task(async function test() {
|
|||
LoginTestUtils.masterPassword.enable();
|
||||
|
||||
let mpDialogShown = waitForMPDialog("cancel");
|
||||
await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
await mpDialogShown;
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
|
@ -50,13 +58,24 @@ add_task(async function test() {
|
|||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let logins = await waitForLoginCountToReach(browser, 0);
|
||||
is(logins, 0, "No logins should be displayed when MP is set and unauthenticated");
|
||||
is(
|
||||
logins,
|
||||
0,
|
||||
"No logins should be displayed when MP is set and unauthenticated"
|
||||
);
|
||||
|
||||
let notification;
|
||||
await BrowserTestUtils.waitForCondition(() =>
|
||||
notification = gBrowser.getNotificationBox().getNotificationWithValue("master-password-login-required"));
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() =>
|
||||
(notification = gBrowser
|
||||
.getNotificationBox()
|
||||
.getNotificationWithValue("master-password-login-required"))
|
||||
);
|
||||
|
||||
ok(notification, "master-password-login-required notification should be visible");
|
||||
ok(
|
||||
notification,
|
||||
"master-password-login-required notification should be visible"
|
||||
);
|
||||
|
||||
let buttons = notification.querySelectorAll(".notification-button");
|
||||
is(buttons.length, 1, "Should have one button.");
|
||||
|
|
|
@ -2,19 +2,31 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [["signon.management.overrideURI", "about:logins?filter=%DOMAIN%"]] });
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["signon.management.overrideURI", "about:logins?filter=%DOMAIN%"]],
|
||||
});
|
||||
|
||||
let storageChangedPromised = TestUtils.topicObserved("passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin");
|
||||
let storageChangedPromised = TestUtils.topicObserved(
|
||||
"passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin"
|
||||
);
|
||||
TEST_LOGIN1 = Services.logins.addLogin(TEST_LOGIN1);
|
||||
await storageChangedPromised;
|
||||
storageChangedPromised = TestUtils.topicObserved("passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin");
|
||||
storageChangedPromised = TestUtils.topicObserved(
|
||||
"passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin"
|
||||
);
|
||||
TEST_LOGIN2 = Services.logins.addLogin(TEST_LOGIN2);
|
||||
await storageChangedPromised;
|
||||
let tabOpenedPromise =
|
||||
BrowserTestUtils.waitForNewTab(gBrowser, "about:logins?filter=" + encodeURIComponent(TEST_LOGIN1.origin), true);
|
||||
LoginHelper.openPasswordManager(window, { filterString: TEST_LOGIN1.origin, entryPoint: "preferences" });
|
||||
let tabOpenedPromise = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
"about:logins?filter=" + encodeURIComponent(TEST_LOGIN1.origin),
|
||||
true
|
||||
);
|
||||
LoginHelper.openPasswordManager(window, {
|
||||
filterString: TEST_LOGIN1.origin,
|
||||
entryPoint: "preferences",
|
||||
});
|
||||
await tabOpenedPromise;
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
@ -28,28 +40,53 @@ add_task(async function test_query_parameter_filter() {
|
|||
LoginHelper.loginToVanillaObject(TEST_LOGIN1),
|
||||
LoginHelper.loginToVanillaObject(TEST_LOGIN2),
|
||||
];
|
||||
await ContentTask.spawn(browser, vanillaLogins, async (logins) => {
|
||||
await ContentTask.spawn(browser, vanillaLogins, async logins => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginList._logins.length == 2;
|
||||
}, "Waiting for logins to be cached");
|
||||
|
||||
let loginItem = Cu.waiveXrays(content.document.querySelector("login-item"));
|
||||
await ContentTaskUtils.waitForCondition(() => loginItem._login.guid == logins[0].guid,
|
||||
"Waiting for TEST_LOGIN1 to be selected for the login-item view");
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => loginItem._login.guid == logins[0].guid,
|
||||
"Waiting for TEST_LOGIN1 to be selected for the login-item view"
|
||||
);
|
||||
|
||||
let loginFilter = content.document.querySelector("login-filter");
|
||||
let xRayLoginFilter = Cu.waiveXrays(loginFilter);
|
||||
is(xRayLoginFilter.value, logins[0].origin, "The filter should be prepopulated");
|
||||
is(content.document.activeElement, loginFilter, "login-filter should be focused");
|
||||
is(loginFilter.shadowRoot.activeElement, loginFilter.shadowRoot.querySelector(".filter"),
|
||||
"the actual input inside of login-filter should be focused");
|
||||
is(
|
||||
xRayLoginFilter.value,
|
||||
logins[0].origin,
|
||||
"The filter should be prepopulated"
|
||||
);
|
||||
is(
|
||||
content.document.activeElement,
|
||||
loginFilter,
|
||||
"login-filter should be focused"
|
||||
);
|
||||
is(
|
||||
loginFilter.shadowRoot.activeElement,
|
||||
loginFilter.shadowRoot.querySelector(".filter"),
|
||||
"the actual input inside of login-filter should be focused"
|
||||
);
|
||||
|
||||
let hiddenLoginListItems = loginList.shadowRoot.querySelectorAll("login-list-item[hidden]");
|
||||
let visibleLoginListItems = loginList.shadowRoot.querySelectorAll("login-list-item:not([hidden])");
|
||||
let hiddenLoginListItems = loginList.shadowRoot.querySelectorAll(
|
||||
"login-list-item[hidden]"
|
||||
);
|
||||
let visibleLoginListItems = loginList.shadowRoot.querySelectorAll(
|
||||
"login-list-item:not([hidden])"
|
||||
);
|
||||
is(visibleLoginListItems.length, 1, "The one login should be visible");
|
||||
is(visibleLoginListItems[0].dataset.guid, logins[0].guid, "TEST_LOGIN1 should be visible");
|
||||
is(
|
||||
visibleLoginListItems[0].dataset.guid,
|
||||
logins[0].guid,
|
||||
"TEST_LOGIN1 should be visible"
|
||||
);
|
||||
is(hiddenLoginListItems.length, 1, "One login should be hidden");
|
||||
is(hiddenLoginListItems[0].dataset.guid, logins[1].guid, "TEST_LOGIN2 should be hidden");
|
||||
is(
|
||||
hiddenLoginListItems[0].dataset.guid,
|
||||
logins[1].guid,
|
||||
"TEST_LOGIN2 should be hidden"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function setup() {
|
||||
let aboutLoginsTab = await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
let aboutLoginsTab = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(aboutLoginsTab);
|
||||
});
|
||||
|
@ -15,10 +18,10 @@ add_task(async function test_open_import() {
|
|||
await BrowserTestUtils.synthesizeMouseAtCenter("menu-button", {}, browser);
|
||||
await ContentTask.spawn(browser, null, async () => {
|
||||
return ContentTaskUtils.waitForCondition(() => {
|
||||
let menuButton = Cu.waiveXrays(content.document.querySelector("menu-button"));
|
||||
return !menuButton.shadowRoot
|
||||
.querySelector(".menu")
|
||||
.hidden;
|
||||
let menuButton = Cu.waiveXrays(
|
||||
content.document.querySelector("menu-button")
|
||||
);
|
||||
return !menuButton.shadowRoot.querySelector(".menu").hidden;
|
||||
}, "waiting for menu to open");
|
||||
});
|
||||
|
||||
|
@ -27,8 +30,10 @@ add_task(async function test_open_import() {
|
|||
// thinks that the shadow DOM element is in another document and throws an exception
|
||||
// when trying to call element.ownerGlobal on the targeted shadow DOM node. This is
|
||||
// on file as bug 1557489. As a workaround, this manually calculates the position to click.
|
||||
let {x, y} = await ContentTask.spawn(browser, null, async () => {
|
||||
let menuButton = Cu.waiveXrays(content.document.querySelector("menu-button"));
|
||||
let { x, y } = await ContentTask.spawn(browser, null, async () => {
|
||||
let menuButton = Cu.waiveXrays(
|
||||
content.document.querySelector("menu-button")
|
||||
);
|
||||
let prefsItem = menuButton.shadowRoot.querySelector(".menuitem-import");
|
||||
return prefsItem.getBoundingClientRect();
|
||||
});
|
||||
|
|
|
@ -2,23 +2,29 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function setup() {
|
||||
await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_open_preferences() {
|
||||
let promiseNewTab = BrowserTestUtils.waitForNewTab(gBrowser, "about:preferences#privacy-logins");
|
||||
let promiseNewTab = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
"about:preferences#privacy-logins"
|
||||
);
|
||||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("menu-button", {}, browser);
|
||||
await ContentTask.spawn(browser, null, async () => {
|
||||
return ContentTaskUtils.waitForCondition(() => {
|
||||
let menuButton = Cu.waiveXrays(content.document.querySelector("menu-button"));
|
||||
return !menuButton.shadowRoot
|
||||
.querySelector(".menu")
|
||||
.hidden;
|
||||
let menuButton = Cu.waiveXrays(
|
||||
content.document.querySelector("menu-button")
|
||||
);
|
||||
return !menuButton.shadowRoot.querySelector(".menu").hidden;
|
||||
}, "waiting for menu to open");
|
||||
});
|
||||
|
||||
|
@ -27,9 +33,13 @@ add_task(async function test_open_preferences() {
|
|||
// thinks that the shadow DOM element is in another document and throws an exception
|
||||
// when trying to call element.ownerGlobal on the targeted shadow DOM node. This is
|
||||
// on file as bug 1557489. As a workaround, this manually calculates the position to click.
|
||||
let {x, y} = await ContentTask.spawn(browser, null, async () => {
|
||||
let menuButton = Cu.waiveXrays(content.document.querySelector("menu-button"));
|
||||
let prefsItem = menuButton.shadowRoot.querySelector(".menuitem-preferences");
|
||||
let { x, y } = await ContentTask.spawn(browser, null, async () => {
|
||||
let menuButton = Cu.waiveXrays(
|
||||
content.document.querySelector("menu-button")
|
||||
);
|
||||
let prefsItem = menuButton.shadowRoot.querySelector(
|
||||
".menuitem-preferences"
|
||||
);
|
||||
return prefsItem.getBoundingClientRect();
|
||||
});
|
||||
await BrowserTestUtils.synthesizeMouseAtPoint(x + 5, y + 5, {}, browser);
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
|
||||
add_task(async function setup() {
|
||||
TEST_LOGIN1 = await addLogin(TEST_LOGIN1);
|
||||
await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
|
@ -11,15 +14,26 @@ add_task(async function setup() {
|
|||
});
|
||||
|
||||
add_task(async function test_launch_login_item() {
|
||||
let promiseNewTab = BrowserTestUtils.waitForNewTab(gBrowser, TEST_LOGIN1.origin);
|
||||
let promiseNewTab = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
TEST_LOGIN1.origin
|
||||
);
|
||||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
await ContentTask.spawn(browser, LoginHelper.loginToVanillaObject(TEST_LOGIN1), async (login) => {
|
||||
let loginItem = Cu.waiveXrays(content.document.querySelector("login-item"));
|
||||
loginItem.setLogin(login);
|
||||
let openSiteButton = loginItem.shadowRoot.querySelector(".open-site-button");
|
||||
openSiteButton.click();
|
||||
});
|
||||
await ContentTask.spawn(
|
||||
browser,
|
||||
LoginHelper.loginToVanillaObject(TEST_LOGIN1),
|
||||
async login => {
|
||||
let loginItem = Cu.waiveXrays(
|
||||
content.document.querySelector("login-item")
|
||||
);
|
||||
loginItem.setLogin(login);
|
||||
let openSiteButton = loginItem.shadowRoot.querySelector(
|
||||
".open-site-button"
|
||||
);
|
||||
openSiteButton.click();
|
||||
}
|
||||
);
|
||||
|
||||
info("waiting for new tab to get opened");
|
||||
let newTab = await promiseNewTab;
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
|
||||
add_task(async function setup() {
|
||||
TEST_LOGIN1 = await addLogin(TEST_LOGIN1);
|
||||
await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||
await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
|
@ -12,11 +15,12 @@ add_task(async function setup() {
|
|||
|
||||
add_task(async function test_show_logins() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
await ContentTask.spawn(browser, TEST_LOGIN1.guid, async (loginGuid) => {
|
||||
await ContentTask.spawn(browser, TEST_LOGIN1.guid, async loginGuid => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
let loginFound = await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginList._logins.length == 1 &&
|
||||
loginList._logins[0].guid == loginGuid;
|
||||
return (
|
||||
loginList._logins.length == 1 && loginList._logins[0].guid == loginGuid
|
||||
);
|
||||
}, "Waiting for login to be displayed");
|
||||
ok(loginFound, "Stored logins should be displayed upon loading the page");
|
||||
});
|
||||
|
@ -24,71 +28,119 @@ add_task(async function test_show_logins() {
|
|||
|
||||
add_task(async function test_login_item() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
await ContentTask.spawn(browser, LoginHelper.loginToVanillaObject(TEST_LOGIN1), async (login) => {
|
||||
let loginList = content.document.querySelector("login-list");
|
||||
let loginListItem = Cu.waiveXrays(loginList.shadowRoot.querySelector("login-list-item[data-guid]"));
|
||||
loginListItem.click();
|
||||
await ContentTask.spawn(
|
||||
browser,
|
||||
LoginHelper.loginToVanillaObject(TEST_LOGIN1),
|
||||
async login => {
|
||||
let loginList = content.document.querySelector("login-list");
|
||||
let loginListItem = Cu.waiveXrays(
|
||||
loginList.shadowRoot.querySelector("login-list-item[data-guid]")
|
||||
);
|
||||
loginListItem.click();
|
||||
|
||||
let loginItem = Cu.waiveXrays(content.document.querySelector("login-item"));
|
||||
let loginItemPopulated = await ContentTaskUtils.waitForCondition(() => {
|
||||
return loginItem._login.guid == loginListItem.dataset.guid &&
|
||||
loginItem._login.guid == login.guid;
|
||||
}, "Waiting for login item to get populated");
|
||||
ok(loginItemPopulated, "The login item should get populated");
|
||||
let loginItem = Cu.waiveXrays(
|
||||
content.document.querySelector("login-item")
|
||||
);
|
||||
let loginItemPopulated = await ContentTaskUtils.waitForCondition(() => {
|
||||
return (
|
||||
loginItem._login.guid == loginListItem.dataset.guid &&
|
||||
loginItem._login.guid == login.guid
|
||||
);
|
||||
}, "Waiting for login item to get populated");
|
||||
ok(loginItemPopulated, "The login item should get populated");
|
||||
|
||||
let usernameInput = loginItem.shadowRoot.querySelector("input[name='username']");
|
||||
let passwordInput = loginItem.shadowRoot.querySelector("input[name='password']");
|
||||
let usernameInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='username']"
|
||||
);
|
||||
let passwordInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='password']"
|
||||
);
|
||||
|
||||
let editButton = loginItem.shadowRoot.querySelector(".edit-button");
|
||||
editButton.click();
|
||||
await Promise.resolve();
|
||||
let editButton = loginItem.shadowRoot.querySelector(".edit-button");
|
||||
editButton.click();
|
||||
await Promise.resolve();
|
||||
|
||||
usernameInput.value += "-undome";
|
||||
passwordInput.value += "-undome";
|
||||
usernameInput.value += "-undome";
|
||||
passwordInput.value += "-undome";
|
||||
|
||||
let cancelButton = loginItem.shadowRoot.querySelector(".cancel-button");
|
||||
cancelButton.click();
|
||||
usernameInput = loginItem.shadowRoot.querySelector("input[name='username']");
|
||||
passwordInput = loginItem.shadowRoot.querySelector("input[name='password']");
|
||||
is(usernameInput.value, login.username, "Username change should be reverted");
|
||||
is(passwordInput.value, login.password, "Password change should be reverted");
|
||||
let cancelButton = loginItem.shadowRoot.querySelector(".cancel-button");
|
||||
cancelButton.click();
|
||||
usernameInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='username']"
|
||||
);
|
||||
passwordInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='password']"
|
||||
);
|
||||
is(
|
||||
usernameInput.value,
|
||||
login.username,
|
||||
"Username change should be reverted"
|
||||
);
|
||||
is(
|
||||
passwordInput.value,
|
||||
login.password,
|
||||
"Password change should be reverted"
|
||||
);
|
||||
|
||||
editButton.click();
|
||||
await Promise.resolve();
|
||||
editButton.click();
|
||||
await Promise.resolve();
|
||||
|
||||
usernameInput.value += "-saveme";
|
||||
passwordInput.value += "-saveme";
|
||||
usernameInput.value += "-saveme";
|
||||
passwordInput.value += "-saveme";
|
||||
|
||||
ok(loginItem.dataset.editing, "LoginItem should be in 'edit' mode");
|
||||
ok(loginItem.dataset.editing, "LoginItem should be in 'edit' mode");
|
||||
|
||||
let saveChangesButton = loginItem.shadowRoot.querySelector(".save-changes-button");
|
||||
saveChangesButton.click();
|
||||
let saveChangesButton = loginItem.shadowRoot.querySelector(
|
||||
".save-changes-button"
|
||||
);
|
||||
saveChangesButton.click();
|
||||
|
||||
usernameInput = loginItem.shadowRoot.querySelector("input[name='username']");
|
||||
passwordInput = loginItem.shadowRoot.querySelector("input[name='password']");
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
loginListItem = Cu.waiveXrays(loginList.shadowRoot.querySelector("login-list-item"));
|
||||
return loginListItem._login.username == usernameInput.value &&
|
||||
loginListItem._login.password == passwordInput.value;
|
||||
}, "Waiting for corresponding login in login list to update");
|
||||
usernameInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='username']"
|
||||
);
|
||||
passwordInput = loginItem.shadowRoot.querySelector(
|
||||
"input[name='password']"
|
||||
);
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
loginListItem = Cu.waiveXrays(
|
||||
loginList.shadowRoot.querySelector("login-list-item")
|
||||
);
|
||||
return (
|
||||
loginListItem._login.username == usernameInput.value &&
|
||||
loginListItem._login.password == passwordInput.value
|
||||
);
|
||||
}, "Waiting for corresponding login in login list to update");
|
||||
|
||||
ok(!loginItem.dataset.editing, "LoginItem should not be in 'edit' mode after saving");
|
||||
ok(
|
||||
!loginItem.dataset.editing,
|
||||
"LoginItem should not be in 'edit' mode after saving"
|
||||
);
|
||||
|
||||
editButton.click();
|
||||
await Promise.resolve();
|
||||
editButton.click();
|
||||
await Promise.resolve();
|
||||
|
||||
ok(loginItem.dataset.editing, "LoginItem should be in 'edit' mode");
|
||||
let deleteButton = loginItem.shadowRoot.querySelector(".delete-button");
|
||||
deleteButton.click();
|
||||
let confirmDeleteDialog = Cu.waiveXrays(content.document.querySelector("confirm-delete-dialog"));
|
||||
let confirmDeleteButton = confirmDeleteDialog.shadowRoot.querySelector(".confirm-button");
|
||||
confirmDeleteButton.click();
|
||||
ok(loginItem.dataset.editing, "LoginItem should be in 'edit' mode");
|
||||
let deleteButton = loginItem.shadowRoot.querySelector(".delete-button");
|
||||
deleteButton.click();
|
||||
let confirmDeleteDialog = Cu.waiveXrays(
|
||||
content.document.querySelector("confirm-delete-dialog")
|
||||
);
|
||||
let confirmDeleteButton = confirmDeleteDialog.shadowRoot.querySelector(
|
||||
".confirm-button"
|
||||
);
|
||||
confirmDeleteButton.click();
|
||||
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
loginListItem = Cu.waiveXrays(loginList.shadowRoot.querySelector("login-list-item"));
|
||||
return !loginListItem;
|
||||
}, "Waiting for login to be removed from list");
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
loginListItem = Cu.waiveXrays(
|
||||
loginList.shadowRoot.querySelector("login-list-item")
|
||||
);
|
||||
return !loginListItem;
|
||||
}, "Waiting for login to be removed from list");
|
||||
|
||||
ok(!loginItem.dataset.editing, "LoginItem should not be in 'edit' mode after deleting");
|
||||
});
|
||||
ok(
|
||||
!loginItem.dataset.editing,
|
||||
"LoginItem should not be in 'edit' mode after deleting"
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,18 +1,41 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
|
||||
Ci.nsILoginInfo, "init");
|
||||
let TEST_LOGIN1 = new nsLoginInfo("https://example.com/", "https://example.com/", null, "user1", "pass1", "username", "password");
|
||||
let TEST_LOGIN2 = new nsLoginInfo("https://2.example.com/", "https://2.example.com/", null, "user2", "pass2", "username", "password");
|
||||
let nsLoginInfo = new Components.Constructor(
|
||||
"@mozilla.org/login-manager/loginInfo;1",
|
||||
Ci.nsILoginInfo,
|
||||
"init"
|
||||
);
|
||||
let TEST_LOGIN1 = new nsLoginInfo(
|
||||
"https://example.com/",
|
||||
"https://example.com/",
|
||||
null,
|
||||
"user1",
|
||||
"pass1",
|
||||
"username",
|
||||
"password"
|
||||
);
|
||||
let TEST_LOGIN2 = new nsLoginInfo(
|
||||
"https://2.example.com/",
|
||||
"https://2.example.com/",
|
||||
null,
|
||||
"user2",
|
||||
"pass2",
|
||||
"username",
|
||||
"password"
|
||||
);
|
||||
|
||||
async function addLogin(login) {
|
||||
let storageChangedPromised = TestUtils.topicObserved("passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin");
|
||||
let storageChangedPromised = TestUtils.topicObserved(
|
||||
"passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin"
|
||||
);
|
||||
login = Services.logins.addLogin(login);
|
||||
await storageChangedPromised;
|
||||
registerCleanupFunction(() => {
|
||||
let matchData = Cc["@mozilla.org/hash-property-bag;1"].createInstance(Ci.nsIWritablePropertyBag2);
|
||||
let matchData = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
|
||||
Ci.nsIWritablePropertyBag2
|
||||
);
|
||||
matchData.setPropertyAsAUTF8String("guid", login.guid);
|
||||
if (!Services.logins.searchLogins(matchData).length) {
|
||||
return;
|
||||
|
|
|
@ -29,8 +29,7 @@ Object.defineProperty(document, "l10n", {
|
|||
configurable: true,
|
||||
writable: true,
|
||||
value: {
|
||||
connectRoot() {
|
||||
},
|
||||
connectRoot() {},
|
||||
translateElements() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
|
|
@ -5,13 +5,20 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["AttributionCode"];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Services",
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
const ATTR_CODE_MAX_LENGTH = 200;
|
||||
|
@ -92,9 +99,11 @@ var AttributionCode = {
|
|||
}
|
||||
} else if (AppConstants.platform == "macosx") {
|
||||
try {
|
||||
let appPath = Services.dirsvc.get("GreD", Ci.nsIFile).parent.parent.path;
|
||||
let attributionSvc = Cc["@mozilla.org/mac-attribution;1"]
|
||||
.getService(Ci.nsIMacAttributionService);
|
||||
let appPath = Services.dirsvc.get("GreD", Ci.nsIFile).parent.parent
|
||||
.path;
|
||||
let attributionSvc = Cc["@mozilla.org/mac-attribution;1"].getService(
|
||||
Ci.nsIMacAttributionService
|
||||
);
|
||||
let referrer = attributionSvc.getReferrerUrl(appPath);
|
||||
let params = new URL(referrer).searchParams;
|
||||
for (let key of ATTR_CODE_KEYS) {
|
||||
|
@ -149,8 +158,9 @@ var AttributionCode = {
|
|||
* Does nothing if called from outside of an xpcshell test.
|
||||
*/
|
||||
_clearCache() {
|
||||
let env = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(
|
||||
Ci.nsIEnvironment
|
||||
);
|
||||
if (env.exists("XPCSHELL_TEST_PROFILE_DIR")) {
|
||||
gCachedAttrData = null;
|
||||
}
|
||||
|
|
|
@ -3,29 +3,46 @@
|
|||
*/
|
||||
"use strict";
|
||||
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const {AttributionCode} = ChromeUtils.import("resource:///modules/AttributionCode.jsm");
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { AttributionCode } = ChromeUtils.import(
|
||||
"resource:///modules/AttributionCode.jsm"
|
||||
);
|
||||
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let validAttrCodes = [
|
||||
{code: "source%3Dgoogle.com%26medium%3Dorganic%26campaign%3D(not%20set)%26content%3D(not%20set)",
|
||||
parsed: {"source": "google.com", "medium": "organic",
|
||||
"campaign": "(not%20set)", "content": "(not%20set)"}},
|
||||
{code: "source%3Dgoogle.com%26medium%3Dorganic%26campaign%3D%26content%3D",
|
||||
parsed: {"source": "google.com", "medium": "organic"}},
|
||||
{code: "source%3Dgoogle.com%26medium%3Dorganic%26campaign%3D(not%20set)",
|
||||
parsed: {"source": "google.com", "medium": "organic", "campaign": "(not%20set)"}},
|
||||
{code: "source%3Dgoogle.com%26medium%3Dorganic",
|
||||
parsed: {"source": "google.com", "medium": "organic"}},
|
||||
{code: "source%3Dgoogle.com",
|
||||
parsed: {"source": "google.com"}},
|
||||
{code: "medium%3Dgoogle.com",
|
||||
parsed: {"medium": "google.com"}},
|
||||
{code: "campaign%3Dgoogle.com",
|
||||
parsed: {"campaign": "google.com"}},
|
||||
{code: "content%3Dgoogle.com",
|
||||
parsed: {"content": "google.com"}},
|
||||
{
|
||||
code:
|
||||
"source%3Dgoogle.com%26medium%3Dorganic%26campaign%3D(not%20set)%26content%3D(not%20set)",
|
||||
parsed: {
|
||||
source: "google.com",
|
||||
medium: "organic",
|
||||
campaign: "(not%20set)",
|
||||
content: "(not%20set)",
|
||||
},
|
||||
},
|
||||
{
|
||||
code: "source%3Dgoogle.com%26medium%3Dorganic%26campaign%3D%26content%3D",
|
||||
parsed: { source: "google.com", medium: "organic" },
|
||||
},
|
||||
{
|
||||
code: "source%3Dgoogle.com%26medium%3Dorganic%26campaign%3D(not%20set)",
|
||||
parsed: {
|
||||
source: "google.com",
|
||||
medium: "organic",
|
||||
campaign: "(not%20set)",
|
||||
},
|
||||
},
|
||||
{
|
||||
code: "source%3Dgoogle.com%26medium%3Dorganic",
|
||||
parsed: { source: "google.com", medium: "organic" },
|
||||
},
|
||||
{ code: "source%3Dgoogle.com", parsed: { source: "google.com" } },
|
||||
{ code: "medium%3Dgoogle.com", parsed: { medium: "google.com" } },
|
||||
{ code: "campaign%3Dgoogle.com", parsed: { campaign: "google.com" } },
|
||||
{ code: "content%3Dgoogle.com", parsed: { content: "google.com" } },
|
||||
];
|
||||
|
||||
let invalidAttrCodes = [
|
||||
|
@ -47,8 +64,7 @@ async function writeAttributionFile(data) {
|
|||
file.append(Services.appinfo.vendor || "mozilla");
|
||||
file.append(AppConstants.MOZ_APP_NAME);
|
||||
|
||||
await OS.File.makeDir(file.path,
|
||||
{from: appDir.path, ignoreExisting: true});
|
||||
await OS.File.makeDir(file.path, { from: appDir.path, ignoreExisting: true });
|
||||
|
||||
file.append("postSigningData");
|
||||
await OS.File.writeAtomic(file.path, data);
|
||||
|
@ -63,8 +79,11 @@ add_task(async function testValidAttrCodes() {
|
|||
AttributionCode._clearCache();
|
||||
await writeAttributionFile(entry.code);
|
||||
let result = await AttributionCode.getAttrDataAsync();
|
||||
Assert.deepEqual(result, entry.parsed,
|
||||
"Parsed code should match expected value, code was: " + entry.code);
|
||||
Assert.deepEqual(
|
||||
result,
|
||||
entry.parsed,
|
||||
"Parsed code should match expected value, code was: " + entry.code
|
||||
);
|
||||
}
|
||||
AttributionCode._clearCache();
|
||||
});
|
||||
|
@ -77,8 +96,7 @@ add_task(async function testInvalidAttrCodes() {
|
|||
AttributionCode._clearCache();
|
||||
await writeAttributionFile(code);
|
||||
let result = await AttributionCode.getAttrDataAsync();
|
||||
Assert.deepEqual(result, {},
|
||||
"Code should have failed to parse: " + code);
|
||||
Assert.deepEqual(result, {}, "Code should have failed to parse: " + code);
|
||||
}
|
||||
AttributionCode._clearCache();
|
||||
});
|
||||
|
@ -91,18 +109,27 @@ add_task(async function testDeletedFile() {
|
|||
// Set up the test by clearing the cache and writing a valid file.
|
||||
await writeAttributionFile(validAttrCodes[0].code);
|
||||
let result = await AttributionCode.getAttrDataAsync();
|
||||
Assert.deepEqual(result, validAttrCodes[0].parsed,
|
||||
"The code should be readable directly from the file");
|
||||
Assert.deepEqual(
|
||||
result,
|
||||
validAttrCodes[0].parsed,
|
||||
"The code should be readable directly from the file"
|
||||
);
|
||||
|
||||
// Delete the file and make sure we can still read the value back from cache.
|
||||
await AttributionCode.deleteFileAsync();
|
||||
result = await AttributionCode.getAttrDataAsync();
|
||||
Assert.deepEqual(result, validAttrCodes[0].parsed,
|
||||
"The code should be readable from the cache");
|
||||
Assert.deepEqual(
|
||||
result,
|
||||
validAttrCodes[0].parsed,
|
||||
"The code should be readable from the cache"
|
||||
);
|
||||
|
||||
// Clear the cache and check we can't read anything.
|
||||
AttributionCode._clearCache();
|
||||
result = await AttributionCode.getAttrDataAsync();
|
||||
Assert.deepEqual(result, {},
|
||||
"Shouldn't be able to get a code after file is deleted and cache is cleared");
|
||||
Assert.deepEqual(
|
||||
result,
|
||||
{},
|
||||
"Shouldn't be able to get a code after file is deleted and cache is cleared"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -4,13 +4,16 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {AttributionCode} = ChromeUtils.import("resource:///modules/AttributionCode.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { AttributionCode } = ChromeUtils.import(
|
||||
"resource:///modules/AttributionCode.jsm"
|
||||
);
|
||||
|
||||
add_task(async function test_attribution() {
|
||||
let appPath = Services.dirsvc.get("GreD", Ci.nsIFile).parent.parent.path;
|
||||
let attributionSvc = Cc["@mozilla.org/mac-attribution;1"]
|
||||
.getService(Ci.nsIMacAttributionService);
|
||||
let attributionSvc = Cc["@mozilla.org/mac-attribution;1"].getService(
|
||||
Ci.nsIMacAttributionService
|
||||
);
|
||||
|
||||
attributionSvc.setReferrerUrl(appPath, "", true);
|
||||
let referrer = attributionSvc.getReferrerUrl(appPath);
|
||||
|
@ -28,5 +31,9 @@ add_task(async function test_attribution() {
|
|||
equal(referrer, url, "referrer url is not changed");
|
||||
|
||||
let result = await AttributionCode.getAttrDataAsync();
|
||||
Assert.deepEqual(result, {content: "foo", source: "bar"}, "parsed attributes match");
|
||||
Assert.deepEqual(
|
||||
result,
|
||||
{ content: "foo", source: "bar" },
|
||||
"parsed attributes match"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
requestLongerTimeout(2);
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["signon.management.page.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["signon.management.page.enabled", true]],
|
||||
});
|
||||
|
||||
let aboutURLs = [];
|
||||
|
||||
|
@ -31,7 +31,9 @@ add_task(async function() {
|
|||
];
|
||||
|
||||
for (let cid in Cc) {
|
||||
let result = cid.match(/@mozilla.org\/network\/protocol\/about;1\?what\=(.*)$/);
|
||||
let result = cid.match(
|
||||
/@mozilla.org\/network\/protocol\/about;1\?what\=(.*)$/
|
||||
);
|
||||
if (!result) {
|
||||
continue;
|
||||
}
|
||||
|
@ -42,8 +44,10 @@ add_task(async function() {
|
|||
let am = Cc[contract].getService(Ci.nsIAboutModule);
|
||||
let uri = Services.io.newURI("about:" + aboutType);
|
||||
let flags = am.getURIFlags(uri);
|
||||
if (!(flags & Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT) &&
|
||||
!skipURLs.includes(aboutType)) {
|
||||
if (
|
||||
!(flags & Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT) &&
|
||||
!skipURLs.includes(aboutType)
|
||||
) {
|
||||
aboutURLs.push(aboutType);
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -54,7 +58,9 @@ add_task(async function() {
|
|||
|
||||
for (let url of aboutURLs) {
|
||||
info("Loading about:" + url);
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:" + url, {userContextId: 1});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:" + url, {
|
||||
userContextId: 1,
|
||||
});
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
ok(true, "Done loading about:" + url);
|
||||
|
|
|
@ -2,18 +2,19 @@
|
|||
|
||||
// Here we want to test that blob URLs are not available cross containers.
|
||||
|
||||
const BASE_URI = "http://mochi.test:8888/browser/browser/components/"
|
||||
+ "contextualidentity/test/browser/empty_file.html";
|
||||
const BASE_URI =
|
||||
"http://mochi.test:8888/browser/browser/components/" +
|
||||
"contextualidentity/test/browser/empty_file.html";
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
info("Creating a tab with UCI = 1...");
|
||||
let tab1 = BrowserTestUtils.addTab(gBrowser, BASE_URI, {userContextId: 1});
|
||||
let tab1 = BrowserTestUtils.addTab(gBrowser, BASE_URI, { userContextId: 1 });
|
||||
is(tab1.getAttribute("usercontextid"), 1, "New tab has UCI equal 1");
|
||||
|
||||
let browser1 = gBrowser.getBrowserForTab(tab1);
|
||||
|
@ -23,13 +24,17 @@ add_task(async function test() {
|
|||
|
||||
info("Creating a blob URL...");
|
||||
await ContentTask.spawn(browser1, null, function() {
|
||||
return Promise.resolve(content.window.URL.createObjectURL(new content.window.Blob([123])));
|
||||
}).then(newURL => { blobURL = newURL; });
|
||||
return Promise.resolve(
|
||||
content.window.URL.createObjectURL(new content.window.Blob([123]))
|
||||
);
|
||||
}).then(newURL => {
|
||||
blobURL = newURL;
|
||||
});
|
||||
|
||||
info("Blob URL: " + blobURL);
|
||||
|
||||
info("Creating a tab with UCI = 2...");
|
||||
let tab2 = BrowserTestUtils.addTab(gBrowser, BASE_URI, {userContextId: 2});
|
||||
let tab2 = BrowserTestUtils.addTab(gBrowser, BASE_URI, { userContextId: 2 });
|
||||
is(tab2.getAttribute("usercontextid"), 2, "New tab has UCI equal 2");
|
||||
|
||||
let browser2 = gBrowser.getBrowserForTab(tab2);
|
||||
|
@ -38,17 +43,25 @@ add_task(async function test() {
|
|||
await ContentTask.spawn(browser2, blobURL, function(url) {
|
||||
return new Promise(resolve => {
|
||||
var xhr = new content.window.XMLHttpRequest();
|
||||
xhr.onerror = function() { resolve("SendErrored"); };
|
||||
xhr.onload = function() { resolve("SendLoaded"); };
|
||||
xhr.onerror = function() {
|
||||
resolve("SendErrored");
|
||||
};
|
||||
xhr.onload = function() {
|
||||
resolve("SendLoaded");
|
||||
};
|
||||
xhr.open("GET", url);
|
||||
xhr.send();
|
||||
});
|
||||
}).then(status => {
|
||||
is(status, "SendErrored", "Using a blob URI from one user context id in another should not work");
|
||||
is(
|
||||
status,
|
||||
"SendErrored",
|
||||
"Using a blob URI from one user context id in another should not work"
|
||||
);
|
||||
});
|
||||
|
||||
info("Creating a tab with UCI = 1...");
|
||||
let tab3 = BrowserTestUtils.addTab(gBrowser, BASE_URI, {userContextId: 1});
|
||||
let tab3 = BrowserTestUtils.addTab(gBrowser, BASE_URI, { userContextId: 1 });
|
||||
is(tab3.getAttribute("usercontextid"), 1, "New tab has UCI equal 1");
|
||||
|
||||
let browser3 = gBrowser.getBrowserForTab(tab3);
|
||||
|
@ -66,7 +79,11 @@ add_task(async function test() {
|
|||
}
|
||||
});
|
||||
}).then(status => {
|
||||
is(status, "SendSucceeded", "Using a blob URI within a single user context id should work");
|
||||
is(
|
||||
status,
|
||||
"SendSucceeded",
|
||||
"Using a blob URI within a single user context id should work"
|
||||
);
|
||||
});
|
||||
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
const BASE_ORIGIN = "http://example.com";
|
||||
const URI = BASE_ORIGIN +
|
||||
const URI =
|
||||
BASE_ORIGIN +
|
||||
"/browser/browser/components/contextualidentity/test/browser/empty_file.html";
|
||||
|
||||
// Opens `uri' in a new tab with the provided userContextId and focuses it.
|
||||
// Returns the newly opened tab and browser.
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// open the tab in the correct userContextId
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// select tab and make sure its browser is focused
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -14,14 +15,17 @@ async function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
// Opens `uri' in a new <iframe mozbrowser> with the provided userContextId.
|
||||
// Returns the newly opened browser.
|
||||
async function addBrowserFrameInUserContext(uri, userContextId) {
|
||||
// Create a browser frame with the user context and uri
|
||||
const browser = document.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
|
||||
const browser = document.createElementNS(
|
||||
"http://www.w3.org/1999/xhtml",
|
||||
"iframe"
|
||||
);
|
||||
browser.setAttribute("remote", "true");
|
||||
browser.setAttribute("usercontextid", userContextId);
|
||||
browser.setAttribute("mozbrowser", "true");
|
||||
|
@ -69,17 +73,15 @@ async function runTestForReceiver(receiver) {
|
|||
let channelName = "contextualidentity-broadcastchannel";
|
||||
|
||||
// reflect the received message on title
|
||||
await ContentTask.spawn(receiver.browser, channelName,
|
||||
function(name) {
|
||||
content.window.testPromise = new content.window.Promise(resolve => {
|
||||
content.window.bc = new content.window.BroadcastChannel(name);
|
||||
content.window.bc.onmessage = function(e) {
|
||||
content.document.title += e.data;
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
await ContentTask.spawn(receiver.browser, channelName, function(name) {
|
||||
content.window.testPromise = new content.window.Promise(resolve => {
|
||||
content.window.bc = new content.window.BroadcastChannel(name);
|
||||
content.window.bc.onmessage = function(e) {
|
||||
content.document.title += e.data;
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
let sender1 = await openTabInUserContext(URI, 1);
|
||||
let sender2 = await openTabInUserContext(URI, 2);
|
||||
|
@ -90,24 +92,28 @@ async function runTestForReceiver(receiver) {
|
|||
// then send a message from a tab in the same user context
|
||||
for (let sender of [sender1, sender2]) {
|
||||
await ContentTask.spawn(
|
||||
sender.browser,
|
||||
{ name: channelName, message: sender.message },
|
||||
function(opts) {
|
||||
let bc = new content.window.BroadcastChannel(opts.name);
|
||||
bc.postMessage(opts.message);
|
||||
});
|
||||
sender.browser,
|
||||
{ name: channelName, message: sender.message },
|
||||
function(opts) {
|
||||
let bc = new content.window.BroadcastChannel(opts.name);
|
||||
bc.postMessage(opts.message);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Since sender1 sends before sender2, if the title is exactly
|
||||
// sender2's message, sender1's message must've been blocked
|
||||
await ContentTask.spawn(receiver.browser, sender2.message,
|
||||
async function(message) {
|
||||
await content.window.testPromise.then(function() {
|
||||
is(content.document.title, message,
|
||||
"should only receive messages from the same user context");
|
||||
});
|
||||
}
|
||||
);
|
||||
await ContentTask.spawn(receiver.browser, sender2.message, async function(
|
||||
message
|
||||
) {
|
||||
await content.window.testPromise.then(function() {
|
||||
is(
|
||||
content.document.title,
|
||||
message,
|
||||
"should only receive messages from the same user context"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
gBrowser.removeTab(sender1.tab);
|
||||
gBrowser.removeTab(sender2.tab);
|
||||
|
@ -115,9 +121,9 @@ async function runTestForReceiver(receiver) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
|
@ -129,9 +135,9 @@ add_task(async function test() {
|
|||
|
||||
add_task(async function test() {
|
||||
info("Checking broadcast channel with <iframe mozbrowser> receiver");
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.mozBrowserFramesEnabled", true]],
|
||||
});
|
||||
let receiver = await addBrowserFrameInUserContext(URI, 2);
|
||||
await runTestForReceiver(receiver);
|
||||
removeBrowserFrame(receiver);
|
||||
|
|
|
@ -1,45 +1,111 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm");
|
||||
const { ContextualIdentityService } = ChromeUtils.import(
|
||||
"resource://gre/modules/ContextualIdentityService.jsm"
|
||||
);
|
||||
|
||||
function openTabInUserContext(userContextId) {
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:blank", {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:blank", { userContextId });
|
||||
gBrowser.selectedTab = tab;
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
// make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
is(ContextualIdentityService.countContainerTabs(), 0, "0 container tabs by default.");
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(),
|
||||
0,
|
||||
"0 container tabs by default."
|
||||
);
|
||||
|
||||
openTabInUserContext(1);
|
||||
is(ContextualIdentityService.countContainerTabs(), 1, "1 container tab created");
|
||||
is(ContextualIdentityService.countContainerTabs(1), 1, "1 container tab created with id 1");
|
||||
is(ContextualIdentityService.countContainerTabs(2), 0, "0 container tabs created with id 2");
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(),
|
||||
1,
|
||||
"1 container tab created"
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(1),
|
||||
1,
|
||||
"1 container tab created with id 1"
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(2),
|
||||
0,
|
||||
"0 container tabs created with id 2"
|
||||
);
|
||||
|
||||
openTabInUserContext(1);
|
||||
is(ContextualIdentityService.countContainerTabs(), 2, "2 container tabs created");
|
||||
is(ContextualIdentityService.countContainerTabs(1), 2, "2 container tabs created with id 1");
|
||||
is(ContextualIdentityService.countContainerTabs(2), 0, "0 container tabs created with id 2");
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(),
|
||||
2,
|
||||
"2 container tabs created"
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(1),
|
||||
2,
|
||||
"2 container tabs created with id 1"
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(2),
|
||||
0,
|
||||
"0 container tabs created with id 2"
|
||||
);
|
||||
|
||||
openTabInUserContext(2);
|
||||
is(ContextualIdentityService.countContainerTabs(), 3, "3 container tab created");
|
||||
is(ContextualIdentityService.countContainerTabs(1), 2, "2 container tabs created with id 1");
|
||||
is(ContextualIdentityService.countContainerTabs(2), 1, "1 container tab created with id 2");
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(),
|
||||
3,
|
||||
"3 container tab created"
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(1),
|
||||
2,
|
||||
"2 container tabs created with id 1"
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(2),
|
||||
1,
|
||||
"1 container tab created with id 2"
|
||||
);
|
||||
|
||||
await ContextualIdentityService.closeContainerTabs(1);
|
||||
is(ContextualIdentityService.countContainerTabs(), 1, "1 container tab created");
|
||||
is(ContextualIdentityService.countContainerTabs(1), 0, "0 container tabs created with id 1");
|
||||
is(ContextualIdentityService.countContainerTabs(2), 1, "1 container tab created with id 2");
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(),
|
||||
1,
|
||||
"1 container tab created"
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(1),
|
||||
0,
|
||||
"0 container tabs created with id 1"
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(2),
|
||||
1,
|
||||
"1 container tab created with id 2"
|
||||
);
|
||||
|
||||
await ContextualIdentityService.closeContainerTabs();
|
||||
is(ContextualIdentityService.countContainerTabs(), 0, "0 container tabs at the end.");
|
||||
is(ContextualIdentityService.countContainerTabs(1), 0, "0 container tabs at the end with id 1.");
|
||||
is(ContextualIdentityService.countContainerTabs(2), 0, "0 container tabs at the end with id 2.");
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(),
|
||||
0,
|
||||
"0 container tabs at the end."
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(1),
|
||||
0,
|
||||
"0 container tabs at the end with id 1."
|
||||
);
|
||||
is(
|
||||
ContextualIdentityService.countContainerTabs(2),
|
||||
0,
|
||||
"0 container tabs at the end with id 2."
|
||||
);
|
||||
});
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
const CC = Components.Constructor;
|
||||
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_URL = "http://" + TEST_HOST + "/browser/browser/components/contextualidentity/test/browser/";
|
||||
const TEST_URL =
|
||||
"http://" +
|
||||
TEST_HOST +
|
||||
"/browser/browser/components/contextualidentity/test/browser/";
|
||||
|
||||
const TESTKEY = {
|
||||
initDataType: "keyids",
|
||||
|
@ -19,7 +22,7 @@ const USER_ID_PERSONAL = 1;
|
|||
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -27,7 +30,7 @@ async function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
function HexToBase64(hex) {
|
||||
|
@ -35,7 +38,11 @@ function HexToBase64(hex) {
|
|||
for (var i = 0; i < hex.length; i += 2) {
|
||||
bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||||
}
|
||||
return window.btoa(bin).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
||||
return window
|
||||
.btoa(bin)
|
||||
.replace(/=/g, "")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_");
|
||||
}
|
||||
|
||||
function Base64ToHex(str) {
|
||||
|
@ -65,9 +72,11 @@ function generateKeyObject(aKid, aKey) {
|
|||
k: HexToBase64(aKey),
|
||||
};
|
||||
|
||||
return new TextEncoder().encode(JSON.stringify({
|
||||
keys: [keyObj],
|
||||
}));
|
||||
return new TextEncoder().encode(
|
||||
JSON.stringify({
|
||||
keys: [keyObj],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function generateKeyInfo(aData) {
|
||||
|
@ -83,83 +92,110 @@ function generateKeyInfo(aData) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// Make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
[ "privacy.userContext.enabled", true ],
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.mediasource.webm.enabled", true ],
|
||||
[ "media.clearkey.persistent-license.enabled", true ],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
["media.mediasource.enabled", true],
|
||||
["media.mediasource.webm.enabled", true],
|
||||
["media.clearkey.persistent-license.enabled", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
// Open a tab with the default container.
|
||||
let defaultContainer = await openTabInUserContext(TEST_URL + "empty_file.html", USER_ID_DEFAULT);
|
||||
let defaultContainer = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
USER_ID_DEFAULT
|
||||
);
|
||||
|
||||
// Generate the key info for the default container.
|
||||
let keyInfo = generateKeyInfo(TESTKEY);
|
||||
|
||||
// Update the media key for the default container.
|
||||
let result = await ContentTask.spawn(defaultContainer.browser, keyInfo, async function(aKeyInfo) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
|
||||
[{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{contentType: "video/webm"}],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
}]);
|
||||
let mediaKeys = await access.createMediaKeys();
|
||||
let session = mediaKeys.createSession(aKeyInfo.sessionType);
|
||||
let res = {};
|
||||
let result = await ContentTask.spawn(
|
||||
defaultContainer.browser,
|
||||
keyInfo,
|
||||
async function(aKeyInfo) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess(
|
||||
"org.w3.clearkey",
|
||||
[
|
||||
{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{ contentType: "video/webm" }],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
},
|
||||
]
|
||||
);
|
||||
let mediaKeys = await access.createMediaKeys();
|
||||
let session = mediaKeys.createSession(aKeyInfo.sessionType);
|
||||
let res = {};
|
||||
|
||||
// Insert the media key.
|
||||
await new Promise(resolve => {
|
||||
session.addEventListener("message", function(event) {
|
||||
session.update(aKeyInfo.keyObj).then(
|
||||
() => { resolve(); }
|
||||
).catch(
|
||||
() => {
|
||||
ok(false, "Update the media key fail.");
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
// Insert the media key.
|
||||
await new Promise(resolve => {
|
||||
session.addEventListener("message", function(event) {
|
||||
session
|
||||
.update(aKeyInfo.keyObj)
|
||||
.then(() => {
|
||||
resolve();
|
||||
})
|
||||
.catch(() => {
|
||||
ok(false, "Update the media key fail.");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
session.generateRequest(aKeyInfo.initDataType, aKeyInfo.initData);
|
||||
});
|
||||
|
||||
session.generateRequest(aKeyInfo.initDataType, aKeyInfo.initData);
|
||||
});
|
||||
let map = session.keyStatuses;
|
||||
|
||||
let map = session.keyStatuses;
|
||||
is(map.size, 1, "One media key has been added.");
|
||||
|
||||
is(map.size, 1, "One media key has been added.");
|
||||
if (map.size === 1) {
|
||||
res.keyId = map.keys().next().value;
|
||||
res.sessionId = session.sessionId;
|
||||
}
|
||||
|
||||
if (map.size === 1) {
|
||||
res.keyId = map.keys().next().value;
|
||||
res.sessionId = session.sessionId;
|
||||
// Close the session.
|
||||
session.close();
|
||||
await session.closed;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Close the session.
|
||||
session.close();
|
||||
await session.closed;
|
||||
|
||||
return res;
|
||||
});
|
||||
);
|
||||
|
||||
// Check the media key ID.
|
||||
is(ByteArrayToHex(result.keyId), Base64ToHex(TESTKEY.kid), "The key Id of the default container is correct.");
|
||||
is(
|
||||
ByteArrayToHex(result.keyId),
|
||||
Base64ToHex(TESTKEY.kid),
|
||||
"The key Id of the default container is correct."
|
||||
);
|
||||
|
||||
// Store the sessionId for the further checking.
|
||||
keyInfo.sessionId = result.sessionId;
|
||||
|
||||
// Open a tab with personal container.
|
||||
let personalContainer = await openTabInUserContext(TEST_URL + "empty_file.html", USER_ID_PERSONAL);
|
||||
let personalContainer = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
USER_ID_PERSONAL
|
||||
);
|
||||
|
||||
await ContentTask.spawn(personalContainer.browser, keyInfo, async function(aKeyInfo) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
|
||||
[{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{contentType: "video/webm"}],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
}]);
|
||||
await ContentTask.spawn(personalContainer.browser, keyInfo, async function(
|
||||
aKeyInfo
|
||||
) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess(
|
||||
"org.w3.clearkey",
|
||||
[
|
||||
{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{ contentType: "video/webm" }],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
},
|
||||
]
|
||||
);
|
||||
let mediaKeys = await access.createMediaKeys();
|
||||
let session = mediaKeys.createSession(aKeyInfo.sessionType);
|
||||
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
/*
|
||||
* Bug 1270678 - A test case to test does the favicon obey originAttributes.
|
||||
*/
|
||||
const {PlacesUtils} = ChromeUtils.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
let {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
const { PlacesUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/PlacesUtils.jsm"
|
||||
);
|
||||
let { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
"work",
|
||||
];
|
||||
const USER_CONTEXTS = ["default", "personal", "work"];
|
||||
|
||||
let gHttpServer = null;
|
||||
let gUserContextId;
|
||||
|
@ -16,21 +14,25 @@ let gFaviconData;
|
|||
|
||||
function getIconFile() {
|
||||
new Promise(resolve => {
|
||||
NetUtil.asyncFetch({
|
||||
uri: "http://www.example.com/browser/browser/components/contextualidentity/test/browser/favicon-normal32.png",
|
||||
loadUsingSystemPrincipal: true,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON,
|
||||
}, function(inputStream, status) {
|
||||
NetUtil.asyncFetch(
|
||||
{
|
||||
uri:
|
||||
"http://www.example.com/browser/browser/components/contextualidentity/test/browser/favicon-normal32.png",
|
||||
loadUsingSystemPrincipal: true,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON,
|
||||
},
|
||||
function(inputStream, status) {
|
||||
let size = inputStream.available();
|
||||
gFaviconData = NetUtil.readInputStreamToString(inputStream, size);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// open the tab in the correct userContextId
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// select tab and make sure its browser is focused
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -38,7 +40,7 @@ async function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
function loadIndexHandler(metadata, response) {
|
||||
|
@ -62,7 +64,11 @@ function loadFaviconHandler(metadata, response) {
|
|||
let expectedCookie = "userContext=" + USER_CONTEXTS[gUserContextId];
|
||||
|
||||
if (metadata.hasHeader("Cookie")) {
|
||||
is(metadata.getHeader("Cookie"), expectedCookie, "The cookie has matched with the expected cookie.");
|
||||
is(
|
||||
metadata.getHeader("Cookie"),
|
||||
expectedCookie,
|
||||
"The cookie has matched with the expected cookie."
|
||||
);
|
||||
} else {
|
||||
ok(false, "The request should have a cookie.");
|
||||
}
|
||||
|
@ -74,9 +80,9 @@ function loadFaviconHandler(metadata, response) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// Make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
|
||||
// Create a http server for the image cache test.
|
||||
if (!gHttpServer) {
|
||||
|
@ -113,21 +119,30 @@ add_task(async function test() {
|
|||
let tabInfo = await openTabInUserContext(testURL, userContextId);
|
||||
|
||||
// Write a cookie according to the userContext.
|
||||
await ContentTask.spawn(tabInfo.browser, { userContext: USER_CONTEXTS[userContextId] }, function(arg) {
|
||||
content.document.cookie = "userContext=" + arg.userContext;
|
||||
});
|
||||
await ContentTask.spawn(
|
||||
tabInfo.browser,
|
||||
{ userContext: USER_CONTEXTS[userContextId] },
|
||||
function(arg) {
|
||||
content.document.cookie = "userContext=" + arg.userContext;
|
||||
}
|
||||
);
|
||||
|
||||
let pageURI = NetUtil.newURI(testURL);
|
||||
let favIconURI = NetUtil.newURI(testFaviconURL);
|
||||
|
||||
await new Promise(resolve => {
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, favIconURI,
|
||||
true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, {
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
pageURI,
|
||||
favIconURI,
|
||||
true,
|
||||
PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
{
|
||||
onComplete() {
|
||||
resolve();
|
||||
},
|
||||
},
|
||||
tabInfo.browser.contentPrincipal);
|
||||
tabInfo.browser.contentPrincipal
|
||||
);
|
||||
});
|
||||
|
||||
BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
const CC = Components.Constructor;
|
||||
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_URL = "http://" + TEST_HOST + "/browser/browser/components/contextualidentity/test/browser/";
|
||||
const TEST_URL =
|
||||
"http://" +
|
||||
TEST_HOST +
|
||||
"/browser/browser/components/contextualidentity/test/browser/";
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
];
|
||||
const USER_CONTEXTS = ["default", "personal"];
|
||||
|
||||
const TEST_EME_KEY = {
|
||||
initDataType: "keyids",
|
||||
|
@ -26,7 +26,7 @@ const TEST_EME_KEY = {
|
|||
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -34,7 +34,7 @@ async function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
function HexToBase64(hex) {
|
||||
|
@ -42,7 +42,11 @@ function HexToBase64(hex) {
|
|||
for (var i = 0; i < hex.length; i += 2) {
|
||||
bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||||
}
|
||||
return window.btoa(bin).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
||||
return window
|
||||
.btoa(bin)
|
||||
.replace(/=/g, "")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_");
|
||||
}
|
||||
|
||||
function Base64ToHex(str) {
|
||||
|
@ -72,9 +76,11 @@ function generateKeyObject(aKid, aKey) {
|
|||
k: HexToBase64(aKey),
|
||||
};
|
||||
|
||||
return new TextEncoder().encode(JSON.stringify({
|
||||
keys: [keyObj],
|
||||
}));
|
||||
return new TextEncoder().encode(
|
||||
JSON.stringify({
|
||||
keys: [keyObj],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function generateKeyInfo(aData) {
|
||||
|
@ -94,14 +100,20 @@ async function setupEMEKey(browser) {
|
|||
let keyInfo = generateKeyInfo(TEST_EME_KEY);
|
||||
|
||||
// Setup the EME key.
|
||||
let result = await ContentTask.spawn(browser, keyInfo, async function(aKeyInfo) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
|
||||
[{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{contentType: "video/webm"}],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
}]);
|
||||
let result = await ContentTask.spawn(browser, keyInfo, async function(
|
||||
aKeyInfo
|
||||
) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess(
|
||||
"org.w3.clearkey",
|
||||
[
|
||||
{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{ contentType: "video/webm" }],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
},
|
||||
]
|
||||
);
|
||||
let mediaKeys = await access.createMediaKeys();
|
||||
let session = mediaKeys.createSession(aKeyInfo.sessionType);
|
||||
let res = {};
|
||||
|
@ -109,14 +121,15 @@ async function setupEMEKey(browser) {
|
|||
// Insert the EME key.
|
||||
await new Promise(resolve => {
|
||||
session.addEventListener("message", function(event) {
|
||||
session.update(aKeyInfo.keyObj).then(
|
||||
() => { resolve(); }
|
||||
).catch(
|
||||
() => {
|
||||
session
|
||||
.update(aKeyInfo.keyObj)
|
||||
.then(() => {
|
||||
resolve();
|
||||
})
|
||||
.catch(() => {
|
||||
ok(false, "Update the EME key fail.");
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
session.generateRequest(aKeyInfo.initDataType, aKeyInfo.initData);
|
||||
|
@ -139,7 +152,11 @@ async function setupEMEKey(browser) {
|
|||
});
|
||||
|
||||
// Check the EME key ID.
|
||||
is(ByteArrayToHex(result.keyId), Base64ToHex(TEST_EME_KEY.kid), "The key Id is correct.");
|
||||
is(
|
||||
ByteArrayToHex(result.keyId),
|
||||
Base64ToHex(TEST_EME_KEY.kid),
|
||||
"The key Id is correct."
|
||||
);
|
||||
return result.sessionId;
|
||||
}
|
||||
|
||||
|
@ -150,13 +167,17 @@ async function checkEMEKey(browser, emeSessionId) {
|
|||
keyInfo.sessionId = emeSessionId;
|
||||
|
||||
await ContentTask.spawn(browser, keyInfo, async function(aKeyInfo) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
|
||||
[{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{contentType: "video/webm"}],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
}]);
|
||||
let access = await content.navigator.requestMediaKeySystemAccess(
|
||||
"org.w3.clearkey",
|
||||
[
|
||||
{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{ contentType: "video/webm" }],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
},
|
||||
]
|
||||
);
|
||||
let mediaKeys = await access.createMediaKeys();
|
||||
let session = mediaKeys.createSession(aKeyInfo.sessionType);
|
||||
|
||||
|
@ -166,7 +187,11 @@ async function checkEMEKey(browser, emeSessionId) {
|
|||
let map = session.keyStatuses;
|
||||
|
||||
// Check that there is no media key here.
|
||||
is(map.size, 0, "No media key should be here after forgetThisSite() was called.");
|
||||
is(
|
||||
map.size,
|
||||
0,
|
||||
"No media key should be here after forgetThisSite() was called."
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -176,12 +201,14 @@ async function checkEMEKey(browser, emeSessionId) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// Make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
[ "privacy.userContext.enabled", true ],
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.mediasource.webm.enabled", true ],
|
||||
[ "media.clearkey.persistent-license.enabled", true ],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
["media.mediasource.enabled", true],
|
||||
["media.mediasource.webm.enabled", true],
|
||||
["media.clearkey.persistent-license.enabled", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_EME_forgetThisSite() {
|
||||
|
@ -190,27 +217,39 @@ add_task(async function test_EME_forgetThisSite() {
|
|||
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Open our tab in the given user context.
|
||||
tabs[userContextId] = await openTabInUserContext(TEST_URL + "empty_file.html", userContextId);
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Setup EME Key.
|
||||
emeSessionIds[userContextId] = await setupEMEKey(tabs[userContextId].browser);
|
||||
emeSessionIds[userContextId] = await setupEMEKey(
|
||||
tabs[userContextId].browser
|
||||
);
|
||||
|
||||
// Close this tab.
|
||||
BrowserTestUtils.removeTab(tabs[userContextId].tab);
|
||||
}
|
||||
|
||||
// Clear all EME data for a given domain with originAttributes pattern.
|
||||
let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"].
|
||||
getService(Ci.mozIGeckoMediaPluginChromeService);
|
||||
let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"].getService(
|
||||
Ci.mozIGeckoMediaPluginChromeService
|
||||
);
|
||||
mps.forgetThisSite(TEST_HOST, JSON.stringify({}));
|
||||
|
||||
// Open tabs again to check EME keys have been cleared.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Open our tab in the given user context.
|
||||
tabs[userContextId] = await openTabInUserContext(TEST_URL + "empty_file.html", userContextId);
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Check whether EME Key has been cleared.
|
||||
await checkEMEKey(tabs[userContextId].browser, emeSessionIds[userContextId]);
|
||||
await checkEMEKey(
|
||||
tabs[userContextId].browser,
|
||||
emeSessionIds[userContextId]
|
||||
);
|
||||
|
||||
// Close this tab.
|
||||
BrowserTestUtils.removeTab(tabs[userContextId].tab);
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
const CC = Components.Constructor;
|
||||
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_URL = "http://" + TEST_HOST + "/browser/browser/components/contextualidentity/test/browser/";
|
||||
const TEST_URL =
|
||||
"http://" +
|
||||
TEST_HOST +
|
||||
"/browser/browser/components/contextualidentity/test/browser/";
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
];
|
||||
const USER_CONTEXTS = ["default", "personal"];
|
||||
|
||||
//
|
||||
// Support functions.
|
||||
|
@ -18,7 +18,7 @@ const USER_CONTEXTS = [
|
|||
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -26,11 +26,11 @@ async function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
function getCookiesForOA(host, userContextId) {
|
||||
return Services.cookies.getCookiesFromHost(host, {userContextId});
|
||||
return Services.cookies.getCookiesFromHost(host, { userContextId });
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -39,9 +39,9 @@ function getCookiesForOA(host, userContextId) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// Make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
[ "privacy.userContext.enabled", true ],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_cookie_getCookiesWithOriginAttributes() {
|
||||
|
@ -54,7 +54,10 @@ add_task(async function test_cookie_getCookiesWithOriginAttributes() {
|
|||
let value = USER_CONTEXTS[userContextId];
|
||||
|
||||
// Open our tab in the given user context.
|
||||
tabs[userContextId] = await openTabInUserContext(TEST_URL + "file_reflect_cookie_into_title.html?" + value, userContextId);
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
TEST_URL + "file_reflect_cookie_into_title.html?" + value,
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Close this tab.
|
||||
BrowserTestUtils.removeTab(tabs[userContextId].tab);
|
||||
|
@ -72,8 +75,17 @@ add_task(async function test_cookie_getCookiesWithOriginAttributes() {
|
|||
|
||||
// Using getCookiesWithOriginAttributes() to get all cookies for a certain
|
||||
// domain by using the originAttributes pattern, and clear all these cookies.
|
||||
for (let cookie of Services.cookies.getCookiesWithOriginAttributes(JSON.stringify({}), TEST_HOST)) {
|
||||
Services.cookies.remove(cookie.host, cookie.name, cookie.path, false, cookie.originAttributes);
|
||||
for (let cookie of Services.cookies.getCookiesWithOriginAttributes(
|
||||
JSON.stringify({}),
|
||||
TEST_HOST
|
||||
)) {
|
||||
Services.cookies.remove(
|
||||
cookie.host,
|
||||
cookie.name,
|
||||
cookie.path,
|
||||
false,
|
||||
cookie.originAttributes
|
||||
);
|
||||
}
|
||||
|
||||
// Check that whether cookies has been cleared.
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
const CC = Components.Constructor;
|
||||
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_URL = "http://" + TEST_HOST + "/browser/browser/components/contextualidentity/test/browser/";
|
||||
const TEST_URL =
|
||||
"http://" +
|
||||
TEST_HOST +
|
||||
"/browser/browser/components/contextualidentity/test/browser/";
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
];
|
||||
const USER_CONTEXTS = ["default", "personal"];
|
||||
|
||||
//
|
||||
// Support functions.
|
||||
|
@ -18,7 +18,7 @@ const USER_CONTEXTS = [
|
|||
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -26,12 +26,14 @@ async function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
// Setup an entry for the indexedDB.
|
||||
async function setupIndexedDB(browser) {
|
||||
await ContentTask.spawn(browser, { input: "TestForgetAPIs" }, async function(arg) {
|
||||
await ContentTask.spawn(browser, { input: "TestForgetAPIs" }, async function(
|
||||
arg
|
||||
) {
|
||||
let request = content.indexedDB.open("idb", 1);
|
||||
|
||||
request.onerror = function() {
|
||||
|
@ -53,7 +55,7 @@ async function setupIndexedDB(browser) {
|
|||
// Add an entry into the indexedDB.
|
||||
let transaction = db.transaction(["obj"], "readwrite");
|
||||
let store = transaction.objectStore("obj");
|
||||
store.add({id: 1, userContext: arg.input});
|
||||
store.add({ id: 1, userContext: arg.input });
|
||||
|
||||
await new Promise(resolve => {
|
||||
transaction.oncomplete = () => {
|
||||
|
@ -105,9 +107,9 @@ async function checkIndexedDB(browser) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// Make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
[ "privacy.userContext.enabled", true ],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_quota_clearStoragesForPrincipal() {
|
||||
|
@ -115,7 +117,10 @@ add_task(async function test_quota_clearStoragesForPrincipal() {
|
|||
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Open our tab in the given user context.
|
||||
tabs[userContextId] = await openTabInUserContext(TEST_URL + "empty_file.html", userContextId);
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Setup an entry for the indexedDB.
|
||||
await setupIndexedDB(tabs[userContextId].browser);
|
||||
|
@ -126,12 +131,21 @@ add_task(async function test_quota_clearStoragesForPrincipal() {
|
|||
|
||||
// Using quota manager to clear all indexed DB for a given domain.
|
||||
let caUtils = {};
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js",
|
||||
caUtils);
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://global/content/contentAreaUtils.js",
|
||||
caUtils
|
||||
);
|
||||
let httpURI = caUtils.makeURI("http://" + TEST_HOST);
|
||||
let httpPrincipal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(httpURI, {});
|
||||
let clearRequest = Services.qms.clearStoragesForPrincipal(httpPrincipal, null, null, true);
|
||||
let httpPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(
|
||||
httpURI,
|
||||
{}
|
||||
);
|
||||
let clearRequest = Services.qms.clearStoragesForPrincipal(
|
||||
httpPrincipal,
|
||||
null,
|
||||
null,
|
||||
true
|
||||
);
|
||||
await new Promise(resolve => {
|
||||
clearRequest.callback = () => {
|
||||
resolve();
|
||||
|
@ -140,7 +154,10 @@ add_task(async function test_quota_clearStoragesForPrincipal() {
|
|||
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Open our tab in the given user context.
|
||||
tabs[userContextId] = await openTabInUserContext(TEST_URL + "empty_file.html", userContextId);
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Check whether indexed DB has been cleared.
|
||||
await checkIndexedDB(tabs[userContextId].browser);
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
|
||||
const CC = Components.Constructor;
|
||||
|
||||
let {ForgetAboutSite} = ChromeUtils.import("resource://gre/modules/ForgetAboutSite.jsm");
|
||||
let {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
let { ForgetAboutSite } = ChromeUtils.import(
|
||||
"resource://gre/modules/ForgetAboutSite.jsm"
|
||||
);
|
||||
let { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
];
|
||||
const USER_CONTEXTS = ["default", "personal"];
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_URL = "http://" + TEST_HOST + "/browser/browser/components/contextualidentity/test/browser/";
|
||||
const TEST_URL =
|
||||
"http://" +
|
||||
TEST_HOST +
|
||||
"/browser/browser/components/contextualidentity/test/browser/";
|
||||
const COOKIE_NAME = "userContextId";
|
||||
|
||||
// Counter for image load hits.
|
||||
|
@ -23,8 +25,10 @@ let gHttpServer = null;
|
|||
function imageHandler(metadata, response) {
|
||||
// A 1x1 PNG image.
|
||||
// Source: https://commons.wikimedia.org/wiki/File:1x1.png (Public Domain)
|
||||
const IMAGE = atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
|
||||
"ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=");
|
||||
const IMAGE = atob(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
|
||||
"ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII="
|
||||
);
|
||||
gHits++;
|
||||
response.setHeader("Cache-Control", "max-age=10000", false);
|
||||
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||
|
@ -36,7 +40,8 @@ function loadImagePageHandler(metadata, response) {
|
|||
response.setHeader("Cache-Control", "max-age=10000", false);
|
||||
response.setStatusLine(metadata.httpVersion, 200, "Ok");
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
let body = "<!DOCTYPE HTML>\
|
||||
let body =
|
||||
"<!DOCTYPE HTML>\
|
||||
<html>\
|
||||
<head>\
|
||||
<meta charset='utf-8'>\
|
||||
|
@ -51,7 +56,7 @@ function loadImagePageHandler(metadata, response) {
|
|||
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -59,11 +64,11 @@ async function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
function getCookiesForOA(host, userContextId) {
|
||||
return Services.cookies.getCookiesFromHost(host, {userContextId});
|
||||
return Services.cookies.getCookiesFromHost(host, { userContextId });
|
||||
}
|
||||
|
||||
function createURI(uri) {
|
||||
|
@ -71,12 +76,18 @@ function createURI(uri) {
|
|||
}
|
||||
|
||||
function getCacheStorage(where, lci, appcache) {
|
||||
if (!lci) lci = Services.loadContextInfo.default;
|
||||
if (!lci) {
|
||||
lci = Services.loadContextInfo.default;
|
||||
}
|
||||
switch (where) {
|
||||
case "disk": return Services.cache2.diskCacheStorage(lci, false);
|
||||
case "memory": return Services.cache2.memoryCacheStorage(lci);
|
||||
case "appcache": return Services.cache2.appCacheStorage(lci, appcache);
|
||||
case "pin": return Services.cache2.pinningCacheStorage(lci);
|
||||
case "disk":
|
||||
return Services.cache2.diskCacheStorage(lci, false);
|
||||
case "memory":
|
||||
return Services.cache2.memoryCacheStorage(lci);
|
||||
case "appcache":
|
||||
return Services.cache2.appCacheStorage(lci, appcache);
|
||||
case "pin":
|
||||
return Services.cache2.pinningCacheStorage(lci);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -84,7 +95,7 @@ function getCacheStorage(where, lci, appcache) {
|
|||
function OpenCacheEntry(key, where, flags, lci) {
|
||||
return new Promise(resolve => {
|
||||
key = createURI(key);
|
||||
function CacheListener() { }
|
||||
function CacheListener() {}
|
||||
CacheListener.prototype = {
|
||||
_appCache: null,
|
||||
|
||||
|
@ -104,7 +115,7 @@ function OpenCacheEntry(key, where, flags, lci) {
|
|||
},
|
||||
};
|
||||
|
||||
(new CacheListener()).run();
|
||||
new CacheListener().run();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -122,7 +133,10 @@ async function test_cookie_cleared() {
|
|||
let value = USER_CONTEXTS[userContextId];
|
||||
|
||||
// Open our tab in the given user context.
|
||||
tabs[userContextId] = await openTabInUserContext(TEST_URL + "file_reflect_cookie_into_title.html?" + value, userContextId);
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
TEST_URL + "file_reflect_cookie_into_title.html?" + value,
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Close this tab.
|
||||
BrowserTestUtils.removeTab(tabs[userContextId].tab);
|
||||
|
@ -134,7 +148,11 @@ async function test_cookie_cleared() {
|
|||
|
||||
let foundCookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
|
||||
Assert.equal(foundCookie.name, COOKIE_NAME, "Check cookie name");
|
||||
Assert.equal(foundCookie.value, USER_CONTEXTS[userContextId], "Check cookie value");
|
||||
Assert.equal(
|
||||
foundCookie.value,
|
||||
USER_CONTEXTS[userContextId],
|
||||
"Check cookie value"
|
||||
);
|
||||
}
|
||||
|
||||
// Forget the site.
|
||||
|
@ -151,25 +169,40 @@ async function test_cookie_cleared() {
|
|||
async function test_cache_cleared() {
|
||||
// First, add some caches.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
await OpenCacheEntry("http://" + TEST_HOST + "/",
|
||||
"disk",
|
||||
Ci.nsICacheStorage.OPEN_NORMALLY,
|
||||
Services.loadContextInfo.custom(false, {userContextId}));
|
||||
await OpenCacheEntry(
|
||||
"http://" + TEST_HOST + "/",
|
||||
"disk",
|
||||
Ci.nsICacheStorage.OPEN_NORMALLY,
|
||||
Services.loadContextInfo.custom(false, { userContextId })
|
||||
);
|
||||
|
||||
await OpenCacheEntry("http://" + TEST_HOST + "/",
|
||||
"memory",
|
||||
Ci.nsICacheStorage.OPEN_NORMALLY,
|
||||
Services.loadContextInfo.custom(false, {userContextId}));
|
||||
await OpenCacheEntry(
|
||||
"http://" + TEST_HOST + "/",
|
||||
"memory",
|
||||
Ci.nsICacheStorage.OPEN_NORMALLY,
|
||||
Services.loadContextInfo.custom(false, { userContextId })
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Check that caches have been set correctly.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
let mem = getCacheStorage("memory", Services.loadContextInfo.custom(false, {userContextId}));
|
||||
let disk = getCacheStorage("disk", Services.loadContextInfo.custom(false, {userContextId}));
|
||||
let mem = getCacheStorage(
|
||||
"memory",
|
||||
Services.loadContextInfo.custom(false, { userContextId })
|
||||
);
|
||||
let disk = getCacheStorage(
|
||||
"disk",
|
||||
Services.loadContextInfo.custom(false, { userContextId })
|
||||
);
|
||||
|
||||
Assert.ok(mem.exists(createURI("http://" + TEST_HOST + "/"), ""), "The memory cache has been set correctly");
|
||||
Assert.ok(disk.exists(createURI("http://" + TEST_HOST + "/"), ""), "The disk cache has been set correctly");
|
||||
Assert.ok(
|
||||
mem.exists(createURI("http://" + TEST_HOST + "/"), ""),
|
||||
"The memory cache has been set correctly"
|
||||
);
|
||||
Assert.ok(
|
||||
disk.exists(createURI("http://" + TEST_HOST + "/"), ""),
|
||||
"The disk cache has been set correctly"
|
||||
);
|
||||
}
|
||||
|
||||
// Forget the site.
|
||||
|
@ -177,11 +210,23 @@ async function test_cache_cleared() {
|
|||
|
||||
// Check that do caches be removed or not?
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
let mem = getCacheStorage("memory", Services.loadContextInfo.custom(false, {userContextId}));
|
||||
let disk = getCacheStorage("disk", Services.loadContextInfo.custom(false, {userContextId}));
|
||||
let mem = getCacheStorage(
|
||||
"memory",
|
||||
Services.loadContextInfo.custom(false, { userContextId })
|
||||
);
|
||||
let disk = getCacheStorage(
|
||||
"disk",
|
||||
Services.loadContextInfo.custom(false, { userContextId })
|
||||
);
|
||||
|
||||
Assert.ok(!mem.exists(createURI("http://" + TEST_HOST + "/"), ""), "The memory cache is cleared");
|
||||
Assert.ok(!disk.exists(createURI("http://" + TEST_HOST + "/"), ""), "The disk cache is cleared");
|
||||
Assert.ok(
|
||||
!mem.exists(createURI("http://" + TEST_HOST + "/"), ""),
|
||||
"The memory cache is cleared"
|
||||
);
|
||||
Assert.ok(
|
||||
!disk.exists(createURI("http://" + TEST_HOST + "/"), ""),
|
||||
"The disk cache is cleared"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,15 +236,23 @@ async function test_image_cache_cleared() {
|
|||
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Open our tab in the given user context to cache image.
|
||||
tabs[userContextId] = await openTabInUserContext("http://localhost:" + gHttpServer.identity.primaryPort + "/loadImage.html",
|
||||
userContextId);
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
"http://localhost:" +
|
||||
gHttpServer.identity.primaryPort +
|
||||
"/loadImage.html",
|
||||
userContextId
|
||||
);
|
||||
BrowserTestUtils.removeTab(tabs[userContextId].tab);
|
||||
}
|
||||
|
||||
let expectedHits = USER_CONTEXTS.length;
|
||||
|
||||
// Check that image cache works with the userContextId.
|
||||
is(gHits, expectedHits, "The image should be loaded" + expectedHits + "times.");
|
||||
is(
|
||||
gHits,
|
||||
expectedHits,
|
||||
"The image should be loaded" + expectedHits + "times."
|
||||
);
|
||||
|
||||
// Reset the cache count.
|
||||
gHits = 0;
|
||||
|
@ -210,13 +263,21 @@ async function test_image_cache_cleared() {
|
|||
// Load again.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Open our tab in the given user context to cache image.
|
||||
tabs[userContextId] = await openTabInUserContext("http://localhost:" + gHttpServer.identity.primaryPort + "/loadImage.html",
|
||||
userContextId);
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
"http://localhost:" +
|
||||
gHttpServer.identity.primaryPort +
|
||||
"/loadImage.html",
|
||||
userContextId
|
||||
);
|
||||
BrowserTestUtils.removeTab(tabs[userContextId].tab);
|
||||
}
|
||||
|
||||
// Check that image cache was cleared and the server gets another two hits.
|
||||
is(gHits, expectedHits, "The image should be loaded" + expectedHits + "times.");
|
||||
is(
|
||||
gHits,
|
||||
expectedHits,
|
||||
"The image should be loaded" + expectedHits + "times."
|
||||
);
|
||||
}
|
||||
|
||||
// Offline Storage
|
||||
|
@ -227,37 +288,56 @@ async function test_storage_cleared() {
|
|||
let value = USER_CONTEXTS[userContextId];
|
||||
|
||||
// Open our tab in the given user context.
|
||||
let tabInfo = await openTabInUserContext(TEST_URL + "file_set_storages.html?" + value, userContextId);
|
||||
let tabInfo = await openTabInUserContext(
|
||||
TEST_URL + "file_set_storages.html?" + value,
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Check that the storages has been set correctly.
|
||||
await ContentTask.spawn(tabInfo.browser, { userContext: USER_CONTEXTS[userContextId] }, async function(arg) {
|
||||
// Check that the local storage has been set correctly.
|
||||
Assert.equal(content.localStorage.getItem("userContext"), arg.userContext, "Check the local storage value");
|
||||
await ContentTask.spawn(
|
||||
tabInfo.browser,
|
||||
{ userContext: USER_CONTEXTS[userContextId] },
|
||||
async function(arg) {
|
||||
// Check that the local storage has been set correctly.
|
||||
Assert.equal(
|
||||
content.localStorage.getItem("userContext"),
|
||||
arg.userContext,
|
||||
"Check the local storage value"
|
||||
);
|
||||
|
||||
// Check that the session storage has been set correctly.
|
||||
Assert.equal(content.sessionStorage.getItem("userContext"), arg.userContext, "Check the session storage value");
|
||||
// Check that the session storage has been set correctly.
|
||||
Assert.equal(
|
||||
content.sessionStorage.getItem("userContext"),
|
||||
arg.userContext,
|
||||
"Check the session storage value"
|
||||
);
|
||||
|
||||
// Check that the indexedDB has been set correctly.
|
||||
let request = content.indexedDB.open("idb", 1);
|
||||
// Check that the indexedDB has been set correctly.
|
||||
let request = content.indexedDB.open("idb", 1);
|
||||
|
||||
let db = await new Promise(done => {
|
||||
request.onsuccess = event => {
|
||||
done(event.target.result);
|
||||
};
|
||||
});
|
||||
let db = await new Promise(done => {
|
||||
request.onsuccess = event => {
|
||||
done(event.target.result);
|
||||
};
|
||||
});
|
||||
|
||||
let transaction = db.transaction(["obj"], "readonly");
|
||||
let store = transaction.objectStore("obj");
|
||||
let storeRequest = store.get(1);
|
||||
let transaction = db.transaction(["obj"], "readonly");
|
||||
let store = transaction.objectStore("obj");
|
||||
let storeRequest = store.get(1);
|
||||
|
||||
await new Promise(done => {
|
||||
storeRequest.onsuccess = event => {
|
||||
let res = storeRequest.result;
|
||||
Assert.equal(res.userContext, arg.userContext, "Check the indexedDB value");
|
||||
done();
|
||||
};
|
||||
});
|
||||
});
|
||||
await new Promise(done => {
|
||||
storeRequest.onsuccess = event => {
|
||||
let res = storeRequest.result;
|
||||
Assert.equal(
|
||||
res.userContext,
|
||||
arg.userContext,
|
||||
"Check the indexedDB value"
|
||||
);
|
||||
done();
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// Close this tab.
|
||||
BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
|
@ -270,15 +350,24 @@ async function test_storage_cleared() {
|
|||
// local storage has been cleared or not.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Open our tab in the given user context without setting local storage.
|
||||
let tabInfo = await openTabInUserContext(TEST_URL + "file_set_storages.html", userContextId);
|
||||
let tabInfo = await openTabInUserContext(
|
||||
TEST_URL + "file_set_storages.html",
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Check that do storages be cleared or not.
|
||||
await ContentTask.spawn(tabInfo.browser, null, async function() {
|
||||
// Check that does the local storage be cleared or not.
|
||||
Assert.ok(!content.localStorage.getItem("userContext"), "The local storage has been cleared");
|
||||
Assert.ok(
|
||||
!content.localStorage.getItem("userContext"),
|
||||
"The local storage has been cleared"
|
||||
);
|
||||
|
||||
// Check that does the session storage be cleared or not.
|
||||
Assert.ok(!content.sessionStorage.getItem("userContext"), "The session storage has been cleared");
|
||||
Assert.ok(
|
||||
!content.sessionStorage.getItem("userContext"),
|
||||
"The session storage has been cleared"
|
||||
);
|
||||
|
||||
// Check that does the indexedDB be cleared or not.
|
||||
let request = content.indexedDB.open("idb", 1);
|
||||
|
@ -292,7 +381,11 @@ async function test_storage_cleared() {
|
|||
db.transaction(["obj"], "readonly");
|
||||
Assert.ok(false, "The indexedDB should not exist");
|
||||
} catch (e) {
|
||||
Assert.equal(e.name, "NotFoundError", "The indexedDB does not exist as expected");
|
||||
Assert.equal(
|
||||
e.name,
|
||||
"NotFoundError",
|
||||
"The indexedDB does not exist as expected"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -303,9 +396,9 @@ async function test_storage_cleared() {
|
|||
|
||||
add_task(async function setup() {
|
||||
// Make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
|
||||
// Create a http server for the image cache test.
|
||||
if (!gHttpServer) {
|
||||
|
@ -324,8 +417,9 @@ let tests = [
|
|||
];
|
||||
|
||||
add_task(async function test() {
|
||||
for (let i = 0; i < tests.length; i++)
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
add_task(tests[i]);
|
||||
}
|
||||
});
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
let { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
|
||||
const NUM_USER_CONTEXTS = 3;
|
||||
|
||||
|
@ -18,7 +18,8 @@ function imageHandler(metadata, response) {
|
|||
response.setHeader("Cache-Control", "max-age=10000", false);
|
||||
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "image/png", false);
|
||||
var body = "iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=";
|
||||
var body =
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=";
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
|
@ -31,14 +32,16 @@ function fileHandler(metadata, response) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [["privacy.userContext.enabled", true]]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
// opens `uri' in a new tab with the provided userContextId and focuses it.
|
||||
// returns the newly opened tab
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// open the tab in the correct userContextId
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// select tab and make sure its browser is focused
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -50,9 +53,17 @@ async function openTabInUserContext(uri, userContextId) {
|
|||
}
|
||||
|
||||
add_task(async function test() {
|
||||
for (let userContextId = 0; userContextId < NUM_USER_CONTEXTS; userContextId++) {
|
||||
for (
|
||||
let userContextId = 0;
|
||||
userContextId < NUM_USER_CONTEXTS;
|
||||
userContextId++
|
||||
) {
|
||||
let tab = await openTabInUserContext(FILE_URI, userContextId);
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
is(gHits, NUM_USER_CONTEXTS, "should get an image request for each user contexts");
|
||||
is(
|
||||
gHits,
|
||||
NUM_USER_CONTEXTS,
|
||||
"should get an image request for each user contexts"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
const BASE_ORIGIN = "http://example.com";
|
||||
const URI = BASE_ORIGIN +
|
||||
const URI =
|
||||
BASE_ORIGIN +
|
||||
"/browser/browser/components/contextualidentity/test/browser/empty_file.html";
|
||||
|
||||
add_task(async function() {
|
||||
|
@ -14,23 +15,29 @@ add_task(async function() {
|
|||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
info("Create a HTMLAnchorElement...");
|
||||
await ContentTask.spawn(browser, URI,
|
||||
function(uri) {
|
||||
let anchor = content.document.createElement("a");
|
||||
anchor.setAttribute("id", "clickMe");
|
||||
anchor.setAttribute("href", uri);
|
||||
anchor.appendChild(content.document.createTextNode("click me!"));
|
||||
content.document.body.appendChild(anchor);
|
||||
}
|
||||
);
|
||||
await ContentTask.spawn(browser, URI, function(uri) {
|
||||
let anchor = content.document.createElement("a");
|
||||
anchor.setAttribute("id", "clickMe");
|
||||
anchor.setAttribute("href", uri);
|
||||
anchor.appendChild(content.document.createTextNode("click me!"));
|
||||
content.document.body.appendChild(anchor);
|
||||
});
|
||||
|
||||
info("Synthesize a mouse click and wait for a new tab...");
|
||||
let newTab = await new Promise((resolve, reject) => {
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", function(openEvent) {
|
||||
resolve(openEvent.target);
|
||||
}, {once: true});
|
||||
gBrowser.tabContainer.addEventListener(
|
||||
"TabOpen",
|
||||
function(openEvent) {
|
||||
resolve(openEvent.target);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
BrowserTestUtils.synthesizeMouseAtCenter("#clickMe", { button: 1 }, browser);
|
||||
BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"#clickMe",
|
||||
{ button: 1 },
|
||||
browser
|
||||
);
|
||||
});
|
||||
|
||||
is(newTab.getAttribute("usercontextid"), 1, "Correct UserContextId?");
|
||||
|
|
|
@ -8,25 +8,32 @@ function findPopup(browser = gBrowser) {
|
|||
}
|
||||
|
||||
add_task(async function test_menu_with_timeout() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
["privacy.userContext.longPressBehavior", 2],
|
||||
]});
|
||||
],
|
||||
});
|
||||
|
||||
let newTabButton = gBrowser.tabContainer.newTabButton;
|
||||
ok(newTabButton, "New tab button exists");
|
||||
ok(!newTabButton.hidden, "New tab button is visible");
|
||||
|
||||
await BrowserTestUtils.waitForCondition(() => !!findPopup(), "Wait for popup to exist");
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => !!findPopup(),
|
||||
"Wait for popup to exist"
|
||||
);
|
||||
|
||||
let popup = findPopup();
|
||||
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(newTabButton, {type: "mousedown"});
|
||||
EventUtils.synthesizeMouseAtCenter(newTabButton, { type: "mousedown" });
|
||||
|
||||
await popupShownPromise;
|
||||
let contextIdItem = popup.querySelector(`menuitem[data-usercontextid="${i}"]`);
|
||||
let contextIdItem = popup.querySelector(
|
||||
`menuitem[data-usercontextid="${i}"]`
|
||||
);
|
||||
|
||||
ok(contextIdItem, `User context id ${i} exists`);
|
||||
|
||||
|
@ -41,21 +48,26 @@ add_task(async function test_menu_with_timeout() {
|
|||
});
|
||||
|
||||
add_task(async function test_menu_without_timeout() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
["privacy.userContext.longPressBehavior", 1],
|
||||
]});
|
||||
],
|
||||
});
|
||||
|
||||
let newTabButton = gBrowser.tabContainer.newTabButton;
|
||||
ok(newTabButton, "New tab button exists");
|
||||
ok(!newTabButton.hidden, "New tab button is visible");
|
||||
|
||||
await BrowserTestUtils.waitForCondition(() => !!findPopup(), "Wait for popup to exist");
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => !!findPopup(),
|
||||
"Wait for popup to exist"
|
||||
);
|
||||
let popup = findPopup();
|
||||
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(popup, "popuphidden");
|
||||
EventUtils.synthesizeMouseAtCenter(newTabButton, {type: "mousedown"});
|
||||
EventUtils.synthesizeMouseAtCenter(newTabButton, { type: "mousedown" });
|
||||
await popupShownPromise;
|
||||
let contextIdItems = popup.querySelectorAll("menuitem");
|
||||
// 4 + default + manage containers
|
||||
|
@ -65,15 +77,20 @@ add_task(async function test_menu_without_timeout() {
|
|||
|
||||
for (let i = 0; i <= 4; i++) {
|
||||
popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(newTabButton, {type: "mousedown"});
|
||||
EventUtils.synthesizeMouseAtCenter(newTabButton, { type: "mousedown" });
|
||||
|
||||
await popupShownPromise;
|
||||
let contextIdItem = popup.querySelector(`menuitem[data-usercontextid="${i}"]`);
|
||||
let contextIdItem = popup.querySelector(
|
||||
`menuitem[data-usercontextid="${i}"]`
|
||||
);
|
||||
|
||||
ok(contextIdItem, `User context id ${i} exists`);
|
||||
|
||||
// waitForNewTab doesn't work for default tabs due to a different code path that doesn't cause a load event
|
||||
let waitForTabPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
|
||||
let waitForTabPromise = BrowserTestUtils.waitForEvent(
|
||||
gBrowser.tabContainer,
|
||||
"TabOpen"
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(contextIdItem, {});
|
||||
|
||||
let tabEvent = await waitForTabPromise;
|
||||
|
@ -88,10 +105,12 @@ add_task(async function test_menu_without_timeout() {
|
|||
});
|
||||
|
||||
add_task(async function test_no_menu() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
["privacy.userContext.longPressBehavior", 0],
|
||||
]});
|
||||
],
|
||||
});
|
||||
|
||||
let newTabButton = gBrowser.tabContainer.newTabButton;
|
||||
ok(newTabButton, "New tab button exists");
|
||||
|
@ -101,9 +120,11 @@ add_task(async function test_no_menu() {
|
|||
});
|
||||
|
||||
add_task(async function test_private_mode() {
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({
|
||||
private: true,
|
||||
});
|
||||
let privateDocument = privateWindow.document;
|
||||
let {tabContainer} = privateWindow.gBrowser;
|
||||
let { tabContainer } = privateWindow.gBrowser;
|
||||
let newTab = tabContainer.newTabButton;
|
||||
let newTab2 = privateDocument.getElementById("new-tab-button");
|
||||
// Check to ensure we are talking about the right button
|
||||
|
@ -113,4 +134,3 @@ add_task(async function test_private_mode() {
|
|||
ok(!popup, "new tab should not have a popup");
|
||||
await BrowserTestUtils.closeWindow(privateWindow);
|
||||
});
|
||||
|
||||
|
|
|
@ -5,33 +5,69 @@
|
|||
*/
|
||||
|
||||
add_task(async function() {
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:blank", {userContextId: 1});
|
||||
let ReferrerInfo = Components.Constructor("@mozilla.org/referrer-info;1",
|
||||
"nsIReferrerInfo",
|
||||
"init");
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:blank", {
|
||||
userContextId: 1,
|
||||
});
|
||||
let ReferrerInfo = Components.Constructor(
|
||||
"@mozilla.org/referrer-info;1",
|
||||
"nsIReferrerInfo",
|
||||
"init"
|
||||
);
|
||||
|
||||
gBrowser.selectedTab = tab;
|
||||
let relatedTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {relatedToCurrent: true});
|
||||
is(relatedTab.getAttribute("usercontextid"), 1, "Related tab (relatedToCurrent) inherits current tab's usercontextid");
|
||||
let relatedTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {
|
||||
relatedToCurrent: true,
|
||||
});
|
||||
is(
|
||||
relatedTab.getAttribute("usercontextid"),
|
||||
1,
|
||||
"Related tab (relatedToCurrent) inherits current tab's usercontextid"
|
||||
);
|
||||
BrowserTestUtils.removeTab(relatedTab);
|
||||
|
||||
gBrowser.selectedTab = tab;
|
||||
relatedTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {relatedToCurrent: true, userContextId: 2});
|
||||
is(relatedTab.getAttribute("usercontextid"), 2, "Related tab (relatedToCurrent) with overridden usercontextid");
|
||||
relatedTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {
|
||||
relatedToCurrent: true,
|
||||
userContextId: 2,
|
||||
});
|
||||
is(
|
||||
relatedTab.getAttribute("usercontextid"),
|
||||
2,
|
||||
"Related tab (relatedToCurrent) with overridden usercontextid"
|
||||
);
|
||||
BrowserTestUtils.removeTab(relatedTab);
|
||||
|
||||
gBrowser.selectedTab = tab;
|
||||
let referrerInfo = new ReferrerInfo(
|
||||
Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, gBrowser.currentURI);
|
||||
relatedTab = BrowserTestUtils.addTab(gBrowser, "about:blank", { referrerInfo });
|
||||
is(relatedTab.getAttribute("usercontextid"), 1, "Related tab (referrer) inherits current tab's usercontextid");
|
||||
Ci.nsIHttpChannel.REFERRER_POLICY_UNSET,
|
||||
true,
|
||||
gBrowser.currentURI
|
||||
);
|
||||
relatedTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {
|
||||
referrerInfo,
|
||||
});
|
||||
is(
|
||||
relatedTab.getAttribute("usercontextid"),
|
||||
1,
|
||||
"Related tab (referrer) inherits current tab's usercontextid"
|
||||
);
|
||||
BrowserTestUtils.removeTab(relatedTab);
|
||||
|
||||
gBrowser.selectedTab = tab;
|
||||
referrerInfo = new ReferrerInfo(
|
||||
Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, gBrowser.currentURI);
|
||||
relatedTab = BrowserTestUtils.addTab(gBrowser, "about:blank", { referrerInfo, userContextId: 2});
|
||||
is(relatedTab.getAttribute("usercontextid"), 2, "Related tab (referrer) with overridden usercontextid");
|
||||
Ci.nsIHttpChannel.REFERRER_POLICY_UNSET,
|
||||
true,
|
||||
gBrowser.currentURI
|
||||
);
|
||||
relatedTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {
|
||||
referrerInfo,
|
||||
userContextId: 2,
|
||||
});
|
||||
is(
|
||||
relatedTab.getAttribute("usercontextid"),
|
||||
2,
|
||||
"Related tab (referrer) with overridden usercontextid"
|
||||
);
|
||||
BrowserTestUtils.removeTab(relatedTab);
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
"use strict";
|
||||
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_URL = "http://" + TEST_HOST + "/browser/browser/components/contextualidentity/test/browser/";
|
||||
const TEST_URL =
|
||||
"http://" +
|
||||
TEST_HOST +
|
||||
"/browser/browser/components/contextualidentity/test/browser/";
|
||||
|
||||
async function openTabMenuFor(tab) {
|
||||
let tabMenu = tab.ownerDocument.getElementById("tabContextMenu");
|
||||
|
||||
let tabMenuShown = BrowserTestUtils.waitForEvent(tabMenu, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(tab, {type: "contextmenu"},
|
||||
tab.ownerGlobal);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
tab,
|
||||
{ type: "contextmenu" },
|
||||
tab.ownerGlobal
|
||||
);
|
||||
await tabMenuShown;
|
||||
|
||||
return tabMenu;
|
||||
|
@ -17,13 +23,18 @@ async function openTabMenuFor(tab) {
|
|||
async function openReopenMenuForTab(tab) {
|
||||
openTabMenuFor(tab);
|
||||
|
||||
let reopenItem = tab.ownerDocument.getElementById("context_reopenInContainer");
|
||||
let reopenItem = tab.ownerDocument.getElementById(
|
||||
"context_reopenInContainer"
|
||||
);
|
||||
ok(!reopenItem.hidden, "Reopen in Container item should be shown");
|
||||
|
||||
let reopenMenu = reopenItem.getElementsByTagName("menupopup")[0];
|
||||
let reopenMenuShown = BrowserTestUtils.waitForEvent(reopenMenu, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(reopenItem, {type: "mousemove"},
|
||||
tab.ownerGlobal);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
reopenItem,
|
||||
{ type: "mousemove" },
|
||||
tab.ownerGlobal
|
||||
);
|
||||
await reopenMenuShown;
|
||||
|
||||
return reopenMenu;
|
||||
|
@ -31,52 +42,72 @@ async function openReopenMenuForTab(tab) {
|
|||
|
||||
function checkMenuItem(reopenMenu, shown, hidden) {
|
||||
for (let id of shown) {
|
||||
ok(reopenMenu.querySelector(`menuitem[data-usercontextid="${id}"]`),
|
||||
`User context id ${id} should exist`);
|
||||
ok(
|
||||
reopenMenu.querySelector(`menuitem[data-usercontextid="${id}"]`),
|
||||
`User context id ${id} should exist`
|
||||
);
|
||||
}
|
||||
for (let id of hidden) {
|
||||
ok(!reopenMenu.querySelector(`menuitem[data-usercontextid="${id}"]`),
|
||||
`User context id ${id} shouldn't exist`);
|
||||
ok(
|
||||
!reopenMenu.querySelector(`menuitem[data-usercontextid="${id}"]`),
|
||||
`User context id ${id} shouldn't exist`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function openTabInContainer(gBrowser, reopenMenu, id) {
|
||||
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, TEST_URL, true);
|
||||
let menuitem = reopenMenu.querySelector(`menuitem[data-usercontextid="${id}"]`);
|
||||
let menuitem = reopenMenu.querySelector(
|
||||
`menuitem[data-usercontextid="${id}"]`
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(menuitem, {}, menuitem.ownerGlobal);
|
||||
return tabPromise;
|
||||
}
|
||||
|
||||
add_task(async function testReopen() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: TEST_URL,
|
||||
});
|
||||
ok(!tab.hasAttribute("usercontextid"), "Tab with No Container should be opened");
|
||||
ok(
|
||||
!tab.hasAttribute("usercontextid"),
|
||||
"Tab with No Container should be opened"
|
||||
);
|
||||
|
||||
let reopenMenu = await openReopenMenuForTab(tab);
|
||||
checkMenuItem(reopenMenu, [1, 2, 3, 4], [0]);
|
||||
|
||||
let containerTab = await openTabInContainer(gBrowser, reopenMenu, "1");
|
||||
|
||||
is(containerTab.getAttribute("usercontextid"), "1",
|
||||
"Tab with UCI=1 should be opened");
|
||||
is(containerTab.linkedBrowser.currentURI.spec, TEST_URL,
|
||||
"Same page should be opened");
|
||||
is(
|
||||
containerTab.getAttribute("usercontextid"),
|
||||
"1",
|
||||
"Tab with UCI=1 should be opened"
|
||||
);
|
||||
is(
|
||||
containerTab.linkedBrowser.currentURI.spec,
|
||||
TEST_URL,
|
||||
"Same page should be opened"
|
||||
);
|
||||
|
||||
reopenMenu = await openReopenMenuForTab(containerTab);
|
||||
checkMenuItem(reopenMenu, [0, 2, 3, 4], [1]);
|
||||
|
||||
let noContainerTab = await openTabInContainer(gBrowser, reopenMenu, "0");
|
||||
|
||||
ok(!noContainerTab.hasAttribute("usercontextid"),
|
||||
"Tab with no UCI should be opened");
|
||||
is(noContainerTab.linkedBrowser.currentURI.spec, TEST_URL,
|
||||
"Same page should be opened");
|
||||
ok(
|
||||
!noContainerTab.hasAttribute("usercontextid"),
|
||||
"Tab with no UCI should be opened"
|
||||
);
|
||||
is(
|
||||
noContainerTab.linkedBrowser.currentURI.spec,
|
||||
TEST_URL,
|
||||
"Same page should be opened"
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
BrowserTestUtils.removeTab(containerTab);
|
||||
|
@ -84,15 +115,18 @@ add_task(async function testReopen() {
|
|||
});
|
||||
|
||||
add_task(async function testDisabled() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", false],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", false]],
|
||||
});
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: TEST_URL,
|
||||
});
|
||||
ok(!tab.hasAttribute("usercontextid"), "Tab with No Container should be opened");
|
||||
ok(
|
||||
!tab.hasAttribute("usercontextid"),
|
||||
"Tab with No Container should be opened"
|
||||
);
|
||||
|
||||
openTabMenuFor(tab);
|
||||
let reopenItem = document.getElementById("context_reopenInContainer");
|
||||
|
@ -105,19 +139,26 @@ add_task(async function testDisabled() {
|
|||
});
|
||||
|
||||
add_task(async function testPrivateMode() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({
|
||||
private: true,
|
||||
});
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser: privateWindow.gBrowser,
|
||||
url: TEST_URL,
|
||||
});
|
||||
ok(!tab.hasAttribute("usercontextid"), "Tab with No Container should be opened");
|
||||
ok(
|
||||
!tab.hasAttribute("usercontextid"),
|
||||
"Tab with No Container should be opened"
|
||||
);
|
||||
|
||||
openTabMenuFor(tab);
|
||||
let reopenItem = privateWindow.document.getElementById("context_reopenInContainer");
|
||||
let reopenItem = privateWindow.document.getElementById(
|
||||
"context_reopenInContainer"
|
||||
);
|
||||
ok(reopenItem.hidden, "Reopen in Container item should be hidden");
|
||||
|
||||
// Close the tab menu.
|
||||
|
|
|
@ -5,13 +5,12 @@
|
|||
const CC = Components.Constructor;
|
||||
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_URL = "http://" + TEST_HOST + "/browser/browser/components/contextualidentity/test/browser/";
|
||||
const TEST_URL =
|
||||
"http://" +
|
||||
TEST_HOST +
|
||||
"/browser/browser/components/contextualidentity/test/browser/";
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
"work",
|
||||
];
|
||||
const USER_CONTEXTS = ["default", "personal", "work"];
|
||||
|
||||
const DELETE_CONTEXT = 1;
|
||||
const COOKIE_NAME = "userContextId";
|
||||
|
@ -22,7 +21,7 @@ const COOKIE_NAME = "userContextId";
|
|||
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -30,11 +29,11 @@ async function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
function getCookiesForOA(host, userContextId) {
|
||||
return Services.cookies.getCookiesFromHost(host, {userContextId});
|
||||
return Services.cookies.getCookiesFromHost(host, { userContextId });
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -43,9 +42,9 @@ function getCookiesForOA(host, userContextId) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// Make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
[ "privacy.userContext.enabled", true ],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
function checkCookies(ignoreContext = null) {
|
||||
|
@ -65,9 +64,18 @@ function checkCookies(ignoreContext = null) {
|
|||
function deleteCookies(onlyContext = null) {
|
||||
// Using getCookiesWithOriginAttributes() to get all cookies for a certain
|
||||
// domain by using the originAttributes pattern, and clear all these cookies.
|
||||
for (let cookie of Services.cookies.getCookiesWithOriginAttributes(JSON.stringify({}), TEST_HOST)) {
|
||||
for (let cookie of Services.cookies.getCookiesWithOriginAttributes(
|
||||
JSON.stringify({}),
|
||||
TEST_HOST
|
||||
)) {
|
||||
if (!onlyContext || cookie.originAttributes.userContextId == onlyContext) {
|
||||
Services.cookies.remove(cookie.host, cookie.name, cookie.path, false, cookie.originAttributes);
|
||||
Services.cookies.remove(
|
||||
cookie.host,
|
||||
cookie.name,
|
||||
cookie.path,
|
||||
false,
|
||||
cookie.originAttributes
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +89,10 @@ add_task(async function test_cookie_getCookiesWithOriginAttributes() {
|
|||
let value = USER_CONTEXTS[userContextId];
|
||||
|
||||
// Open our tab in the given user context.
|
||||
tabs[userContextId] = await openTabInUserContext(TEST_URL + "file_reflect_cookie_into_title.html?" + value, userContextId);
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
TEST_URL + "file_reflect_cookie_into_title.html?" + value,
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Close this tab.
|
||||
BrowserTestUtils.removeTab(tabs[userContextId].tab);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
const BASE_ORIGIN = "https://example.com";
|
||||
const URI = BASE_ORIGIN +
|
||||
const URI =
|
||||
BASE_ORIGIN +
|
||||
"/browser/browser/components/contextualidentity/test/browser/saveLink.sjs";
|
||||
|
||||
let MockFilePicker = SpecialPowers.MockFilePicker;
|
||||
|
@ -11,9 +12,9 @@ add_task(async function setup() {
|
|||
info("Setting the prefs.");
|
||||
|
||||
// make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
|
@ -21,7 +22,9 @@ add_task(async function test() {
|
|||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
info("Opening tab with UCI: 1");
|
||||
let tab = BrowserTestUtils.addTab(win.gBrowser, URI + "?UCI=1", {userContextId: 1});
|
||||
let tab = BrowserTestUtils.addTab(win.gBrowser, URI + "?UCI=1", {
|
||||
userContextId: 1,
|
||||
});
|
||||
|
||||
// select tab and make sure its browser is focused
|
||||
win.gBrowser.selectedTab = tab;
|
||||
|
@ -31,10 +34,16 @@ add_task(async function test() {
|
|||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(win.document, "popupshown");
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(
|
||||
win.document,
|
||||
"popupshown"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("#fff", {type: "contextmenu", button: 2},
|
||||
win.gBrowser.selectedBrowser);
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"#fff",
|
||||
{ type: "contextmenu", button: 2 },
|
||||
win.gBrowser.selectedBrowser
|
||||
);
|
||||
info("Right clicked!");
|
||||
|
||||
await popupShownPromise;
|
||||
|
@ -58,7 +67,7 @@ add_task(async function test() {
|
|||
info("MockFilePicker showCallback done");
|
||||
};
|
||||
|
||||
let transferCompletePromise = new Promise((resolve) => {
|
||||
let transferCompletePromise = new Promise(resolve => {
|
||||
function onTransferComplete(downloadSuccess) {
|
||||
ok(downloadSuccess, "File should have been downloaded successfully");
|
||||
resolve();
|
||||
|
@ -80,7 +89,10 @@ add_task(async function test() {
|
|||
saveLinkCommand.doCommand();
|
||||
|
||||
let contextMenu = win.document.getElementById("contentAreaContextMenu");
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(
|
||||
contextMenu,
|
||||
"popuphidden"
|
||||
);
|
||||
contextMenu.hidePopup();
|
||||
await popupHiddenPromise;
|
||||
info("popup hidden");
|
||||
|
@ -97,7 +109,10 @@ add_task(async function test() {
|
|||
});
|
||||
|
||||
/* import-globals-from ../../../../../toolkit/content/tests/browser/common/mockTransfer.js */
|
||||
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js", this);
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js",
|
||||
this
|
||||
);
|
||||
|
||||
function createTemporarySaveDirectory() {
|
||||
let saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
let swm = Cc["@mozilla.org/serviceworkers/manager;1"].
|
||||
getService(Ci.nsIServiceWorkerManager);
|
||||
let swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService(
|
||||
Ci.nsIServiceWorkerManager
|
||||
);
|
||||
|
||||
const BASE_ORIGIN = "https://example.com";
|
||||
const URI = BASE_ORIGIN +
|
||||
const URI =
|
||||
BASE_ORIGIN +
|
||||
"/browser/browser/components/contextualidentity/test/browser/serviceworker.html";
|
||||
const NUM_USER_CONTEXTS = 3;
|
||||
|
||||
|
@ -10,7 +12,7 @@ const NUM_USER_CONTEXTS = 3;
|
|||
// returns the newly opened tab
|
||||
function openTabInUserContext(uri, userContextId) {
|
||||
// open the tab in the correct userContextId
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// select tab and make sure its browser is focused
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -21,10 +23,9 @@ function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
["dom.ipc.processCount", 1],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true], ["dom.ipc.processCount", 1]],
|
||||
});
|
||||
});
|
||||
|
||||
let infos = [];
|
||||
|
@ -32,7 +33,11 @@ let infos = [];
|
|||
add_task(async function test() {
|
||||
// Open the same URI in multiple user contexts, and make sure we have a
|
||||
// separate service worker in each of the contexts
|
||||
for (let userContextId = 0; userContextId < NUM_USER_CONTEXTS; userContextId++) {
|
||||
for (
|
||||
let userContextId = 0;
|
||||
userContextId < NUM_USER_CONTEXTS;
|
||||
userContextId++
|
||||
) {
|
||||
// Open a tab in given user contexts
|
||||
let tab = openTabInUserContext(URI, userContextId);
|
||||
|
||||
|
@ -58,14 +63,21 @@ function allRegistered() {
|
|||
let results = [];
|
||||
let registrations = swm.getAllRegistrations();
|
||||
for (let i = 0; i < registrations.length; i++) {
|
||||
let info = registrations.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
|
||||
let info = registrations.queryElementAt(
|
||||
i,
|
||||
Ci.nsIServiceWorkerRegistrationInfo
|
||||
);
|
||||
let principal = info.principal;
|
||||
if (principal.originNoSuffix === BASE_ORIGIN) {
|
||||
results[principal.userContextId] = true;
|
||||
infos[principal.userContextId] = info;
|
||||
}
|
||||
}
|
||||
for (let userContextId = 0; userContextId < NUM_USER_CONTEXTS; userContextId++) {
|
||||
for (
|
||||
let userContextId = 0;
|
||||
userContextId < NUM_USER_CONTEXTS;
|
||||
userContextId++
|
||||
) {
|
||||
if (!results[userContextId]) {
|
||||
return false;
|
||||
}
|
||||
|
@ -89,14 +101,18 @@ function promiseAllRegistered() {
|
|||
|
||||
function promiseUnregister(info) {
|
||||
return new Promise(function(resolve) {
|
||||
swm.unregister(info.principal, {
|
||||
unregisterSucceeded(aState) {
|
||||
ok(aState, "ServiceWorkerRegistration exists");
|
||||
resolve();
|
||||
swm.unregister(
|
||||
info.principal,
|
||||
{
|
||||
unregisterSucceeded(aState) {
|
||||
ok(aState, "ServiceWorkerRegistration exists");
|
||||
resolve();
|
||||
},
|
||||
unregisterFailed(aState) {
|
||||
ok(false, "unregister should succeed");
|
||||
},
|
||||
},
|
||||
unregisterFailed(aState) {
|
||||
ok(false, "unregister should succeed");
|
||||
},
|
||||
}, info.scope);
|
||||
info.scope
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const USER_CONTEXTS = ["default", "personal", "work"];
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
"work",
|
||||
];
|
||||
|
||||
const BASE_URI = "http://mochi.test:8888/browser/browser/components/"
|
||||
+ "contextualidentity/test/browser/file_reflect_cookie_into_title.html";
|
||||
|
||||
const BASE_URI =
|
||||
"http://mochi.test:8888/browser/browser/components/" +
|
||||
"contextualidentity/test/browser/file_reflect_cookie_into_title.html";
|
||||
|
||||
// opens `uri' in a new tab with the provided userContextId and focuses it.
|
||||
// returns the newly opened tab
|
||||
function openTabInUserContext(uri, userContextId) {
|
||||
// open the tab in the correct userContextId
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, {userContextId});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// select tab and make sure its browser is focused
|
||||
gBrowser.selectedTab = tab;
|
||||
|
@ -27,10 +22,9 @@ function openTabInUserContext(uri, userContextId) {
|
|||
|
||||
add_task(async function setup() {
|
||||
// make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
["dom.ipc.processCount", 1],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true], ["dom.ipc.processCount", 1]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
|
@ -74,9 +68,16 @@ add_task(async function test() {
|
|||
// check each item in the title and validate it meets expectatations
|
||||
for (let part of title) {
|
||||
let [storageMethodName, value] = part.split("=");
|
||||
is(value, expectedContext,
|
||||
"the title reflects the expected contextual identity of " +
|
||||
expectedContext + " for method " + storageMethodName + ": " + value);
|
||||
is(
|
||||
value,
|
||||
expectedContext,
|
||||
"the title reflects the expected contextual identity of " +
|
||||
expectedContext +
|
||||
" for method " +
|
||||
storageMethodName +
|
||||
": " +
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
// Test that the content of new browser windows have the expected
|
||||
// userContextId when it passed as the window arguments.
|
||||
|
||||
const TEST_URI = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://mochi.test:8888") + "empty_file.html";
|
||||
const TEST_URI =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"http://mochi.test:8888"
|
||||
) + "empty_file.html";
|
||||
|
||||
function openWindowWithUserContextId(userContextId, isPrivate) {
|
||||
let flags = "chrome,dialog=no,all";
|
||||
|
@ -16,7 +20,9 @@ function openWindowWithUserContextId(userContextId, isPrivate) {
|
|||
|
||||
let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
|
||||
let urlSupports = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
|
||||
let urlSupports = Cc["@mozilla.org/supports-string;1"].createInstance(
|
||||
Ci.nsISupportsString
|
||||
);
|
||||
urlSupports.data = TEST_URI;
|
||||
args.appendElement(urlSupports);
|
||||
|
||||
|
@ -25,7 +31,9 @@ function openWindowWithUserContextId(userContextId, isPrivate) {
|
|||
args.appendElement(null);
|
||||
args.appendElement(null);
|
||||
|
||||
let userContextIdSupports = Cc["@mozilla.org/supports-PRUint32;1"].createInstance(Ci.nsISupportsPRUint32);
|
||||
let userContextIdSupports = Cc[
|
||||
"@mozilla.org/supports-PRUint32;1"
|
||||
].createInstance(Ci.nsISupportsPRUint32);
|
||||
userContextIdSupports.data = userContextId;
|
||||
args.appendElement(userContextIdSupports);
|
||||
|
||||
|
@ -33,25 +41,35 @@ function openWindowWithUserContextId(userContextId, isPrivate) {
|
|||
args.appendElement(Services.scriptSecurityManager.getSystemPrincipal());
|
||||
args.appendElement(Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
let windowPromise = BrowserTestUtils.waitForNewWindow({url: TEST_URI});
|
||||
Services.ww.openWindow(null, AppConstants.BROWSER_CHROME_URL, "_blank", flags, args);
|
||||
let windowPromise = BrowserTestUtils.waitForNewWindow({ url: TEST_URI });
|
||||
Services.ww.openWindow(
|
||||
null,
|
||||
AppConstants.BROWSER_CHROME_URL,
|
||||
"_blank",
|
||||
flags,
|
||||
args
|
||||
);
|
||||
return windowPromise;
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.userContext.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_new_window() {
|
||||
let win = await openWindowWithUserContextId(1, false);
|
||||
|
||||
await ContentTask.spawn(win.gBrowser.selectedBrowser, TEST_URI, (url) => {
|
||||
await ContentTask.spawn(win.gBrowser.selectedBrowser, TEST_URI, url => {
|
||||
Assert.equal(content.document.URL, url, "expected document URL");
|
||||
let {originAttributes} = content.document.nodePrincipal;
|
||||
let { originAttributes } = content.document.nodePrincipal;
|
||||
Assert.equal(originAttributes.userContextId, 1, "expected userContextId");
|
||||
Assert.equal(originAttributes.privateBrowsingId, 0, "expected non-private context");
|
||||
Assert.equal(
|
||||
originAttributes.privateBrowsingId,
|
||||
0,
|
||||
"expected non-private context"
|
||||
);
|
||||
});
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
@ -60,11 +78,15 @@ add_task(async function test_new_window() {
|
|||
add_task(async function test_new_private_window() {
|
||||
let win = await openWindowWithUserContextId(1, true);
|
||||
|
||||
await ContentTask.spawn(win.gBrowser.selectedBrowser, TEST_URI, (url) => {
|
||||
await ContentTask.spawn(win.gBrowser.selectedBrowser, TEST_URI, url => {
|
||||
Assert.equal(content.document.URL, url, "expected document URL");
|
||||
let {originAttributes} = content.document.nodePrincipal;
|
||||
let { originAttributes } = content.document.nodePrincipal;
|
||||
Assert.equal(originAttributes.userContextId, 1, "expected userContextId");
|
||||
Assert.equal(originAttributes.privateBrowsingId, 1, "expected private context");
|
||||
Assert.equal(
|
||||
originAttributes.privateBrowsingId,
|
||||
1,
|
||||
"expected private context"
|
||||
);
|
||||
});
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
let EventUtils = {};
|
||||
Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
|
||||
EventUtils
|
||||
);
|
||||
|
||||
/**
|
||||
* Dragging an URL to a tab without userContextId set.
|
||||
|
@ -11,7 +14,11 @@ add_task(async function() {
|
|||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
let awaitDrop = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "drop");
|
||||
let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "http://test1.example.com/", true);
|
||||
let newTabPromise = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
"http://test1.example.com/",
|
||||
true
|
||||
);
|
||||
|
||||
// A drop type of "link" onto an existing tab would normally trigger a
|
||||
// load in that same tab, but tabbrowser code in _getDragTargetTab treats
|
||||
|
@ -25,16 +32,30 @@ add_task(async function() {
|
|||
screenX: 0,
|
||||
screenY: 0,
|
||||
};
|
||||
EventUtils.synthesizeDrop(tab, tab, [[{type: "text/plain", data: "http://test1.example.com/"}]], "link", window, undefined, event);
|
||||
EventUtils.synthesizeDrop(
|
||||
tab,
|
||||
tab,
|
||||
[[{ type: "text/plain", data: "http://test1.example.com/" }]],
|
||||
"link",
|
||||
window,
|
||||
undefined,
|
||||
event
|
||||
);
|
||||
|
||||
await awaitDrop;
|
||||
|
||||
let tab2 = await newTabPromise;
|
||||
Assert.ok(!tab2.hasAttribute("usercontextid"), "Tab shouldn't have usercontextid attribute");
|
||||
Assert.ok(
|
||||
!tab2.hasAttribute("usercontextid"),
|
||||
"Tab shouldn't have usercontextid attribute"
|
||||
);
|
||||
|
||||
await ContentTask.spawn(tab2.linkedBrowser, {}, async function() {
|
||||
Assert.equal(content.document.documentURI, "http://test1.example.com/");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.userContextId, 0);
|
||||
Assert.equal(
|
||||
content.document.nodePrincipal.originAttributes.userContextId,
|
||||
0
|
||||
);
|
||||
|
||||
// referrer is empty when urls are dragged to new or existing tabs.
|
||||
// If this changes in the future, it would be okay to send the referrer
|
||||
|
@ -52,11 +73,17 @@ add_task(async function() {
|
|||
* userContextId as the original tab.
|
||||
*/
|
||||
add_task(async function() {
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com/", {userContextId: 1});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com/", {
|
||||
userContextId: 1,
|
||||
});
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
let awaitDrop = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "drop");
|
||||
let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "http://test1.example.com/", true);
|
||||
let newTabPromise = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
"http://test1.example.com/",
|
||||
true
|
||||
);
|
||||
|
||||
// A drop type of "link" onto an existing tab would normally trigger a
|
||||
// load in that same tab, but tabbrowser code in _getDragTargetTab treats
|
||||
|
@ -70,7 +97,15 @@ add_task(async function() {
|
|||
screenX: 0,
|
||||
screenY: 0,
|
||||
};
|
||||
EventUtils.synthesizeDrop(tab, tab, [[{type: "text/plain", data: "http://test1.example.com/"}]], "link", window, undefined, event);
|
||||
EventUtils.synthesizeDrop(
|
||||
tab,
|
||||
tab,
|
||||
[[{ type: "text/plain", data: "http://test1.example.com/" }]],
|
||||
"link",
|
||||
window,
|
||||
undefined,
|
||||
event
|
||||
);
|
||||
|
||||
await awaitDrop;
|
||||
|
||||
|
@ -79,7 +114,10 @@ add_task(async function() {
|
|||
|
||||
await ContentTask.spawn(tab2.linkedBrowser, {}, async function() {
|
||||
Assert.equal(content.document.documentURI, "http://test1.example.com/");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.userContextId, 1);
|
||||
Assert.equal(
|
||||
content.document.nodePrincipal.originAttributes.userContextId,
|
||||
1
|
||||
);
|
||||
|
||||
// referrer is empty when urls are dragged to new or existing tabs.
|
||||
// If this changes in the future, it would be okay to send the referrer
|
||||
|
@ -99,15 +137,25 @@ add_task(async function() {
|
|||
* userContext 2, the link will open in tab 2 with userContext 2.
|
||||
*/
|
||||
add_task(async function() {
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com/", {userContextId: 1});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com/", {
|
||||
userContextId: 1,
|
||||
});
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
let tab2 = BrowserTestUtils.addTab(gBrowser, "http://example.org/", {userContextId: 2});
|
||||
let tab2 = BrowserTestUtils.addTab(gBrowser, "http://example.org/", {
|
||||
userContextId: 2,
|
||||
});
|
||||
await BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
|
||||
|
||||
let awaitDrop = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "drop");
|
||||
|
||||
EventUtils.synthesizeDrop(tab, tab2, [[{type: "text/plain", data: "http://test1.example.com/"}]], "link", window);
|
||||
EventUtils.synthesizeDrop(
|
||||
tab,
|
||||
tab2,
|
||||
[[{ type: "text/plain", data: "http://test1.example.com/" }]],
|
||||
"link",
|
||||
window
|
||||
);
|
||||
|
||||
await awaitDrop;
|
||||
Assert.equal(tab2.getAttribute("usercontextid"), 2);
|
||||
|
@ -116,7 +164,10 @@ add_task(async function() {
|
|||
|
||||
await ContentTask.spawn(tab2.linkedBrowser, {}, async function() {
|
||||
Assert.equal(content.document.documentURI, "http://test1.example.com/");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.userContextId, 2);
|
||||
Assert.equal(
|
||||
content.document.nodePrincipal.originAttributes.userContextId,
|
||||
2
|
||||
);
|
||||
|
||||
// referrer is empty when urls are dragged to new or existing tabs.
|
||||
// If this changes in the future, we should ensure that we are not sending
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const USER_CONTEXTS = ["default", "personal", "work"];
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
"work",
|
||||
];
|
||||
|
||||
const BASE_URI = "http://mochi.test:8888/browser/browser/components/"
|
||||
+ "contextualidentity/test/browser/empty_file.html";
|
||||
const BASE_URI =
|
||||
"http://mochi.test:8888/browser/browser/components/" +
|
||||
"contextualidentity/test/browser/empty_file.html";
|
||||
|
||||
add_task(async function setup() {
|
||||
// make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
["browser.link.open_newwindow", 3],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
["browser.link.open_newwindow", 3],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
info("Creating first tab...");
|
||||
let tab1 = BrowserTestUtils.addTab(gBrowser, BASE_URI + "?old", {userContextId: 1});
|
||||
let tab1 = BrowserTestUtils.addTab(gBrowser, BASE_URI + "?old", {
|
||||
userContextId: 1,
|
||||
});
|
||||
let browser1 = gBrowser.getBrowserForTab(tab1);
|
||||
await BrowserTestUtils.browserLoaded(browser1);
|
||||
await ContentTask.spawn(browser1, null, function(opts) {
|
||||
|
@ -29,7 +29,9 @@ add_task(async function test() {
|
|||
});
|
||||
|
||||
info("Creating second tab...");
|
||||
let tab2 = BrowserTestUtils.addTab(gBrowser, BASE_URI + "?old", {userContextId: 2});
|
||||
let tab2 = BrowserTestUtils.addTab(gBrowser, BASE_URI + "?old", {
|
||||
userContextId: 2,
|
||||
});
|
||||
let browser2 = gBrowser.getBrowserForTab(tab2);
|
||||
await BrowserTestUtils.browserLoaded(browser2);
|
||||
await ContentTask.spawn(browser2, null, function(opts) {
|
||||
|
@ -38,11 +40,15 @@ add_task(async function test() {
|
|||
|
||||
// Let's try to open a window from tab1 with a name 'tab-2'.
|
||||
info("Opening a window from the first tab...");
|
||||
await ContentTask.spawn(browser1, { url: BASE_URI + "?new" }, async function(opts) {
|
||||
await (new content.window.wrappedJSObject.Promise(resolve => {
|
||||
await ContentTask.spawn(browser1, { url: BASE_URI + "?new" }, async function(
|
||||
opts
|
||||
) {
|
||||
await new content.window.wrappedJSObject.Promise(resolve => {
|
||||
let w = content.window.wrappedJSObject.open(opts.url, "tab-2");
|
||||
w.onload = function() { resolve(); };
|
||||
}));
|
||||
w.onload = function() {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
is(browser1.contentTitle, "?old", "Tab1 title must be 'old'");
|
||||
|
|
|
@ -3,27 +3,29 @@
|
|||
// Here we want to test that a new opened window shows the same UI of the
|
||||
// parent one if this has been loaded from a particular container.
|
||||
|
||||
const BASE_URI = "http://mochi.test:8888/browser/browser/components/"
|
||||
+ "contextualidentity/test/browser/empty_file.html";
|
||||
const BASE_URI =
|
||||
"http://mochi.test:8888/browser/browser/components/" +
|
||||
"contextualidentity/test/browser/empty_file.html";
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
["browser.link.open_newwindow", 2],
|
||||
]});
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
["browser.link.open_newwindow", 2],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
add_task(async function test() {
|
||||
info("Creating a tab with UCI = 1...");
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, BASE_URI, {userContextId: 1});
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, BASE_URI, { userContextId: 1 });
|
||||
is(tab.getAttribute("usercontextid"), 1, "New tab has UCI equal 1");
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
info("Opening a new window from this tab...");
|
||||
let newWinPromise = BrowserTestUtils.waitForNewWindow({url: BASE_URI});
|
||||
let newWinPromise = BrowserTestUtils.waitForNewWindow({ url: BASE_URI });
|
||||
ContentTask.spawn(browser, BASE_URI, function(url) {
|
||||
content.window.newWindow = content.window.open(url, "_blank");
|
||||
});
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6,14 +6,21 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["CustomizableWidgets"];
|
||||
|
||||
const {CustomizableUI} = ChromeUtils.import("resource:///modules/CustomizableUI.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const { CustomizableUI } = ChromeUtils.import(
|
||||
"resource:///modules/CustomizableUI.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
PanelView: "resource:///modules/PanelMultiView.jsm",
|
||||
RecentlyClosedTabsAndWindowsMenuUtils: "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm",
|
||||
RecentlyClosedTabsAndWindowsMenuUtils:
|
||||
"resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm",
|
||||
ShortcutUtils: "resource://gre/modules/ShortcutUtils.jsm",
|
||||
CharsetMenu: "resource://gre/modules/CharsetMenu.jsm",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
|
@ -39,20 +46,19 @@ XPCOMUtils.defineLazyGetter(this, "log", () => {
|
|||
return new scope.ConsoleAPI(consoleOptions);
|
||||
});
|
||||
|
||||
|
||||
|
||||
function setAttributes(aNode, aAttrs) {
|
||||
let doc = aNode.ownerDocument;
|
||||
for (let [name, value] of Object.entries(aAttrs)) {
|
||||
if (!value) {
|
||||
if (aNode.hasAttribute(name))
|
||||
if (aNode.hasAttribute(name)) {
|
||||
aNode.removeAttribute(name);
|
||||
}
|
||||
} else {
|
||||
if (name == "shortcutId") {
|
||||
continue;
|
||||
}
|
||||
if (name == "label" || name == "tooltiptext") {
|
||||
let stringId = (typeof value == "string") ? value : name;
|
||||
let stringId = typeof value == "string" ? value : name;
|
||||
let additionalArgs = [];
|
||||
if (aAttrs.shortcutId) {
|
||||
let shortcut = doc.getElementById(aAttrs.shortcutId);
|
||||
|
@ -60,7 +66,11 @@ function setAttributes(aNode, aAttrs) {
|
|||
additionalArgs.push(ShortcutUtils.prettifyShortcut(shortcut));
|
||||
}
|
||||
}
|
||||
value = CustomizableUI.getLocalizedProperty({id: aAttrs.id}, stringId, additionalArgs);
|
||||
value = CustomizableUI.getLocalizedProperty(
|
||||
{ id: aAttrs.id },
|
||||
stringId,
|
||||
additionalArgs
|
||||
);
|
||||
}
|
||||
aNode.setAttribute(name, value);
|
||||
}
|
||||
|
@ -89,24 +99,35 @@ const CustomizableWidgets = [
|
|||
}
|
||||
},
|
||||
onViewShowing(event) {
|
||||
if (this._panelMenuView)
|
||||
if (this._panelMenuView) {
|
||||
return;
|
||||
}
|
||||
|
||||
let panelview = event.target;
|
||||
let document = panelview.ownerDocument;
|
||||
let window = document.defaultView;
|
||||
|
||||
// We restrict the amount of results to 42. Not 50, but 42. Why? Because 42.
|
||||
let query = "place:queryType=" + Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY +
|
||||
"&sort=" + Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING +
|
||||
let query =
|
||||
"place:queryType=" +
|
||||
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY +
|
||||
"&sort=" +
|
||||
Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING +
|
||||
"&maxResults=42&excludeQueries=1";
|
||||
|
||||
this._panelMenuView = new window.PlacesPanelview(document.getElementById("appMenu_historyMenu"),
|
||||
panelview, query);
|
||||
this._panelMenuView = new window.PlacesPanelview(
|
||||
document.getElementById("appMenu_historyMenu"),
|
||||
panelview,
|
||||
query
|
||||
);
|
||||
// When either of these sub-subviews show, populate them with recently closed
|
||||
// objects data.
|
||||
document.getElementById(this.recentlyClosedTabsPanel).addEventListener("ViewShowing", this);
|
||||
document.getElementById(this.recentlyClosedWindowsPanel).addEventListener("ViewShowing", this);
|
||||
document
|
||||
.getElementById(this.recentlyClosedTabsPanel)
|
||||
.addEventListener("ViewShowing", this);
|
||||
document
|
||||
.getElementById(this.recentlyClosedWindowsPanel)
|
||||
.addEventListener("ViewShowing", this);
|
||||
// When the popup is hidden (thus the panelmultiview node as well), make
|
||||
// sure to stop listening to PlacesDatabase updates.
|
||||
panelview.panelMultiView.addEventListener("PanelMultiViewHidden", this);
|
||||
|
@ -120,8 +141,12 @@ const CustomizableWidgets = [
|
|||
if (this._panelMenuView) {
|
||||
this._panelMenuView.uninit();
|
||||
delete this._panelMenuView;
|
||||
document.getElementById(this.recentlyClosedTabsPanel).removeEventListener("ViewShowing", this);
|
||||
document.getElementById(this.recentlyClosedWindowsPanel).removeEventListener("ViewShowing", this);
|
||||
document
|
||||
.getElementById(this.recentlyClosedTabsPanel)
|
||||
.removeEventListener("ViewShowing", this);
|
||||
document
|
||||
.getElementById(this.recentlyClosedWindowsPanel)
|
||||
.removeEventListener("ViewShowing", this);
|
||||
}
|
||||
panelMultiView.removeEventListener("PanelMultiViewHidden", this);
|
||||
},
|
||||
|
@ -129,7 +154,8 @@ const CustomizableWidgets = [
|
|||
let panelview = event.target;
|
||||
let document = event.target.ownerDocument;
|
||||
let window = document.defaultView;
|
||||
let viewType = panelview.id == this.recentlyClosedTabsPanel ? "Tabs" : "Windows";
|
||||
let viewType =
|
||||
panelview.id == this.recentlyClosedTabsPanel ? "Tabs" : "Windows";
|
||||
|
||||
this._panelMenuView.clearAllContents(panelview);
|
||||
|
||||
|
@ -138,8 +164,9 @@ const CustomizableWidgets = [
|
|||
let fragment = utils[method](window, "toolbarbutton", true);
|
||||
let elementCount = fragment.childElementCount;
|
||||
this._panelMenuView._setEmptyPopupStatus(panelview, !elementCount);
|
||||
if (!elementCount)
|
||||
if (!elementCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
let body = document.createXULElement("vbox");
|
||||
body.className = "panel-subview-body";
|
||||
|
@ -159,7 +186,8 @@ const CustomizableWidgets = [
|
|||
panelview.appendChild(body);
|
||||
panelview.appendChild(footer);
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
id: "save-page-button",
|
||||
shortcutId: "key_savePage",
|
||||
tooltiptext: "save-page-button.tooltiptext3",
|
||||
|
@ -167,7 +195,8 @@ const CustomizableWidgets = [
|
|||
let win = aEvent.target.ownerGlobal;
|
||||
win.saveBrowser(win.gBrowser.selectedBrowser);
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
id: "find-button",
|
||||
shortcutId: "key_find",
|
||||
tooltiptext: "find-button.tooltiptext3",
|
||||
|
@ -177,7 +206,8 @@ const CustomizableWidgets = [
|
|||
win.gLazyFindCommand("onFindCommand");
|
||||
}
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
id: "open-file-button",
|
||||
shortcutId: "openFileKb",
|
||||
tooltiptext: "open-file-button.tooltiptext3",
|
||||
|
@ -185,7 +215,8 @@ const CustomizableWidgets = [
|
|||
let win = aEvent.target.ownerGlobal;
|
||||
win.BrowserOpenFileWindow();
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
id: "sidebar-button",
|
||||
tooltiptext: "sidebar-button.tooltiptext2",
|
||||
onCommand(aEvent) {
|
||||
|
@ -205,7 +236,8 @@ const CustomizableWidgets = [
|
|||
aNode.appendChild(obChecked);
|
||||
aNode.appendChild(obPosition);
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
id: "add-ons-button",
|
||||
shortcutId: "key_openAddons",
|
||||
tooltiptext: "add-ons-button.tooltiptext3",
|
||||
|
@ -213,94 +245,118 @@ const CustomizableWidgets = [
|
|||
let win = aEvent.target.ownerGlobal;
|
||||
win.BrowserOpenAddonsMgr();
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
id: "zoom-controls",
|
||||
type: "custom",
|
||||
tooltiptext: "zoom-controls.tooltiptext2",
|
||||
onBuild(aDocument) {
|
||||
let buttons = [{
|
||||
id: "zoom-out-button",
|
||||
command: "cmd_fullZoomReduce",
|
||||
label: true,
|
||||
closemenu: "none",
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_fullZoomReduce",
|
||||
"class": "toolbarbutton-1 toolbarbutton-combined",
|
||||
}, {
|
||||
id: "zoom-reset-button",
|
||||
command: "cmd_fullZoomReset",
|
||||
closemenu: "none",
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_fullZoomReset",
|
||||
"class": "toolbarbutton-1 toolbarbutton-combined",
|
||||
}, {
|
||||
id: "zoom-in-button",
|
||||
command: "cmd_fullZoomEnlarge",
|
||||
closemenu: "none",
|
||||
label: true,
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_fullZoomEnlarge",
|
||||
"class": "toolbarbutton-1 toolbarbutton-combined",
|
||||
}];
|
||||
let buttons = [
|
||||
{
|
||||
id: "zoom-out-button",
|
||||
command: "cmd_fullZoomReduce",
|
||||
label: true,
|
||||
closemenu: "none",
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_fullZoomReduce",
|
||||
class: "toolbarbutton-1 toolbarbutton-combined",
|
||||
},
|
||||
{
|
||||
id: "zoom-reset-button",
|
||||
command: "cmd_fullZoomReset",
|
||||
closemenu: "none",
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_fullZoomReset",
|
||||
class: "toolbarbutton-1 toolbarbutton-combined",
|
||||
},
|
||||
{
|
||||
id: "zoom-in-button",
|
||||
command: "cmd_fullZoomEnlarge",
|
||||
closemenu: "none",
|
||||
label: true,
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_fullZoomEnlarge",
|
||||
class: "toolbarbutton-1 toolbarbutton-combined",
|
||||
},
|
||||
];
|
||||
|
||||
let node = aDocument.createXULElement("toolbaritem");
|
||||
node.setAttribute("id", "zoom-controls");
|
||||
node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
|
||||
node.setAttribute("title", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
|
||||
node.setAttribute(
|
||||
"label",
|
||||
CustomizableUI.getLocalizedProperty(this, "label")
|
||||
);
|
||||
node.setAttribute(
|
||||
"title",
|
||||
CustomizableUI.getLocalizedProperty(this, "tooltiptext")
|
||||
);
|
||||
// Set this as an attribute in addition to the property to make sure we can style correctly.
|
||||
node.setAttribute("removable", "true");
|
||||
node.classList.add("chromeclass-toolbar-additional");
|
||||
node.classList.add("toolbaritem-combined-buttons");
|
||||
|
||||
buttons.forEach(function(aButton, aIndex) {
|
||||
if (aIndex != 0)
|
||||
if (aIndex != 0) {
|
||||
node.appendChild(aDocument.createXULElement("separator"));
|
||||
}
|
||||
let btnNode = aDocument.createXULElement("toolbarbutton");
|
||||
setAttributes(btnNode, aButton);
|
||||
node.appendChild(btnNode);
|
||||
});
|
||||
return node;
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
id: "edit-controls",
|
||||
type: "custom",
|
||||
tooltiptext: "edit-controls.tooltiptext2",
|
||||
onBuild(aDocument) {
|
||||
let buttons = [{
|
||||
id: "cut-button",
|
||||
command: "cmd_cut",
|
||||
label: true,
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_cut",
|
||||
"class": "toolbarbutton-1 toolbarbutton-combined",
|
||||
}, {
|
||||
id: "copy-button",
|
||||
command: "cmd_copy",
|
||||
label: true,
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_copy",
|
||||
"class": "toolbarbutton-1 toolbarbutton-combined",
|
||||
}, {
|
||||
id: "paste-button",
|
||||
command: "cmd_paste",
|
||||
label: true,
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_paste",
|
||||
"class": "toolbarbutton-1 toolbarbutton-combined",
|
||||
}];
|
||||
let buttons = [
|
||||
{
|
||||
id: "cut-button",
|
||||
command: "cmd_cut",
|
||||
label: true,
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_cut",
|
||||
class: "toolbarbutton-1 toolbarbutton-combined",
|
||||
},
|
||||
{
|
||||
id: "copy-button",
|
||||
command: "cmd_copy",
|
||||
label: true,
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_copy",
|
||||
class: "toolbarbutton-1 toolbarbutton-combined",
|
||||
},
|
||||
{
|
||||
id: "paste-button",
|
||||
command: "cmd_paste",
|
||||
label: true,
|
||||
tooltiptext: "tooltiptext2",
|
||||
shortcutId: "key_paste",
|
||||
class: "toolbarbutton-1 toolbarbutton-combined",
|
||||
},
|
||||
];
|
||||
|
||||
let node = aDocument.createXULElement("toolbaritem");
|
||||
node.setAttribute("id", "edit-controls");
|
||||
node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
|
||||
node.setAttribute("title", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
|
||||
node.setAttribute(
|
||||
"label",
|
||||
CustomizableUI.getLocalizedProperty(this, "label")
|
||||
);
|
||||
node.setAttribute(
|
||||
"title",
|
||||
CustomizableUI.getLocalizedProperty(this, "tooltiptext")
|
||||
);
|
||||
// Set this as an attribute in addition to the property to make sure we can style correctly.
|
||||
node.setAttribute("removable", "true");
|
||||
node.classList.add("chromeclass-toolbar-additional");
|
||||
node.classList.add("toolbaritem-combined-buttons");
|
||||
|
||||
buttons.forEach(function(aButton, aIndex) {
|
||||
if (aIndex != 0)
|
||||
if (aIndex != 0) {
|
||||
node.appendChild(aDocument.createXULElement("separator"));
|
||||
}
|
||||
let btnNode = aDocument.createXULElement("toolbarbutton");
|
||||
setAttributes(btnNode, aButton);
|
||||
node.appendChild(btnNode);
|
||||
|
@ -308,8 +364,9 @@ const CustomizableWidgets = [
|
|||
|
||||
let listener = {
|
||||
onWidgetInstanceRemoved: (aWidgetId, aDoc) => {
|
||||
if (aWidgetId != this.id || aDoc != aDocument)
|
||||
if (aWidgetId != this.id || aDoc != aDocument) {
|
||||
return;
|
||||
}
|
||||
CustomizableUI.removeListener(listener);
|
||||
},
|
||||
onWidgetOverflow(aWidgetNode) {
|
||||
|
@ -336,8 +393,10 @@ const CustomizableWidgets = [
|
|||
tooltiptext: "characterencoding-button2.tooltiptext",
|
||||
maybeDisableMenu(aDocument) {
|
||||
let window = aDocument.defaultView;
|
||||
return !(window.gBrowser &&
|
||||
window.gBrowser.selectedBrowser.mayEnableCharacterEncodingMenu);
|
||||
return !(
|
||||
window.gBrowser &&
|
||||
window.gBrowser.selectedBrowser.mayEnableCharacterEncodingMenu
|
||||
);
|
||||
},
|
||||
populateList(aDocument, aContainerId, aSection) {
|
||||
let containerElem = aDocument.getElementById(aContainerId);
|
||||
|
@ -357,22 +416,39 @@ const CustomizableWidgets = [
|
|||
}
|
||||
},
|
||||
updateCurrentCharset(aDocument) {
|
||||
let currentCharset = aDocument.defaultView.gBrowser.selectedBrowser.characterSet;
|
||||
let {charsetAutodetected} = aDocument.defaultView.gBrowser.selectedBrowser;
|
||||
currentCharset = CharsetMenu.foldCharset(currentCharset, charsetAutodetected);
|
||||
let currentCharset =
|
||||
aDocument.defaultView.gBrowser.selectedBrowser.characterSet;
|
||||
let {
|
||||
charsetAutodetected,
|
||||
} = aDocument.defaultView.gBrowser.selectedBrowser;
|
||||
currentCharset = CharsetMenu.foldCharset(
|
||||
currentCharset,
|
||||
charsetAutodetected
|
||||
);
|
||||
|
||||
let pinnedContainer = aDocument.getElementById("PanelUI-characterEncodingView-pinned");
|
||||
let charsetContainer = aDocument.getElementById("PanelUI-characterEncodingView-charsets");
|
||||
let elements = [...(pinnedContainer.children), ...(charsetContainer.children)];
|
||||
let pinnedContainer = aDocument.getElementById(
|
||||
"PanelUI-characterEncodingView-pinned"
|
||||
);
|
||||
let charsetContainer = aDocument.getElementById(
|
||||
"PanelUI-characterEncodingView-charsets"
|
||||
);
|
||||
let elements = [
|
||||
...pinnedContainer.children,
|
||||
...charsetContainer.children,
|
||||
];
|
||||
|
||||
this._updateElements(elements, currentCharset);
|
||||
},
|
||||
updateCurrentDetector(aDocument) {
|
||||
let detectorContainer = aDocument.getElementById("PanelUI-characterEncodingView-autodetect");
|
||||
let detectorContainer = aDocument.getElementById(
|
||||
"PanelUI-characterEncodingView-autodetect"
|
||||
);
|
||||
let currentDetector;
|
||||
try {
|
||||
currentDetector = Services.prefs.getComplexValue(
|
||||
"intl.charset.detector", Ci.nsIPrefLocalizedString).data;
|
||||
"intl.charset.detector",
|
||||
Ci.nsIPrefLocalizedString
|
||||
).data;
|
||||
} catch (e) {}
|
||||
|
||||
this._updateElements(detectorContainer.children, currentDetector);
|
||||
|
@ -406,15 +482,21 @@ const CustomizableWidgets = [
|
|||
if (!autoDetectLabel.hasAttribute("value")) {
|
||||
let label = CharsetBundle.GetStringFromName("charsetMenuAutodet");
|
||||
autoDetectLabel.setAttribute("value", label);
|
||||
this.populateList(document,
|
||||
"PanelUI-characterEncodingView-pinned",
|
||||
"pinnedCharsets");
|
||||
this.populateList(document,
|
||||
"PanelUI-characterEncodingView-charsets",
|
||||
"otherCharsets");
|
||||
this.populateList(document,
|
||||
"PanelUI-characterEncodingView-autodetect",
|
||||
"detectors");
|
||||
this.populateList(
|
||||
document,
|
||||
"PanelUI-characterEncodingView-pinned",
|
||||
"pinnedCharsets"
|
||||
);
|
||||
this.populateList(
|
||||
document,
|
||||
"PanelUI-characterEncodingView-charsets",
|
||||
"otherCharsets"
|
||||
);
|
||||
this.populateList(
|
||||
document,
|
||||
"PanelUI-characterEncodingView-autodetect",
|
||||
"detectors"
|
||||
);
|
||||
}
|
||||
this.updateCurrentDetector(document);
|
||||
this.updateCurrentCharset(document);
|
||||
|
@ -448,40 +530,52 @@ const CustomizableWidgets = [
|
|||
let document = aNode.ownerDocument;
|
||||
|
||||
let updateButton = () => {
|
||||
if (this.maybeDisableMenu(document))
|
||||
if (this.maybeDisableMenu(document)) {
|
||||
aNode.setAttribute("disabled", "true");
|
||||
else
|
||||
} else {
|
||||
aNode.removeAttribute("disabled");
|
||||
}
|
||||
};
|
||||
|
||||
let getPanel = () => {
|
||||
let {PanelUI} = document.ownerGlobal;
|
||||
let { PanelUI } = document.ownerGlobal;
|
||||
return PanelUI.overflowPanel;
|
||||
};
|
||||
|
||||
if (CustomizableUI.getAreaType(this.currentArea) == CustomizableUI.TYPE_MENU_PANEL) {
|
||||
if (
|
||||
CustomizableUI.getAreaType(this.currentArea) ==
|
||||
CustomizableUI.TYPE_MENU_PANEL
|
||||
) {
|
||||
getPanel().addEventListener("popupshowing", updateButton);
|
||||
}
|
||||
|
||||
let listener = {
|
||||
onWidgetAdded: (aWidgetId, aArea) => {
|
||||
if (aWidgetId != this.id)
|
||||
if (aWidgetId != this.id) {
|
||||
return;
|
||||
if (CustomizableUI.getAreaType(aArea) == CustomizableUI.TYPE_MENU_PANEL) {
|
||||
}
|
||||
if (
|
||||
CustomizableUI.getAreaType(aArea) == CustomizableUI.TYPE_MENU_PANEL
|
||||
) {
|
||||
getPanel().addEventListener("popupshowing", updateButton);
|
||||
}
|
||||
},
|
||||
onWidgetRemoved: (aWidgetId, aPrevArea) => {
|
||||
if (aWidgetId != this.id)
|
||||
if (aWidgetId != this.id) {
|
||||
return;
|
||||
}
|
||||
aNode.removeAttribute("disabled");
|
||||
if (CustomizableUI.getAreaType(aPrevArea) == CustomizableUI.TYPE_MENU_PANEL) {
|
||||
if (
|
||||
CustomizableUI.getAreaType(aPrevArea) ==
|
||||
CustomizableUI.TYPE_MENU_PANEL
|
||||
) {
|
||||
getPanel().removeEventListener("popupshowing", updateButton);
|
||||
}
|
||||
},
|
||||
onWidgetInstanceRemoved: (aWidgetId, aDoc) => {
|
||||
if (aWidgetId != this.id || aDoc != document)
|
||||
if (aWidgetId != this.id || aDoc != document) {
|
||||
return;
|
||||
}
|
||||
|
||||
CustomizableUI.removeListener(listener);
|
||||
getPanel().removeEventListener("popupshowing", updateButton);
|
||||
|
@ -496,14 +590,16 @@ const CustomizableWidgets = [
|
|||
this.charsetInfo = CharsetMenu.getData();
|
||||
}
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
id: "email-link-button",
|
||||
tooltiptext: "email-link-button.tooltiptext3",
|
||||
onCommand(aEvent) {
|
||||
let win = aEvent.view;
|
||||
win.MailIntegration.sendLinkForBrowser(win.gBrowser.selectedBrowser);
|
||||
},
|
||||
}];
|
||||
},
|
||||
];
|
||||
|
||||
if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
|
||||
CustomizableWidgets.push({
|
||||
|
@ -558,7 +654,9 @@ if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
|
|||
}
|
||||
},
|
||||
setDeckIndex(index) {
|
||||
let deck = this._tabsList.ownerDocument.getElementById("PanelUI-remotetabs-deck");
|
||||
let deck = this._tabsList.ownerDocument.getElementById(
|
||||
"PanelUI-remotetabs-deck"
|
||||
);
|
||||
// We call setAttribute instead of relying on the XBL property setter due
|
||||
// to things going wrong when we try and set the index before the XBL
|
||||
// binding has been created - see bug 1241851 for the gory details.
|
||||
|
@ -568,11 +666,14 @@ if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
|
|||
_showTabsPromise: Promise.resolve(),
|
||||
// Update the tab list after any existing in-flight updates are complete.
|
||||
_showTabs(paginationInfo) {
|
||||
this._showTabsPromise = this._showTabsPromise.then(() => {
|
||||
return this.__showTabs(paginationInfo);
|
||||
}, e => {
|
||||
Cu.reportError(e);
|
||||
});
|
||||
this._showTabsPromise = this._showTabsPromise.then(
|
||||
() => {
|
||||
return this.__showTabs(paginationInfo);
|
||||
},
|
||||
e => {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
);
|
||||
},
|
||||
// Return a new promise to update the tab list.
|
||||
__showTabs(paginationInfo) {
|
||||
|
@ -582,48 +683,55 @@ if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
|
|||
return undefined;
|
||||
}
|
||||
let doc = this._tabsList.ownerDocument;
|
||||
return SyncedTabs.getTabClients().then(clients => {
|
||||
// The view may have been hidden while the promise was resolving.
|
||||
if (!this._tabsList) {
|
||||
return;
|
||||
}
|
||||
if (clients.length === 0 && !SyncedTabs.hasSyncedThisSession) {
|
||||
// the "fetching tabs" deck is being shown - let's leave it there.
|
||||
// When that first sync completes we'll be notified and update.
|
||||
return;
|
||||
}
|
||||
|
||||
if (clients.length === 0) {
|
||||
this.setDeckIndex(this.deckIndices.DECKINDEX_NOCLIENTS);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setDeckIndex(this.deckIndices.DECKINDEX_TABS);
|
||||
this._clearTabList();
|
||||
SyncedTabs.sortTabClientsByLastUsed(clients);
|
||||
let fragment = doc.createDocumentFragment();
|
||||
|
||||
for (let client of clients) {
|
||||
// add a menu separator for all clients other than the first.
|
||||
if (fragment.lastElementChild) {
|
||||
let separator = doc.createXULElement("menuseparator");
|
||||
fragment.appendChild(separator);
|
||||
return SyncedTabs.getTabClients()
|
||||
.then(clients => {
|
||||
// The view may have been hidden while the promise was resolving.
|
||||
if (!this._tabsList) {
|
||||
return;
|
||||
}
|
||||
if (paginationInfo && paginationInfo.clientId == client.id) {
|
||||
this._appendClient(client, fragment, paginationInfo.maxTabs);
|
||||
} else {
|
||||
this._appendClient(client, fragment);
|
||||
if (clients.length === 0 && !SyncedTabs.hasSyncedThisSession) {
|
||||
// the "fetching tabs" deck is being shown - let's leave it there.
|
||||
// When that first sync completes we'll be notified and update.
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._tabsList.appendChild(fragment);
|
||||
PanelView.forNode(this._tabsList.closest("panelview"))
|
||||
.descriptionHeightWorkaround();
|
||||
}).catch(err => {
|
||||
Cu.reportError(err);
|
||||
}).then(() => {
|
||||
// an observer for tests.
|
||||
Services.obs.notifyObservers(null, "synced-tabs-menu:test:tabs-updated");
|
||||
});
|
||||
|
||||
if (clients.length === 0) {
|
||||
this.setDeckIndex(this.deckIndices.DECKINDEX_NOCLIENTS);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setDeckIndex(this.deckIndices.DECKINDEX_TABS);
|
||||
this._clearTabList();
|
||||
SyncedTabs.sortTabClientsByLastUsed(clients);
|
||||
let fragment = doc.createDocumentFragment();
|
||||
|
||||
for (let client of clients) {
|
||||
// add a menu separator for all clients other than the first.
|
||||
if (fragment.lastElementChild) {
|
||||
let separator = doc.createXULElement("menuseparator");
|
||||
fragment.appendChild(separator);
|
||||
}
|
||||
if (paginationInfo && paginationInfo.clientId == client.id) {
|
||||
this._appendClient(client, fragment, paginationInfo.maxTabs);
|
||||
} else {
|
||||
this._appendClient(client, fragment);
|
||||
}
|
||||
}
|
||||
this._tabsList.appendChild(fragment);
|
||||
PanelView.forNode(
|
||||
this._tabsList.closest("panelview")
|
||||
).descriptionHeightWorkaround();
|
||||
})
|
||||
.catch(err => {
|
||||
Cu.reportError(err);
|
||||
})
|
||||
.then(() => {
|
||||
// an observer for tests.
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"synced-tabs-menu:test:tabs-updated"
|
||||
);
|
||||
});
|
||||
},
|
||||
_clearTabList() {
|
||||
let list = this._tabsList;
|
||||
|
@ -651,25 +759,34 @@ if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
|
|||
let clientItem = doc.createXULElement("label");
|
||||
clientItem.setAttribute("itemtype", "client");
|
||||
let window = doc.defaultView;
|
||||
clientItem.setAttribute("tooltiptext",
|
||||
window.gSync.formatLastSyncDate(new Date(client.lastModified)));
|
||||
clientItem.setAttribute(
|
||||
"tooltiptext",
|
||||
window.gSync.formatLastSyncDate(new Date(client.lastModified))
|
||||
);
|
||||
clientItem.textContent = client.name;
|
||||
|
||||
attachFragment.appendChild(clientItem);
|
||||
|
||||
if (client.tabs.length == 0) {
|
||||
let label = this._appendMessageLabel("notabsforclientlabel", attachFragment);
|
||||
let label = this._appendMessageLabel(
|
||||
"notabsforclientlabel",
|
||||
attachFragment
|
||||
);
|
||||
label.setAttribute("class", "PanelUI-remotetabs-notabsforclient-label");
|
||||
} else {
|
||||
// If this page will display all tabs, show no additional buttons.
|
||||
// If the next page will display all the remaining tabs, show a "Show All" button
|
||||
// Otherwise, show a "Shore More" button
|
||||
let hasNextPage = client.tabs.length > maxTabs;
|
||||
let nextPageIsLastPage = hasNextPage && maxTabs + this.TABS_PER_PAGE >= client.tabs.length;
|
||||
let nextPageIsLastPage =
|
||||
hasNextPage && maxTabs + this.TABS_PER_PAGE >= client.tabs.length;
|
||||
if (nextPageIsLastPage) {
|
||||
// When the user clicks "Show All", try to have at least NEXT_PAGE_MIN_TABS more tabs
|
||||
// to display in order to avoid user frustration
|
||||
maxTabs = Math.min(client.tabs.length - this.NEXT_PAGE_MIN_TABS, maxTabs);
|
||||
maxTabs = Math.min(
|
||||
client.tabs.length - this.NEXT_PAGE_MIN_TABS,
|
||||
maxTabs
|
||||
);
|
||||
}
|
||||
if (hasNextPage) {
|
||||
client.tabs = client.tabs.slice(0, maxTabs);
|
||||
|
@ -679,28 +796,35 @@ if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
|
|||
attachFragment.appendChild(tabEnt);
|
||||
}
|
||||
if (hasNextPage) {
|
||||
let showAllEnt = this._createShowMoreElement(doc, client.id,
|
||||
nextPageIsLastPage ?
|
||||
Infinity :
|
||||
maxTabs + this.TABS_PER_PAGE);
|
||||
let showAllEnt = this._createShowMoreElement(
|
||||
doc,
|
||||
client.id,
|
||||
nextPageIsLastPage ? Infinity : maxTabs + this.TABS_PER_PAGE
|
||||
);
|
||||
attachFragment.appendChild(showAllEnt);
|
||||
}
|
||||
}
|
||||
},
|
||||
_createTabElement(doc, tabInfo) {
|
||||
let item = doc.createXULElement("toolbarbutton");
|
||||
let tooltipText = (tabInfo.title ? tabInfo.title + "\n" : "") + tabInfo.url;
|
||||
let tooltipText =
|
||||
(tabInfo.title ? tabInfo.title + "\n" : "") + tabInfo.url;
|
||||
item.setAttribute("itemtype", "tab");
|
||||
item.setAttribute("class", "subviewbutton");
|
||||
item.setAttribute("targetURI", tabInfo.url);
|
||||
item.setAttribute("label", tabInfo.title != "" ? tabInfo.title : tabInfo.url);
|
||||
item.setAttribute(
|
||||
"label",
|
||||
tabInfo.title != "" ? tabInfo.title : tabInfo.url
|
||||
);
|
||||
item.setAttribute("image", tabInfo.icon);
|
||||
item.setAttribute("tooltiptext", tooltipText);
|
||||
// We need to use "click" instead of "command" here so openUILink
|
||||
// respects different buttons (eg, to open in a new tab).
|
||||
item.addEventListener("click", e => {
|
||||
doc.defaultView.openUILink(tabInfo.url, e, {
|
||||
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
|
||||
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal(
|
||||
{}
|
||||
),
|
||||
});
|
||||
if (doc.defaultView.whereToOpenLink(e) != "current") {
|
||||
e.preventDefault();
|
||||
|
@ -765,10 +889,20 @@ if (Services.prefs.getBoolPref("privacy.panicButton.enabled")) {
|
|||
let doc = aEvent.target.ownerDocument;
|
||||
let group = doc.getElementById("PanelUI-panic-timeSpan");
|
||||
let itemsToClear = [
|
||||
"cookies", "history", "openWindows", "formdata", "sessions", "cache", "downloads", "offlineApps",
|
||||
"cookies",
|
||||
"history",
|
||||
"openWindows",
|
||||
"formdata",
|
||||
"sessions",
|
||||
"cache",
|
||||
"downloads",
|
||||
"offlineApps",
|
||||
];
|
||||
let newWindowPrivateState = PrivateBrowsingUtils.isWindowPrivate(doc.defaultView) ?
|
||||
"private" : "non-private";
|
||||
let newWindowPrivateState = PrivateBrowsingUtils.isWindowPrivate(
|
||||
doc.defaultView
|
||||
)
|
||||
? "private"
|
||||
: "non-private";
|
||||
let promise = Sanitizer.sanitize(itemsToClear, {
|
||||
ignoreTimespan: false,
|
||||
range: Sanitizer.getClearRange(+group.value),
|
||||
|
@ -834,7 +968,9 @@ if (Services.prefs.getBoolPref("privacy.panicButton.enabled")) {
|
|||
eventBlocker = doc.l10n.translateElements([aEvent.target]);
|
||||
}
|
||||
|
||||
let forgetButton = aEvent.target.querySelector("#PanelUI-panic-view-button");
|
||||
let forgetButton = aEvent.target.querySelector(
|
||||
"#PanelUI-panic-view-button"
|
||||
);
|
||||
let group = doc.getElementById("PanelUI-panic-timeSpan");
|
||||
group.selectedItem = doc.getElementById("PanelUI-panic-5min");
|
||||
forgetButton.addEventListener("command", this);
|
||||
|
@ -844,7 +980,9 @@ if (Services.prefs.getBoolPref("privacy.panicButton.enabled")) {
|
|||
}
|
||||
},
|
||||
onViewHiding(aEvent) {
|
||||
let forgetButton = aEvent.target.querySelector("#PanelUI-panic-view-button");
|
||||
let forgetButton = aEvent.target.querySelector(
|
||||
"#PanelUI-panic-view-button"
|
||||
);
|
||||
forgetButton.removeEventListener("command", this);
|
||||
},
|
||||
});
|
||||
|
@ -856,7 +994,7 @@ if (PrivateBrowsingUtils.enabled) {
|
|||
shortcutId: "key_privatebrowsing",
|
||||
onCommand(e) {
|
||||
let win = e.target.ownerGlobal;
|
||||
win.OpenBrowserWindow({private: true});
|
||||
win.OpenBrowserWindow({ private: true });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -88,8 +88,7 @@ AreaPositionManager.prototype = {
|
|||
// Check if we're closer to the next target than to this one:
|
||||
// Only move if we're not targeting a node in a different row:
|
||||
if (aY > targetBounds.top && aY < targetBounds.bottom) {
|
||||
if ((!this._rtl && aX > outsideX) ||
|
||||
(this._rtl && aX < outsideX)) {
|
||||
if ((!this._rtl && aX > outsideX) || (this._rtl && aX < outsideX)) {
|
||||
return closest.nextElementSibling || aContainer;
|
||||
}
|
||||
}
|
||||
|
@ -127,8 +126,11 @@ AreaPositionManager.prototype = {
|
|||
child.style.transform = "";
|
||||
}
|
||||
}
|
||||
if (aContainer.lastElementChild && aIsFromThisArea &&
|
||||
!this._lastPlaceholderInsertion) {
|
||||
if (
|
||||
aContainer.lastElementChild &&
|
||||
aIsFromThisArea &&
|
||||
!this._lastPlaceholderInsertion
|
||||
) {
|
||||
// Flush layout:
|
||||
aContainer.lastElementChild.getBoundingClientRect();
|
||||
// then remove all the [notransition]
|
||||
|
@ -226,8 +228,10 @@ AreaPositionManager.prototype = {
|
|||
// (i.e. the row in which this item is placed is full)
|
||||
// we should move it to align with the first item in the next row instead
|
||||
let bound = this._containerInfo[this._rtl ? "left" : "right"];
|
||||
if ((!this._rtl && xDiff + aNodeBounds.right > bound) ||
|
||||
(this._rtl && xDiff + aNodeBounds.left < bound)) {
|
||||
if (
|
||||
(!this._rtl && xDiff + aNodeBounds.right > bound) ||
|
||||
(this._rtl && xDiff + aNodeBounds.left < bound)
|
||||
) {
|
||||
xDiff = this._lazyStoreGet(aFirstNodeInRow)[side] - aNodeBounds[side];
|
||||
}
|
||||
return xDiff;
|
||||
|
|
|
@ -99,19 +99,22 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"PanelMultiView",
|
||||
"PanelView",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["PanelMultiView", "PanelView"];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gBundle", function() {
|
||||
return Services.strings.createBundle(
|
||||
"chrome://browser/locale/browser.properties");
|
||||
"chrome://browser/locale/browser.properties"
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -223,33 +226,42 @@ var AssociatedToNode = class {
|
|||
async dispatchAsyncEvent(eventName) {
|
||||
// Wait for all the previous blockers before dispatching the event.
|
||||
let blockersPromise = this._blockersPromise.catch(() => {});
|
||||
return this._blockersPromise = blockersPromise.then(async () => {
|
||||
return (this._blockersPromise = blockersPromise.then(async () => {
|
||||
let blockers = new Set();
|
||||
let cancel = this.dispatchCustomEvent(eventName, {
|
||||
addBlocker(promise) {
|
||||
// Any exception in the blocker will cancel the operation.
|
||||
blockers.add(promise.catch(ex => {
|
||||
Cu.reportError(ex);
|
||||
return true;
|
||||
}));
|
||||
let cancel = this.dispatchCustomEvent(
|
||||
eventName,
|
||||
{
|
||||
addBlocker(promise) {
|
||||
// Any exception in the blocker will cancel the operation.
|
||||
blockers.add(
|
||||
promise.catch(ex => {
|
||||
Cu.reportError(ex);
|
||||
return true;
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
}, true);
|
||||
true
|
||||
);
|
||||
if (blockers.size) {
|
||||
let timeoutPromise = new Promise((resolve, reject) => {
|
||||
this.window.setTimeout(reject, BLOCKERS_TIMEOUT_MS);
|
||||
});
|
||||
try {
|
||||
let results = await Promise.race([Promise.all(blockers),
|
||||
timeoutPromise]);
|
||||
let results = await Promise.race([
|
||||
Promise.all(blockers),
|
||||
timeoutPromise,
|
||||
]);
|
||||
cancel = cancel || results.some(result => result === false);
|
||||
} catch (ex) {
|
||||
Cu.reportError(new Error(
|
||||
`One of the blockers for ${eventName} timed out.`));
|
||||
Cu.reportError(
|
||||
new Error(`One of the blockers for ${eventName} timed out.`)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return cancel;
|
||||
});
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -326,12 +338,17 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
return;
|
||||
}
|
||||
|
||||
window.addEventListener("unload", () => {
|
||||
for (let panelMultiViewNode of
|
||||
window.document.querySelectorAll("panelmultiview")) {
|
||||
this.forNode(panelMultiViewNode).disconnect();
|
||||
}
|
||||
}, { once: true });
|
||||
window.addEventListener(
|
||||
"unload",
|
||||
() => {
|
||||
for (let panelMultiViewNode of window.document.querySelectorAll(
|
||||
"panelmultiview"
|
||||
)) {
|
||||
this.forNode(panelMultiViewNode).disconnect();
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
gWindowsWithUnloadHandler.add(window);
|
||||
}
|
||||
|
@ -349,10 +366,12 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
}
|
||||
|
||||
get _screenManager() {
|
||||
if (this.__screenManager)
|
||||
if (this.__screenManager) {
|
||||
return this.__screenManager;
|
||||
return this.__screenManager = Cc["@mozilla.org/gfx/screenmanager;1"]
|
||||
.getService(Ci.nsIScreenManager);
|
||||
}
|
||||
return (this.__screenManager = Cc[
|
||||
"@mozilla.org/gfx/screenmanager;1"
|
||||
].getService(Ci.nsIScreenManager));
|
||||
}
|
||||
|
||||
constructor(node) {
|
||||
|
@ -366,19 +385,21 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
|
||||
PanelMultiView.ensureUnloadHandlerRegistered(this.window);
|
||||
|
||||
let viewContainer = this._viewContainer =
|
||||
this.document.createXULElement("box");
|
||||
let viewContainer = (this._viewContainer = this.document.createXULElement(
|
||||
"box"
|
||||
));
|
||||
viewContainer.classList.add("panel-viewcontainer");
|
||||
|
||||
let viewStack = this._viewStack = this.document.createXULElement("box");
|
||||
let viewStack = (this._viewStack = this.document.createXULElement("box"));
|
||||
viewStack.classList.add("panel-viewstack");
|
||||
viewContainer.append(viewStack);
|
||||
|
||||
let offscreenViewContainer = this.document.createXULElement("box");
|
||||
offscreenViewContainer.classList.add("panel-viewcontainer", "offscreen");
|
||||
|
||||
let offscreenViewStack = this._offscreenViewStack =
|
||||
this.document.createXULElement("box");
|
||||
let offscreenViewStack = (this._offscreenViewStack = this.document.createXULElement(
|
||||
"box"
|
||||
));
|
||||
offscreenViewStack.classList.add("panel-viewstack");
|
||||
offscreenViewContainer.append(offscreenViewStack);
|
||||
|
||||
|
@ -404,8 +425,9 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
|
||||
disconnect() {
|
||||
// Guard against re-entrancy.
|
||||
if (!this.node || !this.connected)
|
||||
if (!this.node || !this.connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._panel.removeEventListener("mousemove", this);
|
||||
this._panel.removeEventListener("popupshowing", this);
|
||||
|
@ -413,8 +435,7 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
this._panel.removeEventListener("popupshown", this);
|
||||
this._panel.removeEventListener("popuphidden", this);
|
||||
this.window.removeEventListener("keydown", this, true);
|
||||
this.node = this._openPopupPromise = this._openPopupCancelCallback =
|
||||
this._viewContainer = this._viewStack = this._transitionDetails = null;
|
||||
this.node = this._openPopupPromise = this._openPopupCancelCallback = this._viewContainer = this._viewStack = this._transitionDetails = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -462,7 +483,7 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
// because hidePopup wants to dispatch the "popuphidden" event synchronously
|
||||
// even if the panel has not been opened yet.
|
||||
let canCancel = true;
|
||||
let cancelCallback = this._openPopupCancelCallback = () => {
|
||||
let cancelCallback = (this._openPopupCancelCallback = () => {
|
||||
// If the cancel callback is called and the panel hasn't been prepared
|
||||
// yet, cancel showing it. Setting canCancel to false will prevent the
|
||||
// popup from opening. If the panel has opened by the time the cancel
|
||||
|
@ -472,7 +493,7 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
canCancel = false;
|
||||
this.dispatchCustomEvent("popuphidden");
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Create a promise that is resolved with the result of the last call to
|
||||
// this method, where errors indicate that the panel was not opened.
|
||||
|
@ -483,7 +504,7 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
// Make the preparation done before showing the panel non-reentrant. The
|
||||
// promise created here will be resolved only after the panel preparation is
|
||||
// completed, even if a cancellation request is received in the meantime.
|
||||
return this._openPopupPromise = openPopupPromise.then(async wasShown => {
|
||||
return (this._openPopupPromise = openPopupPromise.then(async wasShown => {
|
||||
// The panel may have been destroyed in the meantime.
|
||||
if (!this.node) {
|
||||
return false;
|
||||
|
@ -527,9 +548,13 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (options && typeof options == "object" && options.triggerEvent &&
|
||||
options.triggerEvent.type == "keypress" &&
|
||||
this.openViews.length) {
|
||||
if (
|
||||
options &&
|
||||
typeof options == "object" &&
|
||||
options.triggerEvent &&
|
||||
options.triggerEvent.type == "keypress" &&
|
||||
this.openViews.length
|
||||
) {
|
||||
// This was opened via the keyboard, so focus the first item.
|
||||
this.openViews[0].focusWhenActive = true;
|
||||
}
|
||||
|
@ -539,7 +564,7 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
this.dispatchCustomEvent("popuphidden");
|
||||
throw ex;
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -618,8 +643,10 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
this._showSubView(viewIdOrNode, anchor).catch(Cu.reportError);
|
||||
}
|
||||
async _showSubView(viewIdOrNode, anchor) {
|
||||
let viewNode = typeof viewIdOrNode == "string" ?
|
||||
this.document.getElementById(viewIdOrNode) : viewIdOrNode;
|
||||
let viewNode =
|
||||
typeof viewIdOrNode == "string"
|
||||
? this.document.getElementById(viewIdOrNode)
|
||||
: viewIdOrNode;
|
||||
if (!viewNode) {
|
||||
Cu.reportError(new Error(`Subview ${viewIdOrNode} doesn't exist.`));
|
||||
return;
|
||||
|
@ -680,8 +707,9 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
// reset all the properties that may be set on a subview.
|
||||
nextPanelView.mainview = false;
|
||||
// The header may change based on how the subview was opened.
|
||||
nextPanelView.headerText = viewNode.getAttribute("title") ||
|
||||
(anchor && anchor.getAttribute("label"));
|
||||
nextPanelView.headerText =
|
||||
viewNode.getAttribute("title") ||
|
||||
(anchor && anchor.getAttribute("label"));
|
||||
// The constrained width of subviews may also vary between panels.
|
||||
nextPanelView.minMaxWidth = prevPanelView.knownWidth;
|
||||
|
||||
|
@ -736,8 +764,9 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
* Prepares the main view before showing the panel.
|
||||
*/
|
||||
async _showMainView() {
|
||||
let nextPanelView = PanelView.forNode(this.document.getElementById(
|
||||
this.node.getAttribute("mainViewId")));
|
||||
let nextPanelView = PanelView.forNode(
|
||||
this.document.getElementById(this.node.getAttribute("mainViewId"))
|
||||
);
|
||||
|
||||
// If the view is already open in another panel, close the panel first.
|
||||
let oldPanelMultiViewNode = nextPanelView.node.panelMultiView;
|
||||
|
@ -877,9 +906,9 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
let nextPanelView = PanelView.forNode(viewNode);
|
||||
let prevPanelView = PanelView.forNode(previousViewNode);
|
||||
|
||||
let details = this._transitionDetails = {
|
||||
let details = (this._transitionDetails = {
|
||||
phase: TRANSITION_PHASES.START,
|
||||
};
|
||||
});
|
||||
|
||||
// Set the viewContainer dimensions to make sure only the current view is
|
||||
// visible.
|
||||
|
@ -896,8 +925,10 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
if (reverse) {
|
||||
// Use the cached size when going back to a previous view, but not when
|
||||
// reopening a subview, because its contents may have changed.
|
||||
viewRect = { width: nextPanelView.knownWidth,
|
||||
height: nextPanelView.knownHeight };
|
||||
viewRect = {
|
||||
width: nextPanelView.knownWidth,
|
||||
height: nextPanelView.knownHeight,
|
||||
};
|
||||
nextPanelView.visible = true;
|
||||
} else if (viewNode.customRectGetter) {
|
||||
// We use a customRectGetter for WebExtensions panels, because they need
|
||||
|
@ -906,7 +937,7 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
// moved around, otherwise the state of the browser would get disrupted.
|
||||
let width = prevPanelView.knownWidth;
|
||||
let height = prevPanelView.knownHeight;
|
||||
viewRect = Object.assign({height, width}, viewNode.customRectGetter());
|
||||
viewRect = Object.assign({ height, width }, viewNode.customRectGetter());
|
||||
nextPanelView.visible = true;
|
||||
// Until the header is visible, it has 0 height.
|
||||
// Wait for layout before measuring it
|
||||
|
@ -945,21 +976,24 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
details.phase = TRANSITION_PHASES.PREPARE;
|
||||
|
||||
// The 'magic' part: build up the amount of pixels to move right or left.
|
||||
let moveToLeft = (this.window.RTL_UI && !reverse) || (!this.window.RTL_UI && reverse);
|
||||
let moveToLeft =
|
||||
(this.window.RTL_UI && !reverse) || (!this.window.RTL_UI && reverse);
|
||||
let deltaX = prevPanelView.knownWidth;
|
||||
let deepestNode = reverse ? previousViewNode : viewNode;
|
||||
|
||||
// With a transition when navigating backwards - user hits the 'back'
|
||||
// button - we need to make sure that the views are positioned in a way
|
||||
// that a translateX() unveils the previous view from the right direction.
|
||||
if (reverse)
|
||||
if (reverse) {
|
||||
this._viewStack.style.marginInlineStart = "-" + deltaX + "px";
|
||||
}
|
||||
|
||||
// Set the transition style and listen for its end to clean up and make sure
|
||||
// the box sizing becomes dynamic again.
|
||||
// Somehow, putting these properties in PanelUI.css doesn't work for newly
|
||||
// shown nodes in a XUL parent node.
|
||||
this._viewStack.style.transition = "transform var(--animation-easing-function)" +
|
||||
this._viewStack.style.transition =
|
||||
"transform var(--animation-easing-function)" +
|
||||
" var(--panelui-subview-transition-duration)";
|
||||
this._viewStack.style.willChange = "transform";
|
||||
// Use an outline instead of a border so that the size is not affected.
|
||||
|
@ -985,27 +1019,42 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
|
||||
// Kick off the transition!
|
||||
details.phase = TRANSITION_PHASES.TRANSITION;
|
||||
this._viewStack.style.transform = "translateX(" + (moveToLeft ? "" : "-") + deltaX + "px)";
|
||||
this._viewStack.style.transform =
|
||||
"translateX(" + (moveToLeft ? "" : "-") + deltaX + "px)";
|
||||
|
||||
await new Promise(resolve => {
|
||||
details.resolve = resolve;
|
||||
this._viewContainer.addEventListener("transitionend", details.listener = ev => {
|
||||
// It's quite common that `height` on the view container doesn't need
|
||||
// to transition, so we make sure to do all the work on the transform
|
||||
// transition-end, because that is guaranteed to happen.
|
||||
if (ev.target != this._viewStack || ev.propertyName != "transform")
|
||||
return;
|
||||
this._viewContainer.removeEventListener("transitionend", details.listener);
|
||||
delete details.listener;
|
||||
resolve();
|
||||
});
|
||||
this._viewContainer.addEventListener("transitioncancel", details.cancelListener = ev => {
|
||||
if (ev.target != this._viewStack)
|
||||
return;
|
||||
this._viewContainer.removeEventListener("transitioncancel", details.cancelListener);
|
||||
delete details.cancelListener;
|
||||
resolve();
|
||||
});
|
||||
this._viewContainer.addEventListener(
|
||||
"transitionend",
|
||||
(details.listener = ev => {
|
||||
// It's quite common that `height` on the view container doesn't need
|
||||
// to transition, so we make sure to do all the work on the transform
|
||||
// transition-end, because that is guaranteed to happen.
|
||||
if (ev.target != this._viewStack || ev.propertyName != "transform") {
|
||||
return;
|
||||
}
|
||||
this._viewContainer.removeEventListener(
|
||||
"transitionend",
|
||||
details.listener
|
||||
);
|
||||
delete details.listener;
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
this._viewContainer.addEventListener(
|
||||
"transitioncancel",
|
||||
(details.cancelListener = ev => {
|
||||
if (ev.target != this._viewStack) {
|
||||
return;
|
||||
}
|
||||
this._viewContainer.removeEventListener(
|
||||
"transitioncancel",
|
||||
details.cancelListener
|
||||
);
|
||||
delete details.cancelListener;
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Bail out if the panel was closed during the transition.
|
||||
|
@ -1032,7 +1081,7 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
return;
|
||||
}
|
||||
|
||||
let {phase, resolve, listener, cancelListener} = this._transitionDetails;
|
||||
let { phase, resolve, listener, cancelListener } = this._transitionDetails;
|
||||
this._transitionDetails = null;
|
||||
|
||||
if (phase >= TRANSITION_PHASES.START) {
|
||||
|
@ -1048,12 +1097,18 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
}
|
||||
if (phase >= TRANSITION_PHASES.TRANSITION) {
|
||||
this._viewStack.style.removeProperty("transform");
|
||||
if (listener)
|
||||
if (listener) {
|
||||
this._viewContainer.removeEventListener("transitionend", listener);
|
||||
if (cancelListener)
|
||||
this._viewContainer.removeEventListener("transitioncancel", cancelListener);
|
||||
if (resolve)
|
||||
}
|
||||
if (cancelListener) {
|
||||
this._viewContainer.removeEventListener(
|
||||
"transitioncancel",
|
||||
cancelListener
|
||||
);
|
||||
}
|
||||
if (resolve) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1065,11 +1120,14 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
let anchor = this._panel.anchorNode;
|
||||
let anchorRect = anchor.getBoundingClientRect();
|
||||
|
||||
let screen = this._screenManager.screenForRect(anchor.screenX,
|
||||
anchor.screenY,
|
||||
anchorRect.width,
|
||||
anchorRect.height);
|
||||
let availTop = {}, availHeight = {};
|
||||
let screen = this._screenManager.screenForRect(
|
||||
anchor.screenX,
|
||||
anchor.screenY,
|
||||
anchorRect.width,
|
||||
anchorRect.height
|
||||
);
|
||||
let availTop = {},
|
||||
availHeight = {};
|
||||
screen.GetAvailRect({}, availTop, {}, availHeight);
|
||||
let cssAvailTop = availTop.value / screen.defaultCSSScaleFactor;
|
||||
|
||||
|
@ -1101,8 +1159,11 @@ var PanelMultiView = class extends AssociatedToNode {
|
|||
handleEvent(aEvent) {
|
||||
// Only process actual popup events from the panel or events we generate
|
||||
// ourselves, but not from menus being shown from within the panel.
|
||||
if (aEvent.type.startsWith("popup") && aEvent.target != this._panel &&
|
||||
aEvent.target != this.node) {
|
||||
if (
|
||||
aEvent.type.startsWith("popup") &&
|
||||
aEvent.target != this._panel &&
|
||||
aEvent.target != this.node
|
||||
) {
|
||||
return;
|
||||
}
|
||||
switch (aEvent.type) {
|
||||
|
@ -1273,8 +1334,10 @@ var PanelView = class extends AssociatedToNode {
|
|||
"subviewbutton subviewbutton-iconic subviewbutton-back";
|
||||
backButton.setAttribute("closemenu", "none");
|
||||
backButton.setAttribute("tabindex", "0");
|
||||
backButton.setAttribute("aria-label",
|
||||
gBundle.GetStringFromName("panel.back"));
|
||||
backButton.setAttribute(
|
||||
"aria-label",
|
||||
gBundle.GetStringFromName("panel.back")
|
||||
);
|
||||
backButton.addEventListener("command", () => {
|
||||
// The panelmultiview element may change if the view is reused.
|
||||
this.node.panelMultiView.goBack();
|
||||
|
@ -1349,7 +1412,10 @@ var PanelView = class extends AssociatedToNode {
|
|||
}
|
||||
|
||||
// Ignore content inside a <toolbarbutton>
|
||||
if (element.tagName != "toolbarbutton" && element.closest("toolbarbutton")) {
|
||||
if (
|
||||
element.tagName != "toolbarbutton" &&
|
||||
element.closest("toolbarbutton")
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1360,9 +1426,13 @@ var PanelView = class extends AssociatedToNode {
|
|||
let previous = gMultiLineElementsMap.get(element);
|
||||
// We don't need to (re-)apply the workaround for invisible elements or
|
||||
// on elements we've seen before and haven't changed in the meantime.
|
||||
if (!bounds.width || !bounds.height ||
|
||||
(previous && element.textContent == previous.textContent &&
|
||||
bounds.width == previous.bounds.width)) {
|
||||
if (
|
||||
!bounds.width ||
|
||||
!bounds.height ||
|
||||
(previous &&
|
||||
element.textContent == previous.textContent &&
|
||||
bounds.width == previous.bounds.width)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1404,7 +1474,10 @@ var PanelView = class extends AssociatedToNode {
|
|||
|
||||
// Now we can make all the necessary DOM changes at once.
|
||||
for (let { element, bounds } of items) {
|
||||
gMultiLineElementsMap.set(element, { bounds, textContent: element.textContent });
|
||||
gMultiLineElementsMap.set(element, {
|
||||
bounds,
|
||||
textContent: element.textContent,
|
||||
});
|
||||
element.style.height = bounds.height + "px";
|
||||
}
|
||||
}
|
||||
|
@ -1415,10 +1488,15 @@ var PanelView = class extends AssociatedToNode {
|
|||
*/
|
||||
_isNavigableWithTabOnly(element) {
|
||||
let tag = element.localName;
|
||||
return tag == "menulist" || tag == "textbox" || tag == "input"
|
||||
|| tag == "textarea"
|
||||
// Allow tab to reach embedded documents.
|
||||
|| tag == "browser" || tag == "iframe";
|
||||
return (
|
||||
tag == "menulist" ||
|
||||
tag == "textbox" ||
|
||||
tag == "input" ||
|
||||
tag == "textarea" ||
|
||||
// Allow tab to reach embedded documents.
|
||||
tag == "browser" ||
|
||||
tag == "iframe"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1436,23 +1514,32 @@ var PanelView = class extends AssociatedToNode {
|
|||
if (bounds.width == 0 || bounds.height == 0) {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
if (node.tagName == "button" || node.tagName == "toolbarbutton" ||
|
||||
node.classList.contains("text-link") ||
|
||||
node.classList.contains("navigable") ||
|
||||
(!arrowKey && this._isNavigableWithTabOnly(node))) {
|
||||
if (
|
||||
node.tagName == "button" ||
|
||||
node.tagName == "toolbarbutton" ||
|
||||
node.classList.contains("text-link") ||
|
||||
node.classList.contains("navigable") ||
|
||||
(!arrowKey && this._isNavigableWithTabOnly(node))
|
||||
) {
|
||||
// Set the tabindex attribute to make sure the node is focusable.
|
||||
// Don't do this for browser and iframe elements because this breaks
|
||||
// tabbing behavior. They're already focusable anyway.
|
||||
if (node.tagName != "browser" && node.tagName != "iframe" &&
|
||||
!node.hasAttribute("tabindex")) {
|
||||
if (
|
||||
node.tagName != "browser" &&
|
||||
node.tagName != "iframe" &&
|
||||
!node.hasAttribute("tabindex")
|
||||
) {
|
||||
node.setAttribute("tabindex", "-1");
|
||||
}
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
}
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
};
|
||||
return this.document.createTreeWalker(this.node, NodeFilter.SHOW_ELEMENT,
|
||||
filter);
|
||||
return this.document.createTreeWalker(
|
||||
this.node,
|
||||
NodeFilter.SHOW_ELEMENT,
|
||||
filter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1500,13 +1587,17 @@ var PanelView = class extends AssociatedToNode {
|
|||
*/
|
||||
focusFirstNavigableElement(homeKey = false, skipBack = false) {
|
||||
// The home key is conceptually similar to the up/down arrow keys.
|
||||
let walker = homeKey ?
|
||||
this._arrowNavigableWalker : this._tabNavigableWalker;
|
||||
let walker = homeKey
|
||||
? this._arrowNavigableWalker
|
||||
: this._tabNavigableWalker;
|
||||
walker.currentNode = walker.root;
|
||||
this.selectedElement = walker.firstChild();
|
||||
if (skipBack && walker.currentNode
|
||||
&& walker.currentNode.classList.contains("subviewbutton-back")
|
||||
&& walker.nextNode()) {
|
||||
if (
|
||||
skipBack &&
|
||||
walker.currentNode &&
|
||||
walker.currentNode.classList.contains("subviewbutton-back") &&
|
||||
walker.nextNode()
|
||||
) {
|
||||
this.selectedElement = walker.currentNode;
|
||||
}
|
||||
this.focusSelectedElement(/* byKey */ true);
|
||||
|
@ -1520,8 +1611,7 @@ var PanelView = class extends AssociatedToNode {
|
|||
*/
|
||||
focusLastNavigableElement(endKey = false) {
|
||||
// The end key is conceptually similar to the up/down arrow keys.
|
||||
let walker = endKey ?
|
||||
this._arrowNavigableWalker : this._tabNavigableWalker;
|
||||
let walker = endKey ? this._arrowNavigableWalker : this._tabNavigableWalker;
|
||||
walker.currentNode = walker.root;
|
||||
this.selectedElement = walker.lastChild();
|
||||
this.focusSelectedElement(/* byKey */ true);
|
||||
|
@ -1536,8 +1626,9 @@ var PanelView = class extends AssociatedToNode {
|
|||
* @return {DOMNode} the element we selected.
|
||||
*/
|
||||
moveSelection(isDown, arrowKey = false) {
|
||||
let walker = arrowKey ?
|
||||
this._arrowNavigableWalker : this._tabNavigableWalker;
|
||||
let walker = arrowKey
|
||||
? this._arrowNavigableWalker
|
||||
: this._tabNavigableWalker;
|
||||
let oldSel = this.selectedElement;
|
||||
let newSel;
|
||||
if (oldSel) {
|
||||
|
@ -1582,8 +1673,13 @@ var PanelView = class extends AssociatedToNode {
|
|||
// We use Node.compareDocumentPosition because Node.contains doesn't
|
||||
// behave as expected for anonymous content; e.g. the input inside a
|
||||
// textbox.
|
||||
if (focus && !(this.node.compareDocumentPosition(focus)
|
||||
& Node.DOCUMENT_POSITION_CONTAINED_BY)) {
|
||||
if (
|
||||
focus &&
|
||||
!(
|
||||
this.node.compareDocumentPosition(focus) &
|
||||
Node.DOCUMENT_POSITION_CONTAINED_BY
|
||||
)
|
||||
) {
|
||||
focus = null;
|
||||
}
|
||||
|
||||
|
@ -1633,14 +1729,14 @@ var PanelView = class extends AssociatedToNode {
|
|||
if (tabOnly()) {
|
||||
break;
|
||||
}
|
||||
// Fall-through...
|
||||
// Fall-through...
|
||||
case "Tab": {
|
||||
if (isContextMenuOpen()) {
|
||||
break;
|
||||
}
|
||||
stop();
|
||||
let isDown = (keyCode == "ArrowDown") ||
|
||||
(keyCode == "Tab" && !event.shiftKey);
|
||||
let isDown =
|
||||
keyCode == "ArrowDown" || (keyCode == "Tab" && !event.shiftKey);
|
||||
let button = this.moveSelection(isDown, keyCode != "Tab");
|
||||
Services.focus.setFocus(button, Services.focus.FLAG_BYKEY);
|
||||
break;
|
||||
|
@ -1665,8 +1761,10 @@ var PanelView = class extends AssociatedToNode {
|
|||
break;
|
||||
}
|
||||
stop();
|
||||
if ((!this.window.RTL_UI && keyCode == "ArrowLeft") ||
|
||||
(this.window.RTL_UI && keyCode == "ArrowRight")) {
|
||||
if (
|
||||
(!this.window.RTL_UI && keyCode == "ArrowLeft") ||
|
||||
(this.window.RTL_UI && keyCode == "ArrowRight")
|
||||
) {
|
||||
this.node.panelMultiView.goBack();
|
||||
break;
|
||||
}
|
||||
|
@ -1685,8 +1783,9 @@ var PanelView = class extends AssociatedToNode {
|
|||
break;
|
||||
}
|
||||
let button = this.selectedElement;
|
||||
if (!button)
|
||||
if (!button) {
|
||||
break;
|
||||
}
|
||||
stop();
|
||||
|
||||
this._doingKeyboardActivation = true;
|
||||
|
@ -1699,9 +1798,13 @@ var PanelView = class extends AssociatedToNode {
|
|||
// there is no command event handler and the mousedown event executes the
|
||||
// action instead.
|
||||
button.doCommand();
|
||||
let dispEvent = new event.target.ownerGlobal.MouseEvent("mousedown", {"bubbles": true});
|
||||
let dispEvent = new event.target.ownerGlobal.MouseEvent("mousedown", {
|
||||
bubbles: true,
|
||||
});
|
||||
button.dispatchEvent(dispEvent);
|
||||
dispEvent = new event.target.ownerGlobal.MouseEvent("click", {"bubbles": true});
|
||||
dispEvent = new event.target.ownerGlobal.MouseEvent("click", {
|
||||
bubbles: true,
|
||||
});
|
||||
button.dispatchEvent(dispEvent);
|
||||
this._doingKeyboardActivation = false;
|
||||
break;
|
||||
|
|
|
@ -10,10 +10,13 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["SearchWidgetTracker"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm"
|
||||
);
|
||||
|
||||
const WIDGET_ID = "search-container";
|
||||
const PREF_NAME = "browser.search.widget.inNavBar";
|
||||
|
@ -31,8 +34,9 @@ const SearchWidgetTracker = {
|
|||
}
|
||||
};
|
||||
CustomizableUI.addListener(this);
|
||||
Services.prefs.addObserver(PREF_NAME,
|
||||
() => this.syncWidgetWithPreference());
|
||||
Services.prefs.addObserver(PREF_NAME, () =>
|
||||
this.syncWidgetWithPreference()
|
||||
);
|
||||
},
|
||||
|
||||
onAreaNodeRegistered(aArea) {
|
||||
|
@ -63,8 +67,11 @@ const SearchWidgetTracker = {
|
|||
if (newValue) {
|
||||
// The URL bar widget is always present in the navigation toolbar, so we
|
||||
// can simply read its position to place the search bar right after it.
|
||||
CustomizableUI.addWidgetToArea(WIDGET_ID, CustomizableUI.AREA_NAVBAR,
|
||||
CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
WIDGET_ID,
|
||||
CustomizableUI.AREA_NAVBAR,
|
||||
CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1
|
||||
);
|
||||
} else {
|
||||
CustomizableUI.removeWidgetFromArea(WIDGET_ID);
|
||||
}
|
||||
|
|
|
@ -2,12 +2,21 @@
|
|||
* 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/. */
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AppMenuNotifications",
|
||||
"resource://gre/modules/AppMenuNotifications.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "NewTabUtils",
|
||||
"resource://gre/modules/NewTabUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PanelMultiView",
|
||||
"resource:///modules/PanelMultiView.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"AppMenuNotifications",
|
||||
"resource://gre/modules/AppMenuNotifications.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"NewTabUtils",
|
||||
"resource://gre/modules/NewTabUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"PanelMultiView",
|
||||
"resource:///modules/PanelMultiView.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* Maintains the state and dispatches events for the main menu panel.
|
||||
|
@ -51,8 +60,12 @@ const PanelUI = {
|
|||
Services.obs.addObserver(this, "fullscreen-nav-toolbox");
|
||||
Services.obs.addObserver(this, "appMenu-notifications");
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "autoHideToolbarInFullScreen",
|
||||
"browser.fullscreen.autohide", false, (pref, previousValue, newValue) => {
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"autoHideToolbarInFullScreen",
|
||||
"browser.fullscreen.autohide",
|
||||
false,
|
||||
(pref, previousValue, newValue) => {
|
||||
// On OSX, or with autohide preffed off, MozDOMFullscreen is the only
|
||||
// event we care about, since fullscreen should behave just like non
|
||||
// fullscreen. Otherwise, we don't want to listen to these because
|
||||
|
@ -69,7 +82,9 @@ const PanelUI = {
|
|||
}
|
||||
|
||||
this._updateNotifications(false);
|
||||
}, autoHidePref => autoHidePref && Services.appinfo.OS !== "Darwin");
|
||||
},
|
||||
autoHidePref => autoHidePref && Services.appinfo.OS !== "Darwin"
|
||||
);
|
||||
|
||||
if (this.autoHideToolbarInFullScreen) {
|
||||
window.addEventListener("fullscreen", this);
|
||||
|
@ -78,11 +93,17 @@ const PanelUI = {
|
|||
window.addEventListener("MozDOMFullscreen:Exited", this);
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "libraryRecentHighlightsEnabled",
|
||||
"browser.library.activity-stream.enabled", false, (pref, previousValue, newValue) => {
|
||||
if (!newValue)
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"libraryRecentHighlightsEnabled",
|
||||
"browser.library.activity-stream.enabled",
|
||||
false,
|
||||
(pref, previousValue, newValue) => {
|
||||
if (!newValue) {
|
||||
this.clearLibraryRecentHighlights();
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
window.addEventListener("activate", this);
|
||||
CustomizableUI.addListener(this);
|
||||
|
@ -96,10 +117,17 @@ const PanelUI = {
|
|||
this.overflowFixedList.hidden = false;
|
||||
// Also unhide the separator. We use CSS to hide/show it based on the panel's content.
|
||||
this.overflowFixedList.previousElementSibling.hidden = false;
|
||||
CustomizableUI.registerMenuPanel(this.overflowFixedList, CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.registerMenuPanel(
|
||||
this.overflowFixedList,
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
this.updateOverflowStatus();
|
||||
|
||||
Services.obs.notifyObservers(null, "appMenu-notifications-request", "refresh");
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"appMenu-notifications-request",
|
||||
"refresh"
|
||||
);
|
||||
|
||||
this._initialized = true;
|
||||
},
|
||||
|
@ -111,15 +139,16 @@ const PanelUI = {
|
|||
let id = v;
|
||||
this.__defineGetter__(getKey, function() {
|
||||
delete this[getKey];
|
||||
return this[getKey] = document.getElementById(id);
|
||||
return (this[getKey] = document.getElementById(id));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_eventListenersAdded: false,
|
||||
_ensureEventListenersAdded() {
|
||||
if (this._eventListenersAdded)
|
||||
if (this._eventListenersAdded) {
|
||||
return;
|
||||
}
|
||||
this._addEventListeners();
|
||||
},
|
||||
|
||||
|
@ -191,8 +220,10 @@ const PanelUI = {
|
|||
(async () => {
|
||||
await this.ensureReady();
|
||||
|
||||
if (this.panel.state == "open" ||
|
||||
document.documentElement.hasAttribute("customizing")) {
|
||||
if (
|
||||
this.panel.state == "open" ||
|
||||
document.documentElement.hasAttribute("customizing")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -239,24 +270,23 @@ const PanelUI = {
|
|||
|
||||
handleEvent(aEvent) {
|
||||
// Ignore context menus and menu button menus showing and hiding:
|
||||
if (aEvent.type.startsWith("popup") &&
|
||||
aEvent.target != this.panel) {
|
||||
if (aEvent.type.startsWith("popup") && aEvent.target != this.panel) {
|
||||
return;
|
||||
}
|
||||
switch (aEvent.type) {
|
||||
case "popupshowing":
|
||||
updateEditUIVisibility();
|
||||
// Fall through
|
||||
// Fall through
|
||||
case "popupshown":
|
||||
if (aEvent.type == "popupshown") {
|
||||
CustomizableUI.addPanelCloseListeners(this.panel);
|
||||
}
|
||||
// Fall through
|
||||
// Fall through
|
||||
case "popuphiding":
|
||||
if (aEvent.type == "popuphiding") {
|
||||
updateEditUIVisibility();
|
||||
}
|
||||
// Fall through
|
||||
// Fall through
|
||||
case "popuphidden":
|
||||
this._updateNotifications();
|
||||
this._updatePanelButton(aEvent.target);
|
||||
|
@ -265,8 +295,9 @@ const PanelUI = {
|
|||
}
|
||||
break;
|
||||
case "mousedown":
|
||||
if (aEvent.button == 0)
|
||||
if (aEvent.button == 0) {
|
||||
this.toggle(aEvent);
|
||||
}
|
||||
break;
|
||||
case "keypress":
|
||||
if (aEvent.key == " " || aEvent.key == "Enter") {
|
||||
|
@ -343,15 +374,35 @@ const PanelUI = {
|
|||
if (aEvent.type == "mousedown" && aEvent.button != 0) {
|
||||
return;
|
||||
}
|
||||
if (aEvent.type == "keypress" && aEvent.key != " " &&
|
||||
aEvent.key != "Enter") {
|
||||
if (
|
||||
aEvent.type == "keypress" &&
|
||||
aEvent.key != " " &&
|
||||
aEvent.key != "Enter"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (aEvent.type == "command" && aEvent.inputSource != null) {
|
||||
// Synthesize a new DOM mouse event to pass on the inputSource.
|
||||
domEvent = document.createEvent("MouseEvent");
|
||||
domEvent.initNSMouseEvent("click", true, true, null, 0, aEvent.screenX, aEvent.screenY,
|
||||
0, 0, false, false, false, false, 0, aEvent.target, 0, aEvent.inputSource);
|
||||
domEvent.initNSMouseEvent(
|
||||
"click",
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
0,
|
||||
aEvent.screenX,
|
||||
aEvent.screenY,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
aEvent.target,
|
||||
0,
|
||||
aEvent.inputSource
|
||||
);
|
||||
} else if (aEvent.mozInputSource != null || aEvent.type == "keypress") {
|
||||
domEvent = aEvent;
|
||||
}
|
||||
|
@ -365,7 +416,9 @@ const PanelUI = {
|
|||
}
|
||||
|
||||
if (!aAnchor) {
|
||||
Cu.reportError("Expected an anchor when opening subview with id: " + aViewId);
|
||||
Cu.reportError(
|
||||
"Expected an anchor when opening subview with id: " + aViewId
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -390,10 +443,14 @@ const PanelUI = {
|
|||
}
|
||||
tempPanel.setAttribute("context", "");
|
||||
tempPanel.setAttribute("photon", true);
|
||||
document.getElementById(CustomizableUI.AREA_NAVBAR).appendChild(tempPanel);
|
||||
document
|
||||
.getElementById(CustomizableUI.AREA_NAVBAR)
|
||||
.appendChild(tempPanel);
|
||||
// If the view has a footer, set a convenience class on the panel.
|
||||
tempPanel.classList.toggle("cui-widget-panelWithFooter",
|
||||
viewNode.querySelector(".panel-subview-footer"));
|
||||
tempPanel.classList.toggle(
|
||||
"cui-widget-panelWithFooter",
|
||||
viewNode.querySelector(".panel-subview-footer")
|
||||
);
|
||||
|
||||
let multiView = document.createXULElement("panelmultiview");
|
||||
multiView.setAttribute("id", "customizationui-widget-multiview");
|
||||
|
@ -448,8 +505,9 @@ const PanelUI = {
|
|||
* @param {panelview} viewNode The library view.
|
||||
*/
|
||||
ensureLibraryInitialized(viewNode) {
|
||||
if (viewNode != this.libraryView || viewNode._initialized)
|
||||
if (viewNode != this.libraryView || viewNode._initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewNode._initialized = true;
|
||||
viewNode.addEventListener("ViewShowing", this);
|
||||
|
@ -487,17 +545,19 @@ const PanelUI = {
|
|||
* view with the results.
|
||||
*/
|
||||
async fetchAndPopulateLibraryRecentHighlights() {
|
||||
let highlights = await NewTabUtils.activityStreamLinks.getHighlights({
|
||||
// As per bug 1402023, hard-coded limit, until Activity Stream develops a
|
||||
// richer list.
|
||||
numItems: 6,
|
||||
withFavicons: true,
|
||||
excludePocket: true,
|
||||
}).catch(ex => {
|
||||
// Just hide the section if we can't retrieve the items from the database.
|
||||
Cu.reportError(ex);
|
||||
return [];
|
||||
});
|
||||
let highlights = await NewTabUtils.activityStreamLinks
|
||||
.getHighlights({
|
||||
// As per bug 1402023, hard-coded limit, until Activity Stream develops a
|
||||
// richer list.
|
||||
numItems: 6,
|
||||
withFavicons: true,
|
||||
excludePocket: true,
|
||||
})
|
||||
.catch(ex => {
|
||||
// Just hide the section if we can't retrieve the items from the database.
|
||||
Cu.reportError(ex);
|
||||
return [];
|
||||
});
|
||||
|
||||
// Since the call above is asynchronous, the panel may be already hidden
|
||||
// at this point, but we still prepare the items for the next time the
|
||||
|
@ -509,12 +569,16 @@ const PanelUI = {
|
|||
}
|
||||
|
||||
let container = this.libraryRecentHighlights;
|
||||
container.hidden = container.previousElementSibling.hidden =
|
||||
container.previousElementSibling.previousElementSibling.hidden = false;
|
||||
container.hidden = container.previousElementSibling.hidden = container.previousElementSibling.previousElementSibling.hidden = false;
|
||||
let fragment = document.createDocumentFragment();
|
||||
for (let highlight of highlights) {
|
||||
let button = document.createXULElement("toolbarbutton");
|
||||
button.classList.add("subviewbutton", "highlight", "subviewbutton-iconic", "bookmark-item");
|
||||
button.classList.add(
|
||||
"subviewbutton",
|
||||
"highlight",
|
||||
"subviewbutton-iconic",
|
||||
"bookmark-item"
|
||||
);
|
||||
let title = highlight.title || highlight.url;
|
||||
button.setAttribute("label", title);
|
||||
button.setAttribute("tooltiptext", title);
|
||||
|
@ -548,8 +612,7 @@ const PanelUI = {
|
|||
while (container.firstChild) {
|
||||
container.firstChild.remove();
|
||||
}
|
||||
container.hidden = container.previousElementSibling.hidden =
|
||||
container.previousElementSibling.previousElementSibling.hidden = true;
|
||||
container.hidden = container.previousElementSibling.hidden = container.previousElementSibling.previousElementSibling.hidden = true;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -567,7 +630,9 @@ const PanelUI = {
|
|||
CustomizableUI.hidePanelForNode(button);
|
||||
}
|
||||
window.openUILink(button._highlight.url, event, {
|
||||
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
|
||||
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal(
|
||||
{}
|
||||
),
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -613,8 +678,8 @@ const PanelUI = {
|
|||
* on the state of the panel.
|
||||
*/
|
||||
_updatePanelButton() {
|
||||
this.menuButton.open = this.panel.state == "open" ||
|
||||
this.panel.state == "showing";
|
||||
this.menuButton.open =
|
||||
this.panel.state == "open" || this.panel.state == "showing";
|
||||
},
|
||||
|
||||
_onHelpViewShow(aEvent) {
|
||||
|
@ -631,16 +696,20 @@ const PanelUI = {
|
|||
}
|
||||
|
||||
// Add the current set of menuitems of the Help menu to this view
|
||||
let menuItems = Array.prototype.slice.call(helpMenu.getElementsByTagName("menuitem"));
|
||||
let menuItems = Array.prototype.slice.call(
|
||||
helpMenu.getElementsByTagName("menuitem")
|
||||
);
|
||||
let fragment = document.createDocumentFragment();
|
||||
for (let node of menuItems) {
|
||||
if (node.hidden)
|
||||
if (node.hidden) {
|
||||
continue;
|
||||
}
|
||||
let button = document.createXULElement("toolbarbutton");
|
||||
// Copy specific attributes from a menuitem of the Help menu
|
||||
for (let attrName of attrs) {
|
||||
if (!node.hasAttribute(attrName))
|
||||
if (!node.hasAttribute(attrName)) {
|
||||
continue;
|
||||
}
|
||||
button.setAttribute(attrName, node.getAttribute(attrName));
|
||||
}
|
||||
button.setAttribute("class", "subviewbutton");
|
||||
|
@ -654,16 +723,23 @@ const PanelUI = {
|
|||
return;
|
||||
}
|
||||
|
||||
let tooltipId = AppConstants.platform == "macosx" ?
|
||||
"quit-button.tooltiptext.mac" :
|
||||
"quit-button.tooltiptext.linux2";
|
||||
let tooltipId =
|
||||
AppConstants.platform == "macosx"
|
||||
? "quit-button.tooltiptext.mac"
|
||||
: "quit-button.tooltiptext.linux2";
|
||||
|
||||
let brands = Services.strings.createBundle("chrome://branding/locale/brand.properties");
|
||||
let brands = Services.strings.createBundle(
|
||||
"chrome://branding/locale/brand.properties"
|
||||
);
|
||||
let stringArgs = [brands.GetStringFromName("brandShortName")];
|
||||
|
||||
let key = document.getElementById("key_quitApplication");
|
||||
stringArgs.push(ShortcutUtils.prettifyShortcut(key));
|
||||
let tooltipString = CustomizableUI.getLocalizedProperty({x: tooltipId}, "x", stringArgs);
|
||||
let tooltipString = CustomizableUI.getLocalizedProperty(
|
||||
{ x: tooltipId },
|
||||
"x",
|
||||
stringArgs
|
||||
);
|
||||
let quitButton = document.getElementById("PanelUI-quit");
|
||||
quitButton.setAttribute("tooltiptext", tooltipString);
|
||||
},
|
||||
|
@ -684,13 +760,17 @@ const PanelUI = {
|
|||
return;
|
||||
}
|
||||
|
||||
if ((window.fullScreen && FullScreen.navToolboxHidden) || document.fullscreenElement) {
|
||||
if (
|
||||
(window.fullScreen && FullScreen.navToolboxHidden) ||
|
||||
document.fullscreenElement
|
||||
) {
|
||||
this._hidePopup();
|
||||
return;
|
||||
}
|
||||
|
||||
let doorhangers =
|
||||
notifications.filter(n => !n.dismissed && !n.options.badgeOnly);
|
||||
let doorhangers = notifications.filter(
|
||||
n => !n.dismissed && !n.options.badgeOnly
|
||||
);
|
||||
|
||||
if (this.panel.state == "showing" || this.panel.state == "open") {
|
||||
// If the menu is already showing, then we need to dismiss all notifications
|
||||
|
@ -708,7 +788,10 @@ const PanelUI = {
|
|||
}
|
||||
} else if (doorhangers.length > 0) {
|
||||
// Only show the doorhanger if the window is focused and not fullscreen
|
||||
if ((window.fullScreen && this.autoHideToolbarInFullScreen) || Services.focus.activeWindow !== window) {
|
||||
if (
|
||||
(window.fullScreen && this.autoHideToolbarInFullScreen) ||
|
||||
Services.focus.activeWindow !== window
|
||||
) {
|
||||
this._hidePopup();
|
||||
this._showBadge(doorhangers[0]);
|
||||
this._showBannerItem(doorhangers[0]);
|
||||
|
@ -743,10 +826,13 @@ const PanelUI = {
|
|||
MozXULElement.insertFTLIfNeeded("browser/appMenuNotifications.ftl");
|
||||
|
||||
// After Fluent files are loaded into document replace data-lazy-l10n-ids with actual ones
|
||||
document.getElementById("appMenu-notification-popup").querySelectorAll("[data-lazy-l10n-id]").forEach(el => {
|
||||
el.setAttribute("data-l10n-id", el.getAttribute("data-lazy-l10n-id"));
|
||||
el.removeAttribute("data-lazy-l10n-id");
|
||||
});
|
||||
document
|
||||
.getElementById("appMenu-notification-popup")
|
||||
.querySelectorAll("[data-lazy-l10n-id]")
|
||||
.forEach(el => {
|
||||
el.setAttribute("data-l10n-id", el.getAttribute("data-lazy-l10n-id"));
|
||||
el.removeAttribute("data-lazy-l10n-id");
|
||||
});
|
||||
|
||||
this.notificationPanel.openPopup(anchor, "bottomcenter topright");
|
||||
},
|
||||
|
@ -780,9 +866,14 @@ const PanelUI = {
|
|||
let popupnotification = document.getElementById(popupnotificationID);
|
||||
|
||||
popupnotification.setAttribute("id", popupnotificationID);
|
||||
popupnotification.setAttribute("buttoncommand", "PanelUI._onNotificationButtonEvent(event, 'buttoncommand');");
|
||||
popupnotification.setAttribute("secondarybuttoncommand",
|
||||
"PanelUI._onNotificationButtonEvent(event, 'secondarybuttoncommand');");
|
||||
popupnotification.setAttribute(
|
||||
"buttoncommand",
|
||||
"PanelUI._onNotificationButtonEvent(event, 'buttoncommand');"
|
||||
);
|
||||
popupnotification.setAttribute(
|
||||
"secondarybuttoncommand",
|
||||
"PanelUI._onNotificationButtonEvent(event, 'secondarybuttoncommand');"
|
||||
);
|
||||
|
||||
if (notification.options.message) {
|
||||
let desc = this._formatDescriptionMessage(notification);
|
||||
|
@ -837,11 +928,17 @@ const PanelUI = {
|
|||
_onNotificationButtonEvent(event, type) {
|
||||
let notificationEl = getNotificationFromElement(event.originalTarget);
|
||||
|
||||
if (!notificationEl)
|
||||
throw new Error("PanelUI._onNotificationButtonEvent: couldn't find notification element");
|
||||
if (!notificationEl) {
|
||||
throw new Error(
|
||||
"PanelUI._onNotificationButtonEvent: couldn't find notification element"
|
||||
);
|
||||
}
|
||||
|
||||
if (!notificationEl.notification)
|
||||
throw new Error("PanelUI._onNotificationButtonEvent: couldn't find notification");
|
||||
if (!notificationEl.notification) {
|
||||
throw new Error(
|
||||
"PanelUI._onNotificationButtonEvent: couldn't find notification"
|
||||
);
|
||||
}
|
||||
|
||||
let notification = notificationEl.notification;
|
||||
|
||||
|
@ -854,16 +951,23 @@ const PanelUI = {
|
|||
|
||||
_onBannerItemSelected(event) {
|
||||
let target = event.originalTarget;
|
||||
if (!target.notification)
|
||||
throw new Error("menucommand target has no associated action/notification");
|
||||
if (!target.notification) {
|
||||
throw new Error(
|
||||
"menucommand target has no associated action/notification"
|
||||
);
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
AppMenuNotifications.callMainAction(window, target.notification, false);
|
||||
},
|
||||
|
||||
_getPopupId(notification) { return "appMenu-" + notification.id + "-notification"; },
|
||||
_getPopupId(notification) {
|
||||
return "appMenu-" + notification.id + "-notification";
|
||||
},
|
||||
|
||||
_getBadgeStatus(notification) { return notification.id; },
|
||||
_getBadgeStatus(notification) {
|
||||
return notification.id;
|
||||
},
|
||||
|
||||
_getPanelAnchor(candidate) {
|
||||
let iconAnchor = candidate.badgeStack || candidate.icon;
|
||||
|
|
|
@ -10,12 +10,19 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["CustomizableUITestUtils"];
|
||||
|
||||
const {Assert} = ChromeUtils.import("resource://testing-common/Assert.jsm");
|
||||
const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
|
||||
const {TestUtils} = ChromeUtils.import("resource://testing-common/TestUtils.jsm");
|
||||
const { Assert } = ChromeUtils.import("resource://testing-common/Assert.jsm");
|
||||
const { BrowserTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/BrowserTestUtils.jsm"
|
||||
);
|
||||
const { TestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/TestUtils.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm"
|
||||
);
|
||||
|
||||
class CustomizableUITestUtils {
|
||||
/**
|
||||
|
@ -35,9 +42,12 @@ class CustomizableUITestUtils {
|
|||
if (panel.state == "open") {
|
||||
// Some tests may intermittently leave the panel open. We report this, but
|
||||
// don't fail so we don't introduce new intermittent test failures.
|
||||
Assert.ok(true, "A previous test left the panel open. This should be" +
|
||||
" fixed, but we can still do a best-effort recovery and" +
|
||||
" assume that the requested view will be made visible.");
|
||||
Assert.ok(
|
||||
true,
|
||||
"A previous test left the panel open. This should be" +
|
||||
" fixed, but we can still do a best-effort recovery and" +
|
||||
" assume that the requested view will be made visible."
|
||||
);
|
||||
await openFn();
|
||||
return;
|
||||
}
|
||||
|
@ -48,9 +58,12 @@ class CustomizableUITestUtils {
|
|||
// or may not be fully closed when the following test runs. We handle this
|
||||
// case gracefully so we don't risk introducing new intermittent test
|
||||
// failures that may show up at a later time.
|
||||
Assert.ok(true, "A previous test requested the panel to close but" +
|
||||
" didn't wait for the operation to complete. While" +
|
||||
" the test should be fixed, we can still continue.");
|
||||
Assert.ok(
|
||||
true,
|
||||
"A previous test requested the panel to close but" +
|
||||
" didn't wait for the operation to complete. While" +
|
||||
" the test should be fixed, we can still continue."
|
||||
);
|
||||
} else {
|
||||
Assert.equal(panel.state, "closed", "The panel is closed to begin with.");
|
||||
}
|
||||
|
@ -76,16 +89,20 @@ class CustomizableUITestUtils {
|
|||
* Opens the main menu and waits for it to become fully interactive.
|
||||
*/
|
||||
async openMainMenu() {
|
||||
await this.openPanelMultiView(this.PanelUI.panel, this.PanelUI.mainView,
|
||||
() => this.PanelUI.show());
|
||||
await this.openPanelMultiView(
|
||||
this.PanelUI.panel,
|
||||
this.PanelUI.mainView,
|
||||
() => this.PanelUI.show()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the main menu and waits for the operation to complete.
|
||||
*/
|
||||
async hideMainMenu() {
|
||||
await this.hidePanelMultiView(this.PanelUI.panel,
|
||||
() => this.PanelUI.hide());
|
||||
await this.hidePanelMultiView(this.PanelUI.panel, () =>
|
||||
this.PanelUI.hide()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,8 +114,10 @@ class CustomizableUITestUtils {
|
|||
*/
|
||||
async addSearchBar() {
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"search-container", CustomizableUI.AREA_NAVBAR,
|
||||
CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1);
|
||||
"search-container",
|
||||
CustomizableUI.AREA_NAVBAR,
|
||||
CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1
|
||||
);
|
||||
|
||||
// addWidgetToArea adds the search bar into the nav bar first. If the
|
||||
// search bar overflows, OverflowableToolbar for the nav bar moves the
|
||||
|
@ -113,7 +132,9 @@ class CustomizableUITestUtils {
|
|||
// Check if the OverflowableToolbar is handling the overflow event.
|
||||
// _lastOverflowCounter property is incremented synchronously at the top
|
||||
// of the overflow event handler, and is set to 0 when it finishes.
|
||||
let navbar = this.window.document.getElementById(CustomizableUI.AREA_NAVBAR);
|
||||
let navbar = this.window.document.getElementById(
|
||||
CustomizableUI.AREA_NAVBAR
|
||||
);
|
||||
await TestUtils.waitForCondition(() => {
|
||||
// This test is using a private variable, that can be renamed or removed
|
||||
// in the future. Use === so that this won't silently skip if the value
|
||||
|
@ -131,9 +152,11 @@ class CustomizableUITestUtils {
|
|||
// We cannot use navbar's property to check if overflow happens, since it
|
||||
// can be different widget than the search bar that overflows.
|
||||
if (searchbar.closest("#widget-overflow")) {
|
||||
throw new Error("The search bar should not overflow from the nav bar. " +
|
||||
"This test fails if the screen resolution is small and " +
|
||||
"the search bar overflows from the nav bar.");
|
||||
throw new Error(
|
||||
"The search bar should not overflow from the nav bar. " +
|
||||
"This test fails if the screen resolution is small and " +
|
||||
"the search bar overflows from the nav bar."
|
||||
);
|
||||
}
|
||||
|
||||
return searchbar;
|
||||
|
|
|
@ -4,16 +4,22 @@
|
|||
"use strict";
|
||||
|
||||
function simulateItemDragAndEnd(aToDrag, aTarget) {
|
||||
var ds = Cc["@mozilla.org/widget/dragservice;1"].
|
||||
getService(Ci.nsIDragService);
|
||||
var ds = Cc["@mozilla.org/widget/dragservice;1"].getService(
|
||||
Ci.nsIDragService
|
||||
);
|
||||
|
||||
ds.startDragSession();
|
||||
try {
|
||||
var [result, dataTransfer] = EventUtils.synthesizeDragOver(aToDrag.parentNode, aTarget);
|
||||
var [result, dataTransfer] = EventUtils.synthesizeDragOver(
|
||||
aToDrag.parentNode,
|
||||
aTarget
|
||||
);
|
||||
EventUtils.synthesizeDropAfterDragOver(result, dataTransfer, aTarget);
|
||||
// Send dragend to move dragging item back to initial place.
|
||||
EventUtils.sendDragEvent({ type: "dragend", dataTransfer },
|
||||
aToDrag.parentNode);
|
||||
EventUtils.sendDragEvent(
|
||||
{ type: "dragend", dataTransfer },
|
||||
aToDrag.parentNode
|
||||
);
|
||||
} finally {
|
||||
ds.endDragSession(true);
|
||||
}
|
||||
|
@ -59,7 +65,6 @@ add_task(async function checkAddingToToolbar() {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
add_task(async function checkDragging() {
|
||||
let startArea = CustomizableUI.AREA_TABSTRIP;
|
||||
let targetArea = CustomizableUI.AREA_FIXED_OVERFLOW_PANEL;
|
||||
|
@ -81,32 +86,45 @@ add_task(async function checkDragging() {
|
|||
|
||||
await startCustomizing();
|
||||
let existingSpecial = null;
|
||||
existingSpecial = gCustomizeMode.visiblePalette.querySelector("toolbarspring");
|
||||
ok(existingSpecial, "Should have a flexible space in the palette by default in photon");
|
||||
existingSpecial = gCustomizeMode.visiblePalette.querySelector(
|
||||
"toolbarspring"
|
||||
);
|
||||
ok(
|
||||
existingSpecial,
|
||||
"Should have a flexible space in the palette by default in photon"
|
||||
);
|
||||
for (let id of elementsToMove) {
|
||||
simulateItemDragAndEnd(document.getElementById(id), document.getElementById(targetArea));
|
||||
simulateItemDragAndEnd(
|
||||
document.getElementById(id),
|
||||
document.getElementById(targetArea)
|
||||
);
|
||||
}
|
||||
|
||||
assertAreaPlacements(startArea, placementsWithSpecials);
|
||||
assertAreaPlacements(targetArea, startingTargetPlacements);
|
||||
|
||||
for (let id of elementsToMove) {
|
||||
simulateItemDrag(document.getElementById(id), gCustomizeMode.visiblePalette);
|
||||
simulateItemDrag(
|
||||
document.getElementById(id),
|
||||
gCustomizeMode.visiblePalette
|
||||
);
|
||||
}
|
||||
|
||||
assertAreaPlacements(startArea, startingToolbarPlacements);
|
||||
assertAreaPlacements(targetArea, startingTargetPlacements);
|
||||
|
||||
let allSpecials = gCustomizeMode.visiblePalette.querySelectorAll("toolbarspring,toolbarseparator,toolbarspacer");
|
||||
let allSpecials = gCustomizeMode.visiblePalette.querySelectorAll(
|
||||
"toolbarspring,toolbarseparator,toolbarspacer"
|
||||
);
|
||||
allSpecials = [...allSpecials].filter(special => special != existingSpecial);
|
||||
ok(!allSpecials.length,
|
||||
"No (new) specials should make it to the palette alive.");
|
||||
ok(
|
||||
!allSpecials.length,
|
||||
"No (new) specials should make it to the palette alive."
|
||||
);
|
||||
await endCustomizing();
|
||||
});
|
||||
|
||||
|
||||
add_task(async function asyncCleanup() {
|
||||
await endCustomizing();
|
||||
CustomizableUI.reset();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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/. */
|
||||
* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -12,7 +12,7 @@ const MAX_THEME_COUNT = 6; // Not exposed from CustomizeMode.jsm
|
|||
async function installTheme(id) {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id}},
|
||||
applications: { gecko: { id } },
|
||||
manifest_version: 2,
|
||||
name: "Theme " + id,
|
||||
description: "wow. such theme.",
|
||||
|
@ -29,8 +29,10 @@ async function installTheme(id) {
|
|||
add_task(async function() {
|
||||
await startCustomizing();
|
||||
// Check restore defaults button is disabled.
|
||||
ok(document.getElementById("customization-reset-button").disabled,
|
||||
"Reset button should start out disabled");
|
||||
ok(
|
||||
document.getElementById("customization-reset-button").disabled,
|
||||
"Reset button should start out disabled"
|
||||
);
|
||||
|
||||
let themesButton = document.getElementById("customization-lwtheme-button");
|
||||
let themesButtonIcon = themesButton.icon;
|
||||
|
@ -40,11 +42,16 @@ add_task(async function() {
|
|||
// case the icon is determined by CSS (which will be the default
|
||||
// theme's icon).
|
||||
if (iconURL) {
|
||||
ok((/default/i).test(themesButtonIcon.style.backgroundImage),
|
||||
`Button should show default theme thumbnail - was: "${iconURL}"`);
|
||||
ok(
|
||||
/default/i.test(themesButtonIcon.style.backgroundImage),
|
||||
`Button should show default theme thumbnail - was: "${iconURL}"`
|
||||
);
|
||||
} else {
|
||||
is(iconURL, "",
|
||||
`Button should show default theme thumbnail (empty string) - was: "${iconURL}"`);
|
||||
is(
|
||||
iconURL,
|
||||
"",
|
||||
`Button should show default theme thumbnail (empty string) - was: "${iconURL}"`
|
||||
);
|
||||
}
|
||||
let popup = document.getElementById("customization-lwtheme-menu");
|
||||
|
||||
|
@ -66,16 +73,31 @@ add_task(async function() {
|
|||
let header = document.getElementById("customization-lwtheme-menu-header");
|
||||
let footer = document.getElementById("customization-lwtheme-menu-footer");
|
||||
|
||||
is(header.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling, footer,
|
||||
"There should only be three themes (default, light, dark) in the 'My Themes' section by default");
|
||||
is(header.nextElementSibling.theme.id, DEFAULT_THEME_ID,
|
||||
"The first theme should be the default theme");
|
||||
is(header.nextElementSibling.nextElementSibling.theme.id, LIGHT_THEME_ID,
|
||||
"The second theme should be the light theme");
|
||||
is(header.nextElementSibling.nextElementSibling.nextElementSibling.theme.id, DARK_THEME_ID,
|
||||
"The third theme should be the dark theme");
|
||||
is(
|
||||
header.nextElementSibling.nextElementSibling.nextElementSibling
|
||||
.nextElementSibling,
|
||||
footer,
|
||||
"There should only be three themes (default, light, dark) in the 'My Themes' section by default"
|
||||
);
|
||||
is(
|
||||
header.nextElementSibling.theme.id,
|
||||
DEFAULT_THEME_ID,
|
||||
"The first theme should be the default theme"
|
||||
);
|
||||
is(
|
||||
header.nextElementSibling.nextElementSibling.theme.id,
|
||||
LIGHT_THEME_ID,
|
||||
"The second theme should be the light theme"
|
||||
);
|
||||
is(
|
||||
header.nextElementSibling.nextElementSibling.nextElementSibling.theme.id,
|
||||
DARK_THEME_ID,
|
||||
"The third theme should be the dark theme"
|
||||
);
|
||||
|
||||
let themeChangedPromise = promiseObserverNotified("lightweight-theme-styling-update");
|
||||
let themeChangedPromise = promiseObserverNotified(
|
||||
"lightweight-theme-styling-update"
|
||||
);
|
||||
header.nextElementSibling.nextElementSibling.doCommand(); // Select light theme
|
||||
info("Clicked on light theme");
|
||||
await themeChangedPromise;
|
||||
|
@ -84,20 +106,29 @@ add_task(async function() {
|
|||
await TestUtils.waitForCondition(() => !button.disabled);
|
||||
|
||||
// Check restore defaults button is enabled.
|
||||
ok(!button.disabled,
|
||||
"Reset button should not be disabled anymore");
|
||||
ok((/light/i).test(themesButtonIcon.style.backgroundImage),
|
||||
`Button should show light theme thumbnail - was: "${themesButtonIcon.style.backgroundImage}"`);
|
||||
ok(!button.disabled, "Reset button should not be disabled anymore");
|
||||
ok(
|
||||
/light/i.test(themesButtonIcon.style.backgroundImage),
|
||||
`Button should show light theme thumbnail - was: "${
|
||||
themesButtonIcon.style.backgroundImage
|
||||
}"`
|
||||
);
|
||||
|
||||
popupShownPromise = popupShown(popup);
|
||||
EventUtils.synthesizeMouseAtCenter(themesButton, {});
|
||||
info("Clicked on themes button a third time");
|
||||
await popupShownPromise;
|
||||
|
||||
let activeThemes = popup.querySelectorAll("toolbarbutton.customization-lwtheme-menu-theme[active]");
|
||||
let activeThemes = popup.querySelectorAll(
|
||||
"toolbarbutton.customization-lwtheme-menu-theme[active]"
|
||||
);
|
||||
is(activeThemes.length, 1, "Exactly 1 theme should be selected");
|
||||
if (activeThemes.length > 0) {
|
||||
is(activeThemes[0].theme.id, LIGHT_THEME_ID, "Light theme should be selected");
|
||||
is(
|
||||
activeThemes[0].theme.id,
|
||||
LIGHT_THEME_ID,
|
||||
"Light theme should be selected"
|
||||
);
|
||||
}
|
||||
popup.hidePopup();
|
||||
|
||||
|
@ -108,23 +139,35 @@ add_task(async function() {
|
|||
}
|
||||
addons = await Promise.all(addons);
|
||||
|
||||
ok(!themesButtonIcon.style.backgroundImage,
|
||||
`Button should show fallback theme thumbnail - was: "${themesButtonIcon.style.backgroundImage}"`);
|
||||
ok(
|
||||
!themesButtonIcon.style.backgroundImage,
|
||||
`Button should show fallback theme thumbnail - was: "${
|
||||
themesButtonIcon.style.backgroundImage
|
||||
}"`
|
||||
);
|
||||
|
||||
popupShownPromise = popupShown(popup);
|
||||
EventUtils.synthesizeMouseAtCenter(themesButton, {});
|
||||
info("Clicked on themes button a fourth time");
|
||||
await popupShownPromise;
|
||||
|
||||
activeThemes = popup.querySelectorAll("toolbarbutton.customization-lwtheme-menu-theme[active]");
|
||||
activeThemes = popup.querySelectorAll(
|
||||
"toolbarbutton.customization-lwtheme-menu-theme[active]"
|
||||
);
|
||||
is(activeThemes.length, 1, "Exactly 1 theme should be selected");
|
||||
if (activeThemes.length > 0) {
|
||||
is(activeThemes[0].theme.id, "my-theme-5@example.com", "Last installed theme should be selected");
|
||||
is(
|
||||
activeThemes[0].theme.id,
|
||||
"my-theme-5@example.com",
|
||||
"Last installed theme should be selected"
|
||||
);
|
||||
}
|
||||
|
||||
let firstLWTheme = footer.previousElementSibling;
|
||||
let firstLWThemeId = firstLWTheme.theme.id;
|
||||
themeChangedPromise = promiseObserverNotified("lightweight-theme-styling-update");
|
||||
themeChangedPromise = promiseObserverNotified(
|
||||
"lightweight-theme-styling-update"
|
||||
);
|
||||
firstLWTheme.doCommand();
|
||||
info("Clicked on first theme");
|
||||
await themeChangedPromise;
|
||||
|
@ -136,21 +179,34 @@ add_task(async function() {
|
|||
info("Clicked on themes button");
|
||||
await popupShownPromise;
|
||||
|
||||
activeThemes = popup.querySelectorAll("toolbarbutton.customization-lwtheme-menu-theme[active]");
|
||||
activeThemes = popup.querySelectorAll(
|
||||
"toolbarbutton.customization-lwtheme-menu-theme[active]"
|
||||
);
|
||||
is(activeThemes.length, 1, "Exactly 1 theme should be selected");
|
||||
if (activeThemes.length > 0) {
|
||||
is(activeThemes[0].theme.id, firstLWThemeId, "First theme should be selected");
|
||||
is(
|
||||
activeThemes[0].theme.id,
|
||||
firstLWThemeId,
|
||||
"First theme should be selected"
|
||||
);
|
||||
}
|
||||
|
||||
is(header.nextElementSibling.theme.id, DEFAULT_THEME_ID, "The first theme should be the Default theme");
|
||||
is(
|
||||
header.nextElementSibling.theme.id,
|
||||
DEFAULT_THEME_ID,
|
||||
"The first theme should be the Default theme"
|
||||
);
|
||||
let themeCount = 0;
|
||||
let iterNode = header;
|
||||
while (iterNode.nextElementSibling && iterNode.nextElementSibling.theme) {
|
||||
themeCount++;
|
||||
iterNode = iterNode.nextElementSibling;
|
||||
}
|
||||
is(themeCount, MAX_THEME_COUNT,
|
||||
"There should be the max number of themes in the 'My Themes' section");
|
||||
is(
|
||||
themeCount,
|
||||
MAX_THEME_COUNT,
|
||||
"There should be the max number of themes in the 'My Themes' section"
|
||||
);
|
||||
|
||||
let defaultTheme = header.nextElementSibling;
|
||||
defaultTheme.doCommand();
|
||||
|
@ -177,15 +233,27 @@ add_task(async function() {
|
|||
header = document.getElementById("customization-lwtheme-menu-header");
|
||||
is(header.hidden, false, "Header should never be hidden");
|
||||
let themeNode = header.nextElementSibling;
|
||||
is(themeNode.theme.id, DEFAULT_THEME_ID, "The first theme should be the Default theme");
|
||||
is(
|
||||
themeNode.theme.id,
|
||||
DEFAULT_THEME_ID,
|
||||
"The first theme should be the Default theme"
|
||||
);
|
||||
is(themeNode.hidden, false, "The default theme should never be hidden");
|
||||
|
||||
themeNode = themeNode.nextElementSibling;
|
||||
is(themeNode.theme.id, LIGHT_THEME_ID, "The second theme should be the Light theme");
|
||||
is(
|
||||
themeNode.theme.id,
|
||||
LIGHT_THEME_ID,
|
||||
"The second theme should be the Light theme"
|
||||
);
|
||||
is(themeNode.hidden, false, "The light theme should never be hidden");
|
||||
|
||||
themeNode = themeNode.nextElementSibling;
|
||||
is(themeNode.theme.id, DARK_THEME_ID, "The third theme should be the Dark theme");
|
||||
is(
|
||||
themeNode.theme.id,
|
||||
DARK_THEME_ID,
|
||||
"The third theme should be the Dark theme"
|
||||
);
|
||||
is(themeNode.hidden, false, "The dark theme should never be hidden");
|
||||
|
||||
await Promise.all(addons.map(a => a.unload()));
|
||||
|
|
|
@ -10,38 +10,58 @@ const kAnchorAttribute = "cui-anchorid";
|
|||
* and into the palette.
|
||||
*/
|
||||
add_task(async function() {
|
||||
CustomizableUI.addWidgetToArea("history-panelmenu", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"history-panelmenu",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
await startCustomizing();
|
||||
let button = document.getElementById("history-panelmenu");
|
||||
is(button.getAttribute(kAnchorAttribute), "nav-bar-overflow-button",
|
||||
"Button (" + button.id + ") starts out with correct anchor");
|
||||
is(
|
||||
button.getAttribute(kAnchorAttribute),
|
||||
"nav-bar-overflow-button",
|
||||
"Button (" + button.id + ") starts out with correct anchor"
|
||||
);
|
||||
|
||||
let navbar = CustomizableUI.getCustomizationTarget(document.getElementById("nav-bar"));
|
||||
let navbar = CustomizableUI.getCustomizationTarget(
|
||||
document.getElementById("nav-bar")
|
||||
);
|
||||
let onMouseUp = BrowserTestUtils.waitForEvent(navbar, "mouseup");
|
||||
simulateItemDrag(button, navbar);
|
||||
await onMouseUp;
|
||||
is(CustomizableUI.getPlacementOfWidget(button.id).area, "nav-bar",
|
||||
"Button (" + button.id + ") ends up in nav-bar");
|
||||
is(
|
||||
CustomizableUI.getPlacementOfWidget(button.id).area,
|
||||
"nav-bar",
|
||||
"Button (" + button.id + ") ends up in nav-bar"
|
||||
);
|
||||
|
||||
ok(!button.hasAttribute(kAnchorAttribute),
|
||||
"Button (" + button.id + ") has no anchor in toolbar");
|
||||
ok(
|
||||
!button.hasAttribute(kAnchorAttribute),
|
||||
"Button (" + button.id + ") has no anchor in toolbar"
|
||||
);
|
||||
|
||||
CustomizableUI.addWidgetToArea("history-panelmenu", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"history-panelmenu",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
|
||||
is(button.getAttribute(kAnchorAttribute), "nav-bar-overflow-button",
|
||||
"Button (" + button.id + ") has anchor again");
|
||||
is(
|
||||
button.getAttribute(kAnchorAttribute),
|
||||
"nav-bar-overflow-button",
|
||||
"Button (" + button.id + ") has anchor again"
|
||||
);
|
||||
|
||||
let resetButton = document.getElementById("customization-reset-button");
|
||||
ok(!resetButton.hasAttribute("disabled"), "Should be able to reset now.");
|
||||
await gCustomizeMode.reset();
|
||||
|
||||
ok(!button.hasAttribute(kAnchorAttribute),
|
||||
"Button (" + button.id + ") once again has no anchor in customize panel");
|
||||
ok(
|
||||
!button.hasAttribute(kAnchorAttribute),
|
||||
"Button (" + button.id + ") once again has no anchor in customize panel"
|
||||
);
|
||||
|
||||
await endCustomizing();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Check that anchor gets set correctly when moving an item from the panel to the toolbar
|
||||
* using 'reset'
|
||||
|
@ -49,24 +69,34 @@ add_task(async function() {
|
|||
add_task(async function() {
|
||||
await startCustomizing();
|
||||
let button = document.getElementById("home-button");
|
||||
ok(!button.hasAttribute(kAnchorAttribute),
|
||||
"Button (" + button.id + ") has no anchor in toolbar");
|
||||
ok(
|
||||
!button.hasAttribute(kAnchorAttribute),
|
||||
"Button (" + button.id + ") has no anchor in toolbar"
|
||||
);
|
||||
|
||||
let panel = document.getElementById(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
let onMouseUp = BrowserTestUtils.waitForEvent(panel, "mouseup");
|
||||
simulateItemDrag(button, panel);
|
||||
await onMouseUp;
|
||||
is(CustomizableUI.getPlacementOfWidget(button.id).area, CustomizableUI.AREA_FIXED_OVERFLOW_PANEL,
|
||||
"Button (" + button.id + ") ends up in panel");
|
||||
is(button.getAttribute(kAnchorAttribute), "nav-bar-overflow-button",
|
||||
"Button (" + button.id + ") has correct anchor in the panel");
|
||||
is(
|
||||
CustomizableUI.getPlacementOfWidget(button.id).area,
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL,
|
||||
"Button (" + button.id + ") ends up in panel"
|
||||
);
|
||||
is(
|
||||
button.getAttribute(kAnchorAttribute),
|
||||
"nav-bar-overflow-button",
|
||||
"Button (" + button.id + ") has correct anchor in the panel"
|
||||
);
|
||||
|
||||
let resetButton = document.getElementById("customization-reset-button");
|
||||
ok(!resetButton.hasAttribute("disabled"), "Should be able to reset now.");
|
||||
await gCustomizeMode.reset();
|
||||
|
||||
ok(!button.hasAttribute(kAnchorAttribute),
|
||||
"Button (" + button.id + ") once again has no anchor in toolbar");
|
||||
ok(
|
||||
!button.hasAttribute(kAnchorAttribute),
|
||||
"Button (" + button.id + ") once again has no anchor in toolbar"
|
||||
);
|
||||
|
||||
await endCustomizing();
|
||||
});
|
||||
|
|
|
@ -7,25 +7,36 @@
|
|||
// don't try this at home, kids.
|
||||
function test() {
|
||||
// Customize something to make sure stuff changed:
|
||||
CustomizableUI.addWidgetToArea("save-page-button", CustomizableUI.AREA_NAVBAR);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"save-page-button",
|
||||
CustomizableUI.AREA_NAVBAR
|
||||
);
|
||||
|
||||
// Check what version we're on:
|
||||
let CustomizableUIBSPass = ChromeUtils.import("resource:///modules/CustomizableUI.jsm", null);
|
||||
let CustomizableUIBSPass = ChromeUtils.import(
|
||||
"resource:///modules/CustomizableUI.jsm",
|
||||
null
|
||||
);
|
||||
|
||||
let oldState = CustomizableUIBSPass.gSavedState;
|
||||
registerCleanupFunction(() => CustomizableUIBSPass.gSavedState = oldState );
|
||||
registerCleanupFunction(() => (CustomizableUIBSPass.gSavedState = oldState));
|
||||
|
||||
is(CustomizableUIBSPass.gFuturePlacements.size, 0,
|
||||
"All future placements should be dealt with by now.");
|
||||
is(
|
||||
CustomizableUIBSPass.gFuturePlacements.size,
|
||||
0,
|
||||
"All future placements should be dealt with by now."
|
||||
);
|
||||
|
||||
let {CustomizableUIInternal, gFuturePlacements, gPalette} = CustomizableUIBSPass;
|
||||
let {
|
||||
CustomizableUIInternal,
|
||||
gFuturePlacements,
|
||||
gPalette,
|
||||
} = CustomizableUIBSPass;
|
||||
CustomizableUIInternal._updateForNewVersion();
|
||||
is(gFuturePlacements.size, 0,
|
||||
"No change to future placements initially.");
|
||||
is(gFuturePlacements.size, 0, "No change to future placements initially.");
|
||||
|
||||
let currentVersion = CustomizableUIBSPass.kVersion;
|
||||
|
||||
|
||||
// Add our widget to the defaults:
|
||||
let testWidgetNew = {
|
||||
id: "test-messing-with-default-placements-new",
|
||||
|
@ -34,8 +45,10 @@ function test() {
|
|||
introducedInVersion: currentVersion + 1,
|
||||
};
|
||||
|
||||
let normalizedWidget = CustomizableUIInternal.normalizeWidget(testWidgetNew,
|
||||
CustomizableUI.SOURCE_BUILTIN);
|
||||
let normalizedWidget = CustomizableUIInternal.normalizeWidget(
|
||||
testWidgetNew,
|
||||
CustomizableUI.SOURCE_BUILTIN
|
||||
);
|
||||
ok(normalizedWidget, "Widget should be normalizable");
|
||||
if (!normalizedWidget) {
|
||||
return;
|
||||
|
@ -49,27 +62,29 @@ function test() {
|
|||
introducedInVersion: currentVersion,
|
||||
};
|
||||
|
||||
normalizedWidget = CustomizableUIInternal.normalizeWidget(testWidgetOld,
|
||||
CustomizableUI.SOURCE_BUILTIN);
|
||||
normalizedWidget = CustomizableUIInternal.normalizeWidget(
|
||||
testWidgetOld,
|
||||
CustomizableUI.SOURCE_BUILTIN
|
||||
);
|
||||
ok(normalizedWidget, "Widget should be normalizable");
|
||||
if (!normalizedWidget) {
|
||||
return;
|
||||
}
|
||||
CustomizableUIBSPass.gPalette.set(testWidgetOld.id, normalizedWidget);
|
||||
|
||||
|
||||
// Now increase the version in the module:
|
||||
CustomizableUIBSPass.kVersion++;
|
||||
|
||||
let hadSavedState = !!CustomizableUIBSPass.gSavedState;
|
||||
if (!hadSavedState) {
|
||||
CustomizableUIBSPass.gSavedState = {currentVersion: CustomizableUIBSPass.kVersion - 1};
|
||||
CustomizableUIBSPass.gSavedState = {
|
||||
currentVersion: CustomizableUIBSPass.kVersion - 1,
|
||||
};
|
||||
}
|
||||
|
||||
// Then call the re-init routine so we re-add the builtin widgets
|
||||
CustomizableUIInternal._updateForNewVersion();
|
||||
is(gFuturePlacements.size, 1,
|
||||
"Should have 1 more future placement");
|
||||
is(gFuturePlacements.size, 1, "Should have 1 more future placement");
|
||||
let haveNavbarPlacements = gFuturePlacements.has(CustomizableUI.AREA_NAVBAR);
|
||||
ok(haveNavbarPlacements, "Should have placements for nav-bar");
|
||||
if (haveNavbarPlacements) {
|
||||
|
@ -93,7 +108,11 @@ function test() {
|
|||
}
|
||||
|
||||
is(placements.length, 1, "Should have 1 newly placed widget in nav-bar");
|
||||
is(placements[0], testWidgetNew.id, "Should have our test widget to be placed in nav-bar");
|
||||
is(
|
||||
placements[0],
|
||||
testWidgetNew.id,
|
||||
"Should have our test widget to be placed in nav-bar"
|
||||
);
|
||||
}
|
||||
|
||||
// Reset kVersion
|
||||
|
@ -114,22 +133,49 @@ function test() {
|
|||
is(springs.length, 2, "Should have 2 toolbarsprings in placements now");
|
||||
navbarPlacements = navbarPlacements.filter(id => !id.includes("spring"));
|
||||
is(navbarPlacements[0], "back-button", "Back button is in the right place.");
|
||||
is(navbarPlacements[1], "forward-button", "Fwd button is in the right place.");
|
||||
is(navbarPlacements[2], "stop-reload-button", "Stop/reload button is in the right place.");
|
||||
is(
|
||||
navbarPlacements[1],
|
||||
"forward-button",
|
||||
"Fwd button is in the right place."
|
||||
);
|
||||
is(
|
||||
navbarPlacements[2],
|
||||
"stop-reload-button",
|
||||
"Stop/reload button is in the right place."
|
||||
);
|
||||
is(navbarPlacements[3], "home-button", "Home button is in the right place.");
|
||||
is(navbarPlacements[4], "urlbar-container", "URL bar is in the right place.");
|
||||
is(navbarPlacements[5], "downloads-button", "Downloads button is in the right place.");
|
||||
is(navbarPlacements[6], "library-button", "Library button is in the right place.");
|
||||
is(navbarPlacements[7], "sidebar-button", "Sidebar button is in the right place.");
|
||||
is(navbarPlacements[8], "fxa-toolbar-menu-button", "FxA button is in the right place.");
|
||||
is(
|
||||
navbarPlacements[5],
|
||||
"downloads-button",
|
||||
"Downloads button is in the right place."
|
||||
);
|
||||
is(
|
||||
navbarPlacements[6],
|
||||
"library-button",
|
||||
"Library button is in the right place."
|
||||
);
|
||||
is(
|
||||
navbarPlacements[7],
|
||||
"sidebar-button",
|
||||
"Sidebar button is in the right place."
|
||||
);
|
||||
is(
|
||||
navbarPlacements[8],
|
||||
"fxa-toolbar-menu-button",
|
||||
"FxA button is in the right place."
|
||||
);
|
||||
is(navbarPlacements.length, 9, "Should have 9 items");
|
||||
|
||||
let overflowPlacements = CustomizableUIBSPass.gSavedState.placements["widget-overflow-fixed-list"];
|
||||
let overflowPlacements =
|
||||
CustomizableUIBSPass.gSavedState.placements["widget-overflow-fixed-list"];
|
||||
Assert.deepEqual(overflowPlacements, ["panic-button"]);
|
||||
|
||||
// Finally, test the downloads and fxa avatar button migrations work.
|
||||
let oldNavbarPlacements = [
|
||||
"urlbar-container", "customizableui-special-spring3", "search-container",
|
||||
"urlbar-container",
|
||||
"customizableui-special-spring3",
|
||||
"search-container",
|
||||
];
|
||||
CustomizableUIBSPass.gSavedState = {
|
||||
currentVersion: 10,
|
||||
|
@ -140,10 +186,16 @@ function test() {
|
|||
};
|
||||
CustomizableUIInternal._updateForNewVersion();
|
||||
navbarPlacements = CustomizableUIBSPass.gSavedState.placements["nav-bar"];
|
||||
Assert.deepEqual(navbarPlacements, oldNavbarPlacements.concat(["downloads-button", "fxa-toolbar-menu-button"]),
|
||||
"Downloads button inserted in navbar");
|
||||
Assert.deepEqual(CustomizableUIBSPass.gSavedState.placements["widget-overflow-fixed-list"], [],
|
||||
"Overflow panel is empty");
|
||||
Assert.deepEqual(
|
||||
navbarPlacements,
|
||||
oldNavbarPlacements.concat(["downloads-button", "fxa-toolbar-menu-button"]),
|
||||
"Downloads button inserted in navbar"
|
||||
);
|
||||
Assert.deepEqual(
|
||||
CustomizableUIBSPass.gSavedState.placements["widget-overflow-fixed-list"],
|
||||
[],
|
||||
"Overflow panel is empty"
|
||||
);
|
||||
|
||||
CustomizableUIBSPass.gSavedState = {
|
||||
currentVersion: 10,
|
||||
|
@ -153,11 +205,17 @@ function test() {
|
|||
};
|
||||
CustomizableUIInternal._updateForNewVersion();
|
||||
navbarPlacements = CustomizableUIBSPass.gSavedState.placements["nav-bar"];
|
||||
Assert.deepEqual(navbarPlacements, oldNavbarPlacements.concat(["downloads-button", "fxa-toolbar-menu-button"]),
|
||||
"Downloads button reinserted in navbar");
|
||||
Assert.deepEqual(
|
||||
navbarPlacements,
|
||||
oldNavbarPlacements.concat(["downloads-button", "fxa-toolbar-menu-button"]),
|
||||
"Downloads button reinserted in navbar"
|
||||
);
|
||||
|
||||
oldNavbarPlacements = [
|
||||
"urlbar-container", "customizableui-special-spring3", "search-container", "other-widget",
|
||||
"urlbar-container",
|
||||
"customizableui-special-spring3",
|
||||
"search-container",
|
||||
"other-widget",
|
||||
];
|
||||
CustomizableUIBSPass.gSavedState = {
|
||||
currentVersion: 10,
|
||||
|
@ -168,14 +226,20 @@ function test() {
|
|||
CustomizableUIInternal._updateForNewVersion();
|
||||
navbarPlacements = CustomizableUIBSPass.gSavedState.placements["nav-bar"];
|
||||
let expectedNavbarPlacements = [
|
||||
"urlbar-container", "customizableui-special-spring3", "search-container",
|
||||
"downloads-button", "other-widget", "fxa-toolbar-menu-button",
|
||||
"urlbar-container",
|
||||
"customizableui-special-spring3",
|
||||
"search-container",
|
||||
"downloads-button",
|
||||
"other-widget",
|
||||
"fxa-toolbar-menu-button",
|
||||
];
|
||||
Assert.deepEqual(navbarPlacements, expectedNavbarPlacements,
|
||||
"Downloads button inserted in navbar before other widgets");
|
||||
Assert.deepEqual(
|
||||
navbarPlacements,
|
||||
expectedNavbarPlacements,
|
||||
"Downloads button inserted in navbar before other widgets"
|
||||
);
|
||||
|
||||
gFuturePlacements.delete(CustomizableUI.AREA_NAVBAR);
|
||||
gPalette.delete(testWidgetNew.id);
|
||||
gPalette.delete(testWidgetOld.id);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,14 @@ add_task(async function() {
|
|||
info("Enter customization mode");
|
||||
await startCustomizing();
|
||||
|
||||
let toolbarsToggle = document.getElementById("customization-toolbar-visibility-button");
|
||||
let toolbarsToggle = document.getElementById(
|
||||
"customization-toolbar-visibility-button"
|
||||
);
|
||||
ok(toolbarsToggle, "The toolbars toggle dropdown exists");
|
||||
ok(!toolbarsToggle.hasAttribute("hidden"),
|
||||
"The toolbars toggle dropdown is displayed");
|
||||
ok(
|
||||
!toolbarsToggle.hasAttribute("hidden"),
|
||||
"The toolbars toggle dropdown is displayed"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function asyncCleanup() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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/. */
|
||||
* 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/. */
|
||||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
|
||||
"use strict";
|
||||
|
@ -8,7 +8,10 @@
|
|||
add_task(async function() {
|
||||
info("Check fullscreen button existence and functionality");
|
||||
|
||||
CustomizableUI.addWidgetToArea("fullscreen-button", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"fullscreen-button",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
registerCleanupFunction(() => CustomizableUI.reset());
|
||||
|
||||
await waitForOverflowButtonShown();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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/. */
|
||||
* 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/. */
|
||||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
|
||||
"use strict";
|
||||
|
@ -9,7 +9,10 @@ var newTab = null;
|
|||
|
||||
add_task(async function() {
|
||||
info("Check preferences button existence and functionality");
|
||||
CustomizableUI.addWidgetToArea("preferences-button", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"preferences-button",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
registerCleanupFunction(() => CustomizableUI.reset());
|
||||
|
||||
await waitForOverflowButtonShown();
|
||||
|
@ -29,8 +32,9 @@ add_task(async function() {
|
|||
});
|
||||
|
||||
add_task(function asyncCleanup() {
|
||||
if (gBrowser.tabs.length == 1)
|
||||
if (gBrowser.tabs.length == 1) {
|
||||
BrowserTestUtils.addTab(gBrowser, "about:blank");
|
||||
}
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
info("Tabs were restored");
|
||||
|
|
|
@ -10,17 +10,32 @@ add_task(async function() {
|
|||
});
|
||||
|
||||
const kPrefCustomizationState = "browser.uiCustomization.state";
|
||||
let bsPass = ChromeUtils.import("resource:///modules/CustomizableUI.jsm", null);
|
||||
ok(bsPass.gSeenWidgets.has(BUTTONID), "Widget should be seen after createWidget is called.");
|
||||
let bsPass = ChromeUtils.import(
|
||||
"resource:///modules/CustomizableUI.jsm",
|
||||
null
|
||||
);
|
||||
ok(
|
||||
bsPass.gSeenWidgets.has(BUTTONID),
|
||||
"Widget should be seen after createWidget is called."
|
||||
);
|
||||
CustomizableUI.reset();
|
||||
ok(bsPass.gSeenWidgets.has(BUTTONID), "Widget should still be seen after reset.");
|
||||
ok(
|
||||
bsPass.gSeenWidgets.has(BUTTONID),
|
||||
"Widget should still be seen after reset."
|
||||
);
|
||||
CustomizableUI.addWidgetToArea(BUTTONID, CustomizableUI.AREA_NAVBAR);
|
||||
gCustomizeMode.removeFromArea(document.getElementById(BUTTONID));
|
||||
let hasUserValue = Services.prefs.prefHasUserValue(kPrefCustomizationState);
|
||||
ok(hasUserValue, "Pref should be set right now.");
|
||||
if (hasUserValue) {
|
||||
let seenArray = JSON.parse(Services.prefs.getCharPref(kPrefCustomizationState)).seen;
|
||||
isnot(seenArray.indexOf(BUTTONID), -1, "Widget should be in saved 'seen' list.");
|
||||
let seenArray = JSON.parse(
|
||||
Services.prefs.getCharPref(kPrefCustomizationState)
|
||||
).seen;
|
||||
isnot(
|
||||
seenArray.indexOf(BUTTONID),
|
||||
-1,
|
||||
"Widget should be in saved 'seen' list."
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -4,22 +4,34 @@
|
|||
// don't try this at home, kids.
|
||||
function test() {
|
||||
// Customize something to make sure stuff changed:
|
||||
CustomizableUI.addWidgetToArea("save-page-button", CustomizableUI.AREA_NAVBAR);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"save-page-button",
|
||||
CustomizableUI.AREA_NAVBAR
|
||||
);
|
||||
|
||||
let CustomizableUIBSPass = ChromeUtils.import("resource:///modules/CustomizableUI.jsm", null);
|
||||
let CustomizableUIBSPass = ChromeUtils.import(
|
||||
"resource:///modules/CustomizableUI.jsm",
|
||||
null
|
||||
);
|
||||
|
||||
is(CustomizableUIBSPass.gFuturePlacements.size, 0,
|
||||
"All future placements should be dealt with by now.");
|
||||
is(
|
||||
CustomizableUIBSPass.gFuturePlacements.size,
|
||||
0,
|
||||
"All future placements should be dealt with by now."
|
||||
);
|
||||
|
||||
let {CustomizableUIInternal, gFuturePlacements, gPalette} = CustomizableUIBSPass;
|
||||
let {
|
||||
CustomizableUIInternal,
|
||||
gFuturePlacements,
|
||||
gPalette,
|
||||
} = CustomizableUIBSPass;
|
||||
|
||||
// Force us to have a saved state:
|
||||
CustomizableUIInternal.saveState();
|
||||
CustomizableUIInternal.loadSavedState();
|
||||
|
||||
CustomizableUIInternal._updateForNewVersion();
|
||||
is(gFuturePlacements.size, 0,
|
||||
"No change to future placements initially.");
|
||||
is(gFuturePlacements.size, 0, "No change to future placements initially.");
|
||||
|
||||
// Add our widget to the defaults:
|
||||
let testWidgetNew = {
|
||||
|
@ -29,8 +41,10 @@ function test() {
|
|||
introducedInVersion: "pref",
|
||||
};
|
||||
|
||||
let normalizedWidget = CustomizableUIInternal.normalizeWidget(testWidgetNew,
|
||||
CustomizableUI.SOURCE_BUILTIN);
|
||||
let normalizedWidget = CustomizableUIInternal.normalizeWidget(
|
||||
testWidgetNew,
|
||||
CustomizableUI.SOURCE_BUILTIN
|
||||
);
|
||||
ok(normalizedWidget, "Widget should be normalizable");
|
||||
if (!normalizedWidget) {
|
||||
return;
|
||||
|
@ -40,28 +54,45 @@ function test() {
|
|||
// Now adjust default placements for area:
|
||||
let navbarArea = CustomizableUIBSPass.gAreas.get(CustomizableUI.AREA_NAVBAR);
|
||||
let navbarPlacements = navbarArea.get("defaultPlacements");
|
||||
navbarPlacements.splice(navbarPlacements.indexOf("bookmarks-menu-button") + 1, 0, testWidgetNew.id);
|
||||
navbarPlacements.splice(
|
||||
navbarPlacements.indexOf("bookmarks-menu-button") + 1,
|
||||
0,
|
||||
testWidgetNew.id
|
||||
);
|
||||
|
||||
let savedPlacements = CustomizableUIBSPass.gSavedState.placements[CustomizableUI.AREA_NAVBAR];
|
||||
let savedPlacements =
|
||||
CustomizableUIBSPass.gSavedState.placements[CustomizableUI.AREA_NAVBAR];
|
||||
// Then call the re-init routine so we re-add the builtin widgets
|
||||
CustomizableUIInternal._updateForNewVersion();
|
||||
is(gFuturePlacements.size, 1,
|
||||
"Should have 1 more future placement");
|
||||
let futureNavbarPlacements = gFuturePlacements.get(CustomizableUI.AREA_NAVBAR);
|
||||
is(gFuturePlacements.size, 1, "Should have 1 more future placement");
|
||||
let futureNavbarPlacements = gFuturePlacements.get(
|
||||
CustomizableUI.AREA_NAVBAR
|
||||
);
|
||||
ok(futureNavbarPlacements, "Should have placements for nav-bar");
|
||||
if (futureNavbarPlacements) {
|
||||
ok(futureNavbarPlacements.has(testWidgetNew.id), "widget should be in future placements");
|
||||
ok(
|
||||
futureNavbarPlacements.has(testWidgetNew.id),
|
||||
"widget should be in future placements"
|
||||
);
|
||||
}
|
||||
CustomizableUIInternal._placeNewDefaultWidgetsInArea(CustomizableUI.AREA_NAVBAR);
|
||||
CustomizableUIInternal._placeNewDefaultWidgetsInArea(
|
||||
CustomizableUI.AREA_NAVBAR
|
||||
);
|
||||
|
||||
let indexInSavedPlacements = savedPlacements.indexOf(testWidgetNew.id);
|
||||
info("Saved placements: " + savedPlacements.join(", "));
|
||||
isnot(indexInSavedPlacements, -1, "Widget should have been inserted");
|
||||
is(indexInSavedPlacements, savedPlacements.indexOf("bookmarks-menu-button") + 1,
|
||||
"Widget should be in the right place.");
|
||||
is(
|
||||
indexInSavedPlacements,
|
||||
savedPlacements.indexOf("bookmarks-menu-button") + 1,
|
||||
"Widget should be in the right place."
|
||||
);
|
||||
|
||||
if (futureNavbarPlacements) {
|
||||
ok(!futureNavbarPlacements.has(testWidgetNew.id), "widget should be out of future placements");
|
||||
ok(
|
||||
!futureNavbarPlacements.has(testWidgetNew.id),
|
||||
"widget should be out of future placements"
|
||||
);
|
||||
}
|
||||
|
||||
if (indexInSavedPlacements != -1) {
|
||||
|
|
|
@ -43,45 +43,48 @@ add_task(async function test_PanelMultiView_toggle_with_other_popup() {
|
|||
});
|
||||
registerCleanupFunction(() => PlacesUtils.bookmarks.remove(bookmark));
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: TEST_URL,
|
||||
}, async function(browser) {
|
||||
// 1. Open the main menu.
|
||||
await gCUITestUtils.openMainMenu();
|
||||
|
||||
// 2. Open another popup not managed by PanelMultiView.
|
||||
let bookmarkPanel = document.getElementById("editBookmarkPanel");
|
||||
let shown = BrowserTestUtils.waitForEvent(bookmarkPanel, "popupshown");
|
||||
let hidden = BrowserTestUtils.waitForEvent(bookmarkPanel, "popuphidden");
|
||||
EventUtils.synthesizeKey("D", { accelKey: true });
|
||||
await shown;
|
||||
|
||||
// 3. Click the button to which the main menu is anchored. We need a native
|
||||
// mouse event to simulate the exact platform behavior with popups.
|
||||
let clickFn = () => synthesizeNativeMouseClick(
|
||||
document.getElementById("PanelUI-button"));
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
// On Windows, the operation will close both popups.
|
||||
await gCUITestUtils.hidePanelMultiView(PanelUI.panel, clickFn);
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// 4. Test that the popup can be opened again after it's been closed.
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: TEST_URL,
|
||||
},
|
||||
async function(browser) {
|
||||
// 1. Open the main menu.
|
||||
await gCUITestUtils.openMainMenu();
|
||||
Assert.equal(PanelUI.panel.state, "open");
|
||||
} else {
|
||||
// On other platforms, the operation will close both popups and reopen the
|
||||
// main menu immediately, so we wait for the reopen to occur.
|
||||
shown = BrowserTestUtils.waitForEvent(PanelUI.mainView, "ViewShown");
|
||||
clickFn();
|
||||
|
||||
// 2. Open another popup not managed by PanelMultiView.
|
||||
let bookmarkPanel = document.getElementById("editBookmarkPanel");
|
||||
let shown = BrowserTestUtils.waitForEvent(bookmarkPanel, "popupshown");
|
||||
let hidden = BrowserTestUtils.waitForEvent(bookmarkPanel, "popuphidden");
|
||||
EventUtils.synthesizeKey("D", { accelKey: true });
|
||||
await shown;
|
||||
|
||||
// 3. Click the button to which the main menu is anchored. We need a native
|
||||
// mouse event to simulate the exact platform behavior with popups.
|
||||
let clickFn = () =>
|
||||
synthesizeNativeMouseClick(document.getElementById("PanelUI-button"));
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
// On Windows, the operation will close both popups.
|
||||
await gCUITestUtils.hidePanelMultiView(PanelUI.panel, clickFn);
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// 4. Test that the popup can be opened again after it's been closed.
|
||||
await gCUITestUtils.openMainMenu();
|
||||
Assert.equal(PanelUI.panel.state, "open");
|
||||
} else {
|
||||
// On other platforms, the operation will close both popups and reopen the
|
||||
// main menu immediately, so we wait for the reopen to occur.
|
||||
shown = BrowserTestUtils.waitForEvent(PanelUI.mainView, "ViewShown");
|
||||
clickFn();
|
||||
await shown;
|
||||
}
|
||||
|
||||
await gCUITestUtils.hideMainMenu();
|
||||
|
||||
// Make sure the events for the bookmarks panel have also been processed
|
||||
// before closing the tab and removing the bookmark.
|
||||
await hidden;
|
||||
}
|
||||
|
||||
await gCUITestUtils.hideMainMenu();
|
||||
|
||||
// Make sure the events for the bookmarks panel have also been processed
|
||||
// before closing the tab and removing the bookmark.
|
||||
await hidden;
|
||||
});
|
||||
);
|
||||
});
|
||||
|
|
|
@ -24,7 +24,10 @@ add_task(async function test_syncPreferenceWithWidget() {
|
|||
|
||||
// Moving the widget to any position outside of the navigation toolbar should
|
||||
// turn the preference back to false.
|
||||
CustomizableUI.addWidgetToArea(WIDGET_ID, CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
WIDGET_ID,
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
ok(!Services.prefs.getBoolPref(PREF_NAME));
|
||||
});
|
||||
|
||||
|
@ -34,8 +37,10 @@ add_task(async function test_syncWidgetWithPreference() {
|
|||
Services.prefs.setBoolPref(PREF_NAME, true);
|
||||
let placement = CustomizableUI.getPlacementOfWidget(WIDGET_ID);
|
||||
is(placement.area, CustomizableUI.AREA_NAVBAR);
|
||||
is(placement.position,
|
||||
CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1);
|
||||
is(
|
||||
placement.position,
|
||||
CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1
|
||||
);
|
||||
|
||||
// This should move the widget back to the customization palette.
|
||||
Services.prefs.setBoolPref(PREF_NAME, false);
|
||||
|
|
|
@ -20,8 +20,10 @@ add_task(async function addToolbarWith2SpringsAndDownloadsButton() {
|
|||
|
||||
// Add a second spring, check if that's there and doesn't share IDs
|
||||
CustomizableUI.addWidgetToArea("spring", kToolbarName);
|
||||
assertAreaPlacements(kToolbarName, [springId,
|
||||
/customizableui-special-spring\d+/]);
|
||||
assertAreaPlacements(kToolbarName, [
|
||||
springId,
|
||||
/customizableui-special-spring\d+/,
|
||||
]);
|
||||
let [, spring2Id] = getAreaWidgetIds(kToolbarName);
|
||||
|
||||
isnot(springId, spring2Id, "Springs shouldn't have identical IDs.");
|
||||
|
@ -42,14 +44,20 @@ add_task(async function addSeparatorsAroundDownloadsButton() {
|
|||
let [separatorId] = getAreaWidgetIds(kToolbarName);
|
||||
|
||||
CustomizableUI.addWidgetToArea("separator", kToolbarName);
|
||||
assertAreaPlacements(kToolbarName, [separatorId,
|
||||
/customizableui-special-separator\d+/]);
|
||||
assertAreaPlacements(kToolbarName, [
|
||||
separatorId,
|
||||
/customizableui-special-separator\d+/,
|
||||
]);
|
||||
let [, separator2Id] = getAreaWidgetIds(kToolbarName);
|
||||
|
||||
isnot(separatorId, separator2Id, "Separator ids shouldn't be equal.");
|
||||
|
||||
CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1);
|
||||
assertAreaPlacements(kToolbarName, [separatorId, "downloads-button", separator2Id]);
|
||||
assertAreaPlacements(kToolbarName, [
|
||||
separatorId,
|
||||
"downloads-button",
|
||||
separator2Id,
|
||||
]);
|
||||
await removeCustomToolbars();
|
||||
});
|
||||
|
||||
|
@ -63,8 +71,10 @@ add_task(async function addSpacersAroundDownloadsButton() {
|
|||
let [spacerId] = getAreaWidgetIds(kToolbarName);
|
||||
|
||||
CustomizableUI.addWidgetToArea("spacer", kToolbarName);
|
||||
assertAreaPlacements(kToolbarName, [spacerId,
|
||||
/customizableui-special-spacer\d+/]);
|
||||
assertAreaPlacements(kToolbarName, [
|
||||
spacerId,
|
||||
/customizableui-special-spacer\d+/,
|
||||
]);
|
||||
let [, spacer2Id] = getAreaWidgetIds(kToolbarName);
|
||||
|
||||
isnot(spacerId, spacer2Id, "Spacer ids shouldn't be equal.");
|
||||
|
|
|
@ -11,7 +11,13 @@ const kToolbar = CustomizableUI.AREA_NAVBAR;
|
|||
const kVisiblePalette = "customization-palette";
|
||||
|
||||
function checkWrapper(id) {
|
||||
is(document.querySelectorAll("#wrapper-" + id).length, 1, "There should be exactly 1 wrapper for " + id + " in the customizing window.");
|
||||
is(
|
||||
document.querySelectorAll("#wrapper-" + id).length,
|
||||
1,
|
||||
"There should be exactly 1 wrapper for " +
|
||||
id +
|
||||
" in the customizing window."
|
||||
);
|
||||
}
|
||||
|
||||
async function ensureVisible(node) {
|
||||
|
@ -24,7 +30,12 @@ async function ensureVisible(node) {
|
|||
let nodeBounds = dwu.getBoundsWithoutFlushing(node);
|
||||
if (isInPalette) {
|
||||
let paletteBounds = dwu.getBoundsWithoutFlushing(gNavToolbox.palette);
|
||||
if (!(nodeBounds.top >= paletteBounds.top && nodeBounds.bottom <= paletteBounds.bottom)) {
|
||||
if (
|
||||
!(
|
||||
nodeBounds.top >= paletteBounds.top &&
|
||||
nodeBounds.bottom <= paletteBounds.bottom
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +44,7 @@ async function ensureVisible(node) {
|
|||
}
|
||||
|
||||
var move = {
|
||||
"drag": async function(id, target) {
|
||||
async drag(id, target) {
|
||||
let targetNode = document.getElementById(target);
|
||||
if (CustomizableUI.getCustomizationTarget(targetNode)) {
|
||||
targetNode = CustomizableUI.getCustomizationTarget(targetNode);
|
||||
|
@ -43,7 +54,7 @@ var move = {
|
|||
|
||||
simulateItemDrag(nodeToMove, targetNode, "end");
|
||||
},
|
||||
"dragToItem": async function(id, target) {
|
||||
async dragToItem(id, target) {
|
||||
let targetNode = document.getElementById(target);
|
||||
if (CustomizableUI.getCustomizationTarget(targetNode)) {
|
||||
targetNode = CustomizableUI.getCustomizationTarget(targetNode);
|
||||
|
@ -58,7 +69,7 @@ var move = {
|
|||
await ensureVisible(nodeToMove);
|
||||
simulateItemDrag(nodeToMove, targetNode, "start");
|
||||
},
|
||||
"API": function(id, target) {
|
||||
API(id, target) {
|
||||
if (target == kVisiblePalette) {
|
||||
return CustomizableUI.removeWidgetFromArea(id);
|
||||
}
|
||||
|
@ -68,20 +79,35 @@ var move = {
|
|||
|
||||
function isLast(containerId, defaultPlacements, id) {
|
||||
assertAreaPlacements(containerId, defaultPlacements.concat([id]));
|
||||
let thisTarget =
|
||||
CustomizableUI.getCustomizationTarget(document.getElementById(containerId));
|
||||
is(thisTarget.lastElementChild.firstElementChild.id, id,
|
||||
"Widget " + id + " should be in " + containerId + " in customizing window.");
|
||||
let otherTarget =
|
||||
CustomizableUI.getCustomizationTarget(otherWin.document.getElementById(containerId));
|
||||
is(otherTarget.lastElementChild.id, id,
|
||||
"Widget " + id + " should be in " + containerId + " in other window.");
|
||||
let thisTarget = CustomizableUI.getCustomizationTarget(
|
||||
document.getElementById(containerId)
|
||||
);
|
||||
is(
|
||||
thisTarget.lastElementChild.firstElementChild.id,
|
||||
id,
|
||||
"Widget " + id + " should be in " + containerId + " in customizing window."
|
||||
);
|
||||
let otherTarget = CustomizableUI.getCustomizationTarget(
|
||||
otherWin.document.getElementById(containerId)
|
||||
);
|
||||
is(
|
||||
otherTarget.lastElementChild.id,
|
||||
id,
|
||||
"Widget " + id + " should be in " + containerId + " in other window."
|
||||
);
|
||||
}
|
||||
|
||||
function getLastVisibleNodeInToolbar(containerId, win = window) {
|
||||
let container = CustomizableUI.getCustomizationTarget(win.document.getElementById(containerId));
|
||||
let container = CustomizableUI.getCustomizationTarget(
|
||||
win.document.getElementById(containerId)
|
||||
);
|
||||
let rv = container.lastElementChild;
|
||||
while (rv && (rv.getAttribute("hidden") == "true" || (rv.firstElementChild && rv.firstElementChild.getAttribute("hidden") == "true"))) {
|
||||
while (
|
||||
rv &&
|
||||
(rv.getAttribute("hidden") == "true" ||
|
||||
(rv.firstElementChild &&
|
||||
rv.firstElementChild.getAttribute("hidden") == "true"))
|
||||
) {
|
||||
rv = rv.previousElementSibling;
|
||||
}
|
||||
return rv;
|
||||
|
@ -102,22 +128,36 @@ function isLastVisibleInToolbar(containerId, defaultPlacements, id) {
|
|||
} else {
|
||||
assertAreaPlacements(containerId, newPlacements);
|
||||
}
|
||||
is(getLastVisibleNodeInToolbar(containerId).firstElementChild.id, id,
|
||||
"Widget " + id + " should be in " + containerId + " in customizing window.");
|
||||
is(getLastVisibleNodeInToolbar(containerId, otherWin).id, id,
|
||||
"Widget " + id + " should be in " + containerId + " in other window.");
|
||||
is(
|
||||
getLastVisibleNodeInToolbar(containerId).firstElementChild.id,
|
||||
id,
|
||||
"Widget " + id + " should be in " + containerId + " in customizing window."
|
||||
);
|
||||
is(
|
||||
getLastVisibleNodeInToolbar(containerId, otherWin).id,
|
||||
id,
|
||||
"Widget " + id + " should be in " + containerId + " in other window."
|
||||
);
|
||||
}
|
||||
|
||||
function isFirst(containerId, defaultPlacements, id) {
|
||||
assertAreaPlacements(containerId, [id].concat(defaultPlacements));
|
||||
let thisTarget =
|
||||
CustomizableUI.getCustomizationTarget(document.getElementById(containerId));
|
||||
is(thisTarget.firstElementChild.firstElementChild.id, id,
|
||||
"Widget " + id + " should be in " + containerId + " in customizing window.");
|
||||
let otherTarget =
|
||||
CustomizableUI.getCustomizationTarget(otherWin.document.getElementById(containerId));
|
||||
is(otherTarget.firstElementChild.id, id,
|
||||
"Widget " + id + " should be in " + containerId + " in other window.");
|
||||
let thisTarget = CustomizableUI.getCustomizationTarget(
|
||||
document.getElementById(containerId)
|
||||
);
|
||||
is(
|
||||
thisTarget.firstElementChild.firstElementChild.id,
|
||||
id,
|
||||
"Widget " + id + " should be in " + containerId + " in customizing window."
|
||||
);
|
||||
let otherTarget = CustomizableUI.getCustomizationTarget(
|
||||
otherWin.document.getElementById(containerId)
|
||||
);
|
||||
is(
|
||||
otherTarget.firstElementChild.id,
|
||||
id,
|
||||
"Widget " + id + " should be in " + containerId + " in other window."
|
||||
);
|
||||
}
|
||||
|
||||
async function checkToolbar(id, method) {
|
||||
|
@ -137,7 +177,9 @@ async function checkToolbar(id, method) {
|
|||
async function checkPanel(id, method) {
|
||||
let panelPlacements = getAreaWidgetIds(kPanel);
|
||||
await move[method](id, kPanel);
|
||||
let children = document.getElementById(kPanel).querySelectorAll("toolbarpaletteitem");
|
||||
let children = document
|
||||
.getElementById(kPanel)
|
||||
.querySelectorAll("toolbarpaletteitem");
|
||||
let otherChildren = otherWin.document.getElementById(kPanel).children;
|
||||
let newPlacements = panelPlacements.concat([id]);
|
||||
// Relative position of the new item from the end:
|
||||
|
@ -151,10 +193,16 @@ async function checkPanel(id, method) {
|
|||
position = -2;
|
||||
}
|
||||
assertAreaPlacements(kPanel, newPlacements);
|
||||
is(children[children.length + position].firstElementChild.id, id,
|
||||
"Widget " + id + " should be in " + kPanel + " in customizing window.");
|
||||
is(otherChildren[otherChildren.length + position].id, id,
|
||||
"Widget " + id + " should be in " + kPanel + " in other window.");
|
||||
is(
|
||||
children[children.length + position].firstElementChild.id,
|
||||
id,
|
||||
"Widget " + id + " should be in " + kPanel + " in customizing window."
|
||||
);
|
||||
is(
|
||||
otherChildren[otherChildren.length + position].id,
|
||||
id,
|
||||
"Widget " + id + " should be in " + kPanel + " in other window."
|
||||
);
|
||||
checkWrapper(id);
|
||||
}
|
||||
|
||||
|
@ -163,15 +211,29 @@ async function checkPalette(id, method) {
|
|||
await move[method](id, kVisiblePalette);
|
||||
ok(CustomizableUI.inDefaultState, "Should end in default state");
|
||||
let visibleChildren = gCustomizeMode.visiblePalette.children;
|
||||
let expectedChild = method == "dragToItem" ? visibleChildren[0] : visibleChildren[visibleChildren.length - 1];
|
||||
let expectedChild =
|
||||
method == "dragToItem"
|
||||
? visibleChildren[0]
|
||||
: visibleChildren[visibleChildren.length - 1];
|
||||
// Items dragged to the end of the palette should be the final item. That they're the penultimate
|
||||
// item when dragged is tracked in bug 1395950. Once that's fixed, this hack can be removed.
|
||||
if (method == "drag") {
|
||||
expectedChild = expectedChild.previousElementSibling;
|
||||
}
|
||||
is(expectedChild.firstElementChild.id, id, "Widget " + id + " was moved using " + method + " and should now be wrapped in palette in customizing window.");
|
||||
is(
|
||||
expectedChild.firstElementChild.id,
|
||||
id,
|
||||
"Widget " +
|
||||
id +
|
||||
" was moved using " +
|
||||
method +
|
||||
" and should now be wrapped in palette in customizing window."
|
||||
);
|
||||
if (id == kXULWidgetId) {
|
||||
ok(otherWin.gNavToolbox.palette.querySelector("#" + id), "Widget " + id + " should be in invisible palette in other window.");
|
||||
ok(
|
||||
otherWin.gNavToolbox.palette.querySelector("#" + id),
|
||||
"Widget " + id + " should be in invisible palette in other window."
|
||||
);
|
||||
}
|
||||
checkWrapper(id);
|
||||
}
|
||||
|
@ -209,11 +271,17 @@ add_task(async function MoveWidgetsInTwoWindows() {
|
|||
// We add an item to the panel because otherwise we can't test dragging
|
||||
// to items that are already there. We remove it because
|
||||
// 'checkPalette' checks that we leave the browser in the default state.
|
||||
CustomizableUI.addWidgetToArea("cui-mode-wrapping-some-panel-item", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"cui-mode-wrapping-some-panel-item",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
await checkPanel(widgetId, method);
|
||||
CustomizableUI.removeWidgetFromArea("cui-mode-wrapping-some-panel-item");
|
||||
await checkPalette(widgetId, method);
|
||||
CustomizableUI.addWidgetToArea("cui-mode-wrapping-some-panel-item", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"cui-mode-wrapping-some-panel-item",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
await checkPanel(widgetId, method);
|
||||
await checkToolbar(widgetId, method);
|
||||
CustomizableUI.removeWidgetFromArea("cui-mode-wrapping-some-panel-item");
|
||||
|
|
|
@ -9,13 +9,25 @@ const kTestWidget1 = "test-customize-mode-create-destroy1";
|
|||
// Creating and destroying a widget should correctly wrap/unwrap stuff
|
||||
add_task(async function testWrapUnwrap() {
|
||||
await startCustomizing();
|
||||
CustomizableUI.createWidget({id: kTestWidget1, label: "Pretty label", tooltiptext: "Pretty tooltip"});
|
||||
CustomizableUI.createWidget({
|
||||
id: kTestWidget1,
|
||||
label: "Pretty label",
|
||||
tooltiptext: "Pretty tooltip",
|
||||
});
|
||||
let elem = document.getElementById(kTestWidget1);
|
||||
let wrapper = document.getElementById("wrapper-" + kTestWidget1);
|
||||
ok(elem, "There should be an item");
|
||||
ok(wrapper, "There should be a wrapper");
|
||||
is(wrapper.firstElementChild.id, kTestWidget1, "Wrapper should have test widget");
|
||||
is(wrapper.parentNode.id, "customization-palette", "Wrapper should be in palette");
|
||||
is(
|
||||
wrapper.firstElementChild.id,
|
||||
kTestWidget1,
|
||||
"Wrapper should have test widget"
|
||||
);
|
||||
is(
|
||||
wrapper.parentNode.id,
|
||||
"customization-palette",
|
||||
"Wrapper should be in palette"
|
||||
);
|
||||
CustomizableUI.destroyWidget(kTestWidget1);
|
||||
wrapper = document.getElementById("wrapper-" + kTestWidget1);
|
||||
ok(!wrapper, "There should be a wrapper");
|
||||
|
|
|
@ -12,8 +12,7 @@ add_task(function testAddbrokenViewWidget() {
|
|||
type: "view",
|
||||
viewId: "idontexist",
|
||||
/* Empty handler so we try to attach it maybe? */
|
||||
onViewShowing() {
|
||||
},
|
||||
onViewShowing() {},
|
||||
};
|
||||
|
||||
let noError = true;
|
||||
|
@ -24,7 +23,10 @@ add_task(function testAddbrokenViewWidget() {
|
|||
Cu.reportError(ex);
|
||||
noError = false;
|
||||
}
|
||||
ok(noError, "Should not throw an exception trying to add a broken view widget.");
|
||||
ok(
|
||||
noError,
|
||||
"Should not throw an exception trying to add a broken view widget."
|
||||
);
|
||||
|
||||
noError = true;
|
||||
try {
|
||||
|
@ -33,7 +35,10 @@ add_task(function testAddbrokenViewWidget() {
|
|||
Cu.reportError(ex);
|
||||
noError = false;
|
||||
}
|
||||
ok(noError, "Should not throw an exception trying to remove the broken view widget.");
|
||||
ok(
|
||||
noError,
|
||||
"Should not throw an exception trying to remove the broken view widget."
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function asyncCleanup() {
|
||||
|
|
|
@ -8,25 +8,38 @@ registerCleanupFunction(removeCustomToolbars);
|
|||
|
||||
// Sanity checks
|
||||
add_task(function sanityChecks() {
|
||||
SimpleTest.doesThrow(() => CustomizableUI.registerArea("@foo"),
|
||||
"Registering areas with an invalid ID should throw.");
|
||||
SimpleTest.doesThrow(
|
||||
() => CustomizableUI.registerArea("@foo"),
|
||||
"Registering areas with an invalid ID should throw."
|
||||
);
|
||||
|
||||
SimpleTest.doesThrow(() => CustomizableUI.registerArea([]),
|
||||
"Registering areas with an invalid ID should throw.");
|
||||
SimpleTest.doesThrow(
|
||||
() => CustomizableUI.registerArea([]),
|
||||
"Registering areas with an invalid ID should throw."
|
||||
);
|
||||
|
||||
SimpleTest.doesThrow(() => CustomizableUI.unregisterArea("@foo"),
|
||||
"Unregistering areas with an invalid ID should throw.");
|
||||
SimpleTest.doesThrow(
|
||||
() => CustomizableUI.unregisterArea("@foo"),
|
||||
"Unregistering areas with an invalid ID should throw."
|
||||
);
|
||||
|
||||
SimpleTest.doesThrow(() => CustomizableUI.unregisterArea([]),
|
||||
"Unregistering areas with an invalid ID should throw.");
|
||||
SimpleTest.doesThrow(
|
||||
() => CustomizableUI.unregisterArea([]),
|
||||
"Unregistering areas with an invalid ID should throw."
|
||||
);
|
||||
|
||||
SimpleTest.doesThrow(() => CustomizableUI.unregisterArea("unknown"),
|
||||
"Unregistering an area that's not registered should throw.");
|
||||
SimpleTest.doesThrow(
|
||||
() => CustomizableUI.unregisterArea("unknown"),
|
||||
"Unregistering an area that's not registered should throw."
|
||||
);
|
||||
});
|
||||
|
||||
// Check areas are loaded with their default placements.
|
||||
add_task(function checkLoadedAres() {
|
||||
ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
|
||||
ok(
|
||||
CustomizableUI.inDefaultState,
|
||||
"Everything should be in its default state."
|
||||
);
|
||||
});
|
||||
|
||||
// Check registering and unregistering a new area.
|
||||
|
@ -35,14 +48,21 @@ add_task(function checkRegisteringAndUnregistering() {
|
|||
const kButtonId = "test-registration-button";
|
||||
createDummyXULButton(kButtonId);
|
||||
createToolbarWithPlacements(kToolbarId, ["spring", kButtonId, "spring"]);
|
||||
assertAreaPlacements(kToolbarId,
|
||||
[/customizableui-special-spring\d+/,
|
||||
kButtonId,
|
||||
/customizableui-special-spring\d+/]);
|
||||
ok(!CustomizableUI.inDefaultState, "With a new toolbar it is no longer in a default state.");
|
||||
assertAreaPlacements(kToolbarId, [
|
||||
/customizableui-special-spring\d+/,
|
||||
kButtonId,
|
||||
/customizableui-special-spring\d+/,
|
||||
]);
|
||||
ok(
|
||||
!CustomizableUI.inDefaultState,
|
||||
"With a new toolbar it is no longer in a default state."
|
||||
);
|
||||
removeCustomToolbars(); // Will call unregisterArea for us
|
||||
ok(CustomizableUI.inDefaultState, "When the toolbar is unregistered, " +
|
||||
"everything will return to the default state.");
|
||||
ok(
|
||||
CustomizableUI.inDefaultState,
|
||||
"When the toolbar is unregistered, " +
|
||||
"everything will return to the default state."
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function asyncCleanup() {
|
||||
|
|
|
@ -12,12 +12,22 @@ add_task(function skipMissingIDS() {
|
|||
ok(CustomizableUI.inDefaultState, "Should be in the default state.");
|
||||
let btn = createDummyXULButton(kButtonId, "Gone!");
|
||||
CustomizableUI.addWidgetToArea(kButtonId, CustomizableUI.AREA_NAVBAR);
|
||||
ok(!CustomizableUI.inDefaultState, "Should no longer be in the default state.");
|
||||
is(btn.parentNode.parentNode.id, CustomizableUI.AREA_NAVBAR, "Button should be in navbar");
|
||||
ok(
|
||||
!CustomizableUI.inDefaultState,
|
||||
"Should no longer be in the default state."
|
||||
);
|
||||
is(
|
||||
btn.parentNode.parentNode.id,
|
||||
CustomizableUI.AREA_NAVBAR,
|
||||
"Button should be in navbar"
|
||||
);
|
||||
btn.remove();
|
||||
is(btn.parentNode, null, "Button is no longer in the navbar");
|
||||
ok(CustomizableUI.inDefaultState, "Should be back in the default state, " +
|
||||
"despite unknown button ID in placements.");
|
||||
ok(
|
||||
CustomizableUI.inDefaultState,
|
||||
"Should be back in the default state, " +
|
||||
"despite unknown button ID in placements."
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function asyncCleanup() {
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
CustomizableUI.createWidget({id: "cui-panel-item-to-drag-to", defaultArea: CustomizableUI.AREA_FIXED_OVERFLOW_PANEL, label: "Item in panel to drag to"});
|
||||
CustomizableUI.createWidget({
|
||||
id: "cui-panel-item-to-drag-to",
|
||||
defaultArea: CustomizableUI.AREA_FIXED_OVERFLOW_PANEL,
|
||||
label: "Item in panel to drag to",
|
||||
});
|
||||
|
||||
// Dragging an item from the palette to another button in the panel should work.
|
||||
add_task(async function() {
|
||||
|
@ -13,10 +17,15 @@ add_task(async function() {
|
|||
|
||||
let lastButtonIndex = placements.length - 1;
|
||||
let lastButton = placements[lastButtonIndex];
|
||||
let placementsAfterInsert = placements.slice(0, lastButtonIndex).concat(["new-window-button", lastButton]);
|
||||
let placementsAfterInsert = placements
|
||||
.slice(0, lastButtonIndex)
|
||||
.concat(["new-window-button", lastButton]);
|
||||
let lastButtonNode = document.getElementById(lastButton);
|
||||
simulateItemDrag(btn, lastButtonNode, "start");
|
||||
assertAreaPlacements(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL, placementsAfterInsert);
|
||||
assertAreaPlacements(
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL,
|
||||
placementsAfterInsert
|
||||
);
|
||||
ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
|
||||
let palette = document.getElementById("customization-palette");
|
||||
simulateItemDrag(btn, palette);
|
||||
|
@ -26,7 +35,10 @@ add_task(async function() {
|
|||
|
||||
// Dragging an item from the palette to the panel itself should also work.
|
||||
add_task(async function() {
|
||||
CustomizableUI.addWidgetToArea("cui-panel-item-to-drag-to", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"cui-panel-item-to-drag-to",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
await startCustomizing();
|
||||
let btn = document.getElementById("new-window-button");
|
||||
let panel = document.getElementById(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
|
@ -34,7 +46,10 @@ add_task(async function() {
|
|||
|
||||
let placementsAfterAppend = placements.concat(["new-window-button"]);
|
||||
simulateItemDrag(btn, panel);
|
||||
assertAreaPlacements(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL, placementsAfterAppend);
|
||||
assertAreaPlacements(
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL,
|
||||
placementsAfterAppend
|
||||
);
|
||||
ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
|
||||
let palette = document.getElementById("customization-palette");
|
||||
simulateItemDrag(btn, palette);
|
||||
|
@ -56,7 +71,10 @@ add_task(async function() {
|
|||
|
||||
let placementsAfterAppend = ["new-window-button"];
|
||||
simulateItemDrag(btn, panel);
|
||||
assertAreaPlacements(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL, placementsAfterAppend);
|
||||
assertAreaPlacements(
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL,
|
||||
placementsAfterAppend
|
||||
);
|
||||
ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
|
||||
let palette = document.getElementById("customization-palette");
|
||||
simulateItemDrag(btn, palette);
|
||||
|
|
|
@ -15,7 +15,10 @@ add_task(async function() {
|
|||
|
||||
originalWindowWidth = window.outerWidth;
|
||||
let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
|
||||
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
|
||||
ok(
|
||||
!navbar.hasAttribute("overflowing"),
|
||||
"Should start with a non-overflowing toolbar."
|
||||
);
|
||||
window.resizeTo(400, window.outerHeight);
|
||||
|
||||
await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing"));
|
||||
|
@ -26,15 +29,28 @@ add_task(async function() {
|
|||
chevron.click();
|
||||
await shownPanelPromise;
|
||||
|
||||
let contextMenu = document.getElementById("customizationPanelItemContextMenu");
|
||||
let contextMenu = document.getElementById(
|
||||
"customizationPanelItemContextMenu"
|
||||
);
|
||||
let shownContextPromise = popupShown(contextMenu);
|
||||
let sidebarButton = document.getElementById("sidebar-button");
|
||||
ok(sidebarButton, "sidebar-button was found");
|
||||
is(sidebarButton.getAttribute("overflowedItem"), "true", "Sidebar button is overflowing");
|
||||
EventUtils.synthesizeMouse(sidebarButton, 2, 2, {type: "contextmenu", button: 2});
|
||||
is(
|
||||
sidebarButton.getAttribute("overflowedItem"),
|
||||
"true",
|
||||
"Sidebar button is overflowing"
|
||||
);
|
||||
EventUtils.synthesizeMouse(sidebarButton, 2, 2, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
});
|
||||
await shownContextPromise;
|
||||
|
||||
is(overflowPanel.state, "open", "The widget overflow panel should still be open.");
|
||||
is(
|
||||
overflowPanel.state,
|
||||
"open",
|
||||
"The widget overflow panel should still be open."
|
||||
);
|
||||
|
||||
let expectedEntries = [
|
||||
[".customize-context-moveToPanel", true],
|
||||
|
@ -54,19 +70,34 @@ add_task(async function() {
|
|||
await hiddenContextPromise;
|
||||
await hiddenPromise;
|
||||
|
||||
let sidebarButtonPlacement = CustomizableUI.getPlacementOfWidget("sidebar-button");
|
||||
let sidebarButtonPlacement = CustomizableUI.getPlacementOfWidget(
|
||||
"sidebar-button"
|
||||
);
|
||||
ok(sidebarButtonPlacement, "Sidebar button should still have a placement");
|
||||
is(sidebarButtonPlacement && sidebarButtonPlacement.area,
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL, "Sidebar button should be pinned now");
|
||||
is(
|
||||
sidebarButtonPlacement && sidebarButtonPlacement.area,
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL,
|
||||
"Sidebar button should be pinned now"
|
||||
);
|
||||
CustomizableUI.reset();
|
||||
|
||||
// In some cases, it can take a tick for the navbar to overflow again. Wait for it:
|
||||
await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing"));
|
||||
ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
|
||||
|
||||
sidebarButtonPlacement = CustomizableUI.getPlacementOfWidget("sidebar-button");
|
||||
sidebarButtonPlacement = CustomizableUI.getPlacementOfWidget(
|
||||
"sidebar-button"
|
||||
);
|
||||
ok(sidebarButtonPlacement, "Sidebar button should still have a placement");
|
||||
is(sidebarButtonPlacement && sidebarButtonPlacement.area, "nav-bar", "Sidebar button should be back in the navbar now");
|
||||
is(
|
||||
sidebarButtonPlacement && sidebarButtonPlacement.area,
|
||||
"nav-bar",
|
||||
"Sidebar button should be back in the navbar now"
|
||||
);
|
||||
|
||||
is(sidebarButton.getAttribute("overflowedItem"), "true", "Sidebar button should still be overflowed");
|
||||
is(
|
||||
sidebarButton.getAttribute("overflowedItem"),
|
||||
"true",
|
||||
"Sidebar button should still be overflowed"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -11,7 +11,10 @@ function isFullscreenSizeMode() {
|
|||
|
||||
// Observers should be disabled when in customization mode.
|
||||
add_task(async function() {
|
||||
CustomizableUI.addWidgetToArea("fullscreen-button", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"fullscreen-button",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
|
||||
await waitForOverflowButtonShown();
|
||||
|
||||
|
@ -22,26 +25,49 @@ add_task(async function() {
|
|||
document.getElementById("widget-overflow").hidePopup();
|
||||
|
||||
let fullscreenButton = document.getElementById("fullscreen-button");
|
||||
ok(!fullscreenButton.checked, "Fullscreen button should not be checked when not in fullscreen.");
|
||||
ok(!isFullscreenSizeMode(), "Should not be in fullscreen sizemode before we enter fullscreen.");
|
||||
ok(
|
||||
!fullscreenButton.checked,
|
||||
"Fullscreen button should not be checked when not in fullscreen."
|
||||
);
|
||||
ok(
|
||||
!isFullscreenSizeMode(),
|
||||
"Should not be in fullscreen sizemode before we enter fullscreen."
|
||||
);
|
||||
|
||||
BrowserFullScreen();
|
||||
await TestUtils.waitForCondition(() => isFullscreenSizeMode());
|
||||
ok(fullscreenButton.checked, "Fullscreen button should be checked when in fullscreen.");
|
||||
ok(
|
||||
fullscreenButton.checked,
|
||||
"Fullscreen button should be checked when in fullscreen."
|
||||
);
|
||||
|
||||
await startCustomizing();
|
||||
|
||||
let fullscreenButtonWrapper = document.getElementById("wrapper-fullscreen-button");
|
||||
ok(fullscreenButtonWrapper.hasAttribute("itemobserves"), "Observer should be moved to wrapper");
|
||||
let fullscreenButtonWrapper = document.getElementById(
|
||||
"wrapper-fullscreen-button"
|
||||
);
|
||||
ok(
|
||||
fullscreenButtonWrapper.hasAttribute("itemobserves"),
|
||||
"Observer should be moved to wrapper"
|
||||
);
|
||||
fullscreenButton = document.getElementById("fullscreen-button");
|
||||
ok(!fullscreenButton.hasAttribute("observes"), "Observer should be removed from button");
|
||||
ok(!fullscreenButton.checked, "Fullscreen button should no longer be checked during customization mode");
|
||||
ok(
|
||||
!fullscreenButton.hasAttribute("observes"),
|
||||
"Observer should be removed from button"
|
||||
);
|
||||
ok(
|
||||
!fullscreenButton.checked,
|
||||
"Fullscreen button should no longer be checked during customization mode"
|
||||
);
|
||||
|
||||
await endCustomizing();
|
||||
|
||||
BrowserFullScreen();
|
||||
fullscreenButton = document.getElementById("fullscreen-button");
|
||||
await TestUtils.waitForCondition(() => !isFullscreenSizeMode());
|
||||
ok(!fullscreenButton.checked, "Fullscreen button should not be checked when not in fullscreen.");
|
||||
ok(
|
||||
!fullscreenButton.checked,
|
||||
"Fullscreen button should not be checked when not in fullscreen."
|
||||
);
|
||||
CustomizableUI.reset();
|
||||
});
|
||||
|
|
|
@ -8,11 +8,16 @@ const kWidgetId = "some-widget";
|
|||
|
||||
function assertWidgetExists(aWindow, aExists) {
|
||||
if (aExists) {
|
||||
ok(aWindow.document.getElementById(kWidgetId),
|
||||
"Should have found test widget in the window");
|
||||
ok(
|
||||
aWindow.document.getElementById(kWidgetId),
|
||||
"Should have found test widget in the window"
|
||||
);
|
||||
} else {
|
||||
is(aWindow.document.getElementById(kWidgetId), null,
|
||||
"Should not have found test widget in the window");
|
||||
is(
|
||||
aWindow.document.getElementById(kWidgetId),
|
||||
null,
|
||||
"Should not have found test widget in the window"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,8 +27,10 @@ add_task(function() {
|
|||
let wrapper = CustomizableUI.createWidget({
|
||||
id: kWidgetId,
|
||||
});
|
||||
ok(wrapper.showInPrivateBrowsing,
|
||||
"showInPrivateBrowsing should have defaulted to true.");
|
||||
ok(
|
||||
wrapper.showInPrivateBrowsing,
|
||||
"showInPrivateBrowsing should have defaulted to true."
|
||||
);
|
||||
CustomizableUI.destroyWidget(kWidgetId);
|
||||
});
|
||||
|
||||
|
@ -32,28 +39,26 @@ add_task(function() {
|
|||
// private windows.
|
||||
add_task(async function() {
|
||||
let plain1 = await openAndLoadWindow();
|
||||
let private1 = await openAndLoadWindow({private: true});
|
||||
let private1 = await openAndLoadWindow({ private: true });
|
||||
CustomizableUI.createWidget({
|
||||
id: kWidgetId,
|
||||
removable: true,
|
||||
showInPrivateBrowsing: false,
|
||||
});
|
||||
CustomizableUI.addWidgetToArea(kWidgetId,
|
||||
CustomizableUI.AREA_NAVBAR);
|
||||
CustomizableUI.addWidgetToArea(kWidgetId, CustomizableUI.AREA_NAVBAR);
|
||||
assertWidgetExists(plain1, true);
|
||||
assertWidgetExists(private1, false);
|
||||
|
||||
// Now open up some new windows. The widget should exist in the new
|
||||
// plain window, but not the new private window.
|
||||
let plain2 = await openAndLoadWindow();
|
||||
let private2 = await openAndLoadWindow({private: true});
|
||||
let private2 = await openAndLoadWindow({ private: true });
|
||||
assertWidgetExists(plain2, true);
|
||||
assertWidgetExists(private2, false);
|
||||
|
||||
// Try moving the widget around and make sure it doesn't get added
|
||||
// to the private windows. We'll start by appending it to the tabstrip.
|
||||
CustomizableUI.addWidgetToArea(kWidgetId,
|
||||
CustomizableUI.AREA_TABSTRIP);
|
||||
CustomizableUI.addWidgetToArea(kWidgetId, CustomizableUI.AREA_TABSTRIP);
|
||||
assertWidgetExists(plain1, true);
|
||||
assertWidgetExists(plain2, true);
|
||||
assertWidgetExists(private1, false);
|
||||
|
@ -72,7 +77,9 @@ add_task(async function() {
|
|||
assertWidgetExists(private1, false);
|
||||
assertWidgetExists(private2, false);
|
||||
|
||||
await Promise.all([plain1, plain2, private1, private2].map(promiseWindowClosed));
|
||||
await Promise.all(
|
||||
[plain1, plain2, private1, private2].map(promiseWindowClosed)
|
||||
);
|
||||
|
||||
CustomizableUI.destroyWidget("some-widget");
|
||||
});
|
||||
|
@ -82,30 +89,28 @@ add_task(async function() {
|
|||
// private browsing windows.
|
||||
add_task(async function() {
|
||||
let plain1 = await openAndLoadWindow();
|
||||
let private1 = await openAndLoadWindow({private: true});
|
||||
let private1 = await openAndLoadWindow({ private: true });
|
||||
|
||||
CustomizableUI.createWidget({
|
||||
id: kWidgetId,
|
||||
removable: true,
|
||||
showInPrivateBrowsing: true,
|
||||
});
|
||||
CustomizableUI.addWidgetToArea(kWidgetId,
|
||||
CustomizableUI.AREA_NAVBAR);
|
||||
CustomizableUI.addWidgetToArea(kWidgetId, CustomizableUI.AREA_NAVBAR);
|
||||
assertWidgetExists(plain1, true);
|
||||
assertWidgetExists(private1, true);
|
||||
|
||||
// Now open up some new windows. The widget should exist in the new
|
||||
// plain window, but not the new private window.
|
||||
let plain2 = await openAndLoadWindow();
|
||||
let private2 = await openAndLoadWindow({private: true});
|
||||
let private2 = await openAndLoadWindow({ private: true });
|
||||
|
||||
assertWidgetExists(plain2, true);
|
||||
assertWidgetExists(private2, true);
|
||||
|
||||
// Try moving the widget around and make sure it doesn't get added
|
||||
// to the private windows. We'll start by appending it to the tabstrip.
|
||||
CustomizableUI.addWidgetToArea(kWidgetId,
|
||||
CustomizableUI.AREA_TABSTRIP);
|
||||
CustomizableUI.addWidgetToArea(kWidgetId, CustomizableUI.AREA_TABSTRIP);
|
||||
assertWidgetExists(plain1, true);
|
||||
assertWidgetExists(plain2, true);
|
||||
assertWidgetExists(private1, true);
|
||||
|
@ -124,7 +129,9 @@ add_task(async function() {
|
|||
assertWidgetExists(private1, false);
|
||||
assertWidgetExists(private2, false);
|
||||
|
||||
await Promise.all([plain1, plain2, private1, private2].map(promiseWindowClosed));
|
||||
await Promise.all(
|
||||
[plain1, plain2, private1, private2].map(promiseWindowClosed)
|
||||
);
|
||||
|
||||
CustomizableUI.destroyWidget("some-widget");
|
||||
});
|
||||
|
|
|
@ -25,17 +25,29 @@ add_task(async function() {
|
|||
defaultPlacements: [],
|
||||
});
|
||||
CustomizableUI.addWidgetToArea(kButtonId, kLazyAreaId);
|
||||
assertAreaPlacements(kLazyAreaId, [kButtonId],
|
||||
"Placements should have changed because widget is removable.");
|
||||
assertAreaPlacements(
|
||||
kLazyAreaId,
|
||||
[kButtonId],
|
||||
"Placements should have changed because widget is removable."
|
||||
);
|
||||
let btn = document.getElementById(kButtonId);
|
||||
btn.setAttribute("removable", "false");
|
||||
gLazyArea._customizationTarget = gLazyArea;
|
||||
CustomizableUI.registerToolbarNode(gLazyArea, []);
|
||||
assertAreaPlacements(kLazyAreaId, [], "Placements should no longer include widget.");
|
||||
is(btn.parentNode.id, CustomizableUI.getCustomizationTarget(gNavBar).id,
|
||||
"Button shouldn't actually have moved as it's not removable");
|
||||
assertAreaPlacements(
|
||||
kLazyAreaId,
|
||||
[],
|
||||
"Placements should no longer include widget."
|
||||
);
|
||||
is(
|
||||
btn.parentNode.id,
|
||||
CustomizableUI.getCustomizationTarget(gNavBar).id,
|
||||
"Button shouldn't actually have moved as it's not removable"
|
||||
);
|
||||
btn = document.getElementById(kButtonId);
|
||||
if (btn) btn.remove();
|
||||
if (btn) {
|
||||
btn.remove();
|
||||
}
|
||||
CustomizableUI.removeWidgetFromArea(kButtonId);
|
||||
CustomizableUI.unregisterArea(kLazyAreaId);
|
||||
gLazyArea.remove();
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
"use strict";
|
||||
|
||||
const kLazyAreaId = "test-890262-lazy-area";
|
||||
const kWidget1Id = "test-890262-widget1";
|
||||
const kWidget2Id = "test-890262-widget2";
|
||||
const kWidget1Id = "test-890262-widget1";
|
||||
const kWidget2Id = "test-890262-widget2";
|
||||
|
||||
setupArea();
|
||||
|
||||
|
@ -24,7 +24,10 @@ add_task(function() {
|
|||
Cu.reportError(ex);
|
||||
noError = false;
|
||||
}
|
||||
ok(noError, "Shouldn't throw an exception for a widget that was created in a not-yet-constructed area");
|
||||
ok(
|
||||
noError,
|
||||
"Shouldn't throw an exception for a widget that was created in a not-yet-constructed area"
|
||||
);
|
||||
});
|
||||
|
||||
// Destroying a widget after moving it to a lazy area should work.
|
||||
|
@ -43,7 +46,10 @@ add_task(function() {
|
|||
Cu.reportError(ex);
|
||||
noError = false;
|
||||
}
|
||||
ok(noError, "Shouldn't throw an exception for a widget that was added to a not-yet-constructed area");
|
||||
ok(
|
||||
noError,
|
||||
"Shouldn't throw an exception for a widget that was added to a not-yet-constructed area"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function asyncCleanup() {
|
||||
|
|
|
@ -8,7 +8,10 @@ const kWidgetId = "test-892956-destroyWidget-defaultPlacement";
|
|||
|
||||
// destroyWidget should clean up defaultPlacements if the widget had a defaultArea
|
||||
add_task(async function() {
|
||||
ok(CustomizableUI.inDefaultState, "Should be in the default state when we start");
|
||||
ok(
|
||||
CustomizableUI.inDefaultState,
|
||||
"Should be in the default state when we start"
|
||||
);
|
||||
|
||||
let widgetSpec = {
|
||||
id: kWidgetId,
|
||||
|
@ -16,7 +19,10 @@ add_task(async function() {
|
|||
};
|
||||
CustomizableUI.createWidget(widgetSpec);
|
||||
CustomizableUI.destroyWidget(kWidgetId);
|
||||
ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish");
|
||||
ok(
|
||||
CustomizableUI.inDefaultState,
|
||||
"Should be in the default state when we finish"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function asyncCleanup() {
|
||||
|
|
|
@ -16,8 +16,10 @@ async function waitForSearchBarFocus() {
|
|||
|
||||
// Ctrl+K should open the menu panel and focus the search bar if the search bar is in the panel.
|
||||
add_task(async function check_shortcut_when_in_closed_overflow_panel_closed() {
|
||||
CustomizableUI.addWidgetToArea("search-container",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"search-container",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
|
||||
let shownPanelPromise = promiseOverflowShown(window);
|
||||
sendWebSearchKeyCommand();
|
||||
|
@ -33,8 +35,10 @@ add_task(async function check_shortcut_when_in_closed_overflow_panel_closed() {
|
|||
|
||||
// Ctrl+K should give focus to the searchbar when the searchbar is in the menupanel and the panel is already opened.
|
||||
add_task(async function check_shortcut_when_in_opened_overflow_panel() {
|
||||
CustomizableUI.addWidgetToArea("search-container",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"search-container",
|
||||
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
);
|
||||
|
||||
await document.getElementById("nav-bar").overflowable.show();
|
||||
|
||||
|
@ -52,17 +56,25 @@ add_task(async function check_shortcut_when_in_opened_overflow_panel() {
|
|||
add_task(async function check_shortcut_when_in_overflow() {
|
||||
this.originalWindowWidth = window.outerWidth;
|
||||
let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
|
||||
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
|
||||
ok(
|
||||
!navbar.hasAttribute("overflowing"),
|
||||
"Should start with a non-overflowing toolbar."
|
||||
);
|
||||
ok(CustomizableUI.inDefaultState, "Should start in default state.");
|
||||
|
||||
Services.prefs.setBoolPref("browser.search.widget.inNavBar", true);
|
||||
|
||||
window.resizeTo(kForceOverflowWidthPx, window.outerHeight);
|
||||
await waitForCondition(() => {
|
||||
return navbar.getAttribute("overflowing") == "true" &&
|
||||
!navbar.querySelector("#search-container");
|
||||
return (
|
||||
navbar.getAttribute("overflowing") == "true" &&
|
||||
!navbar.querySelector("#search-container")
|
||||
);
|
||||
});
|
||||
ok(!navbar.querySelector("#search-container"), "Search container should be overflowing");
|
||||
ok(
|
||||
!navbar.querySelector("#search-container"),
|
||||
"Search container should be overflowing"
|
||||
);
|
||||
|
||||
let shownPanelPromise = promiseOverflowShown(window);
|
||||
sendWebSearchKeyCommand();
|
||||
|
@ -82,7 +94,10 @@ add_task(async function check_shortcut_when_in_overflow() {
|
|||
navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
|
||||
window.resizeTo(this.originalWindowWidth, window.outerHeight);
|
||||
await waitForCondition(() => !navbar.hasAttribute("overflowing"));
|
||||
ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
|
||||
ok(
|
||||
!navbar.hasAttribute("overflowing"),
|
||||
"Should not have an overflowing toolbar."
|
||||
);
|
||||
});
|
||||
|
||||
// Ctrl+K should focus the search bar if it is in the navbar and not overflowing.
|
||||
|
@ -100,7 +115,6 @@ add_task(async function check_shortcut_when_not_in_overflow() {
|
|||
Services.prefs.setBoolPref("browser.search.widget.inNavBar", false);
|
||||
});
|
||||
|
||||
|
||||
function sendWebSearchKeyCommand() {
|
||||
document.documentElement.focus();
|
||||
EventUtils.synthesizeKey("k", { accelKey: true });
|
||||
|
@ -110,7 +124,15 @@ function logActiveElement() {
|
|||
let element = document.activeElement;
|
||||
let str = "";
|
||||
while (element && element.parentNode) {
|
||||
str = " (" + element.localName + "#" + element.id + "." + [...element.classList].join(".") + ") >" + str;
|
||||
str =
|
||||
" (" +
|
||||
element.localName +
|
||||
"#" +
|
||||
element.id +
|
||||
"." +
|
||||
[...element.classList].join(".") +
|
||||
") >" +
|
||||
str;
|
||||
element = element.parentNode;
|
||||
}
|
||||
info("Active element: " + element ? str : "null");
|
||||
|
|
|
@ -8,22 +8,40 @@
|
|||
add_task(async function() {
|
||||
let originalWindowWidth = window.outerWidth;
|
||||
let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
|
||||
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
|
||||
let oldChildCount = CustomizableUI.getCustomizationTarget(navbar).childElementCount;
|
||||
ok(
|
||||
!navbar.hasAttribute("overflowing"),
|
||||
"Should start with a non-overflowing toolbar."
|
||||
);
|
||||
let oldChildCount = CustomizableUI.getCustomizationTarget(navbar)
|
||||
.childElementCount;
|
||||
window.resizeTo(kForceOverflowWidthPx, window.outerHeight);
|
||||
await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing"));
|
||||
ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
|
||||
|
||||
ok(CustomizableUI.getCustomizationTarget(navbar).childElementCount < oldChildCount, "Should have fewer children.");
|
||||
ok(
|
||||
CustomizableUI.getCustomizationTarget(navbar).childElementCount <
|
||||
oldChildCount,
|
||||
"Should have fewer children."
|
||||
);
|
||||
let newWindow = await openAndLoadWindow();
|
||||
let otherNavBar = newWindow.document.getElementById(CustomizableUI.AREA_NAVBAR);
|
||||
await TestUtils.waitForCondition(() => otherNavBar.hasAttribute("overflowing"));
|
||||
ok(otherNavBar.hasAttribute("overflowing"), "Other window should have an overflowing toolbar.");
|
||||
let otherNavBar = newWindow.document.getElementById(
|
||||
CustomizableUI.AREA_NAVBAR
|
||||
);
|
||||
await TestUtils.waitForCondition(() =>
|
||||
otherNavBar.hasAttribute("overflowing")
|
||||
);
|
||||
ok(
|
||||
otherNavBar.hasAttribute("overflowing"),
|
||||
"Other window should have an overflowing toolbar."
|
||||
);
|
||||
await promiseWindowClosed(newWindow);
|
||||
|
||||
window.resizeTo(originalWindowWidth, window.outerHeight);
|
||||
await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing"));
|
||||
ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
|
||||
ok(
|
||||
!navbar.hasAttribute("overflowing"),
|
||||
"Should no longer have an overflowing toolbar."
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function asyncCleanup() {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче