1 /* See license.txt for terms of usage */ 2 3 // 4 FBL.ns(function() { with (FBL) { 5 6 // ************************************************************************************************ 7 // Constants 8 9 const Cc = Components.classes; 10 const Ci = Components.interfaces; 11 12 top.Firebug.Console.injector = 13 { 14 isAttached: function(context, win) 15 { 16 if (win.wrappedJSObject) 17 { 18 var attached = (win.wrappedJSObject._getFirebugConsoleElement ? true : false); 19 if (FBTrace.DBG_CONSOLE) 20 FBTrace.sysout("Console.isAttached:"+attached+" to win.wrappedJSObject "+safeGetWindowLocation(win.wrappedJSObject)); 21 22 return attached; 23 } 24 else 25 { 26 if (FBTrace.DBG_CONSOLE) 27 FBTrace.sysout("Console.isAttached? to win "+win.location+" fnc:"+win._getFirebugConsoleElement); 28 return (win._getFirebugConsoleElement ? true : false); 29 } 30 }, 31 32 attachIfNeeded: function(context, win) 33 { 34 if (FBTrace.DBG_CONSOLE) 35 FBTrace.sysout("Console.attachIfNeeded has win "+(win? ((win.wrappedJSObject?"YES":"NO")+" wrappedJSObject"):"null") ); 36 37 if (this.isAttached(context, win)) 38 return true; 39 40 if (FBTrace.DBG_CONSOLE) 41 FBTrace.sysout("Console.attachIfNeeded found isAttached false "); 42 43 this.attachConsoleInjector(context, win); 44 this.addConsoleListener(context, win); 45 46 Firebug.Console.clearReloadWarning(context); 47 48 var attached = this.isAttached(context, win); 49 if (attached) 50 dispatch(Firebug.Console.fbListeners, "onConsoleInjected", [context, win]); 51 52 return attached; 53 }, 54 55 attachConsoleInjector: function(context, win) 56 { 57 var consoleInjection = this.getConsoleInjectionScript(); // Do it all here. 58 59 if (FBTrace.DBG_CONSOLE) 60 FBTrace.sysout("attachConsoleInjector evaluating in "+win.location, consoleInjection); 61 62 Firebug.CommandLine.evaluateInWebPage(consoleInjection, context, win); 63 64 if (FBTrace.DBG_CONSOLE) 65 FBTrace.sysout("attachConsoleInjector evaluation completed for "+win.location); 66 }, 67 68 getConsoleInjectionScript: function() { 69 if (!this.consoleInjectionScript) 70 { 71 var script = ""; 72 script += "window.__defineGetter__('console', function() {\n"; 73 script += " return (window._firebug ? window._firebug : window.loadFirebugConsole()); })\n\n"; 74 75 script += "window.loadFirebugConsole = function() {\n"; 76 script += "window._firebug = new _FirebugConsole();"; 77 78 if (FBTrace.DBG_CONSOLE) 79 script += " window.dump('loadFirebugConsole '+window.location+'\\n');\n"; 80 81 script += " return window._firebug };\n"; 82 83 var theFirebugConsoleScript = getResource("chrome://firebug/content/consoleInjected.js"); 84 script += theFirebugConsoleScript; 85 86 87 this.consoleInjectionScript = script; 88 } 89 return this.consoleInjectionScript; 90 }, 91 92 forceConsoleCompilationInPage: function(context, win) 93 { 94 if (!win) 95 { 96 if (FBTrace.DBG_CONSOLE) 97 FBTrace.sysout("no win in forceConsoleCompilationInPage!"); 98 return; 99 } 100 101 var consoleForcer = "window.loadFirebugConsole();"; 102 103 if (context.stopped) 104 Firebug.Console.injector.evaluateConsoleScript(context); // todo evaluate consoleForcer on stack 105 else 106 Firebug.CommandLine.evaluateInWebPage(consoleForcer, context, win); 107 108 if (FBTrace.DBG_CONSOLE) 109 FBTrace.sysout("forceConsoleCompilationInPage "+win.location, consoleForcer); 110 }, 111 112 evaluateConsoleScript: function(context) 113 { 114 var scriptSource = this.getConsoleInjectionScript(); // TODO XXXjjb this should be getConsoleInjectionScript 115 Firebug.Debugger.evaluate(scriptSource, context); 116 }, 117 118 addConsoleListener: function(context, win) 119 { 120 if (!context.activeConsoleHandlers) // then we have not been this way before 121 context.activeConsoleHandlers = []; 122 else 123 { // we've been this way before... 124 for (var i=0; i<context.activeConsoleHandlers.length; i++) 125 { 126 if (context.activeConsoleHandlers[i].window == win) 127 { 128 context.activeConsoleHandlers[i].detach(); 129 if (FBTrace.DBG_CONSOLE) 130 FBTrace.sysout("consoleInjector addConsoleListener removed handler("+context.activeConsoleHandlers[i].handler_name+") from _firebugConsole in : "+win.location+"\n"); 131 context.activeConsoleHandlers.splice(i,1); 132 } 133 } 134 } 135 136 // We need the element to attach our event listener. 137 var element = Firebug.Console.getFirebugConsoleElement(context, win); 138 if (element) 139 element.setAttribute("FirebugVersion", Firebug.version); // Initialize Firebug version. 140 else 141 return false; 142 143 var handler = new FirebugConsoleHandler(context, win); 144 handler.attachTo(element); 145 146 context.activeConsoleHandlers.push(handler); 147 148 if (FBTrace.DBG_CONSOLE) 149 FBTrace.sysout("consoleInjector addConsoleListener attached handler("+handler.handler_name+") to _firebugConsole in : "+win.location+"\n"); 150 return true; 151 }, 152 153 detachConsole: function(context, win) 154 { 155 if (win && win.document) 156 { 157 var element = win.document.getElementById("_firebugConsole"); 158 if (element) 159 element.parentNode.removeChild(element); 160 } 161 }, 162 } 163 164 var total_handlers = 0; 165 function FirebugConsoleHandler(context, win) 166 { 167 this.window = win; 168 169 this.attachTo = function(element) 170 { 171 this.element = element; 172 // When raised on our injected element, callback to Firebug and append to console 173 this.boundHandler = bind(this.handleEvent, this); 174 this.element.addEventListener('firebugAppendConsole', this.boundHandler, true); // capturing 175 }; 176 177 this.detach = function() 178 { 179 this.element.removeEventListener('firebugAppendConsole', this.boundHandler, true); 180 }; 181 182 this.handler_name = ++total_handlers; 183 this.handleEvent = function(event) 184 { 185 if (FBTrace.DBG_CONSOLE) 186 FBTrace.sysout("FirebugConsoleHandler("+this.handler_name+") "+event.target.getAttribute("methodName")+", event", event); 187 if (!Firebug.CommandLine.CommandHandler.handle(event, this, win)) 188 { 189 if (FBTrace.DBG_CONSOLE) 190 FBTrace.sysout("FirebugConsoleHandler", this); 191 192 var methodName = event.target.getAttribute("methodName"); 193 Firebug.Console.log($STRF("console.MethodNotSupported", [methodName])); 194 } 195 }; 196 197 this.firebug = Firebug.version; 198 199 this.init = function() 200 { 201 var consoleElement = win.document.getElementById('_firebugConsole'); 202 consoleElement.setAttribute("FirebugVersion", Firebug.version); 203 }; 204 205 this.log = function() 206 { 207 logFormatted(arguments, "log"); 208 }; 209 210 this.debug = function() 211 { 212 logFormatted(arguments, "debug", true); 213 }; 214 215 this.info = function() 216 { 217 logFormatted(arguments, "info", true); 218 }; 219 220 this.warn = function() 221 { 222 logFormatted(arguments, "warn", true); 223 }; 224 225 this.error = function() 226 { 227 if (arguments.length == 1) 228 { 229 logAssert("error", arguments); // add more info based on stack trace 230 } 231 else 232 { 233 Firebug.Errors.increaseCount(context); 234 logFormatted(arguments, "error", true); // user already added info 235 } 236 }; 237 238 this.exception = function() 239 { 240 logAssert("error", arguments); 241 }; 242 243 this.assert = function(x) 244 { 245 if (!x) 246 { 247 var rest = []; 248 for (var i = 1; i < arguments.length; i++) 249 rest.push(arguments[i]); 250 logAssert("assert", rest); 251 } 252 }; 253 254 this.dir = function(o) 255 { 256 Firebug.Console.log(o, context, "dir", Firebug.DOMPanel.DirTable); 257 }; 258 259 this.dirxml = function(o) 260 { 261 if (o instanceof Window) 262 o = o.document.documentElement; 263 else if (o instanceof Document) 264 o = o.documentElement; 265 266 Firebug.Console.log(o, context, "dirxml", Firebug.HTMLPanel.SoloElement); 267 }; 268 269 this.group = function() 270 { 271 var sourceLink = getStackLink(); 272 Firebug.Console.openGroup(arguments, null, "group", null, false, sourceLink); 273 }; 274 275 this.groupEnd = function() 276 { 277 Firebug.Console.closeGroup(context); 278 }; 279 280 this.groupCollapsed = function() 281 { 282 var sourceLink = getStackLink(); 283 // noThrottle true is probably ok, openGroups will likely be short strings. 284 var row = Firebug.Console.openGroup(arguments, null, "group", null, true, sourceLink); 285 removeClass(row, "opened"); 286 }; 287 288 this.profile = function(title) 289 { 290 Firebug.Profiler.startProfiling(context, title); 291 }; 292 293 this.profileEnd = function() 294 { 295 Firebug.Profiler.stopProfiling(context); 296 }; 297 298 this.count = function(key) 299 { 300 var frameId = FBL.getStackFrameId(); 301 if (frameId) 302 { 303 if (!context.frameCounters) 304 context.frameCounters = {}; 305 306 if (key != undefined) 307 frameId += key; 308 309 var frameCounter = context.frameCounters[frameId]; 310 if (!frameCounter) 311 { 312 var logRow = logFormatted(["0"], null, true, true); 313 314 frameCounter = {logRow: logRow, count: 1}; 315 context.frameCounters[frameId] = frameCounter; 316 } 317 else 318 ++frameCounter.count; 319 320 var label = key == undefined 321 ? frameCounter.count 322 : key + " " + frameCounter.count; 323 324 frameCounter.logRow.firstChild.firstChild.nodeValue = label; 325 } 326 }; 327 328 this.clear = function() 329 { 330 Firebug.Console.clear(context); 331 }; 332 333 this.time = function(name, reset) 334 { 335 if (!name) 336 return; 337 338 var time = new Date().getTime(); 339 340 if (!this.timeCounters) 341 this.timeCounters = {}; 342 343 var key = "KEY"+name.toString(); 344 345 if (!reset && this.timeCounters[key]) 346 return; 347 348 this.timeCounters[key] = time; 349 }; 350 351 this.timeEnd = function(name) 352 { 353 var time = new Date().getTime(); 354 355 if (!this.timeCounters) 356 return; 357 358 var key = "KEY"+name.toString(); 359 360 var timeCounter = this.timeCounters[key]; 361 if (timeCounter) 362 { 363 var diff = time - timeCounter; 364 var label = name + ": " + diff + "ms"; 365 366 this.info(label); 367 368 delete this.timeCounters[key]; 369 } 370 return diff; 371 }; 372 373 // These functions are over-ridden by commandLine 374 this.evaluated = function(result, context) 375 { 376 if (FBTrace.DBG_CONSOLE) 377 FBTrace.sysout("consoleInjector.FirebugConsoleHandler evalutated default called", result); 378 379 Firebug.Console.log(result, context); 380 }; 381 this.evaluateError = function(result, context) 382 { 383 Firebug.Console.log(result, context, "errorMessage"); 384 }; 385 386 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 387 388 function logFormatted(args, className, linkToSource, noThrottle) 389 { 390 var sourceLink = linkToSource ? getStackLink() : null; 391 return Firebug.Console.logFormatted(args, context, className, noThrottle, sourceLink); 392 } 393 394 function logAssert(category, args) 395 { 396 Firebug.Errors.increaseCount(context); 397 398 if (!args || !args.length || args.length == 0) 399 var msg = [FBL.$STR("Assertion")]; 400 else 401 var msg = args[0]; 402 403 if (Firebug.errorStackTrace) 404 { 405 var trace = Firebug.errorStackTrace; 406 delete Firebug.errorStackTrace; 407 if (FBTrace.DBG_CONSOLE) 408 FBTrace.sysout("logAssert trace from errorStackTrace", trace); 409 } 410 else if (msg.stack) 411 { 412 var trace = parseToStackTrace(msg.stack); 413 if (FBTrace.DBG_CONSOLE) 414 FBTrace.sysout("logAssert trace from msg.stack", trace); 415 } 416 else 417 { 418 var trace = getJSDUserStack(); 419 if (FBTrace.DBG_CONSOLE) 420 FBTrace.sysout("logAssert trace from getJSDUserStack", trace); 421 } 422 423 var errorObject = new FBL.ErrorMessage(msg, (msg.fileName?msg.fileName:win.location), (msg.lineNumber?msg.lineNumber:0), "", category, context, trace); 424 425 426 if (trace && trace.frames && trace.frames[0]) 427 errorObject.correctWithStackTrace(trace); 428 429 errorObject.resetSource(); 430 431 var objects = errorObject; 432 if (args.length > 1) 433 { 434 objects = [errorObject]; 435 for (var i = 1; i < args.length; i++) 436 objects.push(args[i]); 437 } 438 439 var row = Firebug.Console.log(objects, context, "errorMessage", null, true); // noThrottle 440 row.scrollIntoView(); 441 } 442 443 function getComponentsStackDump() 444 { 445 // Starting with our stack, walk back to the user-level code 446 var frame = Components.stack; 447 var userURL = win.location.href.toString(); 448 449 if (FBTrace.DBG_CONSOLE) 450 FBTrace.sysout("consoleInjector.getComponentsStackDump initial stack for userURL "+userURL, frame); 451 452 // Drop frames until we get into user code. 453 while (frame && FBL.isSystemURL(frame.filename) ) 454 frame = frame.caller; 455 456 // Drop two more frames, the injected console function and firebugAppendConsole() 457 if (frame) 458 frame = frame.caller; 459 if (frame) 460 frame = frame.caller; 461 462 if (FBTrace.DBG_CONSOLE) 463 FBTrace.sysout("consoleInjector.getComponentsStackDump final stack for userURL "+userURL, frame); 464 465 return frame; 466 } 467 468 function getStackLink() 469 { 470 return FBL.getFrameSourceLink(getComponentsStackDump()); 471 } 472 473 function getJSDUserStack() 474 { 475 var trace = FBL.getCurrentStackTrace(context); 476 477 var frames = trace ? trace.frames : null; 478 if (frames && (frames.length > 0) ) 479 { 480 var oldest = frames.length - 1; // 6 - 1 = 5 481 for (var i = 0; i < frames.length; i++) 482 { 483 if (frames[oldest - i].href.indexOf("chrome:") == 0) break; 484 var fn = frames[oldest - i].fn + ""; 485 if (fn && (fn.indexOf("_firebugEvalEvent") != -1) ) break; // command line 486 } 487 FBTrace.sysout("consoleInjector getJSDUserStack: "+frames.length+" oldest: "+oldest+" i: "+i+" i - oldest + 2: "+(i - oldest + 2), trace); 488 trace.frames = trace.frames.slice(2 - i); // take the oldest frames, leave 2 behind they are injection code 489 490 return trace; 491 } 492 else 493 return "Firebug failed to get stack trace with any frames"; 494 } 495 } 496 497 }}); 498