//
// 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 */
Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("styles", {
exports: ["Style", "Styles", "styles"],
- require: ["services", "util"],
- use: ["contexts", "messages", "template"]
+ require: ["services", "util"]
}, this);
function cssUri(css) "chrome-data:text/css," + encodeURI(css);
get fullCSS() {
let filter = this.sites;
let css = this.css;
+
+ let preamble = "/* " + this.uri + (this.agent ? " (agent)" : "") + " */\n\n" + namespace + "\n";
if (filter[0] == "*")
- return namespace + css;
+ return preamble + css;
let selectors = filter.map(function (part)
- (/[*]$/.test(part) ? "url-prefix" :
- /[\/:]/.test(part) ? "url"
- : "domain")
- + '("' + part.replace(/"/g, "%22").replace(/\*$/, "") + '")')
+ !/^(?:[a-z-]+[:*]|[a-z-.]+$)/i.test(part) ? "regexp(" + Styles.quote(".*(?:" + part + ").*") + ")" :
+ (/[*]$/.test(part) ? "url-prefix" :
+ /[\/:]/.test(part) ? "url"
+ : "domain")
+ + '(' + Styles.quote(part.replace(/\*$/, "")) + ')')
.join(",\n ");
- return "/* " + this.uri + (this.agent ? " (agent)" : "") + " */\n\n"
- + namespace + "\n@-moz-document " + selectors + " {\n\n" + css + "\n\n}\n";
+
+ return preamble + "@-moz-document " + selectors + " {\n\n" + css + "\n\n}\n";
}
});
get modifiable() this.name !== "system",
addRef: function (obj) {
- this.refs.push(Cu.getWeakReference(obj));
+ this.refs.push(util.weakReference(obj));
this.dropRef(null);
},
dropRef: function (obj) {
this.cleanup();
this.allSheets = {};
- services["dactyl:"].providers["style"] = function styleProvider(uri) {
- let id = /^\/(\d*)/.exec(uri.path)[1];
- if (set.has(styles.allSheets, id))
- return ["text/css", unescape(encodeURI(styles.allSheets[id].fullCSS))];
- return null;
- };
+ update(services["dactyl:"].providers, {
+ "style": function styleProvider(uri, path) {
+ let id = parseInt(path);
+ if (Set.has(styles.allSheets, id))
+ return ["text/css", styles.allSheets[id].fullCSS];
+ return null;
+ }
+ });
},
cleanup: function cleanup() {
systemNames: Class.Property({ get: deprecated("Styles#system.names", function systemNames() this.system.names) }),
sites: Class.Property({ get: deprecated("Styles#user.sites", function sites() this.user.sites) }),
- list: function list(content, filter, name, hives) {
+ list: function list(content, sites, name, hives) {
const { commandline, dactyl } = this.modules;
hives = hives || styles.hives.filter(function (h) h.modifiable && h.sheets.length);
function sheets(group)
group.sheets.slice()
+ .filter(function (sheet) (!name || sheet.name === name) &&
+ (!sites || sites.every(function (s) sheet.sites.indexOf(s) >= 0)))
.sort(function (a, b) a.name && b.name ? String.localeCompare(a.name, b.name)
: !!b.name - !!a.name || a.id - b.id);
<tr highlight="Title">
<td/>
<td/>
- <td style="padding-right: 1em;">Name</td>
- <td style="padding-right: 1em;">Filter</td>
- <td style="padding-right: 1em;">CSS</td>
+ <td style="padding-right: 1em;">{_("title.Name")}</td>
+ <td style="padding-right: 1em;">{_("title.Filter")}</td>
+ <td style="padding-right: 1em;">{_("title.CSS")}</td>
</tr>
<col style="min-width: 4em; padding-right: 1em;"/>
<col style="min-width: 1em; text-align: center; color: red; font-weight: bold;"/>
for (let prop in Styles.propertyIter(str))
props[prop.name] = prop.value;
- return Object.keys(props)[sort ? "sort" : "slice"]()
- .map(function (prop) prop + ": " + props[prop] + ";")
- .join(" ");
+ let val = Object.keys(props)[sort ? "sort" : "slice"]()
+ .map(function (prop) prop + ": " + props[prop] + ";")
+ .join(" ");
+
+ if (/^\s*(\/\*.*?\*\/)/.exec(src))
+ val = RegExp.$1 + " " + val;
+ return val;
},
completeSite: function (context, content, group) {
context.fork("current", 0, this, function (context) {
context.title = ["Current Site"];
context.completions = [
- [content.location.host, "Current Host"],
- [content.location.href, "Current URL"]
+ [content.location.host, /*L*/"Current Host"],
+ [content.location.href, /*L*/"Current URL"]
];
});
}
context.generate = function () values(group.sites);
context.keys.text = util.identity;
- context.keys.description = function (site) this.sheets.length + " sheet" + (this.sheets.length == 1 ? "" : "s") + ": " +
+ context.keys.description = function (site) this.sheets.length + /*L*/" sheet" + (this.sheets.length == 1 ? "" : "s") + ": " +
array.compact(this.sheets.map(function (s) s.name)).join(", ");
context.keys.sheets = function (site) group.sheets.filter(function (s) s.sites.indexOf(site) >= 0);
context.keys.active = function (site) uris.some(Styles.matchFilter(site));
* @returns {nsIURI -> boolean}
*/
matchFilter: function (filter) {
+ filter = filter.trim();
+
if (filter === "*")
var test = function test(uri) true;
else if (!/^(?:[a-z-]+:|[a-z-.]+$)/.test(filter)) {
else
test = function test(uri) { try { return util.isSubdomain(uri.host, filter); } catch (e) { return false; } };
test.toString = function toString() filter;
+ test.key = filter;
if (arguments.length < 2)
return test;
return test(arguments[1]);
for (let item in Iterator({ Active: true, Inactive: false })) {
let [name, active] = item;
context.split(name, null, function (context) {
- context.title[0] = name + " " + (title || "Sheets");
+ context.title[0] = /*L*/name + " " + (title || "Sheets");
context.filters.push(function (item) !!item.active == active);
});
}
| [^;}\s]+
)
]]>, "gix", this)
- })
+ }),
+
+ /**
+ * Quotes a string for use in CSS stylesheets.
+ *
+ * @param {string} str
+ * @returns {string}
+ */
+ quote: function quote(str) {
+ return '"' + str.replace(/([\\"])/g, "\\$1").replace(/\n/g, "\\00000a") + '"';
+ },
}, {
commands: function (dactyl, modules, window) {
const { commands, contexts, styles } = modules;
let [filter, css] = args;
if (!css)
- styles.list(window.content, filter, args["-name"], args.explicitOpts["-group"] ? [args["-group"]] : null);
+ styles.list(window.content, filter ? filter.split(",") : null, args["-name"], args.explicitOpts["-group"] ? [args["-group"]] : null);
else {
util.assert(args["-group"].modifiable && args["-group"].hive.modifiable,
- "Cannot modify styles in the builtin group");
+ _("group.cantChangeBuiltin", _("style.styles")));
if (args["-append"]) {
let sheet = args["-group"].get(args["-name"]);
if (sheet) {
- filter = sheet.sites.concat(filter).join(",");
+ filter = array(sheet.sites).concat(filter).uniq().join(",");
css = sheet.css + " " + css;
-
}
}
let style = args["-group"].add(args["-name"], filter, css, args["-agent"]);
}
},
{
- bang: true,
completer: function (context, args) {
let compl = [];
let sheet = args["-group"].get(args["-name"]);
}
else if (args.completeArg == 1) {
if (sheet)
- context.completions = [[sheet.css, "Current Value"]];
+ context.completions = [
+ [sheet.css, _("option.currentValue")]
+ ];
context.fork("css", 0, modules.completion, "css");
}
},
command: "style",
arguments: [style.sites.join(",")],
literalArg: style.css,
- options: update({
- "-group": hive.name,
- },
- style.name ? { "-name": style.name } : {})
+ options: {
+ "-group": hive.name == "user" ? undefined : hive.name,
+ "-name": style.name || undefined
+ }
})))
.flatten().array
});
commands.add(cmd.name, cmd.desc,
function (args) {
dactyl.assert(args.bang ^ !!(args[0] || args[1] || args["-name"] || args["-index"]),
- "Argument or ! required");
+ _("error.argumentOrBang"));
args["-group"].find(args["-name"], args[0], args.literalArg, args["-index"])
.forEach(cmd.action);
}));
},
completion: function (dactyl, modules, window) {
- const names = Array.slice(util.computedStyle(window.document.createElement("div")));
+ const names = Array.slice(DOM(<div/>, window.document).style);
modules.completion.css = function (context) {
context.title = ["CSS Property"];
context.keys = { text: function (p) p + ":", description: function () "" };
};
},
javascript: function (dactyl, modules, window) {
- modules.JavaScript.setCompleter(["get", "add", "remove", "find"].map(function (m) styles.user[m]),
+ modules.JavaScript.setCompleter(["get", "add", "remove", "find"].map(function (m) Hive.prototype[m]),
[ // Prototype: (name, filter, css, index)
function (context, obj, args) this.names,
function (context, obj, args) Styles.completeSite(context, window.content),
template.highlightCSS = function highlightCSS(css) {
XML.prettyPrinting = XML.ignoreWhitespace = false;
- return this.highlightRegexp(css, patterns.property, function (match) <>{
- match.preSpace}{template.filter(match.name)}: {
+ return this.highlightRegexp(css, patterns.property, function (match) {
+ if (!match.length)
+ return <></>;
+ return <>{match.preSpace}{template.filter(match.name)}: {
template.highlightRegexp(match.value, patterns.token, function (match) {
if (match.function)
})
}{ match.postSpace }</>
- )
+ })
}
},
});