1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-23 09:17:59 +01:00

Show the default styles in :highlight, etc.

This commit is contained in:
Kris Maglione
2008-10-31 22:46:34 +00:00
parent d7c5e79cd7
commit f0d258c8fc
7 changed files with 522 additions and 405 deletions

View File

@@ -26,8 +26,6 @@ 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");
const Point = new Struct("x", "y");
function Buffer() //{{{
@@ -35,241 +33,6 @@ function Buffer() //{{{
////////////////////////////////////////////////////////////////////////////////
////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
const highlightClasses = ["Boolean", "ErrorMsg", "Filter", "Function", "InfoMsg", "Keyword",
"LineNr", "ModeMsg", "MoreMsg", "Normal", "Null", "Number", "Object", "Question",
"StatusLine", "StatusLineBroken", "StatusLineSecure", "String", "TabClose", "TabIcon",
"TabIconNumber", "TabNumber", "TabText", "Tag", "Title", "URL", "WarningMsg",
["Hint", ".liberator-hint", "*"],
["Search", ".__liberator-search", "*"],
["Bell", "#liberator-visualbell"],
];
const highlightDocs = "chrome://liberator/content/buffer.xhtml,chrome://browser/content/browser.xul";
var highlight = storage.newMap("highlight", false);
const util = modules.util;
const arrayIter = util.Array.iterator;
function Styles(name, store, serial)
{
/* Can't reference liberator or Components inside Styles --
* they're members of the window object, which disappear
* with this window.
*/
const sleep = liberator.sleep;
const storage = modules.storage;
const consoleService = Components.classes["@mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService);
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);
const XHTML = "http://www.w3.org/1999/xhtml";
const namespace = "@namespace html url(" + XHTML + ");\n" +
"@namespace xul url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);\n";
const Sheet = new Struct("name", "sites", "css", "ref");
let cssUri = function (css) "chrome-data:text/css," + encodeURI(css);
let userSheets = [];
let systemSheets = [];
let userNames = {};
let systemNames = {};
this.__iterator__ = function () Iterator(userSheets.concat(systemSheets));
this.__defineGetter__("systemSheets", function () Iterator(systemSheets));
this.__defineGetter__("userSheets", function () Iterator(userSheets));
this.__defineGetter__("systemNames", function () Iterator(systemNames));
this.__defineGetter__("userNames", function () Iterator(userNames));
this.addSheet = function (name, filter, css, system, force)
{
let sheets = system ? systemSheets : userSheets;
let names = system ? systemNames : userNames;
if (name && name in names)
this.removeSheet(name, null, null, null, system);
let sheet = sheets.filter(function (s) s.sites.join(",") == filter && s.css == css)[0];
if (!sheet)
sheet = new Sheet(name, filter.split(","), css, null);
if (sheet.ref == null) // Not registered yet
{
sheet.ref = [];
try
{
this.registerSheet(cssUri(wrapCSS(sheet)), !force);
}
catch (e)
{
return e.echoerr || e;
}
sheets.push(sheet);
}
if (name)
{
sheet.ref.push(name);
names[name] = sheet;
}
return null;
}
this.findSheets = function (name, filter, css, index, system)
{
let sheets = system ? systemSheets : userSheets;
let names = system ? systemNames : userNames;
// Grossly inefficient.
let matches = [k for ([k, v] in sheets)];
if (index)
matches = String(index).split(",").filter(function (i) i in sheets);
if (name)
matches = matches.filter(function (i) sheets[i] == names[name]);
if (css)
matches = matches.filter(function (i) sheets[i].css == css);
if (filter)
matches = matches.filter(function (i) sheets[i].sites.indexOf(filter) >= 0);
return matches;
},
this.removeSheet = function (name, filter, css, index, system)
{
let self = this;
let sheets = system ? systemSheets : userSheets;
let names = system ? systemNames : userNames;
if (filter && filter.indexOf(",") > -1)
return filter.split(",").reduce(
function (n, f) n + self.removeSheet(name, f, index, system), 0);
if (filter == undefined)
filter = "";
let matches = this.findSheets(name, filter, css, index, system);
if (matches.length == 0)
return;
for (let [,i] in Iterator(matches.reverse()))
{
let sheet = sheets[i];
if (name)
{
sheet.ref.splice(sheet.ref.indexOf(name));
delete names[name];
}
if (!sheet.ref.length)
{
sheets.splice(i);
this.unregisterSheet(cssUri(wrapCSS(sheet)));
}
// Filter out the given site, and re-add if there are any left
if (filter)
{
let sites = sheet.sites.filter(function (f) f != filter);
if (sites.length)
this.addSheet(name, sites.join(","), css, system, true);
}
}
return matches.length;
}
this.registerSheet = function (uri, doCheckSyntax, reload)
{
if (doCheckSyntax)
checkSyntax(uri);
if (reload)
this.unregisterSheet(uri);
uri = ios.newURI(uri, null, null);
if (reload || !sss.sheetRegistered(uri, sss.USER_SHEET))
sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
}
this.unregisterSheet = function (uri)
{
uri = ios.newURI(uri, null, null);
if (sss.sheetRegistered(uri, sss.USER_SHEET))
sss.unregisterSheet(uri, sss.USER_SHEET);
}
function wrapCSS(sheet)
{
let filter = sheet.sites;
let css = sheet.css;
if (filter[0] == "*")
return namespace + css;
let selectors = filter.map(function (part) (/[*]$/.test(part) ? "url-prefix" :
/[\/:]/.test(part) ? "url"
: "domain")
+ '("' + part.replace(/"/g, "%22").replace(/[*]$/, "") + '")')
.join(", ");
return namespace + "@-moz-document " + selectors + "{\n" + css + "\n}\n";
}
let queryinterface = XPCOMUtils.generateQI([Components.interfaces.nsIConsoleListener]);
/* What happens if more than one thread tries to use this? */
let testDoc = document.implementation.createDocument(XHTML, "doc", null);
function checkSyntax(uri)
{
let errors = [];
let listener = {
QueryInterface: queryinterface,
observe: function (message)
{
try
{
message = message.QueryInterface(Components.interfaces.nsIScriptError);
if (message.sourceName == uri)
errors.push(message);
}
catch (e) {}
}
};
try
{
consoleService.registerListener(listener);
if (testDoc.documentElement.firstChild)
testDoc.documentElement.removeChild(testDoc.documentElement.firstChild);
testDoc.documentElement.appendChild(util.xmlToDom(
<html><head><link type="text/css" rel="stylesheet" href={uri}/></head></html>, testDoc));
while (true)
{
try
{
// Throws NS_ERROR_DOM_INVALID_ACCESS_ERR if not finished loading
testDoc.styleSheets[0].cssRules.length;
break;
}
catch (e)
{
if (e.name != "NS_ERROR_DOM_INVALID_ACCESS_ERR")
return [e.toString()];
sleep(10);
}
}
}
finally
{
consoleService.unregisterListener(listener);
}
if (errors.length)
{
let err = new Error("", errors[0].sourceName.replace(/^(chrome-data:text\/css,).*/, "$1..."), errors[0].lineNumber);
err.name = "CSSError"
err.message = errors.reduce(function (msg, e) msg + "; " + e.lineNumber + ": " + e.errorMessage, errors.shift().errorMessage);
err.echoerr = err.fileName + ":" + err.lineNumber + ": " + err.message;
throw err;
}
}
}
Styles.prototype = {
get sites() util.Array.uniq(util.Array.flatten([v.sites for ([k, v] in this.userSheets)]))
};
let styles = storage.newObject("styles", Styles, false);
/* FIXME: This doesn't belong here. */
let mainWindowID = config.mainWindowID || "main-window";
let fontSize = util.computedStyle(document.getElementById(mainWindowID))["font-size"];
@@ -813,114 +576,6 @@ function Buffer() //{{{
function () { BrowserStop(); },
{ argCount: "0" });
commands.add(["sty[le]"],
"Add or list user styles",
function (args, special)
{
let [filter] = args.arguments;
let name = args["-name"];
let css = args.literalArg;
if (!css)
{
let list = Array.concat([i for (i in styles.userNames)],
[i for (i in styles.userSheets) if (!i[1].ref.length)]);
let str = template.tabular(["", "Filter", "CSS"],
["padding: 0 1em 0 1ex; vertical-align: top", "padding: 0 1em 0 0; vertical-align: top"],
([k, v[1].join(","), v[2]]
for ([i, [k, v]] in Iterator(list))
if ((!filter || v[1].indexOf(filter) >= 0) && (!name || v[0] == name))));
commandline.echo(str, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
}
else
{
let err = styles.addSheet(name, filter, css, false, special);
if (err)
liberator.echoerr(err);
}
},
{
completer: function (filter) {
let compl = [];
try
{
compl.push([content.location.host, "Current Host"]);
compl.push([content.location.href, "Current URL"]);
}
catch (e) {}
comp = compl.concat([[s, ""] for each (s in styles.sites)])
return [0, completion.filter(compl, filter)];
},
argCount: 1,
bang: true,
hereDoc: true,
literal: true,
options: [[["-name", "-n"], commands.OPTION_STRING]],
serial: function () [
{
command: this.name,
bang: true,
options: sty.name ? {"-name": sty.name} : {},
arguments: [sty.sites.join(",")],
literalArg: sty.css
} for ([k, sty] in styles.userSheets)
]
});
commands.add(["dels[tyle]"],
"Remove a user stylesheet",
function (args) {
styles.removeSheet(args["-name"], args.arguments[0], args.literalArg, args["-index"], false);
},
{
argCount: 1,
completer: function (filter) [0, completion.filter(
[[i, <>{s.sites.join(",")}: {s.css.replace("\n", "\\n")}</>]
for ([i, s] in styles.userSheets)
]
.concat([[s, ""] for each (s in styles.sites)])
, filter)],
literal: true,
options: [[["-index", "-i"], commands.OPTION_INT],
[["-name", "-n"], commands.OPTION_STRING]]
});
commands.add(["hi[ghlight]"],
"Set the style of certain display elements",
function (args, special)
{
let key = args.arguments[0];
let css = args.literalArg;
if (!css && !(key && special))
{
let str = template.tabular(["Key", "CSS"],
["padding: 0 1em 0 0; vertical-align: top"],
(h for (h in highlight) if (!key || h[0].indexOf(key) > -1)));
commandline.echo(str, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
return;
}
buffer.highlight(key, css, special);
},
{
// TODO: add this as a standard highlight completion function?
// I agree. It could (should) be much more sophisticated. --Kris
completer: function (filter) [0,
completion.filter([[v instanceof Array ? v[0] : v, ""] for ([k, v] in Iterator(highlightClasses))], filter)
],
argCount: 1,
bang: true,
hereDoc: true,
literal: true,
serial: function () [
{
command: this.name,
arguments: [k],
literalArg: v
}
for ([k, v] in Iterator(highlight))
]
});
commands.add(["vie[wsource]"],
"View source code of current document",
function (args, special) { buffer.viewSource(args.arguments[0], special); },
@@ -1030,7 +685,7 @@ function Buffer() //{{{
// put feeds rss into pageFeeds[]
let nFeed = 0;
var linkNodes = doc.getElementsByTagName("link");
for (link in arrayIter(linkNodes))
for (link in util.arrayIter(linkNodes))
{
if (!link.href)
return;
@@ -1065,7 +720,7 @@ function Buffer() //{{{
.getService(nsICacheService);
let cacheKey = doc.location.toString().replace(/#.*$/, "");
for (let proto in arrayIter(["HTTP", "FTP"]))
for (let proto in util.arrayIter(["HTTP", "FTP"]))
{
try
{
@@ -1206,39 +861,6 @@ function Buffer() //{{{
addPageInfoSection: addPageInfoSection,
highlight: function (key, style, force)
{
let [, class, selectors] = key.match(/^([a-zA-Z_-]+)(.*)/);
class = highlightClasses.filter(function (i) i == class || i[0] == class)[0];
if (!class)
{
liberator.echoerr("Unknown highlight keyword");
return;
}
if (!(class instanceof Array))
class = [class];
styles.removeSheet("hl-" + key, null, null, null, true);
highlight.remove(key);
if (/^\s*$/.test(style))
return;
let cssClass = class[1] || ".hl-" + class[0];
let scope = class[2] || highlightDocs;
let css = style.replace(/(?:!\s*important\s*)?(?:;?\s*$|;)/g, "!important;")
.replace(";!important;", ";", "g") // Seeming Spidermonkey bug
css = cssClass + selectors + " { " + css + " }";
let error = styles.addSheet("hl-" + key, scope, css, true, force);
if (error)
liberator.echoerr(error);
else
highlight.set(key, style);
},
// returns an XPathResult object
evaluateXPath: function (expression, doc, elem, asIterator)
{

View File

@@ -284,7 +284,7 @@ function Search() //{{{
if (!aWord)
{
let elems = doc.getElementsByClassName("__liberator-search");
let elems = doc.getElementsByClassName("liberator-search");
for (let i = elems.length; --i >= 0;)
{
let elem = elems[i];
@@ -303,7 +303,7 @@ function Search() //{{{
return;
}
var baseNode = <span class="__liberator-search"/>
var baseNode = <span class="liberator-search"/>
baseNode = util.xmlToDom(baseNode, window.content.document);
var body = doc.body;
@@ -551,7 +551,7 @@ function Search() //{{{
highlight: function (text)
{
// already highlighted?
if (window.content.document.getElementsByClassName("__liberator-search").length > 0)
if (window.content.document.getElementsByClassName("liberator-search").length > 0)
return;
if (!text)

View File

@@ -25,6 +25,7 @@
["liberator.js",
"util.js",
"style.js",
"config.js",
"buffer.js",
"commands.js",

View File

@@ -37,6 +37,10 @@ const liberator = (function () //{{{
var callbacks = [];
var observers = [];
function registerObserver(type, callback)
{
observers.push([type, callback]);
}
function loadModule(name, func)
{
@@ -46,6 +50,7 @@ const liberator = (function () //{{{
liberator.log(message, 0);
liberator.dump(message);
modules[name] = func();
liberator.triggerObserver("load_" + name, name);
}
catch (e)
{
@@ -57,7 +62,7 @@ const liberator = (function () //{{{
}
// Only general options are added here, which are valid for all vimperator like extensions
function addOptions()
registerObserver("load_options", function ()
{
options.add(["errorbells", "eb"],
"Ring the bell when an error message is displayed",
@@ -140,9 +145,9 @@ const liberator = (function () //{{{
return value;
}
});
}
})
function addMappings()
registerObserver("load_mappings", function ()
{
mappings.add(modes.all, ["<F1>"],
"Open help window",
@@ -158,9 +163,9 @@ const liberator = (function () //{{{
mappings.add([modes.NORMAL], ["ZZ"],
"Quit and save the session",
function () { liberator.quit(true); });
}
})
function addCommands()
registerObserver("load_commands", function ()
{
commands.add(["addo[ns]"],
"Manage available Extensions and Themes",
@@ -529,7 +534,7 @@ const liberator = (function () //{{{
argCount: "0",
bang: true
});
}
})
// initially hide all GUI, it is later restored unless the user has :set go= or something
// similar in his config
@@ -603,10 +608,7 @@ const liberator = (function () //{{{
return false;
},
registerObserver: function (type, callback)
{
observers.push([type, callback]);
},
registerObserver: registerObserver,
triggerObserver: function (type, data)
{
@@ -1145,9 +1147,9 @@ const liberator = (function () //{{{
config.features.push(navigator.platform);
// commands must always be the first module to be initialized
loadModule("commands", Commands); addCommands();
loadModule("options", Options); addOptions();
loadModule("mappings", Mappings); addMappings();
loadModule("commands", Commands);
loadModule("options", Options);
loadModule("mappings", Mappings);
loadModule("buffer", Buffer);
loadModule("events", Events);
loadModule("commandline", CommandLine);

473
content/style.js Normal file
View File

@@ -0,0 +1,473 @@
/***** BEGIN LICENSE BLOCK ***** {{{
©2008 Kris Maglione <maglione.k at Gmail>
Distributable under the terms of the MIT license, which allows
for sublicensing under any compatible license, including the MPL,
GPL, and MPL. Anyone who changes this file is welcome to relicense
it under any or all of those licenseses.
}}} ***** END LICENSE BLOCK *****/
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function Highlights(name, store, serial)
{
const highlightCSS = <![CDATA[
Boolean color: red;
Function color: navy;
Null color: blue;
Number color: blue;
Object color: maroon;
String color: green;
Normal color: black; background: white;
ErrorMsg color: white; background: red;
InfoMsg color: black; background: white;
ModeMsg color: white; background: white;
MoreMsg color: green; background: white;
WarningMsg color: red; background: white;
Message white-space: normal; min-width: 100%; padding-left: 2em; text-indent: -2em; display: block;
Filter font-weight: bold;
Keyword color: red;
Tag color: blue;
LineNr color: orange; background: white;
Question color: green; background: white;
StatusLine color: white; background: black;
StatusLineBroken color: black; background: #FF6060; /* light-red */
StatusLineSecure color: black; background: #B0FF00; /* light-green */
TabClose
TabIcon
TabText
TabNumber font-weight: bold; margin: 0px; padding-right: .3ex;
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;
}
Title color: magenta; background: white; font-weight: bold;
URL text-decoration: none; color: green; background: inherit;
URL:hover text-decoration: underline; cursor: pointer;
Bell,#liberator-visualbell border: none; background-color: black;
Hint,.liberator-hint,* {
z-index: 5000;
font-family: monospace;
font-size: 10px;
font-weight: bold;
color: white;
background-color: red;
border-color: ButtonShadow;
border-width: 0px;
border-style: solid;
padding: 0px 1px 0px 1px;
position: absolute;
}
Search,.liberator-search,* {
display: inline;
font-size: inherit;
padding: 0;
color: black;
background-color: yellow;
padding: 0;
}
]]>.toString();
var self = this;
var highlight = {};
var styles = storage.styles;
const Highlight = Struct("class", "selector", "filter", "default", "value");
Highlight.defaultValue("filter", function () "chrome://liberator/content/buffer.xhtml,chrome://browser/content/browser.xul");
Highlight.defaultValue("selector", function () ".hl-" + this.class);
Highlight.defaultValue("value", function () this.default);
Highlight.prototype.toString = function () [k + ": " + util.escapeString(v || "undefined") for ([k, v] in this)].join(", ");
this.__iterator__ = function () (v for ([k,v] in Iterator(highlight)));
this.get = function (k) highlight[k];
this.set = function (key, newStyle, force)
{
let [, class, selectors] = key.match(/^([a-zA-Z_-]+)(.*)/);
if (!(class in highlight))
return "Unknown highlight keyword";
if (/^\s*$/.test(newStyle))
newStyle = null;
let style = highlight[key] || new Highlight(key);
styles.removeSheet(style.selector, null, null, true);
if (newStyle == null)
{
if (style.default == null)
{
delete highlight[style.class];
return null;
}
newStyle = style.default;
force = true;
}
let css = newStyle.replace(/(?:!\s*important\s*)?(?:;?\s*$|;)/g, "!important;")
.replace(";!important;", ";", "g"); // Seeming Spidermonkey bug
css = style.selector + " { " + css + " }";
let error = styles.addSheet(style.selector, style.filter, css, true, force);
if (!error)
style.value = newStyle;
return error;
}
highlightCSS.replace(/\{((?:.|\n)*?)\}/g, function (_, _1) _1.replace(/\n\s*/g, " "))
.split("\n").filter(function (s) /\S/.test(s))
.forEach(function (style)
{
let style = Highlight.apply(Highlight, Array.slice(style.match(/^\s*([^,\s]+)(?:,([^,\s]+))?(?:,([^,\s]+))?(?:\s+(.*))?/), 1));
highlight[style.class] = style;
self.set(style.class);
});
}
function Styles(name, store, serial)
{
/* Can't reference liberator or Components inside Styles --
* they're members of the window object, which disappear
* with this window.
*/
const util = modules.util;
const sleep = liberator.sleep;
const storage = modules.storage;
const consoleService = Components.classes["@mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService);
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);
const XHTML = "http://www.w3.org/1999/xhtml";
const namespace = "@namespace html url(" + XHTML + ");\n" +
"@namespace xul url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);\n";
const Sheet = new Struct("name", "sites", "css", "ref");
let cssUri = function (css) "chrome-data:text/css," + encodeURI(css);
let userSheets = [];
let systemSheets = [];
let userNames = {};
let systemNames = {};
this.__iterator__ = function () Iterator(userSheets.concat(systemSheets));
this.__defineGetter__("systemSheets", function () Iterator(systemSheets));
this.__defineGetter__("userSheets", function () Iterator(userSheets));
this.__defineGetter__("systemNames", function () Iterator(systemNames));
this.__defineGetter__("userNames", function () Iterator(userNames));
this.addSheet = function (name, filter, css, system, force)
{
let sheets = system ? systemSheets : userSheets;
let names = system ? systemNames : userNames;
if (name && name in names)
this.removeSheet(name, null, null, null, system);
let sheet = sheets.filter(function (s) s.sites.join(",") == filter && s.css == css)[0];
if (!sheet)
sheet = new Sheet(name, filter.split(","), css, null);
if (sheet.ref == null) // Not registered yet
{
sheet.ref = [];
try
{
this.registerSheet(cssUri(wrapCSS(sheet)), !force);
}
catch (e)
{
return e.echoerr || e;
}
sheets.push(sheet);
}
if (name)
{
sheet.ref.push(name);
names[name] = sheet;
}
return null;
}
this.findSheets = function (name, filter, css, index, system)
{
let sheets = system ? systemSheets : userSheets;
let names = system ? systemNames : userNames;
// Grossly inefficient.
let matches = [k for ([k, v] in sheets)];
if (index)
matches = String(index).split(",").filter(function (i) i in sheets);
if (name)
matches = matches.filter(function (i) sheets[i] == names[name]);
if (css)
matches = matches.filter(function (i) sheets[i].css == css);
if (filter)
matches = matches.filter(function (i) sheets[i].sites.indexOf(filter) >= 0);
return matches;
},
this.removeSheet = function (name, filter, css, index, system)
{
let self = this;
let sheets = system ? systemSheets : userSheets;
let names = system ? systemNames : userNames;
if (filter && filter.indexOf(",") > -1)
return filter.split(",").reduce(
function (n, f) n + self.removeSheet(name, f, index, system), 0);
if (filter == undefined)
filter = "";
let matches = this.findSheets(name, filter, css, index, system);
if (matches.length == 0)
return;
for (let [,i] in Iterator(matches.reverse()))
{
let sheet = sheets[i];
if (name)
{
sheet.ref.splice(sheet.ref.indexOf(name));
delete names[name];
}
if (!sheet.ref.length)
{
sheets.splice(i);
this.unregisterSheet(cssUri(wrapCSS(sheet)));
}
// Filter out the given site, and re-add if there are any left
if (filter)
{
let sites = sheet.sites.filter(function (f) f != filter);
if (sites.length)
this.addSheet(name, sites.join(","), css, system, true);
}
}
return matches.length;
}
this.registerSheet = function (uri, doCheckSyntax, reload)
{
if (doCheckSyntax)
checkSyntax(uri);
if (reload)
this.unregisterSheet(uri);
uri = ios.newURI(uri, null, null);
if (reload || !sss.sheetRegistered(uri, sss.USER_SHEET))
sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
}
this.unregisterSheet = function (uri)
{
uri = ios.newURI(uri, null, null);
if (sss.sheetRegistered(uri, sss.USER_SHEET))
sss.unregisterSheet(uri, sss.USER_SHEET);
}
function wrapCSS(sheet)
{
let filter = sheet.sites;
let css = sheet.css;
if (filter[0] == "*")
return namespace + css;
let selectors = filter.map(function (part) (/[*]$/.test(part) ? "url-prefix" :
/[\/:]/.test(part) ? "url"
: "domain")
+ '("' + part.replace(/"/g, "%22").replace(/[*]$/, "") + '")')
.join(", ");
return namespace + "@-moz-document " + selectors + "{\n" + css + "\n}\n";
}
let queryinterface = XPCOMUtils.generateQI([Components.interfaces.nsIConsoleListener]);
/* What happens if more than one thread tries to use this? */
let testDoc = document.implementation.createDocument(XHTML, "doc", null);
function checkSyntax(uri)
{
let errors = [];
let listener = {
QueryInterface: queryinterface,
observe: function (message)
{
try
{
message = message.QueryInterface(Components.interfaces.nsIScriptError);
if (message.sourceName == uri)
errors.push(message);
}
catch (e) {}
}
};
try
{
consoleService.registerListener(listener);
if (testDoc.documentElement.firstChild)
testDoc.documentElement.removeChild(testDoc.documentElement.firstChild);
testDoc.documentElement.appendChild(util.xmlToDom(
<html><head><link type="text/css" rel="stylesheet" href={uri}/></head></html>, testDoc));
while (true)
{
try
{
// Throws NS_ERROR_DOM_INVALID_ACCESS_ERR if not finished loading
testDoc.styleSheets[0].cssRules.length;
break;
}
catch (e)
{
if (e.name != "NS_ERROR_DOM_INVALID_ACCESS_ERR")
return [e.toString()];
sleep(10);
}
}
}
finally
{
consoleService.unregisterListener(listener);
}
if (errors.length)
{
let err = new Error("", errors[0].sourceName.replace(/^(chrome-data:text\/css,).*/, "$1..."), errors[0].lineNumber);
err.name = "CSSError"
err.message = errors.reduce(function (msg, e) msg + "; " + e.lineNumber + ": " + e.errorMessage,
errors.shift().errorMessage);
err.echoerr = err.fileName + ":" + err.lineNumber + ": " + err.message;
throw err;
}
}
}
Styles.prototype = {
get sites() util.Array.uniq(util.Array.flatten([v.sites for ([k, v] in this.userSheets)]))
};
const styles = storage.newObject("styles", Styles, false);
const highlight = storage.newObject("highlight", Highlights, false);
liberator.registerObserver("load_commands", function ()
{
commands.add(["sty[le]"],
"Add or list user styles",
function (args, special)
{
let [filter] = args.arguments;
let name = args["-name"];
let css = args.literalArg;
if (!css)
{
let list = Array.concat([i for (i in styles.userNames)],
[i for (i in styles.userSheets) if (!i[1].ref.length)]);
let str = template.tabular(["", "Filter", "CSS"],
["padding: 0 1em 0 1ex; vertical-align: top", "padding: 0 1em 0 0; vertical-align: top"],
([k, v[1].join(","), v[2]]
for ([i, [k, v]] in Iterator(list))
if ((!filter || v[1].indexOf(filter) >= 0) && (!name || v[0] == name))));
commandline.echo(str, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
}
else
{
let err = styles.addSheet(name, filter, css, false, special);
if (err)
liberator.echoerr(err);
}
},
{
completer: function (filter) {
let compl = [];
try
{
compl.push([content.location.host, "Current Host"]);
compl.push([content.location.href, "Current URL"]);
}
catch (e) {}
comp = compl.concat([[s, ""] for each (s in styles.sites)])
return [0, completion.filter(compl, filter)];
},
argCount: 1,
bang: true,
hereDoc: true,
literal: true,
options: [[["-name", "-n"], commands.OPTION_STRING]],
serial: function () [
{
command: this.name,
bang: true,
options: sty.name ? {"-name": sty.name} : {},
arguments: [sty.sites.join(",")],
literalArg: sty.css
} for ([k, sty] in styles.userSheets)
]
});
commands.add(["dels[tyle]"],
"Remove a user stylesheet",
function (args) {
styles.removeSheet(args["-name"], args.arguments[0], args.literalArg, args["-index"], false);
},
{
argCount: 1,
completer: function (filter) [0, completion.filter(
[[i, <>{s.sites.join(",")}: {s.css.replace("\n", "\\n")}</>]
for ([i, s] in styles.userSheets)
]
.concat([[s, ""] for each (s in styles.sites)])
, filter)],
literal: true,
options: [[["-index", "-i"], commands.OPTION_INT],
[["-name", "-n"], commands.OPTION_STRING]]
});
commands.add(["hi[ghlight]"],
"Set the style of certain display elements",
function (args, special)
{
let key = args.arguments[0];
let css = args.literalArg;
if (!css && !(key && special))
{
let str = template.tabular(["Key", "CSS"],
["padding: 0 1em 0 0; vertical-align: top"],
([h.class, h.value]
for (h in highlight)
if (!key || h.class.indexOf(key) > -1)));
commandline.echo(str, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
return;
}
let error = highlight.set(key, css, special);
if (error)
liberator.echoerr(error);
},
{
// TODO: add this as a standard highlight completion function?
// I agree. It could (should) be much more sophisticated. --Kris
completer: function (filter) [0,
completion.filter([[v.class, ""] for (v in highlight)], filter)
],
argCount: 1,
bang: true,
hereDoc: true,
literal: true,
serial: function () [
{
command: this.name,
arguments: [k],
literalArg: v
}
for ([k, v] in Iterator(highlight))
if (v.value != v.default)
]
});
});

View File

@@ -214,8 +214,10 @@ function CommandLine() //{{{
.selection.getRangeAt(0)
.startContainer.parentNode
.scrollWidth > commandWidget.inputField.scrollWidth)
// Yeah, the min-width is stupid. Somehow, it doesn't work otherwise.
setMultiline(<p style={"white-space: normal; min-width: " + commandWidget.inputField.scrollWidth + "px; width: 100%"}>{str}</p>, highlightGroup);
{
setCommand("");
setMultiline(<span class="hl-Message">{str}</span>, highlightGroup);
}
}
// TODO: extract CSS
@@ -233,7 +235,7 @@ function CommandLine() //{{{
* after interpolated data.
*/
XML.ignoreWhitespace = typeof str == "xml";
var output = <div class={"ex-command-output " + highlightGroup}>{template.maybeXML(str)}</div>;
var output = <div class={"ex-command-output " + highlightGroup} style={"min-width: " + commandlineWidget.scrollWidth + "px"}>{template.maybeXML(str)}</div>;
XML.ignoreWhiteSpace = true;
lastMowOutput = output;
@@ -267,7 +269,7 @@ function CommandLine() //{{{
if (win.scrollY >= win.scrollMaxY)
setLine("Press ENTER or type command to continue", commandline.HL_QUESTION, true);
else
setLine("-- More --", commandline.HL_QUESTION, true);
setLine("-- More --", commandline.HL_MOREMSG, true);
}
else
{
@@ -278,7 +280,7 @@ function CommandLine() //{{{
win.focus();
startHints = false;
modes.push(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE);
modes.set(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE);
}
function autosizeMultilineInputWidget()
@@ -532,7 +534,7 @@ function CommandLine() //{{{
let list = <></>;
for (let [,message] in Iterator(messageHistory.messages))
list += <div class={message.highlight}>{message.str}</div>;
list += <div class={message.highlight + " hl-Message"}>{message.str}</div>;
liberator.echo(list, commandline.FORCE_MULTILINE);
}
@@ -591,7 +593,7 @@ function CommandLine() //{{{
historyIndex = UNINITIALIZED;
completionIndex = UNINITIALIZED;
modes.push(modes.COMMAND_LINE, currentExtendedMode);
modes.set(modes.COMMAND_LINE, currentExtendedMode);
setHighlightGroup(this.HL_NORMAL);
setPrompt(currentPrompt);
setCommand(currentCommand);

View File

@@ -484,10 +484,23 @@ function Struct()
{
let self = this instanceof arguments.callee ? this : new arguments.callee();
for (let [k, v] in Iterator(Array.slice(arguments)))
self[k] = v;
{
if (v != undefined)
self[k] = v;
}
return self;
}
ConStructor.prototype = self;
ConStructor.defaultValue = function (key, val)
{
let i = args.indexOf(key);
let _i = "_" + i;
ConStructor.prototype.__defineGetter__(i, val);
ConStructor.prototype.__defineSetter__(i, function (val) {
this.__defineGetter__(i, function () this[_i]);
this[_i] = val;
});
};
return self.constructor = ConStructor;
}
@@ -497,7 +510,11 @@ Struct.prototype = {
return this.constructor.apply(null, this.slice());
},
// Iterator over our named members
__iterator__: function () ([v, this[v]] for ([k, v] in this.members))
__iterator__: function ()
{
let self = this;
return ([v, self[v]] for ([k, v] in Iterator(self.members)))
}
}
// Add no-sideeffect array methods. Can't set new Array() as the prototype or