Commit 723f16eb authored by joepeck@webkit.org's avatar joepeck@webkit.org
Browse files

2009-11-30 Joseph Pecoraro <joepeck@webkit.org>

        Reviewed by Pavel Feldman.

        Web Inspector: Wrong console output for Regexp escape sequence
        https://bugs.webkit.org/show_bug.cgi?id=31538

        Updated inspector/console-format.html

        * inspector/front-end/ConsoleView.js:
        (WebInspector.ConsoleView.createDividerElement): style issues.
        (WebInspector.ConsoleView.createFilterElement): style issues.
        (WebInspector.ConsoleView): added _customFormatters table.
        (WebInspector.ConsoleView.prototype.updateMessageRepeatCount): style isses.
        (WebInspector.ConsoleView.prototype._incrementErrorWarningCount): style issues.
        (WebInspector.ConsoleView.prototype._format): simplified delegation to formatter logic.
        (WebInspector.ConsoleView.prototype._formatobject):
        (WebInspector.ConsoleView.prototype._formatnode):
        (WebInspector.ConsoleView.prototype._printArray):
        (WebInspector.ConsoleMessage.prototype._format): commented and broke down the algorithm into parts.
        (WebInspector.ConsoleMessage.prototype._formatWithSubstitutionString.append): handle substitution string formatting.
        (WebInspector.ConsoleMessage.prototype._formatIndividualValue): handling individual value formatting.
        (WebInspector.ConsoleCommandResult):
        * inspector/front-end/InjectedScript.js: simplified regex formatting.
        * inspector/front-end/inspector.js:
        (WebInspector.linkifyStringAsFragment): converted new RegExp to literal for performance benefits.
        * inspector/front-end/utilities.js:
        (Element.prototype.hasStyleClass): update inaccurate comment.
        (String.prototype.trimURL): converted new RegExp to literal for performance benefits.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@51506 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 5c6ee644
2009-11-30 Joseph Pecoraro <joepeck@webkit.org>
Reviewed by Pavel Feldman.
Web Inspector: Wrong console output for Regexp escape sequence
https://bugs.webkit.org/show_bug.cgi?id=31538
* inspector/console-format-expected.txt:
* inspector/console-format.html:
2009-11-30 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
 
