summaryrefslogtreecommitdiffstats
path: root/toolkit/content/aboutProfiles.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--toolkit/content/aboutProfiles.js397
1 files changed, 397 insertions, 0 deletions
diff --git a/toolkit/content/aboutProfiles.js b/toolkit/content/aboutProfiles.js
new file mode 100644
index 0000000000..15c0419a11
--- /dev/null
+++ b/toolkit/content/aboutProfiles.js
@@ -0,0 +1,397 @@
+/* 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/. */
+
+"use strict";
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+XPCOMUtils.defineLazyServiceGetter(
+ this,
+ "ProfileService",
+ "@mozilla.org/toolkit/profile-service;1",
+ "nsIToolkitProfileService"
+);
+
+async function flush() {
+ try {
+ ProfileService.flush();
+ rebuildProfileList();
+ } catch (e) {
+ let [title, msg, button] = await document.l10n.formatValues([
+ { id: "profiles-flush-fail-title" },
+ {
+ id:
+ e.result == Cr.NS_ERROR_DATABASE_CHANGED
+ ? "profiles-flush-conflict"
+ : "profiles-flush-failed",
+ },
+ { id: "profiles-flush-restart-button" },
+ ]);
+
+ const PS = Ci.nsIPromptService;
+ let result = Services.prompt.confirmEx(
+ window,
+ title,
+ msg,
+ PS.BUTTON_POS_0 * PS.BUTTON_TITLE_CANCEL +
+ PS.BUTTON_POS_1 * PS.BUTTON_TITLE_IS_STRING,
+ null,
+ button,
+ null,
+ null,
+ {}
+ );
+ if (result == 1) {
+ restart(false);
+ }
+ }
+}
+
+function rebuildProfileList() {
+ let parent = document.getElementById("profiles");
+ while (parent.firstChild) {
+ parent.firstChild.remove();
+ }
+
+ let defaultProfile;
+ try {
+ defaultProfile = ProfileService.defaultProfile;
+ } catch (e) {}
+
+ let currentProfile = ProfileService.currentProfile;
+
+ for (let profile of ProfileService.profiles) {
+ let isCurrentProfile = profile == currentProfile;
+ let isInUse = isCurrentProfile;
+ if (!isInUse) {
+ try {
+ let lock = profile.lock({});
+ lock.unlock();
+ } catch (e) {
+ if (
+ e.result != Cr.NS_ERROR_FILE_NOT_DIRECTORY &&
+ e.result != Cr.NS_ERROR_FILE_NOT_FOUND
+ ) {
+ isInUse = true;
+ }
+ }
+ }
+ display({
+ profile,
+ isDefault: profile == defaultProfile,
+ isCurrentProfile,
+ isInUse,
+ });
+ }
+}
+
+function display(profileData) {
+ let parent = document.getElementById("profiles");
+
+ let div = document.createElement("div");
+ parent.appendChild(div);
+
+ let name = document.createElement("h2");
+
+ div.appendChild(name);
+ document.l10n.setAttributes(name, "profiles-name", {
+ name: profileData.profile.name,
+ });
+
+ if (profileData.isCurrentProfile) {
+ let currentProfile = document.createElement("h3");
+ document.l10n.setAttributes(currentProfile, "profiles-current-profile");
+ div.appendChild(currentProfile);
+ } else if (profileData.isInUse) {
+ let currentProfile = document.createElement("h3");
+ document.l10n.setAttributes(currentProfile, "profiles-in-use-profile");
+ div.appendChild(currentProfile);
+ }
+
+ let table = document.createElement("table");
+ div.appendChild(table);
+
+ let tbody = document.createElement("tbody");
+ table.appendChild(tbody);
+
+ function createItem(title, value, dir = false) {
+ let tr = document.createElement("tr");
+ tbody.appendChild(tr);
+
+ let th = document.createElement("th");
+ th.setAttribute("class", "column");
+ document.l10n.setAttributes(th, title);
+ tr.appendChild(th);
+
+ let td = document.createElement("td");
+ tr.appendChild(td);
+
+ if (dir) {
+ td.appendChild(document.createTextNode(value.path));
+
+ if (value.exists()) {
+ let button = document.createElement("button");
+ button.setAttribute("class", "opendir");
+ document.l10n.setAttributes(button, "profiles-opendir");
+
+ td.appendChild(button);
+
+ button.addEventListener("click", function (e) {
+ value.reveal();
+ });
+ }
+ } else {
+ document.l10n.setAttributes(td, value);
+ }
+ }
+
+ createItem(
+ "profiles-is-default",
+ profileData.isDefault ? "profiles-yes" : "profiles-no"
+ );
+
+ createItem("profiles-rootdir", profileData.profile.rootDir, true);
+
+ if (profileData.profile.localDir.path != profileData.profile.rootDir.path) {
+ createItem("profiles-localdir", profileData.profile.localDir, true);
+ }
+
+ let renameButton = document.createElement("button");
+ document.l10n.setAttributes(renameButton, "profiles-rename");
+ renameButton.onclick = function () {
+ renameProfile(profileData.profile);
+ };
+ div.appendChild(renameButton);
+
+ if (!profileData.isInUse) {
+ let removeButton = document.createElement("button");
+ document.l10n.setAttributes(removeButton, "profiles-remove");
+ removeButton.onclick = function () {
+ removeProfile(profileData.profile);
+ };
+
+ div.appendChild(removeButton);
+ }
+
+ if (!profileData.isDefault) {
+ let defaultButton = document.createElement("button");
+ document.l10n.setAttributes(defaultButton, "profiles-set-as-default");
+ defaultButton.onclick = function () {
+ defaultProfile(profileData.profile);
+ };
+ div.appendChild(defaultButton);
+ }
+
+ if (!profileData.isInUse) {
+ let runButton = document.createElement("button");
+ document.l10n.setAttributes(runButton, "profiles-launch-profile");
+ runButton.onclick = function () {
+ openProfile(profileData.profile);
+ };
+ div.appendChild(runButton);
+ }
+
+ let sep = document.createElement("hr");
+ div.appendChild(sep);
+}
+
+// This is called from the createProfileWizard.xhtml dialog.
+function CreateProfile(profile) {
+ // The wizard created a profile, just make it the default.
+ defaultProfile(profile);
+}
+
+function createProfileWizard() {
+ // This should be rewritten in HTML eventually.
+ window.browsingContext.topChromeWindow.openDialog(
+ "chrome://mozapps/content/profile/createProfileWizard.xhtml",
+ "",
+ "centerscreen,chrome,modal,titlebar",
+ ProfileService,
+ { CreateProfile }
+ );
+}
+
+async function renameProfile(profile) {
+ let newName = { value: profile.name };
+ let [title, msg] = await document.l10n.formatValues([
+ { id: "profiles-rename-profile-title" },
+ { id: "profiles-rename-profile", args: { name: profile.name } },
+ ]);
+
+ if (Services.prompt.prompt(window, title, msg, newName, null, { value: 0 })) {
+ newName = newName.value;
+
+ if (newName == profile.name) {
+ return;
+ }
+
+ try {
+ profile.name = newName;
+ } catch (e) {
+ let [title, msg] = await document.l10n.formatValues([
+ { id: "profiles-invalid-profile-name-title" },
+ { id: "profiles-invalid-profile-name", args: { name: newName } },
+ ]);
+
+ Services.prompt.alert(window, title, msg);
+ return;
+ }
+
+ flush();
+ }
+}
+
+async function removeProfile(profile) {
+ let deleteFiles = false;
+
+ if (profile.rootDir.exists()) {
+ let [title, msg, dontDeleteStr, deleteStr] =
+ await document.l10n.formatValues([
+ { id: "profiles-delete-profile-title" },
+ {
+ id: "profiles-delete-profile-confirm",
+ args: { dir: profile.rootDir.path },
+ },
+ { id: "profiles-dont-delete-files" },
+ { id: "profiles-delete-files" },
+ ]);
+ let buttonPressed = Services.prompt.confirmEx(
+ window,
+ title,
+ msg,
+ Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
+ Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 +
+ Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_2,
+ dontDeleteStr,
+ null,
+ deleteStr,
+ null,
+ { value: 0 }
+ );
+ if (buttonPressed == 1) {
+ return;
+ }
+
+ if (buttonPressed == 2) {
+ deleteFiles = true;
+ }
+ }
+
+ // If we are deleting the default profile we must choose a different one.
+ let isDefault = false;
+ try {
+ isDefault = ProfileService.defaultProfile == profile;
+ } catch (e) {}
+
+ if (isDefault) {
+ for (let p of ProfileService.profiles) {
+ if (profile == p) {
+ continue;
+ }
+
+ if (isDefault) {
+ try {
+ ProfileService.defaultProfile = p;
+ } catch (e) {
+ // This can happen on dev-edition if a non-default profile is in use.
+ // In such a case the next time that dev-edition is started it will
+ // find no default profile and just create a new one.
+ }
+ }
+
+ break;
+ }
+ }
+
+ try {
+ profile.removeInBackground(deleteFiles);
+ } catch (e) {
+ let [title, msg] = await document.l10n.formatValues([
+ { id: "profiles-delete-profile-failed-title" },
+ { id: "profiles-delete-profile-failed-message" },
+ ]);
+
+ Services.prompt.alert(window, title, msg);
+ return;
+ }
+
+ flush();
+}
+
+async function defaultProfile(profile) {
+ try {
+ ProfileService.defaultProfile = profile;
+ flush();
+ } catch (e) {
+ // This can happen on dev-edition.
+ let [title, msg] = await document.l10n.formatValues([
+ { id: "profiles-cannot-set-as-default-title" },
+ { id: "profiles-cannot-set-as-default-message" },
+ ]);
+
+ Services.prompt.alert(window, title, msg);
+ }
+}
+
+function openProfile(profile) {
+ Services.startup.createInstanceWithProfile(profile);
+}
+
+function restart(safeMode) {
+ let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(
+ Ci.nsISupportsPRBool
+ );
+ Services.obs.notifyObservers(
+ cancelQuit,
+ "quit-application-requested",
+ "restart"
+ );
+
+ if (cancelQuit.data) {
+ return;
+ }
+
+ let flags = Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart;
+
+ if (safeMode) {
+ Services.startup.restartInSafeMode(flags);
+ } else {
+ Services.startup.quit(flags);
+ }
+}
+
+window.addEventListener(
+ "DOMContentLoaded",
+ function () {
+ let createButton = document.getElementById("create-button");
+ createButton.addEventListener("click", createProfileWizard);
+
+ let restartSafeModeButton = document.getElementById(
+ "restart-in-safe-mode-button"
+ );
+ if (!Services.policies || Services.policies.isAllowed("safeMode")) {
+ restartSafeModeButton.addEventListener("click", () => {
+ restart(true);
+ });
+ } else {
+ restartSafeModeButton.setAttribute("disabled", "true");
+ }
+
+ let restartNormalModeButton = document.getElementById("restart-button");
+ restartNormalModeButton.addEventListener("click", () => {
+ restart(false);
+ });
+
+ if (ProfileService.isListOutdated) {
+ document.getElementById("owned").hidden = true;
+ } else {
+ document.getElementById("conflict").hidden = true;
+ rebuildProfileList();
+ }
+ },
+ { once: true }
+);