1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 23:57:59 +01:00

Save option restore data until add-on is disabled. Cleanup preferences on uninstall.

This commit is contained in:
Kris Maglione
2011-07-29 05:29:06 -04:00
parent c165fd95be
commit a0de5d9e24
9 changed files with 180 additions and 130 deletions

6
common/bootstrap.js vendored
View File

@@ -241,11 +241,11 @@ function shutdown(data, reason) {
reportError(e); reportError(e);
} }
if ([ADDON_UPGRADE, ADDON_DOWNGRADE, ADDON_UNINSTALL].indexOf(reason) >= 0) if (~[ADDON_UPGRADE, ADDON_DOWNGRADE, ADDON_UNINSTALL].indexOf(reason))
Services.obs.notifyObservers(null, "dactyl-purge", null); Services.obs.notifyObservers(null, "dactyl-purge", null);
Services.obs.notifyObservers(null, "dactyl-cleanup", null); Services.obs.notifyObservers(null, "dactyl-cleanup", reasonToString(reason));
Services.obs.notifyObservers(null, "dactyl-cleanup-modules", null); Services.obs.notifyObservers(null, "dactyl-cleanup-modules", reasonToString(reason));
JSMLoader.purge(); JSMLoader.purge();
for each (let [category, entry] in categories) for each (let [category, entry] in categories)

View File

