1 // Copyright (c) 2011 by Kris Maglione <maglione.k@gmail.com>
3 // This work is licensed for reuse under an MIT license. Details are
4 // given in the LICENSE.txt file included with this file.
9 let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
11 var EXPORTED_SYMBOLS = ["JSMLoader"];
13 var BOOTSTRAP_CONTRACT = "@dactyl.googlecode.com/base/bootstrap";
14 var JSMLoader = BOOTSTRAP_CONTRACT in Components.classes &&
15 Components.classes[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader;
17 if (JSMLoader && JSMLoader.bump === 6)
18 JSMLoader.global = this;
23 builtin: Cu.Sandbox(this),
33 globals: JSMLoader ? JSMLoader.globals : {},
35 io: Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService),
37 loader: Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader),
39 manager: Components.manager.QueryInterface(Ci.nsIComponentRegistrar),
41 modules: JSMLoader && JSMLoader.modules || {},
43 stale: JSMLoader ? JSMLoader.stale : {},
49 add: function add(major, minor, delta) {
52 this[major] = (this[major] || 0) + delta;
55 this[minor] = (this[minor] || 0) + delta;
56 this[major + minor] = (this[major + minor] || 0) + delta;
59 clear: function clear() {
61 if (typeof this[key] !== "number")
66 init: function init(suffix) {
67 this.initialized = true;
68 this.suffix = suffix || "";
70 let base = this.load("base.jsm", this.global);
71 this.global.EXPORTED_SYMBOLS = base.EXPORTED_SYMBOLS;
72 this.global.JSMLoader = this;
73 base.JSMLoader = this;
76 getTarget: function getTarget(url) {
77 if (url.indexOf(":") === -1)
78 url = "resource://dactyl" + this.suffix + "/" + url;
80 let chan = this.io.newChannel(url, null, null);
81 chan.cancel(Cr.NS_BINDING_ABORTED);
85 load: function load(name, target) {
87 if (url.indexOf(":") === -1)
88 url = "resource://dactyl" + this.suffix + "/" + url;
89 let targetURL = this.getTarget(url);
91 let stale = this.stale[name] || this.stale[targetURL];
93 delete this.stale[name];
94 delete this.stale[targetURL];
96 let loadURL = url.replace(RegExp("^(resource://dactyl)/"), "$1" + this.suffix + "/");
98 let global = this.globals[name];
99 if (stale === targetURL)
100 this.loadSubScript(loadURL, global.global || global);
104 let now = Date.now();
105 this.modules[url] = true;
106 let global = Cu.import(url, target);
108 if (!(name in this.globals))
109 this.times.add("require", name, Date.now() - now);
111 return this.globals[name] = global;
114 dump("Importing " + url + ": " + e + "\n" + (e.stack || Error().stack));
119 loadSubScript: function loadSubScript(script) {
120 let now = Date.now();
121 this.loader.loadSubScript.apply(this.loader, arguments);
122 this.times.add("loadSubScript", script, Date.now() - now);
125 cleanup: function unregister() {
126 for each (let factory in this.factories.splice(0))
127 this.manager.unregisterFactory(factory.classID, factory);
130 purge: function purge() {
131 dump("dactyl: JSMLoader: purge\n");
133 this.bootstrap = null;
136 Object.keys(this.modules).reverse().forEach(function (url) {
146 for (let [url, global] in Iterator(this.globals)) {
147 if (url === "bootstrap.jsm" || url === "resource://dactyl/bootstrap.jsm")
150 let target = this.getTarget(url);
151 this.stale[url] = target;
152 this.stale[target] = target;
154 for each (let prop in Object.getOwnPropertyNames(global))
156 if (!(prop in this.builtin) &&
157 ["JSMLoader", "Set", "set", "EXPORTED_SYMBOLS"].indexOf(prop) < 0 &&
158 !global.__lookupGetter__(prop))
159 global[prop] = undefined;
162 dump("Deleting property " + prop + " on " + url + ":\n " + e + "\n");
169 Factory: function Factory(clas) ({
170 __proto__: clas.prototype,
172 createInstance: function (outer, iid) {
175 throw Cr.NS_ERROR_NO_AGGREGATION;
177 clas.instance = new clas();
178 return clas.instance.QueryInterface(iid);
187 registerFactory: function registerFactory(factory) {
188 this.manager.registerFactory(factory.classID,
189 String(factory.classID),
192 this.factories.push(factory);
196 }catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
198 // vim: set fdm=marker sw=4 sts=4 et ft=javascript: