mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-20 01:57:58 +01:00
Because I can.
This commit is contained in:
@@ -15,6 +15,8 @@ syntax: glob
|
|||||||
downloads/*
|
downloads/*
|
||||||
.git/*
|
.git/*
|
||||||
|
|
||||||
|
common/tests/functional/log
|
||||||
|
|
||||||
*.py[co]
|
*.py[co]
|
||||||
|
|
||||||
## Editor backup and swap files
|
## Editor backup and swap files
|
||||||
|
|||||||
@@ -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}
|
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
|
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}
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,35 +11,54 @@ function reportError(e) {
|
|||||||
|
|
||||||
var global = this;
|
var global = this;
|
||||||
var NAME = "command-line-handler";
|
var NAME = "command-line-handler";
|
||||||
var Cc = Components.classes;
|
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||||
var Ci = Components.interfaces;
|
|
||||||
var Cu = Components.utils;
|
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
Cu.import("resource://dactyl/bootstrap.jsm");
|
||||||
|
if (!JSMLoader.initialized)
|
||||||
|
JSMLoader.init();
|
||||||
|
Cu.import("resource://dactyl/base.jsm");
|
||||||
|
require(global, "config");
|
||||||
|
require(global, "util");
|
||||||
|
}
|
||||||
|
|
||||||
function CommandLineHandler() {
|
function CommandLineHandler() {
|
||||||
this.wrappedJSObject = this;
|
this.wrappedJSObject = this;
|
||||||
|
|
||||||
Cu.import("resource://dactyl/base.jsm");
|
|
||||||
require(global, "util");
|
|
||||||
require(global, "config");
|
|
||||||
}
|
}
|
||||||
CommandLineHandler.prototype = {
|
CommandLineHandler.prototype = {
|
||||||
|
|
||||||
classDescription: "Dactyl Command-line Handler",
|
classDescription: "Dactyl command line Handler",
|
||||||
|
|
||||||
classID: Components.ID("{16dc34f7-6d22-4aa4-a67f-2921fb5dcb69}"),
|
classID: Components.ID("{16dc34f7-6d22-4aa4-a67f-2921fb5dcb69}"),
|
||||||
|
|
||||||
contractID: "@mozilla.org/commandlinehandler/general-startup;1?type=dactyl",
|
contractID: "@mozilla.org/commandlinehandler/general-startup;1?type=dactyl",
|
||||||
|
|
||||||
_xpcom_categories: [{
|
_xpcom_categories: [
|
||||||
category: "command-line-handler",
|
{
|
||||||
entry: "m-dactyl"
|
category: "command-line-handler",
|
||||||
}],
|
entry: "m-dactyl"
|
||||||
|
},
|
||||||
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsICommandLineHandler]),
|
// 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([Ci.nsIObserver, Ci.nsICommandLineHandler]),
|
||||||
|
|
||||||
handle: function (commandLine) {
|
handle: function (commandLine) {
|
||||||
|
init();
|
||||||
try {
|
try {
|
||||||
var remote = commandLine.handleFlagWithParam(config.name + "-remote", false);
|
var remote = commandLine.handleFlagWithParam(config.name + "-remote", false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
|
||||||
@@ -29,10 +29,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
this._observers = {};
|
this._observers = {};
|
||||||
util.addObserver(this);
|
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) {
|
this.commands["dactyl.restart"] = function (event) {
|
||||||
dactyl.restart();
|
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()))
|
let results = array((params.iterateIndex || params.iterate).call(params, commands.get(name).newArgs()))
|
||||||
.array.sort(function (a, b) String.localeCompare(a.name, b.name));
|
.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)) {
|
for (let obj in values(results)) {
|
||||||
let res = dactyl.generateHelp(obj, null, null, true);
|
let res = dactyl.generateHelp(obj, null, null, true);
|
||||||
if (!Set.has(tags, obj.helpTag))
|
if (!haveTag(obj.helpTag))
|
||||||
res[1].@tag = obj.helpTag;
|
res[1].@tag = obj.helpTag;
|
||||||
|
|
||||||
yield res;
|
yield res;
|
||||||
@@ -630,33 +626,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
*/
|
*/
|
||||||
has: function (feature) Set.has(config.features, feature),
|
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
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -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
|
* @private
|
||||||
* Initialize the help system.
|
* Initialize the help system.
|
||||||
*/
|
*/
|
||||||
initHelp: function (force) {
|
initHelp: function initHelp(force) {
|
||||||
// Waits for the add-on to become available, if necessary.
|
if ("noscriptOverlay" in window)
|
||||||
config.addon;
|
noscriptOverlay.safeAllow("dactyl:", true, false);
|
||||||
config.version;
|
|
||||||
|
|
||||||
if (force || !this.helpInitialized) {
|
if (!force && help.initialized)
|
||||||
if ("noscriptOverlay" in window) {
|
return;
|
||||||
noscriptOverlay.safeAllow("chrome-data:", true, false);
|
|
||||||
noscriptOverlay.safeAllow("dactyl:", true, false);
|
help.initialize(force);
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
util.reportError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find help and overlay files with the given name.
|
help.files["plugins"] = function () ['text/xml;charset=UTF-8',
|
||||||
let findHelpFile = function findHelpFile(file) {
|
'<?xml version="1.0"?>\n' +
|
||||||
let result = [];
|
'<?xml-stylesheet type="text/xsl" href="dactyl://content/help.xsl"?>\n' +
|
||||||
for (let [, namespace] in Iterator(namespaces)) {
|
'<!DOCTYPE document SYSTEM "resource://dactyl-content/dactyl.dtd">\n' +
|
||||||
let url = ["dactyl://", namespace, "/", file, ".xml"].join("");
|
<document xmlns={NS}
|
||||||
let res = util.httpGet(url);
|
name="plugins" title={config.appName + " Plugins"}>
|
||||||
if (res) {
|
<h1 tag="using-plugins">{_("help.title.Using Plugins")}</h1>
|
||||||
if (res.responseXML.documentElement.localName == "document")
|
<toc start="2"/>
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
let namespaces = ["locale-local", "locale"];
|
{body}
|
||||||
services["dactyl:"].init({});
|
</document>.toXMLString()];
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
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) {
|
stringifyXML: function (xml) {
|
||||||
@@ -995,7 +810,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
|
|
||||||
let chromeFiles = {};
|
let chromeFiles = {};
|
||||||
let styles = {};
|
let styles = {};
|
||||||
for (let [file, ] in Iterator(services["dactyl:"].FILE_MAP)) {
|
for (let [file, ] in Iterator(help.files)) {
|
||||||
let url = "dactyl://help/" + file;
|
let url = "dactyl://help/" + file;
|
||||||
dactyl.open(url);
|
dactyl.open(url);
|
||||||
util.waitFor(function () content.location.href == url && buffer.loaded
|
util.waitFor(function () content.location.href == url && buffer.loaded
|
||||||
@@ -1018,7 +833,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
.join("\n");
|
.join("\n");
|
||||||
addDataEntry("help.css", data.replace(/chrome:[^ ")]+\//g, ""));
|
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;
|
let m, re = /(chrome:[^ ");]+\/)([^ ");]+)/g;
|
||||||
while ((m = re.exec(data)))
|
while ((m = re.exec(data)))
|
||||||
@@ -1047,12 +862,12 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
let args = null;
|
let args = null;
|
||||||
|
|
||||||
if (obj instanceof Command) {
|
if (obj instanceof Command) {
|
||||||
link = function (cmd) <ex>:{cmd}</ex>;
|
link = function (cmd) <ex>{cmd}</ex>;
|
||||||
args = obj.parseArgs("", CompletionContext(str || ""));
|
args = obj.parseArgs("", CompletionContext(str || ""));
|
||||||
tag = function (cmd) <>:{cmd}</>;
|
tag = function (cmd) <>:{cmd}</>;
|
||||||
spec = function (cmd) <>{
|
spec = function (cmd) <>{
|
||||||
obj.count ? <oa>count</oa> : <></>
|
obj.count ? <oa>count</oa> : <></>
|
||||||
}:{
|
}{
|
||||||
cmd
|
cmd
|
||||||
}{
|
}{
|
||||||
obj.bang ? <oa>!</oa> : <></>
|
obj.bang ? <oa>!</oa> : <></>
|
||||||
@@ -1085,7 +900,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
</>;
|
</>;
|
||||||
|
|
||||||
let res = <res>
|
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)
|
template.linkifyHelp(obj.description ? obj.description.replace(/\.$/, "") : "", true)
|
||||||
}</dd></res>;
|
}</dd></res>;
|
||||||
if (specOnly)
|
if (specOnly)
|
||||||
@@ -1095,9 +910,11 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
<item>
|
<item>
|
||||||
<tags>{template.map(obj.names.slice().reverse(), tag, " ")}</tags>
|
<tags>{template.map(obj.names.slice().reverse(), tag, " ")}</tags>
|
||||||
<spec>{
|
<spec>{
|
||||||
spec(template.highlightRegexp((obj.specs || obj.names)[0],
|
let (name = (obj.specs || obj.names)[0])
|
||||||
/\[(.*?)\]/g,
|
spec(template.highlightRegexp(tag(name),
|
||||||
function (m, n0) <oa>{n0}</oa>))
|
/\[(.*?)\]/g,
|
||||||
|
function (m, n0) <oa>{n0}</oa>),
|
||||||
|
name)
|
||||||
}</spec>{
|
}</spec>{
|
||||||
!obj.type ? "" : <>
|
!obj.type ? "" : <>
|
||||||
<type>{obj.type}</type>
|
<type>{obj.type}</type>
|
||||||
@@ -1138,30 +955,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
.replace(/^\s*\n|\n\s*$/g, "") + "\n";
|
.replace(/^\s*\n|\n\s*$/g, "") + "\n";
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
* The map of global variables.
|
||||||
*
|
*
|
||||||
@@ -1764,14 +1557,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
},
|
},
|
||||||
|
|
||||||
mappings: function () {
|
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"))
|
if (dactyl.has("session"))
|
||||||
mappings.add([modes.NORMAL], ["ZQ"],
|
mappings.add([modes.NORMAL], ["ZQ"],
|
||||||
"Quit and don't save the session",
|
"Quit and don't save the session",
|
||||||
@@ -1842,30 +1627,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
literal: 0
|
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"],
|
commands.add(["loadplugins", "lpl"],
|
||||||
"Load all or matching plugins",
|
"Load all or matching plugins",
|
||||||
function (args) {
|
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))];
|
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) {
|
completion.menuItem = function menuItem(context) {
|
||||||
context.title = ["Menu Path", "Label"];
|
context.title = ["Menu Path", "Label"];
|
||||||
context.anchored = false;
|
context.anchored = false;
|
||||||
@@ -2186,7 +1938,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
localPrefs.set("first-run", false);
|
localPrefs.set("first-run", false);
|
||||||
this.withSavedValues(["forceTarget"], function () {
|
this.withSavedValues(["forceTarget"], function () {
|
||||||
this.forceTarget = dactyl.NEW_TAB;
|
this.forceTarget = dactyl.NEW_TAB;
|
||||||
this.help();
|
help.help();
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
|
|||||||
@@ -296,14 +296,18 @@
|
|||||||
<xsl:template name="linkify-tag">
|
<xsl:template name="linkify-tag">
|
||||||
<xsl:param name="contents" select="text()"/>
|
<xsl:param name="contents" select="text()"/>
|
||||||
<xsl:variable name="tag" select="$contents"/>
|
<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;">
|
<a style="color: inherit;">
|
||||||
<xsl:if test="not(@link) or @link != 'false'">
|
<xsl:if test="not(@link) or @link != 'false'">
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
<xsl:when test="contains(ancestor::*/@document-tags, concat(' ', $tag, ' '))">
|
<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:when>
|
||||||
<xsl:otherwise>
|
<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:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ var Map = Class("Map", {
|
|||||||
|
|
||||||
if (this.executing) {
|
if (this.executing) {
|
||||||
util.dumpStack(_("map.recursive", args.command));
|
util.dumpStack(_("map.recursive", args.command));
|
||||||
throw AssertionError(_("map.recursive", args.command));
|
throw FailedAssertion(_("map.recursive", args.command));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -771,10 +771,10 @@ var Mappings = Module("mappings", {
|
|||||||
name: [mode.char + "listk[eys]", mode.char + "lk"],
|
name: [mode.char + "listk[eys]", mode.char + "lk"],
|
||||||
iterateIndex: function (args)
|
iterateIndex: function (args)
|
||||||
let (self = this, prefix = /^[bCmn]$/.test(mode.char) ? "" : mode.char + "_",
|
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 }
|
({ helpTag: prefix + map.name, __proto__: map }
|
||||||
for (map in self.iterate(args, true))
|
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",
|
description: "List all " + mode.displayName + " mode mappings along with their short descriptions",
|
||||||
index: mode.char + "-map",
|
index: mode.char + "-map",
|
||||||
getMode: function (args) mode,
|
getMode: function (args) mode,
|
||||||
|
|||||||
@@ -140,7 +140,7 @@
|
|||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags><scroll-percent> N%</tags>
|
<tags><scroll-percent> N% %</tags>
|
||||||
<spec><a>count</a>%</spec>
|
<spec><a>count</a>%</spec>
|
||||||
<description short="true">
|
<description short="true">
|
||||||
<p>Scroll to <a>count</a> percent of the document.</p>
|
<p>Scroll to <a>count</a> percent of the document.</p>
|
||||||
|
|||||||
@@ -133,7 +133,8 @@ function defineModule(name, params, module) {
|
|||||||
|
|
||||||
module.NAME = name;
|
module.NAME = name;
|
||||||
module.EXPORTED_SYMBOLS = params.exports || [];
|
module.EXPORTED_SYMBOLS = params.exports || [];
|
||||||
defineModule.loadLog.push("defineModule " + name);
|
defineModule.loadLog.push("[Begin " + name + "]");
|
||||||
|
defineModule.prefix += " ";
|
||||||
for (let [, mod] in Iterator(params.require || []))
|
for (let [, mod] in Iterator(params.require || []))
|
||||||
require(module, mod);
|
require(module, mod);
|
||||||
|
|
||||||
@@ -152,11 +153,13 @@ function defineModule(name, params, module) {
|
|||||||
defineModule.loadLog = [];
|
defineModule.loadLog = [];
|
||||||
Object.defineProperty(defineModule.loadLog, "push", {
|
Object.defineProperty(defineModule.loadLog, "push", {
|
||||||
value: function (val) {
|
value: function (val) {
|
||||||
|
val = defineModule.prefix + val;
|
||||||
if (true)
|
if (true)
|
||||||
defineModule.dump(val + "\n");
|
defineModule.dump(val + "\n");
|
||||||
this[this.length] = Date.now() + " " + val;
|
this[this.length] = Date.now() + " " + val;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
defineModule.prefix = "";
|
||||||
defineModule.dump = function dump_() {
|
defineModule.dump = function dump_() {
|
||||||
let msg = Array.map(arguments, function (msg) {
|
let msg = Array.map(arguments, function (msg) {
|
||||||
if (loaded.util && typeof msg == "object")
|
if (loaded.util && typeof msg == "object")
|
||||||
@@ -185,7 +188,8 @@ defineModule.time = function time(major, minor, func, self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function endModule() {
|
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] || []))
|
for (let [, mod] in Iterator(use[currentModule.NAME] || []))
|
||||||
require(mod, currentModule.NAME, "use");
|
require(mod, currentModule.NAME, "use");
|
||||||
@@ -202,7 +206,7 @@ function require(obj, name, from) {
|
|||||||
let caller = Components.stack.caller;
|
let caller = Components.stack.caller;
|
||||||
|
|
||||||
if (!loaded[name])
|
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);
|
JSMLoader.load(name + ".jsm", obj);
|
||||||
return obj;
|
return obj;
|
||||||
@@ -220,11 +224,12 @@ defineModule("base", {
|
|||||||
// sed -n 's/^(const|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt
|
// sed -n 's/^(const|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt
|
||||||
exports: [
|
exports: [
|
||||||
"ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object", "Runnable",
|
"ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object", "Runnable",
|
||||||
"Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMUtils", "XPCSafeJSObjectWrapper",
|
"Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMShim", "XPCOMUtils",
|
||||||
"array", "bind", "call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule",
|
"XPCSafeJSObjectWrapper", "array", "bind", "call", "callable", "ctypes", "curry",
|
||||||
"deprecated", "endModule", "forEach", "isArray", "isGenerator", "isinstance", "isObject",
|
"debuggerProperties", "defineModule", "deprecated", "endModule", "forEach", "isArray",
|
||||||
"isString", "isSubclass", "iter", "iterAll", "iterOwnProperties", "keys", "memoize", "octal",
|
"isGenerator", "isinstance", "isObject", "isString", "isSubclass", "iter", "iterAll",
|
||||||
"properties", "require", "set", "update", "values", "withCallerGlobal"
|
"iterOwnProperties", "keys", "memoize", "octal", "properties", "require", "set", "update",
|
||||||
|
"values", "withCallerGlobal"
|
||||||
],
|
],
|
||||||
use: ["config", "services", "util"]
|
use: ["config", "services", "util"]
|
||||||
}, this);
|
}, this);
|
||||||
@@ -754,6 +759,10 @@ function Class() {
|
|||||||
constructor: { value: Constructor },
|
constructor: { value: Constructor },
|
||||||
});
|
});
|
||||||
self.instance = self;
|
self.instance = self;
|
||||||
|
|
||||||
|
if ("_metaInit_" in self && self._metaInit_)
|
||||||
|
self._metaInit_.apply(self, arguments);
|
||||||
|
|
||||||
var res = self.init.apply(self, arguments);
|
var res = self.init.apply(self, arguments);
|
||||||
return res !== undefined ? res : self;
|
return res !== undefined ? res : self;
|
||||||
})]]>,
|
})]]>,
|
||||||
@@ -1022,7 +1031,7 @@ function XPCOM(interfaces, superClass) {
|
|||||||
interfaces = Array.concat(interfaces);
|
interfaces = Array.concat(interfaces);
|
||||||
|
|
||||||
let shim = interfaces.reduce(function (shim, iface) shim.QueryInterface(iface),
|
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(
|
let res = Class("XPCOM(" + interfaces + ")", superClass || Class, update(
|
||||||
iter.toObject([k, v === undefined || callable(v) ? function stub() null : v]
|
iter.toObject([k, v === undefined || callable(v) ? function stub() null : v]
|
||||||
@@ -1031,6 +1040,18 @@ function XPCOM(interfaces, superClass) {
|
|||||||
shim = interfaces = null;
|
shim = interfaces = null;
|
||||||
return res;
|
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.
|
* An abstract base class for classes that wish to inherit from Error.
|
||||||
@@ -1065,24 +1086,32 @@ var ErrorBase = Class("ErrorBase", Error, {
|
|||||||
* @returns {Class}
|
* @returns {Class}
|
||||||
*/
|
*/
|
||||||
function Module(name, prototype) {
|
function Module(name, prototype) {
|
||||||
let init = callable(prototype) ? 4 : 3;
|
try {
|
||||||
let proto = arguments[callable(prototype) ? 2 : 1];
|
let init = callable(prototype) ? 4 : 3;
|
||||||
|
let proto = arguments[callable(prototype) ? 2 : 1];
|
||||||
|
|
||||||
proto._metaInit_ = function () {
|
proto._metaInit_ = function () {
|
||||||
delete module.prototype._metaInit_;
|
delete module.prototype._metaInit_;
|
||||||
currentModule[name.toLowerCase()] = this;
|
currentModule[name.toLowerCase()] = this;
|
||||||
};
|
};
|
||||||
|
|
||||||
const module = Class.apply(Class, Array.slice(arguments, 0, init));
|
const module = Class.apply(Class, Array.slice(arguments, 0, init));
|
||||||
let instance = module();
|
let instance = module();
|
||||||
module.className = name.toLowerCase();
|
module.className = name.toLowerCase();
|
||||||
|
|
||||||
instance.INIT = update(Object.create(Module.INIT),
|
instance.INIT = update(Object.create(Module.INIT),
|
||||||
arguments[init] || {});
|
arguments[init] || {});
|
||||||
|
|
||||||
currentModule[module.className] = instance;
|
currentModule[module.className] = instance;
|
||||||
defineModule.modules.push(instance);
|
defineModule.modules.push(instance);
|
||||||
return module;
|
return module;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (typeof e === "string")
|
||||||
|
e = Error(e);
|
||||||
|
|
||||||
|
dump(e.fileName + ":" + e.lineNumber + ": " + e + "\n" + (e.stack || Error().stack));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Module.INIT = {
|
Module.INIT = {
|
||||||
init: function Module_INIT_init(dactyl, modules, window) {
|
init: function Module_INIT_init(dactyl, modules, window) {
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ if (!JSMLoader && "@mozilla.org/fuel/application;1" in Components.classes)
|
|||||||
.getService(Components.interfaces.extIApplication)
|
.getService(Components.interfaces.extIApplication)
|
||||||
.storage.get("dactyl.JSMLoader", null);
|
.storage.get("dactyl.JSMLoader", null);
|
||||||
|
|
||||||
if (JSMLoader && JSMLoader.bump === 5)
|
if (JSMLoader && JSMLoader.bump === 6)
|
||||||
JSMLoader.global = this;
|
JSMLoader.global = this;
|
||||||
else
|
else
|
||||||
JSMLoader = {
|
JSMLoader = {
|
||||||
bump: 5,
|
bump: 6,
|
||||||
|
|
||||||
builtin: Cu.Sandbox(this),
|
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) {
|
registerFactory: function registerFactory(factory) {
|
||||||
this.manager.registerFactory(factory.classID,
|
this.manager.registerFactory(factory.classID,
|
||||||
String(factory.classID),
|
String(factory.classID),
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Components.utils.import("resource://dactyl/bootstrap.jsm");
|
|||||||
defineModule("commands", {
|
defineModule("commands", {
|
||||||
exports: ["ArgType", "Command", "Commands", "CommandOption", "Ex", "commands"],
|
exports: ["ArgType", "Command", "Commands", "CommandOption", "Ex", "commands"],
|
||||||
require: ["contexts", "messages", "util"],
|
require: ["contexts", "messages", "util"],
|
||||||
use: ["config", "options", "services", "template"]
|
use: ["config", "help", "options", "services", "template"]
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1585,7 +1585,7 @@ var Commands = Module("commands", {
|
|||||||
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}</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)),
|
this.iterate(args).filter(function (cmd) cmd.hive === commands.builtin || Set.has(tags, cmd.helpTag)),
|
||||||
format: {
|
format: {
|
||||||
headings: ["Command", "Group", "Description"],
|
headings: ["Command", "Group", "Description"],
|
||||||
|
|||||||
@@ -6,16 +6,34 @@
|
|||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
let global = this;
|
let global = this;
|
||||||
Components.utils.import("resource://dactyl/bootstrap.jsm");
|
Components.utils.import("resource://dactyl/bootstrap.jsm");
|
||||||
defineModule("config", {
|
defineModule("config", {
|
||||||
exports: ["ConfigBase", "Config", "config"],
|
exports: ["ConfigBase", "Config", "config"],
|
||||||
require: ["services", "storage", "util", "template"],
|
require: ["protocol", "services", "storage", "util", "template"],
|
||||||
use: ["io", "messages", "prefs", "styles"]
|
use: ["io", "messages", "prefs", "styles"]
|
||||||
}, this);
|
}, 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", {
|
var ConfigBase = Class("ConfigBase", {
|
||||||
/**
|
/**
|
||||||
* Called on dactyl startup to allow for any arbitrary application-specific
|
* Called on dactyl startup to allow for any arbitrary application-specific
|
||||||
@@ -26,9 +44,19 @@ var ConfigBase = Class("ConfigBase", {
|
|||||||
if (this.haveGecko("2b"))
|
if (this.haveGecko("2b"))
|
||||||
Set.add(this.features, "Gecko2");
|
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 () {
|
this.timeout(function () {
|
||||||
services["dactyl:"].pages.dtd = function () [null, util.makeDTD(config.dtd)];
|
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: {
|
modules: {
|
||||||
@@ -41,12 +69,14 @@ var ConfigBase = Class("ConfigBase", {
|
|||||||
"contexts",
|
"contexts",
|
||||||
"downloads",
|
"downloads",
|
||||||
"finder",
|
"finder",
|
||||||
|
"help",
|
||||||
"highlight",
|
"highlight",
|
||||||
"javascript",
|
"javascript",
|
||||||
"messages",
|
"messages",
|
||||||
"options",
|
"options",
|
||||||
"overlay",
|
"overlay",
|
||||||
"prefs",
|
"prefs",
|
||||||
|
"protocol",
|
||||||
"sanitizer",
|
"sanitizer",
|
||||||
"services",
|
"services",
|
||||||
"storage",
|
"storage",
|
||||||
@@ -1065,6 +1095,6 @@ config.INIT = update(Object.create(config.INIT), config.INIT, {
|
|||||||
|
|
||||||
endModule();
|
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:
|
// vim: set fdm=marker sw=4 sts=4 et ft=javascript:
|
||||||
|
|||||||
326
common/modules/help.jsm
Normal file
326
common/modules/help.jsm
Normal file
@@ -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:
|
||||||
@@ -13,7 +13,7 @@ Components.utils.import("resource://dactyl/bootstrap.jsm");
|
|||||||
defineModule("io", {
|
defineModule("io", {
|
||||||
exports: ["IO", "io"],
|
exports: ["IO", "io"],
|
||||||
require: ["services"],
|
require: ["services"],
|
||||||
use: ["config", "messages", "storage", "styles", "template", "util"]
|
use: ["config", "help", "messages", "storage", "styles", "template", "util"]
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
// TODO: why are we passing around strings rather than file objects?
|
// TODO: why are we passing around strings rather than file objects?
|
||||||
@@ -174,7 +174,7 @@ var IO = Module("io", {
|
|||||||
util.flushCache();
|
util.flushCache();
|
||||||
|
|
||||||
dactyl.loadScript(uri.spec, context);
|
dactyl.loadScript(uri.spec, context);
|
||||||
dactyl.helpInitialized = false;
|
help.initialized = false;
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (e.fileName)
|
if (e.fileName)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ try {
|
|||||||
Components.utils.import("resource://dactyl/bootstrap.jsm");
|
Components.utils.import("resource://dactyl/bootstrap.jsm");
|
||||||
defineModule("overlay", {
|
defineModule("overlay", {
|
||||||
exports: ["ModuleBase", "overlay"],
|
exports: ["ModuleBase", "overlay"],
|
||||||
require: ["config", "highlight", "io", "services", "util"]
|
require: ["config", "help", "highlight", "io", "services", "util"]
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,8 +41,6 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen
|
|||||||
util.addObserver(this);
|
util.addObserver(this);
|
||||||
this.overlays = {};
|
this.overlays = {};
|
||||||
|
|
||||||
services["dactyl:"]; // Hack. Force module initialization.
|
|
||||||
|
|
||||||
config.loadStyles();
|
config.loadStyles();
|
||||||
|
|
||||||
this.timeout(this.initialize);
|
this.timeout(this.initialize);
|
||||||
|
|||||||
228
common/modules/protocol.jsm
Normal file
228
common/modules/protocol.jsm
Normal file
@@ -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:
|
||||||
@@ -656,7 +656,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef
|
|||||||
options.add(["cookies", "ck"],
|
options.add(["cookies", "ck"],
|
||||||
"The default mode for newly added cookie permissions",
|
"The default mode for newly added cookie permissions",
|
||||||
"stringlist", "session",
|
"stringlist", "session",
|
||||||
{ get values() iter(Sanitizer.COMMANDS) });
|
{ get values() Sanitizer.COMMANDS });
|
||||||
|
|
||||||
options.add(["cookieaccept", "ca"],
|
options.add(["cookieaccept", "ca"],
|
||||||
"When to accept cookies",
|
"When to accept cookies",
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ var Services = Module("Services", {
|
|||||||
this.addClass("Find", "@mozilla.org/embedcomp/rangefind;1", "nsIFind");
|
this.addClass("Find", "@mozilla.org/embedcomp/rangefind;1", "nsIFind");
|
||||||
this.addClass("HtmlConverter","@mozilla.org/widget/htmlformatconverter;1", "nsIFormatConverter");
|
this.addClass("HtmlConverter","@mozilla.org/widget/htmlformatconverter;1", "nsIFormatConverter");
|
||||||
this.addClass("HtmlEncoder", "@mozilla.org/layout/htmlCopyEncoder;1", "nsIDocumentEncoder");
|
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("InputStream", "@mozilla.org/scriptableinputstream;1", "nsIScriptableInputStream", "init");
|
||||||
this.addClass("Persist", "@mozilla.org/embedding/browser/nsWebBrowserPersist;1", "nsIWebBrowserPersist");
|
this.addClass("Persist", "@mozilla.org/embedding/browser/nsWebBrowserPersist;1", "nsIWebBrowserPersist");
|
||||||
this.addClass("Pipe", "@mozilla.org/pipe;1", "nsIPipe", "init");
|
this.addClass("Pipe", "@mozilla.org/pipe;1", "nsIPipe", "init");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Components.utils.import("resource://dactyl/bootstrap.jsm");
|
|||||||
defineModule("template", {
|
defineModule("template", {
|
||||||
exports: ["Binding", "Template", "template"],
|
exports: ["Binding", "Template", "template"],
|
||||||
require: ["util"],
|
require: ["util"],
|
||||||
use: ["messages", "services"]
|
use: ["help", "messages", "services"]
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
default xml namespace = XHTML;
|
default xml namespace = XHTML;
|
||||||
@@ -204,7 +204,7 @@ var Template = Module("Template", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
helpLink: function (token, text, type) {
|
helpLink: function (token, text, type) {
|
||||||
if (!services["dactyl:"].initialized)
|
if (!help.initialized)
|
||||||
util.dactyl.initHelp();
|
util.dactyl.initHelp();
|
||||||
|
|
||||||
let topic = token; // FIXME: Evil duplication!
|
let topic = token; // FIXME: Evil duplication!
|
||||||
@@ -213,7 +213,7 @@ var Template = Module("Template", {
|
|||||||
else if (/^n_/.test(topic))
|
else if (/^n_/.test(topic))
|
||||||
topic = topic.slice(2);
|
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>;
|
return <span highlight={type || ""}>{text || token}</span>;
|
||||||
|
|
||||||
XML.ignoreWhitespace = false; XML.prettyPrinting = false;
|
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>;
|
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) {
|
HelpLink: function (token) {
|
||||||
if (!services["dactyl:"].initialized)
|
if (!help.initialized)
|
||||||
util.dactyl.initHelp();
|
util.dactyl.initHelp();
|
||||||
|
|
||||||
let topic = token; // FIXME: Evil duplication!
|
let topic = token; // FIXME: Evil duplication!
|
||||||
@@ -233,7 +233,7 @@ var Template = Module("Template", {
|
|||||||
else if (/^n_/.test(topic))
|
else if (/^n_/.test(topic))
|
||||||
topic = topic.slice(2);
|
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}</>;
|
return <>{token}</>;
|
||||||
|
|
||||||
XML.ignoreWhitespace = false; XML.prettyPrinting = false;
|
XML.ignoreWhitespace = false; XML.prettyPrinting = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user