]> git.donarmstrong.com Git - dactyl.git/blob - common/modules/bootstrap.jsm
005ba1624c5ef86dc2a3177863f76aef47b27452
[dactyl.git] / common / modules / bootstrap.jsm
1 // Copyright (c) 2011 by Kris Maglione <maglione.k@gmail.com>
2 //
3 // This work is licensed for reuse under an MIT license. Details are
4 // given in the LICENSE.txt file included with this file.
5 "use strict";
6
7 try {
8
9 var EXPORTED_SYMBOLS = ["JSMLoader"];
10
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;
14
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);
19
20 if (JSMLoader && JSMLoader.bump === 4)
21     JSMLoader.global = this;
22 else
23     JSMLoader = {
24         bump: 4,
25         builtin: Components.utils.Sandbox(this),
26         canonical: {},
27         factories: [],
28         global: 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 : {},
34         suffix: "",
35         init: function init(suffix) {
36             this.initialized = true;
37             this.suffix = suffix || "";
38
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;
43         },
44         getTarget: function getTarget(url) {
45             if (url.indexOf(":") === -1)
46                 url = "resource://dactyl" + this.suffix + "/" + url;
47
48             let chan = this.io.newChannel(url, null, null);
49             chan.cancel(Components.results.NS_BINDING_ABORTED);
50             return chan.name;
51         },
52         load: function load(name, target) {
53             let url = name;
54             if (url.indexOf(":") === -1)
55                 url = "resource://dactyl" + this.suffix + "/" + url;
56             let targetURL = this.getTarget(url);
57
58             let stale = this.stale[name] || this.stale[targetURL];
59             if (stale) {
60                 delete this.stale[name];
61                 delete this.stale[targetURL];
62
63                 let loadURL = url.replace(RegExp("^(resource://dactyl)/"), "$1" + this.suffix + "/");
64
65                 let global = this.globals[name];
66                 if (stale === targetURL)
67                     this.loadSubScript(loadURL, global.global || global);
68             }
69
70             try {
71                 let global = Components.utils.import(url, target);
72                 return this.globals[name] = global;
73             }
74             catch (e) {
75                 dump("Importing " + url + ": " + e + "\n" + (e.stack || Error().stack));
76                 throw e;
77             }
78         },
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);
83         },
84         purge: function purge() {
85             dump("dactyl: JSMLoader: purge\n");
86
87             for (let [url, global] in Iterator(this.globals)) {
88                 if (url === "bootstrap.jsm" || url === "resource://dactyl/bootstrap.jsm")
89                     continue;
90
91                 let target = this.getTarget(url);
92                 this.stale[url] = target;
93                 this.stale[target] = target;
94
95                 for each (let prop in Object.getOwnPropertyNames(global))
96                     try {
97                         if (!(prop in this.builtin) &&
98                             ["JSMLoader", "set", "EXPORTED_SYMBOLS"].indexOf(prop) < 0 &&
99                             !global.__lookupGetter__(prop))
100                             global[prop] = undefined;
101                     }
102                     catch (e) {
103                         dump("Deleting property " + prop + " on " + url + ":\n    " + e + "\n");
104                         Components.utils.reportError(e);
105                     }
106             }
107         },
108
109         registerFactory: function registerFactory(factory) {
110             this.manager.registerFactory(factory.classID,
111                                          String(factory.classID),
112                                          factory.contractID,
113                                          factory);
114             this.factories.push(factory);
115         }
116     };
117
118 }catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
119
120 // vim: set fdm=marker sw=4 sts=4 et ft=javascript: