From 43aa7edc0fe630742f77ac64f41f9fcdbb8ebcd9 Mon Sep 17 00:00:00 2001 From: Panos Astithas Date: Tue, 14 Jun 2011 14:38:11 +0300 Subject: [PATCH] Bug 664131 - Expand console object with group methods that indent future console messages in order to create separate blocks of visually combined output; r=gavin --- browser/devtools/webconsole/HUDService.jsm | 48 ++++++++++++++--- .../webconsole/test/browser/Makefile.in | 1 + ...browser_webconsole_bug_642108_pruneTest.js | 6 ++- ...ser_webconsole_bug_664131_console_group.js | 48 +++++++++++++++++ .../test/browser/test-console-extras.html | 3 -- dom/base/ConsoleAPI.js | 24 ++++++++- dom/tests/browser/browser_ConsoleAPITests.js | 52 +++++++++++++++++-- dom/tests/browser/test-console-api.html | 7 +++ .../mochitest/general/test_consoleAPI.html | 3 ++ 9 files changed, 177 insertions(+), 15 deletions(-) create mode 100644 browser/devtools/webconsole/test/browser/browser_webconsole_bug_664131_console_group.js diff --git a/browser/devtools/webconsole/HUDService.jsm b/browser/devtools/webconsole/HUDService.jsm index 6956922f8c3c..4427c6abac00 100644 --- a/browser/devtools/webconsole/HUDService.jsm +++ b/browser/devtools/webconsole/HUDService.jsm @@ -165,7 +165,10 @@ const LEVELS = { info: SEVERITY_INFO, log: SEVERITY_LOG, trace: SEVERITY_LOG, - dir: SEVERITY_LOG + dir: SEVERITY_LOG, + group: SEVERITY_LOG, + groupCollapsed: SEVERITY_LOG, + groupEnd: SEVERITY_LOG }; // The lowest HTTP response code (inclusive) that is considered an error. @@ -252,6 +255,9 @@ const ERRORS = { LOG_MESSAGE_MISSING_ARGS: LOG_OUTPUT_FAILED: "Log Failure: Could not append messageNode to outputNode", }; +// The indent of a console group in pixels. +const GROUP_INDENT = 12; + /** * Implements the nsIStreamListener and nsIRequestObserver interface. Used * within the HS_httpObserverFactory function to get the response body of @@ -2005,6 +2011,20 @@ HUD_SERVICE.prototype = sourceLine = aMessage.lineNumber; break; + case "group": + case "groupCollapsed": + clipboardText = body = formatResult(args); + sourceURL = aMessage.filename; + sourceLine = aMessage.lineNumber; + hud.groupDepth++; + break; + + case "groupEnd": + if (hud.groupDepth > 0) { + hud.groupDepth--; + } + return; + default: Cu.reportError("Unknown Console API log level: " + level); return; @@ -2014,6 +2034,7 @@ HUD_SERVICE.prototype = CATEGORY_WEBDEV, LEVELS[level], body, + aHUDId, sourceURL, sourceLine, clipboardText, @@ -2076,7 +2097,8 @@ HUD_SERVICE.prototype = let chromeDocument = hud.HUDBox.ownerDocument; let message = stringBundle.GetStringFromName("ConsoleAPIDisabled"); let node = ConsoleUtils.createMessageNode(chromeDocument, CATEGORY_JS, - SEVERITY_WARNING, message); + SEVERITY_WARNING, message, + aHUDId); ConsoleUtils.outputMessageNode(node, aHUDId); }, @@ -2116,6 +2138,7 @@ HUD_SERVICE.prototype = aCategory, severity, aScriptError.errorMessage, + hudId, aScriptError.sourceName, aScriptError.lineNumber); @@ -2576,6 +2599,7 @@ HUD_SERVICE.prototype = CATEGORY_NETWORK, SEVERITY_LOG, msgNode, + hudId, null, null, clipboardText); @@ -3081,6 +3105,11 @@ HeadsUpDisplay.prototype = { consolePanel: null, + /** + * The nesting depth of the currently active console group. + */ + groupDepth: 0, + get mainPopupSet() { return this.chromeDocument.getElementById("mainPopupSet"); @@ -4752,7 +4781,8 @@ JSTerm.prototype = { let node = ConsoleUtils.createMessageNode(this.parentNode.ownerDocument, CATEGORY_OUTPUT, SEVERITY_LOG, - aOutputString); + aOutputString, + this.hudId); let linkNode = node.querySelector(".webconsole-msg-body"); @@ -4799,7 +4829,7 @@ JSTerm.prototype = { { let node = ConsoleUtils.createMessageNode(this.parentNode.ownerDocument, aCategory, aSeverity, - aOutputMessage); + aOutputMessage, this.hudId); ConsoleUtils.outputMessageNode(node, this.hudId); }, @@ -5540,6 +5570,8 @@ ConsoleUtils = { * The severity of the message: one of the SEVERITY_* constants; * @param string|nsIDOMNode aBody * The body of the message, either a simple string or a DOM node. + * @param number aHUDId + * The HeadsUpDisplay ID. * @param string aSourceURL [optional] * The URL of the source file that emitted the error. * @param number aSourceLine [optional] @@ -5557,8 +5589,8 @@ ConsoleUtils = { */ createMessageNode: function ConsoleUtils_createMessageNode(aDocument, aCategory, aSeverity, - aBody, aSourceURL, aSourceLine, - aClipboardText, aLevel) { + aBody, aHUDId, aSourceURL, + aSourceLine, aClipboardText, aLevel) { if (aBody instanceof Ci.nsIDOMNode && aClipboardText == null) { throw new Error("HUDService.createMessageNode(): DOM node supplied " + "without any clipboard text"); @@ -5569,6 +5601,9 @@ ConsoleUtils = { // long multi-line messages. let iconContainer = aDocument.createElementNS(XUL_NS, "vbox"); iconContainer.classList.add("webconsole-msg-icon-container"); + // Apply the curent group by indenting appropriately. + let hud = HUDService.getHudReferenceById(aHUDId); + iconContainer.style.marginLeft = hud.groupDepth * GROUP_INDENT + "px"; // Make the icon node. It's sprited and the actual region of the image is // determined by CSS rules. @@ -6669,6 +6704,7 @@ ConsoleProgressListener.prototype = { CATEGORY_NETWORK, SEVERITY_LOG, msgNode, + this.hudId, null, null, uri.spec); diff --git a/browser/devtools/webconsole/test/browser/Makefile.in b/browser/devtools/webconsole/test/browser/Makefile.in index edad7719b014..29fb8618054a 100644 --- a/browser/devtools/webconsole/test/browser/Makefile.in +++ b/browser/devtools/webconsole/test/browser/Makefile.in @@ -145,6 +145,7 @@ _BROWSER_TEST_FILES = \ browser_webconsole_bug_653531_highlighter_console_helper.js \ browser_webconsole_bug_659907_console_dir.js \ browser_webconsole_bug_678816.js \ + browser_webconsole_bug_664131_console_group.js \ head.js \ $(NULL) diff --git a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_642108_pruneTest.js b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_642108_pruneTest.js index e580697e7eb4..e2ba415b8706 100644 --- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_642108_pruneTest.js +++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_642108_pruneTest.js @@ -25,7 +25,8 @@ function populateConsoleRepeats(aHudRef) { let node = ConsoleUtils.createMessageNode(hud.ownerDocument, CATEGORY_CSS, SEVERITY_WARNING, - "css log x"); + "css log x", + aHudRef.hudId); ConsoleUtils.outputMessageNode(node, aHudRef.hudId); } } @@ -38,7 +39,8 @@ function populateConsole(aHudRef) { let node = ConsoleUtils.createMessageNode(hud.ownerDocument, CATEGORY_CSS, SEVERITY_WARNING, - "css log " + i); + "css log " + i, + aHudRef.hudId); ConsoleUtils.outputMessageNode(node, aHudRef.hudId); } } diff --git a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_664131_console_group.js b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_664131_console_group.js new file mode 100644 index 000000000000..b6fbdc5c8c30 --- /dev/null +++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_664131_console_group.js @@ -0,0 +1,48 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Tests that console.group/groupEnd works as intended. +const GROUP_INDENT = 12; + +function test() { + addTab("data:text/html,Web Console test for bug 664131: Expand console " + + "object with group methods"); + browser.addEventListener("load", onLoad, true); +} + +function onLoad(aEvent) { + browser.removeEventListener(aEvent.type, arguments.callee, true); + + openConsole(); + let hudId = HUDService.getHudIdByWindow(content); + let hud = HUDService.hudReferences[hudId]; + outputNode = hud.outputNode; + + content.console.group("a"); + findLogEntry("a"); + let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container"); + is(msg.length, 1, "one message node displayed"); + is(msg[0].style.marginLeft, GROUP_INDENT + "px", "correct group indent found"); + content.console.log("inside"); + findLogEntry("inside"); + let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container"); + is(msg.length, 2, "two message nodes displayed"); + is(msg[1].style.marginLeft, GROUP_INDENT + "px", "correct group indent found"); + content.console.groupEnd("a"); + content.console.log("outside"); + findLogEntry("outside"); + let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container"); + is(msg.length, 3, "three message nodes displayed"); + is(msg[2].style.marginLeft, "0px", "correct group indent found"); + content.console.groupCollapsed("b"); + findLogEntry("b"); + let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container"); + is(msg.length, 4, "four message nodes displayed"); + is(msg[3].style.marginLeft, GROUP_INDENT + "px", "correct group indent found"); + + finishTest(); +} + diff --git a/browser/devtools/webconsole/test/browser/test-console-extras.html b/browser/devtools/webconsole/test/browser/test-console-extras.html index 706a1a2daaf8..ff23b6442111 100644 --- a/browser/devtools/webconsole/test/browser/test-console-extras.html +++ b/browser/devtools/webconsole/test/browser/test-console-extras.html @@ -10,9 +10,6 @@ console.assert() console.clear() console.dirxml() - console.group() - console.groupCollapsed() - console.groupEnd() console.profile() console.profileEnd() console.count() diff --git a/dom/base/ConsoleAPI.js b/dom/base/ConsoleAPI.js index f0b80ac5d77a..146c6733d2a3 100644 --- a/dom/base/ConsoleAPI.js +++ b/dom/base/ConsoleAPI.js @@ -94,6 +94,15 @@ ConsoleAPI.prototype = { dir: function CA_dir() { self.notifyObservers(outerID, innerID, "dir", arguments); }, + group: function CA_group() { + self.notifyObservers(outerID, innerID, "group", self.beginGroup(arguments)); + }, + groupCollapsed: function CA_groupCollapsed() { + self.notifyObservers(outerID, innerID, "groupCollapsed", self.beginGroup(arguments)); + }, + groupEnd: function CA_groupEnd() { + self.notifyObservers(outerID, innerID, "groupEnd", arguments); + }, __exposedProps__: { log: "r", info: "r", @@ -101,7 +110,10 @@ ConsoleAPI.prototype = { error: "r", debug: "r", trace: "r", - dir: "r" + dir: "r", + group: "r", + groupCollapsed: "r", + groupEnd: "r" } }; @@ -120,6 +132,9 @@ ConsoleAPI.prototype = { debug: genPropDesc('debug'), trace: genPropDesc('trace'), dir: genPropDesc('dir'), + group: genPropDesc('group'), + groupCollapsed: genPropDesc('groupCollapsed'), + groupEnd: genPropDesc('groupEnd'), __noSuchMethod__: { enumerable: true, configurable: true, writable: true, value: function() {} }, __mozillaConsole__: { value: true } @@ -229,6 +244,13 @@ ConsoleAPI.prototype = { } return stack; + }, + + /** + * Begin a new group for logging output together. + **/ + beginGroup: function CA_beginGroup() { + return Array.prototype.join.call(arguments[0], " "); } }; diff --git a/dom/tests/browser/browser_ConsoleAPITests.js b/dom/tests/browser/browser_ConsoleAPITests.js index 9307e14c9855..a77ea6fbe42a 100644 --- a/dom/tests/browser/browser_ConsoleAPITests.js +++ b/dom/tests/browser/browser_ConsoleAPITests.js @@ -108,9 +108,52 @@ function testLocationData(aMessageObject) { is(aMessageObject.arguments[i], a, "correct arg " + i); }); - // Test finished - ConsoleObserver.destroy(); - finish(); + startGroupTest(); +} + +function startGroupTest() { + // Reset the observer function to cope with the fabricated test data. + ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) { + try { + testConsoleGroup(aSubject.wrappedJSObject); + } catch (ex) { + // XXX Exceptions in this function currently aren't reported, because of + // some XPConnect weirdness, so report them manually + ok(false, "Exception thrown in CO_observe: " + ex); + } + }; + let button = gWindow.document.getElementById("test-groups"); + ok(button, "found #test-groups button"); + EventUtils.synthesizeMouse(button, 2, 2, {}, gWindow); +} + +function testConsoleGroup(aMessageObject) { + let messageWindow = getWindowByWindowId(aMessageObject.ID); + is(messageWindow, gWindow, "found correct window by window ID"); + + ok(aMessageObject.level == "group" || + aMessageObject.level == "groupCollapsed" || + aMessageObject.level == "groupEnd", + "expected level received"); + + is(aMessageObject.functionName, "testGroups", "functionName matches"); + ok(aMessageObject.lineNumber >= 32 && aMessageObject.lineNumber <= 34, + "lineNumber matches"); + if (aMessageObject.level == "groupCollapsed") { + ok(aMessageObject.arguments == "a group", "groupCollapsed arguments matches"); + } + else if (aMessageObject.level == "group") { + ok(aMessageObject.arguments == "b group", "group arguments matches"); + } + else if (aMessageObject.level == "groupEnd") { + ok(Array.prototype.join.call(aMessageObject.arguments, " ") == "b group", "groupEnd arguments matches"); + } + + if (aMessageObject.level == "groupEnd") { + // Test finished + ConsoleObserver.destroy(); + finish(); + } } function startTraceTest() { @@ -195,6 +238,9 @@ function consoleAPISanityTest() { ok(win.console.error, "console.error is here"); ok(win.console.trace, "console.trace is here"); ok(win.console.dir, "console.dir is here"); + ok(win.console.group, "console.group is here"); + ok(win.console.groupCollapsed, "console.groupCollapsed is here"); + ok(win.console.groupEnd, "console.groupEnd is here"); } var ConsoleObserver = { diff --git a/dom/tests/browser/test-console-api.html b/dom/tests/browser/test-console-api.html index 58dc264750f7..96066ae24773 100644 --- a/dom/tests/browser/test-console-api.html +++ b/dom/tests/browser/test-console-api.html @@ -27,6 +27,12 @@ console.warn(str); console.error(str); } + + function testGroups() { + console.groupCollapsed("a", "group"); + console.group("b", "group"); + console.groupEnd("b", "group"); + } @@ -34,5 +40,6 @@ + diff --git a/dom/tests/mochitest/general/test_consoleAPI.html b/dom/tests/mochitest/general/test_consoleAPI.html index 6ebc02fafbf7..a82ede0d7c2d 100644 --- a/dom/tests/mochitest/general/test_consoleAPI.html +++ b/dom/tests/mochitest/general/test_consoleAPI.html @@ -27,6 +27,9 @@ function doTest() { "debug": "function", "trace": "function", "dir": "function", + "group": "function", + "groupCollapsed": "function", + "groupEnd": "function", "__noSuchMethod__": "function" };