home *** CD-ROM | disk | FTP | other *** search
/ Computer Active 2010 July / CA07.iso / Multimedija / QuickTimeInstaller.exe / AppleApplicationSupport.msi / WebKit.resources_inspector_Console.js < prev    next >
Encoding:
Text File  |  2010-03-15  |  34.9 KB  |  950 lines

  1. /*
  2.  * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1.  Redistributions of source code must retain the above copyright
  9.  *     notice, this list of conditions and the following disclaimer. 
  10.  * 2.  Redistributions in binary form must reproduce the above copyright
  11.  *     notice, this list of conditions and the following disclaimer in the
  12.  *     documentation and/or other materials provided with the distribution. 
  13.  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  14.  *     its contributors may be used to endorse or promote products derived
  15.  *     from this software without specific prior written permission. 
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  18.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20.  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  21.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. WebInspector.Console = function()
  30. {
  31.     this.messages = [];
  32.  
  33.     WebInspector.View.call(this, document.getElementById("console"));
  34.  
  35.     this.messagesElement = document.getElementById("console-messages");
  36.     this.messagesElement.addEventListener("selectstart", this._messagesSelectStart.bind(this), false);
  37.     this.messagesElement.addEventListener("click", this._messagesClicked.bind(this), true);
  38.  
  39.     this.promptElement = document.getElementById("console-prompt");
  40.     this.promptElement.handleKeyEvent = this._promptKeyDown.bind(this);
  41.     this.prompt = new WebInspector.TextPrompt(this.promptElement, this.completions.bind(this), " .=:[({;");
  42.  
  43.     this.toggleButton = document.getElementById("console-status-bar-item");
  44.     this.toggleButton.title = WebInspector.UIString("Show console.");
  45.     this.toggleButton.addEventListener("click", this._toggleButtonClicked.bind(this), false);
  46.  
  47.     this.clearButton = document.getElementById("clear-console-status-bar-item");
  48.     this.clearButton.title = WebInspector.UIString("Clear console log.");
  49.     this.clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false);
  50.  
  51.     this.topGroup = new WebInspector.ConsoleGroup(null, 0);
  52.     this.messagesElement.insertBefore(this.topGroup.element, this.promptElement);
  53.     this.groupLevel = 0;
  54.     this.currentGroup = this.topGroup;
  55.  
  56.     document.getElementById("main-status-bar").addEventListener("mousedown", this._startStatusBarDragging.bind(this), true);
  57. }
  58.  
  59. WebInspector.Console.prototype = {
  60.     show: function()
  61.     {
  62.         if (this._animating || this.visible)
  63.             return;
  64.  
  65.         WebInspector.View.prototype.show.call(this);
  66.  
  67.         this._animating = true;
  68.  
  69.         this.toggleButton.addStyleClass("toggled-on");
  70.         this.toggleButton.title = WebInspector.UIString("Hide console.");
  71.  
  72.         document.body.addStyleClass("console-visible");
  73.  
  74.         var anchoredItems = document.getElementById("anchored-status-bar-items");
  75.  
  76.         var animations = [
  77.             {element: document.getElementById("main"), end: {bottom: this.element.offsetHeight}},
  78.             {element: document.getElementById("main-status-bar"), start: {"padding-left": anchoredItems.offsetWidth - 1}, end: {"padding-left": 0}},
  79.             {element: document.getElementById("other-console-status-bar-items"), start: {opacity: 0}, end: {opacity: 1}}
  80.         ];
  81.  
  82.         var consoleStatusBar = document.getElementById("console-status-bar");
  83.         consoleStatusBar.insertBefore(anchoredItems, consoleStatusBar.firstChild);
  84.  
  85.         function animationFinished()
  86.         {
  87.             if ("updateStatusBarItems" in WebInspector.currentPanel)
  88.                 WebInspector.currentPanel.updateStatusBarItems();
  89.             WebInspector.currentFocusElement = this.promptElement;
  90.             delete this._animating;
  91.         }
  92.  
  93.         WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this));
  94.  
  95.         if (!this.prompt.isCaretInsidePrompt())
  96.             this.prompt.moveCaretToEndOfPrompt();
  97.     },
  98.  
  99.     hide: function()
  100.     {
  101.         if (this._animating || !this.visible)
  102.             return;
  103.  
  104.         WebInspector.View.prototype.hide.call(this);
  105.  
  106.         this._animating = true;
  107.  
  108.         this.toggleButton.removeStyleClass("toggled-on");
  109.         this.toggleButton.title = WebInspector.UIString("Show console.");
  110.  
  111.         if (this.element === WebInspector.currentFocusElement || this.element.isAncestor(WebInspector.currentFocusElement))
  112.             WebInspector.currentFocusElement = WebInspector.previousFocusElement;
  113.  
  114.         var anchoredItems = document.getElementById("anchored-status-bar-items");
  115.  
  116.         // Temporally set properties and classes to mimic the post-animation values so panels
  117.         // like Elements in their updateStatusBarItems call will size things to fit the final location.
  118.         document.getElementById("main-status-bar").style.setProperty("padding-left", (anchoredItems.offsetWidth - 1) + "px");
  119.         document.body.removeStyleClass("console-visible");
  120.         if ("updateStatusBarItems" in WebInspector.currentPanel)
  121.             WebInspector.currentPanel.updateStatusBarItems();
  122.         document.body.addStyleClass("console-visible");
  123.  
  124.         var animations = [
  125.             {element: document.getElementById("main"), end: {bottom: 0}},
  126.             {element: document.getElementById("main-status-bar"), start: {"padding-left": 0}, end: {"padding-left": anchoredItems.offsetWidth - 1}},
  127.             {element: document.getElementById("other-console-status-bar-items"), start: {opacity: 1}, end: {opacity: 0}}
  128.         ];
  129.  
  130.         function animationFinished()
  131.         {
  132.             var mainStatusBar = document.getElementById("main-status-bar");
  133.             mainStatusBar.insertBefore(anchoredItems, mainStatusBar.firstChild);
  134.             mainStatusBar.style.removeProperty("padding-left");
  135.             document.body.removeStyleClass("console-visible");
  136.             delete this._animating;
  137.         }
  138.  
  139.         WebInspector.animateStyle(animations, window.event && window.event.shiftKey ? 2000 : 250, animationFinished.bind(this));
  140.     },
  141.  
  142.     addMessage: function(msg)
  143.     {
  144.         if (msg instanceof WebInspector.ConsoleMessage && !(msg instanceof WebInspector.ConsoleCommandResult)) {
  145.             msg.totalRepeatCount = msg.repeatCount;
  146.             msg.repeatDelta = msg.repeatCount;
  147.  
  148.             var messageRepeated = false;
  149.  
  150.             if (msg.isEqual && msg.isEqual(this.previousMessage)) {
  151.                 // Because sometimes we get a large number of repeated messages and sometimes
  152.                 // we get them one at a time, we need to know the difference between how many
  153.                 // repeats we used to have and how many we have now.
  154.                 msg.repeatDelta -= this.previousMessage.totalRepeatCount;
  155.  
  156.                 if (!isNaN(this.repeatCountBeforeCommand))
  157.                     msg.repeatCount -= this.repeatCountBeforeCommand;
  158.  
  159.                 if (!this.commandSincePreviousMessage) {
  160.                     // Recreate the previous message element to reset the repeat count.
  161.                     var messagesElement = this.currentGroup.messagesElement;
  162.                     messagesElement.removeChild(messagesElement.lastChild);
  163.                     messagesElement.appendChild(msg.toMessageElement());
  164.  
  165.                     messageRepeated = true;
  166.                 }
  167.             } else
  168.                 delete this.repeatCountBeforeCommand;
  169.  
  170.             // Increment the error or warning count
  171.             switch (msg.level) {
  172.             case WebInspector.ConsoleMessage.MessageLevel.Warning:
  173.                 WebInspector.warnings += msg.repeatDelta;
  174.                 break;
  175.             case WebInspector.ConsoleMessage.MessageLevel.Error:
  176.                 WebInspector.errors += msg.repeatDelta;
  177.                 break;
  178.             }
  179.  
  180.             // Add message to the resource panel
  181.             if (msg.url in WebInspector.resourceURLMap) {
  182.                 msg.resource = WebInspector.resourceURLMap[msg.url];
  183.                 if (WebInspector.panels.resources)
  184.                     WebInspector.panels.resources.addMessageToResource(msg.resource, msg);
  185.             }
  186.  
  187.             this.commandSincePreviousMessage = false;
  188.             this.previousMessage = msg;
  189.  
  190.             if (messageRepeated)
  191.                 return;
  192.         } else if (msg instanceof WebInspector.ConsoleCommand) {
  193.             if (this.previousMessage) {
  194.                 this.commandSincePreviousMessage = true;
  195.                 this.repeatCountBeforeCommand = this.previousMessage.totalRepeatCount;
  196.             }
  197.         }
  198.  
  199.         this.messages.push(msg);
  200.  
  201.         if (msg.level === WebInspector.ConsoleMessage.MessageLevel.EndGroup) {
  202.             if (this.groupLevel < 1)
  203.                 return;
  204.  
  205.             this.groupLevel--;
  206.  
  207.             this.currentGroup = this.currentGroup.parentGroup;
  208.         } else {
  209.             if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) {
  210.                 this.groupLevel++;
  211.  
  212.                 var group = new WebInspector.ConsoleGroup(this.currentGroup, this.groupLevel);
  213.                 this.currentGroup.messagesElement.appendChild(group.element);
  214.                 this.currentGroup = group;
  215.             }
  216.  
  217.             this.currentGroup.addMessage(msg);
  218.         }
  219.  
  220.         this.promptElement.scrollIntoView(false);
  221.     },
  222.  
  223.     clearMessages: function(clearInspectorController)
  224.     {
  225.         if (clearInspectorController)
  226.             InspectorController.clearMessages();
  227.         if (WebInspector.panels.resources)
  228.             WebInspector.panels.resources.clearMessages();
  229.  
  230.         this.messages = [];
  231.  
  232.         this.groupLevel = 0;
  233.         this.currentGroup = this.topGroup;
  234.         this.topGroup.messagesElement.removeChildren();
  235.  
  236.         WebInspector.errors = 0;
  237.         WebInspector.warnings = 0;
  238.  
  239.         delete this.commandSincePreviousMessage;
  240.         delete this.repeatCountBeforeCommand;
  241.         delete this.previousMessage;
  242.     },
  243.  
  244.     completions: function(wordRange, bestMatchOnly, completionsReadyCallback)
  245.     {
  246.         // Pass less stop characters to rangeOfWord so the range will be a more complete expression.
  247.         const expressionStopCharacters = " =:{;";
  248.         var expressionRange = wordRange.startContainer.rangeOfWord(wordRange.startOffset, expressionStopCharacters, this.promptElement, "backward");
  249.         var expressionString = expressionRange.toString();
  250.         var lastIndex = expressionString.length - 1;
  251.  
  252.         var dotNotation = (expressionString[lastIndex] === ".");
  253.         var bracketNotation = (expressionString[lastIndex] === "[");
  254.  
  255.         if (dotNotation || bracketNotation)
  256.             expressionString = expressionString.substr(0, lastIndex);
  257.  
  258.         var prefix = wordRange.toString();
  259.         if (!expressionString && !prefix)
  260.             return;
  261.  
  262.         var reportCompletions = this._reportCompletions.bind(this, bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix);
  263.         this._evalInInspectedWindow(expressionString, reportCompletions);
  264.     },
  265.     
  266.     _reportCompletions: function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result) {
  267.         if (bracketNotation) {
  268.             if (prefix.length && prefix[0] === "'")
  269.                 var quoteUsed = "'";
  270.             else
  271.                 var quoteUsed = "\"";
  272.         }
  273.  
  274.         var results = [];
  275.         var properties = Object.sortedProperties(result);
  276.         for (var i = 0; i < properties.length; ++i) {
  277.             var property = properties[i];
  278.  
  279.             if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property))
  280.                 continue;
  281.  
  282.             if (bracketNotation) {
  283.                 if (!/^[0-9]+$/.test(property))
  284.                     property = quoteUsed + property.escapeCharacters(quoteUsed + "\\") + quoteUsed;
  285.                 property += "]";
  286.             }
  287.  
  288.             if (property.length < prefix.length)
  289.                 continue;
  290.             if (property.indexOf(prefix) !== 0)
  291.                 continue;
  292.  
  293.             results.push(property);
  294.             if (bestMatchOnly)
  295.                 break;
  296.         }
  297.         setTimeout(completionsReadyCallback, 0, results);
  298.     },
  299.  
  300.     _toggleButtonClicked: function()
  301.     {
  302.         this.visible = !this.visible;
  303.     },
  304.  
  305.     _clearButtonClicked: function()
  306.     {
  307.         this.clearMessages(true);
  308.     },
  309.  
  310.     _messagesSelectStart: function(event)
  311.     {
  312.         if (this._selectionTimeout)
  313.             clearTimeout(this._selectionTimeout);
  314.  
  315.         this.prompt.clearAutoComplete();
  316.  
  317.         function moveBackIfOutside()
  318.         {
  319.             delete this._selectionTimeout;
  320.             if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
  321.                 this.prompt.moveCaretToEndOfPrompt();
  322.             this.prompt.autoCompleteSoon();
  323.         }
  324.  
  325.         this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
  326.     },
  327.  
  328.     _messagesClicked: function(event)
  329.     {
  330.         var link = event.target.enclosingNodeOrSelfWithNodeName("a");
  331.         if (!link || !link.representedNode)
  332.             return;
  333.  
  334.         WebInspector.updateFocusedNode(link.representedNode);
  335.         event.stopPropagation();
  336.         event.preventDefault();
  337.     },
  338.  
  339.     _promptKeyDown: function(event)
  340.     {
  341.         switch (event.keyIdentifier) {
  342.             case "Enter":
  343.                 this._enterKeyPressed(event);
  344.                 return;
  345.         }
  346.  
  347.         this.prompt.handleKeyEvent(event);
  348.     },
  349.  
  350.     _startStatusBarDragging: function(event)
  351.     {
  352.         if (!this.visible || event.target !== document.getElementById("main-status-bar"))
  353.             return;
  354.  
  355.         WebInspector.elementDragStart(document.getElementById("main-status-bar"), this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), event, "row-resize");
  356.  
  357.         this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop;
  358.  
  359.         event.stopPropagation();
  360.     },
  361.  
  362.     _statusBarDragging: function(event)
  363.     {
  364.         var mainElement = document.getElementById("main");
  365.  
  366.         var height = window.innerHeight - event.pageY + this._statusBarDragOffset;
  367.         height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - mainElement.totalOffsetTop - Preferences.minConsoleHeight);
  368.  
  369.         mainElement.style.bottom = height + "px";
  370.         this.element.style.height = height + "px";
  371.  
  372.         event.preventDefault();
  373.         event.stopPropagation();
  374.     },
  375.  
  376.     _endStatusBarDragging: function(event)
  377.     {
  378.         WebInspector.elementDragEnd(event);
  379.  
  380.         delete this._statusBarDragOffset;
  381.  
  382.         event.stopPropagation();
  383.     },
  384.  
  385.     _evalInInspectedWindow: function(expression, callback)
  386.     {
  387.         if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) {
  388.             WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, callback);
  389.             return;
  390.         }
  391.         this.doEvalInWindow(expression, callback);
  392.     },
  393.     
  394.     _ensureCommandLineAPIInstalled: function(inspectedWindow)
  395.     {
  396.         if (!inspectedWindow._inspectorCommandLineAPI) {
  397.             inspectedWindow.eval("window._inspectorCommandLineAPI = { \
  398.                 $: function() { return document.getElementById.apply(document, arguments) }, \
  399.                 $$: function() { return document.querySelectorAll.apply(document, arguments) }, \
  400.                 $x: function(xpath, context) { \
  401.                     var nodes = []; \
  402.                     try { \
  403.                         var doc = context || document; \
  404.                         var results = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); \
  405.                         var node; \
  406.                         while (node = results.iterateNext()) nodes.push(node); \
  407.                     } catch (e) {} \
  408.                     return nodes; \
  409.                 }, \
  410.                 dir: function() { return console.dir.apply(console, arguments) }, \
  411.                 dirxml: function() { return console.dirxml.apply(console, arguments) }, \
  412.                 keys: function(o) { var a = []; for (k in o) a.push(k); return a; }, \
  413.                 values: function(o) { var a = []; for (k in o) a.push(o[k]); return a; }, \
  414.                 profile: function() { return console.profile.apply(console, arguments) }, \
  415.                 profileEnd: function() { return console.profileEnd.apply(console, arguments) } \
  416.             };");
  417.  
  418.             inspectedWindow._inspectorCommandLineAPI.clear = InspectorController.wrapCallback(this.clearMessages.bind(this));
  419.         }
  420.     },
  421.     
  422.     doEvalInWindow: function(expression, callback)
  423.     {
  424.         if (!expression) {
  425.             // There is no expression, so the completion should happen against global properties.
  426.             expression = "this";
  427.         }
  428.  
  429.         // Surround the expression in with statements to inject our command line API so that
  430.         // the window object properties still take more precedent than our API functions.
  431.         expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }";
  432.  
  433.         var self = this;
  434.         function delayedEvaluation()
  435.         {
  436.             var inspectedWindow = InspectorController.inspectedWindow();
  437.             self._ensureCommandLineAPIInstalled(inspectedWindow);
  438.             try {
  439.                 callback(inspectedWindow.eval(expression));
  440.             } catch (e) {
  441.                 callback(e, true);
  442.             }
  443.         }
  444.         setTimeout(delayedEvaluation, 0);
  445.     },
  446.  
  447.     _enterKeyPressed: function(event)
  448.     {
  449.         if (event.altKey)
  450.             return;
  451.  
  452.         event.preventDefault();
  453.         event.stopPropagation();
  454.  
  455.         this.prompt.clearAutoComplete(true);
  456.  
  457.         var str = this.prompt.text;
  458.         if (!str.length)
  459.             return;
  460.  
  461.         var commandMessage = new WebInspector.ConsoleCommand(str);
  462.         this.addMessage(commandMessage);
  463.  
  464.         var self = this;
  465.         function printResult(result, exception)
  466.         {
  467.             self.prompt.history.push(str);
  468.             self.prompt.historyOffset = 0;
  469.             self.prompt.text = "";
  470.             self.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage));
  471.         }
  472.         this._evalInInspectedWindow(str, printResult);
  473.     },
  474.  
  475.     _format: function(output, forceObjectFormat)
  476.     {
  477.         var type = (forceObjectFormat ? "object" : Object.type(output, InspectorController.inspectedWindow()));
  478.  
  479.         // We don't perform any special formatting on these types, so we just
  480.         // pass them through the simple _formatvalue function.
  481.         var undecoratedTypes = {
  482.             "undefined": 1,
  483.             "null": 1,
  484.             "boolean": 1,
  485.             "number": 1,
  486.             "date": 1,
  487.             "function": 1,
  488.         };
  489.  
  490.         var formatter;
  491.         if (forceObjectFormat)
  492.             formatter = "_formatobject";
  493.         else if (type in undecoratedTypes)
  494.             formatter = "_formatvalue";
  495.         else {
  496.             formatter = "_format" + type;
  497.             if (!(formatter in this)) {
  498.                 formatter = "_formatobject";
  499.                 type = "object";
  500.             }
  501.         }
  502.  
  503.         var span = document.createElement("span");
  504.         span.addStyleClass("console-formatted-" + type);
  505.         this[formatter](output, span);
  506.         return span;
  507.     },
  508.  
  509.     _formatvalue: function(val, elem)
  510.     {
  511.         elem.appendChild(document.createTextNode(val));
  512.     },
  513.  
  514.     _formatstring: function(str, elem)
  515.     {
  516.         elem.appendChild(document.createTextNode("\"" + str + "\""));
  517.     },
  518.  
  519.     _formatregexp: function(re, elem)
  520.     {
  521.         var formatted = String(re).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1);
  522.         elem.appendChild(document.createTextNode(formatted));
  523.     },
  524.  
  525.     _formatarray: function(arr, elem)
  526.     {
  527.         elem.appendChild(document.createTextNode("["));
  528.         for (var i = 0; i < arr.length; ++i) {
  529.             elem.appendChild(this._format(arr[i]));
  530.             if (i < arr.length - 1)
  531.                 elem.appendChild(document.createTextNode(", "));
  532.         }
  533.         elem.appendChild(document.createTextNode("]"));
  534.     },
  535.  
  536.     _formatnode: function(node, elem)
  537.     {
  538.         var treeOutline = new WebInspector.ElementsTreeOutline();
  539.         treeOutline.rootDOMNode = node;
  540.         treeOutline.element.addStyleClass("outline-disclosure");
  541.         if (!treeOutline.children[0].hasChildren)
  542.             treeOutline.element.addStyleClass("single-node");
  543.         elem.appendChild(treeOutline.element);
  544.     },
  545.  
  546.     _formatobject: function(obj, elem)
  547.     {
  548.         elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null, null, null, true).element);
  549.     },
  550.  
  551.     _formaterror: function(obj, elem)
  552.     {
  553.         var messageElement = document.createElement("span");
  554.         messageElement.className = "error-message";
  555.         messageElement.textContent = obj.name + ": " + obj.message;
  556.         elem.appendChild(messageElement);
  557.  
  558.         if (obj.sourceURL) {
  559.             var urlElement = document.createElement("a");
  560.             urlElement.className = "webkit-html-resource-link";
  561.             urlElement.href = obj.sourceURL;
  562.             urlElement.lineNumber = obj.line;
  563.             urlElement.preferredPanel = "scripts";
  564.  
  565.             if (obj.line > 0)
  566.                 urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL) + ":" + obj.line;
  567.             else
  568.                 urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL);
  569.  
  570.             elem.appendChild(document.createTextNode(" ("));
  571.             elem.appendChild(urlElement);
  572.             elem.appendChild(document.createTextNode(")"));
  573.         }
  574.     },
  575. }
  576.  
  577. WebInspector.Console.prototype.__proto__ = WebInspector.View.prototype;
  578.  
  579. WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, repeatCount)
  580. {
  581.     this.source = source;
  582.     this.level = level;
  583.     this.line = line;
  584.     this.url = url;
  585.     this.groupLevel = groupLevel;
  586.     this.repeatCount = repeatCount;
  587.     if (arguments.length > 6)
  588.         this.setMessageBody(Array.prototype.slice.call(arguments, 6));
  589. }
  590.  
  591. WebInspector.ConsoleMessage.prototype = {
  592.     setMessageBody: function(args)
  593.     {
  594.         switch (this.level) {
  595.             case WebInspector.ConsoleMessage.MessageLevel.Trace:
  596.                 var span = document.createElement("span");
  597.                 span.addStyleClass("console-formatted-trace");
  598.                 var stack = Array.prototype.slice.call(args);
  599.                 var funcNames = stack.map(function(f) {
  600.                     return f || WebInspector.UIString("(anonymous function)");
  601.                 });
  602.                 span.appendChild(document.createTextNode(funcNames.join("\n")));
  603.                 this.formattedMessage = span;
  604.                 break;
  605.             case WebInspector.ConsoleMessage.MessageLevel.Object:
  606.                 this.formattedMessage = this._format(["%O", args[0]]);
  607.                 break;
  608.             default:
  609.                 this.formattedMessage = this._format(args);
  610.                 break;
  611.         }
  612.  
  613.         // This is used for inline message bubbles in SourceFrames, or other plain-text representations.
  614.         this.message = this.formattedMessage.textContent;
  615.     },
  616.  
  617.     isErrorOrWarning: function()
  618.     {
  619.         return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
  620.     },
  621.  
  622.     _format: function(parameters)
  623.     {
  624.         var formattedResult = document.createElement("span");
  625.  
  626.         if (!parameters.length)
  627.             return formattedResult;
  628.  
  629.         function formatForConsole(obj)
  630.         {
  631.             return WebInspector.console._format(obj);
  632.         }
  633.  
  634.         function formatAsObjectForConsole(obj)
  635.         {
  636.             return WebInspector.console._format(obj, true);
  637.         }
  638.  
  639.         if (Object.type(parameters[0], InspectorController.inspectedWindow()) === "string") {
  640.             var formatters = {}
  641.             for (var i in String.standardFormatters)
  642.                 formatters[i] = String.standardFormatters[i];
  643.  
  644.             // Firebug uses %o for formatting objects.
  645.             formatters.o = formatForConsole;
  646.             // Firebug allows both %i and %d for formatting integers.
  647.             formatters.i = formatters.d;
  648.             // Support %O to force object formating, instead of the type-based %o formatting.
  649.             formatters.O = formatAsObjectForConsole;
  650.  
  651.             function append(a, b)
  652.             {
  653.                 if (!(b instanceof Node))
  654.                     a.appendChild(WebInspector.linkifyStringAsFragment(b.toString()));
  655.                 else
  656.                     a.appendChild(b);
  657.                 return a;
  658.             }
  659.  
  660.             var result = String.format(parameters[0], parameters.slice(1), formatters, formattedResult, append);
  661.             formattedResult = result.formattedResult;
  662.             parameters = result.unusedSubstitutions;
  663.             if (parameters.length)
  664.                 formattedResult.appendChild(document.createTextNode(" "));
  665.         }
  666.  
  667.         for (var i = 0; i < parameters.length; ++i) {
  668.             if (typeof parameters[i] === "string")
  669.                 formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i]));
  670.             else
  671.                 formattedResult.appendChild(formatForConsole(parameters[i]));
  672.  
  673.             if (i < parameters.length - 1)
  674.                 formattedResult.appendChild(document.createTextNode(" "));
  675.         }
  676.  
  677.         return formattedResult;
  678.     },
  679.  
  680.     toMessageElement: function()
  681.     {
  682.         if (this.propertiesSection)
  683.             return this.propertiesSection.element;
  684.  
  685.         var element = document.createElement("div");
  686.         element.message = this;
  687.         element.className = "console-message";
  688.  
  689.         switch (this.source) {
  690.             case WebInspector.ConsoleMessage.MessageSource.HTML:
  691.                 element.addStyleClass("console-html-source");
  692.                 break;
  693.             case WebInspector.ConsoleMessage.MessageSource.WML:
  694.                 element.addStyleClass("console-wml-source");
  695.                 break;
  696.             case WebInspector.ConsoleMessage.MessageSource.XML:
  697.                 element.addStyleClass("console-xml-source");
  698.                 break;
  699.             case WebInspector.ConsoleMessage.MessageSource.JS:
  700.                 element.addStyleClass("console-js-source");
  701.                 break;
  702.             case WebInspector.ConsoleMessage.MessageSource.CSS:
  703.                 element.addStyleClass("console-css-source");
  704.                 break;
  705.             case WebInspector.ConsoleMessage.MessageSource.Other:
  706.                 element.addStyleClass("console-other-source");
  707.                 break;
  708.         }
  709.  
  710.         switch (this.level) {
  711.             case WebInspector.ConsoleMessage.MessageLevel.Tip:
  712.                 element.addStyleClass("console-tip-level");
  713.                 break;
  714.             case WebInspector.ConsoleMessage.MessageLevel.Log:
  715.                 element.addStyleClass("console-log-level");
  716.                 break;
  717.             case WebInspector.ConsoleMessage.MessageLevel.Warning:
  718.                 element.addStyleClass("console-warning-level");
  719.                 break;
  720.             case WebInspector.ConsoleMessage.MessageLevel.Error:
  721.                 element.addStyleClass("console-error-level");
  722.                 break;
  723.             case WebInspector.ConsoleMessage.MessageLevel.StartGroup:
  724.                 element.addStyleClass("console-group-title-level");
  725.         }
  726.  
  727.         if (this.elementsTreeOutline) {
  728.             element.addStyleClass("outline-disclosure");
  729.             element.appendChild(this.elementsTreeOutline.element);
  730.             return element;
  731.         }
  732.  
  733.         if (this.repeatCount > 1) {
  734.             var messageRepeatCountElement = document.createElement("span");
  735.             messageRepeatCountElement.className = "bubble";
  736.             messageRepeatCountElement.textContent = this.repeatCount;
  737.  
  738.             element.appendChild(messageRepeatCountElement);
  739.             element.addStyleClass("repeated-message");
  740.         }
  741.  
  742.         if (this.url && this.url !== "undefined") {
  743.             var urlElement = document.createElement("a");
  744.             urlElement.className = "console-message-url webkit-html-resource-link";
  745.             urlElement.href = this.url;
  746.             urlElement.lineNumber = this.line;
  747.  
  748.             if (this.source === WebInspector.ConsoleMessage.MessageSource.JS)
  749.                 urlElement.preferredPanel = "scripts";
  750.  
  751.             if (this.line > 0)
  752.                 urlElement.textContent = WebInspector.displayNameForURL(this.url) + ":" + this.line;
  753.             else
  754.                 urlElement.textContent = WebInspector.displayNameForURL(this.url);
  755.  
  756.             element.appendChild(urlElement);
  757.         }
  758.  
  759.         var messageTextElement = document.createElement("span");
  760.         messageTextElement.className = "console-message-text";
  761.         messageTextElement.appendChild(this.formattedMessage);
  762.         element.appendChild(messageTextElement);
  763.  
  764.         return element;
  765.     },
  766.  
  767.     toString: function()
  768.     {
  769.         var sourceString;
  770.         switch (this.source) {
  771.             case WebInspector.ConsoleMessage.MessageSource.HTML:
  772.                 sourceString = "HTML";
  773.                 break;
  774.             case WebInspector.ConsoleMessage.MessageSource.WML:
  775.                 sourceString = "WML";
  776.                 break;
  777.             case WebInspector.ConsoleMessage.MessageSource.XML:
  778.                 sourceString = "XML";
  779.                 break;
  780.             case WebInspector.ConsoleMessage.MessageSource.JS:
  781.                 sourceString = "JS";
  782.                 break;
  783.             case WebInspector.ConsoleMessage.MessageSource.CSS:
  784.                 sourceString = "CSS";
  785.                 break;
  786.             case WebInspector.ConsoleMessage.MessageSource.Other:
  787.                 sourceString = "Other";
  788.                 break;
  789.         }
  790.  
  791.         var levelString;
  792.         switch (this.level) {
  793.             case WebInspector.ConsoleMessage.MessageLevel.Tip:
  794.                 levelString = "Tip";
  795.                 break;
  796.             case WebInspector.ConsoleMessage.MessageLevel.Log:
  797.                 levelString = "Log";
  798.                 break;
  799.             case WebInspector.ConsoleMessage.MessageLevel.Warning:
  800.                 levelString = "Warning";
  801.                 break;
  802.             case WebInspector.ConsoleMessage.MessageLevel.Error:
  803.                 levelString = "Error";
  804.                 break;
  805.             case WebInspector.ConsoleMessage.MessageLevel.Object:
  806.                 levelString = "Object";
  807.                 break;
  808.             case WebInspector.ConsoleMessage.MessageLevel.Trace:
  809.                 levelString = "Trace";
  810.                 break;
  811.             case WebInspector.ConsoleMessage.MessageLevel.StartGroup:
  812.                 levelString = "Start Group";
  813.                 break;
  814.             case WebInspector.ConsoleMessage.MessageLevel.EndGroup:
  815.                 levelString = "End Group";
  816.                 break;
  817.         }
  818.  
  819.         return sourceString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line;
  820.     },
  821.  
  822.     isEqual: function(msg, disreguardGroup)
  823.     {
  824.         if (!msg)
  825.             return false;
  826.  
  827.         var ret = (this.source == msg.source)
  828.             && (this.level == msg.level)
  829.             && (this.line == msg.line)
  830.             && (this.url == msg.url)
  831.             && (this.message == msg.message);
  832.  
  833.         return (disreguardGroup ? ret : (ret && (this.groupLevel == msg.groupLevel)));
  834.     }
  835. }
  836.  
  837. // Note: Keep these constants in sync with the ones in Console.h
  838. WebInspector.ConsoleMessage.MessageSource = {
  839.     HTML: 0,
  840.     WML: 1,
  841.     XML: 2,
  842.     JS: 3,
  843.     CSS: 4,
  844.     Other: 5
  845. }
  846.  
  847. WebInspector.ConsoleMessage.MessageLevel = {
  848.     Tip: 0,
  849.     Log: 1,
  850.     Warning: 2,
  851.     Error: 3,
  852.     Object: 4,
  853.     Trace: 5,
  854.     StartGroup: 6,
  855.     EndGroup: 7
  856. }
  857.  
  858. WebInspector.ConsoleCommand = function(command)
  859. {
  860.     this.command = command;
  861. }
  862.  
  863. WebInspector.ConsoleCommand.prototype = {
  864.     toMessageElement: function()
  865.     {
  866.         var element = document.createElement("div");
  867.         element.command = this;
  868.         element.className = "console-user-command";
  869.  
  870.         var commandTextElement = document.createElement("span");
  871.         commandTextElement.className = "console-message-text";
  872.         commandTextElement.textContent = this.command;
  873.         element.appendChild(commandTextElement);
  874.  
  875.         return element;
  876.     }
  877. }
  878.  
  879. WebInspector.ConsoleCommandResult = function(result, exception, originatingCommand)
  880. {
  881.     var level = (exception ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log);
  882.     var message = (exception ? String(result) : result);
  883.     var line = (exception ? result.line : -1);
  884.     var url = (exception ? result.sourceURL : null);
  885.  
  886.     WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, level, line, url, null, 1, message);
  887.  
  888.     this.originatingCommand = originatingCommand;
  889. }
  890.  
  891. WebInspector.ConsoleCommandResult.prototype = {
  892.     toMessageElement: function()
  893.     {
  894.         var element = WebInspector.ConsoleMessage.prototype.toMessageElement.call(this);
  895.         element.addStyleClass("console-user-command-result");
  896.         return element;
  897.     }
  898. }
  899.  
  900. WebInspector.ConsoleCommandResult.prototype.__proto__ = WebInspector.ConsoleMessage.prototype;
  901.  
  902. WebInspector.ConsoleGroup = function(parentGroup, level)
  903. {
  904.     this.parentGroup = parentGroup;
  905.     this.level = level;
  906.  
  907.     var element = document.createElement("div");
  908.     element.className = "console-group";
  909.     element.group = this;
  910.     this.element = element;
  911.  
  912.     var messagesElement = document.createElement("div");
  913.     messagesElement.className = "console-group-messages";
  914.     element.appendChild(messagesElement);
  915.     this.messagesElement = messagesElement;
  916. }
  917.  
  918. WebInspector.ConsoleGroup.prototype = {
  919.     addMessage: function(msg)
  920.     {
  921.         var element = msg.toMessageElement();
  922.         
  923.         if (msg.level === WebInspector.ConsoleMessage.MessageLevel.StartGroup) {
  924.             this.messagesElement.parentNode.insertBefore(element, this.messagesElement);
  925.             element.addEventListener("click", this._titleClicked.bind(this), true);
  926.         } else
  927.             this.messagesElement.appendChild(element);
  928.  
  929.         if (element.previousSibling && msg.originatingCommand && element.previousSibling.command === msg.originatingCommand)
  930.             element.previousSibling.addStyleClass("console-adjacent-user-command-result");
  931.     },
  932.  
  933.     _titleClicked: function(event)
  934.     {
  935.         var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title-level");
  936.         if (groupTitleElement) {
  937.             var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group");
  938.             if (groupElement)
  939.                 if (groupElement.hasStyleClass("collapsed"))
  940.                     groupElement.removeStyleClass("collapsed");
  941.                 else
  942.                     groupElement.addStyleClass("collapsed");
  943.             groupTitleElement.scrollIntoViewIfNeeded(true);
  944.         }
  945.  
  946.         event.stopPropagation();
  947.         event.preventDefault();
  948.     }
  949. }
  950.