Add post list container to hold mounted post lists for faster rendering/channel switching.
Этот коммит содержится в:
@@ -64,9 +64,14 @@ export default class ChannelHeader extends React.Component {
|
|||||||
handleLeave() {
|
handleLeave() {
|
||||||
Client.leaveChannel(this.state.channel.id,
|
Client.leaveChannel(this.state.channel.id,
|
||||||
function handleLeaveSuccess() {
|
function handleLeaveSuccess() {
|
||||||
|
AppDispatcher.handleViewAction({
|
||||||
|
type: ActionTypes.LEAVE_CHANNEL,
|
||||||
|
id: this.state.channel.id
|
||||||
|
});
|
||||||
|
|
||||||
const townsquare = ChannelStore.getByName('town-square');
|
const townsquare = ChannelStore.getByName('town-square');
|
||||||
Utils.switchChannel(townsquare);
|
Utils.switchChannel(townsquare);
|
||||||
},
|
}.bind(this),
|
||||||
function handleLeaveError(err) {
|
function handleLeaveError(err) {
|
||||||
AsyncClient.dispatchError(err, 'handleLeave');
|
AsyncClient.dispatchError(err, 'handleLeave');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export default class ChannelLoader extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
this.intervalId = null;
|
||||||
|
|
||||||
this.onSocketChange = this.onSocketChange.bind(this);
|
this.onSocketChange = this.onSocketChange.bind(this);
|
||||||
|
|
||||||
this.state = {};
|
this.state = {};
|
||||||
@@ -35,10 +37,12 @@ export default class ChannelLoader extends React.Component {
|
|||||||
PostStore.clearPendingPosts();
|
PostStore.clearPendingPosts();
|
||||||
|
|
||||||
/* Set up interval functions */
|
/* Set up interval functions */
|
||||||
setInterval(
|
this.intervalId = setInterval(
|
||||||
function pollStatuses() {
|
function pollStatuses() {
|
||||||
AsyncClient.getStatuses();
|
AsyncClient.getStatuses();
|
||||||
}, 30000);
|
},
|
||||||
|
30000
|
||||||
|
);
|
||||||
|
|
||||||
/* Device tracking setup */
|
/* Device tracking setup */
|
||||||
var iOS = (/(iPad|iPhone|iPod)/g).test(navigator.userAgent);
|
var iOS = (/(iPad|iPhone|iPod)/g).test(navigator.userAgent);
|
||||||
@@ -49,12 +53,12 @@ export default class ChannelLoader extends React.Component {
|
|||||||
/* Set up tracking for whether the window is active */
|
/* Set up tracking for whether the window is active */
|
||||||
window.isActive = true;
|
window.isActive = true;
|
||||||
|
|
||||||
$(window).focus(function windowFocus() {
|
$(window).on('focus', function windowFocus() {
|
||||||
AsyncClient.updateLastViewedAt();
|
AsyncClient.updateLastViewedAt();
|
||||||
window.isActive = true;
|
window.isActive = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
$(window).blur(function windowBlur() {
|
$(window).on('blur', function windowBlur() {
|
||||||
window.isActive = false;
|
window.isActive = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -84,6 +88,54 @@ export default class ChannelLoader extends React.Component {
|
|||||||
Utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + Utils.changeColor(user.props.theme, +10) + ';');
|
Utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + Utils.changeColor(user.props.theme, +10) + ';');
|
||||||
$('.team__header').addClass('theme--gray');
|
$('.team__header').addClass('theme--gray');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Setup global mouse events */
|
||||||
|
$('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');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('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');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Setup modal events */
|
||||||
|
$('.modal').on('show.bs.modal', function onShow() {
|
||||||
|
$('.modal-body').css('overflow-y', 'auto');
|
||||||
|
$('.modal-body').css('max-height', $(window).height() * 0.7);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
|
||||||
|
$(window).off('focus');
|
||||||
|
$(window).off('blur');
|
||||||
|
|
||||||
|
SocketStore.removeChangeListener(this.onSocketChange);
|
||||||
|
|
||||||
|
$('body').off('click.userpopover');
|
||||||
|
$('body').off('mouseenter mouseleave', '.post');
|
||||||
|
$('body').off('mouseenter mouseleave', '.post.post--comment.same--root');
|
||||||
|
|
||||||
|
$('.modal').off('show.bs.modal');
|
||||||
}
|
}
|
||||||
onSocketChange(msg) {
|
onSocketChange(msg) {
|
||||||
if (msg && msg.user_id && msg.user_id !== UserStore.getCurrentId()) {
|
if (msg && msg.user_id && msg.user_id !== UserStore.getCurrentId()) {
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ var ActionTypes = Constants.ActionTypes;
|
|||||||
import {strings} from '../utils/config.js';
|
import {strings} from '../utils/config.js';
|
||||||
|
|
||||||
export default class PostList extends React.Component {
|
export default class PostList extends React.Component {
|
||||||
constructor() {
|
constructor(props) {
|
||||||
super();
|
super(props);
|
||||||
|
|
||||||
this.gotMorePosts = false;
|
this.gotMorePosts = false;
|
||||||
this.scrolled = false;
|
this.scrolled = false;
|
||||||
@@ -27,6 +27,7 @@ export default class PostList extends React.Component {
|
|||||||
this.seenNewMessages = false;
|
this.seenNewMessages = false;
|
||||||
this.isUserScroll = true;
|
this.isUserScroll = true;
|
||||||
this.userHasSeenNew = false;
|
this.userHasSeenNew = false;
|
||||||
|
this.loadInProgress = false;
|
||||||
|
|
||||||
this.onChange = this.onChange.bind(this);
|
this.onChange = this.onChange.bind(this);
|
||||||
this.onTimeChange = this.onTimeChange.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.createChannelIntroMessage = this.createChannelIntroMessage.bind(this);
|
||||||
this.loadMorePosts = this.loadMorePosts.bind(this);
|
this.loadMorePosts = this.loadMorePosts.bind(this);
|
||||||
this.loadFirstPosts = this.loadFirstPosts.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.numToDisplay = Constants.POST_CHUNK_SIZE;
|
||||||
this.state.isFirstLoadComplete = false;
|
this.state.isFirstLoadComplete = false;
|
||||||
}
|
}
|
||||||
getStateFromStores() {
|
getStateFromStores(id) {
|
||||||
var channel = ChannelStore.getCurrent();
|
var postList = PostStore.getPosts(id);
|
||||||
|
|
||||||
if (channel == null) {
|
|
||||||
channel = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
var postList = PostStore.getCurrentPosts();
|
|
||||||
|
|
||||||
if (postList != null) {
|
if (postList != null) {
|
||||||
var deletedPosts = PostStore.getUnseenDeletedPosts(channel.id);
|
var deletedPosts = PostStore.getUnseenDeletedPosts(id);
|
||||||
|
|
||||||
if (deletedPosts && Object.keys(deletedPosts).length > 0) {
|
if (deletedPosts && Object.keys(deletedPosts).length > 0) {
|
||||||
for (var pid in deletedPosts) {
|
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) {
|
if (pendingPostList) {
|
||||||
postList.order = pendingPostList.order.concat(postList.order);
|
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 {
|
return {
|
||||||
postList: postList,
|
postList: postList
|
||||||
channel: channel,
|
|
||||||
lastViewed: lastViewed
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
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);
|
PostStore.addChangeListener(this.onChange);
|
||||||
ChannelStore.addChangeListener(this.onChange);
|
|
||||||
UserStore.addStatusesChangeListener(this.onTimeChange);
|
UserStore.addStatusesChangeListener(this.onTimeChange);
|
||||||
SocketStore.addChangeListener(this.onSocketChange);
|
SocketStore.addChangeListener(this.onSocketChange);
|
||||||
|
|
||||||
var postHolder = $('.post-list-holder-by-time');
|
var postHolder = $(React.findDOMNode(this.refs.postlist));
|
||||||
|
|
||||||
$('.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');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$(window).on('resize.' + this.props.channelId, function resize() {
|
||||||
|
this.resize();
|
||||||
if (!this.scrolled) {
|
if (!this.scrolled) {
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
postHolder.scroll(function scroll() {
|
postHolder.on('scroll', function scroll() {
|
||||||
var position = postHolder.scrollTop() + postHolder.height() + 14;
|
var position = postHolder.scrollTop() + postHolder.height() + 14;
|
||||||
var bottom = postHolder[0].scrollHeight;
|
var bottom = postHolder[0].scrollHeight;
|
||||||
|
|
||||||
@@ -134,41 +131,25 @@ export default class PostList extends React.Component {
|
|||||||
this.isUserScroll = true;
|
this.isUserScroll = true;
|
||||||
}.bind(this));
|
}.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 .post').removeClass('post--last');
|
||||||
$('.post-list__content div:last-child .post').addClass('post--last');
|
$('.post-list__content div:last-child .post').addClass('post--last');
|
||||||
|
|
||||||
$('body').on('mouseenter mouseleave', '.post', function mouseOver(ev) {
|
if (!this.state.isFirstLoadComplete) {
|
||||||
if (ev.type === 'mouseenter') {
|
this.loadFirstPosts(this.props.channelId);
|
||||||
$(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');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.scrollToBottom();
|
|
||||||
|
|
||||||
if (this.state.channel.id != null) {
|
|
||||||
this.loadFirstPosts(this.state.channel.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.resize();
|
||||||
|
this.onChange();
|
||||||
|
this.scrollToBottom();
|
||||||
|
}
|
||||||
|
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) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
$('.post-list__content div .post').removeClass('post--last');
|
$('.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 firstPost = posts[order[0]] || {};
|
||||||
var isNewPost = oldOrder.indexOf(order[0]) === -1;
|
var isNewPost = oldOrder.indexOf(order[0]) === -1;
|
||||||
|
|
||||||
if (this.state.channel.id !== prevState.channel.id) {
|
if (this.props.isActive && !prevProps.isActive) {
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
} else if (oldOrder.length === 0) {
|
} else if (oldOrder.length === 0) {
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
@@ -201,37 +182,43 @@ export default class PostList extends React.Component {
|
|||||||
} else if (isNewPost &&
|
} else if (isNewPost &&
|
||||||
userId === firstPost.user_id &&
|
userId === firstPost.user_id &&
|
||||||
!utils.isComment(firstPost)) {
|
!utils.isComment(firstPost)) {
|
||||||
this.state.lastViewed = utils.getTimestamp();
|
|
||||||
this.scrollToBottom(true);
|
this.scrollToBottom(true);
|
||||||
|
|
||||||
// the user clicked 'load more messages'
|
// the user clicked 'load more messages'
|
||||||
} else if (this.gotMorePosts) {
|
} else if (this.gotMorePosts) {
|
||||||
var lastPost = oldPosts[oldOrder[prevState.numToDisplay]];
|
var lastPost = oldPosts[oldOrder[prevState.numToDisplay]];
|
||||||
$('#' + lastPost.id)[0].scrollIntoView();
|
$('#' + lastPost.id)[0].scrollIntoView();
|
||||||
|
this.gotMorePosts = false;
|
||||||
} else {
|
} else {
|
||||||
this.scrollTo(this.prevScrollTop);
|
this.scrollTo(this.prevScrollTop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentWillUpdate() {
|
componentWillUpdate() {
|
||||||
var postHolder = $('.post-list-holder-by-time');
|
var postHolder = $(React.findDOMNode(this.refs.postlist));
|
||||||
this.prevScrollTop = postHolder.scrollTop();
|
this.prevScrollTop = postHolder.scrollTop();
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillReceiveProps(nextProps) {
|
||||||
PostStore.removeChangeListener(this.onChange);
|
if (nextProps.isActive === true && this.props.isActive === false) {
|
||||||
ChannelStore.removeChangeListener(this.onChange);
|
this.activate();
|
||||||
UserStore.removeStatusesChangeListener(this.onTimeChange);
|
} else if (nextProps.isActive === false && this.props.isActive === true) {
|
||||||
SocketStore.removeChangeListener(this.onSocketChange);
|
this.deactivate();
|
||||||
$('body').off('click.userpopover');
|
}
|
||||||
$('.modal').off('show.bs.modal');
|
}
|
||||||
|
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) {
|
scrollTo(val) {
|
||||||
this.isUserScroll = false;
|
this.isUserScroll = false;
|
||||||
var postHolder = $('.post-list-holder-by-time');
|
var postHolder = $(React.findDOMNode(this.refs.postlist));
|
||||||
postHolder[0].scrollTop = val;
|
postHolder[0].scrollTop = val;
|
||||||
}
|
}
|
||||||
scrollToBottom(force) {
|
scrollToBottom(force) {
|
||||||
this.isUserScroll = false;
|
this.isUserScroll = false;
|
||||||
var postHolder = $('.post-list-holder-by-time');
|
var postHolder = $(React.findDOMNode(this.refs.postlist));
|
||||||
if ($('#new_message')[0] && !this.userHasSeenNew && !force) {
|
if ($('#new_message')[0] && !this.userHasSeenNew && !force) {
|
||||||
$('#new_message')[0].scrollIntoView();
|
$('#new_message')[0].scrollIntoView();
|
||||||
} else {
|
} else {
|
||||||
@@ -241,34 +228,32 @@ export default class PostList extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadFirstPosts(id) {
|
loadFirstPosts(id) {
|
||||||
|
if (this.loadInProgress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.channelId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadInProgress = true;
|
||||||
Client.getPosts(
|
Client.getPosts(
|
||||||
id,
|
id,
|
||||||
PostStore.getLatestUpdate(id),
|
PostStore.getLatestUpdate(id),
|
||||||
function success() {
|
function success() {
|
||||||
|
this.loadInProgress = false;
|
||||||
this.setState({isFirstLoadComplete: true});
|
this.setState({isFirstLoadComplete: true});
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
function fail() {
|
function fail() {
|
||||||
|
this.loadInProgress = false;
|
||||||
this.setState({isFirstLoadComplete: true});
|
this.setState({isFirstLoadComplete: true});
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
onChange() {
|
onChange() {
|
||||||
var newState = this.getStateFromStores();
|
var newState = this.getStateFromStores(this.props.channelId);
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!utils.areStatesEqual(newState.postList, this.state.postList)) {
|
||||||
this.setState(newState);
|
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++) {
|
for (var i = 0; i < members.length; i++) {
|
||||||
if (members[i].roles.indexOf('admin') > -1) {
|
if (members[i].roles.indexOf('admin') > -1) {
|
||||||
return members[i].username;
|
return members[i].username;
|
||||||
@@ -488,6 +473,11 @@ export default class PostList extends React.Component {
|
|||||||
var userId = UserStore.getCurrentId();
|
var userId = UserStore.getCurrentId();
|
||||||
|
|
||||||
var renderedLastViewed = false;
|
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;
|
var numToDisplay = this.state.numToDisplay;
|
||||||
if (order.length - 1 < 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;
|
renderedLastViewed = true;
|
||||||
|
|
||||||
// Temporary fix to solve ie10/11 rendering issue
|
// 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 posts = this.state.postList.posts;
|
||||||
var order = this.state.postList.order;
|
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...');
|
$(React.findDOMNode(this.refs.loadmore)).text('Retrieving more messages...');
|
||||||
|
|
||||||
@@ -619,7 +609,7 @@ export default class PostList extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
var order = [];
|
var order = [];
|
||||||
var posts;
|
var posts;
|
||||||
var channel = this.state.channel;
|
var channel = ChannelStore.get(this.props.channelId);
|
||||||
|
|
||||||
if (this.state.postList != null) {
|
if (this.state.postList != null) {
|
||||||
posts = this.state.postList.posts;
|
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>;
|
var moreMessages = <p className='beginning-messages-text'>Beginning of Channel</p>;
|
||||||
if (channel != null) {
|
if (channel != null) {
|
||||||
if (order.length > this.state.numToDisplay) {
|
if (order.length >= this.state.numToDisplay) {
|
||||||
moreMessages = (
|
moreMessages = (
|
||||||
<a
|
<a
|
||||||
ref='loadmore'
|
ref='loadmore'
|
||||||
@@ -655,10 +645,15 @@ export default class PostList extends React.Component {
|
|||||||
/>);
|
/>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var activeClass = '';
|
||||||
|
if (!this.props.isActive) {
|
||||||
|
activeClass = 'inactive';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref='postlist'
|
ref='postlist'
|
||||||
className='post-list-holder-by-time'
|
className={'post-list-holder-by-time ' + activeClass}
|
||||||
>
|
>
|
||||||
<div className='post-list__table'>
|
<div className='post-list__table'>
|
||||||
<div className='post-list__content'>
|
<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
|
||||||
|
};
|
||||||
|
|||||||
62
web/react/components/post_list_container.jsx
Обычный файл
62
web/react/components/post_list_container.jsx
Обычный файл
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
const PostList = require('./post_list.jsx');
|
||||||
|
const ChannelStore = require('../stores/channel_store.jsx');
|
||||||
|
|
||||||
|
export default class PostListContainer extends React.Component {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.onChange = this.onChange.bind(this);
|
||||||
|
this.onLeave = this.onLeave.bind(this);
|
||||||
|
|
||||||
|
let currentChannelId = ChannelStore.getCurrentId();
|
||||||
|
if (currentChannelId) {
|
||||||
|
this.state = {currentChannelId: currentChannelId, postLists: [currentChannelId]};
|
||||||
|
} else {
|
||||||
|
this.state = {currentChannelId: null, postLists: []};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
ChannelStore.addChangeListener(this.onChange);
|
||||||
|
ChannelStore.addLeaveListener(this.onLeave);
|
||||||
|
}
|
||||||
|
onChange() {
|
||||||
|
let channelId = ChannelStore.getCurrentId();
|
||||||
|
if (channelId === this.state.currentChannelId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let postLists = this.state.postLists;
|
||||||
|
if (postLists.indexOf(channelId) === -1) {
|
||||||
|
postLists.push(channelId);
|
||||||
|
}
|
||||||
|
this.setState({currentChannelId: channelId, postLists: postLists});
|
||||||
|
}
|
||||||
|
onLeave(id) {
|
||||||
|
let postLists = this.state.postLists;
|
||||||
|
var index = postLists.indexOf(id);
|
||||||
|
if (index !== -1) {
|
||||||
|
postLists.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
let postLists = this.state.postLists;
|
||||||
|
let channelId = this.state.currentChannelId;
|
||||||
|
|
||||||
|
let postListCtls = [];
|
||||||
|
for (let i = 0; i <= this.state.postLists.length - 1; i++) {
|
||||||
|
postListCtls.push(
|
||||||
|
<PostList
|
||||||
|
channelId={postLists[i]}
|
||||||
|
isActive={postLists[i] === channelId}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>{postListCtls}</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
|||||||
var Navbar = require('../components/navbar.jsx');
|
var Navbar = require('../components/navbar.jsx');
|
||||||
var Sidebar = require('../components/sidebar.jsx');
|
var Sidebar = require('../components/sidebar.jsx');
|
||||||
var ChannelHeader = require('../components/channel_header.jsx');
|
var ChannelHeader = require('../components/channel_header.jsx');
|
||||||
var PostList = require('../components/post_list.jsx');
|
var PostListContainer = require('../components/post_list_container.jsx');
|
||||||
var CreatePost = require('../components/create_post.jsx');
|
var CreatePost = require('../components/create_post.jsx');
|
||||||
var SidebarRight = require('../components/sidebar_right.jsx');
|
var SidebarRight = require('../components/sidebar_right.jsx');
|
||||||
var SidebarRightMenu = require('../components/sidebar_right_menu.jsx');
|
var SidebarRightMenu = require('../components/sidebar_right_menu.jsx');
|
||||||
@@ -159,7 +159,7 @@ function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
React.render(
|
React.render(
|
||||||
<PostList />,
|
<PostListContainer />,
|
||||||
document.getElementById('post-list')
|
document.getElementById('post-list')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ var ActionTypes = Constants.ActionTypes;
|
|||||||
var BrowserStore = require('../stores/browser_store.jsx');
|
var BrowserStore = require('../stores/browser_store.jsx');
|
||||||
|
|
||||||
var CHANGE_EVENT = 'change';
|
var CHANGE_EVENT = 'change';
|
||||||
|
var LEAVE_EVENT = 'leave';
|
||||||
var MORE_CHANGE_EVENT = 'change';
|
var MORE_CHANGE_EVENT = 'change';
|
||||||
var EXTRA_INFO_EVENT = 'extra_info';
|
var EXTRA_INFO_EVENT = 'extra_info';
|
||||||
|
|
||||||
@@ -48,6 +49,15 @@ class ChannelStoreClass extends EventEmitter {
|
|||||||
removeExtraInfoChangeListener(callback) {
|
removeExtraInfoChangeListener(callback) {
|
||||||
this.removeListener(EXTRA_INFO_EVENT, callback);
|
this.removeListener(EXTRA_INFO_EVENT, callback);
|
||||||
}
|
}
|
||||||
|
emitLeave(id) {
|
||||||
|
this.emit(LEAVE_EVENT, id);
|
||||||
|
}
|
||||||
|
addLeaveListener(callback) {
|
||||||
|
this.on(LEAVE_EVENT, callback);
|
||||||
|
}
|
||||||
|
removeLeaveListener(callback) {
|
||||||
|
this.removeListener(LEAVE_EVENT, callback);
|
||||||
|
}
|
||||||
findFirstBy(field, value) {
|
findFirstBy(field, value) {
|
||||||
var channels = this.pGetChannels();
|
var channels = this.pGetChannels();
|
||||||
for (var i = 0; i < channels.length; i++) {
|
for (var i = 0; i < channels.length; i++) {
|
||||||
@@ -272,6 +282,10 @@ ChannelStore.dispatchToken = AppDispatcher.register(function handleAction(payloa
|
|||||||
ChannelStore.emitExtraInfoChange();
|
ChannelStore.emitExtraInfoChange();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ActionTypes.LEAVE_CHANNEL:
|
||||||
|
ChannelStore.emitLeave(action.id);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ module.exports = {
|
|||||||
|
|
||||||
CLICK_CHANNEL: null,
|
CLICK_CHANNEL: null,
|
||||||
CREATE_CHANNEL: null,
|
CREATE_CHANNEL: null,
|
||||||
|
LEAVE_CHANNEL: null,
|
||||||
RECIEVED_CHANNELS: null,
|
RECIEVED_CHANNELS: null,
|
||||||
RECIEVED_CHANNEL: null,
|
RECIEVED_CHANNEL: null,
|
||||||
RECIEVED_MORE_CHANNELS: null,
|
RECIEVED_MORE_CHANNELS: null,
|
||||||
|
|||||||
@@ -143,6 +143,12 @@ body.ios {
|
|||||||
&.hide-scroll::-webkit-scrollbar {
|
&.hide-scroll::-webkit-scrollbar {
|
||||||
width: 0px !important;
|
width: 0px !important;
|
||||||
}
|
}
|
||||||
|
&.inactive {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.post-list__table {
|
.post-list__table {
|
||||||
display: table;
|
display: table;
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user