diff options
author | Christopher Speller <crspeller@gmail.com> | 2015-09-09 08:22:06 -0400 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2015-09-09 08:22:06 -0400 |
commit | b15b297bb3b5ae6dc6d336b0a333e967b31092bf (patch) | |
tree | b48a89da07b0c6b1d07692c532b85ee745cb45f0 /web/react/components/post_list.jsx | |
parent | 64d4890a4109618b383f7cfe1acc541bd72a0899 (diff) | |
parent | 5c0680397de9d3cfd0018743e0b1d58dfbdca25d (diff) | |
download | chat-b15b297bb3b5ae6dc6d336b0a333e967b31092bf.tar.gz chat-b15b297bb3b5ae6dc6d336b0a333e967b31092bf.tar.bz2 chat-b15b297bb3b5ae6dc6d336b0a333e967b31092bf.zip |
Merge pull request #623 from mattermost/plt-35
PLT-35 Add post list container to hold mounted post lists for faster rendering/channel switching.
Diffstat (limited to 'web/react/components/post_list.jsx')
-rw-r--r-- | web/react/components/post_list.jsx | 202 |
1 files changed, 103 insertions, 99 deletions
diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx index 6fa87ca4a..d7c0d4862 100644 --- a/web/react/components/post_list.jsx +++ b/web/react/components/post_list.jsx @@ -18,8 +18,8 @@ var ActionTypes = Constants.ActionTypes; import {strings} from '../utils/config.js'; export default class PostList extends React.Component { - constructor() { - super(); + constructor(props) { + super(props); this.gotMorePosts = false; this.scrolled = false; @@ -27,6 +27,7 @@ export default class PostList extends React.Component { this.seenNewMessages = false; this.isUserScroll = true; this.userHasSeenNew = false; + this.loadInProgress = false; this.onChange = this.onChange.bind(this); this.onTimeChange = this.onTimeChange.bind(this); @@ -34,22 +35,19 @@ export default class PostList extends React.Component { this.createChannelIntroMessage = this.createChannelIntroMessage.bind(this); this.loadMorePosts = this.loadMorePosts.bind(this); this.loadFirstPosts = this.loadFirstPosts.bind(this); + this.activate = this.activate.bind(this); + this.deactivate = this.deactivate.bind(this); + this.resize = this.resize.bind(this); - this.state = this.getStateFromStores(); + this.state = this.getStateFromStores(props.channelId); this.state.numToDisplay = Constants.POST_CHUNK_SIZE; this.state.isFirstLoadComplete = false; } - getStateFromStores() { - var channel = ChannelStore.getCurrent(); - - if (channel == null) { - channel = {}; - } - - var postList = PostStore.getCurrentPosts(); + getStateFromStores(id) { + var postList = PostStore.getPosts(id); if (postList != null) { - var deletedPosts = PostStore.getUnseenDeletedPosts(channel.id); + var deletedPosts = PostStore.getUnseenDeletedPosts(id); if (deletedPosts && Object.keys(deletedPosts).length > 0) { for (var pid in deletedPosts) { @@ -70,7 +68,7 @@ export default class PostList extends React.Component { }); } - var pendingPostList = PostStore.getPendingPosts(channel.id); + var pendingPostList = PostStore.getPendingPosts(id); if (pendingPostList) { postList.order = pendingPostList.order.concat(postList.order); @@ -82,43 +80,42 @@ export default class PostList extends React.Component { } } - var lastViewed = Number.MAX_VALUE; - - if (ChannelStore.getCurrentMember() != null) { - lastViewed = ChannelStore.getCurrentMember().last_viewed_at; - } - return { - postList: postList, - channel: channel, - lastViewed: lastViewed + postList: postList }; } componentDidMount() { + if (this.props.isActive) { + this.activate(); + this.loadFirstPosts(this.props.channelId); + } + } + componentWillUnmount() { + this.deactivate(); + } + activate() { + this.gotMorePosts = false; + this.scrolled = false; + this.prevScrollTop = 0; + this.seenNewMessages = false; + this.isUserScroll = true; + this.userHasSeenNew = false; + + PostStore.clearUnseenDeletedPosts(this.props.channelId); PostStore.addChangeListener(this.onChange); - ChannelStore.addChangeListener(this.onChange); UserStore.addStatusesChangeListener(this.onTimeChange); SocketStore.addChangeListener(this.onSocketChange); - var postHolder = $('.post-list-holder-by-time'); - - $('.modal').on('show.bs.modal', function onShow() { - $('.modal-body').css('overflow-y', 'auto'); - $('.modal-body').css('max-height', $(window).height() * 0.7); - }); - - $(window).resize(function resize() { - if ($('#create_post').length > 0) { - var height = $(window).height() - $('#create_post').height() - $('#error_bar').outerHeight() - 50; - postHolder.css('height', height + 'px'); - } + var postHolder = $(React.findDOMNode(this.refs.postlist)); + $(window).on('resize.' + this.props.channelId, function resize() { + this.resize(); if (!this.scrolled) { this.scrollToBottom(); } }.bind(this)); - postHolder.scroll(function scroll() { + postHolder.on('scroll', function scroll() { var position = postHolder.scrollTop() + postHolder.height() + 14; var bottom = postHolder[0].scrollHeight; @@ -134,41 +131,25 @@ export default class PostList extends React.Component { this.isUserScroll = true; }.bind(this)); - $('body').on('click.userpopover', function popOver(e) { - if ($(e.target).attr('data-toggle') !== 'popover' && - $(e.target).parents('.popover.in').length === 0) { - $('.user-popover').popover('hide'); - } - }); - $('.post-list__content div .post').removeClass('post--last'); $('.post-list__content div:last-child .post').addClass('post--last'); - $('body').on('mouseenter mouseleave', '.post', function mouseOver(ev) { - if (ev.type === 'mouseenter') { - $(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--after'); - $(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--before'); - } else { - $(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--after'); - $(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--before'); - } - }); - - $('body').on('mouseenter mouseleave', '.post.post--comment.same--root', function mouseOver(ev) { - if (ev.type === 'mouseenter') { - $(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--comment'); - $(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--comment'); - } else { - $(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--comment'); - $(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--comment'); - } - }); + if (!this.state.isFirstLoadComplete) { + this.loadFirstPosts(this.props.channelId); + } + this.resize(); + this.onChange(); this.scrollToBottom(); - - if (this.state.channel.id != null) { - this.loadFirstPosts(this.state.channel.id); - } + } + deactivate() { + PostStore.removeChangeListener(this.onChange); + UserStore.removeStatusesChangeListener(this.onTimeChange); + SocketStore.removeChangeListener(this.onSocketChange); + $('body').off('click.userpopover'); + $(window).off('resize.' + this.props.channelId); + var postHolder = $(React.findDOMNode(this.refs.postlist)); + postHolder.off('scroll'); } componentDidUpdate(prevProps, prevState) { $('.post-list__content div .post').removeClass('post--last'); @@ -187,7 +168,7 @@ export default class PostList extends React.Component { var firstPost = posts[order[0]] || {}; var isNewPost = oldOrder.indexOf(order[0]) === -1; - if (this.state.channel.id !== prevState.channel.id) { + if (this.props.isActive && !prevProps.isActive) { this.scrollToBottom(); } else if (oldOrder.length === 0) { this.scrollToBottom(); @@ -201,37 +182,43 @@ export default class PostList extends React.Component { } else if (isNewPost && userId === firstPost.user_id && !utils.isComment(firstPost)) { - this.state.lastViewed = utils.getTimestamp(); this.scrollToBottom(true); // the user clicked 'load more messages' } else if (this.gotMorePosts) { var lastPost = oldPosts[oldOrder[prevState.numToDisplay]]; $('#' + lastPost.id)[0].scrollIntoView(); + this.gotMorePosts = false; } else { this.scrollTo(this.prevScrollTop); } } componentWillUpdate() { - var postHolder = $('.post-list-holder-by-time'); + var postHolder = $(React.findDOMNode(this.refs.postlist)); this.prevScrollTop = postHolder.scrollTop(); } - componentWillUnmount() { - PostStore.removeChangeListener(this.onChange); - ChannelStore.removeChangeListener(this.onChange); - UserStore.removeStatusesChangeListener(this.onTimeChange); - SocketStore.removeChangeListener(this.onSocketChange); - $('body').off('click.userpopover'); - $('.modal').off('show.bs.modal'); + componentWillReceiveProps(nextProps) { + if (nextProps.isActive === true && this.props.isActive === false) { + this.activate(); + } else if (nextProps.isActive === false && this.props.isActive === true) { + this.deactivate(); + } + } + resize() { + const postHolder = $(React.findDOMNode(this.refs.postlist)); + if ($('#create_post').length > 0) { + const height = $(window).height() - $('#create_post').height() - $('#error_bar').outerHeight() - 50; + postHolder.css('height', height + 'px'); + } } scrollTo(val) { this.isUserScroll = false; - var postHolder = $('.post-list-holder-by-time'); + var postHolder = $(React.findDOMNode(this.refs.postlist)); postHolder[0].scrollTop = val; } scrollToBottom(force) { this.isUserScroll = false; - var postHolder = $('.post-list-holder-by-time'); + var postHolder = $(React.findDOMNode(this.refs.postlist)); if ($('#new_message')[0] && !this.userHasSeenNew && !force) { $('#new_message')[0].scrollIntoView(); } else { @@ -241,34 +228,32 @@ export default class PostList extends React.Component { } } loadFirstPosts(id) { + if (this.loadInProgress) { + return; + } + + if (this.props.channelId == null) { + return; + } + + this.loadInProgress = true; Client.getPosts( id, PostStore.getLatestUpdate(id), function success() { + this.loadInProgress = false; this.setState({isFirstLoadComplete: true}); }.bind(this), function fail() { + this.loadInProgress = false; this.setState({isFirstLoadComplete: true}); }.bind(this) ); } onChange() { - var newState = this.getStateFromStores(); - - // Special case where the channel wasn't yet set in componentDidMount - if (!this.state.isFirstLoadComplete && this.state.channel.id == null && newState.channel.id != null) { - this.loadFirstPosts(newState.channel.id); - } - - if (!utils.areStatesEqual(newState, this.state)) { - if (this.state.channel.id !== newState.channel.id) { - PostStore.clearUnseenDeletedPosts(this.state.channel.id); - this.userHasSeenNew = false; - newState.numToDisplay = Constants.POST_CHUNK_SIZE; - } else { - newState.lastViewed = this.state.lastViewed; - } + var newState = this.getStateFromStores(this.props.channelId); + if (!utils.areStatesEqual(newState.postList, this.state.postList)) { this.setState(newState); } } @@ -424,7 +409,7 @@ export default class PostList extends React.Component { } } - var members = ChannelStore.getCurrentExtraInfo().members; + var members = ChannelStore.getExtraInfo(channel.id).members; for (var i = 0; i < members.length; i++) { if (members[i].roles.indexOf('admin') > -1) { return members[i].username; @@ -488,6 +473,11 @@ export default class PostList extends React.Component { var userId = UserStore.getCurrentId(); var renderedLastViewed = false; + var lastViewed = Number.MAX_VALUE; + + if (ChannelStore.getMember(this.props.channelId) != null) { + lastViewed = ChannelStore.getMember(this.props.channelId).last_viewed_at; + } var numToDisplay = this.state.numToDisplay; if (order.length - 1 < numToDisplay) { @@ -543,7 +533,7 @@ export default class PostList extends React.Component { ); } - if (post.user_id !== userId && post.create_at > this.state.lastViewed && !renderedLastViewed) { + if (post.user_id !== userId && post.create_at > lastViewed && !renderedLastViewed) { renderedLastViewed = true; // Temporary fix to solve ie10/11 rendering issue @@ -577,7 +567,7 @@ export default class PostList extends React.Component { var posts = this.state.postList.posts; var order = this.state.postList.order; - var channelId = this.state.channel.id; + var channelId = this.props.channelId; $(React.findDOMNode(this.refs.loadmore)).text('Retrieving more messages...'); @@ -619,7 +609,7 @@ export default class PostList extends React.Component { render() { var order = []; var posts; - var channel = this.state.channel; + var channel = ChannelStore.get(this.props.channelId); if (this.state.postList != null) { posts = this.state.postList.posts; @@ -628,7 +618,7 @@ export default class PostList extends React.Component { var moreMessages = <p className='beginning-messages-text'>Beginning of Channel</p>; if (channel != null) { - if (order.length > this.state.numToDisplay) { + if (order.length >= this.state.numToDisplay) { moreMessages = ( <a ref='loadmore' @@ -655,10 +645,15 @@ export default class PostList extends React.Component { />); } + var activeClass = ''; + if (!this.props.isActive) { + activeClass = 'inactive'; + } + return ( <div ref='postlist' - className='post-list-holder-by-time' + className={'post-list-holder-by-time ' + activeClass} > <div className='post-list__table'> <div className='post-list__content'> @@ -670,3 +665,12 @@ export default class PostList extends React.Component { ); } } + +PostList.defaultProps = { + isActive: false, + channelId: null +}; +PostList.propTypes = { + isActive: React.PropTypes.bool, + channelId: React.PropTypes.string +}; |