зеркало из https://github.com/mozilla/gecko-dev.git
207 строки
5.6 KiB
JavaScript
207 строки
5.6 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 Services = require("Services");
|
|
const EventEmitter = require("devtools/shared/event-emitter");
|
|
|
|
/**
|
|
* Shortcuts for lazily accessing and setting various preferences.
|
|
* Usage:
|
|
* let prefs = new Prefs("root.path.to.branch", {
|
|
* myIntPref: ["Int", "leaf.path.to.my-int-pref"],
|
|
* myCharPref: ["Char", "leaf.path.to.my-char-pref"],
|
|
* myJsonPref: ["Json", "leaf.path.to.my-json-pref"],
|
|
* myFloatPref: ["Float", "leaf.path.to.my-float-pref"]
|
|
* ...
|
|
* });
|
|
*
|
|
* Get/set:
|
|
* prefs.myCharPref = "foo";
|
|
* let aux = prefs.myCharPref;
|
|
*
|
|
* Observe:
|
|
* prefs.registerObserver();
|
|
* prefs.on("pref-changed", (prefName, prefValue) => {
|
|
* ...
|
|
* });
|
|
*
|
|
* @param string prefsRoot
|
|
* The root path to the required preferences branch.
|
|
* @param object prefsBlueprint
|
|
* An object containing { accessorName: [prefType, prefName] } keys.
|
|
*/
|
|
function PrefsHelper(prefsRoot = "", prefsBlueprint = {}) {
|
|
EventEmitter.decorate(this);
|
|
|
|
let cache = new Map();
|
|
|
|
for (let accessorName in prefsBlueprint) {
|
|
let [prefType, prefName] = prefsBlueprint[accessorName];
|
|
map(this, cache, accessorName, prefType, prefsRoot, prefName);
|
|
}
|
|
|
|
let observer = makeObserver(this, cache, prefsRoot, prefsBlueprint);
|
|
this.registerObserver = () => observer.register();
|
|
this.unregisterObserver = () => observer.unregister();
|
|
}
|
|
|
|
/**
|
|
* Helper method for getting a pref value.
|
|
*
|
|
* @param Map cache
|
|
* @param string prefType
|
|
* @param string prefsRoot
|
|
* @param string prefName
|
|
* @return any
|
|
*/
|
|
function get(cache, prefType, prefsRoot, prefName) {
|
|
let cachedPref = cache.get(prefName);
|
|
if (cachedPref !== undefined) {
|
|
return cachedPref;
|
|
}
|
|
let value = Services.prefs["get" + prefType + "Pref"](
|
|
[prefsRoot, prefName].join(".")
|
|
);
|
|
cache.set(prefName, value);
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Helper method for setting a pref value.
|
|
*
|
|
* @param Map cache
|
|
* @param string prefType
|
|
* @param string prefsRoot
|
|
* @param string prefName
|
|
* @param any value
|
|
*/
|
|
function set(cache, prefType, prefsRoot, prefName, value) {
|
|
Services.prefs["set" + prefType + "Pref"](
|
|
[prefsRoot, prefName].join("."),
|
|
value
|
|
);
|
|
cache.set(prefName, value);
|
|
}
|
|
|
|
/**
|
|
* Maps a property name to a pref, defining lazy getters and setters.
|
|
* Supported types are "Bool", "Char", "Int", "Float" (sugar around "Char"
|
|
* type and casting), and "Json" (which is basically just sugar for "Char"
|
|
* using the standard JSON serializer).
|
|
*
|
|
* @param PrefsHelper self
|
|
* @param Map cache
|
|
* @param string accessorName
|
|
* @param string prefType
|
|
* @param string prefsRoot
|
|
* @param string prefName
|
|
* @param array serializer [optional]
|
|
*/
|
|
function map(self, cache, accessorName, prefType, prefsRoot, prefName,
|
|
serializer = { in: e => e, out: e => e }) {
|
|
if (prefName in self) {
|
|
throw new Error(`Can't use ${prefName} because it overrides a property` +
|
|
"on the instance.");
|
|
}
|
|
if (prefType == "Json") {
|
|
map(self, cache, accessorName, "Char", prefsRoot, prefName, {
|
|
in: JSON.parse,
|
|
out: JSON.stringify
|
|
});
|
|
return;
|
|
}
|
|
if (prefType == "Float") {
|
|
map(self, cache, accessorName, "Char", prefsRoot, prefName, {
|
|
in: Number.parseFloat,
|
|
out: (n) => n + ""
|
|
});
|
|
return;
|
|
}
|
|
|
|
Object.defineProperty(self, accessorName, {
|
|
get: () => serializer.in(get(cache, prefType, prefsRoot, prefName)),
|
|
set: (e) => set(cache, prefType, prefsRoot, prefName, serializer.out(e))
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Finds the accessor for the provided pref, based on the blueprint object
|
|
* used in the constructor.
|
|
*
|
|
* @param PrefsHelper self
|
|
* @param object prefsBlueprint
|
|
* @return string
|
|
*/
|
|
function accessorNameForPref(somePrefName, prefsBlueprint) {
|
|
for (let accessorName in prefsBlueprint) {
|
|
let [, prefName] = prefsBlueprint[accessorName];
|
|
if (somePrefName == prefName) {
|
|
return accessorName;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
/**
|
|
* Creates a pref observer for `self`.
|
|
*
|
|
* @param PrefsHelper self
|
|
* @param Map cache
|
|
* @param string prefsRoot
|
|
* @param object prefsBlueprint
|
|
* @return object
|
|
*/
|
|
function makeObserver(self, cache, prefsRoot, prefsBlueprint) {
|
|
return {
|
|
register: function () {
|
|
this._branch = Services.prefs.getBranch(prefsRoot + ".");
|
|
this._branch.addObserver("", this, false);
|
|
},
|
|
unregister: function () {
|
|
this._branch.removeObserver("", this);
|
|
},
|
|
observe: function (subject, topic, prefName) {
|
|
// If this particular pref isn't handled by the blueprint object,
|
|
// even though it's in the specified branch, ignore it.
|
|
let accessorName = accessorNameForPref(prefName, prefsBlueprint);
|
|
if (!(accessorName in self)) {
|
|
return;
|
|
}
|
|
cache.delete(prefName);
|
|
self.emit("pref-changed", accessorName, self[accessorName]);
|
|
}
|
|
};
|
|
}
|
|
|
|
exports.PrefsHelper = PrefsHelper;
|
|
|
|
/**
|
|
* A PreferenceObserver observes a pref branch for pref changes.
|
|
* It emits an event for each preference change.
|
|
*/
|
|
function PrefObserver(branchName) {
|
|
this.branchName = branchName;
|
|
this.branch = Services.prefs.getBranch(branchName);
|
|
this.branch.addObserver("", this, false);
|
|
|
|
EventEmitter.decorate(this);
|
|
}
|
|
|
|
exports.PrefObserver = PrefObserver;
|
|
|
|
PrefObserver.prototype = {
|
|
observe: function (subject, topic, data) {
|
|
if (topic == "nsPref:changed") {
|
|
this.emit(this.branchName + data);
|
|
}
|
|
},
|
|
|
|
destroy: function () {
|
|
if (this.branch) {
|
|
this.branch.removeObserver("", this);
|
|
}
|
|
},
|
|
};
|