fix some jsconsole warnings
[conkeror.git] / components / application.js
blob48c7daecc34e96cf7429f83b649ef4971bcbb758
1 /**
2  * (C) Copyright 2007,2010 John J. Foerch
3  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
4  *
5  * Use, modification, and distribution are subject to the terms specified in the
6  * COPYING file.
7 **/
9 const Cc = Components.classes;
10 const Ci = Components.interfaces;
11 const Cr = Components.results;
12 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
14 function application () {
15     Components.utils.import("resource://gre/modules/XPCOMUtils.jsm", this);
17     this.wrappedJSObject = this;
18     this.conkeror = this;
20     this.load_url = this.subscript_loader.loadSubScript;
21     this.loading_urls = [];
22     this.loading_paths = [];
23     this.loading_modules = [];
24     this.loading_features = [];
25     this.features = {};
26     this.load_paths = [this.module_uri_prefix,
27                        this.module_uri_prefix+'extensions',
28                        this.module_uri_prefix+'page-modes'];
29     this.after_load_functions = {};
30     this.pending_loads = [];
32     this.module_assert_conflict_error.prototype = Error.prototype;
34     try {
35         this.require("conkeror.js", null);
36     } catch (e) {
37         this.dumpln("Error initializing.");
38         this.dump_error(e);
39     }
41 application.prototype = {
42     Cc: Cc,
43     Ci: Ci,
44     Cr: Cr,
45     /* Note: resource://app currently doesn't result in xpcnativewrappers=yes */
46     module_uri_prefix: "chrome://conkeror/content/",
47     subscript_loader: Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader),
48     preferences: Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService),
49     get version () {
50         var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
51             .getService(Ci.nsIURLFormatter);
52         return formatter.formatURL("%VERSION%");
53     },
54     dumpln: function (str) {
55         dump(str);
56         dump("\n");
57     },
58     dump_error: function (e) {
59         if (e instanceof Error) {
60             this.dumpln(e.name + ": " + e.message);
61             this.dumpln(e.fileName + ":" + e.lineNumber);
62             dump(e.stack);
63         } else if (e instanceof Ci.nsIException) {
64             this.dumpln(e.name + ": " + e.message);
65             var stack_frame = e.location;
66             while (stack_frame) {
67                 this.dumpln(stack_frame.name + "()@" + stack_frame.filename + ":" + stack_frame.lineNumber);
68                 stack_frame = stack_frame.caller;
69             }
70         } else {
71             this.dumpln("Error: " + e);
72         }
73     },
75     make_uri: function (uri, charset, base_uri) {
76         const io_service = Cc["@mozilla.org/network/io-service;1"]
77             .getService(Ci.nsIIOService2);
78         if (uri instanceof Ci.nsIURI)
79             return uri;
80         if (uri instanceof Ci.nsIFile)
81             return io_service.newFileURI(uri);
82         return io_service.newURI(uri, charset, base_uri);
83     },
84     skip_module_load: {},
85     load: function (module, as) {
86         var conkeror = this;
87         function module_scope () {
88             this.__proto__ = conkeror;
89             this.conkeror = conkeror;
90         }
91         function load1 (url, scope, path, as) {
92             var success;
93             try {
94                 this.loading_paths.unshift(path);
95                 this.loading_urls.unshift(url);
96                 this.loading_modules.unshift(as);
97                 this.loading_features.unshift({});
98                 if (this.loading_urls.indexOf(url, 1) != -1)
99                     throw new Error("Circular module dependency detected: "+
100                                     this.loading_urls.join(",\n"));
101                 this.load_url(url, scope);
102                 success = true;
103                 if (as)
104                     this[as] = scope;
105                 // call-after-load callbacks
106                 for (let f in this.loading_features[0]) {
107                     this.features[f] = true;
108                     this.run_after_load_functions(f);
109                 }
110             } finally {
111                 this.loading_paths.shift();
112                 this.loading_urls.shift();
113                 this.loading_modules.shift();
114                 this.loading_features.shift();
115             }
116             // do pending loads
117             if (success && this.loading_urls[0] === undefined) {
118                 let pending = this.pending_loads;
119                 this.pending_loads = [];
120                 for (let i = 0, m; m = pending[i]; ++i) {
121                     this.require(m[0], m[1]);
122                 }
123             }
124         }
125         var scope = as;
126         if (as == null)
127             scope = this;
128         else if (typeof as == 'string')
129             scope = new module_scope();
130         else
131             as = null;
132         var path, url;
133         if (module instanceof Ci.nsIURI)
134             path = module.path.substr(0, module.path.lastIndexOf('/')+1);
135         else if (module instanceof Ci.nsIFile)
136             path = module.parent.path;
137         var restarted = false;
138         if (path !== undefined) {
139             url = this.make_uri(module).spec;
140             do {
141                 try {
142                     load1.call(this, url, scope, path, as);
143                     return;
144                 } catch (e if e instanceof this.module_assert_error) {
145                     if (restarted)
146                         throw new this.module_assert_conflict_error(url);
147                     as = e.module;
148                     if (e.module)
149                         scope = new module_scope();
150                     else
151                         scope = this;
152                     restarted = true;
153                 } catch (e if e == this.skip_module_load) {
154                     return;
155                 }
156             } while (restarted);
157         } else {
158             // module name or relative path
159             var autoext = module.substr(-3) != '.js';
160             var suffix = false;
161             var i = -1;
162             var tried = {};
163             path = this.loading_paths[0];
164             if (path === undefined)
165                 path = this.load_paths[++i];
166             while (path !== undefined) {
167                 let opath = path;
168                 try {
169                     let sep = path[path.length-1] == '/' ? '' : '/';
170                     url = path + sep + module + (suffix ? '.js' : '');
171                     let si = module.lastIndexOf('/');
172                     if (si > -1)
173                         path += module.substr(0, si);
174                     if (! tried[url] || tried[url] !== scope) {
175                         tried[url] = scope;
176                         load1.call(this, url, scope, path, as);
177                         return;
178                     }
179                 } catch (e if e instanceof this.module_assert_error) {
180                     if (restarted)
181                         throw new this.module_assert_conflict_error(url);
182                     as = e.module;
183                     if (e.module)
184                         scope = new module_scope();
185                     else
186                         scope = this;
187                     path = opath;
188                     restarted = true;
189                     continue;
190                 } catch (e if (typeof e == 'string' &&
191                                {"ContentLength not available (not a local URL?)":true,
192                                 "Error creating channel (invalid URL scheme?)":true,
193                                 "Error opening input stream (invalid filename?)":true}
194                                [e])) {
195                     // null op. (suppress error, try next path)
196                 } catch (e if e == this.skip_module_load) {
197                     return;
198                 }
199                 if (autoext)
200                     suffix = !suffix;
201                 if (! suffix)
202                     path = this.load_paths[++i];
203             }
204             throw new Error("Module not found");
205         }
206     },
207     module_assert_error: function (module) {
208         this.module = module;
209     },
210     module_assert_conflict_error: function (url) { //subclass of Error
211         this.name = "module_assert_conflict_error";
212         this.message = "Conflicting in_module calls";
213         this.fileName = url;
214         this.lineNumber = '';
215     },
216     in_module: function (module) {
217         if (module != this.loading_modules[0])
218             throw new this.module_assert_error(module);
219     },
220     provide: function (symbol) {
221         if (! symbol)
222             throw new Error("Cannot provide null feature");
223         if (this.loading_urls[0] === undefined) {
224             this.features[symbol] = true;
225             this.run_after_load_functions(symbol);
226         } else
227             this.loading_features[0][symbol] = true;
228     },
229     featurep: function (symbol) {
230         return this.features[symbol] || false;
231     },
232     call_after_load: function (feature, func) {
233         if (this.featurep(feature))
234             func();
235         else {
236             var funcs = this.after_load_functions[feature];
237             if (! funcs)
238                 funcs = this.after_load_functions[feature] = [];
239             funcs.push(func);
240         }
241     },
242     run_after_load_functions: function (symbol) {
243         var funcs = this.after_load_functions[symbol];
244         if (funcs) {
245             delete this.after_load_functions[symbol];
246             for (var i = 0; funcs[i]; ++i) {
247                 try {
248                     funcs[i]();
249                 } catch (e) {
250                     dump_error(e);
251                 }
252             }
253         }
254     },
255     require: function (module, as) {
256         var feature = as;
257         if (! feature) {
258             if (module instanceof Ci.nsIURI)
259                 feature = module.spec.substr(module.spec.lastIndexOf('/')+1);
260             else if (module instanceof Ci.nsIFile)
261                 feature = module.leafName;
262             else
263                 feature = module.substr(module.lastIndexOf('/')+1);
264             let dot = feature.indexOf('.');
265             if (dot == 0)
266                 return false;
267             if (dot > 0)
268                 feature = feature.substr(0, dot);
269             feature = feature.replace('_', '-', 'g');
270         }
271         if (this.featurep(feature))
272             return true;
273         if (as === undefined)
274             as = feature.replace('-', '_', 'g');
275         try {
276             // ensure current path is not searched for 'require'
277             this.loading_paths.unshift(undefined);
278             this.load(module, as);
279         } finally {
280             this.loading_paths.shift();
281         }
282         return true;
283     },
284     require_later: function (module, as) {
285         this.pending_loads.push([module, as]);
286     },
288     /* nsISupports */
289     QueryInterface: XPCOMUtils.generateQI([]),
291     /* XPCOM registration */
292     classDescription: "Conkeror global object",
293     classID: Components.ID("{72a7eea7-a894-47ec-93a9-a7bc172cf1ac}"),
294     contractID: "@conkeror.mozdev.org/application;1"
297 function NSGetModule (compMgr, fileSpec) {
298     return XPCOMUtils.generateModule([application]);