@@ -175,6 +174,8 @@
:cno :cnoremap:cnoremaplhsrhs
+ These aliases are deprecated. The -builtin flag
+ should be used in their stead.
Map the key-sequencelhs to rhs for
the applicable mode(s). The keys in rhs do not
@@ -372,6 +373,33 @@
+
+ ]]>
+
+ ]]>
+
+
+ An arbitrary and meaningless key that some people seem
+ attached to. The \ key will, by default, emit
+ this pseudo-key so that it can be used at the start of
+ other mappings. Note, however, that there is nothing
+ special about it and any key can be mapped to emit any
+ other arbitrary pseudo-key in the same way.
+
+
+ :map ,
+:map ;
+
+:map k -js doStuff()
+:map k -js doOtherReallyNiftyStuff()
+
+
+ Needless to say this behavior is considered childish and
+ discouraged.
+
- List or open multiple bookmarks. Opens the message window
- at the bottom of the screen with all bookmarks with
- titles or URLs matching filter. The resulting
- URLs can be clicked, or accessed via extended hint modes
- such as ;o.
+ List or open multiple bookmarks. Opens the message window at the
+ bottom of the screen with all bookmarks with URLs matching
+ filter. The resulting URLs can be clicked, or accessed via
+ extended hint modes such as ;o.
@@ -180,7 +179,7 @@
QuickMarks are bookmarks stripped to the bone for quickly getting to the
pages that you visit most. A QuickMark is simply a URL assigned to a letter
- or number. They can therefore be saved or opened with only three key
+ or digit. They can therefore be saved or opened with only three key
presses each. QuickMarks are persistent across browser sessions.
Patterns used to determine line numbers used by G. May be
- either a selector expression as accepted by hinttags, in
- which case the first matching element whose text content is equal to
- the desired line number is used or the countth element
- failing that, or the string func: followed by a
- function which, given arguments for the document and desired line
- number, must return the target element.
+ either a selector expression as accepted by hinttags, or the
+ string func: followed by a JavaScript
+ expression which evaluates to a function. In the former case, the
+ first matching element whose text content is equal to the desired
+ line number is used. If no such element exists, the countth
+ matching element is used. In the latter case, the provided function
+ must accept two arguments, the document in question and the desired
+ line number, and must return the element corresponding to the given
+ line.
Pass certain keys through directly for the given URLs.
- For any page with a URL matching a given regexp, all key
- events for keys listed in that regexp's value are passed
+ For any page with a URL matching a given site-filter, all key
+ events for keys listed in the corresponding value are passed
through directly to &dactyl.host;, and are not processed
by &dactyl.appName; in any way. Key names are separated
by commas, where the first key name is treated as a list
@@ -1352,7 +1359,6 @@
colors/
-
macros/
plugins/
@@ -1632,8 +1638,9 @@
The regular expression used to split URL lists in commands
like :open. When set to the empty string, URL lists
- are never split. With the default value, the following will open
- three URLs in the current tab and two new background tabs,
+ are never split. With the default settings, the following will open
+ three URLs (the first one in the current tab and the latter two in
+ two new background tabs):
:open google Linux | wikipedia Arch Linux | imdb Serenity
diff --git a/common/modules/addons.jsm b/common/modules/addons.jsm
index c1e4e33..8ea7f8a 100644
--- a/common/modules/addons.jsm
+++ b/common/modules/addons.jsm
@@ -83,14 +83,14 @@ var actions = {
name: "exte[nable]",
description: "Enable an extension",
action: function (addon) { addon.userDisabled = false; },
- filter: function ({ item }) item.userDisabled,
+ filter: function (addon) addon.userDisabled,
perm: "enable"
},
disable: {
name: "extd[isable]",
description: "Disable an extension",
action: function (addon) { addon.userDisabled = true; },
- filter: function ({ item }) !item.userDisabled,
+ filter: function (addon) !addon.userDisabled,
perm: "disable"
},
options: {
@@ -103,7 +103,7 @@ var actions = {
else
this.dactyl.open(addon.optionsURL, { from: "extoptions" });
},
- filter: function ({ item }) item.isActive && item.optionsURL
+ filter: function (addon) addon.isActive && addon.optionsURL
},
rehash: {
name: "extr[ehash]",
@@ -117,8 +117,8 @@ var actions = {
});
},
get filter() {
- return function ({ item }) !item.userDisabled &&
- !(item.operationsRequiringRestart & (AddonManager.OP_NEEDS_RESTART_ENABLE | AddonManager.OP_NEEDS_RESTART_DISABLE))
+ return function (addon) !addon.userDisabled &&
+ !(addon.operationsRequiringRestart & (AddonManager.OP_NEEDS_RESTART_ENABLE | AddonManager.OP_NEEDS_RESTART_DISABLE))
},
perm: "disable"
},
@@ -170,7 +170,7 @@ var Addon = Class("Addon", {
let action = actions[cmd];
if ("perm" in action && !(this.permissions & AddonManager["PERM_CAN_" + action.perm.toUpperCase()]))
return false;
- if ("filter" in action && !action.filter({ item: this }))
+ if ("filter" in action && !action.filter(this))
return false;
return true;
},
@@ -356,7 +356,7 @@ var Addons = Module("addons", {
}, {
}, {
commands: function (dactyl, modules, window) {
- const { CommandOption, commands, completion } = modules;
+ const { CommandOption, commands, completion, io } = modules;
commands.add(["addo[ns]", "ao"],
"List installed extensions",
@@ -412,7 +412,7 @@ var Addons = Module("addons", {
// TODO: handle extension dependencies
values(actions).forEach(function (command) {
let perm = command.perm && AddonManager["PERM_CAN_" + command.perm.toUpperCase()];
- function ok(addon) !perm || addon.permissions & perm;
+ function ok(addon) (!perm || addon.permissions & perm) && (!command.filter || command.filter(addon));
commands.add(Array.concat(command.name),
command.description,
@@ -430,6 +430,7 @@ var Addons = Module("addons", {
dactyl.assert(list.some(ok), _("error.invalidOperation"));
list = list.filter(ok);
}
+ dactyl.assert(list.every(ok));
if (command.actions)
command.actions(list, this.modules);
else
@@ -441,8 +442,6 @@ var Addons = Module("addons", {
completer: function (context, args) {
completion.addon(context, args["-types"]);
context.filters.push(function ({ item }) ok(item));
- if (command.filter)
- context.filters.push(command.filter);
},
literal: 0,
options: [
diff --git a/common/modules/base.jsm b/common/modules/base.jsm
index bc767f6..51d2f0d 100644
--- a/common/modules/base.jsm
+++ b/common/modules/base.jsm
@@ -289,7 +289,7 @@ function properties(obj, prototypes, debugger_) {
for (; obj; obj = prototypes && prototype(obj)) {
try {
if (sandbox.Object.getOwnPropertyNames || !debugger_ || !services.debugger.isOn)
- var iter = values(Object.getOwnPropertyNames(obj));
+ var iter = (v for each (v in Object.getOwnPropertyNames(obj)));
}
catch (e) {}
if (!iter)
@@ -363,7 +363,7 @@ function keys(obj) iter(function keys() {
* @returns {Generator}
*/
function values(obj) iter(function values() {
- if (isinstance(obj, ["Generator", "Iterator"]))
+ if (isinstance(obj, ["Generator", "Iterator", Iter]))
for (let k in obj)
yield k;
else
@@ -1452,17 +1452,7 @@ function iter(obj, iface) {
return iter(obj.enumerator());
return iter(obj.enumerator);
}
- res.__noSuchMethod__ = function __noSuchMethod__(meth, args) {
- if (meth in iter)
- var res = iter[meth].apply(iter, [this].concat(args));
- else
- res = let (ary = array(this))
- ary[meth] ? ary[meth].apply(ary, args) : ary.__noSuchMethod__(meth, args);
- if (isinstance(res, ["Iterator", "Generator"]))
- return iter(res);
- return res;
- };
- return res;
+ return Iter(res);
}
update(iter, {
toArray: function toArray(iter) array(iter).array,
@@ -1576,6 +1566,23 @@ update(iter, {
}
});
+const Iter = Class("Iter", {
+ init: function init(iter) {
+ this.iter = iter;
+ if ("__iterator__" in iter)
+ this.iter = iter.__iterator__();
+
+ if (this.iter.finalize)
+ this.finalize = function finalize() this.iter.finalize.apply(this.iter, arguments);
+ },
+
+ next: function next() this.iter.next(),
+
+ send: function send() this.iter.send.apply(this.iter, arguments),
+
+ __iterator__: function () this.iter
+});
+
/**
* Array utility methods.
*/
@@ -1731,6 +1738,40 @@ var array = Class("array", Array, {
}
});
+/* Make Minefield not explode, because Minefield exploding is not fun. */
+let iterProto = Iter.prototype;
+Object.keys(iter).forEach(function (k) {
+ iterProto[k] = function () {
+ let res = iter[k].apply(iter, [this].concat(Array.slice(arguments)));
+ if (isinstance(res, ["Iterator", "Generator"]))
+ return Iter(res);
+ return res;
+ };
+});
+
+Object.keys(array).forEach(function (k) {
+ if (!(k in iterProto))
+ iterProto[k] = function () {
+ let res = array[k].apply(array, [this.toArray()].concat(Array.slice(arguments)));
+ if (isinstance(res, ["Iterator", "Generator"]))
+ return Iter(res);
+ if (isArray(res))
+ return array(res);
+ return res;
+ };
+});
+
+Object.getOwnPropertyNames(Array.prototype).forEach(function (k) {
+ if (!(k in iterProto) && callable(Array.prototype[k]))
+ iterProto[k] = function () {
+ let ary = iter(this).toArray();
+ let res = ary[k].apply(ary, arguments);
+ if (isArray(res))
+ return array(res);
+ return res;
+ };
+});
+
endModule();
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);}
diff --git a/common/modules/bookmarkcache.jsm b/common/modules/bookmarkcache.jsm
index 55328a1..2647848 100644
--- a/common/modules/bookmarkcache.jsm
+++ b/common/modules/bookmarkcache.jsm
@@ -42,7 +42,19 @@ update(Bookmark.prototype, {
if (!this.charset || this.charset === "UTF-8")
return encodeURIComponent(str);
let conv = services.CharsetConv(this.charset);
- return escape(conv.ConvertFromUnicode(str) + conv.Finish());
+ return escape(conv.ConvertFromUnicode(str) + conv.Finish()).replace(/\+/g, encodeURIComponent);
+ },
+
+ get folder() {
+ let res = [];
+ res.toString = function () this.join("/");
+
+ let id = this.id, parent, title;
+ while ((id = services.bookmarks.getFolderIdForItem(id)) &&
+ (title = services.bookmarks.getItemTitle(id)))
+ res.push(title);
+
+ return res.reverse();
}
})
Bookmark.prototype.members.uri = Bookmark.prototype.members.url;
@@ -94,8 +106,8 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
let uri = newURI(node.uri);
let keyword = services.bookmarks.getKeywordForBookmark(node.itemId);
- let tags = tags in node ? (node.tags ? node.tags.split(/, /g) : [])
- : services.tagging.getTagsForURI(uri, {}) || [];
+ let tags = "tags" in node ? (node.tags ? node.tags.split(/, /g) : [])
+ : services.tagging.getTagsForURI(uri, {}) || [];
let post = BookmarkCache.getAnnotation(node.itemId, this.POST);
let charset = BookmarkCache.getAnnotation(node.itemId, this.CHARSET);
@@ -172,7 +184,11 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
let query = services.history.getNewQuery();
let options = services.history.getNewQueryOptions();
options.queryType = options.QUERY_TYPE_BOOKMARKS;
- options.excludeItemIfParentHasAnnotation = "livemark/feedURI";
+ try {
+ // https://bugzil.la/702639
+ options.excludeItemIfParentHasAnnotation = "livemark/feedURI";
+ }
+ catch (e) {}
let { root } = services.history.executeQuery(query, options);
root.containerOpen = true;
diff --git a/common/modules/bootstrap.jsm b/common/modules/bootstrap.jsm
index 4343ec2..7145110 100644
--- a/common/modules/bootstrap.jsm
+++ b/common/modules/bootstrap.jsm
@@ -123,8 +123,9 @@ else
},
cleanup: function unregister() {
- for each (let factory in this.factories.splice(0))
+ for each (let factory in this.factories)
this.manager.unregisterFactory(factory.classID, factory);
+ this.factories = {};
},
purge: function purge() {
@@ -185,11 +186,15 @@ else
}),
registerFactory: function registerFactory(factory) {
+ if (Set.has(this.factories, factory.contractID))
+ this.manager.unregisterFactory(this.factories[factory.contractID].classID,
+ this.factories[factory.contractID]);
+
this.manager.registerFactory(factory.classID,
String(factory.classID),
factory.contractID,
factory);
- this.factories.push(factory);
+ this.factories[factory.contractID] = factory;
}
};
diff --git a/common/modules/buffer.jsm b/common/modules/buffer.jsm
index 94b1692..357beea 100644
--- a/common/modules/buffer.jsm
+++ b/common/modules/buffer.jsm
@@ -13,8 +13,9 @@ defineModule("buffer", {
}, this);
this.lazyRequire("finder", ["RangeFind"]);
+this.lazyRequire("io", ["io"]);
this.lazyRequire("overlay", ["overlay"]);
-this.lazyRequire("storage", ["storage"]);
+this.lazyRequire("storage", ["File", "storage"]);
this.lazyRequire("template", ["template"]);
/**
@@ -72,7 +73,7 @@ var Buffer = Module("Buffer", {
dactyl.assert(url instanceof Ci.nsIURL);
while (count-- && url.path != "/")
- url.path = url.path.replace(/[^\/]+\/*$/, "");
+ url.path = url.path.replace(/[^\/]*\/*$/, "");
dactyl.assert(!url.equals(this.documentURI));
dactyl.open(url.spec);
@@ -394,7 +395,7 @@ var Buffer = Module("Buffer", {
function a(regexp, elem) regexp.test(elem.textContent) === regexp.result ||
Array.some(elem.childNodes, function (child) regexp.test(child.alt) === regexp.result);
- function b(regexp, elem) regexp.test(elem.title);
+ function b(regexp, elem) regexp.test(elem.title) === regexp.result;
let res = Array.filter(frame.document.querySelectorAll(selector), Hints.isVisible);
for (let test in values([a, b]))
@@ -456,10 +457,11 @@ var Buffer = Module("Buffer", {
let { dactyl } = this.modules;
let ctrlKey = false, shiftKey = false;
+ let button = 0;
switch (dactyl.forceTarget || where) {
case dactyl.NEW_TAB:
case dactyl.NEW_BACKGROUND_TAB:
- ctrlKey = true;
+ button = 1;
shiftKey = dactyl.forceBackground != null ? dactyl.forceBackground
: where != dactyl.NEW_BACKGROUND_TAB;
break;
@@ -475,7 +477,7 @@ var Buffer = Module("Buffer", {
prefs.withContext(function () {
prefs.set("browser.tabs.loadInBackground", true);
let params = {
- screenX: offsetX, screenY: offsetY,
+ button: button, screenX: offsetX, screenY: offsetY,
ctrlKey: ctrlKey, shiftKey: shiftKey, metaKey: ctrlKey
};
@@ -633,18 +635,24 @@ var Buffer = Module("Buffer", {
| persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
let window = this.topWindow;
+ if (!file.exists())
+ file.create(Ci.nsIFile.NORMAL_FILE_TYPE, octal(666));
+
let downloadListener = new window.DownloadListener(window,
services.Transfer(uri, File(file).URI, "",
null, null, null, persist));
- persist.progressListener = update(Object.create(downloadListener), {
- onStateChange: util.wrapCallback(function onStateChange(progress, request, flags, status) {
- if (callback && (flags & Ci.nsIWebProgressListener.STATE_STOP) && status == 0)
- util.trapErrors(callback, self, uri, file, progress, request, flags, status);
+ if (callback)
+ persist.progressListener = update(Object.create(downloadListener), {
+ onStateChange: util.wrapCallback(function onStateChange(progress, request, flags, status) {
+ if (callback && (flags & Ci.nsIWebProgressListener.STATE_STOP) && status == 0)
+ util.trapErrors(callback, self, uri, file, progress, request, flags, status);
- return onStateChange.superapply(this, arguments);
- })
- });
+ return onStateChange.superapply(this, arguments);
+ })
+ });
+ else
+ persist.progressListener = downloadListener;
persist.saveURI(uri, null, null, null, null, file);
},
@@ -1580,18 +1588,19 @@ var Buffer = Module("Buffer", {
dactyl.assert(!arg || arg[0] == ">" && !config.OS.isWindows,
_("error.trailingCharacters"));
- const PRINTER = "PostScript/default";
- const BRANCH = "print.printer_" + PRINTER + ".";
+ const PRINTER = "PostScript/default";
+ const BRANCH = "printer_" + PRINTER + ".";
+ const BRANCHES = ["print.", BRANCH, "print." + BRANCH];
+ function set(pref, value) {
+ BRANCHES.forEach(function (branch) { prefs.set(branch + pref, value) });
+ }
prefs.withContext(function () {
if (arg) {
prefs.set("print.print_printer", PRINTER);
- prefs.set( "print.print_to_file", true);
- prefs.set(BRANCH + "print_to_file", true);
-
- prefs.set( "print.print_to_filename", io.File(arg.substr(1)).path);
- prefs.set(BRANCH + "print_to_filename", io.File(arg.substr(1)).path);
+ set("print_to_file", true);
+ set("print_to_filename", io.File(arg.substr(1)).path);
dactyl.echomsg(_("print.toFile", arg.substr(1)));
}
@@ -1599,19 +1608,21 @@ var Buffer = Module("Buffer", {
dactyl.echomsg(_("print.sending"));
prefs.set("print.always_print_silent", args.bang);
- prefs.set("print.show_print_progress", !args.bang);
+ if (false)
+ prefs.set("print.show_print_progress", !args.bang);
config.browser.contentWindow.print();
});
- if (arg)
- dactyl.echomsg(_("print.printed", arg.substr(1)));
- else
- dactyl.echomsg(_("print.sent"));
+ dactyl.echomsg(_("print.sent"));
},
{
argCount: "?",
bang: true,
+ completer: function (context, args) {
+ if (args.bang && /^>/.test(context.filter))
+ context.fork("file", 1, modules.completion, "file");
+ },
literal: 0
});
@@ -1806,7 +1817,8 @@ var Buffer = Module("Buffer", {
context.incomplete = false;
try {
if (/filename="(.*?)"/.test(xhr.getResponseHeader("Content-Disposition")))
- context.completions.push([decodeURIComponent(RegExp.$1), _("buffer.save.suggested")]);
+ context.completions.push([decodeURIComponent(RegExp.$1),
+ _("buffer.save.suggested")]);
}
finally {
context.completions = context.completions.slice();
@@ -2020,7 +2032,7 @@ var Buffer = Module("Buffer", {
mappings.add([modes.NORMAL], ["[[", ""],
"Follow the link labeled 'prev', 'previous' or '<' if it exists",
function (args) {
- buffer.findLink("previous", options["previouspattern"], (args.count || 1) - 1, true);
+ buffer.findLink("prev", options["previouspattern"], (args.count || 1) - 1, true);
},
{ count: true });
@@ -2230,11 +2242,14 @@ var Buffer = Module("Buffer", {
options.add(["linenumbers", "ln"],
"Patterns used to determine line numbers used by G",
"sitemap", {
+ // Make sure to update the docs when you change this.
+ "view-source:*": 'body,[id^=line]',
"code.google.com": '#nums [id^="nums_table"] a[href^="#"]',
"github.com": '.line_numbers>*',
"mxr.mozilla.org": 'a.l',
"pastebin.com": '#code_frame>div>ol>li',
"addons.mozilla.org": '.gutter>.line>a',
+ "bugzilla.mozilla.org": ".bz_comment:not(.bz_first_comment):not(.ih_history)",
"*": '/* Hgweb/Gitweb */ .completecodeline a.codeline, a.linenr'
},
{
@@ -2277,12 +2292,12 @@ var Buffer = Module("Buffer", {
options.add(["nextpattern"],
"Patterns to use when guessing the next page in a document sequence",
- "regexplist", UTF8(/'\bnext\b',^>$,^(>>|»)$,^(>|»),(>|»)$,'\bmore\b'/.source),
+ "regexplist", UTF8(/'^Next [>»]','^Next »','\bnext\b',^>$,^(>>|»)$,^(>|»),(>|»)$,'\bmore\b'/.source),
{ regexpFlags: "i" });
options.add(["previouspattern"],
"Patterns to use when guessing the previous page in a document sequence",
- "regexplist", UTF8(/'\bprev|previous\b',^<$,^(<<|«)$,^(<|«),(<|«)$/.source),
+ "regexplist", UTF8(/'[<«] Prev$','« Prev$','\bprev(ious)?\b',^<$,^(<<|«)$,^(<|«),(<|«)$/.source),
{ regexpFlags: "i" });
options.add(["pageinfo", "pa"],
diff --git a/common/modules/completion.jsm b/common/modules/completion.jsm
index ff9c091..c44cbb3 100644
--- a/common/modules/completion.jsm
+++ b/common/modules/completion.jsm
@@ -410,7 +410,7 @@ var CompletionContext = Class("CompletionContext", {
this._cache.offset = this.offset;
this.lastActivated = this.top.runCount;
}
- if (!this.itemCache[this.key]) {
+ if (!this.itemCache[this.key] && !this.waitingForTab) {
try {
let res = this._generate();
if (res != null)
@@ -657,6 +657,7 @@ var CompletionContext = Class("CompletionContext", {
}
catch (e) {
util.reportError(e);
+ XML.ignoreWhitespace = XML.prettyPrinting = false;
cache[idx] = util.xmlToDom(
{this.text}
@@ -1014,7 +1015,6 @@ var Completion = Module("completion", {
context.hasItems = true;
context.completions = context.completions.filter(function ({ url, title })
words.every(function (w) (url + " " + title).toLowerCase().indexOf(w) >= 0))
- context.incomplete = true;
context.format = this.modules.bookmarks.format;
context.keys.extra = function (item) {
@@ -1033,20 +1033,24 @@ var Completion = Module("completion", {
running[provider] = false;
};
- service.startSearch(context.filter, "", context.result, {
- onSearchResult: util.wrapCallback(function onSearchResult(search, result) {
- if (result.searchResult <= result.RESULT_SUCCESS)
- running[provider] = null;
-
- context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
- context.completions = [
- { url: result.getValueAt(i), title: result.getCommentAt(i), icon: result.getImageAt(i) }
- for (i in util.range(0, result.matchCount))
- ];
- }),
- get onUpdateSearchResult() this.onSearchResult
- });
- running[provider] = true;
+ if (!context.waitingForTab) {
+ context.incomplete = true;
+
+ service.startSearch(context.filter, "", context.result, {
+ onSearchResult: util.wrapCallback(function onSearchResult(search, result) {
+ if (result.searchResult <= result.RESULT_SUCCESS)
+ running[provider] = null;
+
+ context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
+ context.completions = [
+ { url: result.getValueAt(i), title: result.getCommentAt(i), icon: result.getImageAt(i) }
+ for (i in util.range(0, result.matchCount))
+ ];
+ }),
+ get onUpdateSearchResult() this.onSearchResult
+ });
+ running[provider] = true;
+ }
}),
urls: function (context, tags) {
diff --git a/common/modules/config.jsm b/common/modules/config.jsm
index c9c1420..f92ea22 100644
--- a/common/modules/config.jsm
+++ b/common/modules/config.jsm
@@ -19,6 +19,7 @@ this.lazyRequire("highlight", ["highlight"]);
this.lazyRequire("messages", ["_"]);
this.lazyRequire("prefs", ["localPrefs", "prefs"]);
this.lazyRequire("storage", ["storage", "File"]);
+this.lazyRequire("styles", ["Styles"]);
function AboutHandler() {}
AboutHandler.prototype = {
@@ -215,7 +216,8 @@ var ConfigBase = Class("ConfigBase", {
let jar = io.isJarURL(uri);
if (jar) {
let prefix = getDir(jar.JAREntry);
- var res = iter(s.slice(prefix.length).replace(/\/.*/, "") for (s in io.listJar(jar.JARFile, prefix)))
+ var res = iter(s.slice(prefix.length).replace(/\/.*/, "")
+ for (s in io.listJar(jar.JARFile, prefix)))
.toArray();
}
else {
@@ -225,7 +227,7 @@ var ConfigBase = Class("ConfigBase", {
if (f.isDirectory())).array;
}
- function exists(pkg) services["resource:"].hasSubstitution("dactyl-locale-" + pkg);
+ let exists = function exists(pkg) services["resource:"].hasSubstitution("dactyl-locale-" + pkg);
return array.uniq([this.appLocale, this.appLocale.replace(/-.*/, "")]
.filter(exists)
@@ -402,11 +404,11 @@ var ConfigBase = Class("ConfigBase", {
dtdDactyl: memoize({
get name() config.name,
- get home() "http://dactyl.sourceforge.net/",
+ get home() "http://5digits.org/",
get apphome() this.home + this.name,
code: "http://code.google.com/p/dactyl/",
get issues() this.home + "bug/" + this.name,
- get plugins() "http://dactyl.sf.net/" + this.name + "/plugins",
+ get plugins() "http://5digits.org/" + this.name + "/plugins",
get faq() this.home + this.name + "/faq",
"list.mailto": Class.Memoize(function () config.name + "@googlegroups.com"),
diff --git a/common/modules/contexts.jsm b/common/modules/contexts.jsm
index 4681936..6d32fb8 100644
--- a/common/modules/contexts.jsm
+++ b/common/modules/contexts.jsm
@@ -222,7 +222,10 @@ var Contexts = Module("contexts", {
util.trapErrors("onUnload", self);
}
else {
- self = args && !isArray(args) ? args : newContext.apply(null, args || [userContext]);
+ let params = Array.slice(args || [userContext]);
+ params[2] = params[2] || File(file).URI.spec;
+
+ self = args && !isArray(args) ? args : newContext.apply(null, params);
update(self, {
NAME: Const(id),
diff --git a/common/modules/dom.jsm b/common/modules/dom.jsm
index 981ec9c..9f7f7e5 100644
--- a/common/modules/dom.jsm
+++ b/common/modules/dom.jsm
@@ -10,6 +10,9 @@ defineModule("dom", {
exports: ["$", "DOM", "NS", "XBL", "XHTML", "XUL"]
}, this);
+this.lazyRequire("highlight", ["highlight"]);
+this.lazyRequire("template", ["template"]);
+
var XBL = Namespace("xbl", "http://www.mozilla.org/xbl");
var XHTML = Namespace("html", "http://www.w3.org/1999/xhtml");
var XUL = Namespace("xul", "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@@ -55,12 +58,12 @@ var DOM = Class("DOM", {
this[length++] = DOM.fromXML(val, context, this.nodes);
else if (val instanceof Ci.nsIDOMNode || val instanceof Ci.nsIDOMWindow)
this[length++] = val;
- else if ("length" in val)
- for (let i = 0; i < val.length; i++)
- this[length++] = val[i];
else if ("__iterator__" in val || isinstance(val, ["Iterator", "Generator"]))
for (let elem in val)
this[length++] = elem;
+ else if ("length" in val)
+ for (let i = 0; i < val.length; i++)
+ this[length++] = val[i];
else
this[length++] = val;
@@ -191,11 +194,11 @@ var DOM = Class("DOM", {
this.each(function (elem) {
while(true) {
elem = fn.call(this, elem)
- if (elem instanceof Ci.nsIDOMElement)
+ if (elem instanceof Ci.nsIDOMNode)
res[res.length++] = elem;
else if (elem && "length" in elem)
- for (let i = 0; i < tmp.length; i++)
- res[res.length++] = tmp[j];
+ for (let i = 0; i < elem.length; i++)
+ res[res.length++] = elem[j];
else
break;
}
@@ -256,6 +259,9 @@ var DOM = Class("DOM", {
get siblingsBefore() this.all(function (elem) elem.previousElementSibling),
get siblingsAfter() this.all(function (elem) elem.nextElementSibling),
+ get allSiblingsBefore() this.all(function (elem) elem.previousSibling),
+ get allSiblingsAfter() this.all(function (elem) elem.nextSibling),
+
get class() let (self = this) ({
toString: function () self[0].className,
@@ -318,22 +324,26 @@ var DOM = Class("DOM", {
this[0] ? this[0].getBoundingClientRect() : {},
get viewport() {
- if (this[0] instanceof Ci.nsIDOMWindow)
+ let node = this[0];
+ if (node instanceof Ci.nsIDOMDocument)
+ node = node.defaultView;
+
+ if (node instanceof Ci.nsIDOMWindow)
return {
get width() this.right - this.left,
get height() this.bottom - this.top,
- bottom: this[0].innerHeight,
- right: this[0].innerWidth,
+ bottom: node.innerHeight,
+ right: node.innerWidth,
top: 0, left: 0
};
let r = this.rect;
return {
- width: this[0].clientWidth,
- height: this[0].clientHeight,
- top: r.top + this[0].clientTop,
+ width: node.clientWidth,
+ height: node.clientHeight,
+ top: r.top + node.clientTop,
get bottom() this.top + this.height,
- left: r.left + this[0].clientLeft,
+ left: r.left + node.clientLeft,
get right() this.left + this.width
}
},
@@ -406,7 +416,7 @@ var DOM = Class("DOM", {
return editor;
},
- get isEditable() !!this.editor,
+ get isEditable() !!this.editor || this[0] instanceof Ci.nsIDOMElement && this.style.MozUserModify == "read-write",
get isInput() isinstance(this[0], [Ci.nsIDOMHTMLInputElement,
Ci.nsIDOMHTMLTextAreaElement,
@@ -784,25 +794,44 @@ var DOM = Class("DOM", {
else
event = array.toObject([[event, listener]]);
- for (let [k, v] in Iterator(event))
- event[k] = util.wrapCallback(v, true);
+ for (let [evt, callback] in Iterator(event))
+ event[evt] = util.wrapCallback(callback, true);
return this.each(function (elem) {
- for (let [k, v] in Iterator(event))
- elem.addEventListener(k, v, capture);
+ for (let [evt, callback] in Iterator(event))
+ elem.addEventListener(evt, callback, capture);
});
},
unlisten: function unlisten(event, listener, capture) {
if (isObject(event))
capture = listener;
else
- event = array.toObject([[key, val]]);
+ event = array.toObject([[event, listener]]);
return this.each(function (elem) {
for (let [k, v] in Iterator(event))
elem.removeEventListener(k, v.wrapper || v, capture);
});
},
+ once: function once(event, listener, capture) {
+ if (isObject(event))
+ capture = listener;
+ else
+ event = array.toObject([[event, listener]]);
+
+ for (let pair in Iterator(event)) {
+ let [evt, callback] = pair;
+ event[evt] = util.wrapCallback(function wrapper(event) {
+ this.removeEventListener(evt, wrapper.wrapper, capture);
+ return callback.apply(this, arguments);
+ }, true);
+ }
+
+ return this.each(function (elem) {
+ for (let [k, v] in Iterator(event))
+ elem.addEventListener(k, v, capture);
+ });
+ },
dispatch: function dispatch(event, params, extraProps) {
this.canceled = false;
@@ -945,21 +974,30 @@ var DOM = Class("DOM", {
// want to refer to within dactyl's source code for
// comparisons like if (key == "") { ... }
this.keyTable = {
- add: ["Plus", "Add"],
+ add: ["+", "Plus", "Add"],
+ back_quote: ["`"],
+ back_slash: ["\\"],
back_space: ["BS"],
+ comma: [","],
count: ["count"],
+ close_bracket: ["]"],
delete: ["Del"],
+ equals: ["="],
escape: ["Esc", "Escape"],
insert: ["Insert", "Ins"],
leader: ["Leader"],
left_shift: ["LT", "<"],
nop: ["Nop"],
+ open_bracket: ["["],
pass: ["Pass"],
+ period: ["."],
+ quote: ["'"],
return: ["Return", "CR", "Enter"],
right_shift: [">"],
+ semicolon: [";"],
slash: ["/"],
space: ["Space", " "],
- subtract: ["Minus", "Subtract"]
+ subtract: ["-", "Minus", "Subtract"]
};
this.key_key = {};
@@ -1176,7 +1214,9 @@ var DOM = Class("DOM", {
if (event.keyCode in this.code_key) {
key = this.code_key[event.keyCode];
- if (event.shiftKey && (key.length > 1 || event.ctrlKey || event.altKey || event.metaKey) || event.dactylShift)
+ if (event.shiftKey && (key.length > 1 || key.toUpperCase() == key.toLowerCase()
+ || event.ctrlKey || event.altKey || event.metaKey)
+ || event.dactylShift)
modifier += "S-";
else if (!modifier && key.length === 1)
if (event.shiftKey)
@@ -1530,12 +1570,16 @@ var DOM = Class("DOM", {
null
);
- return Object.create(result, {
- __iterator__: {
- value: asIterator ? function () { let elem; while ((elem = this.iterateNext())) yield elem; }
- : function () { for (let i = 0; i < this.snapshotLength; i++) yield this.snapshotItem(i); }
- }
- });
+ let res = {
+ iterateNext: function () result.iterateNext(),
+ get resultType() result.resultType,
+ get snapshotLength() result.snapshotLength,
+ snapshotItem: function (i) result.snapshotItem(i),
+ __iterator__:
+ asIterator ? function () { let elem; while ((elem = this.iterateNext())) yield elem; }
+ : function () { for (let i = 0; i < this.snapshotLength; i++) yield this.snapshotItem(i); }
+ };
+ return res;
}
catch (e) {
throw e.stack ? e : Error(e);
diff --git a/common/modules/downloads.jsm b/common/modules/downloads.jsm
index 03ab199..e4d2f11 100644
--- a/common/modules/downloads.jsm
+++ b/common/modules/downloads.jsm
@@ -9,6 +9,8 @@ defineModule("downloads", {
exports: ["Download", "Downloads", "downloads"]
}, this);
+this.lazyRequire("overlay", ["overlay"]);
+
Cu.import("resource://gre/modules/DownloadUtils.jsm", this);
let prefix = "DOWNLOAD_";
@@ -26,6 +28,8 @@ var Download = Class("Download", {
this.nodes = {
commandTarget: self
};
+ XML.ignoreWhitespace = true;
+ XML.prettyPrinting = false;
util.xmlToDom(