]> git.donarmstrong.com Git - dactyl.git/blob - common/modules/bootstrap.jsm
Import 1.0b7.1 supporting Firefox up to 8.*
[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 && "@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);
21
22 if (JSMLoader && JSMLoader.bump === 5)
23     JSMLoader.global = this;
24 else
25     JSMLoader = {
26         bump: 5,
27
28         builtin: Cu.Sandbox(this),
29
30         canonical: {},
31
32         factories: [],
33
34         global: this,
35
36         globals: JSMLoader ? JSMLoader.globals : {},
37
38         io: Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService),
39
40         loader: Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader),
41
42         manager: Components.manager.QueryInterface(Ci.nsIComponentRegistrar),
43
44         modules: JSMLoader && JSMLoader.modules || {},
45
46         stale: JSMLoader ? JSMLoader.stale : {},
47
48         suffix: "",
49
50         times: {
51             all: 0,
52             add: function add(major, minor, delta) {
53                 this.all += delta;
54
55                 this[major] = (this[major] || 0) + delta;
56                 if (minor) {
57                     minor = ":" + minor;
58                     this[minor] = (this[minor] || 0) + delta;
59                     this[major + minor] = (this[major + minor] || 0) + delta;
60                 }
61             },
62             clear: function clear() {
63                 for (let key in this)
64                     if (typeof this[key] !== "number")
65                         delete this[key];
66             }
67         },
68
69         init: function init(suffix) {
70             this.initialized = true;
71             this.suffix = suffix || "";
72
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;
77         },
78
79         getTarget: function getTarget(url) {
80             if (url.indexOf(":") === -1)
81                 url = "resource://dactyl" + this.suffix + "/" + url;
82
83             let chan = this.io.newChannel(url, null, null);
84             chan.cancel(Cr.NS_BINDING_ABORTED);
85             return chan.name;
86         },
87
88         load: function load(name, target) {
89             let url = name;
90             if (url.indexOf(":") === -1)
91                 url = "resource://dactyl" + this.suffix + "/" + url;
92             let targetURL = this.getTarget(url);
93
94             let stale = this.stale[name] || this.stale[targetURL];
95             if (stale) {
96                 delete this.stale[name];
97                 delete this.stale[targetURL];
98
99                 let loadURL = url.replace(RegExp("^(resource://dactyl)/"), "$1" + this.suffix + "/");
100
101                 let global = this.globals[name];
102                 if (stale === targetURL)
103                     this.loadSubScript(loadURL, global.global || global);
104             }
105
106             try {
107                 let now = Date.now();
108                 this.modules[url] = true;
109                 let global = Cu.import(url, target);
110
111                 if (!(name in this.globals))
112                     this.times.add("require", name, Date.now() - now);
113
114                 return this.globals[name] = global;
115             }
116             catch (e) {
117                 dump("Importing " + url + ": " + e + "\n" + (e.stack || Error().stack));
118                 throw e;
119             }
120         },
121
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);
126         },
127
128         cleanup: function unregister() {
129             for each (let factory in this.factories.splice(0))
130                 this.manager.unregisterFactory(factory.classID, factory);
131         },
132
133         purge: function purge() {
134             dump("dactyl: JSMLoader: purge\n");
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         registerFactory: function registerFactory(factory) {
171             this.manager.registerFactory(factory.classID,
172                                          String(factory.classID),
173                                          factory.contractID,
174                                          factory);
175             this.factories.push(factory);
176         }
177     };
178
179 }catch(e){ dump(e + "\n" + (e.stack || Error().stack)); Components.utils.reportError(e) }
180
181 // vim: set fdm=marker sw=4 sts=4 et ft=javascript: