]> git.donarmstrong.com Git - dactyl.git/commitdiff
Import r6923 from upstream hg supporting Firefox up to 22.0a1
authorMichael Schutte <michi@uiae.at>
Tue, 7 May 2013 09:39:55 +0000 (11:39 +0200)
committerMichael Schutte <michi@uiae.at>
Tue, 7 May 2013 09:39:55 +0000 (11:39 +0200)
88 files changed:
.hg_archival.txt
.hgignore [deleted file]
.hgsub [deleted file]
.hgsubstate [deleted file]
README.E4X [deleted file]
common/bootstrap.js
common/chrome.manifest
common/components/commandline-handler.js
common/content/abbreviations.js
common/content/about.xul
common/content/autocommands.js
common/content/bookmarks.js
common/content/browser.js
common/content/commandline.js
common/content/dactyl.js
common/content/editor.js
common/content/eval.js
common/content/events.js
common/content/help.js
common/content/hints.js
common/content/history.js
common/content/key-processors.js
common/content/mappings.js
common/content/marks.js
common/content/modes.js
common/content/mow.js
common/content/quickmarks.js
common/content/statusline.js
common/content/tabs.js
common/locale/en-US/browsing.xml
common/locale/en-US/developer.xml
common/locale/en-US/eval.xml
common/locale/en-US/messages.properties
common/locale/en-US/options.xml
common/locale/en-US/privacy.xml
common/locale/en-US/repeat.xml
common/locale/en-US/various.xml
common/make_jar.sh
common/modules/addons.jsm
common/modules/base.jsm
common/modules/bookmarkcache.jsm
common/modules/bootstrap.jsm
common/modules/buffer.jsm
common/modules/cache.jsm
common/modules/commands.jsm
common/modules/completion.jsm
common/modules/config.jsm
common/modules/contexts.jsm
common/modules/dom-e4x.jsm [new file with mode: 0644]
common/modules/dom.jsm
common/modules/downloads.jsm
common/modules/finder.jsm
common/modules/help.jsm
common/modules/highlight.jsm
common/modules/io.jsm
common/modules/javascript.jsm
common/modules/main.jsm
common/modules/messages.jsm
common/modules/options.jsm
common/modules/overlay.jsm
common/modules/prefs.jsm
common/modules/protocol.jsm
common/modules/sanitizer.jsm
common/modules/services.jsm
common/modules/storage.jsm
common/modules/styles.jsm
common/modules/template.jsm
common/modules/util.jsm
common/skin/global-styles.css
common/tests/functional/testCommands.js
melodactyl/content/player.js
melodactyl/contrib/vim/Makefile [deleted file]
melodactyl/contrib/vim/ftdetect/melodactyl.vim [deleted file]
melodactyl/contrib/vim/mkvimball.txt [deleted file]
melodactyl/locale/en-US/intro.xml
pentadactyl/NEWS
pentadactyl/TODO
pentadactyl/config.json
pentadactyl/content/config.js
pentadactyl/contrib/vim/Makefile [deleted file]
pentadactyl/contrib/vim/ftdetect/pentadactyl.vim [deleted file]
pentadactyl/contrib/vim/mkvimball.txt [deleted file]
pentadactyl/install.rdf
teledactyl/content/addressbook.js
teledactyl/contrib/vim/Makefile [deleted file]
teledactyl/contrib/vim/ftdetect/teledactyl.vim [deleted file]
teledactyl/contrib/vim/mkvimball.txt [deleted file]
teledactyl/locale/en-US/intro.xml

index 826039724d912e76f0ab6938724f5de21976cf6c..f8dc1a26ef56172f3960225b16408e0580a91b73 100644 (file)
@@ -1,4 +1,5 @@
 repo: 373f1649c80dea9be7b5bc9c57e8395f94f93ab1
-node: 227d1399fe7c9d8de98fc6ab3222cf9e1d8ad38f
-branch: pentadactyl-1.0-branch
-tag: pentadactyl-1.0
+node: 6d61fc0f8f2757c919fb4bb29dfed28df23b5030
+branch: default
+latesttag: pentadactyl-1.0rc1
+latesttagdistance: 194
diff --git a/.hgignore b/.hgignore
deleted file mode 100644 (file)
index fcc3ad8..0000000
--- a/.hgignore
+++ /dev/null
@@ -1,43 +0,0 @@
-## To see if new rules exclude any existing files, run
-##
-##   hg status -i
-##
-## after modifying this file.
-
-syntax: glob
-
-## Generated by the build process
-*.xpi
-*.o
-*.so
-*.xpt
-*/.depend
-*/config.local.mk
-*/locale/*/*.html
-*/chrome
-*/contrib/vim/*.vba
-*/bak/*
-downloads/*
-.git/*
-
-binary/src/*/*.h
-
-common/tests/functional/log
-
-*.py[co]
-
-## Editor backup and swap files
-*~
-.#*
-\#**\#
-.*.sw[op]
-.sw[op]
-
-## Generated by Mac filesystem
-.DS_Store
-
-syntax: regexp
-
-## For rejects
-\.(orig|rej|bak|diff)$
-
diff --git a/.hgsub b/.hgsub
deleted file mode 100644 (file)
index 2ee5d68..0000000
--- a/.hgsub
+++ /dev/null
@@ -1 +0,0 @@
-binary/components = https://code.google.com/p/dactyl.binary-modules/
diff --git a/.hgsubstate b/.hgsubstate
deleted file mode 100644 (file)
index 9d9a838..0000000
+++ /dev/null
@@ -1 +0,0 @@
-9f8a25e7d9861892d8e6136764bb88139e0a7253 binary/components
diff --git a/README.E4X b/README.E4X
deleted file mode 100644 (file)
index 5e0b8a9..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-               A terse introduction to E4X
-                      Public Domain
-
-The inline XML literals in this code are part of E4X, a standard
-XML processing interface for ECMAScript. In addition to syntax
-for XML literals, E4X provides a new kind of native object,
-"xml", and a syntax, similar to XPath, for accessing and
-modifying the tree. Here is a brief synopsis of the kind of
-usage you'll see herein:
-
-> let xml =
-        <foo bar="baz" baz="qux">
-            <bar>
-                <baz id="1"/>
-            </bar>
-            <baz id="2"/>
-        </foo>;
-
- // Select all bar elements of the root foo element
-> xml.bar
- <bar><baz id="1"/></bar>
-
- // Select all baz elements anywhere beneath the root
-> xml..baz
- <baz id="1"/>
- <baz id="2"/>
-
- // Select all of the immediate children of the root
-> xml.*
- <bar><baz id="1"/></bar>
- <baz id="2"/>
-
- // Select the bar attribute of the root node
-> xml.@bar
- baz
-
- // Select all id attributes in the tree
-> xml..@id
- 1
- 2
-
- // Select all attributes of the root node
-> xml.@*
- baz
- quz
-
-// Add a quux elemend beneath the first baz
-> xml..baz[0] += <quux/>
-  <baz id="1"/>
-  <quux/>
-> xml
-  <foo bar="baz" baz="qux">
-      <bar>
-          <baz id="1"/>
-          <quux/>
-      </bar>
-      <baz id="2"/>
-  </foo>
-
-  // and beneath the second
-> xml.baz[1] = <quux id="1"/>
-> xml
-  <foo bar="baz" baz="qux">
-      <bar>
-          <baz id="1"/>
-          <quux/>
-      </bar>
-      <baz id="2"/>
-      <quux id="1"/>
-  </foo>
-
-  // Replace bar's subtree with a foo element
-> xml.bar.* = <foo id="1"/>
-> xml
-  <foo bar="baz" baz="qux">
-      <bar>
-          <foo id="1"/>
-      </bar>
-      <baz id="2"/>
-      <quux id="1"/>
-  </foo>
-
-  // Add a bar below bar
-> xml.bar.* += <bar id="1"/>
-  <foo id="1"/>
-  <bar id="1"/>
-> xml
-  <foo bar="baz" baz="qux">
-      <bar>
-          <foo id="1"/>
-          <bar id="1"/>
-      </bar>
-      <baz id="2"/>
-      <quux id="1"/>
-  </foo>
-
-  // Adding a quux attribute to the root
-> xml.@quux = "foo"
-  foo
-> xml
-  <foo bar="baz" baz="qux" quux="foo">
-      <bar>
-          <foo id="1"/>
-          <bar id="1"/>
-      </bar>
-      <baz id="2"/>
-      <quux id="1"/>
-  </foo>
-
-> xml.bar.@id = "0"
-> xml..foo[0] = "Foo"
-  Foo
-> xml..bar[1] = "Bar"
-  Bar
-> xml
-js> xml
-<foo bar="baz" baz="qux" quux="foo" id="0">
-    <bar id="0">
-        <foo id="1">Foo</foo>
-        <bar id="1">Bar</bar>
-    </bar>
-    <baz id="2"/>
-    <quux id="1"/>
-</foo>
-
-  // Selecting all bar elements where id="1"
-> xml..bar.(@id == 1)
-  Bar
-
-  // Literals:
-  // XMLList literal. No root node.
-> <>Foo<br/>Baz</>
-  Foo
-  <br/>
-  Baz
-
-// Interpolation.
-> let x = "<foo/>"
-> <foo bar={x}>{x + "<?>"}</foo>
-  <foo/><?>
-> <foo bar={x}>{x + "<?>"}</foo>.toXMLString()
-  <foo bar="&lt;foo/>">&lt;foo/&gt;&lt;?&gt;</foo>
-
-> let x = <foo/>
-> <foo bar={x}>{x}</foo>.toXMLString()
-  <foo bar="">
-      <foo/>
-  </foo>
-
index d81411ea2877bbb8558e89731af3a158efa59f30..d0dd98a809265f8e95fc3ef420cdb286a89ab02b 100755 (executable)
 //
 // See https://wiki.mozilla.org/Extension_Manager:Bootstrapped_Extensions
 // for details.
+"use strict";
 
-const NAME = "bootstrap";
 const global = this;
 
 var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 
-function module(uri) {
-    let obj = {};
-    Cu.import(uri, obj);
-    return obj;
-}
+function module(uri) Cu.import(uri, {});
+
+const DEBUG = true;
+
+__defineGetter__("BOOTSTRAP", function () "resource://" + moduleName + "/bootstrap.jsm");
 
-const { AddonManager } = module("resource://gre/modules/AddonManager.jsm");
-const { XPCOMUtils }   = module("resource://gre/modules/XPCOMUtils.jsm");
-const { Services }     = module("resource://gre/modules/Services.jsm");
+var { AddonManager } = module("resource://gre/modules/AddonManager.jsm");
+var { XPCOMUtils }   = module("resource://gre/modules/XPCOMUtils.jsm");
+var { Services }     = module("resource://gre/modules/Services.jsm");
 
 const resourceProto = Services.io.getProtocolHandler("resource")
                               .QueryInterface(Ci.nsIResProtocolHandler);
 const categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
 const manager = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 
-const DISABLE_ACR        = "resource://dactyl-content/disable-acr.jsm";
-const BOOTSTRAP_JSM      = "resource://dactyl/bootstrap.jsm";
 const BOOTSTRAP_CONTRACT = "@dactyl.googlecode.com/base/bootstrap";
 
-var JSMLoader = BOOTSTRAP_CONTRACT in Cc && Cc[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader;
 var name = "dactyl";
 
 function reportError(e) {
-    dump("\n" + name + ": bootstrap: " + e + "\n" + (e.stack || Error().stack) + "\n");
+    let stack = e.stack || Error().stack;
+    dump("\n" + name + ": bootstrap: " + e + "\n" + stack + "\n");
     Cu.reportError(e);
+    Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
+                                       .logStringMessage(stack);
 }
-function debug(msg) {
-    dump(name + ": " + msg + "\n");
+function debug() {
+    if (DEBUG)
+        dump(name + ": " + Array.join(arguments, ", ") + "\n");
 }
 
-function httpGet(url) {
+function httpGet(uri) {
     let xmlhttp = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
     xmlhttp.overrideMimeType("text/plain");
-    xmlhttp.open("GET", url, false);
+    xmlhttp.open("GET", uri.spec || uri, false);
     xmlhttp.send(null);
     return xmlhttp;
 }
 
+let moduleName;
 let initialized = false;
 let addon = null;
 let addonData = null;
 let basePath = null;
+let bootstrap;
+let bootstrap_jsm;
 let categories = [];
 let components = {};
 let resources = [];
 let getURI = null;
 
-function updateLoader() {
+let JSMLoader = {
+    SANDBOX: Cu.nukeSandbox && false,
+
+    get addon() addon,
+
+    currentModule: null,
+
+    factories: [],
+
+    get name() name,
+
+    get module() moduleName,
+
+    globals: {},
+    modules: {},
+
+    times: {
+        all: 0,
+        add: function add(major, minor, delta) {
+            this.all += delta;
+
+            this[major] = (this[major] || 0) + delta;
+            if (minor) {
+                minor = ":" + minor;
+                this[minor] = (this[minor] || 0) + delta;
+                this[major + minor] = (this[major + minor] || 0) + delta;
+            }
+        },
+        clear: function clear() {
+            for (let key in this)
+                if (typeof this[key] !== "number")
+                    delete this[key];
+        }
+    },
+
+    getTarget: function getTarget(url) {
+        let uri = Services.io.newURI(url, null, null);
+        if (uri.schemeIs("resource"))
+            return resourceProto.resolveURI(uri);
+
+        let chan = Services.io.newChannelFromURI(uri);
+        try { chan.cancel(Cr.NS_BINDING_ABORTED) } catch (e) {}
+        return chan.name;
+    },
+
+    _atexit: [],
+
+    atexit: function atexit(arg, self) {
+        if (typeof arg !== "string")
+            this._atexit.push(arguments);
+        else
+            for each (let [fn, self] in this._atexit)
+                try {
+                    fn.call(self, arg);
+                }
+                catch (e) {
+                    reportError(e);
+                }
+    },
+
+    _load: function _load(name, target) {
+        let urls = [name];
+        if (name.indexOf(":") === -1)
+            urls = this.config["module-paths"].map(function (path) path + name + ".jsm");
+
+        for each (let url in urls)
+            try {
+                var uri = this.getTarget(url);
+                if (uri in this.globals)
+                    return this.modules[name] = this.globals[uri];
+
+                this.globals[uri] = this.modules[name];
+                bootstrap_jsm.loadSubScript(url, this.modules[name]);
+                return;
+            }
+            catch (e) {
+                debug("Loading " + name + ": " + e);
+                delete this.globals[uri];
+
+                if (typeof e != "string")
+                    throw e;
+            }
+
+        throw Error("No such module: " + name);
+    },
+
+    load: function load(name, target) {
+        if (!this.modules.hasOwnProperty(name)) {
+            this.modules[name] = this.modules.base ? bootstrap.create(this.modules.base)
+                                                   : bootstrap.import({ JSMLoader: this, module: global.module });
+
+            let currentModule = this.currentModule;
+            this.currentModule = this.modules[name];
+
+            try {
+                this._load(name, this.modules[name]);
+            }
+            catch (e) {
+                delete this.modules[name];
+                reportError(e);
+                throw e;
+            }
+            finally {
+                this.currentModule = currentModule;
+            }
+        }
+
+        let module = this.modules[name];
+        if (target)
+            for each (let symbol in module.EXPORTED_SYMBOLS)
+                target[symbol] = module[symbol];
+
+        return module;
+    },
+
+    // Cuts down on stupid, fscking url mangling.
+    get loadSubScript() bootstrap_jsm.loadSubScript,
+
+    cleanup: function unregister() {
+        for each (let factory in this.factories.splice(0))
+            manager.unregisterFactory(factory.classID, factory);
+    },
+
+    Factory: function Factory(class_) ({
+        __proto__: class_.prototype,
+
+        createInstance: function (outer, iid) {
+            try {
+                if (outer != null)
+                    throw Cr.NS_ERROR_NO_AGGREGATION;
+                if (!class_.instance)
+                    class_.instance = new class_();
+                return class_.instance.QueryInterface(iid);
+            }
+            catch (e) {
+                Cu.reportError(e);
+                throw e;
+            }
+        }
+    }),
+
+    registerFactory: function registerFactory(factory) {
+        manager.registerFactory(factory.classID,
+                                String(factory.classID),
+                                factory.contractID,
+                                factory);
+        this.factories.push(factory);
+    }
+};
+
+function init() {
+    debug("bootstrap: init");
+
+    let manifestURI = getURI("chrome.manifest");
+    let manifest = httpGet(manifestURI)
+            .responseText
+            .replace(/#(resource)#/g, "$1")
+            .replace(/^\s*|\s*$|#.*/g, "")
+            .replace(/^\s*\n/gm, "");
+
+    for each (let line in manifest.split("\n")) {
+        let fields = line.split(/\s+/);
+        switch(fields[0]) {
+        case "category":
+            categoryManager.addCategoryEntry(fields[1], fields[2], fields[3], false, true);
+            categories.push([fields[1], fields[2]]);
+            break;
+        case "component":
+            components[fields[1]] = new FactoryProxy(getURI(fields[2]).spec, fields[1]);
+            break;
+        case "contract":
+            components[fields[2]].contractID = fields[1];
+            break;
+
+        case "resource":
+            moduleName = moduleName || fields[1];
+            resources.push(fields[1]);
+            resourceProto.setSubstitution(fields[1], getURI(fields[2]));
+        }
+    }
+
+    JSMLoader.config = JSON.parse(httpGet("resource://dactyl-local/config.json").responseText);
+
+    bootstrap_jsm = module(BOOTSTRAP);
+    if (!JSMLoader.SANDBOX)
+        bootstrap = bootstrap_jsm;
+    else {
+        bootstrap = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance(),
+                               { sandboxName: BOOTSTRAP });
+        Services.scriptloader.loadSubScript(BOOTSTRAP, bootstrap);
+    }
+    bootstrap.require = JSMLoader.load("base").require;
+
+    // Flush the cache if necessary, just to be paranoid
+    let pref = "extensions.dactyl.cacheFlushCheck";
+    let val  = addon.version;
+    if (!Services.prefs.prefHasUserValue(pref) || Services.prefs.getCharPref(pref) != val) {
+        var cacheFlush = true;
+        Services.obs.notifyObservers(null, "startupcache-invalidate", "");
+        Services.prefs.setCharPref(pref, val);
+    }
+
     try {
-        JSMLoader.loader = Cc["@dactyl.googlecode.com/extra/utils"].getService(Ci.dactylIUtils);
+        //JSMLoader.load("disable-acr").init(addon.id);
+    }
+    catch (e) {
+        reportError(e);
     }
-    catch (e) {};
+
+    Services.obs.notifyObservers(null, "dactyl-rehash", null);
+
+    JSMLoader.bootstrap = global;
+
+    JSMLoader.load("config", global);
+    JSMLoader.load("main", global);
+
+    JSMLoader.cacheFlush = cacheFlush;
+    JSMLoader.load("base", global);
+
+    if (!(BOOTSTRAP_CONTRACT in Cc)) {
+        // Use Sandbox to prevent closures over this scope
+        let sandbox = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance());
+        let factory = Cu.evalInSandbox("({ createInstance: function () this })", sandbox);
+
+        factory.classID         = Components.ID("{f541c8b0-fe26-4621-a30b-e77d21721fb5}");
+        factory.contractID      = BOOTSTRAP_CONTRACT;
+        factory.QueryInterface  = XPCOMUtils.generateQI([Ci.nsIFactory]);
+        factory.wrappedJSObject = factory;
+
+        manager.registerFactory(factory.classID, String(factory.classID),
+                                BOOTSTRAP_CONTRACT, factory);
+    }
+
+    Cc[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader = !Cu.unload && JSMLoader;
+
+    for each (let component in components)
+        component.register();
+
+    updateVersion();
+
+    if (addon !== addonData)
+        require("main", global);
 }
 
 /**
  * Performs necessary migrations after a version change.
  */
 function updateVersion() {
+    function isDev(ver) /^hg|pre$/.test(ver);
     try {
-        function isDev(ver) /^hg|pre$/.test(ver);
         if (typeof require === "undefined" || addon === addonData)
             return;
 
-        require(global, "config");
-        require(global, "prefs");
+        JSMLoader.load("prefs", global);
         config.lastVersion = localPrefs.get("lastVersion", null);
 
         localPrefs.set("lastVersion", addon.version);
@@ -100,7 +340,7 @@ function startup(data, reason) {
     if (!initialized) {
         initialized = true;
 
-        debug("bootstrap: init" + " " + data.id);
+        debug("bootstrap: init " + data.id);
 
         addonData = data;
         addon = data;
@@ -108,10 +348,9 @@ function startup(data, reason) {
         AddonManager.getAddonByID(addon.id, function (a) {
             addon = a;
 
-            updateLoader();
             updateVersion();
             if (typeof require !== "undefined")
-                require(global, "main");
+                require("main", global);
         });
 
         if (basePath.isDirectory())
@@ -166,120 +405,13 @@ FactoryProxy.prototype = {
     }
 }
 
-function init() {
-    debug("bootstrap: init");
-
-    let manifestURI = getURI("chrome.manifest");
-    let manifest = httpGet(manifestURI.spec)
-            .responseText
-            .replace(/^\s*|\s*$|#.*/g, "")
-            .replace(/^\s*\n/gm, "");
-
-    let suffix = "-";
-    let chars = "0123456789abcdefghijklmnopqrstuv";
-    for (let n = Date.now(); n; n = Math.round(n / chars.length))
-        suffix += chars[n % chars.length];
-
-    for each (let line in manifest.split("\n")) {
-        let fields = line.split(/\s+/);
-        switch(fields[0]) {
-        case "category":
-            categoryManager.addCategoryEntry(fields[1], fields[2], fields[3], false, true);
-            categories.push([fields[1], fields[2]]);
-            break;
-        case "component":
-            components[fields[1]] = new FactoryProxy(getURI(fields[2]).spec, fields[1]);
-            break;
-        case "contract":
-            components[fields[2]].contractID = fields[1];
-            break;
-
-        case "resource":
-            resources.push(fields[1], fields[1] + suffix);
-            resourceProto.setSubstitution(fields[1], getURI(fields[2]));
-            resourceProto.setSubstitution(fields[1] + suffix, getURI(fields[2]));
-        }
-    }
-
-    // Flush the cache if necessary, just to be paranoid
-    let pref = "extensions.dactyl.cacheFlushCheck";
-    let val  = addon.version;
-    if (!Services.prefs.prefHasUserValue(pref) || Services.prefs.getCharPref(pref) != val) {
-        var cacheFlush = true;
-        Services.obs.notifyObservers(null, "startupcache-invalidate", "");
-        Services.prefs.setCharPref(pref, val);
-    }
-
-    try {
-        module(DISABLE_ACR).init(addon.id);
-    }
-    catch (e) {
-        reportError(e);
-    }
-
-    if (JSMLoader) {
-        // Temporary hacks until platforms and dactyl releases that don't
-        // support Cu.unload are phased out.
-        if (Cu.unload) {
-            // Upgrading from dactyl release without Cu.unload support.
-            Cu.unload(BOOTSTRAP_JSM);
-            for (let [name] in Iterator(JSMLoader.globals))
-                Cu.unload(~name.indexOf(":") ? name : "resource://dactyl" + JSMLoader.suffix + "/" + name);
-        }
-        else if (JSMLoader.bump != 6) {
-            // We're in a version without Cu.unload support and the
-            // JSMLoader interface has changed. Bump off the old one.
-            Services.scriptloader.loadSubScript("resource://dactyl" + suffix + "/bootstrap.jsm",
-                Cu.import(BOOTSTRAP_JSM, global));
-        }
-    }
-
-    if (!JSMLoader || JSMLoader.bump !== 6 || Cu.unload)
-        Cu.import(BOOTSTRAP_JSM, global);
-
-    JSMLoader.name = name;
-    JSMLoader.bootstrap = this;
-
-    JSMLoader.load(BOOTSTRAP_JSM, global);
-
-    JSMLoader.init(suffix);
-    JSMLoader.cacheFlush = cacheFlush;
-    JSMLoader.load("base.jsm", global);
-
-    if (!(BOOTSTRAP_CONTRACT in Cc)) {
-        // Use Sandbox to prevent closures over this scope
-        let sandbox = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].getService());
-        let factory = Cu.evalInSandbox("({ createInstance: function () this })", sandbox);
-
-        factory.classID         = Components.ID("{f541c8b0-fe26-4621-a30b-e77d21721fb5}");
-        factory.contractID      = BOOTSTRAP_CONTRACT;
-        factory.QueryInterface  = XPCOMUtils.generateQI([Ci.nsIFactory]);
-        factory.wrappedJSObject = factory;
-
-        manager.registerFactory(factory.classID, String(factory.classID),
-                                BOOTSTRAP_CONTRACT, factory);
-    }
-
-    Cc[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader = !Cu.unload && JSMLoader;
-
-    for each (let component in components)
-        component.register();
-
-    Services.obs.notifyObservers(null, "dactyl-rehash", null);
-    updateVersion();
-
-    updateLoader();
-    if (addon !== addonData)
-        require(global, "main");
-}
-
 function shutdown(data, reason) {
-    debug("bootstrap: shutdown " + reasonToString(reason));
+    let strReason = reasonToString(reason);
+    debug("bootstrap: shutdown " + strReason);
+
     if (reason != APP_SHUTDOWN) {
         try {
-            module(DISABLE_ACR).cleanup();
-            if (Cu.unload)
-                Cu.unload(DISABLE_ACR);
+            //JSMLoader.load("disable-acr").cleanup(addon.id);
         }
         catch (e) {
             reportError(e);
@@ -288,10 +420,19 @@ function shutdown(data, reason) {
         if (~[ADDON_UPGRADE, ADDON_DOWNGRADE, ADDON_UNINSTALL].indexOf(reason))
             Services.obs.notifyObservers(null, "dactyl-purge", null);
 
-        Services.obs.notifyObservers(null, "dactyl-cleanup", reasonToString(reason));
+        Services.obs.notifyObservers(null, "dactyl-cleanup", strReason);
         Services.obs.notifyObservers(null, "dactyl-cleanup-modules", reasonToString(reason));
 
-        JSMLoader.purge();
+        JSMLoader.atexit(strReason);
+        JSMLoader.cleanup(strReason);
+
+        if (JSMLoader.SANDBOX)
+            Cu.nukeSandbox(bootstrap);
+        bootstrap_jsm.require = null;
+        Cu.unload(BOOTSTRAP);
+        bootstrap = null;
+        bootstrap_jsm = null;
+
         for each (let [category, entry] in categories)
             categoryManager.deleteCategoryEntry(category, entry, false);
         for each (let resource in resources)
index 3eae8e1ca00f20096f248bb9aa3d0d0caeb3dfee..fbf9096256ba21ed66b6216319c10de8431520b6 100644 (file)
@@ -1,14 +1,14 @@
-resource dactyl-local         ./
-resource dactyl-local-content content/
-resource dactyl-local-skin    skin/
-resource dactyl-local-locale  locale/
-
-resource dactyl-common      ../common/
 resource dactyl             ../common/modules/
+resource dactyl-common      ../common/
 resource dactyl-content     ../common/content/
 resource dactyl-skin        ../common/skin/
 resource dactyl-locale      ../common/locale/
 
+resource dactyl-local         ./
+resource dactyl-local-content content/
+resource dactyl-local-skin    skin/
+resource dactyl-local-locale  locale/
+
 content  dactyl  ../common/content/
 
 component {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69} components/commandline-handler.js
index 738e27516d084a8a2f711c7ac28c1a59fe90a0f1..0be89de64a918892be2ac2a70af94beccbefe6eb 100644 (file)
@@ -17,11 +17,8 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function init() {
     Cu.import("resource://dactyl/bootstrap.jsm");
-    if (!JSMLoader.initialized)
-        JSMLoader.init();
-    JSMLoader.load("base.jsm", global);
-    require(global, "config");
-    require(global, "util");
+    require("config", global);
+    require("util", global);
 }
 
 function CommandLineHandler() {
index 08294970d684e4e6541513620430f99c9129e4d7..4b646446aa607139f3c151137b818571d8f8eb72 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2010 by anekos <anekos@snca.net>
-// Copyright (c) 2010-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2010-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -213,18 +213,18 @@ var Abbreviations = Module("abbreviations", {
             nonkeyword: /[   "']/
         };
 
-        this._match = util.regexp(<><![CDATA[
+        this._match = util.regexp(literal(/*
             (^ | \s | <nonkeyword>) (<keyword>+             )$ | // full-id
             (^ | \s | <keyword>   ) (<nonkeyword>+ <keyword>)$ | // end-id
             (^ | \s               ) (\S* <nonkeyword>       )$   // non-id
-        ]]></>, "x", params);
-        this._check = util.regexp(<><![CDATA[
+        */), "x", params);
+        this._check = util.regexp(literal(/*
             ^ (?:
               <keyword>+              | // full-id
               <nonkeyword>+ <keyword> | // end-id
               \S* <nonkeyword>          // non-id
             ) $
-        ]]></>, "x", params);
+        */), "x", params);
     },
 
     get: deprecated("group.abbrevs.get", { get: function get() this.user.closure.get }),
@@ -262,33 +262,29 @@ var Abbreviations = Module("abbreviations", {
         function abbrevs(hive)
             hive.merged.filter(function (abbr) (abbr.inModes(modes) && abbr.lhs.indexOf(lhs) == 0));
 
-        let list = <table>
-                <tr highlight="Title">
-                    <td/>
-                    <td style="padding-right: 1em;">{_("title.Mode")}</td>
-                    <td style="padding-right: 1em;">{_("title.Abbrev")}</td>
-                    <td style="padding-right: 1em;">{_("title.Replacement")}</td>
-                </tr>
-                <col style="min-width: 6em; padding-right: 1em;"/>
-                {
-                    template.map(hives, function (hive) let (i = 0)
-                        <tr style="height: .5ex;"/> +
-                        template.map(abbrevs(hive), function (abbrev)
-                            <tr>
-                                <td highlight="Title">{!i++ ? hive.name : ""}</td>
-                                <td>{abbrev.modeChar}</td>
-                                <td>{abbrev.lhs}</td>
-                                <td>{abbrev.rhs}</td>
-                            </tr>) +
-                        <tr style="height: .5ex;"/>)
-                }
-                </table>;
-
-        // TODO: Move this to an ItemList to show this automatically
-        if (list.*.length() === list.text().length() + 2)
-            dactyl.echomsg(_("abbreviation.none"));
-        else
-            commandline.commandOutput(list);
+        let list = ["table", {},
+                ["tr", { highlight: "Title" },
+                    ["td"],
+                    ["td", { style: "padding-right: 1em;" }, _("title.Mode")],
+                    ["td", { style: "padding-right: 1em;" }, _("title.Abbrev")],
+                    ["td", { style: "padding-right: 1em;" }, _("title.Replacement")]],
+                ["col", { style: "min-width: 6em; padding-right: 1em;" }],
+                hives.map(function (hive) let (i = 0) [
+                    ["tr", { style: "height: .5ex;" }],
+                    abbrevs(hive).map(function (abbrev)
+                        ["tr", {},
+                            ["td", { highlight: "Title" }, !i++ ? String(hive.name) : ""],
+                            ["td", {}, abbrev.modeChar],
+                            ["td", {}, abbrev.lhs],
+                            ["td", {}, abbrev.rhs]]),
+                    ["tr", { style: "height: .5ex;" }]])];
+
+        // FIXME?
+        // // TODO: Move this to an ItemList to show this automatically
+        // if (list.*.length() === list.text().length() + 2)
+        //     dactyl.echomsg(_("abbreviation.none"));
+        // else
+        commandline.commandOutput(list);
     }
 
 }, {
@@ -299,7 +295,7 @@ var Abbreviations = Module("abbreviations", {
             user: contexts.hives.abbrevs.user
         });
     },
-    completion: function () {
+    completion: function initCompletion() {
         completion.abbreviation = function abbreviation(context, modes, group) {
             group = group || abbreviations.user;
             let fn = modes ? function (abbr) abbr.inModes(modes) : util.identity;
@@ -307,7 +303,7 @@ var Abbreviations = Module("abbreviations", {
             context.completions = group.merged.filter(fn);
         };
     },
-    commands: function () {
+    commands: function initCommands() {
         function addAbbreviationCommands(modes, ch, modeDescription) {
             modes.sort();
             modeDescription = modeDescription ? " in " + modeDescription + " mode" : "";
index aba640b3e4c9b5fb8227be6f6d0b47ec5bdec1ff..7c1aa158f82159c2497698172e795b2e0b119de1 100644 (file)
@@ -20,7 +20,7 @@ by Kris Maglione, Doug Kearns, et al.
 &dactyl.appName; is open source and freely distributable
 
 type :q&lt;<span class="key">Enter</span>>                 to exit         <!---->
-type :help&lt;<span class="key">Enter</span>>  or  &lt;<span class="key">F1</span>>    for on-line help
+type :help&lt;<span class="key">Enter</span>>                                        for on-line help
 type :help faq&lt;<span class="key">Enter</span>>          for the FAQ page
 type :help versions&lt;<span class="key">Enter</span>>     for version info
       </div>
index 31c3ad90826bcae04fddd387b0c39182311fb596..b1419028b76320b4d9472e8af0dc25e993cdfb38 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -103,31 +103,28 @@ var AutoCommands = Module("autocommands", {
             return cmds;
         }
 
-        XML.prettyPrinting = XML.ignoreWhitespace = false;
-        commandline.commandOutput(
-            <table>
-                <tr highlight="Title">
-                    <td colspan="3">----- Auto Commands -----</td>
-                </tr>
-                {
-                    template.map(hives, function (hive)
-                        <tr>
-                            <td colspan="3"><span highlight="Title">{hive.name}</span>
-                                            {hive.filter}</td>
-                        </tr> +
-                        <tr style="height: .5ex;"/> +
-                        template.map(cmds(hive), function ([event, items])
-                            <tr style="height: .5ex;"/> +
-                            template.map(items, function (item, i)
-                                <tr>
-                                    <td highlight="Title" style="padding-left: 1em; padding-right: 1em;">{i == 0 ? event : ""}</td>
-                                    <td>{item.filter.toXML ? item.filter.toXML() : item.filter}</td>
-                                    <td>{item.command}</td>
-                                </tr>) +
-                            <tr style="height: .5ex;"/>) +
-                        <tr style="height: .5ex;"/>)
-                }
-            </table>);
+        let table = (
+            ["table", {},
+                ["tr", { highlight: "Title" },
+                    ["td", { colspan: "3" }, "----- Auto Commands -----"]],
+                hives.map(function (hive) [
+                    ["tr", {},
+                        ["td", { colspan: "3" },
+                            ["span", { highlight: "Title" }, hive.name],
+                            " ", hive.filter.toJSONXML(modules)]],
+                    ["tr", { style: "height: .5ex;" }],
+                    iter(cmds(hive)).map(function ([event, items]) [
+                        ["tr", { style: "height: .5ex;" }],
+                        items.map(function (item, i)
+                            ["tr", {},
+                                ["td", { highlight: "Title", style: "padding-left: 1em; padding-right: 1em;" },
+                                    i == 0 ? event : ""],
+                                ["td", {}, item.filter.toJSONXML ? item.filter.toJSONXML(modules) : String(item.filter)],
+                                ["td", {}, String(item.command)]]),
+                        ["tr", { style: "height: .5ex;" }]]).toArray(),
+                    ["tr", { style: "height: .5ex;" }],
+                ])]);
+        commandline.commandOutput(table);
     },
 
     /**
@@ -168,7 +165,7 @@ var AutoCommands = Module("autocommands", {
     }
 }, {
 }, {
-    contexts: function () {
+    contexts: function initContexts() {
         update(AutoCommands.prototype, {
             hives: contexts.Hives("autocmd", AutoCmdHive),
             user: contexts.hives.autocmd.user,
@@ -176,7 +173,7 @@ var AutoCommands = Module("autocommands", {
             matchingHives: function matchingHives(uri, doc) contexts.matchingGroups(uri, doc).autocmd
         });
     },
-    commands: function () {
+    commands: function initCommands() {
         commands.add(["au[tocmd]"],
             "Execute commands automatically on events",
             function (args) {
@@ -280,15 +277,15 @@ var AutoCommands = Module("autocommands", {
                 });
         });
     },
-    completion: function () {
+    completion: function initCompletion() {
         completion.autocmdEvent = function autocmdEvent(context) {
             context.completions = Iterator(config.autocommands);
         };
     },
-    javascript: function () {
+    javascript: function initJavascript() {
         JavaScript.setCompleter(AutoCmdHive.prototype.get, [function () Iterator(config.autocommands)]);
     },
-    options: function () {
+    options: function initOptions() {
         options.add(["eventignore", "ei"],
             "List of autocommand event names which should be ignored",
             "stringlist", "",
index 195bee664cfd3673e13bf2c0e51c4079ec59235e..65ec1150733c7681fc97d963c435c5f82f7d6aa5 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 // also includes methods for dealing with keywords and search engines
 var Bookmarks = Module("bookmarks", {
@@ -135,7 +135,7 @@ var Bookmarks = Module("bookmarks", {
 
     checkBookmarked: function checkBookmarked(uri) {
         if (PlacesUtils.asyncGetBookmarkIds)
-            PlacesUtils.asyncGetBookmarkIds(uri, function (ids) {
+            PlacesUtils.asyncGetBookmarkIds(uri, function withBookmarkIDs(ids) {
                 statusline.bookmarked = ids.length;
             });
         else
@@ -402,7 +402,7 @@ var Bookmarks = Module("bookmarks", {
     }
 }, {
 }, {
-    commands: function () {
+    commands: function initCommands() {
         // TODO: Clean this up.
         const tags = {
             names: ["-tags", "-T"],
@@ -565,7 +565,7 @@ var Bookmarks = Module("bookmarks", {
                 privateData: true
             });
     },
-    mappings: function () {
+    mappings: function initMappings() {
         var myModes = config.browserModes;
 
         mappings.add(myModes, ["a"],
@@ -605,7 +605,7 @@ var Bookmarks = Module("bookmarks", {
             "Toggle bookmarked state of current URL",
             function () { bookmarks.toggle(buffer.uri.spec); });
     },
-    options: function () {
+    options: function initOptions() {
         options.add(["defsearch", "ds"],
             "The default search engine",
             "string", "google",
@@ -622,7 +622,7 @@ var Bookmarks = Module("bookmarks", {
              { completer: function completer(context) completion.searchEngine(context, true), });
     },
 
-    completion: function () {
+    completion: function initCompletion() {
         completion.bookmark = function bookmark(context, tags, extra) {
             context.title = ["Bookmark", "Title"];
             context.format = bookmarks.format;
index cc504ff12b97ba7c742b0a7827d0c0a8409397e4..a1b111094fd986cd1bb80763c2d9d862365fe984 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -202,11 +202,11 @@ var Browser = Module("browser", XPCOM(Ci.nsISupportsWeakReference, ModuleBase),
         commands.add(["redr[aw]"],
             "Redraw the screen",
             function () {
-                window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
-                      .redraw();
                 statusline.overLink = null;
                 statusline.updateStatus();
                 commandline.clear();
+                window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
+                      .redraw();
             },
             { argCount: "0" });
     },
@@ -267,12 +267,12 @@ var Browser = Module("browser", XPCOM(Ci.nsISupportsWeakReference, ModuleBase),
 
         mappings.add([modes.NORMAL], ["<open-homepage>", "gh"],
             "Open homepage",
-            function () { BrowserHome(); });
+            function () { window.BrowserHome(); });
 
         mappings.add([modes.NORMAL], ["<tab-open-homepage>", "gH"],
             "Open homepage in a new tab",
             function () {
-                let homepages = gHomeButton.getHomePage();
+                let homepages = window.gHomeButton.getHomePage();
                 dactyl.open(homepages, { from: "homepage", where: dactyl.NEW_TAB });
             });
 
index c318759626db4b8df5accd6c6466c13b0ee1abdf..f01cbb0b33b9f31a84b8d7af8bfd8ca3c5438037 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -14,56 +14,47 @@ var CommandWidgets = Class("CommandWidgets", {
     init: function init() {
         let s = "dactyl-statusline-field-";
 
-        XML.ignoreWhitespace = true;
         overlay.overlayWindow(window, {
             objects: {
                 eventTarget: commandline
             },
-            append: <e4x xmlns={XUL} xmlns:dactyl={NS}>
-                <vbox id={config.ids.commandContainer}>
-                    <vbox class="dactyl-container" hidden="false" collapsed="true">
-                        <iframe class="dactyl-completions" id="dactyl-completions-dactyl-commandline" src="dactyl://content/buffer.xhtml"
-                                contextmenu="dactyl-contextmenu"
-                                flex="1" hidden="false" collapsed="false"
-                                highlight="Events" events="mowEvents" />
-                    </vbox>
-
-                    <stack orient="horizontal" align="stretch" class="dactyl-container" id="dactyl-container" highlight="CmdLine CmdCmdLine">
-                        <textbox class="plain" id="dactyl-strut"   flex="1" crop="end" collapsed="true"/>
-                        <textbox class="plain" id="dactyl-mode"    flex="1" crop="end"/>
-                        <textbox class="plain" id="dactyl-message" flex="1" readonly="true"/>
-
-                        <hbox id="dactyl-commandline" hidden="false" class="dactyl-container" highlight="Normal CmdNormal" collapsed="true">
-                            <label   id="dactyl-commandline-prompt"  class="dactyl-commandline-prompt  plain" flex="0" crop="end" value="" collapsed="true"/>
-                            <textbox id="dactyl-commandline-command" class="dactyl-commandline-command plain" flex="1" type="input" timeout="100"
-                                     highlight="Events" />
-                        </hbox>
-                    </stack>
-
-                    <vbox class="dactyl-container" hidden="false" collapsed="false" highlight="CmdLine">
-                        <textbox id="dactyl-multiline-input" class="plain" flex="1" rows="1" hidden="false" collapsed="true" multiline="true"
-                                 highlight="Normal Events" events="multilineInputEvents" />
-                    </vbox>
-                </vbox>
-
-                <stack id="dactyl-statusline-stack">
-                    <hbox id={s + "commandline"} hidden="false" class="dactyl-container" highlight="Normal StatusNormal" collapsed="true">
-                        <label id={s + "commandline-prompt"}    class="dactyl-commandline-prompt  plain" flex="0" crop="end" value="" collapsed="true"/>
-                        <textbox id={s + "commandline-command"} class="dactyl-commandline-command plain" flex="1" type="text" timeout="100"
-                                 highlight="Events" />
-                    </hbox>
-                </stack>
-            </e4x>.elements(),
-
-            before: <e4x xmlns={XUL} xmlns:dactyl={NS}>
-                <toolbar id={statusline.statusBar.id}>
-                    <vbox id={"dactyl-completions-" + s + "commandline-container"} class="dactyl-container" hidden="false" collapsed="true">
-                        <iframe class="dactyl-completions" id={"dactyl-completions-" + s + "commandline"} src="dactyl://content/buffer.xhtml"
-                                contextmenu="dactyl-contextmenu" flex="1" hidden="false" collapsed="false"
-                                highlight="Events" events="mowEvents" />
-                    </vbox>
-                </toolbar>
-            </e4x>.elements()
+            append: [
+                ["vbox", { id: config.ids.commandContainer, xmlns: "xul" },
+                    ["vbox", { class: "dactyl-container", hidden: "false", collapsed: "true" },
+                        ["iframe", { class: "dactyl-completions", id: "dactyl-completions-dactyl-commandline",
+                                     src: "dactyl://content/buffer.xhtml", contextmenu: "dactyl-contextmenu",
+                                     flex: "1", hidden: "false", collapsed: "false",
+                                     highlight: "Events", events: "mowEvents" }]],
+
+                    ["stack", { orient: "horizontal", align: "stretch", class: "dactyl-container",
+                                id: "dactyl-container", highlight: "CmdLine CmdCmdLine" },
+                        ["textbox", { class: "plain", id: "dactyl-strut",   flex: "1", crop: "end", collapsed: "true" }],
+                        ["textbox", { class: "plain", id: "dactyl-mode",    flex: "1", crop: "end" }],
+                        ["hbox", { id: "dactyl-message-box" },
+                            ["label", { class: "plain", id: "dactyl-message-pre", flex: "0", readonly: "true", highlight: "WarningMsg" }],
+                            ["textbox", { class: "plain", id: "dactyl-message", flex: "1", readonly: "true" }]],
+
+                        ["hbox", { id: "dactyl-commandline", hidden: "false", class: "dactyl-container", highlight: "Normal CmdNormal", collapsed: "true" },
+                            ["label", {   id: "dactyl-commandline-prompt",  class: "dactyl-commandline-prompt  plain", flex: "0", crop: "end", value: "", collapsed: "true" }],
+                            ["textbox", { id: "dactyl-commandline-command", class: "dactyl-commandline-command plain", flex: "1", type: "input", timeout: "100",
+                                          highlight: "Events" }]]],
+
+                    ["vbox", { class: "dactyl-container", hidden: "false", collapsed: "false", highlight: "CmdLine" },
+                        ["textbox", { id: "dactyl-multiline-input", class: "plain", flex: "1", rows: "1", hidden: "false", collapsed: "true",
+                                      multiline: "true", highlight: "Normal Events", events: "multilineInputEvents" }]]],
+
+                ["stack", { id: "dactyl-statusline-stack", xmlns: "xul" },
+                    ["hbox", { id: s + "commandline", hidden: "false", class: "dactyl-container", highlight: "Normal StatusNormal", collapsed: "true" },
+                        ["label", { id: s + "commandline-prompt",    class: "dactyl-commandline-prompt  plain", flex: "0", crop: "end", value: "", collapsed: "true" }],
+                        ["textbox", { id: s + "commandline-command", class: "dactyl-commandline-command plain", flex: "1", type: "text", timeout: "100",
+                                      highlight: "Events",  }]]]],
+
+            before: [
+                ["toolbar", { id: statusline.statusBar.id, xmlns: "xul" },
+                    ["vbox", { id: "dactyl-completions-" + s + "commandline-container", class: "dactyl-container", hidden: "false", collapsed: "true" },
+                        ["iframe", { class: "dactyl-completions", id: "dactyl-completions-" + s + "commandline", src: "dactyl://content/buffer.xhtml",
+                                     contextmenu: "dactyl-contextmenu", flex: "1", hidden: "false", collapsed: "false", highlight: "Events",
+                                     events: "mowEvents" }]]]],
         });
 
         this.elements = {};
@@ -135,12 +126,26 @@ var CommandWidgets = Class("CommandWidgets", {
                     return this.statusbar;
 
                 let statusElem = this.statusbar.message;
-                if (value && !value[2] && statusElem.editor && statusElem.editor.rootElement.scrollWidth > statusElem.scrollWidth)
+                // Currently doesn't work as expected with <hbox> parent.
+                if (false && value && !value[2] && statusElem.editor && statusElem.editor.rootElement.scrollWidth > statusElem.scrollWidth)
                     return this.commandbar;
                 return this.activeGroup.mode;
             }
         });
 
+        this.addElement({
+            name: "message-pre",
+            defaultGroup: "WarningMsg",
+            getGroup: function () this.activeGroup.message
+        });
+
+        this.addElement({
+            name: "message-box",
+            defaultGroup: "Normal",
+            getGroup: function () this.activeGroup.message,
+            getValue: function () this.message
+        });
+
         this.addElement({
             name: "mode",
             defaultGroup: "ModeMsg",
@@ -224,6 +229,7 @@ var CommandWidgets = Class("CommandWidgets", {
     },
 
     updateVisibility: function updateVisibility() {
+        let changed = 0;
         for (let elem in values(this.elements))
             if (elem.getGroup) {
                 let value = elem.getValue ? elem.getValue.call(this)
@@ -234,6 +240,7 @@ var CommandWidgets = Class("CommandWidgets", {
                     let meth, node = group[elem.name];
                     let visible = (value && group === activeGroup);
                     if (node && !node.collapsed == !visible) {
+                        changed++;
                         node.collapsed = !visible;
                         if (elem.onVisibility)
                             elem.onVisibility.call(this, node, visible);
@@ -247,12 +254,22 @@ var CommandWidgets = Class("CommandWidgets", {
         function check(node) {
             if (DOM(node).style.display === "-moz-stack") {
                 let nodes = Array.filter(node.children, function (n) !n.collapsed && n.boxObject.height);
-                nodes.forEach(function (node, i) node.style.opacity = (i == nodes.length - 1) ? "" : "0");
+                nodes.forEach(function (node, i) { node.style.opacity = (i == nodes.length - 1) ? "" : "0" });
             }
             Array.forEach(node.children, check);
         }
         [this.commandbar.container, this.statusbar.container].forEach(check);
 
+        // Work around a redrawing bug.
+        if (changed && config.haveGecko("16", "20")) {
+            util.delay(function () {
+                // Urgh.
+                statusline.statusBar.style.paddingRight = "1px";
+                DOM(statusline.statusBar).rect; // Force reflow.
+                statusline.statusBar.style.paddingRight = "";
+            }, 0);
+        }
+
         if (this.initialized && loaded.mow && mow.visible)
             mow.resize(false);
     },
@@ -650,6 +667,7 @@ var CommandLine = Module("commandline", {
         if (!scroll || Date.now() - this._lastEchoTime > 5000)
             this.clearMessage();
         this._lastEchoTime = 0;
+        this.hiddenMessages = 0;
 
         if (!this.commandSession) {
             this.widgets.command = null;
@@ -664,8 +682,10 @@ var CommandLine = Module("commandline", {
     },
 
     clearMessage: function clearMessage() {
-        if (this.widgets.message && this.widgets.message[1] === this._lastClearable)
+        if (this.widgets.message && this.widgets.message[1] === this._lastClearable) {
             this.widgets.message = null;
+            this.hiddenMessages = 0;
+        }
     },
 
     /**
@@ -675,11 +695,11 @@ var CommandLine = Module("commandline", {
      * @param {XML} xml The output as an E4X XML object.
      */
     commandOutput: function commandOutput(xml) {
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        if (this.command)
-            this.echo(<><div xmlns={XHTML}>:{this.command}</div>&#x0d;{xml}</>, this.HIGHLIGHT_NORMAL, this.FORCE_MULTILINE);
-        else
+        if (!this.command)
             this.echo(xml, this.HIGHLIGHT_NORMAL, this.FORCE_MULTILINE);
+        else
+            this.echo([["div", { xmlns: "html" }, ":" + this.command], "\n", xml],
+                      this.HIGHLIGHT_NORMAL, this.FORCE_MULTILINE);
         this.command = null;
     },
 
@@ -710,10 +730,20 @@ var CommandLine = Module("commandline", {
         let field = this.widgets.active.message.inputField;
         if (field.value && !forceSingle && field.editor.rootElement.scrollWidth > field.scrollWidth) {
             this.widgets.message = null;
-            mow.echo(<span highlight="Message">{str}</span>, highlightGroup, true);
+            mow.echo(["span", { highlight: "Message" }, str], highlightGroup, true);
         }
     },
 
+    _hiddenMessages: 0,
+    get hiddenMessages() this._hiddenMessages,
+    set hiddenMessages(val) {
+        this._hiddenMessages = val;
+        if (val)
+            this.widgets["message-pre"] = _("commandline.moreMessages", val) + " ";
+        else
+            this.widgets["message-pre"] = null
+    },
+
     _lastEcho: null,
 
     /**
@@ -747,40 +777,68 @@ var CommandLine = Module("commandline", {
 
         highlightGroup = highlightGroup || this.HL_NORMAL;
 
-        if (flags & this.APPEND_TO_MESSAGES) {
-            let message = isObject(data) ? data : { message: data };
+        let self = this;
+        function appendToMessages(data) {
+            let message = isObject(data) && !DOM.isJSONXML(data) ? data : { message: data };
 
             // Make sure the memoized message property is an instance property.
             message.message;
-            this._messageHistory.add(update({ highlight: highlightGroup }, message));
-            data = message.message;
+            self._messageHistory.add(update({ highlight: highlightGroup }, message));
+            return message.message;
         }
 
+        if (flags & this.APPEND_TO_MESSAGES)
+            data = appendToMessages(data);
+
         if ((flags & this.ACTIVE_WINDOW) && window != overlay.activeWindow)
             return;
 
         if ((flags & this.DISALLOW_MULTILINE) && !this.widgets.mowContainer.collapsed)
             return;
 
-        let single = flags & (this.FORCE_SINGLELINE | this.DISALLOW_MULTILINE);
+        let forceSingle = flags & (this.FORCE_SINGLELINE | this.DISALLOW_MULTILINE);
         let action = this._echoLine;
 
         if ((flags & this.FORCE_MULTILINE) || (/\n/.test(data) || !isinstance(data, [_, "String"])) && !(flags & this.FORCE_SINGLELINE))
             action = mow.closure.echo;
 
-        if (single)
+        let single = function () action == self._echoLine;
+
+        if (forceSingle) {
             this._lastEcho = null;
+            this.hiddenMessages = 0;
+        }
         else {
-            if (this.widgets.message && this.widgets.message[1] == this._lastEcho)
-                mow.echo(<span highlight="Message">{this._lastEcho}</span>,
-                         this.widgets.message[0], true);
-
-            if (action === this._echoLine && !(flags & this.FORCE_MULTILINE)
-                && !(dactyl.fullyInitialized && this.widgets.mowContainer.collapsed)) {
+            // So complicated...
+            if (single() && !this.widgets.mowContainer.collapsed) {
                 highlightGroup += " Message";
                 action = mow.closure.echo;
             }
-            this._lastEcho = (action == this._echoLine) && data;
+            else if (!single() && this.widgets.mowContainer.collapsed) {
+                if (this._lastEcho && this.widgets.message && this.widgets.message[1] == this._lastEcho.msg) {
+                    if (!(this._lastEcho.flags & this.APPEND_TO_MESSAGES))
+                        appendToMessages(this._lastEcho.data);
+
+                    mow.echo(
+                        ["span", { highlight: "Message" },
+                            ["span", { highlight: "WarningMsg" },
+                                _("commandline.moreMessages", this.hiddenMessages + 1) + " "],
+                            this._lastEcho.msg],
+                        this.widgets.message[0], true);
+
+                    this.hiddenMessages = 0;
+                }
+            }
+            else if (this._lastEcho && this.widgets.message && this.widgets.message[1] == this._lastEcho.msg) {
+                if (!(this._lastEcho.flags & this.APPEND_TO_MESSAGES))
+                    appendToMessages(this._lastEcho.data);
+                if (single() && !(flags & this.APPEND_TO_MESSAGES))
+                    appendToMessages(data);
+
+                flags |= this.APPEND_TO_MESSAGES;
+                this.hiddenMessages++;
+            }
+            this._lastEcho = single() && { flags: flags, msg: data, data: arguments[0] };
         }
 
         this._lastClearable = action === this._echoLine && String(data);
@@ -944,12 +1002,18 @@ var CommandLine = Module("commandline", {
         save: function save() {
             if (events.feedingKeys)
                 return;
+
             let str = this.input.value;
             if (/^\s*$/.test(str))
                 return;
+
+            let privateData = this.checkPrivate(str);
+            if (privateData == "never-save")
+                return;
+
             this.store = this.store.filter(function (line) (line.value || line) != str);
             dactyl.trapErrors(function () {
-                this.store.push({ value: str, timestamp: Date.now()*1000, privateData: this.checkPrivate(str) });
+                this.store.push({ value: str, timestamp: Date.now()*1000, privateData: privateData });
             }, this);
             this.store = this.store.slice(Math.max(0, this.store.length - options["history"]));
         },
@@ -1404,8 +1468,8 @@ var CommandLine = Module("commandline", {
             substring = substring.substr(value.length);
             this.removeSubstring = substring;
 
-            let node = DOM.fromXML(<span highlight="Preview">{substring}</span>,
-                                   document);
+            let node = DOM.fromJSON(["span", { highlight: "Preview" }, substring],
+                                    document);
 
             this.withSavedValues(["caret"], function () {
                 this.editor.insertNode(node, this.editor.rootElement, 1);
@@ -1593,7 +1657,7 @@ var CommandLine = Module("commandline", {
         return arg;
     }
 }, {
-    commands: function init_commands() {
+    commands: function initCommands() {
         [
             {
                 name: "ec[ho]",
@@ -1631,10 +1695,10 @@ var CommandLine = Module("commandline", {
                     commandline.echo(message.message, message.highlight, commandline.FORCE_SINGLELINE);
                 }
                 else if (commandline._messageHistory.length > 1) {
-                    XML.ignoreWhitespace = false;
                     commandline.commandOutput(
                         template.map(commandline._messageHistory.messages, function (message)
-                            <div highlight={message.highlight + " Message"}>{message.message}</div>));
+                           ["div", { highlight: message.highlight + " Message" },
+                               message.message]));
                 }
             },
             { argCount: "0" });
@@ -1679,7 +1743,7 @@ var CommandLine = Module("commandline", {
             bases: [modes.INSERT]
         });
     },
-    mappings: function init_mappings() {
+    mappings: function initMappings() {
 
         mappings.add([modes.COMMAND],
             [":"], "Enter Command Line mode",
@@ -1809,7 +1873,7 @@ var CommandLine = Module("commandline", {
         bind(["<C-]>", "<C-5>"], "Expand command line abbreviation",
              function () { editor.expandAbbreviation(modes.COMMAND_LINE); });
     },
-    options: function init_options() {
+    options: function initOptions() {
         options.add(["history", "hi"],
             "Number of Ex commands and search patterns to store in the command-line history",
             "number", 500,
@@ -1825,7 +1889,7 @@ var CommandLine = Module("commandline", {
             "number", 100,
             { validator: function (value) value >= 0 });
     },
-    sanitizer: function init_sanitizer() {
+    sanitizer: function initSanitizer() {
         sanitizer.addItem("commandline", {
             description: "Command-line and search history",
             persistent: true,
@@ -1896,21 +1960,21 @@ var ItemList = Class("ItemList", {
         DOM(this.win).resize(this._onResize.closure.tell);
     },
 
-    get rootXML() <e4x>
-        <div highlight="Normal" style="white-space: nowrap" key="root">
-            <div key="wrapper">
-                <div highlight="Completions" key="noCompletions"><span highlight="Title">{_("completion.noCompletions")}</span></div>
-                <div key="completions"/>
-            </div>
+    get rootXML()
+        ["div", { highlight: "Normal", style: "white-space: nowrap", key: "root" },
+            ["div", { key: "wrapper" },
+                ["div", { highlight: "Completions", key: "noCompletions" },
+                    ["span", { highlight: "Title" },
+                        _("completion.noCompletions")]],
+                ["div", { key: "completions" }]],
 
-            <div highlight="Completions">{
-            template.map(util.range(0, options["maxitems"] * 2), function (i)
-                <div highlight="CompItem NonText"><li>~</li></div>)
-            }</div>
-        </div>
-    </e4x>.elements(),
+            ["div", { highlight: "Completions" },
+                template.map(util.range(0, options["maxitems"] * 2), function (i)
+                    ["div", { highlight: "CompItem NonText" },
+                        "~"])]],
 
-    get itemCount() this.context.contextList.reduce(function (acc, ctxt) acc + ctxt.items.length, 0),
+    get itemCount() this.context.contextList
+                        .reduce(function (acc, ctxt) acc + ctxt.items.length, 0),
 
     get visible() !this.container.collapsed,
     set visible(val) this.container.collapsed = !val,
@@ -2180,9 +2244,11 @@ var ItemList = Class("ItemList", {
                 let off = group.getOffset(idx);
 
                 start = Math.constrain(start,
-                                       off + Math.min(this.CONTEXT_LINES, group.itemCount - idx + group.offsets.end)
+                                       off + Math.min(this.CONTEXT_LINES,
+                                                      group.itemCount - idx + group.offsets.end)
                                            - this.maxItems + 1,
-                                       off - Math.min(this.CONTEXT_LINES, idx + group.offsets.start));
+                                       off - Math.min(this.CONTEXT_LINES,
+                                                      idx + group.offsets.start));
             }
 
             let count = this.maxItems;
@@ -2232,21 +2298,19 @@ var ItemList = Class("ItemList", {
         },
 
         get rootXML()
-            <div key="root" highlight="CompGroup">
-                <div highlight="Completions">
-                    { this.context.createRow(this.context.title || [], "CompTitle") }
-                </div>
-                <div highlight="CompTitleSep"/>
-                <div key="contents">
-                    <div key="up" highlight="CompLess"/>
-                    <div key="message" highlight="CompMsg">{this.context.message}</div>
-                    <div key="itemsContainer" class="completion-items-container">
-                        <div key="items" highlight="Completions"/>
-                    </div>
-                    <div key="waiting" highlight="CompMsg">{ItemList.WAITING_MESSAGE}</div>
-                    <div key="down" highlight="CompMore"/>
-                </div>
-            </div>,
+            ["div", { key: "root", highlight: "CompGroup" },
+                ["div", { highlight: "Completions" },
+                    this.context.createRow(this.context.title || [], "CompTitle")],
+                ["div", { highlight: "CompTitleSep" }],
+                ["div", { key: "contents" },
+                    ["div", { key: "up", highlight: "CompLess" }],
+                    ["div", { key: "message", highlight: "CompMsg" },
+                        this.context.message || []],
+                    ["div", { key: "itemsContainer", class: "completion-items-container" },
+                        ["div", { key: "items", highlight: "Completions" }]],
+                    ["div", { key: "waiting", highlight: "CompMsg" },
+                        ItemList.WAITING_MESSAGE],
+                    ["div", { key: "down", highlight: "CompMore" }]]],
 
         get doc() this.parent.doc,
         get win() this.parent.win,
@@ -2288,7 +2352,7 @@ var ItemList = Class("ItemList", {
             this.nodes = {};
             this.generatedRange = ItemList.Range(0, 0);
 
-            DOM.fromXML(this.rootXML, this.doc, this.nodes);
+            DOM.fromJSON(this.rootXML, this.doc, this.nodes);
         },
 
         /**
@@ -2299,9 +2363,10 @@ var ItemList = Class("ItemList", {
             DOM(this.nodes.items).empty();
 
             if (this.context.message)
-                DOM(this.nodes.message).empty().append(<>{this.context.message}</>);
+                DOM(this.nodes.message).empty()
+                    .append(DOM.fromJSON(this.context.message, this.doc));
 
-            if (!this.selectedIdx > this.itemCount)
+            if (this.selectedIdx > this.itemCount)
                 this.selectedIdx = null;
         },
 
index 2933dcd95d2a35e65ef0a1794d507e6b37188c3c..02ce9bd177eec85c419f7875c35bdd8caac1e2be 100644 (file)
@@ -1,17 +1,13 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
-default xml namespace = XHTML;
-XML.ignoreWhitespace = false;
-XML.prettyPrinting = false;
-
 var EVAL_ERROR = "__dactyl_eval_error";
 var EVAL_RESULT = "__dactyl_eval_result";
 var EVAL_STRING = "__dactyl_eval_string";
@@ -20,7 +16,8 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
     init: function () {
         window.dactyl = this;
         // cheap attempt at compatibility
-        let prop = { get: deprecated("dactyl", function liberator() dactyl) };
+        let prop = { get: deprecated("dactyl", function liberator() dactyl),
+                     configurable: true };
         Object.defineProperty(window, "liberator", prop);
         Object.defineProperty(modules, "liberator", prop);
         this.commands = {};
@@ -57,9 +54,9 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
         delete window.liberator;
 
         // Prevents box ordering bugs after our stylesheet is removed.
-        styles.system.add("cleanup-sheet", config.styleableChrome, <![CDATA[
+        styles.system.add("cleanup-sheet", config.styleableChrome, literal(/*
             #TabsToolbar tab { display: none; }
-        ]]>);
+        */));
         styles.unregisterSheet("resource://dactyl-skin/dactyl.css");
         DOM('#TabsToolbar tab', document).style.display;
     },
@@ -112,7 +109,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
 
     signals: {
         "io.source": function ioSource(context, file, modTime) {
-            if (context.INFO)
+            if (contexts.getDocs(context))
                 help.flush("help/plugins.xml", modTime);
         }
     },
@@ -167,6 +164,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
     NEW_WINDOW: "window",
 
     forceBackground: null,
+    forcePrivate: null,
     forceTarget: null,
 
     get forceOpen() ({ background: this.forceBackground,
@@ -285,7 +283,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                 for (let obj in values(results)) {
                     let res = dactyl.generateHelp(obj, null, null, true);
                     if (!haveTag(obj.helpTag))
-                        res[1].@tag = obj.helpTag;
+                        res[0][1].tag = obj.helpTag;
 
                     yield res;
                 }
@@ -304,20 +302,15 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                 bell: document.getElementById("dactyl-bell"),
                 strut: document.getElementById("dactyl-bell-strut")
             };
-            XML.ignoreWhitespace = true;
             if (!elems.bell)
                 overlay.overlayWindow(window, {
                     objects: elems,
-                    prepend: <>
-                        <window id={document.documentElement.id} xmlns={XUL}>
-                            <hbox style="display: none" highlight="Bell" id="dactyl-bell" key="bell"/>
-                        </window>
-                    </>,
-                    append: <>
-                        <window id={document.documentElement.id} xmlns={XUL}>
-                            <hbox style="display: none" highlight="Bell" id="dactyl-bell-strut" key="strut"/>
-                        </window>
-                    </>
+                    prepend: [
+                        ["window", { id: document.documentElement.id, xmlns: "xul" },
+                            ["hbox", { style: "display: none",  highlight: "Bell", id: "dactyl-bell", key: "bell" }]]],
+                    append: [
+                        ["window", { id: document.documentElement.id, xmlns: "xul" },
+                            ["hbox", { style: "display: none", highlight: "Bell", id: "dactyl-bell-strut", key: "strut" }]]]
                 }, elems);
 
             elems.bell.style.height = window.innerHeight + "px";
@@ -427,7 +420,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
         if (isObject(str) && "echoerr" in str)
             str = str.echoerr;
         else if (isinstance(str, ["Error", FailedAssertion]) && str.fileName)
-            str = <>{str.fileName.replace(/^.* -> /, "")}: {str.lineNumber}: {str}</>;
+            str = [str.fileName.replace(/^.* -> /, ""), ": ", str.lineNumber, ": ", str].join("");
 
         if (options["errorbells"])
             dactyl.beep();
@@ -475,11 +468,11 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      * @param {Object} context The context object into which the script
      *     should be loaded.
      */
-    loadScript: function (uri, context) {
+    loadScript: function loadScript(uri, context) {
         JSMLoader.loadSubScript(uri, context, File.defaultEncoding);
     },
 
-    userEval: function (str, context, fileName, lineNumber) {
+    userEval: function userEval(str, context, fileName, lineNumber) {
         let ctxt;
         if (jsmodules.__proto__ != window && jsmodules.__proto__ != XPCNativeWrapper(window) &&
                 jsmodules.isPrototypeOf(context))
@@ -531,7 +524,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      * Acts like the Function builtin, but the code executes in the
      * userContext global.
      */
-    userFunc: function () {
+    userFunc: function userFunc() {
         return this.userEval(
             "(function userFunction(" + Array.slice(arguments, 0, -1).join(", ") + ")" +
             " { " + arguments[arguments.length - 1] + " })");
@@ -546,7 +539,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      * @param {boolean} silent Whether the command should be echoed on the
      *     command line.
      */
-    execute: function (str, modifiers, silent) {
+    execute: function execute(str, modifiers, silent) {
         // skip comments and blank lines
         if (/^\s*("|$)/.test(str))
             return;
@@ -630,7 +623,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      * @param {string} feature The feature name.
      * @returns {boolean}
      */
-    has: function (feature) Set.has(config.features, feature),
+    has: function has(feature) Set.has(config.features, feature),
 
     /**
      * @private
@@ -656,17 +649,11 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      */
     initHelp: function initHelp() {
         if ("noscriptOverlay" in window)
-            noscriptOverlay.safeAllow("dactyl:", true, false);
+            window.noscriptOverlay.safeAllow("dactyl:", true, false);
 
         help.initialize();
     },
 
-    stringifyXML: function (xml) {
-        XML.prettyPrinting = false;
-        XML.ignoreWhitespace = false;
-        return UTF8(xml.toXMLString());
-    },
-
     /**
      * Generates a help entry and returns it as a string.
      *
@@ -676,107 +663,94 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      * @returns {string}
      */
     generateHelp: function generateHelp(obj, extraHelp, str, specOnly) {
-        default xml namespace = "";
-
         let link, tag, spec;
         link = tag = spec = util.identity;
         let args = null;
 
         if (obj instanceof Command) {
-            link = function (cmd) <ex>{cmd}</ex>;
+            link = function (cmd) ["ex", {}, cmd];
             args = obj.parseArgs("", CompletionContext(str || ""));
-            tag  = function (cmd) <>:{cmd}</>;
-            spec = function (cmd) <>{
-                    obj.count ? <oa>count</oa> : <></>
-                }{
-                    cmd
-                }{
-                    obj.bang ? <oa>!</oa> : <></>
-                }</>;
+            tag  = function (cmd) DOM.DOMString(":" + cmd);
+            spec = function (cmd) [
+                obj.count ? ["oa", {}, "count"] : [],
+                cmd,
+                obj.bang ? ["oa", {}, "!"] : []
+            ];
         }
         else if (obj instanceof Map) {
-            spec = function (map) obj.count ? <><oa>count</oa>{map}</> : <>{map}</>;
-            tag = function (map) <>{
-                    let (c = obj.modes[0].char) c ? c + "_" : ""
-                }{ map }</>;
+            spec = function (map) obj.count ? [["oa", {}, "count"], map] : DOM.DOMString(map);
+            tag = function (map) [
+                let (c = obj.modes[0].char) c ? c + "_" : "",
+                map
+            ]
             link = function (map) {
                 let [, mode, name, extra] = /^(?:(.)_)?(?:<([^>]+)>)?(.*)$/.exec(map);
-                let k = <k>{extra}</k>;
+                let k = ["k", {}, extra];
                 if (name)
-                    k.@name = name;
+                    k[1].name = name;
                 if (mode)
-                    k.@mode = mode;
+                    k[1].mode = mode;
                 return k;
             };
         }
         else if (obj instanceof Option) {
             spec = function () template.map(obj.names, tag, " ");
-            tag = function (name) <>'{name}'</>;
-            link = function (opt, name) <o>{name}</o>;
+            tag = function (name) DOM.DOMString("'" + name + "'");
+            link = function (opt, name) ["o", {}, name];
             args = { value: "", values: [] };
         }
 
-        XML.prettyPrinting = false;
-        XML.ignoreWhitespace = false;
-        default xml namespace = NS;
-
-        // E4X has its warts.
-        let br = <>
-                    </>;
-
-        let res = <res>
-                <dt>{link(obj.helpTag || tag(obj.name), obj.name)}</dt> <dd>{
-                    template.linkifyHelp(obj.description ? obj.description.replace(/\.$/, "") : "", true)
-                }</dd></res>;
+        let res = [
+                ["dt", {}, link(obj.helpTag || tag(obj.name), obj.name)],
+                ["dd", {},
+                    template.linkifyHelp(obj.description ? obj.description.replace(/\.$/, "") : "", true)]];
         if (specOnly)
-            return res.elements();
+            return res;
 
-        res.* += <>
-            <item>
-                <tags>{template.map(obj.names.slice().reverse(), tag, " ")}</tags>
-                <spec>{let (name = (obj.specs || obj.names)[0])
+        let description = ["description", {},
+            obj.description ? ["p", {}, template.linkifyHelp(obj.description.replace(/\.?$/, "."), true)] : "",
+            extraHelp ? extraHelp : "",
+            !(extraHelp || obj.description) ? ["p", {}, /*L*/ "Sorry, no help available."] : ""]
+
+        res.push(
+            ["item", {},
+                ["tags", {}, template.map(obj.names.slice().reverse(),
+                                          tag,
+                                          " ").join("")],
+                ["spec", {},
+                    let (name = (obj.specs || obj.names)[0])
                           spec(template.highlightRegexp(tag(name),
                                /\[(.*?)\]/g,
-                               function (m, n0) <oa>{n0}</oa>),
-                               name)
-                }</spec>{
-                !obj.type ? "" : <>
-                <type>{obj.type}</type>
-                <default>{obj.stringDefaultValue}</default></>}
-                <description>{
-                    obj.description ? br + <p>{template.linkifyHelp(obj.description.replace(/\.?$/, "."), true)}</p> : "" }{
-                        extraHelp ? br + extraHelp : "" }{
-                        !(extraHelp || obj.description) ? br + <p><!--L-->Sorry, no help available.</p> : "" }
-                </description>
-            </item></>;
+                               function (m, n0) ["oa", {}, n0]),
+                               name)],
+                !obj.type ? "" : [
+                    ["type", {}, obj.type],
+                    ["default", {}, obj.stringDefaultValue]],
+                description]);
 
         function add(ary) {
-            res.item.description.* += br +
-                let (br = br + <>    </>)
-                    <><dl>{ br + template.map(ary, function ([a, b]) <><dt>{a}</dt> <dd>{b}</dd></>, br) }
-                    </dl>
-                </>;
+            description.push(
+                ["dl", {}, template.map(ary,
+                                        function ([a, b]) [["dt", {}, a], " ",
+                                                           ["dd", {}, b]])]);
         }
 
-        if (obj.completer)
+        if (obj.completer && false)
             add(completion._runCompleter(obj.closure.completer, "", null, args).items
                           .map(function (i) [i.text, i.description]));
 
-        if (obj.options && obj.options.some(function (o) o.description))
+        if (obj.options && obj.options.some(function (o) o.description) && false)
             add(obj.options.filter(function (o) o.description)
                    .map(function (o) [
                         o.names[0],
-                        <>{o.description}{
-                            o.names.length == 1 ? "" :
-                                <> (short name: {
-                                    template.map(o.names.slice(1), function (n) <em>{n}</em>, <>, </>)
-                                })</>
-                        }</>
+                        [o.description,
+                         o.names.length == 1 ? "" :
+                             ["", " (short name: ",
+                                 template.map(o.names.slice(1), function (n) ["em", {}, n], ", "),
+                              ")"]]
                     ]));
-        return res.*.toXMLString()
-                  .replace(' xmlns="' + NS + '"', "", "g")
-                  .replace(/^ {12}|[ \t]+$/gm, "")
-                  .replace(/^\s*\n|\n\s*$/g, "") + "\n";
+
+        return DOM.toPrettyXML(res, true, null, { "": String(NS) });
     },
 
     /**
@@ -789,7 +763,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
         get: function globalVariables() this._globalVariables
     }),
 
-    loadPlugins: function (args, force) {
+    loadPlugins: function loadPlugins(args, force) {
         function sourceDirectory(dir) {
             dactyl.assert(dir.isReadable(), _("io.notReadable", dir.path));
 
@@ -846,7 +820,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      * @param {string|Object} msg The message to print.
      * @param {number} level The logging level 0 - 15.
      */
-    log: function (msg, level) {
+    log: function log(msg, level) {
         let verbose = config.prefs.get("loglevel", 0);
 
         if (!level || level <= verbose) {
@@ -916,7 +890,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      *     tabs.
      * @returns {boolean}
      */
-    open: function (urls, params, force) {
+    open: function open(urls, params, force) {
         if (typeof urls == "string")
             urls = dactyl.parseURLs(urls);
 
@@ -982,7 +956,11 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                     });
 
                 case dactyl.NEW_WINDOW:
-                    let win = window.openDialog(document.documentURI, "_blank", "chrome,all,dialog=no");
+                    let options = ["chrome", "all", "dialog=no"];
+                    if (dactyl.forcePrivate)
+                        options.push("private");
+
+                    let win = window.openDialog(document.documentURI, "_blank", options.join(","));
                     util.waitFor(function () win.document.readyState === "complete");
                     browser = win.dactyl && win.dactyl.modules.config.tabbrowser || win.getBrowser();
                     // FALLTHROUGH
@@ -1035,7 +1013,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                     // Try to find a matching file.
                     let file = io.File(url);
                     if (file.exists() && file.isReadable())
-                        return services.io.newFileURI(file).spec;
+                        return file.URI.spec;
                 }
                 catch (e) {}
             }
@@ -1060,15 +1038,15 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
         }, this);
     },
     stringToURLArray: deprecated("dactyl.parseURLs", "parseURLs"),
-    urlish: Class.Memoize(function () util.regexp(<![CDATA[
+    urlish: Class.Memoize(function () util.regexp(literal(/*
             ^ (
                 <domain>+ (:\d+)? (/ .*) |
                 <domain>+ (:\d+) |
                 <domain>+ \. [a-z0-9]+ |
                 localhost
             ) $
-        ]]>, "ix", {
-        domain: util.regexp(String.replace(<![CDATA[
+        */), "ix", {
+        domain: util.regexp(String.replace(literal(/*
             [^
                 U0000-U002c // U002d-U002e --.
                 U002f       // /
@@ -1077,7 +1055,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                 U005b-U0060 // U0061-U007a A-Z
                 U007b-U007f
             ]
-        ]]>, /U/g, "\\u"), "x")
+        */), /U/g, "\\u"), "x")
     })),
 
     pluginFiles: {},
@@ -1105,7 +1083,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      * @param {boolean} force Forcibly quit irrespective of whether all
      *    windows could be closed individually.
      */
-    quit: function (saveSession, force) {
+    quit: function quit(saveSession, force) {
         if (!force && !this.confirmQuit())
             return;
 
@@ -1122,7 +1100,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
     /**
      * Restart the host application.
      */
-    restart: function (args) {
+    restart: function restart(args) {
         if (!this.confirmQuit())
             return;
 
@@ -1198,7 +1176,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
      * @returns {Object}
      * @see Commands#parseArgs
      */
-    parseCommandLine: function (cmdline) {
+    parseCommandLine: function parseCommandLine(cmdline) {
         try {
             return commands.get("rehash").parseArgs(cmdline);
         }
@@ -1207,7 +1185,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
             return [];
         }
     },
-    wrapCallback: function (callback, self) {
+    wrapCallback: function wrapCallback(callback, self) {
         self = self || this;
         let save = ["forceOpen"];
         let saved = save.map(function (p) dactyl[p]);
@@ -1234,28 +1212,31 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
 }, {
     toolbarHidden: function hidden(elem) (elem.getAttribute("autohide") || elem.getAttribute("collapsed")) == "true"
 }, {
-    cache: function () {
+    cache: function initCache() {
         cache.register("help/plugins.xml", function () {
             // Process plugin help entries.
-            XML.ignoreWhiteSpace = XML.prettyPrinting = false;
 
-            let body = XML();
+            let body = [];
             for (let [, context] in Iterator(plugins.contexts))
                 try {
                     let info = contexts.getDocs(context);
-                    if (info instanceof XML) {
-                        if (info.*.@lang.length()) {
-                            let lang = config.bestLocale(String(a) for each (a in info.*.@lang));
-
-                            info.* = info.*.(function::attribute("lang").length() == 0 || @lang == lang);
-
-                            for each (let elem in info.NS::info)
-                                for (let attr in values(["@name", "@summary", "@href"]))
-                                    if (elem[attr].length())
-                                        info[attr] = elem[attr];
+                    if (DOM.isJSONXML(info)) {
+                        let langs = info.slice(2).filter(function (e) isArray(e) && isObject(e[1]) && e[1].lang);
+                        if (langs) {
+                            let lang = config.bestLocale(l[1].lang for each (l in langs));
+
+                            info = info.slice(0, 2).concat(
+                                info.slice(2).filter(function (e) !isArray(e) || !isObject(e[1])
+                                                               || e[1].lang == lang));
+
+                            for each (let elem in info.slice(2).filter(function (e) isArray(e) && e[0] == "info" && isObject(e[1])))
+                                for (let attr in values(["name", "summary", "href"]))
+                                    if (attr in elem[1])
+                                        info[attr] = elem[1][attr];
                         }
-                        body += <h2 xmlns={NS.uri} tag={info.@name + '-plugin'}>{info.@summary}</h2> +
-                            info;
+                        body.push(["h2", { xmlns: "dactyl", tag: info[1].name + '-plugin' },
+                                       String(info[1].summary)]);
+                        body.push(info);
                     }
                 }
                 catch (e) {
@@ -1264,63 +1245,54 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
 
             return '<?xml version="1.0"?>\n' +
                    '<?xml-stylesheet type="text/xsl" href="dactyl://content/help.xsl"?>\n' +
-                   '<!DOCTYPE document SYSTEM "resource://dactyl-content/dactyl.dtd">\n' +
-                   <document xmlns={NS}
-                       name="plugins" title={config.appName + " Plugins"}>
-                       <h1 tag="using-plugins">{_("help.title.Using Plugins")}</h1>
-                       <toc start="2"/>
-
-                       {body}
-                   </document>.toXMLString();
+                   DOM.toXML(
+                       ["document", { xmlns: "dactyl", name: "plugins",
+                                      title: config.appName + ", Plugins" },
+                           ["h1", { tag: "using-plugins" }, _("help.title.Using Plugins")],
+                           ["toc", { start: "2" }],
+
+                           body]);
         });
 
         cache.register("help/index.xml", function () {
-            default xml namespace = NS;
-
             return '<?xml version="1.0"?>\n' +
-                   <overlay xmlns={NS}>{
-                   template.map(dactyl.indices, function ([name, iter])
-                       <dl insertafter={name + "-index"}>{
-                           template.map(iter(), util.identity)
-                       }</dl>, <>{"\n\n"}</>)
-                   }</overlay>;
+                   DOM.toXML(["overlay", { xmlns: "dactyl" },
+                       template.map(dactyl.indices, function ([name, iter])
+                           ["dl", { insertafter: name + "-index" },
+                               template.map(iter(), util.identity)],
+                           "\n\n")]);
         });
 
         cache.register("help/gui.xml", function () {
-            default xml namespace = NS;
-
             return '<?xml version="1.0"?>\n' +
-                   <overlay xmlns={NS}>
-                       <dl insertafter="dialog-list">{
-                       template.map(config.dialogs, function ([name, val])
-                           (!val[2] || val[2]())
-                               ? <><dt>{name}</dt><dd>{val[0]}</dd></>
-                               : undefined,
-                           <>{"\n"}</>)
-                       }</dl>
-                   </overlay>;
+                   DOM.toXML(["overlay", { xmlns: "dactyl" },
+                       ["dl", { insertafter: "dialog-list" },
+                           template.map(config.dialogs, function ([name, val])
+                               (!val[2] || val[2]())
+                                   ? [["dt", {}, name],
+                                      ["dd", {}, val[0]]]
+                                   : undefined,
+                               "\n")]]);
         });
 
         cache.register("help/privacy.xml", function () {
-            default xml namespace = NS;
-
             return '<?xml version="1.0"?>\n' +
-                   <overlay xmlns={NS}>
-                       <dl insertafter="sanitize-items">{
-                       template.map(options.get("sanitizeitems").values
-                           .sort(function (a, b) String.localeCompare(a.name, b.name)),
-                           function ({ name, description })
-                           <><dt>{name}</dt><dd>{template.linkifyHelp(description, true)}</dd></>,
-                           <>{"\n"}</>)
-                       }</dl>
-                   </overlay>;
+                   DOM.toXML(["overlay", { xmlns: "dactyl" },
+                       ["dl", { insertafter: "sanitize-items" },
+                           template.map(options.get("sanitizeitems").values
+                                                .sort(function (a, b) String.localeCompare(a.name,
+                                                                                           b.name)),
+                               function ({ name, description })
+                               [["dt", {}, name],
+                                ["dd", {}, template.linkifyHelp(description, true)]],
+                               "\n")]]);
         });
     },
-    events: function () {
+    events: function initEvents() {
         events.listen(window, dactyl, "events", true);
     },
     // Only general options are added here, which are valid for all Dactyl extensions
-    options: function () {
+    options: function initOptions() {
         options.add(["errorbells", "eb"],
             "Ring the bell when an error message is displayed",
             "boolean", false);
@@ -1453,15 +1425,16 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                             document.title = document.title.replace(RegExp("(.*)" + util.regexp.escape(old)), "$1" + current);
                     }
 
-                    if (services.has("privateBrowsing")) {
+                    if (win.hasAttribute("titlemodifier_privatebrowsing")) {
                         let oldValue = win.getAttribute("titlemodifier_normal");
                         let suffix = win.getAttribute("titlemodifier_privatebrowsing").substr(oldValue.length);
 
                         win.setAttribute("titlemodifier_normal", value);
                         win.setAttribute("titlemodifier_privatebrowsing", value + suffix);
 
-                        if (services.privateBrowsing.privateBrowsingEnabled) {
+                        if (storage.privateMode) {
                             updateTitle(oldValue + suffix, value + suffix);
+                            win.setAttribute("titlemodifier", value + suffix);
                             return value;
                         }
                     }
@@ -1495,7 +1468,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
             });
     },
 
-    mappings: function () {
+    mappings: function initMappings() {
         if (dactyl.has("session"))
             mappings.add([modes.NORMAL], ["ZQ"],
                 "Quit and don't save the session",
@@ -1506,7 +1479,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
             function () { dactyl.quit(true); });
     },
 
-    commands: function () {
+    commands: function initCommands() {
         commands.add(["dia[log]"],
             "Open a " + config.appName + " dialog",
             function (args) {
@@ -1593,6 +1566,21 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                 literal: 0
             });
 
+        commands.add(["pr[ivate]", "pr0n", "porn"],
+            "Enable privacy features of a command, when applicable, and do not save the invocation in command history",
+            function (args) {
+                dactyl.withSavedValues(["forcePrivate"], function () {
+                    this.forcePrivate = true;
+                    dactyl.execute(args[0], null, true);
+                });
+            }, {
+                argCount: "1",
+                completer: function (context) completion.ex(context),
+                literal: 0,
+                privateData: "never-save",
+                subCommand: 0
+            });
+
         commands.add(["exit", "x"],
             "Quit " + config.appName,
             function (args) {
@@ -1649,13 +1637,13 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
             "Reload the " + config.appName + " add-on",
             function (args) {
                 if (args.trailing)
-                    storage.session.rehashCmd = args.trailing; // Hack.
+                    storage.storeForSession("rehashCmd", args.trailing); // Hack.
                 args.break = true;
 
                 if (args["+purgecaches"])
                     cache.flush();
 
-                util.rehash(args);
+                util.delay(function () { util.rehash(args) });
             },
             {
                 argCount: "0", // FIXME
@@ -1753,14 +1741,24 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                             totalUnits = "msec";
 
                         commandline.commandOutput(
-                                <table>
-                                    <tr highlight="Title" align="left">
-                                        <th colspan="3">{_("title.Code execution summary")}</th>
-                                    </tr>
-                                    <tr><td>&#xa0;&#xa0;{_("title.Executed")}:</td><td align="right"><span class="times-executed">{count}</span></td><td><!--L-->times</td></tr>
-                                    <tr><td>&#xa0;&#xa0;{_("title.Average time")}:</td><td align="right"><span class="time-average">{each.toFixed(2)}</span></td><td>{eachUnits}</td></tr>
-                                    <tr><td>&#xa0;&#xa0;{_("title.Total time")}:</td><td align="right"><span class="time-total">{total.toFixed(2)}</span></td><td>{totalUnits}</td></tr>
-                                </table>);
+                                ["table", {}
+                                    ["tr", { highlight: "Title", align: "left" },
+                                        ["th", { colspan: "3" }, _("title.Code execution summary")]],
+                                    ["tr", {},
+                                        ["td", {}, _("title.Executed"), ":"],
+                                        ["td", { align: "right" },
+                                            ["span", { class: "times-executed" }, count]],
+                                        ["td", {}, /*L*/"times"]],
+                                    ["tr", {},
+                                        ["td", {}, _("title.Average time"), ":"],
+                                        ["td", { align: "right" },
+                                            ["span", { class: "time-average" }, each.toFixed(2)]],
+                                        ["td", {}, eachUnits]],
+                                    ["tr", {},
+                                        ["td", {}, _("title.Total time"), ":"],
+                                        ["td", { align: "right" },
+                                            ["span", { class: "time-total" }, total.toFixed(2)]],
+                                        ["td", {}, totalUnits]]]);
                     }
                     else {
                         let beforeTime = Date.now();
@@ -1828,9 +1826,10 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
                     let date = config.buildDate;
                     date = date ? " (" + date + ")" : "";
 
-                    commandline.commandOutput(
-                        <div>{config.appName} {config.version}{date} running on: </div> +
-                        <div>{navigator.userAgent}</div>)
+                    commandline.commandOutput([
+                        ["div", {}, [config.appName, " ", config.version, date, " running on: "].join("")],
+                        ["div", {}, [window.navigator.userAgent].join("")]
+                    ])
                 }
             }, {
                 argCount: "0",
@@ -1839,7 +1838,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
 
     },
 
-    completion: function () {
+    completion: function initCompletion() {
         completion.dialog = function dialog(context) {
             context.title = ["Dialog"];
             context.filters.push(function ({ item }) !item[2] || item[2]());
@@ -1870,7 +1869,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
             context.completions = dactyl.windows;
         };
     },
-    load: function () {
+    load: function initLoad() {
         dactyl.triggerObserver("load");
 
         dactyl.log(_("dactyl.modulesLoaded"), 3);
@@ -1878,6 +1877,22 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
         userContext.DOM = Class("DOM", DOM, { init: function DOM_(sel, ctxt) DOM(sel, ctxt || buffer.focusedFrame.document) });
         userContext.$ = modules.userContext.DOM;
 
+        // Hack: disable disabling of Personas in private windows.
+        let root = document.documentElement;
+
+        if (PrivateBrowsingUtils && PrivateBrowsingUtils.isWindowPrivate(window)
+                && root._lightweightTheme
+                && root._lightweightTheme._lastScreenWidth == null) {
+
+            dactyl.withSavedValues.call(PrivateBrowsingUtils,
+                                      ["isWindowPrivate"], function () {
+                PrivateBrowsingUtils.isWindowPrivate = function () false;
+
+                Cu.import("resource://gre/modules/LightweightThemeConsumer.jsm", {})
+                  .LightweightThemeConsumer.call(root._lightweightTheme, document);
+            });
+        }
+
         dactyl.timeout(function () {
             try {
                 var args = config.prefs.get("commandline-args")
index 63ec3eb675b3e65fc32443f9365e445dcb9abee7..eef3c1ded03f38f4fecd42e038b8c192b47dafa3 100644 (file)
@@ -3,7 +3,7 @@
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -168,14 +168,14 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
             this.setRegister(name, range);
     },
 
-    cut: function cut(range, name) {
+    cut: function cut(range, name, noStrip) {
         if (range)
             this.selectedRange = range;
 
         if (!this.selection.isCollapsed)
             this.setRegister(name, this.selection);
 
-        this.editor.deleteSelection(0);
+        this.editor.deleteSelection(0, this.editor[noStrip ? "eNoStrip" : "eStrip"]);
     },
 
     paste: function paste(name) {
@@ -688,7 +688,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
         return DOM(elem).editor;
     }
 }, {
-    modes: function init_modes() {
+    modes: function initModes() {
         modes.addMode("OPERATOR", {
             char: "o",
             description: "Mappings which move the cursor",
@@ -745,7 +745,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
             bases: [modes.INSERT]
         });
     },
-    commands: function init_commands() {
+    commands: function initCommands() {
         commands.add(["reg[isters]"],
             "List the contents of known registers",
             function (args) {
@@ -753,7 +753,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
             },
             { argCount: "*" });
     },
-    completion: function init_completion() {
+    completion: function initCompletion() {
         completion.register = function complete_register(context) {
             context = context.fork("registers");
             context.keys = { text: util.identity, description: editor.closure.getRegister };
@@ -777,7 +777,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
             });
         };
     },
-    mappings: function init_mappings() {
+    mappings: function initMappings() {
 
         Map.types["editor"] = {
             preExecute: function preExecute(args) {
@@ -1035,7 +1035,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
         }
 
         addMotionMap(["d", "x"], "Delete text", true,  function (editor) { editor.cut(); });
-        addMotionMap(["c"],      "Change text", true,  function (editor) { editor.cut(); }, modes.INSERT);
+        addMotionMap(["c"],      "Change text", true,  function (editor) { editor.cut(null, null, true); }, modes.INSERT);
         addMotionMap(["y"],      "Yank text",   false, function (editor, range) { editor.copy(range); }, null, true);
 
         addMotionMap(["gu"], "Lowercase text", false,
@@ -1346,7 +1346,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
         bind(["<C-n>"], "Select the next autocomplete result",
              function () { events.feedkeys("<Down>", { skipmap: true }); });
     },
-    options: function init_options() {
+    options: function initOptions() {
         options.add(["editor"],
             "The external text editor",
             "string", 'gvim -f +<line> +"sil! call cursor(0, <column>)" <file>', {
@@ -1391,7 +1391,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), {
                 }
             });
     },
-    sanitizer: function () {
+    sanitizer: function initSanitizer() {
         sanitizer.addItem("registers", {
             description: "Register values",
             persistent: true,
index 49298d92b3bd7481a63871f92d87867b4430bcfa..9e10d9f5a37e44c0450239e534d4bda4a092315d 100644 (file)
@@ -4,7 +4,7 @@ catch (e) { __dactyl_eval_error = e; }
 // IMPORTANT: The eval statement *must* remain on the first line
 // in order for line numbering in any errors to remain correct.
 
-// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
index ac846d8ce1cb38cab38a91e81e9dfe02fe6937dc..98dc0281f512df5362a4c5f6528498d3576c68c2 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -102,17 +102,14 @@ var Events = Module("events", {
     init: function () {
         this.keyEvents = [];
 
-        XML.ignoreWhitespace = true;
         overlay.overlayWindow(window, {
-            append: <e4x xmlns={XUL}>
-                <window id={document.documentElement.id}>
-                    <!-- http://developer.mozilla.org/en/docs/XUL_Tutorial:Updating_Commands -->
-                    <commandset id="dactyl-onfocus" commandupdater="true" events="focus"
-                                oncommandupdate="dactyl.modules.events.onFocusChange(event);"/>
-                    <commandset id="dactyl-onselect" commandupdater="true" events="select"
-                                oncommandupdate="dactyl.modules.events.onSelectionChange(event);"/>
-                </window>
-            </e4x>.elements()
+            append: [
+                ["window", { id: document.documentElement.id, xmlns: "xul" },
+                    // http://developer.mozilla.org/en/docs/XUL_Tutorial:Updating_Commands
+                    ["commandset", { id: "dactyl-onfocus", commandupdater: "true", events: "focus",
+                                     commandupdate: this.closure.onFocusChange }],
+                    ["commandset", { id: "dactyl-onselect", commandupdater: "true", events: "select",
+                                     commandupdate: this.closure.onSelectionChange }]]]
         });
 
         this._fullscreen = window.fullScreen;
@@ -664,13 +661,15 @@ var Events = Module("events", {
             let duringFeed = this.duringFeed || [];
             this.duringFeed = [];
             try {
-                if (DOM.Event.feedingEvent)
-                    for (let [k, v] in Iterator(DOM.Event.feedingEvent))
+                let ourEvent = DOM.Event.feedingEvent;
+                DOM.Event.feedingEvent = null;
+                if (ourEvent)
+                    for (let [k, v] in Iterator(ourEvent))
                         if (!(k in event))
                             event[k] = v;
-                DOM.Event.feedingEvent = null;
 
-                let key = DOM.Event.stringify(event);
+                let key = DOM.Event.stringify(ourEvent || event);
+                event.dactylString = key;
 
                 // Hack to deal with <BS> and so forth not dispatching input
                 // events
@@ -983,7 +982,7 @@ var Events = Module("events", {
         });
     },
 
-    commands: function () {
+    commands: function initCommands() {
         commands.add(["delmac[ros]"],
             "Delete macros",
             function (args) {
@@ -1009,13 +1008,13 @@ var Events = Module("events", {
                 completer: function (context) completion.macro(context)
             });
     },
-    completion: function () {
+    completion: function initCompletion() {
         completion.macro = function macro(context) {
             context.title = ["Macro", "Keys"];
             context.completions = [item for (item in events.getMacros())];
         };
     },
-    mappings: function () {
+    mappings: function initMappings() {
 
         mappings.add([modes.MAIN],
             ["<A-b>", "<pass-next-key-builtin>"], "Process the next key as a builtin mapping",
@@ -1097,7 +1096,7 @@ var Events = Module("events", {
             },
             { count: true });
     },
-    options: function () {
+    options: function initOptions() {
         const Hive = Class("Hive", {
             init: function init(values, map) {
                 this.name = "passkeys:" + map;
index 0bde1ee4c4c5c6fe6887f2fddb3be04f8395141b..70c37533c366c66dc9ebc00aa6f68edfb5c39a82 100644 (file)
@@ -1,8 +1,8 @@
-// Copyright (c) 2009-2011 by Kris Maglione <kris@vimperator.org>
+// Copyright (c) 2009-2012 Kris Maglione <kris@vimperator.org>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 function checkFragment() {
     document.title = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "title")[0].textContent;
index 96fe44acbbbfa5399fa2a7aed63596d6fa999051..a9154e88fcea43a9b57b84d53df8df9d25ea7f9f 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 /** @instance hints */
@@ -312,11 +312,11 @@ var HintSession = Class("HintSession", CommandMode, {
 
         let body = doc.body || doc.querySelector("body");
         if (body) {
-            let fragment = DOM(<div highlight="hints"/>, doc).appendTo(body);
+            let fragment = DOM(["div", { highlight: "hints" }], doc).appendTo(body);
             fragment.style.height; // Force application of binding.
             let container = doc.getAnonymousElementByAttribute(fragment[0], "anonid", "hints") || fragment[0];
 
-            let baseNode = DOM(<span highlight="Hint" style="display: none;"/>, doc)[0];
+            let baseNode = DOM(["span", { highlight: "Hint", style: "display: none;" }], doc)[0];
 
             let mode = this.hintMode;
             let res = mode.matcher(doc);
@@ -490,6 +490,10 @@ var HintSession = Class("HintSession", CommandMode, {
 
         let n = 5;
         (function next() {
+            if (Cu.isDeadWrapper && Cu.isDeadWrapper(elem))
+                // Hint document has been unloaded.
+                return;
+
             let hinted = n || this.validHints.some(function (h) h.elem === elem);
             if (!hinted)
                 hints.setClass(elem, null);
@@ -569,7 +573,9 @@ var HintSession = Class("HintSession", CommandMode, {
     /**
      * Display the hints in pageHints that are still valid.
      */
+    showCount: 0,
     show: function _show() {
+        let count = ++this.showCount;
         let hintnum = 1;
         let validHint = hints.hintMatcher(this.hintString.toLowerCase());
         let activeHint = this.hintNumber || 1;
@@ -581,6 +587,9 @@ var HintSession = Class("HintSession", CommandMode, {
 
         inner:
             for (let i in (util.interruptibleRange(start, end + 1, 500))) {
+                if (this.showCount != count)
+                    return;
+
                 let hint = this.pageHints[i];
 
                 hint.valid = validHint(hint.text);
@@ -593,7 +602,7 @@ var HintSession = Class("HintSession", CommandMode, {
                         if (!rect)
                             continue;
 
-                        hint.imgSpan = DOM(<span highlight="Hint" dactyl:hl="HintImage" xmlns:dactyl={NS}/>, doc).css({
+                        hint.imgSpan = DOM(["span", { highlight: "Hint", "dactyl:hl": "HintImage" }], doc).css({
                             display: "none",
                             left: (rect.left + offsetX) + "px",
                             top: (rect.top + offsetY) + "px",
@@ -746,6 +755,7 @@ var Hints = Module("hints", {
         this.modes = {};
         this.addMode(";", "Focus hint",                           buffer.closure.focusElement);
         this.addMode("?", "Show information for hint",            function (elem) buffer.showElementInfo(elem));
+        // TODO: allow for ! override to overwrite existing paths -- where? --djk
         this.addMode("s", "Save hint",                            function (elem) buffer.saveLink(elem, false));
         this.addMode("f", "Focus frame",                          function (elem) dactyl.focus(elem.ownerDocument.defaultView));
         this.addMode("F", "Focus frame or pseudo-frame",          buffer.closure.focusElement, isScrollable);
@@ -856,7 +866,8 @@ var Hints = Module("hints", {
                 }
                 else if (option == "label") {
                     if (elem.id) {
-                        let label = elem.ownerDocument.dactylLabels[elem.id];
+                        let label = (elem.ownerDocument.dactylLabels || {})[elem.id];
+                        // Urgh.
                         if (label)
                             return [label.textContent.toLowerCase(), true];
                     }
@@ -1301,7 +1312,7 @@ var Hints = Module("hints", {
         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," +
+            "stringlist", ":-moz-any-link,area,button,iframe,input:not([type=hidden]),label[for],select,textarea," +
                           "[onclick],[onmouseover],[onmousedown],[onmouseup],[oncommand]," +
                           "[tabindex],[role=link],[role=button],[contenteditable=true]",
             {
index 94985d2648024d9d7afb2b7906b009c3a58aaa78..c69237f1fc16403d0e6a7028f838b32dccfface8 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 var History = Module("history", {
     SORT_DEFAULT: "-date",
@@ -175,7 +175,7 @@ var History = Module("history", {
     }
 }, {
 }, {
-    commands: function () {
+    commands: function initCommands() {
         commands.add(["ba[ck]"],
             "Go back in the browser history",
             function (args) {
@@ -321,7 +321,7 @@ var History = Module("history", {
             { argCount: "0" });
 
     },
-    completion: function () {
+    completion: function initCompletion() {
         completion.domain = function (context) {
             context.anchored = false;
             context.compare = function (a, b) String.localeCompare(a.key, b.key);
@@ -351,7 +351,7 @@ var History = Module("history", {
 
         completion.addUrlCompleter("history", "History", completion.history);
     },
-    mappings: function () {
+    mappings: function initMappings() {
         function bind() mappings.add.apply(mappings, [config.browserModes].concat(Array.slice(arguments)));
 
         bind(["<C-o>"], "Go to an older position in the jump list",
index e1ba321f46c35b2b446d471481f420974cb4ccf0..aa1e016df8d8ae3db8ce6ae5b387fdcf22483b46 100644 (file)
@@ -1,8 +1,8 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -159,7 +159,7 @@ var ProcessorStack = Class("ProcessorStack", {
         if (this.timer)
             this.timer.cancel();
 
-        let key = DOM.Event.stringify(event);
+        let key = event.dactylString || DOM.Event.stringify(event);
         this.events.push(event);
         if (this.keyEvents)
             this.keyEvents.push(event);
@@ -233,7 +233,7 @@ var KeyProcessor = Class("KeyProcessor", {
 
     append: function append(event) {
         this.events.push(event);
-        let key = DOM.Event.stringify(event);
+        let key = event.dactylString || DOM.Event.stringify(event);
 
         if (this.wantCount && !this.command &&
                 (this.countStr ? /^[0-9]$/ : /^[1-9]$/).test(key))
index f14b3d2f5fbbbf2a004b8396beaf926fc83824d6..c272eb5f8d9c50b26bccb33de0a33207af9f9f2c 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -480,34 +480,30 @@ var Mappings = Module("mappings", {
             return maps;
         }
 
-        let list = <table>
-                <tr highlight="Title">
-                    <td/>
-                    <td style="padding-right: 1em;">{_("title.Mode")}</td>
-                    <td style="padding-right: 1em;">{_("title.Command")}</td>
-                    <td style="padding-right: 1em;">{_("title.Action")}</td>
-                </tr>
-                <col style="min-width: 6em; padding-right: 1em;"/>
-                {
-                    template.map(hives, function ([hive, maps]) let (i = 0)
-                        <tr style="height: .5ex;"/> +
-                        template.map(maps, function (map)
-                            template.map(map.names, function (name)
-                            <tr>
-                                <td highlight="Title">{!i++ ? hive.name : ""}</td>
-                                <td>{modeSign}</td>
-                                <td>{name}</td>
-                                <td>{map.rhs || map.action.toSource()}</td>
-                            </tr>)) +
-                        <tr style="height: .5ex;"/>)
-                }
-                </table>;
-
-        // TODO: Move this to an ItemList to show this automatically
-        if (list.*.length() === list.text().length() + 2)
-            dactyl.echomsg(_("map.none"));
-        else
-            commandline.commandOutput(list);
+        let list = ["table", {},
+                ["tr", { highlight: "Title" },
+                    ["td", {}],
+                    ["td", { style: "padding-right: 1em;" }, _("title.Mode")],
+                    ["td", { style: "padding-right: 1em;" }, _("title.Command")],
+                    ["td", { style: "padding-right: 1em;" }, _("title.Action")]],
+                ["col", { style: "min-width: 6em; padding-right: 1em;" }],
+                hives.map(function ([hive, maps]) let (i = 0) [
+                    ["tr", { style: "height: .5ex;" }],
+                    maps.map(function (map)
+                        map.names.map(function (name)
+                        ["tr", {},
+                            ["td", { highlight: "Title" }, !i++ ? hive.name : ""],
+                            ["td", {}, modeSign],
+                            ["td", {}, name],
+                            ["td", {}, map.rhs || map.action.toSource()]])),
+                    ["tr", { style: "height: .5ex;" }]])]
+
+        // E4X-FIXME
+        // // TODO: Move this to an ItemList to show this automatically
+        // if (list.*.length() === list.text().length() + 2)
+        //     dactyl.echomsg(_("map.none"));
+        // else
+        commandline.commandOutput(list);
     }
 }, {
 }, {
@@ -761,25 +757,28 @@ var Mappings = Module("mappings", {
                                     yield {
                                         name: name,
                                         columns: [
-                                            i === 0 ? "" : <span highlight="Object" style="padding-right: 1em;">{mode.name}</span>,
-                                            hive == mappings.builtin ? "" : <span highlight="Object" style="padding-right: 1em;">{hive.name}</span>
+                                            i === 0 ? "" : ["span", { highlight: "Object", style: "padding-right: 1em;" },
+                                                                mode.name],
+                                            hive == mappings.builtin ? "" : ["span", { highlight: "Object", style: "padding-right: 1em;" },
+                                                                                 hive.name]
                                         ],
                                         __proto__: map
                                     };
                                 }
             },
             format: {
-                description: function (map) (XML.ignoreWhitespace = false, XML.prettyPrinting = false, <>
-                        {options.get("passkeys").has(map.name)
-                            ? <span highlight="URLExtra">(passed by {template.helpLink("'passkeys'")})</span>
-                            : <></>}
-                        {template.linkifyHelp(map.description + (map.rhs ? ": " + map.rhs : ""))}
-                </>),
+                description: function (map) [
+                        options.get("passkeys").has(map.name)
+                            ? ["span", { highlight: "URLExtra" },
+                                "(", template.linkifyHelp(_("option.passkeys.passedBy")), ")"]
+                            : [],
+                        template.linkifyHelp(map.description + (map.rhs ? ": " + map.rhs : ""))
+                ],
                 help: function (map) let (char = array.compact(map.modes.map(function (m) m.char))[0])
                     char === "n" ? map.name : char ? char + "_" + map.name : "",
                 headings: ["Command", "Mode", "Group", "Description"]
             }
-        }
+        };
 
         dactyl.addUsageCommand({
             __proto__: args,
index e32d0c6f9c61be4de44cff94a9738131eef0ecbc..4776c1cefed387cf541a8a56679bc882deaeefc4 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /**
  * @scope modules
@@ -332,7 +332,7 @@ var Marks = Module("marks", {
             { arg: true });
     },
 
-    commands: function () {
+    commands: function initCommands() {
         commands.add(["delm[arks]"],
             "Delete the specified marks",
             function (args) {
@@ -372,7 +372,7 @@ var Marks = Module("marks", {
             });
     },
 
-    completion: function () {
+    completion: function initCompletion() {
         completion.mark = function mark(context) {
             function percent(i) Math.round(i * 100);
 
@@ -383,7 +383,7 @@ var Marks = Module("marks", {
             context.completions = marks.all;
         };
     },
-    sanitizer: function () {
+    sanitizer: function initSanitizer() {
         sanitizer.addItem("marks", {
             description: "Local and URL marks",
             persistent: true,
index 127fa95a9f89b716c4e735c556e1bc9215408813..2df79d9c3811ebf295186b72dfaaacf44a569d79 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -119,7 +119,11 @@ var Modes = Module("modes", {
             onKeyPress: function (events) { if (modes.main == modes.QUOTE) modes.pop(); }
         });
         this.addMode("IGNORE", { hidden: true }, {
-            onKeyPress: function (events) false,
+            onKeyPress: function (events_) {
+                if (events.isCancelKey(DOM.Event.stringify(events_[0])))
+                    return true;
+                return false;
+            },
             bases: [],
             passthrough: true
         });
@@ -487,7 +491,9 @@ var Modes = Module("modes", {
         update(StackElement.prototype, {
             get toStringParams() !loaded.modes ? this.main.name : [
                 this.main.name,
-                <>({ modes.all.filter(function (m) this.extended & m, this).map(function (m) m.name).join("|") })</>
+                ["(", modes.all.filter(function (m) this.extended & m, this)
+                           .map(function (m) m.name).join("|"),
+                 ")"].join("")
             ]
         });
         return StackElement;
@@ -530,23 +536,23 @@ var Modes = Module("modes", {
                 for (let base in values(mode.bases))
                     tree[base.name][mode.name] = tree[mode.name];
 
-            let roots = iter([m.name, tree[m.name]] for (m in values(list)) if (!m.bases.length)).toObject();
+            let roots = iter([m.name, tree[m.name]]
+                             for (m in values(list))
+                             if (!m.bases.length)).toObject();
 
-            default xml namespace = NS;
             function rec(obj) {
-                XML.ignoreWhitespace = XML.prettyPrinting = false;
-
-                let res = <ul dactyl:highlight="Dense" xmlns:dactyl={NS}/>;
+                let res = ["ul", { "dactyl:highlight": "Dense" }];
                 Object.keys(obj).sort().forEach(function (name) {
                     let mode = modes.getMode(name);
-                    res.* += <li><em>{mode.displayName}</em>: {mode.description}{
-                        rec(obj[name])
-                    }</li>;
+                    res.push(["li", {},
+                                ["em", {}, mode.displayName],
+                                ": ", mode.description,
+                                rec(obj[name])]);
                 });
 
-                if (res.*.length())
+                if (res.length > 2)
                     return res;
-                return <></>;
+                return [];
             }
 
             return rec(roots);
index 770929dd5fb580df96979c5d50810aa2b7bfb297..689d9a793120ee4c8c94fa92f169bae7d960ce11 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 var MOW = Module("mow", {
     init: function init() {
@@ -41,38 +41,28 @@ var MOW = Module("mow", {
                            html|html > xul|scrollbar { visibility: collapse !important; }",
                           true);
 
-        XML.ignoreWhitespace = true;
         overlay.overlayWindow(window, {
             objects: {
                 eventTarget: this
             },
-            append: <e4x xmlns={XUL} xmlns:dactyl={NS}>
-                <window id={document.documentElement.id}>
-                    <popupset>
-                        <menupopup id="dactyl-contextmenu" highlight="Events" events="contextEvents">
-                            <menuitem id="dactyl-context-copylink"
-                                      label={_("mow.contextMenu.copyLink")} dactyl:group="link"
-                                      oncommand="goDoCommand('cmd_copyLink');"/>
-                            <menuitem id="dactyl-context-copypath"
-                                      label={_("mow.contextMenu.copyPath")} dactyl:group="link path"
-                                      oncommand="dactyl.clipboardWrite(document.popupNode.getAttribute('path'));"/>
-                            <menuitem id="dactyl-context-copy"
-                                      label={_("mow.contextMenu.copy")} dactyl:group="selection"
-                                      command="cmd_copy"/>
-                            <menuitem id="dactyl-context-selectall"
-                                      label={_("mow.contextMenu.selectAll")}
-                                      command="cmd_selectAll"/>
-                        </menupopup>
-                    </popupset>
-                </window>
-                <vbox id={config.ids.commandContainer}>
-                    <vbox class="dactyl-container" id="dactyl-multiline-output-container" hidden="false" collapsed="true">
-                        <iframe id="dactyl-multiline-output" src="dactyl://content/buffer.xhtml"
-                                flex="1" hidden="false" collapsed="false" contextmenu="dactyl-contextmenu"
-                                highlight="Events" />
-                    </vbox>
-                </vbox>
-            </e4x>
+            append: [
+                ["window", { id: document.documentElement.id, xmlns: "xul" },
+                    ["popupset", {},
+                        ["menupopup", { id: "dactyl-contextmenu", highlight: "Events", events: "contextEvents" },
+                            ["menuitem", { id: "dactyl-context-copylink", label: _("mow.contextMenu.copyLink"),
+                                           "dactyl:group": "link",      oncommand: "goDoCommand('cmd_copyLink');" }],
+                            ["menuitem", { id: "dactyl-context-copypath", label: _("mow.contextMenu.copyPath"),
+                                           "dactyl:group": "link path", oncommand: "dactyl.clipboardWrite(document.popupNode.getAttribute('path'));" }],
+                            ["menuitem", { id: "dactyl-context-copy", label: _("mow.contextMenu.copy"),
+                                           "dactyl:group": "selection", command: "cmd_copy" }],
+                            ["menuitem", { id: "dactyl-context-selectall", label: _("mow.contextMenu.selectAll"),
+                                           command: "cmd_selectAll" }]]]],
+
+                ["vbox", { id: config.ids.commandContainer, xmlns: "xul" },
+                    ["vbox", { class: "dactyl-container", id: "dactyl-multiline-output-container", hidden: "false", collapsed: "true" },
+                        ["iframe", { id: "dactyl-multiline-output", src: "dactyl://content/buffer.xhtml",
+                                     flex: "1", hidden: "false", collapsed: "false",
+                                     contextmenu: "dactyl-contextmenu", highlight: "Events" }]]]]
         });
     },
 
@@ -114,18 +104,12 @@ var MOW = Module("mow", {
             this.messages = [];
         }
 
-        // If it's already XML, assume it knows what it's doing.
-        // Otherwise, white space is significant.
-        // The problem elsewhere is that E4X tends to insert new lines
-        // after interpolated data.
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-
         highlightGroup = "CommandOutput " + (highlightGroup || "");
 
-        if (isObject(data) && !isinstance(data, _)) {
+        if (isObject(data) && !isinstance(data, _) && !DOM.isJSONXML(data)) {
             this.lastOutput = null;
 
-            var output = DOM(<div style="white-space: nowrap" highlight={highlightGroup}/>,
+            var output = DOM(["div", { style: "white-space: nowrap", highlight: highlightGroup }],
                              this.document);
             data.document = this.document;
             try {
@@ -139,7 +123,8 @@ var MOW = Module("mow", {
         }
         else {
             let style = isString(data) ? "pre-wrap" : "nowrap";
-            this.lastOutput = <div style={"white-space: " + style} highlight={highlightGroup}>{data}</div>;
+            this.lastOutput = ["div", { style: "white-space: " + style, highlight: highlightGroup },
+                               data];
 
             var output = DOM(this.lastOutput, this.document);
         }
@@ -400,7 +385,7 @@ var MOW = Module("mow", {
 
         // copy text to clipboard
         bind(["<C-y>"], "Yank selection to clipboard",
-             function () { dactyl.clipboardWrite(buffer.getCurrentWord(mow.window)); });
+             function () { dactyl.clipboardWrite(Buffer.currentWord(mow.window)); });
 
         // close the window
         bind(["q"], "Close the output window",
index d2a5627cd98e95ed7209d155272c94b8e6fd8e11..9fc5acae5654028c63729c4292fb4d50cb0e52d1 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -118,7 +118,7 @@ var QuickMarks = Module("quickmarks", {
     }
 }, {
 }, {
-    commands: function () {
+    commands: function initCommands() {
         commands.add(["delqm[arks]"],
             "Delete the specified QuickMarks",
             function (args) {
@@ -175,13 +175,13 @@ var QuickMarks = Module("quickmarks", {
                 completer: function (context) completion.quickmark(context),
             });
     },
-    completion: function () {
+    completion: function initCompletion() {
         completion.quickmark = function (context) {
             context.title = ["QuickMark", "URL"];
             context.generate = function () Iterator(quickmarks._qmarks);
         };
     },
-    mappings: function () {
+    mappings: function initMappings() {
         var myModes = config.browserModes;
 
         mappings.add(myModes,
index 5b7d2a8898696d69d6231bfa1e9972de07cc0a87..0de02088a37cb79f91c3f8b811796feff49f07f2 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -15,25 +15,26 @@ var StatusLine = Module("statusline", {
         this.baseGroup = this.statusBar == this._statusLine ? "StatusLine " : "";
 
         if (this.statusBar.localName == "toolbar") {
-            styles.system.add("addon-bar", config.styleableChrome, <css><![CDATA[
+            styles.system.add("addon-bar", config.styleableChrome, literal(/*
                 #status-bar { margin-top: 0 !important; }
                 #addon-bar > statusbar { -moz-box-flex: 1 }
                 #addon-bar > #addonbar-closebutton { visibility: collapse; }
                 #addon-bar > xul|toolbarspring { visibility: collapse; }
-            ]]></css>);
+            */));
 
-            overlay.overlayWindow(window, { append: <><statusbar id="status-bar" ordinal="0"/></> });
+            overlay.overlayWindow(window, {
+                append: [
+                    ["statusbar", { id: "status-bar", ordinal: "0" }]]
+            });
 
-            highlight.loadCSS(util.compileMacro(<![CDATA[
+            highlight.loadCSS(util.compileMacro(literal(/*
                 !AddonBar;#addon-bar {
-                    /* The Add-on Bar */
                     padding-left: 0 !important;
                     min-height: 18px !important;
                     -moz-appearance: none !important;
                     <padding>
                 }
                 !AddonButton;#addon-bar xul|toolbarbutton {
-                    /* An Add-on Bar button */
                     -moz-appearance: none !important;
                     padding: 0 !important;
                     border-width: 0px !important;
@@ -41,50 +42,52 @@ var StatusLine = Module("statusline", {
                     color: inherit !important;
                 }
                 AddonButton:not(:hover)  background: transparent;
-            ]]>)({ padding: config.OS.isMacOSX ? "padding-right: 10px !important;" : "" }));
+            */))({ padding: config.OS.isMacOSX ? "padding-right: 10px !important;" : "" }));
 
             if (document.getElementById("appmenu-button"))
-                highlight.loadCSS(<![CDATA[
-                    AppmenuButton       /* The app-menu button */ \
-                                        min-width: 0 !important; padding: 0 .5em !important;
-                ]]>);
+                highlight.loadCSS(literal(/*
+                    AppmenuButton       min-width: 0 !important; padding: 0 .5em !important;
+                */));
         }
 
-        XML.ignoreWhitespace = true;
         let _commandline = "if (window.dactyl) return dactyl.modules.commandline";
-        let prepend = <e4x xmlns={XUL} xmlns:dactyl={NS}>
-            <button id="appmenu-button" label="" image="chrome://branding/content/icon16.png" highlight="AppmenuButton" />
-            <toolbarbutton id="appmenu-toolbar-button" label="" image="chrome://branding/content/icon16.png" />
-            <statusbar id="status-bar" highlight="StatusLine">
-                <!-- insertbefore="dactyl.statusBefore;" insertafter="dactyl.statusAfter;" -->
-                <hbox key="container" hidden="false" align="center"  flex="1">
-                    <stack orient="horizontal"       align="stretch" flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container">
-                        <hbox                                                 highlight="CmdLine StatusCmdLine" class="dactyl-container">
-                            <label key="mode"          crop="end"                                               class="plain" collapsed="true"/>
-                            <stack  id="dactyl-statusline-stack"     flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container">
-                                <textbox key="url"     crop="end"    flex="1" style="background: transparent;"  class="plain dactyl-status-field-url" readonly="true"/>
-                                <textbox key="message" crop="end"    flex="1" highlight="Normal StatusNormal"   class="plain"                         readonly="true"/>
-                            </stack>
-                        </hbox>
-                    </stack>
-                    <label class="plain" key="inputbuffer"    flex="0"/>
-                    <label class="plain" key="progress"       flex="0"/>
-                    <label class="plain" key="tabcount"       flex="0"/>
-                    <label class="plain" key="bufferposition" flex="0"/>
-                    <label class="plain" key="zoomlevel"      flex="0"/>
-                </hbox>
-                <!-- just hide them since other elements expect them -->
-                <statusbarpanel id="statusbar-display"       hidden="true"/>
-                <statusbarpanel id="statusbar-progresspanel" hidden="true"/>
-            </statusbar>
-        </e4x>;
-
-        for each (let attr in prepend..@key)
-            attr.parent().@id = "dactyl-statusline-field-" + attr;
+        let prepend = [
+            ["button", { id: "appmenu-button", label: "", image: "chrome://branding/content/icon16.png", highlight: "AppmenuButton", xmlns: "xul" }],
+            ["toolbarbutton", { id: "appmenu-toolbar-button", label: "", image: "chrome://branding/content/icon16.png" }],
+            ["statusbar", { id: "status-bar", highlight: "StatusLine", xmlns: "xul" },
+                // <!-- insertbefore="dactyl.statusBefore;" insertafter="dactyl.statusAfter;" -->
+                ["hbox", { key: "container", hidden: "false", align: "center",  flex: "1" },
+                    ["stack", { orient: "horizontal",       align: "stretch", flex: "1", highlight: "CmdLine StatusCmdLine", class: "dactyl-container" },
+                        ["hbox", {                                                       highlight: "CmdLine StatusCmdLine", class: "dactyl-container" },
+                            ["label", { key: "mode",          crop: "end",                                                   class: "plain", collapsed: "true" }],
+                            ["stack", {  id: "dactyl-statusline-stack",       flex: "1", highlight: "CmdLine StatusCmdLine", class: "dactyl-container" },
+                                ["textbox", { key: "url",     crop: "end",    flex: "1", style: "background: transparent;",  class: "plain dactyl-status-field-url",
+                                              readonly: "true" }],
+                                ["hbox", { key: "message-box" },
+                                    ["label", { key: "message-pre", highlight: "WarningMsg StatusWarningMsg", class: "plain", readonly: "true" }],
+                                    ["textbox", { key: "message", crop: "end",    flex: "1", highlight: "Normal StatusNormal",   class: "plain",
+                                                  readonly: "true" }]]]]],
+                    ["label", { class: "plain", key: "inputbuffer",    flex: "0" }],
+                    ["label", { class: "plain", key: "progress",       flex: "0" }],
+                    ["label", { class: "plain", key: "tabcount",       flex: "0" }],
+                    ["label", { class: "plain", key: "bufferposition", flex: "0" }],
+                    ["label", { class: "plain", key: "zoomlevel",      flex: "0" }]],
+                // just hide them since other elements expect them
+                ["statusbarpanel", { id: "statusbar-display",       hidden: "true" }],
+                ["statusbarpanel", { id: "statusbar-progresspanel", hidden: "true" }]]];
+
+        (function rec(ary) {
+            ary.forEach(function (elem) {
+                if ("key" in elem[1])
+                    elem[1].id = "dactyl-statusline-field-" + elem[1].key;
+                if (elem.length > 2)
+                    rec(elem.slice(2));
+            });
+        })(prepend);
 
         overlay.overlayWindow(window, {
             objects: this.widgets = { get status() this.container },
-            prepend: prepend.elements()
+            prepend: prepend
         });
 
         try {
@@ -157,6 +160,16 @@ var StatusLine = Module("statusline", {
             this.timeout(function () {
                 this.status = message || buffer.uri;
             });
+        },
+        "fullscreen": function onFullscreen(fullscreen) {
+            let go = options.get("guioptions");
+            if (fullscreen) {
+                this.wasVisible = go.has("s");
+                go.op("-", "s");
+            }
+            else if (this.wasVisible) {
+                go.op("+", "s");
+            }
         }
     },
 
index 9b906607ecd12af76702e686cbd9c99fb37b6ac8..fb155db8d36539cf5a309521d74ba06cfdb49c6e 100644 (file)
@@ -1,10 +1,10 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 /** @scope modules */
 
@@ -35,9 +35,9 @@ var Tabs = Module("tabs", {
             tabs.switchTo(event.originalTarget.getAttribute("identifier"));
         };
 
-        this.tabBinding = styles.system.add("tab-binding", "chrome://browser/content/browser.xul", String.replace(<><![CDATA[
+        this.tabBinding = styles.system.add("tab-binding", "chrome://browser/content/browser.xul", literal(/*
                 xul|tab { -moz-binding: url(chrome://dactyl/content/bindings.xml#tab) !important; }
-            ]]></>, /tab-./g, function (m) config.OS.isMacOSX ? "tab-mac" : m),
+            */).replace(/tab-./g, function (m) config.OS.isMacOSX ? "tab-mac" : m),
             false, true);
 
         this.timeout(function () {
@@ -78,10 +78,14 @@ var Tabs = Module("tabs", {
                 if (!node("dactyl-tab-number")) {
                     let img = node("tab-icon-image");
                     if (img) {
-                        let dom = DOM(<xul xmlns:xul={XUL} xmlns:html={XHTML}>
-                            <xul:hbox highlight="tab-number"><xul:label key="icon" align="center" highlight="TabIconNumber" class="dactyl-tab-icon-number"/></xul:hbox>
-                            <xul:hbox highlight="tab-number"><html:div key="label" highlight="TabNumber" class="dactyl-tab-number"/></xul:hbox>
-                        </xul>.elements(), document).appendTo(img.parentNode);
+                        let dom = DOM([
+                            ["xul:hbox", { highlight: "tab-number" },
+                                ["xul:label", { key: "icon", align: "center", highlight: "TabIconNumber",
+                                                class: "dactyl-tab-icon-number" }]],
+                            ["xul:hbox", { highlight: "tab-number" },
+                                ["html:div", { key: "label", highlight: "TabNumber",
+                                               class: "dactyl-tab-number" }]]],
+                            document).appendTo(img.parentNode);
 
                         update(tab, {
                             get dactylOrdinal() Number(dom.nodes.icon.value),
@@ -235,8 +239,8 @@ var Tabs = Module("tabs", {
         if (func)
             func = bind(function (func) { func(this._groups) }, this, func);
 
-        if (window.TabView && TabView._initFrame)
-            TabView._initFrame(func);
+        if (window.TabView && window.TabView._initFrame)
+            window.TabView._initFrame(func);
 
         this._groups = iframe ? iframe.contentWindow : null;
         if (this._groups && !func)
@@ -596,10 +600,10 @@ var Tabs = Module("tabs", {
         services.sessionStore.setTabState(to, tabState);
     }
 }, {
-    load: function init_load() {
+    load: function initLoad() {
         tabs.updateTabCount();
     },
-    commands: function init_commands() {
+    commands: function initCommands() {
         [
             {
                 name: ["bd[elete]"],
@@ -1015,7 +1019,7 @@ var Tabs = Module("tabs", {
                 { argCount: "0" });
         }
     },
-    completion: function init_completion() {
+    completion: function initCompletion() {
 
         completion.buffer = function buffer(context, visible) {
             let { tabs } = modules;
@@ -1035,10 +1039,11 @@ var Tabs = Module("tabs", {
                 group[1].push([i, tab.linkedBrowser]);
             });
 
-            context.pushProcessor(0, function (item, text, next) <>
-                <span highlight="Indicator" style="display: inline-block;">{item.indicator}</span>
-                { next.call(this, item, text) }
-            </>);
+            context.pushProcessor(0, function (item, text, next) [
+                ["span", { highlight: "Indicator", style: "display: inline-block;" },
+                    item.indicator],
+                next.call(this, item, text)
+            ]);
             context.process[1] = function (item, text) template.bookmarkDescription(item, template.highlightFilter(text, this.filter));
 
             context.anchored = false;
@@ -1096,7 +1101,7 @@ var Tabs = Module("tabs", {
             };
         };
     },
-    events: function init_events() {
+    events: function initEvents() {
         let tabContainer = config.tabbrowser.mTabContainer;
         function callback() {
             tabs.timeout(function () { this.updateTabCount(); });
@@ -1105,7 +1110,7 @@ var Tabs = Module("tabs", {
             events.listen(tabContainer, event, callback, false);
         events.listen(tabContainer, "TabSelect", tabs.closure._onTabSelect, false);
     },
-    mappings: function init_mappings() {
+    mappings: function initMappings() {
 
         mappings.add([modes.COMMAND], ["<C-t>", "<new-tab-next>"],
             "Execute the next mapping in a new tab",
@@ -1199,7 +1204,7 @@ var Tabs = Module("tabs", {
                 { count: true });
         }
     },
-    options: function init_options() {
+    options: function initOptions() {
         options.add(["showtabline", "stal"],
             "Define when the tab bar is visible",
             "string", true,
index de536683fba57122c0c4e969c042e0baad84181d..d526ba80090d0f9c0db8b03f459e076abdd84f32 100644 (file)
             Like <ex>:tabopen</ex>, but all arguments are opened in
             a single new window.
         </p>
+        <p>
+            When called via <ex>:private</ex>, the new window is a
+            private browsing window.
+        </p>
     </description>
 </item>
 
index 9925d02b58128a7340f49ba49c37ce3d556c5c11..1c1ae7327a6de3e30859308dc65e342ab78f1348 100644 (file)
@@ -24,9 +24,8 @@
 </p>
 
 <xml-block><item>
-    <tags>&lt;F1> :help :h help</tags>
+    <tags>:help :h help</tags>
     <spec>:h<oa>elp</oa> <oa>subject</oa></spec>
-    <spec>&lt;F1></spec>
     <description>
         <p>
             Open the help page. The default page, as specified by <o>helpfile</o> is shown
 </item></xml-block>
 
 <p>
-    creates a new help section for the command <ex>:help</ex> and for
-    the related key binding, <k name="F1"/>. It also creates help tags
-    for the command, its shortcuts, the key binding, and the general
-    topic, ‘help’. These tags enable linking to this section from
-    other mentions of the topic and from the <ex>:help</ex> command.
+    creates a new help section for the command <ex>:help</ex>. It
+    also creates help tags for the command, its shortcuts, the key
+    binding, and the general topic, ‘help’. These tags enable
+    linking to this section from other mentions of the topic and
+    from the <ex>:help</ex> command.
 </p>
 
 <h3 tag="help-tags help-xml">Help tags</h3>
@@ -216,7 +215,7 @@ XML.prettyPrinting   = <hl key="Boolean">false</hl>;
             </p>
         </description>
     </item>
-    <escape><oa>...</oa>
+    <escape><oa></oa>
 <hl key="HelpXMLTagEnd">&lt;/plugin></hl></escape>;</xml-block>
 
 <p>
index d10fd02f0b96cb83602f5b20184b7f5e0604a0b7..dfcae27f44a0d843782d6d37c6995feb98200318 100644 (file)
@@ -91,7 +91,7 @@
     <spec>:javas<oa>cript</oa> <a>cmd</a></spec>
     <spec style="white-space: pre; height: 1.6em; overflow: visible;">:javascript &lt;&lt;<a>endpattern</a>
   <a>cmd</a>
-  ...
+  …
 <a>endpattern</a></spec>
     <description>
         <p>
index 2a7ce15bf290712678a62fb520fbc3f99b38f6e7..fc69e8fa40286fb8178497daab471f2c361a1d1b 100644 (file)
@@ -122,6 +122,8 @@ command.set.unknownOption-1 = E518: Unknown option: %S
 command.yank.yankedLine-1 = Yanked %S line
 command.yank.yankedLines-1 = Yanked %S lines
 
+commandline.moreMessages = [%S more. Type :messages to read]
+
 completion.additional = (additional)
 completion.generating = Generating results...
 completion.noCompletions = No Completions
@@ -153,6 +155,7 @@ dialog.notAvailable-1 = Dialog %S not available
 # TODO: merge with addon.*?
 download.unknownCommand = Unknown command
 download.commandNotAllowed = Command not allowed
+download.givingUpAfter = Giving up loading downloads after %S seconds
 download.prompt.launchExecutable = This will launch an executable download. Would you like to continue? (yes/[no]/always):
 
 download.nActive-1 = %S active
@@ -204,8 +207,11 @@ io.commandFailed = E472: Command failed
 io.definedAt = Defined at
 io.downloadFinished-2 = Download of %S to %S finished
 io.eNotDir = Not a directory
+io.eNotDir-1 = Not a directory %S
 io.exists = File exists (add ! to override)
 io.exists-1 = File %S exists (add ! to override)
+# XXX
+io.existsNoOverride-1 = File %S exists
 io.noCommand-1 = Command not found: %S
 io.noPrevDir = E186: No previous directory
 io.noSuchDir-1 = E344: Can't find directory %S
@@ -220,6 +226,7 @@ io.shellReturn-1 = shell returned %S
 io.sourcing-1 = sourcing %S
 io.sourcingEnd-1 = finished sourcing %S
 io.sourcingError-1 = Sourcing file: %S
+io.writing-1 = writing %S
 
 macro.canceled-1 = Canceled playback of macro '%S'
 macro.recorded-1 = Recorded macro '%S'
index b48c5047740270f10e4e5765fba0c3ebe69ff83e..26c77c2ecfc11ca69fbfc8fa2fb2e0bb7f7c62b9 100644 (file)
 </item>
 
 <item>
-    <spec>:se<oa>t</oa> <a>option</a> <oa>...</oa></spec>
+    <spec>:se<oa>t</oa> <a>option</a> <oa></oa></spec>
     <description>
         <p>
             For boolean options, turn them on. For all other types,
 </item>
 
 <item>
-    <spec>:se<oa>t</oa> no<a>option</a> <oa>...</oa></spec>
+    <spec>:se<oa>t</oa> no<a>option</a> <oa></oa></spec>
     <description>
         <p>
             For boolean options, turn them off. For all other types,
 </item>
 
 <item>
-    <spec>:se<oa>t</oa> <a>option</a>! <oa>...</oa></spec>
-    <spec>:se<oa>t</oa> inv<a>option</a> <oa>...</oa></spec>
+    <spec>:se<oa>t</oa> <a>option</a>! <oa></oa></spec>
+    <spec>:se<oa>t</oa> inv<a>option</a> <oa></oa></spec>
     <description>
         <p>
             For boolean options, invert their value. For all other types,
 
 <item>
     <tags>:set!=</tags>
-    <spec>:se<oa>t</oa> inv<a>option</a>=<a>value</a> <oa>...</oa></spec>
-    <spec>:se<oa>t</oa> <a>option</a>!=<a>value</a> <oa>...</oa></spec>
+    <spec>:se<oa>t</oa> inv<a>option</a>=<a>value</a> <oa></oa></spec>
+    <spec>:se<oa>t</oa> <a>option</a>!=<a>value</a> <oa></oa></spec>
     <description>
         <p>For list options, toggle the specified values.</p>
 
 
 <item>
     <tags>:set-default</tags>
-    <spec>:se<oa>t</oa> <a>option</a>&amp; <oa>...</oa></spec>
+    <spec>:se<oa>t</oa> <a>option</a>&amp; <oa></oa></spec>
     <description>
         <p>Reset option to its default value.</p>
     </description>
 
 <item>
     <tags>:set-args E487 E521</tags>
-    <spec>:se<oa>t</oa> <a>option</a>=<a>value</a> <oa>...</oa></spec>
+    <spec>:se<oa>t</oa> <a>option</a>=<a>value</a> <oa></oa></spec>
     <description>
         <p>
             Set string or number option to <a>value</a>.
 
 <item>
     <tags>:set+=</tags>
-    <spec>:se<oa>t</oa> <a>option</a>+=<a>value</a> <oa>...</oa></spec>
+    <spec>:se<oa>t</oa> <a>option</a>+=<a>value</a> <oa></oa></spec>
     <description>
         <p>
             Add the <a>value</a> to a number option, or append the <a>value</a>
 
 <item>
     <tags>:set^=</tags>
-    <spec>:se<oa>t</oa> <a>option</a>^=<a>value</a> <oa>...</oa></spec>
+    <spec>:se<oa>t</oa> <a>option</a>^=<a>value</a> <oa></oa></spec>
     <description>
         <p>
             Multiply the <a>value</a> to a number option, or prepend the
 
 <item>
     <tags>:set-=</tags>
-    <spec>:se<oa>t</oa> <a>option</a>-=<a>value</a> <oa>...</oa></spec>
+    <spec>:se<oa>t</oa> <a>option</a>-=<a>value</a> <oa></oa></spec>
     <description>
         <p>
             Subtract the <a>value</a> from a number option, or remove the
     <strut/>
     <spec>'hinttags' 'ht'</spec>
     <type>&option.hinttags.type;</type>
-    <default>:-moz-any-link,area,button,iframe,input:not([type=hidden]),select,textarea,
+    <default>:-moz-any-link,area,button,iframe,input:not([type=hidden]),
+          label[for],select,textarea,
           [onclick],[onmouseover],[onmousedown],[onmouseup],[oncommand],
           [tabindex],[role=link],[role=button],[contenteditable=true]</default>
     <description>
 <item>
     <tags>'pu' 'passunknown'</tags>
     <spec>'passunknown' 'pu'</spec>
-    <type>&option.showmode.type;</type>
-    <default>&option.showmode.default;</default>
+    <type>&option.passunknown.type;</type>
+    <default>&option.passunknown.default;</default>
     <description>
         <p>
             Pass unknown keys through to &dactyl.host; in these
index db936e490ed05130e0cd6ae0bf39fdf81dd46dfa..ee7e6b8c92548d2bfafb65012f37078562cffba9 100644 (file)
     </description>
 </item>
 
+<item>
+    <tags>:private :pr</tags>
+    <tags>:pr0n :porn</tags>
+    <strut/>
+    <spec>:pr<oa>ivate</oa> <a>cmd</a></spec>
+    <description>
+        <p>
+            Execute <a>cmd</a> with privacy features enabled, and
+            do not save the invocation in command history.
+        </p>
+    </description>
+</item>
+
 <h2 tag="cookie-settings">Cookie settings</h2>
 <item>
     <tags>:cookies :ck</tags>
index e4e7d4dadbf9ee61d7037f1c8688d9ea0d3266d8..f977e0cb24a6453aee2a2b7e650c41addfb0da08 100644 (file)
 <item>
     <tags>:lpl :loadplugins</tags>
     <strut/>
-    <spec>:loadplugins <oa>pattern</oa> …</spec>
+    <spec>:loadplugins[!] <oa>pattern</oa> …</spec>
     <description>
         <p>
             Immediately load all plugins which have yet to be loaded. Because
             If <oa>pattern</oa>s are provided, the given regular expressions are
             used as filters rather than those in <o>loadplugins</o>.
         </p>
+        <p>
+            If <oa>!</oa> is given the plugins are forcibly loaded.
+        </p>
     </description>
 </item>
 
index e54bec3fc99a63039ad88eec97671ddc6e38667f..3d3dade6a1a1c713a6a643cac64fa80ee8b89254 100644 (file)
 </item>
 
 <item>
-    <tags>:mks :mksyntax</tags>
-    <spec>:mks<oa>yntax</oa><oa>!</oa> <oa>path</oa></spec>
+    <tags>:mkv :mkvimruntime</tags>
+    <spec>:mkv<oa>imruntime</oa><oa>!</oa> <oa>dir</oa></spec>
     <description>
         <p>
-            Generate a Vim syntax file. If <oa>path</oa> is not given, the local
-            Vim runtime path is guessed. If <oa>path</oa> is a directory, the
-            file <str delim="">&dactyl.name;.vim</str> in that directory is
-            used. An existing file will never be overwritten unless
-            <oa>bang</oa> is given.
+            Creates and installs Vim ftdetect, ftplugin and syntax files. If
+            <oa>dir</oa> is not given, the local Vim runtime path is guessed.
+            An existing file will never be overwritten unless <oa>!</oa> is
+            given.
+        </p>
+        <p>
+            See <em>:help 'runtimepath'</em> and <em>:help after-directory</em>
+            in Vim for an explanation of how best to manage personal changes to
+            these files.
         </p>
     </description>
 </item>
 <p>
     What is the meaning of life, the universe and everything? Douglas Adams,
     the only person who knew what this question really was about is now dead,
-    unfortunately. So now you might wonder what the meaning of death is...
+    unfortunately. So now you might wonder what the meaning of death is
 </p>
 
 <h2 tag="uncategorized">Uncategorized help</h2>
index a84aad838f18f9b845dfe42172ff756cb3c3a381..f12bb9bf92f23c5b6e4ec7373108767e1bad2524 100644 (file)
@@ -37,14 +37,35 @@ then
     }
 fi
 
+mungeliterals=$(cat <<'!'
+    local $/;
+    $_ = <>;
+    s{(?<!function )\bliteral\(/\*(.*?)\*/\)}{
+        my $s = $1;
+        $s =~ s/[\\']/\\$&/g;
+        $s =~ s/\n/\\n\\$&/g;
+        "/* Preprocessors FTW. */ '$s'";
+    }ges;
+    print;
+!
+)
+
+mungeliterals() {
+    if which perl >/dev/null 2>&1
+    then perl -e "$mungeliterals"
+    else cat
+    fi
+}
+
 getfiles() {
     filter="\.($(echo $1 | tr ' ' '|'))$"; shift
     find "$@" -not -path '*\.hg*' 2>/dev/null | grep -E "$filter" || true
 }
 copytext() {
+    mungeliterals <"$1" |
     sed -e "s,@VERSION@,$VERSION,g" \
         -e "s,@DATE@,$BUILD_DATE,g" \
-        <"$1" >"$2"
+        >"$2"
     cmp -s -- "$1" "$2" ||
     ( echo "modified: $1"; diff -u -- "$1" "$2" | grep '^[-+][^-+]' )
 }
@@ -68,7 +89,7 @@ do
             for f in $(getfiles "$bin" "$dir")
             do
                 mkdir -p "$stage/${f%/*}"
-                cp -- $f "$stage/$f"
+                cp -- "$f" "$stage/$f"
             done
             for f in $(getfiles "$text" "$dir")
             do
@@ -78,7 +99,15 @@ do
         done
         for f in $files
         do
-            [ -f "$f" ] && copytext "$f" "$stage/$f"
+            if [ -f "$f" ]
+            then
+                case "$f" in
+                *.js|*.jsm|*.css|*.dtd|*.xml|*.xul|*.html|*.xhtml|*.xsl|*.properties|*.json)
+                    copytext "$f" "$stage/$f";;
+                *)
+                    cp -- "$f" "$stage/$f";;
+                esac
+            fi
         done
        true
     ) || exit 1
index 8ea7f8a4a6414a0016ffd0c77f13a9dd9c398d17..2e52a9aaee7f888675b430c852032b193e5f2df5 100644 (file)
@@ -1,17 +1,19 @@
-// Copyright (c) 2009-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2012 Kris Maglione <maglione.k@gmail.com>
 // Copyright (c) 2009-2010 by Doug Kearns <dougkearns@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("addons", {
     exports: ["AddonManager", "Addons", "Addon", "addons"],
-    require: ["services"]
-}, this);
+    require: ["services", "util"]
+});
+
+this.lazyRequire("completion", ["completion"]);
+lazyRequire("template", ["template"]);
 
 var callResult = function callResult(method) {
     let args = Array.slice(arguments, 1);
@@ -144,21 +146,18 @@ var Addon = Class("Addon", {
         this.nodes = {
             commandTarget: this
         };
-        XML.ignoreWhitespace = true;
-        util.xmlToDom(
-            <tr highlight="Addon" key="row" xmlns:dactyl={NS} xmlns={XHTML}>
-                <td highlight="AddonName" key="name"/>
-                <td highlight="AddonVersion" key="version"/>
-                <td highlight="AddonButtons Buttons">
-                    <a highlight="Button" href="javascript:0" key="enable">{_("addon.action.On")}</a>
-                    <a highlight="Button" href="javascript:0" key="disable">{_("addon.action.Off")}</a>
-                    <a highlight="Button" href="javascript:0" key="delete">{_("addon.action.Delete")}</a>
-                    <a highlight="Button" href="javascript:0" key="update">{_("addon.action.Update")}</a>
-                    <a highlight="Button" href="javascript:0" key="options">{_("addon.action.Options")}</a>
-                </td>
-                <td highlight="AddonStatus" key="status"/>
-                <td highlight="AddonDescription" key="description"/>
-            </tr>,
+        DOM.fromJSON(
+            ["tr", { highlight: "Addon", key: "row" },
+                ["td", { highlight: "AddonName", key: "name" }],
+                ["td", { highlight: "AddonVersion", key: "version" }],
+                ["td", { highlight: "AddonButtons Buttons" },
+                    ["a", { highlight: "Button", href: "javascript:0", key: "enable" }, _("addon.action.On")],
+                    ["a", { highlight: "Button", href: "javascript:0", key: "disable" }, _("addon.action.Off")],
+                    ["a", { highlight: "Button", href: "javascript:0", key: "delete" }, _("addon.action.Delete")],
+                    ["a", { highlight: "Button", href: "javascript:0", key: "update" }, _("addon.action.Update")],
+                    ["a", { highlight: "Button", href: "javascript:0", key: "options" }, _("addon.action.Options")]],
+                ["td", { highlight: "AddonStatus", key: "status" }],
+                ["td", { highlight: "AddonDescription", key: "description" }]],
             this.list.document, this.nodes);
 
         this.update();
@@ -188,11 +187,8 @@ var Addon = Class("Addon", {
     compare: function compare(other) String.localeCompare(this.name, other.name),
 
     get statusInfo() {
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        default xml namespace = XHTML;
-
-        let info = this.isActive ? <span highlight="Enabled">enabled</span>
-                                 : <span highlight="Disabled">disabled</span>;
+        let info = this.isActive ? ["span", { highlight: "Enabled" }, "enabled"]
+                                 : ["span", { highlight: "Disabled" }, "disabled"];
 
         let pending;
         if (this.pendingOperations & AddonManager.PENDING_UNINSTALL)
@@ -206,8 +202,11 @@ var Addon = Class("Addon", {
         else if (this.pendingOperations & AddonManager.PENDING_UPGRADE)
             pending = ["Enabled", "upgraded"];
         if (pending)
-            return <>{info}&#xa0;(<span highlight={pending[0]}>{pending[1]}</span>
-                                  &#xa0;on <a href="#" dactyl:command="dactyl.restart" xmlns:dactyl={NS}>restart</a>)</>;
+            return [info, " (",
+                    ["span", { highlight: pending[0] }, pending[1]],
+                    " on ",
+                    ["a", { href: "#", "dactyl:command": "dactyl.restart" }, "restart"],
+                    ")"]
         return info;
     },
 
@@ -217,7 +216,8 @@ var Addon = Class("Addon", {
             let node = self.nodes[key];
             while (node.firstChild)
                 node.removeChild(node.firstChild);
-            node.appendChild(util.xmlToDom(<>{xml}</>, self.list.document));
+
+            DOM(node).append(isArray(xml) ? xml : DOM.DOMString(xml));
         }
 
         update("name", template.icon({ icon: this.iconURL }, this.name));
@@ -279,17 +279,14 @@ var AddonList = Class("AddonList", {
     },
 
     message: Class.Memoize(function () {
-
-        XML.ignoreWhitespace = true;
-        util.xmlToDom(<table highlight="Addons" key="list" xmlns={XHTML}>
-                        <tr highlight="AddonHead">
-                            <td>{_("title.Name")}</td>
-                            <td>{_("title.Version")}</td>
-                            <td/>
-                            <td>{_("title.Status")}</td>
-                            <td>{_("title.Description")}</td>
-                        </tr>
-                      </table>, this.document, this.nodes);
+        DOM.fromJSON(["table", { highlight: "Addons", key: "list" },
+                        ["tr", { highlight: "AddonHead" },
+                            ["td", {}, _("title.Name")],
+                            ["td", {}, _("title.Version")],
+                            ["td"],
+                            ["td", {}, _("title.Status")],
+                            ["td", {}, _("title.Description")]]],
+                      this.document, this.nodes);
 
         if (this._addons)
             this._init();
@@ -355,7 +352,7 @@ var Addons = Module("addons", {
                 .toObject())
 }, {
 }, {
-    commands: function (dactyl, modules, window) {
+    commands: function initCommands(dactyl, modules, window) {
         const { CommandOption, commands, completion, io } = modules;
 
         commands.add(["addo[ns]", "ao"],
@@ -456,7 +453,7 @@ var Addons = Module("addons", {
                 });
         });
     },
-    completion: function (dactyl, modules, window) {
+    completion: function initCompletion(dactyl, modules, window) {
         completion.addonType = function addonType(context) {
             let base = ["extension", "theme"];
             function update(types) {
@@ -495,127 +492,7 @@ var Addons = Module("addons", {
     }
 });
 
-if (!services.has("extensionManager"))
-    Components.utils.import("resource://gre/modules/AddonManager.jsm");
-else
-    var AddonManager = {
-        PERM_CAN_UNINSTALL: 1,
-        PERM_CAN_ENABLE: 2,
-        PERM_CAN_DISABLE: 4,
-        PERM_CAN_UPGRADE: 8,
-
-        getAddonByID: function (id, callback) {
-            callback = callback || util.identity;
-            addon = services.extensionManager.getItemForID(id);
-            if (addon)
-                addon = this.wrapAddon(addon);
-            return callback(addon);
-        },
-
-        wrapAddon: function wrapAddon(addon) {
-            addon = Object.create(addon.QueryInterface(Ci.nsIUpdateItem));
-
-            ["aboutURL", "creator", "description", "developers",
-             "homepageURL", "installDate", "optionsURL",
-             "releaseNotesURI", "updateDate"].forEach(function (item) {
-                memoize(addon, item, function (item) this.getProperty(item));
-            });
-
-            update(addon, {
-
-                get permissions() 1 | (this.userDisabled ? 2 : 4),
-
-                appDisabled: false,
-
-                getProperty: function getProperty(property) {
-                    let resource = services.rdf.GetResource("urn:mozilla:item:" + this.id);
-
-                    if (resource) {
-                        let target = services.extensionManager.datasource.GetTarget(resource,
-                            services.rdf.GetResource("http://www.mozilla.org/2004/em-rdf#" + property), true);
-
-                        if (target && target instanceof Ci.nsIRDFLiteral)
-                            return target.Value;
-                    }
-
-                    return "";
-                },
-
-                installLocation: Class.Memoize(function () services.extensionManager.getInstallLocation(this.id)),
-                getResourceURI: function getResourceURI(path) {
-                    let file = this.installLocation.getItemFile(this.id, path);
-                    return services.io.newFileURI(file);
-                },
-
-                get isActive() this.getProperty("isDisabled") != "true",
-
-                uninstall: function uninstall() {
-                    services.extensionManager.uninstallItem(this.id);
-                },
-
-                get userDisabled() this.getProperty("userDisabled") === "true",
-                set userDisabled(val) {
-                    services.extensionManager[val ? "disableItem" : "enableItem"](this.id);
-                }
-            });
-
-            return addon;
-        },
-
-        getAddonsByTypes: function (types, callback) {
-            let res = [];
-            for (let [, type] in Iterator(types))
-                for (let [, item] in Iterator(services.extensionManager
-                            .getItemList(Ci.nsIUpdateItem["TYPE_" + type.toUpperCase()], {})))
-                    res.push(this.wrapAddon(item));
-
-            if (callback)
-                util.timeout(function () { callback(res); });
-            return res;
-        },
-
-        getInstallForFile: function (file, callback, mimetype) {
-            callback({
-                addListener: function () {},
-                install: function () {
-                    services.extensionManager.installItemFromFile(file, "app-profile");
-                }
-            });
-        },
-
-        getInstallForURL: function (url, callback, mimetype) {
-            util.assert(false, _("error.unavailable", config.host, services.runtime.version));
-        },
-
-        observers: [],
-        addAddonListener: function (listener) {
-            observer.listener = listener;
-            function observer(subject, topic, data) {
-                if (subject instanceof Ci.nsIUpdateItem)
-                    subject = AddonManager.wrapAddon(subject);
-
-                if (data === "item-installed")
-                    listener.onInstalling(subject, true);
-                else if (data === "item-uninstalled")
-                    listener.onUnistalling(subject, true);
-                else if (data === "item-upgraded")
-                    listener.onInstalling(subject, true);
-                else if (data === "item-enabled")
-                    listener.onEnabling(subject, true);
-                else if (data === "item-disabled")
-                    listener.onDisabling(subject, true);
-            }
-            services.observer.addObserver(observer, "em-action-requested", false);
-            this.observers.push(observer);
-        },
-        removeAddonListener: function (listener) {
-            this.observers = this.observers.filter(function (observer) {
-                if (observer.listener !== listener)
-                    return true;
-                services.observer.removeObserver(observer, "em-action-requested");
-            });
-        }
-    };
+Components.utils.import("resource://gre/modules/AddonManager.jsm", this);
 
 endModule();
 
index 51d2f0d757ca93bd5fa1d5579fc2fb76b4bc2360..589c8042478c4c948821c6761d9202e592da283d 100644 (file)
@@ -1,13 +1,12 @@
-// Copyright (c) 2009-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 
-Cu.import("resource://dactyl/bootstrap.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 try {
     var ctypes;
     Cu.import("resource://gre/modules/ctypes.jsm");
@@ -21,122 +20,27 @@ let { __lookupGetter__, __lookupSetter__, __defineGetter__, __defineSetter__,
 if (typeof XPCSafeJSObjectWrapper === "undefined")
     this.XPCSafeJSObjectWrapper = XPCNativeWrapper;
 
-if (!XPCNativeWrapper.unwrap)
-    XPCNativeWrapper.unwrap = function unwrap(obj) {
-        if (hasOwnProperty.call(obj, "wrappedJSObject"))
-            return obj.wrappedJSObject;
-        return obj;
-    };
-if (!Object.create)
-    Object.create = function create(proto, props) {
-        let obj = { __proto__: proto };
-        for (let k in properties(props || {}))
-            Object.defineProperty(obj, k, props[k]);
-        return obj;
-    };
-if (!Object.defineProperty)
-    Object.defineProperty = function defineProperty(obj, prop, desc) {
-        try {
-            let value = desc.value;
-            if ("value" in desc)
-                if (desc.writable && !__lookupGetter__.call(obj, prop)
-                                  && !__lookupSetter__.call(obj, prop))
-                    try {
-                        obj[prop] = value;
-                    }
-                    catch (e if e instanceof TypeError) {}
-                else {
-                    __defineGetter__.call(obj, prop, function () value);
-                    if (desc.writable)
-                        __defineSetter__.call(obj, prop, function (val) { value = val; });
-                }
+let getGlobalForObject = Cu.getGlobalForObject || function (obj) obj.__parent__;
 
-            if ("get" in desc)
-                __defineGetter__.call(obj, prop, desc.get);
-            if ("set" in desc)
-                __defineSetter__.call(obj, prop, desc.set);
-        }
-        catch (e) {
-            throw e.stack ? e : Error(e);
-        }
-    };
-if (!Object.defineProperties)
-    Object.defineProperties = function defineProperties(obj, props) {
-        for (let [k, v] in Iterator(props))
-            Object.defineProperty(obj, k, v);
-    };
-if (!Object.freeze)
-    Object.freeze = function freeze(obj) {};
-if (!Object.getPropertyDescriptor)
-    Object.getPropertyDescriptor = function getPropertyDescriptor(obj, prop) {
-        try {
-            let desc = {
-                configurable: true,
-                enumerable: propertyIsEnumerable.call(obj, prop)
-            };
-            var get = __lookupGetter__.call(obj, prop),
-                set = __lookupSetter__.call(obj, prop);
-            if (!get && !set) {
-                desc.value = obj[prop];
-                desc.writable = true;
-            }
-            if (get)
-                desc.get = get;
-            if (set)
-                desc.set = set;
-            return desc;
-        }
-        catch (e) {
-            throw e.stack ? e : Error(e);
-        }
-    };
-if (!Object.getOwnPropertyDescriptor)
-    Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(obj, prop) {
-        if (hasOwnProperty.call(obj, prop))
-            return Object.getPropertyDescriptor(obj, prop);
-    };
-if (!Object.getOwnPropertyNames)
-    Object.getOwnPropertyNames = function getOwnPropertyNames(obj, _debugger) {
-        try {
-            // This is an ugly and unfortunately necessary hack.
-            if (hasOwnProperty.call(obj, "__iterator__")) {
-                var oldIter = obj.__iterator__;
-                delete obj.__iterator__;
-            }
-            let res = [k for (k in obj) if (hasOwnProperty.call(obj, k))];
-            if (oldIter !== undefined) {
-                obj.__iterator__ = oldIter;
-                res.push("__iterator__");
-            }
-            return res;
-        }
-        catch (e) {
-            throw e.stack ? e : Error(e);
-        }
-    };
-if (!Object.getPrototypeOf)
-    Object.getPrototypeOf = function getPrototypeOf(obj) obj.__proto__;
-if (!Object.keys)
-    Object.keys = function keys(obj)
-        Object.getOwnPropertyNames(obj).filter(function (k) propertyIsEnumerable.call(obj, k));
+function require(module, target) JSMLoader.load(module, target);
 
-let getGlobalForObject = Cu.getGlobalForObject || function (obj) obj.__parent__;
+function lazyRequire(module, names, target) {
+    for each (let name in names)
+        memoize(target || this, name, function (name) require(module)[name]);
+}
 
-let jsmodules = {
-    lazyRequire: function lazyRequire(module, names, target) {
-        for each (let name in names)
-            memoize(target || this, name, function (name) require(module)[name]);
-    }
-};
+let jsmodules = { lazyRequire: lazyRequire };
 jsmodules.jsmodules = jsmodules;
 
+function toString() "[module-global " + this.NAME + "]";
+
 let use = {};
 let loaded = {};
 let currentModule;
 let global = this;
 function defineModule(name, params, module) {
     if (!module)
-        module = getGlobalForObject(params);
+        module = this;
 
     module.NAME = name;
     module.EXPORTED_SYMBOLS = params.exports || [];
@@ -147,8 +51,7 @@ function defineModule(name, params, module) {
     defineModule.prefix += "  ";
 
     for (let [, mod] in Iterator(params.require || []))
-        require(module, mod, null, name);
-    module.__proto__ = jsmodules;
+        require(mod, module);
 
     module._lastModule = currentModule;
     currentModule = module;
@@ -159,7 +62,7 @@ defineModule.loadLog = [];
 Object.defineProperty(defineModule.loadLog, "push", {
     value: function (val) {
         val = defineModule.prefix + val;
-        if (false)
+        if (true)
             defineModule.dump(val + "\n");
         this[this.length] = Date.now() + " " + val;
     }
@@ -196,11 +99,11 @@ function endModule() {
     defineModule.loadLog.push("(End   " + currentModule.NAME + ")");
 
     loaded[currentModule.NAME] = 1;
-    require(jsmodules, currentModule.NAME);
+    require(currentModule.NAME, jsmodules);
     currentModule = currentModule._lastModule;
 }
 
-function require(obj, name, from, targetName) {
+function require_(obj, name, from, targetName) {
     try {
         if (arguments.length === 1)
             [obj, name] = [{}, obj];
@@ -230,18 +133,47 @@ function require(obj, name, from, targetName) {
 defineModule("base", {
     // sed -n 's/^(const|var|function) ([a-zA-Z0-9_]+).*/      "\2",/p' base.jsm | sort | fmt
     exports: [
-        "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object",
+        "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Finished", "Module", "JSMLoader",
         "Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMShim", "XPCOMUtils",
         "XPCSafeJSObjectWrapper", "array", "bind", "call", "callable", "ctypes", "curry",
         "debuggerProperties", "defineModule", "deprecated", "endModule", "forEach", "isArray",
-        "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "iter", "iterAll",
-        "iterOwnProperties", "keys", "memoize", "octal", "properties", "require", "set", "update",
-        "values", "withCallerGlobal"
+        "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "isXML", "iter",
+        "iterAll", "iterOwnProperties", "keys", "literal", "memoize", "octal", "properties",
+        "require", "set", "update", "values", "update_"
     ]
-}, this);
+});
 
+this.lazyRequire("cache", ["cache"]);
+this.lazyRequire("config", ["config"]);
 this.lazyRequire("messages", ["_", "Messages"]);
-this.lazyRequire("util", ["util"]);
+this.lazyRequire("services", ["services"]);
+this.lazyRequire("storage", ["File"]);
+this.lazyRequire("util", ["FailedAssertion", "util"]);
+
+function literal(/* comment */) {
+    let { caller } = Components.stack;
+    while (caller && caller.language != 2)
+        caller = caller.caller;
+
+    let file = caller.filename.replace(/.* -> /, "");
+    let key = "literal:" + file + ":" + caller.line;
+
+    let source = File.readURL(file);
+
+    let match = RegExp("(?:.*\\n){" + (caller.lineNumber - 1) + "}" +
+                       ".*literal\\(/\\*([^]*?)\\*/\\)").exec(source);
+    return match[1];
+
+    // Later...
+    return cache.get(key, function () {
+        let source = cache.get("literal:" + file,
+                               function () util.httpGet(file).responseText);
+
+        let match = RegExp("(?:.*\\n){" + (caller.lineNumber - 1) + "}" +
+                           ".*literal\\(/\\*([^]*?)\\*/\\)").exec(source);
+        return match[1];
+    });
+}
 
 /**
  * Returns a list of all of the top-level properties of an object, by
@@ -269,7 +201,6 @@ function debuggerProperties(obj) {
  * @returns {Generator}
  */
 function prototype(obj)
-    /* Temporary hack: */ typeof obj === "xml" || obj.__proto__ !== obj.__proto__ ? null :
     obj.__proto__ || Object.getPrototypeOf(obj) ||
     XPCNativeWrapper.unwrap(obj).__proto__ ||
     Object.getPrototypeOf(XPCNativeWrapper.unwrap(obj));
@@ -286,10 +217,42 @@ function properties(obj, prototypes, debugger_) {
     }
     catch (e) {}
 
+    function props(obj) {
+        // Grr.
+        try {
+            return Object.getOwnPropertyNames(obj);
+        }
+        catch (e) {
+            if (e.result === Cr.NS_ERROR_FAILURE) {
+                // This is being thrown for PDF.js content windows,
+                // currently.
+                let filter = function filter(prop) {
+                    try {
+                        return prop in obj;
+                    }
+                    catch (e) {
+                        util.reportError("Filtering properties for " +
+                                         String.quote(obj) + ", " +
+                                         "error checking presence of " +
+                                         String.quote(prop) + ": " + e);
+                    }
+                    return false;
+                };
+                return array.uniq([k for (k in obj)].concat(
+                    Object.getOwnPropertyNames(
+                              XPCNativeWrapper.unwrap(obj))
+                          .filter(filter)))
+            }
+            else if (!e.stack) {
+                throw Error(e);
+            }
+        }
+    }
+
     for (; obj; obj = prototypes && prototype(obj)) {
         try {
-            if (sandbox.Object.getOwnPropertyNames || !debugger_ || !services.debugger.isOn)
-                var iter = (v for each (v in Object.getOwnPropertyNames(obj)));
+            if (!debugger_ || !services.debugger.isOn)
+                var iter = (v for each (v in props(obj)));
         }
         catch (e) {}
         if (!iter)
@@ -331,8 +294,8 @@ function deprecated(alternative, fn) {
 deprecated.warn = function warn(func, name, alternative, frame) {
     if (!func.seenCaller)
         func.seenCaller = Set([
-            "resource://dactyl" + JSMLoader.suffix + "/javascript.jsm",
-            "resource://dactyl" + JSMLoader.suffix + "/util.jsm"
+            "resource://dactyl/javascript.jsm",
+            "resource://dactyl/util.jsm"
         ]);
 
     frame = frame || Components.stack.caller.caller;
@@ -570,6 +533,12 @@ function isinstance(object, interfaces) {
  */
 function isObject(obj) typeof obj === "object" && obj != null || obj instanceof Ci.nsISupports;
 
+/**
+ * Returns true if obje is an E4X XML object.
+ * @deprecated
+ */
+function isXML(obj) typeof obj === "xml";
+
 /**
  * Returns true if and only if its sole argument is an
  * instance of the builtin Array type. The array may come from
@@ -653,20 +622,8 @@ function memoize(obj, key, getter) {
     }
 }
 
-let sandbox = Cu.Sandbox(this);
+let sandbox = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance());
 sandbox.__proto__ = this;
-/**
- * Wraps a function so that when called, the global object of the caller
- * is prepended to its arguments.
- */
-// Hack to get around lack of access to caller in strict mode.
-var withCallerGlobal = Cu.evalInSandbox(<![CDATA[
-    (function withCallerGlobal(fn)
-        function withCallerGlobal_wrapped()
-            fn.apply(this,
-                     [Class.objectGlobal(withCallerGlobal_wrapped.caller)]
-                        .concat(Array.slice(arguments))))
-]]>, Cu.Sandbox(this), "1.8");
 
 /**
  * Updates an object with the properties of another object. Getters
@@ -699,7 +656,7 @@ function update(target) {
                 if (typeof desc.value === "function" && target.__proto__ && !(desc.value instanceof Ci.nsIDOMElement /* wtf? */)) {
                     let func = desc.value.wrapped || desc.value;
                     if (!func.superapply) {
-                        func.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]);
+                        func.__defineGetter__("super", function get_super() Object.getPrototypeOf(target)[k]);
                         func.superapply = function superapply(self, args)
                             let (meth = Object.getPrototypeOf(target)[k])
                                 meth && meth.apply(self, args);
@@ -714,6 +671,33 @@ function update(target) {
     }
     return target;
 }
+function update_(target) {
+    for (let i = 1; i < arguments.length; i++) {
+        let src = arguments[i];
+        Object.getOwnPropertyNames(src || {}).forEach(function (k) {
+            let desc = Object.getOwnPropertyDescriptor(src, k);
+            if (desc.value instanceof Class.Property)
+                desc = desc.value.init(k, target) || desc.value;
+
+            try {
+                if (typeof desc.value === "function" && target.__proto__ && !(desc.value instanceof Ci.nsIDOMElement /* wtf? */)) {
+                    let func = desc.value.wrapped || desc.value;
+                    if (!func.superapply) {
+                        func.__defineGetter__("super", function get_super_() Object.getPrototypeOf(target)[k]);
+                        func.superapply = function super_apply(self, args)
+                            let (meth = Object.getPrototypeOf(target)[k])
+                                meth && meth.apply(self, args);
+                        func.supercall = function super_call(self)
+                            func.superapply(self, Array.slice(arguments, 1));
+                    }
+                }
+                Object.defineProperty(target, k, desc);
+            }
+            catch (e) {}
+        });
+    }
+    return target;
+}
 
 /**
  * @constructor Class
@@ -751,6 +735,7 @@ function Class() {
         var Constructor = function Constructor() {
             var self = Object.create(Constructor.prototype);
             self.instance = self;
+            self.globalInstance = self;
 
             if ("_metaInit_" in self && self._metaInit_)
                 self._metaInit_.apply(self, arguments);
@@ -759,17 +744,18 @@ function Class() {
             return res !== undefined ? res : self;
         };
     else
-        var Constructor = eval(String.replace(<![CDATA[
-            (function constructor(PARAMS) {
-                var self = Object.create(Constructor.prototype);
-                self.instance = self;
-
-                if ("_metaInit_" in self && self._metaInit_)
-                    self._metaInit_.apply(self, arguments);
-
-                var res = self.init.apply(self, arguments);
-                return res !== undefined ? res : self;
-            })]]>,
+        var Constructor = eval(String.replace('\n\
+            (function constructor(PARAMS) {                      \n\
+                var self = Object.create(Constructor.prototype); \n\
+                self.instance = self;                            \n\
+                self.globalInstance = self;                      \n\
+                                                                 \n\
+                if ("_metaInit_" in self && self._metaInit_)     \n\
+                    self._metaInit_.apply(self, arguments);      \n\
+                                                                 \n\
+                var res = self.init.apply(self, arguments);      \n\
+                return res !== undefined ? res : self;           \n\
+            })',
             "constructor", (name || superclass.className).replace(/\W/g, "_"))
                 .replace("PARAMS", /^function .*?\((.*?)\)/.exec(args[0] && args[0].init || Class.prototype.init)[1]
                                                            .replace(/\b(self|res|Constructor)\b/g, "$1_")));
@@ -1126,6 +1112,12 @@ var ErrorBase = Class("ErrorBase", Error, {
     toString: function () String(this.message)
 });
 
+/**
+ * An Error subclass to throw in order to stop sourcing a plugin without
+ * printing a stack trace.
+ */
+var Finished = Class("Finished", ErrorBase);
+
 /**
  * Constructs a new Module class and instantiates an instance into the current
  * module global object.
@@ -1424,7 +1416,8 @@ function iter(obj, iface) {
     }
     else if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList]))
         res = array.iterItems(obj);
-    else if (obj instanceof Ci.nsIDOMNamedNodeMap)
+    else if (Ci.nsIDOMNamedNodeMap && obj instanceof Ci.nsIDOMNamedNodeMap ||
+             Ci.nsIDOMMozNamedAttrMap && obj instanceof Ci.nsIDOMMozNamedAttrMap)
         res = (function () {
             for (let i = 0; i < obj.length; i++)
                 yield [obj.name, obj];
index 2647848d2f97209cd9c27bf2c5d8fa255a2883b4..cedf7bd90d51bda721676114205385e4a61f0292 100644 (file)
@@ -2,13 +2,12 @@
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("bookmarkcache", {
     exports: ["Bookmark", "BookmarkCache", "Keyword", "bookmarkcache"],
     require: ["services", "util"]
-}, this);
+});
 
 this.lazyRequire("storage", ["storage"]);
 
index 7145110bd84b69aee933dc3bb26847451147539c..6c9426d242c7f0c92ebb0cd11bc205a09ec2c285 100644 (file)
-// Copyright (c) 2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2011-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-try {
+var EXPORTED_SYMBOLS = ["require"];
 
-let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+// Deal with cross-compartment XML passing issues.
+function create(proto) Object.create(proto);
+this["import"] = function import_(obj) {
+    let res = {};
+    for each (let key in Object.getOwnPropertyNames(obj))
+        Object.defineProperty(res, key, Object.getOwnPropertyDescriptor(obj, key));
+    return res;
+}
 
-var EXPORTED_SYMBOLS = ["JSMLoader"];
+// Deal with subScriptLoader prepending crap to loaded URLs
+Components.utils.import("resource://gre/modules/Services.jsm");
+function loadSubScript() Services.scriptloader.loadSubScript.apply(null, arguments);
 
-var BOOTSTRAP_CONTRACT = "@dactyl.googlecode.com/base/bootstrap";
-var JSMLoader = BOOTSTRAP_CONTRACT in Components.classes &&
-    Components.classes[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader;
-
-if (JSMLoader && JSMLoader.bump === 6)
-    JSMLoader.global = this;
-else
-    JSMLoader = {
-        bump: 6,
-
-        builtin: Cu.Sandbox(this),
-
-        canonical: {},
-
-        factories: [],
-
-        name: "dactyl",
-
-        global: this,
-
-        globals: JSMLoader ? JSMLoader.globals : {},
-
-        io: Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService),
-
-        loader: Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader),
-
-        manager: Components.manager.QueryInterface(Ci.nsIComponentRegistrar),
-
-        modules: JSMLoader && JSMLoader.modules || {},
-
-        stale: JSMLoader ? JSMLoader.stale : {},
-
-        suffix: "",
-
-        times: {
-            all: 0,
-            add: function add(major, minor, delta) {
-                this.all += delta;
-
-                this[major] = (this[major] || 0) + delta;
-                if (minor) {
-                    minor = ":" + minor;
-                    this[minor] = (this[minor] || 0) + delta;
-                    this[major + minor] = (this[major + minor] || 0) + delta;
-                }
-            },
-            clear: function clear() {
-                for (let key in this)
-                    if (typeof this[key] !== "number")
-                        delete this[key];
-            }
-        },
-
-        init: function init(suffix) {
-            this.initialized = true;
-            this.suffix = suffix || "";
-
-            let base = this.load("base.jsm", this.global);
-            this.global.EXPORTED_SYMBOLS = base.EXPORTED_SYMBOLS;
-            this.global.JSMLoader = this;
-            base.JSMLoader = this;
-        },
-
-        getTarget: function getTarget(url) {
-            if (url.indexOf(":") === -1)
-                url = "resource://dactyl" + this.suffix + "/" + url;
-
-            let chan = this.io.newChannel(url, null, null);
-            chan.cancel(Cr.NS_BINDING_ABORTED);
-            return chan.name;
-        },
-
-        load: function load(name, target) {
-            let url = name;
-            if (url.indexOf(":") === -1)
-                url = "resource://dactyl" + this.suffix + "/" + url;
-            let targetURL = this.getTarget(url);
-
-            let stale = this.stale[name] || this.stale[targetURL];
-            if (stale) {
-                delete this.stale[name];
-                delete this.stale[targetURL];
-
-                let loadURL = url.replace(RegExp("^(resource://dactyl)/"), "$1" + this.suffix + "/");
-
-                let global = this.globals[name];
-                if (stale === targetURL)
-                    this.loadSubScript(loadURL, global.global || global);
-            }
-
-            try {
-                let now = Date.now();
-                this.modules[url] = true;
-                let global = Cu.import(url, target);
-
-                if (!(name in this.globals))
-                    this.times.add("require", name, Date.now() - now);
-
-                return this.globals[name] = global;
-            }
-            catch (e) {
-                dump("Importing " + url + ": " + e + "\n" + (e.stack || Error().stack));
-                throw e;
-            }
-        },
-
-        loadSubScript: function loadSubScript(script) {
-            let now = Date.now();
-            this.loader.loadSubScript.apply(this.loader, arguments);
-            this.times.add("loadSubScript", script, Date.now() - now);
-        },
-
-        cleanup: function unregister() {
-            for each (let factory in this.factories)
-                this.manager.unregisterFactory(factory.classID, factory);
-            this.factories = {};
-        },
-
-        purge: function purge() {
-            dump("dactyl: JSMLoader: purge\n");
-
-            this.bootstrap = null;
-
-            if (Cu.unload) {
-                Object.keys(this.modules).reverse().forEach(function (url) {
-                    try {
-                        Cu.unload(url);
-                    }
-                    catch (e) {
-                        Cu.reportError(e);
-                    }
-                });
-            }
-            else {
-                for (let [url, global] in Iterator(this.globals)) {
-                    if (url === "bootstrap.jsm" || url === "resource://dactyl/bootstrap.jsm")
-                        continue;
-
-                    let target = this.getTarget(url);
-                    this.stale[url] = target;
-                    this.stale[target] = target;
-
-                    for each (let prop in Object.getOwnPropertyNames(global))
-                        try {
-                            if (!(prop in this.builtin) &&
-                                ["JSMLoader", "Set", "set", "EXPORTED_SYMBOLS"].indexOf(prop) < 0 &&
-                                !global.__lookupGetter__(prop))
-                                global[prop] = undefined;
-                        }
-                        catch (e) {
-                            dump("Deleting property " + prop + " on " + url + ":\n    " + e + "\n");
-                            Cu.reportError(e);
-                        }
-                }
-            }
-        },
-
-        Factory: function Factory(clas) ({
-            __proto__: clas.prototype,
-
-            createInstance: function (outer, iid) {
-                try {
-                    if (outer != null)
-                        throw Cr.NS_ERROR_NO_AGGREGATION;
-                    if (!clas.instance)
-                        clas.instance = new clas();
-                    return clas.instance.QueryInterface(iid);
-                }
-                catch (e) {
-                    Cu.reportError(e);
-                    throw e;
-                }
-            }
-        }),
-
-        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[factory.contractID] = factory;
-        }
-    };
-
-}catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
-
-// vim: set fdm=marker sw=4 sts=4 et ft=javascript:
index 357beea6556566c60eac0ce21dad1b9a82224b55..964c3c8166c4c6778202a58885c246498cb655d6 100644 (file)
@@ -1,22 +1,24 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-try {"use strict";
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("buffer", {
     exports: ["Buffer", "buffer"],
     require: ["prefs", "services", "util"]
-}, this);
+});
 
-this.lazyRequire("finder", ["RangeFind"]);
-this.lazyRequire("io", ["io"]);
-this.lazyRequire("overlay", ["overlay"]);
-this.lazyRequire("storage", ["File", "storage"]);
-this.lazyRequire("template", ["template"]);
+lazyRequire("bookmarkcache", ["bookmarkcache"]);
+lazyRequire("contexts", ["Group"]);
+lazyRequire("io", ["io"]);
+lazyRequire("finder", ["RangeFind"]);
+lazyRequire("overlay", ["overlay"]);
+lazyRequire("sanitizer", ["sanitizer"]);
+lazyRequire("storage", ["File", "storage"]);
+lazyRequire("template", ["template"]);
 
 /**
  * A class to manage the primary web content buffer. The name comes
@@ -66,6 +68,45 @@ var Buffer = Module("Buffer", {
         );
     },
 
+    /**
+     * Gets a content preference for the given buffer.
+     *
+     * @param {string} pref The preference to get.
+     * @param {function(string|number|boolean)} callback The callback to
+     *      call with the preference value. @optional
+     * @returns {string|number|boolean} The value of the preference, if
+     *      callback is not provided.
+     */
+    getPref: function getPref(pref, callback) {
+        // God damn it.
+        if (config.haveGecko("19.0a1"))
+            services.contentPrefs.getPref(this.uri, pref,
+                                          sanitizer.getContext(this.win), callback);
+        else
+            services.contentPrefs.getPref(uri, pref, callback);
+    },
+
+    /**
+     * Sets a content preference for the given buffer.
+     *
+     * @param {string} pref The preference to set.
+     * @param {string} value The value to store.
+     */
+    setPref: function setPref(pref, value) {
+        services.contentPrefs.setPref(
+            this.uri, pref, value, sanitizer.getContext(this.win));
+    },
+
+    /**
+     * Clear a content preference for the given buffer.
+     *
+     * @param {string} pref The preference to clear.
+     */
+    clearPref: function clearPref(pref) {
+        services.contentPrefs.removePref(
+            this.uri, pref, sanitizer.getContext(this.win));
+    },
+
     climbUrlPath: function climbUrlPath(count) {
         let { dactyl } = this.modules;
 
@@ -234,8 +275,8 @@ var Buffer = Module("Buffer", {
         })(win || this.win);
 
         if (focusedFirst)
-            return frames.filter(function (f) f === this.focusedFrame).concat(
-                   frames.filter(function (f) f !== this.focusedFrame));
+            return frames.filter(function (f) f === this.focusedFrame, this).concat(
+                   frames.filter(function (f) f !== this.focusedFrame, this));
         return frames;
     },
 
@@ -574,6 +615,31 @@ var Buffer = Module("Buffer", {
      */
     get selectionController() util.selectionController(this.focusedFrame),
 
+    /**
+     * @property {string|null} The canonical short URL for the current
+     *      document.
+     */
+    get shortURL() {
+        let { uri, doc } = this;
+
+        for each (let shortener in Buffer.uriShorteners)
+            try {
+                let shortened = shortener(uri, doc);
+                if (shortened)
+                    return shortened.spec;
+            }
+            catch (e) {
+                util.reportError(e);
+            }
+
+        let link = DOM("link[href][rev=canonical], \
+                        link[href][rel=shortlink]", doc);
+        if (link)
+            return link.attr("href");
+
+        return null;
+    },
+
     /**
      * Opens the appropriate context menu for *elem*.
      *
@@ -585,8 +651,9 @@ var Buffer = Module("Buffer", {
      * Saves a page link to disk.
      *
      * @param {HTMLAnchorElement} elem The page link to save.
+     * @param {boolean} overwrite If true, overwrite any existing file.
      */
-    saveLink: function saveLink(elem) {
+    saveLink: function saveLink(elem, overwrite) {
         let { completion, dactyl, io } = this.modules;
 
         let self = this;
@@ -604,6 +671,8 @@ var Buffer = Module("Buffer", {
                     if (file.exists() && file.isDirectory())
                         file.append(Buffer.getDefaultNames(elem)[0][0]);
 
+                    util.assert(!file.exists() || overwrite, _("io.existsNoOverride", file.path));
+
                     try {
                         if (!file.exists())
                             file.create(File.NORMAL_FILE_TYPE, octal(644));
@@ -612,7 +681,7 @@ var Buffer = Module("Buffer", {
                         util.assert(false, _("save.invalidDestination", e.name));
                     }
 
-                    self.saveURI(uri, file);
+                    self.saveURI({ uri: uri, file: file, context: elem });
                 },
 
                 completer: function (context) completion.savePage(context, elem)
@@ -629,24 +698,33 @@ var Buffer = Module("Buffer", {
      * @param {nsIURI} uri The URI to save
      * @param {nsIFile} file The file into which to write the result.
      */
-    saveURI: function saveURI(uri, file, callback, self) {
+    saveURI: function saveURI(params) {
+        if (params instanceof Ci.nsIURI)
+            // Deprecated?
+            params = { uri: arguments[0], file: arguments[1],
+                       callback: arguments[2], self: arguments[3] };
+
         var persist = services.Persist();
         persist.persistFlags = persist.PERSIST_FLAGS_FROM_CACHE
                              | persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
 
         let window = this.topWindow;
+        let privacy = sanitizer.getContext(params.context || this.win);
+        let file = File(params.file);
         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));
+                services.Transfer(params.uri, file.URI, "", null, null, null,
+                                  persist, privacy && privacy.usePrivateBrowsing));
 
+        var { callback, self } = params;
         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);
+                        util.trapErrors(callback, self, params.uri, file.file,
+                                        progress, request, flags, status);
 
                     return onStateChange.superapply(this, arguments);
                 })
@@ -654,7 +732,8 @@ var Buffer = Module("Buffer", {
         else
             persist.progressListener = downloadListener;
 
-        persist.saveURI(uri, null, null, null, null, file);
+        persist.saveURI(params.uri, null, null, null, null,
+                        file.file, privacy);
     },
 
     /**
@@ -748,8 +827,26 @@ var Buffer = Module("Buffer", {
             var sel = this.focusedFrame.getSelection();
         }
         catch (e) {}
+
         if (!elem && sel && sel.rangeCount)
             elem = sel.getRangeAt(0).startContainer;
+
+        if (!elem) {
+            let area = -1;
+            for (let e in DOM(Buffer.SCROLLABLE_SEARCH_SELECTOR,
+                              this.focusedFrame.document)) {
+                if (Buffer.isScrollable(e, dir, horizontal)) {
+                    let r = DOM(e).rect;
+                    let a = r.width * r.height;
+                    if (a > area) {
+                        area = a;
+                        elem = e;
+                    }
+                }
+            }
+            if (elem)
+                util.trapErrors("focus", elem);
+        }
         if (elem)
             elem = find(elem);
 
@@ -865,14 +962,14 @@ var Buffer = Module("Buffer", {
 
         // add the frame indicator
         let doc = frames[next].document;
-        let indicator = DOM(<div highlight="FrameIndicator"/>, doc)
+        let indicator = DOM(["div", { highlight: "FrameIndicator" }], doc)
                             .appendTo(doc.body || doc.documentElement || doc);
 
         util.timeout(function () { indicator.remove(); }, 500);
 
         // Doesn't unattach
-        //doc.body.setAttributeNS(NS.uri, "activeframe", "true");
-        //util.timeout(function () { doc.body.removeAttributeNS(NS.uri, "activeframe"); }, 500);
+        //doc.body.setAttributeNS(NS, "activeframe", "true");
+        //util.timeout(function () { doc.body.removeAttributeNS(NS, "activeframe"); }, 500);
     },
 
     // similar to pageInfo
@@ -885,8 +982,7 @@ var Buffer = Module("Buffer", {
     showElementInfo: function showElementInfo(elem) {
         let { dactyl } = this.modules;
 
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        dactyl.echo(<><!--L-->Element:<br/>{util.objectToString(elem, true)}</>);
+        dactyl.echo(["", /*L*/"Element:", ["br"], util.objectToString(elem, true)]);
     },
 
     /**
@@ -910,12 +1006,12 @@ var Buffer = Module("Buffer", {
                 (sections || options["pageinfo"])
                     .map(function (opt) Buffer.pageInfo[opt].action.call(self)),
                 function (res) res && iter(res).join(", ") || undefined,
-                ", ");
+                ", ").join("");
 
             if (bookmarkcache.isBookmarked(this.URL))
                 info += ", " + _("buffer.bookmarked");
 
-            let pageInfoText = <>{file.quote()} [{info}] {title}</>;
+            let pageInfoText = [file.quote(), " [", info, "] ", title].join("");
             dactyl.echo(pageInfoText, commandline.FORCE_SINGLELINE);
             return;
         }
@@ -923,7 +1019,7 @@ var Buffer = Module("Buffer", {
         let list = template.map(sections || options["pageinfo"], function (option) {
             let { action, title } = Buffer.pageInfo[option];
             return template.table(title, action.call(self, true));
-        }, <br/>);
+        }, ["br"]);
 
         commandline.commandOutput(list);
     },
@@ -1037,7 +1133,15 @@ var Buffer = Module("Buffer", {
                     return true;
                 };
 
-            let uri = isString(doc) ? util.newURI(doc) : util.newURI(doc.location.href);
+            if (isString(doc)) {
+                var privacyContext = null;
+                var uri = util.newURI(doc);
+            }
+            else {
+                privacyContext = sanitizer.getContext(doc);
+                uri = util.newURI(doc.location.href);
+            }
+
             let ext = uri.fileExtension || "txt";
             if (doc.contentType)
                 ext = services.mime.getPrimaryExtension(doc.contentType, ext);
@@ -1058,7 +1162,8 @@ var Buffer = Module("Buffer", {
                 var persist = services.Persist();
                 persist.persistFlags = persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
                 persist.progressListener = this;
-                persist.saveURI(uri, null, null, null, null, this.file);
+                persist.saveURI(uri, null, null, null, null, this.file,
+                                privacyContext);
             }
             return null;
         },
@@ -1110,7 +1215,7 @@ var Buffer = Module("Buffer", {
      *   closed range [Buffer.ZOOM_MIN, Buffer.ZOOM_MAX].
      */
     setZoom: function setZoom(value, fullZoom) {
-        let { dactyl, statusline } = this.modules;
+        let { dactyl, statusline, storage } = this.modules;
         let { ZoomManager } = this;
 
         if (fullZoom === undefined)
@@ -1127,12 +1232,16 @@ var Buffer = Module("Buffer", {
             return dactyl.echoerr(_("zoom.illegal"));
         }
 
-        if (services.has("contentPrefs") && !storage.privateMode
-                && prefs.get("browser.zoom.siteSpecific")) {
-            services.contentPrefs[value != 1 ? "setPref" : "removePref"]
-                (this.uri, "browser.content.full-zoom", value);
-            services.contentPrefs[value != 1 ? "setPref" : "removePref"]
-                (this.uri, "dactyl.content.full-zoom", fullZoom);
+        if (prefs.get("browser.zoom.siteSpecific")) {
+            var privacy = sanitizer.getContext(this.win);
+            if (value == 1) {
+                this.clearPref("browser.content.full-zoom");
+                this.clearPref("dactyl.content.full-zoom");
+            }
+            else {
+                this.setPref("browser.content.full-zoom", value);
+                this.setPref("dactyl.content.full-zoom", fullZoom);
+            }
         }
 
         statusline.updateZoomLevel();
@@ -1145,12 +1254,13 @@ var Buffer = Module("Buffer", {
         let self = this;
         let uri = this.uri;
 
-        if (services.has("contentPrefs") && prefs.get("browser.zoom.siteSpecific"))
-            services.contentPrefs.getPref(uri, "dactyl.content.full-zoom", function (val) {
+        if (prefs.get("browser.zoom.siteSpecific")) {
+            this.getPref("dactyl.content.full-zoom", function (val) {
                 if (val != null && uri.equals(self.uri) && val != prefs.get("browser.zoom.full"))
                     [self.contentViewer.textZoom, self.contentViewer.fullZoom] =
                         [self.contentViewer.fullZoom, self.contentViewer.textZoom];
             });
+        }
     }),
 
     /**
@@ -1191,6 +1301,12 @@ var Buffer = Module("Buffer", {
     scrollTo: deprecated("Buffer.scrollTo", function scrollTo(x, y) this.win.scrollTo(x, y)),
     textZoom: deprecated("buffer.zoomValue/buffer.fullZoom", function textZoom() this.contentViewer.markupDocumentViewer.textZoom * 100)
 }, {
+    /**
+     * The pattern used to search for a scrollable element when we have
+     * no starting point.
+     */
+    SCROLLABLE_SEARCH_SELECTOR: "html, body, div",
+
     PageInfo: Struct("PageInfo", "name", "title", "action")
                         .localize("title"),
 
@@ -1209,6 +1325,27 @@ var Buffer = Module("Buffer", {
         this.pageInfo[option] = Buffer.PageInfo(option, title, func);
     },
 
+    uriShorteners: [],
+
+    /**
+     * Adds a new URI shortener for documents matching the given filter.
+     *
+     * @param {string|function(URI, Document):boolean} filter A site filter
+     *      string or a function which accepts a URI and a document and
+     *      returns true if it can shorten the document's URI.
+     * @param {function(URI, Document):URI} shortener Returns a shortened
+     *      URL for the given URI and document.
+     */
+    addURIShortener: function addURIShortener(filter, shortener) {
+        if (isString(filter))
+            filter = Group.compileFilter(filter);
+
+        this.uriShorteners.push(function uriShortener(uri, doc) {
+            if (filter(uri, doc))
+                return shortener(uri, doc);
+        });
+    },
+
     Scrollable: function Scrollable(elem) {
         if (elem instanceof Ci.nsIDOMElement)
             return elem;
@@ -1224,6 +1361,9 @@ var Buffer = Module("Buffer", {
                 get scrollWidth() this.win.scrollMaxX + this.win.innerWidth,
                 get scrollHeight() this.win.scrollMaxY + this.win.innerHeight,
 
+                get scrollLeftMax() this.win.scrollMaxX,
+                get scrollRightMax() this.win.scrollMaxY,
+
                 get scrollLeft() this.win.scrollX,
                 set scrollLeft(val) { this.win.scrollTo(val, this.win.scrollY) },
 
@@ -1321,23 +1461,30 @@ var Buffer = Module("Buffer", {
     },
 
     canScroll: function canScroll(elem, dir, horizontal) {
-        let pos = "scrollTop", size = "clientHeight", max = "scrollHeight", layoutSize = "offsetHeight",
+        let pos = "scrollTop", size = "clientHeight", end = "scrollHeight", layoutSize = "offsetHeight",
             overflow = "overflowX", border1 = "borderTopWidth", border2 = "borderBottomWidth";
         if (horizontal)
-            pos = "scrollLeft", size = "clientWidth", max = "scrollWidth", layoutSize = "offsetWidth",
+            pos = "scrollLeft", size = "clientWidth", end = "scrollWidth", layoutSize = "offsetWidth",
             overflow = "overflowX", border1 = "borderLeftWidth", border2 = "borderRightWidth";
 
+        if (dir < 0)
+            return elem[pos] > 0;
+
+        let max = pos + "Max";
+        if (max in elem && pos > 0)
+            return elem[pos] < elem[max];
+
         let style = DOM(elem).style;
         let borderSize = Math.round(parseFloat(style[border1]) + parseFloat(style[border2]));
         let realSize = elem[size];
 
         // Stupid Gecko eccentricities. May fail for quirks mode documents.
-        if (elem[size] + borderSize == elem[max] || elem[size] == 0) // Stupid, fallible heuristic.
+        if (elem[size] + borderSize >= elem[end] || elem[size] == 0) // Stupid, fallible heuristic.
             return false;
 
         if (style[overflow] == "hidden")
             realSize += borderSize;
-        return dir < 0 && elem[pos] > 0 || dir > 0 && elem[pos] + realSize < elem[max] || !dir && realSize < elem[max];
+        return dir > 0 && elem[pos] + realSize < elem[end] || !dir && realSize < elem[end];
     },
 
     /**
@@ -1444,7 +1591,7 @@ var Buffer = Module("Buffer", {
     /**
      * Scrolls the given element vertically.
      *
-     * @param {Element} elem The element to scroll.
+     * @param {Node} node The node to scroll.
      * @param {string} unit The increment by which to scroll.
      *   Possible values are: "lines", "pages"
      * @param {number} number The possibly fractional number of
@@ -1530,7 +1677,7 @@ var Buffer = Module("Buffer", {
 
     _exWidth: function _exWidth(elem) {
         try {
-            let div = DOM(<elem style="width: 1ex !important; position: absolute !important; padding: 0 !important; display: block;"/>,
+            let div = DOM(["elem", { style: "width: 1ex !important; position: absolute !important; padding: 0 !important; display: block;" }],
                           elem.ownerDocument).appendTo(elem.body || elem);
             try {
                 return parseFloat(div.style.width);
@@ -1690,7 +1837,7 @@ var Buffer = Module("Buffer", {
                             function (file) {
                                 let output = io.system(filename.substr(1), file);
                                 commandline.command = command;
-                                commandline.commandOutput(<span highlight="CmdOutput">{output}</span>);
+                                commandline.commandOutput(["span", { highlight: "CmdOutput" }, output]);
                             });
 
                     if (/^>>/.test(filename)) {
@@ -1716,7 +1863,7 @@ var Buffer = Module("Buffer", {
 
                     dactyl.assert(args.bang || !file.exists(), _("io.exists"));
 
-                    chosenData = { file: file, uri: util.newURI(doc.location.href) };
+                    chosenData = { file: file.file, uri: util.newURI(doc.location.href) };
                 }
 
                 // if browser.download.useDownloadDir = false then the "Save As"
@@ -1734,7 +1881,7 @@ var Buffer = Module("Buffer", {
                 window.internalSave(doc.location.href, doc, null, contentDisposition,
                                     doc.contentType, false, null, chosenData,
                                     doc.referrer ? window.makeURI(doc.referrer) : null,
-                                    true);
+                                    doc, true);
             },
             {
                 argCount: "?",
@@ -1854,8 +2001,7 @@ var Buffer = Module("Buffer", {
                     uri.query = uri.query.replace(/(?:^|&)utm_[^&]+/g, "")
                                          .replace(/^&/, "");
 
-                let link = DOM("link[href][rev=canonical], link[href][rel=shortlink]", doc);
-                let url = link.length && options.get("yankshort").getKey(uri) ? link.attr("href") : uri.spec;
+                let url = options.get("yankshort").getKey(uri) && buffer.shortURL || uri.spec;
                 dactyl.clipboardWrite(url, true);
             });
 
@@ -1907,7 +2053,7 @@ var Buffer = Module("Buffer", {
             function (args) { buffer.scrollVertical("lines", -Math.max(args.count, 1)); },
             { count: true });
 
-        mappings.add([modes.COMMAND], dactyl.has("mail") ? ["h", "<scroll-left-column>"] : ["h", "<Left>", "<scroll-left-column>"],
+        mappings.add([modes.NORMAL], dactyl.has("mail") ? ["h", "<scroll-left-column>"] : ["h", "<Left>", "<scroll-left-column>"],
             "Scroll document to the left",
             function (args) { buffer.scrollHorizontal("columns", -Math.max(args.count, 1)); },
             { count: true });
@@ -2369,9 +2515,9 @@ Buffer.addPageInfoSection("e", "Search Engines", function (verbose) {
         if (verbose)
             for (let link in engines)
                 yield [link.title || /*L*/ "Engine " + n++,
-                       <a xmlns={XHTML} href={link.href}
-                          onclick="if (event.button == 0) { window.external.AddSearchProvider(this.href); return false; }"
-                          highlight="URL">{link.href}</a>];
+                       ["a", { href: link.href, highlight: "URL",
+                               onclick: "if (event.button == 0) { window.external.AddSearchProvider(this.href); return false; }" },
+                            link.href]];
     }
 
     if (!verbose && nEngines)
@@ -2427,7 +2573,8 @@ Buffer.addPageInfoSection("f", "Feeds", function (verbose) {
                 nFeed++;
                 let type = feedTypes[feed.type] || "RSS";
                 if (verbose)
-                    yield [feed.title, template.highlightURL(feed.href, true) + <span class="extra-info">&#xa0;({type})</span>];
+                    yield [feed.title, [template.highlightURL(feed.href, true),
+                                        ["span", { class: "extra-info" }, " (" + type + ")"]]];
             }
         }
 
@@ -2477,6 +2624,10 @@ Buffer.addPageInfoSection("g", "General Info", function (verbose) {
     yield ["Title", doc.title];
     yield ["URL", template.highlightURL(doc.location.href, true)];
 
+    let { shortURL } = this;
+    if (shortURL)
+        yield ["Short URL", template.highlightURL(shortURL, true)];
+
     let ref = "referrer" in doc && doc.referrer;
     if (ref)
         yield ["Referrer", template.highlightURL(ref, true)];
@@ -2499,7 +2650,8 @@ Buffer.addPageInfoSection("m", "Meta Tags", function (verbose) {
     // get meta tag data, sort and put into pageMeta[]
     let metaNodes = this.focusedFrame.document.getElementsByTagName("meta");
 
-    return Array.map(metaNodes, function (node) [(node.name || node.httpEquiv), template.highlightURL(node.content)])
+    return Array.map(metaNodes, function (node) [(node.name || node.httpEquiv),
+                                                 template.highlightURL(node.content)])
                 .sort(function (a, b) util.compareIgnoreCase(a[0], b[0]));
 });
 
@@ -2541,7 +2693,7 @@ Buffer.addPageInfoSection("s", "Security", function (verbose) {
     }
 });
 
-} catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
+// catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
 
 endModule();
 
index c24084671c6b1f9dc71af75a93708fec03ad4872..5f39bc6a3264ca2d43f93cf6785598ceed00e152 100644 (file)
@@ -1,14 +1,16 @@
-// Copyright (c) 2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2011-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("cache", {
     exports: ["Cache", "cache"],
     require: ["config", "services", "util"]
-}, this);
+});
+
+lazyRequire("overlay", ["overlay"]);
+lazyRequire("storage", ["File"]);
 
 var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), {
     init: function init() {
@@ -77,7 +79,7 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), {
         if (!this._cacheReader && this.cacheFile.exists()
                 && !this.inQueue)
             try {
-                this._cacheReader = services.ZipReader(this.cacheFile);
+                this._cacheReader = services.ZipReader(this.cacheFile.file);
             }
             catch (e if e.result == Cr.NS_ERROR_FILE_CORRUPTED) {
                 util.reportError(e);
@@ -97,14 +99,14 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), {
                 if (!this.cacheFile.exists())
                     mode |= File.MODE_CREATE;
 
-                cache._cacheWriter = services.ZipWriter(this.cacheFile, mode);
+                cache._cacheWriter = services.ZipWriter(this.cacheFile.file, mode);
             }
             catch (e if e.result == Cr.NS_ERROR_FILE_CORRUPTED) {
                 util.reportError(e);
                 this.cacheFile.remove(false);
 
                 mode |= File.MODE_CREATE;
-                cache._cacheWriter = services.ZipWriter(this.cacheFile, mode);
+                cache._cacheWriter = services.ZipWriter(this.cacheFile.file, mode);
             }
         return this._cacheWriter;
     },
@@ -116,7 +118,7 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), {
         }
     },
 
-    closeWriter: function closeWriter() {
+    closeWriter: util.wrapCallback(function closeWriter() {
         this.closeReader();
 
         if (this._cacheWriter) {
@@ -127,7 +129,7 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), {
             if (this.cacheFile.fileSize <= 22)
                 this.cacheFile.remove(false);
         }
-    },
+    }),
 
     flush: function flush() {
         cache.cache = {};
@@ -157,7 +159,7 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), {
     },
 
     flushJAR: function flushJAR(file) {
-        services.observer.notifyObservers(file, "flush-cache-entry", "");
+        services.observer.notifyObservers(File(file).file, "flush-cache-entry", "");
     },
 
     flushStartup: function flushStartup() {
@@ -200,8 +202,12 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), {
             return cache.force(name);
     },
 
-    get: function get(name) {
+    get: function get(name, callback, self) {
         if (!Set.has(this.cache, name)) {
+            if (callback && !(Set.has(this.providers, name) ||
+                              Set.has(this.localProviders, name)))
+                this.register(name, callback, self);
+
             this.cache[name] = this.force(name);
             util.assert(this.cache[name] !== undefined,
                         "No such cache key", false);
@@ -228,11 +234,14 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), {
 
         if (this.queue.length && !this.inQueue) {
             // removeEntry does not work properly with queues.
+            let removed = 0;
             for each (let [, entry] in this.queue)
                 if (this.getCacheWriter().hasEntry(entry)) {
                     this.getCacheWriter().removeEntry(entry, false);
-                    this.closeWriter();
+                    removed++;
                 }
+            if (removed)
+                this.closeWriter();
 
             this.queue.splice(0).forEach(function ([time, entry]) {
                 if (time && Set.has(this.cache, entry)) {
index eca375bfd65d502493183bbd545ff34a871f07ce..199cfff13eca5e0b999b0a74c6d1a77504d36661 100644 (file)
@@ -1,18 +1,21 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("commands", {
     exports: ["ArgType", "Command", "Commands", "CommandOption", "Ex", "commands"],
     require: ["contexts", "messages", "util"]
-}, this);
+});
+
+lazyRequire("help", ["help"]);
+lazyRequire("options", ["Option"]);
+lazyRequire("template", ["template"]);
 
 /**
  * A structure representing the options available for a command.
@@ -106,6 +109,7 @@ update(CommandOption, {
  * @param {function} action The action invoked by this command when executed.
  * @param {Object} extraInfo An optional extra configuration hash. The
  *     following properties are supported.
+ *         always      - see {@link Command#always}
  *         argCount    - see {@link Command#argCount}
  *         bang        - see {@link Command#bang}
  *         completer   - see {@link Command#completer}
@@ -240,28 +244,41 @@ var Command = Class("Command", {
      * @property {function (Args)} The function called to execute this command.
      */
     action: null,
+
+    /**
+     * @property {function (Args)} A function which is called when this
+     * command is encountered, even if we are ignoring commands. Used to
+     * implement control structures.
+     */
+    always: null,
+
     /**
      * @property {string} This command's argument count spec.
      * @see Commands#parseArguments
      */
     argCount: 0,
+
     /**
      * @property {function (CompletionContext, Args)} This command's completer.
      * @see CompletionContext
      */
     completer: null,
+
     /** @property {boolean} Whether this command accepts a here document. */
     hereDoc: false,
+
     /**
      * @property {boolean} Whether this command may be called with a bang,
      *     e.g., :com!
      */
     bang: false,
+
     /**
      * @property {boolean} Whether this command may be called with a count,
      *     e.g., :12bdel
      */
     count: false,
+
     /**
      * @property {function(args)} A function which should return a list
      *     of domains referenced in the given args. Used in determining
@@ -269,6 +286,7 @@ var Command = Class("Command", {
      *     private data.
      */
     domains: function (args) [],
+
     /**
      * @property {boolean} At what index this command's literal arguments
      *     begin. For instance, with a value of 2, all arguments starting with
@@ -277,6 +295,7 @@ var Command = Class("Command", {
      *     key mappings or Ex command lines as arguments.
      */
     literal: null,
+
     /**
      * @property {Array} The options this command takes.
      * @see Commands@parseArguments
@@ -485,7 +504,7 @@ var CommandHive = Class("CommandHive", Contexts.Hive, {
         let { cache } = this.modules;
         this.cached = true;
 
-        cache.register(this.cacheKey, function () {
+        let cached = cache.get(this.cacheKey, function () {
             self.cached = false;
             this.modules.moduleManager.initDependencies("commands");
 
@@ -750,38 +769,34 @@ var Commands = Module("commands", {
 
             let hives = (hives || this.userHives).map(function (h) [h, cmds(h)]).filter(function ([h, c]) c.length);
 
-            let list = <table>
-                <tr highlight="Title">
-                    <td/>
-                    <td style="padding-right: 1em;"></td>
-                    <td style="padding-right: 1ex;">{_("title.Name")}</td>
-                    <td style="padding-right: 1ex;">{_("title.Args")}</td>
-                    <td style="padding-right: 1ex;">{_("title.Range")}</td>
-                    <td style="padding-right: 1ex;">{_("title.Complete")}</td>
-                    <td style="padding-right: 1ex;">{_("title.Definition")}</td>
-                </tr>
-                <col style="min-width: 6em; padding-right: 1em;"/>
-                {
-                    template.map(hives, function ([hive, cmds]) let (i = 0)
-                        <tr style="height: .5ex;"/> +
-                        template.map(cmds, function (cmd)
-                            <tr>
-                                <td highlight="Title">{!i++ ? hive.name : ""}</td>
-                                <td>{cmd.bang ? "!" : " "}</td>
-                                <td>{cmd.name}</td>
-                                <td>{cmd.argCount}</td>
-                                <td>{cmd.count ? "0c" : ""}</td>
-                                <td>{completerToString(cmd.completer)}</td>
-                                <td>{cmd.replacementText || "function () { ... }"}</td>
-                            </tr>) +
-                        <tr style="height: .5ex;"/>)
-                }
-            </table>;
-
-            if (list.*.length() === list.text().length() + 2)
-                dactyl.echomsg(_("command.none"));
-            else
-                commandline.commandOutput(list);
+            let list = ["table", {},
+                ["tr", { highlight: "Title" },
+                    ["td"],
+                    ["td", { style: "padding-right: 1em;" }],
+                    ["td", { style: "padding-right: 1ex;" }, _("title.Name")],
+                    ["td", { style: "padding-right: 1ex;" }, _("title.Args")],
+                    ["td", { style: "padding-right: 1ex;" }, _("title.Range")],
+                    ["td", { style: "padding-right: 1ex;" }, _("title.Complete")],
+                    ["td", { style: "padding-right: 1ex;" }, _("title.Definition")]],
+                ["col", { style: "min-width: 6em; padding-right: 1em;" }],
+                hives.map(function ([hive, cmds]) let (i = 0) [
+                    ["tr", { style: "height: .5ex;" }],
+                    cmds.map(function (cmd)
+                        ["tr", {},
+                            ["td", { highlight: "Title" }, !i++ ? hive.name : ""],
+                            ["td", {}, cmd.bang ? "!" : " "],
+                            ["td", {}, cmd.name],
+                            ["td", {}, cmd.argCount],
+                            ["td", {}, cmd.count ? "0c" : ""],
+                            ["td", {}, completerToString(cmd.completer)],
+                            ["td", {}, cmd.replacementText || "function () { ... }"]]),
+                    ["tr", { style: "height: .5ex;" }]])];
+
+            // E4X-FIXME
+            // if (list.*.length() === list.text().length() + 2)
+            //     dactyl.echomsg(_("command.none"));
+            // else
+            commandline.commandOutput(list);
         }
     }),
 
@@ -900,7 +915,8 @@ var Commands = Module("commands", {
     hasPrivateData: function hasPrivateData(command) {
         for (let [cmd, args] in this.subCommands(command))
             if (cmd.privateData)
-                return !callable(cmd.privateData) || cmd.privateData(args);
+                return !callable(cmd.privateData) ? cmd.privateData
+                                                  : cmd.privateData(args);
         return false;
     },
 
@@ -1226,14 +1242,14 @@ var Commands = Module("commands", {
         }
     },
 
-    nameRegexp: util.regexp(<![CDATA[
+    nameRegexp: util.regexp(literal(/*
             [^
                 0-9
                 <forbid>
             ]
             [^ <forbid> ]*
-        ]]>, "gx", {
-        forbid: util.regexp(String.replace(<![CDATA[
+        */), "gx", {
+        forbid: util.regexp(String.replace(literal(/*
             U0000-U002c // U002d -
             U002e-U002f
             U003a-U0040 // U0041-U005a a-z
@@ -1256,12 +1272,12 @@ var Commands = Module("commands", {
             Ufe70-Ufeff // Arabic Presentation Forms-B
             Uff00-Uffef // Halfwidth and Fullwidth Forms
             Ufff0-Uffff // Specials
-        ]]>, /U/g, "\\u"), "x")
+        */), /U/g, "\\u"), "x")
     }),
 
     validName: Class.Memoize(function validName() util.regexp("^" + this.nameRegexp.source + "$")),
 
-    commandRegexp: Class.Memoize(function commandRegexp() util.regexp(<![CDATA[
+    commandRegexp: Class.Memoize(function commandRegexp() util.regexp(literal(/*
             ^
             (?P<spec>
                 (?P<prespace> [:\s]*)
@@ -1276,7 +1292,7 @@ var Commands = Module("commands", {
                 (?:. | \n)*?
             )?
             $
-        ]]>, "x", {
+        */), "x", {
             name: this.nameRegexp
         })),
 
@@ -1705,7 +1721,8 @@ var Commands = Module("commands", {
             iterate: function (args) commands.iterator().map(function (cmd) ({
                 __proto__: cmd,
                 columns: [
-                    cmd.hive == commands.builtin ? "" : <span highlight="Object" style="padding-right: 1em;">{cmd.hive.name}</span>
+                    cmd.hive == commands.builtin ? "" : ["span", { highlight: "Object", style: "padding-right: 1em;" },
+                                                            cmd.hive.name]
                 ]
             })),
             iterateIndex: function (args) let (tags = help.tags)
@@ -1760,39 +1777,37 @@ var Commands = Module("commands", {
     }
 });
 
-(function () {
-
-    Commands.quoteMap = {
-        "\n": "\\n",
-        "\t": "\\t",
-    };
-    function quote(q, list, map) {
-        map = map || Commands.quoteMap;
-        let re = RegExp("[" + list + "]", "g");
-        function quote(str) q + String.replace(str, re, function ($0) $0 in map ? map[$0] : ("\\" + $0)) + q;
-        quote.list = list;
-        return quote;
-    };
-
-    Commands.quoteArg = {
-        '"': quote('"', '\n\t"\\\\'),
-        "'": quote("'", "'", { "'": "''" }),
-        "":  quote("",  "|\\\\\\s'\"")
-    };
-    Commands.complQuote = {
-        '"': ['"', quote("", Commands.quoteArg['"'].list), '"'],
-        "'": ["'", quote("", Commands.quoteArg["'"].list), "'"],
-        "":  ["", Commands.quoteArg[""], ""]
-    };
-
-    Commands.parseBool = function (arg) {
-        if (/^(true|1|on)$/i.test(arg))
-            return true;
-        if (/^(false|0|off)$/i.test(arg))
-            return false;
-        return NaN;
-    };
-})();
+let quote = function quote(q, list, map) {
+    map = map || Commands.quoteMap;
+    let re = RegExp("[" + list + "]", "g");
+    function quote(str) q + String.replace(str, re, function ($0) $0 in map ? map[$0] : ("\\" + $0)) + q;
+    quote.list = list;
+    return quote;
+};
+
+Commands.quoteMap = {
+    "\n": "\\n",
+    "\t": "\\t",
+};
+
+Commands.quoteArg = {
+    '"': quote('"', '\n\t"\\\\'),
+    "'": quote("'", "'", { "'": "''" }),
+    "":  quote("",  "|\\\\\\s'\"")
+};
+Commands.complQuote = {
+    '"': ['"', quote("", Commands.quoteArg['"'].list), '"'],
+    "'": ["'", quote("", Commands.quoteArg["'"].list), "'"],
+    "":  ["", Commands.quoteArg[""], ""]
+};
+
+Commands.parseBool = function (arg) {
+    if (/^(true|1|on)$/i.test(arg))
+        return true;
+    if (/^(false|0|off)$/i.test(arg))
+        return false;
+    return NaN;
+};
 
 endModule();
 
index c44cbb30031fa4363fd29e86ff748a1be9201757..eec3857bbf914d584154414053c8e10838e94fd1 100644 (file)
@@ -1,16 +1,19 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("completion", {
     exports: ["CompletionContext", "Completion", "completion"]
 }, this);
 
+lazyRequire("dom", ["DOM"]);
+lazyRequire("messages", ["_", "messages"]);
+lazyRequire("template", ["template"]);
+
 /**
  * Creates a new completion context.
  *
@@ -30,7 +33,7 @@ defineModule("completion", {
  * @constructor
  */
 var CompletionContext = Class("CompletionContext", {
-    init: function (editor, name, offset) {
+    init: function cc_init(editor, name, offset) {
         if (!name)
             name = "";
 
@@ -57,12 +60,12 @@ var CompletionContext = Class("CompletionContext", {
              */
             self.parent = parent;
 
-            ["filters", "keys", "process", "title", "quote"].forEach(function (key)
+            ["filters", "keys", "process", "title", "quote"].forEach(function fe(key)
                 self[key] = parent[key] && util.cloneObject(parent[key]));
             ["anchored", "compare", "editor", "_filter", "filterFunc", "forceAnchored", "top"].forEach(function (key)
                 self[key] = parent[key]);
 
-            self.__defineGetter__("value", function () this.top.value);
+            self.__defineGetter__("value", function get_value() this.top.value);
 
             self.offset = parent.offset;
             self.advance(offset || 0);
@@ -87,7 +90,7 @@ var CompletionContext = Class("CompletionContext", {
             delete self.ignoreCase;
             if (self != this)
                 return self;
-            ["_caret", "contextList", "maxItems", "onUpdate", "selectionTypes", "tabPressed", "updateAsync", "value"].forEach(function (key) {
+            ["_caret", "contextList", "maxItems", "onUpdate", "selectionTypes", "tabPressed", "updateAsync", "value"].forEach(function fe(key) {
                 self.__defineGetter__(key, function () this.top[key]);
                 self.__defineSetter__(key, function (val) this.top[key] = val);
             });
@@ -105,7 +108,7 @@ var CompletionContext = Class("CompletionContext", {
             this.anchored = true;
             this.forceAnchored = null;
 
-            this.compare = function (a, b) String.localeCompare(a.text, b.text);
+            this.compare = function compare(a, b) String.localeCompare(a.text, b.text);
             /**
              * @property {function} This function is called when we close
              *     a completion window with Esc or Ctrl-c. Usually this callback
@@ -131,10 +134,10 @@ var CompletionContext = Class("CompletionContext", {
              * @default Selects all results which match every predicate in the
              *     {@link #filters} array.
              */
-            this.filterFunc = function (items) {
+            this.filterFunc = function filterFunc(items) {
                     let self = this;
                     return this.filters.
-                        reduce(function (res, filter) res.filter(function (item) filter.call(self, item)),
+                        reduce(function r(res, filter) res.filter(function f(item) filter.call(self, item)),
                                 items);
             };
             /**
@@ -159,7 +162,7 @@ var CompletionContext = Class("CompletionContext", {
              *     changes its completion list. Only called when
              *     {@link #updateAsync} is true.
              */
-            this.onUpdate = function () true;
+            this.onUpdate = function onUpdate() true;
 
             this.runCount = 0;
 
@@ -167,10 +170,12 @@ var CompletionContext = Class("CompletionContext", {
              * @property {CompletionContext} The top-level completion context.
              */
             this.top = this;
-            this.__defineGetter__("incomplete", function () this._incomplete || this.contextList.some(function (c) c.parent && c.incomplete));
-            this.__defineGetter__("waitingForTab", function () this._waitingForTab || this.contextList.some(function (c) c.parent && c.waitingForTab));
-            this.__defineSetter__("incomplete", function (val) { this._incomplete = val; });
-            this.__defineSetter__("waitingForTab", function (val) { this._waitingForTab = val; });
+            this.__defineGetter__("incomplete", function get_incomplete() this._incomplete
+                || this.contextList.some(function (c) c.parent && c.incomplete));
+            this.__defineGetter__("waitingForTab", function get_waitingForTab() this._waitingForTab
+                || this.contextList.some(function (c) c.parent && c.waitingForTab));
+            this.__defineSetter__("incomplete", function get_incomplete(val) { this._incomplete = val; });
+            this.__defineSetter__("waitingForTab", function get_waitingForTab(val) { this._waitingForTab = val; });
             this.reset();
         }
         /**
@@ -203,13 +208,13 @@ var CompletionContext = Class("CompletionContext", {
          * Returns a key, as detailed in {@link #keys}.
          * @function
          */
-        this.getKey = function (item, key) (typeof self.keys[key] == "function") ? self.keys[key].call(this, item.item) :
+        this.getKey = function getKey(item, key) (typeof self.keys[key] == "function") ? self.keys[key].call(this, item.item) :
                 key in self.keys ? item.item[self.keys[key]]
                                  : item.item[key];
         return this;
     },
 
-    __title: Class.Memoize(function () this._title.map(function (s)
+    __title: Class.Memoize(function __title() this._title.map(function (s)
                 typeof s == "string" ? messages.get("completion.title." + s, s)
                                      : s)),
 
@@ -219,7 +224,7 @@ var CompletionContext = Class("CompletionContext", {
     },
     get title() this.__title,
 
-    get activeContexts() this.contextList.filter(function (c) c.items.length),
+    get activeContexts() this.contextList.filter(function f(c) c.items.length),
 
     // Temporary
     /**
@@ -234,12 +239,12 @@ var CompletionContext = Class("CompletionContext", {
         let self = this;
 
         try {
-            let allItems = this.contextList.map(function (context) context.hasItems && context.items.length);
+            let allItems = this.contextList.map(function m(context) context.hasItems && context.items.length);
             if (this.cache.allItems && array.equals(this.cache.allItems, allItems))
                 return this.cache.allItemsResult;
             this.cache.allItems = allItems;
 
-            let minStart = Math.min.apply(Math, this.activeContexts.map(function (c) c.offset));
+            let minStart = Math.min.apply(Math, this.activeContexts.map(function m(c) c.offset));
             if (minStart == Infinity)
                 minStart = 0;
 
@@ -248,10 +253,10 @@ var CompletionContext = Class("CompletionContext", {
 
                 get longestSubstring() self.longestAllSubstring,
 
-                get items() array.flatten(self.activeContexts.map(function (context) {
+                get items() array.flatten(self.activeContexts.map(function m(context) {
                     let prefix = self.value.substring(minStart, context.offset);
 
-                    return context.items.map(function (item) ({
+                    return context.items.map(function m(item) ({
                         text: prefix + item.text,
                         result: prefix + item.result,
                         __proto__: item
@@ -269,17 +274,17 @@ var CompletionContext = Class("CompletionContext", {
     // Temporary
     get allSubstrings() {
         let contexts = this.activeContexts;
-        let minStart = Math.min.apply(Math, contexts.map(function (c) c.offset));
-        let lists = contexts.map(function (context) {
+        let minStart = Math.min.apply(Math, contexts.map(function m(c) c.offset));
+        let lists = contexts.map(function m(context) {
             let prefix = context.value.substring(minStart, context.offset);
-            return context.substrings.map(function (s) prefix + s);
+            return context.substrings.map(function m(s) prefix + s);
         });
 
         /* TODO: Deal with sub-substrings for multiple contexts again.
          * Possibly.
          */
         let substrings = lists.reduce(
-                function (res, list) res.filter(function (str) list.some(function (s) s.substr(0, str.length) == str)),
+                function r(res, list) res.filter(function f(str) list.some(function s_(s) s.substr(0, str.length) == str)),
                 lists.pop());
         if (!substrings) // FIXME: How is this undefined?
             return [];
@@ -287,13 +292,13 @@ var CompletionContext = Class("CompletionContext", {
     },
     // Temporary
     get longestAllSubstring() {
-        return this.allSubstrings.reduce(function (a, b) a.length > b.length ? a : b, "");
+        return this.allSubstrings.reduce(function r(a, b) a.length > b.length ? a : b, "");
     },
 
     get caret() this._caret - this.offset,
     set caret(val) this._caret = val + this.offset,
 
-    get compare() this._compare || function () 0,
+    get compare() this._compare || function compare() 0,
     set compare(val) this._compare = val,
 
     get completions() this._completions || [],
@@ -359,10 +364,10 @@ var CompletionContext = Class("CompletionContext", {
         let res = { highlight: "" };
 
         function result(quote) {
-            yield ["context", function () self];
-            yield ["result", quote ? function () quote[0] + util.trapErrors(1, quote, this.text) + quote[2]
-                                   : function () this.text];
-            yield ["texts", function () Array.concat(this.text)];
+            yield ["context", function p_context() self];
+            yield ["result", quote ? function p_result() quote[0] + util.trapErrors(1, quote, this.text) + quote[2]
+                                   : function p_result() this.text];
+            yield ["texts", function p_texts() Array.concat(this.text)];
         };
 
         for (let i in iter(this.keys, result(this.quote))) {
@@ -372,10 +377,10 @@ var CompletionContext = Class("CompletionContext", {
                 // reference any variables. Don't bother with eval context.
                 v = Function("i", "return i" + v);
             if (typeof v == "function")
-                res.__defineGetter__(k, function () Class.replaceProperty(this, k, v.call(this, this.item, self)));
+                res.__defineGetter__(k, function p_gf() Class.replaceProperty(this, k, v.call(this, this.item, self)));
             else
-                res.__defineGetter__(k, function () Class.replaceProperty(this, k, this.item[v]));
-            res.__defineSetter__(k, function (val) Class.replaceProperty(this, k, val));
+                res.__defineGetter__(k, function p_gp() Class.replaceProperty(this, k, this.item[v]));
+            res.__defineSetter__(k, function p_s(val) Class.replaceProperty(this, k, val));
         }
         return res;
     },
@@ -427,7 +432,7 @@ var CompletionContext = Class("CompletionContext", {
         this.noUpdate = false;
     },
 
-    ignoreCase: Class.Memoize(function () {
+    ignoreCase: Class.Memoize(function M() {
         let mode = this.wildcase;
         if (mode == "match")
             return false;
@@ -480,24 +485,24 @@ var CompletionContext = Class("CompletionContext", {
         // Item matchers
         if (this.ignoreCase)
             this.matchString = this.anchored ?
-                function (filter, str) String.toLowerCase(str).indexOf(filter.toLowerCase()) == 0 :
-                function (filter, str) String.toLowerCase(str).indexOf(filter.toLowerCase()) >= 0;
+                function matchString(filter, str) String.toLowerCase(str).indexOf(filter.toLowerCase()) == 0 :
+                function matchString(filter, str) String.toLowerCase(str).indexOf(filter.toLowerCase()) >= 0;
         else
             this.matchString = this.anchored ?
-                function (filter, str) String.indexOf(str, filter) == 0 :
-                function (filter, str) String.indexOf(str, filter) >= 0;
+                function matchString(filter, str) String.indexOf(str, filter) == 0 :
+                function matchString(filter, str) String.indexOf(str, filter) >= 0;
 
         // Item formatters
         this.processor = Array.slice(this.process);
         if (!this.anchored)
-            this.processor[0] = function (item, text) self.process[0].call(self, item,
+            this.processor[0] = function processor_0(item, text) self.process[0].call(self, item,
                     template.highlightFilter(item.text, self.filter, null, item.isURI));
 
         try {
             // Item prototypes
             if (!this._cache.constructed) {
                 let proto = this.itemPrototype;
-                this._cache.constructed = items.map(function (item) ({ __proto__: proto, item: item }));
+                this._cache.constructed = items.map(function m(item) ({ __proto__: proto, item: item }));
             }
 
             // Filters
@@ -510,7 +515,7 @@ var CompletionContext = Class("CompletionContext", {
                 filtered.sort(this.compare);
                 if (!this.anchored) {
                     let filter = this.filter;
-                    filtered.sort(function (a, b) (b.text.indexOf(filter) == 0) - (a.text.indexOf(filter) == 0));
+                    filtered.sort(function s(a, b) (b.text.indexOf(filter) == 0) - (a.text.indexOf(filter) == 0));
                 }
             }
 
@@ -558,8 +563,8 @@ var CompletionContext = Class("CompletionContext", {
             }
         }
 
-        substrings = items.reduce(function (res, item)
-            res.map(function (substring) {
+        substrings = items.reduce(function r(res, item)
+            res.map(function m(substring) {
                 // A simple binary search to find the longest substring
                 // of the given string which also matches the current
                 // item's text.
@@ -584,7 +589,7 @@ var CompletionContext = Class("CompletionContext", {
 
         let quote = this.quote;
         if (quote)
-            substrings = substrings.map(function (str) quote[0] + quote[1](str));
+            substrings = substrings.map(function m(str) quote[0] + quote[1](str));
         return this._substrings = substrings;
     },
 
@@ -619,7 +624,7 @@ var CompletionContext = Class("CompletionContext", {
      * Calls the {@link #cancel} method of all currently active
      * sub-contexts.
      */
-    cancelAll: function () {
+    cancelAll: function cancelAll() {
         for (let [, context] in Iterator(this.contextList)) {
             if (context.cancel)
                 context.cancel();
@@ -633,7 +638,7 @@ var CompletionContext = Class("CompletionContext", {
      * @param {string} key
      * @param defVal
      */
-    getCache: function (key, defVal) {
+    getCache: function getCache(key, defVal) {
         if (!(key in this.cache))
             this.cache[key] = defVal();
         return this.cache[key];
@@ -644,7 +649,7 @@ var CompletionContext = Class("CompletionContext", {
         let step = start > end ? -1 : 1;
         start = Math.max(0, start || 0);
         end = Math.min(items.length, end ? end : items.length);
-        return iter.map(util.range(start, end, step), function (i) items[i]);
+        return iter.map(util.range(start, end, step), function m(i) items[i]);
     },
 
     getRow: function getRow(idx, doc) {
@@ -652,17 +657,17 @@ var CompletionContext = Class("CompletionContext", {
         if (cache) {
             if (idx in this.items && !(idx in this.cache.rows))
                 try {
-                    cache[idx] = util.xmlToDom(this.createRow(this.items[idx]),
-                                               doc || this.doc);
+                    cache[idx] = DOM.fromJSON(this.createRow(this.items[idx]),
+                                              doc || this.doc);
                 }
                 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>
-                            <li highlight="CompDesc ErrorMsg">{e}&#xa0;</li>
-                        </div>, doc || this.doc);
+                    util.dump(util.prettifyJSON(this.createRow(this.items[idx]), null, true));
+                    cache[idx] = DOM.fromJSON(
+                        ["div", { highlight: "CompItem", style: "white-space: nowrap" },
+                            ["li", { highlight: "CompResult" }, this.text + "\u00a0"],
+                            ["li", { highlight: "CompDesc ErrorMsg" }, e + "\u00a0"]],
+                        doc || this.doc);
                 }
             return cache[idx];
         }
@@ -732,8 +737,8 @@ var CompletionContext = Class("CompletionContext", {
 
         let context = this.fork(name);
         function alias(prop) {
-            context.__defineGetter__(prop, function () self[prop]);
-            context.__defineSetter__(prop, function (val) self[prop] = val);
+            context.__defineGetter__(prop, function get_() self[prop]);
+            context.__defineSetter__(prop, function set_(val) self[prop] = val);
         }
         alias("_cache");
         alias("_completions");
@@ -807,7 +812,7 @@ var CompletionContext = Class("CompletionContext", {
      */
     pushProcessor: function pushProcess(index, func) {
         let next = this.process[index];
-        this.process[index] = function (item, text) func(item, text, next);
+        this.process[index] = function process_(item, text) func(item, text, next);
     },
 
     /**
@@ -821,7 +826,7 @@ var CompletionContext = Class("CompletionContext", {
             throw Error();
 
         this.offset = 0;
-        this.process = [template.icon, function (item, k) k];
+        this.process = [template.icon, function process_1(item, k) k];
         this.filters = [CompletionContext.Filter.text];
         this.tabPressed = false;
         this.title = ["Completions"];
@@ -860,16 +865,17 @@ var CompletionContext = Class("CompletionContext", {
      */
     wait: function wait(timeout, interruptable) {
         this.allItems;
-        return util.waitFor(function () !this.incomplete, this, timeout, interruptable);
+        return util.waitFor(function wf() !this.incomplete, this, timeout, interruptable);
     }
 }, {
     Sort: {
-        number: function (a, b) parseInt(a.text) - parseInt(b.text) || String.localeCompare(a.text, b.text),
+        number: function S_number(a, b) parseInt(a.text) - parseInt(b.text)
+                    || String.localeCompare(a.text, b.text),
         unsorted: null
     },
 
     Filter: {
-        text: function (item) {
+        text: function F_text(item) {
             let text = item.texts;
             for (let [i, str] in Iterator(text)) {
                 if (this.match(String(str))) {
@@ -879,7 +885,7 @@ var CompletionContext = Class("CompletionContext", {
             }
             return false;
         },
-        textDescription: function (item) {
+        textDescription: function F_textDescription(item) {
             return CompletionContext.Filter.text.call(this, item) || this.match(item.description);
         }
     }
@@ -889,12 +895,12 @@ var CompletionContext = Class("CompletionContext", {
  * @instance completion
  */
 var Completion = Module("completion", {
-    init: function () {
+    init: function init() {
     },
 
     get setFunctionCompleter() JavaScript.setCompleter, // Backward compatibility
 
-    Local: function (dactyl, modules, window) ({
+    Local: function Local(dactyl, modules, window) ({
         urlCompleters: {},
 
         get modules() modules,
@@ -907,7 +913,7 @@ var Completion = Module("completion", {
             let res = context.fork.apply(context, ["run", 0, this, name].concat(Array.slice(arguments, 3)));
             if (res) {
                 if (Components.stack.caller.name === "runCompleter") // FIXME
-                    return { items: res.map(function (i) ({ item: i })) };
+                    return { items: res.map(function m(i) ({ item: i })) };
                 context.contexts["/run"].completions = res;
             }
             context.wait(null, true);
@@ -916,7 +922,7 @@ var Completion = Module("completion", {
 
         runCompleter: function runCompleter(name, filter, maxItems) {
             return this._runCompleter.apply(this, Array.slice(arguments))
-                       .items.map(function (i) i.item);
+                       .items.map(function m(i) i.item);
         },
 
         listCompleter: function listCompleter(name, filter, maxItems) {
@@ -928,16 +934,15 @@ var Completion = Module("completion", {
 
             let contexts = context.activeContexts;
             if (!contexts.length)
-                contexts = context.contextList.filter(function (c) c.hasItems).slice(0, 1);
+                contexts = context.contextList.filter(function f(c) c.hasItems).slice(0, 1);
             if (!contexts.length)
                 contexts = context.contextList.slice(-1);
 
             modules.commandline.commandOutput(
-                <div highlight="Completions">
-                    { template.map(contexts, function (context)
-                            template.completionRow(context.title, "CompTitle") +
-                            template.map(context.items, function (item) context.createRow(item), null, 100)) }
-                </div>);
+                ["div", { highlight: "Completions" },
+                    template.map(contexts, function m(context)
+                        [template.completionRow(context.title, "CompTitle"),
+                         template.map(context.items, function m(item) context.createRow(item), null, 100)])]);
         },
     }),
 
@@ -956,7 +961,7 @@ var Completion = Module("completion", {
 
             context.quote = context.quote || ["", util.identity, ""];
             let quote = context.quote[1];
-            context.quote[1] = function (str) quote(str.replace(/!/g, escape));
+            context.quote[1] = function quote_1(str) quote(str.replace(/!/g, escape));
         }
 
         if (this.options["urlseparator"])
@@ -967,9 +972,9 @@ var Completion = Module("completion", {
             context.advance(skip[0].length);
 
         if (/^about:/.test(context.filter))
-            context.fork("about", 6, this, function (context) {
+            context.fork("about", 6, this, function fork_(context) {
                 context.title = ["about:"];
-                context.generate = function () {
+                context.generate = function generate_() {
                     return [[k.substr(services.ABOUT.length), ""]
                             for (k in Cc)
                             if (k.indexOf(services.ABOUT) == 0)];
@@ -980,7 +985,7 @@ var Completion = Module("completion", {
             complete = this.options["complete"];
 
         // Will, and should, throw an error if !(c in opts)
-        Array.forEach(complete, function (c) {
+        Array.forEach(complete, function fe(c) {
             let completer = this.urlCompleters[c] || { args: [], completer: this.autocomplete(c.replace(/^native:/, "")) };
             context.forkapply(c, 0, this, completer.completer, completer.args);
         }, this);
@@ -1013,11 +1018,11 @@ var Completion = Module("completion", {
 
         let words = context.filter.toLowerCase().split(/\s+/g);
         context.hasItems = true;
-        context.completions = context.completions.filter(function ({ url, title })
-            words.every(function (w) (url + " " + title).toLowerCase().indexOf(w) >= 0))
+        context.completions = context.completions.filter(function f({ url, title })
+            words.every(function e(w) (url + " " + title).toLowerCase().indexOf(w) >= 0))
 
         context.format = this.modules.bookmarks.format;
-        context.keys.extra = function (item) {
+        context.keys.extra = function k_extra(item) {
             try {
                 return bookmarkcache.get(item.url).extra;
             }
@@ -1026,7 +1031,7 @@ var Completion = Module("completion", {
         };
         context.title = [_("autocomplete.title", provider)];
 
-        context.cancel = function () {
+        context.cancel = function cancel_() {
             this.incomplete = false;
             if (running[provider])
                 service.stopSearch();
@@ -1053,24 +1058,24 @@ var Completion = Module("completion", {
         }
     }),
 
-    urls: function (context, tags) {
+    urls: function urls(context, tags) {
         let compare = String.localeCompare;
         let contains = String.indexOf;
         if (context.ignoreCase) {
             compare = util.compareIgnoreCase;
-            contains = function (a, b) a && a.toLowerCase().indexOf(b.toLowerCase()) > -1;
+            contains = function contains_(a, b) a && a.toLowerCase().indexOf(b.toLowerCase()) > -1;
         }
 
         if (tags)
-            context.filters.push(function (item) tags.
-                every(function (tag) (item.tags || []).
-                    some(function (t) !compare(tag, t))));
+            context.filters.push(function filter_(item) tags.
+                every(function e(tag) (item.tags || []).
+                    some(function s(t) !compare(tag, t))));
 
         context.anchored = false;
         if (!context.title)
             context.title = ["URL", "Title"];
 
-        context.fork("additional", 0, this, function (context) {
+        context.fork("additional", 0, this, function fork_(context) {
             context.title[0] += " " + _("completion.additional");
             context.filter = context.parent.filter; // FIXME
             context.completions = context.parent.completions;
@@ -1079,20 +1084,20 @@ var Completion = Module("completion", {
             // accept them if all tokens match either the URL or the title.
             // Filter out all directly matching strings.
             let match = context.filters[0];
-            context.filters[0] = function (item) !match.call(this, item);
+            context.filters[0] = function filters_0(item) !match.call(this, item);
 
             // and all that don't match the tokens.
             let tokens = context.filter.split(/\s+/);
-            context.filters.push(function (item) tokens.every(
-                    function (tok) contains(item.url, tok) ||
+            context.filters.push(function filter_(item) tokens.every(
+                    function e(tok) contains(item.url, tok) ||
                                    contains(item.title, tok)));
 
             let re = RegExp(tokens.filter(util.identity).map(util.regexp.escape).join("|"), "g");
             function highlight(item, text, i) process[i].call(this, item, template.highlightRegexp(text, re));
             let process = context.process;
             context.process = [
-                function (item, text) highlight.call(this, item, item.text, 0),
-                function (item, text) highlight.call(this, item, text, 1)
+                function process_0(item, text) highlight.call(this, item, item.text, 0),
+                function process_1(item, text) highlight.call(this, item, text, 1)
             ];
         });
     }
@@ -1112,16 +1117,16 @@ var Completion = Module("completion", {
             get options() this.modules.options
         });
     },
-    commands: function (dactyl, modules, window) {
+    commands: function initCommands(dactyl, modules, window) {
         const { commands, completion } = modules;
         commands.add(["contexts"],
             "List the completion contexts used during completion of an Ex command",
             function (args) {
                 modules.commandline.commandOutput(
-                    <div highlight="Completions">
-                        { template.completionRow(["Context", "Title"], "CompTitle") }
-                        { template.map(completion.contextList || [], function (item) template.completionRow(item, "CompItem")) }
-                    </div>);
+                    ["div", { highlight: "Completions" },
+                        template.completionRow(["Context", "Title"], "CompTitle"),
+                        template.map(completion.contextList || [],
+                                     function m(item) template.completionRow(item, "CompItem"))]);
             },
             {
                 argCount: "*",
@@ -1133,7 +1138,7 @@ var Completion = Module("completion", {
                 literal: 0
             });
     },
-    options: function (dactyl, modules, window) {
+    options: function initOptions(dactyl, modules, window) {
         const { completion, options } = modules;
         let wildmode = {
             values: {
@@ -1151,7 +1156,7 @@ var Completion = Module("completion", {
                 return first == val || second == val;
             },
             has: function () {
-                test = function (val) this.value.some(function (value) this.checkHas(value, val), this);
+                let test = function test(val) this.value.some(function s(value) this.checkHas(value, val), this);
                 return Array.some(arguments, test, this);
             }
         };
@@ -1187,7 +1192,7 @@ var Completion = Module("completion", {
                 setter: function setter(values) {
                     if (values.length == 1 && !Set.has(values[0], this.values)
                             && Array.every(values[0], Set.has(this.valueMap)))
-                        return Array.map(values[0], function (v) this[v], this.valueMap);
+                        return Array.map(values[0], function m(v) this[v], this.valueMap);
                     return values;
                 },
 
index f92ea2258989cf5c8b8518303ce7b96aaf257ec4..305880d3cbd5bdae938f6ad985ca10696892f56a 100644 (file)
@@ -1,25 +1,24 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 let global = this;
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("config", {
     exports: ["ConfigBase", "Config", "config"],
     require: ["dom", "io", "protocol", "services", "util", "template"]
-}, this);
+});
 
-this.lazyRequire("addons", ["AddonManager"]);
-this.lazyRequire("cache", ["cache"]);
-this.lazyRequire("highlight", ["highlight"]);
-this.lazyRequire("messages", ["_"]);
-this.lazyRequire("prefs", ["localPrefs", "prefs"]);
-this.lazyRequire("storage", ["storage", "File"]);
-this.lazyRequire("styles", ["Styles"]);
+lazyRequire("addons", ["AddonManager"]);
+lazyRequire("cache", ["cache"]);
+lazyRequire("highlight", ["highlight"]);
+lazyRequire("messages", ["_"]);
+lazyRequire("prefs", ["localPrefs", "prefs"]);
+lazyRequire("storage", ["storage", "File"]);
+lazyRequire("styles", ["Styles"]);
 
 function AboutHandler() {}
 AboutHandler.prototype = {
@@ -109,6 +108,7 @@ var ConfigBase = Class("ConfigBase", {
         global: ["addons",
                  "base",
                  "io",
+                 ["bookmarkcache", "bookmarkcache"],
                  "buffer",
                  "cache",
                  "commands",
@@ -156,7 +156,7 @@ var ConfigBase = Class("ConfigBase", {
         highlight.loadCSS(this.helpCSS.replace(/__MSG_(.*?)__/g, function (m0, m1) _(m1)));
 
         if (!this.haveGecko("2b"))
-            highlight.loadCSS(<![CDATA[
+            highlight.loadCSS(literal(/*
                 !TabNumber               font-weight: bold; margin: 0px; padding-right: .8ex;
                 !TabIconNumber  {
                     font-weight: bold;
@@ -164,7 +164,7 @@ var ConfigBase = Class("ConfigBase", {
                     text-align: center;
                     text-shadow: black -1px 0 1px, black 0 1px 1px, black 1px 0 1px, black 0 -1px 1px;
                 }
-            ]]>);
+            */));
 
         let hl = highlight.set("Find", "");
         hl.onChange = function () {
@@ -261,7 +261,7 @@ var ConfigBase = Class("ConfigBase", {
             }
         }
         function processJar(file) {
-            let jar = services.ZipReader(file);
+            let jar = services.ZipReader(file.file);
             if (jar)
                 try {
                     if (jar.hasEntry("chrome.manifest"))
@@ -423,9 +423,9 @@ var ConfigBase = Class("ConfigBase", {
         "xmlns.html":   "http://www.w3.org/1999/xhtml",
         "xmlns.xul":    "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
 
-        "tag.command-line": <link topic="command-line">command line</link>,
-        "tag.status-line":  <link topic="status-line">status line</link>,
-        "mode.command-line": <link topic="command-line-mode">Command Line</link>,
+        "tag.command-line": ["link", { xmlns: "dactyl", topic: "command-line" }, "command line"],
+        "tag.status-line":  ["link", { xmlns: "dactyl", topic: "status-line" }, "status line"],
+        "mode.command-line": ["link", { xmlns: "dactyl", topic: "command-line-mode" }, "Command Line"]
     },
 
     dtdStrings: [
@@ -452,21 +452,22 @@ var ConfigBase = Class("ConfigBase", {
         init: function init() {
             this.loadConfig(document.documentURI);
 
-            let append = <e4x xmlns={XUL} xmlns:dactyl={NS}>
-                    <menupopup id="viewSidebarMenu"/>
-                    <broadcasterset id="mainBroadcasterSet"/>
-            </e4x>;
+            let append = [
+                    ["menupopup", { id: "viewSidebarMenu", xmlns: "xul" }],
+                    ["broadcasterset", { id: "mainBroadcasterSet", xmlns: "xul" }]];
+
             for each (let [id, [name, key, uri]] in Iterator(this.sidebars)) {
-                append.XUL::menupopup[0].* +=
-                        <menuitem observes={"pentadactyl-" + id + "Sidebar"} label={name} accesskey={key} xmlns={XUL}/>;
-                append.XUL::broadcasterset[0].* +=
-                        <broadcaster id={"pentadactyl-" + id + "Sidebar"}
-                            autoCheck="false" type="checkbox" group="sidebar"
-                            sidebartitle={name} sidebarurl={uri}
-                            oncommand="toggleSidebar(this.id || this.observes);" xmlns={XUL}/>;
+                append[0].push(
+                        ["menuitem", { observes: "pentadactyl-" + id + "Sidebar", label: name,
+                                       accesskey: key }]);
+                append[1].push(
+                        ["broadcaster", { id: "pentadactyl-" + id + "Sidebar", autoCheck: "false",
+                                          type: "checkbox", group: "sidebar", sidebartitle: name,
+                                          sidebarurl: uri,
+                                          oncommand: "toggleSidebar(this.id || this.observes);" }]);
             }
 
-            util.overlayWindow(window, { append: append.elements() });
+            util.overlayWindow(window, { append: append });
         },
 
         get window() window,
@@ -592,12 +593,14 @@ config.INIT = update(Object.create(config.INIT), config.INIT, {
         let img = window.Image();
         img.src = this.logo || "resource://dactyl-local-content/logo.png";
         img.onload = util.wrapCallback(function () {
-            highlight.loadCSS(<>{"!Logo  {"}
+            highlight.loadCSS(literal(/*
+                !Logo  {
                      display:    inline-block;
-                     background: url({img.src});
-                     width:      {img.width}px;
-                     height:     {img.height}px;
-                 {"}"}</>);
+                     background: url({src});
+                     width:      {width}px;
+                     height:     {height}px;
+                }
+            */).replace(/\{(.*?)\}/g, function (m, m1) img[m1]));
             img = null;
         });
     },
index 6d32fb8358074121eb8a7af5e77263e05f19d8a8..c34d2dded318ad56c02ee56b595b86b86768366c 100644 (file)
@@ -1,16 +1,19 @@
-// Copyright (c) 2010-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2010-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("contexts", {
     exports: ["Contexts", "Group", "contexts"],
     require: ["services", "util"]
-}, this);
+});
 
-this.lazyRequire("overlay", ["overlay"]);
+lazyRequire("commands", ["ArgType", "CommandOption", "commands"]);
+lazyRequire("options", ["Option"]);
+lazyRequire("overlay", ["overlay"]);
+lazyRequire("storage", ["File"]);
+lazyRequire("template", ["template"]);
 
 var Const = function Const(val) Class.Property({ enumerable: true, value: val });
 
@@ -75,10 +78,11 @@ var Group = Class("Group", {
         return update(siteFilter, {
             toString: function () this.filters.join(","),
 
-            toXML: function (modules) let (uri = modules && modules.buffer.uri)
+            toJSONXML: function (modules) let (uri = modules && modules.buffer.uri)
                 template.map(this.filters,
-                             function (f) <span highlight={uri && f(uri) ? "Filter" : ""}>{f}</span>,
-                             <>,</>),
+                             function (f) ["span", { highlight: uri && f(uri) ? "Filter" : "" },
+                                               "toJSONXML" in f ? f.toJSONXML() : String(f)],
+                             ","),
 
             filters: Option.parse.sitelist(patterns)
         });
@@ -374,7 +378,7 @@ var Contexts = Module("contexts", {
            return {
                 __proto__: frame,
                 filename: this.context.file[0] == "[" ? this.context.file
-                                                      : services.io.newFileURI(File(this.context.file)).spec,
+                                                      : File(this.context.file).URI.spec,
                 lineNumber: this.context.line
             };
         return frame;
@@ -480,10 +484,12 @@ var Contexts = Module("contexts", {
     getDocs: function getDocs(context) {
         try {
             if (isinstance(context, ["Sandbox"])) {
-                let info = "INFO" in context && Cu.evalInSandbox("this.INFO instanceof XML && INFO.toXMLString()", context);
-                return info && XML(info);
+                let info = "INFO" in context && Cu.evalInSandbox("this.INFO instanceof XML ? INFO.toXMLString() : this.INFO", context);
+                return /^</.test(info) ? XML(info) : info;
             }
-            if (typeof context.INFO == "xml")
+            if (DOM.isJSONXML(context.INFO))
+                return context.INFO;
+            if (typeof context.INFO == "xml" && config.haveGecko(null, "14.*"))
                 return context.INFO;
         }
         catch (e) {}
@@ -663,12 +669,12 @@ var Contexts = Module("contexts", {
                     {
                         names: ["-description", "-desc", "-d"],
                         description: "A description of this group",
-                        default: ["User-defined group"],
+                        default: "User-defined group",
                         type: CommandOption.STRING
                     },
                     {
                         names: ["-locations", "-locs", "-loc", "-l"],
-                        description: ["The URLs for which this group should be active"],
+                        description: "The URLs for which this group should be active",
                         default: ["*"],
                         type: CommandOption.LIST
                     },
@@ -794,7 +800,7 @@ var Contexts = Module("contexts", {
             context.keys = {
                 active: function (group) group.filter(uri),
                 text: "name",
-                description: function (g) <>{g.filter.toXML ? g.filter.toXML(modules) + <>&#xa0;</> : ""}{g.description || ""}</>
+                description: function (g) ["", g.filter.toJSONXML ? g.filter.toJSONXML(modules).concat("\u00a0") : "", g.description || ""]
             };
             context.completions = (active === undefined ? contexts.groupList : contexts.initializedGroups(active))
                                     .slice(0, -1);
diff --git a/common/modules/dom-e4x.jsm b/common/modules/dom-e4x.jsm
new file mode 100644 (file)
index 0000000..5a1cdfb
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
+//
+// This work is licensed for reuse under an MIT license. Details are
+// given in the LICENSE.txt file included with this file.
+/* use strict */
+
+defineModule("dom", {
+    exports: ["fromXML"]
+});
+
+lazyRequire("highlight", ["highlight"]);
+
+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");
+var NS = Namespace("dactyl", "http://vimperator.org/namespaces/liberator");
+
+function fromXML(node, doc, nodes) {
+    XML.ignoreWhitespace = XML.prettyPrinting = false;
+    if (typeof node === "string") // Sandboxes can't currently pass us XML objects.
+        node = XML(node);
+
+    if (node.length() != 1) {
+        let domnode = doc.createDocumentFragment();
+        for each (let child in node)
+            domnode.appendChild(fromXML(child, doc, nodes));
+        return domnode;
+    }
+
+    switch (node.nodeKind()) {
+    case "text":
+        return doc.createTextNode(String(node));
+    case "element":
+        let domnode = doc.createElementNS(node.namespace(), node.localName());
+
+        for each (let attr in node.@*::*)
+            if (attr.name() != "highlight")
+                domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr));
+
+        for each (let child in node.*::*)
+            domnode.appendChild(fromXML(child, doc, nodes));
+        if (nodes && node.@key)
+            nodes[node.@key] = domnode;
+
+        if ("@highlight" in node)
+            highlight.highlightNode(domnode, String(node.@highlight), nodes || true);
+        return domnode;
+    default:
+        return null;
+    }
+}
+
index 9f7f7e5f9a38bd831e456506876c0c688559688b..7a0c5556fca4791a9c87083e0862435e1e79bc99 100644 (file)
@@ -1,23 +1,23 @@
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("dom", {
     exports: ["$", "DOM", "NS", "XBL", "XHTML", "XUL"]
-}, this);
+});
 
-this.lazyRequire("highlight", ["highlight"]);
-this.lazyRequire("template", ["template"]);
+lazyRequire("highlight", ["highlight"]);
+lazyRequire("messages", ["_"]);
+lazyRequire("prefs", ["prefs"]);
+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");
-var NS = Namespace("dactyl", "http://vimperator.org/namespaces/liberator");
-default xml namespace = XHTML;
+var XBL = "http://www.mozilla.org/xbl";
+var XHTML = "http://www.w3.org/1999/xhtml";
+var XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+var NS = "http://vimperator.org/namespaces/liberator";
 
 function BooleanAttribute(attr) ({
     get: function (elem) elem.getAttribute(attr) == "true",
@@ -56,6 +56,12 @@ var DOM = Class("DOM", {
             ;
         else if (typeof val == "xml" && context instanceof Ci.nsIDOMDocument)
             this[length++] = DOM.fromXML(val, context, this.nodes);
+        else if (DOM.isJSONXML(val)) {
+            if (context instanceof Ci.nsIDOMDocument)
+                this[length++] = DOM.fromJSON(val, context, this.nodes);
+            else
+                this[length++] = val;
+        }
         else if (val instanceof Ci.nsIDOMNode || val instanceof Ci.nsIDOMWindow)
             this[length++] = val;
         else if ("__iterator__" in val || isinstance(val, ["Iterator", "Generator"]))
@@ -111,15 +117,6 @@ var DOM = Class("DOM", {
     },
 
     eachDOM: function eachDOM(val, fn, self) {
-        XML.prettyPrinting = XML.ignoreWhitespace = false;
-        if (isString(val))
-            val = XML(val);
-
-        if (typeof val == "xml")
-            return this.each(function (elem, i) {
-                fn.call(this, DOM.fromXML(val, elem.ownerDocument), elem, i);
-            }, self || this);
-
         let dom = this;
         function munge(val, container, idx) {
             if (val instanceof Ci.nsIDOMRange)
@@ -127,7 +124,7 @@ var DOM = Class("DOM", {
             if (val instanceof Ci.nsIDOMNode)
                 return val;
 
-            if (typeof val == "xml") {
+            if (typeof val == "xml" || DOM.isJSONXML(val)) {
                 val = dom.constructor(val, dom.document);
                 if (container)
                     container[idx] = val[0];
@@ -502,8 +499,15 @@ var DOM = Class("DOM", {
                 if (DOM(elem).isInput
                         || /^(?:hidden|textarea)$/.test(elem.type)
                         || elem.type == "submit" && elem == field
-                        || elem.checked && /^(?:checkbox|radio)$/.test(elem.type))
-                    elems.push(encode(elem.name, elem.value, elem === field));
+                        || elem.checked && /^(?:checkbox|radio)$/.test(elem.type)) {
+
+                    if (elem !== field)
+                        elems.push(encode(elem.name, elem.value));
+                    else if (overlay.getData(elem, "had-focus"))
+                        elems.push(encode(elem.name, elem.value, true));
+                    else
+                        elems.push(encode(elem.name, "", true));
+                }
                 else if (elem instanceof Ci.nsIDOMHTMLSelectElement) {
                     for (let [, opt] in Iterator(elem.options))
                         if (opt.selected)
@@ -557,14 +561,13 @@ var DOM = Class("DOM", {
      *  representation of this node.
      */
     repr: function repr(color) {
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-
         function namespaced(node) {
-            var ns = DOM.namespaceNames[node.namespaceURI] || /^(?:(.*?):)?/.exec(node.name)[0];
+            var ns = DOM.namespaceNames[node.namespaceURI] || /^(?:(.*?):)?/.exec(node.name)[1];
             if (!ns)
                 return node.localName;
             if (color)
-                return <><span highlight="HelpXMLNamespace">{ns}</span>{node.localName}</>
+                return [["span", { highlight: "HelpXMLNamespace" }, ns],
+                        node.localName];
             return ns + ":" + node.localName;
         }
 
@@ -573,20 +576,24 @@ var DOM = Class("DOM", {
             try {
                 let hasChildren = elem.firstChild && (!/^\s*$/.test(elem.firstChild) || elem.firstChild.nextSibling)
                 if (color)
-                    res.push(<span highlight="HelpXML"><span highlight="HelpXMLTagStart">&lt;{
-                            namespaced(elem)} {
-                                template.map(array.iterValues(elem.attributes),
-                                    function (attr)
-                                        <span highlight="HelpXMLAttribute">{namespaced(attr)}</span> +
-                                        <span highlight="HelpXMLString">{attr.value}</span>,
-                                    <> </>)
-                            }{ !hasChildren ? "/>" : ">"
-                        }</span>{ !hasChildren ? "" : <>...</> +
-                            <span highlight="HtmlTagEnd">&lt;{namespaced(elem)}></span>
-                    }</span>);
+                    res.push(["span", { highlight: "HelpXML" },
+                        ["span", { highlight: "HelpXMLTagStart" },
+                            "<", namespaced(elem), " ",
+                            template.map(array.iterValues(elem.attributes),
+                                function (attr) [
+                                    ["span", { highlight: "HelpXMLAttribute" }, namespaced(attr)],
+                                    ["span", { highlight: "HelpXMLString" }, attr.value]
+                                ],
+                                " "),
+                            !hasChildren ? "/>" : ">",
+                        ],
+                        !hasChildren ? "" :
+                            ["", "...",
+                             ["span", { highlight: "HtmlTagEnd" },"<", namespaced(elem), ">"]]
+                    ]);
                 else {
                     let tag = "<" + [namespaced(elem)].concat(
-                        [namespaced(a) + "=" + template.highlight(a.value, true)
+                        [namespaced(a) + '="' + String.replace(a.value, /["<]/, DOM.escapeHTML) + '"'
                          for ([i, a] in array.iterItems(elem.attributes))]).join(" ");
 
                     res.push(tag + (!hasChildren ? "/>" : ">...</" + namespaced(elem) + ">"));
@@ -596,7 +603,8 @@ var DOM = Class("DOM", {
                 res.push({}.toString.call(elem));
             }
         }, this);
-        return template.map(res, util.identity, <>,</>);
+        res = template.map(res, util.identity, ",");
+        return color ? res : res.join("");
     },
 
     attr: function attr(key, val) {
@@ -719,6 +727,15 @@ var DOM = Class("DOM", {
         }, this);
     },
 
+    fragment: function fragment() {
+        let frag = this.document.createDocumentFragment();
+        this.appendTo(frag);
+        return this;
+    },
+
+    clone: function clone(deep)
+        this.map(function (elem) elem.cloneNode(deep)),
+
     toggle: function toggle(val, self) {
         if (callable(val))
             return this.each(function (elem, i) {
@@ -773,7 +790,7 @@ var DOM = Class("DOM", {
     html: function html(txt, self) {
         return this.getSet(arguments,
                            function (elem) elem.innerHTML,
-                           function (elem, val) { elem.innerHTML = val });
+                           util.wrapCallback(function (elem, val) { elem.innerHTML = val }));
     },
 
     text: function text(txt, self) {
@@ -1013,6 +1030,9 @@ var DOM = Class("DOM", {
                 }
 
             for (let [k, v] in Iterator(Ci.nsIDOMKeyEvent)) {
+                if (!/^DOM_VK_/.test(k))
+                    continue;
+
                 this.code_nativeKey[v] = k.substr(4);
 
                 k = k.substr(7).toLowerCase();
@@ -1378,6 +1398,17 @@ var DOM = Class("DOM", {
         ? function (elem, dir) services.dactyl.getScrollable(elem) & (dir ? services.dactyl["DIRECTION_" + dir.toUpperCase()] : ~0)
         : function (elem, dir) true),
 
+    isJSONXML: function isJSONXML(val) isArray(val) && isinstance(val[0], ["String", "Array", "XML", DOM.DOMString])
+                                    || isObject(val) && "toDOM" in val,
+
+    DOMString: function DOMString(val) ({
+        __proto__: DOMString.prototype,
+
+        toDOM: function toDOM(doc) doc.createTextNode(val),
+
+        toString: function () val
+    }),
+
     /**
      * The set of input element type attribute values that mark the element as
      * an editable field.
@@ -1484,11 +1515,14 @@ var DOM = Class("DOM", {
      * entities.
      *
      * @param {string} str
+     * @param {boolean} simple If true, only escape for the simple case
+     *     of text nodes.
      * @returns {string}
      */
-    escapeHTML: function escapeHTML(str) {
+    escapeHTML: function escapeHTML(str, simple) {
         let map = { "'": "&apos;", '"': "&quot;", "%": "&#x25;", "&": "&amp;", "<": "&lt;", ">": "&gt;" };
-        return str.replace(/['"&<>]/g, function (m) map[m]);
+        let regexp = simple ? /[<>]/g : /['"&<>]/g;
+        return str.replace(regexp, function (m) map[m]);
     },
 
     /**
@@ -1502,39 +1536,282 @@ var DOM = Class("DOM", {
      *     stored here, keyed to the value thereof.
      * @returns {Node}
      */
-    fromXML: function fromXML(node, doc, nodes) {
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        if (typeof node === "string") // Sandboxes can't currently pass us XML objects.
-            node = XML(node);
-
-        if (node.length() != 1) {
-            let domnode = doc.createDocumentFragment();
-            for each (let child in node)
-                domnode.appendChild(fromXML(child, doc, nodes));
-            return domnode;
+    fromXML: deprecated("DOM.fromJSON", { get: function fromXML()
+               prefs.get("javascript.options.xml.chrome") !== false
+            && require("dom-e4x").fromXML }),
+
+    fromJSON: update(function fromJSON(xml, doc, nodes, namespaces) {
+        if (!doc)
+            doc = document;
+
+        function tag(args, namespaces) {
+            let _namespaces = namespaces;
+
+            // Deal with common error case
+            if (args == null) {
+                util.reportError(Error("Unexpected null when processing XML."));
+                args = ["html:i", {}, "[NULL]"];
+            }
+
+            if (isinstance(args, ["String", "Number", "Boolean", _]))
+                return doc.createTextNode(args);
+            if (isXML(args))
+                return DOM.fromXML(args, doc, nodes);
+            if (isObject(args) && "toDOM" in args)
+                return args.toDOM(doc, namespaces, nodes);
+            if (args instanceof Ci.nsIDOMNode)
+                return args;
+            if (args instanceof DOM)
+                return args.fragment();
+            if ("toJSONXML" in args)
+                args = args.toJSONXML();
+
+            let [name, attr] = args;
+
+            if (!isString(name) || args.length == 0 || name === "") {
+                var frag = doc.createDocumentFragment();
+                Array.forEach(args, function (arg) {
+                    if (!isArray(arg[0]))
+                        arg = [arg];
+                    arg.forEach(function (arg) {
+                        frag.appendChild(tag(arg, namespaces));
+                    });
+                });
+                return frag;
+            }
+
+            attr = attr || {};
+
+            function parseNamespace(name) DOM.parseNamespace(name, namespaces);
+
+            // FIXME: Surely we can do better.
+            for (var key in attr) {
+                if (/^xmlns(?:$|:)/.test(key)) {
+                    if (_namespaces === namespaces)
+                        namespaces = Object.create(namespaces);
+
+                    namespaces[key.substr(6)] = namespaces[attr[key]] || attr[key];
+                }}
+
+            var args = Array.slice(args, 2);
+            var vals = parseNamespace(name);
+            var elem = doc.createElementNS(vals[0] || namespaces[""],
+                                           name);
+
+            for (var key in attr)
+                if (!/^xmlns(?:$|:)/.test(key)) {
+                    var val = attr[key];
+                    if (nodes && key == "key")
+                        nodes[val] = elem;
+
+                    vals = parseNamespace(key);
+                    if (key == "highlight")
+                        ;
+                    else if (typeof val == "function")
+                        elem.addEventListener(key.replace(/^on/, ""), val, false);
+                    else
+                        elem.setAttributeNS(vals[0] || "", key, val);
+                }
+            args.forEach(function(e) {
+                elem.appendChild(tag(e, namespaces));
+            });
+
+            if ("highlight" in attr)
+                highlight.highlightNode(elem, attr.highlight, nodes || true);
+            return elem;
         }
 
-        switch (node.nodeKind()) {
-        case "text":
-            return doc.createTextNode(String(node));
-        case "element":
-            let domnode = doc.createElementNS(node.namespace(), node.localName());
-
-            for each (let attr in node.@*::*)
-                if (attr.name() != "highlight")
-                    domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr));
-
-            for each (let child in node.*::*)
-                domnode.appendChild(fromXML(child, doc, nodes));
-            if (nodes && node.@key)
-                nodes[node.@key] = domnode;
-
-            if ("@highlight" in node)
-                highlight.highlightNode(domnode, String(node.@highlight), nodes || true);
-            return domnode;
-        default:
-            return null;
+        if (namespaces)
+            namespaces = update({}, fromJSON.namespaces, namespaces);
+        else
+            namespaces = fromJSON.namespaces;
+
+        return tag(xml, namespaces)
+    }, {
+        namespaces: {
+            "": "http://www.w3.org/1999/xhtml",
+            dactyl: String(NS),
+            html: "http://www.w3.org/1999/xhtml",
+            xmlns: "http://www.w3.org/2000/xmlns/",
+            xul: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         }
+    }),
+
+    toXML: function toXML(xml) {
+        // Meh. For now.
+        let doc = services.XMLDocument();
+        let node = this.fromJSON(xml, doc);
+        return services.XMLSerializer()
+                       .serializeToString(node);
+    },
+
+    toPrettyXML: function toPrettyXML(xml, asXML, indent, namespaces) {
+        const INDENT = indent || "    ";
+
+        const EMPTY = Set("area base basefont br col frame hr img input isindex link meta param"
+                            .split(" "));
+
+        function namespaced(namespaces, namespace, localName) {
+            for (let [k, v] in Iterator(namespaces))
+                if (v == namespace)
+                    return (k ? k + ":" + localName : localName);
+
+            throw Error("No such namespace");
+        }
+
+        function isFragment(args) !isString(args[0]) || args.length == 0 || args[0] === "";
+
+        function hasString(args) {
+            return args.some(function (a) isString(a) || isFragment(a) && hasString(a))
+        }
+
+        function isStrings(args) {
+            if (!isArray(args))
+                return util.dump("ARGS: " + {}.toString.call(args) + " " + args), false;
+            return args.every(function (a) isinstance(a, ["String", DOM.DOMString]) || isFragment(a) && isStrings(a))
+        }
+
+        function tag(args, namespaces, indent) {
+            let _namespaces = namespaces;
+
+            if (args == "")
+                return "";
+
+            if (isinstance(args, ["String", "Number", "Boolean", _, DOM.DOMString]))
+                return indent +
+                       DOM.escapeHTML(String(args), true);
+
+            if (isXML(args))
+                return indent +
+                       args.toXMLString()
+                           .replace(/^/m, indent);
+
+            if (isObject(args) && "toDOM" in args)
+                return indent +
+                       services.XMLSerializer()
+                               .serializeToString(args.toDOM(services.XMLDocument()))
+                               .replace(/^/m, indent);
+
+            if (args instanceof Ci.nsIDOMNode)
+                return indent +
+                       services.XMLSerializer()
+                               .serializeToString(args)
+                               .replace(/^/m, indent);
+
+            if ("toJSONXML" in args)
+                args = args.toJSONXML();
+
+            // Deal with common error case
+            if (args == null) {
+                util.reportError(Error("Unexpected null when processing XML."));
+                return "[NULL]";
+            }
+
+            let [name, attr] = args;
+
+            if (isFragment(args)) {
+                let res = [];
+                let join = isArray(args) && isStrings(args) ? "" : "\n";
+                Array.forEach(args, function (arg) {
+                    if (!isArray(arg[0]))
+                        arg = [arg];
+
+                    let contents = [];
+                    arg.forEach(function (arg) {
+                        let string = tag(arg, namespaces, indent);
+                        if (string)
+                            contents.push(string);
+                    });
+                    if (contents.length)
+                        res.push(contents.join("\n"), join)
+                });
+                if (res[res.length - 1] == join)
+                    res.pop();
+                return res.join("");
+            }
+
+            attr = attr || {};
+
+            function parseNamespace(name) {
+                var m = /^(?:(.*):)?(.*)$/.exec(name);
+                return [namespaces[m[1]], m[2]];
+            }
+
+            // FIXME: Surely we can do better.
+            let skipAttr = {};
+            for (var key in attr) {
+                if (/^xmlns(?:$|:)/.test(key)) {
+                    if (_namespaces === namespaces)
+                        namespaces = update({}, namespaces);
+
+                    let ns = namespaces[attr[key]] || attr[key];
+                    if (ns == namespaces[key.substr(6)])
+                        skipAttr[key] = true;
+
+                    attr[key] = namespaces[key.substr(6)] = ns;
+                }}
+
+            var args = Array.slice(args, 2);
+            var vals = parseNamespace(name);
+
+            let res = [indent, "<", name];
+
+            for (let [key, val] in Iterator(attr)) {
+                if (Set.has(skipAttr, key))
+                    continue;
+
+                let vals = parseNamespace(key);
+                if (typeof val == "function") {
+                    key = key.replace(/^(?:on)?/, "on");
+                    val = val.toSource() + "(event)";
+                }
+
+                if (key != "highlight" || vals[0] == String(NS))
+                    res.push(" ", key, '="', DOM.escapeHTML(val), '"');
+                else
+                    res.push(" ", namespaced(namespaces, String(NS), "highlight"),
+                             '="', DOM.escapeHTML(val), '"');
+            }
+
+            if ((vals[0] || namespaces[""]) == String(XHTML) && Set.has(EMPTY, vals[1])
+                    || asXML && !args.length)
+                res.push("/>");
+            else {
+                res.push(">");
+
+                if (isStrings(args))
+                    res.push(args.map(function (e) tag(e, namespaces, "")).join(""),
+                             "</", name, ">");
+                else {
+                    let contents = [];
+                    args.forEach(function(e) {
+                        let string = tag(e, namespaces, indent + INDENT);
+                        if (string)
+                            contents.push(string);
+                    });
+
+                    res.push("\n", contents.join("\n"), "\n", indent, "</", name, ">");
+                }
+            }
+
+            return res.join("");
+        }
+
+        if (namespaces)
+            namespaces = update({}, DOM.fromJSON.namespaces, namespaces);
+        else
+            namespaces = DOM.fromJSON.namespaces;
+
+        return tag(xml, namespaces, "")
+    },
+
+    parseNamespace: function parseNamespace(name, namespaces) {
+        if (name == "xmlns")
+            return [DOM.fromJSON.namespaces.xmlns, "xmlns"];
+
+        var m = /^(?:(.*):)?(.*)$/.exec(name);
+        return [(namespaces || DOM.fromJSON.namespaces)[m[1]],
+                m[2]];
     },
 
     /**
@@ -1604,11 +1881,11 @@ var DOM = Class("DOM", {
     },
 
     namespaces: {
-        xul: XUL.uri,
-        xhtml: XHTML.uri,
-        html: XHTML.uri,
+        xul: XUL,
+        xhtml: XHTML,
+        html: XHTML,
         xhtml2: "http://www.w3.org/2002/06/xhtml2",
-        dactyl: NS.uri
+        dactyl: NS
     },
 
     namespaceNames: Class.Memoize(function ()
index e4d2f11f7981dfd9eb87406718cde8875ca61669..fdf5925b846d5d01853db1de0debec0aad957919 100644 (file)
@@ -1,18 +1,20 @@
-// Copyright (c) 2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2011-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("downloads", {
-    exports: ["Download", "Downloads", "downloads"]
-}, this);
+    exports: ["Download", "Downloads", "downloads"],
+    require: ["util"]
+});
 
-this.lazyRequire("overlay", ["overlay"]);
+lazyRequire("overlay", ["overlay"]);
 
 Cu.import("resource://gre/modules/DownloadUtils.jsm", this);
 
+var MAX_LOAD_TIME = 10 * 1000;
+
 let prefix = "DOWNLOAD_";
 var states = iter([v, k.slice(prefix.length).toLowerCase()]
                   for ([k, v] in Iterator(Ci.nsIDownloadManager))
@@ -28,35 +30,32 @@ 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">
-                    <span highlight="Link">
-                        <a key="launch"
-                           href={self.target.spec} path={self.targetFile.path}>{self.displayName}</a>
-                        <span highlight="LinkInfo">{self.targetFile.path}</span>
-                    </span>
-                </td>
-                <td highlight="DownloadState" key="state"/>
-                <td highlight="DownloadButtons Buttons">
-                    <a highlight="Button" href="javascript:0" key="pause">{_("download.action.Pause")}</a>
-                    <a highlight="Button" href="javascript:0" key="remove">{_("download.action.Remove")}</a>
-                    <a highlight="Button" href="javascript:0" key="resume">{_("download.action.Resume")}</a>
-                    <a highlight="Button" href="javascript:0" key="retry">{_("download.action.Retry")}</a>
-                    <a highlight="Button" href="javascript:0" key="cancel">{_("download.action.Cancel")}</a>
-                    <a highlight="Button" href="javascript:0" key="delete">{_("download.action.Delete")}</a>
-                </td>
-                <td highlight="DownloadProgress" key="progress">
-                    <span highlight="DownloadProgressHave" key="progressHave"
-                    />/<span highlight="DownloadProgressTotal" key="progressTotal"/>
-                </td>
-                <td highlight="DownloadPercent" key="percent"/>
-                <td highlight="DownloadSpeed" key="speed"/>
-                <td highlight="DownloadTime" key="time"/>
-                <td><a highlight="DownloadSource" key="source" href={self.source.spec}>{self.source.spec}</a></td>
-            </tr>,
+        DOM.fromJSON(
+            ["tr", { highlight: "Download", key: "row" },
+                ["td", { highlight: "DownloadTitle" },
+                    ["span", { highlight: "Link" },
+                        ["a", { key: "launch", href: self.target.spec, path: self.targetFile.path },
+                            self.displayName],
+                        ["span", { highlight: "LinkInfo" },
+                            self.targetFile.path]]],
+                ["td", { highlight: "DownloadState", key: "state" }],
+                ["td", { highlight: "DownloadButtons Buttons" },
+                    ["a", { highlight: "Button", href: "javascript:0", key: "pause" }, _("download.action.Pause")],
+                    ["a", { highlight: "Button", href: "javascript:0", key: "remove" }, _("download.action.Remove")],
+                    ["a", { highlight: "Button", href: "javascript:0", key: "resume" }, _("download.action.Resume")],
+                    ["a", { highlight: "Button", href: "javascript:0", key: "retry" }, _("download.action.Retry")],
+                    ["a", { highlight: "Button", href: "javascript:0", key: "cancel" }, _("download.action.Cancel")],
+                    ["a", { highlight: "Button", href: "javascript:0", key: "delete" }, _("download.action.Delete")]],
+                ["td", { highlight: "DownloadProgress", key: "progress" },
+                    ["span", { highlight: "DownloadProgressHave", key: "progressHave" }],
+                    "/",
+                    ["span", { highlight: "DownloadProgressTotal", key: "progressTotal" }]],,
+                ["td", { highlight: "DownloadPercent", key: "percent" }],
+                ["td", { highlight: "DownloadSpeed", key: "speed" }],
+                ["td", { highlight: "DownloadTime", key: "time" }],
+                ["td", {},
+                    ["a", { highlight: "DownloadSource", key: "source", href: self.source.spec },
+                        self.source.spec]]],
             this.list.document, this.nodes);
 
         this.nodes.launch.addEventListener("click", function (event) {
@@ -108,7 +107,7 @@ var Download = Class("Download", {
             function action() {
                 try {
                     if (this.MIMEInfo && this.MIMEInfo.preferredAction == this.MIMEInfo.useHelperApp)
-                        this.MIMEInfo.launchWithFile(file);
+                        this.MIMEInfo.launchWithFile(file.file);
                     else
                         file.launch();
                 }
@@ -226,43 +225,50 @@ 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" key="head">
-                            <span>{_("title.Title")}</span>
-                            <span>{_("title.Status")}</span>
-                            <span/>
-                            <span>{_("title.Progress")}</span>
-                            <span/>
-                            <span>{_("title.Speed")}</span>
-                            <span>{_("title.Time remaining")}</span>
-                            <span>{_("title.Source")}</span>
-                        </tr>
-                        <tr highlight="Download"><span><div style="min-height: 1ex; /* FIXME */"/></span></tr>
-                        <tr highlight="Download" key="totals" active="true">
-                            <td><span highlight="Title">{_("title.Totals")}:</span>&#xa0;<span key="total"/></td>
-                            <td/>
-                            <td highlight="DownloadButtons">
-                                <a highlight="Button" href="javascript:0" key="clear">{_("download.action.Clear")}</a>
-                            </td>
-                            <td highlight="DownloadProgress" key="progress">
-                                <span highlight="DownloadProgressHave" key="progressHave"
-                                />/<span highlight="DownloadProgressTotal" key="progressTotal"/>
-                            </td>
-                            <td highlight="DownloadPercent" key="percent"/>
-                            <td highlight="DownloadSpeed" key="speed"/>
-                            <td highlight="DownloadTime" key="time"/>
-                            <td/>
-                        </tr>
-                      </table>, this.document, this.nodes);
+        DOM.fromJSON(["table", { highlight: "Downloads", key: "list" },
+                        ["tr", { highlight: "DownloadHead", key: "head" },
+                            ["span", {}, _("title.Title")],
+                            ["span", {}, _("title.Status")],
+                            ["span"],
+                            ["span", {}, _("title.Progress")],
+                            ["span"],
+                            ["span", {}, _("title.Speed")],
+                            ["span", {}, _("title.Time remaining")],
+                            ["span", {}, _("title.Source")]],
+                        ["tr", { highlight: "Download" },
+                            ["span", {},
+                                ["div", { style: "min-height: 1ex; /* FIXME */" }]]],
+                        ["tr", { highlight: "Download", key: "totals", active: "true" },
+                            ["td", {},
+                                ["span", { highlight: "Title" },
+                                    _("title.Totals") + ":"],
+                                " ",
+                                ["span", { key: "total" }]],
+                            ["td"],
+                            ["td", { highlight: "DownloadButtons" },
+                                ["a", { highlight: "Button", href: "javascript:0", key: "clear" }, _("download.action.Clear")]],
+                            ["td", { highlight: "DownloadProgress", key: "progress" },
+                                ["span", { highlight: "DownloadProgressHave", key: "progressHave" }],
+                                "/",
+                                ["span", { highlight: "DownloadProgressTotal", key: "progressTotal" }]],
+                            ["td", { highlight: "DownloadPercent", key: "percent" }],
+                            ["td", { highlight: "DownloadSpeed", key: "speed" }],
+                            ["td", { highlight: "DownloadTime", key: "time" }],
+                            ["td"]]],
+                      this.document, this.nodes);
 
         this.index = Array.indexOf(this.nodes.list.childNodes,
                                    this.nodes.head);
 
+        let start = Date.now();
         for (let row in iter(services.downloadManager.DBConnection
-                                     .createStatement("SELECT id FROM moz_downloads")))
+                                     .createStatement("SELECT id FROM moz_downloads"))) {
+            if (Date.now() - start > MAX_LOAD_TIME) {
+                util.dactyl.warn(_("download.givingUpAfter", (Date.now() - start) / 1000));
+                break;
+            }
             this.addDownload(row.id);
+        }
         this.update();
 
         util.addObserver(this);
@@ -402,7 +408,7 @@ var Downloads = Module("downloads", XPCOM(Ci.nsIDownloadProgressListener), {
         services.downloadManager.addListener(this);
     },
 
-    destroy: function destroy() {
+    cleanup: function destroy() {
         services.downloadManager.removeListener(this);
     },
 
index bde3f4293ff777681cb6b34a0e683b354a4e1049..ee85905b3f89322b6bbd7b93bd58febc674a6fe4 100644 (file)
@@ -1,19 +1,20 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("finder", {
     exports: ["RangeFind", "RangeFinder", "rangefinder"],
-    require: ["prefs"]
-}, this);
+    require: ["prefs", "util"]
+});
 
-this.lazyRequire("buffer", ["Buffer"]);
-this.lazyRequire("overlay", ["overlay"]);
+lazyRequire("buffer", ["Buffer"]);
+lazyRequire("overlay", ["overlay"]);
 
-function equals(a, b) XPCNativeWrapper(a) == XPCNativeWrapper(b);
+function id(w) w.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
+                .outerWindowID;
+function equals(a, b) id(a) == id(b);
 
 /** @instance rangefinder */
 var RangeFinder = Module("rangefinder", {
@@ -260,7 +261,7 @@ var RangeFinder = Module("rangefinder", {
             get onSubmit() modules.rangefinder.closure.onSubmit
         });
     },
-    mappings: function (dactyl, modules, window) {
+    mappings: function initMappings(dactyl, modules, window) {
         const { Buffer, buffer, config, mappings, modes, rangefinder } = modules;
         var myModes = config.browserModes.concat([modes.CARET]);
 
@@ -295,7 +296,7 @@ var RangeFinder = Module("rangefinder", {
             });
 
     },
-    options: function (dactyl, modules, window) {
+    options: function initOptions(dactyl, modules, window) {
         const { options, rangefinder } = modules;
 
         options.add(["hlfind", "hlf"],
index dadadfcd6993d2e78dd960a290fd91ca9762f2d4..a092ad5c8a71fc02de197919eda53dd9b58b6957 100644 (file)
@@ -1,17 +1,17 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("help", {
     exports: ["help"],
     require: ["cache", "dom", "protocol", "services", "util"]
-}, this);
+});
 
-this.lazyRequire("completion", ["completion"]);
-this.lazyRequire("overlay", ["overlay"]);
+lazyRequire("completion", ["completion"]);
+lazyRequire("overlay", ["overlay"]);
+lazyRequire("template", ["template"]);
 
 var HelpBuilder = Class("HelpBuilder", {
     init: function init() {
@@ -108,7 +108,7 @@ var Help = Module("Help", {
                                     { mimeType: "text/plain;charset=UTF-8" })
                            .responseText;
 
-            let re = util.regexp(UTF8(<![CDATA[
+            let re = util.regexp(UTF8(literal(/*
                   ^ (?P<comment> \s* # .*\n)
 
                 | ^ (?P<space> \s*)
@@ -124,7 +124,7 @@ var Help = Module("Help", {
                   )
 
                 | (?: ^ [^\S\n]* \n) +
-            ]]>), "gmxy");
+            */)), "gmxy");
 
             let betas = util.regexp(/\[((?:b|rc)\d)\]/, "gx");
 
@@ -132,11 +132,8 @@ var Help = Module("Help", {
                         .map(function (m) m[1]).uniq().slice(-1)[0];
 
 
-            default xml namespace = NS;
             function rec(text, level, li) {
-                XML.ignoreWhitespace = XML.prettyPrinting = false;
-
-                let res = <></>;
+                let res = [];
                 let list, space, i = 0;
 
 
@@ -145,10 +142,13 @@ var Help = Module("Help", {
                         continue;
                     else if (match.char) {
                         if (!list)
-                            res += list = <ul/>;
-                        let li = <li/>;
-                        li.* += rec(match.content.replace(RegExp("^" + match.space, "gm"), ""), level + 1, li);
-                        list.* += li;
+                            res.push(list = ["ul", {}]);
+                        let li = ["li", {}];
+                        li.push(rec(match.content
+                                         .replace(RegExp("^" + match.space, "gm"), ""),
+                                    level + 1,
+                                    li));
+                        list.push(li);
                     }
                     else if (match.par) {
                         let [, par, tags] = /([^]*?)\s*((?:\[[^\]]+\])*)\n*$/.exec(match.par);
@@ -158,58 +158,52 @@ var Help = Module("Help", {
                         let group = !tags.length                       ? "" :
                                     !tags.some(function (t) t == beta) ? "HelpNewsOld" : "HelpNewsNew";
                         if (i === 0 && li) {
-                            li.@highlight = group;
+                            li[1]["dactyl:highlight"] = group;
                             group = "";
                         }
 
                         list = null;
                         if (level == 0 && /^.*:\n$/.test(match.par)) {
                             let text = par.slice(0, -1);
-                            res += <h2 tag={"news-" + text}>{template.linkifyHelp(text, true)}</h2>;
+                            res.push(["h2", { tag: "news-" + text },
+                                          template.linkifyHelp(text, true)]);
                         }
                         else {
                             let [, a, b] = /^(IMPORTANT:?)?([^]*)/.exec(par);
-                            res += <p highlight={group + " HelpNews"}>{
-                                !tags.length ? "" :
-                                <hl key="HelpNewsTag">{tags.join(" ")}</hl>
-                            }{
-                                a ? <hl key="HelpWarning">{a}</hl> : ""
-                            }{
-                                template.linkifyHelp(b, true)
-                            }</p>;
+
+                            res.push(["p", { "dactyl:highlight": group + " HelpNews" },
+                                !tags.length ? "" : ["hl", { key: "HelpNewsTag" }, tags.join(" ")],
+                                a ? ["hl", { key: "HelpWarning" }, a] : "",
+                                template.linkifyHelp(b, true)]);
                         }
                     }
                     i++;
                 }
-                for each (let attr in res..@highlight) {
-                    attr.parent().@NS::highlight = attr;
-                    delete attr.parent().@highlight;
-                }
+
                 return res;
             }
 
-            XML.ignoreWhitespace = XML.prettyPrinting = false;
             let body = rec(NEWS, 0);
-            for each (let li in body..li) {
-                let list = li..li.(@NS::highlight == "HelpNewsOld");
-                if (list.length() && list.length() == li..li.(@NS::highlight != "").length()) {
-                    for each (let li in list)
-                        li.@NS::highlight = "";
-                    li.@NS::highlight = "HelpNewsOld";
-                }
-            }
+
+            // E4X-FIXME
+            // for each (let li in body..li) {
+            //     let list = li..li.(@NS::highlight == "HelpNewsOld");
+            //     if (list.length() && list.length() == li..li.(@NS::highlight != "").length()) {
+            //         for each (let li in list)
+            //             li.@NS::highlight = "";
+            //         li.@NS::highlight = "HelpNewsOld";
+            //     }
+            // }
 
 
             return '<?xml version="1.0"?>\n' +
                    '<?xml-stylesheet type="text/xsl" href="dactyl://content/help.xsl"?>\n' +
-                   '<!DOCTYPE document SYSTEM "resource://dactyl-content/dactyl.dtd">\n' +
-                   <document xmlns={NS} xmlns:dactyl={NS}
-                       name="versions" title={config.appName + " Versions"}>
-                       <h1 tag="versions news NEWS">{config.appName} Versions</h1>
-                       <toc start="2"/>
-
-                       {body}
-                   </document>.toXMLString()
+                   DOM.toXML(["document", { xmlns: "dactyl", name: "versions",
+                                  title: config.appName + " Versions" },
+                       ["h1", { tag: "versions news NEWS" }, config.appName + " Versions"],
+                       ["toc", { start: "2" }],
+
+                       body]);
         });
     },
 
@@ -234,7 +228,7 @@ var Help = Module("Help", {
         init: function init() {
             dactyl.commands["dactyl.help"] = function (event) {
                 let elem = event.originalTarget;
-                help.help(elem.getAttribute("tag") || elem.textContent);
+                modules.help.help(elem.getAttribute("tag") || elem.textContent);
             };
         },
 
@@ -304,7 +298,7 @@ var Help = Module("Help", {
                 var addURIEntry  = function addURIEntry(file, uri) addDataEntry(file, util.httpGet(uri).responseText);
             }
             else {
-                var zip = services.ZipWriter(FILE, File.MODE_CREATE | File.MODE_WRONLY | File.MODE_TRUNCATE);
+                var zip = services.ZipWriter(FILE.file, File.MODE_CREATE | File.MODE_WRONLY | File.MODE_TRUNCATE);
 
                 addURIEntry = function addURIEntry(file, uri)
                     zip.addEntryChannel(PATH + file, TIME, 9,
@@ -321,10 +315,10 @@ var Help = Module("Help", {
                     if (isinstance(node, [Ci.nsIDOMHTMLBaseElement]))
                         return;
 
-                    data.push("<"); data.push(node.localName);
+                    data.push("<"node.localName);
                     if (node instanceof Ci.nsIDOMHTMLHtmlElement)
-                        data.push(" xmlns=" + XHTML.uri.quote(),
-                                  " xmlns:dactyl=" + NS.uri.quote());
+                        data.push(" xmlns=" + XHTML.quote(),
+                                  " xmlns:dactyl=" + NS.quote());
 
                     for (let { name, value } in array.iterValues(node.attributes)) {
                         if (name == "dactyl:highlight") {
@@ -352,22 +346,20 @@ var Help = Module("Help", {
                             value = value.replace(/.*\//, "");
                         }
 
-                        data.push(" ", name, '="',
-                                  <>{value}</>.toXMLString().replace(/"/g, "&quot;"),
-                                  '"');
+                        data.push(" ", name, '="', DOM.escapeHTML(value), '"');
                     }
                     if (node.localName in empty)
                         data.push(" />");
                     else {
                         data.push(">");
                         if (node instanceof Ci.nsIDOMHTMLHeadElement)
-                            data.push(<link rel="stylesheet" type="text/css" href="help.css"/>.toXMLString());
+                            data.push('<link rel="stylesheet" type="text/css" href="help.css"/>');
                         Array.map(node.childNodes, fix);
                         data.push("</", node.localName, ">");
                     }
                     break;
                 case Ci.nsIDOMNode.TEXT_NODE:
-                    data.push(<>{node.textContent}</>.toXMLString());
+                    data.push(DOM.escapeHTML(node.textContent, true));
                 }
             }
 
@@ -414,7 +406,7 @@ var Help = Module("Help", {
     })
 }, {
 }, {
-    commands: function init_commands(dactyl, modules, window) {
+    commands: function initCommands(dactyl, modules, window) {
         const { commands, completion, help } = modules;
 
         [
@@ -441,7 +433,7 @@ var Help = Module("Help", {
                 });
         });
     },
-    completion: function init_completion(dactyl, modules, window) {
+    completion: function initCompletion(dactyl, modules, window) {
         const { completion } = modules;
 
         completion.help = function completion_help(context, consolidated) {
@@ -453,18 +445,7 @@ var Help = Module("Help", {
                 context.keys = { text: 0, description: function () "all" };
         };
     },
-    mappings: function init_mappings(dactyl, modules, window) {
-        const { help, mappings, modes } = modules;
-
-        mappings.add([modes.MAIN], ["<open-help>", "<F1>"],
-            "Open the introductory help page",
-            function () { help.help(); });
-
-        mappings.add([modes.MAIN], ["<open-single-help>", "<A-F1>"],
-            "Open the single, consolidated help page",
-            function () { modules.ex.helpall(); });
-    },
-    javascript: function init_javascript(dactyl, modules, window) {
+    javascript: function initJavascript(dactyl, modules, window) {
         modules.JavaScript.setCompleter([modules.help.exportHelp],
             [function (context, args) overlay.activeModules.completion.file(context)]);
     }
index 7d6cfaf03cf61a7cef814116d9128b535cc169b7..bf242e08f70eed2c3caaa0354166c9ac38a35c78 100644 (file)
@@ -1,16 +1,16 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("highlight", {
     exports: ["Highlight", "Highlights", "highlight"],
     require: ["services", "util"]
-}, this);
+});
 
-this.lazyRequire("styles", ["Styles", "styles"]);
+lazyRequire("styles", ["Styles", "styles"]);
+lazyRequire("template", ["template"]);
 
 var Highlight = Struct("class", "selector", "sites",
                        "defaultExtends", "defaultValue",
@@ -197,7 +197,7 @@ var Highlights = Module("Highlight", {
      * @param {string} group
      */
     highlightNode: function highlightNode(node, group, applyBindings) {
-        node.setAttributeNS(NS.uri, "highlight", group);
+        node.setAttributeNS(NS, "highlight", group);
 
         let groups = group.split(" ");
         for each (let group in groups)
@@ -224,14 +224,14 @@ var Highlights = Module("Highlight", {
                 (self.highlight[hl] && self.highlight[hl].class != class_
                     ? self.highlight[hl].selector : "[dactyl|highlight~=" + hl + "]")),
 
-    groupRegexp: util.regexp(<![CDATA[
+    groupRegexp: util.regexp(literal(/*
         ^
         (\s* (?:\S|\s\S)+ \s+)
         \{ ([^}]*) \}
         \s*
         $
-    ]]>, "gmx"),
-    sheetRegexp: util.regexp(<![CDATA[
+    */), "gmx"),
+    sheetRegexp: util.regexp(literal(/*
         ^\s*
         !? \*?
              (?P<group>    (?:[^;\s]|\s[^;\s])+ )
@@ -240,7 +240,8 @@ var Highlights = Module("Highlight", {
         (?:; (?P<extends>  (?:[^;\s]|\s[^;\s])+ )? )?
         \s*  (?P<css>      .*)
         $
-    ]]>, "x"),
+    */), "x"),
+    // </css>
 
     /**
      * Bulk loads new CSS rules, in the format of,
@@ -322,7 +323,7 @@ var Highlights = Module("Highlight", {
         commands.add(["hi[ghlight]"],
             "Set the style of certain display elements",
             function (args) {
-                let style = <![CDATA[
+                let style = literal(/*
                     ;
                     display: inline-block !important;
                     position: static !important;
@@ -330,7 +331,7 @@ var Highlights = Module("Highlight", {
                     width: 3em !important; min-width: 3em !important; max-width: 3em !important;
                     height: 1em !important; min-height: 1em !important; max-height: 1em !important;
                     overflow: hidden !important;
-                ]]>;
+                */);
                 let clear = args[0] == "clear";
                 if (clear)
                     args.shift();
@@ -349,10 +350,10 @@ var Highlights = Module("Highlight", {
                             ["padding: 0 1em 0 0; vertical-align: top; max-width: 16em; overflow: hidden;",
                              "text-align: center"],
                             ([h.class,
-                              <span style={"text-align: center; line-height: 1em;" + h.value + style}>XXX</span>,
-                              template.map(h.extends, function (s) template.highlight(s), <>,</>),
+                              ["span", { style: "text-align: center; line-height: 1em;" + h.value + style }, "XXX"],
+                              template.map(h.extends, function (s) template.highlight(s), ","),
                               template.highlightRegexp(h.value, /\b[-\w]+(?=:)|\/\*.*?\*\//g,
-                                                       function (match) <span highlight={match[0] == "/" ? "Comment" : "Key"}>{match}</span>)
+                                                       function (match) ["span", { highlight: match[0] == "/" ? "Comment" : "Key" }, match])
                              ]
                              for (h in highlight)
                              if (!key || h.class.indexOf(key) > -1))));
index 0e0a39499c6b073e1c936e746486ce6eab70cb13..9e717d74ed51ebd217ea017e821b017e7a7ef7c7 100644 (file)
@@ -1,22 +1,24 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
-// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2007-2012 by Doug Kearns <dougkearns@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 // Some code based on Venkman
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("io", {
     exports: ["IO", "io"],
     require: ["services"]
-}, this);
+});
 
-this.lazyRequire("config", ["config"]);
-this.lazyRequire("contexts", ["Contexts", "contexts"]);
+lazyRequire("config", ["config"]);
+lazyRequire("contexts", ["Contexts", "contexts"]);
+lazyRequire("storage", ["File", "storage"]);
+lazyRequire("styles", ["styles"]);
+lazyRequire("template", ["template"]);
 
 // TODO: why are we passing around strings rather than file objects?
 /**
@@ -149,7 +151,7 @@ var IO = Module("io", {
                         dactyl.triggerObserver("io.source", context, file, file.lastModifiedTime);
                     }
 
-                    if (/\.js,$/.test(filename))
+                    if (/\.jsm$/.test(filename))
                         sourceJSM();
                     else if (/\.js$/.test(filename)) {
                         try {
@@ -166,12 +168,14 @@ var IO = Module("io", {
                                 sourceJSM();
                             }
                             else {
+                                if (e instanceof Finished)
+                                    return;
                                 if (e.fileName && !(e instanceof FailedAssertion))
                                     try {
                                         e.fileName = util.fixURI(e.fileName);
                                         if (e.fileName == uri.spec)
                                             e.fileName = filename;
-                                        e.echoerr = <>{e.fileName}:{e.lineNumber}: {e}</>;
+                                        e.echoerr = [e.fileName, ":", e.lineNumber, ": ", e].join("");
                                     }
                                     catch (e) {}
                                 throw e;
@@ -359,7 +363,7 @@ var IO = Module("io", {
         file = util.getFile(file);
         if (file && file.exists() && file.isFile() && file.isReadable()) {
             // let jar = services.zipReader.getZip(file); Crashes.
-            let jar = services.ZipReader(file);
+            let jar = services.ZipReader(file.file);
             try {
                 let filter = RegExp("^" + util.regexp.escape(decodeURI(path))
                                     + "[^/]*/?$");
@@ -442,7 +446,7 @@ var IO = Module("io", {
             return -1;
         }
 
-        let process = services.Process(file);
+        let process = services.Process(file.file);
         process.run(false, args.map(String), args.length);
         try {
             if (callable(blocking))
@@ -573,7 +577,7 @@ var IO = Module("io", {
      */
     PATH_SEP: deprecated("File.PATH_SEP", { get: function PATH_SEP() File.PATH_SEP })
 }, {
-    commands: function init_commands(dactyl, modules, window) {
+    commands: function initCommands(dactyl, modules, window) {
         const { commands, completion, io } = modules;
 
         commands.add(["cd", "chd[ir]"],
@@ -636,6 +640,7 @@ var IO = Module("io", {
 
                 try {
                     file.write(lines.join("\n"));
+                    dactyl.echomsg(_("io.writing", file.path.quote()), 2);
                 }
                 catch (e) {
                     dactyl.echoerr(_("io.notWriteable", file.path.quote()));
@@ -647,24 +652,65 @@ var IO = Module("io", {
                 completer: function (context) completion.file(context, true)
             });
 
-        commands.add(["mks[yntax]"],
-            "Generate a Vim syntax file",
+        commands.add(["mkv[imruntime]"],
+            "Create and install Vim runtime files for " + config.appName,
             function (args) {
-                let runtime = config.OS.isWindows ? "~/vimfiles/" : "~/.vim/";
-                let file = io.File(runtime + "syntax/" + config.name + ".vim");
-                if (args.length)
-                    file = io.File(args[0]);
+                dactyl.assert(args.length <= 1, _("io.oneFileAllowed"));
+
+                if (args.length) {
+                    var rtDir = io.File(args[0]);
+                    dactyl.assert(rtDir.exists(), _("io.noSuchDir", rtDir.path.quote()));
+                }
+                else
+                    rtDir = io.File(config.OS.isWindows ? "~/vimfiles/" : "~/.vim/");
+
+                dactyl.assert(!rtDir.exists() || rtDir.isDirectory(), _("io.eNotDir", rtDir.path.quote()));
+
+                let rtItems = { ftdetect: {}, ftplugin: {}, syntax: {} };
+
+                // require bang if any of the paths exist
+                for (let [type, item] in iter(rtItems)) {
+                    let file = io.File(rtDir).child(type, config.name + ".vim");
+                    dactyl.assert(!file.exists() || args.bang, _("io.exists", file.path.quote()));
+                    item.file = file;
+                }
+
+                rtItems.ftdetect.template = // {{{
+literal(/*" Vim filetype detection file
+<header>
+
+au BufNewFile,BufRead *<name>rc*,*.<fileext> set filetype=<name>
+*/);//}}}
+                rtItems.ftplugin.template = // {{{
+literal(/*" Vim filetype plugin file
+<header>
+
+if exists("b:did_ftplugin")
+  finish
+endif
+let b:did_ftplugin = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
 
-                if (file.exists() && file.isDirectory() || args[0] && /\/$/.test(args[0]))
-                    file.append(config.name + ".vim");
-                dactyl.assert(!file.exists() || args.bang, _("io.exists"));
+let b:undo_ftplugin = "setl com< cms< fo< ofu< | unlet! b:browsefilter"
 
-                let template = util.compileMacro(<![CDATA[
-" Vim syntax file
-" Language:         Pentadactyl configuration file
-" Maintainer:       Doug Kearns <dougkearns@gmail.com>
+setlocal comments=:\"
+setlocal commentstring=\"%s
+setlocal formatoptions-=t formatoptions+=croql
+setlocal omnifunc=syntaxcomplete#Complete
+
+if has("gui_win32") && !exists("b:browsefilter")
+    let b:browsefilter = "<appname> Config Files (*.<fileext>)\t*.<fileext>\n" .
+        \ "All Files (*.*)\t*.*\n"
+endif
 
-" TODO: make this <name> specific - shared dactyl config?
+let &cpo = s:cpo_save
+unlet s:cpo_save
+*/);//}}}
+                rtItems.syntax.template = // {{{
+literal(/*" Vim syntax file
+<header>
 
 if exists("b:current_syntax")
   finish
@@ -741,11 +787,13 @@ let b:current_syntax = "<name>"
 let &cpo = s:cpo_save
 unlet s:cpo_save
 
-" vim: tw=130 et ts=4 sw=4:
-]]>, true);
+" vim: tw=130 et ts=8 sts=4 sw=4:
+*/);//}}}
+
+                const { options } = modules;
 
                 const WIDTH = 80;
-                function wrap(prefix, items, sep) {
+                function wrap(prefix, items, sep) {//{{{
                     sep = sep || " ";
                     let width = 0;
                     let lines = [];
@@ -762,11 +810,16 @@ unlet s:cpo_save
                     }
                     lines.last.pop();
                     return lines.map(function (l) l.join("")).join("\n").replace(/\s+\n/gm, "\n");
-                }
+                }//}}}
 
-                const { commands, options } = modules;
-                file.write(template({
+                let params = { // {{{
+                    header: ['" Language:    ' + config.appName + ' configuration file',
+                             '" Maintainer:  Doug Kearns <dougkearns@gmail.com>',
+                             '" Version:     ' + config.version].join("\n"),
                     name: config.name,
+                    appname: config.appName,
+                    fileext: config.fileExtension,
+                    maintainer: "Doug Kearns <dougkearns@gmail.com>",
                     autocommands: wrap("syn keyword " + config.name + "AutoEvent ",
                                        keys(config.autocommands)),
                     commands: wrap("syn keyword " + config.name + "Command ",
@@ -777,11 +830,22 @@ unlet s:cpo_save
                                         array(o.realNames for (o in options) if (o.type == "boolean"))
                                             .flatten().map(String.quote),
                                         ", ") + "]"
-                }));
+                }; // }}}
+
+                for (let { file, template } in values(rtItems)) {
+                    try {
+                        file.write(util.compileMacro(template, true)(params));
+                        dactyl.echomsg(_("io.writing", file.path.quote()), 2);
+                    }
+                    catch (e) {
+                        dactyl.echoerr(_("io.notWriteable", file.path.quote()));
+                        dactyl.log(_("error.notWriteable", file.path, e.message));
+                    }
+                }
             }, {
                 argCount: "?",
                 bang: true,
-                completer: function (context) completion.file(context, true),
+                completer: function (context) completion.directory(context, true),
                 literal: 1
             });
 
@@ -854,7 +918,7 @@ unlet s:cpo_save
                     result.output += "\n" + _("io.shellReturn", result.returnValue);
 
                 modules.commandline.command = args.commandName.replace("run", "$& ") + arg;
-                modules.commandline.commandOutput(<span highlight="CmdOutput">{result.output}</span>);
+                modules.commandline.commandOutput(["span", { highlight: "CmdOutput" }, result.output]);
 
                 modules.autocommands.trigger("ShellCmdPost", {});
             }, {
@@ -865,7 +929,7 @@ unlet s:cpo_save
                 literal: 0
             });
     },
-    completion: function init_completion(dactyl, modules, window) {
+    completion: function initCompletion(dactyl, modules, window) {
         const { completion, io } = modules;
 
         completion.charset = function (context) {
@@ -977,7 +1041,7 @@ unlet s:cpo_save
         };
 
         completion.addUrlCompleter("file", "Local files", function (context, full) {
-            let match = util.regexp(<![CDATA[
+            let match = util.regexp(literal(/*
                 ^
                 (?P<prefix>
                     (?P<proto>
@@ -988,7 +1052,7 @@ unlet s:cpo_save
                 )
                 (?P<path> \/[^\/]* )?
                 $
-            ]]>, "x").exec(context.filter);
+            */), "x").exec(context.filter);
             if (match) {
                 if (!match.path) {
                     context.key = match.proto;
@@ -1013,7 +1077,7 @@ unlet s:cpo_save
                     completion.file(context, full);
         });
     },
-    javascript: function init_javascript(dactyl, modules, window) {
+    javascript: function initJavascript(dactyl, modules, window) {
         modules.JavaScript.setCompleter([File, File.expandPath],
             [function (context, obj, args) {
                 context.quote[2] = "";
@@ -1032,7 +1096,7 @@ unlet s:cpo_save
             input: true
         });
     },
-    options: function init_options(dactyl, modules, window) {
+    options: function initOptions(dactyl, modules, window) {
         const { completion, options } = modules;
 
         var shell, shellcmdflag;
index c33ca86930e8eb8bf36e229ff5955b7f47dfe649..a0981d7894fed5048a2ca8b945035fa2d6389a60 100644 (file)
@@ -1,18 +1,19 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 let { getOwnPropertyNames } = Object;
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("javascript", {
     exports: ["JavaScript", "javascript"],
     require: ["util"]
-}, this);
+});
+
+lazyRequire("template", ["template"]);
 
 let isPrototypeOf = Object.prototype.isPrototypeOf;
 
@@ -118,7 +119,8 @@ var JavaScript = Module("javascript", {
 
         context[JavaScript.EVAL_TMP] = tmp;
         try {
-            cache[key] = this.modules.dactyl.userEval(arg, context, /*L*/"[Command Line Completion]", 1);
+            cache[key] = this.modules.dactyl.userEval(arg, context,
+                                                      /*L*/"[Command Line Completion]", 1);
 
             return cache[key];
         }
@@ -489,9 +491,9 @@ var JavaScript = Module("javascript", {
                         let [, prefix, args] = /^(function .*?)\((.*?)\)/.exec(Function.prototype.toString.call(func));
                         let n = this._get(i).comma.length;
                         args = template.map(Iterator(args.split(", ")),
-                            function ([i, arg]) <span highlight={i == n ? "Filter" : ""}>{arg}</span>,
-                            <>,&#xa0;</>);
-                        this.context.message = <>{prefix}({args})</>;
+                            function ([i, arg]) ["span", { highlight: i == n ? "Filter" : "" }, arg],
+                            ",\u00a0");
+                        this.context.message = ["", prefix + "(", args, ")"];
                     }
                 }
             }
@@ -595,8 +597,8 @@ var JavaScript = Module("javascript", {
         if (!this.context.tabPressed && key == "" && obj.length > 1) {
             let message = this.context.message || "";
             this.context.waitingForTab = true;
-            this.context.message = <>{message}
-                                     {_("completion.waitingForKeyPress")}</>;
+            this.context.message = ["", message, "\n",
+                                    _("completion.waitingForKeyPress")];
             return null;
         }
 
@@ -715,7 +717,6 @@ var JavaScript = Module("javascript", {
             },
 
             addOutput: function addOutput(js) {
-                default xml namespace = XHTML;
                 this.count++;
 
                 try {
@@ -728,19 +729,21 @@ var JavaScript = Module("javascript", {
 
                     if (e.fileName)
                         e = util.fixURI(e.fileName) + ":" + e.lineNumber + ": " + e;
-                    xml = <span highlight="ErrorMsg">{e}</span>;
+                    xml = ["span", { highlight: "ErrorMsg" }, e];
                 }
 
                 let prompt = "js" + this.count;
                 Class.replaceProperty(this.context, prompt, result);
 
-                XML.ignoreWhitespace = XML.prettyPrinting = false;
                 let nodes = {};
                 this.rootNode.appendChild(
-                    util.xmlToDom(<e4x>
-                        <div highlight="REPL-E" key="e"><span highlight="REPL-R">{prompt}></span> {js}</div>
-                        <div highlight="REPL-P" key="p">{xml}</div>
-                    </e4x>.elements(), this.document, nodes));
+                    DOM.fromJSON(
+                        [["div", { highlight: "REPL-E", key: "e" },
+                            ["span", { highlight: "REPL-R" },
+                                prompt, ">"], " ", js],
+                         ["div", { highlight: "REPL-P", key: "p" },
+                            xml]],
+                        this.document, nodes));
 
                 this.rootNode.scrollTop += nodes.e.getBoundingClientRect().top
                                          - this.rootNode.getBoundingClientRect().top;
@@ -749,8 +752,7 @@ var JavaScript = Module("javascript", {
             count: 0,
 
             message: Class.Memoize(function () {
-                default xml namespace = XHTML;
-                util.xmlToDom(<div highlight="REPL" key="rootNode"/>,
+                DOM.fromJSON(["div", { highlight: "REPL", key: "rootNode" }],
                               this.document, this);
 
                 return this.rootNode;
@@ -878,7 +880,7 @@ var JavaScript = Module("javascript", {
         bind(["<C-b>", "<PageUp>"], "Scroll up half a page",
              function ({ self }) { self.repl.scrollVertical("pages", -1); });
     },
-    options: function (dactyl, modules, window) {
+    options: function initOptions(dactyl, modules, window) {
         modules.options.add(["jsdebugger", "jsd"],
             "Enable the JavaScript debugger service for use in JavaScript completion",
             "boolean", false, {
index ffc89ee8e5d25f643bc291a79fa4ca12c4d37ea0..41ef16cf570cfcf40a260d4abbb934bf158bcbe6 100644 (file)
@@ -1,16 +1,15 @@
-// Copyright (c) 2009-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("main", {
     exports: ["ModuleBase"],
     require: ["config", "overlay", "services", "util"]
-}, this);
+});
 
 var BASE = "resource://dactyl-content/";
 
@@ -91,20 +90,13 @@ var Modules = function Modules(window) {
     Module.list = [];
     Module.constructors = {};
 
-    const create = window.Object.create || (function () {
-        window.__dactyl_eval_string = "(function (proto) ({ __proto__: proto }))";
-        JSMLoader.loadSubScript(BASE + "eval.js", window);
-
-        let res = window.__dactyl_eval_result;
-        delete window.__dactyl_eval_string;
-        delete window.__dactyl_eval_result;
-        return res;
-    })();
+    const create = window.Object.create.bind(window.Object);
 
 
     const BASES = [BASE, "resource://dactyl-local-content/"];
 
-    const jsmodules = { NAME: "jsmodules" };
+    jsmodules = Cu.createObjectIn(window);
+    jsmodules.NAME = "jsmodules";
     const modules = update(create(jsmodules), {
         yes_i_know_i_should_not_report_errors_in_these_branches_thanks: [],
 
@@ -130,7 +122,7 @@ var Modules = function Modules(window) {
                 }
             }
             try {
-                require(jsmodules, script);
+                require(script, jsmodules);
             }
             catch (e) {
                 util.dump("Loading script " + script + ":");
@@ -150,7 +142,7 @@ var Modules = function Modules(window) {
                                                              wantXrays: false });
 
             // Hack:
-            sandbox.Object = jsmodules.Object;
+            // sandbox.Object = jsmodules.Object;
             sandbox.File = jsmodules.File;
             sandbox.Math = jsmodules.Math;
             sandbox.__proto__ = proto || modules;
@@ -181,7 +173,12 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({
 
         defineModule.time("load", null, function _load() {
             config.modules.global
-                  .forEach(function (name) defineModule.time("load", name, require, null, modules.jsmodules, name));
+                  .forEach(function (name) {
+                      if (!isArray(name))
+                          defineModule.time("load", name, require, null, name, modules.jsmodules);
+                      else
+                          lazyRequire(name[0], name.slice(1), modules.jsmodules);
+                  });
 
             config.modules.window
                   .forEach(function (name) defineModule.time("load", name, modules.load, modules, name));
index 3e20f27afa9e9e9c21f7657c212ba7b509fea84f..12ab0f357fa94b2195db31466b6bb2bdabea2506 100644 (file)
@@ -1,16 +1,13 @@
-// Copyright (c) 2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2011-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-try {
-
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("messages", {
     exports: ["Messages", "messages", "_"],
     require: ["services", "util"]
-}, this);
+});
 
 var Messages = Module("messages", {
 
@@ -206,6 +203,6 @@ var { _ } = messages;
 
 endModule();
 
-} catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
+// catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
 
 // vim: set fdm=marker sw=4 ts=4 et ft=javascript:
index dacafbdd28b282cc3e9879e3c6c7871ceff749aa..1440e23cd6e7b0ad6d5dc4abc944db69fed729ce 100644 (file)
@@ -4,17 +4,22 @@
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("options", {
     exports: ["Option", "Options", "ValueError", "options"],
     require: ["contexts", "messages", "storage"]
-}, this);
+});
 
-this.lazyRequire("config", ["config"]);
+lazyRequire("cache", ["cache"]);
+lazyRequire("config", ["config"]);
+lazyRequire("commands", ["Commands"]);
+lazyRequire("completion", ["CompletionContext"]);
+lazyRequire("prefs", ["prefs"]);
+lazyRequire("styles", ["Styles"]);
+lazyRequire("template", ["template"]);
 
 /** @scope modules */
 
@@ -849,35 +854,38 @@ var Options = Module("options", {
 
             function opts(opt) {
                 for (let opt in Iterator(this)) {
+                    if (filter && !filter(opt))
+                        continue;
+                    if (!(opt.scope & scope))
+                        continue;
+
                     let option = {
                         __proto__: opt,
                         isDefault: opt.isDefault,
                         default:   opt.stringDefaultValue,
                         pre:       "\u00a0\u00a0", // Unicode nonbreaking space.
-                        value:     <></>
+                        value:     []
                     };
 
-                    if (filter && !filter(opt))
-                        continue;
-                    if (!(opt.scope & scope))
-                        continue;
-
                     if (opt.type == "boolean") {
                         if (!opt.value)
                             option.pre = "no";
                         option.default = (opt.defaultValue ? "" : "no") + opt.name;
                     }
                     else if (isArray(opt.value) && opt.type != "charlist")
-                        option.value = <>={template.map(opt.value,
-                            function (v) template.highlight(String(v)),
-                            <>,<span style="width: 0; display: inline-block"> </span></>)}</>;
+                        option.value = ["", "=",
+                                        template.map(opt.value,
+                                                     function (v) template.highlight(String(v)),
+                                                     ["", ",",
+                                                      ["span", { style: "width: 0; display: inline-block" }, " "]])];
                     else
-                        option.value = <>={template.highlight(opt.stringValue)}</>;
+                        option.value = ["", "=", template.highlight(opt.stringValue)];
                     yield option;
                 }
             };
 
-            modules.commandline.commandOutput(template.options("Options", opts.call(this), this["verbose"] > 0));
+            modules.commandline.commandOutput(
+                template.options("Options", opts.call(this), this["verbose"] > 0));
         },
 
         cleanup: function cleanup() {
@@ -1063,36 +1071,19 @@ var Options = Module("options", {
     commands: function initCommands(dactyl, modules, window) {
         const { commands, contexts, options } = modules;
 
-        let args = {
-            getMode: function (args) findMode(args["-mode"]),
-            iterate: function (args) {
-                for (let map in mappings.iterate(this.getMode(args)))
-                    for (let name in values(map.names))
-                        yield { name: name, __proto__: map };
-            },
-            format: {
-                description: function (map) (XML.ignoreWhitespace = false, XML.prettyPrinting = false, <>
-                        {options.get("passkeys").has(map.name)
-                            ? <span highlight="URLExtra">({
-                                tempate.linkifyHelp(_("option.passkeys.passedBy"))
-                              })</span>
-                            : <></>}
-                        {template.linkifyHelp(map.description)}
-                </>)
-            }
-        };
-
         dactyl.addUsageCommand({
             name: ["listo[ptions]", "lo"],
             description: "List all options along with their short descriptions",
             index: "option",
             iterate: function (args) options,
             format: {
-                description: function (opt) (XML.ignoreWhitespace = false, XML.prettyPrinting = false, <>
-                        {opt.scope == Option.SCOPE_LOCAL
-                            ? <span highlight="URLExtra">({_("option.bufferLocal")})</span> : ""}
-                        {template.linkifyHelp(opt.description)}
-                </>),
+                description: function (opt) [
+                        opt.scope == Option.SCOPE_LOCAL
+                            ? ["span", { highlight: "URLExtra" },
+                                  "(" + _("option.bufferLocal") + ")"]
+                            : "",
+                        template.linkifyHelp(opt.description)
+                ],
                 help: function (opt) "'" + opt.name + "'"
             }
         });
@@ -1304,24 +1295,7 @@ var Options = Module("options", {
                 function fmt(value) (typeof value == "number"   ? "#" :
                                      typeof value == "function" ? "*" :
                                                                   " ") + value;
-                if (!args || args == "g:") {
-                    let str =
-                        <table>
-                        {
-                            template.map(globalVariables, function ([i, value]) {
-                                return <tr>
-                                            <td style="width: 200px;">{i}</td>
-                                            <td>{fmt(value)}</td>
-                                       </tr>;
-                            })
-                        }
-                        </table>;
-                    if (str.text().length() == str.*.length())
-                        dactyl.echomsg(_("variable.none"));
-                    else
-                        dactyl.echo(str, modules.commandline.FORCE_MULTILINE);
-                    return;
-                }
+                util.assert(!(!args || args == "g:"));
 
                 let matches = args.match(/^([a-z]:)?([\w]+)(?:\s*([-+.])?=\s*(.*)?)?$/);
                 if (matches) {
index 0ccf502c00984159200124271c2ff193df84b416..f8a4fb5d314bebe9beb2c649bf53a9a63801e454 100644 (file)
@@ -1,16 +1,17 @@
-// Copyright (c) 2009-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("overlay", {
     exports: ["overlay"],
     require: ["util"]
-}, this);
+});
+
+lazyRequire("highlight", ["highlight"]);
 
 var getAttr = function getAttr(elem, ns, name)
     elem.hasAttributeNS(ns, name) ? elem.getAttributeNS(ns, name) : null;
@@ -47,6 +48,8 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen
         util.addObserver(this);
         this.overlays = {};
 
+        this.weakMap = WeakMap();
+
         this.onWindowVisible = [];
     },
 
@@ -152,30 +155,39 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen
     },
 
     getData: function getData(obj, key, constructor) {
-        let { id } = this;
 
-        if (!(id in obj && obj[id]))
-            obj[id] = {};
+        if (!this.weakMap.has(obj))
+            try {
+                this.weakMap.set(obj, {});
+            }
+            catch (e if e instanceof TypeError) {
+                // util.dump("Bad WeakMap key: " + obj + " " + Components.stack.caller);
+                let { id } = this;
+
+                if (!(id in obj && obj[id]))
+                    obj[id] = {};
+
+                var data = obj[id];
+            }
+
+        data = data || this.weakMap.get(obj);
 
         if (arguments.length == 1)
-            return obj[id];
+            return data;
 
-        if (obj[id][key] === undefined)
+        if (data[key] === undefined)
             if (constructor === undefined || callable(constructor))
-                obj[id][key] = (constructor || Array)();
+                data[key] = (constructor || Array)();
             else
-                obj[id][key] = constructor;
+                data[key] = constructor;
 
-        return obj[id][key];
+        return data[key];
     },
 
     setData: function setData(obj, key, val) {
-        let { id } = this;
-
-        if (!(id in obj))
-            obj[id] = {};
+        let data = this.getData(obj);
 
-        return obj[id][key] = val;
+        return data[key] = val;
     },
 
     overlayWindow: function (url, fn) {
@@ -214,32 +226,56 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen
 
     _loadOverlay: function _loadOverlay(window, obj) {
         let doc = window.document;
-        let elems = this.getData(doc, "overlayElements");
-        let attrs = this.getData(doc, "overlayAttributes");
+        let savedElems = this.getData(doc, "overlayElements");
+        let savedAttrs = this.getData(doc, "overlayAttributes");
 
         function insert(key, fn) {
             if (obj[key]) {
                 let iterator = Iterator(obj[key]);
-                if (!isObject(obj[key]))
-                    iterator = ([elem.@id, elem.elements(), elem.@*::*.(function::name() != "id")] for each (elem in obj[key]));
+                if (isArray(obj[key])) {
+                    iterator = ([elem[1].id, elem.slice(2), elem[1]]
+                                for each (elem in obj[key]))
+                }
+
+                for (let [elem, xml, attrs] in iterator) {
+                    if (elem = doc.getElementById(String(elem))) {
+                        // Urgh. Hack.
+                        let namespaces;
+                        if (attrs && !isXML(attrs))
+                            namespaces = iter([k.slice(6), DOM.fromJSON.namespaces[v] || v]
+                                              for ([k, v] in Iterator(attrs))
+                                              if (/^xmlns(?:$|:)/.test(k))).toObject();
+
+                        let node;
+                        if (isXML(xml))
+                            node = DOM.fromXML(xml, doc, obj.objects);
+                        else
+                            node = DOM.fromJSON(xml, doc, obj.objects, namespaces);
 
-                for (let [elem, xml, attr] in iterator) {
-                    if (elem = doc.getElementById(elem)) {
-                        let node = DOM.fromXML(xml, doc, obj.objects);
                         if (!(node instanceof Ci.nsIDOMDocumentFragment))
-                            elems.push(node);
+                            savedElems.push(node);
                         else
                             for (let n in array.iterValues(node.childNodes))
-                                elems.push(n);
+                                savedElems.push(n);
 
                         fn(elem, node);
-                        for each (let attr in attr || []) {
-                            let ns = attr.namespace(), name = attr.localName();
-                            attrs.push([elem, ns, name, getAttr(elem, ns, name), String(attr)]);
-                            if (attr.name() != "highlight")
-                                elem.setAttributeNS(ns, name, String(attr));
+
+                        if (isXML(attrs))
+                            // Evilness and such.
+                            let (oldAttrs = attrs) {
+                                attrs = (attr for each (attr in oldAttrs));
+                            }
+
+                        for (let attr in attrs || []) {
+                            let [ns, localName] = DOM.parseNamespace(attr);
+                            let name = attr;
+                            let val = attrs[attr];
+
+                            savedAttrs.push([elem, ns, name, getAttr(elem, ns, name), val]);
+                            if (name === "highlight")
+                                highlight.highlightNode(elem, val);
                             else
-                                highlight.highlightNode(elem, String(attr));
+                                elem.setAttributeNS(ns || "", name, val);
                         }
                     }
                 }
index 3f865b61b959c901cd7dff5a3d41319e5e254b14..b0fdd176d6c80352de3b6722e6a95ca1515cc157 100644 (file)
@@ -1,20 +1,20 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("prefs", {
     exports: ["Prefs", "localPrefs", "prefs"],
     require: ["services", "util"]
-}, this);
+});
 
-this.lazyRequire("messages", ["_"]);
+lazyRequire("messages", ["_"]);
+lazyRequire("template", ["template"]);
 
 var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), {
     ORIGINAL: "extensions.dactyl.original.",
@@ -111,10 +111,11 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
             switch (type) {
             case Ci.nsIPrefBranch.PREF_STRING:
                 let value = this.branch.getComplexValue(name, Ci.nsISupportsString).data;
-                // try in case it's a localized string (will throw an exception if not)
-                if (!this.branch.prefIsLocked(name) && !this.branch.prefHasUserValue(name) &&
-                    RegExp("chrome://.+/locale/.+\\.properties").test(value))
-                        value = this.branch.getComplexValue(name, Ci.nsIPrefLocalizedString).data;
+                try {
+                    if (/^[a-z0-9-]+:/i.test(value))
+                    value = this.branch.getComplexValue(name, Ci.nsIPrefLocalizedString).data;
+                }
+                catch (e) {}
                 return value;
             case Ci.nsIPrefBranch.PREF_INT:
                 return this.branch.getIntPref(name);
@@ -404,7 +405,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
                 let option = {
                     isDefault: !userValue,
                     default:   this.defaults.get(pref, null),
-                    value:     <>={template.highlight(value, true, 100)}</>,
+                    value:     ["", "=", template.highlight(value, true, 100)],
                     name:      pref,
                     pre:       "\u00a0\u00a0" // Unicode nonbreaking space.
                 };
index edb642ecb888aff28704bdaa6f011a0ae69d9c03..82b59a39f2246d7a1a8fe09e1345a14dd08f8df0 100644 (file)
@@ -1,14 +1,13 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("protocol", {
     exports: ["LocaleChannel", "Protocol", "RedirectChannel", "StringChannel", "XMLChannel"],
     require: ["services", "util"]
-}, this);
+});
 
 var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].getService(Ci.nsIPrincipal);
 
@@ -51,8 +50,12 @@ function NetError(orig, error) {
     }).data.QueryInterface(Ci.nsIChannel);
 }
 function RedirectChannel(to, orig, time, message) {
-    let html = <html><head><meta http-equiv="Refresh" content={(time || 0) + ";" + to}/></head>
-                     <body><h2 style="text-align: center">{message || ""}</h2></body></html>.toXMLString();
+    let html = DOM.toXML(
+        ["html", {},
+            ["head", {},
+                ["meta", { "http-equiv": "Refresh", content: (time || 0) + ";" + to }]],
+            ["body", {},
+                ["h2", { style: "text-align: center" }, message || ""]]]);
     return StringChannel(html, "text/html", services.io.newURI(to, null, null));
 }
 
@@ -187,7 +190,7 @@ function XMLChannel(uri, contentType, noErrorChannel, unprivileged) {
     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[
+        let [, pre, doctype, url, extra, open, post] = util.regexp(literal(/*
                 ^ ([^]*?)
                 (?:
                     (<!DOCTYPE \s+ \S+ \s+) (?:SYSTEM \s+ "([^"]*)" | ((?:[^[>\s]|\s[^[])*))
@@ -195,7 +198,7 @@ function XMLChannel(uri, contentType, noErrorChannel, unprivileged) {
                     ([^]*)
                 )?
                 $
-            ]]>, "x").exec(stream.read(4096));
+            */), "x").exec(stream.read(4096));
         this.writes.push(pre);
         if (doctype) {
             this.writes.push(doctype + (extra || "") + " [\n");
@@ -224,6 +227,7 @@ XMLChannel.prototype = {
             this.writes.push(services.io.newChannel(url, null, this.uri).open());
         }
         catch (e) {
+            util.dump("addChannel('" + url + "'):");
             util.reportError(e);
         }
     },
index bbe36e2e244f9c7e6d9eb964e7f9c7a85a6f9317..9b4eb547805e9b2e8a859bf8be683d9dde855715 100644 (file)
@@ -1,9 +1,9 @@
 // Copyright (c) 2009 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2009-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2009-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 // TODO:
 //   - fix Sanitize autocommand
 // FIXME:
 //   - finish 1.9.0 support if we're going to support sanitizing in Melodactyl
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("sanitizer", {
     exports: ["Range", "Sanitizer", "sanitizer"],
     require: ["config", "prefs", "services", "util"]
-}, this);
+});
 
-this.lazyRequire("messages", ["_"]);
-this.lazyRequire("overlay", ["overlay"]);
-this.lazyRequire("storage", ["storage"]);
-this.lazyRequire("template", ["teplate"]);
+lazyRequire("messages", ["_"]);
+lazyRequire("overlay", ["overlay"]);
+lazyRequire("storage", ["storage"]);
+lazyRequire("template", ["template"]);
 
 let tmp = Object.create(this);
 JSMLoader.loadSubScript("chrome://browser/content/sanitize.js", tmp);
@@ -122,12 +121,16 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
             },
             override: true
         });
-        if (services.has("privateBrowsing"))
+        try {
+            var { ForgetAboutSite } = Cu.import("resource://gre/modules/ForgetAboutSite.jsm", {});
+        }
+        catch (e) {}
+        if (ForgetAboutSite)
             this.addItem("host", {
                 description: "All data from the given host",
                 action: function (range, host) {
                     if (host)
-                        services.privateBrowsing.removeDataFromDomain(host);
+                        ForgetAboutSite.removeDataFromDomain(host);
                 }
             });
         this.addItem("sitesettings", {
@@ -166,13 +169,12 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
         ];
 
         function prefOverlay(branch, persistent, local) update(Object.create(local), {
-            before: array.toObject([
-                [branch.substr(Item.PREFIX.length) + "history",
-                    <preferences xmlns={XUL}>{
-                      template.map(ourItems(persistent), function (item)
-                        <preference type="bool" id={branch + item.name} name={branch + item.name}/>)
-                    }</preferences>.*::*]
-            ]),
+            before: [
+                ["preferences", { id: branch.substr(Item.PREFIX.length) + "history",
+                                  xmlns: "xul" },
+                  template.map(ourItems(persistent), function (item)
+                      ["preference", { type: "bool", id: branch + item.name, name: branch + item.name }])]
+            ],
             init: function init(win) {
                 let pane = win.document.getElementById("SanitizeDialogPane");
                 for (let [, pref] in iter(pane.preferences))
@@ -188,20 +190,18 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
                                    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>{
+                            ["groupbox", { orient: "horizontal", xmlns: "xul" },
+                              ["caption", { label: config.appName + /*L*/" (see :help privacy)" }],
+                              ["grid", { flex: "1" },
+                                ["columns", {},
+                                    ["column", { flex: "1" }],
+                                    ["column", { flex: "1" }]],
+                                ["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>
+                                         ["row", {},
+                                             template.map(items.slice(i * 2, i * 2 + 2), function (item)
+                                                ["checkbox", { xmlns: XUL, label: item.description, preference: branch + item.name }])])]]],
                     }
                 }));
             }
@@ -209,16 +209,14 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
                 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();"/>)
-                            }
-                        </>
+                        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", preference: branch + item,
+                                               type: "checkbox", label: config.appName + ", " + desc,
+                                               onsyncfrompreference: "return gSanitizePromptDialog.onReadGeneric();" }]),
+                        ]
                     },
                     ready: function ready(win) {
                         let elem =  win.document.getElementById("itemList");
@@ -296,12 +294,32 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
         }
     },
 
+    /**
+     * Returns a load context for the given thing, to be used with
+     * interfaces needing one for per-window private browsing support.
+     *
+     * @param {Window|Document|Node} thing The thing for which to return
+     *      a load context.
+     */
+    getContext: function getContext(thing) {
+        if (!Ci.nsILoadContext)
+            return null;
+
+        if (thing instanceof Ci.nsIDOMNode && thing.ownerDocument)
+            thing = thing.ownerDocument;
+        if (thing instanceof Ci.nsIDOMDocument)
+            thing = thing.defaultView;
+        if (thing instanceof Ci.nsIInterfaceRequestor)
+            thing = thing.getInterface(Ci.nsIWebNavigation);
+        return thing.QueryInterface(Ci.nsILoadContext);
+    },
+
     get ranAtShutdown()    config.prefs.get("didSanitizeOnShutdown"),
     set ranAtShutdown(val) config.prefs.set("didSanitizeOnShutdown", Boolean(val)),
     get runAtShutdown()    prefs.get("privacy.sanitize.sanitizeOnShutdown"),
     set runAtShutdown(val) prefs.set("privacy.sanitize.sanitizeOnShutdown", Boolean(val)),
 
-    sanitize: function (items, range)
+    sanitize: function sanitize(items, range)
         this.withSavedValues(["sanitizing"], function () {
             this.sanitizing = true;
             let errors = this.sanitizeItems(items, range, null);
@@ -325,7 +343,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
             return errors;
         }),
 
-    sanitizeItems: function (items, range, host, key)
+    sanitizeItems: function sanitizeItems(items, range, host, key)
         this.withSavedValues(["sanitizing"], function () {
             this.sanitizing = true;
             if (items == null)
@@ -387,12 +405,12 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
                 yield p;
     }
 }, {
-    load: function (dactyl, modules, window) {
+    load: function initLoad(dactyl, modules, window) {
         if (!sanitizer.firstRun++ && sanitizer.runAtShutdown && !sanitizer.ranAtShutdown)
             sanitizer.sanitizeItems(null, Range(), null, "shutdown");
         sanitizer.ranAtShutdown = false;
     },
-    autocommands: function (dactyl, modules, window) {
+    autocommands: function initAutocommands(dactyl, modules, window) {
         const { autocommands } = modules;
 
         storage.addObserver("private-mode",
@@ -407,7 +425,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
                     autocommands.trigger("Sanitize", { name: event.substr("clear-".length), domain: value[1] });
             }, window);
     },
-    commands: function (dactyl, modules, window) {
+    commands: function initCommands(dactyl, modules, window) {
         const { commands } = modules;
         commands.add(["sa[nitize]"],
             "Clear private data",
@@ -504,7 +522,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
             }
             function setPerms(host, perm) {
                 let uri = util.createURI(host);
-                services.permissions.remove(uri, "cookie");
+                services.permissions.remove(uri.host, "cookie");
                 services.permissions.add(uri, "cookie", Sanitizer.PERMS[perm]);
             }
             commands.add(["cookies", "ck"],
@@ -534,7 +552,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
                                 ["Host", "Expiry (UTC)", "Path", "Name", "Value"],
                                 ["padding-right: 1em", "padding-right: 1em", "padding-right: 1em", "max-width: 12em; overflow: hidden;", "padding-left: 1ex;"],
                                 ([c.host,
-                                  c.isSession ? <span highlight="Enabled">session</span>
+                                  c.isSession ? ["span", { highlight: "Enabled" }, "session"]
                                               : (new Date(c.expiry * 1000).toJSON() || "Never").replace(/:\d\d\.000Z/, "").replace("T", " ").replace(/-/g, "/"),
                                   c.path,
                                   c.name,
@@ -556,7 +574,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
                                 let count = [0, 0];
                                 for (let c in Sanitizer.iterCookies(host))
                                     count[c.isSession + 0]++;
-                                return <>{Sanitizer.COMMANDS[getPerms(host)]} (session: {count[1]} persistent: {count[0]})</>;
+                                return [Sanitizer.COMMANDS[getPerms(host)], " (session: ", count[1], " persistent: ", count[0], ")"].join("");
                             };
                             break;
                         case 1:
@@ -566,7 +584,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
                     },
                 });
     },
-    completion: function (dactyl, modules, window) {
+    completion: function initCompletion(dactyl, modules, window) {
         modules.completion.visibleHosts = function completeHosts(context) {
             let res = util.visibleHosts(window.content);
             if (context.filter && !res.some(function (host) host.indexOf(context.filter) >= 0))
@@ -579,9 +597,9 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
             context.completions = res;
         };
     },
-    options: function (dactyl, modules) {
+    options: function initOptions(dactyl, modules) {
         const options = modules.options;
-        if (services.has("privateBrowsing"))
+        if (services.has("privateBrowsing") && "privateBrowsingEnabled" in services.privateBrowsing)
             options.add(["private", "pornmode"],
                 "Set the 'private browsing' option",
                 "boolean", false,
index 76c4b6bd7a69e9f1991da8c1700b5e21448f71bb..d3ac781fac3fdfff5fde6cf3a5ca43cfa444b45b 100644 (file)
@@ -1,16 +1,20 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 try {
 
 var global = this;
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("services", {
-    exports: ["services"]
-}, this);
+    exports: ["PrivateBrowsingUtils", "services"]
+});
+
+try {
+    var { PrivateBrowsingUtils } = Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
+}
+catch (e) {}
 
 /**
  * A lazily-instantiated XPCOM class and service cache.
@@ -27,7 +31,6 @@ var Services = Module("Services", {
         this.add("appShell",            "@mozilla.org/appshell/appShellService;1",          "nsIAppShellService");
         this.add("appStartup",          "@mozilla.org/toolkit/app-startup;1",               "nsIAppStartup");
         this.add("bookmarks",           "@mozilla.org/browser/nav-bookmarks-service;1",     "nsINavBookmarksService");
-        this.add("bootstrap",           "@dactyl.googlecode.com/base/bootstrap");
         this.add("browserSearch",       "@mozilla.org/browser/search-service;1",            "nsIBrowserSearchService");
         this.add("cache",               "@mozilla.org/network/cache-service;1",             "nsICacheService");
         this.add("charset",             "@mozilla.org/charset-converter-manager;1",         "nsICharsetConverterManager");
@@ -109,12 +112,13 @@ var Services = Module("Services", {
         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("XMLSerializer","@mozilla.org/xmlextras/xmlserializer;1",    ["nsIDOMSerializer"]);
         this.addClass("ZipReader",    "@mozilla.org/libjar/zip-reader;1",          "nsIZipReader", "open", false);
         this.addClass("ZipWriter",    "@mozilla.org/zipwriter;1",                  "nsIZipWriter", "open", false);
     },
     reinit: function () {},
 
-    _create: function (name, args) {
+    _create: function _create(name, args) {
         try {
             var service = this.services[name];
 
@@ -131,7 +135,10 @@ var Services = Module("Services", {
             }
             return res;
         }
-        catch (e if service.quiet !== false) {
+        catch (e) {
+            if (service.quiet === false)
+                throw e.stack ? e : Error(e);
+
             if (typeof util !== "undefined")
                 util.reportError(e);
             else
@@ -150,7 +157,7 @@ var Services = Module("Services", {
      * @param {string} meth The name of the function used to instantiate
      *     the service.
      */
-    add: function (name, class_, ifaces, meth) {
+    add: function add(name, class_, ifaces, meth) {
         const self = this;
         this.services[name] = { method: meth, class: class_, interfaces: Array.concat(ifaces || []) };
         if (name in this && ifaces && !this.__lookupGetter__(name) && !(this[name] instanceof Ci.nsISupports))
@@ -168,14 +175,14 @@ var Services = Module("Services", {
      * @param {string} init Name of a property or method used to initialize the
      *     class.
      */
-    addClass: function (name, class_, ifaces, init, quiet) {
+    addClass: function addClass(name, class_, ifaces, init, quiet) {
         const self = this;
         this.services[name] = { class: class_, interfaces: Array.concat(ifaces || []), method: "createInstance", init: init, quiet: quiet };
         if (init)
             memoize(this.services[name], "callable",
                     function () callable(XPCOMShim(this.interfaces)[this.init]));
 
-        this[name] = function () self._create(name, arguments);
+        this[name] = function Create() self._create(name, arguments);
         update.apply(null, [this[name]].concat([Ci[i] for each (i in Array.concat(ifaces))]));
         return this[name];
     },
@@ -199,7 +206,7 @@ var Services = Module("Services", {
      *
      * @param {string} name The service's cache key.
      */
-    has: function (name) Set.has(this.services, name) && this.services[name].class in Cc &&
+    has: function has(name) Set.has(this.services, name) && this.services[name].class in Cc &&
         this.services[name].interfaces.every(function (iface) iface in Ci)
 });
 
index 664124e883d6df3cb22d7ba826f49a09c0d19322..0f4cc06e7a83a41c0ca3e89dada9b422948c613e 100644 (file)
@@ -1,43 +1,21 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("storage", {
     exports: ["File", "Storage", "storage"],
     require: ["services", "util"]
-}, this);
+});
 
-this.lazyRequire("config", ["config"]);
-this.lazyRequire("io", ["IO"]);
+lazyRequire("config", ["config"]);
+lazyRequire("io", ["IO"]);
+lazyRequire("overlay", ["overlay"]);
 
 var win32 = /^win(32|nt)$/i.test(services.runtime.OS);
 var myObject = JSON.parse("{}").constructor;
 
-function loadData(name, store, type) {
-    try {
-        let file = storage.infoPath.child(name);
-        if (file.exists()) {
-            let data = file.read();
-            let result = JSON.parse(data);
-            if (result instanceof type)
-                return result;
-        }
-    }
-    catch (e) {
-        util.reportError(e);
-    }
-}
-
-function saveData(obj) {
-    if (obj.privateData && storage.privateMode)
-        return;
-    if (obj.store && storage.infoPath)
-        storage.infoPath.child(obj.name).write(obj.serial);
-}
-
 var StoreBase = Class("StoreBase", {
     OPTIONS: ["privateData", "replacer"],
 
@@ -47,6 +25,7 @@ var StoreBase = Class("StoreBase", {
 
     init: function (name, store, load, options) {
         this._load = load;
+        this._options = options;
 
         this.__defineGetter__("store", function () store);
         this.__defineGetter__("name", function () name);
@@ -56,7 +35,14 @@ var StoreBase = Class("StoreBase", {
         this.reload();
     },
 
-    changed: function () { this.timer.tell(); },
+    clone: function (storage) {
+        let store = storage.privateMode ? false : this.store;
+        let res = this.constructor(this.name, store, this._load, this._options);
+        res.storage = storage;
+        return res;
+    },
+
+    changed: function () { this.timer && this.timer.tell(); },
 
     reload: function reload() {
         this._object = this._load() || this._constructor();
@@ -69,7 +55,7 @@ var StoreBase = Class("StoreBase", {
         storage.infoPath.child(this.name).remove(false);
     },
 
-    save: function () { saveData(this); },
+    save: function () { (self.storage || storage)._saveData(this); },
 
     __iterator__: function () Iterator(this._object)
 });
@@ -176,15 +162,24 @@ var ObjectStore = Class("ObjectStore", StoreBase, {
     }
 });
 
+var sessionGlobal = Cu.import("resource://gre/modules/Services.jsm", {})
+
 var Storage = Module("Storage", {
+    Local: function Local(dactyl, modules, window) ({
+        init: function init() {
+            this.privateMode = PrivateBrowsingUtils.isWindowPrivate(window);
+        }
+    }),
+
     alwaysReload: {},
 
-    init: function () {
+    init: function init() {
         this.cleanup();
 
-        if (services.bootstrap && !services.bootstrap.session)
-            services.bootstrap.session = {};
-        this.session = services.bootstrap ? services.bootstrap.session : {};
+        let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+        if (!Services.dactylSession)
+            Services.dactylSession = Cu.createObjectIn(sessionGlobal);
+        this.session = Services.dactylSession;
     },
 
     cleanup: function () {
@@ -200,6 +195,35 @@ var Storage = Module("Storage", {
         this.observers = {};
     },
 
+    _loadData: function loadData(name, store, type) {
+        try {
+            let file = storage.infoPath.child(name);
+            if (file.exists()) {
+                let data = file.read();
+                let result = JSON.parse(data);
+                if (result instanceof type)
+                    return result;
+            }
+        }
+        catch (e) {
+            util.reportError(e);
+        }
+    },
+
+    _saveData: function saveData(obj) {
+        if (obj.privateData && storage.privateMode)
+            return;
+        if (obj.store && storage.infoPath)
+            storage.infoPath.child(obj.name).write(obj.serial);
+    },
+
+    storeForSession: function storeForSession(key, val) {
+        if (val)
+            this.session[key] = sessionGlobal.JSON.parse(JSON.stringify(val));
+        else
+            delete this.dactylSession[key];
+    },
+
     infoPath: Class.Memoize(function ()
         File(IO.runtimePath.replace(/,.*/, ""))
             .child("info").child(config.profileName)),
@@ -217,16 +241,30 @@ var Storage = Module("Storage", {
     },
 
     newObject: function newObject(key, constructor, params) {
+        let self = this;
         if (params == null || !isObject(params))
             throw Error("Invalid argument type");
 
-        if (!(key in this.keys) || params.reload || this.alwaysReload[key]) {
-            if (key in this && !(params.reload || this.alwaysReload[key]))
-                throw Error();
-            let load = function () loadData(key, params.store, params.type || myObject);
+        if (this.isLocalModule) {
+            this.globalInstance.newObject.apply(this.globalInstance, arguments);
+
+            if (!(key in this.keys) && this.privateMode && key in this.globalInstance.keys) {
+                let obj = this.globalInstance.keys[key];
+                this.keys[key] = this._privatize(obj);
+            }
+
+            return this.keys[key];
+        }
+
+        let reload = params.reload || this.alwaysReload[key];
+        if (!(key in this.keys) || reload) {
+            if (key in this && !reload)
+                throw Error("Cannot add storage key with that name.");
+
+            let load = function () self._loadData(key, params.store, params.type || myObject);
 
             this.keys[key] = new constructor(key, params.store, load, params);
-            this.keys[key].timer = new Timer(1000, 10000, function () storage.save(key));
+            this.keys[key].timer = new Timer(1000, 10000, function () self.save(key));
             this.__defineGetter__(key, function () this.keys[key]);
         }
         return this.keys[key];
@@ -249,27 +287,38 @@ var Storage = Module("Storage", {
         else {
             callbackRef = { get: function () callback };
         }
+
         this.removeDeadObservers();
+
         if (!(key in this.observers))
             this.observers[key] = [];
+
         if (!this.observers[key].some(function (o) o.callback.get() == callback))
             this.observers[key].push({ ref: ref && Cu.getWeakReference(ref), callback: callbackRef });
     },
 
     removeObserver: function (key, callback) {
         this.removeDeadObservers();
+
         if (!(key in this.observers))
             return;
+
         this.observers[key] = this.observers[key].filter(function (elem) elem.callback.get() != callback);
         if (this.observers[key].length == 0)
             delete obsevers[key];
     },
 
     removeDeadObservers: function () {
+        function filter(o) {
+            if (!o.callback.get())
+                return false;
+
+            let ref = o.ref && o.ref.get();
+            return ref && !ref.closed && overlay.getData(ref, "storage-refs", null);
+        }
+
         for (let [key, ary] in Iterator(this.observers)) {
-            this.observers[key] = ary = ary.filter(function (o) o.callback.get()
-                                                             && (!o.ref || o.ref.get()
-                                                                        && overlay.getData(o.ref.get(), "storage-refs", null)));
+            this.observers[key] = ary = ary.filter(filter);
             if (!ary.length)
                 delete this.observers[key];
         }
@@ -277,11 +326,13 @@ var Storage = Module("Storage", {
 
     fireEvent: function fireEvent(key, event, arg) {
         this.removeDeadObservers();
+
         if (key in this.observers)
             // Safe, since we have our own Array object here.
             for each (let observer in this.observers[key])
                 observer.callback.get()(key, event, arg);
-        if (key in this.keys)
+
+        if (key in this.keys && this.keys[key].timer)
             this[key].timer.tell();
     },
 
@@ -292,24 +343,39 @@ var Storage = Module("Storage", {
 
     save: function save(key) {
         if (this[key])
-            saveData(this.keys[key]);
+            this._saveData(this.keys[key]);
     },
 
     saveAll: function storeAll() {
         for each (let obj in this.keys)
-            saveData(obj);
+            this._saveData(obj);
     },
 
     _privateMode: false,
     get privateMode() this._privateMode,
-    set privateMode(val) {
-        if (val && !this._privateMode)
+    set privateMode(enabled) {
+        this._privateMode = Boolean(enabled);
+
+        if (this.isLocalModule) {
             this.saveAll();
-        if (!val && this._privateMode)
-            for (let key in this.keys)
-                this.load(key);
-        return this._privateMode = Boolean(val);
-    }
+
+            if (!enabled)
+                delete this.keys;
+            else {
+                let { keys } = this;
+                this.keys = {};
+                for (let [k, v] in Iterator(keys))
+                    this.keys[k] = this._privatize(v);
+            }
+        }
+        return this._privateMode;
+    },
+
+    _privatize: function privatize(obj) {
+        if (obj.privateData && obj.clone)
+            return obj.clone(this);
+        return obj;
+    },
 }, {
     Replacer: {
         skipXpcom: function skipXpcom(key, val) val instanceof Ci.nsISupports ? null : val
@@ -340,7 +406,7 @@ var File = Class("File", {
         if (path instanceof Ci.nsIFileURL)
             path = path.file;
 
-        if (path instanceof Ci.nsIFile)
+        if (path instanceof Ci.nsIFile || path instanceof File)
             file = path.clone();
         else if (/file:\/\//.test(path))
             file = services["file:"].getFileFromURLSpec(path);
@@ -358,9 +424,8 @@ var File = Class("File", {
                 return File.DoesNotExist(path, e);
             }
         }
-        let self = XPCSafeJSObjectWrapper(file.QueryInterface(Ci.nsILocalFile));
-        self.__proto__ = this;
-        return self;
+        this.file = file.QueryInterface(Ci.nsILocalFile);
+        return this;
     },
 
     charset: Class.Memoize(function () File.defaultEncoding),
@@ -369,7 +434,8 @@ var File = Class("File", {
      * @property {nsIFileURL} Returns the nsIFileURL object for this file.
      */
     URI: Class.Memoize(function () {
-        let uri = services.io.newFileURI(this).QueryInterface(Ci.nsIFileURL);
+        let uri = services.io.newFileURI(this.file)
+                          .QueryInterface(Ci.nsIFileURL);
         uri.QueryInterface(Ci.nsIMutable).mutable = false;
         return uri;
     }),
@@ -377,7 +443,7 @@ var File = Class("File", {
     /**
      * Iterates over the objects in this directory.
      */
-    iterDirectory: function () {
+    iterDirectory: function iterDirectory() {
         if (!this.exists())
             throw Error(_("io.noSuchFile"));
         if (!this.isDirectory())
@@ -389,17 +455,18 @@ var File = Class("File", {
     /**
      * Returns a new file for the given child of this directory entry.
      */
-    child: function (name) {
+    child: function child() {
         let f = this.constructor(this);
-        for each (let elem in name.split(File.pathSplit))
-            f.append(elem);
+        for (let [, name] in Iterator(arguments))
+            for each (let elem in name.split(File.pathSplit))
+                f.append(elem);
         return f;
     },
 
     /**
      * Returns an iterator for all lines in a file.
      */
-    get lines() File.readLines(services.FileInStream(this, -1, 0, 0),
+    get lines() File.readLines(services.FileInStream(this.file, -1, 0, 0),
                                this.charset),
 
     /**
@@ -410,8 +477,8 @@ var File = Class("File", {
      *          @default #charset
      * @returns {string}
      */
-    read: function (encoding) {
-        let ifstream = services.FileInStream(this, -1, 0, 0);
+    read: function read(encoding) {
+        let ifstream = services.FileInStream(this.file, -1, 0, 0);
 
         return File.readStream(ifstream, encoding || this.charset);
     },
@@ -423,7 +490,7 @@ var File = Class("File", {
      *     entries.
      * @returns {[nsIFile]}
      */
-    readDirectory: function (sort) {
+    readDirectory: function readDirectory(sort) {
         if (!this.isDirectory())
             throw Error(_("io.eNotDir"));
 
@@ -438,7 +505,7 @@ var File = Class("File", {
      *
      * @returns {nsIFileURL}
      */
-    toURI: function toURI() services.io.newFileURI(this),
+    toURI: function toURI() services.io.newFileURI(this.file),
 
     /**
      * Writes the string *buf* to this file.
@@ -464,7 +531,7 @@ var File = Class("File", {
      * @param {string} encoding The encoding to used to write the file.
      * @default #charset
      */
-    write: function (buf, mode, perms, encoding) {
+    write: function write(buf, mode, perms, encoding) {
         function getStream(defaultChar) {
             return services.ConvOutStream(ofstream, encoding, 0, defaultChar);
         }
@@ -484,7 +551,7 @@ var File = Class("File", {
         if (!this.exists()) // OCREAT won't create the directory
             this.create(this.NORMAL_FILE_TYPE, perms);
 
-        let ofstream = services.FileOutStream(this, mode, perms, 0);
+        let ofstream = services.FileOutStream(this.file, mode, perms, 0);
         try {
             var ocstream = getStream(0);
             ocstream.writeString(buf);
@@ -503,7 +570,34 @@ var File = Class("File", {
             ofstream.close();
         }
         return true;
-    }
+    },
+
+    // Wrapped native methods:
+    copyTo: function copyTo(dir, name)
+        this.file.copyTo(this.constructor(dir).file,
+                         name),
+
+    copyToFollowingLinks: function copyToFollowingLinks(dir, name)
+        this.file.copyToFollowingLinks(this.constructor(dir).file,
+                                       name),
+
+    moveTo: function moveTo(dir, name)
+        this.file.moveTo(this.constructor(dir).file,
+                         name),
+
+    equals: function equals(file)
+        this.file.equals(this.constructor(file).file),
+
+    contains: function contains(dir, recur)
+        this.file.contains(this.constructor(dir).file,
+                           recur),
+
+    getRelativeDescriptor: function getRelativeDescriptor(file)
+        this.file.getRelativeDescriptor(this.constructor(file).file),
+
+    setRelativeDescriptor: function setRelativeDescriptor(file, path)
+        this.file.setRelativeDescriptor(this.constructor(file).file,
+                                        path)
 }, {
     /**
      * @property {number} Open for reading only.
@@ -694,6 +788,28 @@ var File = Class("File", {
     replacePathSep: function (path) path.replace("/", File.PATH_SEP, "g")
 });
 
+let (file = services.directory.get("ProfD", Ci.nsIFile)) {
+    Object.keys(file).forEach(function (prop) {
+        if (!(prop in File.prototype)) {
+            let isFunction;
+            try {
+                isFunction = callable(file[prop])
+            }
+            catch (e) {}
+
+            if (isFunction)
+                File.prototype[prop] = util.wrapCallback(function wrapper() this.file[prop].apply(this.file, arguments));
+            else
+                Object.defineProperty(File.prototype, prop, {
+                    configurable: true,
+                    get: function wrap_get() this.file[prop],
+                    set: function wrap_set(val) { this.file[prop] = val; }
+                });
+        }
+    });
+    file = null;
+}
+
 endModule();
 
 // catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
index 98d49605a4b4edeb7ad3dde0535d2c37994236aa..c89c2812ef454217e315d0f1388ecb3068ce204d 100644 (file)
@@ -1,19 +1,21 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("styles", {
     exports: ["Style", "Styles", "styles"],
     require: ["services", "util"]
-}, this);
+});
+
+lazyRequire("contexts", ["Contexts"]);
+lazyRequire("template", ["template"]);
 
 function cssUri(css) "chrome-data:text/css," + encodeURI(css);
-var namespace = "@namespace html " + XHTML.uri.quote() + ";\n" +
-                "@namespace xul " + XUL.uri.quote() + ";\n" +
-                "@namespace dactyl " + NS.uri.quote() + ";\n";
+var namespace = "@namespace html " + XHTML.quote() + ";\n" +
+                "@namespace xul " + XUL.quote() + ";\n" +
+                "@namespace dactyl " + NS.quote() + ";\n";
 
 var Sheet = Struct("name", "id", "sites", "css", "hive", "agent");
 Sheet.liveProperty = function (name) {
@@ -34,8 +36,8 @@ Sheet.liveProperty("sites");
 update(Sheet.prototype, {
     formatSites: function (uris)
           template.map(this.sites,
-                       function (filter) <span highlight={uris.some(Styles.matchFilter(filter)) ? "Filter" : ""}>{filter}</span>,
-                       <>,</>),
+                       function (filter) ["span", { highlight: uris.some(Styles.matchFilter(filter)) ? "Filter" : "" }, filter],
+                       ","),
 
     remove: function () { this.hive.remove(this); },
 
@@ -314,38 +316,34 @@ var Styles = Module("Styles", {
 
         let uris = util.visibleURIs(content);
 
-        let list = <table>
-                <tr highlight="Title">
-                    <td/>
-                    <td/>
-                    <td style="padding-right: 1em;">{_("title.Name")}</td>
-                    <td style="padding-right: 1em;">{_("title.Filter")}</td>
-                    <td style="padding-right: 1em;">{_("title.CSS")}</td>
-                </tr>
-                <col style="min-width: 4em; padding-right: 1em;"/>
-                <col style="min-width: 1em; text-align: center; color: red; font-weight: bold;"/>
-                <col style="padding: 0 1em 0 1ex; vertical-align: top;"/>
-                <col style="padding: 0 1em 0 0; vertical-align: top;"/>
-                {
-                    template.map(hives, function (hive) let (i = 0)
-                        <tr style="height: .5ex;"/> +
-                        template.map(sheets(hive), function (sheet)
-                            <tr>
-                                <td highlight="Title">{!i++ ? hive.name : ""}</td>
-                                <td>{sheet.enabled ? "" : UTF8("×")}</td>
-                                <td>{sheet.name || hive.sheets.indexOf(sheet)}</td>
-                                <td>{sheet.formatSites(uris)}</td>
-                                <td>{sheet.css}</td>
-                            </tr>) +
-                        <tr style="height: .5ex;"/>)
-                }
-                </table>;
-
-        // TODO: Move this to an ItemList to show this automatically
-        if (list.*.length() === list.text().length() + 5)
-            dactyl.echomsg(_("style.none"));
-        else
-            commandline.commandOutput(list);
+        let list = ["table", {},
+                ["tr", { highlight: "Title" },
+                    ["td"],
+                    ["td"],
+                    ["td", { style: "padding-right: 1em;" }, _("title.Name")],
+                    ["td", { style: "padding-right: 1em;" }, _("title.Filter")],
+                    ["td", { style: "padding-right: 1em;" }, _("title.CSS")]],
+                ["col", { style: "min-width: 4em; padding-right: 1em;" }],
+                ["col", { style: "min-width: 1em; text-align: center; color: red; font-weight: bold;" }],
+                ["col", { style: "padding: 0 1em 0 1ex; vertical-align: top;" }],
+                ["col", { style: "padding: 0 1em 0 0; vertical-align: top;" }],
+                template.map(hives, function (hive) let (i = 0) [
+                    ["tr", { style: "height: .5ex;" }],
+                    template.map(sheets(hive), function (sheet)
+                        ["tr", {},
+                            ["td", { highlight: "Title" }, !i++ ? hive.name : ""],
+                            ["td", {}, sheet.enabled ? "" : UTF8("×")],
+                            ["td", {}, sheet.name || hive.sheets.indexOf(sheet)],
+                            ["td", {}, sheet.formatSites(uris)],
+                            ["td", {}, sheet.css]]),
+                    ["tr", { style: "height: .5ex;" }]])];
+
+        // E4X-FIXME
+        // // TODO: Move this to an ItemList to show this automatically
+        // if (list.*.length() === list.text().length() + 5)
+        //     dactyl.echomsg(_("style.none"));
+        // else
+        commandline.commandOutput(list);
     },
 
     registerSheet: function registerSheet(url, agent, reload) {
@@ -463,7 +461,7 @@ var Styles = Module("Styles", {
         }
     },
 
-    propertyPattern: util.regexp(<![CDATA[
+    propertyPattern: util.regexp(literal(/*
             (?:
                 (?P<preSpace> <space>*)
                 (?P<name> [-a-z]*)
@@ -485,14 +483,14 @@ var Styles = Module("Styles", {
                 )?
             )
             (?P<postSpace> <space>* (?: ; | $) )
-        ]]>, "gix",
+        */), "gix",
         {
             space: /(?: \s | \/\* .*? \*\/ )/,
             string: /(?:" (?:[^\\"]|\\.)* (?:"|$) | '(?:[^\\']|\\.)* (?:'|$) )/
         }),
 
     patterns: memoize({
-        get property() util.regexp(<![CDATA[
+        get property() util.regexp(literal(/*
                 (?:
                     (?P<preSpace> <space>*)
                     (?P<name> [-a-z]*)
@@ -503,26 +501,26 @@ var Styles = Module("Styles", {
                     )?
                 )
                 (?P<postSpace> <space>* (?: ; | $) )
-            ]]>, "gix", this),
+            */), "gix", this),
 
-        get function() util.regexp(<![CDATA[
+        get function() util.regexp(literal(/*
                 (?P<function>
                     \s* \( \s*
                         (?: <string> | [^)]*  )
                     \s* (?: \) | $)
                 )
-            ]]>, "gx", this),
+            */), "gx", this),
 
         space: /(?: \s | \/\* .*? \*\/ )/,
 
-        get string() util.regexp(<![CDATA[
+        get string() util.regexp(literal(/*
                 (?P<string>
                     " (?:[^\\"]|\\.)* (?:"|$) |
                     ' (?:[^\\']|\\.)* (?:'|$)
                 )
-            ]]>, "gx", this),
+            */), "gx", this),
 
-        get token() util.regexp(<![CDATA[
+        get token() util.regexp(literal(/*
             (?P<token>
                 (?P<word> [-\w]+)
                 <function>?
@@ -532,7 +530,7 @@ var Styles = Module("Styles", {
                 | <space>+
                 | [^;}\s]+
             )
-        ]]>, "gix", this)
+        */), "gix", this)
     }),
 
     /**
@@ -545,7 +543,7 @@ var Styles = Module("Styles", {
         return '"' + str.replace(/([\\"])/g, "\\$1").replace(/\n/g, "\\00000a") + '"';
     },
 }, {
-    commands: function (dactyl, modules, window) {
+    commands: function initCommands(dactyl, modules, window) {
         const { commands, contexts, styles } = modules;
 
         function sheets(context, args, filter) {
@@ -553,7 +551,7 @@ var Styles = Module("Styles", {
             context.compare = modules.CompletionContext.Sort.number;
             context.generate = function () args["-group"].sheets;
             context.keys.active = function (sheet) uris.some(sheet.closure.match);
-            context.keys.description = function (sheet) <>{sheet.formatSites(uris)}: {sheet.css.replace("\n", "\\n")}</>
+            context.keys.description = function (sheet) [sheet.formatSites(uris), ": ", sheet.css.replace("\n", "\\n")];
             if (filter)
                 context.filters.push(function ({ item }) filter(item));
             Styles.splitContext(context);
@@ -694,7 +692,7 @@ var Styles = Module("Styles", {
                 });
         });
     },
-    contexts: function (dactyl, modules, window) {
+    contexts: function initContexts(dactyl, modules, window) {
         modules.contexts.Hives("styles",
             Class("LocalHive", Contexts.Hive, {
                 init: function init(group) {
@@ -715,8 +713,8 @@ var Styles = Module("Styles", {
                 }
             }));
     },
-    completion: function (dactyl, modules, window) {
-        const names = Array.slice(DOM(<div/>, window.document).style);
+    completion: function initCompletion(dactyl, modules, window) {
+        const names = Array.slice(DOM(["div"], window.document).style);
         modules.completion.css = function (context) {
             context.title = ["CSS Property"];
             context.keys = { text: function (p) p + ":", description: function () "" };
@@ -730,7 +728,7 @@ var Styles = Module("Styles", {
             }
         };
     },
-    javascript: function (dactyl, modules, window) {
+    javascript: function initJavascript(dactyl, modules, window) {
         modules.JavaScript.setCompleter(["get", "add", "remove", "find"].map(function (m) Hive.prototype[m]),
             [ // Prototype: (name, filter, css, index)
                 function (context, obj, args) this.names,
@@ -739,35 +737,36 @@ var Styles = Module("Styles", {
                 function (context, obj, args) this.sheets
             ]);
     },
-    template: function () {
+    template: function initTemplate() {
         let patterns = Styles.patterns;
 
         template.highlightCSS = function highlightCSS(css) {
-            XML.prettyPrinting = XML.ignoreWhitespace = false;
-
             return this.highlightRegexp(css, patterns.property, function (match) {
                 if (!match.length)
-                    return <></>;
-                return <>{match.preSpace}{template.filter(match.name)}: {
+                    return [];
+                return ["", match.preSpace, template.filter(match.name), ": ",
 
                     template.highlightRegexp(match.value, patterns.token, function (match) {
                         if (match.function)
-                            return <>{template.filter(match.word)}{
+                            return ["", template.filter(match.word),
                                 template.highlightRegexp(match.function, patterns.string,
-                                    function (match) <span highlight="String">{match.string}</span>)
-                            }</>;
+                                    function (match) ["span", { highlight: "String" }, match.string])
+                            ];
                         if (match.important == "!important")
-                            return <span highlight="String">{match.important}</span>;
+                            return ["span", { highlight: "String" }, match.important];
                         if (match.string)
-                            return <span highlight="String">{match.string}</span>;
-                        return template.highlightRegexp(match.wholeMatch, /^(\d+)(em|ex|px|in|cm|mm|pt|pc)?/g,
-                                                        function (m, n, u) <><span highlight="Number">{n}</span><span highlight="Object">{u || ""}</span></>);
-                    })
-
-                }{ match.postSpace }</>
+                            return ["span", { highlight: "String" }, match.string];
+                        return template._highlightRegexp(match.wholeMatch, /^(\d+)(em|ex|px|in|cm|mm|pt|pc)?/g,
+                                                         function (m, n, u) [
+                                                             ["span", { highlight: "Number" }, n],
+                                                             ["span", { highlight: "Object" }, u || ""]
+                                                         ]);
+                    }),
+                    match.postSpace
+                ]
             })
         }
-    },
+    }
 });
 
 endModule();
index 09300d0e888a419ac729d90439ed92d1b53bb29b..47fd94db2214804890fd76f9f85f26bdd788570b 100644 (file)
@@ -1,17 +1,16 @@
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k at Gmail>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 let global = this;
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("template", {
     exports: ["Binding", "Template", "template"],
     require: ["util"]
-}, this);
+});
 
-default xml namespace = XHTML;
+lazyRequire("help", ["help"]);
 
 var Binding = Class("Binding", {
     init: function (node, nodes) {
@@ -92,27 +91,6 @@ var Binding = Class("Binding", {
 });
 
 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 = XML.prettyPrinting = false;
-        if (typeof iter.length == "number") // FIXME: Kludge?
-            iter = array.iterValues(iter);
-        let res = <></>;
-        let n = 0;
-        for each (let i in Iterator(iter)) {
-            let val = func(i, n);
-            if (val == undefined)
-                continue;
-            if (n++ && sep)
-                res += sep;
-            if (interruptable && n % interruptable == 0)
-                util.threadYield(true, true);
-            res += val;
-        }
-        return res;
-    },
 
     bindings: {
         Button: Class("Button", Binding, {
@@ -171,22 +149,42 @@ var Template = Module("Template", {
         })
     },
 
-    bookmarkDescription: function (item, text)
-    <>
-        {
-            !(item.extra && item.extra.length) ? "" :
-            <span highlight="URLExtra">
-                ({
-                    template.map(item.extra, function (e)
-                    <>{e[0]}: <span highlight={e[2]}>{e[1]}</span></>,
-                    <>&#xa0;</>)
-                })&#xa0;</span>
+    map: function map(iter, func, sep, interruptable) {
+        if (typeof iter.length == "number") // FIXME: Kludge?
+            iter = array.iterValues(iter);
+
+        let res = [];
+        let n = 0;
+        for each (let i in Iterator(iter)) {
+            let val = func(i, n);
+            if (val == undefined)
+                continue;
+            if (n++ && sep)
+                res.push(sep);
+            if (interruptable && n % interruptable == 0)
+                util.threadYield(true, true);
+            res.push(val);
         }
-        <a xmlns:dactyl={NS} identifier={item.id == null ? "" : item.id} dactyl:command={item.command || ""}
-           href={item.item.url} highlight="URL">{text || ""}</a>
-    </>,
+        return res;
+    },
+
+
+    bookmarkDescription: function (item, text) [
+        !(item.extra && item.extra.length) ? [] :
+        ["span", { highlight: "URLExtra" },
+            " (",
+            template.map(item.extra, function (e)
+                ["", e[0], ": ",
+                 ["span", { highlight: e[2] }, e[1]]],
+                "\u00a0"),
+            ")\u00a0"],
+        ["a", { identifier: item.id == null ? "" : item.id,
+                "dactyl:command": item.command || "",
+                href: item.item.url, highlight: "URL" },
+            text || ""]
+    ],
 
-    filter: function (str) <span highlight="Filter">{str}</span>,
+    filter: function (str) ["span", { highlight: "Filter" }, str],
 
     completionRow: function completionRow(item, highlightGroup) {
         if (typeof icon == "function")
@@ -201,17 +199,15 @@ var Template = Module("Template", {
             var desc = this.processor[1].call(this, item, item.description);
         }
 
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        // <e4x>
-        return <div highlight={highlightGroup || "CompItem"} style="white-space: nowrap">
-                   <!-- The non-breaking spaces prevent empty elements
-                      - from pushing the baseline down and enlarging
-                      - the row.
-                      -->
-                   <li highlight={"CompResult " + item.highlight}>{text}&#xa0;</li>
-                   <li highlight="CompDesc">{desc}&#xa0;</li>
-               </div>;
-        // </e4x>
+        return ["div", { highlight: highlightGroup || "CompItem", style: "white-space: nowrap" },
+                   /* The non-breaking spaces prevent empty elements
+                    * from pushing the baseline down and enlarging
+                    * the row.
+                    */
+                   ["li", { highlight: "CompResult " + item.highlight },
+                       text, "\u00a0"],
+                   ["li", { highlight: "CompDesc" },
+                       desc, "\u00a0"]];
     },
 
     helpLink: function (token, text, type) {
@@ -225,14 +221,16 @@ var Template = Module("Template", {
             topic = topic.slice(2);
 
         if (help.initialized && !Set.has(help.tags, topic))
-            return <span highlight={type || ""}>{text || token}</span>;
+            return ["span", { highlight: type || ""}, text || token];
 
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
         type = type || (/^'.*'$/.test(token)   ? "HelpOpt" :
                         /^\[.*\]$|^E\d{3}$/.test(token) ? "HelpTopic" :
                         /^:\w/.test(token)     ? "HelpEx"  : "HelpKey");
 
-        return <a highlight={"InlineHelpLink " + type} tag={topic} href={"dactyl://help-tag/" + topic} dactyl:command="dactyl.help" xmlns:dactyl={NS}>{text || topic}</a>;
+        return ["a", { highlight: "InlineHelpLink " + type, tag: topic,
+                       href: "dactyl://help-tag/" + topic,
+                       "dactyl:command": "dactyl.help" },
+                    text || topic];
     },
     HelpLink: function (token) {
         if (!help.initialized)
@@ -245,28 +243,28 @@ var Template = Module("Template", {
             topic = topic.slice(2);
 
         if (help.initialized && !Set.has(help.tags, topic))
-            return <>{token}</>;
+            return token;
 
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
         let tag = (/^'.*'$/.test(token)            ? "o" :
                    /^\[.*\]$|^E\d{3}$/.test(token) ? "t" :
                    /^:\w/.test(token)              ? "ex"  : "k");
 
         topic = topic.replace(/^'(.*)'$/, "$1");
-        return <{tag} xmlns={NS}>{topic}</{tag}>;
+        return [tag, { xmlns: "dactyl" }, topic];
     },
     linkifyHelp: function linkifyHelp(str, help) {
-        let re = util.regexp(<![CDATA[
+        let re = util.regexp(literal(/*
             (?P<pre> [/\s]|^)
             (?P<tag> '[\w-]+' | :(?:[\w-]+!?|!) | (?:._)?<[\w-]+>\w* | \b[a-zA-Z]_(?:[\w[\]]+|.) | \[[\w-;]+\] | E\d{3} )
             (?=      [[\)!,:;./\s]|$)
-        ]]>, "gx");
+        */), "gx");
         return this.highlightSubstrings(str, (function () {
             for (let res in re.iterate(str))
                 yield [res.index + res.pre.length, res.tag.length];
-        })(), template[help ? "HelpLink" : "helpLink"]);
+        })(), this[help ? "HelpLink" : "helpLink"]);
     },
 
+
     // Fixes some strange stack rewinds on NS_ERROR_OUT_OF_MEMORY
     // exceptions that we can't catch.
     stringify: function stringify(arg) {
@@ -282,12 +280,12 @@ var Template = Module("Template", {
         }
     },
 
-    _sandbox: Class.Memoize(function () Cu.Sandbox(global, { wantXrays: false })),
+    _sandbox: Class.Memoize(function () Cu.Sandbox(Cu.getGlobalForObject(global),
+                                                   { wantXrays: false })),
 
     // 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 = XML.prettyPrinting = false;
         // some objects like window.JSON or getBrowsers()._browsers need the try/catch
         try {
             let str = this.stringify(arg);
@@ -295,44 +293,44 @@ var Template = Module("Template", {
                 str = util.clip(str, clip);
             switch (arg == null ? "undefined" : typeof arg) {
             case "number":
-                return <span highlight="Number">{str}</span>;
+                return ["span", { highlight: "Number" }, str];
             case "string":
                 if (processStrings)
                     str = str.quote();
-                return <span highlight="String">{str}</span>;
+                return ["span", { highlight: "String" }, str];
             case "boolean":
-                return <span highlight="Boolean">{str}</span>;
+                return ["span", { highlight: "Boolean" }, str];
             case "function":
                 if (arg instanceof Ci.nsIDOMElement) // wtf?
                     return util.objectToString(arg, !bw);
 
                 str = str.replace("/* use strict */ \n", "/* use strict */ ");
                 if (processStrings)
-                    return <span highlight="Function">{str.replace(/\{(.|\n)*(?:)/g, "{ ... }")}</span>;
-                    <>}</>; /* Vim */
+                    return ["span", { highlight: "Function" },
+                                str.replace(/\{(.|\n)*(?:)/g, "{ ... }")];
                 arg = String(arg).replace("/* use strict */ \n", "/* use strict */ ");
-                return <>{arg}</>;
+                return arg;
             case "undefined":
-                return <span highlight="Null">{arg}</span>;
+                return ["span", { highlight: "Null" }, "undefined"];
             case "object":
                 if (arg instanceof Ci.nsIDOMElement)
                     return util.objectToString(arg, !bw);
+                if (arg instanceof util.Magic)
+                    return String(arg);
 
-                // for java packages value.toString() would crash so badly
-                // that we cannot even try/catch it
-                if (/^\[JavaPackage.*\]$/.test(arg))
-                    return <>[JavaPackage]</>;
                 if (processStrings && false)
-                    str = template.highlightFilter(str, "\n", function () <span highlight="NonText">^J</span>);
-                return <span highlight="Object">{str}</span>;
+                    str = template._highlightFilter(str, "\n",
+                                                    function () ["span", { highlight: "NonText" },
+                                                                     "^J"]);
+                return ["span", { highlight: "Object" }, str];
             case "xml":
                 return arg;
             default:
-                return <![CDATA[<unknown type>]]>;
+                return "<unknown type>";
             }
         }
         catch (e) {
-            return <![CDATA[<unknown>]]>;
+            return "<error: " + e + ">";
         }
     },
 
@@ -344,7 +342,6 @@ var Template = Module("Template", {
             if (filter.length == 0)
                 return;
 
-            XML.ignoreWhitespace = XML.prettyPrinting = false;
             let lcstr = String.toLowerCase(str);
             let lcfilter = filter.toLowerCase();
             let start = 0;
@@ -363,14 +360,13 @@ var Template = Module("Template", {
     },
 
     highlightSubstrings: function highlightSubstrings(str, iter, highlight) {
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        if (typeof str == "xml")
+        if (!isString(str))
             return str;
+
         if (str == "")
-            return <>{str}</>;
+            return DOM.DOMString(str);
 
-        str = String(str).replace(" ", "\u00a0");
-        let s = <></>;
+        let s = [""];
         let start = 0;
         let n = 0, _i;
         for (let [i, length, args] in iter) {
@@ -378,176 +374,138 @@ var Template = Module("Template", {
                 break;
             _i = i;
 
-            XML.ignoreWhitespace = false;
-            s += <>{str.substring(start, i)}</>;
-            s += highlight.apply(this, Array.concat(args || str.substr(i, length)));
+            s.push(str.substring(start, i),
+                   highlight.apply(this, Array.concat(args || str.substr(i, length))));
             start = i + length;
         }
-        return s + <>{str.substr(start)}</>;
+        s.push(str.substr(start));
+        return s;
     },
 
     highlightURL: function highlightURL(str, force) {
         if (force || /^[a-zA-Z]+:\/\//.test(str))
-            return <a highlight="URL" href={str}>{util.losslessDecodeURI(str)}</a>;
+            return ["a", { highlight: "URL", href: str },
+                        util.losslessDecodeURI(str)];
         else
             return str;
     },
 
-    icon: function (item, text) <>
-        <span highlight="CompIcon">{item.icon ? <img src={item.icon}/> : <></>}</span><span class="td-strut"/>{text}
-    </>,
+    icon: function (item, text) [
+        ["span", { highlight: "CompIcon" },
+            item.icon ? ["img", { src: item.icon }] : []],
+        ["span", { class: "td-strut" }],
+        text
+    ],
 
     jumps: function jumps(index, elems) {
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        // <e4x>
-        return <table>
-                <tr style="text-align: left;" highlight="Title">
-                    <th colspan="2">{_("title.Jump")}</th>
-                    <th>{_("title.HPos")}</th>
-                    <th>{_("title.VPos")}</th>
-                    <th>{_("title.Title")}</th>
-                    <th>{_("title.URI")}</th>
-                </tr>
-                {
-                    this.map(Iterator(elems), function ([idx, val])
-                    <tr>
-                        <td class="indicator">{idx == index ? ">" : ""}</td>
-                        <td>{Math.abs(idx - index)}</td>
-                        <td>{val.offset ? val.offset.x : ""}</td>
-                        <td>{val.offset ? val.offset.y : ""}</td>
-                        <td style="width: 250px; max-width: 500px; overflow: hidden;">{val.title}</td>
-                        <td><a href={val.URI.spec} highlight="URL jump-list">{util.losslessDecodeURI(val.URI.spec)}</a></td>
-                    </tr>)
-                }
-            </table>;
-        // </e4x>
+        return ["table", {},
+                ["tr", { style: "text-align: left;", highlight: "Title" },
+                    ["th", { colspan: "2" }, _("title.Jump")],
+                    ["th", {}, _("title.HPos")],
+                    ["th", {}, _("title.VPos")],
+                    ["th", {}, _("title.Title")],
+                    ["th", {}, _("title.URI")]],
+                this.map(Iterator(elems), function ([idx, val])
+                    ["tr", {},
+                        ["td", { class: "indicator" }, idx == index ? ">" : ""],
+                        ["td", {}, Math.abs(idx - index)],
+                        ["td", {}, val.offset ? val.offset.x : ""],
+                        ["td", {}, val.offset ? val.offset.y : ""],
+                        ["td", { style: "width: 250px; max-width: 500px; overflow: hidden;" }, val.title],
+                        ["td", {},
+                            ["a", { href: val.URI.spec, highlight: "URL jump-list" },
+                                util.losslessDecodeURI(val.URI.spec)]]])];
     },
 
+
     options: function options(title, opts, verbose) {
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        // <e4x>
-        return <table>
-                <tr highlight="Title" align="left">
-                    <th>--- {title} ---</th>
-                </tr>
-                {
-                    this.map(opts, function (opt)
-                    <tr>
-                        <td>
-                            <div highlight="Message"
-                            ><span style={opt.isDefault ? "" : "font-weight: bold"}>{opt.pre}{opt.name}</span><span>{opt.value}</span>{
-                                opt.isDefault || opt.default == null ? "" : <span class="extra-info"> (default: {opt.default})</span>
-                            }</div>{
-                                verbose && opt.setFrom ? <div highlight="Message">       Last set from {template.sourceLink(opt.setFrom)}</div> : <></>
-                            }
-                        </td>
-                    </tr>)
-                }
-            </table>;
-        // </e4x>
+        return ["table", {},
+                ["tr", { highlight: "Title", align: "left" },
+                    ["th", {}, "--- " + title + " ---"]],
+                this.map(opts, function (opt)
+                    ["tr", {},
+                        ["td", {},
+                            ["div", { highlight: "Message" },
+                                ["span", { style: opt.isDefault ? "" : "font-weight: bold" },
+                                    opt.pre, opt.name],
+                                ["span", {}, opt.value],
+                                opt.isDefault || opt.default == null ? "" : ["span", { class: "extra-info" }, " (default: ", opt.default, ")"]],
+                            verbose && opt.setFrom ? ["div", { highlight: "Message" },
+                                                         "       Last set from ",
+                                                         template.sourceLink(opt.setFrom)] : ""]])];
     },
 
     sourceLink: function (frame) {
         let url = util.fixURI(frame.filename || "unknown");
         let path = util.urlPath(url);
 
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        return <a xmlns:dactyl={NS} dactyl:command="buffer.viewSource"
-            href={url} path={path} line={frame.lineNumber}
-            highlight="URL">{
-            path + ":" + frame.lineNumber
-        }</a>;
+        return ["a", { "dactyl:command": "buffer.viewSource",
+                        href: url, path: path, line: frame.lineNumber,
+                        highlight: "URL" },
+            path + ":" + frame.lineNumber];
     },
 
     table: function table(title, data, indent) {
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        let table = // <e4x>
-            <table>
-                <tr highlight="Title" align="left">
-                    <th colspan="2">{title}</th>
-                </tr>
-                {
-                    this.map(data, function (datum)
-                    <tr>
-                       <td style={"font-weight: bold; min-width: 150px; padding-left: " + (indent || "2ex")}>{datum[0]}</td>
-                       <td>{datum[1]}</td>
-                    </tr>)
-                }
-            </table>;
-        // </e4x>
-        if (table.tr.length() > 1)
+        let table = ["table", {},
+            ["tr", { highlight: "Title", align: "left" },
+                ["th", { colspan: "2" }, title]],
+            this.map(data, function (datum)
+                ["tr", {},
+                    ["td", { style: "font-weight: bold; min-width: 150px; padding-left: " + (indent || "2ex") }, datum[0]],
+                    ["td", {}, datum[1]]])];
+
+        if (table[3].length)
             return table;
     },
 
     tabular: function tabular(headings, style, iter) {
+        let self = this;
         // TODO: This might be mind-bogglingly slow. We'll see.
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
-        // <e4x>
-        return <table>
-                <tr highlight="Title" align="left">
-                {
-                    this.map(headings, function (h)
-                    <th>{h}</th>)
-                }
-                </tr>
-                {
-                    this.map(iter, function (row)
-                    <tr>
-                    {
-                        template.map(Iterator(row), function ([i, d])
-                        <td style={style[i] || ""}>{d}</td>)
-                    }
-                    </tr>)
-                }
-            </table>;
-        // </e4x>
+        return ["table", {},
+            ["tr", { highlight: "Title", align: "left" },
+                this.map(headings, function (h)
+                    ["th", {}, h])],
+            this.map(iter, function (row)
+                ["tr", {},
+                    self.map(Iterator(row), function ([i, d])
+                        ["td", { style: style[i] || "" }, d])])];
     },
 
     usage: function usage(iter, format) {
-        XML.ignoreWhitespace = XML.prettyPrinting = false;
+        let self = this;
+
         format = format || {};
-        let desc = format.description || function (item) template.linkifyHelp(item.description);
+        let desc = format.description || function (item) self.linkifyHelp(item.description);
         let help = format.help || function (item) item.name;
         function sourceLink(frame) {
-            let source = template.sourceLink(frame);
-            source.@NS::hint = source.text();
+            let source = self.sourceLink(frame);
+            source[1]["dactyl:hint"] = source[2];
             return source;
         }
-        // <e4x>
-        return <table>
-            { format.headings ?
-                <thead highlight="UsageHead">
-                    <tr highlight="Title" align="left">
-                    {
-                        this.map(format.headings, function (h) <th>{h}</th>)
-                    }
-                    </tr>
-                </thead> : ""
-            }
-            { format.columns ?
-                <colgroup>
-                {
-                    this.map(format.columns, function (c) <col style={c}/>)
-                }
-                </colgroup> : ""
-            }
-            <tbody highlight="UsageBody">{
+        return ["table", {},
+            format.headings ?
+                ["thead", { highlight: "UsageHead" },
+                    ["tr", { highlight: "Title", align: "left" },
+                        this.map(format.headings, function (h) ["th", {}, h])]] :
+                [],
+            format.columns ?
+                ["colgroup", {},
+                    this.map(format.columns, function (c) ["col", { style: c }])] :
+                [],
+            ["tbody", { highlight: "UsageBody" },
                 this.map(iter, function (item)
-                <tr highlight="UsageItem">
-                    <td style="padding-right: 2em;">
-                        <span highlight="Usage Link">{
-                            let (name = item.name || item.names[0], frame = item.definedAt)
-                                !frame ? name :
-                                    template.helpLink(help(item), name, "Title") +
-                                    <span highlight="LinkInfo" xmlns:dactyl={NS}>{_("io.definedAt")} {sourceLink(frame)}</span>
-                        }</span>
-                    </td>
-                    { item.columns ? template.map(item.columns, function (c) <td>{c}</td>) : "" }
-                    <td>{desc(item)}</td>
-                </tr>)
-            }</tbody>
-        </table>;
-        // </e4x>
+                    // Urgh.
+                    let (name = item.name || item.names[0], frame = item.definedAt)
+                        ["tr", { highlight: "UsageItem" },
+                            ["td", { style: "padding-right: 2em;" },
+                                ["span", { highlight: "Usage Link" },
+                                    !frame ? name :
+                                        [self.helpLink(help(item), name, "Title"),
+                                         ["span", { highlight: "LinkInfo" },
+                                            _("io.definedAt"), " ",
+                                            sourceLink(frame)]]]],
+                            item.columns ? self.map(item.columns, function (c) ["td", {}, c]) : [],
+                            ["td", {}, desc(item)]])]]
     }
 });
 
index c5cd610fbcf8ecf6fabc31dea584a43331857e59..0e83efe7a15a6ea7e81fb1111181360e06d296c0 100644 (file)
@@ -1,20 +1,31 @@
 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 try {
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("util", {
     exports: ["DOM", "$", "FailedAssertion", "Math", "NS", "Point", "Util", "XBL", "XHTML", "XUL", "util"],
     require: ["dom", "services"]
-}, this);
+});
+
+lazyRequire("overlay", ["overlay"]);
+lazyRequire("storage", ["File", "storage"]);
+lazyRequire("template", ["template"]);
+
+var Magic = Class("Magic", {
+    init: function init(str) {
+        this.str = str;
+    },
+
+    get message() this.str,
 
-this.lazyRequire("overlay", ["overlay"]);
+    toString: function () this.str
+});
 
 var FailedAssertion = Class("FailedAssertion", ErrorBase, {
     init: function init(message, level, noTrace) {
@@ -51,7 +62,9 @@ var wrapCallback = function wrapCallback(fn, isEvent) {
 }
 
 var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), {
-    init: function () {
+    Magic: Magic,
+
+    init: function init() {
         this.Array = array;
 
         this.addObserver(this);
@@ -76,6 +89,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
     parseForm: deprecated("DOM#formData", function parseForm(elem) values(DOM(elem).formData).toArray()),
     scrollIntoView: deprecated("DOM#scrollIntoView", function scrollIntoView(elem, alignWithTop) DOM(elem).scrollIntoView(alignWithTop)),
     validateMatcher: deprecated("DOM.validateMatcher", { get: function validateMatcher() DOM.validateMatcher }),
+    xmlToDom: deprecated("DOM.fromJSON", function xmlToDom() DOM.fromXML.apply(DOM, arguments)),
 
     map: deprecated("iter.map", function map(obj, fn, self) iter(obj).map(fn, self).toArray()),
     writeToClipboard: deprecated("dactyl.clipboardWrite", function writeToClipboard(str, verbose) util.dactyl.clipboardWrite(str, verbose)),
@@ -90,7 +104,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
             var global = Class.objectGlobal(obj);
 
         return {
-            __noSuchMethod__: function (meth, args) {
+            __noSuchMethod__: function __noSuchMethod__(meth, args) {
                 let win = overlay.activeWindow;
 
                 var dactyl = global && global.dactyl || win && win.dactyl;
@@ -104,7 +118,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
             }
         };
     }, {
-        __noSuchMethod__: function () this().__noSuchMethod__.apply(null, arguments)
+        __noSuchMethod__: function __noSuchMethod__() this().__noSuchMethod__.apply(null, arguments)
     }),
 
     /**
@@ -159,7 +173,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * @param {string} message The message to present to the
      *     user on failure.
      */
-    assert: function (condition, message, quiet) {
+    assert: function assert(condition, message, quiet) {
         if (!condition)
             throw FailedAssertion(message, 1, quiet === undefined ? true : quiet);
         return condition;
@@ -252,7 +266,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
             {
                 elements: [],
                 seen: {},
-                valid: function (obj) this.elements.every(function (e) !e.test || e.test(obj))
+                valid: function valid(obj) this.elements.every(function (e) !e.test || e.test(obj))
             });
 
         let end = 0;
@@ -282,7 +296,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
 
                 stack.top.elements.push(update(
                     function (obj) obj[char] != null ? quote(obj, char) : "",
-                    { test: function (obj) obj[char] != null }));
+                    { test: function test(obj) obj[char] != null }));
 
                 for (let elem in array.iterValues(stack))
                     elem.seen[char] = true;
@@ -335,19 +349,19 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
             {
                 elements: [],
                 seen: {},
-                valid: function (obj) this.elements.every(function (e) !e.test || e.test(obj))
+                valid: function valid(obj) this.elements.every(function (e) !e.test || e.test(obj))
             });
 
         let defaults = { lt: "<", gt: ">" };
 
-        let re = util.regexp(<![CDATA[
+        let re = util.regexp(literal(/*
             ([^]*?) // 1
             (?:
                 (<\{) | // 2
                 (< ((?:[a-z]-)?[a-z-]+?) (?:\[([0-9]+)\])? >) | // 3 4 5
                 (\}>) // 6
             )
-        ]]>, "gixy");
+        */), "gixy");
         macro = String(macro);
         let end = 0;
         for (let match in re.iterate(macro)) {
@@ -363,7 +377,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
             }
             else if (close) {
                 stack.pop();
-                util.assert(stack.length, /*L*/"Unmatched %] in macro");
+                util.assert(stack.length, /*L*/"Unmatched }> in macro");
             }
             else {
                 let [, flags, name] = /^((?:[a-z]-)*)(.*)/.exec(macro);
@@ -385,9 +399,9 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
                             function (obj) obj[name] != null && idx in obj[name] ? quote(obj[name][idx])
                                                                                  : Set.has(obj, name) ? "" : unknown(full),
                             {
-                                test: function (obj) obj[name] != null && idx in obj[name]
-                                                  && obj[name][idx] !== false
-                                                  && (!flags.e || obj[name][idx] != "")
+                                test: function test(obj) obj[name] != null && idx in obj[name]
+                                                      && obj[name][idx] !== false
+                                                      && (!flags.e || obj[name][idx] != "")
                             }));
                     }
                     else {
@@ -395,9 +409,9 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
                             function (obj) obj[name] != null ? quote(obj[name])
                                                              : Set.has(obj, name) ? "" : unknown(full),
                             {
-                                test: function (obj) obj[name] != null
-                                                  && obj[name] !== false
-                                                  && (!flags.e || obj[name] != "")
+                                test: function test(obj) obj[name] != null
+                                                      && obj[name] !== false
+                                                      && (!flags.e || obj[name] != "")
                             }));
                     }
 
@@ -505,6 +519,17 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
         }
     },
 
+    /**
+     * Briefly delay the execution of the passed function.
+     *
+     * @param {function} callback The function to delay.
+     */
+    delay: function delay(callback) {
+        let { mainThread } = services.threading;
+        mainThread.dispatch(callback,
+                            mainThread.DISPATCH_NORMAL);
+    },
+
     /**
      * Removes certain backslash-quoted characters while leaving other
      * backslash-quoting sequences untouched.
@@ -542,7 +567,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * @param {string} stack The stack trace from an Error.
      * @returns {[string]} The stack frames.
      */
-    stackLines: function (stack) {
+    stackLines: function stackLines(stack) {
         let lines = [];
         let match, re = /([^]*?)@([^@\n]*)(?:\n|$)/g;
         while (match = re.exec(stack))
@@ -674,7 +699,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * @param {string} url
      * @returns {string|null}
      */
-    getHost: function (url) {
+    getHost: function getHost(url) {
         try {
             return util.createURI(url).host;
         }
@@ -795,7 +820,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * @param {Object} r2
      * @returns {Object}
      */
-    intersection: function (r1, r2) ({
+    intersection: function intersection(r1, r2) ({
         get width()  this.right - this.left,
         get height() this.bottom - this.top,
         left: Math.max(r1.left, r2.left),
@@ -863,7 +888,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
     },
 
     // ripped from Firefox; modified
-    unsafeURI: Class.Memoize(function () util.regexp(String.replace(<![CDATA[
+    unsafeURI: Class.Memoize(function () util.regexp(String.replace(literal(/*
             [
                 \s
                 // Invisible characters (bug 452979)
@@ -877,7 +902,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
                 // Bidi formatting characters. (RFC 3987 sections 3.2 and 4.1 paragraph 6)
                 U200E U200F U202A U202B U202C U202D U202E
             ]
-        ]]>, /U/g, "\\u"),
+        */), /U/g, "\\u"),
         "gx")),
     losslessDecodeURI: function losslessDecodeURI(url) {
         return url.split("%25").map(function (url) {
@@ -901,12 +926,21 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      *      for *obj*.
      */
     makeDTD: let (map = { "'": "&apos;", '"': "&quot;", "%": "&#x25;", "&": "&amp;", "<": "&lt;", ">": "&gt;" })
-        function makeDTD(obj) iter(obj)
-          .map(function ([k, v]) ["<!ENTITY ", k, " '", String.replace(v == null ? "null" : typeof v == "xml" ? v.toXMLString() : v,
-                                                                       typeof v == "xml" ? /['%]/g : /['"%&<>]/g,
-                                                                       function (m) map[m]),
-                                  "'>"].join(""))
-          .join("\n"),
+        function makeDTD(obj) {
+            function escape(val) {
+               let isDOM = DOM.isJSONXML(val);
+               return String.replace(val == null ? "null" :
+                                     isDOM       ? DOM.toXML(val)
+                                                 : val,
+                                     isDOM ? /['%]/g
+                                           : /['"%&<>]/g,
+                                     function (m) map[m]);
+            }
+
+            return iter(obj).map(function ([k, v])
+                                 ["<!ENTITY ", k, " '", escape(v), "'>"].join(""))
+                            .join("\n");
+        },
 
     /**
      * Converts a URI string into a URI object.
@@ -943,13 +977,6 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * @returns {string}
      */
     objectToString: function objectToString(object, color) {
-        // Use E4X literals so html is automatically quoted
-        // only when it's asked for. No one wants to see &lt;
-        // on their console or :map :foo in their buffer
-        // when they expect :map <C-f> :foo.
-        XML.prettyPrinting = false;
-        XML.ignoreWhitespace = false;
-
         if (object == null)
             return object + "\n";
 
@@ -970,8 +997,14 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
         catch (e) {
             obj = Object.prototype.toString.call(obj);
         }
-        obj = template.highlightFilter(util.clip(obj, 150), "\n", !color ? function () "^J" : function () <span highlight="NonText">^J</span>);
-        let string = <><span highlight="Title Object">{obj}</span>::&#x0a;</>;
+
+        if (color) {
+            obj = template.highlightFilter(util.clip(obj, 150), "\n",
+                                           function () ["span", { highlight: "NonText" }, "^J"]);
+            var head = ["span", { highlight: "Title Object" }, obj, "::\n"];
+        }
+        else
+            head = util.clip(obj, 150).replace(/\n/g, "^J") + "::\n";
 
         let keys = [];
 
@@ -987,7 +1020,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
                 keyIter = keys(object)
 
             for (let i in keyIter) {
-                let value = <![CDATA[<no value>]]>;
+                let value = Magic("<no value>");
                 try {
                     value = object[i];
                 }
@@ -1001,13 +1034,27 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
                     }
                 }
 
-                value = template.highlight(value, true, 150, !color);
-                let key = <span highlight="Key">{i}</span>;
+                let key = i;
                 if (!isNaN(i))
                     i = parseInt(i);
                 else if (/^[A-Z_]+$/.test(i))
                     i = "";
-                keys.push([i, <>{noVal ? value : <>{key}: {value}</>}&#x0a;</>]);
+
+                if (color)
+                    value = template.highlight(value, true, 150, !color);
+                else if (value instanceof Magic)
+                    value = String(value);
+                else
+                    value = util.clip(String(value).replace(/\n/g, "^J"), 150);
+
+                if (noVal)
+                    var val = value;
+                else if (color)
+                    val = [["span", { highlight: "Key" }, key], ": ", value];
+                else
+                    val = key + ": " + value;
+
+                keys.push([i, val]);
             }
         }
         catch (e) {
@@ -1019,12 +1066,75 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
                 return a[0] - b[0];
             return String.localeCompare(a[0], b[0]);
         }
-        string += template.map(keys.sort(compare), function (f) f[1]);
-        return color ? <div style="white-space: pre-wrap;">{string}</div> : [s for each (s in string)].join("");
+
+        let vals = template.map(keys.sort(compare), function (f) f[1], "\n");
+        if (color) {
+            return ["div", { style: "white-space: pre-wrap" }, head, vals];
+        }
+        return head + vals.join("");
+    },
+
+    prettifyJSON: function prettifyJSON(data, indent, invalidOK) {
+        const INDENT = indent || "    ";
+
+        function rec(data, level, seen) {
+            if (isObject(data)) {
+                if (~seen.indexOf(data))
+                    throw Error("Recursive object passed");
+                seen = seen.concat([data]);
+            }
+
+            let prefix = level + INDENT;
+
+            if (data === undefined)
+                data = null;
+
+            if (~["boolean", "number"].indexOf(typeof data) || data === null)
+                res.push(String(data));
+            else if (isinstance(data, ["String", _]))
+                res.push(JSON.stringify(String(data)));
+            else if (isArray(data)) {
+                if (data.length == 0)
+                    res.push("[]");
+                else {
+                    res.push("[\n")
+                    for (let [i, val] in Iterator(data)) {
+                        if (i)
+                            res.push(",\n");
+                        res.push(prefix)
+                        rec(val, prefix, seen);
+                    }
+                    res.push("\n", level, "]");
+                }
+            }
+            else if (isObject(data)) {
+                res.push("{\n")
+
+                let i = 0;
+                for (let [key, val] in Iterator(data)) {
+                    if (i++)
+                        res.push(",\n");
+                    res.push(prefix, JSON.stringify(key), ": ")
+                    rec(val, prefix, seen);
+                }
+                if (i > 0)
+                    res.push("\n", level, "}")
+                else
+                    res[res.length - 1] = "{}";
+            }
+            else if (invalidOK)
+                res.push({}.toString.call(data));
+            else
+                throw Error("Invalid JSON object");
+        }
+
+        let res = [];
+        rec(data, "", []);
+        return res.join("");
     },
 
     observers: {
-        "dactyl-cleanup-modules": function (subject, reason) {
+        "dactyl-cleanup-modules": function cleanupModules(subject, reason) {
             defineModule.loadLog.push("dactyl: util: observe: dactyl-cleanup-modules " + reason);
 
             for (let module in values(defineModule.modules))
@@ -1038,7 +1148,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
             if (!this.rehashing)
                 services.observer.addObserver(this, "dactyl-rehash", true);
         },
-        "dactyl-rehash": function () {
+        "dactyl-rehash": function dactylRehash() {
             services.observer.removeObserver(this, "dactyl-rehash");
 
             defineModule.loadLog.push("dactyl: util: observe: dactyl-rehash");
@@ -1051,7 +1161,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
                         module.init();
                 }
         },
-        "dactyl-purge": function () {
+        "dactyl-purge": function dactylPurge() {
             this.rehashing = 1;
         },
     },
@@ -1135,7 +1245,11 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
 
         // Replace replacement <tokens>.
         if (tokens)
-            expr = String.replace(expr, /(\(?P)?<(\w+)>/g, function (m, n1, n2) !n1 && Set.has(tokens, n2) ? tokens[n2].dactylSource || tokens[n2].source || tokens[n2] : m);
+            expr = String.replace(expr, /(\(?P)?<(\w+)>/g,
+                                  function (m, n1, n2) !n1 && Set.has(tokens, n2) ?    tokens[n2].dactylSource
+                                                                                    || tokens[n2].source
+                                                                                    || tokens[n2]
+                                                                                  : m);
 
         // Strip comments and white space.
         if (/x/.test(flags))
@@ -1157,7 +1271,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
         let res = update(RegExp(expr, flags.replace("x", "")), {
             closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "closure")),
             dactylPropertyNames: ["exec", "match", "test", "toSource", "toString", "global", "ignoreCase", "lastIndex", "multiLine", "source", "sticky"],
-            iterate: function (str, idx) util.regexp.iterate(this, str, idx)
+            iterate: function iterate(str, idx) util.regexp.iterate(this, str, idx)
         });
 
         // Return a struct with properties for named parameters if we
@@ -1220,8 +1334,8 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * Reloads dactyl in entirety by disabling the add-on and
      * re-enabling it.
      */
-    rehash: function (args) {
-        storage.session.commandlineArgs = args;
+    rehash: function rehash(args) {
+        storage.storeForSession("commandlineArgs", args);
         this.timeout(function () {
             this.flushCache();
             this.rehashing = true;
@@ -1253,7 +1367,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
 
             let obj = update({}, error, {
                 toString: function () String(error),
-                stack: <>{util.stackLines(String(error.stack || Error().stack)).join("\n").replace(/^/mg, "\t")}</>
+                stack: Magic(util.stackLines(String(error.stack || Error().stack)).join("\n").replace(/^/mg, "\t"))
             });
 
             services.console.logStringMessage(obj.stack);
@@ -1307,7 +1421,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * @param {Window} window
      * @returns {nsISelectionController}
      */
-    selectionController: function (win)
+    selectionController: function selectionController(win)
         win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation)
            .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsISelectionDisplay)
            .QueryInterface(Ci.nsISelectionController),
@@ -1326,7 +1440,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      *
      * @param {number} delay The time period for which to sleep in milliseconds.
      */
-    sleep: function (delay) {
+    sleep: function sleep(delay) {
         let mainThread = services.threading.mainThread;
 
         let end = Date.now() + delay;
@@ -1347,7 +1461,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * @param {number} limit The maximum number of elements to return.
      * @returns {[string]}
      */
-    split: function (str, re, limit) {
+    split: function split(str, re, limit) {
         re.lastIndex = 0;
         if (!re.global)
             re = RegExp(re.source || re, "g");
@@ -1407,7 +1521,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      *      interrupted by pressing <C-c>, in which case,
      *      Error("Interrupted") will be thrown.
      */
-    threadYield: function (flush, interruptable) {
+    threadYield: function threadYield(flush, interruptable) {
         this.yielders++;
         try {
             let mainThread = services.threading.mainThread;
@@ -1546,7 +1660,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * @param {nsIDOMWindow} win The window for which to find domains.
      * @returns {[string]} The visible domains.
      */
-    visibleHosts: function (win) {
+    visibleHosts: function visibleHosts(win) {
         let res = [], seen = {};
         (function rec(frame) {
             try {
@@ -1566,7 +1680,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
      * @param {nsIDOMWindow} win The window for which to find URIs.
      * @returns {[nsIURI]} The visible URIs.
      */
-    visibleURIs: function (win) {
+    visibleURIs: function visibleURIs(win) {
         let res = [], seen = {};
         (function rec(frame) {
             try {
@@ -1602,9 +1716,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
         catch (e) {
             throw e.stack ? e : Error(e);
         }
-    },
-
-    xmlToDom: function () DOM.fromXML.apply(DOM, arguments)
+    }
 }, {
     Array: array
 });
@@ -1615,7 +1727,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
  * @singleton
  */
 var GlobalMath = Math;
-var Math = update(Object.create(GlobalMath), {
+this.Math = update(Object.create(GlobalMath), {
     /**
      * Returns the specified *value* constrained to the range *min* - *max*.
      *
index 45fe12b972505c1025fe0f40d2af77c5bdbd37e0..b09f40228acca96324f450b3aae8cd1962124a86 100644 (file)
@@ -1,4 +1,3 @@
-
 Boolean      /* JavaScript booleans */       color: red;
 Function     /* JavaScript functions */      color: navy;
 Null         /* JavaScript null values */    color: blue;
@@ -77,6 +76,14 @@ StatusWarningMsg  /* A warning message in the status line */ \
 Disabled          /* Disabled items */ \
                   color: gray    !important;
 
+!Private;xul|window[privatebrowsingmode]  /* A private browsing window */
+
+Private StatusLine::before  /* From the default theme: */ \
+                            display: -moz-box; \
+                            content: ""; \
+                            background: url("chrome://browser/skin/privatebrowsing-mask.png") center no-repeat; \
+                            width: 30px;
+
 CmdLine;>*;;FontFixed   /* The command line */ \
                         padding: 1px !important;
 CmdPrompt;.dactyl-commandline-prompt  /* The default styling form the command prompt */
index 010919cb5791252bc4e042537465beaf9ed5be07..2f986259556b4c1d8333ab7b49dd262bbd444093 100644 (file)
@@ -474,21 +474,13 @@ var tests = {
         completions: [""],
         cleanup: ["silent !rm some-nonexistent-rc.penta"]
     },
-    mksyntax: {
-        noOutput: [
-            "some-nonexistent-pentadactyl-dir/",
-            "! some-nonexistent-pentadactyl-dir/",
-            "some-nonexistent-pentadactyl-dir/foo.vim",
-            "! some-nonexistent-pentadactyl-dir/foo.vim",
-        ],
+    mkvimruntime: {
         error: [
-            "some-nonexistent-pentadactyl-dir/",
-            "some-nonexistent-pentadactyl-dir/foo.vim"
+            "some-nonexistent-pentadactyl-dir/"
         ],
         completions: [
             ["", hasItems]
-        ],
-        cleanup: ["silent !rm -r some-nonexistent-pentadactyl-dir/"]
+        ]
     },
     get mlistkeys() this.listcommands,
     mmap: {},
@@ -835,7 +827,6 @@ var tests = {
     time: {
         error: ["", ":some-nonexistent-command"/*, "some_nonexistent_reference"*/], // FIXME
         singleOutput: [":js null", "null"]
-
     },
     get tlistkeys() this.listcommands,
     tmap: {},
@@ -911,7 +902,7 @@ var tests = {
         error: ["foo"],
         multiOutput: [
             ["", function (msg) {
-                var res = /(\w+dactyl) (\S+) \(([\^)]+)\) running on:\nMozilla/;
+                var res = /(\w+dactyl) (\S+) \(([\^)]+)\) running on:\nMozilla/.exec(msg);
                 return res && res[2] != "null" && res[3] != "null";
             }]
         ]
index f3b943ac4653147fc2596a1df4c102505cb1aa04..8a7bab2979e9aea989c2a2f9fe96ecf4f4741cd5 100644 (file)
@@ -456,7 +456,7 @@ const Player = Module("player", {
         });
 
     },
-    commandline: function () {
+    commandline: function initCommandline() {
         player.CommandMode = Class("CommandSearchViewMode", modules.CommandMode, {
             init: function init(mode) {
                 this.mode = mode;
@@ -472,7 +472,7 @@ const Player = Module("player", {
             get onSubmit() player.closure.onSearchSubmit
         });
     },
-    commands: function () {
+    commands: function initCommands() {
         commands.add(["f[ilter]"],
                 "Filter tracks based on keywords {genre/artist/album/track}",
                 function (args) {
@@ -672,7 +672,7 @@ const Player = Module("player", {
             },
             { argCount: "1" });
     },
-    completion: function () {
+    completion: function initCompletion() {
         completion.album = function album(context, artist) {
             context.title = ["Album"];
             context.completions = [[v, ""] for ([, v] in Iterator(library.getAlbums(artist)))];
@@ -708,7 +708,7 @@ const Player = Module("player", {
             context.completions = [[v, ""] for ([, v] in Iterator(library.getTracks(artist, album)))];
         };
     },
-    mappings: function () {
+    mappings: function initMappings() {
         mappings.add([modes.PLAYER],
             ["x"], "Play track",
             function () { ex.playerplay(); });
@@ -806,7 +806,7 @@ const Player = Module("player", {
             };
         }
     },
-    options: function () {
+    options: function initOptions() {
         options.add(["repeat"],
             "Set the playback repeat mode",
             "number", 0,
diff --git a/melodactyl/contrib/vim/Makefile b/melodactyl/contrib/vim/Makefile
deleted file mode 100644 (file)
index 29972b5..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-VIMBALL = melodactyl.vba
-
-vimball: mkvimball.txt syntax/melodactyl.vim ftdetect/melodactyl.vim
-       -echo '%MkVimball! ${VIMBALL} .' | vim -u NORC -N -e -s mkvimball.txt
-
-all: vimball
-
-clean:
-       rm -f ${VIMBALL}
diff --git a/melodactyl/contrib/vim/ftdetect/melodactyl.vim b/melodactyl/contrib/vim/ftdetect/melodactyl.vim
deleted file mode 100644 (file)
index e7661ca..0000000
+++ /dev/null
@@ -1 +0,0 @@
-au BufNewFile,BufRead *melodactylrc*,*.melo set filetype=melodactyl
diff --git a/melodactyl/contrib/vim/mkvimball.txt b/melodactyl/contrib/vim/mkvimball.txt
deleted file mode 100644 (file)
index ec820b4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-syntax/melodactyl.vim
-ftdetect/melodactyl.vim
index e2d3c3611ac5c0004adb24a8239e987c38f32ab2..6d9eff76133ca5d074605c38abf9d95dd88c42b4 100644 (file)
 <ul replace="features-list">
     <li>Vim-like keybindings (<k>h</k>, <k>j</k>, <k>gg</k>, <k>ZZ</k>, <k name="C-f"/>, etc.)</li>
     <li>Ex commands (<ex>:quit</ex>, <ex>:open www.foo.com</ex>, …)</li>
-    <li>Tab completion for all commands, highly configurable via <o>wildmode</o>, <o>autocomplete</o>, ...</li>
+    <li>Tab completion for all commands, highly configurable via <o>wildmode</o>, <o>autocomplete</o>, </li>
     <li>Hit-a-hint like navigation of links (start with <k>f</k> to follow a link)</li>
     <li>Advanced completion of bookmark and history URLs</li>
     <li>Vim-like status line with a Wget-like progress bar</li>
index 95e5f201b841577407c99bde1626e7471a072c67..8912f301cda55dbbaff4a8905f44b01503e05eff 100644 (file)
@@ -1,4 +1,13 @@
-1.0rc1:
+1.1:
+    • Vim runtime files:
+      - renamed :mksyntax to :mkvimruntime which now generates
+        all Vim related files.
+      - Vimball packages are no longer available.
+    • Removed <F1> and <A-F1> mappings.
+    • Add :private command.
+    • Better per-window private browsing support.
+
+1.0:
     • Extensive Firefox 4 support, including:
       - Fully restartless. Can now be installed, uninstalled,
         enabled, disabled, and upgraded without restarting Firefox.
index af56b4f1ff28ddb9831832fb99b8374921e980a1..2d39dd03fbb8b5c94a2888b5a6dc7ac6affe78c7 100644 (file)
@@ -22,6 +22,7 @@ FEATURES:
 8 add support for filename special characters such as %
 8 :redir and 'verbosefile'
 8 Add information to dactyl/HACKING file about testing and optimization
+7 handle Print Preview 'mode' properly
 7 describe-key command (prompt for a key and display its binding with documentation)
 7 use ctrl-n/p in insert mode for word completion
 7 make an option to disable session saving by default when you close Firefox
index 844c5f42fc71b818b1d3d1d9b6c2984bedd1b2e5..5ba3bdd9875a89b91c21032873741a5124fc2290 100644 (file)
@@ -5,6 +5,10 @@
     "host": "Firefox",
     "hostbin": "firefox",
 
+    "module-paths": [
+        "resource://dactyl/"
+    ],
+
     "autocommands": {
         "BookmarkAdd":      "Triggered after a page is bookmarked",
         "BookmarkChange":   "Triggered after a page's bookmark is changed",
index c9ae10b3823e1d16d5f0f60657b148d3593fa893..8c10f837e3f352f252d88136b3bf5c2d7648700d 100644 (file)
@@ -67,7 +67,9 @@ var Config = Module("config", ConfigBase, {
         },
 
         removeTab: function removeTab(tab) {
-            if (this.tabbrowser.mTabs.length > 1)
+            if (window.gInPrintPreviewMode)
+                window.PrintUtils.exitPrintPreview();
+            else if (this.tabbrowser.mTabs.length > 1)
                 this.tabbrowser.removeTab(tab);
             else {
                 if (modules.buffer.uri.spec !== "about:blank" || window.getWebNavigation().sessionHistory.count > 0) {
@@ -92,7 +94,7 @@ var Config = Module("config", ConfigBase, {
 
 }, {
 }, {
-    commands: function (dactyl, modules, window) {
+    commands: function initCommands(dactyl, modules, window) {
         const { commands, completion, config } = modules;
         const { document } = window;
 
@@ -203,7 +205,7 @@ var Config = Module("config", ConfigBase, {
                 privateData: true
             });
     },
-    completion: function (dactyl, modules, window) {
+    completion: function initCompletion(dactyl, modules, window) {
         const { CompletionContext, bookmarkcache, completion } = modules;
         const { document } = window;
 
@@ -222,7 +224,7 @@ var Config = Module("config", ConfigBase, {
             context.completions = Array.map(menu.childNodes, function (n) [n.getAttribute("label"), ""]);
         };
     },
-    events: function (dactyl, modules, window) {
+    events: function initEvents(dactyl, modules, window) {
         modules.events.listen(window, "SidebarFocused", function (event) {
             modules.config.lastSidebar = window.document.getElementById("sidebar-box")
                                                .getAttribute("sidebarcommand");
@@ -235,7 +237,7 @@ var Config = Module("config", ConfigBase, {
                      "Handled by " + config.host,
                      function () Events.PASS_THROUGH);
     },
-    options: function (dactyl, modules, window) {
+    options: function initOptions(dactyl, modules, window) {
         modules.options.add(["online"],
             "Enables or disables offline mode",
             "boolean", true,
diff --git a/pentadactyl/contrib/vim/Makefile b/pentadactyl/contrib/vim/Makefile
deleted file mode 100644 (file)
index 5bb780d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-VIMBALL = pentadactyl.vba
-
-vimball: mkvimball.txt syntax/pentadactyl.vim ftdetect/pentadactyl.vim
-       -echo '%MkVimball! ${VIMBALL} .' | vim -u NORC -N -e -s mkvimball.txt
-
-all: vimball
-
-clean:
-       rm -f ${VIMBALL}
diff --git a/pentadactyl/contrib/vim/ftdetect/pentadactyl.vim b/pentadactyl/contrib/vim/ftdetect/pentadactyl.vim
deleted file mode 100644 (file)
index 19624df..0000000
+++ /dev/null
@@ -1 +0,0 @@
-au BufNewFile,BufRead *pentadactylrc*,*.penta set filetype=pentadactyl
diff --git a/pentadactyl/contrib/vim/mkvimball.txt b/pentadactyl/contrib/vim/mkvimball.txt
deleted file mode 100644 (file)
index 0350633..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-syntax/pentadactyl.vim
-ftdetect/pentadactyl.vim
index d331fbb64e003482a8be05ae2a6d73ef2017bc13..51305ac3a51544220579f54006f41d084d2af6b0 100644 (file)
@@ -5,7 +5,7 @@
         em:id="pentadactyl@dactyl.googlecode.com"
         em:type="2"
         em:name="Pentadactyl"
-        em:version="1.0"
+        em:version="1.1pre"
         em:description="Firefox for Vim and Links addicts"
         em:homepageURL="http://5digits.org/pentadactyl"
         em:bootstrap="true"
@@ -31,8 +31,8 @@
         <em:targetApplication>
             <Description
                 em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
-                em:minVersion="4.0"
-                em:maxVersion="14.*"/>
+                em:minVersion="8.0"
+                em:maxVersion="22.0a1"/>
         </em:targetApplication>
     </Description>
 </RDF>
index ecc5524ce410f713084d7cac81be3b6e2d4883b6..cd9fe12a91ef0da17b206fc5d752d5268f8126d9 100644 (file)
@@ -88,7 +88,7 @@ var Addressbook = Module("addressbook", {
     }
 }, {
 }, {
-    commands: function () {
+    commands: function initCommands() {
         commands.add(["con[tact]"],
             "Add an address book entry",
             function (args) {
@@ -117,7 +117,7 @@ var Addressbook = Module("addressbook", {
             function (args) { addressbook.list(args.string, args.bang); },
             { bang: true });
     },
-    mappings: function () {
+    mappings: function initMappings() {
         var myModes = config.mailModes;
 
         mappings.add(myModes, ["a"],
diff --git a/teledactyl/contrib/vim/Makefile b/teledactyl/contrib/vim/Makefile
deleted file mode 100644 (file)
index c3a65aa..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-VIMBALL = teledactyl.vba
-
-vimball: mkvimball.txt syntax/teledactyl.vim ftdetect/teledactyl.vim
-       -echo '%MkVimball! ${VIMBALL} .' | vim -u NORC -N -e -s mkvimball.txt
-
-all: vimball
-
-clean:
-       rm -f ${VIMBALL}
diff --git a/teledactyl/contrib/vim/ftdetect/teledactyl.vim b/teledactyl/contrib/vim/ftdetect/teledactyl.vim
deleted file mode 100644 (file)
index f4a303b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-au BufNewFile,BufRead *teledactylrc*,*.tele set filetype=teledactyl
diff --git a/teledactyl/contrib/vim/mkvimball.txt b/teledactyl/contrib/vim/mkvimball.txt
deleted file mode 100644 (file)
index 20148df..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-syntax/teledactyl.vim
-ftdetect/teledactyl.vim
index 328fb1cdc123d99549cb406afdbc5a927048b298..d6145c0408a5e8ef5a11dadea1912dba460881b9 100644 (file)
 <ul replace="features-list">
     <li>Vim-like keybindings (<k>h</k>, <k>j</k>, <k>gg</k>, <k>ZZ</k>, <k name="C-f"/>, etc.)</li>
     <li>Ex commands (<ex>:quit</ex>, <ex>:open www.foo.com</ex>, …)</li>
-    <li>Tab completion for all commands, highly configurable via <o>wildmode</o>, <o>autocomplete</o>, ...</li>
+    <li>Tab completion for all commands, highly configurable via <o>wildmode</o>, <o>autocomplete</o>, </li>
     <li>Hit-a-hint like navigation of links (start with <k>f</k> to follow a link)</li>
     <li>Advanced completion of bookmark and history URLs</li>
     <li>Vim-like status line with a Wget-like progress bar</li>