2 * (C) Copyright 2007,2010 John J. Foerch
3 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
5 * Use, modification, and distribution are subject to the terms specified in the
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;
20 this.load_url = this.subscript_loader.loadSubScript;
21 this.loading_urls = [];
22 this.loading_paths = [];
23 this.loading_modules = [];
24 this.loading_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 // clear the startup-cache so that modules and the user's rc are
35 // loaded from disk, not from a cache. this problem is a
36 // characteristic of using mozIJSSubScriptLoader.loadSubScript as our
37 // primary means of loading, since XULRunner 8.0.
38 var obs = Cc["@mozilla.org/observer-service;1"]
39 .getService(Ci.nsIObserverService);
40 obs.notifyObservers(null, "startupcache-invalidate", null);
43 this.require("conkeror.js", null);
45 this.dumpln("Error initializing.");
49 application.prototype = {
50 constructor: application,
54 /* Note: resource://app currently doesn't result in xpcnativewrappers=yes */
55 module_uri_prefix: "chrome://conkeror/content/",
56 subscript_loader: Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader),
57 preferences: Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService),
59 var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
60 .getService(Ci.nsIURLFormatter);
61 return formatter.formatURL("%VERSION%");
63 dumpln: function (str) {
67 dump_error: function (e) {
68 if (e instanceof Error) {
69 this.dumpln(e.name + ": " + e.message);
70 this.dumpln(e.fileName + ":" + e.lineNumber);
72 } else if (e instanceof Ci.nsIException) {
73 this.dumpln(e.name + ": " + e.message);
74 var stack_frame = e.location;
76 this.dumpln(stack_frame.name + "()@" + stack_frame.filename + ":" + stack_frame.lineNumber);
77 stack_frame = stack_frame.caller;
80 this.dumpln("Error: " + e);
84 make_uri: function (uri, charset, base_uri) {
85 const io_service = Cc["@mozilla.org/network/io-service;1"]
86 .getService(Ci.nsIIOService2);
87 if (uri instanceof Ci.nsIURI)
89 if (uri instanceof Ci.nsIFile)
90 return io_service.newFileURI(uri);
91 return io_service.newURI(uri, charset, base_uri);
94 load: function (module, as) {
96 function module_scope () {
97 this.__proto__ = conkeror;
98 this.conkeror = conkeror;
100 function load1 (url, scope, path, as) {
103 this.loading_paths.unshift(path);
104 this.loading_urls.unshift(url);
105 this.loading_modules.unshift(as);
106 this.loading_features.unshift({});
107 if (this.loading_urls.indexOf(url, 1) != -1)
108 throw new Error("Circular module dependency detected: "+
109 this.loading_urls.join(",\n"));
110 this.load_url(url, scope);
114 // call-after-load callbacks
115 for (let f in this.loading_features[0]) {
116 this.features[f] = true;
117 this.run_after_load_functions(f);
120 this.loading_paths.shift();
121 this.loading_urls.shift();
122 this.loading_modules.shift();
123 this.loading_features.shift();
126 if (success && this.loading_urls[0] === undefined) {
127 let pending = this.pending_loads;
128 this.pending_loads = [];
129 for (let i = 0, m; m = pending[i]; ++i) {
130 this.require(m[0], m[1]);
137 else if (typeof as == 'string')
138 scope = new module_scope();
142 if (module instanceof Ci.nsIURI)
143 path = module.spec.substr(0, module.spec.lastIndexOf('/')+1);
144 else if (module instanceof Ci.nsIFile)
145 path = module.parent.path;
146 var restarted = false;
147 if (path !== undefined) {
148 url = this.make_uri(module).spec;
151 load1.call(this, url, scope, path, as);
153 } catch (e if e instanceof this.module_assert_error) {
155 throw new this.module_assert_conflict_error(url);
158 scope = new module_scope();
162 } catch (e if e == this.skip_module_load) {
167 // module name or relative path
168 var autoext = module.substr(-3) != '.js';
172 path = this.loading_paths[0];
173 if (path === undefined)
174 path = this.load_paths[++i];
175 while (path !== undefined) {
178 let sep = path.substr(-1) == '/' ? '' : '/';
179 url = path + sep + module + (suffix ? '.js' : '');
180 let si = module.lastIndexOf('/');
182 truepath += module.substr(0, si);
183 if (! tried[url] || tried[url] !== scope) {
185 load1.call(this, url, scope, truepath, as);
188 } catch (e if e instanceof this.module_assert_error) {
190 throw new this.module_assert_conflict_error(url);
193 scope = new module_scope();
198 } catch (e if (typeof e == 'string' &&
199 {"ContentLength not available (not a local URL?)":true,
200 "Error creating channel (invalid URL scheme?)":true,
201 "Error opening input stream (invalid filename?)":true}
203 // null op. (suppress error, try next path)
204 } catch (e if e == this.skip_module_load) {
210 path = this.load_paths[++i];
212 throw new Error("Module not found ("+module+")");
215 module_assert_error: function (module) {
216 this.module = module;
218 module_assert_conflict_error: function (url) { //subclass of Error
219 this.name = "module_assert_conflict_error";
220 this.message = "Conflicting in_module calls";
222 this.lineNumber = '';
224 in_module: function (module) {
225 if (module != this.loading_modules[0])
226 throw new this.module_assert_error(module);
228 provide: function (symbol) {
230 throw new Error("Cannot provide null feature");
231 if (this.loading_urls[0] === undefined) {
232 this.features[symbol] = true;
233 this.run_after_load_functions(symbol);
235 this.loading_features[0][symbol] = true;
237 featurep: function (symbol) {
238 return this.features[symbol] || false;
240 call_after_load: function (feature, func) {
241 if (this.featurep(feature))
244 var funcs = this.after_load_functions[feature];
246 funcs = this.after_load_functions[feature] = [];
250 run_after_load_functions: function (symbol) {
251 var funcs = this.after_load_functions[symbol];
253 delete this.after_load_functions[symbol];
254 for (var i = 0; funcs[i]; ++i) {
263 require: function (module, as) {
266 if (module instanceof Ci.nsIURI)
267 feature = module.spec.substr(module.spec.lastIndexOf('/')+1);
268 else if (module instanceof Ci.nsIFile)
269 feature = module.leafName;
271 feature = module.substr(module.lastIndexOf('/')+1);
272 let dot = feature.indexOf('.');
276 feature = feature.substr(0, dot);
277 feature = feature.replace('_', '-', 'g');
279 if (this.featurep(feature))
281 if (as === undefined)
282 as = feature.replace('-', '_', 'g');
284 // ensure current path is not searched for 'require'
285 this.loading_paths.unshift(undefined);
286 this.load(module, as);
288 this.loading_paths.shift();
292 require_later: function (module, as) {
293 this.pending_loads.push([module, as]);
297 QueryInterface: XPCOMUtils.generateQI([]),
299 /* XPCOM registration */
300 classDescription: "Conkeror global object",
301 classID: Components.ID("{72a7eea7-a894-47ec-93a9-a7bc172cf1ac}"),
302 contractID: "@conkeror.mozdev.org/application;1"
305 if (XPCOMUtils.generateNSGetFactory)
306 var NSGetFactory = XPCOMUtils.generateNSGetFactory([application]); //XULRunner 2.0
308 var NSGetModule = XPCOMUtils.generateNSGetModule([application]);