blob: 57bf331ef0e4768d0455f33fedf299c91fd82fdd [file] [log] [blame]
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
WebInspector.ConsolePanel = function()
{
WebInspector.Panel.call(this);
this.messages = [];
this.commandHistory = [];
this.commandOffset = 0;
this.messageList = document.createElement("ol");
this.messageList.className = "console-message-list";
this.element.appendChild(this.messageList);
this.messageList.addEventListener("click", this.messageListClicked.bind(this), true);
this.consolePrompt = document.createElement("textarea");
this.consolePrompt.className = "console-prompt";
this.element.appendChild(this.consolePrompt);
this.consolePrompt.addEventListener("keydown", this.promptKeyDown.bind(this), false);
var clearButtonText = WebInspector.UIString("Clear");
this.clearMessagesElement = document.createElement("button");
this.clearMessagesElement.appendChild(document.createTextNode(clearButtonText));
this.clearMessagesElement.title = clearButtonText;
this.clearMessagesElement.addEventListener("click", this.clearButtonClicked.bind(this), false);
}
WebInspector.ConsolePanel.prototype = {
show: function()
{
WebInspector.Panel.prototype.show.call(this);
WebInspector.consoleListItem.select();
this.clearMessagesElement.removeStyleClass("hidden");
if (!this.clearMessagesElement.parentNode)
document.getElementById("toolbarButtons").appendChild(this.clearMessagesElement);
},
hide: function()
{
WebInspector.Panel.prototype.hide.call(this);
WebInspector.consoleListItem.deselect();
this.clearMessagesElement.addStyleClass("hidden");
},
addMessage: function(msg)
{
if (msg.url in WebInspector.resourceURLMap) {
msg.resource = WebInspector.resourceURLMap[msg.url];
switch (msg.level) {
case WebInspector.ConsoleMessage.MessageLevel.Warning:
++msg.resource.warnings;
msg.resource.panel.addMessageToSource(msg);
break;
case WebInspector.ConsoleMessage.MessageLevel.Error:
++msg.resource.errors;
msg.resource.panel.addMessageToSource(msg);
break;
}
}
this.messages.push(msg);
var item = msg.toListItem();
item.message = msg;
this.messageList.appendChild(item);
item.scrollIntoView(false);
},
clearMessages: function()
{
for (var i = 0; i < this.messages.length; ++i) {
var resource = this.messages[i].resource;
if (!resource)
continue;
resource.errors = 0;
resource.warnings = 0;
}
this.messages = [];
this.messageList.removeChildren();
},
clearButtonClicked: function()
{
this.clearMessages();
},
messageListClicked: function(event)
{
var link = event.target.firstParentOrSelfWithNodeName("a");
if (link && link.representedNode) {
WebInspector.updateFocusedNode(link.representedNode);
return;
}
var item = event.target.firstParentOrSelfWithNodeName("li");
if (!item)
return;
var resource = item.message.resource;
if (!resource)
return;
if (link && link.hasStyleClass("console-message-url")) {
WebInspector.navigateToResource(resource);
resource.panel.showSourceLine(item.message.line);
}
event.stopPropagation();
event.preventDefault();
},
promptKeyDown: function(event)
{
switch (event.keyIdentifier) {
case "Enter":
this._onEnterPressed(event);
break;
case "Up":
this._onUpPressed(event);
break;
case "Down":
this._onDownPressed(event);
break;
}
},
_onEnterPressed: function(event)
{
event.preventDefault();
event.stopPropagation();
var str = this.consolePrompt.value;
if (!str.length)
return;
this.commandHistory.push(str);
this.commandOffset = 0;
this.consolePrompt.value = "";
var result;
var exception = false;
try {
// This with block is needed to work around http://bugs.webkit.org/show_bug.cgi?id=11399
with (InspectorController.inspectedWindow()) {
result = eval(str);
}
} catch(e) {
result = e;
exception = true;
}
var level = exception ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log;
this.addMessage(new WebInspector.ConsoleCommand(str, this._format(result)));
},
_onUpPressed: function(event)
{
event.preventDefault();
event.stopPropagation();
if (this.commandOffset == this.commandHistory.length)
return;
if (this.commandOffset == 0)
this.tempSavedCommand = this.consolePrompt.value;
++this.commandOffset;
this.consolePrompt.value = this.commandHistory[this.commandHistory.length - this.commandOffset];
this.consolePrompt.moveCursorToEnd();
},
_onDownPressed: function(event)
{
event.preventDefault();
event.stopPropagation();
if (this.commandOffset == 0)
return;
--this.commandOffset;
if (this.commandOffset == 0) {
this.consolePrompt.value = this.tempSavedCommand;
this.consolePrompt.moveCursorToEnd();
delete this.tempSavedCommand;
return;
}
this.consolePrompt.value = this.commandHistory[this.commandHistory.length - this.commandOffset];
this.consolePrompt.moveCursorToEnd();
},
_format: function(output)
{
var type = Object.type(output);
if (type === "object") {
if (output instanceof Node)
type = "node";
}
// We don't perform any special formatting on these types, so we just
// pass them through the simple _formatvalue function.
var undecoratedTypes = {
"undefined": 1,
"null": 1,
"boolean": 1,
"number": 1,
"date": 1,
"function": 1,
};
var formatter;
if (type in undecoratedTypes)
formatter = "_formatvalue";
else {
formatter = "_format" + type;
if (!(formatter in this)) {
formatter = "_formatobject";
type = "object";
}
}
var span = document.createElement("span");
span.addStyleClass("console-formatted-" + type);
this[formatter](output, span);
return span;
},
_formatvalue: function(val, elem)
{
elem.appendChild(document.createTextNode(val));
},
_formatstring: function(str, elem)
{
elem.appendChild(document.createTextNode("\"" + str + "\""));
},
_formatregexp: function(re, elem)
{
var formatted = String(re).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1);
elem.appendChild(document.createTextNode(formatted));
},
_formatarray: function(arr, elem)
{
elem.appendChild(document.createTextNode("["));
for (var i = 0; i < arr.length; ++i) {
elem.appendChild(this._format(arr[i]));
if (i < arr.length - 1)
elem.appendChild(document.createTextNode(", "));
}
elem.appendChild(document.createTextNode("]"));
},
_formatnode: function(node, elem)
{
var anchor = document.createElement("a");
anchor.innerHTML = node.titleInfo().title;
anchor.representedNode = node;
elem.appendChild(anchor);
},
_formatobject: function(obj, elem)
{
elem.appendChild(document.createTextNode(Object.describe(obj)));
},
}
WebInspector.ConsolePanel.prototype.__proto__ = WebInspector.Panel.prototype;
WebInspector.ConsoleMessage = function(source, level, message, line, url)
{
this.source = source;
this.level = level;
this.message = message;
this.line = line;
this.url = url;
}
WebInspector.ConsoleMessage.prototype = {
get shortURL()
{
if (this.resource)
return this.resource.displayName;
return this.url;
},
toListItem: function()
{
var item = document.createElement("li");
item.className = "console-message";
switch (this.source) {
case WebInspector.ConsoleMessage.MessageSource.HTML:
item.className += " console-html-source";
break;
case WebInspector.ConsoleMessage.MessageSource.XML:
item.className += " console-xml-source";
break;
case WebInspector.ConsoleMessage.MessageSource.JS:
item.className += " console-js-source";
break;
case WebInspector.ConsoleMessage.MessageSource.CSS:
item.className += " console-css-source";
break;
case WebInspector.ConsoleMessage.MessageSource.Other:
item.className += " console-other-source";
break;
}
switch (this.level) {
case WebInspector.ConsoleMessage.MessageLevel.Tip:
item.className += " console-tip-level";
break;
case WebInspector.ConsoleMessage.MessageLevel.Log:
item.className += " console-log-level";
break;
case WebInspector.ConsoleMessage.MessageLevel.Warning:
item.className += " console-warning-level";
break;
case WebInspector.ConsoleMessage.MessageLevel.Error:
item.className += " console-error-level";
}
var messageDiv = document.createElement("div");
messageDiv.className = "console-message-message";
messageDiv.textContent = this.message;
item.appendChild(messageDiv);
if (this.url && this.url !== "undefined") {
var urlElement = document.createElement("a");
urlElement.className = "console-message-url";
if (this.line > 0)
urlElement.textContent = WebInspector.UIString("%s (line %d)", this.url, this.line);
else
urlElement.textContent = this.url;
item.appendChild(urlElement);
}
return item;
},
toString: function()
{
var sourceString;
switch (this.source) {
case WebInspector.ConsoleMessage.MessageSource.HTML:
sourceString = "HTML";
break;
case WebInspector.ConsoleMessage.MessageSource.XML:
sourceString = "XML";
break;
case WebInspector.ConsoleMessage.MessageSource.JS:
sourceString = "JS";
break;
case WebInspector.ConsoleMessage.MessageSource.CSS:
sourceString = "CSS";
break;
case WebInspector.ConsoleMessage.MessageSource.Other:
sourceString = "Other";
break;
}
var levelString;
switch (this.level) {
case WebInspector.ConsoleMessage.MessageLevel.Tip:
levelString = "Tip";
break;
case WebInspector.ConsoleMessage.MessageLevel.Log:
levelString = "Log";
break;
case WebInspector.ConsoleMessage.MessageLevel.Warning:
levelString = "Warning";
break;
case WebInspector.ConsoleMessage.MessageLevel.Error:
levelString = "Error";
break;
}
return sourceString + " " + levelString + ": " + this.message + "\n" + this.url + " line " + this.line;
}
}
// Note: Keep these constants in sync with the ones in Chrome.h
WebInspector.ConsoleMessage.MessageSource = {
HTML: 0,
XML: 1,
JS: 2,
CSS: 3,
Other: 4,
};
WebInspector.ConsoleMessage.MessageLevel = {
Tip: 0,
Log: 1,
Warning: 2,
Error: 3,
};
WebInspector.ConsoleCommand = function(input, output)
{
this.input = input;
this.output = output;
}
WebInspector.ConsoleCommand.prototype = {
toListItem: function()
{
var item = document.createElement("li");
item.className = "console-command";
var inputDiv = document.createElement("div");
inputDiv.className = "console-command-input";
inputDiv.textContent = this.input;
item.appendChild(inputDiv);
var outputDiv = document.createElement("div");
outputDiv.className = "console-command-output";
outputDiv.appendChild(this.output);
item.appendChild(outputDiv);
return item;
}
}