1/* 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 Joseph Pecoraro 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30WebInspector.ConsoleView = function(drawer) 31{ 32 WebInspector.View.call(this, document.getElementById("console-view")); 33 34 this.messages = []; 35 this.drawer = drawer; 36 37 this.clearButton = document.getElementById("clear-console-status-bar-item"); 38 this.clearButton.title = WebInspector.UIString("Clear console log."); 39 this.clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false); 40 41 this.messagesElement = document.getElementById("console-messages"); 42 this.messagesElement.addEventListener("selectstart", this._messagesSelectStart.bind(this), false); 43 this.messagesElement.addEventListener("click", this._messagesClicked.bind(this), true); 44 45 this.promptElement = document.getElementById("console-prompt"); 46 this.promptElement.handleKeyEvent = this._promptKeyDown.bind(this); 47 this.prompt = new WebInspector.TextPrompt(this.promptElement, this.completions.bind(this), " .=:[({;"); 48 49 this.topGroup = new WebInspector.ConsoleGroup(null, 0); 50 this.messagesElement.insertBefore(this.topGroup.element, this.promptElement); 51 this.groupLevel = 0; 52 this.currentGroup = this.topGroup; 53 54 this.toggleConsoleButton = document.getElementById("console-status-bar-item"); 55 this.toggleConsoleButton.title = WebInspector.UIString("Show console."); 56 this.toggleConsoleButton.addEventListener("click", this._toggleConsoleButtonClicked.bind(this), false); 57 58 var anchoredStatusBar = document.getElementById("anchored-status-bar-items"); 59 anchoredStatusBar.appendChild(this.toggleConsoleButton); 60 61} 62 63WebInspector.ConsoleView.prototype = { 64 _toggleConsoleButtonClicked: function() 65 { 66 this.drawer.visibleView = this; 67 }, 68 69 attach: function(mainElement, statusBarElement) 70 { 71 mainElement.appendChild(this.element); 72 statusBarElement.appendChild(this.clearButton); 73 }, 74 75 show: function() 76 { 77 this.toggleConsoleButton.addStyleClass("toggled-on"); 78 this.toggleConsoleButton.title = WebInspector.UIString("Hide console."); 79 if (!this.prompt.isCaretInsidePrompt()) 80 this.prompt.moveCaretToEndOfPrompt(); 81 }, 82 83 afterShow: function() 84 { 85 WebInspector.currentFocusElement = this.promptElement; 86 }, 87 88 hide: function() 89 { 90 this.toggleConsoleButton.removeStyleClass("toggled-on"); 91 this.toggleConsoleButton.title = WebInspector.UIString("Show console."); 92 }, 93 94 addMessage: function(msg) 95 { 96 if (msg instanceof WebInspector.ConsoleMessage && !(msg instanceof WebInspector.ConsoleCommandResult)) { 97 msg.totalRepeatCount = msg.repeatCount; 98 msg.repeatDelta = msg.repeatCount; 99 100 var messageRepeated = false; 101 102 if (msg.isEqual && msg.isEqual(this.previousMessage)) { 103 // Because sometimes we get a large number of repeated messages and sometimes 104 // we get them one at a time, we need to know the difference between how many 105 // repeats we used to have and how many we have now. 106 msg.repeatDelta -= this.previousMessage.totalRepeatCount; 107 108 if (!isNaN(this.repeatCountBeforeCommand)) 109 msg.repeatCount -= this.repeatCountBeforeCommand; 110 111 if (!this.commandSincePreviousMessage) { 112 // Recreate the previous message element to reset the repeat count. 113 var messagesElement = this.currentGroup.messagesElement; 114 messagesElement.removeChild(messagesElement.lastChild); 115 messagesElement.appendChild(msg.toMessageElement()); 116 117 messageRepeated = true; 118 } 119 } else 120 delete this.repeatCountBeforeCommand; 121 122 // Increment the error or warning count 123 switch (msg.level) { 124 case WebInspector.ConsoleMessage.MessageLevel.Warning: 125 WebInspector.warnings += msg.repeatDelta; 126 break; 127 case WebInspector.ConsoleMessage.MessageLevel.Error: 128 WebInspector.errors += msg.repeatDelta; 129 break; 130 } 131 132 // Add message to the resource panel 133 if (msg.url in WebInspector.resourceURLMap) { 134 msg.resource = WebInspector.resourceURLMap[msg.url]; 135 if (WebInspector.panels.resources) 136 WebInspector.panels.resources.addMessageToResource(msg.resource, msg); 137 } 138 139 this.commandSincePreviousMessage = false; 140 this.previousMessage = msg; 141 142 if (messageRepeated) 143 return; 144 } else if (msg instanceof WebInspector.ConsoleCommand) { 145 if (this.previousMessage) { 146 this.commandSincePreviousMessage = true; 147 this.repeatCountBeforeCommand = this.previousMessage.totalRepeatCount; 148 } 149 } 150 151 this.messages.push(msg); 152 153 if (msg.type === WebInspector.ConsoleMessage.MessageType.EndGroup) { 154 if (this.groupLevel < 1) 155 return; 156 157 this.groupLevel--; 158 159 this.currentGroup = this.currentGroup.parentGroup; 160 } else { 161 if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup) { 162 this.groupLevel++; 163 164 var group = new WebInspector.ConsoleGroup(this.currentGroup, this.groupLevel); 165 this.currentGroup.messagesElement.appendChild(group.element); 166 this.currentGroup = group; 167 } 168 169 this.currentGroup.addMessage(msg); 170 } 171 172 this.promptElement.scrollIntoView(false); 173 }, 174 175 clearMessages: function(clearInspectorController) 176 { 177 if (clearInspectorController) 178 InspectorController.clearMessages(); 179 if (WebInspector.panels.resources) 180 WebInspector.panels.resources.clearMessages(); 181 182 this.messages = []; 183 184 this.groupLevel = 0; 185 this.currentGroup = this.topGroup; 186 this.topGroup.messagesElement.removeChildren(); 187 188 WebInspector.errors = 0; 189 WebInspector.warnings = 0; 190 191 delete this.commandSincePreviousMessage; 192 delete this.repeatCountBeforeCommand; 193 delete this.previousMessage; 194 }, 195 196 completions: function(wordRange, bestMatchOnly, completionsReadyCallback) 197 { 198 // Pass less stop characters to rangeOfWord so the range will be a more complete expression. 199 const expressionStopCharacters = " =:{;"; 200 var expressionRange = wordRange.startContainer.rangeOfWord(wordRange.startOffset, expressionStopCharacters, this.promptElement, "backward"); 201 var expressionString = expressionRange.toString(); 202 var lastIndex = expressionString.length - 1; 203 204 var dotNotation = (expressionString[lastIndex] === "."); 205 var bracketNotation = (expressionString[lastIndex] === "["); 206 207 if (dotNotation || bracketNotation) 208 expressionString = expressionString.substr(0, lastIndex); 209 210 var prefix = wordRange.toString(); 211 if (!expressionString && !prefix) 212 return; 213 214 var reportCompletions = this._reportCompletions.bind(this, bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix); 215 this._evalInInspectedWindow(expressionString, reportCompletions); 216 }, 217 218 _reportCompletions: function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result) { 219 if (bracketNotation) { 220 if (prefix.length && prefix[0] === "'") 221 var quoteUsed = "'"; 222 else 223 var quoteUsed = "\""; 224 } 225 226 var results = []; 227 var properties = Object.properties(result); 228 if (!dotNotation && !bracketNotation && result._inspectorCommandLineAPI) { 229 var commandLineAPI = Object.properties(result._inspectorCommandLineAPI); 230 for (var i = 0; i < commandLineAPI.length; ++i) { 231 var property = commandLineAPI[i]; 232 if (property.charAt(0) !== "_") 233 properties.push(property); 234 } 235 } 236 properties.sort(); 237 238 for (var i = 0; i < properties.length; ++i) { 239 var property = properties[i]; 240 241 if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property)) 242 continue; 243 244 if (bracketNotation) { 245 if (!/^[0-9]+$/.test(property)) 246 property = quoteUsed + property.escapeCharacters(quoteUsed + "\\") + quoteUsed; 247 property += "]"; 248 } 249 250 if (property.length < prefix.length) 251 continue; 252 if (property.indexOf(prefix) !== 0) 253 continue; 254 255 results.push(property); 256 if (bestMatchOnly) 257 break; 258 } 259 setTimeout(completionsReadyCallback, 0, results); 260 }, 261 262 _clearButtonClicked: function() 263 { 264 this.clearMessages(true); 265 }, 266 267 _messagesSelectStart: function(event) 268 { 269 if (this._selectionTimeout) 270 clearTimeout(this._selectionTimeout); 271 272 this.prompt.clearAutoComplete(); 273 274 function moveBackIfOutside() 275 { 276 delete this._selectionTimeout; 277 if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed) 278 this.prompt.moveCaretToEndOfPrompt(); 279 this.prompt.autoCompleteSoon(); 280 } 281 282 this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100); 283 }, 284 285 _messagesClicked: function(event) 286 { 287 var link = event.target.enclosingNodeOrSelfWithNodeName("a"); 288 if (!link || !link.representedNode) 289 return; 290 291 WebInspector.updateFocusedNode(link.representedNode); 292 event.stopPropagation(); 293 event.preventDefault(); 294 }, 295 296 _promptKeyDown: function(event) 297 { 298 switch (event.keyIdentifier) { 299 case "Enter": 300 this._enterKeyPressed(event); 301 return; 302 } 303 304 this.prompt.handleKeyEvent(event); 305 }, 306 307 _evalInInspectedWindow: function(expression, callback) 308 { 309 if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) { 310 WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, callback); 311 return; 312 } 313 this.doEvalInWindow(expression, callback); 314 }, 315 316 _ensureCommandLineAPIInstalled: function(inspectedWindow) 317 { 318 if (!inspectedWindow._inspectorCommandLineAPI) { 319 inspectedWindow.eval("window._inspectorCommandLineAPI = { \ 320 $: function() { return document.getElementById.apply(document, arguments) }, \ 321 $$: function() { return document.querySelectorAll.apply(document, arguments) }, \ 322 $x: function(xpath, context) { \ 323 var nodes = []; \ 324 try { \ 325 var doc = context || document; \ 326 var results = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); \ 327 var node; \ 328 while (node = results.iterateNext()) nodes.push(node); \ 329 } catch (e) {} \ 330 return nodes; \ 331 }, \ 332 dir: function() { return console.dir.apply(console, arguments) }, \ 333 dirxml: function() { return console.dirxml.apply(console, arguments) }, \ 334 keys: function(o) { var a = []; for (var k in o) a.push(k); return a; }, \ 335 values: function(o) { var a = []; for (var k in o) a.push(o[k]); return a; }, \ 336 profile: function() { return console.profile.apply(console, arguments) }, \ 337 profileEnd: function() { return console.profileEnd.apply(console, arguments) }, \ 338 _inspectedNodes: [], \ 339 get $0() { return _inspectorCommandLineAPI._inspectedNodes[0] }, \ 340 get $1() { return _inspectorCommandLineAPI._inspectedNodes[1] }, \ 341 get $2() { return _inspectorCommandLineAPI._inspectedNodes[2] }, \ 342 get $3() { return _inspectorCommandLineAPI._inspectedNodes[3] }, \ 343 get $4() { return _inspectorCommandLineAPI._inspectedNodes[4] } \ 344 };"); 345 346 inspectedWindow._inspectorCommandLineAPI.clear = InspectorController.wrapCallback(this.clearMessages.bind(this)); 347 inspectedWindow._inspectorCommandLineAPI.inspect = InspectorController.wrapCallback(inspectObject.bind(this)); 348 349 function inspectObject(o) 350 { 351 if (arguments.length === 0) 352 return; 353 354 InspectorController.inspectedWindow().console.log(o); 355 if (Object.type(o, InspectorController.inspectedWindow()) === "node") { 356 WebInspector.showElementsPanel(); 357 WebInspector.panels.elements.treeOutline.revealAndSelectNode(o); 358 } else { 359 switch (Object.describe(o)) { 360 case "Database": 361 WebInspector.showDatabasesPanel(); 362 WebInspector.panels.databases.selectDatabase(o); 363 break; 364 case "Storage": 365 WebInspector.showDatabasesPanel(); 366 WebInspector.panels.databases.selectDOMStorage(o); 367 break; 368 } 369 } 370 } 371 } 372 }, 373 374 addInspectedNode: function(node) 375 { 376 var inspectedWindow = InspectorController.inspectedWindow(); 377 this._ensureCommandLineAPIInstalled(inspectedWindow); 378 var inspectedNodes = inspectedWindow._inspectorCommandLineAPI._inspectedNodes; 379 inspectedNodes.unshift(node); 380 if (inspectedNodes.length >= 5) 381 inspectedNodes.pop(); 382 }, 383 384 doEvalInWindow: function(expression, callback) 385 { 386 if (!expression) { 387 // There is no expression, so the completion should happen against global properties. 388 expression = "this"; 389 } 390 391 // Surround the expression in with statements to inject our command line API so that 392 // the window object properties still take more precedent than our API functions. 393 expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }"; 394 395 var self = this; 396 function delayedEvaluation() 397 { 398 var inspectedWindow = InspectorController.inspectedWindow(); 399 self._ensureCommandLineAPIInstalled(inspectedWindow); 400 try { 401 callback(inspectedWindow.eval(expression)); 402 } catch (e) { 403 callback(e, true); 404 } 405 } 406 setTimeout(delayedEvaluation, 0); 407 }, 408 409 _enterKeyPressed: function(event) 410 { 411 if (event.altKey) 412 return; 413 414 event.preventDefault(); 415 event.stopPropagation(); 416 417 this.prompt.clearAutoComplete(true); 418 419 var str = this.prompt.text; 420 if (!str.length) 421 return; 422 423 var commandMessage = new WebInspector.ConsoleCommand(str); 424 this.addMessage(commandMessage); 425 426 var self = this; 427 function printResult(result, exception) 428 { 429 self.prompt.history.push(str); 430 self.prompt.historyOffset = 0; 431 self.prompt.text = ""; 432 self.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage)); 433 } 434 this._evalInInspectedWindow(str, printResult); 435 }, 436 437 _format: function(output, forceObjectFormat) 438 { 439 var inspectedWindow = InspectorController.inspectedWindow(); 440 if (forceObjectFormat) 441 var type = "object"; 442 else if (output instanceof inspectedWindow.NodeList) 443 var type = "array"; 444 else 445 var type = Object.type(output, inspectedWindow); 446 447 // We don't perform any special formatting on these types, so we just 448 // pass them through the simple _formatvalue function. 449 var undecoratedTypes = { 450 "undefined": 1, 451 "null": 1, 452 "boolean": 1, 453 "number": 1, 454 "date": 1, 455 "function": 1, 456 }; 457 458 var formatter; 459 if (forceObjectFormat) 460 formatter = "_formatobject"; 461 else if (type in undecoratedTypes) 462 formatter = "_formatvalue"; 463 else { 464 formatter = "_format" + type; 465 if (!(formatter in this)) { 466 formatter = "_formatobject"; 467 type = "object"; 468 } 469 } 470 471 var span = document.createElement("span"); 472 span.addStyleClass("console-formatted-" + type); 473 this[formatter](output, span); 474 return span; 475 }, 476 477 _formatvalue: function(val, elem) 478 { 479 elem.appendChild(document.createTextNode(val)); 480 }, 481 482 _formatstring: function(str, elem) 483 { 484 elem.appendChild(document.createTextNode("\"" + str + "\"")); 485 }, 486 487 _formatregexp: function(re, elem) 488 { 489 var formatted = String(re).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1); 490 elem.appendChild(document.createTextNode(formatted)); 491 }, 492 493 _formatarray: function(arr, elem) 494 { 495 elem.appendChild(document.createTextNode("[")); 496 for (var i = 0; i < arr.length; ++i) { 497 elem.appendChild(this._format(arr[i])); 498 if (i < arr.length - 1) 499 elem.appendChild(document.createTextNode(", ")); 500 } 501 elem.appendChild(document.createTextNode("]")); 502 }, 503 504 _formatnode: function(node, elem) 505 { 506 var treeOutline = new WebInspector.ElementsTreeOutline(); 507 treeOutline.rootDOMNode = node; 508 treeOutline.element.addStyleClass("outline-disclosure"); 509 if (!treeOutline.children[0].hasChildren) 510 treeOutline.element.addStyleClass("single-node"); 511 elem.appendChild(treeOutline.element); 512 }, 513 514 _formatobject: function(obj, elem) 515 { 516 elem.appendChild(new WebInspector.ObjectPropertiesSection(new WebInspector.ObjectProxy(obj), Object.describe(obj, true), null, null, true).element); 517 }, 518 519 _formaterror: function(obj, elem) 520 { 521 var messageElement = document.createElement("span"); 522 messageElement.className = "error-message"; 523 messageElement.textContent = obj.name + ": " + obj.message; 524 elem.appendChild(messageElement); 525 526 if (obj.sourceURL) { 527 var urlElement = document.createElement("a"); 528 urlElement.className = "webkit-html-resource-link"; 529 urlElement.href = obj.sourceURL; 530 urlElement.lineNumber = obj.line; 531 urlElement.preferredPanel = "scripts"; 532 533 if (obj.line > 0) 534 urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL) + ":" + obj.line; 535 else 536 urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL); 537 538 elem.appendChild(document.createTextNode(" (")); 539 elem.appendChild(urlElement); 540 elem.appendChild(document.createTextNode(")")); 541 } 542 } 543} 544 545WebInspector.ConsoleView.prototype.__proto__ = WebInspector.View.prototype; 546 547WebInspector.ConsoleMessage = function(source, type, level, line, url, groupLevel, repeatCount) 548{ 549 this.source = source; 550 this.type = type; 551 this.level = level; 552 this.line = line; 553 this.url = url; 554 this.groupLevel = groupLevel; 555 this.repeatCount = repeatCount; 556 if (arguments.length > 7) 557 this.setMessageBody(Array.prototype.slice.call(arguments, 7)); 558} 559 560WebInspector.ConsoleMessage.prototype = { 561 setMessageBody: function(args) 562 { 563 switch (this.type) { 564 case WebInspector.ConsoleMessage.MessageType.Trace: 565 var span = document.createElement("span"); 566 span.addStyleClass("console-formatted-trace"); 567 var stack = Array.prototype.slice.call(args); 568 var funcNames = stack.map(function(f) { 569 return f || WebInspector.UIString("(anonymous function)"); 570 }); 571 span.appendChild(document.createTextNode(funcNames.join("\n"))); 572 this.formattedMessage = span; 573 break; 574 case WebInspector.ConsoleMessage.MessageType.Object: 575 this.formattedMessage = this._format(["%O", args[0]]); 576 break; 577 default: 578 this.formattedMessage = this._format(args); 579 break; 580 } 581 582 // This is used for inline message bubbles in SourceFrames, or other plain-text representations. 583 this.message = this.formattedMessage.textContent; 584 }, 585 586 isErrorOrWarning: function() 587 { 588 return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error); 589 }, 590 591 _format: function(parameters) 592 { 593 var formattedResult = document.createElement("span"); 594 595 if (!parameters.length) 596 return formattedResult; 597 598 function formatForConsole(obj) 599 { 600 return WebInspector.console._format(obj); 601 } 602 603 function formatAsObjectForConsole(obj) 604 { 605 return WebInspector.console._format(obj, true); 606 } 607 608 if (Object.type(parameters[0], InspectorController.inspectedWindow()) === "string") { 609 var formatters = {} 610 for (var i in String.standardFormatters) 611 formatters[i] = String.standardFormatters[i]; 612 613 // Firebug uses %o for formatting objects. 614 formatters.o = formatForConsole; 615 // Firebug allows both %i and %d for formatting integers. 616 formatters.i = formatters.d; 617 // Support %O to force object formating, instead of the type-based %o formatting. 618 formatters.O = formatAsObjectForConsole; 619 620 function append(a, b) 621 { 622 if (!(b instanceof Node)) 623 a.appendChild(WebInspector.linkifyStringAsFragment(b.toString())); 624 else 625 a.appendChild(b); 626 return a; 627 } 628 629 var result = String.format(parameters[0], parameters.slice(1), formatters, formattedResult, append); 630 formattedResult = result.formattedResult; 631 parameters = result.unusedSubstitutions; 632 if (parameters.length) 633 formattedResult.appendChild(document.createTextNode(" ")); 634 } 635 636 for (var i = 0; i < parameters.length; ++i) { 637 if (typeof parameters[i] === "string") 638 formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i])); 639 else 640 formattedResult.appendChild(formatForConsole(parameters[i])); 641 642 if (i < parameters.length - 1) 643 formattedResult.appendChild(document.createTextNode(" ")); 644 } 645 646 return formattedResult; 647 }, 648 649 toMessageElement: function() 650 { 651 if (this.propertiesSection) 652 return this.propertiesSection.element; 653 654 var element = document.createElement("div"); 655 element.message = this; 656 element.className = "console-message"; 657 658 switch (this.source) { 659 case WebInspector.ConsoleMessage.MessageSource.HTML: 660 element.addStyleClass("console-html-source"); 661 break; 662 case WebInspector.ConsoleMessage.MessageSource.WML: 663 element.addStyleClass("console-wml-source"); 664 break; 665 case WebInspector.ConsoleMessage.MessageSource.XML: 666 element.addStyleClass("console-xml-source"); 667 break; 668 case WebInspector.ConsoleMessage.MessageSource.JS: 669 element.addStyleClass("console-js-source"); 670 break; 671 case WebInspector.ConsoleMessage.MessageSource.CSS: 672 element.addStyleClass("console-css-source"); 673 break; 674 case WebInspector.ConsoleMessage.MessageSource.Other: 675 element.addStyleClass("console-other-source"); 676 break; 677 } 678 679 switch (this.level) { 680 case WebInspector.ConsoleMessage.MessageLevel.Tip: 681 element.addStyleClass("console-tip-level"); 682 break; 683 case WebInspector.ConsoleMessage.MessageLevel.Log: 684 element.addStyleClass("console-log-level"); 685 break; 686 case WebInspector.ConsoleMessage.MessageLevel.Warning: 687 element.addStyleClass("console-warning-level"); 688 break; 689 case WebInspector.ConsoleMessage.MessageLevel.Error: 690 element.addStyleClass("console-error-level"); 691 break; 692 } 693 694 if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup) { 695 element.addStyleClass("console-group-title"); 696 } 697 698 if (this.elementsTreeOutline) { 699 element.addStyleClass("outline-disclosure"); 700 element.appendChild(this.elementsTreeOutline.element); 701 return element; 702 } 703 704 if (this.repeatCount > 1) { 705 var messageRepeatCountElement = document.createElement("span"); 706 messageRepeatCountElement.className = "bubble"; 707 messageRepeatCountElement.textContent = this.repeatCount; 708 709 element.appendChild(messageRepeatCountElement); 710 element.addStyleClass("repeated-message"); 711 } 712 713 if (this.url && this.url !== "undefined") { 714 var urlElement = document.createElement("a"); 715 urlElement.className = "console-message-url webkit-html-resource-link"; 716 urlElement.href = this.url; 717 urlElement.lineNumber = this.line; 718 719 if (this.source === WebInspector.ConsoleMessage.MessageSource.JS) 720 urlElement.preferredPanel = "scripts"; 721 722 if (this.line > 0) 723 urlElement.textContent = WebInspector.displayNameForURL(this.url) + ":" + this.line; 724 else 725 urlElement.textContent = WebInspector.displayNameForURL(this.url); 726 727 element.appendChild(urlElement); 728 } 729 730 var messageTextElement = document.createElement("span"); 731 messageTextElement.className = "console-message-text"; 732 messageTextElement.appendChild(this.formattedMessage); 733 element.appendChild(messageTextElement); 734 735 return element; 736 }, 737 738 toString: function() 739 { 740 var sourceString; 741 switch (this.source) { 742 case WebInspector.ConsoleMessage.MessageSource.HTML: 743 sourceString = "HTML"; 744 break; 745 case WebInspector.ConsoleMessage.MessageSource.WML: 746 sourceString = "WML"; 747 break; 748 case WebInspector.ConsoleMessage.MessageSource.XML: 749 sourceString = "XML"; 750 break; 751 case WebInspector.ConsoleMessage.MessageSource.JS: 752 sourceString = "JS"; 753 break; 754 case WebInspector.ConsoleMessage.MessageSource.CSS: 755 sourceString = "CSS"; 756 break; 757 case WebInspector.ConsoleMessage.MessageSource.Other: 758 sourceString = "Other"; 759 break; 760 } 761 762 var typeString; 763 switch (this.type) { 764 case WebInspector.ConsoleMessage.MessageType.Log: 765 typeString = "Log"; 766 break; 767 case WebInspector.ConsoleMessage.MessageType.Object: 768 typeString = "Object"; 769 break; 770 case WebInspector.ConsoleMessage.MessageType.Trace: 771 typeString = "Trace"; 772 break; 773 case WebInspector.ConsoleMessage.MessageType.StartGroup: 774 typeString = "Start Group"; 775 break; 776 case WebInspector.ConsoleMessage.MessageType.EndGroup: 777 typeString = "End Group"; 778 break; 779 } 780 781 var levelString; 782 switch (this.level) { 783 case WebInspector.ConsoleMessage.MessageLevel.Tip: 784 levelString = "Tip"; 785 break; 786 case WebInspector.ConsoleMessage.MessageLevel.Log: 787 levelString = "Log"; 788 break; 789 case WebInspector.ConsoleMessage.MessageLevel.Warning: 790 levelString = "Warning"; 791 break; 792 case WebInspector.ConsoleMessage.MessageLevel.Error: 793 levelString = "Error"; 794 break; 795 } 796 797 return sourceString + " " + typeString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line; 798 }, 799 800 isEqual: function(msg, disreguardGroup) 801 { 802 if (!msg) 803 return false; 804 805 var ret = (this.source == msg.source) 806 && (this.type == msg.type) 807 && (this.level == msg.level) 808 && (this.line == msg.line) 809 && (this.url == msg.url) 810 && (this.message == msg.message); 811 812 return (disreguardGroup ? ret : (ret && (this.groupLevel == msg.groupLevel))); 813 } 814} 815 816// Note: Keep these constants in sync with the ones in Console.h 817WebInspector.ConsoleMessage.MessageSource = { 818 HTML: 0, 819 WML: 1, 820 XML: 2, 821 JS: 3, 822 CSS: 4, 823 Other: 5 824} 825 826WebInspector.ConsoleMessage.MessageType = { 827 Log: 0, 828 Object: 1, 829 Trace: 2, 830 StartGroup: 3, 831 EndGroup: 4 832} 833 834WebInspector.ConsoleMessage.MessageLevel = { 835 Tip: 0, 836 Log: 1, 837 Warning: 2, 838 Error: 3 839} 840 841WebInspector.ConsoleCommand = function(command) 842{ 843 this.command = command; 844} 845 846WebInspector.ConsoleCommand.prototype = { 847 toMessageElement: function() 848 { 849 var element = document.createElement("div"); 850 element.command = this; 851 element.className = "console-user-command"; 852 853 var commandTextElement = document.createElement("span"); 854 commandTextElement.className = "console-message-text"; 855 commandTextElement.textContent = this.command; 856 element.appendChild(commandTextElement); 857 858 return element; 859 } 860} 861 862WebInspector.ConsoleCommandResult = function(result, exception, originatingCommand) 863{ 864 var level = (exception ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log); 865 var message = (exception ? String(result) : result); 866 var line = (exception ? result.line : -1); 867 var url = (exception ? result.sourceURL : null); 868 869 WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, WebInspector.ConsoleMessage.MessageType.Log, level, line, url, null, 1, message); 870 871 this.originatingCommand = originatingCommand; 872} 873 874WebInspector.ConsoleCommandResult.prototype = { 875 toMessageElement: function() 876 { 877 var element = WebInspector.ConsoleMessage.prototype.toMessageElement.call(this); 878 element.addStyleClass("console-user-command-result"); 879 return element; 880 } 881} 882 883WebInspector.ConsoleCommandResult.prototype.__proto__ = WebInspector.ConsoleMessage.prototype; 884 885WebInspector.ConsoleGroup = function(parentGroup, level) 886{ 887 this.parentGroup = parentGroup; 888 this.level = level; 889 890 var element = document.createElement("div"); 891 element.className = "console-group"; 892 element.group = this; 893 this.element = element; 894 895 var messagesElement = document.createElement("div"); 896 messagesElement.className = "console-group-messages"; 897 element.appendChild(messagesElement); 898 this.messagesElement = messagesElement; 899} 900 901WebInspector.ConsoleGroup.prototype = { 902 addMessage: function(msg) 903 { 904 var element = msg.toMessageElement(); 905 906 if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup) { 907 this.messagesElement.parentNode.insertBefore(element, this.messagesElement); 908 element.addEventListener("click", this._titleClicked.bind(this), true); 909 } else 910 this.messagesElement.appendChild(element); 911 912 if (element.previousSibling && msg.originatingCommand && element.previousSibling.command === msg.originatingCommand) 913 element.previousSibling.addStyleClass("console-adjacent-user-command-result"); 914 }, 915 916 _titleClicked: function(event) 917 { 918 var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title"); 919 if (groupTitleElement) { 920 var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group"); 921 if (groupElement) 922 if (groupElement.hasStyleClass("collapsed")) 923 groupElement.removeStyleClass("collapsed"); 924 else 925 groupElement.addStyleClass("collapsed"); 926 groupTitleElement.scrollIntoViewIfNeeded(true); 927 } 928 929 event.stopPropagation(); 930 event.preventDefault(); 931 } 932} 933