2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 WebInspector.Console = function()
33 WebInspector.View.call(this, document.getElementById("console"));
35 this.messagesElement = document.getElementById("console-messages");
36 this.messagesElement.addEventListener("selectstart", this._messagesSelectStart.bind(this), false);
37 this.messagesElement.addEventListener("click", this._messagesClicked.bind(this), true);
39 this.promptElement = document.getElementById("console-prompt");
40 this.promptElement.handleKeyEvent = this._promptKeyDown.bind(this);
41 this.prompt = new WebInspector.TextPrompt(this.promptElement, this.completions.bind(this), " .=:[({;");
43 this.toggleButton = document.getElementById("console-status-bar-item");
44 this.toggleButton.title = WebInspector.UIString("Show console.");
45 this.toggleButton.addEventListener("click", this._toggleButtonClicked.bind(this), false);
47 this.clearButton = document.getElementById("clear-console-status-bar-item");
48 this.clearButton.title = WebInspector.UIString("Clear console log.");
49 this.clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false);
51 this.topGroup = new WebInspector.ConsoleGroup(null, 0);
52 this.messagesElement.insertBefore(this.topGroup.element, this.promptElement);
54 this.currentGroup = this.topGroup;
56 document.getElementById("main-status-bar").addEventListener("mousedown", this._startStatusBarDragging.bind(this), true);
59 WebInspector.Console.prototype = {
62 if (this._animating || this.visible)
65 WebInspector.View.prototype.show.call(this);
67 this._animating = true;
69 this.toggleButton.addStyleClass("toggled-on");
70 this.toggleButton.title = WebInspector.UIString("Hide console.");
72 document.body.addStyleClass("console-visible");
74 var anchoredItems = document.getElementById("anchored-status-bar-items");
77 {element: document.getElementById("main"), end: {bottom: this.element.offsetHeight}},
78 {element: document.getElementById("main-status-bar"), start: {"padding-left": anchoredItems.offsetWidth - 1}, end: {"padding-left": 0}},
79 {element: document.getElementById("other-console-status-bar-items"), start: {opacity: 0}, end: {opacity: 1}}
82 var consoleStatusBar = document.getElementById("console-status-bar");
83 consoleStatusBar.insertBefore(anchoredItems, consoleStatusBar.firstChild);
85 function animationFinished()
87 if ("updateStatusBarItems" in WebInspector.currentPanel)
88 WebInspector.currentPanel.updateStatusBarItems();
89 WebInspector.currentFocusElement = this.promptElement;
90 delete this._animating;
93 WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this));
95 if (!this.prompt.isCaretInsidePrompt())
96 this.prompt.moveCaretToEndOfPrompt();
101 if (this._animating || !this.visible)
104 WebInspector.View.prototype.hide.call(this);
106 this._animating = true;
108 this.toggleButton.removeStyleClass("toggled-on");
109 this.toggleButton.title = WebInspector.UIString("Show console.");
111 if (this.element === WebInspector.currentFocusElement || this.element.isAncestor(WebInspector.currentFocusElement))
112 WebInspector.currentFocusElement = WebInspector.previousFocusElement;
114 var anchoredItems = document.getElementById("anchored-status-bar-items");
116 // Temporally set properties and classes to mimic the post-animation values so panels
117 // like Elements in their updateStatusBarItems call will size things to fit the final location.
118 document.getElementById("main-status-bar").style.setProperty("padding-left", (anchoredItems.offsetWidth - 1) + "px");
119 document.body.removeStyleClass("console-visible");
120 if ("updateStatusBarItems" in WebInspector.currentPanel)
121 WebInspector.currentPanel.updateStatusBarItems();
122 document.body.addStyleClass("console-visible");
125 {element: document.getElementById("main"), end: {bottom: 0}},
126 {element: document.getElementById("main-status-bar"), start: {"padding-left": 0}, end: {"padding-left": anchoredItems.offsetWidth - 1}},
127 {element: document.getElementById("other-console-status-bar-items"), start: {opacity: 1}, end: {opacity: 0}}
130 function animationFinished()
132 var mainStatusBar = document.getElementById("main-status-bar");
133 mainStatusBar.insertBefore(anchoredItems, mainStatusBar.firstChild);
134 mainStatusBar.style.removeProperty("padding-left");
135 document.body.removeStyleClass("console-visible");
136 delete this._animating;
139 WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this));
142 addMessage: function(msg)
144 if (msg instanceof WebInspector.ConsoleMessage) {
145 msg.totalRepeatCount = msg.repeatCount;
146 msg.repeatDelta = msg.repeatCount;
148 var messageRepeated = false;
150 if (msg.isEqual && msg.isEqual(this.previousMessage)) {
151 // Because sometimes we get a large number of repeated messages and sometimes
152 // we get them one at a time, we need to know the difference between how many
153 // repeats we used to have and how many we have now.
154 msg.repeatDelta -= this.previousMessage.totalRepeatCount;
156 if (!isNaN(this.repeatCountBeforeCommand))
157 msg.repeatCount -= this.repeatCountBeforeCommand;
159 if (!this.commandSincePreviousMessage) {
160 // Recreate the previous message element to reset the repeat count.
161 var messagesElement = this.currentGroup.messagesElement;
162 messagesElement.removeChild(messagesElement.lastChild);
163 messagesElement.appendChild(msg.toMessageElement());
165 messageRepeated = true;
168 delete this.repeatCountBeforeCommand;
170 // Increment the error or warning count
172 case WebInspector.ConsoleMessage.MessageLevel.Warning:
173 WebInspector.warnings += msg.repeatDelta;
175 case WebInspector.ConsoleMessage.MessageLevel.Error:
176 WebInspector.errors += msg.repeatDelta;
180 // Add message to the resource panel
181 if (msg.url in WebInspector.resourceURLMap) {
182 msg.resource = WebInspector.resourceURLMap[msg.url];
183 if (WebInspector.panels.resources)
184 WebInspector.panels.resources.addMessageToResource(msg.resource, msg);
187 this.commandSincePreviousMessage = false;
188 this.previousMessage = msg;
192 } else if (msg instanceof WebInspector.ConsoleCommand) {
193 if (this.previousMessage) {
194 this.commandSincePreviousMessage = true;
195 this.repeatCountBeforeCommand = this.previousMessage.totalRepeatCount;
199 this.messages.push(msg);
201 if (msg.level === WebInspector.ConsoleMessage.MessageLevel.EndGroup) {
202 if (this.groupLevel < 1)
207 this.currentGroup = this.currentGroup.parentGroup;
209 if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) {
212 var group = new WebInspector.ConsoleGroup(this.currentGroup, this.groupLevel);
213 this.currentGroup.messagesElement.appendChild(group.element);
214 this.currentGroup = group;
217 this.currentGroup.addMessage(msg);
220 this.promptElement.scrollIntoView(false);
223 clearMessages: function(clearInspectorController)
225 if (clearInspectorController)
226 InspectorController.clearMessages();
227 if (WebInspector.panels.resources)
228 WebInspector.panels.resources.clearMessages();
233 this.currentGroup = this.topGroup;
234 this.topGroup.messagesElement.removeChildren();
236 WebInspector.errors = 0;
237 WebInspector.warnings = 0;
239 delete this.commandSincePreviousMessage;
240 delete this.repeatCountBeforeCommand;
241 delete this.previousMessage;
244 completions: function(wordRange, bestMatchOnly)
246 // Pass less stop characters to rangeOfWord so the range will be a more complete expression.
247 const expressionStopCharacters = " =:{;";
248 var expressionRange = wordRange.startContainer.rangeOfWord(wordRange.startOffset, expressionStopCharacters, this.promptElement, "backward");
249 var expressionString = expressionRange.toString();
250 var lastIndex = expressionString.length - 1;
252 var dotNotation = (expressionString[lastIndex] === ".");
253 var bracketNotation = (expressionString[lastIndex] === "[");
255 if (dotNotation || bracketNotation)
256 expressionString = expressionString.substr(0, lastIndex);
258 var prefix = wordRange.toString();
259 if (!expressionString && !prefix)
263 if (expressionString) {
265 result = this._evalInInspectedWindow(expressionString);
267 // Do nothing, the prefix will be considered a window property.
270 // There is no expressionString, so the completion should happen against global properties.
271 // Or if the debugger is paused, against properties in scope of the selected call frame.
272 if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused)
273 result = WebInspector.panels.scripts.variablesInScopeForSelectedCallFrame();
275 result = InspectorController.inspectedWindow();
278 if (bracketNotation) {
279 if (prefix.length && prefix[0] === "'")
282 var quoteUsed = "\"";
286 var properties = Object.sortedProperties(result);
287 for (var i = 0; i < properties.length; ++i) {
288 var property = properties[i];
290 if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property))
293 if (bracketNotation) {
294 if (!/^[0-9]+$/.test(property))
295 property = quoteUsed + property.escapeCharacters(quoteUsed + "\\") + quoteUsed;
299 if (property.length < prefix.length)
301 if (property.indexOf(prefix) !== 0)
304 results.push(property);
312 _toggleButtonClicked: function()
314 this.visible = !this.visible;
317 _clearButtonClicked: function()
319 this.clearMessages(true);
322 _messagesSelectStart: function(event)
324 if (this._selectionTimeout)
325 clearTimeout(this._selectionTimeout);
327 this.prompt.clearAutoComplete();
329 function moveBackIfOutside()
331 delete this._selectionTimeout;
332 if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
333 this.prompt.moveCaretToEndOfPrompt();
334 this.prompt.autoCompleteSoon();
337 this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
340 _messagesClicked: function(event)
342 var link = event.target.enclosingNodeOrSelfWithNodeName("a");
343 if (!link || !link.representedNode)
346 WebInspector.updateFocusedNode(link.representedNode);
347 event.stopPropagation();
348 event.preventDefault();
351 _promptKeyDown: function(event)
353 switch (event.keyIdentifier) {
355 this._enterKeyPressed(event);
359 this.prompt.handleKeyEvent(event);
362 _startStatusBarDragging: function(event)
364 if (!this.visible || event.target !== document.getElementById("main-status-bar"))
367 WebInspector.elementDragStart(document.getElementById("main-status-bar"), this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), event, "row-resize");
369 this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop;
371 event.stopPropagation();
374 _statusBarDragging: function(event)
376 var mainElement = document.getElementById("main");
378 var height = window.innerHeight - event.pageY + this._statusBarDragOffset;
379 height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - mainElement.totalOffsetTop - Preferences.minConsoleHeight);
381 mainElement.style.bottom = height + "px";
382 this.element.style.height = height + "px";
384 event.preventDefault();
385 event.stopPropagation();
388 _endStatusBarDragging: function(event)
390 WebInspector.elementDragEnd(event);
392 delete this._statusBarDragOffset;
394 event.stopPropagation();
397 _evalInInspectedWindow: function(expression)
399 if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused)
400 return WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression);
402 var inspectedWindow = InspectorController.inspectedWindow();
403 if (!inspectedWindow._inspectorCommandLineAPI) {
404 inspectedWindow.eval("window._inspectorCommandLineAPI = { \
405 $: function() { return document.getElementById.apply(document, arguments) }, \
406 $$: function() { return document.querySelectorAll.apply(document, arguments) }, \
407 $x: function(xpath, context) { \
410 var doc = context || document; \
411 var results = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); \
413 while (node = results.iterateNext()) nodes.push(node); \
417 dir: function() { return console.dir.apply(console, arguments) }, \
418 dirxml: function() { return console.dirxml.apply(console, arguments) }, \
419 keys: function(o) { var a = []; for (k in o) a.push(k); return a; }, \
420 values: function(o) { var a = []; for (k in o) a.push(o[k]); return a; }, \
421 profile: function() { return console.profile.apply(console, arguments) }, \
422 profileEnd: function() { return console.profileEnd.apply(console, arguments) } \
425 inspectedWindow._inspectorCommandLineAPI.clear = InspectorController.wrapCallback(this.clearMessages.bind(this));
428 // Surround the expression in with statements to inject our command line API so that
429 // the window object properties still take more precedent than our API functions.
430 expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }";
432 return inspectedWindow.eval(expression);
435 _enterKeyPressed: function(event)
440 event.preventDefault();
441 event.stopPropagation();
443 this.prompt.clearAutoComplete(true);
445 var str = this.prompt.text;
449 var commandMessage = new WebInspector.ConsoleCommand(str);
450 this.addMessage(commandMessage);
453 var exception = false;
455 result = this._evalInInspectedWindow(str);
461 this.prompt.history.push(str);
462 this.prompt.historyOffset = 0;
463 this.prompt.text = "";
465 this.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage));
468 _mouseOverNode: function(event)
470 var anchorElement = event.target.enclosingNodeOrSelfWithNodeName("a");
471 WebInspector.hoveredDOMNode = (anchorElement ? anchorElement.representedNode : null);
474 _mouseOutOfNode: function(event)
476 var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
477 var anchorElement = nodeUnderMouse.enclosingNodeOrSelfWithNodeName("a");
478 if (!anchorElement || !anchorElement.representedNode)
479 WebInspector.hoveredDOMNode = null;
482 _format: function(output, inline)
484 var type = Object.type(output, InspectorController.inspectedWindow());
485 if (type === "object") {
486 if (output instanceof InspectorController.inspectedWindow().Node)
490 // We don't perform any special formatting on these types, so we just
491 // pass them through the simple _formatvalue function.
492 var undecoratedTypes = {
502 if (type in undecoratedTypes)
503 formatter = "_formatvalue";
505 formatter = "_format" + type;
506 if (!(formatter in this)) {
507 formatter = "_formatobject";
512 var span = document.createElement("span");
513 span.addStyleClass("console-formatted-" + type);
514 this[formatter](output, span, inline);
518 _formatvalue: function(val, elem, inline)
520 elem.appendChild(document.createTextNode(val));
523 _formatstring: function(str, elem, inline)
525 elem.appendChild(document.createTextNode("\"" + str + "\""));
528 _formatregexp: function(re, elem, inline)
530 var formatted = String(re).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1);
531 elem.appendChild(document.createTextNode(formatted));
534 _formatarray: function(arr, elem, inline)
536 elem.appendChild(document.createTextNode("["));
537 for (var i = 0; i < arr.length; ++i) {
538 elem.appendChild(this._format(arr[i], true));
539 if (i < arr.length - 1)
540 elem.appendChild(document.createTextNode(", "));
542 elem.appendChild(document.createTextNode("]"));
545 _formatnode: function(node, elem, inline)
547 var anchor = document.createElement("a");
548 anchor.className = "inspectable-node";
549 anchor.innerHTML = nodeTitleInfo.call(node).title;
550 anchor.representedNode = node;
551 anchor.addEventListener("mouseover", this._mouseOverNode.bind(this), false);
552 anchor.addEventListener("mouseout", this._mouseOutOfNode.bind(this), false);
555 elem.appendChild(anchor);
557 elem.appendChild(new WebInspector.ObjectPropertiesSection(node, anchor, null, null, true).element);
560 _formatobject: function(obj, elem, inline)
563 elem.appendChild(document.createTextNode(Object.describe(obj)));
565 elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null, null, null, true).element);
568 _formaterror: function(obj, elem, inline)
570 var messageElement = document.createElement("span");
571 messageElement.className = "error-message";
572 messageElement.textContent = obj.name + ": " + obj.message;
573 elem.appendChild(messageElement);
576 var urlElement = document.createElement("a");
577 urlElement.className = "webkit-html-resource-link";
578 urlElement.href = obj.sourceURL;
579 urlElement.lineNumber = obj.line;
580 urlElement.preferredPanel = "scripts";
583 urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL) + ":" + obj.line;
585 urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL);
587 elem.appendChild(document.createTextNode(" ("));
588 elem.appendChild(urlElement);
589 elem.appendChild(document.createTextNode(")"));
594 WebInspector.Console.prototype.__proto__ = WebInspector.View.prototype;
596 WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, repeatCount)
598 this.source = source;
602 this.groupLevel = groupLevel;
603 this.repeatCount = repeatCount;
605 switch (this.level) {
606 case WebInspector.ConsoleMessage.MessageLevel.Object:
607 var propertiesSection = new WebInspector.ObjectPropertiesSection(arguments[6], null, null, null, true);
608 propertiesSection.element.addStyleClass("console-message");
609 this.propertiesSection = propertiesSection;
611 case WebInspector.ConsoleMessage.MessageLevel.Node:
612 var node = arguments[6];
613 if (!(node instanceof InspectorController.inspectedWindow().Node))
615 this.elementsTreeOutline = new WebInspector.ElementsTreeOutline();
616 this.elementsTreeOutline.rootDOMNode = node;
618 case WebInspector.ConsoleMessage.MessageLevel.Trace:
619 var span = document.createElement("span");
620 span.addStyleClass("console-formatted-trace");
621 var stack = Array.prototype.slice.call(arguments, 6);
622 var funcNames = stack.map(function(f) {
623 return f || WebInspector.UIString("(anonymous function)");
625 span.appendChild(document.createTextNode(funcNames.join("\n")));
626 this.formattedMessage = span;
629 // The formatedMessage property is used for the rich and interactive console.
630 this.formattedMessage = this._format(Array.prototype.slice.call(arguments, 6));
632 // This is used for inline message bubbles in SourceFrames, or other plain-text representations.
633 this.message = this.formattedMessage.textContent;
638 WebInspector.ConsoleMessage.prototype = {
639 isErrorOrWarning: function()
641 return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
644 _format: function(parameters)
646 var formattedResult = document.createElement("span");
648 if (!parameters.length)
649 return formattedResult;
651 function formatForConsole(obj)
653 return WebInspector.console._format(obj, true);
656 if (Object.type(parameters[0], InspectorController.inspectedWindow()) === "string") {
658 for (var i in String.standardFormatters)
659 formatters[i] = String.standardFormatters[i];
661 // Firebug uses %o for formatting objects.
662 formatters.o = formatForConsole;
663 // Firebug allows both %i and %d for formatting integers.
664 formatters.i = formatters.d;
666 function append(a, b)
668 if (!(b instanceof Node))
669 a.appendChild(WebInspector.linkifyStringAsFragment(b.toString()));
675 var result = String.format(parameters[0], parameters.slice(1), formatters, formattedResult, append);
676 formattedResult = result.formattedResult;
677 parameters = result.unusedSubstitutions;
678 if (parameters.length)
679 formattedResult.appendChild(document.createTextNode(" "));
682 for (var i = 0; i < parameters.length; ++i) {
683 if (typeof parameters[i] === "string")
684 formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i]));
685 else if (parameters.length === 1)
686 formattedResult.appendChild(WebInspector.console._format(parameters[0]));
688 formattedResult.appendChild(formatForConsole(parameters[i]));
689 if (i < parameters.length - 1)
690 formattedResult.appendChild(document.createTextNode(" "));
693 return formattedResult;
696 toMessageElement: function()
698 if (this.propertiesSection)
699 return this.propertiesSection.element;
701 var element = document.createElement("div");
702 element.message = this;
703 element.className = "console-message";
705 switch (this.source) {
706 case WebInspector.ConsoleMessage.MessageSource.HTML:
707 element.addStyleClass("console-html-source");
709 case WebInspector.ConsoleMessage.MessageSource.WML:
710 element.addStyleClass("console-wml-source");
712 case WebInspector.ConsoleMessage.MessageSource.XML:
713 element.addStyleClass("console-xml-source");
715 case WebInspector.ConsoleMessage.MessageSource.JS:
716 element.addStyleClass("console-js-source");
718 case WebInspector.ConsoleMessage.MessageSource.CSS:
719 element.addStyleClass("console-css-source");
721 case WebInspector.ConsoleMessage.MessageSource.Other:
722 element.addStyleClass("console-other-source");
726 switch (this.level) {
727 case WebInspector.ConsoleMessage.MessageLevel.Tip:
728 element.addStyleClass("console-tip-level");
730 case WebInspector.ConsoleMessage.MessageLevel.Log:
731 element.addStyleClass("console-log-level");
733 case WebInspector.ConsoleMessage.MessageLevel.Warning:
734 element.addStyleClass("console-warning-level");
736 case WebInspector.ConsoleMessage.MessageLevel.Error:
737 element.addStyleClass("console-error-level");
739 case WebInspector.ConsoleMessage.MessageLevel.StartGroup:
740 element.addStyleClass("console-group-title-level");
743 if (this.elementsTreeOutline) {
744 element.addStyleClass("outline-disclosure");
745 element.appendChild(this.elementsTreeOutline.element);
749 if (this.repeatCount > 1) {
750 var messageRepeatCountElement = document.createElement("span");
751 messageRepeatCountElement.className = "bubble";
752 messageRepeatCountElement.textContent = this.repeatCount;
754 element.appendChild(messageRepeatCountElement);
755 element.addStyleClass("repeated-message");
758 if (this.url && this.url !== "undefined") {
759 var urlElement = document.createElement("a");
760 urlElement.className = "console-message-url webkit-html-resource-link";
761 urlElement.href = this.url;
762 urlElement.lineNumber = this.line;
764 if (this.source === WebInspector.ConsoleMessage.MessageSource.JS)
765 urlElement.preferredPanel = "scripts";
768 urlElement.textContent = WebInspector.displayNameForURL(this.url) + ":" + this.line;
770 urlElement.textContent = WebInspector.displayNameForURL(this.url);
772 element.appendChild(urlElement);
775 var messageTextElement = document.createElement("span");
776 messageTextElement.className = "console-message-text";
777 messageTextElement.appendChild(this.formattedMessage);
778 element.appendChild(messageTextElement);
786 switch (this.source) {
787 case WebInspector.ConsoleMessage.MessageSource.HTML:
788 sourceString = "HTML";
790 case WebInspector.ConsoleMessage.MessageSource.WML:
791 sourceString = "WML";
793 case WebInspector.ConsoleMessage.MessageSource.XML:
794 sourceString = "XML";
796 case WebInspector.ConsoleMessage.MessageSource.JS:
799 case WebInspector.ConsoleMessage.MessageSource.CSS:
800 sourceString = "CSS";
802 case WebInspector.ConsoleMessage.MessageSource.Other:
803 sourceString = "Other";
808 switch (this.level) {
809 case WebInspector.ConsoleMessage.MessageLevel.Tip:
812 case WebInspector.ConsoleMessage.MessageLevel.Log:
815 case WebInspector.ConsoleMessage.MessageLevel.Warning:
816 levelString = "Warning";
818 case WebInspector.ConsoleMessage.MessageLevel.Error:
819 levelString = "Error";
821 case WebInspector.ConsoleMessage.MessageLevel.Object:
822 levelString = "Object";
824 case WebInspector.ConsoleMessage.MessageLevel.GroupTitle:
825 levelString = "GroupTitle";
829 return sourceString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line;
832 isEqual: function(msg, disreguardGroup)
837 var ret = (this.source == msg.source)
838 && (this.level == msg.level)
839 && (this.line == msg.line)
840 && (this.url == msg.url)
841 && (this.message == msg.message);
843 return (disreguardGroup ? ret : (ret && (this.groupLevel == msg.groupLevel)));
847 // Note: Keep these constants in sync with the ones in Console.h
848 WebInspector.ConsoleMessage.MessageSource = {
857 WebInspector.ConsoleMessage.MessageLevel = {
869 WebInspector.ConsoleCommand = function(command)
871 this.command = command;
874 WebInspector.ConsoleCommand.prototype = {
875 toMessageElement: function()
877 var element = document.createElement("div");
878 element.command = this;
879 element.className = "console-user-command";
881 var commandTextElement = document.createElement("span");
882 commandTextElement.className = "console-message-text";
883 commandTextElement.textContent = this.command;
884 element.appendChild(commandTextElement);
890 WebInspector.ConsoleCommandResult = function(result, exception, originatingCommand)
892 var level = (exception ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log);
893 var message = (exception ? String(result) : result);
894 var line = (exception ? result.line : -1);
895 var url = (exception ? result.sourceURL : null);
897 WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, level, line, url, null, 1, message);
899 this.originatingCommand = originatingCommand;
902 WebInspector.ConsoleCommandResult.prototype = {
903 toMessageElement: function()
905 var element = WebInspector.ConsoleMessage.prototype.toMessageElement.call(this);
906 element.addStyleClass("console-user-command-result");
911 WebInspector.ConsoleCommandResult.prototype.__proto__ = WebInspector.ConsoleMessage.prototype;
913 WebInspector.ConsoleGroup = function(parentGroup, level)
915 this.parentGroup = parentGroup;
918 var element = document.createElement("div");
919 element.className = "console-group";
920 element.group = this;
921 this.element = element;
923 var messagesElement = document.createElement("div");
924 messagesElement.className = "console-group-messages";
925 element.appendChild(messagesElement);
926 this.messagesElement = messagesElement;
929 WebInspector.ConsoleGroup.prototype = {
930 addMessage: function(msg)
932 var element = msg.toMessageElement();
934 if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) {
935 this.messagesElement.parentNode.insertBefore(element, this.messagesElement);
936 element.addEventListener("click", this._titleClicked.bind(this), true);
938 this.messagesElement.appendChild(element);
940 if (element.previousSibling && msg.originatingCommand && element.previousSibling.command === msg.originatingCommand)
941 element.previousSibling.addStyleClass("console-adjacent-user-command-result");
944 _titleClicked: function(event)
946 var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title-level");
947 if (groupTitleElement) {
948 var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group");
950 if (groupElement.hasStyleClass("collapsed"))
951 groupElement.removeStyleClass("collapsed");
953 groupElement.addStyleClass("collapsed");
954 groupTitleElement.scrollIntoViewIfNeeded(true);
957 event.stopPropagation();
958 event.preventDefault();