removed unneded debug log
[guerillascript.git] / bootstrap.js
blob05613014c4675812d5ca410bb1a28d2938f7d6dc
1 /* coded by Ketmar // Invisible Vector (psyc://ketmar.no-ip.org/~Ketmar)
2  * Understanding is not required. Only obedience.
3  *
4  * This program is free software. It comes without any warranty, to
5  * the extent permitted by applicable law. You can redistribute it
6  * and/or modify it under the terms of the Do What The Fuck You Want
7  * To Public License, Version 2, as published by Sam Hocevar. See
8  * http://www.wtfpl.net/txt/copying/ for more details.
9  */
10 ////////////////////////////////////////////////////////////////////////////////
11 let K8_GuerillaScriptObject = (function () {
12   const myUrl = (function (spc) {
13     let esp = spc.lastIndexOf("/");
14     return spc.substr(0, esp+1);
15   })(__SCRIPT_URI_SPEC__);
17   const {utils:Cu, classes:Cc, interfaces:Ci, results:Cr} = Components;
19   const sysPrincipal = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
20   let gsbox = new Cu.Sandbox(/*window*/sysPrincipal, {
21     sandboxName: "GuerillaScript Internal Sandbox",
22     wantComponents: false,
23     wantXrays: false,
24     wantXHRConstructor: true,
25   });
27   Cu.import("resource://gre/modules/Services.jsm", gsbox);
29   // add some common API
30   Object.defineProperty(gsbox, "isXPCShell", {get: function () false});
32   // `tieto` API: ties method to object, so it always has correct `this`
33   // you may specify additional arguments that will be always there
34   function tieto (obj, method) {
35     let mt;
36     if (typeof(obj) === "undefined") throw new Error("object or `null` expected");
37     if (obj !== null && typeof(obj) !== "object") throw new Error("object or `null` expected");
38     switch (typeof(method)) {
39       case "string":
40         if (!obj) throw new Error("can't take method by name from `null` object");
41         if (!(method in obj)) throw new Error("method '"+method+"' doesn't exist in object '"+obj+"'");
42         mt = obj[method];
43         if (typeof(mt) !== "function") throw new Error("method '"+method+"' isn't a function in object '"+obj+"'");
44         break;
45       case "function":
46         if (!obj) obj = {};
47         mt = method;
48         break;
49       default:
50         throw new Error("`method` should be function or method name");
51     }
52     let me = obj;
53     let rest = Array.prototype.splice.call(arguments, 2, arguments.length);
54     /*
55     let stk;
56     try { throw new Error("!"); } catch (e) {
57       //print("TIETO!\n"+e.stack);
58       stk = e.stack.split("\n")[1];
59     }
60     */
61     return function () {
62       //print(stk);
63       // `rest` is reused for each invocation, so copy it, and append new arguments to copy
64       let args = Array.prototype.slice.call(rest);
65       Array.prototype.push.apply(args, arguments);
66       return mt.apply(me, args);
67     };
68   }
69   const sb_tieto = tieto(gsbox, tieto);
70   Object.defineProperty(gsbox, "tieto", {get: function () sb_tieto});
72   const sb_Components = tieto(gsbox, function (c) c, Components);
73   const sb_Cu = tieto(gsbox, function (cu) cu, Cu);
74   const sb_Cc = tieto(gsbox, function (cc) cc, Cc);
75   const sb_Ci = tieto(gsbox, function (ci) ci, Ci);
76   const sb_Cr = tieto(gsbox, function (cr) cr, Cr);
78   Object.defineProperty(gsbox, "Components", {get: function () sb_Components()});
79   Object.defineProperty(gsbox, "Cu", {get: function () sb_Cu()});
80   Object.defineProperty(gsbox, "Cc", {get: function () sb_Cc()});
81   Object.defineProperty(gsbox, "Ci", {get: function () sb_Ci()});
82   Object.defineProperty(gsbox, "Cr", {get: function () sb_Cr()});
84   // console log functions
85   const oldlogerr = (typeof(conlog) == "function" ? logError : null);
86   function logErr (str) {
87     if (oldlogerr) oldlogerr(str); else Cu.reportError(str);
88   }
89   const sb_logError = tieto(gsbox, function (logErrMsg) {
90     if (arguments.length) {
91       let s = "";
92       for (let idx = 0; idx < arguments.length; ++idx) s += ""+arguments[idx];
93       logErrMsg(s);
94     }
95   }, logErr);
96   Object.defineProperty(gsbox, "logError", {get: function () sb_logError});
98   const sb_logException = tieto(gsbox, function (logErrMsg) {
99     if (e instanceof this.Error) {
100       logErrMsg(""+msg+" ERROR: "+e.name+": "+e.message+" : "+e.lineNumber)
101       if (e.stack) logErrMsg(e.stack);
102       logErrMsg(e);
103     } else {
104       logErrMsg(""+msg);
105     }
106   }, logErr);
107   Object.defineProperty(gsbox, "logException", {get: function () sb_logException});
109   //let conlogEnabled = true;
110   //Object.defineProperty(gsbox, "conlogEnabled", {get: tieto(this, function () this.conlogEnabled)});
112   // https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIConsoleService#logStringMessage() - wstring / wide string
113   const conService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
114   const oldconlog = (typeof(conlog) == "function" ? conlog : null);
115   function logStr (str) {
116     if (oldconlog) oldconlog(str); else conService.logStringMessage(str);
117   }
119   const sb_conlog = tieto(gsbox, function (logStrMsg) {
120     if (arguments.length > 1) {
121       let le = ("guerillaOptions" in this ? this["guerillaOptions"].logEnabled : true);
122       if (!le) return;
123       let s = "";
124       for (let idx = 1; idx < arguments.length; ++idx) s += ""+arguments[idx];
125       logStrMsg(s);
126     }
127   }, logStr);
128   Object.defineProperty(gsbox, "conlog", {get: function () sb_conlog});
130   const sb_print = tieto(gsbox, function (logStrMsg) {
131     if (arguments.length > 1) {
132       let le = ("guerillaOptions" in this ? this["guerillaOptions"].logEnabled : true);
133       if (!le) return;
134       let s = "";
135       let wasPrint = false;
136       for (let idx = 1; idx < arguments.length; ++idx) {
137         let t = ""+arguments[idx];
138         if (t) s += " "+t;
139       }
140       logStrMsg(s.substr(1));
141     }
142   }, logStr);
143   Object.defineProperty(gsbox, "print", {get: function () sb_print});
145   // script loaders
146   //const scLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
147   const newURI = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService).newURI;
148   //const newFileURI = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService).newFileURI;
149   const loadSubScript = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader).loadSubScript;
151   // include("incname")
152   const sb_include = tieto(gsbox, function (scriptSpec, newURI, loadSubScript, reportError, name) {
153     if (name.length == 0) throw new Error("invalid include name: '"+name+"'");
154     if (!(/.\.js$/.test(name))) name += ".js";
155     try {
156       let uri = newURI(scriptSpec+name, null, null);
157       loadSubScript(uri.spec, gsbox, "UTF-8");
158     } catch (e) {
159       reportError("INCLUDE ERROR: "+e.name+": "+e.message+" : "+e.lineNumber+"\n"+e.stack);
160       reportError(e);
161       throw e;
162     }
163   }, myUrl+"includes/", newURI, loadSubScript, Cu.reportError);
164   Object.defineProperty(gsbox, "include", {get: function () sb_include});
167   let modules = {}; // list of loaded modules
169   // require("modname")
170   const sb_require = tieto(gsbox, function (scriptSpec, newURI, loadSubScript, reportError, import_, modules, name) {
171     if (name.length == 0) throw new Error("invalid include name: '"+name+"'");
172     if (!(/.\.js$/.test(name))) name += ".js";
173     if (name in modules) return modules[name];
174     //let scope = {};
175     let scope = Object.create(gsbox);
176     // uses(name[, name]...);
177     let sc_uses = tieto(gsbox, function (scope, import_) {
178       if (arguments.length > 3) {
179         for (let idx = 2; idx < arguments.length; ++idx) import_(arguments[idx], scope);
180         return null;
181       } else if (arguments.length == 3) {
182         return import_(arguments[2], scope);
183       }
184     }, scope, import_);
185     Object.defineProperty(scope, "uses", {get: function () sc_uses});
186     scope.exports = {};
187     scope.exportsGlobal = {};
188     /*
189     for (let k in gsbox) {
190       print("k=["+k+"]");
191       if (k !== "__exposedProps__" && !(k in scope) && Object.prototype.hasOwnProperty.call(gsbox, k)) {
192         print(" EXPORT: k=["+k+"]");
193         try { scope[k] = gsbox[k]; } catch (e) {}
194       }
195     }
196     */
197     try {
198       let uri = newURI(scriptSpec+name, null, null);
199       loadSubScript(uri.spec, scope, "UTF-8");
200     } catch (e) {
201       reportError("REQUIRE ERROR: "+e.name+": "+e.message+" : "+e.lineNumber+"\n"+e.stack);
202       reportError(e);
203       throw e;
204     }
205     modules[name] = scope.exports;
206     if (typeof(scope.exportsGlobal) === "object") {
207       for (let k in scope.exportsGlobal) {
208         if (k !== "__exposedProps__" && Object.prototype.hasOwnProperty.call(scope.exportsGlobal, k)) {
209           try { gsbox[k] = scope.exportsGlobal[k]; } catch (e) {}
210         }
211       }
212     }
213     return scope.exports;
214   }, myUrl+"modules/", newURI, loadSubScript, Cu.reportError, Cu.import, modules);
215   Object.defineProperty(gsbox, "require", {get: function () sb_require});
218   const promptSvc = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
219   // alert("msg")
220   const sb_alert = tieto(gsbox, function (promptSvc, msg) {
221     promptSvc.alert(null, "Guerilla", ""+msg);
222   }, promptSvc);
223   Object.defineProperty(gsbox, "alert", {get: function () sb_alert});
226   let startupHooks = [], shutdownHooks = [];
228   function runHooks (list, rev, data, reason) {
229     let idx = (rev ? list.length : -1);
230     for (;;) {
231       if (rev) {
232         if (--idx < 0) break;
233       } else {
234         if (++idx >= list.length) break;
235       }
236       let h = list[idx];
237       try {
238         //conService.logStringMessage("running hook: '"+h.name+"'");
239         h.cback(data, reason);
240       } catch (e) {
241         Cu.reportError("HOOK ERROR: "+e.name+": "+e.message+" : "+e.lineNumber+"\n"+e.stack);
242         Cu.reportError(e);
243       }
244     }
245   }
247   function addHook (hooks, name, cback) {
248     if (typeof(cback) === "undefined") {
249       // register*Hook(hookfn)
250       cback = name;
251       name = null;
252     }
253     if (typeof(name) === "undefined") throw new Error("name or `null` expected");
254     if (!name) name = "";
255     if (typeof(name) !== "string") throw new Error("name or `null` expected");
256     if (typeof(cback) !== "function") throw new Error("function expected");
257     hooks.push({name:name, cback:cback});
258   }
260   const sb_rsth = tieto(gsbox, addHook, startupHooks);
261   const sb_rsuh = tieto(gsbox, addHook, shutdownHooks);
263   // registerStartupHook(name, hookfn)
264   Object.defineProperty(gsbox, "registerStartupHook", {get: function () sb_rsth});
265   // registerShutdownHook(name, hookfn)
266   Object.defineProperty(gsbox, "registerShutdownHook", {get: function () sb_rsuh});
268   // now load main file
269   gsbox.include("../main.js"); //HACK!
271   return {
272     sbox: gsbox,
273     onInstall: function (data, reason) {},
274     onUnistall: function (data, reason) {},
275     onStartup: function (data, reason) { runHooks(startupHooks, false, data, reason); },
276     onShutdown: function (data, reason) { runHooks(shutdownHooks, true, data, reason); },
277     tieto: tieto,
278   };
279 })();
282 ////////////////////////////////////////////////////////////////////////////////
283 // ADDON_INSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE
284 function install (data, reason) { K8_GuerillaScriptObject.onInstall(data, reason); }
286 // ADDON_UNINSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE
287 function uninstall (data, reason) { K8_GuerillaScriptObject.onUnistall(data, reason); }
289 // APP_STARTUP, ADDON_ENABLE, ADDON_INSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE
290 function startup (data, reason) { K8_GuerillaScriptObject.onStartup(data, reason); }
292 // APP_SHUTDOWN, ADDON_DISABLE, ADDON_UNINSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE
293 function shutdown (data, reason) { K8_GuerillaScriptObject.onShutdown(data, reason); }