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 && "@mozilla.org/fuel/application;1" in Components.classes)
18 JSMLoader = Components.classes["@mozilla.org/fuel/application;1"]
19 .getService(Components.interfaces.extIApplication)
20 .storage.get("dactyl.JSMLoader", null);
22 if (JSMLoader && JSMLoader.bump === 5)
23 JSMLoader.global = this;
28 builtin: Cu.Sandbox(this),
36 globals: JSMLoader ? JSMLoader.globals : {},
38 io: Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService),
40 loader: Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader),
42 manager: Components.manager.QueryInterface(Ci.nsIComponentRegistrar),
44 modules: JSMLoader && JSMLoader.modules || {},
46 stale: JSMLoader ? JSMLoader.stale : {},
52 add: function add(major, minor, delta) {
55 this[major] = (this[major] || 0) + delta;
58 this[minor] = (this[minor] || 0) + delta;
59 this[major + minor] = (this[major + minor] || 0) + delta;
62 clear: function clear() {
64 if (typeof this[key] !== "number")
69 init: function init(suffix) {
70 this.initialized = true;
71 this.suffix = suffix || "";
73 let base = this.load("base.jsm", this.global);
74 this.global.EXPORTED_SYMBOLS = base.EXPORTED_SYMBOLS;
75 this.global.JSMLoader = this;
76 base.JSMLoader = this;
79 getTarget: function getTarget(url) {
80 if (url.indexOf(":") === -1)
81 url = "resource://dactyl" + this.suffix + "/" + url;
83 let chan = this.io.newChannel(url, null, null);
84 chan.cancel(Cr.NS_BINDING_ABORTED);
88 load: function load(name, target) {
90 if (url.indexOf(":") === -1)
91 url = "resource://dactyl" + this.suffix + "/" + url;
92 let targetURL = this.getTarget(url);
94 let stale = this.stale[name] || this.stale[targetURL];
96 delete this.stale[name];
97 delete this.stale[targetURL];
99 let loadURL = url.replace(RegExp("^(resource://dactyl)/"), "$1" + this.suffix + "/");
101 let global = this.globals[name];
102 if (stale === targetURL)
103 this.loadSubScript(loadURL, global.global || global);
107 let now = Date.now();
108 this.modules[url] = true;
109 let global = Cu.import(url, target);
111 if (!(name in this.globals))
112 this.times.add("require", name, Date.now() - now);
114 return this.globals[name] = global;
117 dump("Importing " + url + ": " + e + "\n" + (e.stack || Error().stack));
122 loadSubScript: function loadSubScript(script) {
123 let now = Date.now();
124 this.loader.loadSubScript.apply(this.loader, arguments);
125 this.times.add("loadSubScript", script, Date.now() - now);
128 cleanup: function unregister() {
129 for each (let factory in this.factories.splice(0))
130 this.manager.unregisterFactory(factory.classID, factory);
133 purge: function purge() {
134 dump("dactyl: JSMLoader: purge\n");
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 registerFactory: function registerFactory(factory) {
171 this.manager.registerFactory(factory.classID,
172 String(factory.classID),
175 this.factories.push(factory);
179 }catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
181 // vim: set fdm=marker sw=4 sts=4 et ft=javascript: