]> git.donarmstrong.com Git - dactyl.git/commitdiff
Import 1.0 supporting Firefox up to 14.* upstream/1.0
authorJérémy Bobbio <lunar@debian.org>
Sat, 28 Jul 2012 12:27:59 +0000 (14:27 +0200)
committerJérémy Bobbio <lunar@debian.org>
Sat, 28 Jul 2012 12:34:13 +0000 (14:34 +0200)
51 files changed:
.hg_archival.txt
common/Makefile
common/bootstrap.js
common/components/commandline-handler.js
common/content/bookmarks.js
common/content/browser.js
common/content/commandline.js
common/content/dactyl.js
common/content/editor.js
common/content/events.js
common/content/help.xsl
common/content/hints.js
common/content/mappings.js
common/content/modes.js
common/content/statusline.js
common/locale/en-US/buffer.xml
common/locale/en-US/developer.xml
common/locale/en-US/hints.xml
common/locale/en-US/map.xml
common/locale/en-US/marks.xml
common/locale/en-US/options.xml
common/modules/addons.jsm
common/modules/base.jsm
common/modules/bookmarkcache.jsm
common/modules/bootstrap.jsm
common/modules/buffer.jsm
common/modules/completion.jsm
common/modules/config.jsm
common/modules/contexts.jsm
common/modules/dom.jsm
common/modules/downloads.jsm
common/modules/finder.jsm
common/modules/help.jsm
common/modules/io.jsm
common/modules/javascript.jsm
common/modules/main.jsm
common/modules/messages.jsm
common/modules/options.jsm
common/modules/prefs.jsm
common/modules/protocol.jsm
common/modules/sanitizer.jsm
common/modules/services.jsm
common/modules/styles.jsm
common/modules/template.jsm
common/modules/util.jsm
common/skin/global-styles.css
common/tests/functional/testCommands.js
melodactyl/install.rdf
pentadactyl/NEWS
pentadactyl/install.rdf
teledactyl/install.rdf

index 50caf3ebda25aaf4306cf54224e76b342f10c161..826039724d912e76f0ab6938724f5de21976cf6c 100644 (file)
@@ -1,4 +1,4 @@
 repo: 373f1649c80dea9be7b5bc9c57e8395f94f93ab1
-node: 91d4f03a135efe65e2e7de46c00ef09c78fdaae3
-branch: default
-tag: pentadactyl-1.0rc1
+node: 227d1399fe7c9d8de98fc6ab3222cf9e1d8ad38f
+branch: pentadactyl-1.0-branch
+tag: pentadactyl-1.0
index ef118e804fc2be6aed3dd0ee4a5660c2d7e277bd..0251c4ab3ce210e14c1b17c5665c456052a80f88 100644 (file)
@@ -16,7 +16,7 @@ GOOGLE_PROJ   = dactyl
 GOOGLE       = https://$(GOOGLE_PROJ).googlecode.com/files
 VERSION             ?= $(shell $(SED) -n 's/.*em:version(>|=")(.*)["<].*/\2/p' $(TOP)/install.rdf | sed 1q)
 UUID                := $(shell $(SED) -n 's/.*em:id(>|=")(.*)["<].*/\2/p' $(TOP)/install.rdf | sed 1q)
-MANGLE      := $(shell date '+%s' | awk '{ printf "%x", $$1 }')
+MANGLE      := chrome
 MOZMILL       = mozmill
 HOSTAPP_PATH  = $(shell which $(HOSTAPP))
 TEST_DIR      = $(BASE)/tests/functional
@@ -50,9 +50,6 @@ XPI_NAME      = $(NAME)-$(VERSION)
 XPI           =  ../downloads/$(XPI_NAME).xpi
 XPI_PATH      = $(TOP)/$(XPI:%.xpi=%)
 
-RDF           = ../downloads/update.rdf
-RDF_IN        = $(RDF).in
-
 BUILD_DIR     = build.$(VERSION).$(OS)
 
 .SILENT:
@@ -78,7 +75,6 @@ help:
        @echo "  make install    - installs this source tree directly to your $(HOSTAPP) profile"
        @echo '                    set $$PROFILE to select a profile by name and $$PROFILEPATHS'
        @echo '                    to change the directory where profiles are searched'
-       @echo "  make release    - updates update.rdf (this is not for you)"
        @echo "  make dist       - uploads to Google Code (this is not for you)"
        @echo "  make clean      - clean up"
        @echo "  make distclean  - clean up more"
@@ -94,8 +90,6 @@ info:
 
 jar: $(JAR)
 
-release: $(XPI) $(RDF)
-
 # This is not for you!
 dist: $(XPI)
        @echo DIST $(XPI) $(GOOGLE)
@@ -160,13 +154,6 @@ install:
 installxpi: xpi
        $(HOSTAPP) $(XPI)
 
-$(RDF): $(RDF_IN) Makefile
-       @echo "Preparing release..."
-       $(SED) -e "s,@VERSION@,$(VERSION),g" \
-                  -e "s,@DATE@,$(BUILD_DATE),g" \
-                  < $< > $@
-       @echo "SUCCESS: $@"
-
 clean:
        @echo "General $(NAME) cleanup..."
        rm -f $(JAR) $(XPI)
index e029387cbea0e7a72404e9f3f9d59ec2793c471d..d81411ea2877bbb8558e89731af3a158efa59f30 100755 (executable)
@@ -195,8 +195,6 @@ function init() {
             break;
 
         case "resource":
-            var hardSuffix = /^[^\/]*/.exec(fields[2])[0];
-
             resources.push(fields[1], fields[1] + suffix);
             resourceProto.setSubstitution(fields[1], getURI(fields[2]));
             resourceProto.setSubstitution(fields[1] + suffix, getURI(fields[2]));
@@ -205,7 +203,7 @@ function init() {
 
     // Flush the cache if necessary, just to be paranoid
     let pref = "extensions.dactyl.cacheFlushCheck";
-    let val  = addon.version + "-" + hardSuffix;
+    let val  = addon.version;
     if (!Services.prefs.prefHasUserValue(pref) || Services.prefs.getCharPref(pref) != val) {
         var cacheFlush = true;
         Services.obs.notifyObservers(null, "startupcache-invalidate", "");
index 0fd118958e77d4b873c26ed3e8da0b65f6152f9e..738e27516d084a8a2f711c7ac28c1a59fe90a0f1 100644 (file)
@@ -73,9 +73,9 @@ CommandLineHandler.prototype = {
                 util.dactyl.execute(remote);
             }
         }
-        catch(e) {
-            util.reportError(e)
-        };
+        catch (e) {
+            util.reportError(e);
+        }
 
         try {
             this.optionValue = commandLine.handleFlagWithParam(config.name, false);
index ca1bdb001d9b3743cf1d2478b7588d20b60e407a..195bee664cfd3673e13bf2c0e51c4079ec59235e 100644 (file)
@@ -15,13 +15,13 @@ var Bookmarks = Module("bookmarks", {
 
         storage.addObserver("bookmark-cache", function (key, event, arg) {
             if (["add", "change", "remove"].indexOf(event) >= 0)
-                autocommands.trigger("Bookmark" + event[0].toUpperCase() + event.substr(1),
+                autocommands.trigger("Bookmark" + util.capitalize(event),
                      iter({
                          bookmark: {
                              toString: function () "bookmarkcache.bookmarks[" + arg.id + "]",
                              valueOf: function () arg
                          }
-                     }, arg));
+                     }, arg).toObject());
             bookmarks.timer.tell();
         }, window);
     },
@@ -345,11 +345,12 @@ var Bookmarks = Module("bookmarks", {
                 catch (e) {}
 
             if (charset)
-                var encodedParam = escape(window.convertFromUnicode(charset, param));
+                var encodedParam = escape(window.convertFromUnicode(charset, param)).replace(/\+/g, encodeURIComponent);
             else
-                encodedParam = bookmarkcache.keywords[keyword].encodeURIComponent(param);
+                encodedParam = bookmarkcache.keywords[keyword.toLowerCase()].encodeURIComponent(param);
 
-            url = url.replace(/%s/g, encodedParam).replace(/%S/g, param);
+            url = url.replace(/%s/g, function () encodedParam)
+                     .replace(/%S/g, function () param);
             if (/%s/i.test(data))
                 postData = window.getPostDataStream(data, param, encodedParam, "application/x-www-form-urlencoded");
         }
@@ -472,7 +473,7 @@ var Bookmarks = Module("bookmarks", {
                 let updated = bookmarks.add(opts);
                 let action  = updated ? "updated" : "added";
 
-                let extra   = (opts.title == opts.url) ? "" : " (" + opts.title + ")";
+                let extra   = (opts.title && opts.title != opts.url) ? " (" + opts.title + ")" : "";
 
                 dactyl.echomsg({ domains: [util.getHost(opts.url)], message: _("bookmark." + action, opts.url + extra) },
                                1, commandline.FORCE_SINGLELINE);
@@ -707,6 +708,9 @@ var Bookmarks = Module("bookmarks", {
                 ctxt.compare = CompletionContext.Sort.unsorted;
                 ctxt.filterFunc = null;
 
+                if (ctxt.waitingForTab)
+                    return;
+
                 let words = ctxt.filter.toLowerCase().split(/\s+/g);
                 ctxt.completions = ctxt.completions.filter(function (i) words.every(function (w) i.toLowerCase().indexOf(w) >= 0));
 
index cee3adbc67cc62cf42db6c15ff89f6929bd3143f..cc504ff12b97ba7c742b0a7827d0c0a8409397e4 100644 (file)
@@ -180,7 +180,7 @@ var Browser = Module("browser", XPCOM(Ci.nsISupportsWeakReference, ModuleBase),
         setOverLink: util.wrapCallback(function setOverLink(link, b) {
             setOverLink.superapply(this, arguments);
             dactyl.triggerObserver("browser.overLink", link);
-        }),
+        })
     }
 }, {
 }, {
@@ -204,6 +204,7 @@ var Browser = Module("browser", XPCOM(Ci.nsISupportsWeakReference, ModuleBase),
             function () {
                 window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
                       .redraw();
+                statusline.overLink = null;
                 statusline.updateStatus();
                 commandline.clear();
             },
index 895ae4db847ac04ebc4fface42c38b8e6c44209d..c318759626db4b8df5accd6c6466c13b0ee1abdf 100644 (file)
@@ -282,9 +282,12 @@ var CommandWidgets = Class("CommandWidgets", {
     contextMenu: Class.Memoize(function () {
         ["copy", "copylink", "selectall"].forEach(function (tail) {
             // some host apps use "hostPrefixContext-copy" ids
-            let xpath = "//xul:menuitem[contains(@id, '" + "ontext-" + tail + "') and not(starts-with(@id, 'dactyl-'))]";
-            document.getElementById("dactyl-context-" + tail).style.listStyleImage =
-                DOM(DOM.XPath(xpath, document).snapshotItem(0)).style.listStyleImage;
+            let css   = "menuitem[id$='ontext-" + tail + "']:not([id^=dactyl-])";
+            let style = DOM(css, document).style;
+            DOM("#dactyl-context-" + tail, document).css({
+                listStyleImage: style.listStyleImage,
+                MozImageRegion: style.MozImageRegion
+            });
         });
         return document.getElementById("dactyl-contextmenu");
     }),
@@ -753,9 +756,7 @@ var CommandLine = Module("commandline", {
             data = message.message;
         }
 
-        if ((flags & this.ACTIVE_WINDOW) &&
-            window != services.windowWatcher.activeWindow &&
-            services.windowWatcher.activeWindow.dactyl)
+        if ((flags & this.ACTIVE_WINDOW) && window != overlay.activeWindow)
             return;
 
         if ((flags & this.DISALLOW_MULTILINE) && !this.widgets.mowContainer.collapsed)
@@ -1217,6 +1218,7 @@ var CommandLine = Module("commandline", {
         complete: function complete(show, tabPressed) {
             this.session.ignoredCount = 0;
 
+            this.waiting = null;
             this.context.reset();
             this.context.tabPressed = tabPressed;
 
@@ -1487,8 +1489,12 @@ var CommandLine = Module("commandline", {
                 this.wildIndex = this.wildtypes.length - 1;
 
             if (idx && idx[1] >= idx[0].items.length) {
-                this.waiting = idx;
-                statusline.progress = _("completion.waitingForResults");
+                if (!idx[0].incomplete)
+                    this.waiting = null;
+                else {
+                    this.waiting = idx;
+                    statusline.progress = _("completion.waitingForResults");
+                }
                 return;
             }
 
@@ -1669,6 +1675,7 @@ var CommandLine = Module("commandline", {
         });
 
         modes.addMode("INPUT_MULTILINE", {
+            description: "Active when the command line's multiline input buffer is open",
             bases: [modes.INSERT]
         });
     },
@@ -1945,6 +1952,7 @@ var ItemList = Class("ItemList", {
             // Check if we've passed any incomplete contexts
 
             let i = groups.indexOf(group);
+            util.assert(i >= 0, undefined, false);
             for (; i < groups.length; i++) {
                 let end = groups[i].offsets.start + groups[i].itemCount;
                 if (start >= end && groups[i].context.incomplete)
index dc9df88be5fd42c2adfc36014e01c939a3d56bb8..2933dcd95d2a35e65ef0a1794d507e6b37188c3c 100644 (file)
@@ -887,11 +887,15 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      * Opens one or more URLs. Returns true when load was initiated, or
      * false on error.
      *
-     * @param {string|object|Array} urls A representation of the URLs to open. May be
-     *     either a string, which will be passed to
-     *     {@link Dactyl#parseURLs}, an array in the same format as
-     *     would be returned by the same, or an object as returned by
-     *     {@link DOM#formData}.
+     * @param {string|Array} urls A representation of the URLs to open.
+     *     A string will be passed to {@link Dactyl#parseURLs}. An array may
+     *     contain elements of the following forms:
+     *
+     *      • {string}                    A URL to open.
+     *      • {[string, {string|Array}]}  Pair of a URL and POST data.
+     *      • {object}                    Object compatible with those returned
+     *                                    by {@link DOM#formData}.
+     *
      * @param {object} params A set of parameters specifying how to open the
      *     URLs. The following properties are recognized:
      *
@@ -952,6 +956,18 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                     loc = { url: loc[0], postData: loc[1] };
                 else if (isString(loc))
                     loc = { url: loc };
+                else
+                    loc = Object.create(loc);
+
+                if (isString(loc.postData))
+                    loc.postData = ["application/x-www-form-urlencoded", loc.postData];
+
+                if (isArray(loc.postData)) {
+                    let stream = services.MIMEStream(services.StringStream(loc.postData[1]));
+                    stream.addHeader("Content-Type", loc.postData[0]);
+                    stream.addContentLength = true;
+                    loc.postData = stream;
+                }
 
                 // decide where to load the first url
                 switch (where) {
@@ -1939,7 +1955,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                 if (dactyl.commandLineOptions.rcFile == "NONE" || dactyl.commandLineOptions.noPlugins)
                     options["loadplugins"] = [];
 
-                if (options["loadplugins"])
+                if (options["loadplugins"].length)
                     dactyl.loadPlugins();
             }
             catch (e) {
index 262391ece5c0696b42388e4cc65c8082146a2764..63ec3eb675b3e65fc32443f9365e445dcb9abee7 100644 (file)
@@ -280,7 +280,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
         }
     },
 
-    findChar: function findNumber(key, count, backward, offset) {
+    findChar: function findChar(key, count, backward, offset) {
         count  = count || 1; // XXX ?
         offset = (offset || 0) - !!backward;
 
@@ -455,7 +455,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
             if (textBox) {
                 textBox.value = val;
 
-                if (false) {
+                if (true) {
                     let elem = DOM(textBox);
                     elem.attrNS(NS, "modifiable", true)
                         .style.MozUserInput;
@@ -783,14 +783,16 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
             preExecute: function preExecute(args) {
                 if (editor.editor && !this.editor) {
                     this.editor = editor.editor;
-                    this.editor.beginTransaction();
+                    if (!this.noTransaction)
+                        this.editor.beginTransaction();
                 }
                 editor.inEditMap = true;
             },
             postExecute: function preExecute(args) {
                 editor.inEditMap = false;
                 if (this.editor) {
-                    this.editor.endTransaction();
+                    if (!this.noTransaction)
+                        this.editor.endTransaction();
                     this.editor = null;
                 }
             },
@@ -1158,17 +1160,17 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
         // text edit mode
         bind(["u"], "Undo changes",
              function (args) {
-                 editor.executeCommand("cmd_undo", Math.max(args.count, 1));
+                 editor.editor.undo(Math.max(args.count, 1));
                  editor.deselect();
              },
-             { count: true });
+             { count: true, noTransaction: true });
 
         bind(["<C-r>"], "Redo undone changes",
              function (args) {
-                 editor.executeCommand("cmd_redo", Math.max(args.count, 1));
+                 editor.editor.redo(Math.max(args.count, 1));
                  editor.deselect();
              },
-             { count: true });
+             { count: true, noTransaction: true });
 
         bind(["D"], "Delete characters from the cursor to the end of the line",
              function () { editor.executeCommand("cmd_deleteToEndOfLine"); });
index 4b1841d916036233bf06ffe07537fbcfc4bf8573..ac846d8ce1cb38cab38a91e81e9dfe02fe6937dc 100644 (file)
@@ -116,7 +116,7 @@ var Events = Module("events", {
         });
 
         this._fullscreen = window.fullScreen;
-        this._lastFocus = null;
+        this._lastFocus = { get: function () null };
         this._macroKeys = [];
         this._lastMacro = "";
 
@@ -143,7 +143,7 @@ var Events = Module("events", {
                         this.active.push(elem);
                 }
 
-                this.active = this.active.filter(function (e) e.popupBoxObject.popupState != "closed");
+                this.active = this.active.filter(function (e) e.popupBoxObject && e.popupBoxObject.popupState != "closed");
 
                 if (!this.active.length && !this.activeMenubar)
                     modes.remove(modes.MENU, true);
@@ -372,8 +372,6 @@ var Events = Module("events", {
             if (quiet)
                 commandline.quiet = quiet;
 
-            keys = mappings.expandLeader(keys);
-
             for (let [, evt_obj] in Iterator(DOM.Event.parse(keys))) {
                 let now = Date.now();
                 let key = DOM.Event.stringify(evt_obj);
@@ -625,7 +623,7 @@ var Events = Module("events", {
             }
 
             if (elem instanceof Element)
-                elem.dactylFocusAllowed = undefined;
+                delete overlay.getData(elem)["focus-allowed"];
         },
 
         /*
@@ -795,9 +793,10 @@ var Events = Module("events", {
                     !this.processor && event.type === "keydown"
                         && options.get("passunknown").getKey(modes.main.allBases)
                         && let (key = DOM.Event.stringify(event))
-                            !modes.main.allBases.some(
+                            !(modes.main.count && /^\d$/.test(key) ||
+                              modes.main.allBases.some(
                                 function (mode) mappings.hives.some(
-                                    function (hive) hive.get(mode, key) || hive.getCandidates(mode, key)));
+                                    function (hive) hive.get(mode, key) || hive.getCandidates(mode, key))));
 
             events.dbg("ON " + event.type.toUpperCase() + " " + DOM.Event.stringify(event) +
                        " passing: " + this.passing + " " +
@@ -902,20 +901,22 @@ var Events = Module("events", {
             }
 
             let urlbar = document.getElementById("urlbar");
-            if (elem == null && urlbar && urlbar.inputField == this._lastFocus)
+            if (elem == null && urlbar && urlbar.inputField == this._lastFocus.get())
                 util.threadYield(true); // Why? --Kris
 
             while (modes.main.ownsFocus
-                    && modes.topOfStack.params.ownsFocus != elem
-                    && modes.topOfStack.params.ownsFocus != win
+                    && let ({ ownsFocus } = modes.topOfStack.params)
+                         (!ownsFocus ||
+                             ownsFocus.get() != elem &&
+                             ownsFocus.get() != win)
                     && !modes.topOfStack.params.holdFocus)
                  modes.pop(null, { fromFocus: true });
         }
         finally {
-            this._lastFocus = elem;
+            this._lastFocus = util.weakReference(elem);
 
             if (modes.main.ownsFocus)
-                modes.topOfStack.params.ownsFocus = elem;
+                modes.topOfStack.params.ownsFocus = util.weakReference(elem);
         }
     }),
 
index f1dfce9eb684486e2879cbd3c22d37dbc29b56f6..0cc36139428f2aacee7972c2e9802c5c939e860d 100644 (file)
         <xsl:param name="contents" select="text()"/>
         <xsl:variable name="tag" select="$contents"/>
         <xsl:variable name="tag-url" select="
-          regexp:replace(regexp:replace($tag, '%', 'g', '%25'),
-                         '#', 'g', '%23')"/>
+          regexp:replace(regexp:replace(regexp:replace($tag, '%', 'g', '%25'),
+                                        '#', 'g', '%23'),
+                         ';', 'g', '%3B')"/>
 
         <a style="color: inherit;">
             <xsl:if test="not(@link) or @link != 'false'">
index 004f90716208469a8c42eaa10e952bb680ed1f91..96fe44acbbbfa5399fa2a7aed63596d6fa999051 100644 (file)
@@ -301,7 +301,8 @@ var HintSession = Class("HintSession", CommandMode, {
 
             if (!rect.width || !rect.height)
                 if (!Array.some(elem.childNodes, function (elem) elem instanceof Element && DOM(elem).style.float != "none" && isVisible(elem)))
-                    return false;
+                    if (elem.textContent || !elem.name)
+                        return false;
 
             let computedStyle = doc.defaultView.getComputedStyle(elem, null);
             if (computedStyle.visibility != "visible" || computedStyle.display == "none")
@@ -532,6 +533,7 @@ var HintSession = Class("HintSession", CommandMode, {
      */
     removeHints: function _removeHints(timeout) {
         for (let { doc, start, end } in values(this.docs)) {
+            DOM(doc.documentElement).highlight.remove("Hinting");
             // Goddamn stupid fucking Gecko 1.x security manager bullshit.
             try { delete doc.dactylLabels; } catch (e) { doc.dactylLabels = undefined; }
 
@@ -574,6 +576,7 @@ var HintSession = Class("HintSession", CommandMode, {
         this.validHints = [];
 
         for (let { doc, start, end } in values(this.docs)) {
+            DOM(doc.documentElement).highlight.add("Hinting");
             let [offsetX, offsetY] = this.getContainerOffsets(doc);
 
         inner:
@@ -590,13 +593,13 @@ var HintSession = Class("HintSession", CommandMode, {
                         if (!rect)
                             continue;
 
-                        hint.imgSpan = util.xmlToDom(<span highlight="Hint" dactyl:hl="HintImage" xmlns:dactyl={NS}/>, doc);
-                        hint.imgSpan.style.display = "none";
-                        hint.imgSpan.style.left = (rect.left + offsetX) + "px";
-                        hint.imgSpan.style.top = (rect.top + offsetY) + "px";
-                        hint.imgSpan.style.width = (rect.right - rect.left) + "px";
-                        hint.imgSpan.style.height = (rect.bottom - rect.top) + "px";
-                        hint.span.parentNode.appendChild(hint.imgSpan);
+                        hint.imgSpan = DOM(<span highlight="Hint" dactyl:hl="HintImage" xmlns:dactyl={NS}/>, doc).css({
+                            display: "none",
+                            left: (rect.left + offsetX) + "px",
+                            top: (rect.top + offsetY) + "px",
+                            width: (rect.right - rect.left) + "px",
+                            height: (rect.bottom - rect.top) + "px"
+                        }).appendTo(hint.span.parentNode)[0];
                     }
                 }
 
@@ -720,7 +723,7 @@ var HintSession = Class("HintSession", CommandMode, {
      * Display the current status to the user.
      */
     updateStatusline: function _updateStatusline() {
-        statusline.inputBuffer = (this.escapeNumbers ? options["mapleader"] : "") +
+        statusline.inputBuffer = (this.escapeNumbers ? "\\" : "") +
                                  (this.hintNumber ? this.getHintString(this.hintNumber) : "");
     },
 });
@@ -759,6 +762,11 @@ var Hints = Module("hints", {
         this.addMode("V", "View hint source in external editor",  function (elem, loc) buffer.viewSource(loc, true));
         this.addMode("y", "Yank hint location",                   function (elem, loc) editor.setRegister(null, loc, true));
         this.addMode("Y", "Yank hint description",                function (elem) editor.setRegister(null, elem.textContent || "", true));
+        this.addMode("A", "Yank hint anchor url",                 function (elem) {
+            let uri = elem.ownerDocument.documentURIObject.clone();
+            uri.ref = elem.id || elem.name;
+            dactyl.clipboardWrite(uri.spec, true);
+        });
         this.addMode("c", "Open context menu",                    function (elem) DOM(elem).contextmenu());
         this.addMode("i", "Show image",                           function (elem) dactyl.open(elem.src));
         this.addMode("I", "Show image in a new tab",              function (elem) dactyl.open(elem.src, dactyl.NEW_TAB));
@@ -1020,7 +1028,7 @@ var Hints = Module("hints", {
 
         let indexOf = String.indexOf;
         if (options.get("hintmatching").has("transliterated"))
-            indexOf = Hints.indexOf;
+            indexOf = Hints.closure.indexOf;
 
         switch (options["hintmatching"][0]) {
         case "contains"      : return containsMatcher(hintString);
@@ -1169,7 +1177,7 @@ var Hints = Module("hints", {
             [0x24d0, 0x24e9, "a"],
             [0xfb00, 0xfb06, ["ff", "fi", "fl", "ffi", "ffl", "st", "st"]],
             [0xff21, 0xff3a, "A"], [0xff41, 0xff5a, "a"]
-        ].forEach(function (start, stop, val) {
+        ].forEach(function ([start, stop, val]) {
             if (typeof val != "string")
                 for (let i = start; i <= stop; i++)
                     table[String.fromCharCode(i)] = val[(i - start) % val.length];
@@ -1187,7 +1195,7 @@ var Hints = Module("hints", {
         if (src.length == 0)
             return 0;
     outer:
-        for (var i = 0; i < end; i++) {
+        for (var i = 0; i <= end; i++) {
                 var j = i;
                 for (var k = 0; k < src.length;) {
                     var s = dest[j++];
@@ -1259,7 +1267,7 @@ var Hints = Module("hints", {
             "Delete the previous character",
             function ({ self }) self.backspace());
 
-        bind(["<Leader>"],
+        bind(["\\"],
             "Toggle hint filtering",
             function ({ self }) { self.escapeNumbers = !self.escapeNumbers; });
     },
@@ -1267,8 +1275,10 @@ var Hints = Module("hints", {
         options.add(["extendedhinttags", "eht"],
             "XPath or CSS selector strings of hintable elements for extended hint modes",
             "regexpmap", {
+                // Make sure to update the docs when you change this.
                 "[iI]": "img",
                 "[asOTvVWy]": [":-moz-any-link", "area[href]", "img[src]", "iframe[src]"],
+                "[A]": ["[id]", "a[name]"],
                 "[f]": "body",
                 "[F]": ["body", "code", "div", "html", "p", "pre", "span"],
                 "[S]": ["input:not([type=hidden])", "textarea", "button", "select"]
@@ -1278,16 +1288,19 @@ var Hints = Module("hints", {
                 getKey: function (val, default_)
                     let (res = array.nth(this.value, function (re) let (match = re.exec(val)) match && match[0] == val, 0))
                         res ? res.matcher : default_,
-                setter: function (vals) {
+                parse: function parse(val) {
+                    let vals = parse.supercall(this, val);
                     for (let value in values(vals))
                         value.matcher = DOM.compileMatcher(Option.splitList(value.result));
                     return vals;
                 },
+                testValues: function testValues(vals, validator) vals.every(function (re) Option.splitList(re).every(validator)),
                 validator: DOM.validateMatcher
             });
 
         options.add(["hinttags", "ht"],
             "XPath or CSS selector strings of hintable elements for Hints mode",
+            // Make sure to update the docs when you change this.
             "stringlist", ":-moz-any-link,area,button,iframe,input:not([type=hidden]),select,textarea," +
                           "[onclick],[onmouseover],[onmousedown],[onmouseup],[oncommand]," +
                           "[tabindex],[role=link],[role=button],[contenteditable=true]",
index 149f3fb86c170e264d2b03435e6e57e03b59b1f3..f14b3d2f5fbbbf2a004b8396beaf926fc83824d6 100644 (file)
@@ -355,7 +355,7 @@ var Mappings = Module("mappings", {
 
     get userHives() this.allHives.filter(function (h) h !== this.builtin, this),
 
-    expandLeader: function expandLeader(keyString) keyString.replace(/<Leader>/i, function () options["mapleader"]),
+    expandLeader: deprecated("your brain", function expandLeader(keyString) keyString),
 
     prefixes: Class.Memoize(function () {
         let list = Array.map("CASM", function (s) s + "-");
@@ -365,8 +365,6 @@ var Mappings = Module("mappings", {
     }),
 
     expand: function expand(keys) {
-        keys = keys.replace(/<leader>/i, options["mapleader"]);
-
         if (!/<\*-/.test(keys))
             var res = keys;
         else
@@ -541,7 +539,7 @@ var Mappings = Module("mappings", {
                     args["-builtin"] = true;
 
                 if (!rhs) // list the mapping
-                    mappings.list(mapmodes, mappings.expandLeader(lhs), hives);
+                    mappings.list(mapmodes, lhs, hives);
                 else {
                     util.assert(args["-group"].modifiable,
                                 _("map.builtinImmutable"));
@@ -659,7 +657,7 @@ var Mappings = Module("mappings", {
             commands.add([ch + "no[remap]"],
                 "Map a key sequence without remapping keys" + modeDescription,
                 function (args) { map(args, true); },
-                update({}, opts));
+                update({ deprecated: ":" + ch + "map -builtin" }, opts));
 
             commands.add([ch + "unm[ap]"],
                 "Remove a mapping" + modeDescription,
@@ -828,18 +826,10 @@ var Mappings = Module("mappings", {
                 function (context, obj, args) [[m.names, m.description] for (m in this.iterate(args[0]))]
             ]);
     },
-    options: function initOptions(dactyl, modules, window) {
-        options.add(["mapleader", "ml"],
-            "Define the replacement keys for the <Leader> pseudo-key",
-            "string", "\\", {
-                setter: function (value) {
-                    if (this.hasChanged)
-                        for (let hive in values(mappings.allHives))
-                            for (let stack in values(hive.stacks))
-                                delete stack.states;
-                    return value;
-                }
-            });
+    mappings: function initMappings(dactyl, modules, window) {
+        mappings.add([modes.COMMAND],
+             ["\\"], "Emits <Leader> pseudo-key",
+             function () { events.feedkeys("<Leader>") });
     }
 });
 
index 50b2ee5b16f4570025d76636cb7bf1ebc74f70ca..127fa95a9f89b716c4e735c556e1bc9215408813 100644 (file)
@@ -119,7 +119,7 @@ var Modes = Module("modes", {
             onKeyPress: function (events) { if (modes.main == modes.QUOTE) modes.pop(); }
         });
         this.addMode("IGNORE", { hidden: true }, {
-            onKeyPress: function (events) Events.KILL,
+            onKeyPress: function (events) false,
             bases: [],
             passthrough: true
         });
@@ -299,7 +299,7 @@ var Modes = Module("modes", {
             return;
         }
 
-        params = params || this.getMode(mainMode || this.main).params;
+        params = params || Object.create(this.getMode(mainMode || this.main).params);
 
         if (!stack && mainMode != null && this._modeStack.length > 1)
             this.reset();
index 8eefc33ecd7f2878d0e2684a7dabd5181a297844..5b7d2a8898696d69d6231bfa1e9972de07cc0a87 100644 (file)
@@ -110,9 +110,11 @@ var StatusLine = Module("statusline", {
         "browser.overLink": function (link) {
             switch (options["showstatuslinks"]) {
             case "status":
+                this.overLink = link ? _("status.link", link) : null;
                 this.status = link ? _("status.link", link) : buffer.uri;
                 break;
             case "command":
+                this.overLink = null;
                 if (link)
                     dactyl.echo(_("status.link", link), commandline.FORCE_SINGLELINE);
                 else
@@ -250,7 +252,7 @@ var StatusLine = Module("statusline", {
 
     updateStatus: function updateStatus() {
         this.timeout(function () {
-            this.status = buffer.uri;
+            this.status = this.overLink || buffer.uri;
         });
     },
 
index 42462c72db782fbbbabc12016bc0688457708555..38673a5859ce94a1d629bf5668a310747aa13bdb 100644 (file)
 
 <item>
     <tags>&lt;yank-location> y</tags>
+    <strut/>
     <spec>y</spec>
-    <description short="true">
-        <p>Yank current location to the clipboard.</p>
+    <description>
+        <p>Yank current location to the clipboard. See also
+            <o>yankshort</o>.</p>
     </description>
 </item>
 
index 869d4c431075dfe15050a7eb4e81c3942ce0705d..9925d02b58128a7340f49ba49c37ce3d556c5c11 100644 (file)
@@ -191,7 +191,7 @@ XML.prettyPrinting   = <hl key="Boolean">false</hl>;
 <hl key="HelpXMLTagStart">&lt;plugin
     <hl key="HelpXMLAttribute">name</hl><hl key="HelpXMLString">flashblock</hl>
     <hl key="HelpXMLAttribute">version</hl><hl key="HelpXMLString">1.0</hl>
-    <hl key="HelpXMLAttribute">href</hl><hl key="HelpXMLString">http://dactyl.sf.net/pentadactyl/plugins#flashblock-plugin</hl>
+    <hl key="HelpXMLAttribute">href</hl><hl key="HelpXMLString">http://5digits.org/pentadactyl/plugins#flashblock-plugin</hl>
     <hl key="HelpXMLAttribute">summary</hl><hl key="HelpXMLString">Flash Blocker</hl>
     <hl key="HelpXMLAttribute">xmlns</hl>{NS}></hl></escape>
     <author email="maglione.k@gmail.com">Kris Maglione</author>
index 769f7da727af9e460addccbebbc0930cb6f218fa..ab5dc32a36a88c0b20fb54d520d539192abaf492 100644 (file)
@@ -48,7 +48,7 @@
             <dt><k name="Tab"/></dt>
             <dd>Moves the focus to the next hintable element</dd>
 
-            <dt><k name="Leader"/></dt>
+            <dt><k>\</k></dt>
             <dd>Temporarily treats all numbers (or other keys, depending on the
                 value of <o>hintkeys</o>) as ordinary text</dd>
 
             <li tag=";V"><em>V</em> to view its destination source in the external editor</li>
             <li tag=";y"><em>y</em> to yank its destination location</li>
             <li tag=";Y"><em>Y</em> to yank its text description</li>
+            <li tag=";A"><em>A</em> to yank its anchor URL</li>
             <li tag=";c"><em>c</em> to open its context menu</li>
             <li tag=";i"><em>i</em> to open an image</li>
             <li tag=";I"><em>I</em> to open an image in a new tab.</li>
index 9ff5c88bbd0dff244a4c5de3b983aaad69f55898..d082024a93714d93229decafedea8ff63f944ff1 100644 (file)
 </dl>
 
 <p>
-    The ordinary <ex>:map</ex> and <ex>:noremap</ex> commands
-    add mappings for Normal and Visual mode. In order to map key
-    bindings in a different mode, any of the mapping commands may be
-    prefixed with one of the above letters. For instance,
+    The ordinary <ex>:map</ex> command adds mappings for Normal and Visual
+    mode. In order to map key bindings in a different mode, any of the mapping
+    commands may be prefixed with one of the above letters. For instance,
     <ex>:imap</ex> creates a new key mapping in Insert mode, while
-    <ex>:cunmap</ex> removes a key mapping from Command Line mode.
-    Other modes can be specified using the <em>-modes</em> option described below.
+    <ex>:cunmap</ex> removes a key mapping from Command Line mode. Other modes
+    can be specified using the <em>-modes</em> option described below.
 </p>
 
 <warning>
 </p>
 
 <dl dt="width: 20em;">
-    <dt>:map   :noremap   :unmap</dt>  <dd>Normal and Visual modes</dd>
-    <dt>:nmap  :nnoremap  :nunmap</dt> <dd>Normal mode</dd>
-    <dt>:vmap  :vnoremap  :vunmap</dt> <dd>Visual mode</dd>
-    <dt>:imap  :inoremap  :iunmap</dt> <dd>Insert mode</dd>
-    <dt>:tmap  :tnoremap  :tunmap</dt> <dd>Text Edit mode</dd>
-    <dt>:cmap  :cnoremap  :cunmap</dt> <dd>Command Line mode</dd>
+    <dt>:map   :unmap</dt>  <dd>Normal and Visual modes</dd>
+    <dt>:nmap  :nunmap</dt> <dd>Normal mode</dd>
+    <dt>:vmap  :vunmap</dt> <dd>Visual mode</dd>
+    <dt>:imap  :iunmap</dt> <dd>Insert mode</dd>
+    <dt>:tmap  :tunmap</dt> <dd>Text Edit mode</dd>
+    <dt>:cmap  :cunmap</dt> <dd>Command Line mode</dd>
 </dl>
 
 <note>
     <tags>:cno :cnoremap</tags>
     <spec>:cno<oa>remap</oa> <a>lhs</a> <a>rhs</a></spec>
     <description>
+        <deprecated>These aliases are deprecated. The <em>-builtin</em> flag
+            should be used in their stead.</deprecated>
         <p>
             Map the <t>key-sequence</t> <a>lhs</a> to <a>rhs</a> for
             the applicable mode(s). The keys in <a>rhs</a> do not
     </description>
 </item>
 
+<item>
+    <tags><![CDATA['mapleader' <Leader>]]></tags>
+    <strut/>
+    <spec><![CDATA[<Leader>]]></spec>
+    <description>
+        <p>
+            An arbitrary and meaningless key that some people seem
+            attached to. The <k>\</k> 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.
+        </p>
+
+        <code><ex>:map , <k name="Leader"/></ex>
+<ex>:map ; <k name="AwesomestLeaderEver"/></ex>
+
+<ex>:map <k name="Leader"/>k <key>-js</key> doStuff()</ex>
+<ex>:map <k name="AwesomestLeaderEver"/>k <key>-js</key> doOtherReallyNiftyStuff()</ex></code>
+
+        <p>
+            Needless to say this behavior is considered childish and
+            discouraged.
+        </p>
+    </description>
+</item>
+
 <item>
     <tags><![CDATA[<Pass>]]></tags>
     <spec><![CDATA[<Pass>]]></spec>
     </description>
 </item>
 
-<item>
-    <tags><![CDATA[<Leader> \]]></tags>
-    <strut/>
-    <spec><![CDATA[<Leader>]]></spec>
-    <description>
-        <p>
-            A pseudo-key which expands to the value of the <o>mapleader</o>
-            option. For example, by default,
-        </p>
-        <code><ex>:map <k name="Leader"/>h</ex> <ex>:echo <str>Hello</str><k name="CR"/></ex></code>
-        <p>works like</p>
-        <code><ex>:map \h</ex> <ex>:echo <str>Hello</str><k name="CR"/></ex></code>
-        <p>but after</p>
-        <set opt="mapleader"><str>,</str></set>
-        <p>it works like</p>
-        <code><ex>:map ,h</ex> <ex>:echo <str>Hello</str><k name="CR"/></ex></code>
-    </description>
-</item>
-
 <h3 tag="map-examples">Mapping examples</h3>
 
 <p>Make <k name="A-n" link="false"/> do the same as <k name="Down" link="false"/> in input <t>modes</t>:</p>
index 75aaf29a5cc2bed61f3be30bf9c6b783dcae6499..154c4293bce5a7f21493eba48df376d391fea9ae 100644 (file)
     <spec>:bmarks<oa>!</oa> <oa>filter</oa></spec>
     <description>
         <p>
-            List or open multiple bookmarks. Opens the message window
-            at the bottom of the screen with all bookmarks with
-            titles or URLs matching <oa>filter</oa>. The resulting
-            URLs can be clicked, or accessed via extended hint modes
-            such as <k>;o</k>.
+            List or open multiple bookmarks. Opens the message window at the
+            bottom of the screen with all bookmarks with URLs matching
+            <oa>filter</oa>. The resulting URLs can be clicked, or accessed via
+            extended hint modes such as <k>;o</k>.
         </p>
 
         <p>
 <p>
     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.
 </p>
 
     <spec>:qmark <a>a-zA-Z0-9</a> <a>url</a></spec>
     <description>
         <p>
-            Mark <a>url</a> with a letter for quick access. See also
+            Mark <a>url</a> with a letter or digit for quick access. See also
             <k>go</k>, <k>gn</k>, and <k>M</k>.
         </p>
 
index 6de3231b5065d8c795fa4698ad07499ad8e14672..b48c5047740270f10e4e5765fba0c3ebe69ff83e 100644 (file)
 </p>
 
 <dl dt="width: 10em;">
-    <dt>boolean</dt>       <dd>Can only be <hl key="Boolean">on</hl> or <hl key="Boolean">off</hl></dd>
+    <dt/><dd tag="boolean"/>
+    <dt>boolean</dt>
+    <dd>
+        Can only be <hl key="Boolean">on</hl> (<ex>:set <a>option</a></ex>) or
+        <hl key="Boolean">off</hl> (<ex>:set no<a>option</a></ex>)
+    </dd>
+
     <dt>number</dt>        <dd>A numeric value</dd>
     <dt>string</dt>        <dd>A string value</dd>
 
     <strut/>
     <type>&option.extendedhinttags.type;</type>
     <default>[asOTvVWy]:':-moz-any-link',area[href],img[src],iframe[src],
+          [A]:[id],a[name],
           [f]:body,
           [F]:body,code,div,html,p,pre,span,
           [iI]:img,
     <tags>'ln' 'linenumbers'</tags>
     <spec>'linenumbers' 'ln'</spec>
     <type>&option.linenumbers.type;</type>
-    <default>&option.linenumbers.default;</default>
+    <default><![CDATA['view-source:*':[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']]></default>
     <description>
         <p>
             Patterns used to determine line numbers used by <k>G</k>. May be
-            either a selector expression as accepted by <o>hinttags</o>, in
-            which case the first matching element whose text content is equal to
-            the desired line number is used or the <oa>count</oa>th element
-            failing that, or the string <str delim="'">func:</str> 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 <o>hinttags</o>, or the
+            string <str delim="'">func:</str> 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 <oa>count</oa>th
+            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.
         </p>
     </description>
 </item>
     </description>
 </item>
 
-<item>
-    <tags>'ml' 'mapleader'</tags>
-    <spec>'mapleader' 'ml'</spec>
-    <type>&option.mapleader.type;</type>
-    <default>&option.mapleader.default;</default>
-    <description>
-        <p>Defines the replacement keys for the <k name="Leader"/> pseudo-key.</p>
-    </description>
-</item>
-
 <item>
     <tags>'maxitems'</tags>
     <spec>'maxitems'</spec>
     <description>
         <p>
             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 <t>site-filter</t>, 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
 
         <ul>
             <li>colors/</li>
-            <li>macros/</li>
             <li>plugins/</li>
         </ul>
 
         <p>
             The regular expression used to split URL lists in commands
             like <ex>:open</ex>. 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):
         </p>
         <code><ex>:open <str delim="">google Linux</str> | <str delim="">wikipedia Arch Linux</str> | <str delim="">imdb Serenity</str></ex></code>
     </description>
index c1e4e335514f8627d69e40dd70fdcc58b78ada50..8ea7f8a4a6414a0016ffd0c77f13a9dd9c398d17 100644 (file)
@@ -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: [
index bc767f68887cf45147ac8e9787c6a21b5c2e33d0..51d2f0d757ca93bd5fa1d5579fc2fb76b4bc2360 100644 (file)
@@ -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);}
index 55328a1fe3aa8dfe4c8db978fd437aac7bfcad08..2647848d2f97209cd9c27bf2c5d8fa255a2883b4 100644 (file)
@@ -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;
index 4343ec215330129868fc4d6a859502f930e8f994..7145110bd84b69aee933dc3bb26847451147539c 100644 (file)
@@ -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;
         }
     };
 
index 94b1692e762d840e0759af5834058630d003804b..357beea6556566c60eac0ce21dad1b9a82224b55 100644 (file)
@@ -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], ["[[", "<previous-page>"],
             "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"],
index ff9c0917dade8a5403118350df32baa0b1485682..c44cbb30031fa4363fd29e86ff748a1be9201757 100644 (file)
@@ -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(
                         <div highlight="CompItem" style="white-space: nowrap">
                             <li highlight="CompResult">{this.text}&#xa0;</li>
@@ -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) {
index c9c1420fba6396ed0edbd3597b141da15a483ecf..f92ea2258989cf5c8b8518303ce7b96aaf257ec4 100644 (file)
@@ -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"),
index 468193659893eb51ef2d84fead71f676b2ba1c92..6d32fb8358074121eb8a7af5e77263e05f19d8a8 100644 (file)
@@ -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),
 
index 981ec9c8a26d1cb3d332f928e3f88b1cc1e5db14..9f7f7e5f9a38bd831e456506876c0c688559688b 100644 (file)
@@ -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 == "<Esc>") { ... }
             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);
index 03ab19909e70014be9dc9d313c329331359d0581..e4d2f11f7981dfd9eb87406718cde8875ca61669 100644 (file)
@@ -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(
             <tr highlight="Download" key="row" xmlns:dactyl={NS} xmlns={XHTML}>
                 <td highlight="DownloadTitle">
@@ -222,8 +226,10 @@ var DownloadList = Class("DownloadList",
 
     message: Class.Memoize(function () {
 
+        XML.ignoreWhitespace = true;
+        XML.prettyPrinting = false;
         util.xmlToDom(<table highlight="Downloads" key="list" xmlns={XHTML}>
-                        <tr highlight="DownloadHead">
+                        <tr highlight="DownloadHead" key="head">
                             <span>{_("title.Title")}</span>
                             <span>{_("title.Status")}</span>
                             <span/>
@@ -251,6 +257,9 @@ var DownloadList = Class("DownloadList",
                         </tr>
                       </table>, this.document, this.nodes);
 
+        this.index = Array.indexOf(this.nodes.list.childNodes,
+                                   this.nodes.head);
+
         for (let row in iter(services.downloadManager.DBConnection
                                      .createStatement("SELECT id FROM moz_downloads")))
             this.addDownload(row.id);
@@ -272,7 +281,7 @@ var DownloadList = Class("DownloadList",
                                               .indexOf(download);
 
             this.nodes.list.insertBefore(download.nodes.row,
-                                         this.nodes.list.childNodes[index + 1]);
+                                         this.nodes.list.childNodes[index + this.index + 1]);
         }
     },
     removeDownload: function removeDownload(id) {
@@ -388,7 +397,30 @@ var DownloadList = Class("DownloadList",
     }
 });
 
-var Downloads = Module("downloads", {
+var Downloads = Module("downloads", XPCOM(Ci.nsIDownloadProgressListener), {
+    init: function () {
+        services.downloadManager.addListener(this);
+    },
+
+    destroy: function destroy() {
+        services.downloadManager.removeListener(this);
+    },
+
+    onDownloadStateChange: function (state, download) {
+        if (download.state == services.downloadManager.DOWNLOAD_FINISHED) {
+            let url   = download.source.spec;
+            let title = download.displayName;
+            let file  = download.targetFile.path;
+            let size  = download.size;
+
+
+            overlay.modules.forEach(function (modules) {
+                modules.dactyl.echomsg({ domains: [util.getHost(url)], message: _("io.downloadFinished", title, file) },
+                                       1, modules.commandline.ACTIVE_WINDOW);
+                modules.autocommands.trigger("DownloadPost", { url: url, title: title, file: file, size: size });
+            });
+        }
+    }
 }, {
 }, {
     commands: function initCommands(dactyl, modules, window) {
index 2696630422d24a1d0309d5eb8a36e06fb4cd5bb8..bde3f4293ff777681cb6b34a0e683b354a4e1049 100644 (file)
@@ -44,7 +44,7 @@ var RangeFinder = Module("rangefinder", {
 
     init: function init() {
         prefs.safeSet("accessibility.typeaheadfind.autostart", false);
-        // The above should be sufficient, but: http://dactyl.sf.net/bmo/348187
+        // The above should be sufficient, but: http://bugzil.la/348187
         prefs.safeSet("accessibility.typeaheadfind", false);
     },
 
index d12312bd678834124a0edb4b1809532ffb65acd7..dadadfcd6993d2e78dd960a290fd91ca9762f2d4 100644 (file)
@@ -126,7 +126,7 @@ var Help = Module("Help", {
                 | (?: ^ [^\S\n]* \n) +
             ]]>), "gmxy");
 
-            let betas = util.regexp(/\[(b\d)\]/, "gx");
+            let betas = util.regexp(/\[((?:b|rc)\d)\]/, "gx");
 
             let beta = array(betas.iterate(NEWS))
                         .map(function (m) m[1]).uniq().slice(-1)[0];
@@ -317,12 +317,12 @@ var Help = Module("Help", {
                                 .split(" "));
             function fix(node) {
                 switch(node.nodeType) {
-                case Node.ELEMENT_NODE:
-                    if (isinstance(node, [HTMLBaseElement]))
+                case Ci.nsIDOMNode.ELEMENT_NODE:
+                    if (isinstance(node, [Ci.nsIDOMHTMLBaseElement]))
                         return;
 
                     data.push("<"); data.push(node.localName);
-                    if (node instanceof HTMLHtmlElement)
+                    if (node instanceof Ci.nsIDOMHTMLHtmlElement)
                         data.push(" xmlns=" + XHTML.uri.quote(),
                                   " xmlns:dactyl=" + NS.uri.quote());
 
@@ -335,8 +335,14 @@ var Help = Module("Help", {
                         if (name == "href") {
                             value = node.href || value;
                             if (value.indexOf("dactyl://help-tag/") == 0) {
-                                let uri = services.io.newChannel(value, null, null).originalURI;
-                                value = uri.spec == value ? "javascript:;" : uri.path.substr(1);
+                                try {
+                                    let uri = services.io.newChannel(value, null, null).originalURI;
+                                    value = uri.spec == value ? "javascript:;" : uri.path.substr(1);
+                                }
+                                catch (e) {
+                                    util.dump("Magical tag thingy failure for: " + value);
+                                    dactyl.reportError(e);
+                                }
                             }
                             if (!/^#|[\/](#|$)|^[a-z]+:/.test(value))
                                 value = value.replace(/(#|$)/, ".xhtml$1");
@@ -354,24 +360,26 @@ var Help = Module("Help", {
                         data.push(" />");
                     else {
                         data.push(">");
-                        if (node instanceof HTMLHeadElement)
+                        if (node instanceof Ci.nsIDOMHTMLHeadElement)
                             data.push(<link rel="stylesheet" type="text/css" href="help.css"/>.toXMLString());
                         Array.map(node.childNodes, fix);
                         data.push("</", node.localName, ">");
                     }
                     break;
-                case Node.TEXT_NODE:
+                case Ci.nsIDOMNode.TEXT_NODE:
                     data.push(<>{node.textContent}</>.toXMLString());
                 }
             }
 
+            let { buffer, content, events } = modules;
             let chromeFiles = {};
             let styles = {};
+
             for (let [file, ] in Iterator(help.files)) {
                 let url = "dactyl://help/" + file;
                 dactyl.open(url);
                 util.waitFor(function () content.location.href == url && buffer.loaded
-                                && content.document.documentElement instanceof HTMLHtmlElement,
+                                && content.document.documentElement instanceof Ci.nsIDOMHTMLHtmlElement,
                              15000);
                 events.waitForPageLoad();
                 var data = [
index 5eefcc17b6bb6aeaceecae247a49df9035a36846..0e0a39499c6b073e1c936e746486ce6eab70cb13 100644 (file)
@@ -41,26 +41,6 @@ var IO = Module("io", {
 
             this._lastRunCommand = ""; // updated whenever the users runs a command with :!
             this._scriptNames = [];
-
-            this.downloadListener = {
-                onDownloadStateChange: function (state, download) {
-                    if (download.state == services.downloadManager.DOWNLOAD_FINISHED) {
-                        let url   = download.source.spec;
-                        let title = download.displayName;
-                        let file  = download.targetFile.path;
-                        let size  = download.size;
-
-                        dactyl.echomsg({ domains: [util.getHost(url)], message: _("io.downloadFinished", title, file) },
-                                       1, modules.commandline.ACTIVE_WINDOW);
-                        modules.autocommands.trigger("DownloadPost", { url: url, title: title, file: file, size: size });
-                    }
-                },
-                onStateChange:    function () {},
-                onProgressChange: function () {},
-                onSecurityChange: function () {}
-            };
-
-            services.downloadManager.addListener(this.downloadListener);
         },
 
         CommandFileMode: Class("CommandFileMode", modules.CommandMode, {
@@ -84,10 +64,6 @@ var IO = Module("io", {
             }
         }),
 
-        destroy: function destroy() {
-            services.downloadManager.removeListener(this.downloadListener);
-        },
-
         /**
          * Returns all directories named *name* in 'runtimepath'.
          *
@@ -331,14 +307,19 @@ var IO = Module("io", {
      *
      * @returns {File}
      */
-    createTempFile: function createTempFile(name) {
-        if (name instanceof Ci.nsIFile)
+    createTempFile: function createTempFile(name, type) {
+        if (name instanceof Ci.nsIFile) {
             var file = name.clone();
+            if (!type || type == "file")
+                file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(666));
+            else
+                file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, octal(777));
+        }
         else {
             file = services.directory.get("TmpD", Ci.nsIFile);
             file.append(this.config.tempFile + (name ? "." + name : ""));
+            file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(666));
         }
-        file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, octal(600));
 
         services.externalApp.deleteTemporaryFileOnExit(file);
 
@@ -414,7 +395,8 @@ var IO = Module("io", {
         if (bin instanceof File || File.isAbsolutePath(bin))
             return this.File(bin);
 
-        let dirs = services.environment.get("PATH").split(config.OS.isWindows ? ";" : ":");
+        let dirs = services.environment.get("PATH")
+                           .split(config.OS.pathListSep);
         // Windows tries the CWD first TODO: desirable?
         if (config.OS.isWindows)
             dirs = [io.cwd].concat(dirs);
@@ -487,10 +469,12 @@ var IO = Module("io", {
     // TODO: when https://bugzilla.mozilla.org/show_bug.cgi?id=68702 is
     // fixed use that instead of a tmpfile
     /**
-     * Runs *command* in a subshell and returns the output in a string. The
-     * shell used is that specified by the 'shell' option.
+     * Runs *command* in a subshell and returns the output. The shell used is
+     * that specified by the 'shell' option.
      *
-     * @param {string} command The command to run.
+     * @param {string|[string]} command The command to run. This can be a shell
+     *      command string or an array of strings (a command and arguments)
+     *      which will be escaped and concatenated.
      * @param {string} input Any input to be provided to the command on stdin.
      * @param {function(object)} callback A callback to be called when
      *      the command completes. @optional
@@ -556,7 +540,8 @@ var IO = Module("io", {
      *     otherwise, the return value of *func*.
      */
     withTempFiles: function withTempFiles(func, self, checked, ext) {
-        let args = array(util.range(0, func.length)).map(bind("createTempFile", this, ext)).array;
+        let args = array(util.range(0, func.length))
+                    .map(bind("createTempFile", this, ext)).array;
         try {
             if (!args.every(util.identity))
                 return false;
index a4d1ab6bf435024c35d1cb68e0ce64bcaf133414..c33ca86930e8eb8bf36e229ff5955b7f47dfe649 100644 (file)
@@ -10,7 +10,8 @@ try {
 
 Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("javascript", {
-    exports: ["JavaScript", "javascript"]
+    exports: ["JavaScript", "javascript"],
+    require: ["util"]
 }, this);
 
 let isPrototypeOf = Object.prototype.isPrototypeOf;
@@ -53,9 +54,9 @@ var JavaScript = Module("javascript", {
 
     lazyInit: true,
 
-    newContext: function () this.modules.newContext(this.modules.userContext, true),
+    newContext: function () this.modules.newContext(this.modules.userContext, true, "Dactyl JS Temp Context"),
 
-    get completers() JavaScript.completers, // For backward compatibility
+    completers: Class.Memoize(function () Object.create(JavaScript.completers)),
 
     // Some object members are only accessible as function calls
     getKey: function (obj, key) {
@@ -550,7 +551,7 @@ var JavaScript = Module("javascript", {
                 }
                 catch (e) {}
                 if (!completer)
-                    completer = JavaScript.completers[funcName];
+                    completer = this.completers[funcName];
                 if (!completer)
                     return null;
 
@@ -765,10 +766,10 @@ var JavaScript = Module("javascript", {
                 let self = this;
                 let sandbox = true || isinstance(context, ["Sandbox"]);
 
-                this.context = modules.newContext(context, !sandbox);
+                this.context = modules.newContext(context, !sandbox, "Dactyl REPL Context");
                 this.js = modules.JavaScript();
                 this.js.replContext = this.context;
-                this.js.newContext = function newContext() modules.newContext(self.context, !sandbox);
+                this.js.newContext = function newContext() modules.newContext(self.context, !sandbox, "Dactyl REPL Temp Context");
 
                 this.js.globals = [
                    [this.context, /*L*/"REPL Variables"],
index 2740b66d612d65afadf9abb85a2f7de4a3e1a043..ffc89ee8e5d25f643bc291a79fa4ca12c4d37ea0 100644 (file)
@@ -28,6 +28,8 @@ var ModuleBase = Class("ModuleBase", {
     toString: function () "[module " + this.constructor.className + "]"
 });
 
+var _id = 0;
+
 var Modules = function Modules(window) {
     /**
      * @constructor Module
@@ -136,7 +138,7 @@ var Modules = function Modules(window) {
             }
         },
 
-        newContext: function newContext(proto, normal) {
+        newContext: function newContext(proto, normal, name) {
             if (normal)
                 return create(proto);
 
@@ -144,6 +146,7 @@ var Modules = function Modules(window) {
                 var sandbox = services.dactyl.createGlobal();
             else
                 sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules,
+                                                             sandboxName: name || ("Dactyl Sandbox " + ++_id),
                                                              wantXrays: false });
 
             // Hack:
@@ -197,13 +200,6 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
         this.loaded = {};
         modules.loaded = this.loaded;
 
-        defineModule.modules.forEach(function defModule(mod) {
-            let names = Set(Object.keys(mod.INIT));
-            if ("init" in mod.INIT)
-                Set.add(names, "init");
-
-            keys(names).forEach(function (name) { self.deferInit(name, mod.INIT, mod); });
-        });
         this.modules = modules;
 
         this.scanModules();
@@ -308,28 +304,38 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
 
         let className = mod.className || mod.constructor.className;
 
-        init[className] = function callee() {
-            function finish() {
-                this.currentDependency = className;
-                defineModule.time(className, name, INIT[name], mod,
-                                  modules.dactyl, modules, window);
-            }
-            if (!callee.frobbed) {
-                callee.frobbed = true;
-                if (modules[name] instanceof Class)
-                    modules[name].withSavedValues(["currentDependency"], finish);
-                else
-                    finish.call({});
-            }
-        };
+        if (!Set.has(init, className)) {
+            init[className] = function callee() {
+                function finish() {
+                    this.currentDependency = className;
+                    defineModule.time(className, name, INIT[name], mod,
+                                      modules.dactyl, modules, window);
+                }
+                if (!callee.frobbed) {
+                    callee.frobbed = true;
+                    if (modules[name] instanceof Class)
+                        modules[name].withSavedValues(["currentDependency"], finish);
+                    else
+                        finish.call({});
+                }
+            };
 
-        INIT[name].require = function (name) { init[name](); };
+            INIT[name].require = function (name) { init[name](); };
+        }
     },
 
     scanModules: function scanModules() {
         let self = this;
         let { Module, modules } = this.modules;
 
+        defineModule.modules.forEach(function defModule(mod) {
+            let names = Set(Object.keys(mod.INIT));
+            if ("init" in mod.INIT)
+                Set.add(names, "init");
+
+            keys(names).forEach(function (name) { self.deferInit(name, mod.INIT, mod); });
+        });
+
         Module.list.forEach(function frobModule(mod) {
             if (!mod.frobbed) {
                 modules.__defineGetter__(mod.className, function () {
index bca366992cf0b3f49a5752a97fcb4ae3ab20a26d..3e20f27afa9e9e9c21f7657c212ba7b509fea84f 100644 (file)
@@ -45,7 +45,8 @@ var Messages = Module("messages", {
         array.uniq([JSMLoader.getTarget("dactyl://locale/" + this.name + ".properties"),
                     JSMLoader.getTarget("dactyl://locale-local/" + this.name + ".properties"),
                     "resource://dactyl-locale/en-US/" + this.name + ".properties",
-                    "resource://dactyl-locale-local/en-US/" + this.name + ".properties"])
+                    "resource://dactyl-locale-local/en-US/" + this.name + ".properties"],
+                   true)
              .map(services.stringBundle.createBundle)
              .filter(function (bundle) { try { bundle.getSimpleEnumeration(); return true; } catch (e) { return false; } })),
 
index 512e304f789b800506c8fe4be6fa6e13f6d6f223..dacafbdd28b282cc3e9879e3c6c7871ceff749aa 100644 (file)
@@ -339,7 +339,9 @@ var Option = Class("Option", {
         if (isArray(defaultValue))
             defaultValue = defaultValue.map(Option.quote).join(",");
         else if (isObject(defaultValue))
-            defaultValue = iter(defaultValue).map(function (val) val.map(Option.quote).join(":")).join(",");
+            defaultValue = iter(defaultValue).map(function (val) val.map(function (v) Option.quote(v, /:/))
+                                                                    .join(":"))
+                                             .join(",");
 
         if (isArray(defaultValue))
             defaultValue = defaultValue.map(Option.quote).join(",");
@@ -446,16 +448,16 @@ var Option = Class("Option", {
     },
 
     unparseRegexp: function unparseRegexp(re, quoted) re.bang + Option.quote(util.regexp.getSource(re), /^!|:/) +
-        (typeof re.result === "boolean" ? "" : ":" + (quoted ? re.result : Option.quote(re.result))),
+        (typeof re.result === "boolean" ? "" : ":" + (quoted ? re.result : Option.quote(re.result, /:/))),
 
     parseSite: function parseSite(pattern, result, rest) {
         if (isArray(rest)) // Called by Array.map
             result = undefined;
 
         let [, bang, filter] = /^(!?)(.*)/.exec(pattern);
-        filter = Option.dequote(filter);
+        filter = Option.dequote(filter).trim();
 
-        let quote = this.keepQuotes ? util.identity : Option.quote;
+        let quote = this.keepQuotes ? util.identity : function (v) Option.quote(v, /:/);
 
         return update(Styles.matchFilter(filter), {
             bang: bang,
@@ -491,7 +493,7 @@ var Option = Class("Option", {
 
         stringlist:  function (vals) vals.map(Option.quote).join(","),
 
-        stringmap:   function (vals) [Option.quote(k, /:/) + ":" + Option.quote(v) for ([k, v] in Iterator(vals))].join(","),
+        stringmap:   function (vals) [Option.quote(k, /:/) + ":" + Option.quote(v, /:/) for ([k, v] in Iterator(vals))].join(","),
 
         regexplist:  function (vals) vals.join(","),
         get regexpmap() this.regexplist,
index f8e7e403713ddeac9d6e2c2cecd91d87157d3285..3f865b61b959c901cd7dff5a3d41319e5e254b14 100644 (file)
@@ -26,7 +26,8 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
         this._prefContexts = [];
 
         this.branch = services.pref[defaults ? "getDefaultBranch" : "getBranch"](branch || "");
-        this.branch instanceof Ci.nsIPrefBranch2;
+        if ("nsIPrefBranch2" in Ci)
+            this.branch instanceof Ci.nsIPrefBranch2;
 
         this.defaults = defaults ? this : this.constructor(branch, true);
 
@@ -68,103 +69,42 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
         }
     },
 
-    /**
-     * Returns the full name of this object's preference branch.
-     */
-    get root() this.branch.root,
-
     /**
      * Returns a new Prefs instance for the sub-branch *branch* of this
      * branch.
      *
-     * @param {string} branch The branch to branch to.
+     * @param {string} branch The sub-branch to branch to.
      * @returns {Prefs}
      */
     Branch: function Branch(branch) Prefs(this.root + branch),
 
-    observe: null,
-    observers: {
-        "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.
+     * Clears the entire branch.
      *
-     * @param {string} pref The preference to observe.
-     * @param {function(object)} callback The callback, called with the
-     *    new value of the preference whenever it changes.
+     * @param {string} name The name of the preference branch to delete.
      */
-    watch: function watch(pref, callback, strong) {
-        if (!this.observe) {
-            util.addObserver(this);
-            this.branch.addObserver("", this, false);
-        }
-
-        if (!this._observers[pref])
-            this._observers[pref] = [];
-        this._observers[pref].push(!strong ? util.weakReference(callback) : { get: function () callback });
+    clear: function clear(branch) {
+        this.branch.deleteBranch(branch || "");
     },
 
     /**
-     * Lists all preferences matching *filter* or only those with changed
-     * values if *onlyNonDefault* 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
+     * Returns the full name of this object's preference branch.
      */
-    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.pref.prefHasUserValue(pref);
-                if (onlyNonDefault && !userValue || pref.indexOf(filter) == -1)
-                    continue;
-
-                let value = this.get(pref);
-
-                let option = {
-                    isDefault: !userValue,
-                    default:   this.defaults.get(pref, null),
-                    value:     <>={template.highlight(value, true, 100)}</>,
-                    name:      pref,
-                    pre:       "\u00a0\u00a0" // Unicode nonbreaking space.
-                };
-
-                yield option;
-            }
-        };
-
-        return template.options(_("pref.hostPreferences", config.host), prefs.call(this));
-    },
+    get root() this.branch.root,
 
     /**
-     * Returns the value of a preference.
+     * Returns the value of the preference *name*, or *defaultValue* if
+     * the preference does not exist.
      *
-     * @param {string} name The preference name.
-     * @param {value} defaultValue The value to return if the preference
-     *     is unset.
+     * @param {string} name The name of the preference to return.
+     * @param {*} defaultValue The value to return if the preference has no value.
+     * @optional
      */
     get: function get(name, defaultValue) {
         if (defaultValue == null)
             defaultValue = null;
+        if (isArray(name))
+            name = name.join(".");
 
         let type = this.branch.getPrefType(name);
         try {
@@ -192,20 +132,27 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
     getDefault: deprecated("Prefs#defaults.get", function getDefault(name, defaultValue) this.defaults.get(name, defaultValue)),
 
     /**
-     * Returns the names of all preferences.
+     * Returns an array of all preference names in this branch or the
+     * given sub-branch.
      *
-     * @param {string} branch The branch in which to search preferences.
-     *     @default ""
+     * @param {string} branch The sub-branch for which to return preferences.
+     * @optional
      */
     getNames: function getNames(branch) this.branch.getChildList(branch || "", { value: 0 }),
 
     /**
-     * Returns true if the current branch has the given preference.
+     * Returns true if the given preference exists in this branch.
      *
-     * @param {string} name The preference name.
-     * @returns {boolean}
+     * @param {string} name The name of the preference to check.
+     */
+    has: function has(name) this.branch.getPrefType(name) !== 0,
+
+    /**
+     * Returns true if the given preference is set to its default value.
+     *
+     * @param {string} name The name of the preference to check.
      */
-    has: function get(name) this.branch.getPrefType(name) != 0,
+    isDefault: function isDefault(name) !this.branch.prefHasUserValue(name),
 
     _checkSafe: function _checkSafe(name, message, value) {
         let curval = this.get(name, null);
@@ -256,10 +203,11 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
     },
 
     /**
-     * Sets the preference *name* to *value*.
+     * Sets the preference *name* to *value*. If the preference already
+     * exists, it must have the same type as the given value.
      *
-     * @param {string} name The preference name.
-     * @param {value} value The new preference value.
+     * @param {name} name The name of the preference to change.
+     * @param {string|number|boolean} value The value to set.
      * @param {boolean} silent Ignore errors.
      */
     set: function set(name, value, silent) {
@@ -329,13 +277,11 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
     /**
      * Resets the preference *name* to its default value.
      *
-     * @param {string} name The preference name.
+     * @param {string} name The name of the preference to reset.
      */
     reset: function reset(name) {
-        try {
+        if (this.branch.prefHasUserValue(name))
             this.branch.clearUserPref(name);
-        }
-        catch (e) {} // ignore - thrown if not a user set value
     },
 
     /**
@@ -395,7 +341,80 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
         finally {
             this.popContext();
         }
-    }
+    },
+
+    observe: null,
+    observers: {
+        "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 watch(pref, callback, strong) {
+        if (!this.observe) {
+            util.addObserver(this);
+            this.branch.addObserver("", this, false);
+        }
+
+        if (!this._observers[pref])
+            this._observers[pref] = [];
+        this._observers[pref].push(!strong ? util.weakReference(callback) : { get: function () callback });
+    },
+
+    /**
+     * Lists all preferences matching *filter* or only those with changed
+     * values if *onlyNonDefault* 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.pref.prefHasUserValue(pref);
+                if (onlyNonDefault && !userValue || pref.indexOf(filter) == -1)
+                    continue;
+
+                let value = this.get(pref);
+
+                let option = {
+                    isDefault: !userValue,
+                    default:   this.defaults.get(pref, null),
+                    value:     <>={template.highlight(value, true, 100)}</>,
+                    name:      pref,
+                    pre:       "\u00a0\u00a0" // Unicode nonbreaking space.
+                };
+
+                yield option;
+            }
+        };
+
+        return template.options(_("pref.hostPreferences", config.host), prefs.call(this));
+    },
 }, {
 }, {
     completion: function init_completion(dactyl, modules) {
index 98d8e3bcab7d0f466869aacc4ce339b2a6d330f1..edb642ecb888aff28704bdaa6f011a0ae69d9c03 100644 (file)
@@ -142,7 +142,7 @@ ProtocolBase.prototype = {
 function LocaleChannel(pkg, locale, path, orig) {
     for each (let locale in [locale, "en-US"])
         for each (let sep in "-/") {
-            var channel = Channel(["resource:/", pkg + sep + locale, path].join("/"), orig, true);
+            var channel = Channel(["resource:/", pkg + sep + locale, path].join("/"), orig, true, true);
             if (channel)
                 return channel;
         }
@@ -182,31 +182,34 @@ function XMLChannel(uri, contentType, noErrorChannel, unprivileged) {
     this.channel.contentType = contentType || channel.contentType;
     this.channel.contentCharset = "UTF-8";
     if (!unprivileged)
-    this.channel.owner = systemPrincipal;
-
-    let stream = services.InputStream(channelStream);
-    let [, pre, doctype, url, extra, open, post] = util.regexp(<![CDATA[
-            ^ ([^]*?)
-            (?:
-                (<!DOCTYPE \s+ \S+ \s+) (?:SYSTEM \s+ "([^"]*)" | ((?:[^[>\s]|\s[^[])*))
-                (\s+ \[)?
-                ([^]*)
-            )?
-            $
-        ]]>, "x").exec(stream.read(4096));
-    this.writes.push(pre);
-    if (doctype) {
-        this.writes.push(doctype + (extra || "") + " [\n");
-        if (url)
-            this.addChannel(url);
-
-        if (!open)
-            this.writes.push("\n]");
-
-        for (let [, pre, url] in util.regexp.iterate(/([^]*?)(?:%include\s+"([^"]*)";|$)/gy, post)) {
-            this.writes.push(pre);
+        this.channel.owner = systemPrincipal;
+
+    let type = this.channel.contentType;
+    if (/^text\/|[\/+]xml$/.test(type)) {
+        let stream = services.InputStream(channelStream);
+        let [, pre, doctype, url, extra, open, post] = util.regexp(<![CDATA[
+                ^ ([^]*?)
+                (?:
+                    (<!DOCTYPE \s+ \S+ \s+) (?:SYSTEM \s+ "([^"]*)" | ((?:[^[>\s]|\s[^[])*))
+                    (\s+ \[)?
+                    ([^]*)
+                )?
+                $
+            ]]>, "x").exec(stream.read(4096));
+        this.writes.push(pre);
+        if (doctype) {
+            this.writes.push(doctype + (extra || "") + " [\n");
             if (url)
                 this.addChannel(url);
+
+            if (!open)
+                this.writes.push("\n]");
+
+            for (let [, pre, url] in util.regexp.iterate(/([^]*?)(?:%include\s+"([^"]*)";|$)/gy, post)) {
+                this.writes.push(pre);
+                if (url)
+                    this.addChannel(url);
+            }
         }
     }
     this.writes.push(channelStream);
index efc0f2de61dca23b76a4ad8ed6ba81de5c59df51..bbe36e2e244f9c7e6d9eb964e7f9c7a85a6f9317 100644 (file)
@@ -19,10 +19,11 @@ defineModule("sanitizer", {
 }, this);
 
 this.lazyRequire("messages", ["_"]);
+this.lazyRequire("overlay", ["overlay"]);
 this.lazyRequire("storage", ["storage"]);
 this.lazyRequire("template", ["teplate"]);
 
-let tmp = {};
+let tmp = Object.create(this);
 JSMLoader.loadSubScript("chrome://browser/content/sanitize.js", tmp);
 tmp.Sanitizer.prototype.__proto__ = Class.prototype;
 
@@ -180,60 +181,63 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
             }
         });
 
-        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={config.appName + /*L*/" (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={/*L*/"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={config.appName + " " + desc}
-                                      preference={branch + item}
-                                      onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>)
-                        }
-                    </>
-                },
-                ready: function ready(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 values(self.itemMap))
-                                                         if (item.shouldSanitize(false))],
-                                                        Range.fromArray(this.range || []));
-                            }, this);
-                        }
-                    });
-                }
-            }));
-        }
+        util.timeout(function () { // Load order issue...
+
+            let (branch = Item.PREFIX + Item.SHUTDOWN_BRANCH) {
+                overlay.overlayWindow("chrome://browser/content/preferences/sanitize.xul",
+                                   function (win) prefOverlay(branch, true, {
+                    append: {
+                        SanitizeDialogPane:
+                            <groupbox orient="horizontal" xmlns={XUL}>
+                              <caption label={config.appName + /*L*/" (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) {
+                overlay.overlayWindow("chrome://browser/content/sanitize.xul",
+                                   function (win) prefOverlay(branch, false, {
+                    append: {
+                        itemList: <>
+                            <listitem xmlns={XUL} label={/*L*/"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={config.appName + " " + desc}
+                                          preference={branch + item}
+                                          onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>)
+                            }
+                        </>
+                    },
+                    ready: function ready(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 values(self.itemMap))
+                                                             if (item.shouldSanitize(false))],
+                                                            Range.fromArray(this.range || []));
+                                }, this);
+                            }
+                        });
+                    }
+                }));
+            }
+        });
     },
 
     firstRun: 0,
index d47da247ba409eb1149614f9568096fd7830fddf..76c4b6bd7a69e9f1991da8c1700b5e21448f71bb 100644 (file)
@@ -92,6 +92,7 @@ var Services = Module("Services", {
         this.addClass("HtmlEncoder",  "@mozilla.org/layout/htmlCopyEncoder;1",     "nsIDocumentEncoder");
         this.addClass("InterfacePointer", "@mozilla.org/supports-interface-pointer;1", "nsISupportsInterfacePointer", "data");
         this.addClass("InputStream",  "@mozilla.org/scriptableinputstream;1",      "nsIScriptableInputStream", "init");
+        this.addClass("MIMEStream",   "@mozilla.org/network/mime-input-stream;1",  "nsIMIMEInputStream", "setData");
         this.addClass("Persist",      "@mozilla.org/embedding/browser/nsWebBrowserPersist;1", "nsIWebBrowserPersist");
         this.addClass("Pipe",         "@mozilla.org/pipe;1",                       "nsIPipe", "init");
         this.addClass("Process",      "@mozilla.org/process/util;1",               "nsIProcess", "init");
@@ -105,7 +106,7 @@ var Services = Module("Services", {
         this.addClass("Transferable", "@mozilla.org/widget/transferable;1",        "nsITransferable");
         this.addClass("Timer",        "@mozilla.org/timer;1",                      "nsITimer", "initWithCallback");
         this.addClass("URL",          "@mozilla.org/network/standard-url;1",       ["nsIStandardURL", "nsIURL"], "init");
-        this.addClass("Xmlhttp",      "@mozilla.org/xmlextras/xmlhttprequest;1",   "nsIXMLHttpRequest", "open");
+        this.addClass("Xmlhttp",      "@mozilla.org/xmlextras/xmlhttprequest;1",   [], "open");
         this.addClass("XPathEvaluator", "@mozilla.org/dom/xpath-evaluator;1",      "nsIDOMXPathEvaluator");
         this.addClass("XMLDocument",  "@mozilla.org/xml/xml-document;1",           ["nsIDOMXMLDocument", "nsIDOMNodeSelector"]);
         this.addClass("ZipReader",    "@mozilla.org/libjar/zip-reader;1",          "nsIZipReader", "open", false);
index 9ee7f6286f581ca56f5b6630946c4c13a8cdb2cc..98d49605a4b4edeb7ad3dde0535d2c37994236aa 100644 (file)
@@ -420,6 +420,8 @@ var Styles = Module("Styles", {
      * @returns {nsIURI -> boolean}
      */
     matchFilter: function (filter) {
+        filter = filter.trim();
+
         if (filter === "*")
             var test = function test(uri) true;
         else if (!/^(?:[a-z-]+:|[a-z-.]+$)/.test(filter)) {
index 61c64cdeae079190451c9041454b4f2477a3fd4c..09300d0e888a419ac729d90439ed92d1b53bb29b 100644 (file)
@@ -82,13 +82,22 @@ var Binding = Class("Binding", {
     })
 });
 
+["appendChild", "getAttribute", "insertBefore", "setAttribute"].forEach(function (key) {
+    Object.defineProperty(Binding.prototype, key, {
+        configurable: true,
+        enumerable: false,
+        value: function () this.node[key].apply(this.node, arguments),
+        writable: true
+    });
+});
+
 var Template = Module("Template", {
     add: function add(a, b) a + b,
     join: function join(c) function (a, b) a + c + b,
 
     map: function map(iter, func, sep, interruptable) {
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
-        if (iter.length) // FIXME: Kludge?
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
+        if (typeof iter.length == "number") // FIXME: Kludge?
             iter = array.iterValues(iter);
         let res = <></>;
         let n = 0;
@@ -192,7 +201,7 @@ var Template = Module("Template", {
             var desc = this.processor[1].call(this, item, item.description);
         }
 
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         // <e4x>
         return <div highlight={highlightGroup || "CompItem"} style="white-space: nowrap">
                    <!-- The non-breaking spaces prevent empty elements
@@ -218,7 +227,7 @@ var Template = Module("Template", {
         if (help.initialized && !Set.has(help.tags, topic))
             return <span highlight={type || ""}>{text || token}</span>;
 
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         type = type || (/^'.*'$/.test(token)   ? "HelpOpt" :
                         /^\[.*\]$|^E\d{3}$/.test(token) ? "HelpTopic" :
                         /^:\w/.test(token)     ? "HelpEx"  : "HelpKey");
@@ -238,7 +247,7 @@ var Template = Module("Template", {
         if (help.initialized && !Set.has(help.tags, topic))
             return <>{token}</>;
 
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         let tag = (/^'.*'$/.test(token)            ? "o" :
                    /^\[.*\]$|^E\d{3}$/.test(token) ? "t" :
                    /^:\w/.test(token)              ? "ex"  : "k");
@@ -249,7 +258,7 @@ var Template = Module("Template", {
     linkifyHelp: function linkifyHelp(str, help) {
         let re = util.regexp(<![CDATA[
             (?P<pre> [/\s]|^)
-            (?P<tag> '[\w-]+' | :(?:[\w-]+!?|!) | (?:._)?<[\w-]+>\w* | \b[a-zA-Z]_(?:\w+|.) | \[[\w-]+\] | E\d{3} )
+            (?P<tag> '[\w-]+' | :(?:[\w-]+!?|!) | (?:._)?<[\w-]+>\w* | \b[a-zA-Z]_(?:[\w[\]]+|.) | \[[\w-;]+\] | E\d{3} )
             (?=      [[\)!,:;./\s]|$)
         ]]>, "gx");
         return this.highlightSubstrings(str, (function () {
@@ -278,7 +287,7 @@ var Template = Module("Template", {
     // if "processStrings" is true, any passed strings will be surrounded by " and
     // any line breaks are displayed as \n
     highlight: function highlight(arg, processStrings, clip, bw) {
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         // some objects like window.JSON or getBrowsers()._browsers need the try/catch
         try {
             let str = this.stringify(arg);
@@ -334,6 +343,8 @@ var Template = Module("Template", {
         return this.highlightSubstrings(str, (function () {
             if (filter.length == 0)
                 return;
+
+            XML.ignoreWhitespace = XML.prettyPrinting = false;
             let lcstr = String.toLowerCase(str);
             let lcfilter = filter.toLowerCase();
             let start = 0;
@@ -387,7 +398,7 @@ var Template = Module("Template", {
     </>,
 
     jumps: function jumps(index, elems) {
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         // <e4x>
         return <table>
                 <tr style="text-align: left;" highlight="Title">
@@ -413,7 +424,7 @@ var Template = Module("Template", {
     },
 
     options: function options(title, opts, verbose) {
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         // <e4x>
         return <table>
                 <tr highlight="Title" align="left">
@@ -440,7 +451,7 @@ var Template = Module("Template", {
         let url = util.fixURI(frame.filename || "unknown");
         let path = util.urlPath(url);
 
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         return <a xmlns:dactyl={NS} dactyl:command="buffer.viewSource"
             href={url} path={path} line={frame.lineNumber}
             highlight="URL">{
@@ -449,7 +460,7 @@ var Template = Module("Template", {
     },
 
     table: function table(title, data, indent) {
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         let table = // <e4x>
             <table>
                 <tr highlight="Title" align="left">
@@ -470,7 +481,7 @@ var Template = Module("Template", {
 
     tabular: function tabular(headings, style, iter) {
         // TODO: This might be mind-bogglingly slow. We'll see.
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         // <e4x>
         return <table>
                 <tr highlight="Title" align="left">
@@ -493,7 +504,7 @@ var Template = Module("Template", {
     },
 
     usage: function usage(iter, format) {
-        XML.ignoreWhitespace = false; XML.prettyPrinting = false;
+        XML.ignoreWhitespace = XML.prettyPrinting = false;
         format = format || {};
         let desc = format.description || function (item) template.linkifyHelp(item.description);
         let help = format.help || function (item) item.name;
index 9cc4a49e99779bb3f33bb891c3b54ae1ec2d0a96..c5cd610fbcf8ecf6fabc31dea584a43331857e59 100644 (file)
@@ -627,10 +627,10 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      */
     formatSeconds: function formatSeconds(seconds) {
         function pad(n, val) ("0000000" + val).substr(-Math.max(n, String(val).length));
-        function div(num, denom) [Math.round(num / denom), Math.round(num % denom)];
+        function div(num, denom) [Math.floor(num / denom), Math.round(num % denom)];
         let days, hours, minutes;
 
-        [minutes, seconds] = div(seconds, 60);
+        [minutes, seconds] = div(Math.round(seconds), 60);
         [hours, minutes]   = div(minutes, 60);
         [days, hours]      = div(hours,   24);
         if (days)
@@ -710,6 +710,8 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      *    responseType: {string} Override the type of the "response"
      *                  property.
      *
+     *    headers: {objects} Extra request headers.
+     *
      *    user: {string} The user name to send via HTTP Authentication.
      *    pass: {string} The password to send via HTTP Authentication.
      *
@@ -749,12 +751,18 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
                 params.data = data;
             }
 
-
             if (params.mimeType)
                 xmlhttp.overrideMimeType(params.mimeType);
 
-            xmlhttp.open(params.method || "GET", url, async,
-                         params.user, params.pass);
+            let args = [params.method || "GET", url, async];
+            if (params.user != null || params.pass != null)
+                args.push(params.user);
+            if (params.pass != null)
+                args.push(prams.pass);
+            xmlhttp.open.apply(xmlhttp, args);
+
+            for (let [header, val] in Iterator(params.headers || {}))
+                xmlhttp.setRequestHeader(header, val);
 
             if (params.responseType)
                 xmlhttp.responseType = params.responseType;
@@ -1308,7 +1316,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * Escapes a string against shell meta-characters and argument
      * separators.
      */
-    shellEscape: function shellEscape(str) '"' + String.replace(str, /[\\"$]/g, "\\$&") + '"',
+    shellEscape: function shellEscape(str) '"' + String.replace(str, /[\\"$`]/g, "\\$&") + '"',
 
     /**
      * Suspend execution for at least *delay* milliseconds. Functions by
index ef99b86c5104774f652985490391efd92f4e3dc3..45fe12b972505c1025fe0f40d2af77c5bdbd37e0 100644 (file)
@@ -243,8 +243,9 @@ FrameIndicator;;* {
 Bell          /* &dactyl.appName;’s visual bell */ \
               background-color: black !important;
 
+Hinting;;*  /* A document which is currently being hinted */
 Hint;;* {
-    /* A hint indicator. See <ex>:help hints</ex> */
+    /* A hint indicator. See :help hints */
     font:        bold 10px "Droid Sans Mono", monospace !important;
     margin:      -.2ex;
     padding:     0 0 0 1px;
index c65365acf0da90d6b110ef618283d886b01e6af1..010919cb5791252bc4e042537465beaf9ed5be07 100644 (file)
@@ -157,11 +157,11 @@ var tests = {
         error: ["!"]
     },
     cookies: {
-        anyOutput: ["dactyl.sf.net", "dactyl.sf.net list"],
+        anyOutput: ["5digits.org", "5digits.org list"],
         error: ["!", ""],
         completions: [
             "",
-            ["dactyl.sf.net ", hasItems]
+            ["5digits.org ", hasItems]
         ]
     },
     cunabbreviate: {},
index 0cebb2b99c50a7d1b9da5b636945255e3bc3db47..723007206cd3f8b7728e27cd9d6ddcee56bc7713 100644 (file)
@@ -9,7 +9,7 @@
         em:version="0.1a1pre"
         em:description="Songbird for Vim and CMus junkies."
         em:creator="Prathyush Thota"
-        em:homepageURL="http://dactyl.sourceforge.net/"
+        em:homepageURL="http://5digits.org/"
         em:iconURL="chrome://melodactyl/skin/icon.png"
         em:optionsURL="chrome://dactyl/content/preferences.xul">
         <em:targetApplication>
index a9b1526b2233d880ef9da7c1ea878a87d183b0cd..95e5f201b841577407c99bde1626e7471a072c67 100644 (file)
     • The command line is now hidden by default. Added c, C, and M to
       'guioptions'. [b4]
     • Hints mode improvements, including:
-      - Added g; continued extended hints mode, which allows
+      - Added [;A] extended hint mode. [rc2]
+      - Added [g;] continued extended hints mode, which allows
         selecting multiple hints. Removed ;F. [b1]
       - Hints are now updated after scrolling and window resizing. [b3]
-      - ;s now prompts for a filename on the command-line rather
+      - [;s] now prompts for a filename on the command-line rather
         than in a dialog. [b5]
-      - Added ;a and ;S modes for creating bookmarks and search keywords. [b4][b3]
+      - Added [;a] and [;S] modes for creating bookmarks and search keywords. [b4][b3]
       - Added 'hintkeys' option. [b2]
       - Added "transliterated" option to 'hintmatching'. [b1]
     • The external editor can now be configured to open to a given
         Hint, Multi-line Output, and Menu. [b4]
       - <C-o> and <C-i> now behave more like Vim. [b8]
       - n_G now uses 'linenumbers' to determine destination if possible. [b8]
-      - Add n_s and n_S. [b8]
+      - Added n_s and n_S. [b8]
       - Added Operator mode for motion maps, per Vim. [b8]
       - Added site-specific mapping groups and related command
         changes. [b6]
         still be used for this purpose. [b4]
       - 'loadplugins' is now a [regexplist] option rather than
         a boolean. [b2]
-      - 'mapleader' is now an option rather than a :let
-        variable. [b4]
+      - Made 'mapleader' an option rather than a :let variable. [b4]
+      - Removed the 'mapleader' option. [rc2]
       - 'passkeys' is now a [sitemap] with key chain support rather
         than a [regexpmap]. [b6]
       - The precise format of 'sanitizeitems' has changed slightly. [b8]
     • Added BookmarkChange, BookmarkRemove autocommands. [b2]
     • Removed the :source line at the end of files generated by
       :mkpentadactylrc. [b2]
-    • gf now toggles between source and content view.
+    • n_gf now toggles between source and content view.
       The | key binding has been removed. [b1]
     • Page zoom information is now shown in the status bar, and
       change in zoom status no longer appears in :messages. [b1]
index 2a257ecbc477a91718714a401557ef7fc9deaa0a..d331fbb64e003482a8be05ae2a6d73ef2017bc13 100644 (file)
@@ -5,10 +5,11 @@
         em:id="pentadactyl@dactyl.googlecode.com"
         em:type="2"
         em:name="Pentadactyl"
-        em:version="1.0rc1"
+        em:version="1.0"
         em:description="Firefox for Vim and Links addicts"
-        em:homepageURL="http://dactyl.sourceforge.net/pentadactyl"
-        em:bootstrap="true">
+        em:homepageURL="http://5digits.org/pentadactyl"
+        em:bootstrap="true"
+        em:strictCompatibility="true">
 
         <em:creator>Kris Maglione, Doug Kearns</em:creator>
         <em:developer>Kris Maglione</em:developer>
@@ -30,8 +31,8 @@
         <em:targetApplication>
             <Description
                 em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
-                em:minVersion="3.6"
-                em:maxVersion="11.*"/>
+                em:minVersion="4.0"
+                em:maxVersion="14.*"/>
         </em:targetApplication>
     </Description>
 </RDF>
index ae822069471331b417ffa509f8f20150e462473c..bb855ea7ace1adc1decff8bfd6988917215d36cc 100644 (file)
@@ -8,7 +8,7 @@
         em:version="0.6"
         em:description="Thunderbird for Mutt and Vim addicts"
         em:creator="Kris Maglione"
-        em:homepageURL="http://dactyl.sf.net/Teledactyl"
+        em:homepageURL="http://5digits.org/teledactyl"
         em:iconURL="chrome://teledactyl/skin/icon.png"
         em:bootstrap="true">
         <em:targetApplication>