}, this);
var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), {
- SAVED: "extensions.dactyl.saved.",
+ ORIGINAL: "extensions.dactyl.original.",
RESTORE: "extensions.dactyl.restore.",
+ SAVED: "extensions.dactyl.saved.",
INIT: {},
- init: function (branch, defaults) {
+ init: function init(branch, defaults) {
this._prefContexts = [];
this.branch = services.pref[defaults ? "getDefaultBranch" : "getBranch"](branch || "");
- if (this.branch instanceof Ci.nsIPrefBranch2)
- this.branch.QueryInterface(Ci.nsIPrefBranch2);
+ this.branch instanceof Ci.nsIPrefBranch2;
this.defaults = defaults ? this : this.constructor(branch, true);
+ this.branches = memoize({
+ __proto__: this,
+ get original() this.constructor(this.ORIGINAL + this.root),
+ get restore() this.constructor(this.RESTORE + this.root),
+ get saved() this.constructor(this.SAVED + this.root),
+ });
+
if (!defaults)
this.restore();
this._observers = {};
},
- cleanup: function cleanup() {
+ cleanup: function cleanup(reason) {
if (this.defaults != this)
this.defaults.cleanup();
+
this._observers = {};
if (this.observe) {
this.branch.removeObserver("", this);
this.observe.unregister();
delete this.observe;
}
+
+ if (this == prefs) {
+ if (~["uninstall", "disable"].indexOf(reason)) {
+ for (let name in values(this.branches.saved.getNames()))
+ this.safeReset(name, null, true);
+
+ this.branches.original.resetBranch();
+ this.branches.saved.resetBranch();
+ }
+
+ if (reason == "uninstall" && this == prefs)
+ localPrefs.resetBranch();
+ }
},
+ /**
+ * Returns the full name of this object's preference branch.
+ */
+ get root() this.branch.root,
+
+ /**
+ * Returns a new Prefs instance for the sub-branch *branch* of this
+ * branch.
+ *
+ * @param {string} branch The branch to branch to.
+ * @returns {Prefs}
+ */
+ Branch: function Branch(branch) Prefs(this.root + branch),
+
observe: null,
observers: {
"nsPref:changed": function (subject, data) {
* @param {function(object)} callback The callback, called with the
* new value of the preference whenever it changes.
*/
- watch: function (pref, callback, strong) {
+ watch: function watch(pref, callback, strong) {
if (!this.observe) {
util.addObserver(this);
this.branch.addObserver("", this, false);
}
};
- return template.options(config.host + " Preferences", prefs.call(this));
+ return template.options(_("pref.hostPreferences", config.host), prefs.call(this));
},
/**
* @param {string} branch The branch in which to search preferences.
* @default ""
*/
- getNames: function (branch) this.branch.getChildList(branch || "", { value: 0 }),
+ getNames: function getNames(branch) this.branch.getChildList(branch || "", { value: 0 }),
- _checkSafe: function (name, message, value) {
+ _checkSafe: function _checkSafe(name, message, value) {
let curval = this.get(name, null);
+
+ if (this.branches.original.get(name) == null)
+ this.branches.original.set(name, curval, true);
+
if (arguments.length > 2 && curval === value)
return;
+
let defval = this.defaults.get(name, null);
- let saved = this.get(this.SAVED + name);
+ let saved = this.branches.saved.get(name);
if (saved == null && curval != defval || saved != null && curval != saved) {
- let msg = "Warning: setting preference " + name + ", but it's changed from its default value.";
+ let msg = _("pref.safeSet.warnChanged", name);
if (message)
msg = template.linkifyHelp(msg + " " + message);
util.dactyl.warn(msg);
*
* @param {string} name The preference name.
* @param {value} value The new preference value.
+ * @param {boolean} silent Ignore errors.
*/
- safeReset: function (name, message) {
+ safeReset: function safeReset(name, message, silent) {
this._checkSafe(name, message);
- this.reset(name);
- this.reset(this.SAVED + name);
+ this.set(name, this.branches.original.get(name), silent);
+ this.branches.original.reset(name);
+ this.branches.saved.reset(name);
},
/**
* @param {string} name The preference name.
* @param {value} value The new preference value.
*/
- safeSet: function (name, value, message, skipSave) {
+ safeSet: function safeSet(name, value, message, skipSave) {
this._checkSafe(name, message, value);
this.set(name, value);
- this[skipSave ? "reset" : "set"](this.SAVED + name, value);
+ this.branches.saved[skipSave ? "reset" : "set"](name, value);
},
/**
*
* @param {string} name The preference name.
* @param {value} value The new preference value.
+ * @param {boolean} silent Ignore errors.
*/
- set: function (name, value) {
- if (this._prefContexts.length) {
- let val = this.get(name, null);
- if (val != null)
- this._prefContexts[this._prefContexts.length - 1][name] = val;
- }
+ set: function set(name, value, silent) {
+ if (this._prefContexts.length)
+ this._prefContexts[this._prefContexts.length - 1][name] = this.get(name, null);
function assertType(needType)
util.assert(type === Ci.nsIPrefBranch.PREF_INVALID || type === needType,
type === Ci.nsIPrefBranch.PREF_INT
- ? "E521: Number required after =: " + name + "=" + value
- : "E474: Invalid argument: " + name + "=" + value);
+ ? /*L*/"E521: Number required after =: " + name + "=" + value
+ : /*L*/"E474: Invalid argument: " + name + "=" + value);
let type = this.branch.getPrefType(name);
- switch (typeof value) {
- case "string":
- assertType(Ci.nsIPrefBranch.PREF_STRING);
-
- this.branch.setComplexValue(name, Ci.nsISupportsString, services.String(value));
- break;
- case "number":
- assertType(Ci.nsIPrefBranch.PREF_INT);
-
- this.branch.setIntPref(name, value);
- break;
- case "boolean":
- assertType(Ci.nsIPrefBranch.PREF_BOOL);
-
- this.branch.setBoolPref(name, value);
- break;
- default:
- throw FailedAssertion("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")");
+ try {
+ switch (typeof value) {
+ case "string":
+ assertType(Ci.nsIPrefBranch.PREF_STRING);
+
+ this.branch.setComplexValue(name, Ci.nsISupportsString, services.String(value));
+ break;
+ case "number":
+ assertType(Ci.nsIPrefBranch.PREF_INT);
+
+ this.branch.setIntPref(name, value);
+ break;
+ case "boolean":
+ assertType(Ci.nsIPrefBranch.PREF_BOOL);
+
+ this.branch.setBoolPref(name, value);
+ break;
+ default:
+ if (value == null && this != this.defaults)
+ this.reset(name);
+ else
+ throw FailedAssertion("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")");
+ }
}
+ catch (e if silent) {}
+ return value;
},
/**
*
* @param {string} name The preference to save.
*/
- save: function (name) {
+ save: function save(name) {
let val = this.get(name);
this.set(this.RESTORE + name, val);
this.safeSet(name, val);
* @param {string} branch The branch from which to restore
* preferences. @optional
*/
- restore: function (branch) {
+ restore: function restore(branch) {
this.getNames(this.RESTORE + (branch || "")).forEach(function (pref) {
this.safeSet(pref.substr(this.RESTORE.length), this.get(pref), null, true);
this.reset(pref);
*
* @param {string} name The preference name.
*/
- reset: function (name) {
+ reset: function reset(name) {
try {
this.branch.clearUserPref(name);
}
catch (e) {} // ignore - thrown if not a user set value
},
+ /**
+ * Resets the preference branch *branch* to its default value.
+ *
+ * @param {string} branch The preference name. @optional
+ */
+ resetBranch: function resetBranch(branch) {
+ this.getNames(branch).forEach(this.closure.reset);
+ },
+
/**
* Toggles the value of the boolean preference *name*.
*
* @param {string} name The preference name.
*/
- toggle: function (name) {
+ toggle: function toggle(name) {
util.assert(this.branch.getPrefType(name) === Ci.nsIPrefBranch.PREF_BOOL,
- _("error.trailing", name + "!"));
+ _("error.trailingCharacters", name + "!"));
this.set(name, !this.get(name));
},
*
* @see #withContext
*/
- pushContext: function () {
+ pushContext: function pushContext() {
this._prefContexts.push({});
},
*
* @see #withContext
*/
- popContext: function () {
+ popContext: function popContext() {
for (let [k, v] in Iterator(this._prefContexts.pop()))
this.set(k, v);
},
* @see #pushContext
* @see #popContext
*/
- withContext: function (func, self) {
+ withContext: function withContext(func, self) {
try {
this.pushContext();
return func.call(self);
}
}, {
}, {
- completion: function (dactyl, modules) {
+ completion: function init_completion(dactyl, modules) {
modules.completion.preference = function preference(context) {
context.anchored = false;
context.title = [config.host + " Preference", "Value"];
context.completions = prefs.getNames();
};
},
- javascript: function (dactyl, modules) {
+ javascript: function init_javascript(dactyl, modules) {
modules.JavaScript.setCompleter([this.get, this.safeSet, this.set, this.reset, this.toggle],
[function (context) (context.anchored=false, this.getNames().map(function (pref) [pref, ""]))]);
}