// 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-2014 Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
/** @scope modules */
-default xml namespace = XHTML;
-XML.ignoreWhitespace = false;
-XML.prettyPrinting = false;
-
var EVAL_ERROR = "__dactyl_eval_error";
var EVAL_RESULT = "__dactyl_eval_result";
var EVAL_STRING = "__dactyl_eval_string";
init: function () {
window.dactyl = this;
// cheap attempt at compatibility
- let prop = { get: deprecated("dactyl", function liberator() dactyl) };
+ let prop = { get: deprecated("dactyl", function liberator() dactyl),
+ configurable: true };
Object.defineProperty(window, "liberator", prop);
Object.defineProperty(modules, "liberator", prop);
this.commands = {};
delete window.liberator;
// Prevents box ordering bugs after our stylesheet is removed.
- styles.system.add("cleanup-sheet", config.styleableChrome, <![CDATA[
+ styles.system.add("cleanup-sheet", config.styleableChrome, literal(/*
#TabsToolbar tab { display: none; }
- ]]>);
+ */));
styles.unregisterSheet("resource://dactyl-skin/dactyl.css");
DOM('#TabsToolbar tab', document).style.display;
},
}
},
-
observers: {
"dactyl-cleanup": function dactyl_cleanup(subject, reason) {
let modules = dactyl.modules;
signals: {
"io.source": function ioSource(context, file, modTime) {
- if (context.INFO)
+ if (contexts.getDocs(context))
help.flush("help/plugins.xml", modTime);
}
},
&& !item.hidden
&& !/rdf:http:/.test(item.getAttribute("label"))) { // FIXME
item.dactylPath = parent + item.getAttribute("label");
- if (!targetPath || targetPath.indexOf(item.dactylPath) == 0)
+ if (!targetPath || targetPath.startsWith(item.dactylPath))
items.push(item);
}
else {
let path = parent;
if (item.localName == "menu")
path += item.getAttribute("label") + ".";
- if (!targetPath || targetPath.indexOf(path) == 0)
+ if (!targetPath || targetPath.startsWith(path))
addChildren(item, path);
}
}
NEW_WINDOW: "window",
forceBackground: null,
+ forcePrivate: null,
forceTarget: null,
get forceOpen() ({ background: this.forceBackground,
registerObservers: function registerObservers(obj, prop) {
for (let [signal, func] in Iterator(obj[prop || "signals"]))
- this.registerObserver(signal, obj.closure(func), false);
+ this.registerObserver(signal, func.bind(obj), false);
},
unregisterObserver: function unregisterObserver(type, callback) {
if (type in this._observers)
- this._observers[type] = this._observers[type].filter(function (c) c.get() != callback);
+ this._observers[type] = this._observers[type].filter(c => c.get() != callback);
},
applyTriggerObserver: function triggerObserver(type, args) {
if (type in this._observers)
- this._observers[type] = this._observers[type].filter(function (callback) {
- if (callback.get()) {
- try {
- try {
- callback.get().apply(null, args);
- }
- catch (e if e.message == "can't wrap XML objects") {
- // Horrible kludge.
- callback.get().apply(null, [String(args[0])].concat(args.slice(1)));
- }
- }
- catch (e) {
- dactyl.reportError(e);
- }
+ this._observers[type] = this._observers[type]
+ .filter(callback => {
+ callback = callback.get();
+ if (callback) {
+ util.trapErrors(() => callback.apply(null, args));
return true;
}
});
},
- triggerObserver: function triggerObserver(type) {
- return this.applyTriggerObserver(type, Array.slice(arguments, 1));
+ triggerObserver: function triggerObserver(type, ...args) {
+ return this.applyTriggerObserver(type, args);
},
addUsageCommand: function (params) {
let name = commands.add(params.name, params.description,
function (args) {
let results = array(params.iterate(args))
- .sort(function (a, b) String.localeCompare(a.name, b.name));
+ .sort((a, b) => String.localeCompare(a.name, b.name));
- let filters = args.map(function (arg) let (re = util.regexp.escape(arg))
+ let filters = args.map(arg => let (re = util.regexp.escape(arg))
util.regexp("\\b" + re + "\\b|(?:^|[()\\s])" + re + "(?:$|[()\\s])", "i"));
if (filters.length)
- results = results.filter(function (item) filters.every(function (re) keys(item).some(re.closure.test)));
+ results = results.filter(item => filters.every(re => keys(item).some(re.bound.test)));
commandline.commandOutput(
template.usage(results, params.format));
if (params.index)
this.indices[params.index] = function () {
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((a, b) => String.localeCompare(a.name, b.name));
- let haveTag = Set.has(help.tags);
for (let obj in values(results)) {
let res = dactyl.generateHelp(obj, null, null, true);
- if (!haveTag(obj.helpTag))
- res[1].@tag = obj.helpTag;
+ if (!hasOwnProperty(help.tags, obj.helpTag))
+ res[0][1].tag = obj.helpTag;
yield res;
}
bell: document.getElementById("dactyl-bell"),
strut: document.getElementById("dactyl-bell-strut")
};
- XML.ignoreWhitespace = true;
if (!elems.bell)
overlay.overlayWindow(window, {
objects: elems,
- prepend: <>
- <window id={document.documentElement.id} xmlns={XUL}>
- <hbox style="display: none" highlight="Bell" id="dactyl-bell" key="bell"/>
- </window>
- </>,
- append: <>
- <window id={document.documentElement.id} xmlns={XUL}>
- <hbox style="display: none" highlight="Bell" id="dactyl-bell-strut" key="strut"/>
- </window>
- </>
+ prepend: [
+ ["window", { id: document.documentElement.id, xmlns: "xul" },
+ ["hbox", { style: "display: none", highlight: "Bell", id: "dactyl-bell", key: "bell" }]]],
+ append: [
+ ["window", { id: document.documentElement.id, xmlns: "xul" },
+ ["hbox", { style: "display: none", highlight: "Bell", id: "dactyl-bell-strut", key: "strut" }]]]
}, elems);
elems.bell.style.height = window.innerHeight + "px";
},
dump: deprecated("util.dump",
- { get: function dump() util.closure.dump }),
+ { get: function dump() util.bound.dump }),
dumpStack: deprecated("util.dumpStack",
- { get: function dumpStack() util.closure.dumpStack }),
+ { get: function dumpStack() util.bound.dumpStack }),
/**
* Outputs a plain message to the command line.
if (isObject(str) && "echoerr" in str)
str = str.echoerr;
else if (isinstance(str, ["Error", FailedAssertion]) && str.fileName)
- str = <>{str.fileName.replace(/^.* -> /, "")}: {str.lineNumber}: {str}</>;
+ str = [str.fileName.replace(/^.* -> /, ""), ": ", str.lineNumber, ": ", str].join("");
if (options["errorbells"])
dactyl.beep();
* @param {Object} context The context object into which the script
* should be loaded.
*/
- loadScript: function (uri, context) {
+ loadScript: function loadScript(uri, context) {
+ let prefix = "literal:" + uri + ":";
+ cache.flush(s => s.startsWith(prefix));
+ delete literal.files[uri];
JSMLoader.loadSubScript(uri, context, File.defaultEncoding);
},
- userEval: function (str, context, fileName, lineNumber) {
- let ctxt;
- if (jsmodules.__proto__ != window && jsmodules.__proto__ != XPCNativeWrapper(window) &&
- jsmodules.isPrototypeOf(context))
- str = "with (window) { with (modules) { (this.eval || eval)(" + str.quote() + ") } }";
+ userEval: function userEval(str, context, fileName, lineNumber) {
+ let ctxt,
+ info = contexts.context;
- let info = contexts.context;
if (fileName == null)
if (info)
({ file: fileName, line: lineNumber, context: ctxt }) = info;
if (fileName && fileName[0] == "[")
fileName = "dactyl://command-line/";
else if (!context)
- context = ctxt || _userContext;
-
- if (isinstance(context, ["Sandbox"]))
- return Cu.evalInSandbox(str, context, "1.8", fileName, lineNumber);
+ context = ctxt || userContext;
if (!context)
context = userContext || ctxt;
+ if (isinstance(context, ["Sandbox"]))
+ return Cu.evalInSandbox(str, context, "1.8", fileName, lineNumber);
+
if (services.has("dactyl") && services.dactyl.evalInContext)
return services.dactyl.evalInContext(str, context, fileName, lineNumber);
* Acts like the Function builtin, but the code executes in the
* userContext global.
*/
- userFunc: function () {
+ userFunc: function userFunc(...args) {
return this.userEval(
- "(function userFunction(" + Array.slice(arguments, 0, -1).join(", ") + ")" +
- " { " + arguments[arguments.length - 1] + " })");
+ "(function userFunction(" + args.slice(0, -1).join(", ") + ")" +
+ " { " + args.pop() + " })");
},
/**
* @param {boolean} silent Whether the command should be echoed on the
* command line.
*/
- execute: function (str, modifiers, silent) {
+ execute: function execute(str, modifiers={}, silent=false) {
// skip comments and blank lines
if (/^\s*("|$)/.test(str))
return;
- modifiers = modifiers || {};
-
if (!silent)
commands.lastCommand = str.replace(/^\s*:\s*/, "");
let res = true;
if (win.frameElement)
win.frameElement.blur();
// Grr.
- if (content.document.activeElement instanceof HTMLIFrameElement)
+ if (content.document.activeElement instanceof Ci.nsIDOMHTMLIFrameElement)
content.document.activeElement.blur();
});
}
* @param {string} feature The feature name.
* @returns {boolean}
*/
- has: function (feature) Set.has(config.features, feature),
+ has: function has(feature) config.has(feature),
/**
* @private
}
},
- help: deprecated("help.help", { get: function help() modules.help.closure.help }),
- findHelp: deprecated("help.findHelp", { get: function findHelp() help.closure.findHelp }),
+ help: deprecated("help.help", { get: function help() modules.help.bound.help }),
+ findHelp: deprecated("help.findHelp", { get: function findHelp() help.bound.findHelp }),
/**
* @private
*/
initHelp: function initHelp() {
if ("noscriptOverlay" in window)
- noscriptOverlay.safeAllow("dactyl:", true, false);
+ window.noscriptOverlay.safeAllow("dactyl:", true, false);
help.initialize();
},
- stringifyXML: function (xml) {
- XML.prettyPrinting = false;
- XML.ignoreWhitespace = false;
- return UTF8(xml.toXMLString());
- },
-
/**
* Generates a help entry and returns it as a string.
*
* @returns {string}
*/
generateHelp: function generateHelp(obj, extraHelp, str, specOnly) {
- default xml namespace = "";
-
let link, tag, spec;
link = tag = spec = util.identity;
let args = null;
if (obj instanceof Command) {
- link = function (cmd) <ex>{cmd}</ex>;
+ link = cmd => ["ex", {}, cmd];
args = obj.parseArgs("", CompletionContext(str || ""));
- tag = function (cmd) <>:{cmd}</>;
- spec = function (cmd) <>{
- obj.count ? <oa>count</oa> : <></>
- }{
- cmd
- }{
- obj.bang ? <oa>!</oa> : <></>
- }</>;
+ tag = cmd => DOM.DOMString(":" + cmd);
+ spec = cmd => [
+ obj.count ? ["oa", {}, "count"] : [],
+ cmd,
+ obj.bang ? ["oa", {}, "!"] : []
+ ];
}
else if (obj instanceof Map) {
- spec = function (map) obj.count ? <><oa>count</oa>{map}</> : <>{map}</>;
- tag = function (map) <>{
- let (c = obj.modes[0].char) c ? c + "_" : ""
- }{ map }</>;
- link = function (map) {
+ spec = map => (obj.count ? [["oa", {}, "count"], map]
+ : DOM.DOMString(map));
+ tag = map => [
+ let (c = obj.modes[0].char) c ? c + "_" : "",
+ map
+ ];
+ link = map => {
let [, mode, name, extra] = /^(?:(.)_)?(?:<([^>]+)>)?(.*)$/.exec(map);
- let k = <k>{extra}</k>;
+ let k = ["k", {}, extra];
if (name)
- k.@name = name;
+ k[1].name = name;
if (mode)
- k.@mode = mode;
+ k[1].mode = mode;
return k;
};
}
else if (obj instanceof Option) {
- spec = function () template.map(obj.names, tag, " ");
- tag = function (name) <>'{name}'</>;
- link = function (opt, name) <o>{name}</o>;
+ spec = () => template.map(obj.names, tag, " ");
+ tag = name => DOM.DOMString("'" + name + "'");
+ link = (opt, name) => ["o", {}, name];
args = { value: "", values: [] };
}
- XML.prettyPrinting = false;
- XML.ignoreWhitespace = false;
- default xml namespace = NS;
-
- // E4X has its warts.
- let br = <>
- </>;
-
- let res = <res>
- <dt>{link(obj.helpTag || tag(obj.name), obj.name)}</dt> <dd>{
- template.linkifyHelp(obj.description ? obj.description.replace(/\.$/, "") : "", true)
- }</dd></res>;
+ let res = [
+ ["dt", {}, link(obj.helpTag || tag(obj.name), obj.name)],
+ ["dd", {},
+ template.linkifyHelp(obj.description ? obj.description.replace(/\.$/, "") : "", true)]];
if (specOnly)
- return res.elements();
+ return res;
- res.* += <>
- <item>
- <tags>{template.map(obj.names.slice().reverse(), tag, " ")}</tags>
- <spec>{let (name = (obj.specs || obj.names)[0])
+ let description = ["description", {},
+ obj.description ? ["p", {}, template.linkifyHelp(obj.description.replace(/\.?$/, "."), true)] : "",
+ extraHelp ? extraHelp : "",
+ !(extraHelp || obj.description) ? ["p", {}, /*L*/ "Sorry, no help available."] : ""];
+
+ res.push(
+ ["item", {},
+ ["tags", {}, template.map(obj.names.slice().reverse(),
+ tag,
+ " ").join("")],
+ ["spec", {},
+ let (name = (obj.specs || obj.names)[0])
spec(template.highlightRegexp(tag(name),
/\[(.*?)\]/g,
- function (m, n0) <oa>{n0}</oa>),
- name)
- }</spec>{
- !obj.type ? "" : <>
- <type>{obj.type}</type>
- <default>{obj.stringDefaultValue}</default></>}
- <description>{
- obj.description ? br + <p>{template.linkifyHelp(obj.description.replace(/\.?$/, "."), true)}</p> : "" }{
- extraHelp ? br + extraHelp : "" }{
- !(extraHelp || obj.description) ? br + <p><!--L-->Sorry, no help available.</p> : "" }
- </description>
- </item></>;
+ (m, n0) => ["oa", {}, n0]),
+ name)],
+ !obj.type ? "" : [
+ ["type", {}, obj.type],
+ ["default", {}, obj.stringDefaultValue]],
+ description]);
function add(ary) {
- res.item.description.* += br +
- let (br = br + <> </>)
- <><dl>{ br + template.map(ary, function ([a, b]) <><dt>{a}</dt> <dd>{b}</dd></>, br) }
- </dl>
- </>;
+ description.push(
+ ["dl", {}, template.map(ary,
+ function ([a, b]) [["dt", {}, a], " ",
+ ["dd", {}, b]])]);
}
- if (obj.completer)
- add(completion._runCompleter(obj.closure.completer, "", null, args).items
- .map(function (i) [i.text, i.description]));
+ if (obj.completer && false)
+ add(completion._runCompleter(obj.bound.completer, "", null, args).items
+ .map(i => [i.text, i.description]));
- if (obj.options && obj.options.some(function (o) o.description))
- add(obj.options.filter(function (o) o.description)
- .map(function (o) [
+ if (obj.options && obj.options.some(o => o.description) && false)
+ add(obj.options.filter(o => o.description)
+ .map(o => [
o.names[0],
- <>{o.description}{
- o.names.length == 1 ? "" :
- <> (short name: {
- template.map(o.names.slice(1), function (n) <em>{n}</em>, <>, </>)
- })</>
- }</>
+ [o.description,
+ o.names.length == 1 ? "" :
+ ["", " (short name: ",
+ template.map(o.names.slice(1),
+ n => ["em", {}, n],
+ ", "),
+ ")"]]
]));
- return res.*.toXMLString()
- .replace(' xmlns="' + NS + '"', "", "g")
- .replace(/^ {12}|[ \t]+$/gm, "")
- .replace(/^\s*\n|\n\s*$/g, "") + "\n";
+
+ return DOM.toPrettyXML(res, true, null, { "": String(NS) });
},
/**
get: function globalVariables() this._globalVariables
}),
- loadPlugins: function (args, force) {
+ loadPlugins: function loadPlugins(args, force) {
function sourceDirectory(dir) {
dactyl.assert(dir.isReadable(), _("io.notReadable", dir.path));
* @param {string|Object} msg The message to print.
* @param {number} level The logging level 0 - 15.
*/
- log: function (msg, level) {
+ log: function log(msg, level) {
let verbose = config.prefs.get("loglevel", 0);
if (!level || level <= verbose) {
},
events: {
+ beforecustomization: function onbeforecustomization(event) {
+ // Show navigation bar on Australis, where it's not supposed
+ // to be collapsible, and is therefore not handled by
+ // builtin code.
+ if ("CustomizableUI" in window)
+ this.setNodeVisible(document.getElementById("nav-bar"),
+ true);
+ },
+
+ aftercustomization: function onaftercustomization(event) {
+ // Restore toolbar states.
+ options["guioptions"] = options["guioptions"];
+ },
+
click: function onClick(event) {
let elem = event.originalTarget;
* Opens one or more URLs. Returns true when load was initiated, or
* false on error.
*
- * @param {string|object|Array} urls A representation of the URLs to open. May be
- * either a string, which will be passed to
- * {@link Dactyl#parseURLs}, an array in the same format as
- * would be returned by the same, or an object as returned by
- * {@link DOM#formData}.
+ * @param {string|Array} urls A representation of the URLs to open.
+ * A string will be passed to {@link Dactyl#parseURLs}. An array may
+ * contain elements of the following forms:
+ *
+ * • {string} A URL to open.
+ * • {[string, {string|Array}]} Pair of a URL and POST data.
+ * • {object} Object compatible with those returned
+ * by {@link DOM#formData}.
+ *
* @param {object} params A set of parameters specifying how to open the
* URLs. The following properties are recognized:
*
* tabs.
* @returns {boolean}
*/
- open: function (urls, params, force) {
+ open: function open(urls, params={}, force=false) {
if (typeof urls == "string")
urls = dactyl.parseURLs(urls);
if (urls.length > prefs.get("browser.tabs.maxOpenBeforeWarn", 20) && !force)
- return commandline.input(_("dactyl.prompt.openMany", urls.length) + " ",
- function (resp) {
+ return commandline.input(_("dactyl.prompt.openMany", urls.length) + " ")
+ .then(function (resp) {
if (resp && resp.match(/^y(es)?$/i))
dactyl.open(urls, params, true);
});
- params = params || {};
if (isString(params))
params = { where: params };
loc = { url: loc[0], postData: loc[1] };
else if (isString(loc))
loc = { url: loc };
+ else
+ loc = Object.create(loc);
+
+ if (isString(loc.postData))
+ loc.postData = ["application/x-www-form-urlencoded", loc.postData];
+
+ if (isArray(loc.postData)) {
+ let stream = services.MIMEStream(services.StringStream(loc.postData[1]));
+ stream.addHeader("Content-Type", loc.postData[0]);
+ stream.addContentLength = true;
+ loc.postData = stream;
+ }
// decide where to load the first url
switch (where) {
});
case dactyl.NEW_WINDOW:
- let win = window.openDialog(document.documentURI, "_blank", "chrome,all,dialog=no");
- util.waitFor(function () win.document.readyState === "complete");
+ let options = ["chrome", "all", "dialog=no"];
+ if (dactyl.forcePrivate)
+ options.push("private");
+
+ let win = window.openDialog(document.documentURI, "_blank", options.join(","));
+ util.waitFor(() => win.document.readyState === "complete");
browser = win.dactyl && win.dactyl.modules.config.tabbrowser || win.getBrowser();
// FALLTHROUGH
case dactyl.CURRENT_TAB:
// Try to find a matching file.
let file = io.File(url);
if (file.exists() && file.isReadable())
- return services.io.newFileURI(file).spec;
+ return file.URI.spec;
}
catch (e) {}
}
}, this);
},
stringToURLArray: deprecated("dactyl.parseURLs", "parseURLs"),
- urlish: Class.Memoize(function () util.regexp(<![CDATA[
+ urlish: Class.Memoize(() => util.regexp(literal(/*
^ (
<domain>+ (:\d+)? (/ .*) |
<domain>+ (:\d+) |
<domain>+ \. [a-z0-9]+ |
localhost
) $
- ]]>, "ix", {
- domain: util.regexp(String.replace(<![CDATA[
+ */), "ix", {
+ domain: util.regexp(String.replace(literal(/*
[^
U0000-U002c // U002d-U002e --.
U002f // /
U005b-U0060 // U0061-U007a A-Z
U007b-U007f
]
- ]]>, /U/g, "\\u"), "x")
+ */), /U/g, "\\u"), "x")
})),
pluginFiles: {},
* @param {boolean} force Forcibly quit irrespective of whether all
* windows could be closed individually.
*/
- quit: function (saveSession, force) {
+ quit: function quit(saveSession, force) {
if (!force && !this.confirmQuit())
return;
/**
* Restart the host application.
*/
- restart: function (args) {
+ restart: function restart(args) {
if (!this.confirmQuit())
return;
* @param {function} func The function to call
* @param {object} self The 'this' object for the function.
*/
- trapErrors: function trapErrors(func, self) {
+ trapErrors: function trapErrors(func, self, ...args) {
try {
if (isString(func))
func = self[func];
- return func.apply(self || this, Array.slice(arguments, 2));
+ return func.apply(self || this, args);
}
catch (e) {
try {
if (error instanceof FailedAssertion && error.noTrace || error.message === "Interrupted") {
let context = contexts.context;
let prefix = context ? context.file + ":" + context.line + ": " : "";
- if (error.message && error.message.indexOf(prefix) !== 0 &&
+ if (error.message && !error.message.startsWith(prefix) &&
prefix != "[Command Line]:1: ")
error.message = prefix + error.message;
* @returns {Object}
* @see Commands#parseArgs
*/
- parseCommandLine: function (cmdline) {
+ parseCommandLine: function parseCommandLine(cmdline) {
try {
return commands.get("rehash").parseArgs(cmdline);
}
return [];
}
},
- wrapCallback: function (callback, self) {
- self = self || this;
+ wrapCallback: function wrapCallback(callback, self=this) {
let save = ["forceOpen"];
- let saved = save.map(function (p) dactyl[p]);
+ let saved = save.map(p => dactyl[p]);
return function wrappedCallback() {
let args = arguments;
return dactyl.withSavedValues(save, function () {
- saved.forEach(function (p, i) dactyl[save[i]] = p);
+ saved.forEach((p, i) => { dactyl[save[i]] = p; });
try {
return callback.apply(self, args);
}
dactyl.reportError(e, true);
}
});
- }
+ };
},
/**
* @property {[Window]} Returns an array of all the host application's
* open windows.
*/
- get windows() [win for (win in iter(services.windowMediator.getEnumerator("navigator:browser"))) if (win.dactyl)],
+ get windows() [w for (w of overlay.windows)]
}, {
- toolbarHidden: function hidden(elem) (elem.getAttribute("autohide") || elem.getAttribute("collapsed")) == "true"
+ toolbarHidden: function toolbarHidden(elem) "true" == (elem.getAttribute("autohide") ||
+ elem.getAttribute("collapsed"))
}, {
- cache: function () {
+ cache: function initCache() {
cache.register("help/plugins.xml", function () {
// Process plugin help entries.
- XML.ignoreWhiteSpace = XML.prettyPrinting = false;
- let body = XML();
+ let body = [];
for (let [, context] in Iterator(plugins.contexts))
try {
let info = contexts.getDocs(context);
- if (info instanceof XML) {
- if (info.*.@lang.length()) {
- let lang = config.bestLocale(String(a) for each (a in info.*.@lang));
-
- info.* = info.*.(function::attribute("lang").length() == 0 || @lang == lang);
-
- for each (let elem in info.NS::info)
- for (let attr in values(["@name", "@summary", "@href"]))
- if (elem[attr].length())
- info[attr] = elem[attr];
+ if (DOM.isJSONXML(info)) {
+ let langs = info.slice(2)
+ .filter(e => isArray(e) && isObject(e[1]) && e[1].lang);
+ if (langs) {
+ let lang = config.bestLocale(langs.map(l => l[1].lang));
+
+ info = info.slice(0, 2).concat(
+ info.slice(2).filter(e => !isArray(e)
+ || !isObject(e[1])
+ || e[1].lang == lang));
+
+ info.slice(2)
+ .filter(e => isArray(e) && e[0] == "info" && isObject(e[1]))
+ .forEach(elem => {
+ for (let attr of ["name", "summary", "href"])
+ if (attr in elem[1])
+ info[attr] = elem[1][attr];
+ });
}
- body += <h2 xmlns={NS.uri} tag={info.@name + '-plugin'}>{info.@summary}</h2> +
- info;
+ body.push(["h2", { xmlns: "dactyl", tag: info[1].name + '-plugin' },
+ String(info[1].summary)]);
+ body.push(info);
}
}
catch (e) {
return '<?xml version="1.0"?>\n' +
'<?xml-stylesheet type="text/xsl" href="dactyl://content/help.xsl"?>\n' +
- '<!DOCTYPE document SYSTEM "resource://dactyl-content/dactyl.dtd">\n' +
- <document xmlns={NS}
- name="plugins" title={config.appName + " Plugins"}>
- <h1 tag="using-plugins">{_("help.title.Using Plugins")}</h1>
- <toc start="2"/>
-
- {body}
- </document>.toXMLString();
- });
+ DOM.toXML(
+ ["document", { xmlns: "dactyl", name: "plugins",
+ title: config.appName + ", Plugins" },
+ ["h1", { tag: "using-plugins" }, _("help.title.Using Plugins")],
+ ["toc", { start: "2" }],
- cache.register("help/index.xml", function () {
- default xml namespace = NS;
+ body]);
+ }, true);
+ cache.register("help/index.xml", function () {
return '<?xml version="1.0"?>\n' +
- <overlay xmlns={NS}>{
- template.map(dactyl.indices, function ([name, iter])
- <dl insertafter={name + "-index"}>{
- template.map(iter(), util.identity)
- }</dl>, <>{"\n\n"}</>)
- }</overlay>;
- });
+ DOM.toXML(["overlay", { xmlns: "dactyl" },
+ template.map(dactyl.indices, ([name, iter]) =>
+ ["dl", { insertafter: name + "-index" },
+ template.map(iter(), util.identity)],
+ "\n\n")]);
+ }, true);
cache.register("help/gui.xml", function () {
- default xml namespace = NS;
-
return '<?xml version="1.0"?>\n' +
- <overlay xmlns={NS}>
- <dl insertafter="dialog-list">{
- template.map(config.dialogs, function ([name, val])
- (!val[2] || val[2]())
- ? <><dt>{name}</dt><dd>{val[0]}</dd></>
- : undefined,
- <>{"\n"}</>)
- }</dl>
- </overlay>;
- });
+ DOM.toXML(["overlay", { xmlns: "dactyl" },
+ ["dl", { insertafter: "dialog-list" },
+ template.map(config.dialogs, ([name, val]) =>
+ (!val[2] || val[2]())
+ ? [["dt", {}, name],
+ ["dd", {}, val[0]]]
+ : undefined,
+ "\n")]]);
+ }, true);
cache.register("help/privacy.xml", function () {
- default xml namespace = NS;
-
return '<?xml version="1.0"?>\n' +
- <overlay xmlns={NS}>
- <dl insertafter="sanitize-items">{
- template.map(options.get("sanitizeitems").values
- .sort(function (a, b) String.localeCompare(a.name, b.name)),
- function ({ name, description })
- <><dt>{name}</dt><dd>{template.linkifyHelp(description, true)}</dd></>,
- <>{"\n"}</>)
- }</dl>
- </overlay>;
- });
+ DOM.toXML(["overlay", { xmlns: "dactyl" },
+ ["dl", { insertafter: "sanitize-items" },
+ template.map(options.get("sanitizeitems").values
+ .sort((a, b) => String.localeCompare(a.name,
+ b.name)),
+ ({ name, description }) =>
+ [["dt", {}, name],
+ ["dd", {}, template.linkifyHelp(description, true)]],
+ "\n")]]);
+ }, true);
},
- events: function () {
+ events: function initEvents() {
events.listen(window, dactyl, "events", true);
},
// Only general options are added here, which are valid for all Dactyl extensions
- options: function () {
+ options: function initOptions() {
options.add(["errorbells", "eb"],
"Ring the bell when an error message is displayed",
"boolean", false);
M: ["Always show messages outside of the status line"]
},
setter: function (opts) {
- if (loaded.commandline || ~opts.indexOf("c"))
+ if (loaded.has("commandline") || ~opts.indexOf("c"))
commandline.widgets.updateVisibility();
}
},
}, config.guioptions),
setter: function (opts) {
for (let [opt, [, ids]] in Iterator(this.opts)) {
- ids.map(function (id) document.getElementById(id))
+ ids.map(id => document.getElementById(id))
.forEach(function (elem) {
if (elem)
dactyl.setNodeVisible(elem, opts.indexOf(opt) >= 0);
},
setter: function (opts) {
let dir = ["horizontal", "vertical"].filter(
- function (dir) !Array.some(opts,
- function (o) this.opts[o] && this.opts[o][1] == dir, this),
- this);
- let class_ = dir.map(function (dir) "html|html > xul|scrollbar[orient=" + dir + "]");
+ dir => !Array.some(opts,
+ o => this.opts[o] && this.opts[o][1] == dir));
+ let class_ = dir.map(dir => "html|html > xul|scrollbar[orient=" + dir + "]");
styles.system.add("scrollbar", "*",
class_.length ? class_.join(", ") + " { visibility: collapse !important; }" : "",
styles.system.add("taboptions", "chrome://*",
classes.length ? classes.join(",") + "{ display: none; }" : "");
- if (!dactyl.has("Gecko2")) {
- tabs.tabBinding.enabled = Array.some(opts, function (k) k in this.opts, this);
- tabs.updateTabCount();
- }
if (config.tabbrowser.tabContainer._positionPinnedTabs)
config.tabbrowser.tabContainer._positionPinnedTabs();
},
Option.validIf(!/[nN]/.test(opts), "Tab numbering not available in this " + config.host + " version")
*/
}
- ].filter(function (group) !group.feature || dactyl.has(group.feature));
+ ].filter(group => !group.feature || dactyl.has(group.feature));
options.add(["guioptions", "go"],
"Show or hide certain GUI elements like the menu or toolbar",
"rb" + [k for ([k, v] in iter(groups[1].opts))
if (!Dactyl.toolbarHidden(document.getElementById(v[1][0])))].join(""),
- values: array(groups).map(function (g) [[k, v[0]] for ([k, v] in Iterator(g.opts))]).flatten(),
+ values: array(groups).map(g => [[k, v[0]] for ([k, v] in Iterator(g.opts))])
+ .flatten(),
setter: function (value) {
for (let group in values(groups))
events.checkFocus();
return value;
},
- validator: function (val) Option.validateCompleter.call(this, val) &&
- groups.every(function (g) !g.validator || g.validator(val))
+ validator: function (val) Option.validateCompleter.call(this, val)
+ && groups.every(g => !g.validator || g.validator(val))
});
- options.add(["helpfile", "hf"],
- "Name of the main help file",
- "string", "intro");
-
options.add(["loadplugins", "lpl"],
"A regexp list that defines which plugins are loaded at startup and via :loadplugins",
"regexplist", "'\\.(js|" + config.fileExtension + ")$'");
document.title = document.title.replace(RegExp("(.*)" + util.regexp.escape(old)), "$1" + current);
}
- if (services.has("privateBrowsing")) {
+ if (win.hasAttribute("titlemodifier_privatebrowsing")) {
let oldValue = win.getAttribute("titlemodifier_normal");
let suffix = win.getAttribute("titlemodifier_privatebrowsing").substr(oldValue.length);
win.setAttribute("titlemodifier_normal", value);
win.setAttribute("titlemodifier_privatebrowsing", value + suffix);
- if (services.privateBrowsing.privateBrowsingEnabled) {
+ if (storage.privateMode) {
updateTitle(oldValue + suffix, value + suffix);
+ win.setAttribute("titlemodifier", value + suffix);
return value;
}
}
options.add(["verbose", "vbs"],
"Define which info messages are displayed",
"number", 1,
- { validator: function (value) Option.validIf(value >= 0 && value <= 15, "Value must be between 0 and 15") });
+ { validator: function (value) Option.validIf(value >= 0 && value <= 15,
+ "Value must be between 0 and 15") });
options.add(["visualbell", "vb"],
"Use visual bell instead of beeping on errors",
});
},
- mappings: function () {
+ mappings: function initMappings() {
if (dactyl.has("session"))
mappings.add([modes.NORMAL], ["ZQ"],
"Quit and don't save the session",
function () { dactyl.quit(true); });
},
- commands: function () {
+ commands: function initCommands() {
commands.add(["dia[log]"],
"Open a " + config.appName + " dialog",
function (args) {
let arg = args[0] || "";
let items = dactyl.getMenuItems(arg);
- dactyl.assert(items.some(function (i) i.dactylPath == arg),
+ dactyl.assert(items.some(i => i.dactylPath == arg),
_("emenu.notFound", arg));
for (let [, item] in Iterator(items)) {
literal: 0
});
+ commands.add(["pr[ivate]", "pr0n", "porn"],
+ "Enable privacy features of a command, when applicable, and do not save the invocation in command history",
+ function (args) {
+ dactyl.withSavedValues(["forcePrivate"], function () {
+ this.forcePrivate = true;
+ dactyl.execute(args[0], null, true);
+ });
+ }, {
+ argCount: "1",
+ completer: function (context) completion.ex(context),
+ literal: 0,
+ privateData: "never-save",
+ subCommand: 0
+ });
+
commands.add(["exit", "x"],
"Quit " + config.appName,
function (args) {
"Reload the " + config.appName + " add-on",
function (args) {
if (args.trailing)
- storage.session.rehashCmd = args.trailing; // Hack.
+ storage.storeForSession("rehashCmd", args.trailing); // Hack.
args.break = true;
if (args["+purgecaches"])
cache.flush();
- util.rehash(args);
+ util.delay(() => { util.rehash(args) });
},
{
argCount: "0", // FIXME
};
toolbarCommand(["toolbars[how]", "tbs[how]"], "Show the named toolbar",
- function (toolbar) dactyl.setNodeVisible(toolbar, true),
- function ({ item }) Dactyl.toolbarHidden(item));
+ toolbar => dactyl.setNodeVisible(toolbar, true),
+ ({ item }) => Dactyl.toolbarHidden(item));
toolbarCommand(["toolbarh[ide]", "tbh[ide]"], "Hide the named toolbar",
- function (toolbar) dactyl.setNodeVisible(toolbar, false),
- function ({ item }) !Dactyl.toolbarHidden(item));
+ toolbar => dactyl.setNodeVisible(toolbar, false),
+ ({ item }) => !Dactyl.toolbarHidden(item));
toolbarCommand(["toolbart[oggle]", "tbt[oggle]"], "Toggle the named toolbar",
- function (toolbar) dactyl.setNodeVisible(toolbar, Dactyl.toolbarHidden(toolbar)));
+ toolbar => dactyl.setNodeVisible(toolbar, Dactyl.toolbarHidden(toolbar)));
}
commands.add(["time"],
args = args[0] || "";
if (args[0] == ":")
- var func = function () commands.execute(args, null, false);
+ var func = () => commands.execute(args, null, false);
else
func = dactyl.userFunc(args);
totalUnits = "msec";
commandline.commandOutput(
- <table>
- <tr highlight="Title" align="left">
- <th colspan="3">{_("title.Code execution summary")}</th>
- </tr>
- <tr><td>  {_("title.Executed")}:</td><td align="right"><span class="times-executed">{count}</span></td><td><!--L-->times</td></tr>
- <tr><td>  {_("title.Average time")}:</td><td align="right"><span class="time-average">{each.toFixed(2)}</span></td><td>{eachUnits}</td></tr>
- <tr><td>  {_("title.Total time")}:</td><td align="right"><span class="time-total">{total.toFixed(2)}</span></td><td>{totalUnits}</td></tr>
- </table>);
+ ["table", {}
+ ["tr", { highlight: "Title", align: "left" },
+ ["th", { colspan: "3" }, _("title.Code execution summary")]],
+ ["tr", {},
+ ["td", {}, _("title.Executed"), ":"],
+ ["td", { align: "right" },
+ ["span", { class: "times-executed" }, count]],
+ ["td", {}, /*L*/"times"]],
+ ["tr", {},
+ ["td", {}, _("title.Average time"), ":"],
+ ["td", { align: "right" },
+ ["span", { class: "time-average" }, each.toFixed(2)]],
+ ["td", {}, eachUnits]],
+ ["tr", {},
+ ["td", {}, _("title.Total time"), ":"],
+ ["td", { align: "right" },
+ ["span", { class: "time-total" }, total.toFixed(2)]],
+ ["td", {}, totalUnits]]]);
}
else {
let beforeTime = Date.now();
let date = config.buildDate;
date = date ? " (" + date + ")" : "";
- commandline.commandOutput(
- <div>{config.appName} {config.version}{date} running on: </div> +
- <div>{navigator.userAgent}</div>)
+ commandline.commandOutput([
+ ["div", {}, [config.appName, " ", config.version, date, " running on: "].join("")],
+ ["div", {}, [window.navigator.userAgent].join("")]
+ ]);
}
}, {
argCount: "0",
},
- completion: function () {
+ completion: function initCompletion() {
completion.dialog = function dialog(context) {
context.title = ["Dialog"];
- context.filters.push(function ({ item }) !item[2] || item[2]());
+ context.filters.push(({ item }) => !item[2] || item[2]());
context.completions = [[k, v[0], v[2]] for ([k, v] in Iterator(config.dialogs))];
};
description: function (item) item.getAttribute("label"),
highlight: function (item) item.disabled ? "Disabled" : ""
};
- context.generate = function () dactyl.menuItems;
+ context.generate = () => dactyl.menuItems;
};
var toolbox = document.getElementById("navigator-toolbox");
completion.window = function window(context) {
context.title = ["Window", "Title"];
- context.keys = { text: function (win) dactyl.windows.indexOf(win) + 1, description: function (win) win.document.title };
+ context.keys = { text: win => dactyl.windows.indexOf(win) + 1,
+ description: win => win.document.title };
context.completions = dactyl.windows;
};
},
- load: function () {
+ load: function initLoad() {
dactyl.triggerObserver("load");
dactyl.log(_("dactyl.modulesLoaded"), 3);
userContext.DOM = Class("DOM", DOM, { init: function DOM_(sel, ctxt) DOM(sel, ctxt || buffer.focusedFrame.document) });
userContext.$ = modules.userContext.DOM;
+ // Hack: disable disabling of Personas in private windows.
+ let root = document.documentElement;
+
+ if (PrivateBrowsingUtils && PrivateBrowsingUtils.isWindowPrivate(window)
+ && root._lightweightTheme
+ && root._lightweightTheme._lastScreenWidth == null) {
+
+ dactyl.withSavedValues.call(PrivateBrowsingUtils,
+ ["isWindowPrivate"], function () {
+ PrivateBrowsingUtils.isWindowPrivate = () => false;
+ Cu.import("resource://gre/modules/LightweightThemeConsumer.jsm", {})
+ .LightweightThemeConsumer.call(root._lightweightTheme, document);
+ });
+ }
+
+ if (config.has("default-theme") && "CustomizableUI" in window)
+ overlay.overlayWindow(window, {
+ append: [
+ ["window", { id: document.documentElement.id, "dactyl-australis": "true", xmlns: "xul" }]]
+ });
+
dactyl.timeout(function () {
try {
var args = config.prefs.get("commandline-args")
// dactyl.hideGUI();
if (dactyl.userEval("typeof document", null, "test.js") === "undefined")
- jsmodules.__proto__ = XPCSafeJSObjectWrapper(window);
+ jsmodules.__proto__ = window;
if (dactyl.commandLineOptions.preCommands)
dactyl.commandLineOptions.preCommands.forEach(function (cmd) {
if (dactyl.commandLineOptions.rcFile == "NONE" || dactyl.commandLineOptions.noPlugins)
options["loadplugins"] = [];
- if (options["loadplugins"])
+ if (options["loadplugins"].length)
dactyl.loadPlugins();
}
catch (e) {
}
});
-// vim: set fdm=marker sw=4 ts=4 et:
+// vim: set fdm=marker sw=4 sts=4 ts=8 et: