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:
Victor Porof 2019-07-05 09:53:32 +02:00
Родитель f9f5914039
Коммит 1f830c96da
1654 изменённых файлов: 129198 добавлений и 60937 удалений

Просмотреть файл

@ -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() {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше