summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js')
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js1248
1 files changed, 1248 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js b/chromium/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
new file mode 100644
index 00000000000..80697a56e57
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
@@ -0,0 +1,1248 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @implements {WebInspector.ViewportElement}
+ * @param {!WebInspector.ConsoleMessage} consoleMessage
+ * @param {?WebInspector.Linkifier} linkifier
+ * @param {number} nestingLevel
+ */
+WebInspector.ConsoleViewMessage = function(consoleMessage, linkifier, nestingLevel)
+{
+ this._message = consoleMessage;
+ this._linkifier = linkifier;
+ this._repeatCount = 1;
+ this._closeGroupDecorationCount = 0;
+ this._nestingLevel = nestingLevel;
+
+ /** @type {!Array.<!WebInspector.DataGrid>} */
+ this._dataGrids = [];
+ /** @type {!Map.<!WebInspector.DataGrid, ?Element>} */
+ this._dataGridParents = new Map();
+
+ /** @type {!Object.<string, function(!WebInspector.RemoteObject, !Element, boolean=)>} */
+ this._customFormatters = {
+ "object": this._formatParameterAsObject,
+ "array": this._formatParameterAsArray,
+ "node": this._formatParameterAsNode,
+ "string": this._formatParameterAsString
+ };
+}
+
+WebInspector.ConsoleViewMessage.prototype = {
+ /**
+ * @return {?WebInspector.Target}
+ */
+ _target: function()
+ {
+ return this.consoleMessage().target();
+ },
+
+ /**
+ * @return {!Element}
+ */
+ element: function()
+ {
+ return this.toMessageElement();
+ },
+
+ wasShown: function()
+ {
+ for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i) {
+ var dataGrid = this._dataGrids[i];
+ var parentElement = this._dataGridParents.get(dataGrid) || null;
+ dataGrid.show(parentElement);
+ dataGrid.updateWidths();
+ }
+ },
+
+ cacheFastHeight: function()
+ {
+ this._cachedHeight = this.contentElement().offsetHeight;
+ },
+
+ willHide: function()
+ {
+ for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i) {
+ var dataGrid = this._dataGrids[i];
+ this._dataGridParents.put(dataGrid, dataGrid.element.parentElement);
+ dataGrid.detach();
+ }
+ },
+
+ /**
+ * @return {number}
+ */
+ fastHeight: function()
+ {
+ if (this._cachedHeight)
+ return this._cachedHeight;
+ const defaultConsoleRowHeight = 16;
+ if (this._message.type === WebInspector.ConsoleMessage.MessageType.Table) {
+ var table = this._message.parameters[0];
+ if (table && table.preview)
+ return defaultConsoleRowHeight * table.preview.properties.length;
+ }
+ return defaultConsoleRowHeight;
+ },
+
+ /**
+ * @return {!WebInspector.ConsoleMessage}
+ */
+ consoleMessage: function()
+ {
+ return this._message;
+ },
+
+ _formatMessage: function()
+ {
+ this._formattedMessage = document.createElement("span");
+ this._formattedMessage.className = "console-message-text source-code";
+
+ /**
+ * @param {string} title
+ * @return {!Element}
+ * @this {WebInspector.ConsoleMessage}
+ */
+ function linkifyRequest(title)
+ {
+ return WebInspector.Linkifier.linkifyUsingRevealer(/** @type {!WebInspector.NetworkRequest} */ (this.request), title, this.url);
+ }
+
+ var consoleMessage = this._message;
+ if (!this._messageElement) {
+ if (consoleMessage.source === WebInspector.ConsoleMessage.MessageSource.ConsoleAPI) {
+ switch (consoleMessage.type) {
+ case WebInspector.ConsoleMessage.MessageType.Trace:
+ this._messageElement = this._format(consoleMessage.parameters || ["console.trace()"]);
+ break;
+ case WebInspector.ConsoleMessage.MessageType.Clear:
+ this._messageElement = document.createTextNode(WebInspector.UIString("Console was cleared"));
+ this._formattedMessage.classList.add("console-info");
+ break;
+ case WebInspector.ConsoleMessage.MessageType.Assert:
+ var args = [WebInspector.UIString("Assertion failed:")];
+ if (consoleMessage.parameters)
+ args = args.concat(consoleMessage.parameters);
+ this._messageElement = this._format(args);
+ break;
+ case WebInspector.ConsoleMessage.MessageType.Dir:
+ var obj = consoleMessage.parameters ? consoleMessage.parameters[0] : undefined;
+ var args = ["%O", obj];
+ this._messageElement = this._format(args);
+ break;
+ case WebInspector.ConsoleMessage.MessageType.Profile:
+ case WebInspector.ConsoleMessage.MessageType.ProfileEnd:
+ this._messageElement = this._format([consoleMessage.messageText]);
+ break;
+ default:
+ var args = consoleMessage.parameters || [consoleMessage.messageText];
+ this._messageElement = this._format(args);
+ }
+ } else if (consoleMessage.source === WebInspector.ConsoleMessage.MessageSource.Network) {
+ if (consoleMessage.request) {
+ this._messageElement = document.createElement("span");
+ if (consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Error) {
+ this._messageElement.appendChild(document.createTextNode(consoleMessage.request.requestMethod + " "));
+ this._messageElement.appendChild(WebInspector.Linkifier.linkifyUsingRevealer(consoleMessage.request, consoleMessage.request.url, consoleMessage.request.url));
+ if (consoleMessage.request.failed)
+ this._messageElement.appendChild(document.createTextNode(" " + consoleMessage.request.localizedFailDescription));
+ else
+ this._messageElement.appendChild(document.createTextNode(" " + consoleMessage.request.statusCode + " (" + consoleMessage.request.statusText + ")"));
+ } else {
+ var fragment = WebInspector.linkifyStringAsFragmentWithCustomLinkifier(consoleMessage.messageText, linkifyRequest.bind(consoleMessage));
+ this._messageElement.appendChild(fragment);
+ }
+ } else {
+ var url = consoleMessage.url;
+ if (url) {
+ var isExternal = !WebInspector.resourceForURL(url) && !WebInspector.workspace.uiSourceCodeForURL(url);
+ this._anchorElement = WebInspector.linkifyURLAsNode(url, url, "console-message-url", isExternal);
+ }
+ this._messageElement = this._format([consoleMessage.messageText]);
+ }
+ } else {
+ var args = consoleMessage.parameters || [consoleMessage.messageText];
+ this._messageElement = this._format(args);
+ }
+ }
+
+ if (consoleMessage.source !== WebInspector.ConsoleMessage.MessageSource.Network || consoleMessage.request) {
+ var callFrame = this._callFrameAnchorFromStackTrace(consoleMessage.stackTrace);
+ if (callFrame)
+ this._anchorElement = this._linkifyCallFrame(callFrame);
+ else if (consoleMessage.url && consoleMessage.url !== "undefined")
+ this._anchorElement = this._linkifyLocation(consoleMessage.url, consoleMessage.line, consoleMessage.column);
+ }
+
+ this._formattedMessage.appendChild(this._messageElement);
+ if (this._anchorElement) {
+ this._formattedMessage.appendChild(document.createTextNode(" "));
+ this._formattedMessage.appendChild(this._anchorElement);
+ }
+
+ var dumpStackTrace = !!consoleMessage.stackTrace && consoleMessage.stackTrace.length && (consoleMessage.source === WebInspector.ConsoleMessage.MessageSource.Network || consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Error || consoleMessage.type === WebInspector.ConsoleMessage.MessageType.Trace);
+ if (dumpStackTrace) {
+ var ol = document.createElement("ol");
+ ol.className = "outline-disclosure";
+ var treeOutline = new TreeOutline(ol);
+
+ var content = this._formattedMessage;
+ var root = new TreeElement(content, null, true);
+ content.treeElementForTest = root;
+ treeOutline.appendChild(root);
+ if (consoleMessage.type === WebInspector.ConsoleMessage.MessageType.Trace)
+ root.expand();
+
+ this._populateStackTraceTreeElement(root);
+ this._formattedMessage = ol;
+ }
+ },
+
+ _formattedMessageText: function()
+ {
+ this.formattedMessage();
+ return this._messageElement.textContent;
+ },
+
+ /**
+ * @return {!Element}
+ */
+ formattedMessage: function()
+ {
+ if (!this._formattedMessage)
+ this._formatMessage();
+ return this._formattedMessage;
+ },
+
+ /**
+ * @param {string} url
+ * @param {number} lineNumber
+ * @param {number} columnNumber
+ * @return {?Element}
+ */
+ _linkifyLocation: function(url, lineNumber, columnNumber)
+ {
+ console.assert(this._linkifier);
+ var target = this._target();
+ if (!this._linkifier || !target)
+ return null;
+ // FIXME(62725): stack trace line/column numbers are one-based.
+ lineNumber = lineNumber ? lineNumber - 1 : 0;
+ columnNumber = columnNumber ? columnNumber - 1 : 0;
+ if (this._message.source === WebInspector.ConsoleMessage.MessageSource.CSS) {
+ var headerIds = target.cssModel.styleSheetIdsForURL(url);
+ var cssLocation = new WebInspector.CSSLocation(target, url, lineNumber, columnNumber);
+ return this._linkifier.linkifyCSSLocation(headerIds[0] || null, cssLocation, "console-message-url");
+ }
+
+ return this._linkifier.linkifyLocation(target, url, lineNumber, columnNumber, "console-message-url");
+ },
+
+ /**
+ * @param {!ConsoleAgent.CallFrame} callFrame
+ * @return {?Element}
+ */
+ _linkifyCallFrame: function(callFrame)
+ {
+ console.assert(this._linkifier);
+ var target = this._target();
+ if (!this._linkifier || !target)
+ return null;
+ // FIXME(62725): stack trace line/column numbers are one-based.
+ var lineNumber = callFrame.lineNumber ? callFrame.lineNumber - 1 : 0;
+ var columnNumber = callFrame.columnNumber ? callFrame.columnNumber - 1 : 0;
+ var rawLocation = new WebInspector.DebuggerModel.Location(target, callFrame.scriptId, lineNumber, columnNumber);
+ return this._linkifier.linkifyRawLocation(rawLocation, "console-message-url");
+ },
+
+ /**
+ * @param {?Array.<!ConsoleAgent.CallFrame>} stackTrace
+ * @return {?ConsoleAgent.CallFrame}
+ */
+ _callFrameAnchorFromStackTrace: function(stackTrace)
+ {
+ if (!stackTrace || !stackTrace.length)
+ return null;
+ var callFrame = stackTrace[0].scriptId ? stackTrace[0] : null;
+ if (!WebInspector.experimentsSettings.frameworksDebuggingSupport.isEnabled())
+ return callFrame;
+ if (!WebInspector.settings.skipStackFramesSwitch.get())
+ return callFrame;
+ var regex = WebInspector.settings.skipStackFramesPattern.asRegExp();
+ if (!regex)
+ return callFrame;
+ for (var i = 0; i < stackTrace.length; ++i) {
+ var script = this._target().debuggerModel.scriptForId(stackTrace[i].scriptId);
+ if (!script || !regex.test(script.sourceURL))
+ return stackTrace[i].scriptId ? stackTrace[i] : null;
+ }
+ return callFrame;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isErrorOrWarning: function()
+ {
+ return (this._message.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this._message.level === WebInspector.ConsoleMessage.MessageLevel.Error);
+ },
+
+ _format: function(parameters)
+ {
+ // This node is used like a Builder. Values are continually appended onto it.
+ var formattedResult = document.createElement("span");
+ if (!parameters.length)
+ return formattedResult;
+
+ var target = this._target();
+
+ // Formatting code below assumes that parameters are all wrappers whereas frontend console
+ // API allows passing arbitrary values as messages (strings, numbers, etc.). Wrap them here.
+ for (var i = 0; i < parameters.length; ++i) {
+ // FIXME: Only pass runtime wrappers here.
+ if (parameters[i] instanceof WebInspector.RemoteObject)
+ continue;
+
+ if (!target) {
+ parameters[i] = WebInspector.RemoteObject.fromLocalObject(parameters[i]);
+ continue;
+ }
+
+ if (typeof parameters[i] === "object")
+ parameters[i] = target.runtimeModel.createRemoteObject(parameters[i]);
+ else
+ parameters[i] = target.runtimeModel.createRemoteObjectFromPrimitiveValue(parameters[i]);
+ }
+
+ // There can be string log and string eval result. We distinguish between them based on message type.
+ var shouldFormatMessage = WebInspector.RemoteObject.type(parameters[0]) === "string" && this._message.type !== WebInspector.ConsoleMessage.MessageType.Result;
+
+ // Multiple parameters with the first being a format string. Save unused substitutions.
+ if (shouldFormatMessage) {
+ // Multiple parameters with the first being a format string. Save unused substitutions.
+ var result = this._formatWithSubstitutionString(parameters[0].description, parameters.slice(1), formattedResult);
+ parameters = result.unusedSubstitutions;
+ if (parameters.length)
+ formattedResult.appendChild(document.createTextNode(" "));
+ }
+
+ if (this._message.type === WebInspector.ConsoleMessage.MessageType.Table) {
+ formattedResult.appendChild(this._formatParameterAsTable(parameters));
+ return formattedResult;
+ }
+
+ // Single parameter, or unused substitutions from above.
+ for (var i = 0; i < parameters.length; ++i) {
+ // Inline strings when formatting.
+ if (shouldFormatMessage && parameters[i].type === "string")
+ formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i].description));
+ else
+ formattedResult.appendChild(this._formatParameter(parameters[i], false, true));
+ if (i < parameters.length - 1)
+ formattedResult.appendChild(document.createTextNode(" "));
+ }
+ return formattedResult;
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} output
+ * @param {boolean=} forceObjectFormat
+ * @param {boolean=} includePreview
+ * @return {!Element}
+ */
+ _formatParameter: function(output, forceObjectFormat, includePreview)
+ {
+ var type = forceObjectFormat ? "object" : (output.subtype || output.type);
+ var formatter = this._customFormatters[type] || this._formatParameterAsValue;
+ var span = document.createElement("span");
+ span.className = "console-formatted-" + type + " source-code";
+ formatter.call(this, output, span, includePreview);
+ return span;
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} obj
+ * @param {!Element} elem
+ */
+ _formatParameterAsValue: function(obj, elem)
+ {
+ elem.appendChild(document.createTextNode(obj.description || ""));
+ if (obj.objectId)
+ elem.addEventListener("contextmenu", this._contextMenuEventFired.bind(this, obj), false);
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} obj
+ * @param {!Element} elem
+ * @param {boolean=} includePreview
+ */
+ _formatParameterAsObject: function(obj, elem, includePreview)
+ {
+ this._formatParameterAsArrayOrObject(obj, obj.description || "", elem, includePreview);
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} obj
+ * @param {string} description
+ * @param {!Element} elem
+ * @param {boolean=} includePreview
+ */
+ _formatParameterAsArrayOrObject: function(obj, description, elem, includePreview)
+ {
+ var titleElement = document.createElement("span");
+ if (description)
+ titleElement.createTextChild(description);
+ if (includePreview && obj.preview) {
+ titleElement.classList.add("console-object-preview");
+ var lossless = this._appendObjectPreview(obj, description, titleElement);
+ if (lossless) {
+ elem.appendChild(titleElement);
+ titleElement.addEventListener("contextmenu", this._contextMenuEventFired.bind(this, obj), false);
+ return;
+ }
+ }
+ var section = new WebInspector.ObjectPropertiesSection(obj, titleElement);
+ section.enableContextMenu();
+ elem.appendChild(section.element);
+
+ var note = section.titleElement.createChild("span", "object-info-state-note");
+ note.title = WebInspector.UIString("Object state below is captured upon first expansion");
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} obj
+ * @param {?Event} event
+ */
+ _contextMenuEventFired: function(obj, event)
+ {
+ var contextMenu = new WebInspector.ContextMenu(event);
+ contextMenu.appendApplicableItems(obj);
+ contextMenu.show();
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} obj
+ * @param {string} description
+ * @param {!Element} titleElement
+ * @return {boolean} true iff preview captured all information.
+ */
+ _appendObjectPreview: function(obj, description, titleElement)
+ {
+ var preview = obj.preview;
+ var isArray = obj.subtype === "array";
+
+ if (description)
+ titleElement.createTextChild(" ");
+ titleElement.createTextChild(isArray ? "[" : "{");
+ for (var i = 0; i < preview.properties.length; ++i) {
+ if (i > 0)
+ titleElement.createTextChild(", ");
+
+ var property = preview.properties[i];
+ var name = property.name;
+ if (!isArray || name != i) {
+ if (/^\s|\s$|^$|\n/.test(name))
+ name = "\"" + name.replace(/\n/g, "\u21B5") + "\"";
+ titleElement.createChild("span", "name").textContent = name;
+ titleElement.createTextChild(": ");
+ }
+
+ titleElement.appendChild(this._renderPropertyPreviewOrAccessor(obj, [property]));
+ }
+ if (preview.overflow)
+ titleElement.createChild("span").textContent = "\u2026";
+ titleElement.createTextChild(isArray ? "]" : "}");
+ return preview.lossless;
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} object
+ * @param {!Array.<!RuntimeAgent.PropertyPreview>} propertyPath
+ * @return {!Element}
+ */
+ _renderPropertyPreviewOrAccessor: function(object, propertyPath)
+ {
+ var property = propertyPath.peekLast();
+ if (property.type === "accessor")
+ return this._formatAsAccessorProperty(object, propertyPath.select("name"), false);
+ return this._renderPropertyPreview(property.type, /** @type {string} */ (property.subtype), property.value);
+ },
+
+ /**
+ * @param {string} type
+ * @param {string=} subtype
+ * @param {string=} description
+ * @return {!Element}
+ */
+ _renderPropertyPreview: function(type, subtype, description)
+ {
+ var span = document.createElement("span");
+ span.className = "console-formatted-" + type;
+
+ if (type === "function") {
+ span.textContent = "function";
+ return span;
+ }
+
+ if (type === "object" && subtype === "regexp") {
+ span.classList.add("console-formatted-string");
+ span.textContent = description;
+ return span;
+ }
+
+ if (type === "object" && subtype === "node" && description) {
+ span.classList.add("console-formatted-preview-node");
+ WebInspector.DOMPresentationUtils.createSpansForNodeTitle(span, description);
+ return span;
+ }
+
+ if (type === "string") {
+ span.textContent = "\"" + description.replace(/\n/g, "\u21B5") + "\"";
+ return span;
+ }
+
+ span.textContent = description;
+ return span;
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} object
+ * @param {!Element} elem
+ */
+ _formatParameterAsNode: function(object, elem)
+ {
+ /**
+ * @param {!WebInspector.DOMNode} node
+ * @this {WebInspector.ConsoleViewMessage}
+ */
+ function printNode(node)
+ {
+ if (!node) {
+ // Sometimes DOM is loaded after the sync message is being formatted, so we get no
+ // nodeId here. So we fall back to object formatting here.
+ this._formatParameterAsObject(object, elem, false);
+ return;
+ }
+ var renderer = WebInspector.moduleManager.instance(WebInspector.Renderer, node);
+ if (renderer)
+ elem.appendChild(renderer.render(node));
+ else
+ console.error("No renderer for node found");
+ }
+ object.pushNodeToFrontend(printNode.bind(this));
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} array
+ * @return {boolean}
+ */
+ useArrayPreviewInFormatter: function(array)
+ {
+ return this._message.type !== WebInspector.ConsoleMessage.MessageType.DirXML && !!array.preview;
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} array
+ * @param {!Element} elem
+ */
+ _formatParameterAsArray: function(array, elem)
+ {
+ if (this.useArrayPreviewInFormatter(array)) {
+ this._formatParameterAsArrayOrObject(array, "", elem, true);
+ return;
+ }
+
+ const maxFlatArrayLength = 100;
+ if (this._message.isOutdated || array.arrayLength() > maxFlatArrayLength)
+ this._formatParameterAsObject(array, elem, false);
+ else
+ array.getOwnProperties(this._printArray.bind(this, array, elem));
+ },
+
+ /**
+ * @param {!Array.<!WebInspector.RemoteObject>} parameters
+ * @return {!Element}
+ */
+ _formatParameterAsTable: function(parameters)
+ {
+ var element = document.createElement("span");
+ var table = parameters[0];
+ if (!table || !table.preview)
+ return element;
+
+ var columnNames = [];
+ var preview = table.preview;
+ var rows = [];
+ for (var i = 0; i < preview.properties.length; ++i) {
+ var rowProperty = preview.properties[i];
+ var rowPreview = rowProperty.valuePreview;
+ if (!rowPreview)
+ continue;
+
+ var rowValue = {};
+ const maxColumnsToRender = 20;
+ for (var j = 0; j < rowPreview.properties.length; ++j) {
+ var cellProperty = rowPreview.properties[j];
+ var columnRendered = columnNames.indexOf(cellProperty.name) != -1;
+ if (!columnRendered) {
+ if (columnNames.length === maxColumnsToRender)
+ continue;
+ columnRendered = true;
+ columnNames.push(cellProperty.name);
+ }
+
+ if (columnRendered) {
+ var cellElement = this._renderPropertyPreviewOrAccessor(table, [rowProperty, cellProperty]);
+ cellElement.classList.add("nowrap-below");
+ rowValue[cellProperty.name] = cellElement;
+ }
+ }
+ rows.push([rowProperty.name, rowValue]);
+ }
+
+ var flatValues = [];
+ for (var i = 0; i < rows.length; ++i) {
+ var rowName = rows[i][0];
+ var rowValue = rows[i][1];
+ flatValues.push(rowName);
+ for (var j = 0; j < columnNames.length; ++j)
+ flatValues.push(rowValue[columnNames[j]]);
+ }
+
+ var dataGridContainer = element.createChild("span");
+ if (!preview.lossless || !flatValues.length) {
+ element.appendChild(this._formatParameter(table, true, false));
+ if (!flatValues.length)
+ return element;
+ }
+
+ columnNames.unshift(WebInspector.UIString("(index)"));
+ var dataGrid = WebInspector.DataGrid.createSortableDataGrid(columnNames, flatValues);
+ dataGrid.renderInline();
+ this._dataGrids.push(dataGrid);
+ this._dataGridParents.put(dataGrid, dataGridContainer);
+ return element;
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} output
+ * @param {!Element} elem
+ */
+ _formatParameterAsString: function(output, elem)
+ {
+ var span = document.createElement("span");
+ span.className = "console-formatted-string source-code";
+ span.appendChild(WebInspector.linkifyStringAsFragment(output.description || ""));
+
+ // Make black quotes.
+ elem.classList.remove("console-formatted-string");
+ elem.appendChild(document.createTextNode("\""));
+ elem.appendChild(span);
+ elem.appendChild(document.createTextNode("\""));
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} array
+ * @param {!Element} elem
+ * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties
+ */
+ _printArray: function(array, elem, properties)
+ {
+ if (!properties)
+ return;
+
+ var elements = [];
+ for (var i = 0; i < properties.length; ++i) {
+ var property = properties[i];
+ var name = property.name;
+ if (isNaN(name))
+ continue;
+ if (property.getter)
+ elements[name] = this._formatAsAccessorProperty(array, [name], true);
+ else if (property.value)
+ elements[name] = this._formatAsArrayEntry(property.value);
+ }
+
+ elem.appendChild(document.createTextNode("["));
+ var lastNonEmptyIndex = -1;
+
+ function appendUndefined(elem, index)
+ {
+ if (index - lastNonEmptyIndex <= 1)
+ return;
+ var span = elem.createChild("span", "console-formatted-undefined");
+ span.textContent = WebInspector.UIString("undefined × %d", index - lastNonEmptyIndex - 1);
+ }
+
+ var length = array.arrayLength();
+ for (var i = 0; i < length; ++i) {
+ var element = elements[i];
+ if (!element)
+ continue;
+
+ if (i - lastNonEmptyIndex > 1) {
+ appendUndefined(elem, i);
+ elem.appendChild(document.createTextNode(", "));
+ }
+
+ elem.appendChild(element);
+ lastNonEmptyIndex = i;
+ if (i < length - 1)
+ elem.appendChild(document.createTextNode(", "));
+ }
+ appendUndefined(elem, length);
+
+ elem.appendChild(document.createTextNode("]"));
+ elem.addEventListener("contextmenu", this._contextMenuEventFired.bind(this, array), false);
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} output
+ * @return {!Element}
+ */
+ _formatAsArrayEntry: function(output)
+ {
+ // Prevent infinite expansion of cross-referencing arrays.
+ return this._formatParameter(output, output.subtype === "array", false);
+ },
+
+ /**
+ * @param {!WebInspector.RemoteObject} object
+ * @param {!Array.<string>} propertyPath
+ * @param {boolean} isArrayEntry
+ * @return {!Element}
+ */
+ _formatAsAccessorProperty: function(object, propertyPath, isArrayEntry)
+ {
+ var rootElement = WebInspector.ObjectPropertyTreeElement.createRemoteObjectAccessorPropertySpan(object, propertyPath, onInvokeGetterClick.bind(this));
+
+ /**
+ * @param {?WebInspector.RemoteObject} result
+ * @param {boolean=} wasThrown
+ * @this {WebInspector.ConsoleViewMessage}
+ */
+ function onInvokeGetterClick(result, wasThrown)
+ {
+ if (!result)
+ return;
+ rootElement.removeChildren();
+ if (wasThrown) {
+ var element = rootElement.createChild("span", "error-message");
+ element.textContent = WebInspector.UIString("<exception>");
+ element.title = /** @type {string} */ (result.description);
+ } else if (isArrayEntry) {
+ rootElement.appendChild(this._formatAsArrayEntry(result));
+ } else {
+ // Make a PropertyPreview from the RemoteObject similar to the backend logic.
+ const maxLength = 100;
+ var type = result.type;
+ var subtype = result.subtype;
+ var description = "";
+ if (type !== "function" && result.description) {
+ if (type === "string" || subtype === "regexp")
+ description = result.description.trimMiddle(maxLength);
+ else
+ description = result.description.trimEnd(maxLength);
+ }
+ rootElement.appendChild(this._renderPropertyPreview(type, subtype, description));
+ }
+ }
+
+ return rootElement;
+ },
+
+ /**
+ * @param {string} format
+ * @param {!Array.<string>} parameters
+ * @param {!Element} formattedResult
+ */
+ _formatWithSubstitutionString: function(format, parameters, formattedResult)
+ {
+ var formatters = {};
+
+ /**
+ * @param {boolean} force
+ * @param {!WebInspector.RemoteObject} obj
+ * @return {!Element}
+ * @this {WebInspector.ConsoleViewMessage}
+ */
+ function parameterFormatter(force, obj)
+ {
+ return this._formatParameter(obj, force, false);
+ }
+
+ function stringFormatter(obj)
+ {
+ return obj.description;
+ }
+
+ function floatFormatter(obj)
+ {
+ if (typeof obj.value !== "number")
+ return "NaN";
+ return obj.value;
+ }
+
+ function integerFormatter(obj)
+ {
+ if (typeof obj.value !== "number")
+ return "NaN";
+ return Math.floor(obj.value);
+ }
+
+ function bypassFormatter(obj)
+ {
+ return (obj instanceof Node) ? obj : "";
+ }
+
+ var currentStyle = null;
+ function styleFormatter(obj)
+ {
+ currentStyle = {};
+ var buffer = document.createElement("span");
+ buffer.setAttribute("style", obj.description);
+ for (var i = 0; i < buffer.style.length; i++) {
+ var property = buffer.style[i];
+ if (isWhitelistedProperty(property))
+ currentStyle[property] = buffer.style[property];
+ }
+ }
+
+ function isWhitelistedProperty(property)
+ {
+ var prefixes = ["background", "border", "color", "font", "line", "margin", "padding", "text", "-webkit-background", "-webkit-border", "-webkit-font", "-webkit-margin", "-webkit-padding", "-webkit-text"];
+ for (var i = 0; i < prefixes.length; i++) {
+ if (property.startsWith(prefixes[i]))
+ return true;
+ }
+ return false;
+ }
+
+ // Firebug uses %o for formatting objects.
+ formatters.o = parameterFormatter.bind(this, false);
+ formatters.s = stringFormatter;
+ formatters.f = floatFormatter;
+ // Firebug allows both %i and %d for formatting integers.
+ formatters.i = integerFormatter;
+ formatters.d = integerFormatter;
+
+ // Firebug uses %c for styling the message.
+ formatters.c = styleFormatter;
+
+ // Support %O to force object formatting, instead of the type-based %o formatting.
+ formatters.O = parameterFormatter.bind(this, true);
+
+ formatters._ = bypassFormatter;
+
+ function append(a, b)
+ {
+ if (b instanceof Node)
+ a.appendChild(b);
+ else if (typeof b !== "undefined") {
+ var toAppend = WebInspector.linkifyStringAsFragment(String(b));
+ if (currentStyle) {
+ var wrapper = document.createElement('span');
+ for (var key in currentStyle)
+ wrapper.style[key] = currentStyle[key];
+ wrapper.appendChild(toAppend);
+ toAppend = wrapper;
+ }
+ a.appendChild(toAppend);
+ }
+ return a;
+ }
+
+ // String.format does treat formattedResult like a Builder, result is an object.
+ return String.format(format, parameters, formatters, formattedResult, append);
+ },
+
+ clearHighlight: function()
+ {
+ if (!this._formattedMessage)
+ return;
+
+ var highlightedMessage = this._formattedMessage;
+ delete this._formattedMessage;
+ delete this._anchorElement;
+ delete this._messageElement;
+ this._formatMessage();
+ this._element.replaceChild(this._formattedMessage, highlightedMessage);
+ },
+
+ highlightSearchResults: function(regexObject)
+ {
+ if (!this._formattedMessage)
+ return;
+
+ this._highlightSearchResultsInElement(regexObject, this._messageElement);
+ if (this._anchorElement)
+ this._highlightSearchResultsInElement(regexObject, this._anchorElement);
+ },
+
+ _highlightSearchResultsInElement: function(regexObject, element)
+ {
+ regexObject.lastIndex = 0;
+ var text = element.textContent;
+ var match = regexObject.exec(text);
+ var matchRanges = [];
+ while (match) {
+ matchRanges.push(new WebInspector.SourceRange(match.index, match[0].length));
+ match = regexObject.exec(text);
+ }
+ WebInspector.highlightSearchResults(element, matchRanges);
+ },
+
+ /**
+ * @return {boolean}
+ */
+ matchesRegex: function(regexObject)
+ {
+ regexObject.lastIndex = 0;
+ return regexObject.test(this._formattedMessageText()) || (!!this._anchorElement && regexObject.test(this._anchorElement.textContent));
+ },
+
+ /**
+ * @param {boolean} show
+ */
+ updateTimestamp: function(show)
+ {
+ if (!this._element)
+ return;
+
+ if (show && !this.timestampElement) {
+ this.timestampElement = this._element.createChild("span", "console-timestamp");
+ this.timestampElement.textContent = (new Date(this._message.timestamp)).toConsoleTime();
+ var afterRepeatCountChild = this._repeatCountElement && this._repeatCountElement.nextSibling;
+ this._element.insertBefore(this.timestampElement, afterRepeatCountChild || this._element.firstChild);
+ return;
+ }
+
+ if (!show && this.timestampElement) {
+ this.timestampElement.remove();
+ delete this.timestampElement;
+ }
+ },
+
+ /**
+ * @return {number}
+ */
+ nestingLevel: function()
+ {
+ return this._nestingLevel;
+ },
+
+ resetCloseGroupDecorationCount: function()
+ {
+ this._closeGroupDecorationCount = 0;
+ this._updateCloseGroupDecorations();
+ },
+
+ incrementCloseGroupDecorationCount: function()
+ {
+ ++this._closeGroupDecorationCount;
+ this._updateCloseGroupDecorations();
+ },
+
+ _updateCloseGroupDecorations: function()
+ {
+ if (!this._nestingLevelMarkers)
+ return;
+ for (var i = 0, n = this._nestingLevelMarkers.length; i < n; ++i) {
+ var marker = this._nestingLevelMarkers[i];
+ marker.classList.toggle("group-closed", n - i <= this._closeGroupDecorationCount);
+ }
+ },
+
+ /**
+ * @return {!Element}
+ */
+ contentElement: function()
+ {
+ if (this._element)
+ return this._element;
+
+ var element = document.createElementWithClass("div", "console-message");
+ this._element = element;
+
+ switch (this._message.level) {
+ case WebInspector.ConsoleMessage.MessageLevel.Log:
+ element.classList.add("console-log-level");
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Debug:
+ element.classList.add("console-debug-level");
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Warning:
+ element.classList.add("console-warning-level");
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Error:
+ element.classList.add("console-error-level");
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Info:
+ element.classList.add("console-info-level");
+ break;
+ }
+
+ if (this._message.type === WebInspector.ConsoleMessage.MessageType.StartGroup || this._message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
+ element.classList.add("console-group-title");
+
+ element.appendChild(this.formattedMessage());
+
+ if (this._repeatCount > 1)
+ this._showRepeatCountElement();
+
+ this.updateTimestamp(WebInspector.settings.consoleTimestampsEnabled.get());
+
+ return this._element;
+ },
+
+ /**
+ * @return {!Element}
+ */
+ toMessageElement: function()
+ {
+ if (this._wrapperElement)
+ return this._wrapperElement;
+
+ this._wrapperElement = document.createElementWithClass("div", "console-message-wrapper");
+ this._nestingLevelMarkers = [];
+ for (var i = 0; i < this._nestingLevel; ++i)
+ this._nestingLevelMarkers.push(this._wrapperElement.createChild("div", "nesting-level-marker"));
+ this._updateCloseGroupDecorations();
+ this._wrapperElement.message = this;
+
+ this._wrapperElement.appendChild(this.contentElement());
+ return this._wrapperElement;
+ },
+
+ _populateStackTraceTreeElement: function(parentTreeElement)
+ {
+ for (var i = 0; i < this._message.stackTrace.length; i++) {
+ var frame = this._message.stackTrace[i];
+
+ var content = document.createElementWithClass("div", "stacktrace-entry");
+ var messageTextElement = document.createElement("span");
+ messageTextElement.className = "console-message-text source-code";
+ var functionName = frame.functionName || WebInspector.UIString("(anonymous function)");
+ messageTextElement.appendChild(document.createTextNode(functionName));
+ content.appendChild(messageTextElement);
+
+ if (frame.scriptId) {
+ content.appendChild(document.createTextNode(" "));
+ var urlElement = this._linkifyCallFrame(frame);
+ if (!urlElement)
+ continue;
+ content.appendChild(urlElement);
+ }
+
+ var treeElement = new TreeElement(content);
+ parentTreeElement.appendChild(treeElement);
+ }
+ },
+
+ resetIncrementRepeatCount: function()
+ {
+ this._repeatCount = 1;
+ if (!this._repeatCountElement)
+ return;
+
+ this._repeatCountElement.remove();
+ delete this._repeatCountElement;
+ },
+
+ incrementRepeatCount: function()
+ {
+ this._repeatCount++;
+ this._showRepeatCountElement();
+ },
+
+ _showRepeatCountElement: function()
+ {
+ if (!this._element)
+ return;
+
+ if (!this._repeatCountElement) {
+ this._repeatCountElement = document.createElement("span");
+ this._repeatCountElement.className = "bubble";
+
+ this._element.insertBefore(this._repeatCountElement, this._element.firstChild);
+ this._element.classList.add("repeated-message");
+ }
+ this._repeatCountElement.textContent = this._repeatCount;
+ },
+
+ /**
+ * @return {string}
+ */
+ toString: function()
+ {
+ var sourceString;
+ switch (this._message.source) {
+ case WebInspector.ConsoleMessage.MessageSource.XML:
+ sourceString = "XML";
+ break;
+ case WebInspector.ConsoleMessage.MessageSource.JS:
+ sourceString = "JavaScript";
+ break;
+ case WebInspector.ConsoleMessage.MessageSource.Network:
+ sourceString = "Network";
+ break;
+ case WebInspector.ConsoleMessage.MessageSource.ConsoleAPI:
+ sourceString = "ConsoleAPI";
+ break;
+ case WebInspector.ConsoleMessage.MessageSource.Storage:
+ sourceString = "Storage";
+ break;
+ case WebInspector.ConsoleMessage.MessageSource.AppCache:
+ sourceString = "AppCache";
+ break;
+ case WebInspector.ConsoleMessage.MessageSource.Rendering:
+ sourceString = "Rendering";
+ break;
+ case WebInspector.ConsoleMessage.MessageSource.CSS:
+ sourceString = "CSS";
+ break;
+ case WebInspector.ConsoleMessage.MessageSource.Security:
+ sourceString = "Security";
+ break;
+ case WebInspector.ConsoleMessage.MessageSource.Other:
+ sourceString = "Other";
+ break;
+ }
+
+ var typeString;
+ switch (this._message.type) {
+ case WebInspector.ConsoleMessage.MessageType.Log:
+ typeString = "Log";
+ break;
+ case WebInspector.ConsoleMessage.MessageType.Dir:
+ typeString = "Dir";
+ break;
+ case WebInspector.ConsoleMessage.MessageType.DirXML:
+ typeString = "Dir XML";
+ break;
+ case WebInspector.ConsoleMessage.MessageType.Trace:
+ typeString = "Trace";
+ break;
+ case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed:
+ case WebInspector.ConsoleMessage.MessageType.StartGroup:
+ typeString = "Start Group";
+ break;
+ case WebInspector.ConsoleMessage.MessageType.EndGroup:
+ typeString = "End Group";
+ break;
+ case WebInspector.ConsoleMessage.MessageType.Assert:
+ typeString = "Assert";
+ break;
+ case WebInspector.ConsoleMessage.MessageType.Result:
+ typeString = "Result";
+ break;
+ case WebInspector.ConsoleMessage.MessageType.Profile:
+ case WebInspector.ConsoleMessage.MessageType.ProfileEnd:
+ typeString = "Profiling";
+ break;
+ }
+
+ var levelString;
+ switch (this._message.level) {
+ case WebInspector.ConsoleMessage.MessageLevel.Log:
+ levelString = "Log";
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Warning:
+ levelString = "Warning";
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Debug:
+ levelString = "Debug";
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Error:
+ levelString = "Error";
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Info:
+ levelString = "Info";
+ break;
+ }
+
+ return sourceString + " " + typeString + " " + levelString + ": " + this.formattedMessage().textContent + "\n" + this._message.url + " line " + this._message.line;
+ },
+
+ get text()
+ {
+ return this._message.messageText;
+ },
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ConsoleViewMessage}
+ * @param {!WebInspector.ConsoleMessage} consoleMessage
+ * @param {?WebInspector.Linkifier} linkifier
+ * @param {number} nestingLevel
+ */
+WebInspector.ConsoleGroupViewMessage = function(consoleMessage, linkifier, nestingLevel)
+{
+ console.assert(consoleMessage.isGroupStartMessage());
+ WebInspector.ConsoleViewMessage.call(this, consoleMessage, linkifier, nestingLevel);
+ this.setCollapsed(consoleMessage.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed);
+}
+
+WebInspector.ConsoleGroupViewMessage.prototype = {
+ /**
+ * @param {boolean} collapsed
+ */
+ setCollapsed: function(collapsed)
+ {
+ this._collapsed = collapsed;
+ if (this._wrapperElement)
+ this._wrapperElement.classList.toggle("collapsed", this._collapsed);
+ },
+
+ /**
+ * @return {boolean}
+ */
+ collapsed: function()
+ {
+ return this._collapsed;
+ },
+
+ /**
+ * @return {!Element}
+ */
+ toMessageElement: function()
+ {
+ if (!this._wrapperElement) {
+ WebInspector.ConsoleViewMessage.prototype.toMessageElement.call(this);
+ this._wrapperElement.classList.toggle("collapsed", this._collapsed);
+ }
+ return this._wrapperElement;
+ },
+
+ __proto__: WebInspector.ConsoleViewMessage.prototype
+}