mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-13 02:37:32 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
|
|
@ -0,0 +1,344 @@
|
|||
/* 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/. */
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ContextualIdentityService"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const DEFAULT_TAB_COLOR = "#909090";
|
||||
const SAVE_DELAY_MS = 1500;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
|
||||
return Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () {
|
||||
return new TextDecoder();
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gTextEncoder", function () {
|
||||
return new TextEncoder();
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
|
||||
"resource://gre/modules/AsyncShutdown.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
|
||||
"resource://gre/modules/DeferredTask.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
function _ContextualIdentityService(path) {
|
||||
this.init(path);
|
||||
}
|
||||
|
||||
_ContextualIdentityService.prototype = {
|
||||
_defaultIdentities: [
|
||||
{ userContextId: 1,
|
||||
public: true,
|
||||
icon: "fingerprint",
|
||||
color: "blue",
|
||||
l10nID: "userContextPersonal.label",
|
||||
accessKey: "userContextPersonal.accesskey",
|
||||
telemetryId: 1,
|
||||
},
|
||||
{ userContextId: 2,
|
||||
public: true,
|
||||
icon: "briefcase",
|
||||
color: "orange",
|
||||
l10nID: "userContextWork.label",
|
||||
accessKey: "userContextWork.accesskey",
|
||||
telemetryId: 2,
|
||||
},
|
||||
{ userContextId: 3,
|
||||
public: true,
|
||||
icon: "dollar",
|
||||
color: "green",
|
||||
l10nID: "userContextBanking.label",
|
||||
accessKey: "userContextBanking.accesskey",
|
||||
telemetryId: 3,
|
||||
},
|
||||
{ userContextId: 4,
|
||||
public: true,
|
||||
icon: "cart",
|
||||
color: "pink",
|
||||
l10nID: "userContextShopping.label",
|
||||
accessKey: "userContextShopping.accesskey",
|
||||
telemetryId: 4,
|
||||
},
|
||||
{ userContextId: 5,
|
||||
public: false,
|
||||
icon: "",
|
||||
color: "",
|
||||
name: "userContextIdInternal.thumbnail",
|
||||
accessKey: "" },
|
||||
],
|
||||
|
||||
_identities: null,
|
||||
_openedIdentities: new Set(),
|
||||
_lastUserContextId: 0,
|
||||
|
||||
_path: null,
|
||||
_dataReady: false,
|
||||
|
||||
_saver: null,
|
||||
|
||||
init(path) {
|
||||
this._path = path;
|
||||
this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS);
|
||||
AsyncShutdown.profileBeforeChange.addBlocker("ContextualIdentityService: writing data",
|
||||
() => this._saver.finalize());
|
||||
|
||||
this.load();
|
||||
},
|
||||
|
||||
load() {
|
||||
OS.File.read(this._path).then(bytes => {
|
||||
// If synchronous loading happened in the meantime, exit now.
|
||||
if (this._dataReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let data = JSON.parse(gTextDecoder.decode(bytes));
|
||||
if (data.version == 1) {
|
||||
this.resetDefault();
|
||||
}
|
||||
if (data.version != 2) {
|
||||
dump("ERROR - ContextualIdentityService - Unknown version found in " + this._path + "\n");
|
||||
this.loadError(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this._identities = data.identities;
|
||||
this._lastUserContextId = data.lastUserContextId;
|
||||
|
||||
this._dataReady = true;
|
||||
} catch (error) {
|
||||
this.loadError(error);
|
||||
}
|
||||
}, (error) => {
|
||||
this.loadError(error);
|
||||
});
|
||||
},
|
||||
|
||||
resetDefault() {
|
||||
this._identities = this._defaultIdentities;
|
||||
this._lastUserContextId = this._defaultIdentities.length;
|
||||
|
||||
this._dataReady = true;
|
||||
|
||||
this.saveSoon();
|
||||
},
|
||||
|
||||
loadError(error) {
|
||||
if (error != null &&
|
||||
!(error instanceof OS.File.Error && error.becauseNoSuchFile) &&
|
||||
!(error instanceof Components.Exception &&
|
||||
error.result == Cr.NS_ERROR_FILE_NOT_FOUND)) {
|
||||
// Let's report the error.
|
||||
Cu.reportError(error);
|
||||
}
|
||||
|
||||
// If synchronous loading happened in the meantime, exit now.
|
||||
if (this._dataReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.resetDefault();
|
||||
},
|
||||
|
||||
saveSoon() {
|
||||
this._saver.arm();
|
||||
},
|
||||
|
||||
save() {
|
||||
let object = {
|
||||
version: 2,
|
||||
lastUserContextId: this._lastUserContextId,
|
||||
identities: this._identities
|
||||
};
|
||||
|
||||
let bytes = gTextEncoder.encode(JSON.stringify(object));
|
||||
return OS.File.writeAtomic(this._path, bytes,
|
||||
{ tmpPath: this._path + ".tmp" });
|
||||
},
|
||||
|
||||
create(name, icon, color) {
|
||||
let identity = {
|
||||
userContextId: ++this._lastUserContextId,
|
||||
public: true,
|
||||
icon,
|
||||
color,
|
||||
name
|
||||
};
|
||||
|
||||
this._identities.push(identity);
|
||||
this.saveSoon();
|
||||
|
||||
return Cu.cloneInto(identity, {});
|
||||
},
|
||||
|
||||
update(userContextId, name, icon, color) {
|
||||
let identity = this._identities.find(identity => identity.userContextId == userContextId &&
|
||||
identity.public);
|
||||
if (identity && name) {
|
||||
identity.name = name;
|
||||
identity.color = color;
|
||||
identity.icon = icon;
|
||||
delete identity.l10nID;
|
||||
delete identity.accessKey;
|
||||
this.saveSoon();
|
||||
}
|
||||
|
||||
return !!identity;
|
||||
},
|
||||
|
||||
remove(userContextId) {
|
||||
let index = this._identities.findIndex(i => i.userContextId == userContextId && i.public);
|
||||
if (index == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(null, "clear-origin-attributes-data",
|
||||
JSON.stringify({ userContextId }));
|
||||
|
||||
this._identities.splice(index, 1);
|
||||
this._openedIdentities.delete(userContextId);
|
||||
this.saveSoon();
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
ensureDataReady() {
|
||||
if (this._dataReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// This reads the file and automatically detects the UTF-8 encoding.
|
||||
let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
inputStream.init(new FileUtils.File(this._path),
|
||||
FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
|
||||
try {
|
||||
let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
|
||||
let data = json.decodeFromStream(inputStream,
|
||||
inputStream.available());
|
||||
this._identities = data.identities;
|
||||
this._lastUserContextId = data.lastUserContextId;
|
||||
|
||||
this._dataReady = true;
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (error) {
|
||||
this.loadError(error);
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
getIdentities() {
|
||||
this.ensureDataReady();
|
||||
return Cu.cloneInto(this._identities.filter(info => info.public), {});
|
||||
},
|
||||
|
||||
getPrivateIdentity(name) {
|
||||
this.ensureDataReady();
|
||||
return Cu.cloneInto(this._identities.find(info => !info.public && info.name == name), {});
|
||||
},
|
||||
|
||||
getIdentityFromId(userContextId) {
|
||||
this.ensureDataReady();
|
||||
return Cu.cloneInto(this._identities.find(info => info.userContextId == userContextId &&
|
||||
info.public), {});
|
||||
},
|
||||
|
||||
getUserContextLabel(userContextId) {
|
||||
let identity = this.getIdentityFromId(userContextId);
|
||||
if (!identity || !identity.public) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// We cannot localize the user-created identity names.
|
||||
if (identity.name) {
|
||||
return identity.name;
|
||||
}
|
||||
|
||||
return gBrowserBundle.GetStringFromName(identity.l10nID);
|
||||
},
|
||||
|
||||
setTabStyle(tab) {
|
||||
if (!tab.hasAttribute("usercontextid")) {
|
||||
return;
|
||||
}
|
||||
|
||||
let userContextId = tab.getAttribute("usercontextid");
|
||||
let identity = this.getIdentityFromId(userContextId);
|
||||
tab.setAttribute("data-identity-color", identity ? identity.color : "");
|
||||
},
|
||||
|
||||
countContainerTabs() {
|
||||
let count = 0;
|
||||
this._forEachContainerTab(function() { ++count; });
|
||||
return count;
|
||||
},
|
||||
|
||||
closeAllContainerTabs() {
|
||||
this._forEachContainerTab(function(tab, tabbrowser) {
|
||||
tabbrowser.removeTab(tab);
|
||||
});
|
||||
},
|
||||
|
||||
_forEachContainerTab(callback) {
|
||||
let windowList = Services.wm.getEnumerator("navigator:browser");
|
||||
while (windowList.hasMoreElements()) {
|
||||
let win = windowList.getNext();
|
||||
|
||||
if (win.closed || !win.gBrowser) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let tabbrowser = win.gBrowser;
|
||||
for (let i = tabbrowser.tabContainer.childNodes.length - 1; i >= 0; --i) {
|
||||
let tab = tabbrowser.tabContainer.childNodes[i];
|
||||
if (tab.hasAttribute("usercontextid")) {
|
||||
callback(tab, tabbrowser);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
telemetry(userContextId) {
|
||||
let identity = this.getIdentityFromId(userContextId);
|
||||
|
||||
// Let's ignore unknown identities for now.
|
||||
if (!identity || !identity.public) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._openedIdentities.has(userContextId)) {
|
||||
this._openedIdentities.add(userContextId);
|
||||
Services.telemetry.getHistogramById("UNIQUE_CONTAINERS_OPENED").add(1);
|
||||
}
|
||||
|
||||
Services.telemetry.getHistogramById("TOTAL_CONTAINERS_OPENED").add(1);
|
||||
|
||||
if (identity.telemetryId) {
|
||||
Services.telemetry.getHistogramById("CONTAINER_USED")
|
||||
.add(identity.telemetryId);
|
||||
}
|
||||
},
|
||||
|
||||
createNewInstanceForTesting(path) {
|
||||
return new _ContextualIdentityService(path);
|
||||
},
|
||||
};
|
||||
|
||||
let path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json");
|
||||
this.ContextualIdentityService = new _ContextualIdentityService(path);
|
||||
11
toolkit/components/contextualidentity/moz.build
Normal file
11
toolkit/components/contextualidentity/moz.build
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'ContextualIdentityService.jsm',
|
||||
]
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
"use strict";
|
||||
|
||||
do_get_profile();
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/ContextualIdentityService.jsm");
|
||||
|
||||
const TEST_STORE_FILE_NAME = "test-containers.json";
|
||||
|
||||
let cis;
|
||||
|
||||
// Basic tests
|
||||
add_task(function() {
|
||||
ok(!!ContextualIdentityService, "ContextualIdentityService exists");
|
||||
|
||||
cis = ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_NAME);
|
||||
ok(!!cis, "We have our instance of ContextualIdentityService");
|
||||
|
||||
equal(cis.getIdentities().length, 4, "By default, 4 containers.");
|
||||
equal(cis.getIdentityFromId(0), null, "No identity with id 0");
|
||||
|
||||
ok(!!cis.getIdentityFromId(1), "Identity 1 exists");
|
||||
ok(!!cis.getIdentityFromId(2), "Identity 2 exists");
|
||||
ok(!!cis.getIdentityFromId(3), "Identity 3 exists");
|
||||
ok(!!cis.getIdentityFromId(4), "Identity 4 exists");
|
||||
});
|
||||
|
||||
// Create a new identity
|
||||
add_task(function() {
|
||||
equal(cis.getIdentities().length, 4, "By default, 4 containers.");
|
||||
|
||||
let identity = cis.create("New Container", "Icon", "Color");
|
||||
ok(!!identity, "New container created");
|
||||
equal(identity.name, "New Container", "Name matches");
|
||||
equal(identity.icon, "Icon", "Icon matches");
|
||||
equal(identity.color, "Color", "Color matches");
|
||||
|
||||
equal(cis.getIdentities().length, 5, "Expected 5 containers.");
|
||||
|
||||
ok(!!cis.getIdentityFromId(identity.userContextId), "Identity exists");
|
||||
equal(cis.getIdentityFromId(identity.userContextId).name, "New Container", "Identity name is OK");
|
||||
equal(cis.getIdentityFromId(identity.userContextId).icon, "Icon", "Identity icon is OK");
|
||||
equal(cis.getIdentityFromId(identity.userContextId).color, "Color", "Identity color is OK");
|
||||
equal(cis.getUserContextLabel(identity.userContextId), "New Container", "Identity label is OK");
|
||||
|
||||
// Remove an identity
|
||||
equal(cis.remove(-1), false, "cis.remove() returns false if identity doesn't exist.");
|
||||
equal(cis.remove(1), true, "cis.remove() returns true if identity exists.");
|
||||
|
||||
equal(cis.getIdentities().length, 4, "Expected 4 containers.");
|
||||
});
|
||||
|
||||
// Update an identity
|
||||
add_task(function() {
|
||||
ok(!!cis.getIdentityFromId(2), "Identity 2 exists");
|
||||
|
||||
equal(cis.update(-1, "Container", "Icon", "Color"), false, "Update returns false if the identity doesn't exist");
|
||||
|
||||
equal(cis.update(2, "Container", "Icon", "Color"), true, "Update returns true if everything is OK");
|
||||
|
||||
ok(!!cis.getIdentityFromId(2), "Identity exists");
|
||||
equal(cis.getIdentityFromId(2).name, "Container", "Identity name is OK");
|
||||
equal(cis.getIdentityFromId(2).icon, "Icon", "Identity icon is OK");
|
||||
equal(cis.getIdentityFromId(2).color, "Color", "Identity color is OK");
|
||||
equal(cis.getUserContextLabel(2), "Container", "Identity label is OK");
|
||||
});
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[DEFAULT]
|
||||
|
||||
[test_basic.js]
|
||||
Loading…
Add table
Add a link
Reference in a new issue