Hooking up external components
Этот коммит содержится в:
@@ -57,14 +57,14 @@
|
|||||||
},
|
},
|
||||||
"EmailSettings": {
|
"EmailSettings": {
|
||||||
"EnableSignUpWithEmail": true,
|
"EnableSignUpWithEmail": true,
|
||||||
"SendEmailNotifications": true,
|
"SendEmailNotifications": false,
|
||||||
"RequireEmailVerification": false,
|
"RequireEmailVerification": false,
|
||||||
"FeedbackName": "",
|
"FeedbackName": "",
|
||||||
"FeedbackEmail": "",
|
"FeedbackEmail": "",
|
||||||
"SMTPUsername": "",
|
"SMTPUsername": "",
|
||||||
"SMTPPassword": "",
|
"SMTPPassword": "",
|
||||||
"SMTPServer": "localhost",
|
"SMTPServer": "",
|
||||||
"SMTPPort": "25",
|
"SMTPPort": "",
|
||||||
"ConnectionSecurity": "",
|
"ConnectionSecurity": "",
|
||||||
"InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9YoS",
|
"InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9YoS",
|
||||||
"PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5eL",
|
"PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5eL",
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ export default class CreatePost extends React.Component {
|
|||||||
|
|
||||||
PostStore.storePendingPost(post);
|
PostStore.storePendingPost(post);
|
||||||
PostStore.storeDraft(channel.id, null);
|
PostStore.storeDraft(channel.id, null);
|
||||||
|
PostStore.jumpPostListBottom();
|
||||||
this.setState({messageText: '', submitting: false, postError: null, previews: [], serverError: null});
|
this.setState({messageText: '', submitting: false, postError: null, previews: [], serverError: null});
|
||||||
|
|
||||||
Client.createPost(post, channel,
|
Client.createPost(post, channel,
|
||||||
|
|||||||
@@ -3,10 +3,9 @@
|
|||||||
|
|
||||||
var UserStore = require('../stores/user_store.jsx');
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
|
var UpdatingTimeSinceCounter = require('./updating_time_since_counter.jsx');
|
||||||
|
|
||||||
var Constants = require('../utils/constants.jsx');
|
var Constants = require('../utils/constants.jsx');
|
||||||
var Tooltip = ReactBootstrap.Tooltip;
|
|
||||||
var OverlayTrigger = ReactBootstrap.OverlayTrigger;
|
|
||||||
|
|
||||||
export default class PostInfo extends React.Component {
|
export default class PostInfo extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -144,21 +143,12 @@ export default class PostInfo extends React.Component {
|
|||||||
|
|
||||||
var dropdown = this.createDropdown();
|
var dropdown = this.createDropdown();
|
||||||
|
|
||||||
let tooltip = <Tooltip id={post.id + 'tooltip'}>{`${utils.displayDate(post.create_at)} at ${utils.displayTime(post.create_at)}`}</Tooltip>;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className='post-header post-info'>
|
<ul className='post-header post-info'>
|
||||||
<li className='post-header-col'>
|
<li className='post-header-col'>
|
||||||
<OverlayTrigger
|
<UpdatingTimeSinceCounter
|
||||||
delayShow={500}
|
eventTime={post.create_at}
|
||||||
container={this}
|
/>
|
||||||
placement='top'
|
|
||||||
overlay={tooltip}
|
|
||||||
>
|
|
||||||
<time className='post-profile-time'>
|
|
||||||
{utils.displayDateTime(post.create_at)}
|
|
||||||
</time>
|
|
||||||
</OverlayTrigger>
|
|
||||||
</li>
|
</li>
|
||||||
<li className='post-header-col post-header__reply'>
|
<li className='post-header-col post-header__reply'>
|
||||||
<div className='dropdown'>
|
<div className='dropdown'>
|
||||||
|
|||||||
@@ -25,10 +25,12 @@ export default class PostListContainer extends React.Component {
|
|||||||
this.loadMorePostsTop = this.loadMorePostsTop.bind(this);
|
this.loadMorePostsTop = this.loadMorePostsTop.bind(this);
|
||||||
this.postsLoaded = this.postsLoaded.bind(this);
|
this.postsLoaded = this.postsLoaded.bind(this);
|
||||||
this.postsLoadedFailure = this.postsLoadedFailure.bind(this);
|
this.postsLoadedFailure = this.postsLoadedFailure.bind(this);
|
||||||
|
this.handlePostListJumpRequest = this.handlePostListJumpRequest.bind(this);
|
||||||
|
|
||||||
const currentChannelId = ChannelStore.getCurrentId();
|
const currentChannelId = ChannelStore.getCurrentId();
|
||||||
const state = {
|
const state = {
|
||||||
scrollType: PostsView.SCROLL_TYPE_BOTTOM,
|
scrollType: PostsView.SCROLL_TYPE_BOTTOM,
|
||||||
|
scrollPost: null,
|
||||||
numPostsToDisplay: Constants.POST_CHUNK_SIZE
|
numPostsToDisplay: Constants.POST_CHUNK_SIZE
|
||||||
};
|
};
|
||||||
if (currentChannelId) {
|
if (currentChannelId) {
|
||||||
@@ -51,11 +53,29 @@ export default class PostListContainer extends React.Component {
|
|||||||
ChannelStore.addChangeListener(this.onChannelChange);
|
ChannelStore.addChangeListener(this.onChannelChange);
|
||||||
ChannelStore.addLeaveListener(this.onChannelLeave);
|
ChannelStore.addLeaveListener(this.onChannelLeave);
|
||||||
PostStore.addChangeListener(this.onPostsChange);
|
PostStore.addChangeListener(this.onPostsChange);
|
||||||
|
PostStore.addPostListJumpListener(this.handlePostListJumpRequest);
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
ChannelStore.removeChangeListener(this.onChannelChange);
|
ChannelStore.removeChangeListener(this.onChannelChange);
|
||||||
ChannelStore.removeLeaveListener(this.onChannelLeave);
|
ChannelStore.removeLeaveListener(this.onChannelLeave);
|
||||||
PostStore.removeChangeListener(this.onPostsChange);
|
PostStore.removeChangeListener(this.onPostsChange);
|
||||||
|
PostStore.removePostListJumpListener(this.handlePostListJumpRequest);
|
||||||
|
}
|
||||||
|
handlePostListJumpRequest(type, post) {
|
||||||
|
switch (type) {
|
||||||
|
case Constants.PostListJumpTypes.BOTTOM:
|
||||||
|
this.setState({scrollType: PostsView.SCROLL_TYPE_BOTTOM});
|
||||||
|
break;
|
||||||
|
case Constants.PostListJumpTypes.POST:
|
||||||
|
this.setState({
|
||||||
|
scrollType: PostsView.SCROLL_TYPE_POST,
|
||||||
|
scrollPost: post
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case Constants.PostListJumpTypes.SIDEBAR_OPEN:
|
||||||
|
this.setState({scrollType: PostsView.SIDEBAR_OPEN});
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onChannelChange() {
|
onChannelChange() {
|
||||||
const postLists = Object.assign({}, this.state.postLists);
|
const postLists = Object.assign({}, this.state.postLists);
|
||||||
@@ -70,7 +90,7 @@ export default class PostListContainer extends React.Component {
|
|||||||
PostStore.clearUnseenDeletedPosts(channelId);
|
PostStore.clearUnseenDeletedPosts(channelId);
|
||||||
|
|
||||||
let lastViewed = Number.MAX_VALUE;
|
let lastViewed = Number.MAX_VALUE;
|
||||||
let member = ChannelStore.getMember(channelId);
|
const member = ChannelStore.getMember(channelId);
|
||||||
if (member != null) {
|
if (member != null) {
|
||||||
lastViewed = member.last_viewed_at;
|
lastViewed = member.last_viewed_at;
|
||||||
}
|
}
|
||||||
@@ -219,10 +239,11 @@ export default class PostListContainer extends React.Component {
|
|||||||
isActive={isActive}
|
isActive={isActive}
|
||||||
postList={postLists[i]}
|
postList={postLists[i]}
|
||||||
scrollType={this.state.scrollType}
|
scrollType={this.state.scrollType}
|
||||||
|
scrollPost={this.state.scrollPost}
|
||||||
postListScrolled={this.handlePostListScroll}
|
postListScrolled={this.handlePostListScroll}
|
||||||
loadMorePostsTopClicked={this.loadMorePostsTop}
|
loadMorePostsTopClicked={this.loadMorePostsTop}
|
||||||
numPostsToDisplay={this.state.numPostsToDisplay}
|
numPostsToDisplay={this.state.numPostsToDisplay}
|
||||||
introText={channel ? createChannelIntroMessage(channel) : []}
|
introText={channel ? createChannelIntroMessage(channel) : null}
|
||||||
messageSeparatorTime={this.state.currentLastViewed}
|
messageSeparatorTime={this.state.currentLastViewed}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,11 +10,16 @@ export default class PostsView extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.handleScroll = this.handleScroll.bind(this);
|
this.handleScroll = this.handleScroll.bind(this);
|
||||||
|
this.isAtBottom = this.isAtBottom.bind(this);
|
||||||
this.loadMorePostsTop = this.loadMorePostsTop.bind(this);
|
this.loadMorePostsTop = this.loadMorePostsTop.bind(this);
|
||||||
this.postsRerendered = this.postsRerendered.bind(this);
|
this.postsRerendered = this.postsRerendered.bind(this);
|
||||||
this.createPosts = this.createPosts.bind(this);
|
this.createPosts = this.createPosts.bind(this);
|
||||||
this.scrollToBottom = this.scrollToBottom.bind(this);
|
this.updateScrolling = this.updateScrolling.bind(this);
|
||||||
this.handleResize = this.handleResize.bind(this);
|
this.handleResize = this.handleResize.bind(this);
|
||||||
|
|
||||||
|
this.jumpToPostNode = null;
|
||||||
|
this.wasAtBottom = true;
|
||||||
|
this.scrollHeight = 0;
|
||||||
}
|
}
|
||||||
static get SCROLL_TYPE_FREE() {
|
static get SCROLL_TYPE_FREE() {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -22,9 +27,28 @@ export default class PostsView extends React.Component {
|
|||||||
static get SCROLL_TYPE_BOTTOM() {
|
static get SCROLL_TYPE_BOTTOM() {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
static get SIDEBAR_OPEN() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
isAtBottom() {
|
||||||
|
return ((this.refs.postlist.scrollHeight - this.refs.postlist.scrollTop) === this.refs.postlist.clientHeight);
|
||||||
|
}
|
||||||
handleScroll() {
|
handleScroll() {
|
||||||
const atBottom = ((this.refs.postlist.scrollHeight - this.refs.postlist.scrollTop) === this.refs.postlist.clientHeight);
|
// HACK FOR RHS -- REMOVE WHEN RHS DIES
|
||||||
this.props.postListScrolled(atBottom);
|
const childNodes = this.refs.postlistcontent.childNodes;
|
||||||
|
for (let i = 0; i < childNodes.length; i++) {
|
||||||
|
// If the node is 1/3 down the page
|
||||||
|
if (childNodes[i].offsetTop > (this.refs.postlist.scrollTop + (this.refs.postlist.offsetHeight / 3))) {
|
||||||
|
this.jumpToPostNode = childNodes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.wasAtBottom = this.isAtBottom();
|
||||||
|
|
||||||
|
// --- --------
|
||||||
|
|
||||||
|
this.props.postListScrolled(this.isAtBottom());
|
||||||
|
this.prevScrollHeight = this.refs.postlist.scrollHeight;
|
||||||
}
|
}
|
||||||
loadMorePostsTop() {
|
loadMorePostsTop() {
|
||||||
this.props.loadMorePostsTopClicked();
|
this.props.loadMorePostsTopClicked();
|
||||||
@@ -134,25 +158,53 @@ export default class PostsView extends React.Component {
|
|||||||
|
|
||||||
return postCtls;
|
return postCtls;
|
||||||
}
|
}
|
||||||
scrollToBottom() {
|
updateScrolling() {
|
||||||
if (this.props.scrollType === PostsView.SCROLL_TYPE_BOTTOM) {
|
if (this.props.scrollType === PostsView.SCROLL_TYPE_BOTTOM) {
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
this.refs.postlist.scrollTop = this.refs.postlist.scrollHeight;
|
this.refs.postlist.scrollTop = this.refs.postlist.scrollHeight;
|
||||||
});
|
});
|
||||||
|
} else if (this.props.scrollType === PostsView.SCROLL_TYPE_POST && this.props.scrollPost) {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
const postNode = ReactDOM.findDOMNode(this.refs[this.props.scrollPost]);
|
||||||
|
postNode.scrollIntoView();
|
||||||
|
if (this.refs.postlist.scrollTop === postNode.offsetTop) {
|
||||||
|
this.refs.postlist.scrollTop -= (this.refs.postlist.offsetHeight / 3);
|
||||||
|
} else {
|
||||||
|
this.refs.postlist.scrollTop -= (this.refs.postlist.offsetHeight / 3) + (this.refs.postlist.scrollTop - postNode.offsetTop);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (this.props.scrollType === PostsView.SIDEBAR_OPEN) {
|
||||||
|
// If we are at the bottom then stay there
|
||||||
|
if (this.wasAtBottom) {
|
||||||
|
this.refs.postlist.scrollTop = this.refs.postlist.scrollHeight;
|
||||||
|
} else {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
this.jumpToPostNode.scrollIntoView();
|
||||||
|
if (this.refs.postlist.scrollTop === this.jumpToPostNode.offsetTop) {
|
||||||
|
this.refs.postlist.scrollTop -= (this.refs.postlist.offsetHeight / 3);
|
||||||
|
} else {
|
||||||
|
this.refs.postlist.scrollTop -= (this.refs.postlist.offsetHeight / 3) + (this.refs.postlist.scrollTop - this.jumpToPostNode.offsetTop);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (this.refs.postlist.scrollHeight !== this.prevScrollHeight) {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
this.refs.postlist.scrollTop += (this.refs.postlist.scrollHeight - this.prevScrollHeight);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleResize() {
|
handleResize() {
|
||||||
this.scrollToBottom();
|
this.updateScrolling();
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.scrollToBottom();
|
this.updateScrolling();
|
||||||
window.addEventListener('resize', this.handleResize);
|
window.addEventListener('resize', this.handleResize);
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
window.removeEventListener('resize', this.handleResize);
|
window.removeEventListener('resize', this.handleResize);
|
||||||
}
|
}
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
this.scrollToBottom();
|
this.updateScrolling();
|
||||||
}
|
}
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
if (this.props.isActive !== nextProps.isActive) {
|
if (this.props.isActive !== nextProps.isActive) {
|
||||||
@@ -197,7 +249,7 @@ export default class PostsView extends React.Component {
|
|||||||
className='more-messages-text theme'
|
className='more-messages-text theme'
|
||||||
href='#'
|
href='#'
|
||||||
onClick={this.loadMorePostsTop}
|
onClick={this.loadMorePostsTop}
|
||||||
>
|
>
|
||||||
{'Load more messages'}
|
{'Load more messages'}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
@@ -238,7 +290,7 @@ PostsView.defaultProps = {
|
|||||||
|
|
||||||
PostsView.propTypes = {
|
PostsView.propTypes = {
|
||||||
isActive: React.PropTypes.bool,
|
isActive: React.PropTypes.bool,
|
||||||
postList: React.PropTypes.object.isRequired,
|
postList: React.PropTypes.object,
|
||||||
scrollPost: React.PropTypes.string,
|
scrollPost: React.PropTypes.string,
|
||||||
scrollType: React.PropTypes.number,
|
scrollType: React.PropTypes.number,
|
||||||
postListScrolled: React.PropTypes.func.isRequired,
|
postListScrolled: React.PropTypes.func.isRequired,
|
||||||
|
|||||||
@@ -20,23 +20,48 @@ export default class SidebarRight extends React.Component {
|
|||||||
this.onSelectedChange = this.onSelectedChange.bind(this);
|
this.onSelectedChange = this.onSelectedChange.bind(this);
|
||||||
this.onSearchChange = this.onSearchChange.bind(this);
|
this.onSearchChange = this.onSearchChange.bind(this);
|
||||||
|
|
||||||
|
this.doStrangeThings = this.doStrangeThings.bind(this);
|
||||||
|
|
||||||
this.state = getStateFromStores();
|
this.state = getStateFromStores();
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
SearchStore.addSearchChangeListener(this.onSearchChange);
|
SearchStore.addSearchChangeListener(this.onSearchChange);
|
||||||
PostStore.addSelectedPostChangeListener(this.onSelectedChange);
|
PostStore.addSelectedPostChangeListener(this.onSelectedChange);
|
||||||
|
this.doStrangeThings();
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
SearchStore.removeSearchChangeListener(this.onSearchChange);
|
SearchStore.removeSearchChangeListener(this.onSearchChange);
|
||||||
PostStore.removeSelectedPostChangeListener(this.onSelectedChange);
|
PostStore.removeSelectedPostChangeListener(this.onSelectedChange);
|
||||||
}
|
}
|
||||||
componentDidUpdate() {
|
componentWillUpdate() {
|
||||||
if (this.plScrolledToBottom) {
|
PostStore.jumpPostListSidebarOpen();
|
||||||
var postHolder = $('.post-list-holder-by-time').not('.inactive');
|
}
|
||||||
postHolder.scrollTop(postHolder[0].scrollHeight);
|
doStrangeThings() {
|
||||||
} else {
|
// We should have a better way to do this stuff
|
||||||
$('.top-visible-post')[0].scrollIntoView();
|
// Hence the function name.
|
||||||
|
$('.inner__wrap').removeClass('.move--right');
|
||||||
|
$('.inner__wrap').addClass('move--left');
|
||||||
|
$('.sidebar--left').removeClass('move--right');
|
||||||
|
$('.sidebar--right').addClass('move--left');
|
||||||
|
|
||||||
|
//$('.sidebar--right').prepend('<div class="sidebar__overlay"></div>');
|
||||||
|
|
||||||
|
if (!(this.state.search_visible || this.state.post_right_visible)) {
|
||||||
|
$('.inner__wrap').removeClass('move--left').removeClass('move--right');
|
||||||
|
$('.sidebar--right').removeClass('move--left');
|
||||||
|
return (
|
||||||
|
<div></div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*setTimeout(() => {
|
||||||
|
$('.sidebar__overlay').fadeOut('200', () => {
|
||||||
|
$('.sidebar__overlay').remove();
|
||||||
|
});
|
||||||
|
}, 500);*/
|
||||||
|
}
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.doStrangeThings();
|
||||||
}
|
}
|
||||||
onSelectedChange(fromSearch) {
|
onSelectedChange(fromSearch) {
|
||||||
var newState = getStateFromStores(fromSearch);
|
var newState = getStateFromStores(fromSearch);
|
||||||
@@ -52,34 +77,6 @@ export default class SidebarRight extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
var postHolder = $('.post-list-holder-by-time').not('.inactive');
|
|
||||||
if (postHolder[0]) {
|
|
||||||
const position = postHolder.scrollTop() + postHolder.height() + 14;
|
|
||||||
const bottom = postHolder[0].scrollHeight;
|
|
||||||
this.plScrolledToBottom = position >= bottom;
|
|
||||||
} else {
|
|
||||||
this.plScrolledToBottom = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(this.state.search_visible || this.state.post_right_visible)) {
|
|
||||||
$('.inner__wrap').removeClass('move--left').removeClass('move--right');
|
|
||||||
$('.sidebar--right').removeClass('move--left');
|
|
||||||
return (
|
|
||||||
<div></div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$('.inner__wrap').removeClass('.move--right').addClass('move--left');
|
|
||||||
$('.sidebar--left').removeClass('move--right');
|
|
||||||
$('.sidebar--right').addClass('move--left');
|
|
||||||
$('.sidebar--right').prepend('<div class="sidebar__overlay"></div>');
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
$('.sidebar__overlay').fadeOut('200', function fadeOverlay() {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
var content = '';
|
var content = '';
|
||||||
|
|
||||||
if (this.state.search_visible) {
|
if (this.state.search_visible) {
|
||||||
|
|||||||
50
web/react/components/updating_time_since_counter.jsx
Обычный файл
50
web/react/components/updating_time_since_counter.jsx
Обычный файл
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
var Utils = require('../utils/utils.jsx');
|
||||||
|
|
||||||
|
var Tooltip = ReactBootstrap.Tooltip;
|
||||||
|
var OverlayTrigger = ReactBootstrap.OverlayTrigger;
|
||||||
|
|
||||||
|
export default class UpdatingTimeSinceCounter extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
this.intervalId = setInterval(() => {
|
||||||
|
this.forceUpdate();
|
||||||
|
}, 30000);
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const displayDate = Utils.displayDate(this.props.eventTime);
|
||||||
|
const displayTime = Utils.displayTime(this.props.eventTime);
|
||||||
|
|
||||||
|
const tooltip = (
|
||||||
|
<Tooltip id={'time-since-tooltip-' + this.props.eventTime}>
|
||||||
|
{displayDate + ' at ' + displayTime}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OverlayTrigger
|
||||||
|
delayShow={400}
|
||||||
|
placement='top'
|
||||||
|
overlay={tooltip}
|
||||||
|
>
|
||||||
|
<time className='post-profile-time'>
|
||||||
|
{Utils.displayDateTime(this.props.eventTime)}
|
||||||
|
</time>
|
||||||
|
</OverlayTrigger>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdatingTimeSinceCounter.defaultProps = {
|
||||||
|
eventTime: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
UpdatingTimeSinceCounter.propTypes = {
|
||||||
|
eventTime: React.PropTypes.number.isRequired
|
||||||
|
};
|
||||||
@@ -55,9 +55,7 @@ function setupChannelPage(props) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<ChannelView
|
<ChannelView/>,
|
||||||
|
|
||||||
/>,
|
|
||||||
document.getElementById('channel_view')
|
document.getElementById('channel_view')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ var ActionTypes = Constants.ActionTypes;
|
|||||||
var CHANGE_EVENT = 'change';
|
var CHANGE_EVENT = 'change';
|
||||||
var SELECTED_POST_CHANGE_EVENT = 'selected_post_change';
|
var SELECTED_POST_CHANGE_EVENT = 'selected_post_change';
|
||||||
var EDIT_POST_EVENT = 'edit_post';
|
var EDIT_POST_EVENT = 'edit_post';
|
||||||
|
var POST_LIST_JUMP_EVENT = 'post_list_jump';
|
||||||
|
|
||||||
class PostStoreClass extends EventEmitter {
|
class PostStoreClass extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -31,6 +32,10 @@ class PostStoreClass extends EventEmitter {
|
|||||||
this.addEditPostListener = this.addEditPostListener.bind(this);
|
this.addEditPostListener = this.addEditPostListener.bind(this);
|
||||||
this.removeEditPostListener = this.removeEditPostListener.bind(this);
|
this.removeEditPostListener = this.removeEditPostListener.bind(this);
|
||||||
|
|
||||||
|
this.emitPostListJump = this.emitPostListJump.bind(this);
|
||||||
|
this.addPostListJumpListener = this.addPostListJumpListener.bind(this);
|
||||||
|
this.removePostListJumpListener = this.removePostListJumpListener.bind(this);
|
||||||
|
|
||||||
this.getCurrentPosts = this.getCurrentPosts.bind(this);
|
this.getCurrentPosts = this.getCurrentPosts.bind(this);
|
||||||
this.storePosts = this.storePosts.bind(this);
|
this.storePosts = this.storePosts.bind(this);
|
||||||
this.pStorePosts = this.pStorePosts.bind(this);
|
this.pStorePosts = this.pStorePosts.bind(this);
|
||||||
@@ -100,6 +105,30 @@ class PostStoreClass extends EventEmitter {
|
|||||||
this.removeListener(EDIT_POST_EVENT, callback);
|
this.removeListener(EDIT_POST_EVENT, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitPostListJump(type, post) {
|
||||||
|
this.emit(POST_LIST_JUMP_EVENT, type, post);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPostListJumpListener(callback) {
|
||||||
|
this.on(POST_LIST_JUMP_EVENT, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
removePostListJumpListener(callback) {
|
||||||
|
this.removeListener(POST_LIST_JUMP_EVENT, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
jumpPostListBottom() {
|
||||||
|
this.emitPostListJump(Constants.PostListJumpTypes.BOTTOM, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
jumpPostListToPost(post) {
|
||||||
|
this.emitPostListJump(Constants.PostListJumpTypes.POST, post);
|
||||||
|
}
|
||||||
|
|
||||||
|
jumpPostListSidebarOpen() {
|
||||||
|
this.emitPostListJump(Constants.PostListJumpTypes.SIDEBAR_OPEN, null);
|
||||||
|
}
|
||||||
|
|
||||||
getCurrentPosts() {
|
getCurrentPosts() {
|
||||||
var currentId = ChannelStore.getCurrentId();
|
var currentId = ChannelStore.getCurrentId();
|
||||||
|
|
||||||
|
|||||||
@@ -350,5 +350,10 @@ module.exports = {
|
|||||||
ruby: 'Ruby',
|
ruby: 'Ruby',
|
||||||
java: 'Java',
|
java: 'Java',
|
||||||
ini: 'ini'
|
ini: 'ini'
|
||||||
|
},
|
||||||
|
PostListJumpTypes: {
|
||||||
|
BOTTOM: 1,
|
||||||
|
POST: 2,
|
||||||
|
SIDEBAR_OPEN: 3
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,18 @@ body {
|
|||||||
background: $body-bg;
|
background: $body-bg;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
&.white {
|
||||||
|
background: #fff;
|
||||||
|
> .container-fluid {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.inner__wrap {
|
||||||
|
> .row.content {
|
||||||
|
min-height: 100%;
|
||||||
|
margin-bottom: -89px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.inner__wrap {
|
.inner__wrap {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user