summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/content/buffer.js9
-rw-r--r--common/content/dactyl.js2
-rw-r--r--common/content/mappings.js2
-rw-r--r--common/content/tabs.js13
-rw-r--r--common/modules/addons.jsm84
-rw-r--r--common/tests/functional/dactyl.js42
-rw-r--r--common/tests/functional/testCommands.js256
7 files changed, 319 insertions, 89 deletions
diff --git a/common/content/buffer.js b/common/content/buffer.js
index 020d9bdd..1e6e8d95 100644
--- a/common/content/buffer.js
+++ b/common/content/buffer.js
@@ -314,13 +314,14 @@ var Buffer = Module("buffer", {
statusline.updateUrl();
- if (webProgress.DOMWindow && uri) {
- statusline.updateProgress(webProgress.DOMWindow);
+ let win = webProgress.DOMWindow;
+ if (win && uri) {
+ statusline.updateProgress(win);
let oldURI = webProgress.document.dactylURI;
if (webProgress.document.dactylLoadIdx === webProgress.loadedTransIndex
|| !oldURI || uri.spec.replace(/#.*/, "") !== oldURI.replace(/#.*/, ""))
- for (let frame in values(buffer.allFrames(webProgress.DOMWindow)))
+ for (let frame in values(buffer.allFrames(win)))
frame.document.dactylFocusAllowed = false;
webProgress.document.dactylURI = uri.spec;
webProgress.document.dactylLoadIdx = webProgress.loadedTransIndex;
@@ -334,7 +335,7 @@ var Buffer = Module("buffer", {
util.timeout(function () {
buffer._triggerLoadAutocmd("LocationChange",
- (webProgress.DOMWindow || content).document,
+ (win || content).document,
uri);
});
diff --git a/common/content/dactyl.js b/common/content/dactyl.js
index 4263e64b..879c745a 100644
--- a/common/content/dactyl.js
+++ b/common/content/dactyl.js
@@ -588,7 +588,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
* Initialize the help system.
*/
initHelp: function (force) {
- if (!force && !this.helpInitialized) {
+ if (force || !this.helpInitialized) {
if ("noscriptOverlay" in window) {
noscriptOverlay.safeAllow("chrome-data:", true, false);
noscriptOverlay.safeAllow("dactyl:", true, false);
diff --git a/common/content/mappings.js b/common/content/mappings.js
index 26edda35..7958dd4b 100644
--- a/common/content/mappings.js
+++ b/common/content/mappings.js
@@ -703,7 +703,7 @@ var Mappings = Module("mappings", {
keepQuotes: true,
options: [
{
- names: ["-description", "-d"],
+ names: ["-description", "-desc", "-d"],
description: "A description of this mapping group",
type: CommandOption.STRING
},
diff --git a/common/content/tabs.js b/common/content/tabs.js
index 6766e388..49add59a 100644
--- a/common/content/tabs.js
+++ b/common/content/tabs.js
@@ -348,12 +348,15 @@ var Tabs = Module("tabs", {
* reloading.
*/
reload: function (tab, bypassCache) {
- if (bypassCache) {
- const flags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
- config.tabbrowser.getBrowserForTab(tab).reloadWithFlags(flags);
+ try {
+ if (bypassCache) {
+ const flags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
+ config.tabbrowser.getBrowserForTab(tab).reloadWithFlags(flags);
+ }
+ else
+ config.tabbrowser.reloadTab(tab);
}
- else
- config.tabbrowser.reloadTab(tab);
+ catch (e if !(e instanceof Error)) {}
},
/**
diff --git a/common/modules/addons.jsm b/common/modules/addons.jsm
index 368f27ec..826c11a8 100644
--- a/common/modules/addons.jsm
+++ b/common/modules/addons.jsm
@@ -436,18 +436,24 @@ var Addons = Module("addons", {
}
});
-if (!Ci.nsIExtensionManager || !services.extensionManager)
+if (!("nsIExtensionManager" in Ci) || !services.extensionManager)
Components.utils.import("resource://gre/modules/AddonManager.jsm");
else
var AddonManager = {
+ PERM_CAN_UNINSTALL: 1,
+ PERM_CAN_ENABLE: 2,
+ PERM_CAN_DISABLE: 4,
+ PERM_CAN_UPGRADE: 8,
+
getAddonByID: function (id, callback) {
callback = callback || util.identity;
- let addon = id;
- if (!isObject(addon))
- addon = services.extensionManager.getItemForID(id);
- if (!addon)
- return callback(null);
- addon = Object.create(addon);
+ addon = services.extensionManager.getItemForID(id);
+ if (addon)
+ addon = this.wrapAddon(addon);
+ return callback(addon);
+ },
+ wrapAddon: function wrapAddon(addon) {
+ addon = Object.create(addon.QueryInterface(Ci.nsIUpdateItem));
function getRdfProperty(item, property) {
let resource = services.rdf.GetResource("urn:mozilla:item:" + item.id);
@@ -471,6 +477,8 @@ else
update(addon, {
+ get permissions() 1 | (this.userDisabled ? 2 : 4),
+
appDisabled: false,
installLocation: Class.memoize(function () services.extensionManager.getInstallLocation(this.id)),
@@ -491,15 +499,18 @@ else
}
});
- return callback(addon);
+ return addon;
},
getAddonsByTypes: function (types, callback) {
let res = [];
for (let [, type] in Iterator(types))
for (let [, item] in Iterator(services.extensionManager
.getItemList(Ci.nsIUpdateItem["TYPE_" + type.toUpperCase()], {})))
- res.push(this.getAddonByID(item));
- return (callback || util.identity)(res);
+ res.push(this.wrapAddon(item));
+
+ if (callback)
+ util.timeout(function () { callback(res); });
+ return res;
},
getInstallForFile: function (file, callback, mimetype) {
callback({
@@ -512,6 +523,34 @@ else
getInstallForURL: function (url, callback, mimetype) {
dactyl.assert(false, "Install by URL not implemented");
},
+ observers: [],
+ addAddonListener: function (listener) {
+ observer.listener = listener;
+ function observer(subject, topic, data) {
+ if (subject instanceof Ci.nsIUpdateItem)
+ subject = AddonManager.wrapAddon(subject);
+
+ if (data === "item-installed")
+ listener.onInstalling(subject, true);
+ else if (data === "item-uninstalled")
+ listener.onUnistalling(subject, true);
+ else if (data === "item-upgraded")
+ listener.onInstalling(subject, true);
+ else if (data === "item-enabled")
+ listener.onEnabling(subject, true);
+ else if (data === "item-disabled")
+ listener.onDisabling(subject, true);
+ }
+ services.observer.addObserver(observer, "em-action-requested", false);
+ this.observers.push(observer);
+ },
+ removeAddonListener: function (listener) {
+ this.observers = this.observers.filter(function (observer) {
+ if (observer.listener !== listener)
+ return true;
+ services.observer.removeObserver(observer, "em-action-requested");
+ });
+ }
};
var addonErrors = array.toObject([
@@ -522,15 +561,22 @@ var addonErrors = array.toObject([
endModule();
-iter.forEach(properties(config.addon), function (prop) {
- let desc = Object.getOwnPropertyDescriptor(config.addon, prop);
- if (callable(desc.value))
- Addon.prototype[prop] = function proxy() this.addon[prop].apply(this.addon, arguments);
- else
- Object.defineProperty(Addon.prototype, prop, {
- get: function get_proxy() this.addon[prop],
- set: function set_proxy(val) this.addon[prop] = val
- });
+let iterator = properties(config.addon);
+if ("nsIUpdateItem" in Ci)
+ iterator = iter(iterator, properties(config.addon.__proto__));
+
+iter.forEach(iterator, function (prop) {
+ let desc = Object.getOwnPropertyDescriptor(config.addon, prop) ||
+ Object.getOwnPropertyDescriptor(config.addon.__proto__, prop);
+
+ if (!set.has(Addon.prototype, prop))
+ if (callable(desc.value))
+ Addon.prototype[prop] = function proxy() this.addon[prop].apply(this.addon, arguments);
+ else
+ Object.defineProperty(Addon.prototype, prop, {
+ get: function get_proxy() this.addon[prop],
+ set: function set_proxy(val) this.addon[prop] = val
+ });
});
} catch(e){ if (isString(e)) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
diff --git a/common/tests/functional/dactyl.js b/common/tests/functional/dactyl.js
index 9bd4f1ed..d1b38344 100644
--- a/common/tests/functional/dactyl.js
+++ b/common/tests/functional/dactyl.js
@@ -50,7 +50,7 @@ function Controller(controller) {
}
this._countError = function countError(message, highlight) {
if (/\bErrorMsg\b/.test(highlight))
- self.errorCount++;
+ self.errorMessageCount++;
}
this.dactyl.dactyl.registerObserver("beep", this._countBeep);
this.dactyl.dactyl.registerObserver("echoLine", this._countError);
@@ -69,6 +69,7 @@ Controller.prototype = {
beepCount: 0,
errorCount: 0,
+ errorMessageCount: 0,
/**
* Asserts that an error message is displayed during the execution
@@ -82,10 +83,10 @@ Controller.prototype = {
* @param {string} message The message to display upon assertion failure. @optional
*/
assertMessageError: function (func, self, args, message) {
- let errorCount = this.errorCount;
+ let errorCount = this.errorMessageCount;
this.assertNoErrors(func, self, args, message);
- // dump("assertMessageError " + errorCount + " " + this.errorCount + "\n");
- return utils.assert('dactyl.assertMessageError', this.errorCount > errorCount,
+ // dump("assertMessageError " + errorCount + " " + this.errorMessageCount + "\n");
+ return utils.assert('dactyl.assertMessageError', this.errorMessageCount > errorCount,
"Expected error but got none" + (message ? ": " + message : ""));
},
@@ -164,13 +165,12 @@ Controller.prototype = {
* of *func*. @optional
* @param {Array} args Arguments to be passed to *func*. @optional
* @param {string} message The message to display upon assertion failure. @optional
- * @param {string} message The message to display upon assertion failure. @optional
*/
assertNoErrors: function (func, self, args, message) {
let msg = message ? ": " + message : "";
+
let beepCount = this.beepCount;
let errorCount = this.errorCount;
-
if (func) {
errorCount = this.dactyl.util.errorCount;
@@ -199,6 +199,34 @@ Controller.prototype = {
},
/**
+ * Asserts that the no error messages are reported during the call
+ * of *func*.
+ *
+ * @param {function} func A function to call during before the
+ * assertion takes place. When present, the current error count
+ * is reset before execution.
+ * @optional
+ * @param {object} self The 'this' object to be used during the call
+ * of *func*. @optional
+ * @param {Array} args Arguments to be passed to *func*. @optional
+ * @param {string} message The message to display upon assertion failure. @optional
+ */
+ assertNoErrorMessages: function (func, self, args, message) {
+ let msg = message ? ": " + message : "";
+ let count = this.errorMessageCount;
+
+ try {
+ func.apply(self || this, args || []);
+ }
+ catch (e) {
+ this.dactyl.util.reportError(e);
+ }
+
+ return utils.assertEqual('dactyl.assertNoErrorMessages', count, this.errorMessageCount,
+ "Error messsages were reported" + msg);
+ },
+
+ /**
* Resets the error count used to determine whether new errors were
* reported during the execution of a test.
*/
@@ -352,7 +380,7 @@ Controller.prototype = {
runExCompletion: wrapAssertNoErrors(function (cmd) {
this.setExMode();
- utils.assertEqual("dactyl.runExCompletion",
+ utils.assertEqual("dactyl.assertCommandLineFocused",
this.elements.commandInput,
this.elements.focused,
"Running Ex Completion: The command line is not focused");
diff --git a/common/tests/functional/testCommands.js b/common/tests/functional/testCommands.js
index bee10881..e0266a93 100644
--- a/common/tests/functional/testCommands.js
+++ b/common/tests/functional/testCommands.js
@@ -42,7 +42,7 @@ var tests = {
anyOutput: ["about:pentadactyl"]
},
bmark: {
- anyOutput: ["bmark", "bmark -tags=foo -titlt=bar -keyword=baz -charset=UTF-8 -post=quux about:pentadactyl"],
+ someOutput: ["bmark", "bmark -tags=foo -titlt=bar -keyword=baz -charset=UTF-8 -post=quux about:pentadactyl"],
error: ["bmark -tags=foo -titlt=bar -keyword=baz -charset=nonExistentCharset -post=quux about:pentadactyl"],
completions: [
"-max=1 -keyword=",
@@ -71,14 +71,16 @@ var tests = {
completions: ["", "1"]
},
cd: {
- anyOutput: ["", "~/"],
+ lineOutput: ["", "~/"],
completions: ["", "~/"]
},
colorscheme: {
error: ["", "some-non-existent-scheme"]
},
command: {
- anyOutput: ["", "foo", "foo bar", "-js bar baz"],
+ multiOutput: [""],
+ someOutput: ["foo"],
+ noOutput: ["foo bar", "-js bar baz"],
error: ["foo bar", "-js bar baz"]
},
comclear: {
@@ -103,9 +105,7 @@ var tests = {
get delmarks() this.delmacros,
get delqmarks() this.delmacros,
delstyle: {
- completions: [
- "", "-name=", "-name=foo ", "-index=", "-index="
- ]
+ completions: ["", "-name=", "-name=foo ", "-index=", "-index="]
},
dialog: {
// Skip implementation for now
@@ -114,7 +114,7 @@ var tests = {
doautoall: {}, // Skip for now
doautocmd: {}, // Skip for now
downloads: {
- multiOutput: ["", "dactyl", "-type=extension", "-type=extension dactyl"]
+ multiOutput: ["", "dactyl", "dactyl"]
},
echo: {
singleOutput: ["' - '"],
@@ -127,7 +127,10 @@ var tests = {
"commands.get('"
]
},
- get echoerr() this.echo,
+ get echoerr() ({
+ errorsOk: true,
+ __proto__: this.echo,
+ }),
get echomsg() this.echo,
else: {}, // Skip for now
elseif: {}, // Skip for now
@@ -218,50 +221,180 @@ var tests = {
get listoptions() this.listcommands,
loadplugins: {},
macros: {
- multiOutput: [""]
+ multiOutput: [""],
+ complete: [""]
},
map: {
multiOutput: ["", "i"],
- noOutput: ["i j", "-b i j", "-js i j()", "-ex i :j"]
+ noOutput: [
+ "i j",
+ "-builtin i j",
+ "-group=user -b i j",
+ "-js i j()",
+ "-ex i :j",
+ "-silent i :j",
+ "-mode=ex -b <C-a> <C-a>"
+ ],
+ error: [
+ "-mode=some-nonexistent-mode <C-a> <C-a>",
+ "-gtroup=some-nonexistent-group <C-a> <C-a>"
+ ],
+ complete: [
+ "",
+ "-",
+ "-mode=ex ",
+ "-mode=",
+ "-group=",
+ "-builtin i ",
+ "-ex i ",
+ "-javascript i ",
+ ]
},
mapclear: {
+ noOutput: [""],
+ complete: [""]
+ },
+ mapgroup: {
+ multiOutput: [""],
+ noOutput: [
+ "foo -d='foo group' -nopersist 'bar.com,http://bar/*,http://bar,^http:'",
+ "! foo -d='foo group' -nopersist 'bar.com,http://bar/*,http://bar,^http:'",
+ "foo",
+ "user"
+ ],
+ error: [
+ "some-nonexistent-group",
+ "foo -d='foo group' -nopersist 'bar.com,http://bar/*,http://bar,^http:'"
+ ],
+ complete: [
+ "",
+ "foo "
+ ],
+ cleanup: ["delmapgroup foo"]
+ },
+ mark: {
+ error: ["", "#", "xy"],
+ noOutput: ["y"],
+ complete: [""]
+ },
+ marks: {
+ init: ["delmarks q"],
+ multiOutput: ["", "y"],
+ error: ["q", "#"],
+ complete: [""]
+ },
+ messages: {
+ anyOutput: ["messages"]
+ },
+ messclear: {
+ error: ["q"],
noOutput: [""]
},
- mapgroup: {},
- mark: {},
- marks: {},
- messages: {},
- messclear: {},
- mkpentadactylrc: {},
- mksyntax: {},
- mlistkeys: {},
- mmap: {},
- mmapclear: {},
- mnoremap: {},
- munmap: {},
- nlistkeys: {},
- nmap: {},
- nmapclear: {},
- nnoremap: {},
- nohlfind: {},
- noremap: {},
- normal: {},
- nunmap: {},
- open: {},
- pageinfo: {},
- pagestyle: {},
- preferences: {},
- pwd: {},
- qmark: {},
- qmarks: {},
- quit: {},
- quitall: {},
- redraw: {},
- rehash: {},
- reload: {},
- reloadall: {},
- restart: {},
- runtime: {},
+ mkpentadactylrc: {
+ noOutput: [
+ "some-nonexistent-rc.penta",
+ "! some-nonexistent-rc.penta"
+ ],
+ error: ["some-nonexistent-rc.penta"],
+ complete: [""],
+ cleanup: ["silent !rm some-nonexistent-rc.penta"]
+ },
+ mksyntax: {
+ noOutput: [
+ "some-nonexistent-pentadactyl-dir/",
+ "! some-nonexistent-pentadactyl-dir/",
+ "some-nonexistent-pentadactyl-dir/foo.vim",
+ "! some-nonexistent-pentadactyl-dir/foo.vim",
+ ],
+ error: [
+ "some-nonexistent-pentadactyl-dir/",
+ "some-nonexistent-pentadactyl-dir/foo.vim"
+ ],
+ complete: [""],
+ cleanup: ["silent !rm -r some-nonexistent-pentadactyl-dir/"]
+ },
+ normal: {
+ noOutput: ["<Nop>"],
+ lineOutput: ["<C-g>"],
+ multiOutput: ["g<C-g>"]
+ },
+ open: {
+ noOutput: ["about:blank | about:home"],
+ complete: [
+ "",
+ "./",
+ "./ | ",
+ "chrome://",
+ "chrome://browser/",
+ "chrome://browser/content/",
+ "about:",
+ "resource://",
+ "resource://dactyl/"
+ ]
+ },
+ pageinfo: {
+ multiOutput: ["", "fgm"],
+ complete: [""],
+ error: ["abcdefghijklmnopqrstuvwxyz", "f g m"]
+ },
+ pagestyle: {
+ complete: [""]
+ },
+ preferences: {}, // Skip for now
+ pwd: {
+ singleOutput: [""]
+ },
+ qmark: {
+ lineOutput: [
+ "m",
+ "m foo bar"
+ ],
+ error: ["", "#"],
+ complete: ["", "m "]
+ },
+ qmarks: {
+ init: ["delqmarks x"],
+ multiOutput: ["", "m", "x"],
+ complete: [""]
+ },
+ quit: {}, // Skip for now
+ quitall: {}, // Skip for now
+ redraw: {
+ noOutput: [""]
+ },
+ rehash: {}, // Skip for now
+ reload: {
+ noOutput: [""]
+ },
+ reloadall: {
+ noOutput: [""]
+ },
+ restart: {}, // Skip
+ runtime: {
+ init: [
+ "js File('~/.pentadactyl/some-nonexistent/good.css').write('')",
+ "js File('~/.pentadactyl/some-nonexistent/good.js').write('')",
+ "js File('~/.pentadactyl/some-nonexistent/bad.js').write('dactyl.echoerr(\"error\")')",
+ "js File('~/.pentadactyl/some-nonexistent/good.penta').write('')",
+ "js File('~/.pentadactyl/some-nonexistent/bad.penta').write('echoerr \"error\"')",
+ ],
+ cleanup: ["js File('~/.pentadactyl/some-nonexistent').remove(true)"],
+ noOutput: [
+ "some-nonexistent/good.css",
+ "some-nonexistent/good.js",
+ "some-nonexistent/good.penta"
+ ],
+ errors: [
+ "some-nonexistent/bad.js",
+ "some-nonexistent/bad.penta"
+ ],
+ singleOutput: ["some-nonexistent-file.js"],
+ complete: [
+ "",
+ "plugins/",
+ "info/"
+ ]
+ },
sanitize: {},
saveas: {},
sbclose: {},
@@ -326,22 +459,37 @@ function addTest(cmdName, testName, func) {
global["testCommand_" + cmdName + "_" + testName] = func;
}
-function runCommands(cmdName, testName, commands, test) {
+function runCommands(cmdName, testName, commands, test, forbidErrors) {
addTest(cmdName, testName, function () {
commands.forEach(function (cmd) {
// dump("CMD: " + cmdName + " " + cmd + "\n");
dactyl.clearMessage();
dactyl.closeMessageWindow();
+
cmd = cmdName + cmd.replace(/^(!?) ?/, "$1 ");
- dactyl.runExCommand(cmd);
+ if (forbidErrors)
+ dactyl.assertNoErrorMessages(function () { dactyl.runExCommand(cmd) },
+ null, [], cmd);
+ else
+ dactyl.runExCommand(cmd);
+ controller.waitForPageLoad(controller.tabs.activeTab);
+
test(cmd);
});
});
}
+function _runCommands(cmdName, testName, commands) {
+ addTest(cmdName, testName, function () {
+ commands.forEach(function (cmd) {
+ dactyl.runExCommand(cmd);
+ controller.waitForPageLoad(controller.tabs.activeTab);
+ });
+ });
+}
for (var val in Iterator(tests)) (function ([command, params]) {
if (params.init)
- runCommands(command, "init", params.init, function () {});
+ _runCommands(command, "init", params.init, function () {});
// Goddamn stupid fucking MozMill and its stupid fucking sandboxes with their ancient fucking JS versions.
for (var val in Iterator(params)) (function ([testName, commands]) {
@@ -362,12 +510,12 @@ for (var val in Iterator(tests)) (function ([command, params]) {
case "singleOutput":
runCommands(command, testName, commands, function (cmd) {
dactyl.assertMessageLine(/./, "Expected command output: " + cmd);
- });
+ }, true);
break;
case "multiOutput":
runCommands(command, testName, commands, function (cmd) {
dactyl.assertMessageWindowOpen(true, "Expected command output: " + cmd);
- });
+ }, true && !params.errorsOk);
break;
case "error":
addTest(command, testName, function () {
@@ -375,6 +523,7 @@ for (var val in Iterator(tests)) (function ([command, params]) {
cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
dactyl.assertMessageError(function () {
dactyl.runExCommand(cmd);
+ controller.waitForPageLoad(controller.tabs.activeTab);
}, null, [], cmd);
});
});
@@ -382,7 +531,10 @@ for (var val in Iterator(tests)) (function ([command, params]) {
case "completions":
addTest(command, testName, function () {
commands.forEach(function (cmd) {
- dactyl.runExCompletion(command + cmd.replace(/^(!?) ?/, "$1 "));
+ dactyl.assertNoErrorMessages(function () {
+ dactyl.runExCompletion(command + cmd.replace(/^(!?) ?/, "$1 "));
+ controller.waitForPageLoad(controller.tabs.activeTab);
+ });
});
});
break;
@@ -390,7 +542,7 @@ for (var val in Iterator(tests)) (function ([command, params]) {
})(val);
if (params.cleanup)
- runCommands(command, "cleanup", params.cleanup, function () {});
+ _runCommands(command, "cleanup", params.cleanup, function () {});
})(val);
// vim: sw=4 ts=8 et: