| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
| 3 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. | 3 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. |
| 4 * Copyright (C) 2009 Joseph Pecoraro | 4 * Copyright (C) 2009 Joseph Pecoraro |
| 5 * | 5 * |
| 6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
| 8 * are met: | 8 * are met: |
| 9 * | 9 * |
| 10 * 1. Redistributions of source code must retain the above copyright | 10 * 1. Redistributions of source code must retain the above copyright |
| 11 * notice, this list of conditions and the following disclaimer. | 11 * notice, this list of conditions and the following disclaimer. |
| 12 * 2. Redistributions in binary form must reproduce the above copyright | 12 * 2. Redistributions in binary form must reproduce the above copyright |
| 13 * notice, this list of conditions and the following disclaimer in the | 13 * notice, this list of conditions and the following disclaimer in the |
| 14 * documentation and/or other materials provided with the distribution. | 14 * documentation and/or other materials provided with the distribution. |
| 15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | 15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
| 16 * its contributors may be used to endorse or promote products derived | 16 * its contributors may be used to endorse or promote products derived |
| 17 * from this software without specific prior written permission. | 17 * from this software without specific prior written permission. |
| 18 * | 18 * |
| 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | 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 | 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 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 | 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 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 | 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 | 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 | 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. | 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | |
| 31 /** | 30 /** |
| 32 * @constructor | |
| 33 * @implements {WebInspector.ViewportElement} | 31 * @implements {WebInspector.ViewportElement} |
| 34 * @param {!WebInspector.ConsoleMessage} consoleMessage | 32 * @unrestricted |
| 35 * @param {!WebInspector.Linkifier} linkifier | |
| 36 * @param {number} nestingLevel | |
| 37 */ | 33 */ |
| 38 WebInspector.ConsoleViewMessage = function(consoleMessage, linkifier, nestingLev
el) | 34 WebInspector.ConsoleViewMessage = class { |
| 39 { | 35 /** |
| 36 * @param {!WebInspector.ConsoleMessage} consoleMessage |
| 37 * @param {!WebInspector.Linkifier} linkifier |
| 38 * @param {number} nestingLevel |
| 39 */ |
| 40 constructor(consoleMessage, linkifier, nestingLevel) { |
| 40 this._message = consoleMessage; | 41 this._message = consoleMessage; |
| 41 this._linkifier = linkifier; | 42 this._linkifier = linkifier; |
| 42 this._repeatCount = 1; | 43 this._repeatCount = 1; |
| 43 this._closeGroupDecorationCount = 0; | 44 this._closeGroupDecorationCount = 0; |
| 44 this._nestingLevel = nestingLevel; | 45 this._nestingLevel = nestingLevel; |
| 45 | 46 |
| 46 /** @type {?WebInspector.DataGrid} */ | 47 /** @type {?WebInspector.DataGrid} */ |
| 47 this._dataGrid = null; | 48 this._dataGrid = null; |
| 48 this._previewFormatter = new WebInspector.RemoteObjectPreviewFormatter(); | 49 this._previewFormatter = new WebInspector.RemoteObjectPreviewFormatter(); |
| 49 this._searchRegex = null; | 50 this._searchRegex = null; |
| 50 }; | 51 } |
| 51 | 52 |
| 52 WebInspector.ConsoleViewMessage.prototype = { | 53 /** |
| 54 * @return {?WebInspector.Target} |
| 55 */ |
| 56 _target() { |
| 57 return this.consoleMessage().target(); |
| 58 } |
| 59 |
| 60 /** |
| 61 * @override |
| 62 * @return {!Element} |
| 63 */ |
| 64 element() { |
| 65 return this.toMessageElement(); |
| 66 } |
| 67 |
| 68 /** |
| 69 * @override |
| 70 */ |
| 71 wasShown() { |
| 72 if (this._dataGrid) |
| 73 this._dataGrid.updateWidths(); |
| 74 this._isVisible = true; |
| 75 } |
| 76 |
| 77 onResize() { |
| 78 if (!this._isVisible) |
| 79 return; |
| 80 if (this._dataGrid) |
| 81 this._dataGrid.onResize(); |
| 82 } |
| 83 |
| 84 /** |
| 85 * @override |
| 86 */ |
| 87 willHide() { |
| 88 this._isVisible = false; |
| 89 this._cachedHeight = this.contentElement().offsetHeight; |
| 90 } |
| 91 |
| 92 /** |
| 93 * @return {number} |
| 94 */ |
| 95 fastHeight() { |
| 96 if (this._cachedHeight) |
| 97 return this._cachedHeight; |
| 98 // This value reflects the 18px min-height of .console-message, plus the |
| 99 // 1px border of .console-message-wrapper. Keep in sync with consoleView.css
. |
| 100 const defaultConsoleRowHeight = 19; |
| 101 if (this._message.type === WebInspector.ConsoleMessage.MessageType.Table) { |
| 102 var table = this._message.parameters[0]; |
| 103 if (table && table.preview) |
| 104 return defaultConsoleRowHeight * table.preview.properties.length; |
| 105 } |
| 106 return defaultConsoleRowHeight; |
| 107 } |
| 108 |
| 109 /** |
| 110 * @return {!WebInspector.ConsoleMessage} |
| 111 */ |
| 112 consoleMessage() { |
| 113 return this._message; |
| 114 } |
| 115 |
| 116 /** |
| 117 * @param {!WebInspector.ConsoleMessage} consoleMessage |
| 118 * @return {!Element} |
| 119 */ |
| 120 _buildTableMessage(consoleMessage) { |
| 121 var formattedMessage = createElement('span'); |
| 122 WebInspector.appendStyle(formattedMessage, 'components/objectValue.css'); |
| 123 formattedMessage.className = 'console-message-text source-code'; |
| 124 var anchorElement = this._buildMessageAnchor(consoleMessage); |
| 125 if (anchorElement) |
| 126 formattedMessage.appendChild(anchorElement); |
| 127 |
| 128 var table = consoleMessage.parameters && consoleMessage.parameters.length ?
consoleMessage.parameters[0] : null; |
| 129 if (table) |
| 130 table = this._parameterToRemoteObject(table, this._target()); |
| 131 if (!table || !table.preview) |
| 132 return formattedMessage; |
| 133 |
| 134 var columnNames = []; |
| 135 var preview = table.preview; |
| 136 var rows = []; |
| 137 for (var i = 0; i < preview.properties.length; ++i) { |
| 138 var rowProperty = preview.properties[i]; |
| 139 var rowPreview = rowProperty.valuePreview; |
| 140 if (!rowPreview) |
| 141 continue; |
| 142 |
| 143 var rowValue = {}; |
| 144 const maxColumnsToRender = 20; |
| 145 for (var j = 0; j < rowPreview.properties.length; ++j) { |
| 146 var cellProperty = rowPreview.properties[j]; |
| 147 var columnRendered = columnNames.indexOf(cellProperty.name) !== -1; |
| 148 if (!columnRendered) { |
| 149 if (columnNames.length === maxColumnsToRender) |
| 150 continue; |
| 151 columnRendered = true; |
| 152 columnNames.push(cellProperty.name); |
| 153 } |
| 154 |
| 155 if (columnRendered) { |
| 156 var cellElement = this._renderPropertyPreviewOrAccessor(table, [rowPro
perty, cellProperty]); |
| 157 cellElement.classList.add('console-message-nowrap-below'); |
| 158 rowValue[cellProperty.name] = cellElement; |
| 159 } |
| 160 } |
| 161 rows.push([rowProperty.name, rowValue]); |
| 162 } |
| 163 |
| 164 var flatValues = []; |
| 165 for (var i = 0; i < rows.length; ++i) { |
| 166 var rowName = rows[i][0]; |
| 167 var rowValue = rows[i][1]; |
| 168 flatValues.push(rowName); |
| 169 for (var j = 0; j < columnNames.length; ++j) |
| 170 flatValues.push(rowValue[columnNames[j]]); |
| 171 } |
| 172 columnNames.unshift(WebInspector.UIString('(index)')); |
| 173 |
| 174 if (flatValues.length) { |
| 175 this._dataGrid = WebInspector.SortableDataGrid.create(columnNames, flatVal
ues); |
| 176 |
| 177 var formattedResult = createElement('span'); |
| 178 var tableElement = formattedResult.createChild('div', 'console-message-for
matted-table'); |
| 179 var dataGridContainer = tableElement.createChild('span'); |
| 180 tableElement.appendChild(this._formatParameter(table, true, false)); |
| 181 dataGridContainer.appendChild(this._dataGrid.element); |
| 182 formattedMessage.appendChild(formattedResult); |
| 183 this._dataGrid.renderInline(); |
| 184 } |
| 185 return formattedMessage; |
| 186 } |
| 187 |
| 188 /** |
| 189 * @param {!WebInspector.ConsoleMessage} consoleMessage |
| 190 * @return {!Element} |
| 191 */ |
| 192 _buildMessage(consoleMessage) { |
| 193 var messageElement; |
| 194 if (consoleMessage.source === WebInspector.ConsoleMessage.MessageSource.Cons
oleAPI) { |
| 195 switch (consoleMessage.type) { |
| 196 case WebInspector.ConsoleMessage.MessageType.Trace: |
| 197 messageElement = this._format(consoleMessage.parameters || ['console.t
race']); |
| 198 break; |
| 199 case WebInspector.ConsoleMessage.MessageType.Clear: |
| 200 messageElement = createElementWithClass('span', 'console-info'); |
| 201 messageElement.textContent = WebInspector.UIString('Console was cleare
d'); |
| 202 break; |
| 203 case WebInspector.ConsoleMessage.MessageType.Assert: |
| 204 var args = [WebInspector.UIString('Assertion failed:')]; |
| 205 if (consoleMessage.parameters) |
| 206 args = args.concat(consoleMessage.parameters); |
| 207 messageElement = this._format(args); |
| 208 break; |
| 209 case WebInspector.ConsoleMessage.MessageType.Dir: |
| 210 var obj = consoleMessage.parameters ? consoleMessage.parameters[0] : u
ndefined; |
| 211 var args = ['%O', obj]; |
| 212 messageElement = this._format(args); |
| 213 break; |
| 214 case WebInspector.ConsoleMessage.MessageType.Profile: |
| 215 case WebInspector.ConsoleMessage.MessageType.ProfileEnd: |
| 216 messageElement = this._format([consoleMessage.messageText]); |
| 217 break; |
| 218 default: |
| 219 if (consoleMessage.parameters && consoleMessage.parameters.length ===
1 && |
| 220 consoleMessage.parameters[0].type === 'string') |
| 221 messageElement = this._tryFormatAsError(/** @type {string} */ (conso
leMessage.parameters[0].value)); |
| 222 var args = consoleMessage.parameters || [consoleMessage.messageText]; |
| 223 messageElement = messageElement || this._format(args); |
| 224 } |
| 225 } else if (consoleMessage.source === WebInspector.ConsoleMessage.MessageSour
ce.Network) { |
| 226 if (consoleMessage.request) { |
| 227 messageElement = createElement('span'); |
| 228 if (consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Er
ror || |
| 229 consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Re
vokedError) { |
| 230 messageElement.createTextChildren(consoleMessage.request.requestMethod
, ' '); |
| 231 messageElement.appendChild(WebInspector.Linkifier.linkifyUsingRevealer
( |
| 232 consoleMessage.request, consoleMessage.request.url, consoleMessage
.request.url)); |
| 233 if (consoleMessage.request.failed) |
| 234 messageElement.createTextChildren(' ', consoleMessage.request.locali
zedFailDescription); |
| 235 else |
| 236 messageElement.createTextChildren( |
| 237 ' ', String(consoleMessage.request.statusCode), ' (', consoleMes
sage.request.statusText, ')'); |
| 238 } else { |
| 239 var fragment = WebInspector.linkifyStringAsFragmentWithCustomLinkifier
( |
| 240 consoleMessage.messageText, linkifyRequest.bind(consoleMessage)); |
| 241 messageElement.appendChild(fragment); |
| 242 } |
| 243 } else { |
| 244 messageElement = this._format([consoleMessage.messageText]); |
| 245 } |
| 246 } else { |
| 247 var args = consoleMessage.parameters || [consoleMessage.messageText]; |
| 248 messageElement = this._format(args); |
| 249 } |
| 250 |
| 251 var formattedMessage = createElement('span'); |
| 252 WebInspector.appendStyle(formattedMessage, 'components/objectValue.css'); |
| 253 formattedMessage.className = 'console-message-text source-code'; |
| 254 |
| 255 var anchorElement = this._buildMessageAnchor(consoleMessage); |
| 256 if (anchorElement) |
| 257 formattedMessage.appendChild(anchorElement); |
| 258 formattedMessage.appendChild(messageElement); |
| 259 return formattedMessage; |
| 260 |
| 53 /** | 261 /** |
| 54 * @return {?WebInspector.Target} | 262 * @param {string} title |
| 263 * @return {!Element} |
| 264 * @this {WebInspector.ConsoleMessage} |
| 55 */ | 265 */ |
| 56 _target: function() | 266 function linkifyRequest(title) { |
| 57 { | 267 return WebInspector.Linkifier.linkifyUsingRevealer( |
| 58 return this.consoleMessage().target(); | 268 /** @type {!WebInspector.NetworkRequest} */ (this.request), title, thi
s.request.url); |
| 59 }, | 269 } |
| 270 } |
| 271 |
| 272 /** |
| 273 * @param {!WebInspector.ConsoleMessage} consoleMessage |
| 274 * @return {?Element} |
| 275 */ |
| 276 _buildMessageAnchor(consoleMessage) { |
| 277 var anchorElement = null; |
| 278 if (consoleMessage.source !== WebInspector.ConsoleMessage.MessageSource.Netw
ork || consoleMessage.request) { |
| 279 if (consoleMessage.scriptId) |
| 280 anchorElement = this._linkifyScriptId( |
| 281 consoleMessage.scriptId, consoleMessage.url || '', consoleMessage.li
ne, consoleMessage.column); |
| 282 else if (consoleMessage.stackTrace && consoleMessage.stackTrace.callFrames
.length) |
| 283 anchorElement = this._linkifyStackTraceTopFrame(consoleMessage.stackTrac
e); |
| 284 else if (consoleMessage.url && consoleMessage.url !== 'undefined') |
| 285 anchorElement = this._linkifyLocation(consoleMessage.url, consoleMessage
.line, consoleMessage.column); |
| 286 } else if (consoleMessage.url) { |
| 287 var url = consoleMessage.url; |
| 288 var isExternal = |
| 289 !WebInspector.resourceForURL(url) && !WebInspector.networkMapping.uiSo
urceCodeForURLForAnyTarget(url); |
| 290 anchorElement = WebInspector.linkifyURLAsNode(url, url, 'console-message-u
rl', isExternal); |
| 291 } |
| 292 |
| 293 // Append a space to prevent the anchor text from being glued to the console
message when the user selects and copies the console messages. |
| 294 if (anchorElement) |
| 295 anchorElement.appendChild(createTextNode(' ')); |
| 296 return anchorElement; |
| 297 } |
| 298 |
| 299 /** |
| 300 * @param {!WebInspector.ConsoleMessage} consoleMessage |
| 301 * @param {!WebInspector.Target} target |
| 302 * @param {!WebInspector.Linkifier} linkifier |
| 303 * @return {!Element} |
| 304 */ |
| 305 _buildMessageWithStackTrace(consoleMessage, target, linkifier) { |
| 306 var toggleElement = createElementWithClass('div', 'console-message-stack-tra
ce-toggle'); |
| 307 var triangleElement = toggleElement.createChild('div', 'console-message-stac
k-trace-triangle'); |
| 308 var contentElement = toggleElement.createChild('div', 'console-message-stack
-trace-wrapper'); |
| 309 |
| 310 var messageElement = this._buildMessage(consoleMessage); |
| 311 var clickableElement = contentElement.createChild('div'); |
| 312 clickableElement.appendChild(messageElement); |
| 313 var stackTraceElement = contentElement.createChild('div'); |
| 314 var stackTracePreview = |
| 315 WebInspector.DOMPresentationUtils.buildStackTracePreviewContents(target,
linkifier, consoleMessage.stackTrace); |
| 316 stackTraceElement.appendChild(stackTracePreview); |
| 317 stackTraceElement.classList.add('hidden'); |
| 60 | 318 |
| 61 /** | 319 /** |
| 62 * @override | 320 * @param {boolean} expand |
| 63 * @return {!Element} | |
| 64 */ | 321 */ |
| 65 element: function() | 322 function expandStackTrace(expand) { |
| 66 { | 323 stackTraceElement.classList.toggle('hidden', !expand); |
| 67 return this.toMessageElement(); | 324 toggleElement.classList.toggle('expanded', expand); |
| 68 }, | 325 } |
| 69 | 326 |
| 70 /** | 327 /** |
| 71 * @override | 328 * @param {?Event} event |
| 72 */ | 329 */ |
| 73 wasShown: function() | 330 function toggleStackTrace(event) { |
| 74 { | 331 if (event.target.hasSelection()) |
| 75 if (this._dataGrid) | 332 return; |
| 76 this._dataGrid.updateWidths(); | 333 expandStackTrace(stackTraceElement.classList.contains('hidden')); |
| 77 this._isVisible = true; | 334 event.consume(); |
| 78 }, | 335 } |
| 79 | 336 |
| 80 onResize: function() | 337 clickableElement.addEventListener('click', toggleStackTrace, false); |
| 81 { | 338 triangleElement.addEventListener('click', toggleStackTrace, false); |
| 82 if (!this._isVisible) | 339 if (consoleMessage.type === WebInspector.ConsoleMessage.MessageType.Trace) |
| 83 return; | 340 expandStackTrace(true); |
| 84 if (this._dataGrid) | 341 |
| 85 this._dataGrid.onResize(); | 342 toggleElement._expandStackTraceForTest = expandStackTrace.bind(null, true); |
| 86 }, | 343 return toggleElement; |
| 344 } |
| 345 |
| 346 /** |
| 347 * @param {string} url |
| 348 * @param {number} lineNumber |
| 349 * @param {number} columnNumber |
| 350 * @return {?Element} |
| 351 */ |
| 352 _linkifyLocation(url, lineNumber, columnNumber) { |
| 353 var target = this._target(); |
| 354 if (!target) |
| 355 return null; |
| 356 return this._linkifier.linkifyScriptLocation(target, null, url, lineNumber,
columnNumber, 'console-message-url'); |
| 357 } |
| 358 |
| 359 /** |
| 360 * @param {!RuntimeAgent.StackTrace} stackTrace |
| 361 * @return {?Element} |
| 362 */ |
| 363 _linkifyStackTraceTopFrame(stackTrace) { |
| 364 var target = this._target(); |
| 365 if (!target) |
| 366 return null; |
| 367 return this._linkifier.linkifyStackTraceTopFrame(target, stackTrace, 'consol
e-message-url'); |
| 368 } |
| 369 |
| 370 /** |
| 371 * @param {string} scriptId |
| 372 * @param {string} url |
| 373 * @param {number} lineNumber |
| 374 * @param {number} columnNumber |
| 375 * @return {?Element} |
| 376 */ |
| 377 _linkifyScriptId(scriptId, url, lineNumber, columnNumber) { |
| 378 var target = this._target(); |
| 379 if (!target) |
| 380 return null; |
| 381 return this._linkifier.linkifyScriptLocation( |
| 382 target, scriptId, url, lineNumber, columnNumber, 'console-message-url'); |
| 383 } |
| 384 |
| 385 /** |
| 386 * @param {!WebInspector.RemoteObject|!Object|string} parameter |
| 387 * @param {?WebInspector.Target} target |
| 388 * @return {!WebInspector.RemoteObject} |
| 389 */ |
| 390 _parameterToRemoteObject(parameter, target) { |
| 391 if (parameter instanceof WebInspector.RemoteObject) |
| 392 return parameter; |
| 393 if (!target) |
| 394 return WebInspector.RemoteObject.fromLocalObject(parameter); |
| 395 if (typeof parameter === 'object') |
| 396 return target.runtimeModel.createRemoteObject(parameter); |
| 397 return target.runtimeModel.createRemoteObjectFromPrimitiveValue(parameter); |
| 398 } |
| 399 |
| 400 /** |
| 401 * @param {!Array.<!WebInspector.RemoteObject|string>} parameters |
| 402 * @return {!Element} |
| 403 */ |
| 404 _format(parameters) { |
| 405 // This node is used like a Builder. Values are continually appended onto it
. |
| 406 var formattedResult = createElement('span'); |
| 407 if (!parameters.length) |
| 408 return formattedResult; |
| 409 |
| 410 // Formatting code below assumes that parameters are all wrappers whereas fr
ontend console |
| 411 // API allows passing arbitrary values as messages (strings, numbers, etc.).
Wrap them here. |
| 412 // FIXME: Only pass runtime wrappers here. |
| 413 for (var i = 0; i < parameters.length; ++i) |
| 414 parameters[i] = this._parameterToRemoteObject(parameters[i], this._target(
)); |
| 415 |
| 416 // There can be string log and string eval result. We distinguish between th
em based on message type. |
| 417 var shouldFormatMessage = WebInspector.RemoteObject.type( |
| 418 (/** @type {!Array.<!WebInspector.RemoteObject
>} **/ (parameters))[0]) === 'string' && |
| 419 (this._message.type !== WebInspector.ConsoleMessage.MessageType.Result |
| |
| 420 this._message.level === WebInspector.ConsoleMessage.MessageLevel.Error
|| |
| 421 this._message.level === WebInspector.ConsoleMessage.MessageLevel.Revoke
dError); |
| 422 |
| 423 // Multiple parameters with the first being a format string. Save unused sub
stitutions. |
| 424 if (shouldFormatMessage) { |
| 425 var result = this._formatWithSubstitutionString( |
| 426 /** @type {string} **/ (parameters[0].description), parameters.slice(1
), formattedResult); |
| 427 parameters = result.unusedSubstitutions; |
| 428 if (parameters.length) |
| 429 formattedResult.createTextChild(' '); |
| 430 } |
| 431 |
| 432 // Single parameter, or unused substitutions from above. |
| 433 for (var i = 0; i < parameters.length; ++i) { |
| 434 // Inline strings when formatting. |
| 435 if (shouldFormatMessage && parameters[i].type === 'string') |
| 436 formattedResult.appendChild(WebInspector.linkifyStringAsFragment(paramet
ers[i].description)); |
| 437 else |
| 438 formattedResult.appendChild(this._formatParameter(parameters[i], false,
true)); |
| 439 if (i < parameters.length - 1) |
| 440 formattedResult.createTextChild(' '); |
| 441 } |
| 442 return formattedResult; |
| 443 } |
| 444 |
| 445 /** |
| 446 * @param {!WebInspector.RemoteObject} output |
| 447 * @param {boolean=} forceObjectFormat |
| 448 * @param {boolean=} includePreview |
| 449 * @return {!Element} |
| 450 */ |
| 451 _formatParameter(output, forceObjectFormat, includePreview) { |
| 452 if (output.customPreview()) |
| 453 return (new WebInspector.CustomPreviewComponent(output)).element; |
| 454 |
| 455 var type = forceObjectFormat ? 'object' : (output.subtype || output.type); |
| 456 var element; |
| 457 switch (type) { |
| 458 case 'array': |
| 459 case 'typedarray': |
| 460 element = this._formatParameterAsArray(output); |
| 461 break; |
| 462 case 'error': |
| 463 element = this._formatParameterAsError(output); |
| 464 break; |
| 465 case 'function': |
| 466 case 'generator': |
| 467 element = this._formatParameterAsFunction(output, includePreview); |
| 468 break; |
| 469 case 'iterator': |
| 470 case 'map': |
| 471 case 'object': |
| 472 case 'promise': |
| 473 case 'proxy': |
| 474 case 'set': |
| 475 element = this._formatParameterAsObject(output, includePreview); |
| 476 break; |
| 477 case 'node': |
| 478 element = this._formatParameterAsNode(output); |
| 479 break; |
| 480 case 'string': |
| 481 element = this._formatParameterAsString(output); |
| 482 break; |
| 483 case 'boolean': |
| 484 case 'date': |
| 485 case 'null': |
| 486 case 'number': |
| 487 case 'regexp': |
| 488 case 'symbol': |
| 489 case 'undefined': |
| 490 element = this._formatParameterAsValue(output); |
| 491 break; |
| 492 default: |
| 493 element = this._formatParameterAsValue(output); |
| 494 console.error('Tried to format remote object of unknown type.'); |
| 495 } |
| 496 element.classList.add('object-value-' + type); |
| 497 element.classList.add('source-code'); |
| 498 return element; |
| 499 } |
| 500 |
| 501 /** |
| 502 * @param {!WebInspector.RemoteObject} obj |
| 503 * @return {!Element} |
| 504 */ |
| 505 _formatParameterAsValue(obj) { |
| 506 var result = createElement('span'); |
| 507 result.createTextChild(obj.description || ''); |
| 508 if (obj.objectId) |
| 509 result.addEventListener('contextmenu', this._contextMenuEventFired.bind(th
is, obj), false); |
| 510 return result; |
| 511 } |
| 512 |
| 513 /** |
| 514 * @param {!WebInspector.RemoteObject} obj |
| 515 * @param {boolean=} includePreview |
| 516 * @return {!Element} |
| 517 */ |
| 518 _formatParameterAsObject(obj, includePreview) { |
| 519 var titleElement = createElement('span'); |
| 520 if (includePreview && obj.preview) { |
| 521 titleElement.classList.add('console-object-preview'); |
| 522 this._previewFormatter.appendObjectPreview(titleElement, obj.preview); |
| 523 } else if (obj.type === 'function') { |
| 524 WebInspector.ObjectPropertiesSection.formatObjectAsFunction(obj, titleElem
ent, false); |
| 525 titleElement.classList.add('object-value-function'); |
| 526 } else { |
| 527 titleElement.createTextChild(obj.description || ''); |
| 528 } |
| 529 |
| 530 var section = new WebInspector.ObjectPropertiesSection(obj, titleElement, th
is._linkifier); |
| 531 section.element.classList.add('console-view-object-properties-section'); |
| 532 section.enableContextMenu(); |
| 533 return section.element; |
| 534 } |
| 535 |
| 536 /** |
| 537 * @param {!WebInspector.RemoteObject} func |
| 538 * @param {boolean=} includePreview |
| 539 * @return {!Element} |
| 540 */ |
| 541 _formatParameterAsFunction(func, includePreview) { |
| 542 var result = createElement('span'); |
| 543 WebInspector.RemoteFunction.objectAsFunction(func).targetFunction().then(for
matTargetFunction.bind(this)); |
| 544 return result; |
| 87 | 545 |
| 88 /** | 546 /** |
| 89 * @override | 547 * @param {!WebInspector.RemoteObject} targetFunction |
| 548 * @this {WebInspector.ConsoleViewMessage} |
| 90 */ | 549 */ |
| 91 willHide: function() | 550 function formatTargetFunction(targetFunction) { |
| 92 { | 551 var functionElement = createElement('span'); |
| 93 this._isVisible = false; | 552 WebInspector.ObjectPropertiesSection.formatObjectAsFunction( |
| 94 this._cachedHeight = this.contentElement().offsetHeight; | 553 targetFunction, functionElement, true, includePreview); |
| 95 }, | 554 result.appendChild(functionElement); |
| 555 if (targetFunction !== func) { |
| 556 var note = result.createChild('span', 'object-info-state-note'); |
| 557 note.title = WebInspector.UIString('Function was resolved from bound fun
ction.'); |
| 558 } |
| 559 result.addEventListener('contextmenu', this._contextMenuEventFired.bind(th
is, targetFunction), false); |
| 560 } |
| 561 } |
| 562 |
| 563 /** |
| 564 * @param {!WebInspector.RemoteObject} obj |
| 565 * @param {!Event} event |
| 566 */ |
| 567 _contextMenuEventFired(obj, event) { |
| 568 var contextMenu = new WebInspector.ContextMenu(event); |
| 569 contextMenu.appendApplicableItems(obj); |
| 570 contextMenu.show(); |
| 571 } |
| 572 |
| 573 /** |
| 574 * @param {?WebInspector.RemoteObject} object |
| 575 * @param {!Array.<!RuntimeAgent.PropertyPreview>} propertyPath |
| 576 * @return {!Element} |
| 577 */ |
| 578 _renderPropertyPreviewOrAccessor(object, propertyPath) { |
| 579 var property = propertyPath.peekLast(); |
| 580 if (property.type === 'accessor') |
| 581 return this._formatAsAccessorProperty(object, propertyPath.map(property =>
property.name), false); |
| 582 return this._previewFormatter.renderPropertyPreview( |
| 583 property.type, /** @type {string} */ (property.subtype), property.value)
; |
| 584 } |
| 585 |
| 586 /** |
| 587 * @param {!WebInspector.RemoteObject} object |
| 588 * @return {!Element} |
| 589 */ |
| 590 _formatParameterAsNode(object) { |
| 591 var result = createElement('span'); |
| 592 WebInspector.Renderer.renderPromise(object).then(appendRenderer.bind(this),
failedToRender.bind(this)); |
| 593 return result; |
| 96 | 594 |
| 97 /** | 595 /** |
| 98 * @return {number} | 596 * @param {!Element} rendererElement |
| 597 * @this {WebInspector.ConsoleViewMessage} |
| 99 */ | 598 */ |
| 100 fastHeight: function() | 599 function appendRenderer(rendererElement) { |
| 101 { | 600 result.appendChild(rendererElement); |
| 102 if (this._cachedHeight) | 601 this._formattedParameterAsNodeForTest(); |
| 103 return this._cachedHeight; | 602 } |
| 104 // This value reflects the 18px min-height of .console-message, plus the | 603 |
| 105 // 1px border of .console-message-wrapper. Keep in sync with consoleView
.css. | 604 /** |
| 106 const defaultConsoleRowHeight = 19; | 605 * @this {WebInspector.ConsoleViewMessage} |
| 107 if (this._message.type === WebInspector.ConsoleMessage.MessageType.Table
) { | 606 */ |
| 108 var table = this._message.parameters[0]; | 607 function failedToRender() { |
| 109 if (table && table.preview) | 608 result.appendChild(this._formatParameterAsObject(object, false)); |
| 110 return defaultConsoleRowHeight * table.preview.properties.length
; | 609 } |
| 610 } |
| 611 |
| 612 _formattedParameterAsNodeForTest() { |
| 613 } |
| 614 |
| 615 /** |
| 616 * @param {!WebInspector.RemoteObject} array |
| 617 * @return {!Element} |
| 618 */ |
| 619 _formatParameterAsArray(array) { |
| 620 var usePrintedArrayFormat = this._message.type !== WebInspector.ConsoleMessa
ge.MessageType.DirXML && |
| 621 this._message.type !== WebInspector.ConsoleMessage.MessageType.Result; |
| 622 var isLongArray = array.arrayLength() > 100; |
| 623 if (usePrintedArrayFormat || isLongArray) |
| 624 return this._formatParameterAsObject(array, usePrintedArrayFormat || !isLo
ngArray); |
| 625 var result = createElement('span'); |
| 626 array.getAllProperties(false, printArrayResult.bind(this)); |
| 627 return result; |
| 628 |
| 629 /** |
| 630 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties |
| 631 * @this {!WebInspector.ConsoleViewMessage} |
| 632 */ |
| 633 function printArrayResult(properties) { |
| 634 if (!properties) { |
| 635 result.appendChild(this._formatParameterAsObject(array, false)); |
| 636 return; |
| 637 } |
| 638 |
| 639 var titleElement = createElement('span'); |
| 640 var elements = {}; |
| 641 for (var i = 0; i < properties.length; ++i) { |
| 642 var property = properties[i]; |
| 643 var name = property.name; |
| 644 if (isNaN(name)) |
| 645 continue; |
| 646 if (property.getter) |
| 647 elements[name] = this._formatAsAccessorProperty(array, [name], true); |
| 648 else if (property.value) |
| 649 elements[name] = this._formatAsArrayEntry(property.value); |
| 650 } |
| 651 |
| 652 titleElement.createTextChild('['); |
| 653 var lastNonEmptyIndex = -1; |
| 654 |
| 655 function appendUndefined(titleElement, index) { |
| 656 if (index - lastNonEmptyIndex <= 1) |
| 657 return; |
| 658 var span = titleElement.createChild('span', 'object-value-undefined'); |
| 659 span.textContent = WebInspector.UIString('undefined × %d', index - lastN
onEmptyIndex - 1); |
| 660 } |
| 661 |
| 662 var length = array.arrayLength(); |
| 663 for (var i = 0; i < length; ++i) { |
| 664 var element = elements[i]; |
| 665 if (!element) |
| 666 continue; |
| 667 |
| 668 if (i - lastNonEmptyIndex > 1) { |
| 669 appendUndefined(titleElement, i); |
| 670 titleElement.createTextChild(', '); |
| 111 } | 671 } |
| 112 return defaultConsoleRowHeight; | 672 |
| 113 }, | 673 titleElement.appendChild(element); |
| 674 lastNonEmptyIndex = i; |
| 675 if (i < length - 1) |
| 676 titleElement.createTextChild(', '); |
| 677 } |
| 678 appendUndefined(titleElement, length); |
| 679 |
| 680 titleElement.createTextChild(']'); |
| 681 |
| 682 var section = new WebInspector.ObjectPropertiesSection(array, titleElement
, this._linkifier); |
| 683 section.element.classList.add('console-view-object-properties-section'); |
| 684 section.enableContextMenu(); |
| 685 result.appendChild(section.element); |
| 686 } |
| 687 } |
| 688 |
| 689 /** |
| 690 * @param {!WebInspector.RemoteObject} output |
| 691 * @return {!Element} |
| 692 */ |
| 693 _formatParameterAsString(output) { |
| 694 var span = createElement('span'); |
| 695 span.appendChild(WebInspector.linkifyStringAsFragment(output.description ||
'')); |
| 696 |
| 697 var result = createElement('span'); |
| 698 result.createChild('span', 'object-value-string-quote').textContent = '"'; |
| 699 result.appendChild(span); |
| 700 result.createChild('span', 'object-value-string-quote').textContent = '"'; |
| 701 return result; |
| 702 } |
| 703 |
| 704 /** |
| 705 * @param {!WebInspector.RemoteObject} output |
| 706 * @return {!Element} |
| 707 */ |
| 708 _formatParameterAsError(output) { |
| 709 var result = createElement('span'); |
| 710 var errorSpan = this._tryFormatAsError(output.description || ''); |
| 711 result.appendChild(errorSpan ? errorSpan : WebInspector.linkifyStringAsFragm
ent(output.description || '')); |
| 712 return result; |
| 713 } |
| 714 |
| 715 /** |
| 716 * @param {!WebInspector.RemoteObject} output |
| 717 * @return {!Element} |
| 718 */ |
| 719 _formatAsArrayEntry(output) { |
| 720 return this._previewFormatter.renderPropertyPreview(output.type, output.subt
ype, output.description); |
| 721 } |
| 722 |
| 723 /** |
| 724 * @param {?WebInspector.RemoteObject} object |
| 725 * @param {!Array.<string>} propertyPath |
| 726 * @param {boolean} isArrayEntry |
| 727 * @return {!Element} |
| 728 */ |
| 729 _formatAsAccessorProperty(object, propertyPath, isArrayEntry) { |
| 730 var rootElement = WebInspector.ObjectPropertyTreeElement.createRemoteObjectA
ccessorPropertySpan( |
| 731 object, propertyPath, onInvokeGetterClick.bind(this)); |
| 114 | 732 |
| 115 /** | 733 /** |
| 116 * @return {!WebInspector.ConsoleMessage} | 734 * @param {?WebInspector.RemoteObject} result |
| 735 * @param {boolean=} wasThrown |
| 736 * @this {WebInspector.ConsoleViewMessage} |
| 117 */ | 737 */ |
| 118 consoleMessage: function() | 738 function onInvokeGetterClick(result, wasThrown) { |
| 119 { | 739 if (!result) |
| 120 return this._message; | 740 return; |
| 121 }, | 741 rootElement.removeChildren(); |
| 742 if (wasThrown) { |
| 743 var element = rootElement.createChild('span'); |
| 744 element.textContent = WebInspector.UIString('<exception>'); |
| 745 element.title = /** @type {string} */ (result.description); |
| 746 } else if (isArrayEntry) { |
| 747 rootElement.appendChild(this._formatAsArrayEntry(result)); |
| 748 } else { |
| 749 // Make a PropertyPreview from the RemoteObject similar to the backend l
ogic. |
| 750 const maxLength = 100; |
| 751 var type = result.type; |
| 752 var subtype = result.subtype; |
| 753 var description = ''; |
| 754 if (type !== 'function' && result.description) { |
| 755 if (type === 'string' || subtype === 'regexp') |
| 756 description = result.description.trimMiddle(maxLength); |
| 757 else |
| 758 description = result.description.trimEnd(maxLength); |
| 759 } |
| 760 rootElement.appendChild(this._previewFormatter.renderPropertyPreview(typ
e, subtype, description)); |
| 761 } |
| 762 } |
| 763 |
| 764 return rootElement; |
| 765 } |
| 766 |
| 767 /** |
| 768 * @param {string} format |
| 769 * @param {!Array.<!WebInspector.RemoteObject>} parameters |
| 770 * @param {!Element} formattedResult |
| 771 */ |
| 772 _formatWithSubstitutionString(format, parameters, formattedResult) { |
| 773 var formatters = {}; |
| 122 | 774 |
| 123 /** | 775 /** |
| 124 * @param {!WebInspector.ConsoleMessage} consoleMessage | 776 * @param {boolean} force |
| 125 * @return {!Element} | |
| 126 */ | |
| 127 _buildTableMessage: function(consoleMessage) | |
| 128 { | |
| 129 var formattedMessage = createElement("span"); | |
| 130 WebInspector.appendStyle(formattedMessage, "components/objectValue.css")
; | |
| 131 formattedMessage.className = "console-message-text source-code"; | |
| 132 var anchorElement = this._buildMessageAnchor(consoleMessage); | |
| 133 if (anchorElement) | |
| 134 formattedMessage.appendChild(anchorElement); | |
| 135 | |
| 136 var table = consoleMessage.parameters && consoleMessage.parameters.lengt
h ? consoleMessage.parameters[0] : null; | |
| 137 if (table) | |
| 138 table = this._parameterToRemoteObject(table, this._target()); | |
| 139 if (!table || !table.preview) | |
| 140 return formattedMessage; | |
| 141 | |
| 142 var columnNames = []; | |
| 143 var preview = table.preview; | |
| 144 var rows = []; | |
| 145 for (var i = 0; i < preview.properties.length; ++i) { | |
| 146 var rowProperty = preview.properties[i]; | |
| 147 var rowPreview = rowProperty.valuePreview; | |
| 148 if (!rowPreview) | |
| 149 continue; | |
| 150 | |
| 151 var rowValue = {}; | |
| 152 const maxColumnsToRender = 20; | |
| 153 for (var j = 0; j < rowPreview.properties.length; ++j) { | |
| 154 var cellProperty = rowPreview.properties[j]; | |
| 155 var columnRendered = columnNames.indexOf(cellProperty.name) !==
-1; | |
| 156 if (!columnRendered) { | |
| 157 if (columnNames.length === maxColumnsToRender) | |
| 158 continue; | |
| 159 columnRendered = true; | |
| 160 columnNames.push(cellProperty.name); | |
| 161 } | |
| 162 | |
| 163 if (columnRendered) { | |
| 164 var cellElement = this._renderPropertyPreviewOrAccessor(tabl
e, [rowProperty, cellProperty]); | |
| 165 cellElement.classList.add("console-message-nowrap-below"); | |
| 166 rowValue[cellProperty.name] = cellElement; | |
| 167 } | |
| 168 } | |
| 169 rows.push([rowProperty.name, rowValue]); | |
| 170 } | |
| 171 | |
| 172 var flatValues = []; | |
| 173 for (var i = 0; i < rows.length; ++i) { | |
| 174 var rowName = rows[i][0]; | |
| 175 var rowValue = rows[i][1]; | |
| 176 flatValues.push(rowName); | |
| 177 for (var j = 0; j < columnNames.length; ++j) | |
| 178 flatValues.push(rowValue[columnNames[j]]); | |
| 179 } | |
| 180 columnNames.unshift(WebInspector.UIString("(index)")); | |
| 181 | |
| 182 if (flatValues.length) { | |
| 183 this._dataGrid = WebInspector.SortableDataGrid.create(columnNames, f
latValues); | |
| 184 | |
| 185 var formattedResult = createElement("span"); | |
| 186 var tableElement = formattedResult.createChild("div", "console-messa
ge-formatted-table"); | |
| 187 var dataGridContainer = tableElement.createChild("span"); | |
| 188 tableElement.appendChild(this._formatParameter(table, true, false)); | |
| 189 dataGridContainer.appendChild(this._dataGrid.element); | |
| 190 formattedMessage.appendChild(formattedResult); | |
| 191 this._dataGrid.renderInline(); | |
| 192 } | |
| 193 return formattedMessage; | |
| 194 }, | |
| 195 | |
| 196 /** | |
| 197 * @param {!WebInspector.ConsoleMessage} consoleMessage | |
| 198 * @return {!Element} | |
| 199 */ | |
| 200 _buildMessage: function(consoleMessage) | |
| 201 { | |
| 202 var messageElement; | |
| 203 if (consoleMessage.source === WebInspector.ConsoleMessage.MessageSource.
ConsoleAPI) { | |
| 204 switch (consoleMessage.type) { | |
| 205 case WebInspector.ConsoleMessage.MessageType.Trace: | |
| 206 messageElement = this._format(consoleMessage.parameters || ["con
sole.trace"]); | |
| 207 break; | |
| 208 case WebInspector.ConsoleMessage.MessageType.Clear: | |
| 209 messageElement = createElementWithClass("span", "console-info"); | |
| 210 messageElement.textContent = WebInspector.UIString("Console was
cleared"); | |
| 211 break; | |
| 212 case WebInspector.ConsoleMessage.MessageType.Assert: | |
| 213 var args = [WebInspector.UIString("Assertion failed:")]; | |
| 214 if (consoleMessage.parameters) | |
| 215 args = args.concat(consoleMessage.parameters); | |
| 216 messageElement = this._format(args); | |
| 217 break; | |
| 218 case WebInspector.ConsoleMessage.MessageType.Dir: | |
| 219 var obj = consoleMessage.parameters ? consoleMessage.parameters[
0] : undefined; | |
| 220 var args = ["%O", obj]; | |
| 221 messageElement = this._format(args); | |
| 222 break; | |
| 223 case WebInspector.ConsoleMessage.MessageType.Profile: | |
| 224 case WebInspector.ConsoleMessage.MessageType.ProfileEnd: | |
| 225 messageElement = this._format([consoleMessage.messageText]); | |
| 226 break; | |
| 227 default: | |
| 228 if (consoleMessage.parameters && consoleMessage.parameters.lengt
h === 1 && consoleMessage.parameters[0].type === "string") | |
| 229 messageElement = this._tryFormatAsError(/** @type {string} *
/(consoleMessage.parameters[0].value)); | |
| 230 var args = consoleMessage.parameters || [consoleMessage.messageT
ext]; | |
| 231 messageElement = messageElement || this._format(args); | |
| 232 } | |
| 233 } else if (consoleMessage.source === WebInspector.ConsoleMessage.Message
Source.Network) { | |
| 234 if (consoleMessage.request) { | |
| 235 messageElement = createElement("span"); | |
| 236 if (consoleMessage.level === WebInspector.ConsoleMessage.Message
Level.Error || consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel
.RevokedError) { | |
| 237 messageElement.createTextChildren(consoleMessage.request.req
uestMethod, " "); | |
| 238 messageElement.appendChild(WebInspector.Linkifier.linkifyUsi
ngRevealer(consoleMessage.request, consoleMessage.request.url, consoleMessage.re
quest.url)); | |
| 239 if (consoleMessage.request.failed) | |
| 240 messageElement.createTextChildren(" ", consoleMessage.re
quest.localizedFailDescription); | |
| 241 else | |
| 242 messageElement.createTextChildren(" ", String(consoleMes
sage.request.statusCode), " (", consoleMessage.request.statusText, ")"); | |
| 243 } else { | |
| 244 var fragment = WebInspector.linkifyStringAsFragmentWithCusto
mLinkifier(consoleMessage.messageText, linkifyRequest.bind(consoleMessage)); | |
| 245 messageElement.appendChild(fragment); | |
| 246 } | |
| 247 } else { | |
| 248 messageElement = this._format([consoleMessage.messageText]); | |
| 249 } | |
| 250 } else { | |
| 251 var args = consoleMessage.parameters || [consoleMessage.messageText]
; | |
| 252 messageElement = this._format(args); | |
| 253 } | |
| 254 | |
| 255 var formattedMessage = createElement("span"); | |
| 256 WebInspector.appendStyle(formattedMessage, "components/objectValue.css")
; | |
| 257 formattedMessage.className = "console-message-text source-code"; | |
| 258 | |
| 259 var anchorElement = this._buildMessageAnchor(consoleMessage); | |
| 260 if (anchorElement) | |
| 261 formattedMessage.appendChild(anchorElement); | |
| 262 formattedMessage.appendChild(messageElement); | |
| 263 return formattedMessage; | |
| 264 | |
| 265 /** | |
| 266 * @param {string} title | |
| 267 * @return {!Element} | |
| 268 * @this {WebInspector.ConsoleMessage} | |
| 269 */ | |
| 270 function linkifyRequest(title) | |
| 271 { | |
| 272 return WebInspector.Linkifier.linkifyUsingRevealer(/** @type {!WebIn
spector.NetworkRequest} */ (this.request), title, this.request.url); | |
| 273 } | |
| 274 }, | |
| 275 | |
| 276 /** | |
| 277 * @param {!WebInspector.ConsoleMessage} consoleMessage | |
| 278 * @return {?Element} | |
| 279 */ | |
| 280 _buildMessageAnchor: function(consoleMessage) | |
| 281 { | |
| 282 var anchorElement = null; | |
| 283 if (consoleMessage.source !== WebInspector.ConsoleMessage.MessageSource.
Network || consoleMessage.request) { | |
| 284 if (consoleMessage.scriptId) | |
| 285 anchorElement = this._linkifyScriptId(consoleMessage.scriptId, c
onsoleMessage.url || "", consoleMessage.line, consoleMessage.column); | |
| 286 else if (consoleMessage.stackTrace && consoleMessage.stackTrace.call
Frames.length) | |
| 287 anchorElement = this._linkifyStackTraceTopFrame(consoleMessage.s
tackTrace); | |
| 288 else if (consoleMessage.url && consoleMessage.url !== "undefined") | |
| 289 anchorElement = this._linkifyLocation(consoleMessage.url, consol
eMessage.line, consoleMessage.column); | |
| 290 } else if (consoleMessage.url) { | |
| 291 var url = consoleMessage.url; | |
| 292 var isExternal = !WebInspector.resourceForURL(url) && !WebInspector.
networkMapping.uiSourceCodeForURLForAnyTarget(url); | |
| 293 anchorElement = WebInspector.linkifyURLAsNode(url, url, "console-mes
sage-url", isExternal); | |
| 294 } | |
| 295 | |
| 296 // Append a space to prevent the anchor text from being glued to the con
sole message when the user selects and copies the console messages. | |
| 297 if (anchorElement) | |
| 298 anchorElement.appendChild(createTextNode(" ")); | |
| 299 return anchorElement; | |
| 300 }, | |
| 301 | |
| 302 /** | |
| 303 * @param {!WebInspector.ConsoleMessage} consoleMessage | |
| 304 * @param {!WebInspector.Target} target | |
| 305 * @param {!WebInspector.Linkifier} linkifier | |
| 306 * @return {!Element} | |
| 307 */ | |
| 308 _buildMessageWithStackTrace: function(consoleMessage, target, linkifier) | |
| 309 { | |
| 310 var toggleElement = createElementWithClass("div", "console-message-stack
-trace-toggle"); | |
| 311 var triangleElement = toggleElement.createChild("div", "console-message-
stack-trace-triangle"); | |
| 312 var contentElement = toggleElement.createChild("div", "console-message-s
tack-trace-wrapper"); | |
| 313 | |
| 314 var messageElement = this._buildMessage(consoleMessage); | |
| 315 var clickableElement = contentElement.createChild("div"); | |
| 316 clickableElement.appendChild(messageElement); | |
| 317 var stackTraceElement = contentElement.createChild("div"); | |
| 318 var stackTracePreview = WebInspector.DOMPresentationUtils.buildStackTrac
ePreviewContents(target, linkifier, consoleMessage.stackTrace); | |
| 319 stackTraceElement.appendChild(stackTracePreview); | |
| 320 stackTraceElement.classList.add("hidden"); | |
| 321 | |
| 322 /** | |
| 323 * @param {boolean} expand | |
| 324 */ | |
| 325 function expandStackTrace(expand) | |
| 326 { | |
| 327 stackTraceElement.classList.toggle("hidden", !expand); | |
| 328 toggleElement.classList.toggle("expanded", expand); | |
| 329 } | |
| 330 | |
| 331 /** | |
| 332 * @param {?Event} event | |
| 333 */ | |
| 334 function toggleStackTrace(event) | |
| 335 { | |
| 336 if (event.target.hasSelection()) | |
| 337 return; | |
| 338 expandStackTrace(stackTraceElement.classList.contains("hidden")); | |
| 339 event.consume(); | |
| 340 } | |
| 341 | |
| 342 clickableElement.addEventListener("click", toggleStackTrace, false); | |
| 343 triangleElement.addEventListener("click", toggleStackTrace, false); | |
| 344 if (consoleMessage.type === WebInspector.ConsoleMessage.MessageType.Trac
e) | |
| 345 expandStackTrace(true); | |
| 346 | |
| 347 toggleElement._expandStackTraceForTest = expandStackTrace.bind(null, tru
e); | |
| 348 return toggleElement; | |
| 349 }, | |
| 350 | |
| 351 /** | |
| 352 * @param {string} url | |
| 353 * @param {number} lineNumber | |
| 354 * @param {number} columnNumber | |
| 355 * @return {?Element} | |
| 356 */ | |
| 357 _linkifyLocation: function(url, lineNumber, columnNumber) | |
| 358 { | |
| 359 var target = this._target(); | |
| 360 if (!target) | |
| 361 return null; | |
| 362 return this._linkifier.linkifyScriptLocation(target, null, url, lineNumb
er, columnNumber, "console-message-url"); | |
| 363 }, | |
| 364 | |
| 365 /** | |
| 366 * @param {!RuntimeAgent.StackTrace} stackTrace | |
| 367 * @return {?Element} | |
| 368 */ | |
| 369 _linkifyStackTraceTopFrame: function(stackTrace) | |
| 370 { | |
| 371 var target = this._target(); | |
| 372 if (!target) | |
| 373 return null; | |
| 374 return this._linkifier.linkifyStackTraceTopFrame(target, stackTrace, "co
nsole-message-url"); | |
| 375 }, | |
| 376 | |
| 377 /** | |
| 378 * @param {string} scriptId | |
| 379 * @param {string} url | |
| 380 * @param {number} lineNumber | |
| 381 * @param {number} columnNumber | |
| 382 * @return {?Element} | |
| 383 */ | |
| 384 _linkifyScriptId: function(scriptId, url, lineNumber, columnNumber) | |
| 385 { | |
| 386 var target = this._target(); | |
| 387 if (!target) | |
| 388 return null; | |
| 389 return this._linkifier.linkifyScriptLocation(target, scriptId, url, line
Number, columnNumber, "console-message-url"); | |
| 390 }, | |
| 391 | |
| 392 /** | |
| 393 * @param {!WebInspector.RemoteObject|!Object|string} parameter | |
| 394 * @param {?WebInspector.Target} target | |
| 395 * @return {!WebInspector.RemoteObject} | |
| 396 */ | |
| 397 _parameterToRemoteObject: function(parameter, target) | |
| 398 { | |
| 399 if (parameter instanceof WebInspector.RemoteObject) | |
| 400 return parameter; | |
| 401 if (!target) | |
| 402 return WebInspector.RemoteObject.fromLocalObject(parameter); | |
| 403 if (typeof parameter === "object") | |
| 404 return target.runtimeModel.createRemoteObject(parameter); | |
| 405 return target.runtimeModel.createRemoteObjectFromPrimitiveValue(paramete
r); | |
| 406 }, | |
| 407 | |
| 408 /** | |
| 409 * @param {!Array.<!WebInspector.RemoteObject|string>} parameters | |
| 410 * @return {!Element} | |
| 411 */ | |
| 412 _format: function(parameters) | |
| 413 { | |
| 414 // This node is used like a Builder. Values are continually appended ont
o it. | |
| 415 var formattedResult = createElement("span"); | |
| 416 if (!parameters.length) | |
| 417 return formattedResult; | |
| 418 | |
| 419 // Formatting code below assumes that parameters are all wrappers wherea
s frontend console | |
| 420 // API allows passing arbitrary values as messages (strings, numbers, et
c.). Wrap them here. | |
| 421 // FIXME: Only pass runtime wrappers here. | |
| 422 for (var i = 0; i < parameters.length; ++i) | |
| 423 parameters[i] = this._parameterToRemoteObject(parameters[i], this._t
arget()); | |
| 424 | |
| 425 // There can be string log and string eval result. We distinguish betwee
n them based on message type. | |
| 426 var shouldFormatMessage = WebInspector.RemoteObject.type((/** @type {!Ar
ray.<!WebInspector.RemoteObject>} **/ (parameters))[0]) === "string" && (this._m
essage.type !== WebInspector.ConsoleMessage.MessageType.Result || this._message.
level === WebInspector.ConsoleMessage.MessageLevel.Error || this._message.level
=== WebInspector.ConsoleMessage.MessageLevel.RevokedError); | |
| 427 | |
| 428 // Multiple parameters with the first being a format string. Save unused
substitutions. | |
| 429 if (shouldFormatMessage) { | |
| 430 var result = this._formatWithSubstitutionString(/** @type {string} *
*/ (parameters[0].description), parameters.slice(1), formattedResult); | |
| 431 parameters = result.unusedSubstitutions; | |
| 432 if (parameters.length) | |
| 433 formattedResult.createTextChild(" "); | |
| 434 } | |
| 435 | |
| 436 // Single parameter, or unused substitutions from above. | |
| 437 for (var i = 0; i < parameters.length; ++i) { | |
| 438 // Inline strings when formatting. | |
| 439 if (shouldFormatMessage && parameters[i].type === "string") | |
| 440 formattedResult.appendChild(WebInspector.linkifyStringAsFragment
(parameters[i].description)); | |
| 441 else | |
| 442 formattedResult.appendChild(this._formatParameter(parameters[i],
false, true)); | |
| 443 if (i < parameters.length - 1) | |
| 444 formattedResult.createTextChild(" "); | |
| 445 } | |
| 446 return formattedResult; | |
| 447 }, | |
| 448 | |
| 449 /** | |
| 450 * @param {!WebInspector.RemoteObject} output | |
| 451 * @param {boolean=} forceObjectFormat | |
| 452 * @param {boolean=} includePreview | |
| 453 * @return {!Element} | |
| 454 */ | |
| 455 _formatParameter: function(output, forceObjectFormat, includePreview) | |
| 456 { | |
| 457 if (output.customPreview()) | |
| 458 return (new WebInspector.CustomPreviewComponent(output)).element; | |
| 459 | |
| 460 var type = forceObjectFormat ? "object" : (output.subtype || output.type
); | |
| 461 var element; | |
| 462 switch (type) { | |
| 463 case "array": | |
| 464 case "typedarray": | |
| 465 element = this._formatParameterAsArray(output); | |
| 466 break; | |
| 467 case "error": | |
| 468 element = this._formatParameterAsError(output); | |
| 469 break; | |
| 470 case "function": | |
| 471 case "generator": | |
| 472 element = this._formatParameterAsFunction(output, includePreview); | |
| 473 break; | |
| 474 case "iterator": | |
| 475 case "map": | |
| 476 case "object": | |
| 477 case "promise": | |
| 478 case "proxy": | |
| 479 case "set": | |
| 480 element = this._formatParameterAsObject(output, includePreview); | |
| 481 break; | |
| 482 case "node": | |
| 483 element = this._formatParameterAsNode(output); | |
| 484 break; | |
| 485 case "string": | |
| 486 element = this._formatParameterAsString(output); | |
| 487 break; | |
| 488 case "boolean": | |
| 489 case "date": | |
| 490 case "null": | |
| 491 case "number": | |
| 492 case "regexp": | |
| 493 case "symbol": | |
| 494 case "undefined": | |
| 495 element = this._formatParameterAsValue(output); | |
| 496 break; | |
| 497 default: | |
| 498 element = this._formatParameterAsValue(output); | |
| 499 console.error("Tried to format remote object of unknown type."); | |
| 500 } | |
| 501 element.classList.add("object-value-" + type); | |
| 502 element.classList.add("source-code"); | |
| 503 return element; | |
| 504 }, | |
| 505 | |
| 506 /** | |
| 507 * @param {!WebInspector.RemoteObject} obj | 777 * @param {!WebInspector.RemoteObject} obj |
| 508 * @return {!Element} | 778 * @return {!Element} |
| 779 * @this {WebInspector.ConsoleViewMessage} |
| 509 */ | 780 */ |
| 510 _formatParameterAsValue: function(obj) | 781 function parameterFormatter(force, obj) { |
| 511 { | 782 return this._formatParameter(obj, force, false); |
| 512 var result = createElement("span"); | 783 } |
| 513 result.createTextChild(obj.description || ""); | 784 |
| 514 if (obj.objectId) | 785 function stringFormatter(obj) { |
| 515 result.addEventListener("contextmenu", this._contextMenuEventFired.b
ind(this, obj), false); | 786 return obj.description; |
| 516 return result; | 787 } |
| 517 }, | 788 |
| 789 function floatFormatter(obj) { |
| 790 if (typeof obj.value !== 'number') |
| 791 return 'NaN'; |
| 792 return obj.value; |
| 793 } |
| 794 |
| 795 function integerFormatter(obj) { |
| 796 if (typeof obj.value !== 'number') |
| 797 return 'NaN'; |
| 798 return Math.floor(obj.value); |
| 799 } |
| 800 |
| 801 function bypassFormatter(obj) { |
| 802 return (obj instanceof Node) ? obj : ''; |
| 803 } |
| 804 |
| 805 var currentStyle = null; |
| 806 function styleFormatter(obj) { |
| 807 currentStyle = {}; |
| 808 var buffer = createElement('span'); |
| 809 buffer.setAttribute('style', obj.description); |
| 810 for (var i = 0; i < buffer.style.length; i++) { |
| 811 var property = buffer.style[i]; |
| 812 if (isWhitelistedProperty(property)) |
| 813 currentStyle[property] = buffer.style[property]; |
| 814 } |
| 815 } |
| 816 |
| 817 function isWhitelistedProperty(property) { |
| 818 var prefixes = [ |
| 819 'background', 'border', 'color', 'font', 'line', 'margin', 'padding', 't
ext', '-webkit-background', |
| 820 '-webkit-border', '-webkit-font', '-webkit-margin', '-webkit-padding', '
-webkit-text' |
| 821 ]; |
| 822 for (var i = 0; i < prefixes.length; i++) { |
| 823 if (property.startsWith(prefixes[i])) |
| 824 return true; |
| 825 } |
| 826 return false; |
| 827 } |
| 828 |
| 829 // Firebug uses %o for formatting objects. |
| 830 formatters.o = parameterFormatter.bind(this, false); |
| 831 formatters.s = stringFormatter; |
| 832 formatters.f = floatFormatter; |
| 833 // Firebug allows both %i and %d for formatting integers. |
| 834 formatters.i = integerFormatter; |
| 835 formatters.d = integerFormatter; |
| 836 |
| 837 // Firebug uses %c for styling the message. |
| 838 formatters.c = styleFormatter; |
| 839 |
| 840 // Support %O to force object formatting, instead of the type-based %o forma
tting. |
| 841 formatters.O = parameterFormatter.bind(this, true); |
| 842 |
| 843 formatters._ = bypassFormatter; |
| 844 |
| 845 function append(a, b) { |
| 846 if (b instanceof Node) |
| 847 a.appendChild(b); |
| 848 else if (typeof b !== 'undefined') { |
| 849 var toAppend = WebInspector.linkifyStringAsFragment(String(b)); |
| 850 if (currentStyle) { |
| 851 var wrapper = createElement('span'); |
| 852 wrapper.appendChild(toAppend); |
| 853 applyCurrentStyle(wrapper); |
| 854 for (var i = 0; i < wrapper.children.length; ++i) |
| 855 applyCurrentStyle(wrapper.children[i]); |
| 856 toAppend = wrapper; |
| 857 } |
| 858 a.appendChild(toAppend); |
| 859 } |
| 860 return a; |
| 861 } |
| 518 | 862 |
| 519 /** | 863 /** |
| 520 * @param {!WebInspector.RemoteObject} obj | 864 * @param {!Element} element |
| 521 * @param {boolean=} includePreview | |
| 522 * @return {!Element} | |
| 523 */ | 865 */ |
| 524 _formatParameterAsObject: function(obj, includePreview) | 866 function applyCurrentStyle(element) { |
| 525 { | 867 for (var key in currentStyle) |
| 526 var titleElement = createElement("span"); | 868 element.style[key] = currentStyle[key]; |
| 527 if (includePreview && obj.preview) { | 869 } |
| 528 titleElement.classList.add("console-object-preview"); | 870 |
| 529 this._previewFormatter.appendObjectPreview(titleElement, obj.preview
); | 871 // String.format does treat formattedResult like a Builder, result is an obj
ect. |
| 530 } else if (obj.type === "function") { | 872 return String.format(format, parameters, formatters, formattedResult, append
); |
| 531 WebInspector.ObjectPropertiesSection.formatObjectAsFunction(obj, tit
leElement, false); | 873 } |
| 532 titleElement.classList.add("object-value-function"); | 874 |
| 533 } else { | 875 /** |
| 534 titleElement.createTextChild(obj.description || ""); | 876 * @return {boolean} |
| 535 } | 877 */ |
| 536 | 878 matchesFilterRegex(regexObject) { |
| 537 var section = new WebInspector.ObjectPropertiesSection(obj, titleElement
, this._linkifier); | 879 regexObject.lastIndex = 0; |
| 538 section.element.classList.add("console-view-object-properties-section"); | 880 var text = this.contentElement().deepTextContent(); |
| 539 section.enableContextMenu(); | 881 return regexObject.test(text); |
| 540 return section.element; | 882 } |
| 541 }, | 883 |
| 542 | 884 /** |
| 885 * @param {boolean} show |
| 886 */ |
| 887 updateTimestamp(show) { |
| 888 if (!this._contentElement) |
| 889 return; |
| 890 |
| 891 if (show && !this.timestampElement) { |
| 892 this.timestampElement = createElementWithClass('span', 'console-timestamp'
); |
| 893 this.timestampElement.textContent = (new Date(this._message.timestamp)).to
ConsoleTime() + ' '; |
| 894 this._contentElement.insertBefore(this.timestampElement, this._contentElem
ent.firstChild); |
| 895 return; |
| 896 } |
| 897 |
| 898 if (!show && this.timestampElement) { |
| 899 this.timestampElement.remove(); |
| 900 delete this.timestampElement; |
| 901 } |
| 902 } |
| 903 |
| 904 /** |
| 905 * @return {number} |
| 906 */ |
| 907 nestingLevel() { |
| 908 return this._nestingLevel; |
| 909 } |
| 910 |
| 911 resetCloseGroupDecorationCount() { |
| 912 if (!this._closeGroupDecorationCount) |
| 913 return; |
| 914 this._closeGroupDecorationCount = 0; |
| 915 this._updateCloseGroupDecorations(); |
| 916 } |
| 917 |
| 918 incrementCloseGroupDecorationCount() { |
| 919 ++this._closeGroupDecorationCount; |
| 920 this._updateCloseGroupDecorations(); |
| 921 } |
| 922 |
| 923 _updateCloseGroupDecorations() { |
| 924 if (!this._nestingLevelMarkers) |
| 925 return; |
| 926 for (var i = 0, n = this._nestingLevelMarkers.length; i < n; ++i) { |
| 927 var marker = this._nestingLevelMarkers[i]; |
| 928 marker.classList.toggle('group-closed', n - i <= this._closeGroupDecoratio
nCount); |
| 929 } |
| 930 } |
| 931 |
| 932 /** |
| 933 * @return {!Element} |
| 934 */ |
| 935 contentElement() { |
| 936 if (this._contentElement) |
| 937 return this._contentElement; |
| 938 |
| 939 var contentElement = createElementWithClass('div', 'console-message'); |
| 940 this._contentElement = contentElement; |
| 941 if (this._message.type === WebInspector.ConsoleMessage.MessageType.StartGrou
p || |
| 942 this._message.type === WebInspector.ConsoleMessage.MessageType.StartGrou
pCollapsed) |
| 943 contentElement.classList.add('console-group-title'); |
| 944 |
| 945 var formattedMessage; |
| 946 var consoleMessage = this._message; |
| 947 var target = consoleMessage.target(); |
| 948 var shouldIncludeTrace = !!consoleMessage.stackTrace && |
| 949 (consoleMessage.source === WebInspector.ConsoleMessage.MessageSource.Net
work || |
| 950 consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Error
|| |
| 951 consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Revok
edError || |
| 952 consoleMessage.type === WebInspector.ConsoleMessage.MessageType.Trace |
| |
| 953 consoleMessage.level === WebInspector.ConsoleMessage.MessageLevel.Warni
ng); |
| 954 if (target && shouldIncludeTrace) |
| 955 formattedMessage = this._buildMessageWithStackTrace(consoleMessage, target
, this._linkifier); |
| 956 else if (this._message.type === WebInspector.ConsoleMessage.MessageType.Tabl
e) |
| 957 formattedMessage = this._buildTableMessage(this._message); |
| 958 else |
| 959 formattedMessage = this._buildMessage(consoleMessage); |
| 960 contentElement.appendChild(formattedMessage); |
| 961 |
| 962 this.updateTimestamp(WebInspector.moduleSetting('consoleTimestampsEnabled').
get()); |
| 963 return this._contentElement; |
| 964 } |
| 965 |
| 966 /** |
| 967 * @return {!Element} |
| 968 */ |
| 969 toMessageElement() { |
| 970 if (this._element) |
| 971 return this._element; |
| 972 |
| 973 this._element = createElement('div'); |
| 974 this.updateMessageElement(); |
| 975 return this._element; |
| 976 } |
| 977 |
| 978 updateMessageElement() { |
| 979 if (!this._element) |
| 980 return; |
| 981 |
| 982 this._element.className = 'console-message-wrapper'; |
| 983 this._element.removeChildren(); |
| 984 |
| 985 this._nestingLevelMarkers = []; |
| 986 for (var i = 0; i < this._nestingLevel; ++i) |
| 987 this._nestingLevelMarkers.push(this._element.createChild('div', 'nesting-l
evel-marker')); |
| 988 this._updateCloseGroupDecorations(); |
| 989 this._element.message = this; |
| 990 |
| 991 switch (this._message.level) { |
| 992 case WebInspector.ConsoleMessage.MessageLevel.Log: |
| 993 this._element.classList.add('console-log-level'); |
| 994 break; |
| 995 case WebInspector.ConsoleMessage.MessageLevel.Debug: |
| 996 this._element.classList.add('console-debug-level'); |
| 997 break; |
| 998 case WebInspector.ConsoleMessage.MessageLevel.Warning: |
| 999 this._element.classList.add('console-warning-level'); |
| 1000 break; |
| 1001 case WebInspector.ConsoleMessage.MessageLevel.Error: |
| 1002 this._element.classList.add('console-error-level'); |
| 1003 break; |
| 1004 case WebInspector.ConsoleMessage.MessageLevel.RevokedError: |
| 1005 this._element.classList.add('console-revokedError-level'); |
| 1006 break; |
| 1007 case WebInspector.ConsoleMessage.MessageLevel.Info: |
| 1008 this._element.classList.add('console-info-level'); |
| 1009 break; |
| 1010 } |
| 1011 |
| 1012 this._element.appendChild(this.contentElement()); |
| 1013 if (this._repeatCount > 1) |
| 1014 this._showRepeatCountElement(); |
| 1015 } |
| 1016 |
| 1017 /** |
| 1018 * @return {number} |
| 1019 */ |
| 1020 repeatCount() { |
| 1021 return this._repeatCount || 1; |
| 1022 } |
| 1023 |
| 1024 resetIncrementRepeatCount() { |
| 1025 this._repeatCount = 1; |
| 1026 if (!this._repeatCountElement) |
| 1027 return; |
| 1028 |
| 1029 this._repeatCountElement.remove(); |
| 1030 delete this._repeatCountElement; |
| 1031 } |
| 1032 |
| 1033 incrementRepeatCount() { |
| 1034 this._repeatCount++; |
| 1035 this._showRepeatCountElement(); |
| 1036 } |
| 1037 |
| 1038 _showRepeatCountElement() { |
| 1039 if (!this._contentElement) |
| 1040 return; |
| 1041 |
| 1042 if (!this._repeatCountElement) { |
| 1043 this._repeatCountElement = createElementWithClass('label', 'console-messag
e-repeat-count', 'dt-small-bubble'); |
| 1044 switch (this._message.level) { |
| 1045 case WebInspector.ConsoleMessage.MessageLevel.Warning: |
| 1046 this._repeatCountElement.type = 'warning'; |
| 1047 break; |
| 1048 case WebInspector.ConsoleMessage.MessageLevel.Error: |
| 1049 this._repeatCountElement.type = 'error'; |
| 1050 break; |
| 1051 case WebInspector.ConsoleMessage.MessageLevel.Debug: |
| 1052 this._repeatCountElement.type = 'debug'; |
| 1053 break; |
| 1054 default: |
| 1055 this._repeatCountElement.type = 'info'; |
| 1056 } |
| 1057 this._element.insertBefore(this._repeatCountElement, this._contentElement)
; |
| 1058 this._contentElement.classList.add('repeated-message'); |
| 1059 } |
| 1060 this._repeatCountElement.textContent = this._repeatCount; |
| 1061 } |
| 1062 |
| 1063 get text() { |
| 1064 return this._message.messageText; |
| 1065 } |
| 1066 |
| 1067 /** |
| 1068 * @param {?RegExp} regex |
| 1069 */ |
| 1070 setSearchRegex(regex) { |
| 1071 if (this._searchHiglightNodeChanges && this._searchHiglightNodeChanges.lengt
h) |
| 1072 WebInspector.revertDomChanges(this._searchHiglightNodeChanges); |
| 1073 this._searchRegex = regex; |
| 1074 this._searchHighlightNodes = []; |
| 1075 this._searchHiglightNodeChanges = []; |
| 1076 if (!this._searchRegex) |
| 1077 return; |
| 1078 |
| 1079 var text = this.contentElement().deepTextContent(); |
| 1080 var match; |
| 1081 this._searchRegex.lastIndex = 0; |
| 1082 var sourceRanges = []; |
| 1083 while ((match = this._searchRegex.exec(text)) && match[0]) |
| 1084 sourceRanges.push(new WebInspector.SourceRange(match.index, match[0].lengt
h)); |
| 1085 |
| 1086 if (sourceRanges.length) |
| 1087 this._searchHighlightNodes = |
| 1088 WebInspector.highlightSearchResults(this.contentElement(), sourceRange
s, this._searchHiglightNodeChanges); |
| 1089 } |
| 1090 |
| 1091 /** |
| 1092 * @return {?RegExp} |
| 1093 */ |
| 1094 searchRegex() { |
| 1095 return this._searchRegex; |
| 1096 } |
| 1097 |
| 1098 /** |
| 1099 * @return {number} |
| 1100 */ |
| 1101 searchCount() { |
| 1102 return this._searchHighlightNodes.length; |
| 1103 } |
| 1104 |
| 1105 /** |
| 1106 * @return {!Element} |
| 1107 */ |
| 1108 searchHighlightNode(index) { |
| 1109 return this._searchHighlightNodes[index]; |
| 1110 } |
| 1111 |
| 1112 /** |
| 1113 * @param {string} string |
| 1114 * @return {?Element} |
| 1115 */ |
| 1116 _tryFormatAsError(string) { |
| 543 /** | 1117 /** |
| 544 * @param {!WebInspector.RemoteObject} func | 1118 * @param {string} prefix |
| 545 * @param {boolean=} includePreview | |
| 546 * @return {!Element} | |
| 547 */ | 1119 */ |
| 548 _formatParameterAsFunction: function(func, includePreview) | 1120 function startsWith(prefix) { |
| 549 { | 1121 return string.startsWith(prefix); |
| 550 var result = createElement("span"); | 1122 } |
| 551 WebInspector.RemoteFunction.objectAsFunction(func).targetFunction().then
(formatTargetFunction.bind(this)); | 1123 |
| 552 return result; | 1124 var errorPrefixes = ['EvalError', 'ReferenceError', 'SyntaxError', 'TypeErro
r', 'RangeError', 'Error', 'URIError']; |
| 553 | 1125 var target = this._target(); |
| 554 /** | 1126 if (!target || !errorPrefixes.some(startsWith)) |
| 555 * @param {!WebInspector.RemoteObject} targetFunction | 1127 return null; |
| 556 * @this {WebInspector.ConsoleViewMessage} | 1128 var debuggerModel = WebInspector.DebuggerModel.fromTarget(target); |
| 557 */ | 1129 if (!debuggerModel) |
| 558 function formatTargetFunction(targetFunction) | 1130 return null; |
| 559 { | 1131 |
| 560 var functionElement = createElement("span"); | 1132 var lines = string.split('\n'); |
| 561 WebInspector.ObjectPropertiesSection.formatObjectAsFunction(targetFu
nction, functionElement, true, includePreview); | 1133 var links = []; |
| 562 result.appendChild(functionElement); | 1134 var position = 0; |
| 563 if (targetFunction !== func) { | 1135 for (var i = 0; i < lines.length; ++i) { |
| 564 var note = result.createChild("span", "object-info-state-note"); | 1136 position += i > 0 ? lines[i - 1].length + 1 : 0; |
| 565 note.title = WebInspector.UIString("Function was resolved from b
ound function."); | 1137 var isCallFrameLine = /^\s*at\s/.test(lines[i]); |
| 566 } | 1138 if (!isCallFrameLine && links.length) |
| 567 result.addEventListener("contextmenu", this._contextMenuEventFired.b
ind(this, targetFunction), false); | 1139 return null; |
| 568 } | 1140 |
| 569 }, | 1141 if (!isCallFrameLine) |
| 570 | 1142 continue; |
| 571 /** | 1143 |
| 572 * @param {!WebInspector.RemoteObject} obj | 1144 var openBracketIndex = -1; |
| 573 * @param {!Event} event | 1145 var closeBracketIndex = -1; |
| 574 */ | 1146 var match = /\([^\)\(]+\)/.exec(lines[i]); |
| 575 _contextMenuEventFired: function(obj, event) | 1147 if (match) { |
| 576 { | 1148 openBracketIndex = match.index; |
| 577 var contextMenu = new WebInspector.ContextMenu(event); | 1149 closeBracketIndex = match.index + match[0].length - 1; |
| 578 contextMenu.appendApplicableItems(obj); | 1150 } |
| 579 contextMenu.show(); | 1151 var hasOpenBracket = openBracketIndex !== -1; |
| 580 }, | 1152 var left = hasOpenBracket ? openBracketIndex + 1 : lines[i].indexOf('at')
+ 3; |
| 581 | 1153 var right = hasOpenBracket ? closeBracketIndex : lines[i].length; |
| 582 /** | 1154 var linkCandidate = lines[i].substring(left, right); |
| 583 * @param {?WebInspector.RemoteObject} object | 1155 var splitResult = WebInspector.ParsedURL.splitLineAndColumn(linkCandidate)
; |
| 584 * @param {!Array.<!RuntimeAgent.PropertyPreview>} propertyPath | 1156 if (!splitResult) |
| 585 * @return {!Element} | 1157 return null; |
| 586 */ | 1158 |
| 587 _renderPropertyPreviewOrAccessor: function(object, propertyPath) | 1159 var parsed = splitResult.url.asParsedURL(); |
| 588 { | 1160 var url; |
| 589 var property = propertyPath.peekLast(); | 1161 if (parsed) |
| 590 if (property.type === "accessor") | 1162 url = parsed.url; |
| 591 return this._formatAsAccessorProperty(object, propertyPath.map(prope
rty => property.name), false); | 1163 else if (debuggerModel.scriptsForSourceURL(splitResult.url).length) |
| 592 return this._previewFormatter.renderPropertyPreview(property.type, /** @
type {string} */ (property.subtype), property.value); | 1164 url = splitResult.url; |
| 593 }, | 1165 else if (splitResult.url === '<anonymous>') |
| 594 | 1166 continue; |
| 595 /** | 1167 else |
| 596 * @param {!WebInspector.RemoteObject} object | 1168 return null; |
| 597 * @return {!Element} | 1169 |
| 598 */ | 1170 links.push({ |
| 599 _formatParameterAsNode: function(object) | 1171 url: url, |
| 600 { | 1172 positionLeft: position + left, |
| 601 var result = createElement("span"); | 1173 positionRight: position + right, |
| 602 WebInspector.Renderer.renderPromise(object).then(appendRenderer.bind(thi
s), failedToRender.bind(this)); | 1174 lineNumber: splitResult.lineNumber, |
| 603 return result; | 1175 columnNumber: splitResult.columnNumber |
| 604 | 1176 }); |
| 605 /** | 1177 } |
| 606 * @param {!Element} rendererElement | 1178 |
| 607 * @this {WebInspector.ConsoleViewMessage} | 1179 if (!links.length) |
| 608 */ | 1180 return null; |
| 609 function appendRenderer(rendererElement) | 1181 |
| 610 { | 1182 var formattedResult = createElement('span'); |
| 611 result.appendChild(rendererElement); | 1183 var start = 0; |
| 612 this._formattedParameterAsNodeForTest(); | 1184 for (var i = 0; i < links.length; ++i) { |
| 613 } | 1185 formattedResult.appendChild(WebInspector.linkifyStringAsFragment(string.su
bstring(start, links[i].positionLeft))); |
| 614 | 1186 formattedResult.appendChild(this._linkifier.linkifyScriptLocation( |
| 615 /** | 1187 target, null, links[i].url, links[i].lineNumber, links[i].columnNumber
)); |
| 616 * @this {WebInspector.ConsoleViewMessage} | 1188 start = links[i].positionRight; |
| 617 */ | 1189 } |
| 618 function failedToRender() | 1190 |
| 619 { | 1191 if (start !== string.length) |
| 620 result.appendChild(this._formatParameterAsObject(object, false)); | 1192 formattedResult.appendChild(WebInspector.linkifyStringAsFragment(string.su
bstring(start))); |
| 621 } | 1193 |
| 622 }, | 1194 return formattedResult; |
| 623 | 1195 } |
| 624 _formattedParameterAsNodeForTest: function() | |
| 625 { | |
| 626 }, | |
| 627 | |
| 628 /** | |
| 629 * @param {!WebInspector.RemoteObject} array | |
| 630 * @return {!Element} | |
| 631 */ | |
| 632 _formatParameterAsArray: function(array) | |
| 633 { | |
| 634 var usePrintedArrayFormat = this._message.type !== WebInspector.ConsoleM
essage.MessageType.DirXML && this._message.type !== WebInspector.ConsoleMessage.
MessageType.Result; | |
| 635 var isLongArray = array.arrayLength() > 100; | |
| 636 if (usePrintedArrayFormat || isLongArray) | |
| 637 return this._formatParameterAsObject(array, usePrintedArrayFormat ||
!isLongArray); | |
| 638 var result = createElement("span"); | |
| 639 array.getAllProperties(false, printArrayResult.bind(this)); | |
| 640 return result; | |
| 641 | |
| 642 /** | |
| 643 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties | |
| 644 * @this {!WebInspector.ConsoleViewMessage} | |
| 645 */ | |
| 646 function printArrayResult(properties) | |
| 647 { | |
| 648 if (!properties) { | |
| 649 result.appendChild(this._formatParameterAsObject(array, false)); | |
| 650 return; | |
| 651 } | |
| 652 | |
| 653 var titleElement = createElement("span"); | |
| 654 var elements = {}; | |
| 655 for (var i = 0; i < properties.length; ++i) { | |
| 656 var property = properties[i]; | |
| 657 var name = property.name; | |
| 658 if (isNaN(name)) | |
| 659 continue; | |
| 660 if (property.getter) | |
| 661 elements[name] = this._formatAsAccessorProperty(array, [name
], true); | |
| 662 else if (property.value) | |
| 663 elements[name] = this._formatAsArrayEntry(property.value); | |
| 664 } | |
| 665 | |
| 666 titleElement.createTextChild("["); | |
| 667 var lastNonEmptyIndex = -1; | |
| 668 | |
| 669 function appendUndefined(titleElement, index) | |
| 670 { | |
| 671 if (index - lastNonEmptyIndex <= 1) | |
| 672 return; | |
| 673 var span = titleElement.createChild("span", "object-value-undefi
ned"); | |
| 674 span.textContent = WebInspector.UIString("undefined × %d", index
- lastNonEmptyIndex - 1); | |
| 675 } | |
| 676 | |
| 677 var length = array.arrayLength(); | |
| 678 for (var i = 0; i < length; ++i) { | |
| 679 var element = elements[i]; | |
| 680 if (!element) | |
| 681 continue; | |
| 682 | |
| 683 if (i - lastNonEmptyIndex > 1) { | |
| 684 appendUndefined(titleElement, i); | |
| 685 titleElement.createTextChild(", "); | |
| 686 } | |
| 687 | |
| 688 titleElement.appendChild(element); | |
| 689 lastNonEmptyIndex = i; | |
| 690 if (i < length - 1) | |
| 691 titleElement.createTextChild(", "); | |
| 692 } | |
| 693 appendUndefined(titleElement, length); | |
| 694 | |
| 695 titleElement.createTextChild("]"); | |
| 696 | |
| 697 var section = new WebInspector.ObjectPropertiesSection(array, titleE
lement, this._linkifier); | |
| 698 section.element.classList.add("console-view-object-properties-sectio
n"); | |
| 699 section.enableContextMenu(); | |
| 700 result.appendChild(section.element); | |
| 701 } | |
| 702 }, | |
| 703 | |
| 704 /** | |
| 705 * @param {!WebInspector.RemoteObject} output | |
| 706 * @return {!Element} | |
| 707 */ | |
| 708 _formatParameterAsString: function(output) | |
| 709 { | |
| 710 var span = createElement("span"); | |
| 711 span.appendChild(WebInspector.linkifyStringAsFragment(output.description
|| "")); | |
| 712 | |
| 713 var result = createElement("span"); | |
| 714 result.createChild("span", "object-value-string-quote").textContent = "\
""; | |
| 715 result.appendChild(span); | |
| 716 result.createChild("span", "object-value-string-quote").textContent = "\
""; | |
| 717 return result; | |
| 718 }, | |
| 719 | |
| 720 /** | |
| 721 * @param {!WebInspector.RemoteObject} output | |
| 722 * @return {!Element} | |
| 723 */ | |
| 724 _formatParameterAsError: function(output) | |
| 725 { | |
| 726 var result = createElement("span"); | |
| 727 var errorSpan = this._tryFormatAsError(output.description || ""); | |
| 728 result.appendChild(errorSpan ? errorSpan : WebInspector.linkifyStringAsF
ragment(output.description || "")); | |
| 729 return result; | |
| 730 }, | |
| 731 | |
| 732 /** | |
| 733 * @param {!WebInspector.RemoteObject} output | |
| 734 * @return {!Element} | |
| 735 */ | |
| 736 _formatAsArrayEntry: function(output) | |
| 737 { | |
| 738 return this._previewFormatter.renderPropertyPreview(output.type, output.
subtype, output.description); | |
| 739 }, | |
| 740 | |
| 741 /** | |
| 742 * @param {?WebInspector.RemoteObject} object | |
| 743 * @param {!Array.<string>} propertyPath | |
| 744 * @param {boolean} isArrayEntry | |
| 745 * @return {!Element} | |
| 746 */ | |
| 747 _formatAsAccessorProperty: function(object, propertyPath, isArrayEntry) | |
| 748 { | |
| 749 var rootElement = WebInspector.ObjectPropertyTreeElement.createRemoteObj
ectAccessorPropertySpan(object, propertyPath, onInvokeGetterClick.bind(this)); | |
| 750 | |
| 751 /** | |
| 752 * @param {?WebInspector.RemoteObject} result | |
| 753 * @param {boolean=} wasThrown | |
| 754 * @this {WebInspector.ConsoleViewMessage} | |
| 755 */ | |
| 756 function onInvokeGetterClick(result, wasThrown) | |
| 757 { | |
| 758 if (!result) | |
| 759 return; | |
| 760 rootElement.removeChildren(); | |
| 761 if (wasThrown) { | |
| 762 var element = rootElement.createChild("span"); | |
| 763 element.textContent = WebInspector.UIString("<exception>"); | |
| 764 element.title = /** @type {string} */ (result.description); | |
| 765 } else if (isArrayEntry) { | |
| 766 rootElement.appendChild(this._formatAsArrayEntry(result)); | |
| 767 } else { | |
| 768 // Make a PropertyPreview from the RemoteObject similar to the b
ackend logic. | |
| 769 const maxLength = 100; | |
| 770 var type = result.type; | |
| 771 var subtype = result.subtype; | |
| 772 var description = ""; | |
| 773 if (type !== "function" && result.description) { | |
| 774 if (type === "string" || subtype === "regexp") | |
| 775 description = result.description.trimMiddle(maxLength); | |
| 776 else | |
| 777 description = result.description.trimEnd(maxLength); | |
| 778 } | |
| 779 rootElement.appendChild(this._previewFormatter.renderPropertyPre
view(type, subtype, description)); | |
| 780 } | |
| 781 } | |
| 782 | |
| 783 return rootElement; | |
| 784 }, | |
| 785 | |
| 786 /** | |
| 787 * @param {string} format | |
| 788 * @param {!Array.<!WebInspector.RemoteObject>} parameters | |
| 789 * @param {!Element} formattedResult | |
| 790 */ | |
| 791 _formatWithSubstitutionString: function(format, parameters, formattedResult) | |
| 792 { | |
| 793 var formatters = {}; | |
| 794 | |
| 795 /** | |
| 796 * @param {boolean} force | |
| 797 * @param {!WebInspector.RemoteObject} obj | |
| 798 * @return {!Element} | |
| 799 * @this {WebInspector.ConsoleViewMessage} | |
| 800 */ | |
| 801 function parameterFormatter(force, obj) | |
| 802 { | |
| 803 return this._formatParameter(obj, force, false); | |
| 804 } | |
| 805 | |
| 806 function stringFormatter(obj) | |
| 807 { | |
| 808 return obj.description; | |
| 809 } | |
| 810 | |
| 811 function floatFormatter(obj) | |
| 812 { | |
| 813 if (typeof obj.value !== "number") | |
| 814 return "NaN"; | |
| 815 return obj.value; | |
| 816 } | |
| 817 | |
| 818 function integerFormatter(obj) | |
| 819 { | |
| 820 if (typeof obj.value !== "number") | |
| 821 return "NaN"; | |
| 822 return Math.floor(obj.value); | |
| 823 } | |
| 824 | |
| 825 function bypassFormatter(obj) | |
| 826 { | |
| 827 return (obj instanceof Node) ? obj : ""; | |
| 828 } | |
| 829 | |
| 830 var currentStyle = null; | |
| 831 function styleFormatter(obj) | |
| 832 { | |
| 833 currentStyle = {}; | |
| 834 var buffer = createElement("span"); | |
| 835 buffer.setAttribute("style", obj.description); | |
| 836 for (var i = 0; i < buffer.style.length; i++) { | |
| 837 var property = buffer.style[i]; | |
| 838 if (isWhitelistedProperty(property)) | |
| 839 currentStyle[property] = buffer.style[property]; | |
| 840 } | |
| 841 } | |
| 842 | |
| 843 function isWhitelistedProperty(property) | |
| 844 { | |
| 845 var prefixes = ["background", "border", "color", "font", "line", "ma
rgin", "padding", "text", "-webkit-background", "-webkit-border", "-webkit-font"
, "-webkit-margin", "-webkit-padding", "-webkit-text"]; | |
| 846 for (var i = 0; i < prefixes.length; i++) { | |
| 847 if (property.startsWith(prefixes[i])) | |
| 848 return true; | |
| 849 } | |
| 850 return false; | |
| 851 } | |
| 852 | |
| 853 // Firebug uses %o for formatting objects. | |
| 854 formatters.o = parameterFormatter.bind(this, false); | |
| 855 formatters.s = stringFormatter; | |
| 856 formatters.f = floatFormatter; | |
| 857 // Firebug allows both %i and %d for formatting integers. | |
| 858 formatters.i = integerFormatter; | |
| 859 formatters.d = integerFormatter; | |
| 860 | |
| 861 // Firebug uses %c for styling the message. | |
| 862 formatters.c = styleFormatter; | |
| 863 | |
| 864 // Support %O to force object formatting, instead of the type-based %o f
ormatting. | |
| 865 formatters.O = parameterFormatter.bind(this, true); | |
| 866 | |
| 867 formatters._ = bypassFormatter; | |
| 868 | |
| 869 function append(a, b) | |
| 870 { | |
| 871 if (b instanceof Node) | |
| 872 a.appendChild(b); | |
| 873 else if (typeof b !== "undefined") { | |
| 874 var toAppend = WebInspector.linkifyStringAsFragment(String(b)); | |
| 875 if (currentStyle) { | |
| 876 var wrapper = createElement("span"); | |
| 877 wrapper.appendChild(toAppend); | |
| 878 applyCurrentStyle(wrapper); | |
| 879 for (var i = 0; i < wrapper.children.length; ++i) | |
| 880 applyCurrentStyle(wrapper.children[i]); | |
| 881 toAppend = wrapper; | |
| 882 } | |
| 883 a.appendChild(toAppend); | |
| 884 } | |
| 885 return a; | |
| 886 } | |
| 887 | |
| 888 /** | |
| 889 * @param {!Element} element | |
| 890 */ | |
| 891 function applyCurrentStyle(element) | |
| 892 { | |
| 893 for (var key in currentStyle) | |
| 894 element.style[key] = currentStyle[key]; | |
| 895 } | |
| 896 | |
| 897 // String.format does treat formattedResult like a Builder, result is an
object. | |
| 898 return String.format(format, parameters, formatters, formattedResult, ap
pend); | |
| 899 }, | |
| 900 | |
| 901 /** | |
| 902 * @return {boolean} | |
| 903 */ | |
| 904 matchesFilterRegex: function(regexObject) | |
| 905 { | |
| 906 regexObject.lastIndex = 0; | |
| 907 var text = this.contentElement().deepTextContent(); | |
| 908 return regexObject.test(text); | |
| 909 }, | |
| 910 | |
| 911 /** | |
| 912 * @param {boolean} show | |
| 913 */ | |
| 914 updateTimestamp: function(show) | |
| 915 { | |
| 916 if (!this._contentElement) | |
| 917 return; | |
| 918 | |
| 919 if (show && !this.timestampElement) { | |
| 920 this.timestampElement = createElementWithClass("span", "console-time
stamp"); | |
| 921 this.timestampElement.textContent = (new Date(this._message.timestam
p)).toConsoleTime() + " "; | |
| 922 this._contentElement.insertBefore(this.timestampElement, this._conte
ntElement.firstChild); | |
| 923 return; | |
| 924 } | |
| 925 | |
| 926 if (!show && this.timestampElement) { | |
| 927 this.timestampElement.remove(); | |
| 928 delete this.timestampElement; | |
| 929 } | |
| 930 }, | |
| 931 | |
| 932 /** | |
| 933 * @return {number} | |
| 934 */ | |
| 935 nestingLevel: function() | |
| 936 { | |
| 937 return this._nestingLevel; | |
| 938 }, | |
| 939 | |
| 940 resetCloseGroupDecorationCount: function() | |
| 941 { | |
| 942 if (!this._closeGroupDecorationCount) | |
| 943 return; | |
| 944 this._closeGroupDecorationCount = 0; | |
| 945 this._updateCloseGroupDecorations(); | |
| 946 }, | |
| 947 | |
| 948 incrementCloseGroupDecorationCount: function() | |
| 949 { | |
| 950 ++this._closeGroupDecorationCount; | |
| 951 this._updateCloseGroupDecorations(); | |
| 952 }, | |
| 953 | |
| 954 _updateCloseGroupDecorations: function() | |
| 955 { | |
| 956 if (!this._nestingLevelMarkers) | |
| 957 return; | |
| 958 for (var i = 0, n = this._nestingLevelMarkers.length; i < n; ++i) { | |
| 959 var marker = this._nestingLevelMarkers[i]; | |
| 960 marker.classList.toggle("group-closed", n - i <= this._closeGroupDec
orationCount); | |
| 961 } | |
| 962 }, | |
| 963 | |
| 964 /** | |
| 965 * @return {!Element} | |
| 966 */ | |
| 967 contentElement: function() | |
| 968 { | |
| 969 if (this._contentElement) | |
| 970 return this._contentElement; | |
| 971 | |
| 972 var contentElement = createElementWithClass("div", "console-message"); | |
| 973 this._contentElement = contentElement; | |
| 974 if (this._message.type === WebInspector.ConsoleMessage.MessageType.Start
Group || this._message.type === WebInspector.ConsoleMessage.MessageType.StartGro
upCollapsed) | |
| 975 contentElement.classList.add("console-group-title"); | |
| 976 | |
| 977 var formattedMessage; | |
| 978 var consoleMessage = this._message; | |
| 979 var target = consoleMessage.target(); | |
| 980 var shouldIncludeTrace = !!consoleMessage.stackTrace && (consoleMessage.
source === WebInspector.ConsoleMessage.MessageSource.Network || consoleMessage.l
evel === WebInspector.ConsoleMessage.MessageLevel.Error || consoleMessage.level
=== WebInspector.ConsoleMessage.MessageLevel.RevokedError || consoleMessage.type
=== WebInspector.ConsoleMessage.MessageType.Trace || consoleMessage.level === W
ebInspector.ConsoleMessage.MessageLevel.Warning); | |
| 981 if (target && shouldIncludeTrace) | |
| 982 formattedMessage = this._buildMessageWithStackTrace(consoleMessage,
target, this._linkifier); | |
| 983 else if (this._message.type === WebInspector.ConsoleMessage.MessageType.
Table) | |
| 984 formattedMessage = this._buildTableMessage(this._message); | |
| 985 else | |
| 986 formattedMessage = this._buildMessage(consoleMessage); | |
| 987 contentElement.appendChild(formattedMessage); | |
| 988 | |
| 989 this.updateTimestamp(WebInspector.moduleSetting("consoleTimestampsEnable
d").get()); | |
| 990 return this._contentElement; | |
| 991 }, | |
| 992 | |
| 993 /** | |
| 994 * @return {!Element} | |
| 995 */ | |
| 996 toMessageElement: function() | |
| 997 { | |
| 998 if (this._element) | |
| 999 return this._element; | |
| 1000 | |
| 1001 this._element = createElement("div"); | |
| 1002 this.updateMessageElement(); | |
| 1003 return this._element; | |
| 1004 }, | |
| 1005 | |
| 1006 updateMessageElement: function() | |
| 1007 { | |
| 1008 if (!this._element) | |
| 1009 return; | |
| 1010 | |
| 1011 this._element.className = "console-message-wrapper"; | |
| 1012 this._element.removeChildren(); | |
| 1013 | |
| 1014 this._nestingLevelMarkers = []; | |
| 1015 for (var i = 0; i < this._nestingLevel; ++i) | |
| 1016 this._nestingLevelMarkers.push(this._element.createChild("div", "nes
ting-level-marker")); | |
| 1017 this._updateCloseGroupDecorations(); | |
| 1018 this._element.message = this; | |
| 1019 | |
| 1020 switch (this._message.level) { | |
| 1021 case WebInspector.ConsoleMessage.MessageLevel.Log: | |
| 1022 this._element.classList.add("console-log-level"); | |
| 1023 break; | |
| 1024 case WebInspector.ConsoleMessage.MessageLevel.Debug: | |
| 1025 this._element.classList.add("console-debug-level"); | |
| 1026 break; | |
| 1027 case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
| 1028 this._element.classList.add("console-warning-level"); | |
| 1029 break; | |
| 1030 case WebInspector.ConsoleMessage.MessageLevel.Error: | |
| 1031 this._element.classList.add("console-error-level"); | |
| 1032 break; | |
| 1033 case WebInspector.ConsoleMessage.MessageLevel.RevokedError: | |
| 1034 this._element.classList.add("console-revokedError-level"); | |
| 1035 break; | |
| 1036 case WebInspector.ConsoleMessage.MessageLevel.Info: | |
| 1037 this._element.classList.add("console-info-level"); | |
| 1038 break; | |
| 1039 } | |
| 1040 | |
| 1041 this._element.appendChild(this.contentElement()); | |
| 1042 if (this._repeatCount > 1) | |
| 1043 this._showRepeatCountElement(); | |
| 1044 }, | |
| 1045 | |
| 1046 /** | |
| 1047 * @return {number} | |
| 1048 */ | |
| 1049 repeatCount: function() | |
| 1050 { | |
| 1051 return this._repeatCount || 1; | |
| 1052 }, | |
| 1053 | |
| 1054 resetIncrementRepeatCount: function() | |
| 1055 { | |
| 1056 this._repeatCount = 1; | |
| 1057 if (!this._repeatCountElement) | |
| 1058 return; | |
| 1059 | |
| 1060 this._repeatCountElement.remove(); | |
| 1061 delete this._repeatCountElement; | |
| 1062 }, | |
| 1063 | |
| 1064 incrementRepeatCount: function() | |
| 1065 { | |
| 1066 this._repeatCount++; | |
| 1067 this._showRepeatCountElement(); | |
| 1068 }, | |
| 1069 | |
| 1070 _showRepeatCountElement: function() | |
| 1071 { | |
| 1072 if (!this._contentElement) | |
| 1073 return; | |
| 1074 | |
| 1075 if (!this._repeatCountElement) { | |
| 1076 this._repeatCountElement = createElementWithClass("label", "console-
message-repeat-count", "dt-small-bubble"); | |
| 1077 switch (this._message.level) { | |
| 1078 case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
| 1079 this._repeatCountElement.type = "warning"; | |
| 1080 break; | |
| 1081 case WebInspector.ConsoleMessage.MessageLevel.Error: | |
| 1082 this._repeatCountElement.type = "error"; | |
| 1083 break; | |
| 1084 case WebInspector.ConsoleMessage.MessageLevel.Debug: | |
| 1085 this._repeatCountElement.type = "debug"; | |
| 1086 break; | |
| 1087 default: | |
| 1088 this._repeatCountElement.type = "info"; | |
| 1089 } | |
| 1090 this._element.insertBefore(this._repeatCountElement, this._contentEl
ement); | |
| 1091 this._contentElement.classList.add("repeated-message"); | |
| 1092 } | |
| 1093 this._repeatCountElement.textContent = this._repeatCount; | |
| 1094 }, | |
| 1095 | |
| 1096 get text() | |
| 1097 { | |
| 1098 return this._message.messageText; | |
| 1099 }, | |
| 1100 | |
| 1101 /** | |
| 1102 * @param {?RegExp} regex | |
| 1103 */ | |
| 1104 setSearchRegex: function(regex) | |
| 1105 { | |
| 1106 if (this._searchHiglightNodeChanges && this._searchHiglightNodeChanges.l
ength) | |
| 1107 WebInspector.revertDomChanges(this._searchHiglightNodeChanges); | |
| 1108 this._searchRegex = regex; | |
| 1109 this._searchHighlightNodes = []; | |
| 1110 this._searchHiglightNodeChanges = []; | |
| 1111 if (!this._searchRegex) | |
| 1112 return; | |
| 1113 | |
| 1114 var text = this.contentElement().deepTextContent(); | |
| 1115 var match; | |
| 1116 this._searchRegex.lastIndex = 0; | |
| 1117 var sourceRanges = []; | |
| 1118 while ((match = this._searchRegex.exec(text)) && match[0]) | |
| 1119 sourceRanges.push(new WebInspector.SourceRange(match.index, match[0]
.length)); | |
| 1120 | |
| 1121 if (sourceRanges.length) | |
| 1122 this._searchHighlightNodes = WebInspector.highlightSearchResults(thi
s.contentElement(), sourceRanges, this._searchHiglightNodeChanges); | |
| 1123 }, | |
| 1124 | |
| 1125 /** | |
| 1126 * @return {?RegExp} | |
| 1127 */ | |
| 1128 searchRegex: function() | |
| 1129 { | |
| 1130 return this._searchRegex; | |
| 1131 }, | |
| 1132 | |
| 1133 /** | |
| 1134 * @return {number} | |
| 1135 */ | |
| 1136 searchCount: function() | |
| 1137 { | |
| 1138 return this._searchHighlightNodes.length; | |
| 1139 }, | |
| 1140 | |
| 1141 /** | |
| 1142 * @return {!Element} | |
| 1143 */ | |
| 1144 searchHighlightNode: function(index) | |
| 1145 { | |
| 1146 return this._searchHighlightNodes[index]; | |
| 1147 }, | |
| 1148 | |
| 1149 /** | |
| 1150 * @param {string} string | |
| 1151 * @return {?Element} | |
| 1152 */ | |
| 1153 _tryFormatAsError: function(string) | |
| 1154 { | |
| 1155 /** | |
| 1156 * @param {string} prefix | |
| 1157 */ | |
| 1158 function startsWith(prefix) | |
| 1159 { | |
| 1160 return string.startsWith(prefix); | |
| 1161 } | |
| 1162 | |
| 1163 var errorPrefixes = ["EvalError", "ReferenceError", "SyntaxError", "Type
Error", "RangeError", "Error", "URIError"]; | |
| 1164 var target = this._target(); | |
| 1165 if (!target || !errorPrefixes.some(startsWith)) | |
| 1166 return null; | |
| 1167 var debuggerModel = WebInspector.DebuggerModel.fromTarget(target); | |
| 1168 if (!debuggerModel) | |
| 1169 return null; | |
| 1170 | |
| 1171 var lines = string.split("\n"); | |
| 1172 var links = []; | |
| 1173 var position = 0; | |
| 1174 for (var i = 0; i < lines.length; ++i) { | |
| 1175 position += i > 0 ? lines[i - 1].length + 1 : 0; | |
| 1176 var isCallFrameLine = /^\s*at\s/.test(lines[i]); | |
| 1177 if (!isCallFrameLine && links.length) | |
| 1178 return null; | |
| 1179 | |
| 1180 if (!isCallFrameLine) | |
| 1181 continue; | |
| 1182 | |
| 1183 var openBracketIndex = -1; | |
| 1184 var closeBracketIndex = -1; | |
| 1185 var match = /\([^\)\(]+\)/.exec(lines[i]); | |
| 1186 if (match) { | |
| 1187 openBracketIndex = match.index; | |
| 1188 closeBracketIndex = match.index + match[0].length - 1; | |
| 1189 } | |
| 1190 var hasOpenBracket = openBracketIndex !== -1; | |
| 1191 var left = hasOpenBracket ? openBracketIndex + 1 : lines[i].indexOf(
"at") + 3; | |
| 1192 var right = hasOpenBracket ? closeBracketIndex : lines[i].length; | |
| 1193 var linkCandidate = lines[i].substring(left, right); | |
| 1194 var splitResult = WebInspector.ParsedURL.splitLineAndColumn(linkCand
idate); | |
| 1195 if (!splitResult) | |
| 1196 return null; | |
| 1197 | |
| 1198 var parsed = splitResult.url.asParsedURL(); | |
| 1199 var url; | |
| 1200 if (parsed) | |
| 1201 url = parsed.url; | |
| 1202 else if (debuggerModel.scriptsForSourceURL(splitResult.url).length) | |
| 1203 url = splitResult.url; | |
| 1204 else if (splitResult.url === "<anonymous>") | |
| 1205 continue; | |
| 1206 else | |
| 1207 return null; | |
| 1208 | |
| 1209 links.push({url: url, positionLeft: position + left, positionRight:
position + right, lineNumber: splitResult.lineNumber, columnNumber: splitResult.
columnNumber}); | |
| 1210 } | |
| 1211 | |
| 1212 if (!links.length) | |
| 1213 return null; | |
| 1214 | |
| 1215 var formattedResult = createElement("span"); | |
| 1216 var start = 0; | |
| 1217 for (var i = 0; i < links.length; ++i) { | |
| 1218 formattedResult.appendChild(WebInspector.linkifyStringAsFragment(str
ing.substring(start, links[i].positionLeft))); | |
| 1219 formattedResult.appendChild(this._linkifier.linkifyScriptLocation(ta
rget, null, links[i].url, links[i].lineNumber, links[i].columnNumber)); | |
| 1220 start = links[i].positionRight; | |
| 1221 } | |
| 1222 | |
| 1223 if (start !== string.length) | |
| 1224 formattedResult.appendChild(WebInspector.linkifyStringAsFragment(str
ing.substring(start))); | |
| 1225 | |
| 1226 return formattedResult; | |
| 1227 } | |
| 1228 }; | 1196 }; |
| 1229 | 1197 |
| 1230 /** | 1198 /** |
| 1231 * @constructor | 1199 * @unrestricted |
| 1232 * @extends {WebInspector.ConsoleViewMessage} | |
| 1233 * @param {!WebInspector.ConsoleMessage} consoleMessage | |
| 1234 * @param {!WebInspector.Linkifier} linkifier | |
| 1235 * @param {number} nestingLevel | |
| 1236 */ | 1200 */ |
| 1237 WebInspector.ConsoleGroupViewMessage = function(consoleMessage, linkifier, nesti
ngLevel) | 1201 WebInspector.ConsoleGroupViewMessage = class extends WebInspector.ConsoleViewMes
sage { |
| 1238 { | 1202 /** |
| 1203 * @param {!WebInspector.ConsoleMessage} consoleMessage |
| 1204 * @param {!WebInspector.Linkifier} linkifier |
| 1205 * @param {number} nestingLevel |
| 1206 */ |
| 1207 constructor(consoleMessage, linkifier, nestingLevel) { |
| 1239 console.assert(consoleMessage.isGroupStartMessage()); | 1208 console.assert(consoleMessage.isGroupStartMessage()); |
| 1240 WebInspector.ConsoleViewMessage.call(this, consoleMessage, linkifier, nestin
gLevel); | 1209 super(consoleMessage, linkifier, nestingLevel); |
| 1241 this.setCollapsed(consoleMessage.type === WebInspector.ConsoleMessage.Messag
eType.StartGroupCollapsed); | 1210 this.setCollapsed(consoleMessage.type === WebInspector.ConsoleMessage.Messag
eType.StartGroupCollapsed); |
| 1211 } |
| 1212 |
| 1213 /** |
| 1214 * @param {boolean} collapsed |
| 1215 */ |
| 1216 setCollapsed(collapsed) { |
| 1217 this._collapsed = collapsed; |
| 1218 if (this._element) |
| 1219 this._element.classList.toggle('collapsed', this._collapsed); |
| 1220 } |
| 1221 |
| 1222 /** |
| 1223 * @return {boolean} |
| 1224 */ |
| 1225 collapsed() { |
| 1226 return this._collapsed; |
| 1227 } |
| 1228 |
| 1229 /** |
| 1230 * @override |
| 1231 * @return {!Element} |
| 1232 */ |
| 1233 toMessageElement() { |
| 1234 if (!this._element) { |
| 1235 super.toMessageElement(); |
| 1236 this._element.classList.toggle('collapsed', this._collapsed); |
| 1237 } |
| 1238 return this._element; |
| 1239 } |
| 1242 }; | 1240 }; |
| 1243 | |
| 1244 WebInspector.ConsoleGroupViewMessage.prototype = { | |
| 1245 /** | |
| 1246 * @param {boolean} collapsed | |
| 1247 */ | |
| 1248 setCollapsed: function(collapsed) | |
| 1249 { | |
| 1250 this._collapsed = collapsed; | |
| 1251 if (this._element) | |
| 1252 this._element.classList.toggle("collapsed", this._collapsed); | |
| 1253 }, | |
| 1254 | |
| 1255 /** | |
| 1256 * @return {boolean} | |
| 1257 */ | |
| 1258 collapsed: function() | |
| 1259 { | |
| 1260 return this._collapsed; | |
| 1261 }, | |
| 1262 | |
| 1263 /** | |
| 1264 * @override | |
| 1265 * @return {!Element} | |
| 1266 */ | |
| 1267 toMessageElement: function() | |
| 1268 { | |
| 1269 if (!this._element) { | |
| 1270 WebInspector.ConsoleViewMessage.prototype.toMessageElement.call(this
); | |
| 1271 this._element.classList.toggle("collapsed", this._collapsed); | |
| 1272 } | |
| 1273 return this._element; | |
| 1274 }, | |
| 1275 | |
| 1276 __proto__: WebInspector.ConsoleViewMessage.prototype | |
| 1277 }; | |
| OLD | NEW |