1/* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved. 4 * Copyright (C) 2009 Joseph Pecoraro 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31WebInspector.ConsoleMessageImpl = function(source, level, message, linkifier, type, url, line, column, repeatCount, parameters, stackTrace, request) 32{ 33 WebInspector.ConsoleMessage.call(this, source, level, url, line, column, repeatCount); 34 35 this._linkifier = linkifier; 36 this.type = type || WebInspector.ConsoleMessage.MessageType.Log; 37 this._messageText = message; 38 this._parameters = parameters; 39 this._stackTrace = stackTrace; 40 this._request = request; 41 42 this._customFormatters = { 43 "object": this._formatParameterAsObject, 44 "array": this._formatParameterAsArray, 45 "node": this._formatParameterAsNode, 46 "string": this._formatParameterAsString 47 }; 48} 49 50WebInspector.ConsoleMessageImpl.prototype = { 51 52 enforcesClipboardPrefixString: true, 53 54 _formatMessage: function() 55 { 56 this._formattedMessage = document.createElement("span"); 57 this._formattedMessage.className = "console-message-text source-code"; 58 59 var messageText; 60 if (this.source === WebInspector.ConsoleMessage.MessageSource.ConsoleAPI) { 61 switch (this.type) { 62 case WebInspector.ConsoleMessage.MessageType.Trace: 63 messageText = document.createTextNode("console.trace()"); 64 break; 65 case WebInspector.ConsoleMessage.MessageType.Assert: 66 var args = [WebInspector.UIString("Assertion failed:")]; 67 if (this._parameters) 68 args = args.concat(this._parameters); 69 messageText = this._format(args); 70 break; 71 case WebInspector.ConsoleMessage.MessageType.Dir: 72 var obj = this._parameters ? this._parameters[0] : undefined; 73 var args = ["%O", obj]; 74 messageText = this._format(args); 75 break; 76 default: 77 var args = this._parameters || [this._messageText]; 78 messageText = this._format(args); 79 } 80 } else if (this.source === WebInspector.ConsoleMessage.MessageSource.Network) { 81 if (this._request) { 82 this._stackTrace = this._request.stackTrace; 83 if (this._request.initiator && this._request.initiator.url) { 84 this.url = this._request.initiator.url; 85 this.line = this._request.initiator.lineNumber; 86 } 87 messageText = document.createElement("span"); 88 if (this.level === WebInspector.ConsoleMessage.MessageLevel.Error) { 89 messageText.appendChild(document.createTextNode(this._request.requestMethod + " ")); 90 messageText.appendChild(WebInspector.linkifyRequestAsNode(this._request)); 91 if (this._request.failed) 92 messageText.appendChild(document.createTextNode(" " + this._request.localizedFailDescription)); 93 else 94 messageText.appendChild(document.createTextNode(" " + this._request.statusCode + " (" + this._request.statusText + ")")); 95 } else { 96 var fragment = WebInspector.linkifyStringAsFragmentWithCustomLinkifier(this._messageText, WebInspector.linkifyRequestAsNode.bind(null, this._request, "")); 97 messageText.appendChild(fragment); 98 } 99 } else { 100 if (this.url) { 101 var anchor = WebInspector.linkifyURLAsNode(this.url, this.url, "console-message-url"); 102 this._formattedMessage.appendChild(anchor); 103 } 104 messageText = this._format([this._messageText]); 105 } 106 } else { 107 var args = this._parameters || [this._messageText]; 108 messageText = this._format(args); 109 } 110 111 if (this.source !== WebInspector.ConsoleMessage.MessageSource.Network || this._request) { 112 var firstNonNativeCallFrame = this._firstNonNativeCallFrame(); 113 if (firstNonNativeCallFrame) { 114 var urlElement = this._linkifyCallFrame(firstNonNativeCallFrame); 115 this._formattedMessage.appendChild(urlElement); 116 } else if (this.url && !this._shouldHideURL(this.url)) { 117 var urlElement = this._linkifyLocation(this.url, this.line, this.column); 118 this._formattedMessage.appendChild(urlElement); 119 } 120 } 121 122 this._formattedMessage.appendChild(messageText); 123 124 if (this._shouldDumpStackTrace()) { 125 var ol = document.createElement("ol"); 126 ol.className = "outline-disclosure"; 127 var treeOutline = new TreeOutline(ol); 128 129 var content = this._formattedMessage; 130 var root = new TreeElement(content, null, true); 131 content.treeElementForTest = root; 132 treeOutline.appendChild(root); 133 if (this.type === WebInspector.ConsoleMessage.MessageType.Trace) 134 root.expand(); 135 136 this._populateStackTraceTreeElement(root); 137 this._formattedMessage = ol; 138 } 139 140 // This is used for inline message bubbles in SourceFrames, or other plain-text representations. 141 this._message = messageText.textContent; 142 }, 143 144 _shouldDumpStackTrace: function() 145 { 146 return !!this._stackTrace && this._stackTrace.length && (this.source === WebInspector.ConsoleMessage.MessageSource.Network || this.level === WebInspector.ConsoleMessage.MessageLevel.Error || this.type === WebInspector.ConsoleMessage.MessageType.Trace); 147 }, 148 149 _shouldHideURL: function(url) 150 { 151 return url === "undefined" || url === "[native code]"; 152 }, 153 154 _firstNonNativeCallFrame: function() 155 { 156 if (!this._stackTrace) 157 return null; 158 159 for (var i = 0; i < this._stackTrace.length; i++) { 160 var frame = this._stackTrace[i]; 161 if (!frame.url || frame.url === "[native code]") 162 continue; 163 return frame; 164 } 165 166 return null; 167 }, 168 169 get message() 170 { 171 // force message formatting 172 var formattedMessage = this.formattedMessage; 173 return this._message; 174 }, 175 176 get formattedMessage() 177 { 178 if (!this._formattedMessage) 179 this._formatMessage(); 180 return this._formattedMessage; 181 }, 182 183 _linkifyLocation: function(url, lineNumber, columnNumber) 184 { 185 // ConsoleMessage stack trace line numbers are one-based. 186 lineNumber = lineNumber ? lineNumber - 1 : 0; 187 188 return WebInspector.linkifyLocation(url, lineNumber, columnNumber, "console-message-url"); 189 }, 190 191 _linkifyCallFrame: function(callFrame) 192 { 193 return this._linkifyLocation(callFrame.url, callFrame.lineNumber, callFrame.columnNumber); 194 }, 195 196 isErrorOrWarning: function() 197 { 198 return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error); 199 }, 200 201 _format: function(parameters) 202 { 203 // This node is used like a Builder. Values are continually appended onto it. 204 var formattedResult = document.createElement("span"); 205 if (!parameters.length) 206 return formattedResult; 207 208 // Formatting code below assumes that parameters are all wrappers whereas frontend console 209 // API allows passing arbitrary values as messages (strings, numbers, etc.). Wrap them here. 210 for (var i = 0; i < parameters.length; ++i) { 211 // FIXME: Only pass runtime wrappers here. 212 if (parameters[i] instanceof WebInspector.RemoteObject) 213 continue; 214 215 if (typeof parameters[i] === "object") 216 parameters[i] = WebInspector.RemoteObject.fromPayload(parameters[i]); 217 else 218 parameters[i] = WebInspector.RemoteObject.fromPrimitiveValue(parameters[i]); 219 } 220 221 // There can be string log and string eval result. We distinguish between them based on message type. 222 var shouldFormatMessage = WebInspector.RemoteObject.type(parameters[0]) === "string" && this.type !== WebInspector.ConsoleMessage.MessageType.Result; 223 224 // Multiple parameters with the first being a format string. Save unused substitutions. 225 if (shouldFormatMessage) { 226 // Multiple parameters with the first being a format string. Save unused substitutions. 227 var result = this._formatWithSubstitutionString(parameters, formattedResult); 228 parameters = result.unusedSubstitutions; 229 if (parameters.length) 230 formattedResult.appendChild(document.createTextNode(" ")); 231 } 232 233 // Single parameter, or unused substitutions from above. 234 for (var i = 0; i < parameters.length; ++i) { 235 // Inline strings when formatting. 236 if (shouldFormatMessage && parameters[i].type === "string") 237 formattedResult.appendChild(document.createTextNode(parameters[i].description)); 238 else 239 formattedResult.appendChild(this._formatParameter(parameters[i])); 240 if (i < parameters.length - 1) 241 formattedResult.appendChild(document.createTextNode(" ")); 242 } 243 return formattedResult; 244 }, 245 246 _formatParameter: function(output, forceObjectFormat) 247 { 248 var type; 249 if (forceObjectFormat) 250 type = "object"; 251 else if (output instanceof WebInspector.RemoteObject) 252 type = output.subtype || output.type; 253 else 254 type = typeof output; 255 256 var formatter = this._customFormatters[type]; 257 if (!formatter) { 258 formatter = this._formatParameterAsValue; 259 output = output.description; 260 } 261 262 var span = document.createElement("span"); 263 span.className = "console-formatted-" + type + " source-code"; 264 formatter.call(this, output, span); 265 return span; 266 }, 267 268 _formatParameterAsValue: function(val, elem) 269 { 270 elem.appendChild(document.createTextNode(val)); 271 }, 272 273 _formatParameterAsObject: function(obj, elem) 274 { 275 elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, obj.description).element); 276 }, 277 278 _formatParameterAsNode: function(object, elem) 279 { 280 function printNode(nodeId) 281 { 282 if (!nodeId) { 283 // Sometimes DOM is loaded after the sync message is being formatted, so we get no 284 // nodeId here. So we fall back to object formatting here. 285 this._formatParameterAsObject(object, elem); 286 return; 287 } 288 var treeOutline = new WebInspector.DOMTreeOutline(false, false, true); 289 treeOutline.setVisible(true); 290 treeOutline.rootDOMNode = WebInspector.domTreeManager.nodeForId(nodeId); 291 treeOutline.element.classList.add("outline-disclosure"); 292 if (!treeOutline.children[0].hasChildren) 293 treeOutline.element.classList.add("single-node"); 294 elem.appendChild(treeOutline.element); 295 } 296 object.pushNodeToFrontend(printNode.bind(this)); 297 }, 298 299 _formatParameterAsArray: function(arr, elem) 300 { 301 arr.getOwnProperties(this._printArray.bind(this, arr, elem)); 302 }, 303 304 _formatParameterAsString: function(output, elem) 305 { 306 var span = document.createElement("span"); 307 span.className = "console-formatted-string source-code"; 308 span.appendChild(WebInspector.linkifyStringAsFragment(output.description)); 309 310 // Make black quotes. 311 elem.classList.remove("console-formatted-string"); 312 elem.appendChild(document.createTextNode("\"")); 313 elem.appendChild(span); 314 elem.appendChild(document.createTextNode("\"")); 315 }, 316 317 _printArray: function(array, elem, properties) 318 { 319 if (!properties) 320 return; 321 322 var elements = []; 323 for (var i = 0; i < properties.length; ++i) { 324 var property = properties[i]; 325 var name = property.name; 326 if (!isNaN(name)) 327 elements[name] = this._formatAsArrayEntry(property.value); 328 } 329 330 elem.appendChild(document.createTextNode("[")); 331 var lastNonEmptyIndex = -1; 332 333 function appendUndefined(elem, index) 334 { 335 if (index - lastNonEmptyIndex <= 1) 336 return; 337 var span = elem.createChild("span", "console-formatted-undefined"); 338 span.textContent = WebInspector.UIString("undefined × %d").format(index - lastNonEmptyIndex - 1); 339 } 340 341 var length = array.arrayLength(); 342 for (var i = 0; i < length; ++i) { 343 var element = elements[i]; 344 if (!element) 345 continue; 346 347 if (i - lastNonEmptyIndex > 1) { 348 appendUndefined(elem, i); 349 elem.appendChild(document.createTextNode(", ")); 350 } 351 352 elem.appendChild(element); 353 lastNonEmptyIndex = i; 354 if (i < length - 1) 355 elem.appendChild(document.createTextNode(", ")); 356 } 357 appendUndefined(elem, length); 358 359 elem.appendChild(document.createTextNode("]")); 360 }, 361 362 _formatAsArrayEntry: function(output) 363 { 364 // Prevent infinite expansion of cross-referencing arrays. 365 return this._formatParameter(output, output.subtype && output.subtype === "array"); 366 }, 367 368 _formatWithSubstitutionString: function(parameters, formattedResult) 369 { 370 var formatters = {}; 371 372 function parameterFormatter(force, obj) 373 { 374 return this._formatParameter(obj, force); 375 } 376 377 function stringFormatter(obj) 378 { 379 return obj.description; 380 } 381 382 function floatFormatter(obj) 383 { 384 if (typeof obj.value !== "number") 385 return parseFloat(obj.description); 386 return obj.value; 387 } 388 389 function integerFormatter(obj) 390 { 391 if (typeof obj.value !== "number") 392 return parseInt(obj.description); 393 return Math.floor(obj.value); 394 } 395 396 var currentStyle = null; 397 function styleFormatter(obj) 398 { 399 currentStyle = {}; 400 var buffer = document.createElement("span"); 401 buffer.setAttribute("style", obj.description); 402 for (var i = 0; i < buffer.style.length; i++) { 403 var property = buffer.style[i]; 404 if (isWhitelistedProperty(property)) 405 currentStyle[property] = buffer.style[property]; 406 } 407 } 408 409 function isWhitelistedProperty(property) 410 { 411 var prefixes = ["background", "border", "color", "font", "line", "margin", "padding", "text", "-webkit-background", "-webkit-border", "-webkit-font", "-webkit-margin", "-webkit-padding", "-webkit-text"]; 412 for (var i = 0; i < prefixes.length; i++) { 413 if (property.startsWith(prefixes[i])) 414 return true; 415 } 416 return false; 417 } 418 419 // Firebug uses %o for formatting objects. 420 formatters.o = parameterFormatter.bind(this, false); 421 formatters.s = stringFormatter; 422 formatters.f = floatFormatter; 423 424 // Firebug allows both %i and %d for formatting integers. 425 formatters.i = integerFormatter; 426 formatters.d = integerFormatter; 427 428 // Firebug uses %c for styling the message. 429 formatters.c = styleFormatter; 430 431 // Support %O to force object formatting, instead of the type-based %o formatting. 432 formatters.O = parameterFormatter.bind(this, true); 433 434 function append(a, b) 435 { 436 if (b instanceof Node) 437 a.appendChild(b); 438 else if (b) { 439 var toAppend = WebInspector.linkifyStringAsFragment(b.toString()); 440 if (currentStyle) { 441 var wrapper = document.createElement("span"); 442 for (var key in currentStyle) 443 wrapper.style[key] = currentStyle[key]; 444 wrapper.appendChild(toAppend); 445 toAppend = wrapper; 446 } 447 a.appendChild(toAppend); 448 } 449 return a; 450 } 451 452 // String.format does treat formattedResult like a Builder, result is an object. 453 return String.format(parameters[0].description, parameters.slice(1), formatters, formattedResult, append); 454 }, 455 456 clearHighlight: function() 457 { 458 if (!this._formattedMessage) 459 return; 460 461 var highlightedMessage = this._formattedMessage; 462 delete this._formattedMessage; 463 this._formatMessage(); 464 this._element.replaceChild(this._formattedMessage, highlightedMessage); 465 }, 466 467 highlightSearchResults: function(regexObject) 468 { 469 if (!this._formattedMessage) 470 return; 471 472 regexObject.lastIndex = 0; 473 var text = this.message; 474 var match = regexObject.exec(text); 475 var offset = 0; 476 var matchRanges = []; 477 while (match) { 478 matchRanges.push({ offset: match.index, length: match[0].length }); 479 match = regexObject.exec(text); 480 } 481 highlightSearchResults(this._formattedMessage, matchRanges); 482 this._element.scrollIntoViewIfNeeded(); 483 }, 484 485 matchesRegex: function(regexObject) 486 { 487 return regexObject.test(this.message); 488 }, 489 490 toMessageElement: function() 491 { 492 if (this._element) 493 return this._element; 494 495 var element = document.createElement("div"); 496 element.message = this; 497 element.className = "console-message"; 498 499 this._element = element; 500 501 switch (this.level) { 502 case WebInspector.ConsoleMessage.MessageLevel.Tip: 503 element.classList.add("console-tip-level"); 504 element.setAttribute("data-labelprefix", WebInspector.UIString("Tip: ")); 505 break; 506 case WebInspector.ConsoleMessage.MessageLevel.Log: 507 element.classList.add("console-log-level"); 508 element.setAttribute("data-labelprefix", WebInspector.UIString("Log: ")); 509 break; 510 case WebInspector.ConsoleMessage.MessageLevel.Debug: 511 element.classList.add("console-debug-level"); 512 element.setAttribute("data-labelprefix", WebInspector.UIString("Debug: ")); 513 break; 514 case WebInspector.ConsoleMessage.MessageLevel.Warning: 515 element.classList.add("console-warning-level"); 516 element.setAttribute("data-labelprefix", WebInspector.UIString("Warning: ")); 517 break; 518 case WebInspector.ConsoleMessage.MessageLevel.Error: 519 element.classList.add("console-error-level"); 520 element.setAttribute("data-labelprefix", WebInspector.UIString("Error: ")); 521 break; 522 } 523 524 if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup || this.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) 525 element.classList.add("console-group-title"); 526 527 element.appendChild(this.formattedMessage); 528 529 if (this.repeatCount > 1) 530 this.updateRepeatCount(); 531 532 return element; 533 }, 534 535 _populateStackTraceTreeElement: function(parentTreeElement) 536 { 537 for (var i = 0; i < this._stackTrace.length; i++) { 538 var frame = this._stackTrace[i]; 539 540 var content = document.createElement("div"); 541 var messageTextElement = document.createElement("span"); 542 messageTextElement.className = "console-message-text source-code"; 543 var functionName = frame.functionName || WebInspector.UIString("(anonymous function)"); 544 messageTextElement.appendChild(document.createTextNode(functionName)); 545 content.appendChild(messageTextElement); 546 547 if (frame.url && !this._shouldHideURL(frame.url)) { 548 var urlElement = this._linkifyCallFrame(frame); 549 content.appendChild(urlElement); 550 } 551 552 var treeElement = new TreeElement(content); 553 parentTreeElement.appendChild(treeElement); 554 } 555 }, 556 557 updateRepeatCount: function() { 558 if (!this.repeatCountElement) { 559 this.repeatCountElement = document.createElement("span"); 560 this.repeatCountElement.className = "bubble"; 561 562 this._element.insertBefore(this.repeatCountElement, this._element.firstChild); 563 } 564 this.repeatCountElement.textContent = this.repeatCount; 565 }, 566 567 toString: function() 568 { 569 var sourceString; 570 switch (this.source) { 571 case WebInspector.ConsoleMessage.MessageSource.HTML: 572 sourceString = "HTML"; 573 break; 574 case WebInspector.ConsoleMessage.MessageSource.XML: 575 sourceString = "XML"; 576 break; 577 case WebInspector.ConsoleMessage.MessageSource.JS: 578 sourceString = "JS"; 579 break; 580 case WebInspector.ConsoleMessage.MessageSource.Network: 581 sourceString = "Network"; 582 break; 583 case WebInspector.ConsoleMessage.MessageSource.ConsoleAPI: 584 sourceString = "ConsoleAPI"; 585 break; 586 case WebInspector.ConsoleMessage.MessageSource.Other: 587 sourceString = "Other"; 588 break; 589 } 590 591 var typeString; 592 switch (this.type) { 593 case WebInspector.ConsoleMessage.MessageType.Log: 594 typeString = "Log"; 595 break; 596 case WebInspector.ConsoleMessage.MessageType.Dir: 597 typeString = "Dir"; 598 break; 599 case WebInspector.ConsoleMessage.MessageType.DirXML: 600 typeString = "Dir XML"; 601 break; 602 case WebInspector.ConsoleMessage.MessageType.Trace: 603 typeString = "Trace"; 604 break; 605 case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed: 606 case WebInspector.ConsoleMessage.MessageType.StartGroup: 607 typeString = "Start Group"; 608 break; 609 case WebInspector.ConsoleMessage.MessageType.EndGroup: 610 typeString = "End Group"; 611 break; 612 case WebInspector.ConsoleMessage.MessageType.Assert: 613 typeString = "Assert"; 614 break; 615 case WebInspector.ConsoleMessage.MessageType.Result: 616 typeString = "Result"; 617 break; 618 } 619 620 return sourceString + " " + typeString + " " + this.levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line; 621 }, 622 623 get text() 624 { 625 return this._messageText; 626 }, 627 628 isEqual: function(msg) 629 { 630 if (!msg) 631 return false; 632 633 if (this._stackTrace) { 634 if (!msg._stackTrace) 635 return false; 636 var l = this._stackTrace; 637 var r = msg._stackTrace; 638 for (var i = 0; i < l.length; i++) { 639 if (l[i].url !== r[i].url || 640 l[i].functionName !== r[i].functionName || 641 l[i].lineNumber !== r[i].lineNumber || 642 l[i].columnNumber !== r[i].columnNumber) 643 return false; 644 } 645 } 646 647 return (this.source === msg.source) 648 && (this.type === msg.type) 649 && (this.level === msg.level) 650 && (this.line === msg.line) 651 && (this.url === msg.url) 652 && (this.message === msg.message) 653 && (this._request === msg._request); 654 }, 655 656 get stackTrace() 657 { 658 return this._stackTrace; 659 }, 660 661 clone: function() 662 { 663 return WebInspector.ConsoleMessage.create(this.source, this.level, this._messageText, this.type, this.url, this.line, this.column, this.repeatCount, this._parameters, this._stackTrace, this._request); 664 }, 665 666 get levelString() 667 { 668 switch (this.level) { 669 case WebInspector.ConsoleMessage.MessageLevel.Tip: 670 return "Tip"; 671 case WebInspector.ConsoleMessage.MessageLevel.Log: 672 return "Log"; 673 case WebInspector.ConsoleMessage.MessageLevel.Warning: 674 return "Warning"; 675 case WebInspector.ConsoleMessage.MessageLevel.Debug: 676 return "Debug"; 677 case WebInspector.ConsoleMessage.MessageLevel.Error: 678 return "Error"; 679 } 680 }, 681 682 get clipboardPrefixString() 683 { 684 return "[" + this.levelString + "] "; 685 }, 686 687 toClipboardString: function(isPrefixOptional) 688 { 689 var isTrace = this._shouldDumpStackTrace(); 690 691 var clipboardString = ""; 692 if (this._formattedMessage && !isTrace) 693 clipboardString = this._formattedMessage.querySelector("span").innerText; 694 else 695 clipboardString = this.type === WebInspector.ConsoleMessage.MessageType.Trace ? "console.trace()" : this._message || this._messageText; 696 697 if (!isPrefixOptional || this.enforcesClipboardPrefixString) 698 clipboardString = this.clipboardPrefixString + clipboardString; 699 700 if (isTrace) { 701 this._stackTrace.forEach(function(frame) { 702 clipboardString += "\n\t" + (frame.functionName || WebInspector.UIString("(anonymous function)")); 703 if (frame.url) 704 clipboardString += " (" + WebInspector.displayNameForURL(frame.url) + ", line " + frame.lineNumber + ")"; 705 }); 706 } else { 707 var repeatString = this.repeatCount > 1 ? "x" + this.repeatCount : ""; 708 709 var urlLine = ""; 710 if (this.url) { 711 var components = [WebInspector.displayNameForURL(this.url), "line " + this.line]; 712 if (repeatString) 713 components.push(repeatString); 714 urlLine = " (" + components.join(", ") + ")"; 715 } else if (repeatString) 716 urlLine = " (" + repeatString + ")"; 717 718 if (urlLine) { 719 var lines = clipboardString.split("\n"); 720 lines[0] += urlLine; 721 clipboardString = lines.join("\n"); 722 } 723 } 724 725 return clipboardString; 726 } 727} 728 729WebInspector.ConsoleMessageImpl.prototype.__proto__ = WebInspector.ConsoleMessage.prototype; 730