]> git.donarmstrong.com Git - dactyl.git/blob - common/modules/bootstrap.jsm
Import 1.0 supporting Firefox up to 14.*
[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)
127                 this.manager.unregisterFactory(factory.classID, factory);
128             this.factories = {};
129         },
130
131         purge: function purge() {
132             dump("dactyl: JSMLoader: purge\n");
133
134             this.bootstrap = null;
135
136             if (Cu.unload) {
137                 Object.keys(this.modules).reverse().forEach(function (url) {
138                     try {
139                         Cu.unload(url);
140                     }
141                     catch (e) {
142                         Cu.reportError(e);
143                     }
144                 });
145             }
146             else {
147                 for (let [url, global] in Iterator(this.globals)) {
148                     if (url === "bootstrap.jsm" || url === "resource://dactyl/bootstrap.jsm")
149                         continue;
150
151                     let target = this.getTarget(url);
152                     this.stale[url] = target;
153                     this.stale[target] = target;
154
155                     for each (let prop in Object.getOwnPropertyNames(global))
156                         try {
157                             if (!(prop in this.builtin) &&
158                                 ["JSMLoader", "Set", "set", "EXPORTED_SYMBOLS"].indexOf(prop) < 0 &&
159                                 !global.__lookupGetter__(prop))
160                                 global[prop] = undefined;
161                         }
162                         catch (e) {
163                             dump("Deleting property " + prop + " on " + url + ":\n    " + e + "\n");
164                             Cu.reportError(e);
165                         }
166                 }
167             }
168         },
169
170         Factory: function Factory(clas) ({
171             __proto__: clas.prototype,
172
173             createInstance: function (outer, iid) {
174                 try {
175                     if (outer != null)
176                         throw Cr.NS_ERROR_NO_AGGREGATION;
177                     if (!clas.instance)
178                         clas.instance = new clas();
179                     return clas.instance.QueryInterface(iid);
180                 }
181                 catch (e) {
182                     Cu.reportError(e);
183                     throw e;
184                 }
185             }
186         }),
187
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]);
192
193             this.manager.registerFactory(factory.classID,
194                                          String(factory.classID),
195                                          factory.contractID,
196                                          factory);
197             this.factories[factory.contractID] = factory;
198         }
199     };
200
201 }catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
202
203 // vim: set fdm=marker sw=4 sts=4 et ft=javascript: