diff --git a/browser/devtools/inspector/test/browser_inspector_menu.js b/browser/devtools/inspector/test/browser_inspector_menu.js index 8c7184be8e78..eef6ee7c7e40 100644 --- a/browser/devtools/inspector/test/browser_inspector_menu.js +++ b/browser/devtools/inspector/test/browser_inspector_menu.js @@ -167,7 +167,7 @@ let test = asyncTest(function* () { yield consoleOpened; let webconsoleUI = toolbox.getPanel("webconsole").hud.ui; - let messagesAdded = webconsoleUI.once("messages-added"); + let messagesAdded = webconsoleUI.once("new-messages"); yield messagesAdded; info("Checking if 'inspect($0)' was evaluated"); diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_wrong_window_focus.js b/browser/devtools/scratchpad/test/browser_scratchpad_wrong_window_focus.js index 2ea1059ead5c..f8db7fdfc0a2 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_wrong_window_focus.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_wrong_window_focus.js @@ -47,8 +47,9 @@ function testFocus(sw, hud) { function onMessage(event, messages) { let msg = [...messages][0]; + let node = msg.node; - var loc = msg.querySelector(".message-location"); + var loc = node.querySelector(".message-location"); ok(loc, "location element exists"); is(loc.textContent.trim(), sw.Scratchpad.uniqueName + ":1", "location value is correct"); @@ -74,7 +75,7 @@ function testFocus(sw, hud) { // Sending messages to web console is an asynchronous operation. That's // why we have to setup an observer here. - hud.ui.once("messages-added", onMessage); + hud.ui.once("new-messages", onMessage); sp.setText("console.log('foo');"); sp.run().then(function ([selection, error, result]) { diff --git a/browser/devtools/webconsole/console-output.js b/browser/devtools/webconsole/console-output.js index 4dc34edefd23..cb87c87ae8aa 100644 --- a/browser/devtools/webconsole/console-output.js +++ b/browser/devtools/webconsole/console-output.js @@ -565,17 +565,21 @@ Messages.BaseMessage.prototype = { * * @constructor * @extends Messages.BaseMessage - * @param string url - * The URL to display. + * @param object response + * The response received from the back end. * @param number timestamp * The message date and time, milliseconds elapsed since 1 January 1970 * 00:00:00 UTC. */ -Messages.NavigationMarker = function(url, timestamp) +Messages.NavigationMarker = function(response, timestamp) { Messages.BaseMessage.call(this); - this._url = url; - this.textContent = "------ " + url; + + // Store the response packet received from the server. It might + // be useful for extensions customizing the console output. + this.response = response; + this._url = response.url; + this.textContent = "------ " + this._url; this.timestamp = timestamp; }; @@ -1204,6 +1208,10 @@ Messages.JavaScriptEvalOutput = function(evalResponse, errorMessage) { let severity = "log", msg, quoteStrings = true; + // Store also the response packet from the back end. It might + // be useful to extensions customizing the console output. + this.response = evalResponse; + if (errorMessage) { severity = "error"; msg = errorMessage; @@ -3258,7 +3266,11 @@ Widgets.LongString.prototype = Heritage.extend(Widgets.BaseWidget.prototype, this._renderString(this.longStringActor.initial + response.substring); - this.output.owner.emit("messages-updated", new Set([this.message.element])); + this.output.owner.emit("new-messages", new Set([{ + update: true, + node: this.message.element, + response: response, + }])); let toIndex = Math.min(this.longStringActor.length, MAX_LONG_STRING_LENGTH); if (toIndex != this.longStringActor.length) { diff --git a/browser/devtools/webconsole/test/head.js b/browser/devtools/webconsole/test/head.js index fee01e8797d1..e6b44c964301 100644 --- a/browser/devtools/webconsole/test/head.js +++ b/browser/devtools/webconsole/test/head.js @@ -1302,9 +1302,10 @@ function waitForMessages(aOptions) return aRule.matched.size == count; } - function onMessagesAdded(aEvent, aNewElements) + function onMessagesAdded(aEvent, aNewMessages) { - for (let elem of aNewElements) { + for (let msg of aNewMessages) { + let elem = msg.node; let location = elem.querySelector(".message-location"); if (location) { let url = location.title; @@ -1343,8 +1344,7 @@ function waitForMessages(aOptions) { if (allRulesMatched()) { if (listenerAdded) { - webconsole.ui.off("messages-added", onMessagesAdded); - webconsole.ui.off("messages-updated", onMessagesAdded); + webconsole.ui.off("new-messages", onMessagesAdded); } gPendingOutputTest--; deferred.resolve(rules); @@ -1359,7 +1359,7 @@ function waitForMessages(aOptions) } if (webconsole.ui) { - webconsole.ui.off("messages-added", onMessagesAdded); + webconsole.ui.off("new-messages", onMessagesAdded); } for (let rule of rules) { @@ -1382,12 +1382,21 @@ function waitForMessages(aOptions) } executeSoon(() => { - onMessagesAdded("messages-added", webconsole.outputNode.childNodes); + + let messages = []; + for (let elem of webconsole.outputNode.childNodes) { + messages.push({ + node: elem, + update: false, + }); + } + + onMessagesAdded("new-messages", messages); + if (!allRulesMatched()) { listenerAdded = true; registerCleanupFunction(testCleanup); - webconsole.ui.on("messages-added", onMessagesAdded); - webconsole.ui.on("messages-updated", onMessagesAdded); + webconsole.ui.on("new-messages", onMessagesAdded); } }); diff --git a/browser/devtools/webconsole/webconsole.js b/browser/devtools/webconsole/webconsole.js index 899dfaaa7430..0813288c9a09 100644 --- a/browser/devtools/webconsole/webconsole.js +++ b/browser/devtools/webconsole/webconsole.js @@ -471,7 +471,7 @@ WebConsoleFrame.prototype = { }, (aReason) => { // on failure let node = this.createMessageNode(CATEGORY_JS, SEVERITY_ERROR, aReason.error + ": " + aReason.message); - this.outputMessage(CATEGORY_JS, node); + this.outputMessage(CATEGORY_JS, node, [aReason]); this._initDefer.reject(aReason); }).then(() => { let id = WebConsoleUtils.supportsString(this.hudId); @@ -1454,14 +1454,15 @@ WebConsoleFrame.prototype = { /** * Log network event. * - * @param object aActorId - * The network event actor ID to log. + * @param object aActor + * The network event actor to log. * @return nsIDOMElement|null * The message element to display in the Web Console output. */ - logNetEvent: function WCF_logNetEvent(aActorId) + logNetEvent: function WCF_logNetEvent(aActor) { - let networkInfo = this._networkRequests[aActorId]; + let actorId = aActor.actor; + let networkInfo = this._networkRequests[actorId]; if (!networkInfo) { return null; } @@ -1485,7 +1486,7 @@ WebConsoleFrame.prototype = { if (networkInfo.private) { messageNode.setAttribute("private", true); } - messageNode._connectionId = aActorId; + messageNode._connectionId = actorId; messageNode.url = request.url; let body = methodNode.parentNode; @@ -1526,7 +1527,7 @@ WebConsoleFrame.prototype = { networkInfo.node = messageNode; - this._updateNetMessage(aActorId); + this._updateNetMessage(actorId); return messageNode; }, @@ -1730,7 +1731,7 @@ WebConsoleFrame.prototype = { }; this._networkRequests[aActor.actor] = networkInfo; - this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [aActor.actor]); + this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [aActor]); }, /** @@ -1781,7 +1782,11 @@ WebConsoleFrame.prototype = { } if (networkInfo.node && this._updateNetMessage(aActorId)) { - this.emit("messages-updated", new Set([networkInfo.node])); + this.emit("new-messages", new Set([{ + update: true, + node: networkInfo.node, + response: aPacket, + }])); } // For unit tests we pass the HTTP activity object to the test callback, @@ -2009,7 +2014,7 @@ WebConsoleFrame.prototype = { { if (aEvent == "will-navigate") { if (this.persistLog) { - let marker = new Messages.NavigationMarker(aPacket.url, Date.now()); + let marker = new Messages.NavigationMarker(aPacket, Date.now()); this.output.addMessage(marker); } else { @@ -2042,7 +2047,9 @@ WebConsoleFrame.prototype = { * object and the arguments will be |aArguments|. * @param array [aArguments] * If a method is given to output the message element then the method - * will be invoked with the list of arguments given here. + * will be invoked with the list of arguments given here. The last + * object in this array should be the packet received from the + * back end. */ outputMessage: function WCF_outputMessage(aCategory, aMethodOrNode, aArguments) { @@ -2114,18 +2121,17 @@ WebConsoleFrame.prototype = { Utils.isOutputScrolledToBottom(outputNode); // Output the current batch of messages. - let newMessages = new Set(); - let updatedMessages = new Set(); + let messages = new Set(); for (let i = 0; i < batch.length; i++) { let item = batch[i]; let result = this._outputMessageFromQueue(hudIdSupportsString, item); if (result) { - if (result.isRepeated) { - updatedMessages.add(result.isRepeated); - } - else { - newMessages.add(result.node); - } + messages.add({ + node: result.isRepeated ? result.isRepeated : result.node, + response: result.message, + update: !!result.isRepeated, + }); + if (result.visible && result.node == this.outputNode.lastChild) { lastVisibleNode = result.node; } @@ -2167,11 +2173,8 @@ WebConsoleFrame.prototype = { scrollNode.scrollTop -= oldScrollHeight - scrollNode.scrollHeight; } - if (newMessages.size) { - this.emit("messages-added", newMessages); - } - if (updatedMessages.size) { - this.emit("messages-updated", updatedMessages); + if (messages.size) { + this.emit("new-messages", messages); } // If the output queue is empty, then run _flushCallback. @@ -2228,6 +2231,10 @@ WebConsoleFrame.prototype = { { let [category, methodOrNode, args] = aItem; + // The last object in the args array should be message + // object or response packet received from the server. + let message = (args && args.length) ? args[args.length-1] : null; + let node = typeof methodOrNode == "function" ? methodOrNode.apply(this, args || []) : methodOrNode; @@ -2265,6 +2272,7 @@ WebConsoleFrame.prototype = { visible: visible, node: node, isRepeated: isRepeated, + message: message }; }, @@ -2342,7 +2350,7 @@ WebConsoleFrame.prototype = { if (category == CATEGORY_NETWORK) { let connectionId = null; if (methodOrNode == this.logNetEvent) { - connectionId = args[0]; + connectionId = args[0].actor; } else if (typeof methodOrNode != "function") { connectionId = methodOrNode._connectionId;