Debian package: Declare compliance with Debian Policy 4.3.0
[conkeror.git] / components / application.js
blob665be51b6b5db21735149a72e8d23e13dd05ab7c
1 /**
2  * (C) Copyright 2007,2010,2012 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 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);
45     }
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%");
60     },
61     dumpln: function (str) {
62         dump(str);
63         dump("\n");
64     },
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;
76             }
77         } else {
78             this.dumpln("Error: " + e);
79         }
80     },
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);
90     },
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);
117                 }
118             } finally {
119                 this.loading_paths.shift();
120                 this.loading_urls.shift();
121                 this.loading_features.shift();
122             }
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);
129                 }
130             }
131         }
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;
163                     }
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)
169                 }
170                 if (autoext)
171                     exti = (exti + 1) % exts.len;
172                 if (exti == 0)
173                     path = this.load_paths[++i];
174             }
175             throw new Error("Module not found ("+module+")");
176         }
177     },
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;
186     },
187     featurep: function (symbol) {
188         return this.features[symbol] || false;
189     },
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);
198         }
199     },
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);
209                 }
210             }
211         }
212     },
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();
234         }
235         return true;
236     },
237     require_later: function (module) {
238         this.pending_loads.push(module);
239     },
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]);