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 var EXPORTED_SYMBOLS = ["JSMLoader"];
11 var BOOTSTRAP_CONTRACT = "@dactyl.googlecode.com/base/bootstrap";
12 var JSMLoader = BOOTSTRAP_CONTRACT in Components.classes &&
13 Components.classes[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader;
15 if (!JSMLoader && "@mozilla.org/fuel/application;1" in Components.classes)
16 JSMLoader = Components.classes["@mozilla.org/fuel/application;1"]
17 .getService(Components.interfaces.extIApplication)
18 .storage.get("dactyl.JSMLoader", null);
20 if (JSMLoader && JSMLoader.bump === 4)
21 JSMLoader.global = this;
25 builtin: Components.utils.Sandbox(this),
29 globals: JSMLoader ? JSMLoader.globals : {},
30 io: Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService),
31 loader: Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader),
32 manager: Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar),
33 stale: JSMLoader ? JSMLoader.stale : {},
35 init: function init(suffix) {
36 this.initialized = true;
37 this.suffix = suffix || "";
39 let base = this.load("base.jsm", this.global);
40 this.global.EXPORTED_SYMBOLS = base.EXPORTED_SYMBOLS;
41 this.global.JSMLoader = this;
42 base.JSMLoader = this;
44 getTarget: function getTarget(url) {
45 if (url.indexOf(":") === -1)
46 url = "resource://dactyl" + this.suffix + "/" + url;
48 let chan = this.io.newChannel(url, null, null);
49 chan.cancel(Components.results.NS_BINDING_ABORTED);
52 load: function load(name, target) {
54 if (url.indexOf(":") === -1)
55 url = "resource://dactyl" + this.suffix + "/" + url;
56 let targetURL = this.getTarget(url);
58 let stale = this.stale[name] || this.stale[targetURL];
60 delete this.stale[name];
61 delete this.stale[targetURL];
63 let loadURL = url.replace(RegExp("^(resource://dactyl)/"), "$1" + this.suffix + "/");
65 let global = this.globals[name];
66 if (stale === targetURL)
67 this.loadSubScript(loadURL, global.global || global);
71 let global = Components.utils.import(url, target);
72 return this.globals[name] = global;
75 dump("Importing " + url + ": " + e + "\n" + (e.stack || Error().stack));
79 loadSubScript: function loadSubScript() this.loader.loadSubScript.apply(this.loader, arguments),
80 cleanup: function unregister() {
81 for each (let factory in this.factories.splice(0))
82 this.manager.unregisterFactory(factory.classID, factory);
84 purge: function purge() {
85 dump("dactyl: JSMLoader: purge\n");
87 for (let [url, global] in Iterator(this.globals)) {
88 if (url === "bootstrap.jsm" || url === "resource://dactyl/bootstrap.jsm")
91 let target = this.getTarget(url);
92 this.stale[url] = target;
93 this.stale[target] = target;
95 for each (let prop in Object.getOwnPropertyNames(global))
97 if (!(prop in this.builtin) &&
98 ["JSMLoader", "set", "EXPORTED_SYMBOLS"].indexOf(prop) < 0 &&
99 !global.__lookupGetter__(prop))
100 global[prop] = undefined;
103 dump("Deleting property " + prop + " on " + url + ":\n " + e + "\n");
104 Components.utils.reportError(e);
109 registerFactory: function registerFactory(factory) {
110 this.manager.registerFactory(factory.classID,
111 String(factory.classID),
114 this.factories.push(factory);
118 }catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
120 // vim: set fdm=marker sw=4 sts=4 et ft=javascript: