1 /* See license.txt for terms of usage */
  2 
  3 define([
  4     "firebug/lib/object",
  5     "firebug/firebug",
  6     "firebug/chrome/reps",
  7     "firebug/lib/locale",
  8     "firebug/lib/events",
  9     "firebug/lib/url",
 10     "firebug/js/stackFrame",
 11     "firebug/chrome/window",
 12     "firebug/console/console",
 13     "firebug/lib/array",
 14     "firebug/lib/dom",
 15     "firebug/console/consoleExposed",
 16     "firebug/console/errors",
 17 ],
 18 function(Obj, Firebug, FirebugReps, Locale, Events, Url, StackFrame, Win, Console, Arr, Dom) {
 19 
 20 // ********************************************************************************************* //
 21 // Constants
 22 
 23 const Cc = Components.classes;
 24 const Ci = Components.interfaces;
 25 const Cu = Components.utils;
 26 
 27 // ********************************************************************************************* //
 28 // Console Injector
 29 
 30 Firebug.Console.injector =
 31 {
 32     isAttached: function(context, win)
 33     {
 34         var handler = this.getConsoleHandler(context, win);
 35 
 36         if (FBTrace.DBG_CONSOLE)
 37             FBTrace.sysout("Console.isAttached "+handler+" in context "+context.getName()+
 38                 " and win "+Win.safeGetWindowLocation(win), handler);
 39 
 40         return handler;
 41     },
 42 
 43     attachIfNeeded: function(context, win)
 44     {
 45         if (this.isAttached(context, win))
 46             return true;
 47 
 48         if (FBTrace.DBG_CONSOLE)
 49             FBTrace.sysout("Console.attachIfNeeded found isAttached false " +
 50                 Win.safeGetWindowLocation(win));
 51 
 52         this.attachConsoleInjector(context, win);
 53         this.addConsoleListener(context, win);
 54 
 55         Firebug.Console.clearReloadWarning(context);
 56 
 57         var attached =  this.isAttached(context, win);
 58         if (attached)
 59             Events.dispatch(Firebug.Console.fbListeners, "onConsoleInjected", [context, win]);
 60 
 61         return attached;
 62     },
 63 
 64     attachConsoleInjector: function(context, win)
 65     {
 66         // Get the 'console' object (this comes from chrome scope).
 67         var console = Firebug.ConsoleExposed.createFirebugConsole(context, win);
 68 
 69         // Do not expose the chrome object as is but, rather do a wrapper, see below.
 70         //win.wrappedJSObject.console = console;
 71         //return;
 72 
 73         // Construct a script string that defines a function. This function returns
 74         // an object that wraps every 'console' method. This function will be evaluated
 75         // in a window content sandbox and return a wrapper for the 'console' object.
 76         // Note that this wrapper appends an additional frame that shouldn't be displayed
 77         // to the user.
 78         var expr = "(function(x) { return {\n";
 79         for (var p in console)
 80         {
 81             var func = console[p];
 82             if (typeof(func) == "function")
 83             {
 84                 expr += p + ": function() { return Function.apply.call(x." + p +
 85                     ", x, arguments); },\n";
 86             }
 87         }
 88         expr += "};})";
 89 
 90         // Evaluate the function in the window sandbox/scope and execute. The return value
 91         // is a wrapper for the 'console' object.
 92         var sandbox = Cu.Sandbox(win);
 93         var getConsoleWrapper = Cu.evalInSandbox(expr, sandbox);
 94         win.wrappedJSObject.console = getConsoleWrapper(console);
 95 
 96         if (FBTrace.DBG_CONSOLE)
 97             FBTrace.sysout("console.attachConsoleInjector; Firebug console attached to: " +
 98                 context.getName());
 99     },
100 
101     addConsoleListener: function(context, win)
102     {
103         if (!win)
104             win = context.window;
105 
106         var handler = this.getConsoleHandler(context, win);
107         if (handler)
108             return;
109 
110         var handler = createConsoleHandler(context, win);
111 
112         // Initialize Firebug token
113         Dom.setMappedData(win.document, "firebug-Token", handler.token);
114 
115         this.setConsoleHandler(context, win, handler);
116 
117         return true;
118     },
119 
120     getConsoleHandler: function(context, win)
121     {
122         if (!win.document)
123         {
124             if (FBTrace.DBG_ERRORS)
125             {
126                 FBTrace.sysout("console.getConsoleHandler; NO DOCUMENT",
127                     {win:win, context:context});
128             }
129             return null;
130         }
131 
132         var attachedToken = Dom.getMappedData(win.document, "firebug-Token");
133         if (context.activeConsoleHandlers)
134         {
135             for(var i = 0; i < context.activeConsoleHandlers.length; i++)
136             {
137                 if (context.activeConsoleHandlers[i].token === attachedToken)
138                     return context.activeConsoleHandlers[i];
139             }
140         }
141     },
142 
143     removeConsoleHandler: function(context, win)
144     {
145         var handler = this.getConsoleHandler(context, win);
146         if (handler)
147         {
148             handler.detach();
149             Arr.remove(context.activeConsoleHandlers, handler);
150 
151             if (FBTrace.DBG_CONSOLE)
152                 FBTrace.sysout("consoleInjector.removeConsoleHandler; token " + handler.token +
153                     " and  attached handler("+handler.handler_name+") to _firebugConsole in : "+
154                     Win.safeGetWindowLocation(win));
155         }
156     },
157 
158     setConsoleHandler: function(context, win, handler)
159     {
160         if (!context.activeConsoleHandlers)
161             context.activeConsoleHandlers = [];
162 
163         context.activeConsoleHandlers.push(handler);
164 
165         if (FBTrace.DBG_CONSOLE)
166             FBTrace.sysout("consoleInjector addConsoleListener set token "+handler.token+
167                 " and  attached handler("+handler.handler_name+") to _firebugConsole in : "+
168                 Win.safeGetWindowLocation(win));
169     },
170 
171     detachConsole: function(context, win)
172     {
173         if (!win)
174             win = context.window;
175 
176         this.removeConsoleHandler(context, win);
177     },
178 }
179 
180 // ********************************************************************************************* //
181 
182 var total_handlers = 0;
183 function createConsoleHandler(context, win)
184 {
185     var handler = {};
186     handler.console = Firebug.ConsoleExposed.createFirebugConsole(context, win);
187 
188     // xxxHonza: these two functions should be automatically overridden, check this out
189     // can be probably removed (evaluated and evaluateError).
190     console.evaluated = function(result, context)
191     {
192         if (FBTrace.DBG_CONSOLE)
193         {
194             FBTrace.sysout("consoleInjector.FirebugConsoleHandler evaluated default called",
195                 result);
196         }
197 
198         Firebug.Console.log(result, context);
199     };
200 
201     console.evaluateError = function(result, context)
202     {
203         Firebug.Console.log(result, context, "errorMessage");
204     };
205 
206     handler.detach = function()
207     {
208         Events.removeEventListener(win.document, 'firebugAppendConsole', this.boundHandler, true);
209 
210         if (FBTrace.DBG_CONSOLE)
211             FBTrace.sysout("consoleInjector FirebugConsoleHandler removeEventListener "+
212                 this.handler_name);
213     };
214 
215     handler.handler_name = ++total_handlers;
216     handler.token = Math.random();
217 
218     handler.handleEvent = function(event)
219     {
220         if (FBTrace.DBG_CONSOLE)
221             FBTrace.sysout("FirebugConsoleHandler(" + this.handler_name + ") " +
222                 Dom.getMappedData(win.document, "firebug-methodName") + ", event", event);
223 
224         if (!Firebug.CommandLine.CommandHandler.handle(event, this.console, win))
225         {
226             if (FBTrace.DBG_CONSOLE)
227                 FBTrace.sysout("FirebugConsoleHandler", this);
228 
229             var methodName = Dom.getMappedData(win.document, "firebug-methodName");
230             Firebug.Console.log(Locale.$STRF("console.MethodNotSupported", [methodName]));
231         }
232     };
233 
234     handler.setEvaluatedCallback = function( fnOfResult )
235     {
236         this.console.evaluated = fnOfResult;
237     };
238 
239     handler.setEvaluateErrorCallback = function( fnOfResultAndContext )
240     {
241         this.console.evaluateError = fnOfResultAndContext;
242     };
243 
244     handler.win = win;
245     handler.context = context;
246 
247     // When raised on our injected element, callback to Firebug and append to console
248     handler.boundHandler = Obj.bind(handler.handleEvent, handler);
249 
250     // capturing
251     Events.addEventListener(win.document, "firebugAppendConsole", handler.boundHandler, true);
252 
253     if (FBTrace.DBG_CONSOLE)
254         FBTrace.sysout("consoleInjector FirebugConsoleHandler addEventListener " +
255             handler.handler_name);
256 
257     return handler;
258 }
259 
260 // ********************************************************************************************* //
261 // Registration
262 
263 return Firebug.Console.injector;
264 
265 // ********************************************************************************************* //
266 });
267