mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-20 04:48:08 +01:00
Integrate sanitizer with host UI, sanitize at shutdown support, and control which items are sanitized when more thoroughly. Closes issue #70.
This commit is contained in:
@@ -289,19 +289,16 @@ const Buffer = Module("buffer", {
|
|||||||
},
|
},
|
||||||
setOverLink: function setOverLink(link, b) {
|
setOverLink: function setOverLink(link, b) {
|
||||||
setOverLink.superapply(this, arguments);
|
setOverLink.superapply(this, arguments);
|
||||||
let ssli = options["showstatuslinks"];
|
switch (options["showstatuslinks"]) {
|
||||||
if (link && ssli) {
|
case 1:
|
||||||
if (ssli == 1)
|
statusline.updateUrl(link && "Link: " + link);
|
||||||
statusline.updateUrl("Link: " + link);
|
break;
|
||||||
else if (ssli == 2)
|
case 2:
|
||||||
|
if (link)
|
||||||
dactyl.echo("Link: " + link, commandline.DISALLOW_MULTILINE);
|
dactyl.echo("Link: " + link, commandline.DISALLOW_MULTILINE);
|
||||||
}
|
else
|
||||||
|
|
||||||
if (link == "") {
|
|
||||||
if (ssli == 1)
|
|
||||||
statusline.updateUrl();
|
|
||||||
else if (ssli == 2)
|
|
||||||
commandline.clear();
|
commandline.clear();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -644,8 +641,8 @@ const Buffer = Module("buffer", {
|
|||||||
|
|
||||||
buffer.focusElement(elem);
|
buffer.focusElement(elem);
|
||||||
|
|
||||||
options.withContext(function () {
|
prefs.withContext(function () {
|
||||||
options.setPref("browser.tabs.loadInBackground", true);
|
prefs.set("browser.tabs.loadInBackground", true);
|
||||||
["mousedown", "mouseup", "click"].forEach(function (event) {
|
["mousedown", "mouseup", "click"].forEach(function (event) {
|
||||||
elem.dispatchEvent(events.create(doc, event, {
|
elem.dispatchEvent(events.create(doc, event, {
|
||||||
screenX: offsetX, screenY: offsetY,
|
screenX: offsetX, screenY: offsetY,
|
||||||
@@ -690,7 +687,7 @@ const Buffer = Module("buffer", {
|
|||||||
try {
|
try {
|
||||||
window.urlSecurityCheck(url, doc.nodePrincipal);
|
window.urlSecurityCheck(url, doc.nodePrincipal);
|
||||||
// we always want to save that link relative to the current working directory
|
// we always want to save that link relative to the current working directory
|
||||||
options.setPref("browser.download.lastDir", io.cwd);
|
prefs.set("browser.download.lastDir", io.cwd);
|
||||||
window.saveURL(url, text, null, true, skipPrompt, makeURI(url, doc.characterSet));
|
window.saveURL(url, text, null, true, skipPrompt, makeURI(url, doc.characterSet));
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
@@ -1262,17 +1259,17 @@ const Buffer = Module("buffer", {
|
|||||||
dactyl.assert(!arg || arg[0] == ">" && !dactyl.has("WINNT"),
|
dactyl.assert(!arg || arg[0] == ">" && !dactyl.has("WINNT"),
|
||||||
"E488: Trailing characters");
|
"E488: Trailing characters");
|
||||||
|
|
||||||
options.withContext(function () {
|
prefs.withContext(function () {
|
||||||
if (arg) {
|
if (arg) {
|
||||||
options.setPref("print.print_to_file", "true");
|
prefs.set("print.print_to_file", "true");
|
||||||
options.setPref("print.print_to_filename", io.File(arg.substr(1)).path);
|
prefs.set("print.print_to_filename", io.File(arg.substr(1)).path);
|
||||||
dactyl.echomsg("Printing to file: " + arg.substr(1));
|
dactyl.echomsg("Printing to file: " + arg.substr(1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
dactyl.echomsg("Sending to printer...");
|
dactyl.echomsg("Sending to printer...");
|
||||||
|
|
||||||
options.setPref("print.always_print_silent", args.bang);
|
prefs.set("print.always_print_silent", args.bang);
|
||||||
options.setPref("print.show_print_progress", !args.bang);
|
prefs.set("print.show_print_progress", !args.bang);
|
||||||
|
|
||||||
config.browser.contentWindow.print();
|
config.browser.contentWindow.print();
|
||||||
});
|
});
|
||||||
@@ -1371,7 +1368,7 @@ const Buffer = Module("buffer", {
|
|||||||
// if browser.download.useDownloadDir = false then the "Save As"
|
// if browser.download.useDownloadDir = false then the "Save As"
|
||||||
// dialog is used with this as the default directory
|
// dialog is used with this as the default directory
|
||||||
// TODO: if we're going to do this shouldn't it be done in setCWD or the value restored?
|
// TODO: if we're going to do this shouldn't it be done in setCWD or the value restored?
|
||||||
options.setPref("browser.download.lastDir", io.cwd);
|
prefs.set("browser.download.lastDir", io.cwd);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var contentDisposition = window.content
|
var contentDisposition = window.content
|
||||||
|
|||||||
@@ -1690,6 +1690,7 @@ const CommandLine = Module("commandline", {
|
|||||||
sanitizer: function () {
|
sanitizer: function () {
|
||||||
sanitizer.addItem("commandline", {
|
sanitizer.addItem("commandline", {
|
||||||
description: "Command-line and search history",
|
description: "Command-line and search history",
|
||||||
|
persistent: true,
|
||||||
action: function (timespan, host) {
|
action: function (timespan, host) {
|
||||||
if (!host)
|
if (!host)
|
||||||
storage["history-search"].mutate("filter", function (item) !timespan.contains(item.timestamp));
|
storage["history-search"].mutate("filter", function (item) !timespan.contains(item.timestamp));
|
||||||
|
|||||||
@@ -19,12 +19,6 @@ const EVAL_ERROR = "__dactyl_eval_error";
|
|||||||
const EVAL_RESULT = "__dactyl_eval_result";
|
const EVAL_RESULT = "__dactyl_eval_result";
|
||||||
const EVAL_STRING = "__dactyl_eval_string";
|
const EVAL_STRING = "__dactyl_eval_string";
|
||||||
|
|
||||||
const FailedAssertion = Class("FailedAssertion", Error, {
|
|
||||||
init: function (message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function deprecated(reason, fn) {
|
function deprecated(reason, fn) {
|
||||||
let name, func = callable(fn) ? fn : function () this[fn].apply(this, arguments);
|
let name, func = callable(fn) ? fn : function () this[fn].apply(this, arguments);
|
||||||
function deprecatedMethod() {
|
function deprecatedMethod() {
|
||||||
@@ -633,13 +627,13 @@ const Dactyl = Module("dactyl", {
|
|||||||
<spec>{spec((obj.specs || obj.names)[0])}</spec>{
|
<spec>{spec((obj.specs || obj.names)[0])}</spec>{
|
||||||
!obj.type ? "" : <>
|
!obj.type ? "" : <>
|
||||||
<type>{obj.type}</type>
|
<type>{obj.type}</type>
|
||||||
<default>{opt.stringify(obj.defaultValue)}</default></>}
|
<default>{obj.stringDefaultValue}</default></>}
|
||||||
<description>{
|
<description>{
|
||||||
obj.description ? br+<p>{obj.description.replace(/\.?$/, ".")}</p> : "" }{
|
obj.description ? br+<p>{obj.description.replace(/\.?$/, ".")}</p> : "" }{
|
||||||
extraHelp ? br+extraHelp : "" }{
|
extraHelp ? br+extraHelp : "" }{
|
||||||
!(extraHelp || obj.description) ? br+<p>Sorry, no help available.</p> : "" }
|
!(extraHelp || obj.description) ? br+<p>Sorry, no help available.</p> : "" }
|
||||||
</description>
|
</description>
|
||||||
</item></>.toXMLString(), true);
|
</item></>.toXMLString().replace(/^ {12}/gm, ""), true);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -734,7 +728,7 @@ const Dactyl = Module("dactyl", {
|
|||||||
|
|
||||||
// options does not exist at the very beginning
|
// options does not exist at the very beginning
|
||||||
if (modules.options)
|
if (modules.options)
|
||||||
verbose = options.getPref("extensions.dactyl.loglevel", 0);
|
verbose = prefs.get("extensions.dactyl.loglevel", 0);
|
||||||
|
|
||||||
if (level > verbose)
|
if (level > verbose)
|
||||||
return;
|
return;
|
||||||
@@ -821,8 +815,8 @@ const Dactyl = Module("dactyl", {
|
|||||||
if (!dactyl.has("tabs"))
|
if (!dactyl.has("tabs"))
|
||||||
return open(urls, dactyl.NEW_WINDOW);
|
return open(urls, dactyl.NEW_WINDOW);
|
||||||
|
|
||||||
options.withContext(function () {
|
prefs.withContext(function () {
|
||||||
options.setPref("browser.tabs.loadInBackground", true);
|
prefs.set("browser.tabs.loadInBackground", true);
|
||||||
browser.loadOneTab(url, null, null, postdata, background);
|
browser.loadOneTab(url, null, null, postdata, background);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -870,9 +864,9 @@ const Dactyl = Module("dactyl", {
|
|||||||
quit: function (saveSession, force) {
|
quit: function (saveSession, force) {
|
||||||
// TODO: Use safeSetPref?
|
// TODO: Use safeSetPref?
|
||||||
if (saveSession)
|
if (saveSession)
|
||||||
options.setPref("browser.startup.page", 3); // start with saved session
|
prefs.set("browser.startup.page", 3); // start with saved session
|
||||||
else
|
else
|
||||||
options.setPref("browser.startup.page", 1); // start with default homepage session
|
prefs.set("browser.startup.page", 1); // start with default homepage session
|
||||||
|
|
||||||
if (force)
|
if (force)
|
||||||
services.get("appStartup").quit(Ci.nsIAppStartup.eForceQuit);
|
services.get("appStartup").quit(Ci.nsIAppStartup.eForceQuit);
|
||||||
@@ -939,18 +933,7 @@ const Dactyl = Module("dactyl", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
get assert() util.assert,
|
||||||
* Tests a condition and throws a FailedAssertion error on
|
|
||||||
* failure.
|
|
||||||
*
|
|
||||||
* @param {boolean} condition The condition to test.
|
|
||||||
* @param {string} message The message to present to the
|
|
||||||
* user on failure.
|
|
||||||
*/
|
|
||||||
assert: function (condition, message) {
|
|
||||||
if (!condition)
|
|
||||||
throw new FailedAssertion(message);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Traps errors in the called function, possibly reporting them.
|
* Traps errors in the called function, possibly reporting them.
|
||||||
@@ -1171,7 +1154,7 @@ const Dactyl = Module("dactyl", {
|
|||||||
class_.length ? class_.join(", ") + " { visibility: collapse !important; }" : "",
|
class_.length ? class_.join(", ") + " { visibility: collapse !important; }" : "",
|
||||||
true);
|
true);
|
||||||
|
|
||||||
options.safeSetPref("layout.scrollbar.side", opts.indexOf("l") >= 0 ? 3 : 2,
|
prefs.safeSet("layout.scrollbar.side", opts.indexOf("l") >= 0 ? 3 : 2,
|
||||||
"See 'guioptions' scrollbar flags.");
|
"See 'guioptions' scrollbar flags.");
|
||||||
},
|
},
|
||||||
validator: function (opts) Option.validIf(!(opts.indexOf("l") >= 0 && opts.indexOf("r") >= 0),
|
validator: function (opts) Option.validIf(!(opts.indexOf("l") >= 0 && opts.indexOf("r") >= 0),
|
||||||
@@ -1264,7 +1247,7 @@ const Dactyl = Module("dactyl", {
|
|||||||
"boolean", false,
|
"boolean", false,
|
||||||
{
|
{
|
||||||
setter: function (value) {
|
setter: function (value) {
|
||||||
options.safeSetPref("accessibility.typeaheadfind.enablesound", !value,
|
prefs.safeSet("accessibility.typeaheadfind.enablesound", !value,
|
||||||
"See 'visualbell' option");
|
"See 'visualbell' option");
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -1950,7 +1933,7 @@ const Dactyl = Module("dactyl", {
|
|||||||
AddonManager.getAddonByID(services.get("dactyl:").addonID, function (addon) {
|
AddonManager.getAddonByID(services.get("dactyl:").addonID, function (addon) {
|
||||||
// @DATE@ token replaced by the Makefile
|
// @DATE@ token replaced by the Makefile
|
||||||
// TODO: Find it automatically
|
// TODO: Find it automatically
|
||||||
options.setPref("extensions.dactyl.version", addon.version);
|
prefs.set("extensions.dactyl.version", addon.version);
|
||||||
dactyl.version = addon.version + " (created: @DATE@)";
|
dactyl.version = addon.version + " (created: @DATE@)";
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1970,10 +1953,10 @@ const Dactyl = Module("dactyl", {
|
|||||||
|
|
||||||
// first time intro message
|
// first time intro message
|
||||||
const firstTime = "extensions." + config.name + ".firsttime";
|
const firstTime = "extensions." + config.name + ".firsttime";
|
||||||
if (options.getPref(firstTime, true)) {
|
if (prefs.get(firstTime, true)) {
|
||||||
util.timeout(function () {
|
util.timeout(function () {
|
||||||
dactyl.help();
|
dactyl.help();
|
||||||
options.setPref(firstTime, false);
|
prefs.set(firstTime, false);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -756,7 +756,7 @@ const Events = Module("events", {
|
|||||||
dactyl.echomsg("Recorded macro '" + this._currentMacro + "'");
|
dactyl.echomsg("Recorded macro '" + this._currentMacro + "'");
|
||||||
return killEvent();
|
return killEvent();
|
||||||
}
|
}
|
||||||
else if (!mappings.hasMap(mode, this._input.buffer + key))
|
else if (!mappings.hasMap(modes.main, this._input.buffer + key))
|
||||||
this._macros.set(this._currentMacro, {
|
this._macros.set(this._currentMacro, {
|
||||||
keys: this._macros.get(this._currentMacro, {}).keys + key,
|
keys: this._macros.get(this._currentMacro, {}).keys + key,
|
||||||
timeRecorded: Date.now()
|
timeRecorded: Date.now()
|
||||||
@@ -1087,6 +1087,7 @@ const Events = Module("events", {
|
|||||||
sanitizer: function () {
|
sanitizer: function () {
|
||||||
sanitizer.addItem("macros", {
|
sanitizer.addItem("macros", {
|
||||||
description: "Saved macros",
|
description: "Saved macros",
|
||||||
|
persistent: true,
|
||||||
action: function (timespan, host) {
|
action: function (timespan, host) {
|
||||||
if (!host)
|
if (!host)
|
||||||
for (let [k, m] in events._macros)
|
for (let [k, m] in events._macros)
|
||||||
|
|||||||
@@ -200,9 +200,9 @@ const RangeFinder = Module("rangefinder", {
|
|||||||
|
|
||||||
},
|
},
|
||||||
options: function () {
|
options: function () {
|
||||||
// options.safeSetPref("accessibility.typeaheadfind.autostart", false);
|
// prefs.safeSet("accessibility.typeaheadfind.autostart", false);
|
||||||
// The above should be sufficient, but: https://bugzilla.mozilla.org/show_bug.cgi?id=348187
|
// The above should be sufficient, but: https://bugzilla.mozilla.org/show_bug.cgi?id=348187
|
||||||
options.safeSetPref("accessibility.typeaheadfind", false);
|
prefs.safeSet("accessibility.typeaheadfind", false);
|
||||||
|
|
||||||
options.add(["hlsearch", "hls"],
|
options.add(["hlsearch", "hls"],
|
||||||
"Highlight previous search pattern matches",
|
"Highlight previous search pattern matches",
|
||||||
|
|||||||
@@ -42,13 +42,13 @@ const JavaScript = Module("javascript", {
|
|||||||
|
|
||||||
let seen = isinstance(obj, ["Sandbox"]) ? set(JavaScript.magicalNames) : {};
|
let seen = isinstance(obj, ["Sandbox"]) ? set(JavaScript.magicalNames) : {};
|
||||||
let globals = values(toplevel && window === obj ? JavaScript.globalNames : []);
|
let globals = values(toplevel && window === obj ? JavaScript.globalNames : []);
|
||||||
for (let key in iterAll(globals, properties(obj, !toplevel)))
|
for (let key in iterAll(globals, properties(obj, !toplevel, true)))
|
||||||
if (!set.add(seen, key))
|
if (!set.add(seen, key))
|
||||||
yield key;
|
yield key;
|
||||||
|
|
||||||
// Properties aren't visible in an XPCNativeWrapper until
|
// Properties aren't visible in an XPCNativeWrapper until
|
||||||
// they're accessed.
|
// they're accessed.
|
||||||
for (let key in properties(this.getKey(obj, "wrappedJSObject"), !toplevel))
|
for (let key in properties(this.getKey(obj, "wrappedJSObject"), !toplevel, true))
|
||||||
try {
|
try {
|
||||||
if (key in obj && !set.has(seen, key))
|
if (key in obj && !set.has(seen, key))
|
||||||
yield key;
|
yield key;
|
||||||
|
|||||||
@@ -288,6 +288,8 @@ const Marks = Module("marks", {
|
|||||||
sanitizer: function () {
|
sanitizer: function () {
|
||||||
sanitizer.addItem("marks", {
|
sanitizer.addItem("marks", {
|
||||||
description: "Local and URL marks",
|
description: "Local and URL marks",
|
||||||
|
persistent: true,
|
||||||
|
contains: ["history"],
|
||||||
action: function (timespan, host) {
|
action: function (timespan, host) {
|
||||||
function matchhost(url) !host || util.isDomainURL(url, host);
|
function matchhost(url) !host || util.isDomainURL(url, host);
|
||||||
function match(marks) (k for ([k, v] in Iterator(marks)) if (timespan.contains(v.timestamp) && matchhost(v.location)));
|
function match(marks) (k for ([k, v] in Iterator(marks)) if (timespan.contains(v.timestamp) && matchhost(v.location)));
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ const Modes = Module("modes", {
|
|||||||
this.addMode("COMMAND_LINE", { char: "c", input: true,
|
this.addMode("COMMAND_LINE", { char: "c", input: true,
|
||||||
display: function () modes.extended & modes.OUTPUT_MULTILINE ? null : this.disp });
|
display: function () modes.extended & modes.OUTPUT_MULTILINE ? null : this.disp });
|
||||||
this.addMode("CARET", {}, {
|
this.addMode("CARET", {}, {
|
||||||
get pref() options.getPref("accessibility.browsewithcaret"),
|
get pref() prefs.get("accessibility.browsewithcaret"),
|
||||||
set pref(val) options.setPref("accessibility.browsewithcaret", val),
|
set pref(val) prefs.set("accessibility.browsewithcaret", val),
|
||||||
enter: function (stack) {
|
enter: function (stack) {
|
||||||
if (stack.pop && !this.pref)
|
if (stack.pop && !this.pref)
|
||||||
modes.pop();
|
modes.pop();
|
||||||
@@ -88,8 +88,8 @@ const Modes = Module("modes", {
|
|||||||
|
|
||||||
this.push(this.NORMAL, 0, {
|
this.push(this.NORMAL, 0, {
|
||||||
enter: function (stack, prev) {
|
enter: function (stack, prev) {
|
||||||
if (options.getPref("accessibility.browsewithcaret"))
|
if (prefs.get("accessibility.browsewithcaret"))
|
||||||
options.setPref("accessibility.browsewithcaret", false);
|
prefs.set("accessibility.browsewithcaret", false);
|
||||||
|
|
||||||
statusline.updateUrl();
|
statusline.updateUrl();
|
||||||
if (prev.mainMode.input || prev.mainMode.ownsFocus)
|
if (prev.mainMode.input || prev.mainMode.ownsFocus)
|
||||||
@@ -180,7 +180,7 @@ const Modes = Module("modes", {
|
|||||||
[m for (m in values(this._modeMap)) if (Object.keys(obj).every(function (k) obj[k] == (m[k] || false)))],
|
[m for (m in values(this._modeMap)) if (Object.keys(obj).every(function (k) obj[k] == (m[k] || false)))],
|
||||||
|
|
||||||
// show the current mode string in the command line
|
// show the current mode string in the command line
|
||||||
show: function () {
|
show: function show() {
|
||||||
let msg = null;
|
let msg = null;
|
||||||
if (options["showmode"])
|
if (options["showmode"])
|
||||||
msg = this._getModeMessage();
|
msg = this._getModeMessage();
|
||||||
@@ -189,7 +189,7 @@ const Modes = Module("modes", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// add/remove always work on the this._extended mode only
|
// add/remove always work on the this._extended mode only
|
||||||
add: function (mode) {
|
add: function add(mode) {
|
||||||
this._extended |= mode;
|
this._extended |= mode;
|
||||||
this.show();
|
this.show();
|
||||||
},
|
},
|
||||||
@@ -197,7 +197,7 @@ const Modes = Module("modes", {
|
|||||||
delayed: [],
|
delayed: [],
|
||||||
delay: function (callback, self) { this.delayed.push([callback, self]) },
|
delay: function (callback, self) { this.delayed.push([callback, self]) },
|
||||||
|
|
||||||
save: function (id, obj, prop) {
|
save: function save(id, obj, prop) {
|
||||||
if (!(id in this.boundProperties))
|
if (!(id in this.boundProperties))
|
||||||
for (let elem in array.iterValues(this._modeStack))
|
for (let elem in array.iterValues(this._modeStack))
|
||||||
elem.saved[id] = { obj: obj, prop: prop, value: obj[prop] };
|
elem.saved[id] = { obj: obj, prop: prop, value: obj[prop] };
|
||||||
@@ -206,7 +206,7 @@ const Modes = Module("modes", {
|
|||||||
|
|
||||||
// helper function to set both modes in one go
|
// helper function to set both modes in one go
|
||||||
// if silent == true, you also need to take care of the mode handling changes yourself
|
// if silent == true, you also need to take care of the mode handling changes yourself
|
||||||
set: function (mainMode, extendedMode, params, stack) {
|
set: function set(mainMode, extendedMode, params, stack) {
|
||||||
params = params || this.getMode(mainMode || this.main).params;
|
params = params || this.getMode(mainMode || this.main).params;
|
||||||
|
|
||||||
if (!stack && mainMode != null && this._modeStack.length > 1)
|
if (!stack && mainMode != null && this._modeStack.length > 1)
|
||||||
@@ -258,11 +258,18 @@ const Modes = Module("modes", {
|
|||||||
this.show();
|
this.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
push: function (mainMode, extendedMode, params) {
|
push: function push(mainMode, extendedMode, params) {
|
||||||
this.set(mainMode, extendedMode, params, { push: this.topOfStack });
|
this.set(mainMode, extendedMode, params, { push: this.topOfStack });
|
||||||
},
|
},
|
||||||
|
|
||||||
pop: function (mode) {
|
onCaretChange: function onPrefChange(value) {
|
||||||
|
if (!value && modes.main === modes.CARET)
|
||||||
|
modes.pop();
|
||||||
|
if (value && modes.main === modes.NORMAL)
|
||||||
|
modes.push(modes.CARET);
|
||||||
|
},
|
||||||
|
|
||||||
|
pop: function pop(mode) {
|
||||||
while (this._modeStack.length > 1 && this.main != mode) {
|
while (this._modeStack.length > 1 && this.main != mode) {
|
||||||
let a = this._modeStack.pop();
|
let a = this._modeStack.pop();
|
||||||
this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params,
|
this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params,
|
||||||
@@ -273,7 +280,7 @@ const Modes = Module("modes", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
replace: function (mode, oldMode) {
|
replace: function replace(mode, oldMode) {
|
||||||
while (oldMode && this._modeStack.length > 1 && this.main != oldMode)
|
while (oldMode && this._modeStack.length > 1 && this.main != oldMode)
|
||||||
this.pop();
|
this.pop();
|
||||||
|
|
||||||
@@ -282,14 +289,14 @@ const Modes = Module("modes", {
|
|||||||
this.push(mode);
|
this.push(mode);
|
||||||
},
|
},
|
||||||
|
|
||||||
reset: function () {
|
reset: function reset() {
|
||||||
if (this._modeStack.length == 1 && this.topOfStack.params.enter)
|
if (this._modeStack.length == 1 && this.topOfStack.params.enter)
|
||||||
this.topOfStack.params.enter({}, this.topOfStack);
|
this.topOfStack.params.enter({}, this.topOfStack);
|
||||||
while (this._modeStack.length > 1)
|
while (this._modeStack.length > 1)
|
||||||
this.pop();
|
this.pop();
|
||||||
},
|
},
|
||||||
|
|
||||||
remove: function (mode) {
|
remove: function remove(mode) {
|
||||||
if (this._extended & mode) {
|
if (this._extended & mode) {
|
||||||
this._extended &= ~mode;
|
this._extended &= ~mode;
|
||||||
this.show();
|
this.show();
|
||||||
@@ -342,13 +349,8 @@ const Modes = Module("modes", {
|
|||||||
}, desc));
|
}, desc));
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
options: function () {
|
prefs: function () {
|
||||||
options.observePref("accessibility.browsewithcaret", function (value) {
|
prefs.watch("accessibility.browsewithcaret", modes.closure.onCaretChange);
|
||||||
if (!value && modes.main === modes.CARET)
|
|
||||||
modes.pop();
|
|
||||||
if (value && modes.main === modes.NORMAL)
|
|
||||||
modes.push(modes.CARET);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ const Option = Class("Option", {
|
|||||||
dactyl.trapErrors(function () this.value = this.value, this);
|
dactyl.trapErrors(function () this.value = this.value, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
get isDefault() this.stringify(this.value) === this.stringify(this.defaultValue),
|
get isDefault() this.stringValue === this.stringDefaultValue,
|
||||||
|
|
||||||
/** @property {value} The option's global value. @see #scope */
|
/** @property {value} The option's global value. @see #scope */
|
||||||
get globalValue() options.store.get(this.name, {}).value,
|
get globalValue() options.store.get(this.name, {}).value,
|
||||||
@@ -174,6 +174,11 @@ const Option = Class("Option", {
|
|||||||
get value() this.get(),
|
get value() this.get(),
|
||||||
set value(val) this.set(val),
|
set value(val) this.set(val),
|
||||||
|
|
||||||
|
get stringValue() this.stringify(this.value),
|
||||||
|
set stringValue(value) this.value = this.parse(value),
|
||||||
|
|
||||||
|
get stringDefaultValue() this.stringify(this.defaultValue),
|
||||||
|
|
||||||
getKey: function (key) undefined,
|
getKey: function (key) undefined,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -610,28 +615,6 @@ const Options = Module("options", {
|
|||||||
this.needInit = [];
|
this.needInit = [];
|
||||||
this._options = [];
|
this._options = [];
|
||||||
this._optionMap = {};
|
this._optionMap = {};
|
||||||
this._prefContexts = [];
|
|
||||||
|
|
||||||
for (let [, pref] in Iterator(this.allPrefs(Options.OLD_SAVED))) {
|
|
||||||
let saved = Options.SAVED + pref.substr(Options.OLD_SAVED.length);
|
|
||||||
if (!this.getPref(saved))
|
|
||||||
this.setPref(saved, this.getPref(pref));
|
|
||||||
this.resetPref(pref);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Host application preferences which need to be changed to work well with
|
|
||||||
//
|
|
||||||
|
|
||||||
// Work around the popup blocker
|
|
||||||
// TODO: Make this work like safeSetPref
|
|
||||||
var popupAllowedEvents = this._loadPreference("dom.popup_allowed_events", "change click dblclick mouseup reset submit");
|
|
||||||
if (!/keypress/.test(popupAllowedEvents)) {
|
|
||||||
this._storePreference("dom.popup_allowed_events", popupAllowedEvents + " keypress");
|
|
||||||
dactyl.registerObserver("shutdown", function () {
|
|
||||||
if (this._loadPreference("dom.popup_allowed_events", "") == popupAllowedEvents + " keypress")
|
|
||||||
this._storePreference("dom.popup_allowed_events", popupAllowedEvents);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
storage.newMap("options", { store: false });
|
storage.newMap("options", { store: false });
|
||||||
storage.addObserver("options", function optionObserver(key, event, option) {
|
storage.addObserver("options", function optionObserver(key, event, option) {
|
||||||
@@ -640,34 +623,12 @@ const Options = Module("options", {
|
|||||||
if (event == "change" && opt)
|
if (event == "change" && opt)
|
||||||
opt.set(opt.globalValue, Option.SCOPE_GLOBAL, true);
|
opt.set(opt.globalValue, Option.SCOPE_GLOBAL, true);
|
||||||
}, window);
|
}, window);
|
||||||
|
|
||||||
this._branch = services.get("pref").getBranch("").QueryInterface(Ci.nsIPrefBranch2);
|
|
||||||
this._branch.addObserver("", this, false);
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function () {
|
|
||||||
this._branch.removeObserver("", this);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @property {Iterator(Option)} @private */
|
/** @property {Iterator(Option)} @private */
|
||||||
__iterator__: function ()
|
__iterator__: function ()
|
||||||
values(this._options.sort(function (a, b) String.localeCompare(a.name, b.name))),
|
values(this._options.sort(function (a, b) String.localeCompare(a.name, b.name))),
|
||||||
|
|
||||||
observe: function (subject, topic, data) {
|
|
||||||
if (topic == "nsPref:changed") {
|
|
||||||
let observers = this._observers[data];
|
|
||||||
if (observers) {
|
|
||||||
let value = options.getPref(data, false);
|
|
||||||
this._observers[data] = observers.filter(function (callback) {
|
|
||||||
if (!callback.get())
|
|
||||||
return false;
|
|
||||||
dactyl.trapErrors(callback.get(), null, value);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new option.
|
* Adds a new option.
|
||||||
*
|
*
|
||||||
@@ -705,13 +666,18 @@ const Options = Module("options", {
|
|||||||
this.__defineSetter__(name, function (value) { this._optionMap[name].value = value; });
|
this.__defineSetter__(name, function (value) { this._optionMap[name].value = value; });
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
allPrefs: deprecated("Please use prefs.getNames", function allPrefs() prefs.getNames.apply(prefs, arguments)),
|
||||||
* Returns the names of all preferences.
|
getPref: deprecated("Please use prefs.get", function getPref() prefs.get.apply(prefs, arguments)),
|
||||||
*
|
invertPref: deprecated("Please use prefs.invert", function invertPref() prefs.invert.apply(prefs, arguments)),
|
||||||
* @param {string} branch The branch in which to search preferences.
|
listPrefs: deprecated("Please use prefs.list", function listPrefs() { commandline.commandOutput(prefs.list.apply(prefs, arguments)) }),
|
||||||
* @default ""
|
observePref: deprecated("Please use prefs.observe", function observePref() prefs.observe.apply(prefs, arguments)),
|
||||||
*/
|
popContext: deprecated("Please use prefs.popContext", function popContext() prefs.popContext.apply(prefs, arguments)),
|
||||||
allPrefs: function (branch) services.get("pref").getChildList(branch || "", { value: 0 }),
|
pushContext: deprecated("Please use prefs.pushContext", function pushContext() prefs.pushContext.apply(prefs, arguments)),
|
||||||
|
resetPref: deprecated("Please use prefs.reset", function resetPref() prefs.reset.apply(prefs, arguments)),
|
||||||
|
safeResetPref: deprecated("Please use prefs.safeReset", function safeResetPref() prefs.safeReset.apply(prefs, arguments)),
|
||||||
|
safeSetPref: deprecated("Please use prefs.safeSet", function safeSetPref() prefs.safeSet.apply(prefs, arguments)),
|
||||||
|
setPref: deprecated("Please use prefs.set", function setPref() prefs.set.apply(prefs, arguments)),
|
||||||
|
withContext: deprecated("Please use prefs.withContext", function withContext() prefs.withContext.apply(prefs, arguments)),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the option with <b>name</b> in the specified <b>scope</b>.
|
* Returns the option with <b>name</b> in the specified <b>scope</b>.
|
||||||
@@ -748,7 +714,7 @@ const Options = Module("options", {
|
|||||||
let option = {
|
let option = {
|
||||||
isDefault: opt.isDefault,
|
isDefault: opt.isDefault,
|
||||||
name: opt.name,
|
name: opt.name,
|
||||||
default: opt.stringify(opt.defaultValue),
|
default: opt.stringDefaultValue,
|
||||||
pre: "\u00a0\u00a0", // Unicode nonbreaking space.
|
pre: "\u00a0\u00a0", // Unicode nonbreaking space.
|
||||||
value: <></>
|
value: <></>
|
||||||
};
|
};
|
||||||
@@ -764,7 +730,7 @@ const Options = Module("options", {
|
|||||||
option.default = (option.default ? "" : "no") + opt.name;
|
option.default = (option.default ? "" : "no") + opt.name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
option.value = <>={template.highlight(opt.stringify(opt.value))}</>;
|
option.value = <>={template.highlight(opt.stringValue)}</>;
|
||||||
yield option;
|
yield option;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -772,60 +738,6 @@ const Options = Module("options", {
|
|||||||
commandline.commandOutput(template.options("Options", opts()));
|
commandline.commandOutput(template.options("Options", opts()));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists all preferences matching <b>filter</b> or only those with
|
|
||||||
* changed values if <b>onlyNonDefault</b> is specified.
|
|
||||||
*
|
|
||||||
* @param {boolean} onlyNonDefault Limit the list to prefs with a
|
|
||||||
* non-default value.
|
|
||||||
* @param {string} filter The list filter. A null filter lists all
|
|
||||||
* prefs.
|
|
||||||
* @optional
|
|
||||||
*/
|
|
||||||
listPrefs: function (onlyNonDefault, filter) {
|
|
||||||
if (!filter)
|
|
||||||
filter = "";
|
|
||||||
|
|
||||||
let prefArray = options.allPrefs();
|
|
||||||
prefArray.sort();
|
|
||||||
function prefs() {
|
|
||||||
for (let [, pref] in Iterator(prefArray)) {
|
|
||||||
let userValue = services.get("pref").prefHasUserValue(pref);
|
|
||||||
if (onlyNonDefault && !userValue || pref.indexOf(filter) == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let value = options.getPref(pref);
|
|
||||||
|
|
||||||
let option = {
|
|
||||||
isDefault: !userValue,
|
|
||||||
default: options._loadPreference(pref, null, true),
|
|
||||||
value: <>={template.highlight(value, true, 100)}</>,
|
|
||||||
name: pref,
|
|
||||||
pre: "\u00a0\u00a0" // Unicode nonbreaking space.
|
|
||||||
};
|
|
||||||
|
|
||||||
yield option;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
commandline.commandOutput(
|
|
||||||
template.options(config.host + " Options", prefs()));
|
|
||||||
},
|
|
||||||
|
|
||||||
_observers: Class.memoize(function () ({})),
|
|
||||||
/**
|
|
||||||
* Adds a new preference observer for the given preference.
|
|
||||||
*
|
|
||||||
* @param {string} pref The preference to observe.
|
|
||||||
* @param {function(object)} callback The callback, called with the
|
|
||||||
* new value of the preference whenever it changes.
|
|
||||||
*/
|
|
||||||
observePref: function (pref, callback, weak) {
|
|
||||||
if (!this._observers[pref])
|
|
||||||
this._observers[pref] = [];
|
|
||||||
this._observers[pref].push(weak ? Cu.getWeakReference(callback) : { get: function () callback });
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a :set command's argument string.
|
* Parses a :set command's argument string.
|
||||||
*
|
*
|
||||||
@@ -895,204 +807,8 @@ const Options = Module("options", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/** @property {Object} The options store. */
|
/** @property {Object} The options store. */
|
||||||
get store() storage.options,
|
get store() storage.options
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the preference <b>name</b>.
|
|
||||||
*
|
|
||||||
* @param {string} name The preference name.
|
|
||||||
* @param {value} forcedDefault The default value for this
|
|
||||||
* preference. Used for internal dactyl preferences.
|
|
||||||
*/
|
|
||||||
getPref: function (name, forcedDefault) {
|
|
||||||
return this._loadPreference(name, forcedDefault);
|
|
||||||
},
|
|
||||||
|
|
||||||
_checkPrefSafe: function (name, message, value) {
|
|
||||||
let curval = this._loadPreference(name, null, false);
|
|
||||||
if (arguments.length > 2 && curval === value)
|
|
||||||
return;
|
|
||||||
let defval = this._loadPreference(name, null, true);
|
|
||||||
let saved = this._loadPreference(Options.SAVED + name);
|
|
||||||
|
|
||||||
if (saved == null && curval != defval || curval != saved) {
|
|
||||||
let msg = "Warning: setting preference " + name + ", but it's changed from its default value.";
|
|
||||||
if (message)
|
|
||||||
msg += " " + message;
|
|
||||||
dactyl.echomsg(msg);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the preference <b>name</b> to </b>value</b> but warns the user
|
|
||||||
* if the value is changed from its default.
|
|
||||||
*
|
|
||||||
* @param {string} name The preference name.
|
|
||||||
* @param {value} value The new preference value.
|
|
||||||
*/
|
|
||||||
safeResetPref: function (name, message) {
|
|
||||||
this._checkPrefSafe(name, message);
|
|
||||||
this.resetPref(name);
|
|
||||||
this.resetPref(Options.SAVED + name);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the preference <b>name</b> to </b>value</b> but warns the user
|
|
||||||
* if the value is changed from its default.
|
|
||||||
*
|
|
||||||
* @param {string} name The preference name.
|
|
||||||
* @param {value} value The new preference value.
|
|
||||||
*/
|
|
||||||
safeSetPref: function (name, value, message) {
|
|
||||||
this._checkPrefSafe(name, message, value);
|
|
||||||
this._storePreference(name, value);
|
|
||||||
this._storePreference(Options.SAVED + name, value);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the preference <b>name</b> to </b>value</b>.
|
|
||||||
*
|
|
||||||
* @param {string} name The preference name.
|
|
||||||
* @param {value} value The new preference value.
|
|
||||||
*/
|
|
||||||
setPref: function (name, value) {
|
|
||||||
this._storePreference(name, value);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the preference <b>name</b> to its default value.
|
|
||||||
*
|
|
||||||
* @param {string} name The preference name.
|
|
||||||
*/
|
|
||||||
resetPref: function (name) {
|
|
||||||
try {
|
|
||||||
services.get("pref").clearUserPref(name);
|
|
||||||
}
|
|
||||||
catch (e) {} // ignore - thrown if not a user set value
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles the value of the boolean preference <b>name</b>.
|
|
||||||
*
|
|
||||||
* @param {string} name The preference name.
|
|
||||||
*/
|
|
||||||
invertPref: function (name) {
|
|
||||||
if (services.get("pref").getPrefType(name) == Ci.nsIPrefBranch.PREF_BOOL)
|
|
||||||
this.setPref(name, !this.getPref(name));
|
|
||||||
else
|
|
||||||
dactyl.echoerr("E488: Trailing characters: " + name + "!");
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes a new preference context onto the context stack.
|
|
||||||
*
|
|
||||||
* @see #withContext
|
|
||||||
*/
|
|
||||||
pushContext: function () {
|
|
||||||
this._prefContexts.push({});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pops the top preference context from the stack.
|
|
||||||
*
|
|
||||||
* @see #withContext
|
|
||||||
*/
|
|
||||||
popContext: function () {
|
|
||||||
for (let [k, v] in Iterator(this._prefContexts.pop()))
|
|
||||||
this._storePreference(k, v);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes <b>func</b> with a new preference context. When <b>func</b>
|
|
||||||
* returns, the context is popped and any preferences set via
|
|
||||||
* {@link #setPref} or {@link #invertPref} are restored to their
|
|
||||||
* previous values.
|
|
||||||
*
|
|
||||||
* @param {function} func The function to call.
|
|
||||||
* @param {Object} func The 'this' object with which to call <b>func</b>
|
|
||||||
* @see #pushContext
|
|
||||||
* @see #popContext
|
|
||||||
*/
|
|
||||||
withContext: function (func, self) {
|
|
||||||
try {
|
|
||||||
this.pushContext();
|
|
||||||
return func.call(self);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
this.popContext();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_storePreference: function (name, value) {
|
|
||||||
if (this._prefContexts.length) {
|
|
||||||
let val = this._loadPreference(name, null);
|
|
||||||
if (val != null)
|
|
||||||
this._prefContexts[this._prefContexts.length - 1][name] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
let type = services.get("pref").getPrefType(name);
|
|
||||||
switch (typeof value) {
|
|
||||||
case "string":
|
|
||||||
if (type == Ci.nsIPrefBranch.PREF_INVALID || type == Ci.nsIPrefBranch.PREF_STRING) {
|
|
||||||
let supportString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
|
|
||||||
supportString.data = value;
|
|
||||||
services.get("pref").setComplexValue(name, Ci.nsISupportsString, supportString);
|
|
||||||
}
|
|
||||||
else if (type == Ci.nsIPrefBranch.PREF_INT)
|
|
||||||
dactyl.echoerr("E521: Number required after =: " + name + "=" + value);
|
|
||||||
else
|
|
||||||
dactyl.echoerr("E474: Invalid argument: " + name + "=" + value);
|
|
||||||
break;
|
|
||||||
case "number":
|
|
||||||
if (type == Ci.nsIPrefBranch.PREF_INVALID || type == Ci.nsIPrefBranch.PREF_INT)
|
|
||||||
services.get("pref").setIntPref(name, value);
|
|
||||||
else
|
|
||||||
dactyl.echoerr("E474: Invalid argument: " + name + "=" + value);
|
|
||||||
break;
|
|
||||||
case "boolean":
|
|
||||||
if (type == Ci.nsIPrefBranch.PREF_INVALID || type == Ci.nsIPrefBranch.PREF_BOOL)
|
|
||||||
services.get("pref").setBoolPref(name, value);
|
|
||||||
else if (type == Ci.nsIPrefBranch.PREF_INT)
|
|
||||||
dactyl.echoerr("E521: Number required after =: " + name + "=" + value);
|
|
||||||
else
|
|
||||||
dactyl.echoerr("E474: Invalid argument: " + name + "=" + value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dactyl.echoerr("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_loadPreference: function (name, forcedDefault, defaultBranch) {
|
|
||||||
let defaultValue = null; // XXX
|
|
||||||
if (forcedDefault != null) // this argument sets defaults for non-user settable options (like extensions.history.comp_history)
|
|
||||||
defaultValue = forcedDefault;
|
|
||||||
|
|
||||||
let branch = defaultBranch ? services.get("pref").getDefaultBranch("") : services.get("pref");
|
|
||||||
let type = services.get("pref").getPrefType(name);
|
|
||||||
try {
|
|
||||||
switch (type) {
|
|
||||||
case Ci.nsIPrefBranch.PREF_STRING:
|
|
||||||
let value = branch.getComplexValue(name, Ci.nsISupportsString).data;
|
|
||||||
// try in case it's a localized string (will throw an exception if not)
|
|
||||||
if (!services.get("pref").prefIsLocked(name) && !services.get("pref").prefHasUserValue(name) &&
|
|
||||||
RegExp("chrome://.+/locale/.+\\.properties").test(value))
|
|
||||||
value = branch.getComplexValue(name, Ci.nsIPrefLocalizedString).data;
|
|
||||||
return value;
|
|
||||||
case Ci.nsIPrefBranch.PREF_INT:
|
|
||||||
return branch.getIntPref(name);
|
|
||||||
case Ci.nsIPrefBranch.PREF_BOOL:
|
|
||||||
return branch.getBoolPref(name);
|
|
||||||
default:
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
SAVED: "extensions.dactyl.saved.",
|
|
||||||
OLD_SAVED: "dactyl.saved."
|
|
||||||
}, {
|
}, {
|
||||||
commands: function () {
|
commands: function () {
|
||||||
function setAction(args, modifiers) {
|
function setAction(args, modifiers) {
|
||||||
@@ -1121,16 +837,16 @@ const Options = Module("options", {
|
|||||||
commandline.input("Warning: Resetting all preferences may make " + config.host + " unusable. Continue (yes/[no]): ",
|
commandline.input("Warning: Resetting all preferences may make " + config.host + " unusable. Continue (yes/[no]): ",
|
||||||
function (resp) {
|
function (resp) {
|
||||||
if (resp == "yes")
|
if (resp == "yes")
|
||||||
for (let pref in values(options.allPrefs()))
|
for (let pref in values(prefs.getNames()))
|
||||||
options.resetPref(pref);
|
prefs.reset(pref);
|
||||||
},
|
},
|
||||||
{ promptHighlight: "WarningMsg" });
|
{ promptHighlight: "WarningMsg" });
|
||||||
else if (name == "all")
|
else if (name == "all")
|
||||||
options.listPrefs(onlyNonDefault, "");
|
command.commandOutput(prefs.list(onlyNonDefault, ""));
|
||||||
else if (reset)
|
else if (reset)
|
||||||
options.resetPref(name);
|
prefs.reset(name);
|
||||||
else if (invertBoolean)
|
else if (invertBoolean)
|
||||||
options.invertPref(name);
|
prefs.toggle(name);
|
||||||
else if (valueGiven) {
|
else if (valueGiven) {
|
||||||
if (value == undefined)
|
if (value == undefined)
|
||||||
value = "";
|
value = "";
|
||||||
@@ -1140,10 +856,10 @@ const Options = Module("options", {
|
|||||||
value = false;
|
value = false;
|
||||||
else if (/^\d+$/.test(value))
|
else if (/^\d+$/.test(value))
|
||||||
value = parseInt(value, 10);
|
value = parseInt(value, 10);
|
||||||
options.setPref(name, value);
|
prefs.set(name, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
options.listPrefs(onlyNonDefault, name);
|
command.commandOutput(prefs.list(onlyNonDefault, ""));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1208,8 +924,8 @@ const Options = Module("options", {
|
|||||||
context.advance(filter.length);
|
context.advance(filter.length);
|
||||||
filter = filter.substr(0, filter.length - 1);
|
filter = filter.substr(0, filter.length - 1);
|
||||||
context.completions = [
|
context.completions = [
|
||||||
[options._loadPreference(filter, null, false), "Current Value"],
|
[prefs.get(filter), "Current Value"],
|
||||||
[options._loadPreference(filter, null, true), "Default Value"]
|
[prefs.getDefault(filter), "Default Value"]
|
||||||
].filter(function ([k]) k != null && k.length < 200);
|
].filter(function ([k]) k != null && k.length < 200);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1241,8 +957,8 @@ const Options = Module("options", {
|
|||||||
context.fork("default", 0, this, function (context) {
|
context.fork("default", 0, this, function (context) {
|
||||||
context.title = ["Extra Completions"];
|
context.title = ["Extra Completions"];
|
||||||
context.completions = [
|
context.completions = [
|
||||||
[option.value, "Current value"],
|
[option.stringValue, "Current value"],
|
||||||
[option.defaultValue, "Default value"]
|
[option.stringValue, "Default value"]
|
||||||
].filter(function (f) f[0] !== "" && String(f[0]).length < 200);
|
].filter(function (f) f[0] !== "" && String(f[0]).length < 200);
|
||||||
context.quote = ["", util.identity, ""];
|
context.quote = ["", util.identity, ""];
|
||||||
});
|
});
|
||||||
@@ -1359,7 +1075,7 @@ const Options = Module("options", {
|
|||||||
{
|
{
|
||||||
command: this.name,
|
command: this.name,
|
||||||
literalArg: [opt.type == "boolean" ? (opt.value ? "" : "no") + opt.name
|
literalArg: [opt.type == "boolean" ? (opt.value ? "" : "no") + opt.name
|
||||||
: opt.name + "=" + opt.stringify(opt.value)]
|
: opt.name + "=" + opt.stringValue]
|
||||||
}
|
}
|
||||||
for (opt in options)
|
for (opt in options)
|
||||||
if (!opt.getter && !opt.isDefault && (opt.scope & Option.SCOPE_GLOBAL))
|
if (!opt.getter && !opt.isDefault && (opt.scope & Option.SCOPE_GLOBAL))
|
||||||
@@ -1491,18 +1207,9 @@ const Options = Module("options", {
|
|||||||
if (res)
|
if (res)
|
||||||
context.completions = res;
|
context.completions = res;
|
||||||
};
|
};
|
||||||
|
|
||||||
completion.preference = function preference(context) {
|
|
||||||
context.anchored = false;
|
|
||||||
context.title = [config.host + " Preference", "Value"];
|
|
||||||
context.keys = { text: function (item) item, description: function (item) options.getPref(item) };
|
|
||||||
context.completions = options.allPrefs();
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
javascript: function () {
|
javascript: function () {
|
||||||
JavaScript.setCompleter(this.get, [function () ([o.name, o.description] for (o in options))]);
|
JavaScript.setCompleter(this.get, [function () ([o.name, o.description] for (o in options))]);
|
||||||
JavaScript.setCompleter([this.getPref, this.safeSetPref, this.setPref, this.resetPref, this.invertPref],
|
|
||||||
[function (context) (context.anchored=false, options.allPrefs().map(function (pref) [pref, ""]))]);
|
|
||||||
},
|
},
|
||||||
sanitizer: function () {
|
sanitizer: function () {
|
||||||
sanitizer.addItem("options", {
|
sanitizer.addItem("options", {
|
||||||
|
|||||||
@@ -993,7 +993,7 @@ const Tabs = Module("tabs", {
|
|||||||
if (value == 0)
|
if (value == 0)
|
||||||
tabs.tabStyle.enabled = true;
|
tabs.tabStyle.enabled = true;
|
||||||
else {
|
else {
|
||||||
options.safeSetPref("browser.tabs.autoHide", value == 1,
|
prefs.safeSet("browser.tabs.autoHide", value == 1,
|
||||||
"See 'showtabline' option.");
|
"See 'showtabline' option.");
|
||||||
tabs.tabStyle.enabled = false;
|
tabs.tabStyle.enabled = false;
|
||||||
}
|
}
|
||||||
@@ -1025,7 +1025,7 @@ const Tabs = Module("tabs", {
|
|||||||
];
|
];
|
||||||
options.add(["activate", "act"],
|
options.add(["activate", "act"],
|
||||||
"Define when tabs are automatically activated",
|
"Define when tabs are automatically activated",
|
||||||
"stringlist", [g[0] for (g in values(activateGroups.slice(1))) if (!g[2] || !options.getPref("browser.tabs." + g[2]))].join(","),
|
"stringlist", [g[0] for (g in values(activateGroups.slice(1))) if (!g[2] || !prefs.get("browser.tabs." + g[2]))].join(","),
|
||||||
{
|
{
|
||||||
completer: function (context) activateGroups,
|
completer: function (context) activateGroups,
|
||||||
has: Option.has.toggleAll,
|
has: Option.has.toggleAll,
|
||||||
@@ -1033,7 +1033,7 @@ const Tabs = Module("tabs", {
|
|||||||
let valueSet = set(newValues);
|
let valueSet = set(newValues);
|
||||||
for (let group in values(activateGroups))
|
for (let group in values(activateGroups))
|
||||||
if (group[2])
|
if (group[2])
|
||||||
options.safeSetPref("browser.tabs." + group[2],
|
prefs.safeSet("browser.tabs." + group[2],
|
||||||
!(valueSet["all"] ^ valueSet[group[0]]),
|
!(valueSet["all"] ^ valueSet[group[0]]),
|
||||||
"See the 'activate' option");
|
"See the 'activate' option");
|
||||||
return newValues;
|
return newValues;
|
||||||
@@ -1072,9 +1072,9 @@ const Tabs = Module("tabs", {
|
|||||||
restriction = 2;
|
restriction = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.safeSetPref("browser.link.open_newwindow", open,
|
prefs.safeSet("browser.link.open_newwindow", open,
|
||||||
"See 'popups' option.");
|
"See 'popups' option.");
|
||||||
options.safeSetPref("browser.link.open_newwindow.restriction", restriction,
|
prefs.safeSet("browser.link.open_newwindow.restriction", restriction,
|
||||||
"See 'popups' option.");
|
"See 'popups' option.");
|
||||||
return values;
|
return values;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1174,6 +1174,16 @@
|
|||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<tags>'sanitizeshutdown' 'ss'</tags>
|
||||||
|
<spec>'sanitizeshutdown'</spec>
|
||||||
|
<type>stringlist</type>
|
||||||
|
<default/>
|
||||||
|
<description>
|
||||||
|
<p>The items to sanitize automatically at shutdown.</p>
|
||||||
|
</description>
|
||||||
|
</item>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>'sts' 'sanitizetimespan'</tags>
|
<tags>'sts' 'sanitizetimespan'</tags>
|
||||||
<spec>'sanitizetimespan' 'sts'</spec>
|
<spec>'sanitizetimespan' 'sts'</spec>
|
||||||
|
|||||||
@@ -129,7 +129,11 @@ defineModule.modules = [];
|
|||||||
defineModule.times = { all: 0 };
|
defineModule.times = { all: 0 };
|
||||||
defineModule.time = function time(major, minor, func, self) {
|
defineModule.time = function time(major, minor, func, self) {
|
||||||
let time = Date.now();
|
let time = Date.now();
|
||||||
let res = func.apply(self, Array.slice(arguments, 4));
|
try {
|
||||||
|
var res = func.apply(self, Array.slice(arguments, 4));
|
||||||
|
} catch (e) {
|
||||||
|
loaded.util && util.reportError(e);
|
||||||
|
}
|
||||||
let delta = Date.now() - time;
|
let delta = Date.now() - time;
|
||||||
defineModule.times.all += delta;
|
defineModule.times.all += delta;
|
||||||
defineModule.times[major] = (defineModule.times[major] || 0) + delta;
|
defineModule.times[major] = (defineModule.times[major] || 0) + delta;
|
||||||
@@ -157,7 +161,7 @@ function require(obj, name, from) {
|
|||||||
if (loaded.util)
|
if (loaded.util)
|
||||||
util.reportError(e);
|
util.reportError(e);
|
||||||
else
|
else
|
||||||
defineModule.dump(" " + e.fileName + ":" + e.lineNumber + ": " + e +"\n");
|
defineModule.dump(" " + (e.filename || e.fileName) + ":" + e.lineNumber + ": " + e +"\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +173,8 @@ defineModule("base", {
|
|||||||
"call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule",
|
"call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule",
|
||||||
"endModule", "forEach", "isArray", "isGenerator", "isinstance",
|
"endModule", "forEach", "isArray", "isGenerator", "isinstance",
|
||||||
"isObject", "isString", "isSubclass", "iter", "iterAll", "keys",
|
"isObject", "isString", "isSubclass", "iter", "iterAll", "keys",
|
||||||
"memoize", "properties", "requiresMainThread", "set", "update", "values"
|
"memoize", "properties", "requiresMainThread", "set", "update", "values",
|
||||||
|
"withCallerGlobal"
|
||||||
],
|
],
|
||||||
use: ["services", "util"]
|
use: ["services", "util"]
|
||||||
});
|
});
|
||||||
@@ -217,7 +222,7 @@ function properties(obj, prototypes, debugger_) {
|
|||||||
|
|
||||||
for (; obj; obj = prototypes && prototype(obj)) {
|
for (; obj; obj = prototypes && prototype(obj)) {
|
||||||
try {
|
try {
|
||||||
if (!debugger_ || !services.get("debugger").isOn)
|
if (sandbox.Object.getOwnPropertyNames || !debugger_ || !services.get("debugger").isOn)
|
||||||
var iter = values(Object.getOwnPropertyNames(obj));
|
var iter = values(Object.getOwnPropertyNames(obj));
|
||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
@@ -588,6 +593,21 @@ function requiresMainThread(callback)
|
|||||||
mainThread.dispatch(Runnable(this, callback, arguments), mainThread.DISPATCH_NORMAL);
|
mainThread.dispatch(Runnable(this, callback, arguments), mainThread.DISPATCH_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sandbox = Cu.Sandbox(this);
|
||||||
|
sandbox.__proto__ = this;
|
||||||
|
/**
|
||||||
|
* Wraps a function so that when called, the global object of the caller
|
||||||
|
* is prepended to its arguments.
|
||||||
|
*/
|
||||||
|
// Hack to get around lack of access to caller in strict mode.
|
||||||
|
const withCallerGlobal = Cu.evalInSandbox(<![CDATA[
|
||||||
|
(function withCallerGlobal(fn)
|
||||||
|
function withCallerGlobal_wrapped()
|
||||||
|
fn.apply(this,
|
||||||
|
[Class.objectGlobal(withCallerGlobal_wrapped.caller)]
|
||||||
|
.concat(Array.slice(arguments))))
|
||||||
|
]]>, Cu.Sandbox(this), "1.8");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an object with the properties of another object. Getters
|
* Updates an object with the properties of another object. Getters
|
||||||
* and setters are copied as expected. Moreover, any function
|
* and setters are copied as expected. Moreover, any function
|
||||||
@@ -895,6 +915,8 @@ let StructBase = Class("StructBase", Array, {
|
|||||||
|
|
||||||
clone: function clone() this.constructor.apply(null, this.slice()),
|
clone: function clone() this.constructor.apply(null, this.slice()),
|
||||||
|
|
||||||
|
toString: function () Class.prototype.toString.apply(this, arguments),
|
||||||
|
|
||||||
// Iterator over our named members
|
// Iterator over our named members
|
||||||
__iterator__: function () {
|
__iterator__: function () {
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver),
|
|||||||
.map(function (s) bookmarks[s]),
|
.map(function (s) bookmarks[s]),
|
||||||
|
|
||||||
_deleteBookmark: function deleteBookmark(id) {
|
_deleteBookmark: function deleteBookmark(id) {
|
||||||
let result = this.bookmarks[item.id] || null;
|
let result = this.bookmarks[id] || null;
|
||||||
delete this.bookmarks[id];
|
delete this.bookmarks[id];
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,11 +17,12 @@
|
|||||||
Components.utils.import("resource://dactyl/base.jsm");
|
Components.utils.import("resource://dactyl/base.jsm");
|
||||||
defineModule("sanitizer", {
|
defineModule("sanitizer", {
|
||||||
exports: ["Range", "Sanitizer", "sanitizer"],
|
exports: ["Range", "Sanitizer", "sanitizer"],
|
||||||
require: ["services", "storage", "util"]
|
require: ["services", "storage", "template", "util"]
|
||||||
});
|
});
|
||||||
|
|
||||||
let tmp = {};
|
let tmp = {};
|
||||||
services.get("subscriptLoader").loadSubScript("chrome://browser/content/sanitize.js", tmp);
|
services.get("subscriptLoader").loadSubScript("chrome://browser/content/sanitize.js", tmp);
|
||||||
|
tmp.Sanitizer.prototype.__proto__ = Class.prototype;
|
||||||
|
|
||||||
const Range = Struct("min", "max");
|
const Range = Struct("min", "max");
|
||||||
Range.prototype.contains = function (date)
|
Range.prototype.contains = function (date)
|
||||||
@@ -29,32 +30,67 @@ Range.prototype.contains = function (date)
|
|||||||
Range.prototype.__defineGetter__("isEternity", function () this.max == null && this.min == null);
|
Range.prototype.__defineGetter__("isEternity", function () this.max == null && this.min == null);
|
||||||
Range.prototype.__defineGetter__("isSession", function () this.max == null && this.min == sanitizer.sessionStart);
|
Range.prototype.__defineGetter__("isSession", function () this.max == null && this.min == sanitizer.sessionStart);
|
||||||
|
|
||||||
|
const Item = Class("Item", {
|
||||||
|
init: function (name) {
|
||||||
|
this.name = name;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Hack for completion:
|
||||||
|
"0": Class.Property({ get: function () this.name }),
|
||||||
|
"1": Class.Property({ get: function () this.description }),
|
||||||
|
|
||||||
|
get cpdPref() (this.builtin ? "" : Item.PREFIX) + Item.BRANCH + Sanitizer.argToPref(this.name),
|
||||||
|
get shutdownPref() (this.builtin ? "" : Item.PREFIX) + Item.SHUTDOWN_BRANCH + Sanitizer.argToPref(this.name),
|
||||||
|
get cpd() prefs.get(this.cpdPref),
|
||||||
|
get shutdown() prefs.get(this.shutdownPref),
|
||||||
|
|
||||||
|
shouldSanitize: function (shutdown) (!shutdown || this.builtin || this.persistent) &&
|
||||||
|
prefs.get(shutdown ? this.shutdownPref : this.pref)
|
||||||
|
}, {
|
||||||
|
PREFIX: "extensions.dactyl.",
|
||||||
|
BRANCH: "privacy.cpd.",
|
||||||
|
SHUTDOWN_BRANCH: "privacy.clearOnShutdown."
|
||||||
|
});
|
||||||
|
|
||||||
const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference], tmp.Sanitizer), {
|
const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference], tmp.Sanitizer), {
|
||||||
sessionStart: Date.now() * 1000,
|
sessionStart: Date.now() * 1000,
|
||||||
|
|
||||||
init: function () {
|
init: function () {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
util.addObserver(this);
|
||||||
|
|
||||||
services.add("contentprefs", "@mozilla.org/content-pref/service;1", Ci.nsIContentPrefService);
|
services.add("contentprefs", "@mozilla.org/content-pref/service;1", Ci.nsIContentPrefService);
|
||||||
services.add("cookies", "@mozilla.org/cookiemanager;1", [Ci.nsICookieManager, Ci.nsICookieManager2,
|
services.add("cookies", "@mozilla.org/cookiemanager;1", [Ci.nsICookieManager, Ci.nsICookieManager2,
|
||||||
Ci.nsICookieService]);
|
Ci.nsICookieService]);
|
||||||
services.add("loginmanager", "@mozilla.org/login-manager;1", Ci.nsILoginManager);
|
services.add("loginmanager", "@mozilla.org/login-manager;1", Ci.nsILoginManager);
|
||||||
services.add("permissions", "@mozilla.org/permissionmanager;1", Ci.nsIPermissionManager);
|
services.add("permissions", "@mozilla.org/permissionmanager;1", Ci.nsIPermissionManager);
|
||||||
|
|
||||||
this.itemOverrides = {};
|
this.itemMap = {
|
||||||
this.itemDescriptions = {
|
__iterator__: function () {
|
||||||
all: "Sanitize all items",
|
// For platforms without getOwnPropertyNames :(
|
||||||
// Builtin items
|
for (let p in properties(this))
|
||||||
cache: "Cache",
|
if (p !== "__iterator__")
|
||||||
downloads: "Download history",
|
yield this[p]
|
||||||
formdata: "Saved form and search history",
|
}
|
||||||
history: "Browsing history",
|
|
||||||
offlineapps: "Offline website data",
|
|
||||||
passwords: "Saved passwords",
|
|
||||||
sessions: "Authenticated sessions",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.addItem("all", { description: "Sanitize all items", shouldSanitize: function () false });
|
||||||
|
// Builtin items
|
||||||
|
this.addItem("cache", { builtin: true, description: "Cache" });
|
||||||
|
this.addItem("downloads", { builtin: true, description: "Download history" });
|
||||||
|
this.addItem("formdata", { builtin: true, description: "Saved form and search history" });
|
||||||
|
this.addItem("history", { builtin: true, description: "Browsing history", sessionHistory: true });
|
||||||
|
this.addItem("offlineapps", { builtin: true, description: "Offline website data" });
|
||||||
|
this.addItem("passwords", { builtin: true, description: "Saved passwords" });
|
||||||
|
this.addItem("sessions", { builtin: true, description: "Authenticated sessions" });
|
||||||
|
|
||||||
// These builtin methods don't support hosts or otherwise have
|
// These builtin methods don't support hosts or otherwise have
|
||||||
// insufficient granularity
|
// insufficient granularity
|
||||||
this.addItem("cookies", {
|
this.addItem("cookies", {
|
||||||
|
builtin: true,
|
||||||
description: "Cookies",
|
description: "Cookies",
|
||||||
|
persistent: true,
|
||||||
action: function (range, host) {
|
action: function (range, host) {
|
||||||
for (let c in Sanitizer.iterCookies(host))
|
for (let c in Sanitizer.iterCookies(host))
|
||||||
if (range.contains(c.creationTime) || timespan.isSession && c.isSession)
|
if (range.contains(c.creationTime) || timespan.isSession && c.isSession)
|
||||||
@@ -63,7 +99,9 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR
|
|||||||
override: true
|
override: true
|
||||||
});
|
});
|
||||||
this.addItem("sitesettings", {
|
this.addItem("sitesettings", {
|
||||||
|
builtin: true,
|
||||||
description: "Site preferences",
|
description: "Site preferences",
|
||||||
|
persistent: true,
|
||||||
action: function (range, host) {
|
action: function (range, host) {
|
||||||
if (range.isSession)
|
if (range.isSession)
|
||||||
return;
|
return;
|
||||||
@@ -89,21 +127,95 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR
|
|||||||
},
|
},
|
||||||
override: true
|
override: true
|
||||||
});
|
});
|
||||||
util.addObserver(this);
|
|
||||||
|
function ourItems(persistent) [
|
||||||
|
item for (item in self.itemMap)
|
||||||
|
if (!item.builtin && (!persistent || item.persistent))
|
||||||
|
];
|
||||||
|
|
||||||
|
function prefOverlay(branch, persistent, local) update(Object.create(local), {
|
||||||
|
before: array.toObject([
|
||||||
|
[branch.substr(Item.PREFIX.length) + "history",
|
||||||
|
<preferences xmlns={XUL}>{
|
||||||
|
template.map(ourItems(persistent), function (item)
|
||||||
|
<preference type="bool" id={branch + item.name} name={branch + item.name}/>)
|
||||||
|
}</preferences>.*::*]
|
||||||
|
]),
|
||||||
|
init: function init(win) {
|
||||||
|
let pane = win.document.getElementById("SanitizeDialogPane");
|
||||||
|
for (let [,pref] in iter(pane.preferences))
|
||||||
|
pref.updateElements();
|
||||||
|
init.superapply(this, arguments);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let (branch = Item.PREFIX + Item.SHUTDOWN_BRANCH) {
|
||||||
|
util.overlayWindow("chrome://browser/content/preferences/sanitize.xul",
|
||||||
|
function (win) prefOverlay(branch, true, {
|
||||||
|
append: {
|
||||||
|
SanitizeDialogPane:
|
||||||
|
<groupbox orient="horizontal" xmlns={XUL}>
|
||||||
|
<caption label={services.get("dactyl:").appName + " (see :help privacy)"}/>
|
||||||
|
<grid flex="1">
|
||||||
|
<columns><column flex="1"/><column flex="1"/></columns>
|
||||||
|
<rows>{
|
||||||
|
let (items = ourItems(true))
|
||||||
|
template.map(util.range(0, Math.ceil(items.length/2)), function (i)
|
||||||
|
<row xmlns={XUL}>{
|
||||||
|
template.map(items.slice(i*2, i*2+2), function (item)
|
||||||
|
<checkbox xmlns={XUL} label={item.description} preference={branch + item.name}/>)
|
||||||
|
}</row>)
|
||||||
|
}</rows>
|
||||||
|
</grid>
|
||||||
|
</groupbox>
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
let (branch = Item.PREFIX + Item.BRANCH) {
|
||||||
|
util.overlayWindow("chrome://browser/content/sanitize.xul",
|
||||||
|
function (win) prefOverlay(branch, false, {
|
||||||
|
append: {
|
||||||
|
itemList: <>
|
||||||
|
<listitem xmlns={XUL} label="See :help privacy for the following:" disabled="true" style="font-style: italic; font-weight: bold;"/>
|
||||||
|
{
|
||||||
|
template.map(ourItems(), function ([item, desc])
|
||||||
|
<listitem xmlns={XUL} type="checkbox"
|
||||||
|
label={services.get("dactyl:").appName + " " + desc}
|
||||||
|
preference={branch + item}
|
||||||
|
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>)
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
},
|
||||||
|
init: function (win) {
|
||||||
|
let elem = win.document.getElementById("itemList");
|
||||||
|
elem.setAttribute("rows", elem.itemCount);
|
||||||
|
win.Sanitizer = Class("Sanitizer", win.Sanitizer, {
|
||||||
|
sanitize: function sanitize() {
|
||||||
|
self.withSavedValues(["sanitizing"], function () {
|
||||||
|
self.sanitizing = true;
|
||||||
|
sanitize.superapply(this, arguments);
|
||||||
|
sanitizer.sanitizeItems([item.name for (item in self.itemMap) if (item.shouldSanitize(false))],
|
||||||
|
Range.fromArray(this.range || []));
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addItem: function addItem(name, params) {
|
addItem: function addItem(name, params) {
|
||||||
if (params.description)
|
this.itemMap[name] = update(this.itemMap[name] || Item(name),
|
||||||
this.itemDescriptions[name] = params.description;
|
array([k, v] for ([k, v] in Iterator(params)) if (!callable(v))).toObject());
|
||||||
if (params.override)
|
|
||||||
set.add(this.itemOverrides, name);
|
|
||||||
|
|
||||||
name = "clear-" + name;
|
let names = set([name].concat(params.contains || []).map(function (e) "clear-" + e));
|
||||||
|
if (params.action)
|
||||||
storage.addObserver("sanitizer",
|
storage.addObserver("sanitizer",
|
||||||
function (key, event, arg) {
|
function (key, event, arg) {
|
||||||
if (event == name)
|
if (event in names)
|
||||||
params.action.apply(params, arg);
|
params.action.apply(params, arg);
|
||||||
}, Class.objectGlobal(params.action));
|
},
|
||||||
|
Class.objectGlobal(params.action));
|
||||||
|
|
||||||
if (params.privateEnter || params.privateLeave)
|
if (params.privateEnter || params.privateLeave)
|
||||||
storage.addObserver("private-mode",
|
storage.addObserver("private-mode",
|
||||||
@@ -111,12 +223,13 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR
|
|||||||
let meth = params[arg ? "privateEnter" : "privateLeave"];
|
let meth = params[arg ? "privateEnter" : "privateLeave"];
|
||||||
if (meth)
|
if (meth)
|
||||||
meth.call(params);
|
meth.call(params);
|
||||||
}, Class.objectGlobal(params.action));
|
},
|
||||||
|
Class.objectGlobal(params.action));
|
||||||
},
|
},
|
||||||
|
|
||||||
observe: {
|
observe: {
|
||||||
"browser:purge-domain-data": function (subject, data) {
|
"browser:purge-domain-data": function (subject, host) {
|
||||||
storage.fireEvent("sanitize", "domain", data);
|
storage.fireEvent("sanitize", "domain", host);
|
||||||
// If we're sanitizing, our own sanitization functions will already
|
// If we're sanitizing, our own sanitization functions will already
|
||||||
// be called, and with much greater granularity. Only process this
|
// be called, and with much greater granularity. Only process this
|
||||||
// event if it's triggered externally.
|
// event if it's triggered externally.
|
||||||
@@ -126,7 +239,11 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR
|
|||||||
"browser:purge-session-history": function (subject, data) {
|
"browser:purge-session-history": function (subject, data) {
|
||||||
// See above.
|
// See above.
|
||||||
if (!this.sanitizing)
|
if (!this.sanitizing)
|
||||||
this.sanitizeItems(null, Range(this.sessionStart), null);
|
this.sanitizeItems(null, Range(this.sessionStart), null, "sessionHistory");
|
||||||
|
},
|
||||||
|
"quit-application-granted": function (subject, data) {
|
||||||
|
if (!this.sanitizeItems(null, Range(), null, "shutdown"))
|
||||||
|
this.ranAtShutdown = true;
|
||||||
},
|
},
|
||||||
"private-browsing": function (subject, data) {
|
"private-browsing": function (subject, data) {
|
||||||
if (data == "enter")
|
if (data == "enter")
|
||||||
@@ -137,14 +254,20 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
sanitize: function (items, range) {
|
get ranAtShutdown() prefs.get(Item.PREFIX + "didSanitizeOnShutdown"),
|
||||||
|
set ranAtShutdown(val) prefs.set(Item.PREFIX + "didSanitizeOnShutdown", Boolean(val)),
|
||||||
|
get runAtShutdown() prefs.get("privacy.sanitize.sanitizeOnShutdown"),
|
||||||
|
set runAtShutdown(val) prefs.set("privacy.sanitize.sanitizeOnShutdown", Boolean(val)),
|
||||||
|
|
||||||
|
sanitize: function (items, range)
|
||||||
|
this.withSavedValues(["sanitizing"], function () {
|
||||||
this.sanitizing = true;
|
this.sanitizing = true;
|
||||||
let errors = this.sanitizeItems(items, range, null);
|
let errors = this.sanitizeItems(items, range, null);
|
||||||
|
|
||||||
for (let itemName in values(items)) {
|
for (let itemName in values(items)) {
|
||||||
try {
|
try {
|
||||||
let item = this.items[Sanitizer.argToPref(itemName)];
|
let item = this.items[Sanitizer.argToPref(itemName)];
|
||||||
if (item && !this.itemOverrides[itemName]) {
|
if (item && !this.itemMap[itemName].override) {
|
||||||
item.range = range;
|
item.range = range;
|
||||||
if ("clear" in item && item.canClear)
|
if ("clear" in item && item.canClear)
|
||||||
item.clear();
|
item.clear();
|
||||||
@@ -157,17 +280,19 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR
|
|||||||
util.reportError(e);
|
util.reportError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sanitizing = false;
|
|
||||||
return errors;
|
return errors;
|
||||||
},
|
}),
|
||||||
|
|
||||||
sanitizeItems: function (items, range, host) {
|
sanitizeItems: function (items, range, host, key)
|
||||||
|
this.withSavedValues(["sanitizing"], function () {
|
||||||
|
this.sanitizing = true;
|
||||||
if (items == null)
|
if (items == null)
|
||||||
items = Object.keys(this.itemDescriptions);
|
items = Object.keys(this.itemMap);
|
||||||
|
|
||||||
let errors;
|
let errors;
|
||||||
for (let itemName in values(items))
|
for (let itemName in values(items))
|
||||||
try {
|
try {
|
||||||
|
if (!key || this.itemMap[itemName][key])
|
||||||
storage.fireEvent("sanitizer", "clear-" + itemName, [range, host]);
|
storage.fireEvent("sanitizer", "clear-" + itemName, [range, host]);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
@@ -177,10 +302,9 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR
|
|||||||
util.reportError(e);
|
util.reportError(e);
|
||||||
}
|
}
|
||||||
return errors;
|
return errors;
|
||||||
}
|
})
|
||||||
}, {
|
}, {
|
||||||
argPrefMap: {
|
argPrefMap: {
|
||||||
commandline: "commandLine",
|
|
||||||
offlineapps: "offlineApps",
|
offlineapps: "offlineApps",
|
||||||
sitesettings: "siteSettings",
|
sitesettings: "siteSettings",
|
||||||
},
|
},
|
||||||
@@ -198,6 +322,11 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR
|
|||||||
yield p;
|
yield p;
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
load: function (dactyl, modules, window) {
|
||||||
|
if (sanitizer.runAtShutdown && !sanitizer.ranAtShutdown)
|
||||||
|
sanitizer.sanitizeItems(null, Range(), null, "shutdown");
|
||||||
|
sanitizer.ranAtShutdown = false;
|
||||||
|
},
|
||||||
autocommands: function (dactyl, modules, window) {
|
autocommands: function (dactyl, modules, window) {
|
||||||
storage.addObserver("private-mode",
|
storage.addObserver("private-mode",
|
||||||
function (key, event, value) {
|
function (key, event, value) {
|
||||||
@@ -305,10 +434,34 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR
|
|||||||
"The default list of private items to sanitize",
|
"The default list of private items to sanitize",
|
||||||
"stringlist", "all",
|
"stringlist", "all",
|
||||||
{
|
{
|
||||||
completer: function (value) Iterator(sanitizer.itemDescriptions),
|
completer: function (value) sanitizer.itemMap,
|
||||||
has: modules.Option.has.toggleAll,
|
has: modules.Option.has.toggleAll,
|
||||||
validator: function (values) values.length &&
|
validator: function (values) values.length &&
|
||||||
values.every(function (val) val === "all" || set.has(sanitizer.itemDescriptions, val))
|
values.every(function (val) val === "all" || set.has(sanitizer.itemMap, val))
|
||||||
|
});
|
||||||
|
|
||||||
|
options.add(["sanitizeshutdown", "ss"],
|
||||||
|
"The items to sanitize automatically at shutdown",
|
||||||
|
"stringlist", "",
|
||||||
|
{
|
||||||
|
initialValue: true,
|
||||||
|
completer: function () [i for (i in sanitizer.itemMap) if (i.persistent || i.builtin)],
|
||||||
|
getter: function () !sanitizer.runAtShutdown ? [] : [
|
||||||
|
item.name for (item in sanitizer.itemMap)
|
||||||
|
if (item.shouldSanitize(true))
|
||||||
|
],
|
||||||
|
setter: function (values) {
|
||||||
|
if (values.length === 0)
|
||||||
|
sanitizer.runAtShutdown = false;
|
||||||
|
else {
|
||||||
|
sanitizer.runAtShutdown = true;
|
||||||
|
let have = set(values);
|
||||||
|
for (let item in sanitizer.itemMap)
|
||||||
|
prefs.set(item.shutdownPref,
|
||||||
|
Boolean(set.has(have, item.name) ^ set.has(have, "all")));
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
options.add(["sanitizetimespan", "sts"],
|
options.add(["sanitizetimespan", "sts"],
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ defineModule("storage", {
|
|||||||
require: ["services", "util"]
|
require: ["services", "util"]
|
||||||
});
|
});
|
||||||
|
|
||||||
var prefService = services.get("pref").getBranch("extensions.dactyl.datastore.");
|
|
||||||
|
|
||||||
const win32 = /^win(32|nt)$/i.test(services.get("runtime").OS);
|
const win32 = /^win(32|nt)$/i.test(services.get("runtime").OS);
|
||||||
|
|
||||||
function getFile(name) {
|
function getFile(name) {
|
||||||
@@ -21,38 +19,19 @@ function getFile(name) {
|
|||||||
return File(file);
|
return File(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCharPref(name) {
|
function loadData(name, store, type) {
|
||||||
try {
|
try {
|
||||||
return prefService.getComplexValue(name, Ci.nsISupportsString).data;
|
if (storage.infoPath)
|
||||||
}
|
|
||||||
catch (e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCharPref(name, value) {
|
|
||||||
var str = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
|
|
||||||
str.data = value;
|
|
||||||
return prefService.setComplexValue(name, Ci.nsISupportsString, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadPref(name, store, type) {
|
|
||||||
try {
|
|
||||||
if (store)
|
|
||||||
var pref = getCharPref(name);
|
|
||||||
if (!pref && storage.infoPath)
|
|
||||||
var file = getFile(name).read();
|
var file = getFile(name).read();
|
||||||
if (pref || file)
|
if (file)
|
||||||
var result = services.get("json").decode(pref || file);
|
var result = services.get("json").decode(file);
|
||||||
if (pref) {
|
|
||||||
prefService.clearUserPref(name);
|
|
||||||
savePref({ name: name, store: true, serial: pref });
|
|
||||||
}
|
|
||||||
if (result instanceof type)
|
if (result instanceof type)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function savePref(obj) {
|
function saveData(obj) {
|
||||||
if (obj.privateData && storage.privateMode)
|
if (obj.privateData && storage.privateMode)
|
||||||
return;
|
return;
|
||||||
if (obj.store && storage.infoPath)
|
if (obj.store && storage.infoPath)
|
||||||
@@ -78,7 +57,7 @@ const StoreBase = Class("StoreBase", {
|
|||||||
this._object = this._load() || this._constructor();
|
this._object = this._load() || this._constructor();
|
||||||
this.fireEvent("change", null);
|
this.fireEvent("change", null);
|
||||||
},
|
},
|
||||||
save: function () { savePref(this); },
|
save: function () { saveData(this); },
|
||||||
});
|
});
|
||||||
|
|
||||||
const ArrayStore = Class("ArrayStore", StoreBase, {
|
const ArrayStore = Class("ArrayStore", StoreBase, {
|
||||||
@@ -175,7 +154,7 @@ const Storage = Module("Storage", {
|
|||||||
if (!(key in keys) || params.reload || this.alwaysReload[key]) {
|
if (!(key in keys) || params.reload || this.alwaysReload[key]) {
|
||||||
if (key in this && !(params.reload || this.alwaysReload[key]))
|
if (key in this && !(params.reload || this.alwaysReload[key]))
|
||||||
throw Error();
|
throw Error();
|
||||||
let load = function () loadPref(key, params.store, params.type || myObject);
|
let load = function () loadData(key, params.store, params.type || myObject);
|
||||||
keys[key] = new constructor(key, params.store, load, params);
|
keys[key] = new constructor(key, params.store, load, params);
|
||||||
keys[key].timer = new Timer(1000, 10000, function () storage.save(key));
|
keys[key].timer = new Timer(1000, 10000, function () storage.save(key));
|
||||||
this.__defineGetter__(key, function () keys[key]);
|
this.__defineGetter__(key, function () keys[key]);
|
||||||
@@ -243,12 +222,12 @@ const Storage = Module("Storage", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
save: function save(key) {
|
save: function save(key) {
|
||||||
savePref(keys[key]);
|
saveData(keys[key]);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveAll: function storeAll() {
|
saveAll: function storeAll() {
|
||||||
for each (let obj in keys)
|
for each (let obj in keys)
|
||||||
savePref(obj);
|
saveData(obj);
|
||||||
},
|
},
|
||||||
|
|
||||||
_privateMode: false,
|
_privateMode: false,
|
||||||
|
|||||||
@@ -6,9 +6,11 @@
|
|||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
Components.utils.import("resource://dactyl/base.jsm");
|
Components.utils.import("resource://dactyl/base.jsm");
|
||||||
defineModule("util", {
|
defineModule("util", {
|
||||||
exports: ["Math", "NS", "Util", "XHTML", "XUL", "util"],
|
exports: ["FailedAssertion", "Math", "NS", "Prefs", "Util", "XHTML", "XUL", "prefs", "util"],
|
||||||
require: ["services"],
|
require: ["services"],
|
||||||
use: ["highlight", "template"]
|
use: ["highlight", "template"]
|
||||||
});
|
});
|
||||||
@@ -18,12 +20,33 @@ const XUL = Namespace("xul", "http://www.mozilla.org/keymaster/gatekeeper/there.
|
|||||||
const NS = Namespace("dactyl", "http://vimperator.org/namespaces/liberator");
|
const NS = Namespace("dactyl", "http://vimperator.org/namespaces/liberator");
|
||||||
default xml namespace = XHTML;
|
default xml namespace = XHTML;
|
||||||
|
|
||||||
const Util = Module("Util", {
|
const FailedAssertion = Class("FailedAssertion", Error, {
|
||||||
|
init: function (message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function wrapCallback(fn)
|
||||||
|
fn.wrapper = function wrappedCallback () {
|
||||||
|
try {
|
||||||
|
return fn.apply(this, arguments);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
util.reportError(e);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), {
|
||||||
init: function () {
|
init: function () {
|
||||||
this.Array = array;
|
this.Array = array;
|
||||||
|
|
||||||
|
this.addObserver(this);
|
||||||
|
this.overlays = {};
|
||||||
},
|
},
|
||||||
|
|
||||||
get activeWindow() services.get("windowWatcher").activeWindow,
|
// FIXME: Only works for Pentadactyl
|
||||||
|
get activeWindow() services.get("windowMediator").getMostRecentWindow("navigator:browser"),
|
||||||
dactyl: {
|
dactyl: {
|
||||||
__noSuchMethod__: function (meth, args) {
|
__noSuchMethod__: function (meth, args) {
|
||||||
let win = util.activeWindow;
|
let win = util.activeWindow;
|
||||||
@@ -61,6 +84,19 @@ const Util = Module("Util", {
|
|||||||
register("addObserver");
|
register("addObserver");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tests a condition and throws a FailedAssertion error on
|
||||||
|
* failure.
|
||||||
|
*
|
||||||
|
* @param {boolean} condition The condition to test.
|
||||||
|
* @param {string} message The message to present to the
|
||||||
|
* user on failure.
|
||||||
|
*/
|
||||||
|
assert: function (condition, message) {
|
||||||
|
if (!condition)
|
||||||
|
throw new FailedAssertion(message);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls a function synchronously in the main thread. Return values are not
|
* Calls a function synchronously in the main thread. Return values are not
|
||||||
* preserved.
|
* preserved.
|
||||||
@@ -644,6 +680,41 @@ const Util = Module("Util", {
|
|||||||
return color ? string : [s for each (s in string)].join("");
|
return color ? string : [s for each (s in string)].join("");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
observe: {
|
||||||
|
"toplevel-window-ready": function (window, data) {
|
||||||
|
window.addEventListener("DOMContentLoaded", wrapCallback(function listener(event) {
|
||||||
|
window.removeEventListener("DOMContentLoaded", listener.wrapper, true);
|
||||||
|
|
||||||
|
if (event.originalTarget !== window.document)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let obj = util.overlays[window.document.documentURI];
|
||||||
|
if (obj) {
|
||||||
|
obj = obj(window);
|
||||||
|
|
||||||
|
function overlay(key, fn) {
|
||||||
|
for (let [elem, xml] in Iterator(obj[key] || {}))
|
||||||
|
if (elem = window.document.getElementById(elem))
|
||||||
|
fn(elem, util.xmlToDom(xml, window.document));
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay("before", function (elem, dom) elem.parentNode.insertBefore(dom, elem));
|
||||||
|
overlay("after", function (elem, dom) elem.parentNode.insertBefore(dom, elem.nextSibling));
|
||||||
|
overlay("append", function (elem, dom) elem.appendChild(dom));
|
||||||
|
overlay("prepend", function (elem, dom) elem.insertBefore(dom, elem.firstChild));
|
||||||
|
if (obj.init)
|
||||||
|
obj.init(window, event);
|
||||||
|
|
||||||
|
if (obj.load)
|
||||||
|
window.document.addEventListener("load", function (event) {
|
||||||
|
if (event.originalTarget === event.target)
|
||||||
|
obj.load(window, event);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
}), true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the fields of a form and returns a URL/POST-data pair
|
* Parses the fields of a form and returns a URL/POST-data pair
|
||||||
* that is the equivalent of submitting the form.
|
* that is the equivalent of submitting the form.
|
||||||
@@ -756,6 +827,12 @@ const Util = Module("Util", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
overlayWindow: function (url, fn) {
|
||||||
|
Array.concat(url).forEach(function (url) {
|
||||||
|
this.overlays[url] = fn;
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scrolls an element into view if and only if it's not already
|
* Scrolls an element into view if and only if it's not already
|
||||||
* fully visible.
|
* fully visible.
|
||||||
@@ -881,6 +958,22 @@ const Util = Module("Util", {
|
|||||||
while (flush === true && mainThread.hasPendingEvents());
|
while (flush === true && mainThread.hasPendingEvents());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traps errors in the called function, possibly reporting them.
|
||||||
|
*
|
||||||
|
* @param {function} func The function to call
|
||||||
|
* @param {object} self The 'this' object for the function.
|
||||||
|
*/
|
||||||
|
trapErrors: function trapErrors(func, self) {
|
||||||
|
try {
|
||||||
|
return func.apply(self || this, Array.slice(arguments, 2));
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
util.reportError(e);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an E4X XML literal to a DOM node. Any attribute named
|
* Converts an E4X XML literal to a DOM node. Any attribute named
|
||||||
* highlight is present, it is transformed into dactyl:highlight,
|
* highlight is present, it is transformed into dactyl:highlight,
|
||||||
@@ -927,6 +1020,309 @@ const Util = Module("Util", {
|
|||||||
Array: array
|
Array: array
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), {
|
||||||
|
SAVED: "extensions.dactyl.saved.",
|
||||||
|
|
||||||
|
init: function () {
|
||||||
|
this._prefContexts = [];
|
||||||
|
|
||||||
|
util.addObserver(this);
|
||||||
|
this._branch = services.get("pref").getBranch("").QueryInterface(Ci.nsIPrefBranch2);
|
||||||
|
this._branch.addObserver("", this, false);
|
||||||
|
this._observers = {};
|
||||||
|
},
|
||||||
|
|
||||||
|
observe: {
|
||||||
|
"nsPref:changed": function (subject, data) {
|
||||||
|
let observers = this._observers[data];
|
||||||
|
if (observers) {
|
||||||
|
let value = this.get(data, false);
|
||||||
|
this._observers[data] = observers.filter(function (callback) {
|
||||||
|
if (!callback.get())
|
||||||
|
return false;
|
||||||
|
util.trapErrors(callback.get(), null, value);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new preference observer for the given preference.
|
||||||
|
*
|
||||||
|
* @param {string} pref The preference to observe.
|
||||||
|
* @param {function(object)} callback The callback, called with the
|
||||||
|
* new value of the preference whenever it changes.
|
||||||
|
*/
|
||||||
|
watch: function (pref, callback, strong) {
|
||||||
|
if (!this._observers[pref])
|
||||||
|
this._observers[pref] = [];
|
||||||
|
this._observers[pref].push(!strong ? Cu.getWeakReference(callback) : { get: function () callback });
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all preferences matching <b>filter</b> or only those with
|
||||||
|
* changed values if <b>onlyNonDefault</b> is specified.
|
||||||
|
*
|
||||||
|
* @param {boolean} onlyNonDefault Limit the list to prefs with a
|
||||||
|
* non-default value.
|
||||||
|
* @param {string} filter The list filter. A null filter lists all
|
||||||
|
* prefs.
|
||||||
|
* @optional
|
||||||
|
*/
|
||||||
|
list: function list(onlyNonDefault, filter) {
|
||||||
|
if (!filter)
|
||||||
|
filter = "";
|
||||||
|
|
||||||
|
let prefArray = this.getNames();
|
||||||
|
prefArray.sort();
|
||||||
|
function prefs() {
|
||||||
|
for (let [, pref] in Iterator(prefArray)) {
|
||||||
|
let userValue = services.get("pref").prefHasUserValue(pref);
|
||||||
|
if (onlyNonDefault && !userValue || pref.indexOf(filter) == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let value = this.get(pref);
|
||||||
|
|
||||||
|
let option = {
|
||||||
|
isDefault: !userValue,
|
||||||
|
default: this._load(pref, null, true),
|
||||||
|
value: <>={template.highlight(value, true, 100)}</>,
|
||||||
|
name: pref,
|
||||||
|
pre: "\u00a0\u00a0" // Unicode nonbreaking space.
|
||||||
|
};
|
||||||
|
|
||||||
|
yield option;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return template.options(services.get("dactyl:").host + " Preferences", prefs.call(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of a preference.
|
||||||
|
*
|
||||||
|
* @param {string} name The preference name.
|
||||||
|
* @param {value} defaultValue The value to return if the preference
|
||||||
|
* is unset.
|
||||||
|
*/
|
||||||
|
get: function (name, defaultValue) {
|
||||||
|
return this._load(name, defaultValue);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default value of a preference
|
||||||
|
*
|
||||||
|
* @param {string} name The preference name.
|
||||||
|
* @param {value} defaultValue The value to return if the preference
|
||||||
|
* has no default value.
|
||||||
|
*/
|
||||||
|
getDefault: function (name, defaultValue) {
|
||||||
|
return this._load(name, defaultValue, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the names of all preferences.
|
||||||
|
*
|
||||||
|
* @param {string} branch The branch in which to search preferences.
|
||||||
|
* @default ""
|
||||||
|
*/
|
||||||
|
getNames: function (branch) services.get("pref").getChildList(branch || "", { value: 0 }),
|
||||||
|
|
||||||
|
_checkSafe: function (name, message, value) {
|
||||||
|
let curval = this._load(name, null, false);
|
||||||
|
if (arguments.length > 2 && curval === value)
|
||||||
|
return;
|
||||||
|
let defval = this._load(name, null, true);
|
||||||
|
let saved = this._load(this.SAVED + name);
|
||||||
|
|
||||||
|
if (saved == null && curval != defval || curval != saved) {
|
||||||
|
let msg = "Warning: setting preference " + name + ", but it's changed from its default value.";
|
||||||
|
if (message)
|
||||||
|
msg += " " + message;
|
||||||
|
util.dactyl.echomsg(msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the preference <b>name</b> to </b>value</b> but warns the user
|
||||||
|
* if the value is changed from its default.
|
||||||
|
*
|
||||||
|
* @param {string} name The preference name.
|
||||||
|
* @param {value} value The new preference value.
|
||||||
|
*/
|
||||||
|
safeReset: function (name, message) {
|
||||||
|
this._checkSafe(name, message);
|
||||||
|
this.reset(name);
|
||||||
|
this.reset(this.SAVED + name);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the preference <b>name</b> to </b>value</b> but warns the user
|
||||||
|
* if the value is changed from its default.
|
||||||
|
*
|
||||||
|
* @param {string} name The preference name.
|
||||||
|
* @param {value} value The new preference value.
|
||||||
|
*/
|
||||||
|
safeSet: function (name, value, message) {
|
||||||
|
this._checkSafe(name, message, value);
|
||||||
|
this._store(name, value);
|
||||||
|
this._store(this.SAVED + name, value);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the preference <b>name</b> to </b>value</b>.
|
||||||
|
*
|
||||||
|
* @param {string} name The preference name.
|
||||||
|
* @param {value} value The new preference value.
|
||||||
|
*/
|
||||||
|
set: function (name, value) {
|
||||||
|
this._store(name, value);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the preference <b>name</b> to its default value.
|
||||||
|
*
|
||||||
|
* @param {string} name The preference name.
|
||||||
|
*/
|
||||||
|
reset: function (name) {
|
||||||
|
try {
|
||||||
|
services.get("pref").clearUserPref(name);
|
||||||
|
}
|
||||||
|
catch (e) {} // ignore - thrown if not a user set value
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the value of the boolean preference <b>name</b>.
|
||||||
|
*
|
||||||
|
* @param {string} name The preference name.
|
||||||
|
*/
|
||||||
|
toggle: function (name) {
|
||||||
|
util.assert(services.get("pref").getPrefType(name) === Ci.nsIPrefBranch.PREF_BOOL,
|
||||||
|
"E488: Trailing characters: " + name + "!");
|
||||||
|
this.set(name, !this.get(name));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes a new preference context onto the context stack.
|
||||||
|
*
|
||||||
|
* @see #withContext
|
||||||
|
*/
|
||||||
|
pushContext: function () {
|
||||||
|
this._prefContexts.push({});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pops the top preference context from the stack.
|
||||||
|
*
|
||||||
|
* @see #withContext
|
||||||
|
*/
|
||||||
|
popContext: function () {
|
||||||
|
for (let [k, v] in Iterator(this._prefContexts.pop()))
|
||||||
|
this._store(k, v);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes <b>func</b> with a new preference context. When <b>func</b>
|
||||||
|
* returns, the context is popped and any preferences set via
|
||||||
|
* {@link #setPref} or {@link #invertPref} are restored to their
|
||||||
|
* previous values.
|
||||||
|
*
|
||||||
|
* @param {function} func The function to call.
|
||||||
|
* @param {Object} func The 'this' object with which to call <b>func</b>
|
||||||
|
* @see #pushContext
|
||||||
|
* @see #popContext
|
||||||
|
*/
|
||||||
|
withContext: function (func, self) {
|
||||||
|
try {
|
||||||
|
this.pushContext();
|
||||||
|
return func.call(self);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
this.popContext();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_store: function (name, value) {
|
||||||
|
if (this._prefContexts.length) {
|
||||||
|
let val = this._load(name, null);
|
||||||
|
if (val != null)
|
||||||
|
this._prefContexts[this._prefContexts.length - 1][name] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
let type = services.get("pref").getPrefType(name);
|
||||||
|
switch (typeof value) {
|
||||||
|
case "string":
|
||||||
|
assertType(Ci.nsIPrefBranch.PREF_STRING);
|
||||||
|
|
||||||
|
let supportString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
|
||||||
|
supportString.data = value;
|
||||||
|
services.get("pref").setComplexValue(name, Ci.nsISupportsString, supportString);
|
||||||
|
break;
|
||||||
|
case "number":
|
||||||
|
assertType(Ci.nsIPrefBranch.PREF_INT);
|
||||||
|
|
||||||
|
services.get("pref").setIntPref(name, value);
|
||||||
|
break;
|
||||||
|
case "boolean":
|
||||||
|
assertType(Ci.nsIPrefBranch.PREF_BOOL);
|
||||||
|
|
||||||
|
services.get("pref").setBoolPref(name, value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw FailedAssertion("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_load: function (name, defaultValue, defaultBranch) {
|
||||||
|
if (defaultValue == null)
|
||||||
|
defaultValue = null;
|
||||||
|
|
||||||
|
let branch = defaultBranch ? services.get("pref").getDefaultBranch("") : services.get("pref");
|
||||||
|
let type = services.get("pref").getPrefType(name);
|
||||||
|
try {
|
||||||
|
switch (type) {
|
||||||
|
case Ci.nsIPrefBranch.PREF_STRING:
|
||||||
|
let value = branch.getComplexValue(name, Ci.nsISupportsString).data;
|
||||||
|
// try in case it's a localized string (will throw an exception if not)
|
||||||
|
if (!services.get("pref").prefIsLocked(name) && !services.get("pref").prefHasUserValue(name) &&
|
||||||
|
RegExp("chrome://.+/locale/.+\\.properties").test(value))
|
||||||
|
value = branch.getComplexValue(name, Ci.nsIPrefLocalizedString).data;
|
||||||
|
return value;
|
||||||
|
case Ci.nsIPrefBranch.PREF_INT:
|
||||||
|
return branch.getIntPref(name);
|
||||||
|
case Ci.nsIPrefBranch.PREF_BOOL:
|
||||||
|
return branch.getBoolPref(name);
|
||||||
|
default:
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
}, {
|
||||||
|
completion: function (dactyl, modules) {
|
||||||
|
modules.completion.preference = function preference(context) {
|
||||||
|
context.anchored = false;
|
||||||
|
context.title = [services.get("dactyl:").host + " Preference", "Value"];
|
||||||
|
context.keys = { text: function (item) item, description: function (item) prefs.get(item) };
|
||||||
|
context.completions = prefs.getNames();
|
||||||
|
};
|
||||||
|
},
|
||||||
|
javascript: function (dactyl, modules) {
|
||||||
|
modules.JavaScript.setCompleter([this.get, this.safeSet, this.set, this.reset, this.toggle],
|
||||||
|
[function (context) (context.anchored=false, prefs.getNames().map(function (pref) [pref, ""]))]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Math utility methods.
|
* Math utility methods.
|
||||||
* @singleton
|
* @singleton
|
||||||
@@ -945,8 +1341,8 @@ var Math = update(Object.create(GlobalMath), {
|
|||||||
constrain: function constrain(value, min, max) Math.min(Math.max(min, value), max)
|
constrain: function constrain(value, min, max) Math.min(Math.max(min, value), max)
|
||||||
});
|
});
|
||||||
|
|
||||||
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);}
|
|
||||||
|
|
||||||
endModule();
|
endModule();
|
||||||
|
|
||||||
|
} catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);}
|
||||||
|
|
||||||
// vim: set fdm=marker sw=4 ts=4 et ft=javascript:
|
// vim: set fdm=marker sw=4 ts=4 et ft=javascript:
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
* Significant completion speed improvements, especially for
|
* Significant completion speed improvements, especially for
|
||||||
JavaScript.
|
JavaScript.
|
||||||
* Greatly improved private mode support and :sanitize command.
|
* Greatly improved private mode support and :sanitize command.
|
||||||
|
- Full integration with Firefox data clearing dialogs.
|
||||||
|
- Support for sanitizing items at shutdown.
|
||||||
|
- Fine-grained control over what data is sanitized and for
|
||||||
|
what timespan.
|
||||||
|
- Support for sanitizing reference to particular hosts,
|
||||||
|
everywhere from command-line and message history to option
|
||||||
|
values and cookies.
|
||||||
* New and much more powerful incremental search implementation.
|
* New and much more powerful incremental search implementation.
|
||||||
Improvements over the standard Firefox find include:
|
Improvements over the standard Firefox find include:
|
||||||
- Starts at the cursor position in the currently selected
|
- Starts at the cursor position in the currently selected
|
||||||
|
|||||||
Reference in New Issue
Block a user