// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2012 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
"use strict";
-try {
-
let global = this;
-Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("config", {
exports: ["ConfigBase", "Config", "config"],
- require: ["services", "storage", "util", "template"],
- use: ["io", "prefs"]
-}, this);
+ require: ["dom", "io", "protocol", "services", "util", "template"]
+});
+
+lazyRequire("addons", ["AddonManager"]);
+lazyRequire("cache", ["cache"]);
+lazyRequire("highlight", ["highlight"]);
+lazyRequire("messages", ["_"]);
+lazyRequire("prefs", ["localPrefs", "prefs"]);
+lazyRequire("storage", ["storage", "File"]);
+lazyRequire("styles", ["Styles"]);
+
+function AboutHandler() {}
+AboutHandler.prototype = {
+ get classDescription() "About " + config.appName + " Page",
+
+ classID: Components.ID("81495d80-89ee-4c36-a88d-ea7c4e5ac63f"),
+
+ get contractID() services.ABOUT + 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
* initialization code. Must call superclass's init function.
*/
init: function init() {
- this.features.push = deprecated("set.add", function push(feature) set.add(this, feature));
- if (util.haveGecko("2b"))
- set.add(this.features, "Gecko2");
+ this.loadConfig();
+
+ this.features.push = deprecated("Set.add", function push(feature) Set.add(this, feature));
+ 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,
- iter(config.dtdExtra,
- (["dactyl." + k, v] for ([k, v] in iter(config.dtd))),
- (["dactyl." + s, config[s]] for each (s in config.dtdStrings)))
- .map(function ([k, v]) ["<!ENTITY ", k, " '", String.replace(v || "null", /'/g, "'"), "'>"].join(""))
- .join("\n")]
+ cache.register("config.dtd", function () util.makeDTD(config.dtd));
+ });
+
+ services["dactyl:"].pages["dtd"] = function () [null, cache.get("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)
});
},
- loadStyles: function loadStyles() {
- const { highlight } = require("highlight");
+ get prefs() localPrefs,
+
+ get has() Set.has(this.features),
+
+ configFiles: [
+ "resource://dactyl-common/config.json",
+ "resource://dactyl-local/config.json"
+ ],
+
+ configs: Class.Memoize(function () this.configFiles.map(function (url) JSON.parse(File.readURL(url)))),
+
+ loadConfig: function loadConfig(documentURL) {
+
+ for each (let config in this.configs) {
+ if (documentURL)
+ config = config.overlays && config.overlays[documentURL] || {};
+
+ for (let [name, value] in Iterator(config)) {
+ let prop = util.camelCase(name);
+
+ if (isArray(this[prop]))
+ this[prop] = [].concat(this[prop], value);
+ else if (isObject(this[prop])) {
+ if (isArray(value))
+ value = Set(value);
+
+ this[prop] = update({}, this[prop],
+ iter([util.camelCase(k), value[k]]
+ for (k in value)).toObject());
+ }
+ else
+ this[prop] = value;
+ }
+ }
+ },
+
+ modules: {
+ global: ["addons",
+ "base",
+ "io",
+ ["bookmarkcache", "bookmarkcache"],
+ "buffer",
+ "cache",
+ "commands",
+ "completion",
+ "config",
+ "contexts",
+ "dom",
+ "downloads",
+ "finder",
+ "help",
+ "highlight",
+ "javascript",
+ "main",
+ "messages",
+ "options",
+ "overlay",
+ "prefs",
+ "protocol",
+ "sanitizer",
+ "services",
+ "storage",
+ "styles",
+ "template",
+ "util"],
+
+ window: ["dactyl",
+ "modes",
+ "commandline",
+ "abbreviations",
+ "autocommands",
+ "editor",
+ "events",
+ "hints",
+ "key-processors",
+ "mappings",
+ "marks",
+ "mow",
+ "statusline"]
+ },
+
+ loadStyles: function loadStyles(force) {
highlight.styleableChrome = this.styleableChrome;
- highlight.loadCSS(this.CSS);
- highlight.loadCSS(this.helpCSS);
- if (!util.haveGecko("2b"))
- highlight.loadCSS(<![CDATA[
+
+ highlight.loadCSS(this.CSS.replace(/__MSG_(.*?)__/g, function (m0, m1) _(m1)));
+ highlight.loadCSS(this.helpCSS.replace(/__MSG_(.*?)__/g, function (m0, m1) _(m1)));
+
+ if (!this.haveGecko("2b"))
+ highlight.loadCSS(literal(/*
!TabNumber font-weight: bold; margin: 0px; padding-right: .8ex;
- !TabIconNumber {
+ !TabIconNumber {
font-weight: bold;
color: white;
text-align: center;
text-shadow: black -1px 0 1px, black 0 1px 1px, black 1px 0 1px, black 0 -1px 1px;
}
- ]]>);
+ */));
+
+ let hl = highlight.set("Find", "");
+ hl.onChange = function () {
+ function hex(val) ("#" + util.regexp.iterate(/\d+/g, val)
+ .map(function (num) ("0" + Number(num).toString(16)).slice(-2))
+ .join("")
+ ).slice(0, 7);
+
+ let elem = services.appShell.hiddenDOMWindow.document.createElement("div");
+ elem.style.cssText = this.cssText;
+
+ let keys = iter(Styles.propertyIter(this.cssText)).map(function (p) p.name).toArray();
+ let bg = keys.some(bind("test", /^background/));
+ let fg = keys.indexOf("color") >= 0;
+
+ let style = DOM(elem).style;
+ prefs[bg ? "safeSet" : "safeReset"]("ui.textHighlightBackground", hex(style.backgroundColor));
+ prefs[fg ? "safeSet" : "safeReset"]("ui.textHighlightForeground", hex(style.color));
+ };
},
get addonID() this.name + "@dactyl.googlecode.com",
- addon: Class.memoize(function () {
- let addon;
- do {
- addon = (JSMLoader.bootstrap || {}).addon;
- if (addon && !addon.getResourceURI) {
- util.reportError(Error(_("addon.unavailable")));
- yield 10;
- }
- }
- while (addon && !addon.getResourceURI);
- if (!addon)
- addon = require("addons").AddonManager.getAddonByID(this.addonID);
- yield addon;
- }, true),
+ addon: Class.Memoize(function () {
+ return (JSMLoader.bootstrap || {}).addon ||
+ AddonManager.getAddonByID(this.addonID);
+ }),
+
+ get styleableChrome() Object.keys(this.overlays),
/**
* The current application locale.
*/
- appLocale: Class.memoize(function () services.chromeRegistry.getSelectedLocale("global")),
+ appLocale: Class.Memoize(function () services.chromeRegistry.getSelectedLocale("global")),
/**
* The current dactyl locale.
*/
- locale: Class.memoize(function () this.bestLocale(this.locales)),
+ locale: Class.Memoize(function () this.bestLocale(this.locales)),
/**
* The current application locale.
*/
- locales: Class.memoize(function () {
+ locales: Class.Memoize(function () {
// TODO: Merge with completion.file code.
function getDir(str) str.match(/^(?:.*[\/\\])?/)[0];
let jar = io.isJarURL(uri);
if (jar) {
let prefix = getDir(jar.JAREntry);
- var res = iter(s.slice(prefix.length).replace(/\/.*/, "") for (s in io.listJar(jar.JARFile, prefix)))
+ var res = iter(s.slice(prefix.length).replace(/\/.*/, "")
+ for (s in io.listJar(jar.JARFile, prefix)))
.toArray();
}
else {
if (f.isDirectory())).array;
}
- function exists(pkg) {
- try {
- services["resource:"].getSubstitution(pkg);
- return true;
- }
- catch (e) {
- return false;
- }
- }
+ let exists = function exists(pkg) services["resource:"].hasSubstitution("dactyl-locale-" + pkg);
return array.uniq([this.appLocale, this.appLocale.replace(/-.*/, "")]
- .filter(function (locale) exists("dactyl-locale-" + locale))
+ .filter(exists)
.concat(res));
}),
* @returns {string}
*/
bestLocale: function (list) {
- let langs = set(list);
return values([this.appLocale, this.appLocale.replace(/-.*/, ""),
- "en", "en-US", iter(langs).next()])
- .nth(function (l) set.has(langs, l), 0);
+ "en", "en-US", list[0]])
+ .nth(Set.has(Set(list)), 0);
+ },
+
+ /**
+ * A list of all known registered chrome and resource packages.
+ */
+ get chromePackages() {
+ // Horrible hack.
+ let res = {};
+ function process(manifest) {
+ for each (let line in manifest.split(/\n+/)) {
+ let match = /^\s*(content|skin|locale|resource)\s+([^\s#]+)\s/.exec(line);
+ if (match)
+ res[match[2]] = true;
+ }
+ }
+ function processJar(file) {
+ let jar = services.ZipReader(file.file);
+ if (jar)
+ try {
+ if (jar.hasEntry("chrome.manifest"))
+ process(File.readStream(jar.getInputStream("chrome.manifest")));
+ }
+ finally {
+ jar.close();
+ }
+ }
+
+ for each (let dir in ["UChrm", "AChrom"]) {
+ dir = File(services.directory.get(dir, Ci.nsIFile));
+ if (dir.exists() && dir.isDirectory())
+ for (let file in dir.iterDirectory())
+ if (/\.manifest$/.test(file.leafName))
+ process(file.read());
+
+ dir = File(dir.parent);
+ if (dir.exists() && dir.isDirectory())
+ for (let file in dir.iterDirectory())
+ if (/\.jar$/.test(file.leafName))
+ processJar(file);
+
+ dir = dir.child("extensions");
+ if (dir.exists() && dir.isDirectory())
+ for (let ext in dir.iterDirectory()) {
+ if (/\.xpi$/.test(ext.leafName))
+ processJar(ext);
+ else {
+ if (ext.isFile())
+ ext = File(ext.read().replace(/\n*$/, ""));
+ let mf = ext.child("chrome.manifest");
+ if (mf.exists())
+ process(mf.read());
+ }
+ }
+ }
+ return Object.keys(res).sort();
},
- haveHg: Class.memoize(function () {
+ /**
+ * Returns true if the current Gecko runtime is of the given version
+ * or greater.
+ *
+ * @param {string} min The minimum required version. @optional
+ * @param {string} max The maximum required version. @optional
+ * @returns {boolean}
+ */
+ haveGecko: function (min, max) let ({ compare } = services.versionCompare,
+ { platformVersion } = services.runtime)
+ (min == null || compare(platformVersion, min) >= 0) &&
+ (max == null || compare(platformVersion, max) < 0),
+
+ /** Dactyl's notion of the current operating system platform. */
+ OS: memoize({
+ _arch: services.runtime.OS,
+ /**
+ * @property {string} The normalised name of the OS. This is one of
+ * "Windows", "Mac OS X" or "Unix".
+ */
+ get name() this.isWindows ? "Windows" : this.isMacOSX ? "Mac OS X" : "Unix",
+ /** @property {boolean} True if the OS is Windows. */
+ get isWindows() this._arch == "WINNT",
+ /** @property {boolean} True if the OS is Mac OS X. */
+ get isMacOSX() this._arch == "Darwin",
+ /** @property {boolean} True if the OS is some other *nix variant. */
+ get isUnix() !this.isWindows,
+ /** @property {RegExp} A RegExp which matches illegal characters in path components. */
+ get illegalCharacters() this.isWindows ? /[<>:"/\\|?*\x00-\x1f]/g : /[\/\x00]/g,
+
+ get pathListSep() this.isWindows ? ";" : ":"
+ }),
+
+ /**
+ * @property {string} The pathname of the VCS repository clone's root
+ * directory if the application is running from one via an extension
+ * proxy file.
+ */
+ VCSPath: Class.Memoize(function () {
if (/pre$/.test(this.addon.version)) {
- let uri = this.addon.getResourceURI("../.hg");
+ let uri = util.newURI(this.addon.getResourceURI("").spec + "../.hg");
if (uri instanceof Ci.nsIFileURL &&
- uri.QueryInterface(Ci.nsIFileURL).file.exists() &&
+ uri.file.exists() &&
io.pathSearch("hg"))
- return ["hg", "-R", uri.file.parent.path];
+ return uri.file.parent.path;
}
return null;
}),
- branch: Class.memoize(function () {
- if (this.haveHg)
- return io.system(this.haveHg.concat(["branch"])).output;
+ /**
+ * @property {string} The name of the VCS branch that the application is
+ * running from if using an extension proxy file or was built from if
+ * installed as an XPI.
+ */
+ branch: Class.Memoize(function () {
+ if (this.VCSPath)
+ return io.system(["hg", "-R", this.VCSPath, "branch"]).output;
return (/pre-hg\d+-(\S*)/.exec(this.version) || [])[1];
}),
+ /** @property {string} The name of the current user profile. */
+ profileName: Class.Memoize(function () {
+ // NOTE: services.profile.selectedProfile.name doesn't return
+ // what you might expect. It returns the last _actively_ selected
+ // profile (i.e. via the Profile Manager or -P option) rather than the
+ // current profile. These will differ if the current process was run
+ // without explicitly selecting a profile.
+
+ let dir = services.directory.get("ProfD", Ci.nsIFile);
+ for (let prof in iter(services.profile.profiles))
+ if (prof.QueryInterface(Ci.nsIToolkitProfile).rootDir.path === dir.path)
+ return prof.name;
+ return "unknown";
+ }),
+
/** @property {string} The Dactyl version string. */
- version: Class.memoize(function () {
- if (/pre$/.test(this.addon.version)) {
- let uri = this.addon.getResourceURI("../.hg");
- if (uri instanceof Ci.nsIFileURL &&
- uri.QueryInterface(Ci.nsIFileURL).file.exists() &&
- io.pathSearch("hg")) {
- return io.system(["hg", "-R", uri.file.parent.path,
- "log", "-r.",
- "--template=hg{rev}-" + this.branch + " ({date|isodate})"]).output;
- }
- }
- let version = this.addon.version;
+ version: Class.Memoize(function () {
+ if (this.VCSPath)
+ return io.system(["hg", "-R", this.VCSPath, "log", "-r.",
+ "--template=hg{rev}-{branch}"]).output;
+
+ return this.addon.version;
+ }),
+
+ buildDate: Class.Memoize(function () {
+ if (this.VCSPath)
+ return io.system(["hg", "-R", this.VCSPath, "log", "-r.",
+ "--template={date|isodate}"]).output;
if ("@DATE@" !== "@" + "DATE@")
- version += " (created: @DATE@)";
- return version;
+ return _("dactyl.created", "@DATE@");
}),
- get fileExt() this.name.slice(0, -5),
+ get fileExt() this.name.slice(0, -6),
+
+ dtd: Class.Memoize(function ()
+ iter(this.dtdExtra,
+ (["dactyl." + k, v] for ([k, v] in iter(config.dtdDactyl))),
+ (["dactyl." + s, config[s]] for each (s in config.dtdStrings)))
+ .toObject()),
- dtd: memoize({
+ dtdDactyl: memoize({
get name() config.name,
- get home() "http://dactyl.sourceforge.net/",
+ get home() "http://5digits.org/",
get apphome() this.home + this.name,
code: "http://code.google.com/p/dactyl/",
get issues() this.home + "bug/" + this.name,
- get plugins() "http://dactyl.sf.net/" + this.name + "/plugins",
+ get plugins() "http://5digits.org/" + this.name + "/plugins",
get faq() this.home + this.name + "/faq",
- "list.mailto": Class.memoize(function () config.name + "@googlegroups.com"),
- "list.href": Class.memoize(function () "http://groups.google.com/group/" + config.name),
+ "list.mailto": Class.Memoize(function () config.name + "@googlegroups.com"),
+ "list.href": Class.Memoize(function () "http://groups.google.com/group/" + config.name),
- "hg.latest": Class.memoize(function () this.code + "source/browse/"), // XXX
- "irc": "irc://irc.oftc.net/#pentadactyl",
+ "hg.latest": Class.Memoize(function () this.code + "source/browse/"), // XXX
+ "irc": "irc://irc.oftc.net/#pentadactyl"
}),
dtdExtra: {
"xmlns.html": "http://www.w3.org/1999/xhtml",
"xmlns.xul": "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
- "tag.command-line": '<link topic="command-line">command line</link>',
- "tag.status-line": '<link topic="status-line">status line</link>',
+ "tag.command-line": ["link", { xmlns: "dactyl", topic: "command-line" }, "command line"],
+ "tag.status-line": ["link", { xmlns: "dactyl", topic: "status-line" }, "status line"],
+ "mode.command-line": ["link", { xmlns: "dactyl", topic: "command-line-mode" }, "Command Line"]
},
dtdStrings: [
"version"
],
- helpStyles: /^(Help|StatusLine|REPL)|^(Boolean|Indicator|MoreMsg|Number|Object|Logo|Key(word)?|String)$/,
+ helpStyles: /^(Help|StatusLine|REPL)|^(Boolean|Dense|Indicator|MoreMsg|Number|Object|Logo|Key(word)?|String)$/,
styleHelp: function styleHelp() {
if (!this.helpStyled) {
- const { highlight } = require("highlight");
for (let k in keys(highlight.loaded))
if (this.helpStyles.test(k))
highlight.loaded[k] = true;
this.helpCSS = true;
},
- Local: function Local(dactyl, modules, window) ({
+ Local: function Local(dactyl, modules, { document, window }) ({
init: function init() {
+ this.loadConfig(document.documentURI);
+
+ let append = [
+ ["menupopup", { id: "viewSidebarMenu", xmlns: "xul" }],
+ ["broadcasterset", { id: "mainBroadcasterSet", xmlns: "xul" }]];
- let append = <e4x xmlns={XUL} xmlns:dactyl={NS}>
- <menupopup id="viewSidebarMenu"/>
- <broadcasterset id="mainBroadcasterSet"/>
- </e4x>;
for each (let [id, [name, key, uri]] in Iterator(this.sidebars)) {
- append.XUL::menupopup[0].* +=
- <menuitem observes={"pentadactyl-" + id + "Sidebar"} label={name} accesskey={key} xmlns={XUL}/>
- append.XUL::broadcasterset[0].* +=
- <broadcaster id={"pentadactyl-" + id + "Sidebar"}
- autoCheck="false" type="checkbox" group="sidebar"
- sidebartitle={name} sidebarurl={uri}
- oncommand="toggleSidebar(this.id || this.observes);" xmlns={XUL}/>
+ append[0].push(
+ ["menuitem", { observes: "pentadactyl-" + id + "Sidebar", label: name,
+ accesskey: key }]);
+ append[1].push(
+ ["broadcaster", { id: "pentadactyl-" + id + "Sidebar", autoCheck: "false",
+ type: "checkbox", group: "sidebar", sidebartitle: name,
+ sidebarurl: uri,
+ oncommand: "toggleSidebar(this.id || this.observes);" }]);
}
- util.overlayWindow(window, { append: append.elements() });
+ util.overlayWindow(window, { append: append });
},
- browser: Class.memoize(function () window.gBrowser),
- tabbrowser: Class.memoize(function () window.gBrowser),
+ get window() window,
+
+ get document() document,
+
+ ids: Class.Update({
+ get commandContainer() document.documentElement.id
+ }),
+
+ browser: Class.Memoize(function () window.gBrowser),
+ tabbrowser: Class.Memoize(function () window.gBrowser),
get browserModes() [modules.modes.NORMAL],
/**
* @property {string} The ID of the application's main XUL window.
*/
- mainWindowId: window.document.documentElement.id,
+ mainWindowId: document.documentElement.id,
/**
* @property {number} The height (px) that is available to the output
*/
get outputHeight() this.browser.mPanelContainer.boxObject.height,
- tabStrip: Class.memoize(function () window.document.getElementById("TabsToolbar") || this.tabbrowser.mTabContainer),
+ tabStrip: Class.Memoize(function () document.getElementById("TabsToolbar") || this.tabbrowser.mTabContainer)
}),
/**
* @property {Object} A map of :command-complete option values to completer
* function names.
*/
- completers: {
- abbreviation: "abbreviation",
- altstyle: "alternateStyleSheet",
- bookmark: "bookmark",
- buffer: "buffer",
- charset: "charset",
- color: "colorScheme",
- command: "command",
- dialog: "dialog",
- dir: "directory",
- environment: "environment",
- event: "autocmdEvent",
- extension: "extension",
- file: "file",
- help: "help",
- highlight: "highlightGroup",
- history: "history",
- javascript: "javascript",
- macro: "macro",
- mapping: "userMapping",
- mark: "mark",
- menu: "menuItem",
- option: "option",
- preference: "preference",
- qmark: "quickmark",
- runtime: "runtime",
- search: "search",
- shellcmd: "shellCommand",
- toolbar: "toolbar",
- url: "url",
- usercommand: "userCommand"
- },
+ completers: {},
/**
* @property {Object} Application specific defaults for option values. The
* property names must be the options' canonical names, and the values
* must be strings as entered via :set.
*/
- defaults: { guioptions: "rb" },
+ optionDefaults: {},
+
cleanups: {},
/**
* @property {Object} A map of dialogs available via the
* :dialog command. Property names map dialog names to an array
- * as follows:
+ * with the following elements:
* [0] description - A description of the dialog, used in
* command completion results for :dialog.
* [1] action - The function executed by :dialog.
+ * [2] test - Function which returns true if the dialog is available in
+ * the current window. @optional
*/
dialogs: {},
guioptions: {},
- hasTabbrowser: false,
-
/**
* @property {string} The name of the application that hosts the
* extension. E.g., "Firefox" or "XULRunner".
*/
host: null,
- /**
- * @property {[[]]} An array of application specific mode specifications.
- * The values of each mode are passed to modes.addMode during
- * dactyl startup.
- */
- modes: [],
-
/**
* @property {string} The name of the extension.
* Required.
sidebars: {},
- /**
- * @property {string} The leaf name of any temp files created by
- * {@link io.createTempFile}.
- */
- get tempFile() this.name + ".tmp",
-
/**
* @constant
* @property {string} The default highlighting rules.
* See {@link Highlights#loadCSS} for details.
*/
- CSS: UTF8(String.replace(<><![CDATA[
- // <css>
- Boolean color: red;
- Function color: navy;
- Null color: blue;
- Number color: blue;
- Object color: maroon;
- String color: green; white-space: pre;
-
- Key font-weight: bold;
-
- Enabled color: blue;
- Disabled color: red;
-
- FontFixed font-family: monospace !important;
- FontCode font-size: 9pt; font-family: -mox-fixed, monospace !important;
- FontProportional font-size: 10pt; font-family: "Droid Sans", "Helvetica LT Std", Helvetica, "DejaVu Sans", Verdana, sans-serif !important;
-
- // Hack to give these groups slightly higher precedence
- // than their unadorned variants.
- CmdCmdLine;[dactyl|highlight]>* 
 StatusCmdLine;[dactyl|highlight]>*
- CmdNormal;[dactyl|highlight] 
 StatusNormal;[dactyl|highlight]
- CmdErrorMsg;[dactyl|highlight] 
 StatusErrorMsg;[dactyl|highlight]
- CmdInfoMsg;[dactyl|highlight] 
 StatusInfoMsg;[dactyl|highlight]
- CmdModeMsg;[dactyl|highlight] 
 StatusModeMsg;[dactyl|highlight]
- CmdMoreMsg;[dactyl|highlight] 
 StatusMoreMsg;[dactyl|highlight]
- CmdQuestion;[dactyl|highlight] 
 StatusQuestion;[dactyl|highlight]
- CmdWarningMsg;[dactyl|highlight] 
 StatusWarningMsg;[dactyl|highlight]
-
- Normal color: black !important; background: white !important; font-weight: normal !important;
- StatusNormal color: inherit !important; background: transparent !important;
- ErrorMsg color: white !important; background: red !important; font-weight: bold !important;
- InfoMsg color: black !important; background: white !important;
- StatusInfoMsg color: inherit !important; background: transparent !important;
- LineNr color: orange !important; background: white !important;
- ModeMsg color: black !important; background: white !important;
- StatusModeMsg color: inherit !important; background: transparent !important; padding-right: 1em;
- MoreMsg color: green !important; background: white !important;
- StatusMoreMsg background: transparent !important;
- Message white-space: pre-wrap !important; min-width: 100%; width: 100%; padding-left: 4em; text-indent: -4em; display: block;
- Message String white-space: pre-wrap;
- NonText color: blue; background: transparent !important;
- *Preview color: gray;
- Question color: green !important; background: white !important; font-weight: bold !important;
- StatusQuestion color: green !important; background: transparent !important;
- WarningMsg color: red !important; background: white !important;
- StatusWarningMsg color: red !important; background: transparent !important;
-
- CmdLine;>*;;FontFixed padding: 1px !important;
- CmdPrompt;.dactyl-commandline-prompt
- CmdInput;.dactyl-commandline-command
- CmdOutput white-space: pre;
-
-
- CompGroup
- CompGroup:not(:first-of-type) margin-top: .5em;
- CompGroup:last-of-type padding-bottom: 1.5ex;
-
- CompTitle color: magenta; background: white; font-weight: bold;
- CompTitle>* padding: 0 .5ex;
- CompTitleSep height: 1px; background: magenta; background: -moz-linear-gradient(60deg, magenta, white);
-
- CompMsg font-style: italic; margin-left: 16px;
-
- CompItem
- CompItem:nth-child(2n+1) background: rgba(0, 0, 0, .04);
- CompItem[selected] background: yellow;
- CompItem>* padding: 0 .5ex;
-
- CompIcon width: 16px; min-width: 16px; display: inline-block; margin-right: .5ex;
- CompIcon>img max-width: 16px; max-height: 16px; vertical-align: middle;
-
- CompResult width: 36%; padding-right: 1%; overflow: hidden;
- CompDesc color: gray; width: 62%; padding-left: 1em;
-
- CompLess text-align: center; height: 0; line-height: .5ex; padding-top: 1ex;
- CompLess::after content: "⌃";
-
- CompMore text-align: center; height: .5ex; line-height: .5ex; margin-bottom: -.5ex;
- CompMore::after content: "⌄";
-
-
- EditorEditing;;* background: #bbb !important; -moz-user-input: none !important; -moz-user-modify: read-only !important;
- EditorError;;* background: red !important;
- EditorBlink1;;* background: yellow !important;
- EditorBlink2;;*
-
- REPL overflow: auto; max-height: 40em;
- REPL-R;;;Question
- REPL-E white-space: pre-wrap;
- REPL-P white-space: pre-wrap; margin-bottom: 1em;
-
- Usage width: 100%;
- UsageBody
- UsageHead
- UsageItem
- UsageItem:nth-of-type(2n) background: rgba(0, 0, 0, .04);
-
- Indicator color: blue; width: 1.5em; text-align: center;
- Filter font-weight: bold;
-
- Keyword color: red;
- Tag color: blue;
-
- Link position: relative; padding-right: 2em;
- Link:not(:hover)>LinkInfo opacity: 0; left: 0; width: 1px; height: 1px; overflow: hidden;
- LinkInfo {
- color: black;
- position: absolute;
- left: 100%;
- padding: 1ex;
- margin: -1ex -1em;
- background: rgba(255, 255, 255, .8);
- border-radius: 1ex;
- }
-
- StatusLine;;;FontFixed {
- -moz-appearance: none !important;
- font-weight: bold;
- background: transparent !important;
- border: 0px !important;
- padding-right: 0px !important;
- min-height: 18px !important;
- text-shadow: none !important;
- }
- StatusLineNormal;[dactyl|highlight] color: white !important; background: black !important;
- StatusLineBroken;[dactyl|highlight] color: black !important; background: #FFa0a0 !important; /* light-red */
- StatusLineSecure;[dactyl|highlight] color: black !important; background: #a0a0FF !important; /* light-blue */
- StatusLineExtended;[dactyl|highlight] color: black !important; background: #a0FFa0 !important; /* light-green */
-
- TabClose;.tab-close-button
- TabIcon;.tab-icon min-width: 16px;
- TabText;.tab-text
- TabNumber font-weight: bold; margin: 0px; padding-right: .8ex; cursor: default;
- TabIconNumber {
- cursor: default;
- width: 16px;
- margin: 0 2px 0 -18px !important;
- font-weight: bold;
- color: white;
- text-align: center;
- text-shadow: black -1px 0 1px, black 0 1px 1px, black 1px 0 1px, black 0 -1px 1px;
- }
-
- Title color: magenta; font-weight: bold;
- URL text-decoration: none; color: green; background: inherit;
- URL:hover text-decoration: underline; cursor: pointer;
- URLExtra color: gray;
-
- FrameIndicator;;* {
- background-color: red;
- opacity: 0.5;
- z-index: 999999;
- position: fixed;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- }
-
- Bell background-color: black !important;
-
- Hint;;* {
- font: bold 10px "Droid Sans Mono", monospace !important;
- margin: -.2ex;
- padding: 0 0 0 1px;
- outline: 1px solid rgba(0, 0, 0, .5);
- background: rgba(255, 248, 231, .8);
- color: black;
- }
- Hint[active];;* background: rgba(255, 253, 208, .8);
- Hint::after;;* content: attr(text) !important;
- HintElem;;* background-color: yellow !important; color: black !important;
- HintActive;;* background-color: #88FF00 !important; color: black !important;
- HintImage;;* opacity: .5 !important;
-
- Button display: inline-block; font-weight: bold; cursor: pointer; color: black; text-decoration: none;
- Button:hover text-decoration: underline;
- Button[collapsed] visibility: collapse; width: 0;
- Button::before content: "["; color: gray; text-decoration: none !important;
- Button::after content: "]"; color: gray; text-decoration: none !important;
- Button:not([collapsed]) ~ Button:not([collapsed])::before content: "/[";
-
- Buttons
-
- DownloadCell display: table-cell; padding: 0 1ex;
-
- Downloads display: table; margin: 0; padding: 0;
- DownloadHead;;;CompTitle display: table-row;
- DownloadHead>*;;;DownloadCell
-
- Download display: table-row;
- Download:not([active]) color: gray;
-
- Download>*;;;DownloadCell
- DownloadButtons
- DownloadPercent
- DownloadProgress
- DownloadProgressHave
- DownloadProgressTotal
- DownloadSource
- DownloadState
- DownloadTime
- DownloadTitle
- DownloadTitle>Link>a max-width: 48ex; overflow: hidden; display: inline-block;
-
- AddonCell display: table-cell; padding: 0 1ex;
-
- Addons display: table; margin: 0; padding: 0;
- AddonHead;;;CompTitle display: table-row;
- AddonHead>*;;;AddonCell
-
- Addon display: table-row;
-
- Addon>*;;;AddonCell
- AddonButtons
- AddonDescription
- AddonName max-width: 48ex; overflow: hidden;
- AddonStatus
- AddonVersion
-
- // </css>
- ]]></>, /
/g, "\n")),
+ CSS: Class.Memoize(function () File.readURL("resource://dactyl-skin/global-styles.css")),
- helpCSS: UTF8(<><![CDATA[
- // <css>
- InlineHelpLink font-size: inherit !important; font-family: inherit !important;
-
- Help;;;FontProportional line-height: 1.4em;
-
- HelpInclude margin: 2em 0;
-
- HelpArg;;;FontCode color: #6A97D4;
- HelpOptionalArg;;;FontCode color: #6A97D4;
-
- HelpBody display: block; margin: 1em auto; max-width: 100ex; padding-bottom: 1em; margin-bottom: 4em; border-bottom-width: 1px;
- HelpBorder;*;dactyl://help/* border-color: silver; border-width: 0px; border-style: solid;
- HelpCode;;;FontCode display: block; white-space: pre; margin-left: 2em;
- HelpTT;html|tt;dactyl://help/*;FontCode
-
- HelpDefault;;;FontCode display: inline-block; margin: -1px 1ex 0 0; white-space: pre; vertical-align: text-top;
-
- HelpDescription display: block; clear: right;
- HelpDescription[short] clear: none;
- HelpEm;html|em;dactyl://help/* font-weight: bold; font-style: normal;
-
- HelpEx;;;FontCode display: inline-block; color: #527BBD;
-
- HelpExample display: block; margin: 1em 0;
- HelpExample::before content: "Example: "; font-weight: bold;
-
- HelpInfo display: block; width: 20em; margin-left: auto;
- HelpInfoLabel display: inline-block; width: 6em; color: magenta; font-weight: bold; vertical-align: text-top;
- HelpInfoValue display: inline-block; width: 14em; text-decoration: none; vertical-align: text-top;
-
- HelpItem display: block; margin: 1em 1em 1em 10em; clear: both;
-
- HelpKey;;;FontCode color: #102663;
- HelpKeyword font-weight: bold; color: navy;
-
- HelpLink;html|a;dactyl://help/* text-decoration: none !important;
- HelpLink[href]:hover text-decoration: underline !important;
- HelpLink[href^="mailto:"]::after content: "✉"; padding-left: .2em;
- HelpLink[rel=external] {
- /* Thanks, Wikipedia */
- background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAFVBMVEVmmcwzmcyZzP8AZswAZv////////9E6giVAAAAB3RSTlP///////8AGksDRgAAADhJREFUGFcly0ESAEAEA0Ei6/9P3sEcVB8kmrwFyni0bOeyyDpy9JTLEaOhQq7Ongf5FeMhHS/4AVnsAZubxDVmAAAAAElFTkSuQmCC) no-repeat scroll right center;
- padding-right: 13px;
- }
-
-
- HelpTOC
- HelpTOC>ol ol margin-left: -1em;
-
- HelpOrderedList;ol;dactyl://help/* margin: 1em 0;
- HelpOrderedList1;ol[level="1"],ol;dactyl://help/* list-style: outside decimal; display: block;
- HelpOrderedList2;ol[level="2"],ol ol;dactyl://help/* list-style: outside upper-alpha;
- HelpOrderedList3;ol[level="3"],ol ol ol;dactyl://help/* list-style: outside lower-roman;
- HelpOrderedList4;ol[level="4"],ol ol ol ol;dactyl://help/* list-style: outside decimal;
-
- HelpList;html|ul;dactyl://help/* display: block; list-style-position: outside; margin: 1em 0;
- HelpListItem;html|li;dactyl://help/* display: list-item;
-
-
- HelpNote color: red; font-weight: bold;
-
- HelpOpt;;;FontCode color: #106326;
- HelpOptInfo;;;FontCode display: block; margin-bottom: 1ex; padding-left: 4em;
-
- HelpParagraph;html|p;dactyl://help/* display: block; margin: 1em 0em;
- HelpParagraph:first-child margin-top: 0;
- HelpParagraph:last-child margin-bottom: 0;
- HelpSpec;;;FontCode display: block; margin-left: -10em; float: left; clear: left; color: #527BBD; margin-right: 1em;
-
- HelpString;;;FontCode color: green; font-weight: normal;
- HelpString::before content: '"';
- HelpString::after content: '"';
- HelpString[delim]::before content: attr(delim);
- HelpString[delim]::after content: attr(delim);
-
- HelpNews position: relative;
- HelpNewsOld opacity: .7;
- HelpNewsNew font-style: italic;
- HelpNewsTag font-style: normal; position: absolute; left: 100%; padding-left: 1em; color: #527BBD; opacity: .6; white-space: pre;
-
- HelpHead;html|h1,html|h2,html|h3,html|h4;dactyl://help/* {
- font-weight: bold;
- color: #527BBD;
- clear: both;
- }
- HelpHead1;html|h1;dactyl://help/* {
- margin: 2em 0 1em;
- padding-bottom: .2ex;
- border-bottom-width: 1px;
- font-size: 2em;
- }
- HelpHead2;html|h2;dactyl://help/* {
- margin: 2em 0 1em;
- padding-bottom: .2ex;
- border-bottom-width: 1px;
- font-size: 1.2em;
- }
- HelpHead3;html|h3;dactyl://help/* {
- margin: 1em 0;
- padding-bottom: .2ex;
- font-size: 1.1em;
- }
- HelpHead4;html|h4;dactyl://help/* {
- }
-
-
- HelpTab;html|dl;dactyl://help/* {
- display: table;
- width: 100%;
- margin: 1em 0;
- border-bottom-width: 1px;
- border-top-width: 1px;
- padding: .5ex 0;
- table-layout: fixed;
- }
- HelpTabColumn;html|column;dactyl://help/* display: table-column;
- HelpTabColumn:first-child width: 25%;
- HelpTabTitle;html|dt;dactyl://help/*;FontCode display: table-cell; padding: .1ex 1ex; font-weight: bold;
- HelpTabDescription;html|dd;dactyl://help/* display: table-cell; padding: .3ex 1em; text-indent: -1em; border-width: 0px;
- HelpTabDescription>*;;dactyl://help/* text-indent: 0;
- HelpTabRow;html|dl>html|tr;dactyl://help/* display: table-row;
-
- HelpTag;;;FontCode display: inline-block; color: #527BBD; margin-left: 1ex; font-weight: normal;
- HelpTags display: block; float: right; clear: right;
- HelpTopic;;;FontCode color: #102663;
- HelpType;;;FontCode margin-right: 2ex;
-
- HelpWarning color: red; font-weight: bold;
-
- HelpXML;;;FontCode color: #C5F779; background-color: #444444; font-family: Terminus, Fixed, monospace;
- HelpXMLBlock { white-space: pre; color: #C5F779; background-color: #444444;
- border: 1px dashed #aaaaaa;
- display: block;
- margin-left: 2em;
- font-family: Terminus, Fixed, monospace;
- }
- HelpXMLAttribute color: #C5F779;
- HelpXMLAttribute::after color: #E5E5E5; content: "=";
- HelpXMLComment color: #444444;
- HelpXMLComment::before content: "<!--";
- HelpXMLComment::after content: "-->";
- HelpXMLProcessing color: #C5F779;
- HelpXMLProcessing::before color: #444444; content: "<?";
- HelpXMLProcessing::after color: #444444; content: "?>";
- HelpXMLString color: #C5F779; white-space: pre;
- HelpXMLString::before content: '"';
- HelpXMLString::after content: '"';
- HelpXMLNamespace color: #FFF796;
- HelpXMLNamespace::after color: #777777; content: ":";
- HelpXMLTagStart color: #FFF796; white-space: normal; display: inline-block; text-indent: -1.5em; padding-left: 1.5em;
- HelpXMLTagEnd color: #71BEBE;
- HelpXMLText color: #E5E5E5;
- // </css>
- ]]></>)
+ helpCSS: Class.Memoize(function () File.readURL("resource://dactyl-skin/help-styles.css"))
}, {
});
-
JSMLoader.loadSubScript("resource://dactyl-local-content/config.js", this);
config.INIT = update(Object.create(config.INIT), config.INIT, {
let img = window.Image();
img.src = this.logo || "resource://dactyl-local-content/logo.png";
img.onload = util.wrapCallback(function () {
- const { highlight } = require("highlight");
- highlight.loadCSS(<>{"!Logo {"}
+ highlight.loadCSS(literal(/*
+ !Logo {
display: inline-block;
- background: url({img.src});
- width: {img.width}px;
- height: {img.height}px;
- {"}"}</>);
+ background: url({src});
+ width: {width}px;
+ height: {height}px;
+ }
+ */).replace(/\{(.*?)\}/g, function (m, m1) img[m1]));
img = null;
});
},
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 ts=8 et ft=javascript: