diff options
Diffstat (limited to 'devtools/client/webconsole/new-console-output/components/console-output.js')
-rw-r--r-- | devtools/client/webconsole/new-console-output/components/console-output.js | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/devtools/client/webconsole/new-console-output/components/console-output.js b/devtools/client/webconsole/new-console-output/components/console-output.js new file mode 100644 index 000000000..1ba7f8dda --- /dev/null +++ b/devtools/client/webconsole/new-console-output/components/console-output.js @@ -0,0 +1,125 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +const { + createClass, + createFactory, + DOM: dom, + PropTypes +} = require("devtools/client/shared/vendor/react"); +const ReactDOM = require("devtools/client/shared/vendor/react-dom"); +const { connect } = require("devtools/client/shared/vendor/react-redux"); + +const { + getAllMessages, + getAllMessagesUiById, + getAllMessagesTableDataById, + getAllGroupsById, +} = require("devtools/client/webconsole/new-console-output/selectors/messages"); +const { getScrollSetting } = require("devtools/client/webconsole/new-console-output/selectors/ui"); +const MessageContainer = createFactory(require("devtools/client/webconsole/new-console-output/components/message-container").MessageContainer); + +const ConsoleOutput = createClass({ + + displayName: "ConsoleOutput", + + propTypes: { + messages: PropTypes.object.isRequired, + messagesUi: PropTypes.object.isRequired, + serviceContainer: PropTypes.shape({ + attachRefToHud: PropTypes.func.isRequired, + }), + autoscroll: PropTypes.bool.isRequired, + }, + + componentDidMount() { + scrollToBottom(this.outputNode); + this.props.serviceContainer.attachRefToHud("outputScroller", this.outputNode); + }, + + componentWillUpdate(nextProps, nextState) { + if (!this.outputNode) { + return; + } + + const outputNode = this.outputNode; + + // Figure out if we are at the bottom. If so, then any new message should be scrolled + // into view. + if (this.props.autoscroll && outputNode.lastChild) { + this.shouldScrollBottom = isScrolledToBottom(outputNode.lastChild, outputNode); + } + }, + + componentDidUpdate() { + if (this.shouldScrollBottom) { + scrollToBottom(this.outputNode); + } + }, + + render() { + let { + dispatch, + autoscroll, + messages, + messagesUi, + messagesTableData, + serviceContainer, + groups, + } = this.props; + + let messageNodes = messages.map((message) => { + const parentGroups = message.groupId ? ( + (groups.get(message.groupId) || []) + .concat([message.groupId]) + ) : []; + + return ( + MessageContainer({ + dispatch, + message, + key: message.id, + serviceContainer, + open: messagesUi.includes(message.id), + tableData: messagesTableData.get(message.id), + autoscroll, + indent: parentGroups.length, + }) + ); + }); + return ( + dom.div({ + className: "webconsole-output", + ref: node => { + this.outputNode = node; + }, + }, messageNodes + ) + ); + } +}); + +function scrollToBottom(node) { + node.scrollTop = node.scrollHeight; +} + +function isScrolledToBottom(outputNode, scrollNode) { + let lastNodeHeight = outputNode.lastChild ? + outputNode.lastChild.clientHeight : 0; + return scrollNode.scrollTop + scrollNode.clientHeight >= + scrollNode.scrollHeight - lastNodeHeight / 2; +} + +function mapStateToProps(state, props) { + return { + messages: getAllMessages(state), + messagesUi: getAllMessagesUiById(state), + messagesTableData: getAllMessagesTableDataById(state), + autoscroll: getScrollSetting(state), + groups: getAllGroupsById(state), + }; +} + +module.exports = connect(mapStateToProps)(ConsoleOutput); |