/* 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"; module.metadata = { "stability": "unstable" }; // The minimum and maximum integers that can be set as preferences. // The range of valid values is narrower than the range of valid JS values // because the native preferences code treats integers as NSPR PRInt32s, // which are 32-bit signed integers on all platforms. const MAX_INT = 0x7FFFFFFF; const MIN_INT = -0x80000000; const {Cc,Ci,Cr} = require("chrome"); const prefService = Cc["@mozilla.org/preferences-service;1"]. getService(Ci.nsIPrefService); const prefSvc = prefService.getBranch(null); const defaultBranch = prefService.getDefaultBranch(null); const { Preferences } = require("resource://gre/modules/Preferences.jsm"); const prefs = new Preferences({}); const branchKeys = branchName => keys(branchName).map($ => $.replace(branchName, "")); const Branch = function(branchName) { return new Proxy(Branch.prototype, { getOwnPropertyDescriptor(target, name, receiver) { return { configurable: true, enumerable: true, writable: false, value: this.get(target, name, receiver) }; }, ownKeys(target) { return branchKeys(branchName); }, get(target, name, receiver) { return get(`${branchName}${name}`); }, set(target, name, value, receiver) { set(`${branchName}${name}`, value); return true; }, has(target, name) { return this.hasOwn(target, name); }, hasOwn(target, name) { return has(`${branchName}${name}`); }, deleteProperty(target, name) { reset(`${branchName}${name}`); return true; } }); } function get(name, defaultValue) { return prefs.get(name, defaultValue); } exports.get = get; function set(name, value) { var prefType; if (typeof value != "undefined" && value != null) prefType = value.constructor.name; switch (prefType) { case "Number": if (value % 1 != 0) throw new Error("cannot store non-integer number: " + value); } prefs.set(name, value); } exports.set = set; const has = prefs.has.bind(prefs) exports.has = has; function keys(root) { return prefSvc.getChildList(root); } exports.keys = keys; const isSet = prefs.isSet.bind(prefs); exports.isSet = isSet; function reset(name) { try { prefSvc.clearUserPref(name); } catch (e) { // The pref service throws NS_ERROR_UNEXPECTED when the caller tries // to reset a pref that doesn't exist or is already set to its default // value. This interface fails silently in those cases, so callers // can unconditionally reset a pref without having to check if it needs // resetting first or trap exceptions after the fact. It passes through // other exceptions, however, so callers know about them, since we don't // know what other exceptions might be thrown and what they might mean. if (e.result != Cr.NS_ERROR_UNEXPECTED) { throw e; } } } exports.reset = reset; function getLocalized(name, defaultValue) { let value = null; try { value = prefSvc.getComplexValue(name, Ci.nsIPrefLocalizedString).data; } finally { return value || defaultValue; } } exports.getLocalized = getLocalized; function setLocalized(name, value) { // We can't use `prefs.set` here as we have to use `getDefaultBranch` // (instead of `getBranch`) in order to have `mIsDefault` set to true, here: // http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/nsPrefBranch.cpp#233 // Otherwise, we do not enter into this expected condition: // http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/nsPrefBranch.cpp#244 defaultBranch.setCharPref(name, value); } exports.setLocalized = setLocalized; exports.Branch = Branch;