2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved.
4 * Copyright (C) 2009 Joseph Pecoraro
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 WebInspector.ConsoleMessageImpl = function(source, level, message, linkifier, type, url, line, column, repeatCount, parameters, stackTrace, request)
33 WebInspector.ConsoleMessage.call(this, source, level, url, line, column, repeatCount);
35 this._linkifier = linkifier;
36 this.type = type || WebInspector.ConsoleMessage.MessageType.Log;
37 this._messageText = message;
38 this._parameters = parameters;
39 this._stackTrace = stackTrace;
40 this._request = request;
42 this._customFormatters = {
43 "object": this._formatParameterAsObject,
44 "error": this._formatParameterAsObject,
45 "map": this._formatParameterAsObject,
46 "set": this._formatParameterAsObject,
47 "weakmap": this._formatParameterAsObject,
48 "array": this._formatParameterAsArray,
49 "node": this._formatParameterAsNode,
50 "string": this._formatParameterAsString
54 WebInspector.ConsoleMessageImpl.prototype = {
56 enforcesClipboardPrefixString: true,
58 _formatMessage: function()
60 this._formattedMessage = document.createElement("span");
61 this._formattedMessage.className = "console-message-text source-code";
64 if (this.source === WebInspector.ConsoleMessage.MessageSource.ConsoleAPI) {
66 case WebInspector.ConsoleMessage.MessageType.Trace:
67 messageText = document.createTextNode("console.trace()");
69 case WebInspector.ConsoleMessage.MessageType.Assert:
70 var args = [WebInspector.UIString("Assertion failed:")];
72 args = args.concat(this._parameters);
73 messageText = this._format(args);
75 case WebInspector.ConsoleMessage.MessageType.Dir:
76 var obj = this._parameters ? this._parameters[0] : undefined;
77 var args = ["%O", obj];
78 messageText = this._format(args);
81 var args = this._parameters || [this._messageText];
82 messageText = this._format(args);
84 } else if (this.source === WebInspector.ConsoleMessage.MessageSource.Network) {
86 this._stackTrace = this._request.stackTrace;
87 if (this._request.initiator && this._request.initiator.url) {
88 this.url = this._request.initiator.url;
89 this.line = this._request.initiator.lineNumber;
91 messageText = document.createElement("span");
92 if (this.level === WebInspector.ConsoleMessage.MessageLevel.Error) {
93 messageText.appendChild(document.createTextNode(this._request.requestMethod + " "));
94 messageText.appendChild(WebInspector.linkifyRequestAsNode(this._request));
95 if (this._request.failed)
96 messageText.appendChild(document.createTextNode(" " + this._request.localizedFailDescription));
98 messageText.appendChild(document.createTextNode(" " + this._request.statusCode + " (" + this._request.statusText + ")"));
100 var fragment = WebInspector.linkifyStringAsFragmentWithCustomLinkifier(this._messageText, WebInspector.linkifyRequestAsNode.bind(null, this._request, ""));
101 messageText.appendChild(fragment);
105 var anchor = WebInspector.linkifyURLAsNode(this.url, this.url, "console-message-url");
106 this._formattedMessage.appendChild(anchor);
108 messageText = this._format([this._messageText]);
111 var args = this._parameters || [this._messageText];
112 messageText = this._format(args);
115 if (this.source !== WebInspector.ConsoleMessage.MessageSource.Network || this._request) {
116 var firstNonNativeCallFrame = this._firstNonNativeCallFrame();
117 if (firstNonNativeCallFrame) {
118 var urlElement = this._linkifyCallFrame(firstNonNativeCallFrame);
119 this._formattedMessage.appendChild(urlElement);
120 } else if (this.url && !this._shouldHideURL(this.url)) {
121 var urlElement = this._linkifyLocation(this.url, this.line, this.column);
122 this._formattedMessage.appendChild(urlElement);
126 this._formattedMessage.appendChild(messageText);
128 if (this._shouldDumpStackTrace()) {
129 var ol = document.createElement("ol");
130 ol.className = "outline-disclosure";
131 var treeOutline = new TreeOutline(ol);
133 var content = this._formattedMessage;
134 var root = new TreeElement(content, null, true);
135 content.treeElementForTest = root;
136 treeOutline.appendChild(root);
137 if (this.type === WebInspector.ConsoleMessage.MessageType.Trace)
140 this._populateStackTraceTreeElement(root);
141 this._formattedMessage = ol;
144 // This is used for inline message bubbles in SourceFrames, or other plain-text representations.
145 this._message = messageText.textContent;
148 _shouldDumpStackTrace: function()
150 return !!this._stackTrace && this._stackTrace.length && (this.source === WebInspector.ConsoleMessage.MessageSource.Network || this.level === WebInspector.ConsoleMessage.MessageLevel.Error || this.type === WebInspector.ConsoleMessage.MessageType.Trace);
153 _shouldHideURL: function(url)
155 return url === "undefined" || url === "[native code]";
158 _firstNonNativeCallFrame: function()
160 if (!this._stackTrace)
163 for (var i = 0; i < this._stackTrace.length; i++) {
164 var frame = this._stackTrace[i];
165 if (!frame.url || frame.url === "[native code]")
175 // force message formatting
176 var formattedMessage = this.formattedMessage;
177 return this._message;
180 get formattedMessage()
182 if (!this._formattedMessage)
183 this._formatMessage();
184 return this._formattedMessage;
187 _linkifyLocation: function(url, lineNumber, columnNumber)
189 // ConsoleMessage stack trace line numbers are one-based.
190 lineNumber = lineNumber ? lineNumber - 1 : 0;
192 return WebInspector.linkifyLocation(url, lineNumber, columnNumber, "console-message-url");
195 _linkifyCallFrame: function(callFrame)
197 return this._linkifyLocation(callFrame.url, callFrame.lineNumber, callFrame.columnNumber);
200 isErrorOrWarning: function()
202 return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
205 _format: function(parameters)
207 // This node is used like a Builder. Values are continually appended onto it.
208 var formattedResult = document.createElement("span");
209 if (!parameters.length)
210 return formattedResult;
212 // Formatting code below assumes that parameters are all wrappers whereas frontend console
213 // API allows passing arbitrary values as messages (strings, numbers, etc.). Wrap them here.
214 for (var i = 0; i < parameters.length; ++i) {
215 // FIXME: Only pass runtime wrappers here.
216 if (parameters[i] instanceof WebInspector.RemoteObject)
219 if (typeof parameters[i] === "object")
220 parameters[i] = WebInspector.RemoteObject.fromPayload(parameters[i]);
222 parameters[i] = WebInspector.RemoteObject.fromPrimitiveValue(parameters[i]);
225 // There can be string log and string eval result. We distinguish between them based on message type.
226 var shouldFormatMessage = WebInspector.RemoteObject.type(parameters[0]) === "string" && this.type !== WebInspector.ConsoleMessage.MessageType.Result;
228 if (shouldFormatMessage) {
229 // Multiple parameters with the first being a format string. Save unused substitutions.
230 var result = this._formatWithSubstitutionString(parameters, formattedResult);
231 parameters = result.unusedSubstitutions;
232 if (parameters.length)
233 formattedResult.appendChild(document.createTextNode(" "));
236 if (this.type === WebInspector.ConsoleMessage.MessageType.Table) {
237 formattedResult.appendChild(this._formatParameterAsTable(parameters));
238 return formattedResult;
241 // Single parameter, or unused substitutions from above.
242 for (var i = 0; i < parameters.length; ++i) {
243 // Inline strings when formatting.
244 if (shouldFormatMessage && parameters[i].type === "string") {
245 var span = document.createElement("span");
246 span.classList.add("type-string");
247 span.textContent = parameters[i].description;
248 formattedResult.appendChild(span);
250 formattedResult.appendChild(this._formatParameter(parameters[i], false));
252 if (i < parameters.length - 1 && !this._isExpandable(parameters[i]))
253 formattedResult.appendChild(document.createTextNode(" "));
256 return formattedResult;
259 _isExpandable: function(remoteObject) {
263 if (remoteObject.hasChildren && remoteObject.preview && remoteObject.preview.lossless)
266 return remoteObject.hasChildren;
269 _formatParameter: function(output, forceObjectFormat)
272 if (forceObjectFormat)
274 else if (output instanceof WebInspector.RemoteObject)
275 type = output.subtype || output.type;
277 type = typeof output;
279 var formatter = this._customFormatters[type];
281 formatter = this._formatParameterAsValue;
282 output = output.description;
285 var span = document.createElement("span");
286 span.className = "console-formatted-" + type + " source-code";
288 if (this._isExpandable(output))
289 span.classList.add("expandable");
291 formatter.call(this, output, span, forceObjectFormat);
295 _formatParameterAsValue: function(val, elem)
297 elem.appendChild(document.createTextNode(val));
300 _formatParameterAsObject: function(obj, elem, forceExpansion)
302 var objectTree = new WebInspector.ObjectTreeView(obj, WebInspector.ObjectTreeView.Mode.Properties, forceExpansion);
303 elem.appendChild(objectTree.element);
306 _propertyPreviewElement: function(property)
308 // FIXME: Used by console.table. We should be able to eliminate this in favor of ObjectPreview.
310 var span = document.createElement("span");
311 span.classList.add(WebInspector.ObjectTreeView.classNameForObject(property));
313 if (property.type === "string") {
314 span.textContent = "\"" + property.value.replace(/\n/g, "\u21B5").replace(/"/g, "\\\"") + "\"";
318 if (property.type === "function") {
319 span.textContent = "function";
323 span.textContent = property.value;
327 _formatParameterAsNode: function(object, elem)
329 function printNode(nodeId)
332 // Sometimes DOM is loaded after the sync message is being formatted, so we get no
333 // nodeId here. So we fall back to object formatting here.
334 this._formatParameterAsObject(object, elem, true);
337 var treeOutline = new WebInspector.DOMTreeOutline(false, false, true);
338 treeOutline.setVisible(true);
339 treeOutline.rootDOMNode = WebInspector.domTreeManager.nodeForId(nodeId);
340 treeOutline.element.classList.add("outline-disclosure");
341 if (!treeOutline.children[0].hasChildren)
342 treeOutline.element.classList.add("single-node");
343 elem.appendChild(treeOutline.element);
345 object.pushNodeToFrontend(printNode.bind(this));
348 _formatParameterAsArray: function(arr, elem)
350 // FIXME: Array previews look poor. Keep doing what we currently do for arrays.
351 arr.getOwnProperties(this._printArray.bind(this, arr, elem));
354 _userProvidedColumnNames: function(columnNamesArgument)
356 if (!columnNamesArgument)
359 var remoteObject = WebInspector.RemoteObject.fromPayload(columnNamesArgument);
361 // Single primitive argument.
362 if (remoteObject.type === "string" || remoteObject.type === "number")
363 return [String(columnNamesArgument.value)];
365 // Ignore everything that is not an array with property previews.
366 if (remoteObject.type !== "object" || remoteObject.subtype !== "array" || !remoteObject.preview || !remoteObject.preview.properties)
369 // Array. Look into the preview and get string values.
370 var extractedColumnNames = [];
371 for (var propertyPreview of remoteObject.preview.properties) {
372 if (propertyPreview.type === "string" || propertyPreview.type === "number")
373 extractedColumnNames.push(String(propertyPreview.value));
376 return extractedColumnNames.length ? extractedColumnNames : null;
379 _formatParameterAsTable: function(parameters)
381 var element = document.createElement("span");
382 var table = parameters[0];
383 if (!table || !table.preview)
387 var columnNames = [];
389 var preview = table.preview;
390 var userProvidedColumnNames = false;
392 // User provided columnNames.
393 var extractedColumnNames = this._userProvidedColumnNames(parameters[1]);
394 if (extractedColumnNames) {
395 userProvidedColumnNames = true;
396 columnNames = extractedColumnNames;
399 // Check first for valuePreviews in the properties meaning this was an array of objects.
400 for (var i = 0; i < preview.properties.length; ++i) {
401 var rowProperty = preview.properties[i];
402 var rowPreview = rowProperty.valuePreview;
407 const maxColumnsToRender = 10;
408 for (var j = 0; j < rowPreview.properties.length; ++j) {
409 var cellProperty = rowPreview.properties[j];
410 var columnRendered = columnNames.contains(cellProperty.name);
411 if (!columnRendered) {
412 if (userProvidedColumnNames || columnNames.length === maxColumnsToRender)
414 columnRendered = true;
415 columnNames.push(cellProperty.name);
418 rowValue[cellProperty.name] = this._propertyPreviewElement(cellProperty);
420 rows.push([rowProperty.name, rowValue]);
423 // If there were valuePreviews, convert to a flat list.
425 const emDash = "\u2014";
426 columnNames.unshift(WebInspector.UIString("(Index)"));
427 for (var i = 0; i < rows.length; ++i) {
428 var rowName = rows[i][0];
429 var rowValue = rows[i][1];
430 flatValues.push(rowName);
431 for (var j = 1; j < columnNames.length; ++j) {
432 var columnName = columnNames[j];
433 if (!(columnName in rowValue))
434 flatValues.push(emDash);
436 flatValues.push(rowValue[columnName]);
441 // If there were no value Previews, then check for an array of values.
442 if (!flatValues.length) {
443 for (var i = 0; i < preview.properties.length; ++i) {
444 var rowProperty = preview.properties[i];
445 if (!("value" in rowProperty))
448 if (!columnNames.length) {
449 columnNames.push(WebInspector.UIString("Index"));
450 columnNames.push(WebInspector.UIString("Value"));
453 flatValues.push(rowProperty.name);
454 flatValues.push(this._propertyPreviewElement(rowProperty));
458 // If lossless or not table data, output the object so full data can be gotten.
459 if (!preview.lossless || !flatValues.length) {
460 element.appendChild(this._formatParameter(table, true));
461 if (!flatValues.length)
465 var dataGridContainer = element.createChild("span");
466 var dataGrid = WebInspector.DataGrid.createSortableDataGrid(columnNames, flatValues);
467 dataGrid.element.classList.add("inline");
468 dataGridContainer.appendChild(dataGrid.element);
473 _formatParameterAsString: function(output, elem)
475 var span = document.createElement("span");
476 span.className = "console-formatted-string source-code";
477 span.appendChild(document.createTextNode("\""));
478 span.appendChild(WebInspector.linkifyStringAsFragment(output.description.replace(/"/g, "\\\"")));
479 span.appendChild(document.createTextNode("\""));
481 elem.classList.remove("console-formatted-string");
482 elem.appendChild(span);
485 _printArray: function(array, elem, properties)
491 for (var i = 0; i < properties.length; ++i) {
492 var property = properties[i];
493 var name = property.name;
495 elements[name] = this._formatAsArrayEntry(property.value);
498 elem.appendChild(document.createTextNode("["));
499 var lastNonEmptyIndex = -1;
501 function appendUndefined(elem, index)
503 if (index - lastNonEmptyIndex <= 1)
505 var span = elem.createChild("span", "console-formatted-undefined");
506 span.textContent = WebInspector.UIString("undefined × %d").format(index - lastNonEmptyIndex - 1);
509 var length = array.arrayLength();
510 for (var i = 0; i < length; ++i) {
511 var element = elements[i];
515 if (i - lastNonEmptyIndex > 1) {
516 appendUndefined(elem, i);
517 elem.appendChild(document.createTextNode(", "));
520 elem.appendChild(element);
521 lastNonEmptyIndex = i;
523 elem.appendChild(document.createTextNode(", "));
525 appendUndefined(elem, length);
527 elem.appendChild(document.createTextNode("]"));
530 _formatAsArrayEntry: function(output)
532 // Prevent infinite expansion of cross-referencing arrays.
533 return this._formatParameter(output, output.subtype && output.subtype === "array");
536 _formatWithSubstitutionString: function(parameters, formattedResult)
540 function parameterFormatter(force, obj)
542 return this._formatParameter(obj, force);
545 function stringFormatter(obj)
547 return obj.description;
550 function floatFormatter(obj)
552 if (typeof obj.value !== "number")
553 return parseFloat(obj.description);
557 function integerFormatter(obj)
559 if (typeof obj.value !== "number")
560 return parseInt(obj.description);
561 return Math.floor(obj.value);
564 var currentStyle = null;
565 function styleFormatter(obj)
568 var buffer = document.createElement("span");
569 buffer.setAttribute("style", obj.description);
570 for (var i = 0; i < buffer.style.length; i++) {
571 var property = buffer.style[i];
572 if (isWhitelistedProperty(property))
573 currentStyle[property] = buffer.style[property];
577 function isWhitelistedProperty(property)
579 var prefixes = ["background", "border", "color", "font", "line", "margin", "padding", "text", "-webkit-background", "-webkit-border", "-webkit-font", "-webkit-margin", "-webkit-padding", "-webkit-text"];
580 for (var i = 0; i < prefixes.length; i++) {
581 if (property.startsWith(prefixes[i]))
587 // Firebug uses %o for formatting objects.
588 formatters.o = parameterFormatter.bind(this, false);
589 formatters.s = stringFormatter;
590 formatters.f = floatFormatter;
592 // Firebug allows both %i and %d for formatting integers.
593 formatters.i = integerFormatter;
594 formatters.d = integerFormatter;
596 // Firebug uses %c for styling the message.
597 formatters.c = styleFormatter;
599 // Support %O to force object formatting, instead of the type-based %o formatting.
600 formatters.O = parameterFormatter.bind(this, true);
602 function append(a, b)
604 if (b instanceof Node)
607 var toAppend = WebInspector.linkifyStringAsFragment(b.toString());
609 var wrapper = document.createElement("span");
610 for (var key in currentStyle)
611 wrapper.style[key] = currentStyle[key];
612 wrapper.appendChild(toAppend);
615 var span = document.createElement("span");
616 span.className = "type-string";
617 span.appendChild(toAppend);
623 // String.format does treat formattedResult like a Builder, result is an object.
624 return String.format(parameters[0].description, parameters.slice(1), formatters, formattedResult, append);
627 decorateMessageElement: function(element)
630 return this._element;
632 element.message = this;
633 element.classList.add("console-message");
635 this._element = element;
637 switch (this.level) {
638 case WebInspector.ConsoleMessage.MessageLevel.Tip:
639 element.classList.add("console-tip-level");
640 element.setAttribute("data-labelprefix", WebInspector.UIString("Tip: "));
642 case WebInspector.ConsoleMessage.MessageLevel.Log:
643 element.classList.add("console-log-level");
644 element.setAttribute("data-labelprefix", WebInspector.UIString("Log: "));
646 case WebInspector.ConsoleMessage.MessageLevel.Debug:
647 element.classList.add("console-debug-level");
648 element.setAttribute("data-labelprefix", WebInspector.UIString("Debug: "));
650 case WebInspector.ConsoleMessage.MessageLevel.Warning:
651 element.classList.add("console-warning-level");
652 element.setAttribute("data-labelprefix", WebInspector.UIString("Warning: "));
654 case WebInspector.ConsoleMessage.MessageLevel.Error:
655 element.classList.add("console-error-level");
656 element.setAttribute("data-labelprefix", WebInspector.UIString("Error: "));
660 if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup || this.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
661 element.classList.add("console-group-title");
663 element.appendChild(this.formattedMessage);
665 if (this.repeatCount > 1)
666 this.updateRepeatCount();
671 toMessageElement: function()
674 return this._element;
676 var element = document.createElement("div");
678 return this.decorateMessageElement(element);
681 _populateStackTraceTreeElement: function(parentTreeElement)
683 for (var i = 0; i < this._stackTrace.length; i++) {
684 var frame = this._stackTrace[i];
686 var content = document.createElement("div");
687 var messageTextElement = document.createElement("span");
688 messageTextElement.className = "console-message-text source-code";
689 var functionName = frame.functionName || WebInspector.UIString("(anonymous function)");
690 messageTextElement.appendChild(document.createTextNode(functionName));
691 content.appendChild(messageTextElement);
693 if (frame.url && !this._shouldHideURL(frame.url)) {
694 var urlElement = this._linkifyCallFrame(frame);
695 content.appendChild(urlElement);
698 var treeElement = new TreeElement(content);
699 parentTreeElement.appendChild(treeElement);
703 updateRepeatCount: function() {
704 if (!this.repeatCountElement) {
705 this.repeatCountElement = document.createElement("span");
706 this.repeatCountElement.className = "bubble";
708 this._element.insertBefore(this.repeatCountElement, this._element.firstChild);
710 this.repeatCountElement.textContent = this.repeatCount;
716 switch (this.source) {
717 case WebInspector.ConsoleMessage.MessageSource.HTML:
718 sourceString = "HTML";
720 case WebInspector.ConsoleMessage.MessageSource.XML:
721 sourceString = "XML";
723 case WebInspector.ConsoleMessage.MessageSource.JS:
726 case WebInspector.ConsoleMessage.MessageSource.Network:
727 sourceString = "Network";
729 case WebInspector.ConsoleMessage.MessageSource.ConsoleAPI:
730 sourceString = "ConsoleAPI";
732 case WebInspector.ConsoleMessage.MessageSource.Other:
733 sourceString = "Other";
739 case WebInspector.ConsoleMessage.MessageType.Log:
742 case WebInspector.ConsoleMessage.MessageType.Dir:
745 case WebInspector.ConsoleMessage.MessageType.DirXML:
746 typeString = "Dir XML";
748 case WebInspector.ConsoleMessage.MessageType.Trace:
749 typeString = "Trace";
751 case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed:
752 case WebInspector.ConsoleMessage.MessageType.StartGroup:
753 typeString = "Start Group";
755 case WebInspector.ConsoleMessage.MessageType.EndGroup:
756 typeString = "End Group";
758 case WebInspector.ConsoleMessage.MessageType.Assert:
759 typeString = "Assert";
761 case WebInspector.ConsoleMessage.MessageType.Result:
762 typeString = "Result";
766 return sourceString + " " + typeString + " " + this.levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line;
771 return this._messageText;
774 isEqual: function(msg)
779 if (this._stackTrace) {
780 if (!msg._stackTrace)
782 var l = this._stackTrace;
783 var r = msg._stackTrace;
784 for (var i = 0; i < l.length; i++) {
785 if (l[i].url !== r[i].url ||
786 l[i].functionName !== r[i].functionName ||
787 l[i].lineNumber !== r[i].lineNumber ||
788 l[i].columnNumber !== r[i].columnNumber)
793 return (this.source === msg.source)
794 && (this.type === msg.type)
795 && (this.level === msg.level)
796 && (this.line === msg.line)
797 && (this.url === msg.url)
798 && (this.message === msg.message)
799 && (this._request === msg._request);
804 return this._stackTrace;
809 return WebInspector.ConsoleMessage.create(this.source, this.level, this._messageText, this.type, this.url, this.line, this.column, this.repeatCount, this._parameters, this._stackTrace, this._request);
814 switch (this.level) {
815 case WebInspector.ConsoleMessage.MessageLevel.Tip:
817 case WebInspector.ConsoleMessage.MessageLevel.Log:
819 case WebInspector.ConsoleMessage.MessageLevel.Warning:
821 case WebInspector.ConsoleMessage.MessageLevel.Debug:
823 case WebInspector.ConsoleMessage.MessageLevel.Error:
828 get clipboardPrefixString()
830 return "[" + this.levelString + "] ";
833 toClipboardString: function(isPrefixOptional)
835 var isTrace = this._shouldDumpStackTrace();
837 var clipboardString = "";
838 if (this._formattedMessage && !isTrace)
839 clipboardString = this._formattedMessage.querySelector("span").innerText;
841 clipboardString = this.type === WebInspector.ConsoleMessage.MessageType.Trace ? "console.trace()" : this._message || this._messageText;
843 if (!isPrefixOptional || this.enforcesClipboardPrefixString)
844 clipboardString = this.clipboardPrefixString + clipboardString;
847 this._stackTrace.forEach(function(frame) {
848 clipboardString += "\n\t" + (frame.functionName || WebInspector.UIString("(anonymous function)"));
850 clipboardString += " (" + WebInspector.displayNameForURL(frame.url) + ", line " + frame.lineNumber + ")";
853 var repeatString = this.repeatCount > 1 ? "x" + this.repeatCount : "";
857 var components = [WebInspector.displayNameForURL(this.url), "line " + this.line];
859 components.push(repeatString);
860 urlLine = " (" + components.join(", ") + ")";
861 } else if (repeatString)
862 urlLine = " (" + repeatString + ")";
865 var lines = clipboardString.split("\n");
867 clipboardString = lines.join("\n");
871 return clipboardString;
875 WebInspector.ConsoleMessageImpl.prototype.__proto__ = WebInspector.ConsoleMessage.prototype;