diff --git a/common/bootstrap.js b/common/bootstrap.js index fbbabbeb..30a5a673 100755 --- a/common/bootstrap.js +++ b/common/bootstrap.js @@ -102,7 +102,7 @@ function startup(data, reason) { addon = a; updateVersion(); if (typeof require !== "undefined") - require(global, "overlay"); + require(global, "main"); }); if (basePath.isDirectory()) @@ -260,7 +260,7 @@ function init() { updateVersion(); if (addon !== addonData) - require(global, "overlay"); + require(global, "main"); } function shutdown(data, reason) { diff --git a/common/content/disable-acr.jsm b/common/content/disable-acr.jsm index 3481cda8..5f5b4fea 100644 --- a/common/content/disable-acr.jsm +++ b/common/content/disable-acr.jsm @@ -8,8 +8,7 @@ const OVERLAY_URLS = [ "chrome://mozapps/content/extensions/extensions.xul" ]; -const Ci = Components.interfaces; -const Cu = Components.utils; +let { interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); @@ -64,7 +63,10 @@ function chromeDocuments() { let docShells = window.docShell.getDocShellEnumerator(Ci.nsIDocShellTreeItem[type], Ci.nsIDocShell.ENUMERATE_FORWARDS); while (docShells.hasMoreElements()) + try { yield docShells.getNext().QueryInterface(Ci.nsIDocShell).contentViewer.DOMDocument; + } + catch (e) {} } } } diff --git a/common/modules/base.jsm b/common/modules/base.jsm index 6dce9d58..9e18365c 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -339,6 +339,7 @@ function keys(obj) iter(function keys() { if (hasOwnProperty.call(obj, k)) yield k; }()); + /** * Iterates over all of the top-level, iterable property values of an * object. diff --git a/common/modules/config.jsm b/common/modules/config.jsm index 1a45ca43..bfcc36fc 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -72,6 +72,7 @@ var ConfigBase = Class("ConfigBase", { "help", "highlight", "javascript", + "main", "messages", "options", "overlay", diff --git a/common/modules/dom.jsm b/common/modules/dom.jsm index ef72c02c..06864b77 100644 --- a/common/modules/dom.jsm +++ b/common/modules/dom.jsm @@ -268,7 +268,13 @@ var DOM = Class("DOM", { add: function add(cls) this.each("add", cls), remove: function remove(cls) this.each("remove", cls), - toggle: function toggle(cls, val) this.each(val == null ? "toggle" : val ? "add" : "remove", cls), + toggle: function toggle(cls, val, thisObj) { + if (callable(val)) + return self.each(function (elem, i) { + this.class.toggle(cls, val.call(thisObj || this, elem, i)); + }); + return this.each(val == null ? "toggle" : val ? "add" : "remove", cls); + }, has: function has(cls) this[0].classList.has(cls) }), @@ -524,7 +530,7 @@ var DOM = Class("DOM", { let hooks = this.attrHooks[ns] || {}; if (isObject(key)) - return this.each(function (elem) { + return this.each(function (elem, i) { for (let [k, v] in Iterator(key)) { if (callable(v)) v = v.call(this, elem, i); @@ -550,7 +556,6 @@ var DOM = Class("DOM", { return this[0].getAttributeNS(ns, key); }, - css: update(function css(key, val) { if (val !== undefined) key = array.toObject([[key, val]]); diff --git a/common/modules/main.jsm b/common/modules/main.jsm new file mode 100644 index 00000000..295dfcd1 --- /dev/null +++ b/common/modules/main.jsm @@ -0,0 +1,301 @@ +// Copyright (c) 2009-2011 by Kris Maglione +// +// This work is licensed for reuse under an MIT license. Details are +// given in the LICENSE.txt file included with this file. +"use strict"; + +try { + +Components.utils.import("resource://dactyl/bootstrap.jsm"); +defineModule("main", { + exports: ["ModuleBase"], + require: ["config", "help", "highlight", "io", "overlay", "services", "util"] +}, this); + +/** + * @class ModuleBase + * The base class for all modules. + */ +var ModuleBase = Class("ModuleBase", { + /** + * @property {[string]} A list of module prerequisites which + * must be initialized before this module is loaded. + */ + requires: [], + + toString: function () "[module " + this.constructor.className + "]" +}); + +config.loadStyles(); + +overlay.overlayWindow(config.overlayChrome, function _overlay(window) ({ + ready: function onInit(document) { + /** + * @constructor Module + * + * Constructs a new ModuleBase class and makes arrangements for its + * initialization. Arguments marked as optional must be either + * entirely elided, or they must have the exact type specified. + * Loading semantics are as follows: + * + * - A module is guaranteed not to be initialized before any of its + * prerequisites as listed in its {@see ModuleBase#requires} member. + * - A module is considered initialized once it's been instantiated, + * its {@see Class#init} method has been called, and its + * instance has been installed into the top-level {@see modules} + * object. + * - Once the module has been initialized, its module-dependent + * initialization functions will be called as described hereafter. + * @param {string} name The module's name as it will appear in the + * top-level {@see modules} object. + * @param {ModuleBase} base The base class for this module. + * @optional + * @param {Object} prototype The prototype for instances of this + * object. The object itself is copied and not used as a prototype + * directly. + * @param {Object} classProperties The class properties for the new + * module constructor. + * @optional + * @param {Object} moduleInit The module initialization functions + * for the new module. Each function is called as soon as the named module + * has been initialized, but after the module itself. The constructors are + * guaranteed to be called in the same order that the dependent modules + * were initialized. + * @optional + * + * @returns {function} The constructor for the resulting module. + */ + function Module(name) { + let args = Array.slice(arguments); + + var base = ModuleBase; + if (callable(args[1])) + base = args.splice(1, 1)[0]; + let [, prototype, classProperties, moduleInit] = args; + const module = Class(name, base, prototype, classProperties); + + module.INIT = moduleInit || {}; + module.modules = modules; + module.prototype.INIT = module.INIT; + module.requires = prototype.requires || []; + Module.list.push(module); + Module.constructors[name] = module; + return module; + } + Module.list = []; + Module.constructors = {}; + + const BASE = "resource://dactyl-content/"; + + const create = window.Object.create || (function () { + window.__dactyl_eval_string = "(function (proto) ({ __proto__: proto }))"; + JSMLoader.loadSubScript(BASE + "eval.js", window); + + let res = window.__dactyl_eval_result; + delete window.__dactyl_eval_string; + delete window.__dactyl_eval_result; + return res; + })(); + + const jsmodules = { NAME: "jsmodules" }; + const modules = update(create(jsmodules), { + yes_i_know_i_should_not_report_errors_in_these_branches_thanks: [], + + jsmodules: jsmodules, + + get content() this.config.browser.contentWindow || window.content, + + window: window, + + Module: Module, + + load: function load(script) { + for (let [i, base] in Iterator(prefix)) { + try { + JSMLoader.loadSubScript(base + script + ".js", modules, "UTF-8"); + return; + } + catch (e) { + if (typeof e !== "string") { + util.dump("Trying: " + (base + script + ".js") + ":"); + util.reportError(e); + } + } + } + try { + require(jsmodules, script); + } + catch (e) { + util.dump("Loading script " + script + ":"); + util.reportError(e); + } + }, + + newContext: function newContext(proto, normal) { + if (normal) + return create(proto); + let sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules, wantXrays: false }); + // Hack: + sandbox.Object = jsmodules.Object; + sandbox.Math = jsmodules.Math; + sandbox.__proto__ = proto || modules; + return sandbox; + }, + + get ownPropertyValues() array.compact( + Object.getOwnPropertyNames(this) + .map(function (name) Object.getOwnPropertyDescriptor(this, name).value, this)), + + get moduleList() this.ownPropertyValues.filter(function (mod) mod instanceof this.ModuleBase || mod.isLocalModule, this) + }); + modules.plugins = create(modules); + modules.modules = modules; + window.dactyl = { modules: modules }; + + let prefix = [BASE, "resource://dactyl-local-content/"]; + + defineModule.time("load", null, function _load() { + config.modules.global + .forEach(function (name) defineModule.time("load", name, require, null, jsmodules, name)); + + config.modules.window + .forEach(function (name) defineModule.time("load", name, modules.load, modules, name)); + }, this); + }, + load: function onLoad(document) { + // This is getting to be horrible. --Kris + + var { modules, Module } = window.dactyl.modules; + delete window.dactyl; + + this.startTime = Date.now(); + const deferredInit = { load: {} }; + const seen = Set(); + const loaded = Set(); + modules.loaded = loaded; + + function load(module, prereq, frame) { + if (isString(module)) { + if (!Module.constructors.hasOwnProperty(module)) + modules.load(module); + module = Module.constructors[module]; + } + + try { + if (module.className in loaded) + return; + if (module.className in seen) + throw Error("Module dependency loop."); + Set.add(seen, module.className); + + for (let dep in values(module.requires)) + load(Module.constructors[dep], module.className); + + defineModule.loadLog.push("Load" + (isString(prereq) ? " " + prereq + " dependency: " : ": ") + module.className); + if (frame && frame.filename) + defineModule.loadLog.push(" from: " + util.fixURI(frame.filename) + ":" + frame.lineNumber); + + let obj = defineModule.time(module.className, "init", module); + Class.replaceProperty(modules, module.className, obj); + loaded[module.className] = true; + + if (loaded.dactyl && obj.signals) + modules.dactyl.registerObservers(obj); + + frob(module.className); + } + catch (e) { + util.dump("Loading " + (module && module.className) + ":"); + util.reportError(e); + } + return modules[module.className]; + } + + function deferInit(name, INIT, mod) { + let init = deferredInit[name] = deferredInit[name] || {}; + let className = mod.className || mod.constructor.className; + + init[className] = function callee() { + if (!callee.frobbed) + defineModule.time(className, name, INIT[name], mod, + modules.dactyl, modules, window); + callee.frobbed = true; + }; + + INIT[name].require = function (name) { init[name](); }; + } + + function frobModules() { + Module.list.forEach(function frobModule(mod) { + if (!mod.frobbed) { + modules.__defineGetter__(mod.className, function () { + delete modules[mod.className]; + return load(mod.className, null, Components.stack.caller); + }); + Object.keys(mod.prototype.INIT) + .forEach(function (name) { deferInit(name, mod.prototype.INIT, mod); }); + } + mod.frobbed = true; + }); + } + defineModule.modules.forEach(function defModule(mod) { + let names = Set(Object.keys(mod.INIT)); + if ("init" in mod.INIT) + Set.add(names, "init"); + + keys(names).forEach(function (name) { deferInit(name, mod.INIT, mod); }); + }); + + function frob(name) { values(deferredInit[name] || {}).forEach(call); } + this.frob = frob; + this.modules = modules; + + frobModules(); + frob("init"); + + modules.config.scripts.forEach(modules.load); + + frobModules(); + + defineModule.modules.forEach(function defModule({ lazyInit, constructor: { className } }) { + if (!lazyInit) { + frob(className); + Class.replaceProperty(modules, className, modules[className]); + } + else + modules.__defineGetter__(className, function () { + delete modules[className]; + frob(className); + return modules[className] = modules[className]; + }); + }); + + modules.events.listen(window, "unload", function onUnload() { + window.removeEventListener("unload", onUnload.wrapped, false); + + overlay.windows = overlay.windows.filter(function (w) w != window); + + for each (let mod in modules.moduleList.reverse()) { + mod.stale = true; + + if ("destroy" in mod) + util.trapErrors("destroy", mod); + } + }, false); + }, + visible: function visible(window) { + // Module.list.forEach(load); + this.frob("load"); + this.modules.times = update({}, defineModule.times); + + defineModule.loadLog.push("Loaded in " + (Date.now() - this.startTime) + "ms"); + + overlay.windows = array.uniq(overlay.windows.concat(window), true); + } +})); + +endModule(); + +} catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); } + +// vim: set fdm=marker sw=4 ts=4 et ft=javascript: diff --git a/common/modules/overlay.jsm b/common/modules/overlay.jsm index 6cc124d4..b28d287b 100644 --- a/common/modules/overlay.jsm +++ b/common/modules/overlay.jsm @@ -8,24 +8,10 @@ try { Components.utils.import("resource://dactyl/bootstrap.jsm"); defineModule("overlay", { - exports: ["ModuleBase", "overlay"], - require: ["config", "help", "highlight", "io", "services", "util"] + exports: ["overlay"], + require: ["util"] }, this); -/** - * @class ModuleBase - * The base class for all modules. - */ -var ModuleBase = Class("ModuleBase", { - /** - * @property {[string]} A list of module prerequisites which - * must be initialized before this module is loaded. - */ - requires: [], - - toString: function () "[module " + this.constructor.className + "]" -}); - var getAttr = function getAttr(elem, ns, name) elem.hasAttributeNS(ns, name) ? elem.getAttributeNS(ns, name) : null; var setAttr = function setAttr(elem, ns, name, val) { @@ -35,6 +21,26 @@ var setAttr = function setAttr(elem, ns, name, val) { elem.setAttributeNS(ns, name, val); } +var Overlay = Class("Overlay", { + init: function init(window) { + this.window = window; + }, + + cleanups: Class.Memoize(function () []), + objects: Class.Memoize(function () ({})), + + get doc() this.window.document, + + get win() this.window, + + $: function $(sel, node) DOM(sel, node || this.doc), + + cleanup: function cleanup(window, reason) { + for (let fn in values(this.cleanups)) + util.trapErrors(fn, this, window, reason); + } +}); + var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), { init: function init() { @@ -42,283 +48,11 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen this.overlays = {}; this.onWindowVisible = []; - - config.loadStyles(); - - this.timeout(this.initialize); }, id: Class.Memoize(function () config.addon.id), - initialize: function () { - this.overlayWindow(config.overlayChrome, function _overlay(window) ({ - init: function onInit(document) { - /** - * @constructor Module - * - * Constructs a new ModuleBase class and makes arrangements for its - * initialization. Arguments marked as optional must be either - * entirely elided, or they must have the exact type specified. - * Loading semantics are as follows: - * - * - A module is guaranteed not to be initialized before any of its - * prerequisites as listed in its {@see ModuleBase#requires} member. - * - A module is considered initialized once it's been instantiated, - * its {@see Class#init} method has been called, and its - * instance has been installed into the top-level {@see modules} - * object. - * - Once the module has been initialized, its module-dependent - * initialization functions will be called as described hereafter. - * @param {string} name The module's name as it will appear in the - * top-level {@see modules} object. - * @param {ModuleBase} base The base class for this module. - * @optional - * @param {Object} prototype The prototype for instances of this - * object. The object itself is copied and not used as a prototype - * directly. - * @param {Object} classProperties The class properties for the new - * module constructor. - * @optional - * @param {Object} moduleInit The module initialization functions - * for the new module. Each function is called as soon as the named module - * has been initialized, but after the module itself. The constructors are - * guaranteed to be called in the same order that the dependent modules - * were initialized. - * @optional - * - * @returns {function} The constructor for the resulting module. - */ - function Module(name) { - let args = Array.slice(arguments); - - var base = ModuleBase; - if (callable(args[1])) - base = args.splice(1, 1)[0]; - let [, prototype, classProperties, moduleInit] = args; - const module = Class(name, base, prototype, classProperties); - - module.INIT = moduleInit || {}; - module.modules = modules; - module.prototype.INIT = module.INIT; - module.requires = prototype.requires || []; - Module.list.push(module); - Module.constructors[name] = module; - return module; - } - Module.list = []; - Module.constructors = {}; - - const BASE = "resource://dactyl-content/"; - - const create = window.Object.create || (function () { - window.__dactyl_eval_string = "(function (proto) ({ __proto__: proto }))"; - JSMLoader.loadSubScript(BASE + "eval.js", window); - - let res = window.__dactyl_eval_result; - delete window.__dactyl_eval_string; - delete window.__dactyl_eval_result; - return res; - })(); - - const jsmodules = { NAME: "jsmodules" }; - const modules = update(create(jsmodules), { - yes_i_know_i_should_not_report_errors_in_these_branches_thanks: [], - - jsmodules: jsmodules, - - get content() this.config.browser.contentWindow || window.content, - - window: window, - - Module: Module, - - load: function load(script) { - for (let [i, base] in Iterator(prefix)) { - try { - JSMLoader.loadSubScript(base + script + ".js", modules, "UTF-8"); - return; - } - catch (e) { - if (typeof e !== "string") { - util.dump("Trying: " + (base + script + ".js") + ":"); - util.reportError(e); - } - } - } - try { - require(jsmodules, script); - } - catch (e) { - util.dump("Loading script " + script + ":"); - util.reportError(e); - } - }, - - newContext: function newContext(proto, normal) { - if (normal) - return create(proto); - let sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules, wantXrays: false }); - // Hack: - sandbox.Object = jsmodules.Object; - sandbox.Math = jsmodules.Math; - sandbox.__proto__ = proto || modules; - return sandbox; - }, - - get ownPropertyValues() array.compact( - Object.getOwnPropertyNames(this) - .map(function (name) Object.getOwnPropertyDescriptor(this, name).value, this)), - - get moduleList() this.ownPropertyValues.filter(function (mod) mod instanceof this.ModuleBase || mod.isLocalModule, this) - }); - modules.plugins = create(modules); - modules.modules = modules; - window.dactyl = { modules: modules }; - - let prefix = [BASE, "resource://dactyl-local-content/"]; - - defineModule.time("load", null, function _load() { - config.modules.global - .forEach(function (name) defineModule.time("load", name, require, null, jsmodules, name)); - - config.modules.window - .forEach(function (name) defineModule.time("load", name, modules.load, modules, name)); - }, this); - }, - load: function onLoad(document) { - // This is getting to be horrible. --Kris - - var { modules, Module } = window.dactyl.modules; - delete window.dactyl; - - this.startTime = Date.now(); - const deferredInit = { load: {} }; - const seen = Set(); - const loaded = Set(); - modules.loaded = loaded; - - function load(module, prereq, frame) { - if (isString(module)) { - if (!Module.constructors.hasOwnProperty(module)) - modules.load(module); - module = Module.constructors[module]; - } - - try { - if (module.className in loaded) - return; - if (module.className in seen) - throw Error("Module dependency loop."); - Set.add(seen, module.className); - - for (let dep in values(module.requires)) - load(Module.constructors[dep], module.className); - - defineModule.loadLog.push("Load" + (isString(prereq) ? " " + prereq + " dependency: " : ": ") + module.className); - if (frame && frame.filename) - defineModule.loadLog.push(" from: " + util.fixURI(frame.filename) + ":" + frame.lineNumber); - - let obj = defineModule.time(module.className, "init", module); - Class.replaceProperty(modules, module.className, obj); - loaded[module.className] = true; - - if (loaded.dactyl && obj.signals) - modules.dactyl.registerObservers(obj); - - frob(module.className); - } - catch (e) { - util.dump("Loading " + (module && module.className) + ":"); - util.reportError(e); - } - return modules[module.className]; - } - - function deferInit(name, INIT, mod) { - let init = deferredInit[name] = deferredInit[name] || {}; - let className = mod.className || mod.constructor.className; - - init[className] = function callee() { - if (!callee.frobbed) - defineModule.time(className, name, INIT[name], mod, - modules.dactyl, modules, window); - callee.frobbed = true; - }; - - INIT[name].require = function (name) { init[name](); }; - } - - function frobModules() { - Module.list.forEach(function frobModule(mod) { - if (!mod.frobbed) { - modules.__defineGetter__(mod.className, function () { - delete modules[mod.className]; - return load(mod.className, null, Components.stack.caller); - }); - Object.keys(mod.prototype.INIT) - .forEach(function (name) { deferInit(name, mod.prototype.INIT, mod); }); - } - mod.frobbed = true; - }); - } - defineModule.modules.forEach(function defModule(mod) { - let names = Set(Object.keys(mod.INIT)); - if ("init" in mod.INIT) - Set.add(names, "init"); - - keys(names).forEach(function (name) { deferInit(name, mod.INIT, mod); }); - }); - - function frob(name) { values(deferredInit[name] || {}).forEach(call); } - this.frob = frob; - this.modules = modules; - - frobModules(); - frob("init"); - - modules.config.scripts.forEach(modules.load); - - frobModules(); - - defineModule.modules.forEach(function defModule({ lazyInit, constructor: { className } }) { - if (!lazyInit) { - frob(className); - Class.replaceProperty(modules, className, modules[className]); - } - else - modules.__defineGetter__(className, function () { - delete modules[className]; - frob(className); - return modules[className] = modules[className]; - }); - }); - - modules.events.listen(window, "unload", function onUnload() { - window.removeEventListener("unload", onUnload.wrapped, false); - - overlay.windows = overlay.windows.filter(function (w) w != window); - - for each (let mod in modules.moduleList.reverse()) { - mod.stale = true; - - if ("destroy" in mod) - util.trapErrors("destroy", mod); - } - }, false); - }, - visible: function visible(window) { - // Module.list.forEach(load); - this.frob("load"); - this.modules.times = update({}, defineModule.times); - - defineModule.loadLog.push("Loaded in " + (Date.now() - this.startTime) + "ms"); - - overlay.windows = array.uniq(overlay.windows.concat(window), true); - } - })); - }, - - cleanup: function cleanup() { + cleanup: function cleanup(reason) { for (let doc in util.iterDocuments()) { for (let elem in values(this.getData(doc, "overlayElements"))) if (elem.parentNode) @@ -328,6 +62,9 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen if (getAttr(elem, ns, name) === value) setAttr(elem, ns, name, orig); + for (let callback in values(this.getData(doc, "cleanup"))) + util.trapErrors(callback, doc, reason); + delete doc[this.id]; delete doc.defaultView[this.id]; } @@ -357,7 +94,7 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen if (!(id in obj)) obj[id] = {}; - if (!(key in obj[id])) + if (obj[id][key] === undefined) obj[id][key] = (constructor || Array)(); return obj[id][key]; @@ -419,7 +156,7 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen for (let [elem, xml, attr] in iterator) { if (elem = doc.getElementById(elem)) { - let node = util.xmlToDom(xml, doc, obj.objects); + let node = DOM.fromXML(xml, doc, obj.objects); if (!(node instanceof Ci.nsIDOMDocumentFragment)) elems.push(node); else @@ -444,14 +181,14 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen insert("after", function (elem, dom) elem.parentNode.insertBefore(dom, elem.nextSibling)); insert("append", function (elem, dom) elem.appendChild(dom)); insert("prepend", function (elem, dom) elem.insertBefore(dom, elem.firstChild)); - if (obj.init) - obj.init(window); + if (obj.ready) + util.trapErrors("ready", obj, window); function load(event) { - obj.load(window, event); + util.trapErrors("load", obj, window, event); if (obj.visible) if (!event || !overlay.onWindowVisible || window != util.topWindow(window)) - obj.visible(window); + util.trapErrors("visible", obj, window); else overlay.onWindowVisible.push(function () { obj.visible(window) }); } @@ -466,6 +203,21 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen load(event); } }), true); + + if (obj.unload || obj.cleanup) + this.listen(window, "unload", function unload(event) { + if (event.originalTarget === doc) { + overlay.unlisten(window, "unload", unload); + if (obj.unload) + util.trapErrors("unload", obj, window, event); + + if (obj.cleanup) + util.trapErrors("cleanup", obj, window, "unload", event); + } + }); + + if (obj.cleanup) + this.getData(doc, "cleanup").push(bind("cleanup", obj, window)); }, /** diff --git a/common/modules/protocol.jsm b/common/modules/protocol.jsm index da0ce1f3..06d25498 100644 --- a/common/modules/protocol.jsm +++ b/common/modules/protocol.jsm @@ -12,7 +12,7 @@ defineModule("protocol", { var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].getService(Ci.nsIPrincipal); -function Channel(url, orig, noErrorChannel) { +function Channel(url, orig, noErrorChannel, unprivileged) { try { if (url == null) return noErrorChannel ? null : NetError(orig); @@ -97,6 +97,17 @@ ProtocolBase.prototype = { get classDescription() this.scheme + " utility protocol", QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]), + purge: function purge() { + for (let doc in util.iterDocuments()) + try { + if (doc.documentURIObject.scheme == this.scheme) + doc.defaultView.close(); + } + catch (e) { + util.reportError(e); + } + }, + defaultPort: -1, allowPort: function (port, scheme) false, protocolFlags: 0 @@ -151,7 +162,7 @@ function StringChannel(data, contentType, uri) { return channel; } -function XMLChannel(uri, contentType, noErrorChannel) { +function XMLChannel(uri, contentType, noErrorChannel, unprivileged) { try { var channel = services.io.newChannelFromURI(uri); var channelStream = channel.open(); @@ -170,13 +181,14 @@ function XMLChannel(uri, contentType, noErrorChannel) { this.channel.contentStream = this.pipe.inputStream; this.channel.contentType = contentType || channel.contentType; this.channel.contentCharset = "UTF-8"; + if (!unprivileged) this.channel.owner = systemPrincipal; let stream = services.InputStream(channelStream); - let [, pre, doctype, url, open, post] = util.regexp(\s]|\s[^[])*)) (\s+ \[)? ([^]*) )? @@ -184,14 +196,18 @@ function XMLChannel(uri, contentType, noErrorChannel) { ]]>, "x").exec(stream.read(4096)); this.writes.push(pre); if (doctype) { - this.writes.push(doctype + "[\n"); - try { - this.writes.push(services.io.newChannel(url, null, null).open()); - } - catch (e) {} + this.writes.push(doctype + (extra || "") + " [\n"); + if (url) + this.addChannel(url); + if (!open) this.writes.push("\n]"); - this.writes.push(post); + + for (let [, pre, url] in util.regexp.iterate(/([^]*?)(?:%include\s+"([^"]*)";|$)/gy, post)) { + this.writes.push(pre); + if (url) + this.addChannel(url); + } } this.writes.push(channelStream); @@ -199,6 +215,16 @@ function XMLChannel(uri, contentType, noErrorChannel) { } XMLChannel.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver]), + + addChannel: function addChannel(url) { + try { + this.writes.push(services.io.newChannel(url, null, this.uri).open()); + } + catch (e) { + util.reportError(e); + } + }, + writeNext: function () { try { if (!this.writes.length) diff --git a/common/modules/sanitizer.jsm b/common/modules/sanitizer.jsm index 22552b3b..37ae8de6 100644 --- a/common/modules/sanitizer.jsm +++ b/common/modules/sanitizer.jsm @@ -215,7 +215,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef } }, - init: function (win) { + ready: function ready(win) { let elem = win.document.getElementById("itemList"); elem.setAttribute("rows", elem.itemCount); win.Sanitizer = Class("Sanitizer", win.Sanitizer, { diff --git a/common/modules/util.jsm b/common/modules/util.jsm index bd9e6ef0..2655a8c2 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -60,6 +60,29 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), overlayObject: deprecated("overlay.overlayObject", { get: function overlayObject() overlay.closure.overlayObject }), overlayWindow: deprecated("overlay.overlayWindow", { get: function overlayWindow() overlay.closure.overlayWindow }), + compileMatcher: deprecated("DOM.compileMatcher", { get: function compileMatcher() DOM.compileMatcher }), + computedStyle: deprecated("DOM#style", function computedStyle(elem) DOM(elem).style), + domToString: deprecated("DOM.stringify", { get: function domToString() DOM.stringify }), + editableInputs: deprecated("DOM.editableInputs", { get: function editableInputs(elem) DOM.editableInputs }), + escapeHTML: deprecated("DOM.escapeHTML", { get: function escapeHTML(elem) DOM.escapeHTML }), + evaluateXPath: deprecated("DOM.XPath", + function evaluateXPath(path, elem, asIterator) DOM.XPath(path, elem || util.activeWindow.content.document, asIterator)), + isVisible: deprecated("DOM#isVisible", function isVisible(elem) DOM(elem).isVisible), + makeXPath: deprecated("DOM.makeXPath", { get: function makeXPath(elem) DOM.makeXPath }), + namespaces: deprecated("DOM.namespaces", { get: function namespaces(elem) DOM.namespaces }), + namespaceNames: deprecated("DOM.namespaceNames", { get: function namespaceNames(elem) DOM.namespaceNames }), + parseForm: deprecated("DOM#formData", function parseForm(elem) values(DOM(elem).formData).toArray()), + scrollIntoView: deprecated("DOM#scrollIntoView", function scrollIntoView(elem, alignWithTop) DOM(elem).scrollIntoView(alignWithTop)), + validateMatcher: deprecated("DOM.validateMatcher", { get: function validateMatcher() DOM.validateMatcher }), + + map: deprecated("iter.map", function map(obj, fn, self) iter(obj).map(fn, self).toArray()), + writeToClipboard: deprecated("dactyl.clipboardWrite", function writeToClipboard(str, verbose) util.dactyl.clipboardWrite(str, verbose)), + readFromClipboard: deprecated("dactyl.clipboardRead", function readFromClipboard() util.dactyl.clipboardRead(false)), + + chromePackages: deprecated("config.chromePackages", { get: function chromePackages() config.chromePackages }), + haveGecko: deprecated("config.haveGecko", { get: function haveGecko() config.closure.haveGecko }), + OS: deprecated("config.OS", { get: function OS() config.OS }), + dactyl: update(function dactyl(obj) { if (obj) var global = Class.objectGlobal(obj); @@ -375,25 +398,6 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), return stack.top; }, - compileMatcher: deprecated("DOM.compileMatcher", { get: function compileMatcher() DOM.compileMatcher }), - computedStyle: deprecated("DOM#style", function computedStyle(elem) DOM(elem).style), - domToString: deprecated("DOM.stringify", { get: function domToString() DOM.stringify }), - editableInputs: deprecated("DOM.editableInputs", { get: function editableInputs(elem) DOM.editableInputs }), - escapeHTML: deprecated("DOM.escapeHTML", { get: function escapeHTML(elem) DOM.escapeHTML }), - evaluateXPath: deprecated("DOM.XPath", - function evaluateXPath(path, elem, asIterator) DOM.XPath(path, elem || util.activeWindow.content.document, asIterator)), - isVisible: deprecated("DOM#isVisible", function isVisible(elem) DOM(elem).isVisible), - makeXPath: deprecated("DOM.makeXPath", { get: function makeXPath(elem) DOM.makeXPath }), - namespaces: deprecated("DOM.namespaces", { get: function namespaces(elem) DOM.namespaces }), - namespaceNames: deprecated("DOM.namespaceNames", { get: function namespaceNames(elem) DOM.namespaceNames }), - parseForm: deprecated("DOM#formData", function parseForm(elem) values(DOM(elem).formData).toArray()), - scrollIntoView: deprecated("DOM#scrollIntoView", function scrollIntoView(elem, alignWithTop) DOM(elem).scrollIntoView(alignWithTop)), - validateMatcher: deprecated("DOM.validateMatcher", { get: function validateMatcher() DOM.validateMatcher }), - - chromePackages: deprecated("config.chromePackages", { get: function chromePackages() config.chromePackages }), - haveGecko: deprecated("config.haveGecko", { get: function haveGecko() config.closure.haveGecko }), - OS: deprecated("config.OS", { get: function OS() config.OS }), - /** * Converts any arbitrary string into an URI object. Returns null on * failure. @@ -826,10 +830,6 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), "'>"].join("")) .join("\n"), - map: deprecated("iter.map", function map(obj, fn, self) iter(obj).map(fn, self).toArray()), - writeToClipboard: deprecated("dactyl.clipboardWrite", function writeToClipboard(str, verbose) util.dactyl.clipboardWrite(str, verbose)), - readFromClipboard: deprecated("dactyl.clipboardRead", function readFromClipboard() util.dactyl.clipboardRead(false)), - /** * Converts a URI string into a URI object. *