summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorKris Maglione <maglione.k@gmail.com>2011-08-21 00:47:18 -0400
committerKris Maglione <maglione.k@gmail.com>2011-08-21 00:47:18 -0400
commit1607affa588598925597f5501a26bb7db806c1f6 (patch)
tree4aa2b63c77e667dc776f6de22bdb858acd7faaaf /common
parentcef61c873316cc3abfc3954f4a1d05430497bf97 (diff)
downloadpentadactyl-1607affa588598925597f5501a26bb7db806c1f6.tar.gz
Because I can.
Diffstat (limited to 'common')
-rw-r--r--common/chrome.manifest7
-rw-r--r--common/components/commandline-handler.js45
-rw-r--r--common/components/protocols.js384
-rw-r--r--common/content/dactyl.js410
-rw-r--r--common/content/help.xsl8
-rw-r--r--common/content/mappings.js6
-rw-r--r--common/locale/en-US/buffer.xml2
-rw-r--r--common/modules/base.jsm75
-rw-r--r--common/modules/bootstrap.jsm22
-rw-r--r--common/modules/commands.jsm4
-rw-r--r--common/modules/config.jsm38
-rw-r--r--common/modules/help.jsm326
-rw-r--r--common/modules/io.jsm4
-rw-r--r--common/modules/overlay.jsm4
-rw-r--r--common/modules/protocol.jsm228
-rw-r--r--common/modules/sanitizer.jsm2
-rw-r--r--common/modules/services.jsm1
-rw-r--r--common/modules/template.jsm10
18 files changed, 795 insertions, 781 deletions
diff --git a/common/chrome.manifest b/common/chrome.manifest
index 4995b0e8..b55978f4 100644
--- a/common/chrome.manifest
+++ b/common/chrome.manifest
@@ -13,10 +13,3 @@ component {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69} components/commandline-handler.
contract @mozilla.org/commandlinehandler/general-startup;1?type=dactyl {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69}
category command-line-handler m-dactyl @mozilla.org/commandlinehandler/general-startup;1?type=dactyl
-component {c1b67a07-18f7-4e13-b361-2edcc35a5a0d} components/protocols.js
-contract @mozilla.org/network/protocol;1?name=chrome-data {c1b67a07-18f7-4e13-b361-2edcc35a5a0d}
-component {9c8f2530-51c8-4d41-b356-319e0b155c44} components/protocols.js
-contract @mozilla.org/network/protocol;1?name=dactyl {9c8f2530-51c8-4d41-b356-319e0b155c44}
-component {f4506a17-5b4d-4cd9-92d4-2eb4630dc388} components/protocols.js
-contract @dactyl.googlecode.com/base/xpc-interface-shim {f4506a17-5b4d-4cd9-92d4-2eb4630dc388}
-
diff --git a/common/components/commandline-handler.js b/common/components/commandline-handler.js
index ba2c578c..2bd10f9b 100644
--- a/common/components/commandline-handler.js
+++ b/common/components/commandline-handler.js
@@ -11,35 +11,54 @@ function reportError(e) {
var global = this;
var NAME = "command-line-handler";
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
+var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-function CommandLineHandler() {
- this.wrappedJSObject = this;
-
+function init() {
+ Cu.import("resource://dactyl/bootstrap.jsm");
+ if (!JSMLoader.initialized)
+ JSMLoader.init();
Cu.import("resource://dactyl/base.jsm");
- require(global, "util");
require(global, "config");
+ require(global, "util");
+}
+
+function CommandLineHandler() {
+ this.wrappedJSObject = this;
}
CommandLineHandler.prototype = {
- classDescription: "Dactyl Command-line Handler",
+ classDescription: "Dactyl command line Handler",
classID: Components.ID("{16dc34f7-6d22-4aa4-a67f-2921fb5dcb69}"),
contractID: "@mozilla.org/commandlinehandler/general-startup;1?type=dactyl",
- _xpcom_categories: [{
- category: "command-line-handler",
- entry: "m-dactyl"
- }],
+ _xpcom_categories: [
+ {
+ category: "command-line-handler",
+ entry: "m-dactyl"
+ },
+
+ // FIXME: Belongs elsewhere
+ {
+ category: "profile-after-change",
+ entry: "m-dactyl"
+ }
+ ],
+
+ observe: function observe(subject, topic, data) {
+ if (topic === "profile-after-change") {
+ init();
+ require(global, "overlay");
+ }
+ },
- QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsICommandLineHandler]),
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsICommandLineHandler]),
handle: function (commandLine) {
+ init();
try {
var remote = commandLine.handleFlagWithParam(config.name + "-remote", false);
}
diff --git a/common/components/protocols.js b/common/components/protocols.js
deleted file mode 100644
index 78691973..00000000
--- a/common/components/protocols.js
+++ /dev/null
@@ -1,384 +0,0 @@
-// Copyright (c) 2008-2011 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";
-function reportError(e) {
- dump("dactyl: protocols: " + e + "\n" + (e.stack || Error().stack));
- Cu.reportError(e);
-}
-
-var NAME = "protocols";
-var global = this;
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
-var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].getService(Ci.nsIPrincipal);
-
-var DNE = "resource://dactyl/content/does/not/exist";
-var _DNE;
-
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-function makeChannel(url, orig) {
- try {
- if (url == null)
- return fakeChannel(orig);
-
- if (typeof url === "function")
- return let ([type, data] = url(orig)) StringChannel(data, type, orig);
-
- if (isArray(url))
- return let ([type, data] = url) StringChannel(data, type, orig);
-
- let uri = ioService.newURI(url, null, null);
- return (new XMLChannel(uri)).channel;
- }
- catch (e) {
- util.reportError(e);
- throw e;
- }
-}
-function fakeChannel(orig) {
- let channel = ioService.newChannel(DNE, null, null);
- channel.originalURI = orig;
- return channel;
-}
-function redirect(to, orig, time) {
- let html = <html><head><meta http-equiv="Refresh" content={(time || 0) + ";" + to}/></head></html>.toXMLString();
- return StringChannel(html, "text/html", ioService.newURI(to, null, null));
-}
-
-function Factory(clas) ({
- __proto__: clas.prototype,
- createInstance: function (outer, iid) {
- try {
- if (outer != null)
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- if (!clas.instance)
- clas.instance = new clas();
- return clas.instance.QueryInterface(iid);
- }
- catch (e) {
- reportError(e);
- throw e;
- }
- }
-});
-
-/* Adds support for data: URIs with chrome privileges
- * and fragment identifiers.
- *
- * "chrome-data:" <content-type> [; <flag>]* "," [<data>]
- *
- * By Kris Maglione, ideas from Ed Anuff's nsChromeExtensionHandler.
- */
-function ChromeData() {}
-ChromeData.prototype = {
- contractID: "@mozilla.org/network/protocol;1?name=chrome-data",
- classID: Components.ID("{c1b67a07-18f7-4e13-b361-2edcc35a5a0d}"),
- classDescription: "Data URIs with chrome privileges",
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]),
- _xpcom_factory: Factory(ChromeData),
-
- scheme: "chrome-data",
- defaultPort: -1,
- allowPort: function (port, scheme) false,
- protocolFlags: Ci.nsIProtocolHandler.URI_NORELATIVE
- | Ci.nsIProtocolHandler.URI_NOAUTH
- | Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE,
-
- newURI: function (spec, charset, baseURI) {
- var uri = Components.classes["@mozilla.org/network/standard-url;1"]
- .createInstance(Components.interfaces.nsIStandardURL)
- .QueryInterface(Components.interfaces.nsIURI);
- uri.init(uri.URLTYPE_STANDARD, this.defaultPort, spec, charset, null);
- return uri;
- },
-
- newChannel: function (uri) {
- try {
- if (uri.scheme == this.scheme) {
- let channel = ioService.newChannel(uri.spec.replace(/^.*?:\/*(.*)(?:#.*)?/, "data:$1"),
- null, null);
- channel.contentCharset = "UTF-8";
- channel.owner = systemPrincipal;
- channel.originalURI = uri;
- return channel;
- }
- }
- catch (e) {}
- return fakeChannel(uri);
- }
-};
-
-function Dactyl() {
- // Kill stupid validator warning.
- this["wrapped" + "JSObject"] = this;
-
- this.HELP_TAGS = {};
- this.FILE_MAP = {};
- this.OVERLAY_MAP = {};
-
- this.pages = {};
- this.providers = {};
-
- Cu.import("resource://dactyl/bootstrap.jsm");
- if (!JSMLoader.initialized)
- JSMLoader.init();
- JSMLoader.load("base.jsm", global);
- require(global, "config");
- require(global, "services");
- require(global, "util");
- _DNE = ioService.newChannel(DNE, null, null).name;
-
- // Doesn't belong here:
- AboutHandler.prototype.register();
-}
-Dactyl.prototype = {
- contractID: "@mozilla.org/network/protocol;1?name=dactyl",
- classID: Components.ID("{9c8f2530-51c8-4d41-b356-319e0b155c44}"),
- classDescription: "Dactyl utility protocol",
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsIProtocolHandler]),
- _xpcom_factory: Factory(Dactyl),
-
- init: function (obj) {
- for each (let prop in ["HELP_TAGS", "FILE_MAP", "OVERLAY_MAP"]) {
- this[prop] = this[prop].constructor();
- for (let [k, v] in Iterator(obj[prop] || {}))
- this[prop][k] = v;
- }
- this.initialized = true;
- },
-
- scheme: "dactyl",
- defaultPort: -1,
- allowPort: function (port, scheme) false,
- protocolFlags: 0
- | Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE
- | Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE,
-
- newURI: function newURI(spec, charset, baseURI) {
- var uri = Cc["@mozilla.org/network/standard-url;1"]
- .createInstance(Ci.nsIStandardURL)
- .QueryInterface(Ci.nsIURI);
- if (baseURI && baseURI.host === "data")
- baseURI = null;
- uri.init(uri.URLTYPE_STANDARD, this.defaultPort, spec, charset, baseURI);
- return uri;
- },
-
- newChannel: function newChannel(uri) {
- try {
- if (/^help/.test(uri.host) && !("all" in this.FILE_MAP))
- return redirect(uri.spec, uri, 1);
-
- if (uri.host in this.providers)
- return makeChannel(this.providers[uri.host](uri), uri);
-
- let path = decodeURIComponent(uri.path.replace(/^\/|#.*/g, ""));
- switch(uri.host) {
- case "content":
- return makeChannel(this.pages[path] || "resource://dactyl-content/" + path, uri);
- case "data":
- try {
- var channel = ioService.newChannel(uri.path.replace(/^\/(.*)(?:#.*)?/, "data:$1"),
- null, null);
- }
- catch (e) {
- var error = e;
- break;
- }
- channel.contentCharset = "UTF-8";
- channel.owner = systemPrincipal;
- channel.originalURI = uri;
- return channel;
- case "help":
- return makeChannel(this.FILE_MAP[path], uri);
- case "help-overlay":
- return makeChannel(this.OVERLAY_MAP[path], uri);
- case "help-tag":
- let tag = decodeURIComponent(uri.path.substr(1));
- if (tag in this.FILE_MAP)
- return redirect("dactyl://help/" + tag, uri);
- if (tag in this.HELP_TAGS)
- return redirect("dactyl://help/" + this.HELP_TAGS[tag] + "#" + tag.replace(/#/g, encodeURIComponent), uri);
- break;
- case "locale":
- return LocaleChannel("dactyl-locale", path, uri);
- case "locale-local":
- return LocaleChannel("dactyl-local-locale", path, uri);
- }
- }
- catch (e) {
- util.reportError(e);
- }
- if (error)
- throw error;
- return fakeChannel(uri);
- },
-
- // FIXME: Belongs elsewhere
- _xpcom_categories: [{
- category: "profile-after-change",
- entry: "m-dactyl"
- }],
-
- observe: function observe(subject, topic, data) {
- if (topic === "profile-after-change") {
- Cu.import("resource://dactyl/bootstrap.jsm");
- JSMLoader.init();
- require(global, "overlay");
- }
- }
-};
-
-function LocaleChannel(pkg, path, orig) {
- for each (let locale in [config.locale, "en-US"])
- for each (let sep in "-/") {
- var channel = makeChannel(["resource:/", pkg + sep + config.locale, path].join("/"), orig);
- if (channel.name !== _DNE)
- return channel;
- }
- return channel;
-}
-
-function StringChannel(data, contentType, uri) {
- let channel = services.StreamChannel(uri);
- channel.contentStream = services.CharsetConv("UTF-8").convertToInputStream(data);
- if (contentType)
- channel.contentType = contentType;
- channel.contentCharset = "UTF-8";
- channel.owner = systemPrincipal;
- if (uri)
- channel.originalURI = uri;
- return channel;
-}
-
-function XMLChannel(uri, contentType) {
- try {
- var channel = services.io.newChannelFromURI(uri);
- var channelStream = channel.open();
- }
- catch (e) {
- this.channel = fakeChannel(uri);
- return;
- }
-
- this.uri = uri;
- this.sourceChannel = services.io.newChannelFromURI(uri);
- this.pipe = services.Pipe(true, true, 0, 0, null);
- this.writes = [];
-
- this.channel = services.StreamChannel(uri);
- this.channel.contentStream = this.pipe.inputStream;
- this.channel.contentType = contentType || channel.contentType;
- this.channel.contentCharset = "UTF-8";
- this.channel.owner = systemPrincipal;
-
- let stream = services.InputStream(channelStream);
- let [, pre, doctype, url, open, post] = util.regexp(<![CDATA[
- ^ ([^]*?)
- (?:
- (<!DOCTYPE \s+ \S+ \s+) SYSTEM \s+ "([^"]*)"
- (\s+ \[)?
- ([^]*)
- )?
- $
- ]]>, "x").exec(stream.read(4096));
- this.writes.push(pre);
- if (doctype) {
- this.writes.push(doctype + "[\n");
- try {
- this.writes.push(services.io.newChannel(url, null, null).open());
- }
- catch (e) {}
- if (!open)
- this.writes.push("\n]");
- this.writes.push(post);
- }
- this.writes.push(channelStream);
-
- this.writeNext();
-}
-XMLChannel.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver]),
- writeNext: function () {
- try {
- if (!this.writes.length)
- this.pipe.outputStream.close();
- else {
- let stream = this.writes.shift();
- if (isString(stream))
- stream = services.StringStream(stream);
-
- services.StreamCopier(stream, this.pipe.outputStream, null,
- false, true, 4096, true, false)
- .asyncCopy(this, null);
- }
- }
- catch (e) {
- util.reportError(e);
- }
- },
-
- onStartRequest: function (request, context) {},
- onStopRequest: function (request, context, statusCode) {
- this.writeNext();
- }
-};
-
-function AboutHandler() {}
-AboutHandler.prototype = {
- register: function () {
- try {
- JSMLoader.registerFactory(Factory(AboutHandler));
- }
- catch (e) {
- util.reportError(e);
- }
- },
-
- get classDescription() "About " + config.appName + " Page",
-
- classID: Components.ID("81495d80-89ee-4c36-a88d-ea7c4e5ac63f"),
-
- get contractID() "@mozilla.org/network/protocol/about;1?what=" + config.name,
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
-
- newChannel: function (uri) {
- let channel = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService)
- .newChannel("dactyl://content/about.xul", null, null);
- channel.originalURI = uri;
- return channel;
- },
-
- getURIFlags: function (uri) Ci.nsIAboutModule.ALLOW_SCRIPT,
-};
-
-// A hack to get information about interfaces.
-// Doesn't belong here.
-function Shim() {}
-Shim.prototype = {
- contractID: "@dactyl.googlecode.com/base/xpc-interface-shim",
- classID: Components.ID("{f4506a17-5b4d-4cd9-92d4-2eb4630dc388}"),
- classDescription: "XPCOM empty interface shim",
- QueryInterface: function (iid) {
- if (iid.equals(Ci.nsISecurityCheckedComponent))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- },
- getHelperForLanguage: function () null,
- getInterfaces: function (count) { count.value = 0; }
-};
-
-if (XPCOMUtils.generateNSGetFactory)
- var NSGetFactory = XPCOMUtils.generateNSGetFactory([ChromeData, Dactyl, Shim]);
-else
- var NSGetModule = XPCOMUtils.generateNSGetModule([ChromeData, Dactyl, Shim]);
-var EXPORTED_SYMBOLS = ["NSGetFactory", "global"];
-
-// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/common/content/dactyl.js b/common/content/dactyl.js
index f5bb119d..1c16719c 100644
--- a/common/content/dactyl.js
+++ b/common/content/dactyl.js
@@ -29,10 +29,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
this._observers = {};
util.addObserver(this);
- this.commands["dactyl.help"] = function (event) {
- let elem = event.originalTarget;
- dactyl.help(elem.getAttribute("tag") || elem.textContent);
- };
this.commands["dactyl.restart"] = function (event) {
dactyl.restart();
};
@@ -287,10 +283,10 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
let results = array((params.iterateIndex || params.iterate).call(params, commands.get(name).newArgs()))
.array.sort(function (a, b) String.localeCompare(a.name, b.name));
- let tags = services["dactyl:"].HELP_TAGS;
+ let haveTag = Set.has(help.tags);
for (let obj in values(results)) {
let res = dactyl.generateHelp(obj, null, null, true);
- if (!Set.has(tags, obj.helpTag))
+ if (!haveTag(obj.helpTag))
res[1].@tag = obj.helpTag;
yield res;
@@ -631,33 +627,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
has: function (feature) Set.has(config.features, feature),
/**
- * Returns the URL of the specified help *topic* if it exists.
- *
- * @param {string} topic The help topic to look up.
- * @param {boolean} consolidated Whether to search the consolidated help page.
- * @returns {string}
- */
- findHelp: function (topic, consolidated) {
- if (!consolidated && topic in services["dactyl:"].FILE_MAP)
- return topic;
- let items = completion._runCompleter("help", topic, null, !!consolidated).items;
- let partialMatch = null;
-
- function format(item) item.description + "#" + encodeURIComponent(item.text);
-
- for (let [i, item] in Iterator(items)) {
- if (item.text == topic)
- return format(item);
- else if (!partialMatch && topic)
- partialMatch = item;
- }
-
- if (partialMatch)
- return format(partialMatch);
- return null;
- },
-
- /**
* @private
*/
initDocument: function initDocument(doc) {
@@ -672,243 +641,89 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
}
},
+ help: deprecated("help.help", { get: function help() modules.help.closure.help }),
+ findHelp: deprecated("help.findHelp", { get: function findHelp() help.closure.findHelp }),
+
/**
* @private
* Initialize the help system.
*/
- initHelp: function (force) {
- // Waits for the add-on to become available, if necessary.
- config.addon;
- config.version;
-
- if (force || !this.helpInitialized) {
- if ("noscriptOverlay" in window) {
- noscriptOverlay.safeAllow("chrome-data:", true, false);
- noscriptOverlay.safeAllow("dactyl:", true, false);
- }
+ initHelp: function initHelp(force) {
+ if ("noscriptOverlay" in window)
+ noscriptOverlay.safeAllow("dactyl:", true, false);
- // Find help and overlay files with the given name.
- let findHelpFile = function findHelpFile(file) {
- let result = [];
- for (let [, namespace] in Iterator(namespaces)) {
- let url = ["dactyl://", namespace, "/", file, ".xml"].join("");
- let res = util.httpGet(url);
- if (res) {
- if (res.responseXML.documentElement.localName == "document")
- fileMap[file] = url;
- if (res.responseXML.documentElement.localName == "overlay")
- overlayMap[file] = url;
- result.push(res.responseXML);
- }
- }
- return result;
- };
- // Find the tags in the document.
- let addTags = function addTags(file, doc) {
- for (let elem in DOM.XPath("//@tag|//dactyl:tags/text()|//dactyl:tag/text()", doc))
- for (let tag in values((elem.value || elem.textContent).split(/\s+/)))
- tagMap[tag] = file;
- };
+ if (!force && help.initialized)
+ return;
- let namespaces = ["locale-local", "locale"];
- services["dactyl:"].init({});
-
- let tagMap = services["dactyl:"].HELP_TAGS;
- let fileMap = services["dactyl:"].FILE_MAP;
- let overlayMap = services["dactyl:"].OVERLAY_MAP;
-
- // Scrape the list of help files from all.xml
- // Manually process main and overlay files, since XSLTProcessor and
- // XMLHttpRequest don't allow access to chrome documents.
- tagMap["all"] = tagMap["all.xml"] = "all";
- tagMap["versions"] = tagMap["versions.xml"] = "versions";
- let files = findHelpFile("all").map(function (doc)
- [f.value for (f in DOM.XPath("//dactyl:include/@href", doc))]);
-
- // Scrape the tags from the rest of the help files.
- array.flatten(files).forEach(function (file) {
- tagMap[file + ".xml"] = file;
- findHelpFile(file).forEach(function (doc) {
- addTags(file, doc);
- });
- });
+ help.initialize(force);
- // Process plugin help entries.
- XML.ignoreWhiteSpace = XML.prettyPrinting = false;
+ // Process plugin help entries.
+ XML.ignoreWhiteSpace = XML.prettyPrinting = false;
- let body = XML();
- 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));
+ let body = XML();
+ 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);
+ info.* = info.*.(function::attribute("lang").length() == 0 || @lang == lang);
- for each (let elem in info.NS::info)
- for each (let attr in ["@name", "@summary", "@href"])
- if (elem[attr].length())
- info[attr] = elem[attr];
- }
- body += <h2 xmlns={NS.uri} tag={info.@name + '-plugin'}>{info.@summary}</h2> +
- info;
+ for each (let elem in info.NS::info)
+ for each (let attr in ["@name", "@summary", "@href"])
+ if (elem[attr].length())
+ info[attr] = elem[attr];
}
+ body += <h2 xmlns={NS.uri} tag={info.@name + '-plugin'}>{info.@summary}</h2> +
+ info;
}
- catch (e) {
- util.reportError(e);
- }
+ }
+ catch (e) {
+ util.reportError(e);
+ }
- let help =
- '<?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();
- fileMap["plugins"] = function () ['text/xml;charset=UTF-8', help];
-
- fileMap["versions"] = function () {
- let NEWS = util.httpGet(config.addon.getResourceURI("NEWS").spec,
- { mimeType: "text/plain;charset=UTF-8" })
- .responseText;
-
- let re = util.regexp(<![CDATA[
- ^ (?P<comment> \s* # .*\n)
-
- | ^ (?P<space> \s*)
- (?P<char> [-•*+]) \ //
- (?P<content> .*\n
- (?: \2\ \ .*\n | \s*\n)* )
-
- | (?P<par>
- (?: ^ [^\S\n]*
- (?:[^-•*+\s] | [-•*+]\S)
- .*\n
- )+
- )
-
- | (?: ^ [^\S\n]* \n) +
- ]]>, "gmxy");
-
- let betas = util.regexp(/\[(b\d)\]/, "gx");
-
- let beta = array(betas.iterate(NEWS))
- .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 list, space, i = 0;
-
- for (let match in re.iterate(text)) {
- if (match.comment)
- 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;
- }
- else if (match.par) {
- let [, par, tags] = /([^]*?)\s*((?:\[[^\]]+\])*)\n*$/.exec(match.par);
- let t = tags;
- tags = array(betas.iterate(tags)).map(function (m) m[1]);
-
- let group = !tags.length ? "" :
- !tags.some(function (t) t == beta) ? "HelpNewsOld" : "HelpNewsNew";
- if (i === 0 && li) {
- li.@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>;
- }
- 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>;
- }
- }
- i++;
- }
- for each (let attr in res..@highlight) {
- attr.parent().@NS::highlight = attr;
- delete attr.parent().@highlight;
- }
- return res;
- }
+ help.files["plugins"] = function () ['text/xml;charset=UTF-8',
+ '<?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"/>
- 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";
- }
- }
+ {body}
+ </document>.toXMLString()];
- return ["application/xml",
- '<?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()
- ];
- }
- addTags("versions", util.httpGet("dactyl://help/versions").responseXML);
- addTags("plugins", util.httpGet("dactyl://help/plugins").responseXML);
-
- default xml namespace = NS;
-
- overlayMap["index"] = ['text/xml;charset=UTF-8',
- '<?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>];
- addTags("index", util.httpGet("dactyl://help-overlay/index").responseXML);
-
- overlayMap["gui"] = ['text/xml;charset=UTF-8',
- '<?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>];
-
-
- this.helpInitialized = true;
- }
+
+ default xml namespace = NS;
+
+ help.overlays["index"] = ['text/xml;charset=UTF-8',
+ '<?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>];
+
+ help.overlays["gui"] = ['text/xml;charset=UTF-8',
+ '<?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>];
+
+ help.tags["plugins"] = help.tags["plugins.xml"] = "plugins";
+ help.tags["index"] = help.tags["index.xml"] = "index";
+
+ help.addTags("plugins", util.httpGet("dactyl://help/plugins").responseXML);
+ help.addTags("index", util.httpGet("dactyl://help-overlay/index").responseXML);
},
stringifyXML: function (xml) {
@@ -995,7 +810,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
let chromeFiles = {};
let styles = {};
- for (let [file, ] in Iterator(services["dactyl:"].FILE_MAP)) {
+ for (let [file, ] in Iterator(help.files)) {
let url = "dactyl://help/" + file;
dactyl.open(url);
util.waitFor(function () content.location.href == url && buffer.loaded
@@ -1018,7 +833,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
.join("\n");
addDataEntry("help.css", data.replace(/chrome:[^ ")]+\//g, ""));
- addDataEntry("tag-map.json", JSON.stringify(services["dactyl:"].HELP_TAGS));
+ addDataEntry("tag-map.json", JSON.stringify(help.tags));
let m, re = /(chrome:[^ ");]+\/)([^ ");]+)/g;
while ((m = re.exec(data)))
@@ -1047,12 +862,12 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
let args = null;
if (obj instanceof Command) {
- link = function (cmd) <ex>:{cmd}</ex>;
+ link = function (cmd) <ex>{cmd}</ex>;
args = obj.parseArgs("", CompletionContext(str || ""));
tag = function (cmd) <>:{cmd}</>;
spec = function (cmd) <>{
obj.count ? <oa>count</oa> : <></>
- }:{
+ }{
cmd
}{
obj.bang ? <oa>!</oa> : <></>
@@ -1085,7 +900,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
</>;
let res = <res>
- <dt>{link(obj.helpTag || obj.name, obj.name)}</dt> <dd>{
+ <dt>{link(obj.helpTag || tag(obj.name), obj.name)}</dt> <dd>{
template.linkifyHelp(obj.description ? obj.description.replace(/\.$/, "") : "", true)
}</dd></res>;
if (specOnly)
@@ -1095,9 +910,11 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
<item>
<tags>{template.map(obj.names.slice().reverse(), tag, " ")}</tags>
<spec>{
- spec(template.highlightRegexp((obj.specs || obj.names)[0],
- /\[(.*?)\]/g,
- function (m, n0) <oa>{n0}</oa>))
+ 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>
@@ -1139,30 +956,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
},
/**
- * Opens the help page containing the specified *topic* if it exists.
- *
- * @param {string} topic The help topic to open.
- * @param {boolean} consolidated Whether to use the consolidated help page.
- */
- help: function (topic, consolidated) {
- dactyl.initHelp();
- if (!topic) {
- let helpFile = consolidated ? "all" : options["helpfile"];
-
- if (helpFile in services["dactyl:"].FILE_MAP)
- dactyl.open("dactyl://help/" + helpFile, { from: "help" });
- else
- dactyl.echomsg(_("help.noFile", helpFile.quote()));
- return;
- }
-
- let page = this.findHelp(topic, consolidated);
- dactyl.assert(page != null, _("help.noTopic", topic));
-
- dactyl.open("dactyl://help/" + page, { from: "help" });
- },
-
- /**
* The map of global variables.
*
* These are set and accessed with the "g:" prefix.
@@ -1764,14 +1557,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
},
mappings: function () {
- mappings.add([modes.MAIN], ["<open-help>", "<F1>"],
- "Open the introductory help page",
- function () { dactyl.help(); });
-
- mappings.add([modes.MAIN], ["<open-single-help>", "<A-F1>"],
- "Open the single, consolidated help page",
- function () { ex.helpall(); });
-
if (dactyl.has("session"))
mappings.add([modes.NORMAL], ["ZQ"],
"Quit and don't save the session",
@@ -1842,30 +1627,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
literal: 0
});
- [
- {
- name: "h[elp]",
- description: "Open the introductory help page"
- }, {
- name: "helpa[ll]",
- description: "Open the single consolidated help page"
- }
- ].forEach(function (command) {
- let consolidated = command.name == "helpa[ll]";
-
- commands.add([command.name],
- command.description,
- function (args) {
- dactyl.assert(!args.bang, _("help.dontPanic"));
- dactyl.help(args.literalArg, consolidated);
- }, {
- argCount: "?",
- bang: true,
- completer: function (context) completion.help(context, consolidated),
- literal: 0
- });
- });
-
commands.add(["loadplugins", "lpl"],
"Load all or matching plugins",
function (args) {
@@ -2123,15 +1884,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
context.completions = [[k, v[0], v[2]] for ([k, v] in Iterator(config.dialogs))];
};
- completion.help = function help(context, consolidated) {
- dactyl.initHelp();
- context.title = ["Help"];
- context.anchored = false;
- context.completions = services["dactyl:"].HELP_TAGS;
- if (consolidated)
- context.keys = { text: 0, description: function () "all" };
- };
-
completion.menuItem = function menuItem(context) {
context.title = ["Menu Path", "Label"];
context.anchored = false;
@@ -2186,7 +1938,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
localPrefs.set("first-run", false);
this.withSavedValues(["forceTarget"], function () {
this.forceTarget = dactyl.NEW_TAB;
- this.help();
+ help.help();
});
}, 1000);
diff --git a/common/content/help.xsl b/common/content/help.xsl
index 1ebd6d6b..132ed738 100644
--- a/common/content/help.xsl
+++ b/common/content/help.xsl
@@ -296,14 +296,18 @@
<xsl:template name="linkify-tag">
<xsl:param name="contents" select="text()"/>
<xsl:variable name="tag" select="$contents"/>
+ <xsl:variable name="tag-url" select="
+ regexp:replace(regexp:replace($tag, '%', 'g', '%25'),
+ '#', 'g', '%23')"/>
+
<a style="color: inherit;">
<xsl:if test="not(@link) or @link != 'false'">
<xsl:choose>
<xsl:when test="contains(ancestor::*/@document-tags, concat(' ', $tag, ' '))">
- <xsl:attribute name="href">#<xsl:value-of select="$tag"/></xsl:attribute>
+ <xsl:attribute name="href">#<xsl:value-of select="$tag-url"/></xsl:attribute>
</xsl:when>
<xsl:otherwise>
- <xsl:attribute name="href">dactyl://help-tag/<xsl:value-of select="$tag"/></xsl:attribute>
+ <xsl:attribute name="href">dactyl://help-tag/<xsl:value-of select="$tag-url"/></xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
diff --git a/common/content/mappings.js b/common/content/mappings.js
index 6fbcead3..b1336161 100644
--- a/common/content/mappings.js
+++ b/common/content/mappings.js
@@ -130,7 +130,7 @@ var Map = Class("Map", {
if (this.executing) {
util.dumpStack(_("map.recursive", args.command));
- throw AssertionError(_("map.recursive", args.command));
+ throw FailedAssertion(_("map.recursive", args.command));
}
try {
@@ -771,10 +771,10 @@ var Mappings = Module("mappings", {
name: [mode.char + "listk[eys]", mode.char + "lk"],
iterateIndex: function (args)
let (self = this, prefix = /^[bCmn]$/.test(mode.char) ? "" : mode.char + "_",
- tags = services["dactyl:"].HELP_TAGS)
+ haveTag = Set.has(help.tags))
({ helpTag: prefix + map.name, __proto__: map }
for (map in self.iterate(args, true))
- if (map.hive === mappings.builtin || Set.has(tags, prefix + map.name))),
+ if (map.hive === mappings.builtin || haveTag(prefix + map.name))),
description: "List all " + mode.displayName + " mode mappings along with their short descriptions",
index: mode.char + "-map",
getMode: function (args) mode,
diff --git a/common/locale/en-US/buffer.xml b/common/locale/en-US/buffer.xml
index e76ee24f..7e1b645b 100644
--- a/common/locale/en-US/buffer.xml
+++ b/common/locale/en-US/buffer.xml
@@ -140,7 +140,7 @@
</item>
<item>
- <tags>&lt;scroll-percent> N%</tags>
+ <tags>&lt;scroll-percent> N% %</tags>
<spec><a>count</a>%</spec>
<description short="true">
<p>Scroll to <a>count</a> percent of the document.</p>
diff --git a/common/modules/base.jsm b/common/modules/base.jsm
index b7b7d441..7c72334a 100644
--- a/common/modules/base.jsm
+++ b/common/modules/base.jsm
@@ -133,7 +133,8 @@ function defineModule(name, params, module) {
module.NAME = name;
module.EXPORTED_SYMBOLS = params.exports || [];
- defineModule.loadLog.push("defineModule " + name);
+ defineModule.loadLog.push("[Begin " + name + "]");
+ defineModule.prefix += " ";
for (let [, mod] in Iterator(params.require || []))
require(module, mod);
@@ -152,11 +153,13 @@ function defineModule(name, params, module) {
defineModule.loadLog = [];
Object.defineProperty(defineModule.loadLog, "push", {
value: function (val) {
+ val = defineModule.prefix + val;
if (true)
defineModule.dump(val + "\n");
this[this.length] = Date.now() + " " + val;
}
});
+defineModule.prefix = "";
defineModule.dump = function dump_() {
let msg = Array.map(arguments, function (msg) {
if (loaded.util && typeof msg == "object")
@@ -185,7 +188,8 @@ defineModule.time = function time(major, minor, func, self) {
}
function endModule() {
- defineModule.loadLog.push("endModule " + currentModule.NAME);
+ defineModule.prefix = defineModule.prefix.slice(0, -2);
+ defineModule.loadLog.push("(End " + currentModule.NAME + ")");
for (let [, mod] in Iterator(use[currentModule.NAME] || []))
require(mod, currentModule.NAME, "use");
@@ -202,7 +206,7 @@ function require(obj, name, from) {
let caller = Components.stack.caller;
if (!loaded[name])
- defineModule.loadLog.push(" " + (from || "require") + ": loading " + name + " into " + (obj.NAME || caller.filename + ":" + caller.lineNumber));
+ defineModule.loadLog.push((from || "require") + ": loading " + name + " into " + (obj.NAME || caller.filename + ":" + caller.lineNumber));
JSMLoader.load(name + ".jsm", obj);
return obj;
@@ -220,11 +224,12 @@ defineModule("base", {
// sed -n 's/^(const|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt
exports: [
"ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object", "Runnable",
- "Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "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"
+ "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"
],
use: ["config", "services", "util"]
}, this);
@@ -754,6 +759,10 @@ function Class() {
constructor: { value: Constructor },
});
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;
})]]>,
@@ -1022,7 +1031,7 @@ function XPCOM(interfaces, superClass) {
interfaces = Array.concat(interfaces);
let shim = interfaces.reduce(function (shim, iface) shim.QueryInterface(iface),
- Cc["@dactyl.googlecode.com/base/xpc-interface-shim"].createInstance());
+ XPCOMShim());
let res = Class("XPCOM(" + interfaces + ")", superClass || Class, update(
iter.toObject([k, v === undefined || callable(v) ? function stub() null : v]
@@ -1031,6 +1040,18 @@ function XPCOM(interfaces, superClass) {
shim = interfaces = null;
return res;
}
+function XPCOMShim() {
+ let ip = services.InterfacePointer({
+ QueryInterface: function (iid) {
+ if (iid.equals(Ci.nsISecurityCheckedComponent))
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ return this;
+ },
+ getHelperForLanguage: function () null,
+ getInterfaces: function (count) { count.value = 0; }
+ });
+ return ip.data;
+};
/**
* An abstract base class for classes that wish to inherit from Error.
@@ -1065,24 +1086,32 @@ var ErrorBase = Class("ErrorBase", Error, {
* @returns {Class}
*/
function Module(name, prototype) {
- let init = callable(prototype) ? 4 : 3;
- let proto = arguments[callable(prototype) ? 2 : 1];
+ try {
+ let init = callable(prototype) ? 4 : 3;
+ let proto = arguments[callable(prototype) ? 2 : 1];
- proto._metaInit_ = function () {
- delete module.prototype._metaInit_;
- currentModule[name.toLowerCase()] = this;
- };
+ proto._metaInit_ = function () {
+ delete module.prototype._metaInit_;
+ currentModule[name.toLowerCase()] = this;
+ };
- const module = Class.apply(Class, Array.slice(arguments, 0, init));
- let instance = module();
- module.className = name.toLowerCase();
+ const module = Class.apply(Class, Array.slice(arguments, 0, init));
+ let instance = module();
+ module.className = name.toLowerCase();
- instance.INIT = update(Object.create(Module.INIT),
- arguments[init] || {});
+ instance.INIT = update(Object.create(Module.INIT),
+ arguments[init] || {});
- currentModule[module.className] = instance;
- defineModule.modules.push(instance);
- return module;
+ currentModule[module.className] = instance;
+ defineModule.modules.push(instance);
+ return module;
+ }
+ catch (e) {
+ if (typeof e === "string")
+ e = Error(e);
+
+ dump(e.fileName + ":" + e.lineNumber + ": " + e + "\n" + (e.stack || Error().stack));
+ }
}
Module.INIT = {
init: function Module_INIT_init(dactyl, modules, window) {
diff --git a/common/modules/bootstrap.jsm b/common/modules/bootstrap.jsm
index d51f8696..fc4eac60 100644
--- a/common/modules/bootstrap.jsm
+++ b/common/modules/bootstrap.jsm
@@ -19,11 +19,11 @@ if (!JSMLoader && "@mozilla.org/fuel/application;1" in Components.classes)
.getService(Components.interfaces.extIApplication)
.storage.get("dactyl.JSMLoader", null);
-if (JSMLoader && JSMLoader.bump === 5)
+if (JSMLoader && JSMLoader.bump === 6)
JSMLoader.global = this;
else
JSMLoader = {
- bump: 5,
+ bump: 6,
builtin: Cu.Sandbox(this),
@@ -167,6 +167,24 @@ else
}
},
+ 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) {
this.manager.registerFactory(factory.classID,
String(factory.classID),
diff --git a/common/modules/commands.jsm b/common/modules/commands.jsm
index 95d4b2eb..a837ef33 100644
--- a/common/modules/commands.jsm
+++ b/common/modules/commands.jsm
@@ -12,7 +12,7 @@ Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("commands", {
exports: ["ArgType", "Command", "Commands", "CommandOption", "Ex", "commands"],
require: ["contexts", "messages", "util"],
- use: ["config", "options", "services", "template"]
+ use: ["config", "help", "options", "services", "template"]
}, this);
/**
@@ -1585,7 +1585,7 @@ var Commands = Module("commands", {
cmd.hive == commands.builtin ? "" : <span highlight="Object" style="padding-right: 1em;">{cmd.hive.name}</span>
]
})),
- iterateIndex: function (args) let (tags = services["dactyl:"].HELP_TAGS)
+ iterateIndex: function (args) let (tags = help.tags)
this.iterate(args).filter(function (cmd) cmd.hive === commands.builtin || Set.has(tags, cmd.helpTag)),
format: {
headings: ["Command", "Group", "Description"],
diff --git a/common/modules/config.jsm b/common/modules/config.jsm
index f5d231cb..482216b2 100644
--- a/common/modules/config.jsm
+++ b/common/modules/config.jsm
@@ -6,16 +6,34 @@
// given in the LICENSE.txt file included with this file.
"use strict";
-try {
-
let global = this;
Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("config", {
exports: ["ConfigBase", "Config", "config"],
- require: ["services", "storage", "util", "template"],
+ require: ["protocol", "services", "storage", "util", "template"],
use: ["io", "messages", "prefs", "styles"]
}, this);
+function AboutHandler() {}
+AboutHandler.prototype = {
+ get classDescription() "About " + config.appName + " Page",
+
+ classID: Components.ID("81495d80-89ee-4c36-a88d-ea7c4e5ac63f"),
+
+ get contractID() "@mozilla.org/network/protocol/about;1?what=" + config.name,
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+
+ newChannel: function (uri) {
+ let channel = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService)
+ .newChannel("dactyl://content/about.xul", null, null);
+ channel.originalURI = uri;
+ return channel;
+ },
+
+ getURIFlags: function (uri) Ci.nsIAboutModule.ALLOW_SCRIPT,
+};
+
var ConfigBase = Class("ConfigBase", {
/**
* Called on dactyl startup to allow for any arbitrary application-specific
@@ -26,9 +44,19 @@ var ConfigBase = Class("ConfigBase", {
if (this.haveGecko("2b"))
Set.add(this.features, "Gecko2");
+ JSMLoader.registerFactory(JSMLoader.Factory(AboutHandler));
+ JSMLoader.registerFactory(JSMLoader.Factory(
+ Protocol("dactyl", "{9c8f2530-51c8-4d41-b356-319e0b155c44}",
+ "resource://dactyl-content/")));
+
this.timeout(function () {
services["dactyl:"].pages.dtd = function () [null, util.makeDTD(config.dtd)];
});
+
+ update(services["dactyl:"].providers, {
+ "locale": function (uri, path) LocaleChannel("dactyl-locale", config.locale, path, uri),
+ "locale-local": function (uri, path) LocaleChannel("dactyl-local-locale", config.locale, path, uri)
+ });
},
modules: {
@@ -41,12 +69,14 @@ var ConfigBase = Class("ConfigBase", {
"contexts",
"downloads",
"finder",
+ "help",
"highlight",
"javascript",
"messages",
"options",
"overlay",
"prefs",
+ "protocol",
"sanitizer",
"services",
"storage",
@@ -1065,6 +1095,6 @@ config.INIT = update(Object.create(config.INIT), config.INIT, {
endModule();
-} catch(e){ if (typeof e === "string") e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
+// catch(e){ if (typeof e === "string") e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
// vim: set fdm=marker sw=4 sts=4 et ft=javascript:
diff --git a/common/modules/help.jsm b/common/modules/help.jsm
new file mode 100644
index 00000000..c6dfd445
--- /dev/null
+++ b/common/modules/help.jsm
@@ -0,0 +1,326 @@
+// Copyright (c) 2008-2011 by 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";
+
+Components.utils.import("resource://dactyl/bootstrap.jsm");
+defineModule("help", {
+ exports: ["help"],
+ require: ["protocol", "services", "util"],
+ use: ["config", "highlight", "messages", "template"]
+}, this);
+
+var Help = Module("Help", {
+ init: function init() {
+ this.initialized = false;
+ this.files = {};
+ this.overlays = {};
+ this.tags = {};
+
+ function Loop(fn)
+ function (uri, path) {
+ if (!help.initialized)
+ return RedirectChannel(uri.spec, uri, 1);
+ return fn.apply(this, arguments);
+ }
+
+ update(services["dactyl:"].providers, {
+ "help": Loop(function (uri, path) help.files[path]),
+ "help-overlay": Loop(function (uri, path) help.overlays[path]),
+ "help-tag": Loop(function (uri, path) {
+ let tag = decodeURIComponent(path);
+ if (tag in help.files)
+ return RedirectChannel("dactyl://help/" + tag, uri);
+ if (tag in help.tags)
+ return RedirectChannel("dactyl://help/" + help.tags[tag] + "#" + tag.replace(/#/g, encodeURIComponent), uri);
+ })
+ });
+ },
+
+ Local: function Local(dactyl, modules, window) ({
+ init: function init() {
+ dactyl.commands["dactyl.help"] = function (event) {
+ let elem = event.originalTarget;
+ help.help(elem.getAttribute("tag") || elem.textContent);
+ };
+ },
+
+ /**
+ * Returns the URL of the specified help *topic* if it exists.
+ *
+ * @param {string} topic The help topic to look up.
+ * @param {boolean} consolidated Whether to search the consolidated help page.
+ * @returns {string}
+ */
+ findHelp: function (topic, consolidated) {
+ if (!consolidated && Set.has(help.files, topic))
+ return topic;
+ let items = modules.completion._runCompleter("help", topic, null, !!consolidated).items;
+ let partialMatch = null;
+
+ function format(item) item.description + "#" + encodeURIComponent(item.text);
+
+ for (let [i, item] in Iterator(items)) {
+ if (item.text == topic)
+ return format(item);
+ else if (!partialMatch && topic)
+ partialMatch = item;
+ }
+
+ if (partialMatch)
+ return format(partialMatch);
+ return null;
+ },
+
+ /**
+ * Opens the help page containing the specified *topic* if it exists.
+ *
+ * @param {string} topic The help topic to open.
+ * @param {boolean} consolidated Whether to use the consolidated help page.
+ */
+ help: function (topic, consolidated) {
+ dactyl.initHelp();
+ if (!topic) {
+ let helpFile = consolidated ? "all" : modules.options["helpfile"];
+
+ if (Set.has(help.files, helpFile))
+ dactyl.open("dactyl://help/" + helpFile, { from: "help" });
+ else
+ dactyl.echomsg(_("help.noFile", helpFile.quote()));
+ return;
+ }
+
+ let page = this.findHelp(topic, consolidated);
+ dactyl.assert(page != null, _("help.noTopic", topic));
+
+ dactyl.open("dactyl://help/" + page, { from: "help" });
+ }
+
+ }),
+
+ // Find the tags in the document.
+ addTags: function addTags(file, doc) {
+ for (let elem in DOM.XPath("//@tag|//dactyl:tags/text()|//dactyl:tag/text()", doc))
+ for (let tag in values((elem.value || elem.textContent).split(/\s+/)))
+ this.tags[tag] = file;
+ },
+
+ namespaces: ["locale-local", "locale"],
+
+ // Find help and overlay files with the given name.
+ findHelpFile: function findHelpFile(file) {
+ let result = [];
+ for (let namespace in values(this.namespaces)) {
+ let url = ["dactyl://", namespace, "/", file, ".xml"].join("");
+ let res = util.httpGet(url);
+ if (res) {
+ if (res.responseXML.documentElement.localName == "document")
+ this.files[file] = url;
+ if (res.responseXML.documentElement.localName == "overlay")
+ this.overlays[file] = url;
+ result.push(res.responseXML);
+ }
+ }
+ return result;
+ },
+
+ initialize: function initialize(force) {
+ // Waits for the add-on to become available, if necessary.
+ config.addon;
+ config.version;
+
+ if (force || !this.initialized) {
+
+ this.files["versions"] = function () {
+ let NEWS = util.httpGet(config.addon.getResourceURI("NEWS").spec,
+ { mimeType: "text/plain;charset=UTF-8" })
+ .responseText;
+
+ let re = util.regexp(<![CDATA[
+ ^ (?P<comment> \s* # .*\n)
+
+ | ^ (?P<space> \s*)
+ (?P<char> [-•*+]) \ //
+ (?P<content> .*\n
+ (?: \2\ \ .*\n | \s*\n)* )
+
+ | (?P<par>
+ (?: ^ [^\S\n]*
+ (?:[^-•*+\s] | [-•*+]\S)
+ .*\n
+ )+
+ )
+
+ | (?: ^ [^\S\n]* \n) +
+ ]]>, "gmxy");
+
+ let betas = util.regexp(/\[(b\d)\]/, "gx");
+
+ let beta = array(betas.iterate(NEWS))
+ .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 list, space, i = 0;
+
+
+ for (let match in re.iterate(text)) {
+ if (match.comment)
+ 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;
+ }
+ else if (match.par) {
+ let [, par, tags] = /([^]*?)\s*((?:\[[^\]]+\])*)\n*$/.exec(match.par);
+ let t = tags;
+ tags = array(betas.iterate(tags)).map(function (m) m[1]);
+
+ let group = !tags.length ? "" :
+ !tags.some(function (t) t == beta) ? "HelpNewsOld" : "HelpNewsNew";
+ if (i === 0 && li) {
+ li.@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>;
+ }
+ 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>;
+ }
+ }
+ 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";
+ }
+ }
+
+
+ return ["application/xml",
+ '<?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()
+ ];
+ }
+
+
+
+ // Scrape the list of help files from all.xml
+ // Manually process main and overlay files, since XSLTProcessor and
+ // XMLHttpRequest don't allow access to chrome documents.
+ this.tags["all"] = this.tags["all.xml"] = "all";
+ let files = this.findHelpFile("all").map(function (doc)
+ [f.value for (f in DOM.XPath("//dactyl:include/@href", doc))]);
+
+ // Scrape the tags from the rest of the help files.
+ array.flatten(files).forEach(function (file) {
+ this.tags[file + ".xml"] = file;
+ this.findHelpFile(file).forEach(function (doc) {
+ this.addTags(file, doc);
+ }, this);
+ }, this);
+
+ this.tags["versions"] = this.tags["versions.xml"] = "versions";
+
+ this.addTags("versions", util.httpGet("dactyl://help/versions").responseXML);
+
+ help.initialized = true;
+ }
+ },
+}, {
+}, {
+ commands: function init_commands(dactyl, modules, window) {
+ const { commands, completion, help } = modules;
+
+ [
+ {
+ name: "h[elp]",
+ description: "Open the introductory help page"
+ }, {
+ name: "helpa[ll]",
+ description: "Open the single consolidated help page"
+ }
+ ].forEach(function (command) {
+ let consolidated = command.name == "helpa[ll]";
+
+ commands.add([command.name],
+ command.description,
+ function (args) {
+ dactyl.assert(!args.bang, _("help.dontPanic"));
+ help.help(args.literalArg, consolidated);
+ }, {
+ argCount: "?",
+ bang: true,
+ completer: function (context) completion.help(context, consolidated),
+ literal: 0
+ });
+ });
+ },
+ completion: function init_completion(dactyl, modules, window) {
+ const { completion } = modules;
+
+ completion.help = function completion_help(context, consolidated) {
+ dactyl.initHelp();
+ context.title = ["Help"];
+ context.anchored = false;
+ context.completions = help.tags;
+ if (consolidated)
+ 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(); });
+ }
+});
+
+endModule();
+
+// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/common/modules/io.jsm b/common/modules/io.jsm
index aeead9b3..20bbc3d9 100644
--- a/common/modules/io.jsm
+++ b/common/modules/io.jsm
@@ -13,7 +13,7 @@ Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("io", {
exports: ["IO", "io"],
require: ["services"],
- use: ["config", "messages", "storage", "styles", "template", "util"]
+ use: ["config", "help", "messages", "storage", "styles", "template", "util"]
}, this);
// TODO: why are we passing around strings rather than file objects?
@@ -174,7 +174,7 @@ var IO = Module("io", {
util.flushCache();
dactyl.loadScript(uri.spec, context);
- dactyl.helpInitialized = false;
+ help.initialized = false;
}
catch (e) {
if (e.fileName)
diff --git a/common/modules/overlay.jsm b/common/modules/overlay.jsm
index 788c923d..10e20a8a 100644
--- a/common/modules/overlay.jsm
+++ b/common/modules/overlay.jsm
@@ -9,7 +9,7 @@ try {
Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("overlay", {
exports: ["ModuleBase", "overlay"],
- require: ["config", "highlight", "io", "services", "util"]
+ require: ["config", "help", "highlight", "io", "services", "util"]
}, this);
/**
@@ -41,8 +41,6 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen
util.addObserver(this);
this.overlays = {};
- services["dactyl:"]; // Hack. Force module initialization.
-
config.loadStyles();
this.timeout(this.initialize);
diff --git a/common/modules/protocol.jsm b/common/modules/protocol.jsm
new file mode 100644
index 00000000..23b6801c
--- /dev/null
+++ b/common/modules/protocol.jsm
@@ -0,0 +1,228 @@
+// Copyright (c) 2008-2011 by 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";
+
+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);
+
+var DNE = "resource://gre/does/not/exist";
+var _DNE;
+
+function Channel(url, orig, noFake) {
+ try {
+ if (url == null)
+ return noFake ? null : FakeChannel(orig);
+
+ if (url instanceof Ci.nsIChannel)
+ return url;
+
+ if (typeof url === "function")
+ return let ([type, data] = url(orig)) StringChannel(data, type, orig);
+
+ if (isArray(url))
+ return let ([type, data] = url) StringChannel(data, type, orig);
+
+ let uri = services.io.newURI(url, null, null);
+ return (new XMLChannel(uri, null, noFake)).channel;
+ }
+ catch (e) {
+ util.reportError(e);
+ throw e;
+ }
+}
+function FakeChannel(orig) {
+ let channel = services.io.newChannel(DNE, null, null);
+ channel.originalURI = orig;
+ return channel;
+}
+function RedirectChannel(to, orig, time) {
+ let html = <html><head><meta http-equiv="Refresh" content={(time || 0) + ";" + to}/></head></html>.toXMLString();
+ return StringChannel(html, "text/html", services.io.newURI(to, null, null));
+}
+
+function Protocol(scheme, classID, contentBase) {
+ function Protocol() {
+ ProtocolBase.call(this);
+ }
+ Protocol.prototype = {
+ __proto__: ProtocolBase.prototype,
+
+ classID: Components.ID(classID),
+
+ scheme: scheme,
+
+ contentBase: contentBase,
+
+ _xpcom_factory: JSMLoader.Factory(Protocol),
+ };
+ return Protocol;
+}
+
+function ProtocolBase() {
+ this.wrappedJSObject = this;
+
+ this.pages = {};
+ this.providers = {};
+}
+ProtocolBase.prototype = {
+ get contractID() "@mozilla.org/network/protocol;1?name=" + this.scheme,
+ get classDescription() this.scheme + " utility protocol",
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]),
+
+ defaultPort: -1,
+ allowPort: function (port, scheme) false,
+ protocolFlags: 0
+ | Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE
+ | Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE,
+
+ newURI: function newURI(spec, charset, baseURI) {
+ var uri = Cc["@mozilla.org/network/standard-url;1"]
+ .createInstance(Ci.nsIStandardURL)
+ .QueryInterface(Ci.nsIURI);
+ if (baseURI && baseURI.host === "data")
+ baseURI = null;
+ uri.init(uri.URLTYPE_STANDARD, this.defaultPort, spec, charset, baseURI);
+ return uri;
+ },
+
+ newChannel: function newChannel(uri) {
+ try {
+ uri.QueryInterface(Ci.nsIURL);
+
+ if (uri.host in this.providers)
+ return Channel(this.providers[uri.host](uri, uri.filePath.substr(1)), uri);
+
+ let path = decodeURIComponent(uri.path.replace(/^\/|#.*/g, ""));
+ switch(uri.host) {
+ case "content":
+ return Channel(this.pages[path] || this.contentBase + path, uri);
+ case "data":
+ try {
+ var channel = services.io.newChannel(uri.path.replace(/^\/(.*)(?:#.*)?/, "data:$1"),
+ null, null);
+ }
+ catch (e) {
+ var error = e;
+ break;
+ }
+ channel.contentCharset = "UTF-8";
+ channel.owner = systemPrincipal;
+ channel.originalURI = uri;
+ return channel;
+ }
+ }
+ catch (e) {
+ util.reportError(e);
+ }
+ if (error)
+ throw error;
+ return FakeChannel(uri);
+ }
+};
+
+function LocaleChannel(pkg, locale, path, orig) {
+ for each (let locale in [locale, "en-US"])
+ for each (let sep in "-/") {
+ var channel = Channel(["resource:/", pkg + sep + locale, path].join("/"), orig, true);
+ if (channel)
+ return channel;
+ }
+
+ return FakeChannel(orig);
+}
+
+function StringChannel(data, contentType, uri) {
+ let channel = services.StreamChannel(uri);
+ channel.contentStream = services.CharsetConv("UTF-8").convertToInputStream(data);
+ if (contentType)
+ channel.contentType = contentType;
+ channel.contentCharset = "UTF-8";
+ channel.owner = systemPrincipal;
+ if (uri)
+ channel.originalURI = uri;
+ return channel;
+}
+
+function XMLChannel(uri, contentType, noFake) {
+ try {
+ var channel = services.io.newChannelFromURI(uri);
+ var channelStream = channel.open();
+ }
+ catch (e) {
+ this.channel = noFake ? null : FakeChannel(uri);
+ return;
+ }
+
+ this.uri = uri;
+ this.sourceChannel = services.io.newChannelFromURI(uri);
+ this.pipe = services.Pipe(true, true, 0, 0, null);
+ this.writes = [];
+
+ this.channel = services.StreamChannel(uri);
+ this.channel.contentStream = this.pipe.inputStream;
+ this.channel.contentType = contentType || channel.contentType;
+ this.channel.contentCharset = "UTF-8";
+ this.channel.owner = systemPrincipal;
+
+ let stream = services.InputStream(channelStream);
+ let [, pre, doctype, url, open, post] = util.regexp(<![CDATA[
+ ^ ([^]*?)
+ (?:
+ (<!DOCTYPE \s+ \S+ \s+) SYSTEM \s+ "([^"]*)"
+ (\s+ \[)?
+ ([^]*)
+ )?
+ $
+ ]]>, "x").exec(stream.read(4096));
+ this.writes.push(pre);
+ if (doctype) {
+ this.writes.push(doctype + "[\n");
+ try {
+ this.writes.push(services.io.newChannel(url, null, null).open());
+ }
+ catch (e) {}
+ if (!open)
+ this.writes.push("\n]");
+ this.writes.push(post);
+ }
+ this.writes.push(channelStream);
+
+ this.writeNext();
+}
+XMLChannel.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver]),
+ writeNext: function () {
+ try {
+ if (!this.writes.length)
+ this.pipe.outputStream.close();
+ else {
+ let stream = this.writes.shift();
+ if (isString(stream))
+ stream = services.StringStream(stream);
+
+ services.StreamCopier(stream, this.pipe.outputStream, null,
+ false, true, 4096, true, false)
+ .asyncCopy(this, null);
+ }
+ }
+ catch (e) {
+ util.reportError(e);
+ }
+ },
+
+ onStartRequest: function (request, context) {},
+ onStopRequest: function (request, context, statusCode) {
+ this.writeNext();
+ }
+};
+
+endModule();
+
+// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/common/modules/sanitizer.jsm b/common/modules/sanitizer.jsm
index 886121d1..0d602110 100644
--- a/common/modules/sanitizer.jsm
+++ b/common/modules/sanitizer.jsm
@@ -656,7 +656,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
options.add(["cookies", "ck"],
"The default mode for newly added cookie permissions",
"stringlist", "session",
- { get values() iter(Sanitizer.COMMANDS) });
+ { get values() Sanitizer.COMMANDS });
options.add(["cookieaccept", "ca"],
"When to accept cookies",
diff --git a/common/modules/services.jsm b/common/modules/services.jsm
index 707619f2..d699d699 100644
--- a/common/modules/services.jsm
+++ b/common/modules/services.jsm
@@ -75,6 +75,7 @@ var Services = Module("Services", {
this.addClass("Find", "@mozilla.org/embedcomp/rangefind;1", "nsIFind");
this.addClass("HtmlConverter","@mozilla.org/widget/htmlformatconverter;1", "nsIFormatConverter");
this.addClass("HtmlEncoder", "@mozilla.org/layout/htmlCopyEncoder;1", "nsIDocumentEncoder");
+ this.addClass("InterfacePointer", "@mozilla.org/supports-interface-pointer;1", "nsISupportsInterfacePointer", "data");
this.addClass("InputStream", "@mozilla.org/scriptableinputstream;1", "nsIScriptableInputStream", "init");
this.addClass("Persist", "@mozilla.org/embedding/browser/nsWebBrowserPersist;1", "nsIWebBrowserPersist");
this.addClass("Pipe", "@mozilla.org/pipe;1", "nsIPipe", "init");
diff --git a/common/modules/template.jsm b/common/modules/template.jsm
index 17ccb9df..9fb99f3e 100644
--- a/common/modules/template.jsm
+++ b/common/modules/template.jsm
@@ -8,7 +8,7 @@ Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("template", {
exports: ["Binding", "Template", "template"],
require: ["util"],
- use: ["messages", "services"]
+ use: ["help", "messages", "services"]
}, this);
default xml namespace = XHTML;
@@ -204,7 +204,7 @@ var Template = Module("Template", {
},
helpLink: function (token, text, type) {
- if (!services["dactyl:"].initialized)
+ if (!help.initialized)
util.dactyl.initHelp();
let topic = token; // FIXME: Evil duplication!
@@ -213,7 +213,7 @@ var Template = Module("Template", {
else if (/^n_/.test(topic))
topic = topic.slice(2);
- if (services["dactyl:"].initialized && !Set.has(services["dactyl:"].HELP_TAGS, topic))
+ if (help.initialized && !Set.has(help.tags, topic))
return <span highlight={type || ""}>{text || token}</span>;
XML.ignoreWhitespace = false; XML.prettyPrinting = false;
@@ -224,7 +224,7 @@ var Template = Module("Template", {
return <a highlight={"InlineHelpLink " + type} tag={topic} href={"dactyl://help-tag/" + topic} dactyl:command="dactyl.help" xmlns:dactyl={NS}>{text || topic}</a>;
},
HelpLink: function (token) {
- if (!services["dactyl:"].initialized)
+ if (!help.initialized)
util.dactyl.initHelp();
let topic = token; // FIXME: Evil duplication!
@@ -233,7 +233,7 @@ var Template = Module("Template", {
else if (/^n_/.test(topic))
topic = topic.slice(2);
- if (services["dactyl:"].initialized && !Set.has(services["dactyl:"].HELP_TAGS, topic))
+ if (help.initialized && !Set.has(help.tags, topic))
return <>{token}</>;
XML.ignoreWhitespace = false; XML.prettyPrinting = false;