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)
127 this.manager.unregisterFactory(factory.classID, factory);
131 purge: function purge() {
132 dump("dactyl: JSMLoader: purge\n");
134 this.bootstrap = null;
137 Object.keys(this.modules).reverse().forEach(function (url) {
147 for (let [url, global] in Iterator(this.globals)) {
148 if (url === "bootstrap.jsm" || url === "resource://dactyl/bootstrap.jsm")
151 let target = this.getTarget(url);
152 this.stale[url] = target;
153 this.stale[target] = target;
155 for each (let prop in Object.getOwnPropertyNames(global))
157 if (!(prop in this.builtin) &&
158 ["JSMLoader", "Set", "set", "EXPORTED_SYMBOLS"].indexOf(prop) < 0 &&
159 !global.__lookupGetter__(prop))
160 global[prop] = undefined;
163 dump("Deleting property " + prop + " on " + url + ":\n " + e + "\n");
170 Factory: function Factory(clas) ({
171 __proto__: clas.prototype,
173 createInstance: function (outer, iid) {
176 throw Cr.NS_ERROR_NO_AGGREGATION;
178 clas.instance = new clas();
179 return clas.instance.QueryInterface(iid);
188 registerFactory: function registerFactory(factory) {
189 if (Set.has(this.factories, factory.contractID))
190 this.manager.unregisterFactory(this.factories[factory.contractID].classID,
191 this.factories[factory.contractID]);
193 this.manager.registerFactory(factory.classID,
194 String(factory.classID),
197 this.factories[factory.contractID] = factory;
201 }catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
203 // vim: set fdm=marker sw=4 sts=4 et ft=javascript: