diff --git a/common/content/commandline.js b/common/content/commandline.js index b8f4768e..e151a926 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -1741,8 +1741,8 @@ const CommandLine = Module("commandline", { styles: function () { let fontSize = util.computedStyle(document.getElementById(config.mainWindowId)).fontSize; styles.registerSheet("chrome://dactyl/skin/dactyl.css"); - styles.addSheet(true, "font-size", "chrome://dactyl/content/buffer.xhtml", - "body { font-size: " + fontSize + "; }"); + styles.system.add("font-size", "chrome://dactyl/content/buffer.xhtml", + "body { font-size: " + fontSize + "; }"); } }); diff --git a/common/content/dactyl.js b/common/content/dactyl.js index f9b6ef13..1bd1d1fc 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -19,25 +19,6 @@ const EVAL_ERROR = "__dactyl_eval_error"; const EVAL_RESULT = "__dactyl_eval_result"; const EVAL_STRING = "__dactyl_eval_string"; -function deprecated(reason, fn) { - let name, func = callable(fn) ? fn : function () this[fn].apply(this, arguments); - function deprecatedMethod() { - let frame = Components.stack.caller; - let obj = this.className || this.constructor.className; - if (!set.add(deprecatedMethod.seen, frame.filename)) - dactyl.echoerr( - (frame.filename || "unknown").replace(/^.*? -> /, "") + - ":" + frame.lineNumber + ": " + - (obj ? obj + "." : "") + (fn.name || name) + " is deprecated: " + reason); - return func.apply(this, arguments); - } - deprecatedMethod.seen = { "chrome://dactyl/content/javascript.js": true }; - return callable(fn) ? deprecatedMethod : Class.Property({ - get: function () deprecatedMethod, - init: function (prop) { name = prop; } - }); -} - const Dactyl = Module("dactyl", { init: function () { window.dactyl = this; @@ -1266,9 +1247,9 @@ const Dactyl = Module("dactyl", { this); let class_ = dir.map(function (dir) "html|html > xul|scrollbar[orient=" + dir + "]"); - styles.addSheet(true, "scrollbar", "*", - class_.length ? class_.join(", ") + " { visibility: collapse !important; }" : "", - true); + styles.system.add("scrollbar", "*", + class_.length ? class_.join(", ") + " { visibility: collapse !important; }" : "", + true); prefs.safeSet("layout.scrollbar.side", opts.indexOf("l") >= 0 ? 3 : 2, "See 'guioptions' scrollbar flags."); @@ -1285,8 +1266,8 @@ const Dactyl = Module("dactyl", { setter: function (opts) { let classes = [v[1] for ([k, v] in Iterator(this.opts)) if (opts.indexOf(k) < 0)]; - styles.addSheet(true, "taboptions", "chrome://*", - classes.length ? classes.join(",") + "{ display: none; }" : ""); + styles.system.add("taboptions", "chrome://*", + classes.length ? classes.join(",") + "{ display: none; }" : ""); }, validator: function (opts) dactyl.has("Gecko2") || Option.validIf(!/[nN]/.test(opts), "Tab numbering not available in this " + config.host + " version") diff --git a/common/content/hints.js b/common/content/hints.js index 6e56acfa..61140e30 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -463,7 +463,7 @@ const Hints = Module("hints", { if (hint.imgSpan) css.push(selector + imgSpan + " { " + hint.span.style.cssText + " }"); } - styles.addSheet(true, "hint-positions", "*", css.join("\n")); + styles.system.add("hint-positions", "*", css.join("\n")); } return true; @@ -484,7 +484,7 @@ const Hints = Module("hints", { for (let i in util.range(start, end + 1)) this._setClass(this._pageHints[i].elem, null); } - styles.removeSheet(true, "hint-positions"); + styles.system.remove("hint-positions"); this._reset(slight); }, diff --git a/common/content/statusline.js b/common/content/statusline.js index 9667489b..29b83de7 100644 --- a/common/content/statusline.js +++ b/common/content/statusline.js @@ -21,7 +21,7 @@ const StatusLine = Module("statusline", { this.widgets.status = this.widgets.container; if (this.statusBar.localName == "toolbar") { - styles.addSheet(true, "addon-bar", config.styleableChrome, statusbar { -moz-box-flex: 1 } diff --git a/common/content/tabs.js b/common/content/tabs.js index b2c7dcfb..16ad6d62 100644 --- a/common/content/tabs.js +++ b/common/content/tabs.js @@ -26,7 +26,7 @@ const Tabs = Module("tabs", { if (config.hasTabbrowser) config.tabStrip.collapsed = true; - this.tabStyle = styles.addSheet(true, "tab-strip-hiding", config.styleableChrome, + this.tabStyle = styles.system.add("tab-strip-hiding", config.styleableChrome, (config.tabStrip.id ? "#" + config.tabStrip.id : ".tabbrowser-strip") + "{ visibility: collapse; }", false, true); diff --git a/common/modules/base.jsm b/common/modules/base.jsm index da855270..5e0a12d3 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -175,9 +175,9 @@ defineModule("base", { "Cc", "Ci", "Class", "Cr", "Cu", "Module", "Object", "Runnable", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMUtils", "array", "call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule", - "endModule", "forEach", "isArray", "isGenerator", "isinstance", - "isObject", "isString", "isSubclass", "iter", "iterAll", "keys", - "memoize", "octal", "properties", "set", "update", "values", + "deprecated", "endModule", "forEach", "isArray", "isGenerator", + "isinstance", "isObject", "isString", "isSubclass", "iter", "iterAll", + "keys", "memoize", "octal", "properties", "set", "update", "values", "withCallerGlobal" ], use: ["services", "util"] @@ -221,6 +221,7 @@ function prototype(obj) obj.__proto__ || Object.getPrototypeOf(obj) || XPCNativeWrapper.unwrap(obj).__proto__ || Object.getPrototypeOf(XPCNativeWrapper.unwrap(obj)); + function properties(obj, prototypes, debugger_) { let orig = obj; let seen = {}; @@ -240,6 +241,26 @@ function properties(obj, prototypes, debugger_) { } } +function deprecated(reason, fn) { + let name, func = callable(fn) ? fn : function () this[fn].apply(this, arguments); + + function deprecatedMethod() { + let frame = Components.stack.caller; + let obj = this.className || this.constructor.className; + if (!set.add(deprecatedMethod.seen, frame.filename)) + util.dactyl.echoerr( + util.urlPath(frame.filename || "unknown") + ":" + frame.lineNumber + ": " + + (obj ? obj + "." : "") + (fn.name || name) + " is deprecated: " + reason); + return func.apply(this, arguments); + } + deprecatedMethod.seen = { "chrome://dactyl/content/javascript.js": true }; + + return callable(fn) ? deprecatedMethod : Class.Property({ + get: function () deprecatedMethod, + init: function (prop) { name = prop; } + }); +} + /** * Iterates over all of the top-level, iterable property names of an * object. diff --git a/common/modules/highlight.jsm b/common/modules/highlight.jsm index c519b712..ebd15571 100644 --- a/common/modules/highlight.jsm +++ b/common/modules/highlight.jsm @@ -35,7 +35,7 @@ Highlight.defaultValue("sites", function () : ["chrome://dactyl/*", "dactyl:*", "file://*"].concat( highlight.styleableChrome)); Highlight.defaultValue("style", function () - styles.addSheet(true, "highlight:" + this.class, this.sites, this.css, this.agent, true)); + styles.system.add("highlight:" + this.class, this.sites, this.css, this.agent, true)); Highlight.defaultValue("value", function () this.default); Highlight.prototype.__defineGetter__("base", function () diff --git a/common/modules/styles.jsm b/common/modules/styles.jsm index 525bcec2..a24a0702 100644 --- a/common/modules/styles.jsm +++ b/common/modules/styles.jsm @@ -16,7 +16,7 @@ const namespace = "@namespace html " + XHTML.uri.quote() + ";\n" + "@namespace xul " + XUL.uri.quote() + ";\n" + "@namespace dactyl " + NS.uri.quote() + ";\n"; -const Sheet = Struct("name", "id", "sites", "css", "system", "agent"); +const Sheet = Struct("name", "id", "sites", "css", "hive", "agent"); Sheet.liveProperty = function (name) { let i = this.prototype.members[name]; this.prototype.__defineGetter__(name, function () this[i]); @@ -34,6 +34,10 @@ update(Sheet.prototype, { function (filter) {filter}, <>,), + remove: function () { this.hive.remove(this) }, + + system: Class.Property({ get: deprecated("Please use Style#hive instead", function system() this.hive === styles.system) }), + get uri() cssUri(this.fullCSS), get enabled() this._enabled, @@ -71,102 +75,86 @@ update(Sheet.prototype, { } }); -/** - * Manages named and unnamed user style sheets, which apply to both - * chrome and content pages. - * - * @author Kris Maglione - */ -const Styles = Module("Styles", { +const Hive = Class("Hive", { init: function () { - this._id = 0; - this.userSheets = []; - this.systemSheets = []; - this.userNames = {}; - this.systemNames = {}; + this.sheets = []; + this.names = {}; }, - get sites() array(this.userSheets).map(function (s) s.sites).flatten().uniq().array, + __iterator__: function () Iterator(this.sheets), - __iterator__: function () Iterator(this.userSheets.concat(this.systemSheets)), + get sites() array(this.sheets).map(function (s) s.sites).flatten().uniq().array, /** * Add a new style sheet. * - * @param {boolean} system Declares whether this is a system or - * user sheet. System sheets are used internally by - * @dactyl. * @param {string} name The name given to the style sheet by * which it may be later referenced. * @param {string} filter The sites to which this sheet will * apply. Can be a domain name or a URL. Any URL ending in * "*" is matched as a prefix. * @param {string} css The CSS to be applied. + * @param {boolean} agent If true, the sheet is installed as an + * agent sheet. + * @param {boolean} lazy If true, the sheet is not initially enabled. + * @returns {Sheet} */ - addSheet: function addSheet(system, name, filter, css, agent, lazy) { - let sheets = system ? this.systemSheets : this.userSheets; - let names = system ? this.systemNames : this.userNames; + add: function add(name, filter, css, agent, lazy) { if (!isArray(filter)) filter = filter.split(","); - if (name && name in names) { - var sheet = names[name]; + if (name && name in this.names) { + var sheet = this.names[name]; sheet.agent = agent; sheet.css = String(css); sheet.sites = filter; } else { - sheet = Sheet(name, this._id++, filter.filter(util.identity), String(css), system, agent); - sheets.push(sheet); + sheet = Sheet(name, this._id++, filter.filter(util.identity), String(css), this, agent); + this.sheets.push(sheet); } if (!lazy) sheet.enabled = true; if (name) - names[name] = sheet; + this.names[name] = sheet; return sheet; }, /** * Get a sheet with a given name or index. * - * @param {boolean} system * @param {string or number} sheet The sheet to retrieve. Strings indicate * sheet names, while numbers indicate indices. */ - get: function get(system, sheet) { - let sheets = system ? this.systemSheets : this.userSheets; - let names = system ? this.systemNames : this.userNames; + get: function get(sheet) { if (typeof sheet === "number") - return sheets[sheet]; - return names[sheet]; + return this.sheets[sheet]; + return this.names[sheet]; }, /** * Find sheets matching the parameters. See {@link #addSheet} * for parameters. * - * @param {boolean} system * @param {string} name * @param {string} filter * @param {string} css * @param {number} index */ - findSheets: function findSheets(system, name, filter, css, index) { - let sheets = system ? this.systemSheets : this.userSheets; - + find: function find(name, filter, css, index) { // Grossly inefficient. - let matches = [k for ([k, v] in Iterator(sheets))]; + let matches = [k for ([k, v] in Iterator(this.sheets))]; if (index) - matches = String(index).split(",").filter(function (i) i in sheets); + matches = String(index).split(",").filter(function (i) i in this.sheets, this); if (name) - matches = matches.filter(function (i) sheets[i].name == name); + matches = matches.filter(function (i) this.sheets[i].name == name, this); if (css) - matches = matches.filter(function (i) sheets[i].css == css); + matches = matches.filter(function (i) this.sheets[i].css == css, this); if (filter) - matches = matches.filter(function (i) sheets[i].sites.indexOf(filter) >= 0); - return matches.map(function (i) sheets[i]); + matches = matches.filter(function (i) this.sheets[i].sites.indexOf(filter) >= 0, this); + return matches.map(function (i) this.sheets[i], this); }, /** @@ -174,30 +162,27 @@ const Styles = Module("Styles", { * In cases where *filter* is supplied, the given filters are removed from * matching sheets. If any remain, the sheet is left in place. * - * @param {boolean} system * @param {string} name * @param {string} filter * @param {string} css * @param {number} index */ - removeSheet: function removeSheet(system, name, filter, css, index) { + remove: function remove(name, filter, css, index) { let self = this; if (arguments.length == 1) { - var matches = [system]; - system = matches[0].system; + var matches = [name]; + name = null; } - let sheets = system ? this.systemSheets : this.userSheets; - let names = system ? this.systemNames : this.userNames; if (filter && filter.indexOf(",") > -1) return filter.split(",").reduce( - function (n, f) n + self.removeSheet(system, name, f, index), 0); + function (n, f) n + self.removeSheet(name, f, index), 0); if (filter == undefined) filter = ""; if (!matches) - matches = this.findSheets(system, name, filter, css, index); + matches = this.findSheets(name, filter, css, index); if (matches.length == 0) return null; @@ -211,21 +196,43 @@ const Styles = Module("Styles", { } sheet.enabled = false; if (sheet.name) - delete names[sheet.name]; - if (sheets.indexOf(sheet) > -1) - sheets.splice(sheets.indexOf(sheet), 1); + delete this.names[sheet.name]; } + this.sheets = this.sheets.filter(function (s) matches.indexOf(s) == -1); return matches.length; }, +}); + +/** + * Manages named and unnamed user style sheets, which apply to both + * chrome and content pages. + * + * @author Kris Maglione + */ +const Styles = Module("Styles", { + init: function () { + this._id = 0; + this.user = Hive(); + this.system = Hive(); + }, + + userSheets: Class.Property({ get: deprecated("Please use Styles#user.sheets instead", function userSheets() this.user.sheets) }), + systemSheets: Class.Property({ get: deprecated("Please use Styles#system.sheets instead", function systemSheets() this.system.sheets) }), + userNames: Class.Property({ get: deprecated("Please use Styles#user.names instead", function userNames() this.user.names) }), + systemNames: Class.Property({ get: deprecated("Please use Styles#system.names instead", function systemNames() this.system.names) }), + sites: Class.Property({ get: deprecated("Please use Styles#user.sites instead", function sites() this.user.sites) }), + + __iterator__: function () Iterator(this.user.sheets.concat(this.system.sheets)), + + _proxy: function (name, args) + let (obj = this[args[0] ? "system" : "user"]) + obj[name].apply(obj, Array.slice(args, 1)), + + addSheet: deprecated("Please use Styles#{user,system}.add instead", function addSheet() this._proxy("add", arguments)), + findSheets: deprecated("Please use Styles#{user,system}.find instead", function findSheets() this._proxy("find", arguments)), + get: deprecated("Please use Styles#{user,system}.get instead", function get() this._proxy("get", arguments)), + removeSheet: deprecated("Please use Styles#{user,system}.remove instead", function removeSheet() this._proxy("remove", arguments)), - /** - * Register a user style sheet at the given URI. - * - * @param {string} url The URI of the sheet to register. - * @param {boolean} agent If true, sheet is registered as an agent sheet. - * @param {boolean} reload Whether to reload any sheets that are - * already registered. - */ registerSheet: function registerSheet(url, agent, reload) { let uri = services.io.newURI(url, null, null); if (reload) @@ -236,12 +243,6 @@ const Styles = Module("Styles", { services.stylesheet.loadAndRegisterSheet(uri, type); }, - /** - * Unregister a sheet at the given URI. - * - * @param {string} url The URI of the sheet to unregister. - * @param {boolean} agent If true, sheet is registered as an agent sheet. - */ unregisterSheet: function unregisterSheet(url, agent) { let uri = services.io.newURI(url, null, null); let type = services.stylesheet[agent ? "AGENT_SHEET" : "USER_SHEET"]; @@ -251,10 +252,10 @@ const Styles = Module("Styles", { }, { append: function (dest, src, sort) { let props = {}; - for each (let str in [dest, src]) 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(" "); @@ -274,7 +275,7 @@ const Styles = Module("Styles", { catch (e) {} context.fork("others", 0, this, function (context) { context.title = ["Site"]; - context.completions = [[s, ""] for ([, s] in Iterator(styles.sites))]; + context.completions = [[s, ""] for ([, s] in Iterator(styles.user.sites))]; }); }, @@ -354,7 +355,7 @@ const Styles = Module("Styles", { let name = args["-name"]; if (!css) { - let list = styles.userSheets.slice() + let list = styles.user.sheets.slice() .sort(function (a, b) a.name && b.name ? String.localeCompare(a.name, b.name) : !!b.name - !!a.name || a.id - b.id); let uris = util.visibleURIs(window.content); @@ -364,7 +365,7 @@ const Styles = Module("Styles", { "padding: 0 1em 0 1ex; vertical-align: top;", "padding: 0 1em 0 0; vertical-align: top;"], ([sheet.enabled ? "" : UTF8("×"), - sheet.name || styles.userSheets.indexOf(sheet), + sheet.name || styles.user.sheets.indexOf(sheet), sheet.formatSites(uris), sheet.css] for (sheet in values(list)) @@ -372,13 +373,13 @@ const Styles = Module("Styles", { } else { if ("-append" in args) { - let sheet = styles.get(false, name); + let sheet = styles.user.get(name); if (sheet) { filter = sheet.sites.concat(filter).join(","); css = Styles.append(sheet.css, css); } } - styles.addSheet(false, name, filter, css, args["-agent"]); + styles.user.add(name, filter, css, args["-agent"]); } }, { @@ -388,7 +389,7 @@ const Styles = Module("Styles", { if (args.completeArg == 0) Styles.completeSite(context, window.content); else if (args.completeArg == 1) { - let sheet = styles.get(false, args["-name"]); + let sheet = styles.user.get(args["-name"]); if (sheet) context.completions = [[sheet.css, "Current Value"]]; context.fork("css", 0, modules.completion, "css"); @@ -402,7 +403,7 @@ const Styles = Module("Styles", { { names: ["-name", "-n"], description: "The name of this stylesheet", - completer: function () [[k, v.css] for ([k, v] in Iterator(styles.userNames))], + completer: function () [[k, v.css] for ([k, v] in Iterator(styles.user.names))], type: modules.CommandOption.STRING } ], @@ -413,7 +414,7 @@ const Styles = Module("Styles", { bang: true, literalArg: sty.css, options: sty.name ? { "-name": sty.name } : {} - } for ([k, sty] in Iterator(styles.userSheets.slice().sort(function (a, b) String.localeCompare(a.name || "", b.name || "")))) + } for ([k, sty] in Iterator(styles.user.sheets.slice().sort(function (a, b) String.localeCompare(a.name || "", b.name || "")))) ] }); @@ -438,7 +439,7 @@ const Styles = Module("Styles", { { name: ["dels[tyle]"], desc: "Remove a user style sheet", - action: function (sheet) styles.removeSheet(sheet) + action: function (sheet) sheet.remove() } ].forEach(function (cmd) { @@ -454,7 +455,7 @@ const Styles = Module("Styles", { function sheets(context) { let uris = util.visibleURIs(window.content); context.compare = modules.CompletionContext.Sort.number; - context.generate = function () styles.userSheets; + context.generate = function () styles.user.sheets; context.keys.active = function (sheet) sheet.sites.some(function (site) uris.some(Styles.matchFilter(site))), context.keys.description = function (sheet) <>{sheet.formatSites(uris)}: {sheet.css.replace("\n", "\\n")} if (cmd.filter) @@ -464,16 +465,16 @@ const Styles = Module("Styles", { commands.add(cmd.name, cmd.desc, function (args) { - styles.findSheets(false, args["-name"], args[0], args.literalArg, args["-index"]) + styles.user.find(args["-name"], args[0], args.literalArg, args["-index"]) .forEach(cmd.action); }, { completer: function (context) { let uris = util.visibleURIs(window.content); - context.generate = function () styles.sites; + context.generate = function () styles.user.sites; context.keys.text = util.identity; context.keys.description = function (site) this.sheets.length + " sheet" + (this.sheets.length == 1 ? "" : "s") + ": " + array.compact(this.sheets.map(function (s) s.name)).join(", ") - context.keys.sheets = function (site) styles.userSheets.filter(function (s) s.sites.indexOf(site) >= 0); + context.keys.sheets = function (site) styles.user.sheets.filter(function (s) s.sites.indexOf(site) >= 0); context.keys.active = function (site) uris.some(Styles.matchFilter(site)); if (cmd.filter) @@ -487,7 +488,7 @@ const Styles = Module("Styles", { names: ["-index", "-i"], type: modules.CommandOption.INT, completer: function (context) { - context.keys.text = function (sheet) styles.userSheets.indexOf(sheet); + context.keys.text = function (sheet) styles.user.sheets.indexOf(sheet); sheets(context); }, }, { @@ -519,13 +520,12 @@ const Styles = Module("Styles", { }; }, javascript: function (dactyl, modules, window) { - modules.JavaScript.setCompleter(["get", "addSheet", "removeSheet", "findSheets"].map(function (m) styles[m]), - [ // Prototype: (system, name, filter, css, index) - null, - function (context, obj, args) args[0] ? this.systemNames : this.userNames, + modules.JavaScript.setCompleter(["get", "add", "remove", "find"].map(function (m) styles.user[m]), + [ // Prototype: (name, filter, css, index) + function (context, obj, args) this.names, function (context, obj, args) Styles.completeSite(context, window.content), null, - function (context, obj, args) args[0] ? this.systemSheets : this.userSheets + function (context, obj, args) this.sheets ]); } }); diff --git a/common/modules/template.jsm b/common/modules/template.jsm index 706001f1..6b27b5eb 100644 --- a/common/modules/template.jsm +++ b/common/modules/template.jsm @@ -249,20 +249,12 @@ const Template = Module("Template", { sourceLink: function (frame) { let url = (frame.filename || "unknown").replace(/.* -> /, ""); - function getPath(url) { - try { - return util.getFile(url).path; - } - catch (e) { - return url; - } - } XML.ignoreWhitespace = false; XML.prettyPrinting = false; return { - getPath(url) + ":" + frame.lineNumber + util.urlPath(url) + ":" + frame.lineNumber } }, diff --git a/common/modules/util.jsm b/common/modules/util.jsm index da30fdeb..e34b6fba 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -55,14 +55,25 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) // FIXME: Only works for Pentadactyl get activeWindow() services.windowMediator.getMostRecentWindow("navigator:browser"), - dactyl: { - __noSuchMethod__: function (meth, args) { - let win = util.activeWindow; - if (win && win.dactyl) - return win.dactyl[meth].apply(win.dactyl, args); - return null; + dactyl: update(function dactyl(obj) { + if (obj) + var global = Class.objectGlobal(obj); + return { + __noSuchMethod__: function (meth, args) { + let win = util.activeWindow; + var dactyl = global && global.dactyl || win && win.dactyl; + if (!win) + return null; + + let prop = dactyl[meth]; + if (callable(prop)) + return prop.apply(dactyl, args); + return prop; + } } - }, + }, { + __noSuchMethod__: function () this().__noSuchMethod__.apply(null, arguments) + }), /** * Registers a obj as a new observer with the observer service. obj.observe @@ -1235,6 +1246,16 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) } }, + urlPath: function urlPath(url) { + url = (url || "unknown").replace(/.* -> /, ""); + try { + return util.getFile(url).path; + } + catch (e) { + return url; + } + }, + visibleHosts: function (win) { let res = [], seen = {}; (function rec(frame) {