diff --git a/content/buffer.js b/content/buffer.js index e15ebd8a..428420ce 100644 --- a/content/buffer.js +++ b/content/buffer.js @@ -26,22 +26,121 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + liberator.Buffer = function () //{{{ { //////////////////////////////////////////////////////////////////////////////// ////////////////////// PRIVATE SECTION ///////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ - function arrayIter(ary) - { - let length = ary.length; - for (let i = 0; i < length; i++) - yield ary[i]; - } + const arrayIter = liberator.util.arrayIter; var zoomLevels = [ 1, 10, 25, 50, 75, 90, 100, 120, 150, 200, 300, 500, 1000, 2000 ]; + function Styles(name, store, serial) + { + const XHTML = "http://www.w3.org/1999/xhtml"; + const ios = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService); + const sss = Components.classes["@mozilla.org/content/style-sheet-service;1"] + .getService(Components.interfaces.nsIStyleSheetService); + + let cssUri = function (css) ios.newURI("data:text/css," + encodeURI(css), null, null); + + let sheets = []; + this.__iterator__ = function () Iterator(sheets); + + this.addSheet = function (filter, css) + { + let errors = checkSyntax(css); + if (errors.length) + return errors.map(function (e) "CSS: " + filter + ": " + e).join("\n"); + + let chrome = /^chrome:/.test(filter); + if (chrome) + return "Chrome styling not supported"; /* For now. */ + + if (sheets.some(function (s) s[0] == filter && s[1] == css)) + return null; + sheets.push([filter, css]); + let uri = cssUri(wrapCSS(filter, css)); + sss.loadAndRegisterSheet(uri, sss.USER_SHEET); + return null; + } + + this.removeSheet = function (number) + { + if (number >= sheets.length) + return false; + let sheet = sheets.splice(number)[0]; + let uri = cssUri(wrapCSS(sheet[0], sheet[1])); + sss.unregisterSheet(uri, sss.USER_SHEET); + return true; + } + + function wrapCSS(filter, css) + { + if (filter == "*") + return css; + let selector = /[\/:]/.test(filter) ? "url" : "domain"; + filter = filter.replace('"', "%22", "g"); + return "@namespace url(" + XHTML + ");\n" + + "@-moz-document " + selector + '("' + filter + '") {\n' + css + "\n}\n"; + /* } vim */ + } + + function checkSyntax(css) + { + let errors = []; + let listener = { + QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIConsoleListener]), + observe: function (message) + { + try + { + message = message.QueryInterface(Components.interfaces.nsIScriptError); + if (message.sourceName.indexOf("data:text/css,") == 0) + errors.push(message.errorMessage); + } + catch (e) {} + } + }; + + var consoleService = Components.classes["@mozilla.org/consoleservice;1"] + .getService(Components.interfaces.nsIConsoleService); + consoleService.registerListener(listener); + + try + { + var doc = document.implementation.createDocument(XHTML, "doc", null); + doc.documentElement.appendChild(liberator.util.xmlToDom( + , doc)); + + while (true) + { + try { + // Throws NS_ERROR_DOM_INVALID_ACCESS_ERR if not finished loading + doc.styleSheets[0].cssRules.length; + break; + } catch (e) { + if (e.name != "NS_ERROR_DOM_INVALID_ACCESS_ERR") + throw e; + liberator.sleep(10); + } + } + } + finally + { + consoleService.unregisterListener(listener); + } + return errors; + } + } + + let styles = liberator.storage.newObject(styles, Styles, false); + function setZoom(value, fullZoom) { if (value < 1 || value > 2000) @@ -181,10 +280,7 @@ liberator.Buffer = function () //{{{ liberator.options.add(["pageinfo", "pa"], "Desired info on :pa[geinfo]", "charlist", "gfm", { - completer: function (filter) - { - return [[k, v[1]] for ([k, v] in Iterator(pageInfo))] - }, + completer: function (filter) [0, [[k, v[1]] for ([k, v] in Iterator(pageInfo))]] }); liberator.options.add(["scroll", "scr"], @@ -198,14 +294,11 @@ liberator.Buffer = function () //{{{ "Show the destination of the link under the cursor in the status bar", "number", 1, { - completer: function (filter) - { - return [ + completer: function (filter) [0, [ ["0", "Don't show link destination"], ["1", "Show the link in the status line"], ["2", "Show the link in the command line"] - ]; - }, + ]], validator: function (value) value >= 0 && value <= 2 }); @@ -567,6 +660,42 @@ liberator.Buffer = function () //{{{ }, { argCount: "0" }); + liberator.commands.add(["sty[le]"], + "Add or list user styles", + function (args, special) + { + let [, filter, css] = args.match(/([^\s]+)\s*(.*)/) || []; + if (!css) + { + let str = liberator.template.tabular(["", "Filter", "CSS"], + ([i, style[0], style[1]] for ([i, style] in styles) + if (!filter || style[0] == filter))); + liberator.commandline.echo(str, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); + } + else + { + // TODO: Accept here docs. + let err = styles.addSheet(filter, css); + if (err) + liberator.echoerr(err); + } + }, + { + completer: function (filter) [0, [ + [content.location.host, ""], + [content.location.href, ""]] + .concat([[s[0], ""] for ([i, s] in styles)]) + ], + }); + + liberator.commands.add(["dels[tyle]"], + "Remove a user stylesheet", + function (args, special) styles.removeSheet(parseInt(args.arguments[0])), + { + completer: function (filter) [0, [[i, s[0] + ": " + s[1].replace("\n", "\\n")] for ([i, s] in styles)]], + argCount: 1 + }); + liberator.commands.add(["vie[wsource]"], "View source code of current document", function (args, special) { liberator.buffer.viewSource(args, special); }); @@ -1243,8 +1372,6 @@ liberator.Buffer = function () //{{{ frames[next].frameElement.scrollIntoView(false); // add the frame indicator - // TODO: make this an XBL element rather than messing with the content - // document var doc = frames[next].document; var indicator =
; if (table.tr.length() > 1) return table; - } + }, + + tabular: function (headings, iter) + { + /* This might be mind-bogglingly slow. We'll see. */ + return this.generic( + + + { + this.map(headings, function (h) + ) + } + + { + this.map(iter, function (row) + + { + liberator.template.map(row, function (d) + ) + } + ) + } +
{h}
{d}
); + }, }; // vim: set fdm=marker sw=4 ts=4 et: diff --git a/content/commands.js b/content/commands.js index b6a8d402..8af5e1d9 100644 --- a/content/commands.js +++ b/content/commands.js @@ -697,23 +697,9 @@ liberator.Commands = function () //{{{ var cmdlist = getMatchingUserCommands(cmd); if (cmdlist.length > 0) { - XML.prettyPrinting = false; - var str = liberator.template.generic( - - - - - - - { - liberator.template.map(cmdlist, function (cmd) - - - - - ) - } -
NameArgsDefinition
{cmd.name}*{cmd.replacementText || "function () { ... }"}
); + var str = liberator.template.tabular(["Name", "Args", "Definition"], + ([cmd.name, "*", cmd.replacementText || "function () { ... }"] + for each (cmd in cmdlist))); liberator.commandline.echo(str, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); } else diff --git a/content/events.js b/content/events.js index a60d2252..febbe17d 100644 --- a/content/events.js +++ b/content/events.js @@ -666,16 +666,7 @@ liberator.Events = function () //{{{ function (args) { XML.prettyPrinting = false; - var str = - { - liberator.template.map2(liberator.events.getMacros(args), - function (macro, keys) - - - - ) - } -
{macro}{keys}
.toXMLString(); + var str = liberator.template.tabular(["Macro", "Keys"], liberator.events.getMacros(args)); liberator.echo(str, liberator.commandline.FORCE_MULTILINE); }, { diff --git a/content/liberator.js b/content/liberator.js index 221a00e3..851fdafd 100644 --- a/content/liberator.js +++ b/content/liberator.js @@ -440,10 +440,10 @@ const liberator = (function () //{{{ Code execution summary - Executed:{count}times - Average time:{each.toFixed(2)}{eachUnits} - Total time:{total.toFixed(2)}{totalUnits} - ); +   Executed:{count}times +   Average time:{each.toFixed(2)}{eachUnits} +   Total time:{total.toFixed(2)}{totalUnits} + ); liberator.commandline.echo(str, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); } diff --git a/content/ui.js b/content/ui.js index a1f6b749..6a49c5e8 100644 --- a/content/ui.js +++ b/content/ui.js @@ -504,7 +504,7 @@ liberator.CommandLine = function () //{{{ // TODO: color messages // : are all messages single line? Some display an aggregation // of single line messages at least. E.g. :source - let list = messageHistory.messages.join("
"); + let list = messageHistory.messages.join("\n"); liberator.commandline.echo(list); }, { argCount: "0" });