X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fcontent%2Fdactyl.js;fp=common%2Fcontent%2Fdactyl.js;h=dc9df88be5fd42c2adfc36014e01c939a3d56bb8;hb=9044153cb63835e39b9de8ec4ade237c03e3888a;hp=1a244ff641412240d89ec6c7c4726bdcd993529e;hpb=70740024f9c028c1fd63e1a1850ab062ff956054;p=dactyl.git diff --git a/common/content/dactyl.js b/common/content/dactyl.js index 1a244ff..dc9df88 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -4,7 +4,7 @@ // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. -"use strict"; +/* use strict */ /** @scope modules */ @@ -29,10 +29,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { this._observers = {}; util.addObserver(this); - this.commands["dactyl.help"] = function (event) { - let elem = event.originalTarget; - dactyl.help(elem.getAttribute("tag") || elem.textContent); - }; this.commands["dactyl.restart"] = function (event) { dactyl.restart(); }; @@ -40,7 +36,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { styles.registerSheet("resource://dactyl-skin/dactyl.css"); this.cleanups = []; - this.cleanups.push(util.overlayObject(window, { + this.cleanups.push(overlay.overlayObject(window, { focusAndSelectUrlBar: function focusAndSelectUrlBar() { switch (options.get("strictfocus").getKey(document.documentURIObject || util.newURI(document.documentURI), "moderate")) { case "laissez-faire": @@ -60,10 +56,16 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { delete window.dactyl; delete window.liberator; + // Prevents box ordering bugs after our stylesheet is removed. + styles.system.add("cleanup-sheet", config.styleableChrome, ); styles.unregisterSheet("resource://dactyl-skin/dactyl.css"); + DOM('#TabsToolbar tab', document).style.display; }, destroy: function () { + this.observe.unregister(); autocommands.trigger("LeavePre", {}); dactyl.triggerObserver("shutdown", null); util.dump("All dactyl modules destroyed\n"); @@ -97,9 +99,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { this.trapErrors("destroy", mod, reason); } - for (let mod in values(modules.ownPropertyValues.reverse())) - if (mod instanceof Class && "INIT" in mod && "cleanup" in mod.INIT) - this.trapErrors(mod.cleanup, mod, dactyl, modules, window, reason); + modules.moduleManager.initDependencies("cleanup"); for (let name in values(Object.getOwnPropertyNames(modules).reverse())) try { @@ -110,20 +110,14 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { } }, - /** @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"; - }), + signals: { + "io.source": function ioSource(context, file, modTime) { + if (context.INFO) + help.flush("help/plugins.xml", modTime); + } + }, + + profileName: deprecated("config.profileName", { get: function profileName() config.profileName }), /** * @property {Modes.Mode} The current main mode. @@ -134,29 +128,27 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { set: function mode(val) modes.main = val }), - get menuItems() { - function dispatch(node, name) { - let event = node.ownerDocument.createEvent("Events"); - event.initEvent(name, false, false); - node.dispatchEvent(event); - } - + getMenuItems: function getMenuItems(targetPath) { function addChildren(node, parent) { + DOM(node).createContents(); + if (~["menu", "menupopup"].indexOf(node.localName) && node.children.length) - dispatch(node, "popupshowing"); + DOM(node).popupshowing({ bubbles: false }); for (let [, item] in Iterator(node.childNodes)) { if (item.childNodes.length == 0 && item.localName == "menuitem" && !item.hidden && !/rdf:http:/.test(item.getAttribute("label"))) { // FIXME item.dactylPath = parent + item.getAttribute("label"); - items.push(item); + if (!targetPath || targetPath.indexOf(item.dactylPath) == 0) + items.push(item); } else { let path = parent; if (item.localName == "menu") path += item.getAttribute("label") + "."; - addChildren(item, path); + if (!targetPath || targetPath.indexOf(path) == 0) + addChildren(item, path); } } } @@ -166,14 +158,24 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { return items; }, + get menuItems() this.getMenuItems(), + // Global constants CURRENT_TAB: "here", NEW_TAB: "tab", NEW_BACKGROUND_TAB: "background-tab", NEW_WINDOW: "window", - forceNewTab: false, - forceNewWindow: false, + forceBackground: null, + forceTarget: null, + + get forceOpen() ({ background: this.forceBackground, + target: this.forceTarget }), + set forceOpen(val) { + for (let [k, v] in Iterator({ background: "forceBackground", target: "forceTarget" })) + if (k in val) + this[v] = val[k]; + }, version: deprecated("config.version", { get: function version() config.version }), @@ -202,7 +204,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { registerObserver: function registerObserver(type, callback, weak) { if (!(type in this._observers)) this._observers[type] = []; - this._observers[type].push(weak ? Cu.getWeakReference(callback) : { get: function () callback }); + this._observers[type].push(weak ? util.weakReference(callback) : { get: function () callback }); }, registerObservers: function registerObservers(obj, prop) { @@ -215,7 +217,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { this._observers[type] = this._observers[type].filter(function (c) c.get() != callback); }, - // TODO: "zoom": if the zoom value of the current buffer changed applyTriggerObserver: function triggerObserver(type, args) { if (type in this._observers) this._observers[type] = this._observers[type].filter(function (callback) { @@ -249,7 +250,8 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { let results = array(params.iterate(args)) .sort(function (a, b) String.localeCompare(a.name, b.name)); - let filters = args.map(function (arg) util.regexp("\\b" + util.regexp.escape(arg) + "\\b", "i")); + let filters = args.map(function (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))); @@ -261,10 +263,11 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { completer: function (context, args) { context.keys.text = util.identity; context.keys.description = function () seen[this.text] + /*L*/" matching items"; + context.ignoreCase = true; let seen = {}; context.completions = array(keys(item).join(" ").toLowerCase().split(/[()\s]+/) for (item in params.iterate(args))) - .flatten().filter(function (w) /^\w[\w-_']+$/.test(w)) + .flatten() .map(function (k) { seen[k] = (seen[k] || 0) + 1; return k; @@ -278,10 +281,10 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { let results = array((params.iterateIndex || params.iterate).call(params, commands.get(name).newArgs())) .array.sort(function (a, b) String.localeCompare(a.name, b.name)); - let tags = services["dactyl:"].HELP_TAGS; + let haveTag = Set.has(help.tags); for (let obj in values(results)) { let res = dactyl.generateHelp(obj, null, null, true); - if (!Set.has(tags, obj.helpTag)) + if (!haveTag(obj.helpTag)) res[1].@tag = obj.helpTag; yield res; @@ -303,7 +306,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { }; XML.ignoreWhitespace = true; if (!elems.bell) - util.overlayWindow(window, { + overlay.overlayWindow(window, { objects: elems, prepend: <> @@ -335,16 +338,20 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { * This is same as Firefox's readFromClipboard function, but is needed for * apps like Thunderbird which do not provide it. * + * @param {string} which Which clipboard to write to. Either + * "global" or "selection". If not provided, both clipboards are + * updated. + * @optional * @returns {string} */ - clipboardRead: function clipboardRead(getClipboard) { + clipboardRead: function clipboardRead(which) { try { - const clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard); - const transferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable); + const { clipboard } = services; + let transferable = services.Transferable(); transferable.addDataFlavor("text/unicode"); - let source = clipboard[getClipboard || !clipboard.supportsSelectionClipboard() ? + let source = clipboard[which == "global" || !clipboard.supportsSelectionClipboard() ? "kGlobalClipboard" : "kSelectionClipboard"]; clipboard.getData(transferable, source); @@ -363,12 +370,19 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { * Copies a string to the system clipboard. If *verbose* is specified the * copied string is also echoed to the command line. * - * @param {string} str - * @param {boolean} verbose + * @param {string} str The string to write. + * @param {boolean} verbose If true, the user is notified of the copied data. + * @param {string} which Which clipboard to write to. Either + * "global" or "selection". If not provided, both clipboards are + * updated. + * @optional */ - clipboardWrite: function clipboardWrite(str, verbose) { - const clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); - clipboardHelper.copyString(str); + clipboardWrite: function clipboardWrite(str, verbose, which) { + if (which == null || which == "selection" && !services.clipboard.supportsSelectionClipboard()) + services.clipboardHelper.copyString(str); + else + services.clipboardHelper.copyStringToClipboard(str, + services.clipboard["k" + util.capitalize(which) + "Clipboard"]); if (verbose) { let message = { message: _("dactyl.yank", str) }; @@ -406,8 +420,10 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { echoerr: function echoerr(str, flags) { flags |= commandline.APPEND_TO_MESSAGES; - if (isinstance(str, ["DOMException", "Error", "Exception"]) || isinstance(str, ["XPCWrappedNative_NoHelper"]) && /^\[Exception/.test(str)) + if (isinstance(str, ["DOMException", "Error", "Exception", ErrorBase]) + || isinstance(str, ["XPCWrappedNative_NoHelper"]) && /^\[Exception/.test(str)) dactyl.reportError(str); + if (isObject(str) && "echoerr" in str) str = str.echoerr; else if (isinstance(str, ["Error", FailedAssertion]) && str.fileName) @@ -465,43 +481,50 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { userEval: function (str, context, fileName, lineNumber) { let ctxt; - if (jsmodules.__proto__ != window) + if (jsmodules.__proto__ != window && jsmodules.__proto__ != XPCNativeWrapper(window) && + jsmodules.isPrototypeOf(context)) str = "with (window) { with (modules) { (this.eval || eval)(" + str.quote() + ") } }"; let info = contexts.context; if (fileName == null) - if (info && info.file[0] !== "[") + if (info) ({ file: fileName, line: lineNumber, context: ctxt }) = info; - if (!context && fileName && fileName[0] !== "[") + 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); - else - try { - if (!context) - context = userContext || ctxt; - - context[EVAL_ERROR] = null; - context[EVAL_STRING] = str; - context[EVAL_RESULT] = null; - this.loadScript("resource://dactyl-content/eval.js", context); - if (context[EVAL_ERROR]) { - try { - context[EVAL_ERROR].fileName = info.file; - context[EVAL_ERROR].lineNumber += info.line; - } - catch (e) {} - throw context[EVAL_ERROR]; + + if (!context) + context = userContext || ctxt; + + if (services.has("dactyl") && services.dactyl.evalInContext) + return services.dactyl.evalInContext(str, context, fileName, lineNumber); + + try { + context[EVAL_ERROR] = null; + context[EVAL_STRING] = str; + context[EVAL_RESULT] = null; + + this.loadScript("resource://dactyl-content/eval.js", context); + if (context[EVAL_ERROR]) { + try { + context[EVAL_ERROR].fileName = info.file; + context[EVAL_ERROR].lineNumber += info.line; } - return context[EVAL_RESULT]; - } - finally { - delete context[EVAL_ERROR]; - delete context[EVAL_RESULT]; - delete context[EVAL_STRING]; + catch (e) {} + throw context[EVAL_ERROR]; } + return context[EVAL_RESULT]; + } + finally { + delete context[EVAL_ERROR]; + delete context[EVAL_RESULT]; + delete context[EVAL_STRING]; + } }, /** @@ -543,19 +566,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { }, focus: function focus(elem, flags) { - flags = flags || services.focus.FLAG_BYMOUSE; - try { - if (elem instanceof Document) - elem = elem.defaultView; - if (elem instanceof Element) - services.focus.setFocus(elem, flags); - else if (elem instanceof Window) - services.focus.focusedWindow = elem; - } - catch (e) { - util.dump(elem); - util.reportError(e); - } + DOM(elem).focus(flags); }, /** @@ -621,33 +632,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { */ has: function (feature) Set.has(config.features, feature), - /** - * Returns the URL of the specified help *topic* if it exists. - * - * @param {string} topic The help topic to look up. - * @param {boolean} consolidated Whether to search the consolidated help page. - * @returns {string} - */ - findHelp: function (topic, consolidated) { - if (!consolidated && topic in services["dactyl:"].FILE_MAP) - return topic; - let items = completion._runCompleter("help", topic, null, !!consolidated).items; - let partialMatch = null; - - function format(item) item.description + "#" + encodeURIComponent(item.text); - - for (let [i, item] in Iterator(items)) { - if (item.text == topic) - return format(item); - else if (!partialMatch && topic) - partialMatch = item; - } - - if (partialMatch) - return format(partialMatch); - return null; - }, - /** * @private */ @@ -663,243 +647,18 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { } }, + help: deprecated("help.help", { get: function help() modules.help.closure.help }), + findHelp: deprecated("help.findHelp", { get: function findHelp() help.closure.findHelp }), + /** * @private * Initialize the help system. */ - initHelp: function (force) { - // Waits for the add-on to become available, if necessary. - config.addon; - config.version; - - if (force || !this.helpInitialized) { - if ("noscriptOverlay" in window) { - noscriptOverlay.safeAllow("chrome-data:", true, false); - noscriptOverlay.safeAllow("dactyl:", true, false); - } - - // Find help and overlay files with the given name. - let findHelpFile = function findHelpFile(file) { - let result = []; - for (let [, namespace] in Iterator(namespaces)) { - let url = ["dactyl://", namespace, "/", file, ".xml"].join(""); - let res = util.httpGet(url); - if (res) { - if (res.responseXML.documentElement.localName == "document") - fileMap[file] = url; - if (res.responseXML.documentElement.localName == "overlay") - overlayMap[file] = url; - result.push(res.responseXML); - } - } - return result; - }; - // Find the tags in the document. - let addTags = function addTags(file, doc) { - for (let elem in util.evaluateXPath("//@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"]; - services["dactyl:"].init({}); - - let tagMap = services["dactyl:"].HELP_TAGS; - let fileMap = services["dactyl:"].FILE_MAP; - let overlayMap = services["dactyl:"].OVERLAY_MAP; - - // Scrape the list of help files from all.xml - // Manually process main and overlay files, since XSLTProcessor and - // XMLHttpRequest don't allow access to chrome documents. - tagMap["all"] = tagMap["all.xml"] = "all"; - tagMap["versions"] = tagMap["versions.xml"] = "versions"; - let files = findHelpFile("all").map(function (doc) - [f.value for (f in util.evaluateXPath("//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 +=

