1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 const EventEmitter = require("resource://devtools/shared/event-emitter.js");
9 * Shortcuts for lazily accessing and setting various preferences.
11 * let prefs = new Prefs("root.path.to.branch", {
12 * myIntPref: ["Int", "leaf.path.to.my-int-pref"],
13 * myCharPref: ["Char", "leaf.path.to.my-char-pref"],
14 * myJsonPref: ["Json", "leaf.path.to.my-json-pref"],
15 * myFloatPref: ["Float", "leaf.path.to.my-float-pref"]
20 * prefs.myCharPref = "foo";
21 * let aux = prefs.myCharPref;
24 * prefs.registerObserver();
25 * prefs.on("pref-changed", (prefValue) => {
29 * @param string prefsRoot
30 * The root path to the required preferences branch.
31 * @param object prefsBlueprint
32 * An object containing { accessorName: [prefType, prefName] } keys.
34 function PrefsHelper(prefsRoot = "", prefsBlueprint = {}) {
35 EventEmitter.decorate(this);
37 const cache = new Map();
39 for (const accessorName in prefsBlueprint) {
40 const [prefType, prefName, fallbackValue] = prefsBlueprint[accessorName];
52 const observer = makeObserver(this, cache, prefsRoot, prefsBlueprint);
53 this.registerObserver = () => observer.register();
54 this.unregisterObserver = () => observer.unregister();
58 * Helper method for getting a pref value.
61 * @param string prefType
62 * @param string prefsRoot
63 * @param string prefName
64 * @param string|int|boolean fallbackValue
67 function get(cache, prefType, prefsRoot, prefName, fallbackValue) {
68 const cachedPref = cache.get(prefName);
69 if (cachedPref !== undefined) {
72 const value = Services.prefs["get" + prefType + "Pref"](
73 [prefsRoot, prefName].join("."),
76 cache.set(prefName, value);
81 * Helper method for setting a pref value.
84 * @param string prefType
85 * @param string prefsRoot
86 * @param string prefName
89 function set(cache, prefType, prefsRoot, prefName, value) {
90 Services.prefs["set" + prefType + "Pref"](
91 [prefsRoot, prefName].join("."),
94 cache.set(prefName, value);
98 * Maps a property name to a pref, defining lazy getters and setters.
99 * Supported types are "Bool", "Char", "Int", "Float" (sugar around "Char"
100 * type and casting), and "Json" (which is basically just sugar for "Char"
101 * using the standard JSON serializer).
103 * @param PrefsHelper self
105 * @param string accessorName
106 * @param string prefType
107 * @param string prefsRoot
108 * @param string prefName
109 * @param string|int|boolean fallbackValue
110 * @param array serializer [optional]
120 serializer = { in: e => e, out: e => e }
122 if (prefName in self) {
124 `Can't use ${prefName} because it overrides a property` +
128 if (prefType == "Json") {
144 if (prefType == "Float") {
145 map(self, cache, accessorName, "Char", prefsRoot, prefName, fallbackValue, {
146 in: Number.parseFloat,
152 Object.defineProperty(self, accessorName, {
154 serializer.in(get(cache, prefType, prefsRoot, prefName, fallbackValue)),
156 set(cache, prefType, prefsRoot, prefName, serializer.out(e));
162 * Finds the accessor for the provided pref, based on the blueprint object
163 * used in the constructor.
165 * @param PrefsHelper self
166 * @param object prefsBlueprint
169 function accessorNameForPref(somePrefName, prefsBlueprint) {
170 for (const accessorName in prefsBlueprint) {
171 const [, prefName] = prefsBlueprint[accessorName];
172 if (somePrefName == prefName) {
180 * Creates a pref observer for `self`.
182 * @param PrefsHelper self
184 * @param string prefsRoot
185 * @param object prefsBlueprint
188 function makeObserver(self, cache, prefsRoot, prefsBlueprint) {
191 this._branch = Services.prefs.getBranch(prefsRoot + ".");
192 this._branch.addObserver("", this);
195 this._branch.removeObserver("", this);
197 observe(subject, topic, prefName) {
198 // If this particular pref isn't handled by the blueprint object,
199 // even though it's in the specified branch, ignore it.
200 const accessorName = accessorNameForPref(prefName, prefsBlueprint);
201 if (!(accessorName in self)) {
204 cache.delete(prefName);
205 self.emit("pref-changed", accessorName, self[accessorName]);
210 exports.PrefsHelper = PrefsHelper;
213 * A PreferenceObserver observes a pref branch for pref changes.
214 * It emits an event for each preference change.
216 class PrefObserver extends EventEmitter {
217 constructor(branchName) {
220 this.#branchName = branchName;
221 this.#branch = Services.prefs.getBranch(branchName);
222 this.#branch.addObserver("", this);
228 observe(subject, topic, data) {
229 if (topic == "nsPref:changed") {
230 this.emit(this.#branchName + data);
235 this.#branch.removeObserver("", this);
239 exports.PrefObserver = PrefObserver;