Skipping test that fails because of broken DND, and some tests
CONSOLE MESSAGE: line 9: Message format number %i, %d and %f
CONSOLE MESSAGE: line 10: Message %s for %s
CONSOLE MESSAGE: line 11: Object %o
CONSOLE MESSAGE: line 16: test,test2,,,test4
CONSOLE MESSAGE: line 12: Message format number %i, %d and %f
CONSOLE MESSAGE: line 13: Message %s for %s
CONSOLE MESSAGE: line 14: Object %o
CONSOLE MESSAGE: line 19: test,test2,,,test4
CONSOLE MESSAGE: line 49: /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
CONSOLE MESSAGE: line 50: /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
CONSOLE MESSAGE: line 49: /foo\\bar\sbaz/i
CONSOLE MESSAGE: line 50: /foo\\bar\sbaz/i
CONSOLE MESSAGE: line 49: test
CONSOLE MESSAGE: line 50: test
CONSOLE MESSAGE: line 49: Error: Unknown error
CONSOLE MESSAGE: line 50: Error: Unknown error
CONSOLE MESSAGE: line 49: [object HTMLBodyElement]
CONSOLE MESSAGE: line 50: [object HTMLBodyElement]
CONSOLE MESSAGE: line 49: function () { return 1; }
CONSOLE MESSAGE: line 50: function () { return 1; }
CONSOLE MESSAGE: line 49: function () {
return 2;
}
CONSOLE MESSAGE: line 50: function () {
return 2;
}
CONSOLE MESSAGE: line 49: 0.12
CONSOLE MESSAGE: line 50: 0.12
CONSOLE MESSAGE: line 49: http://webkit.org/
CONSOLE MESSAGE: line 50: http://webkit.org/
CONSOLE MESSAGE: line 49: null
CONSOLE MESSAGE: line 50:
CONSOLE MESSAGE: line 49: undefined
CONSOLE MESSAGE: line 50:
Tests that console logging dumps proper messages.
console-format.html:9Message format number 1, 2 and 3.5
console-format.html:10Message format for string
console-format.html:11Object Object
console-format.html:16["test", "test2", undefined, undefined, "test4"]
console-format.html:12Message format number 1, 2 and 3.5
console-format.html:13Message format for string
console-format.html:14Object Object
console-format.html:19["test", "test2", undefined, undefined, "test4"]
console-format.html:49/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
console-format.html:50[/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i]
"/^url\(\s*(?:(?:\"(?:[^\\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*\"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i"
console-format.html:49/foo\\bar\sbaz/i
console-format.html:50[/foo\\bar\sbaz/i]
"/foo\\bar\sbaz/i"
console-format.html:49test
console-format.html:50["test"]
"test"
console-format.html:49Error: Unknown error
console-format.html:50[Error: Unknown error]
Error: Unknown error
console-format.html:49<body onload="onload()">
console-format.html:50[<body onload="onload()">]
"HTMLBodyElement"
console-format.html:49function () { return 1; }
console-format.html:50[function () { return 1; }]
"function () { return 1; }"
console-format.html:49function () { return 2; }
console-format.html:50[function () {]
"function () {<br> return 2;<br> }"
console-format.html:490.12
console-format.html:50[0.12]
"0.12"
console-format.html:49http://webkit.org/
console-format.html:50["http://webkit.org/"]
"http://webkit.org/"
console-format.html:49null
console-format.html:50[null]
"null"
console-format.html:49undefined
console-format.html:50[undefined]
"undefined"
......@@ -4,6 +4,9 @@
<script src="console-tests.js"></script>
<script>
// Global Values
var globals = [];
function doit()
{
console.log('Message format number %i, %d and %f', 1, 2, 3.5);
......@@ -15,7 +18,60 @@ function doit()
array[4] = "test4";
console.log(array);
dumpConsoleMessages();
// Populate Globals
var regex1 = /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i;
var regex2 = new RegExp("foo\\\\bar\\sbaz", "i");
var str = "test";
var error = new Error;
var node = document.body;
var func = function() { return 1; };
var multilinefunc = function() {
return 2;
};
var num = 1.2e-1;
var linkify = "http://webkit.org/";
globals = [regex1, regex2, str, error, node, func, multilinefunc, num, linkify, null, undefined];
loopOverGlobals(0);
}
function loopOverGlobals(current)
{
function advance()
{
var next = current + 1;
if (next == globals.length)
dumpConsoleMessages();
else
loopOverGlobals(next);
}
console.log(globals[current]);
console.log([globals[current]]);
evaluateInWebInspector("frontend_evaluateGlobal", advance);
}
// Frontend functions.
function frontend_evaluateGlobal()
{
window.__next = window.__next || 0;
var current = window.__next++;
var expression = "globals[" + current + "]";
frontend_evalExpression(expression);
}
function frontend_evalExpression(expression, isDate)
{
var self = WebInspector.console;
function printResult(result, exception)
{
if (typeof result.description === "string")
result = result.description.replace(/\n/g, "<br>");
self.addMessage(new WebInspector.ConsoleCommandResult(result, exception, expression));
}
self.evalInInspectedWindow(expression, "console", printResult);
}
</script>
......
2009-11-30 Joseph Pecoraro <joepeck@webkit.org>
Reviewed by Pavel Feldman.
Web Inspector: Wrong console output for Regexp escape sequence
https://bugs.webkit.org/show_bug.cgi?id=31538
Updated inspector/console-format.html
* inspector/front-end/ConsoleView.js:
(WebInspector.ConsoleView.createDividerElement): style issues.
(WebInspector.ConsoleView.createFilterElement): style issues.
(WebInspector.ConsoleView): added _customFormatters table.
(WebInspector.ConsoleView.prototype.updateMessageRepeatCount): style isses.
(WebInspector.ConsoleView.prototype._incrementErrorWarningCount): style issues.
(WebInspector.ConsoleView.prototype._format): simplified delegation to formatter logic.
(WebInspector.ConsoleView.prototype._formatobject):
(WebInspector.ConsoleView.prototype._formatnode):
(WebInspector.ConsoleView.prototype._printArray):
(WebInspector.ConsoleMessage.prototype._format): commented and broke down the algorithm into parts.
(WebInspector.ConsoleMessage.prototype._formatWithSubstitutionString.append): handle substitution string formatting.
(WebInspector.ConsoleMessage.prototype._formatIndividualValue): handling individual value formatting.
(WebInspector.ConsoleCommandResult):
* inspector/front-end/InjectedScript.js: simplified regex formatting.
* inspector/front-end/inspector.js:
(WebInspector.linkifyStringAsFragment): converted new RegExp to literal for performance benefits.
* inspector/front-end/utilities.js:
(Element.prototype.hasStyleClass): update inaccurate comment.
(String.prototype.trimURL): converted new RegExp to literal for performance benefits.
2009-11-30 Erik Arvidsson <arv@chromium.org>
 
Reviewed by Adam Barth.
......@@ -1868,5 +1868,5 @@ void InspectorController::deleteCookie(const String& cookieName, const String& d
}
} // namespace WebCore
#endif // ENABLE(INSPECTOR)
......@@ -59,34 +59,29 @@ WebInspector.ConsoleView = function(drawer)
// Will hold the list of filter elements
this.filterBarElement = document.getElementById("console-filter");
function createDividerElement() {
var dividerElement = document.createElement("div");
dividerElement.addStyleClass("divider");
this.filterBarElement.appendChild(dividerElement);
}
var updateFilterHandler = this._updateFilter.bind(this);
function createFilterElement(category) {
var categoryElement = document.createElement("li");
categoryElement.category = category;
categoryElement.addStyleClass(categoryElement.category);
categoryElement.addStyleClass(categoryElement.category);
categoryElement.addEventListener("click", updateFilterHandler, false);
var label = category.toString();
categoryElement.appendChild(document.createTextNode(label));
categoryElement.addEventListener("click", this._updateFilter.bind(this), false);
this.filterBarElement.appendChild(categoryElement);
return categoryElement;
}
this.allElement = createFilterElement.call(this, "All");
createDividerElement.call(this);
this.errorElement = createFilterElement.call(this, "Errors");
this.warningElement = createFilterElement.call(this, "Warnings");
this.logElement = createFilterElement.call(this, "Logs");
......@@ -103,6 +98,12 @@ WebInspector.ConsoleView = function(drawer)
this._shortcuts[shortcut].isMacOnly = true;
shortcut = WebInspector.KeyboardShortcut.makeKey("l", WebInspector.KeyboardShortcut.Modifiers.Ctrl);
this._shortcuts[shortcut] = handler;
this._customFormatters = {
"object": this._formatobject,
"array": this._formatarray,
"node": this._formatnode
};
}
WebInspector.ConsoleView.prototype = {
......@@ -250,7 +251,8 @@ WebInspector.ConsoleView.prototype = {
this.promptElement.scrollIntoView(false);
},
updateMessageRepeatCount: function(count) {
updateMessageRepeatCount: function(count)
{
var msg = this.previousMessage;
var prevRepeatCount = msg.totalRepeatCount;
......@@ -268,7 +270,8 @@ WebInspector.ConsoleView.prototype = {
}
},
_incrementErrorWarningCount: function(msg) {
_incrementErrorWarningCount: function(msg)
{
switch (msg.level) {
case WebInspector.ConsoleMessage.MessageLevel.Warning:
WebInspector.warnings += msg.repeatDelta;
......@@ -478,44 +481,18 @@ WebInspector.ConsoleView.prototype = {
_format: function(output, forceObjectFormat)
{
var isProxy = (output != null && typeof output === "object");
var type = (forceObjectFormat ? "object" : Object.proxyType(output));
if (forceObjectFormat)
var type = "object";
else
var type = Object.proxyType(output);
if (isProxy && type !== "object" && type !== "function" && type !== "array" && type !== "node") {
// Unwrap primitive value, skip decoration.
output = output.description;
type = "undecorated"
}
// 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,
"undecorated": 1
};
var formatter;
if (forceObjectFormat)
formatter = "_formatobject";
else if (type in undecoratedTypes)
formatter = "_formatvalue";
else {
formatter = "_format" + type;
if (!(formatter in this)) {
formatter = "_formatobject";
type = "object";
}
var formatter = this._customFormatters[type];
if (!formatter || !isProxy) {
formatter = this._formatvalue;
output = output.description || output;
type = "undecorated";
}
var span = document.createElement("span");
span.addStyleClass("console-formatted-" + type);
this[formatter](output, span);
formatter.call(this, output, span);
return span;
},
......@@ -524,25 +501,27 @@ WebInspector.ConsoleView.prototype = {
elem.appendChild(document.createTextNode(val));
},
_formatfunction: function(func, elem)
{
elem.appendChild(document.createTextNode(func.description));
},
_formatdate: function(date, elem)
_formatobject: function(obj, elem)
{
elem.appendChild(document.createTextNode(date));
elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, obj.description, null, true).element);
},
_formatstring: function(str, elem)
_formatnode: function(object, elem)
{
elem.appendChild(document.createTextNode("\"" + str + "\""));
},
function printNode(nodeId)
{
if (!nodeId)
return;
var treeOutline = new WebInspector.ElementsTreeOutline();
treeOutline.showInElementsPanelEnabled = true;
treeOutline.rootDOMNode = WebInspector.domAgent.nodeForId(nodeId);
treeOutline.element.addStyleClass("outline-disclosure");
if (!treeOutline.children[0].hasChildren)
treeOutline.element.addStyleClass("single-node");
elem.appendChild(treeOutline.element);
}
_formatregexp: function(re, elem)
{
var formatted = String(re.description).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1);
elem.appendChild(document.createTextNode(formatted));
InjectedScriptAccess.pushNodeToFrontend(object, printNode);
},
_formatarray: function(arr, elem)
......@@ -554,6 +533,7 @@ WebInspector.ConsoleView.prototype = {
{
if (!properties)
return;
var elements = [];
for (var i = 0; i < properties.length; ++i) {
var name = properties[i].name;
......@@ -572,53 +552,6 @@ WebInspector.ConsoleView.prototype = {
elem.appendChild(document.createTextNode(", "));
}
elem.appendChild(document.createTextNode("]"));
},
_formatnode: function(object, elem)
{
function printNode(nodeId)
{
if (!nodeId)
return;
var treeOutline = new WebInspector.ElementsTreeOutline();
treeOutline.showInElementsPanelEnabled = true;
treeOutline.rootDOMNode = WebInspector.domAgent.nodeForId(nodeId);
treeOutline.element.addStyleClass("outline-disclosure");
if (!treeOutline.children[0].hasChildren)
treeOutline.element.addStyleClass("single-node");
elem.appendChild(treeOutline.element);
}
InjectedScriptAccess.pushNodeToFrontend(object, printNode);
},
_formatobject: function(obj, elem)
{
elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, obj.description, null, true).element);
},
_formaterror: function(obj, elem)
{
var messageElement = document.createElement("span");
messageElement.className = "error-message";
messageElement.textContent = obj.name + ": " + obj.message;
elem.appendChild(messageElement);
if (obj.sourceURL) {
var urlElement = document.createElement("a");
urlElement.className = "webkit-html-resource-link";
urlElement.href = obj.sourceURL;
urlElement.lineNumber = obj.line;
urlElement.preferredPanel = "scripts";
if (obj.line > 0)
urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL) + ":" + obj.line;
else
urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL);
elem.appendChild(document.createTextNode(" ("));
elem.appendChild(urlElement);
elem.appendChild(document.createTextNode(")"));
}
}
}
......@@ -673,62 +606,28 @@ WebInspector.ConsoleMessage.prototype = {
_format: function(parameters)
{
// This node is used like a Builder. Values are contintually appended onto it.
var formattedResult = document.createElement("span");
if (!parameters.length)
return formattedResult;
// Formatting code below assumes that parameters are all wrappers whereas frontend console
// API allows passing arbitrary values as messages (strings, numberts, etc.). Wrap them here.
for (var i = 0; i < parameters.length; ++i) {
// API allows passing arbitrary values as messages (strings, numbers, etc.). Wrap them here.
for (var i = 0; i < parameters.length; ++i)
if (typeof parameters[i] !== "object" && typeof parameters[i] !== "function")
parameters[i] = WebInspector.ObjectProxy.wrapPrimitiveValue(parameters[i]);
}
function formatForConsole(obj)
{
return WebInspector.console._format(obj);
}
function formatAsObjectForConsole(obj)
{
return WebInspector.console._format(obj, true);
}
if (Object.proxyType(parameters[0]) === "string") {
var formatters = {}
for (var i in String.standardFormatters)
formatters[i] = String.standardFormatters[i];
// Firebug uses %o for formatting objects.
formatters.o = formatForConsole;
// Firebug allows both %i and %d for formatting integers.
formatters.i = formatters.d;
// Support %O to force object formating, instead of the type-based %o formatting.
formatters.O = formatAsObjectForConsole;
function append(a, b)
{
if (!(b instanceof Node))
a.appendChild(WebInspector.linkifyStringAsFragment(b.toString()));
else
a.appendChild(b);
return a;
}
var result = String.format(parameters[0].description, parameters.slice(1), formatters, formattedResult, append);
formattedResult = result.formattedResult;
// Multiple parameters with the first being a format string. Save unused substitutions.
if (parameters.length > 1 && Object.proxyType(parameters[0]) === "string") {
var result = this._formatWithSubstitutionString(parameters, formattedResult)
parameters = result.unusedSubstitutions;
if (parameters.length)
formattedResult.appendChild(document.createTextNode(" "));
}
// Single parameter, or unused substitutions from above.
for (var i = 0; i < parameters.length; ++i) {
if (Object.proxyType(parameters[i]) === "string")
formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i].description));
else
formattedResult.appendChild(formatForConsole(parameters[i]));
this._formatIndividualValue(parameters[i], formattedResult);
if (i < parameters.length - 1)
formattedResult.appendChild(document.createTextNode(" "));
}
......@@ -736,6 +635,51 @@ WebInspector.ConsoleMessage.prototype = {
return formattedResult;
},
_formatWithSubstitutionString: function(parameters, formattedResult)
{
var formatters = {}
for (var i in String.standardFormatters)
formatters[i] = String.standardFormatters[i];
function consoleFormatWrapper(force)
{
return function(obj) {
return WebInspector.console._format(obj, force);
};
}
// Firebug uses %o for formatting objects.
formatters.o = consoleFormatWrapper();
// Firebug allows both %i and %d for formatting integers.
formatters.i = formatters.d;
// Support %O to force object formating, instead of the type-based %o formatting.
formatters.O = consoleFormatWrapper(true);
function append(a, b)
{
if (!(b instanceof Node))
a.appendChild(WebInspector.linkifyStringAsFragment(b.toString()));
else
a.appendChild(b);
return a;
}
// String.format does treat formattedResult like a Builder, result is an object.
return String.format(parameters[0].description, parameters.slice(1), formatters, formattedResult, append);
},
_formatIndividualValue: function(param, formattedResult)
{
if (Object.proxyType(param) === "string") {
if (this.originatingCommand && this.level === WebInspector.ConsoleMessage.MessageLevel.Log) {
var quotedString = "\"" + param.description.replace(/"/g, "\\\"") + "\"";
formattedResult.appendChild(WebInspector.linkifyStringAsFragment(quotedString));
} else
formattedResult.appendChild(WebInspector.linkifyStringAsFragment(param.description));
} else
formattedResult.appendChild(WebInspector.console._format(param));
},
toMessageElement: function()
{
if (this._element)
......@@ -983,9 +927,9 @@ WebInspector.ConsoleCommandResult = function(result, exception, originatingComma
var line = (exception ? result.line : -1);
var url = (exception ? result.sourceURL : null);
WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, WebInspector.ConsoleMessage.MessageType.Log, level, line, url, null, 1, message);
this.originatingCommand = originatingCommand;
WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, WebInspector.ConsoleMessage.MessageType.Log, level, line, url, null, 1, message);
}
WebInspector.ConsoleCommandResult.prototype = {
......
......@@ -1216,8 +1216,6 @@ Object.describe = function(obj, abbreviated)
else if (abbreviated)
objectText = /.*/.exec(obj)[0].replace(/ +$/g, "");
return objectText;
case "regexp":
return String(obj).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1);
default:
return String(obj);
}
......
......@@ -1464,7 +1464,7 @@ WebInspector.showResourceForURL = function(url, line, preferredPanel)
WebInspector.linkifyStringAsFragment = function(string)
{
var container = document.createDocumentFragment();
var linkStringRegEx = new RegExp("(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}://|www\\.)[\\w$\\-_+*'=\\|/\\\\(){}[\\]%@&#~,:;.!?]{2,}[\\w$\\-_+*=\\|/\\\\({%@&#~]");
var linkStringRegEx = /(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\/\/|www\.)[\w$\-_+*'=\|\/\\(){}[\]%@&#~,:;.!?]{2,}[\w$\-_+*=\|\/\\({%@&#~]/;
while (string) {
var linkString = linkStringRegEx.exec(string);
......
......@@ -178,7 +178,7 @@ Element.prototype.hasStyleClass = function(className)
{
if (!className)
return false;