summaryrefslogtreecommitdiffstats
path: root/toolkit/profile/content
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/profile/content')
-rw-r--r--toolkit/profile/content/createProfileWizard.js266
-rw-r--r--toolkit/profile/content/createProfileWizard.xhtml90
-rw-r--r--toolkit/profile/content/profileDowngrade.js39
-rw-r--r--toolkit/profile/content/profileDowngrade.xhtml40
-rw-r--r--toolkit/profile/content/profileSelection.js355
-rw-r--r--toolkit/profile/content/profileSelection.xhtml101
6 files changed, 891 insertions, 0 deletions
diff --git a/toolkit/profile/content/createProfileWizard.js b/toolkit/profile/content/createProfileWizard.js
new file mode 100644
index 0000000000..9e87fb4220
--- /dev/null
+++ b/toolkit/profile/content/createProfileWizard.js
@@ -0,0 +1,266 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const C = Cc;
+const I = Ci;
+
+const { AppConstants } = ChromeUtils.importESModule(
+ "resource://gre/modules/AppConstants.sys.mjs"
+);
+
+const ToolkitProfileService = "@mozilla.org/toolkit/profile-service;1";
+
+var gProfileService;
+var gProfileManagerBundle;
+
+var gDefaultProfileParent;
+
+// The directory where the profile will be created.
+var gProfileRoot;
+
+// Text node to display the location and name of the profile to create.
+var gProfileDisplay;
+
+// Called once when the wizard is opened.
+function initWizard() {
+ try {
+ gProfileService = C[ToolkitProfileService].getService(
+ I.nsIToolkitProfileService
+ );
+ gProfileManagerBundle = document.getElementById("bundle_profileManager");
+
+ gDefaultProfileParent = Services.dirsvc.get("DefProfRt", I.nsIFile);
+
+ // Initialize the profile location display.
+ gProfileDisplay = document.getElementById("profileDisplay").firstChild;
+ document.addEventListener("wizardfinish", onFinish);
+ document
+ .getElementById("explanation")
+ .addEventListener("pageshow", enableNextButton);
+ document
+ .getElementById("createProfile")
+ .addEventListener("pageshow", initSecondWizardPage);
+ setDisplayToDefaultFolder();
+ } catch (e) {
+ window.close();
+ throw e;
+ }
+}
+
+// Called every time the second wizard page is displayed.
+function initSecondWizardPage() {
+ var profileName = document.getElementById("profileName");
+ profileName.select();
+ profileName.focus();
+
+ // Initialize profile name validation.
+ checkCurrentInput(profileName.value);
+}
+
+const kSaltTable = [
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "0",
+];
+
+var kSaltString = "";
+for (var i = 0; i < 8; ++i) {
+ kSaltString += kSaltTable[Math.floor(Math.random() * kSaltTable.length)];
+}
+
+function saltName(aName) {
+ return kSaltString + "." + aName;
+}
+
+function setDisplayToDefaultFolder() {
+ var defaultProfileDir = gDefaultProfileParent.clone();
+ defaultProfileDir.append(
+ saltName(document.getElementById("profileName").value)
+ );
+ gProfileRoot = defaultProfileDir;
+ document.getElementById("useDefault").disabled = true;
+}
+
+function updateProfileDisplay() {
+ gProfileDisplay.data = gProfileRoot.path;
+}
+
+// Invoke a folder selection dialog for choosing the directory of profile storage.
+function chooseProfileFolder() {
+ var newProfileRoot;
+
+ var dirChooser = C["@mozilla.org/filepicker;1"].createInstance(
+ I.nsIFilePicker
+ );
+ dirChooser.init(
+ window,
+ gProfileManagerBundle.getString("chooseFolder"),
+ I.nsIFilePicker.modeGetFolder
+ );
+ dirChooser.appendFilters(I.nsIFilePicker.filterAll);
+
+ // default to the Profiles folder
+ dirChooser.displayDirectory = gDefaultProfileParent;
+
+ dirChooser.open(() => {
+ newProfileRoot = dirChooser.file;
+
+ // Disable the "Default Folder..." button when the default profile folder
+ // was selected manually in the File Picker.
+ document.getElementById("useDefault").disabled =
+ newProfileRoot.parent.equals(gDefaultProfileParent);
+
+ gProfileRoot = newProfileRoot;
+ updateProfileDisplay();
+ });
+}
+
+// Checks the current user input for validity and triggers an error message accordingly.
+function checkCurrentInput(currentInput) {
+ let wizard = document.querySelector("wizard");
+ var finishButton = wizard.getButton("finish");
+ var finishText = document.getElementById("finishText");
+ var canAdvance;
+
+ var errorMessage = checkProfileName(currentInput);
+
+ if (!errorMessage) {
+ finishText.className = "";
+ if (AppConstants.platform == "macosx") {
+ finishText.firstChild.data = gProfileManagerBundle.getString(
+ "profileFinishTextMac"
+ );
+ } else {
+ finishText.firstChild.data =
+ gProfileManagerBundle.getString("profileFinishText");
+ }
+ canAdvance = true;
+ } else {
+ finishText.className = "error";
+ finishText.firstChild.data = errorMessage;
+ canAdvance = false;
+ }
+
+ wizard.canAdvance = canAdvance;
+ finishButton.disabled = !canAdvance;
+
+ updateProfileDisplay();
+
+ return canAdvance;
+}
+
+function updateProfileName(aNewName) {
+ if (checkCurrentInput(aNewName)) {
+ gProfileRoot.leafName = saltName(aNewName);
+ updateProfileDisplay();
+ }
+}
+
+// Checks whether the given string is a valid profile name.
+// Returns an error message describing the error in the name or "" when it's valid.
+function checkProfileName(profileNameToCheck) {
+ // Check for emtpy profile name.
+ if (!/\S/.test(profileNameToCheck)) {
+ return gProfileManagerBundle.getString("profileNameEmpty");
+ }
+
+ // Check whether all characters in the profile name are allowed.
+ if (/([\\*:?<>|\/\"])/.test(profileNameToCheck)) {
+ return gProfileManagerBundle.getFormattedString("invalidChar", [RegExp.$1]);
+ }
+
+ // Check whether a profile with the same name already exists.
+ if (profileExists(profileNameToCheck)) {
+ return gProfileManagerBundle.getString("profileExists");
+ }
+
+ // profileNameToCheck is valid.
+ return "";
+}
+
+function profileExists(aName) {
+ for (let profile of gProfileService.profiles) {
+ if (profile.name.toLowerCase() == aName.toLowerCase()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Called when the first wizard page is shown.
+function enableNextButton() {
+ document.querySelector("wizard").canAdvance = true;
+}
+
+function onFinish(event) {
+ var profileName = document.getElementById("profileName").value;
+ var profile;
+
+ // Create profile named profileName in profileRoot.
+ try {
+ profile = gProfileService.createProfile(gProfileRoot, profileName);
+ } catch (e) {
+ var profileCreationFailed = gProfileManagerBundle.getString(
+ "profileCreationFailed"
+ );
+ var profileCreationFailedTitle = gProfileManagerBundle.getString(
+ "profileCreationFailedTitle"
+ );
+ Services.prompt.alert(
+ window,
+ profileCreationFailedTitle,
+ profileCreationFailed + "\n" + e
+ );
+
+ event.preventDefault();
+ return;
+ }
+
+ if (window.arguments && window.arguments[1]) {
+ // Add new profile to the list in the Profile Manager.
+ window.arguments[1].CreateProfile(profile);
+ } else {
+ // Use the newly created Profile.
+ var profileLock = profile.lock(null);
+
+ var dialogParams = window.arguments[0].QueryInterface(
+ I.nsIDialogParamBlock
+ );
+ dialogParams.objects.insertElementAt(profileLock, 0);
+ }
+}
diff --git a/toolkit/profile/content/createProfileWizard.xhtml b/toolkit/profile/content/createProfileWizard.xhtml
new file mode 100644
index 0000000000..34db95db1e
--- /dev/null
+++ b/toolkit/profile/content/createProfileWizard.xhtml
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+
+<!DOCTYPE wizard>
+
+<window
+ id="createProfileWizard"
+ data-l10n-id="create-profile-window2"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="initWizard();"
+ data-l10n-attrs="style"
+>
+ <linkset>
+ <html:link rel="localization" href="branding/brand.ftl" />
+ <html:link
+ rel="localization"
+ href="toolkit/global/createProfileWizard.ftl"
+ />
+ </linkset>
+
+ <script src="chrome://global/content/customElements.js" />
+ <script src="chrome://global/content/globalOverlay.js" />
+ <script src="chrome://global/content/editMenuOverlay.js" />
+ <script src="chrome://mozapps/content/profile/createProfileWizard.js" />
+
+ <wizard>
+ <stringbundle
+ id="bundle_profileManager"
+ src="chrome://mozapps/locale/profile/profileSelection.properties"
+ />
+
+ <wizardpage
+ id="explanation"
+ data-header-label-id="create-profile-first-page-header2"
+ >
+ <description data-l10n-id="profile-creation-explanation-1"></description>
+ <description data-l10n-id="profile-creation-explanation-2"></description>
+ <description data-l10n-id="profile-creation-explanation-3"></description>
+ <spacer flex="1" />
+ <description data-l10n-id="profile-creation-explanation-4"></description>
+ </wizardpage>
+
+ <wizardpage
+ id="createProfile"
+ data-header-label-id="create-profile-last-page-header2"
+ >
+ <description data-l10n-id="profile-creation-intro"></description>
+
+ <label data-l10n-id="profile-prompt" control="ProfileName"></label>
+ <html:input
+ id="profileName"
+ data-l10n-id="profile-default-name"
+ data-l10n-attrs="value"
+ oninput="updateProfileName(this.value);"
+ />
+
+ <separator />
+
+ <description data-l10n-id="profile-directory-explanation"></description>
+
+ <vbox class="indent" flex="1" style="overflow: auto">
+ <description id="profileDisplay">*</description>
+ </vbox>
+
+ <hbox>
+ <button
+ data-l10n-id="create-profile-choose-folder"
+ oncommand="chooseProfileFolder();"
+ />
+
+ <button
+ id="useDefault"
+ data-l10n-id="create-profile-use-default"
+ oncommand="setDisplayToDefaultFolder(); updateProfileDisplay();"
+ disabled="true"
+ />
+ </hbox>
+
+ <separator />
+
+ <description id="finishText">*</description>
+ </wizardpage>
+ </wizard>
+</window>
diff --git a/toolkit/profile/content/profileDowngrade.js b/toolkit/profile/content/profileDowngrade.js
new file mode 100644
index 0000000000..ba1f723ec2
--- /dev/null
+++ b/toolkit/profile/content/profileDowngrade.js
@@ -0,0 +1,39 @@
+/* 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/. */
+
+let gParams;
+
+const { AppConstants } = ChromeUtils.importESModule(
+ "resource://gre/modules/AppConstants.sys.mjs"
+);
+
+function init() {
+ /*
+ * The C++ code passes a dialog param block using its integers as in and out
+ * arguments for this UI. The following are the uses of the integers:
+ *
+ * 0: A set of flags from nsIToolkitProfileService.downgradeUIFlags.
+ * 1: A return argument, one of nsIToolkitProfileService.downgradeUIChoice.
+ */
+ gParams = window.arguments[0].QueryInterface(Ci.nsIDialogParamBlock);
+ if (AppConstants.MOZ_SERVICES_SYNC) {
+ let hasSync = gParams.GetInt(0) & Ci.nsIToolkitProfileService.hasSync;
+
+ document.getElementById("sync").hidden = !hasSync;
+ document.getElementById("nosync").hidden = hasSync;
+ }
+
+ document.addEventListener("dialogextra1", createProfile);
+ document.addEventListener("dialogaccept", quit);
+ document.addEventListener("dialogcancel", quit);
+}
+
+function quit() {
+ gParams.SetInt(1, Ci.nsIToolkitProfileService.quit);
+}
+
+function createProfile() {
+ gParams.SetInt(1, Ci.nsIToolkitProfileService.createNewProfile);
+ window.close();
+}
diff --git a/toolkit/profile/content/profileDowngrade.xhtml b/toolkit/profile/content/profileDowngrade.xhtml
new file mode 100644
index 0000000000..3e1c22f832
--- /dev/null
+++ b/toolkit/profile/content/profileDowngrade.xhtml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mozapps/skin/profileDowngrade.css" type="text/css"?>
+
+<!DOCTYPE window>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ prefwidth="min-width"
+ data-l10n-id="profiledowngrade-window2"
+ data-l10n-attrs="title,style"
+ onload="init()">
+<linkset>
+ <html:link rel="localization" href="branding/brand.ftl"/>
+ <html:link rel="localization" href="toolkit/branding/accounts.ftl"/>
+ <html:link rel="localization" href="toolkit/global/profileDowngrade.ftl"/>
+</linkset>
+<dialog buttons="accept,extra1" buttonpack="end"
+ buttonidextra1="profiledowngrade-window-create"
+ buttonidaccept="profiledowngrade-quit">
+
+ <script src="profileDowngrade.js"/>
+ <script src="chrome://global/content/customElements.js"/>
+
+ <hbox flex="1" align="start">
+ <image id="info" role="presentation"/>
+ <vbox flex="1">
+ <description data-l10n-id="profiledowngrade-nosync"></description>
+#ifdef MOZ_SERVICES_SYNC
+ <description data-l10n-id="profiledowngrade-sync"></description>
+#endif
+ </vbox>
+ </hbox>
+
+</dialog>
+</window>
diff --git a/toolkit/profile/content/profileSelection.js b/toolkit/profile/content/profileSelection.js
new file mode 100644
index 0000000000..b5bbfd5ab1
--- /dev/null
+++ b/toolkit/profile/content/profileSelection.js
@@ -0,0 +1,355 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { AppConstants } = ChromeUtils.importESModule(
+ "resource://gre/modules/AppConstants.sys.mjs"
+);
+
+const C = Cc;
+const I = Ci;
+
+const ToolkitProfileService = "@mozilla.org/toolkit/profile-service;1";
+
+const fluentStrings = new Localization([
+ "branding/brand.ftl",
+ "toolkit/global/profileSelection.ftl",
+]);
+
+var gDialogParams;
+var gProfileManagerBundle;
+var gBrandBundle;
+var gProfileService;
+var gNeedsFlush = false;
+
+function getFluentString(str) {
+ return fluentStrings.formatValue(str);
+}
+
+function startup() {
+ try {
+ gDialogParams = window.arguments[0].QueryInterface(I.nsIDialogParamBlock);
+
+ gProfileService = C[ToolkitProfileService].getService(
+ I.nsIToolkitProfileService
+ );
+
+ gProfileManagerBundle = document.getElementById("bundle_profileManager");
+ gBrandBundle = document.getElementById("bundle_brand");
+
+ document.getElementById("profileWindow").centerWindowOnScreen();
+
+ var profilesElement = document.getElementById("profiles");
+
+ for (let profile of gProfileService.profiles.entries(I.nsIToolkitProfile)) {
+ var listitem = profilesElement.appendItem(profile.name, "");
+
+ var tooltiptext = gProfileManagerBundle.getFormattedString(
+ "profileTooltip",
+ [profile.name, profile.rootDir.path]
+ );
+ listitem.setAttribute("tooltiptext", tooltiptext);
+ listitem.profile = profile;
+ try {
+ if (profile === gProfileService.defaultProfile) {
+ setTimeout(
+ function (a) {
+ profilesElement.ensureElementIsVisible(a);
+ profilesElement.selectItem(a);
+ },
+ 0,
+ listitem
+ );
+ }
+ } catch (e) {}
+ }
+
+ var autoSelectLastProfile = document.getElementById(
+ "autoSelectLastProfile"
+ );
+ autoSelectLastProfile.checked = gProfileService.startWithLastProfile;
+ profilesElement.focus();
+ } catch (e) {
+ window.close();
+ throw e;
+ }
+ document.addEventListener("dialogaccept", acceptDialog);
+ document.addEventListener("dialogcancel", exitDialog);
+}
+
+async function flush(cancelled) {
+ updateStartupPrefs();
+
+ gDialogParams.SetInt(
+ 1,
+ document.getElementById("offlineState").checked ? 1 : 0
+ );
+
+ if (gNeedsFlush) {
+ try {
+ gProfileService.flush();
+ } catch (e) {
+ let appName = gBrandBundle.getString("brandShortName");
+
+ let title = gProfileManagerBundle.getString("flushFailTitle");
+ let restartButton = gProfileManagerBundle.getFormattedString(
+ "flushFailRestartButton",
+ [appName]
+ );
+ let exitButton = gProfileManagerBundle.getString("flushFailExitButton");
+
+ let message;
+ if (e.result == undefined) {
+ message = await getFluentString("profile-selection-conflict-message");
+ } else {
+ message = gProfileManagerBundle.getString("flushFailMessage");
+ }
+
+ const PS = Ci.nsIPromptService;
+ let result = Services.prompt.confirmEx(
+ window,
+ title,
+ message,
+ PS.BUTTON_POS_0 * PS.BUTTON_TITLE_IS_STRING +
+ PS.BUTTON_POS_1 * PS.BUTTON_TITLE_IS_STRING,
+ restartButton,
+ exitButton,
+ null,
+ null,
+ {}
+ );
+
+ gDialogParams.SetInt(
+ 0,
+ result == 0
+ ? Ci.nsIToolkitProfileService.restart
+ : Ci.nsIToolkitProfileService.exit
+ );
+ return;
+ }
+ gNeedsFlush = false;
+ }
+
+ gDialogParams.SetInt(
+ 0,
+ cancelled
+ ? Ci.nsIToolkitProfileService.exit
+ : Ci.nsIToolkitProfileService.launchWithProfile
+ );
+}
+
+function acceptDialog(event) {
+ var appName = gBrandBundle.getString("brandShortName");
+
+ var profilesElement = document.getElementById("profiles");
+ var selectedProfile = profilesElement.selectedItem;
+ if (!selectedProfile) {
+ var pleaseSelectTitle =
+ gProfileManagerBundle.getString("pleaseSelectTitle");
+ var pleaseSelect = gProfileManagerBundle.getFormattedString(
+ "pleaseSelect",
+ [appName]
+ );
+ Services.prompt.alert(window, pleaseSelectTitle, pleaseSelect);
+ event.preventDefault();
+ return;
+ }
+
+ gDialogParams.objects.insertElementAt(selectedProfile.profile.rootDir, 0);
+ gDialogParams.objects.insertElementAt(selectedProfile.profile.localDir, 1);
+
+ if (gProfileService.defaultProfile != selectedProfile.profile) {
+ try {
+ gProfileService.defaultProfile = selectedProfile.profile;
+ gNeedsFlush = true;
+ } catch (e) {
+ // This can happen on dev-edition. We'll still restart with the selected
+ // profile based on the lock's directories.
+ }
+ }
+ flush(false);
+}
+
+function exitDialog() {
+ flush(true);
+}
+
+function updateStartupPrefs() {
+ var autoSelectLastProfile = document.getElementById("autoSelectLastProfile");
+ if (gProfileService.startWithLastProfile != autoSelectLastProfile.checked) {
+ gProfileService.startWithLastProfile = autoSelectLastProfile.checked;
+ gNeedsFlush = true;
+ }
+}
+
+// handle key event on listboxes
+function onProfilesKey(aEvent) {
+ switch (aEvent.keyCode) {
+ case KeyEvent.DOM_VK_BACK_SPACE:
+ if (AppConstants.platform != "macosx") {
+ break;
+ }
+ // fall through
+ case KeyEvent.DOM_VK_DELETE:
+ ConfirmDelete();
+ break;
+ case KeyEvent.DOM_VK_F2:
+ RenameProfile();
+ break;
+ }
+}
+
+function onProfilesDblClick(aEvent) {
+ if (aEvent.target.closest("richlistitem")) {
+ document.getElementById("profileWindow").acceptDialog();
+ }
+}
+
+// invoke the createProfile Wizard
+function CreateProfileWizard() {
+ window.openDialog(
+ "chrome://mozapps/content/profile/createProfileWizard.xhtml",
+ "",
+ "centerscreen,chrome,modal,titlebar",
+ gProfileService,
+ { CreateProfile }
+ );
+}
+
+/**
+ * Called from createProfileWizard to update the display.
+ */
+function CreateProfile(aProfile) {
+ var profilesElement = document.getElementById("profiles");
+
+ var listitem = profilesElement.appendItem(aProfile.name, "");
+
+ var tooltiptext = gProfileManagerBundle.getFormattedString("profileTooltip", [
+ aProfile.name,
+ aProfile.rootDir.path,
+ ]);
+ listitem.setAttribute("tooltiptext", tooltiptext);
+ listitem.profile = aProfile;
+
+ profilesElement.ensureElementIsVisible(listitem);
+ profilesElement.selectItem(listitem);
+
+ gNeedsFlush = true;
+}
+
+// rename the selected profile
+function RenameProfile() {
+ var profilesElement = document.getElementById("profiles");
+ var selectedItem = profilesElement.selectedItem;
+ if (!selectedItem) {
+ return false;
+ }
+
+ var selectedProfile = selectedItem.profile;
+
+ var oldName = selectedProfile.name;
+ var newName = { value: oldName };
+
+ var dialogTitle = gProfileManagerBundle.getString("renameProfileTitle");
+ var msg = gProfileManagerBundle.getFormattedString("renameProfilePrompt", [
+ oldName,
+ ]);
+
+ if (
+ Services.prompt.prompt(window, dialogTitle, msg, newName, null, {
+ value: 0,
+ })
+ ) {
+ newName = newName.value;
+
+ // User hasn't changed the profile name. Treat as if cancel was pressed.
+ if (newName == oldName) {
+ return false;
+ }
+
+ try {
+ selectedProfile.name = newName;
+ gNeedsFlush = true;
+ } catch (e) {
+ var alTitle = gProfileManagerBundle.getString("profileNameInvalidTitle");
+ var alMsg = gProfileManagerBundle.getFormattedString(
+ "profileNameInvalid",
+ [newName]
+ );
+ Services.prompt.alert(window, alTitle, alMsg);
+ return false;
+ }
+
+ selectedItem.firstChild.setAttribute("value", newName);
+ var tiptext = gProfileManagerBundle.getFormattedString("profileTooltip", [
+ newName,
+ selectedProfile.rootDir.path,
+ ]);
+ selectedItem.setAttribute("tooltiptext", tiptext);
+
+ return true;
+ }
+
+ return false;
+}
+
+function ConfirmDelete() {
+ var profileList = document.getElementById("profiles");
+
+ var selectedItem = profileList.selectedItem;
+ if (!selectedItem) {
+ return false;
+ }
+
+ var selectedProfile = selectedItem.profile;
+ var deleteFiles = false;
+
+ if (selectedProfile.rootDir.exists()) {
+ var dialogTitle = gProfileManagerBundle.getString("deleteTitle");
+ var dialogText = gProfileManagerBundle.getFormattedString(
+ "deleteProfileConfirm",
+ [selectedProfile.rootDir.path]
+ );
+
+ var buttonPressed = Services.prompt.confirmEx(
+ window,
+ dialogTitle,
+ dialogText,
+ 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,
+ gProfileManagerBundle.getString("dontDeleteFiles"),
+ null,
+ gProfileManagerBundle.getString("deleteFiles"),
+ null,
+ { value: 0 }
+ );
+ if (buttonPressed == 1) {
+ return false;
+ }
+
+ if (buttonPressed == 2) {
+ deleteFiles = true;
+ }
+ }
+
+ try {
+ selectedProfile.remove(deleteFiles);
+ gNeedsFlush = true;
+ } catch (e) {
+ let title = gProfileManagerBundle.getString("profileDeletionFailedTitle");
+ let msg = gProfileManagerBundle.getString("profileDeletionFailed");
+ Services.prompt.alert(window, title, msg);
+
+ return true;
+ }
+
+ profileList.removeChild(selectedItem);
+ if (profileList.firstChild != undefined) {
+ profileList.selectItem(profileList.firstChild);
+ }
+
+ return true;
+}
diff --git a/toolkit/profile/content/profileSelection.xhtml b/toolkit/profile/content/profileSelection.xhtml
new file mode 100644
index 0000000000..0351295b22
--- /dev/null
+++ b/toolkit/profile/content/profileSelection.xhtml
@@ -0,0 +1,101 @@
+<?xml version="1.0"?>
+<!-- -*- Mode: SGML; indent-tabs-mode: nil; -*- -->
+<!--
+
+ 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/. -->
+
+<?xml-stylesheet href="chrome://mozapps/skin/profileSelection.css" type="text/css"?>
+
+<!DOCTYPE window>
+
+<window
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ class="non-resizable"
+ data-l10n-id="profile-selection-window"
+ orient="vertical"
+ prefwidth="min-width"
+ style="min-width: 30em"
+ onload="startup();"
+>
+ <dialog
+ id="profileWindow"
+ buttons="accept,cancel"
+ buttonidaccept="profile-selection-button-accept"
+ buttonidcancel="profile-selection-button-cancel"
+ >
+ <linkset>
+ <html:link rel="localization" href="branding/brand.ftl" />
+ <html:link
+ rel="localization"
+ href="toolkit/global/profileSelection.ftl"
+ />
+ </linkset>
+
+ <script src="chrome://global/content/customElements.js" />
+
+ <stringbundle
+ id="bundle_profileManager"
+ src="chrome://mozapps/locale/profile/profileSelection.properties"
+ />
+ <stringbundle
+ id="bundle_brand"
+ src="chrome://branding/locale/brand.properties"
+ />
+
+ <script src="chrome://mozapps/content/profile/profileSelection.js" />
+
+ <description
+ class="label"
+ data-l10n-id="profile-manager-description"
+ ></description>
+
+ <separator class="thin" />
+
+ <hbox class="indent">
+ <vbox id="managebuttons">
+ <button
+ id="newbutton"
+ data-l10n-id="profile-selection-new-button"
+ oncommand="CreateProfileWizard();"
+ />
+ <button
+ id="renbutton"
+ data-l10n-id="profile-selection-rename-button"
+ oncommand="RenameProfile();"
+ />
+ <button
+ id="delbutton"
+ data-l10n-id="profile-selection-delete-button"
+ oncommand="ConfirmDelete();"
+ />
+ </vbox>
+
+ <vbox id="profilesContainer">
+ <richlistbox
+ id="profiles"
+ class="theme-listbox"
+ seltype="single"
+ ondblclick="onProfilesDblClick(event)"
+ onkeypress="onProfilesKey(event);"
+ >
+ </richlistbox>
+
+ <!-- Bug 257777 -->
+ <checkbox
+ id="offlineState"
+ data-l10n-id="profile-manager-work-offline"
+ native="true"
+ />
+
+ <checkbox
+ id="autoSelectLastProfile"
+ data-l10n-id="profile-manager-use-selected"
+ native="true"
+ />
+ </vbox>
+ </hbox>
+ </dialog>
+</window>