Debian: Switch to debhelper compatibility level 10
[conkeror.git] / components / application.js
blob665be51b6b5db21735149a72e8d23e13dd05ab7c
1 /**
2 * (C) Copyright 2007,2010,2012 John J. Foerch
3 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
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 const Cu = Components.utils;
13 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
15 function application () {
16 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
18 this.wrappedJSObject = this;
19 this.conkeror = this;
21 this.load_url = this.subscript_loader.loadSubScript;
22 this.loading_urls = [];
23 this.loading_paths = [];
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 // clear the startup-cache so that modules and the user's rc are
33 // loaded from disk, not from a cache. this problem is a
34 // characteristic of using mozIJSSubScriptLoader.loadSubScript as our
35 // primary means of loading, since XULRunner 8.0.
36 var obs = Cc["@mozilla.org/observer-service;1"]
37 .getService(Ci.nsIObserverService);
38 obs.notifyObservers(null, "startupcache-invalidate", null);
40 try {
41 this.require("conkeror.js");
42 } catch (e) {
43 this.dumpln("Error initializing.");
44 this.dump_error(e);
47 application.prototype = {
48 constructor: application,
49 Cc: Cc,
50 Ci: Ci,
51 Cr: Cr,
52 /* Note: resource://app currently doesn't result in xpcnativewrappers=yes */
53 module_uri_prefix: "chrome://conkeror/content/",
54 subscript_loader: Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader),
55 preferences: Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService),
56 get version () {
57 var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
58 .getService(Ci.nsIURLFormatter);
59 return formatter.formatURL("%VERSION%");
61 dumpln: function (str) {
62 dump(str);
63 dump("\n");
65 dump_error: function (e) {
66 if (e instanceof Error) {
67 this.dumpln(e.name + ": " + e.message);
68 this.dumpln(e.fileName + ":" + e.lineNumber);
69 dump(e.stack);
70 } else if (e instanceof Ci.nsIException) {
71 this.dumpln(e.name + ": " + e.message);
72 var stack_frame = e.location;
73 while (stack_frame) {
74 this.dumpln(stack_frame.name + "()@" + stack_frame.filename + ":" + stack_frame.lineNumber);
75 stack_frame = stack_frame.caller;
77 } else {
78 this.dumpln("Error: " + e);
82 make_uri: function (uri, charset, base_uri) {
83 const io_service = Cc["@mozilla.org/network/io-service;1"]
84 .getService(Ci.nsIIOService2);
85 if (uri instanceof Ci.nsIURI)
86 return uri;
87 if (uri instanceof Ci.nsIFile)
88 return io_service.newFileURI(uri);
89 return io_service.newURI(uri, charset, base_uri);
91 load: function (module) {
92 function load1 (url, path) {
93 try {
94 this.loading_paths.unshift(path);
95 this.loading_urls.unshift(url);
96 this.loading_features.unshift({});
97 if (this.loading_urls.indexOf(url, 1) != -1)
98 throw new Error("Circular module dependency detected: "+
99 this.loading_urls.join(",\n"));
100 if (url.substr(-4) == ".jsx") {
101 var scopename = url.substr(url.lastIndexOf('/')+1)
102 .replace(/-/g, '_');
103 var dot = scopename.indexOf(".");
104 if (dot > -1)
105 scopename = scopename.substr(0, dot);
106 var scope = { __proto__: this };
107 } else
108 scope = this;
109 this.load_url(url, scope);
110 if (scopename)
111 this[scopename] = scope;
112 var success = true;
113 // call-after-load callbacks
114 for (let f in this.loading_features[0]) {
115 this.features[f] = true;
116 this.run_after_load_functions(f);
118 } finally {
119 this.loading_paths.shift();
120 this.loading_urls.shift();
121 this.loading_features.shift();
123 // do pending loads
124 if (success && this.loading_urls[0] === undefined) {
125 let pending = this.pending_loads;
126 this.pending_loads = [];
127 for (let i = 0, m; m = pending[i]; ++i) {
128 this.require(m);
132 if (module instanceof Ci.nsIURI)
133 var path = module.spec.substr(0, module.spec.lastIndexOf('/')+1);
134 else if (module instanceof Ci.nsIFile)
135 path = module.parent.path;
136 if (path !== undefined) {
137 var url = this.make_uri(module).spec;
138 load1.call(this.conkeror, url, path);
139 } else {
140 // module name or relative path
141 var si = module.lastIndexOf('/');
142 var module_leaf = module.substr(si+1);
143 var autoext = module_leaf.lastIndexOf(".") <= 0;
144 var exts = { 0:"", 1:".js", 2:".jsx", len:3 };
145 var exti = 0;
146 var i = -1;
147 var tried = {};
148 path = this.loading_paths[0];
149 if (path === undefined)
150 path = this.load_paths[++i];
151 while (path !== undefined) {
152 var truepath = path;
153 var sep = path.substr(-1) == '/' ? '' : '/';
154 var ext = exts[exti];
155 try {
156 url = path + sep + module + ext;
157 if (si > -1)
158 truepath += sep + module.substr(0, si);
159 if (! tried[url]) {
160 tried[url] = true;
161 load1.call(this.conkeror, url, truepath);
162 return;
164 } catch (e if (typeof e == 'string' &&
165 (e.startsWith("ContentLength not available (not a local URL?)") ||
166 e.startsWith("Error creating channel (invalid URL scheme?)") ||
167 e.startsWith("Error opening input stream (invalid filename?)")))) {
168 // null op. (suppress error, try next path)
170 if (autoext)
171 exti = (exti + 1) % exts.len;
172 if (exti == 0)
173 path = this.load_paths[++i];
175 throw new Error("Module not found ("+module+")");
178 provide: function (symbol) {
179 if (! symbol)
180 throw new Error("Cannot provide null feature");
181 if (this.loading_urls[0] === undefined) {
182 this.features[symbol] = true;
183 this.run_after_load_functions(symbol);
184 } else
185 this.loading_features[0][symbol] = true;
187 featurep: function (symbol) {
188 return this.features[symbol] || false;
190 call_after_load: function (feature, func) {
191 if (this.featurep(feature))
192 func();
193 else {
194 var funcs = this.after_load_functions[feature];
195 if (! funcs)
196 funcs = this.after_load_functions[feature] = [];
197 funcs.push(func);
200 run_after_load_functions: function (symbol) {
201 var funcs = this.after_load_functions[symbol];
202 if (funcs) {
203 delete this.after_load_functions[symbol];
204 for (var i = 0, n = funcs.length; i < n; ++i) {
205 try {
206 funcs[i]();
207 } catch (e) {
208 this.dump_error(e);
213 require: function (module) {
214 if (module instanceof Ci.nsIURI)
215 var feature = module.spec.substr(module.spec.lastIndexOf('/')+1);
216 else if (module instanceof Ci.nsIFile)
217 feature = module.leafName;
218 else
219 feature = module.substr(module.lastIndexOf('/')+1);
220 var dot = feature.indexOf('.');
221 if (dot == 0)
222 return false;
223 if (dot > 0)
224 feature = feature.substr(0, dot);
225 feature = feature.replace(/_/g, '-');
226 if (this.featurep(feature))
227 return true;
228 try {
229 // ensure current path is not searched for 'require'
230 this.loading_paths.unshift(undefined);
231 this.load(module);
232 } finally {
233 this.loading_paths.shift();
235 return true;
237 require_later: function (module) {
238 this.pending_loads.push(module);
241 /* nsISupports */
242 QueryInterface: XPCOMUtils.generateQI([]),
244 /* XPCOM registration */
245 classDescription: "Conkeror global object",
246 classID: Components.ID("{72a7eea7-a894-47ec-93a9-a7bc172cf1ac}"),
247 contractID: "@conkeror.mozdev.org/application;1"
250 if (XPCOMUtils.generateNSGetFactory)
251 var NSGetFactory = XPCOMUtils.generateNSGetFactory([application]); //XULRunner 2.0
252 else
253 var NSGetModule = XPCOMUtils.generateNSGetModule([application]);