{info.@summary}

+ - info; - } - } - catch (e) { - util.reportError(e); - } + initHelp: function initHelp() { + if ("noscriptOverlay" in window) + noscriptOverlay.safeAllow("dactyl:", true, false); - let help = - '\n' + - '\n' + - '\n' + - -

{_("help.title.Using Plugins")}

- - - {body} -
.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( \s* # .*\n) - - | ^ (?P \s*) - (?P [-•*+]) \ // - (?P .*\n - (?: \2\ \ .*\n | \s*\n)* ) - - | (?P - (?: ^ [^\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 =
    ; - let 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 +=

    {template.linkifyHelp(text, true)}

    ; - } - else { - let [, a, b] = /^(IMPORTANT:?)?([^]*)/.exec(par); - res +=

    { - !tags.length ? "" : - {tags.join(" ")} - }{ - a ? {a} : "" - }{ - template.linkifyHelp(b, true) - }

    ; - } - } - i++; - } - for each (let attr in res..@highlight) { - attr.parent().@NS::highlight = attr; - delete attr.parent().@highlight; - } - return res; - } - - XML.ignoreWhitespace = XML.prettyPrinting = false; - let body = rec(NEWS, 0); - for each (let li in body..li) { - let list = li..li.(@NS::highlight == "HelpNewsOld"); - if (list.length() && list.length() == li..li.(@NS::highlight != "").length()) { - for each (let li in list) - li.@NS::highlight = ""; - li.@NS::highlight = "HelpNewsOld"; - } - } - - return ["application/xml", - '\n' + - '\n' + - '\n' + - -

    {config.appName} Versions

    - - - {body} -
    .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', - '\n' + - { - template.map(dactyl.indices, function ([name, iter]) -
    { - template.map(iter(), util.identity) - }
    , <>{"\n\n"}) - }
    ]; - addTags("index", util.httpGet("dactyl://help-overlay/index").responseXML); - - overlayMap["gui"] = ['text/xml;charset=UTF-8', - '\n' + - -
    { - template.map(config.dialogs, function ([name, val]) - (!val[2] || val[2]()) - ? <>
    {name}
    {val[0]}
    - : undefined, - <>{"\n"}) - }
    -
    ]; - - - this.helpInitialized = true; - } + help.initialize(); }, stringifyXML: function (xml) { @@ -908,120 +667,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { return UTF8(xml.toXMLString()); }, - exportHelp: JavaScript.setCompleter(function (path) { - const FILE = io.File(path); - const PATH = FILE.leafName.replace(/\..*/, "") + "/"; - const TIME = Date.now(); - - if (!FILE.exists() && (/\/$/.test(path) && !/\./.test(FILE.leafName))) - FILE.create(FILE.DIRECTORY_TYPE, octal(755)); - - dactyl.initHelp(); - if (FILE.isDirectory()) { - var addDataEntry = function addDataEntry(file, data) FILE.child(file).write(data); - var addURIEntry = function addURIEntry(file, uri) addDataEntry(file, util.httpGet(uri).responseText); - } - else { - var zip = services.ZipWriter(); - zip.open(FILE, File.MODE_CREATE | File.MODE_WRONLY | File.MODE_TRUNCATE); - - addURIEntry = function addURIEntry(file, uri) - zip.addEntryChannel(PATH + file, TIME, 9, - services.io.newChannel(uri, null, null), false); - addDataEntry = function addDataEntry(file, data) // Unideal to an extreme. - addURIEntry(file, "data:text/plain;charset=UTF-8," + encodeURI(data)); - } - - let empty = Set("area base basefont br col frame hr img input isindex link meta param" - .split(" ")); - function fix(node) { - switch(node.nodeType) { - case Node.ELEMENT_NODE: - if (isinstance(node, [HTMLBaseElement])) - return; - - data.push("<"); data.push(node.localName); - if (node instanceof HTMLHtmlElement) - data.push(" xmlns=" + XHTML.uri.quote(), - " xmlns:dactyl=" + NS.uri.quote()); - - for (let { name, value } in array.iterValues(node.attributes)) { - if (name == "dactyl:highlight") { - Set.add(styles, value); - name = "class"; - value = "hl-" + value; - } - if (name == "href") { - value = node.href || value; - if (value.indexOf("dactyl://help-tag/") == 0) { - let uri = services.io.newChannel(value, null, null).originalURI; - value = uri.spec == value ? "javascript:;" : uri.path.substr(1); - } - if (!/^#|[\/](#|$)|^[a-z]+:/.test(value)) - value = value.replace(/(#|$)/, ".xhtml$1"); - } - if (name == "src" && value.indexOf(":") > 0) { - chromeFiles[value] = value.replace(/.*\//, ""); - value = value.replace(/.*\//, ""); - } - - data.push(" ", name, '="', - <>{value}.toXMLString().replace(/"/g, """), - '"'); - } - if (node.localName in empty) - data.push(" />"); - else { - data.push(">"); - if (node instanceof HTMLHeadElement) - data.push(.toXMLString()); - Array.map(node.childNodes, fix); - data.push(""); - } - break; - case Node.TEXT_NODE: - data.push(<>{node.textContent}.toXMLString()); - } - } - - let chromeFiles = {}; - let styles = {}; - for (let [file, ] in Iterator(services["dactyl:"].FILE_MAP)) { - let url = "dactyl://help/" + file; - dactyl.open(url); - util.waitFor(function () content.location.href == url && buffer.loaded - && content.document.documentElement instanceof HTMLHtmlElement, - 15000); - events.waitForPageLoad(); - var data = [ - '\n', - '\n' - ]; - fix(content.document.documentElement); - addDataEntry(file + ".xhtml", data.join("")); - } - - let data = [h for (h in highlight) if (Set.has(styles, h.class) || /^Help/.test(h.class))] - .map(function (h) h.selector - .replace(/^\[.*?=(.*?)\]/, ".hl-$1") - .replace(/html\|/g, "") + "\t" + "{" + h.cssText + "}") - .join("\n"); - addDataEntry("help.css", data.replace(/chrome:[^ ")]+\//g, "")); - - addDataEntry("tag-map.json", JSON.stringify(services["dactyl:"].HELP_TAGS)); - - let m, re = /(chrome:[^ ");]+\/)([^ ");]+)/g; - while ((m = re.exec(data))) - chromeFiles[m[0]] = m[2]; - - for (let [uri, leaf] in Iterator(chromeFiles)) - addURIEntry(leaf, uri); - - if (zip) - zip.close(); - }, [function (context, args) completion.file(context)]), - /** * Generates a help entry and returns it as a string. * @@ -1040,6 +685,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { if (obj instanceof Command) { link = function (cmd) {cmd}; args = obj.parseArgs("", CompletionContext(str || "")); + tag = function (cmd) <>:{cmd}; spec = function (cmd) <>{ obj.count ? count : <> }{ @@ -1050,6 +696,9 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { } else if (obj instanceof Map) { spec = function (map) obj.count ? <>count{map} : <>{map}; + tag = function (map) <>{ + let (c = obj.modes[0].char) c ? c + "_" : "" + }{ map }; link = function (map) { let [, mode, name, extra] = /^(?:(.)_)?(?:<([^>]+)>)?(.*)$/.exec(map); let k = {extra}; @@ -1061,7 +710,8 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { }; } else if (obj instanceof Option) { - tag = spec = function (name) <>'{name}'; + spec = function () template.map(obj.names, tag, " "); + tag = function (name) <>'{name}'; link = function (opt, name) {name}; args = { value: "", values: [] }; } @@ -1075,7 +725,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { ; let res = -
    {link(obj.helpTag || obj.name, obj.name)}
    { +
    {link(obj.helpTag || tag(obj.name), obj.name)}
    { template.linkifyHelp(obj.description ? obj.description.replace(/\.$/, "") : "", true) }
    ; if (specOnly) @@ -1084,10 +734,11 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { res.* += <> {template.map(obj.names.slice().reverse(), tag, " ")} - { - spec(template.highlightRegexp((obj.specs || obj.names)[0], - /\[(.*?)\]/g, - function (m, n0) {n0})) + {let (name = (obj.specs || obj.names)[0]) + spec(template.highlightRegexp(tag(name), + /\[(.*?)\]/g, + function (m, n0) {n0}), + name) }{ !obj.type ? "" : <> {obj.type} @@ -1128,30 +779,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { .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. * @@ -1173,7 +800,9 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { loadplugins = { __proto__: loadplugins, value: args.map(Option.parseRegexp) }; dir.readDirectory(true).forEach(function (file) { - if (file.isFile() && loadplugins.getKey(file.path) + if (file.leafName[0] == ".") + ; + else if (file.isFile() && loadplugins.getKey(file.path) && !(!force && file.path in dactyl.pluginFiles && dactyl.pluginFiles[file.path] >= file.lastModifiedTime)) { try { io.source(file.path); @@ -1218,7 +847,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { * @param {number} level The logging level 0 - 15. */ log: function (msg, level) { - let verbose = localPrefs.get("loglevel", 0); + let verbose = config.prefs.get("loglevel", 0); if (!level || level <= verbose) { if (isObject(msg) && !isinstance(msg, _)) @@ -1228,35 +857,41 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { } }, - onClick: function onClick(event) { - if (event.originalTarget instanceof Element) { - let command = event.originalTarget.getAttributeNS(NS, "command"); - if (command && event.button == 0) { - event.preventDefault(); + events: { + click: function onClick(event) { + let elem = event.originalTarget; - if (dactyl.commands[command]) - dactyl.withSavedValues(["forceNewTab"], function () { - dactyl.forceNewTab = event.ctrlKey || event.shiftKey || event.button == 1; - dactyl.commands[command](event); - }); + if (elem instanceof Element && services.security.isSystemPrincipal(elem.nodePrincipal)) { + let command = elem.getAttributeNS(NS, "command"); + if (command && event.button == 0) { + event.preventDefault(); + + if (dactyl.commands[command]) + dactyl.withSavedValues(["forceTarget"], function () { + if (event.ctrlKey || event.shiftKey || event.button == 1) + dactyl.forceTarget = dactyl.NEW_TAB; + dactyl.commands[command](event); + }); + } } - } - }, + }, - onExecute: function onExecute(event) { - let cmd = event.originalTarget.getAttribute("dactyl-execute"); - commands.execute(cmd, null, false, null, - { file: /*L*/"[Command Line]", line: 1 }); + "dactyl.execute": function onExecute(event) { + let cmd = event.originalTarget.getAttribute("dactyl-execute"); + commands.execute(cmd, null, false, null, + { file: /*L*/"[Command Line]", line: 1 }); + } }, /** * Opens one or more URLs. Returns true when load was initiated, or * false on error. * - * @param {string|Array} urls A representation of the URLs to open. May be + * @param {string|object|Array} urls A representation of the URLs to open. May be * either a string, which will be passed to - * {@see Dactyl#parseURLs}, or an array in the same format as - * would be returned by the same. + * {@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 {object} params A set of parameters specifying how to open the * URLs. The following properties are recognized: * @@ -1297,8 +932,9 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { flags |= params[opt] && Ci.nsIWebNavigation["LOAD_FLAGS_" + flag]; let where = params.where || dactyl.CURRENT_TAB; - let background = ("background" in params) ? params.background - : params.where == dactyl.NEW_BACKGROUND_TAB; + let background = dactyl.forceBackground != null ? dactyl.forceBackground : + ("background" in params) ? params.background + : params.where == dactyl.NEW_BACKGROUND_TAB; if (params.from && dactyl.has("tabs")) { if (!params.where && options.get("newtab").has(params.from)) @@ -1310,21 +946,23 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { return; let browser = config.tabbrowser; - function open(urls, where) { + function open(loc, where) { try { - let url = Array.concat(urls)[0]; - let postdata = Array.concat(urls)[1]; + if (isArray(loc)) + loc = { url: loc[0], postData: loc[1] }; + else if (isString(loc)) + loc = { url: loc }; // decide where to load the first url switch (where) { case dactyl.NEW_TAB: if (!dactyl.has("tabs")) - return open(urls, dactyl.NEW_WINDOW); + return open(loc, dactyl.NEW_WINDOW); return prefs.withContext(function () { prefs.set("browser.tabs.loadInBackground", true); - return browser.loadOneTab(url, null, null, postdata, background).linkedBrowser.contentDocument; + return browser.loadOneTab(loc.url, null, null, loc.postData, background).linkedBrowser.contentDocument; }); case dactyl.NEW_WINDOW: @@ -1333,7 +971,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { browser = win.dactyl && win.dactyl.modules.config.tabbrowser || win.getBrowser(); // FALLTHROUGH case dactyl.CURRENT_TAB: - browser.loadURIWithFlags(url, flags, null, null, postdata); + browser.loadURIWithFlags(loc.url, flags, null, null, loc.postData); return browser.contentWindow; } } @@ -1343,10 +981,8 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { // any genuine errors go unreported. } - if (dactyl.forceNewTab) - where = dactyl.NEW_TAB; - else if (dactyl.forceNewWindow) - where = dactyl.NEW_WINDOW; + if (dactyl.forceTarget) + where = dactyl.forceTarget; else if (!where) where = dactyl.CURRENT_TAB; @@ -1378,7 +1014,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { return urls.map(function (url) { url = url.trim(); - if (/^(\.{0,2}|~)(\/|$)/.test(url) || util.OS.isWindows && /^[a-z]:/i.test(url)) { + if (/^(\.{0,2}|~)(\/|$)/.test(url) || config.OS.isWindows && /^[a-z]:/i.test(url)) { try { // Try to find a matching file. let file = io.File(url); @@ -1390,7 +1026,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { // If it starts with a valid protocol, pass it through. let proto = /^([-\w]+):/.exec(url); - if (proto && "@mozilla.org/network/protocol;1?name=" + proto[1] in Cc) + if (proto && services.PROTOCOL + proto[1] in Cc) return url; // Check for a matching search keyword. @@ -1408,7 +1044,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { }, this); }, stringToURLArray: deprecated("dactyl.parseURLs", "parseURLs"), - urlish: Class.memoize(function () util.regexp(+ (:\d+)? (/ .*) | + (:\d+) | @@ -1470,10 +1106,12 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { /** * Restart the host application. */ - restart: function () { + restart: function (args) { if (!this.confirmQuit()) return; + config.prefs.set("commandline-args", args); + services.appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart); }, @@ -1492,7 +1130,12 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { return func.apply(self || this, Array.slice(arguments, 2)); } catch (e) { - dactyl.reportError(e, true); + try { + dactyl.reportError(e, true); + } + catch (e) { + util.reportError(e); + } return e; } }, @@ -1507,7 +1150,8 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { 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.indexOf(prefix) !== 0 && + prefix != "[Command Line]:1: ") error.message = prefix + error.message; if (error.message) @@ -1519,8 +1163,10 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { util.reportError(error); return; } + if (error.result == Cr.NS_BINDING_ABORTED) return; + if (echo) dactyl.echoerr(error, commandline.FORCE_SINGLELINE); else @@ -1545,10 +1191,9 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { return []; } }, - wrapCallback: function (callback, self) { self = self || this; - let save = ["forceNewTab", "forceNewWindow"]; + let save = ["forceOpen"]; let saved = save.map(function (p) dactyl[p]); return function wrappedCallback() { let args = arguments; @@ -1573,9 +1218,90 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { }, { toolbarHidden: function hidden(elem) (elem.getAttribute("autohide") || elem.getAttribute("collapsed")) == "true" }, { + cache: function () { + cache.register("help/plugins.xml", function () { + // 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 (let attr in values(["@name", "@summary", "@href"])) + if (elem[attr].length()) + info[attr] = elem[attr]; + } + body +=

    {info.@summary}

    + + info; + } + } + catch (e) { + util.reportError(e); + } + + return '\n' + + '\n' + + '\n' + + +

    {_("help.title.Using Plugins")}

    + + + {body} +
    .toXMLString(); + }); + + cache.register("help/index.xml", function () { + default xml namespace = NS; + + return '\n' + + { + template.map(dactyl.indices, function ([name, iter]) +
    { + template.map(iter(), util.identity) + }
    , <>{"\n\n"}) + }
    ; + }); + + cache.register("help/gui.xml", function () { + default xml namespace = NS; + + return '\n' + + +
    { + template.map(config.dialogs, function ([name, val]) + (!val[2] || val[2]()) + ? <>
    {name}
    {val[0]}
    + : undefined, + <>{"\n"}) + }
    +
    ; + }); + + cache.register("help/privacy.xml", function () { + default xml namespace = NS; + + return '\n' + + +
    { + template.map(options.get("sanitizeitems").values + .sort(function (a, b) String.localeCompare(a.name, b.name)), + function ({ name, description }) + <>
    {name}
    {template.linkifyHelp(description, true)}
    , + <>{"\n"}) + }
    +
    ; + }); + }, events: function () { - events.listen(window, "click", dactyl.closure.onClick, true); - events.listen(window, "dactyl.execute", dactyl.closure.onExecute, true); + events.listen(window, dactyl, "events", true); }, // Only general options are added here, which are valid for all Dactyl extensions options: function () { @@ -1671,12 +1397,12 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { options.add(["guioptions", "go"], "Show or hide certain GUI elements like the menu or toolbar", - "charlist", config.defaults.guioptions || "", { + "charlist", "", { // FIXME: cleanup cleanupValue: config.cleanups.guioptions || - "r" + [k for ([k, v] in iter(groups[1].opts)) - if (!Dactyl.toolbarHidden(document.getElementById(v[1][0])))].join(""), + "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(), @@ -1700,12 +1426,15 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { options.add(["titlestring"], "The string shown at the end of the window title", - "string", config.defaults.titlestring || config.host, + "string", config.host, { setter: function (value) { let win = document.documentElement; function updateTitle(old, current) { - document.title = document.title.replace(RegExp("(.*)" + util.regexp.escape(old)), "$1" + current); + if (config.browser.updateTitlebar) + config.browser.updateTitlebar(); + else + document.title = document.title.replace(RegExp("(.*)" + util.regexp.escape(old)), "$1" + current); } if (services.has("privateBrowsing")) { @@ -1744,21 +1473,13 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { { setter: function (value) { prefs.safeSet("accessibility.typeaheadfind.enablesound", !value, - _("option.visualbell.safeSet")); + _("option.safeSet", "visualbell")); return value; } }); }, mappings: function () { - mappings.add([modes.MAIN], ["", ""], - "Open the introductory help page", - function () { dactyl.help(); }); - - mappings.add([modes.MAIN], ["", ""], - "Open the single, consolidated help page", - function () { ex.helpall(); }); - if (dactyl.has("session")) mappings.add([modes.NORMAL], ["ZQ"], "Quit and don't save the session", @@ -1797,7 +1518,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { "Execute the specified menu item from the command line", function (args) { let arg = args[0] || ""; - let items = dactyl.menuItems; + let items = dactyl.getMenuItems(arg); dactyl.assert(items.some(function (i) i.dactylPath == arg), _("emenu.notFound", arg)); @@ -1829,30 +1550,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { literal: 0 }); - [ - { - name: "h[elp]", - description: "Open the introductory help page" - }, { - name: "helpa[ll]", - description: "Open the single consolidated help page" - } - ].forEach(function (command) { - let consolidated = command.name == "helpa[ll]"; - - commands.add([command.name], - command.description, - function (args) { - dactyl.assert(!args.bang, _("help.dontPanic")); - dactyl.help(args.literalArg, consolidated); - }, { - argCount: "?", - bang: true, - completer: function (context) completion.help(context, consolidated), - literal: 0 - }); - }); - commands.add(["loadplugins", "lpl"], "Load all or matching plugins", function (args) { @@ -1903,47 +1600,66 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { bang: true }); + let startupOptions = [ + { + names: ["+u"], + description: "The initialization file to execute at startup", + type: CommandOption.STRING + }, + { + names: ["++noplugin"], + description: "Do not automatically load plugins" + }, + { + names: ["++cmd"], + description: "Ex commands to execute prior to initialization", + type: CommandOption.STRING, + multiple: true + }, + { + names: ["+c"], + description: "Ex commands to execute after initialization", + type: CommandOption.STRING, + multiple: true + }, + { + names: ["+purgecaches"], + description: "Purge " + config.appName + " caches at startup", + type: CommandOption.NOARG + } + ]; + commands.add(["reh[ash]"], "Reload the " + config.appName + " add-on", function (args) { if (args.trailing) storage.session.rehashCmd = args.trailing; // Hack. args.break = true; + + if (args["+purgecaches"]) + cache.flush(); + util.rehash(args); }, { argCount: "0", // FIXME - options: [ - { - names: ["+u"], - description: "The initialization file to execute at startup", - type: CommandOption.STRING - }, - { - names: ["++noplugin"], - description: "Do not automatically load plugins" - }, - { - names: ["++cmd"], - description: "Ex commands to execute prior to initialization", - type: CommandOption.STRING, - multiple: true - }, - { - names: ["+c"], - description: "Ex commands to execute after initialization", - type: CommandOption.STRING, - multiple: true - } - ] + options: startupOptions }); commands.add(["res[tart]"], - "Force " + config.appName + " to restart", - function () { dactyl.restart(); }, - { argCount: "0" }); + "Force " + config.host + " to restart", + function (args) { + if (args["+purgecaches"]) + cache.flush(); - function findToolbar(name) util.evaluateXPath( + dactyl.restart(args.string); + }, + { + argCount: "0", + options: startupOptions + }); + + function findToolbar(name) DOM.XPath( "//*[@toolbarname=" + util.escapeString(name, "'") + " or " + "@toolbarname=" + util.escapeString(name.trim(), "'") + "]", document).snapshotItem(0); @@ -2092,10 +1808,14 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { function (args) { if (args.bang) dactyl.open("about:"); - else - commandline.commandOutput(<> - {config.appName} {config.version} running on:
    {navigator.userAgent} - ); + else { + let date = config.buildDate; + date = date ? " (" + date + ")" : ""; + + commandline.commandOutput( +
    {config.appName} {config.version}{date} running on:
    + +
    {navigator.userAgent}
    ) + } }, { argCount: "0", bang: true @@ -2110,15 +1830,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { context.completions = [[k, v[0], v[2]] for ([k, v] in Iterator(config.dialogs))]; }; - completion.help = function help(context, consolidated) { - dactyl.initHelp(); - context.title = ["Help"]; - context.anchored = false; - context.completions = services["dactyl:"].HELP_TAGS; - if (consolidated) - context.keys = { text: 0, description: function () "all" }; - }; - completion.menuItem = function menuItem(context) { context.title = ["Menu Path", "Label"]; context.anchored = false; @@ -2134,7 +1845,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { completion.toolbar = function toolbar(context) { context.title = ["Toolbar"]; context.keys = { text: function (item) item.getAttribute("toolbarname"), description: function () "" }; - context.completions = util.evaluateXPath("//*[@toolbarname]", document); + context.completions = DOM.XPath("//*[@toolbarname]", document); }; completion.window = function window(context) { @@ -2148,9 +1859,17 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { 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; + dactyl.timeout(function () { try { - var args = storage.session.commandlineArgs || services.commandLineHandler.optionValue; + var args = config.prefs.get("commandline-args") + || storage.session.commandlineArgs + || services.commandLineHandler.optionValue; + + config.prefs.reset("commandline-args"); + if (isString(args)) args = dactyl.parseCommandLine(args); @@ -2168,17 +1887,14 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { dactyl.log(_("dactyl.commandlineOpts", util.objectToString(dactyl.commandLineOptions)), 3); - // first time intro message - const firstTime = "extensions." + config.name + ".firsttime"; - if (prefs.get(firstTime, true)) { + if (config.prefs.get("first-run", true)) dactyl.timeout(function () { - this.withSavedValues(["forceNewTab"], function () { - this.forceNewTab = true; - this.help(); - prefs.set(firstTime, false); + config.prefs.set("first-run", false); + this.withSavedValues(["forceTarget"], function () { + this.forceTarget = dactyl.NEW_TAB; + help.help(); }); }, 1000); - } // TODO: we should have some class where all this guioptions stuff fits well // dactyl.hideGUI();