]> git.donarmstrong.com Git - dactyl.git/blob - common/modules/bootstrap.jsm
Import 1.0rc1 supporting Firefox up to 11.*
[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 let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
10
11 var EXPORTED_SYMBOLS = ["JSMLoader"];
12
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;
16
17 if (JSMLoader && JSMLoader.bump === 6)
18     JSMLoader.global = this;
19 else
20     JSMLoader = {
21         bump: 6,
22
23         builtin: Cu.Sandbox(this),
24
25         canonical: {},
26
27         factories: [],
28
29         name: "dactyl",
30
31         global: this,
32
33         globals: JSMLoader ? JSMLoader.globals : {},
34
35         io: Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService),
36
37         loader: Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader),
38
39         manager: Components.manager.QueryInterface(Ci.nsIComponentRegistrar),
40
41         modules: JSMLoader && JSMLoader.modules || {},
42
43         stale: JSMLoader ? JSMLoader.stale : {},
44
45         suffix: "",
46
47         times: {
48             all: 0,
49             add: function add(major, minor, delta) {
50                 this.all += delta;
51
52                 this[major] = (this[major] || 0) + delta;
53                 if (minor) {
54                     minor = ":" + minor;
55                     this[minor] = (this[minor] || 0) + delta;
56                     this[major + minor] = (this[major + minor] || 0) + delta;
57                 }
58             },
59             clear: function clear() {
60                 for (let key in this)
61                     if (typeof this[key] !== "number")
62                         delete this[key];
63             }
64         },
65
66         init: function init(suffix) {
67             this.initialized = true;
68             this.suffix = suffix || "";
69
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;
74         },
75
76         getTarget: function getTarget(url) {
77             if (url.indexOf(":") === -1)
78                 url = "resource://dactyl" + this.suffix + "/" + url;
79
80             let chan = this.io.newChannel(url, null, null);
81             chan.cancel(Cr.NS_BINDING_ABORTED);
82             return chan.name;
83         },
84
85         load: function load(name, target) {
86             let url = name;
87             if (url.indexOf(":") === -1)
88                 url = "resource://dactyl" + this.suffix + "/" + url;
89             let targetURL = this.getTarget(url);
90
91             let stale = this.stale[name] || this.stale[targetURL];
92             if (stale) {
93                 delete this.stale[name];
94                 delete this.stale[targetURL];
95
96                 let loadURL = url.replace(RegExp("^(resource://dactyl)/"), "$1" + this.suffix + "/");
97
98                 let global = this.globals[name];
99                 if (stale === targetURL)
100                     this.loadSubScript(loadURL, global.global || global);
101             }
102
103             try {
104                 let now = Date.now();
105                 this.modules[url] = true;
106                 let global = Cu.import(url, target);
107
108                 if (!(name in this.globals))
109                     this.times.add("require", name, Date.now() - now);
110
111                 return this.globals[name] = global;
112             }
113             catch (e) {
114                 dump("Importing " + url + ": " + e + "\n" + (e.stack || Error().stack));
115                 throw e;
116             }
117         },
118
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);
123         },
124
125         cleanup: function unregister() {
126             for each (let factory in this.factories.splice(0))
127                 this.manager.unregisterFactory(factory.classID, factory);
128         },
129
130         purge: function purge() {
131             dump("dactyl: JSMLoader: purge\n");
132
133             this.bootstrap = null;
134
135             if (Cu.unload) {
136                 Object.keys(this.modules).reverse().forEach(function (url) {
137                     try {
138                         Cu.unload(url);
139                     }
140                     catch (e) {
141                         Cu.reportError(e);
142                     }
143                 });
144             }
145             else {
146                 for (let [url, global] in Iterator(this.globals)) {
147                     if (url === "bootstrap.jsm" || url === "resource://dactyl/bootstrap.jsm")
148                         continue;
149
150                     let target = this.getTarget(url);
151                     this.stale[url] = target;
152                     this.stale[target] = target;
153
154                     for each (let prop in Object.getOwnPropertyNames(global))
155                         try {
156                             if (!(prop in this.builtin) &&
157                                 ["JSMLoader", "Set", "set", "EXPORTED_SYMBOLS"].indexOf(prop) < 0 &&
158                                 !global.__lookupGetter__(prop))
159                                 global[prop] = undefined;
160                         }
161                         catch (e) {
162                             dump("Deleting property " + prop + " on " + url + ":\n    " + e + "\n");
163                             Cu.reportError(e);
164                         }
165                 }
166             }
167         },
168
169         Factory: function Factory(clas) ({
170             __proto__: clas.prototype,
171
172             createInstance: function (outer, iid) {
173                 try {
174                     if (outer != null)
175                         throw Cr.NS_ERROR_NO_AGGREGATION;
176                     if (!clas.instance)
177                         clas.instance = new clas();
178                     return clas.instance.QueryInterface(iid);
179                 }
180                 catch (e) {
181                     Cu.reportError(e);
182                     throw e;
183                 }
184             }
185         }),
186
187         registerFactory: function registerFactory(factory) {
188             this.manager.registerFactory(factory.classID,
189                                          String(factory.classID),
190                                          factory.contractID,
191                                          factory);
192             this.factories.push(factory);
193         }
194     };
195
196 }catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
197
198 // vim: set fdm=marker sw=4 sts=4 et ft=javascript: