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;
35 this.require("conkeror.js", null);
37 this.dumpln("Error initializing.");
41 application.prototype = {
42 constructor: application,
46 /* Note: resource://app currently doesn't result in xpcnativewrappers=yes */
47 module_uri_prefix: "chrome://conkeror/content/",
48 subscript_loader: Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader),
49 preferences: Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService),
51 var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
52 .getService(Ci.nsIURLFormatter);
53 return formatter.formatURL("%VERSION%");
55 dumpln: function (str) {
59 dump_error: function (e) {
60 if (e instanceof Error) {
61 this.dumpln(e.name + ": " + e.message);
62 this.dumpln(e.fileName + ":" + e.lineNumber);
64 } else if (e instanceof Ci.nsIException) {
65 this.dumpln(e.name + ": " + e.message);
66 var stack_frame = e.location;
68 this.dumpln(stack_frame.name + "()@" + stack_frame.filename + ":" + stack_frame.lineNumber);
69 stack_frame = stack_frame.caller;
72 this.dumpln("Error: " + e);
76 make_uri: function (uri, charset, base_uri) {
77 const io_service = Cc["@mozilla.org/network/io-service;1"]
78 .getService(Ci.nsIIOService2);
79 if (uri instanceof Ci.nsIURI)
81 if (uri instanceof Ci.nsIFile)
82 return io_service.newFileURI(uri);
83 return io_service.newURI(uri, charset, base_uri);
86 load: function (module, as) {
88 function module_scope () {
89 this.__proto__ = conkeror;
90 this.conkeror = conkeror;
92 function load1 (url, scope, path, as) {
95 this.loading_paths.unshift(path);
96 this.loading_urls.unshift(url);
97 this.loading_modules.unshift(as);
98 this.loading_features.unshift({});
99 if (this.loading_urls.indexOf(url, 1) != -1)
100 throw new Error("Circular module dependency detected: "+
101 this.loading_urls.join(",\n"));
102 this.load_url(url, scope);
106 // call-after-load callbacks
107 for (let f in this.loading_features[0]) {
108 this.features[f] = true;
109 this.run_after_load_functions(f);
112 this.loading_paths.shift();
113 this.loading_urls.shift();
114 this.loading_modules.shift();
115 this.loading_features.shift();
118 if (success && this.loading_urls[0] === undefined) {
119 let pending = this.pending_loads;
120 this.pending_loads = [];
121 for (let i = 0, m; m = pending[i]; ++i) {
122 this.require(m[0], m[1]);
129 else if (typeof as == 'string')
130 scope = new module_scope();
134 if (module instanceof Ci.nsIURI)
135 path = module.spec.substr(0, module.spec.lastIndexOf('/')+1);
136 else if (module instanceof Ci.nsIFile)
137 path = module.parent.path;
138 var restarted = false;
139 if (path !== undefined) {
140 url = this.make_uri(module).spec;
143 load1.call(this, url, scope, path, as);
145 } catch (e if e instanceof this.module_assert_error) {
147 throw new this.module_assert_conflict_error(url);
150 scope = new module_scope();
154 } catch (e if e == this.skip_module_load) {
159 // module name or relative path
160 var autoext = module.substr(-3) != '.js';
164 path = this.loading_paths[0];
165 if (path === undefined)
166 path = this.load_paths[++i];
167 while (path !== undefined) {
170 let sep = path.substr(-1) == '/' ? '' : '/';
171 url = path + sep + module + (suffix ? '.js' : '');
172 let si = module.lastIndexOf('/');
174 truepath += module.substr(0, si);
175 if (! tried[url] || tried[url] !== scope) {
177 load1.call(this, url, scope, truepath, as);
180 } catch (e if e instanceof this.module_assert_error) {
182 throw new this.module_assert_conflict_error(url);
185 scope = new module_scope();
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}
195 // null op. (suppress error, try next path)
196 } catch (e if e == this.skip_module_load) {
202 path = this.load_paths[++i];
204 throw new Error("Module not found");
207 module_assert_error: function (module) {
208 this.module = module;
210 module_assert_conflict_error: function (url) { //subclass of Error
211 this.name = "module_assert_conflict_error";
212 this.message = "Conflicting in_module calls";
214 this.lineNumber = '';
216 in_module: function (module) {
217 if (module != this.loading_modules[0])
218 throw new this.module_assert_error(module);
220 provide: function (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);
227 this.loading_features[0][symbol] = true;
229 featurep: function (symbol) {
230 return this.features[symbol] || false;
232 call_after_load: function (feature, func) {
233 if (this.featurep(feature))
236 var funcs = this.after_load_functions[feature];
238 funcs = this.after_load_functions[feature] = [];
242 run_after_load_functions: function (symbol) {
243 var funcs = this.after_load_functions[symbol];
245 delete this.after_load_functions[symbol];
246 for (var i = 0; funcs[i]; ++i) {
255 require: function (module, as) {
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;
263 feature = module.substr(module.lastIndexOf('/')+1);
264 let dot = feature.indexOf('.');
268 feature = feature.substr(0, dot);
269 feature = feature.replace('_', '-', 'g');
271 if (this.featurep(feature))
273 if (as === undefined)
274 as = feature.replace('-', '_', 'g');
276 // ensure current path is not searched for 'require'
277 this.loading_paths.unshift(undefined);
278 this.load(module, as);
280 this.loading_paths.shift();
284 require_later: function (module, as) {
285 this.pending_loads.push([module, as]);
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 if (XPCOMUtils.generateNSGetFactory)
298 var NSGetFactory = XPCOMUtils.generateNSGetFactory([application]); //XULRunner 2.0
300 var NSGetModule = XPCOMUtils.generateNSGetModule([application]);