Bug 1389803 - Scroll the console to the bottom on Evaluation result. r=bgrins
This ensures that we scroll to the bottom when the user evaluate
something in the console.
A test is added to make sure this works as expected.
MozReview-Commit-ID: Arh6rftQeKo
--- a/devtools/client/webconsole/new-console-output/components/console-output.js
+++ b/devtools/client/webconsole/new-console-output/components/console-output.js
@@ -17,16 +17,19 @@ const {
getAllMessagesTableDataById,
getAllMessagesObjectPropertiesById,
getAllMessagesObjectEntriesById,
getAllNetworkMessagesUpdateById,
getVisibleMessages,
getAllRepeatById,
} = require("devtools/client/webconsole/new-console-output/selectors/messages");
const MessageContainer = createFactory(require("devtools/client/webconsole/new-console-output/components/message-container").MessageContainer);
+const {
+ MESSAGE_TYPE,
+} = require("devtools/client/webconsole/new-console-output/constants");
const ConsoleOutput = createClass({
displayName: "ConsoleOutput",
propTypes: {
messages: PropTypes.object.isRequired,
messagesUi: PropTypes.object.isRequired,
@@ -55,21 +58,30 @@ const ConsoleOutput = createClass({
},
componentWillUpdate(nextProps, nextState) {
const outputNode = this.outputNode;
if (!outputNode || !outputNode.lastChild) {
return;
}
- // Figure out if we are at the bottom. If so, then any new message should be scrolled
- // into view.
const lastChild = outputNode.lastChild;
- const delta = nextProps.visibleMessages.length - this.props.visibleMessages.length;
- this.shouldScrollBottom = delta > 0 && isScrolledToBottom(lastChild, outputNode);
+ const visibleMessagesDelta =
+ nextProps.visibleMessages.length - this.props.visibleMessages.length;
+ const messagesDelta =
+ nextProps.messages.length - this.props.messages.length;
+
+ // We need to scroll to the bottom if:
+ // - the number of messages displayed changed
+ // and we are already scrolled to the bottom
+ // - the number of messages in the store changed
+ // and the new message is an evaluation result.
+ this.shouldScrollBottom =
+ (messagesDelta > 0 && nextProps.messages.last().type === MESSAGE_TYPE.RESULT) ||
+ (visibleMessagesDelta > 0 && isScrolledToBottom(lastChild, outputNode));
},
componentDidUpdate() {
if (this.shouldScrollBottom) {
scrollToBottom(this.outputNode);
}
},
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -49,16 +49,17 @@ skip-if = (os == 'linux' && bits == 32 &
[browser_webconsole_location_styleeditor_link.js]
[browser_webconsole_logErrorInPage.js]
[browser_webconsole_network_messages_click.js]
[browser_webconsole_nodes_highlight.js]
[browser_webconsole_nodes_select.js]
[browser_webconsole_object_inspector_entries.js]
[browser_webconsole_object_inspector.js]
[browser_webconsole_observer_notifications.js]
+[browser_webconsole_scroll.js]
[browser_webconsole_shows_reqs_in_netmonitor.js]
[browser_webconsole_sourcemap_error.js]
[browser_webconsole_sourcemap_nosource.js]
[browser_webconsole_stacktrace_location_debugger_link.js]
[browser_webconsole_stacktrace_location_scratchpad_link.js]
[browser_webconsole_string.js]
[browser_webconsole_timestamps.js]
[browser_webconsole_warn_about_replaced_api.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_scroll.js
@@ -0,0 +1,69 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for " +
+ "scroll behavior";
+add_task(async function () {
+ const hud = await openNewTabAndConsole(TEST_URI);
+ let {ui} = hud;
+
+ info("Waiting for logged messages");
+
+ let receievedMessages = waitForMessages({hud, messages: [{
+ text: "init-99"
+ }]});
+ ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
+ for (let i = 0; i < 100; i++) {
+ content.wrappedJSObject.console.log("init-" + i);
+ }
+ });
+ await receievedMessages;
+
+ const outputContainer = ui.outputNode.querySelector(".webconsole-output");
+ ok(outputContainer.scrollHeight > outputContainer.clientHeight,
+ "There is a vertical overflow");
+
+ info("Scroll up");
+ outputContainer.scrollTop = 0;
+
+ info("Add a message to check that the scroll isn't impacted");
+ receievedMessages = waitForMessages({hud, messages: [{
+ text: "stay"
+ }]});
+ ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
+ content.wrappedJSObject.console.log("stay");
+ });
+ await receievedMessages;
+ is(outputContainer.scrollTop, 0, "The console stayed scrolled to the top");
+
+ info("Evaluate a command to check that the console scrolls to the bottom");
+ receievedMessages = waitForMessages({hud, messages: [{
+ text: "42"
+ }]});
+ ui.jsterm.execute("21 + 21");
+ await receievedMessages;
+ is(isScrolledToBottom(outputContainer), true, "The console is scrolled to the bottom");
+
+ info("Add a message to check that the console do scroll since we're at the bottom");
+ receievedMessages = waitForMessages({hud, messages: [{
+ text: "scroll"
+ }]});
+ ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
+ content.wrappedJSObject.console.log("scroll");
+ });
+ await receievedMessages;
+ is(isScrolledToBottom(outputContainer), true, "The console is scrolled to the bottom");
+});
+
+function isScrolledToBottom(container) {
+ if (!container.lastChild) {
+ return true;
+ }
+ let lastNodeHeight = container.lastChild.clientHeight;
+ return container.scrollTop + container.clientHeight >=
+ container.scrollHeight - lastNodeHeight / 2;
+}