Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698