@@ -329,6 +329,7 @@ var Abbreviations = Module("abbreviations", {
args["-group"].add(modes, lhs, rhs); args["-group"].add(modes, lhs, rhs);
} }
}, { }, {
identifier: "abbreviate",
completer: function (context, args) { completer: function (context, args) {
if (args.length == 1) if (args.length == 1)
return completion.abbreviation(context, modes, args["-group"]); return completion.abbreviation(context, modes, args["-group"]);

View File

@@ -70,21 +70,36 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
autocommands.trigger("Leave", {}); autocommands.trigger("Leave", {});
}, },
// initially hide all GUI elements, they are later restored unless the user
// has :set go= or something similar in his config
hideGUI: function () {
let guioptions = config.guioptions;
for (let option in guioptions) {
guioptions[option].forEach(function (elem) {
try {
document.getElementById(elem).collapsed = true;
}
catch (e) {}
});
}
},
observers: { observers: {
"dactyl-cleanup": function dactyl_cleanup() { "dactyl-cleanup": function dactyl_cleanup(subject, reason) {
let modules = dactyl.modules; let modules = dactyl.modules;
for (let mod in values(modules.moduleList.reverse())) { for (let mod in values(modules.moduleList.reverse())) {
mod.stale = true; mod.stale = true;
if ("cleanup" in mod) if ("cleanup" in mod)
this.trapErrors("cleanup", mod); this.trapErrors("cleanup", mod, reason);
if ("destroy" in mod) if ("destroy" in mod)
this.trapErrors("destroy", mod); this.trapErrors("destroy", mod, reason);
} }
for (let mod in values(modules.ownPropertyValues.reverse())) for (let mod in values(modules.ownPropertyValues.reverse()))
if (mod instanceof Class && "INIT" in mod && "cleanup" in mod.INIT) if (mod instanceof Class && "INIT" in mod && "cleanup" in mod.INIT)
this.trapErrors(mod.cleanup, mod, dactyl, modules, window); this.trapErrors(mod.cleanup, mod, dactyl, modules, window, reason);
for (let name in values(Object.getOwnPropertyNames(modules).reverse())) for (let name in values(Object.getOwnPropertyNames(modules).reverse()))
try { try {
@@ -1547,19 +1562,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
get windows() [win for (win in iter(services.windowMediator.getEnumerator("navigator:browser"))) if (win.dactyl)], get windows() [win for (win in iter(services.windowMediator.getEnumerator("navigator:browser"))) if (win.dactyl)],
}, { }, {
// initially hide all GUI elements, they are later restored unless the user toolbarHidden: function hidden(elem) (elem.getAttribute("autohide") || elem.getAttribute("collapsed")) == "true"
// has :set go= or something similar in his config
hideGUI: function () {
let guioptions = config.guioptions;
for (let option in guioptions) {
guioptions[option].forEach(function (elem) {
try {
document.getElementById(elem).collapsed = true;
}
catch (e) {}
});
}
}
}, { }, {
events: function () { events: function () {
events.listen(window, "click", dactyl.closure.onClick, true); events.listen(window, "click", dactyl.closure.onClick, true);
@@ -1664,7 +1667,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
// FIXME: cleanup // FIXME: cleanup
cleanupValue: config.cleanups.guioptions || cleanupValue: config.cleanups.guioptions ||
"r" + [k for ([k, v] in iter(groups[1].opts)) "r" + [k for ([k, v] in iter(groups[1].opts))
if (!document.getElementById(v[1][0]).collapsed)].join(""), if (!Dactyl.toolbarHidden(document.getElementById(v[1][0])))].join(""),
values: array(groups).map(function (g) [[k, v[0]] for ([k, v] in Iterator(g.opts))]).flatten(), values: array(groups).map(function (g) [[k, v[0]] for ([k, v] in Iterator(g.opts))]).flatten(),
@@ -1938,8 +1941,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
var toolbox = document.getElementById("navigator-toolbox"); var toolbox = document.getElementById("navigator-toolbox");
if (toolbox) { if (toolbox) {
let hidden = function hidden(elem) (elem.getAttribute("autohide") || elem.getAttribute("collapsed")) == "true";
let toolbarCommand = function (names, desc, action, filter) { let toolbarCommand = function (names, desc, action, filter) {
commands.add(names, desc, commands.add(names, desc,
function (args) { function (args) {
@@ -1960,12 +1961,12 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
toolbarCommand(["toolbars[how]", "tbs[how]"], "Show the named toolbar", toolbarCommand(["toolbars[how]", "tbs[how]"], "Show the named toolbar",
function (toolbar) dactyl.setNodeVisible(toolbar, true), function (toolbar) dactyl.setNodeVisible(toolbar, true),
function ({ item }) hidden(item)); function ({ item }) Dactyl.toolbarHidden(item));
toolbarCommand(["toolbarh[ide]", "tbh[ide]"], "Hide the named toolbar", toolbarCommand(["toolbarh[ide]", "tbh[ide]"], "Hide the named toolbar",
function (toolbar) dactyl.setNodeVisible(toolbar, false), function (toolbar) dactyl.setNodeVisible(toolbar, false),
function ({ item }) !hidden(item)); function ({ item }) !Dactyl.toolbarHidden(item));
toolbarCommand(["toolbart[oggle]", "tbt[oggle]"], "Toggle the named toolbar", toolbarCommand(["toolbart[oggle]", "tbt[oggle]"], "Toggle the named toolbar",
function (toolbar) dactyl.setNodeVisible(toolbar, hidden(toolbar))); function (toolbar) dactyl.setNodeVisible(toolbar, Dactyl.toolbarHidden(toolbar)));
} }
commands.add(["time"], commands.add(["time"],
@@ -2171,7 +2172,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
} }
// TODO: we should have some class where all this guioptions stuff fits well // TODO: we should have some class where all this guioptions stuff fits well
// Dactyl.hideGUI(); // dactyl.hideGUI();
if (dactyl.userEval("typeof document", null, "test.js") === "undefined") if (dactyl.userEval("typeof document", null, "test.js") === "undefined")
jsmodules.__proto__ = XPCSafeJSObjectWrapper(window); jsmodules.__proto__ = XPCSafeJSObjectWrapper(window);

View File

@@ -507,6 +507,7 @@ var Mappings = Module("mappings", {
} }
const opts = { const opts = {
identifier: "map",
completer: function (context, args) { completer: function (context, args) {
let mapmodes = array.uniq(args["-modes"].map(findMode)); let mapmodes = array.uniq(args["-modes"].map(findMode));
if (args.length == 1) if (args.length == 1)
@@ -629,6 +630,7 @@ var Mappings = Module("mappings", {
dactyl.echoerr(_("map.noSuch", args[0])); dactyl.echoerr(_("map.noSuch", args[0]));
}, },
{ {
identifier: "unmap",
argCount: "?", argCount: "?",
bang: true, bang: true,
completer: opts.completer, completer: opts.completer,

View File

@@ -958,8 +958,9 @@ Class.prototype = {
func.superapply(self, Array.slice(arguments, 1)); func.superapply(self, Array.slice(arguments, 1));
} }
} }
try { try {
if ("value" in desc && i in this.localizedProperties) if ("value" in desc && (k in this.localizedProperties || k in this.magicalProperties))
this[k] = desc.value; this[k] = desc.value;
else else
Object.defineProperty(this, k, desc); Object.defineProperty(this, k, desc);
@@ -967,7 +968,9 @@ Class.prototype = {
catch (e) {} catch (e) {}
}, this); }, this);
} }
} },
magicalProperties: {}
}; };
Class.makeClosure = function makeClosure() { Class.makeClosure = function makeClosure() {
const self = this; const self = this;

View File

@@ -700,7 +700,8 @@ var JavaScript = Module("javascript", {
modes.addMode("REPL", { modes.addMode("REPL", {
description: "JavaScript Read Eval Print Loop", description: "JavaScript Read Eval Print Loop",
bases: [modes.COMMAND_LINE] bases: [modes.COMMAND_LINE],
displayName: "REPL"
}); });
}, },
commandline: function initCommandLine(dactyl, modules, window) { commandline: function initCommandLine(dactyl, modules, window) {

View File

@@ -78,6 +78,8 @@ var Option = Class("Option", {
this.globalValue = this.defaultValue; this.globalValue = this.defaultValue;
}, },
magicalProperties: Set(["cleanupValue"]),
/** /**
* @property {string} This option's description, as shown in :listoptions. * @property {string} This option's description, as shown in :listoptions.
*/ */
@@ -91,6 +93,13 @@ var Option = Class("Option", {
get isDefault() this.stringValue === this.stringDefaultValue, get isDefault() this.stringValue === this.stringDefaultValue,
/** @property {value} The value to reset this option to at cleanup time. */
get cleanupValue() options.cleanupPrefs.get(this.name),
set cleanupValue(value) {
if (options.cleanupPrefs.get(this.name) == null)
options.cleanupPrefs.set(this.name, value);
},
/** @property {value} The option's global value. @see #scope */ /** @property {value} The option's global value. @see #scope */
get globalValue() { try { return options.store.get(this.name, {}).value; } catch (e) { util.reportError(e); throw e; } }, get globalValue() { try { return options.store.get(this.name, {}).value; } catch (e) { util.reportError(e); throw e; } },
set globalValue(val) { options.store.set(this.name, { value: val, time: Date.now() }); }, set globalValue(val) { options.store.set(this.name, { value: val, time: Date.now() }); },
@@ -282,8 +291,6 @@ var Option = Class("Option", {
*/ */
scope: 1, // Option.SCOPE_GLOBAL // XXX set to BOTH by default someday? - kstep scope: 1, // Option.SCOPE_GLOBAL // XXX set to BOTH by default someday? - kstep
cleanupValue: null,
/** /**
* @property {function(CompletionContext, Args)} This option's completer. * @property {function(CompletionContext, Args)} This option's completer.
* @see CompletionContext * @see CompletionContext
@@ -817,7 +824,7 @@ var Options = Module("options", {
cleanup: function cleanup() { cleanup: function cleanup() {
for (let opt in this) for (let opt in this)
if (opt.cleanupValue != null) if (opt.cleanupValue != null)
opt.value = opt.parse(opt.cleanupValue); opt.stringValue = opt.cleanupValue;
}, },
/** /**
@@ -883,6 +890,13 @@ var Options = Module("options", {
setPref: deprecated("prefs.set", function setPref() prefs.set.apply(prefs, arguments)), setPref: deprecated("prefs.set", function setPref() prefs.set.apply(prefs, arguments)),
withContext: deprecated("prefs.withContext", function withContext() prefs.withContext.apply(prefs, arguments)), withContext: deprecated("prefs.withContext", function withContext() prefs.withContext.apply(prefs, arguments)),
cleanupPrefs: Class.memoize(function () localPrefs.Branch("cleanup.option.")),
cleanup: function cleanup(reason) {
if (~["disable", "uninstall"].indexOf(reason))
this.cleanupPrefs.resetBranch();
},
/** /**
* Returns the option with *name* in the specified *scope*. * Returns the option with *name* in the specified *scope*.
* *

View File

@@ -20,7 +20,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
RESTORE: "extensions.dactyl.restore.", RESTORE: "extensions.dactyl.restore.",
INIT: {}, INIT: {},
init: function (branch, defaults) { init: function init(branch, defaults) {
this._prefContexts = []; this._prefContexts = [];
this.branch = services.pref[defaults ? "getDefaultBranch" : "getBranch"](branch || ""); this.branch = services.pref[defaults ? "getDefaultBranch" : "getBranch"](branch || "");
@@ -34,7 +34,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
this._observers = {}; this._observers = {};
}, },
cleanup: function cleanup() { cleanup: function cleanup(reason) {
if (this.defaults != this) if (this.defaults != this)
this.defaults.cleanup(); this.defaults.cleanup();
this._observers = {}; this._observers = {};
@@ -43,8 +43,25 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
this.observe.unregister(); this.observe.unregister();
delete this.observe; delete this.observe;
} }
if (reason == "uninstall")
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, observe: null,
observers: { observers: {
"nsPref:changed": function (subject, data) { "nsPref:changed": function (subject, data) {
@@ -68,7 +85,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
* @param {function(object)} callback The callback, called with the * @param {function(object)} callback The callback, called with the
* new value of the preference whenever it changes. * new value of the preference whenever it changes.
*/ */
watch: function (pref, callback, strong) { watch: function watch(pref, callback, strong) {
if (!this.observe) { if (!this.observe) {
util.addObserver(this); util.addObserver(this);
this.branch.addObserver("", this, false); this.branch.addObserver("", this, false);
@@ -160,9 +177,9 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
* @param {string} branch The branch in which to search preferences. * @param {string} branch The branch in which to search preferences.
* @default "" * @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); let curval = this.get(name, null);
if (arguments.length > 2 && curval === value) if (arguments.length > 2 && curval === value)
return; return;
@@ -184,7 +201,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
* @param {string} name The preference name. * @param {string} name The preference name.
* @param {value} value The new preference value. * @param {value} value The new preference value.
*/ */
safeReset: function (name, message) { safeReset: function safeReset(name, message) {
this._checkSafe(name, message); this._checkSafe(name, message);
this.reset(name); this.reset(name);
this.reset(this.SAVED + name); this.reset(this.SAVED + name);
@@ -197,7 +214,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
* @param {string} name The preference name. * @param {string} name The preference name.
* @param {value} value The new preference value. * @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._checkSafe(name, message, value);
this.set(name, value); this.set(name, value);
this[skipSave ? "reset" : "set"](this.SAVED + name, value); this[skipSave ? "reset" : "set"](this.SAVED + name, value);
@@ -209,7 +226,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
* @param {string} name The preference name. * @param {string} name The preference name.
* @param {value} value The new preference value. * @param {value} value The new preference value.
*/ */
set: function (name, value) { set: function set(name, value) {
if (this._prefContexts.length) if (this._prefContexts.length)
this._prefContexts[this._prefContexts.length - 1][name] = this.get(name, null); this._prefContexts[this._prefContexts.length - 1][name] = this.get(name, null);
@@ -242,6 +259,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
else else
throw FailedAssertion("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")"); throw FailedAssertion("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")");
} }
return value;
}, },
/** /**
@@ -250,7 +268,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
* *
* @param {string} name The preference to save. * @param {string} name The preference to save.
*/ */
save: function (name) { save: function save(name) {
let val = this.get(name); let val = this.get(name);
this.set(this.RESTORE + name, val); this.set(this.RESTORE + name, val);
this.safeSet(name, val); this.safeSet(name, val);
@@ -262,7 +280,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
* @param {string} branch The branch from which to restore * @param {string} branch The branch from which to restore
* preferences. @optional * preferences. @optional
*/ */
restore: function (branch) { restore: function restore(branch) {
this.getNames(this.RESTORE + (branch || "")).forEach(function (pref) { this.getNames(this.RESTORE + (branch || "")).forEach(function (pref) {
this.safeSet(pref.substr(this.RESTORE.length), this.get(pref), null, true); this.safeSet(pref.substr(this.RESTORE.length), this.get(pref), null, true);
this.reset(pref); this.reset(pref);
@@ -274,19 +292,28 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
* *
* @param {string} name The preference name. * @param {string} name The preference name.
*/ */
reset: function (name) { reset: function reset(name) {
try { try {
this.branch.clearUserPref(name); this.branch.clearUserPref(name);
} }
catch (e) {} // ignore - thrown if not a user set value 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*. * Toggles the value of the boolean preference *name*.
* *
* @param {string} name The 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, util.assert(this.branch.getPrefType(name) === Ci.nsIPrefBranch.PREF_BOOL,
_("error.trailingCharacters", name + "!")); _("error.trailingCharacters", name + "!"));
this.set(name, !this.get(name)); this.set(name, !this.get(name));

View File

@@ -115,7 +115,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
* *
* @param {object} obj * @param {object} obj
*/ */
addObserver: function (obj) { addObserver: update(function addObserver(obj) {
if (!obj.observers) if (!obj.observers)
obj.observers = obj.observe; obj.observers = obj.observe;
@@ -137,7 +137,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
} }
catch (e) { catch (e) {
if (typeof util === "undefined") if (typeof util === "undefined")
dump("dactyl: error: " + e + "\n" + (e.stack || Error().stack).replace(/^/gm, "dactyl: ")); addObserver.dump("dactyl: error: " + e + "\n" + (e.stack || addObserver.Error().stack).replace(/^/gm, "dactyl: "));
else else
util.reportError(e); util.reportError(e);
} }
@@ -145,7 +145,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
obj.observe.unregister = function () register("removeObserver"); obj.observe.unregister = function () register("removeObserver");
register("addObserver"); register("addObserver");
}, }, { dump: dump, Error: Error }),
/* /*
* Tests a condition and throws a FailedAssertion error on * Tests a condition and throws a FailedAssertion error on
@@ -1226,13 +1226,13 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
}, },
observers: { observers: {
"dactyl-cleanup-modules": function () { "dactyl-cleanup-modules": function (subject, reason) {
defineModule.loadLog.push("dactyl: util: observe: dactyl-cleanup-modules"); defineModule.loadLog.push("dactyl: util: observe: dactyl-cleanup-modules " + reason);
for (let module in values(defineModule.modules)) for (let module in values(defineModule.modules))
if (module.cleanup) { if (module.cleanup) {
util.dump("cleanup: " + module.constructor.className); util.dump("cleanup: " + module.constructor.className);
util.trapErrors(module.cleanup, module); util.trapErrors(module.cleanup, module, reason);
} }
JSMLoader.cleanup(); JSMLoader.cleanup();
@@ -1256,6 +1256,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
"dactyl-purge": function () { "dactyl-purge": function () {
this.rehashing = 1; this.rehashing = 1;
}, },
"toplevel-window-ready": function (window, data) { "toplevel-window-ready": function (window, data) {
window.addEventListener("DOMContentLoaded", wrapCallback(function listener(event) { window.addEventListener("DOMContentLoaded", wrapCallback(function listener(event) {
if (event.originalTarget === window.document) { if (event.originalTarget === window.document) {