forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			397 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			397 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* 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 }
 | 
						|
);
 |