1 /* See license.txt for terms of usage */ 2 3 define([ 4 "firebug/chrome/reps", 5 "firebug/lib/locale", 6 "firebug/lib/wrapper", 7 "firebug/lib/url", 8 "firebug/lib/string", 9 "firebug/js/stackFrame", 10 "firebug/console/errors", 11 "firebug/trace/debug", 12 "firebug/console/console", 13 "firebug/lib/options", 14 ], 15 function(FirebugReps, Locale, Wrapper, Url, Str, StackFrame, Errors, Debug, Console, Options) { 16 17 // ********************************************************************************************* // 18 19 /** 20 * Returns a console object (bundled with passed window through closure). The object 21 * provides all necessary APIs as described here: http://getfirebug.com/wiki/index.php/Console_API 22 * 23 * @param {Object} context 24 * @param {Object} win 25 */ 26 function createFirebugConsole(context, win) 27 { 28 // Defined as a chrome object, but exposed into the web content scope. 29 var console = { 30 __exposedProps__: {} 31 }; 32 33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 34 // Exposed Properties 35 36 console.log = function log() 37 { 38 return logFormatted(arguments, "log", true); 39 }; 40 41 console.debug = function debug() 42 { 43 return logFormatted(arguments, "debug", true); 44 }; 45 46 console.info = function info() 47 { 48 return logFormatted(arguments, "info", true); 49 }; 50 51 console.warn = function warn() 52 { 53 return logFormatted(arguments, "warn", true); 54 }; 55 56 console.exception = function exception() 57 { 58 return logAssert("error", arguments); 59 }; 60 61 console.assert = function assert(x) 62 { 63 if (!x) 64 { 65 var rest = []; 66 for (var i = 1; i < arguments.length; i++) 67 rest.push(arguments[i]); 68 return logAssert("assert", rest); 69 } 70 71 return Console.getDefaultReturnValue(win); 72 }; 73 74 console.dir = function dir(o) 75 { 76 Firebug.Console.log(o, context, "dir", Firebug.DOMPanel.DirTable); 77 return Console.getDefaultReturnValue(win); 78 }; 79 80 console.dirxml = function dirxml(o) 81 { 82 if (o instanceof Wrapper.getContentView(win).Window) 83 o = o.document.documentElement; 84 else if (o instanceof Wrapper.getContentView(win).Document) 85 o = o.documentElement; 86 87 Firebug.Console.log(o, context, "dirxml", Firebug.HTMLPanel.SoloElement); 88 return Console.getDefaultReturnValue(win); 89 }; 90 91 console.trace = function firebugDebuggerTracer() 92 { 93 var unwrapped = Wrapper.unwrapObject(win); 94 unwrapped.top._firebugStackTrace = "console-tracer"; 95 debugger; 96 delete unwrapped.top._firebugStackTrace; 97 98 return Console.getDefaultReturnValue(win); 99 }; 100 101 console.group = function group() 102 { 103 var sourceLink = getStackLink(); 104 Firebug.Console.openGroup(arguments, null, "group", null, false, sourceLink); 105 return Console.getDefaultReturnValue(win); 106 }; 107 108 console.groupEnd = function() 109 { 110 Firebug.Console.closeGroup(context); 111 return Console.getDefaultReturnValue(win); 112 }; 113 114 console.groupCollapsed = function() 115 { 116 var sourceLink = getStackLink(); 117 118 // noThrottle true can't be used here (in order to get the result row now) 119 // because there can be some logs delayed in the queue and they would end up 120 // in a different grup. 121 // Use rather a different method that causes auto collapsing of the group 122 // when it's created. 123 Firebug.Console.openCollapsedGroup(arguments, null, "group", null, false, sourceLink); 124 return Console.getDefaultReturnValue(win); 125 }; 126 127 console.profile = function(title) 128 { 129 Firebug.Profiler.startProfiling(context, title); 130 return Console.getDefaultReturnValue(win); 131 }; 132 133 console.profileEnd = function() 134 { 135 Firebug.Profiler.stopProfiling(context); 136 return Console.getDefaultReturnValue(win); 137 }; 138 139 console.count = function(key) 140 { 141 var frameId = getStackFrameId(); 142 if (frameId) 143 { 144 if (!context.frameCounters) 145 context.frameCounters = {}; 146 147 if (key != undefined) 148 frameId += key; 149 150 var frameCounter = context.frameCounters[frameId]; 151 if (!frameCounter) 152 { 153 var logRow = logFormatted(["0"], null, true, true); 154 155 frameCounter = {logRow: logRow, count: 1}; 156 context.frameCounters[frameId] = frameCounter; 157 } 158 else 159 ++frameCounter.count; 160 161 var label = key == undefined 162 ? frameCounter.count 163 : key + " " + frameCounter.count; 164 165 frameCounter.logRow.firstChild.firstChild.nodeValue = label; 166 } 167 return Console.getDefaultReturnValue(win); 168 }; 169 170 console.clear = function() 171 { 172 Firebug.Console.clear(context); 173 return Console.getDefaultReturnValue(win); 174 }; 175 176 console.time = function(name, reset) 177 { 178 if (!name) 179 return Console.getDefaultReturnValue(win); 180 181 var time = new Date().getTime(); 182 183 if (!this.timeCounters) 184 this.timeCounters = {}; 185 186 var key = "KEY"+name.toString(); 187 188 if (!reset && this.timeCounters[key]) 189 return Console.getDefaultReturnValue(win); 190 191 this.timeCounters[key] = time; 192 return Console.getDefaultReturnValue(win); 193 }; 194 195 console.timeEnd = function(name) 196 { 197 var time = new Date().getTime(); 198 199 if (!this.timeCounters) 200 return Console.getDefaultReturnValue(win); 201 202 var key = "KEY"+name.toString(); 203 204 var timeCounter = this.timeCounters[key]; 205 if (timeCounter) 206 { 207 var diff = time - timeCounter; 208 var label = name + ": " + diff + "ms"; 209 210 this.info(label); 211 212 delete this.timeCounters[key]; 213 } 214 return diff; 215 }; 216 217 console.timeStamp = function(label) 218 { 219 label = label || ""; 220 221 if (FBTrace.DBG_CONSOLE) 222 FBTrace.sysout("consoleExposed.timeStamp; " + label); 223 224 var now = new Date(); 225 Firebug.NetMonitor.addTimeStamp(context, now.getTime(), label); 226 227 var formattedTime = now.getHours() + ":" + now.getMinutes() + ":" + 228 now.getSeconds() + "." + now.getMilliseconds(); 229 return logFormatted([formattedTime, label], "timeStamp"); 230 }; 231 232 console.table = function(data, columns) 233 { 234 FirebugReps.Table.log(data, columns, context); 235 return Console.getDefaultReturnValue(win); 236 }; 237 238 console.error = function error() 239 { 240 // TODO stack trace 241 if (arguments.length == 1) 242 { 243 return logAssert("error", arguments); // add more info based on stack trace 244 } 245 else 246 { 247 Errors.increaseCount(context); 248 return logFormatted(arguments, "error", true); // user already added info 249 } 250 }; 251 252 // xxxHonza: removed from 1.10 (issue 5599) 253 /*console.memoryProfile = function(title) 254 { 255 Firebug.MemoryProfiler.start(context, title); 256 return Console.getDefaultReturnValue(win); 257 }; 258 259 console.memoryProfileEnd = function() 260 { 261 Firebug.MemoryProfiler.stop(context); 262 return Console.getDefaultReturnValue(win); 263 };*/ 264 265 // Expose only these properties to the content scope (read only). 266 console.__exposedProps__.log = "r"; 267 console.__exposedProps__.debug = "r"; 268 console.__exposedProps__.info = "r"; 269 console.__exposedProps__.warn = "r"; 270 console.__exposedProps__.exception = "r"; 271 console.__exposedProps__.assert = "r"; 272 console.__exposedProps__.dir = "r"; 273 console.__exposedProps__.dirxml = "r"; 274 console.__exposedProps__.trace = "r"; 275 console.__exposedProps__.group = "r"; 276 console.__exposedProps__.groupEnd = "r"; 277 console.__exposedProps__.groupCollapsed = "r"; 278 console.__exposedProps__.time = "r"; 279 console.__exposedProps__.timeEnd = "r"; 280 console.__exposedProps__.timeStamp = "r"; 281 console.__exposedProps__.profile = "r"; 282 console.__exposedProps__.profileEnd = "r"; 283 console.__exposedProps__.count = "r"; 284 console.__exposedProps__.clear = "r"; 285 console.__exposedProps__.table = "r"; 286 console.__exposedProps__.error = "r"; 287 //console.__exposedProps__.memoryProfile = "r"; 288 //console.__exposedProps__.memoryProfileEnd = "r"; 289 290 // DBG console.uid = Math.random(); 291 292 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 293 // Helpers (not accessible from web content) 294 295 function logFormatted(args, className, linkToSource, noThrottle) 296 { 297 var sourceLink; 298 299 // Using JSD to get user stack is time consuming. 300 if (Options.get("preferJSDSourceLinks")) 301 { 302 var stack = getJSDUserStack(); 303 if (stack && stack.toSourceLink) 304 sourceLink = stack.toSourceLink(); 305 } 306 307 if (!sourceLink) 308 sourceLink = linkToSource ? getStackLink() : null; 309 310 var ignoreReturnValue = Firebug.Console.getDefaultReturnValue(win); 311 var rc = Firebug.Console.logFormatted(args, context, className, noThrottle, sourceLink); 312 return rc ? rc : ignoreReturnValue; 313 }; 314 315 function logAssert(category, args) 316 { 317 Errors.increaseCount(context); 318 319 if (!args || !args.length || args.length == 0) 320 var msg = [Locale.$STR("Assertion")]; 321 else 322 var msg = args[0]; 323 324 // If there's no error message, there's also no stack trace. See Issue 4700. 325 if (!msg) 326 { 327 var trace = null; 328 } 329 else if (msg.stack) 330 { 331 var trace = StackFrame.parseToStackTrace(msg.stack, context); 332 if (FBTrace.DBG_CONSOLE) 333 FBTrace.sysout("logAssert trace from msg.stack", trace); 334 } 335 else if (context.stackTrace) 336 { 337 var trace = context.stackTrace; 338 if (FBTrace.DBG_CONSOLE) 339 FBTrace.sysout("logAssert trace from context.window.stackTrace", trace); 340 } 341 else 342 { 343 var trace = getJSDUserStack(); 344 if (FBTrace.DBG_CONSOLE) 345 FBTrace.sysout("logAssert trace from getJSDUserStack", trace); 346 } 347 348 trace = StackFrame.cleanStackTraceOfFirebug(trace); 349 350 var url = msg && msg.fileName ? msg.fileName : win.location.href; 351 352 // we may have only the line popped above 353 var lineNo = (trace && msg && msg.lineNumber) ? msg.lineNumber : 0; 354 var errorObject = new FirebugReps.ErrorMessageObj(msg, url, lineNo, "", 355 category, context, trace); 356 357 if (trace && trace.frames && trace.frames[0]) 358 errorObject.correctWithStackTrace(trace); 359 360 errorObject.resetSource(); 361 362 if (args.length > 1) 363 { 364 errorObject.objects = [] 365 for (var i = 1; i < args.length; i++) 366 errorObject.objects.push(args[i]); 367 } 368 369 var row = Firebug.Console.log(errorObject, context, "errorMessage"); 370 if (row) 371 row.scrollIntoView(); 372 373 return Console.getDefaultReturnValue(win); 374 }; 375 376 function getComponentsStackDump() 377 { 378 // Starting with our stack, walk back to the user-level code 379 var frame = Components.stack; 380 var userURL = win.location.href.toString(); 381 382 if (FBTrace.DBG_CONSOLE) 383 FBTrace.sysout("consoleInjector.getComponentsStackDump initial stack for userURL " + 384 userURL, frame); 385 386 // Drop frames until we get into user code. 387 while (frame && Url.isSystemURL(frame.filename) ) 388 frame = frame.caller; 389 390 // Drop two more frames, the injected console function and firebugAppendConsole() 391 //if (frame) 392 // frame = frame.caller; 393 //if (frame) 394 // frame = frame.caller; 395 396 if (FBTrace.DBG_CONSOLE) 397 FBTrace.sysout("consoleInjector.getComponentsStackDump final stack for userURL " + 398 userURL, frame); 399 400 return frame; 401 }; 402 403 function getStackLink() 404 { 405 return StackFrame.getFrameSourceLink(getComponentsStackDump()); 406 }; 407 408 function getJSDUserStack() 409 { 410 var trace = Firebug.Debugger.getCurrentStackTrace(context); 411 412 var frames = trace ? trace.frames : null; 413 if (frames && (frames.length > 0) ) 414 { 415 var filteredFrames = []; 416 417 for (var i = 0; i < frames.length; i++) 418 { 419 if (Str.hasPrefix(frames[i].href, "chrome:")) 420 continue; 421 422 if (Str.hasPrefix(frames[i].href, "resource:")) 423 continue; 424 425 // firebug-service scope reached, in some cases the url starts with file:// 426 if (frames[i].href.indexOf("modules/firebug-service.js") != -1) 427 continue; 428 429 // command line 430 var fn = frames[i].getFunctionName() + ""; 431 if (fn && (fn.indexOf("_firebugEvalEvent") != -1)) 432 continue; 433 434 filteredFrames.push(frames[i]); 435 } 436 437 // take the oldest frames, leave 2 behind they are injection code 438 trace.frames = filteredFrames; //trace.frames.slice(2 - i); 439 440 return trace; 441 } 442 else 443 { 444 return "Firebug failed to get stack trace with any frames"; 445 } 446 }; 447 448 function getStackFrameId(inputFrame) 449 { 450 for (var frame = Components.stack; frame; frame = frame.caller) 451 { 452 if (frame.languageName == "JavaScript" 453 && !(frame.filename && frame.filename.indexOf("://firebug/") > 0)) 454 { 455 return frame.filename + "/" + frame.lineNumber; 456 } 457 } 458 return null; 459 }; 460 461 return console; 462 } 463 464 // ********************************************************************************************* // 465 // Registration 466 467 Firebug.ConsoleExposed = 468 { 469 createFirebugConsole: createFirebugConsole 470 }; 471 472 return Firebug.ConsoleExposed; 473 474 // ********************************************************************************************* // 475 }); 476