summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--webapp/components/common/post_flag_icon.jsx87
-rw-r--r--webapp/components/post_view/components/post.jsx1
-rw-r--r--webapp/components/post_view/components/post_header.jsx2
-rw-r--r--webapp/components/post_view/components/post_info.jsx76
-rw-r--r--webapp/components/rhs_comment.jsx80
-rw-r--r--webapp/components/rhs_root_post.jsx62
-rw-r--r--webapp/components/rhs_thread.jsx15
-rw-r--r--webapp/components/search_results.jsx6
-rw-r--r--webapp/components/search_results_item.jsx67
9 files changed, 158 insertions, 238 deletions
diff --git a/webapp/components/common/post_flag_icon.jsx b/webapp/components/common/post_flag_icon.jsx
new file mode 100644
index 000000000..5f714f76b
--- /dev/null
+++ b/webapp/components/common/post_flag_icon.jsx
@@ -0,0 +1,87 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+import {FormattedMessage} from 'react-intl';
+import {Tooltip, OverlayTrigger} from 'react-bootstrap';
+
+import {flagPost, unflagPost} from 'actions/post_actions.jsx';
+import Constants from 'utils/constants.jsx';
+import * as Utils from 'utils/utils.jsx';
+
+function flagToolTip(isFlagged) {
+ return (
+ <Tooltip id='flagTooltip'>
+ <FormattedMessage
+ id={isFlagged ? 'flag_post.unflag' : 'flag_post.flag'}
+ defaultMessage={isFlagged ? 'Unflag' : 'Flag for follow up'}
+ />
+ </Tooltip>
+ );
+}
+
+function flagIcon() {
+ return (
+ <span
+ className='icon'
+ dangerouslySetInnerHTML={{__html: Constants.FLAG_ICON_SVG}}
+ />
+ );
+}
+
+export default function PostFlagIcon(props) {
+ function onFlagPost(e) {
+ e.preventDefault();
+ flagPost(props.postId);
+ }
+
+ function onUnflagPost(e) {
+ e.preventDefault();
+ unflagPost(props.postId);
+ }
+
+ const flagFunc = props.isFlagged ? onUnflagPost : onFlagPost;
+ const flagVisible = props.isFlagged ? 'visible' : '';
+
+ let flagIconId = null;
+ if (props.idCount > -1) {
+ flagIconId = Utils.createSafeId(props.idPrefix + props.idCount);
+ }
+
+ if (!props.isEphemeral) {
+ return (
+ <OverlayTrigger
+ key={'flagtooltipkey' + flagVisible}
+ delayShow={Constants.OVERLAY_TIME_DELAY}
+ placement='top'
+ overlay={flagToolTip(props.isFlagged)}
+ >
+ <a
+ id={flagIconId}
+ href='#'
+ className={'flag-icon__container ' + flagVisible}
+ onClick={flagFunc}
+ >
+ {flagIcon()}
+ </a>
+ </OverlayTrigger>
+ );
+ }
+
+ return '';
+}
+
+PostFlagIcon.propTypes = {
+ idPrefix: React.PropTypes.string.isRequired,
+ idCount: React.PropTypes.number,
+ postId: React.PropTypes.string.isRequired,
+ isFlagged: React.PropTypes.bool.isRequired,
+ isEphemeral: React.PropTypes.bool
+};
+
+PostFlagIcon.defaultProps = {
+ idCount: -1,
+ postId: '',
+ isFlagged: false,
+ isEphemeral: false
+};
diff --git a/webapp/components/post_view/components/post.jsx b/webapp/components/post_view/components/post.jsx
index 1959d5cad..38f95a85b 100644
--- a/webapp/components/post_view/components/post.jsx
+++ b/webapp/components/post_view/components/post.jsx
@@ -292,6 +292,7 @@ export default class Post extends Component {
ref='header'
post={post}
sameRoot={this.props.sameRoot}
+ lastPostCount={this.props.lastPostCount}
commentCount={this.props.commentCount}
handleCommentClick={this.handleCommentClick}
handleDropdownOpened={this.handleDropdownOpened}
diff --git a/webapp/components/post_view/components/post_header.jsx b/webapp/components/post_view/components/post_header.jsx
index 9de0b7e79..eccd092b5 100644
--- a/webapp/components/post_view/components/post_header.jsx
+++ b/webapp/components/post_view/components/post_header.jsx
@@ -79,6 +79,7 @@ export default class PostHeader extends React.Component {
<li className='col'>
<PostInfo
post={post}
+ lastPostCount={this.props.lastPostCount}
commentCount={this.props.commentCount}
handleCommentClick={this.props.handleCommentClick}
handleDropdownOpened={this.props.handleDropdownOpened}
@@ -105,6 +106,7 @@ PostHeader.propTypes = {
post: React.PropTypes.object.isRequired,
user: React.PropTypes.object,
currentUser: React.PropTypes.object.isRequired,
+ lastPostCount: React.PropTypes.number,
commentCount: React.PropTypes.number.isRequired,
isLastComment: React.PropTypes.bool.isRequired,
handleCommentClick: React.PropTypes.func.isRequired,
diff --git a/webapp/components/post_view/components/post_info.jsx b/webapp/components/post_view/components/post_info.jsx
index 0cb8ff5ac..1496429b3 100644
--- a/webapp/components/post_view/components/post_info.jsx
+++ b/webapp/components/post_view/components/post_info.jsx
@@ -5,6 +5,7 @@ import $ from 'jquery';
import ReactDOM from 'react-dom';
import PostTime from './post_time.jsx';
+import PostFlagIcon from 'components/common/post_flag_icon.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import * as PostActions from 'actions/post_actions.jsx';
@@ -13,7 +14,7 @@ import * as Utils from 'utils/utils.jsx';
import * as PostUtils from 'utils/post_utils.jsx';
import Constants from 'utils/constants.jsx';
import DelayedAction from 'utils/delayed_action.jsx';
-import {Tooltip, OverlayTrigger, Overlay} from 'react-bootstrap';
+import {Overlay} from 'react-bootstrap';
import EmojiPicker from 'components/emoji_picker/emoji_picker.jsx';
import React from 'react';
@@ -325,7 +326,11 @@ export default class PostInfo extends React.Component {
render() {
var post = this.props.post;
- const flagIcon = Constants.FLAG_ICON_SVG;
+
+ let idCount = -1;
+ if (this.props.lastPostCount >= 0 && this.props.lastPostCount < Constants.TEST_ID_COUNT) {
+ idCount = this.props.lastPostCount;
+ }
this.canDelete = PostUtils.canDeletePost(post);
this.canEdit = PostUtils.canEditPost(post, this.editDisableAction);
@@ -420,64 +425,6 @@ export default class PostInfo extends React.Component {
}
}
- let flag;
- let flagFunc;
- let flagVisible = '';
- let flagTooltip = (
- <Tooltip id='flagTooltip'>
- <FormattedMessage
- id='flag_post.flag'
- defaultMessage='Flag for follow up'
- />
- </Tooltip>
- );
- if (this.props.isFlagged) {
- flagVisible = 'visible';
- flag = (
- <span
- className='icon'
- dangerouslySetInnerHTML={{__html: flagIcon}}
- />
- );
- flagFunc = this.unflagPost;
- flagTooltip = (
- <Tooltip id='flagTooltip'>
- <FormattedMessage
- id='flag_post.unflag'
- defaultMessage='Unflag'
- />
- </Tooltip>
- );
- } else {
- flag = (
- <span
- className='icon'
- dangerouslySetInnerHTML={{__html: flagIcon}}
- />
- );
- flagFunc = this.flagPost;
- }
-
- let flagTrigger;
- if (!isEphemeral) {
- flagTrigger = (
- <OverlayTrigger
- key={'flagtooltipkey' + flagVisible}
- delayShow={Constants.OVERLAY_TIME_DELAY}
- placement='top'
- overlay={flagTooltip}
- >
- <a
- href='#'
- className={'flag-icon__container ' + flagVisible}
- onClick={flagFunc}
- >
- {flag}
- </a>
- </OverlayTrigger>
- );
- }
-
let pinnedBadge;
if (post.is_pinned) {
pinnedBadge = (
@@ -502,7 +449,13 @@ export default class PostInfo extends React.Component {
/>
{pinnedBadge}
{this.state.showEmojiPicker}
- {flagTrigger}
+ <PostFlagIcon
+ idPrefix={'centerPostFlag'}
+ idCount={idCount}
+ postId={post.id}
+ isFlagged={this.props.isFlagged}
+ isEphemeral={isEphemeral}
+ />
</li>
{options}
</ul>
@@ -518,6 +471,7 @@ PostInfo.defaultProps = {
};
PostInfo.propTypes = {
post: React.PropTypes.object.isRequired,
+ lastPostCount: React.PropTypes.number,
commentCount: React.PropTypes.number.isRequired,
isLastComment: React.PropTypes.bool.isRequired,
handleCommentClick: React.PropTypes.func.isRequired,
diff --git a/webapp/components/rhs_comment.jsx b/webapp/components/rhs_comment.jsx
index fb0972804..88e8c1ca6 100644
--- a/webapp/components/rhs_comment.jsx
+++ b/webapp/components/rhs_comment.jsx
@@ -8,6 +8,7 @@ import PostMessageContainer from 'components/post_view/components/post_message_c
import ProfilePicture from 'components/profile_picture.jsx';
import ReactionListContainer from 'components/post_view/components/reaction_list_container.jsx';
import RhsDropdown from 'components/rhs_dropdown.jsx';
+import PostFlagIcon from 'components/common/post_flag_icon.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import {flagPost, unflagPost, pinPost, unpinPost, addReaction} from 'actions/post_actions.jsx';
@@ -19,7 +20,7 @@ import * as PostUtils from 'utils/post_utils.jsx';
import Constants from 'utils/constants.jsx';
import DelayedAction from 'utils/delayed_action.jsx';
-import {Tooltip, OverlayTrigger, Overlay} from 'react-bootstrap';
+import {Overlay} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
@@ -128,6 +129,10 @@ export default class RhsComment extends React.Component {
return true;
}
+ if (nextProps.lastPostCount !== this.props.lastPostCount) {
+ return true;
+ }
+
return false;
}
@@ -384,9 +389,13 @@ export default class RhsComment extends React.Component {
render() {
const post = this.props.post;
- const flagIcon = Constants.FLAG_ICON_SVG;
const mattermostLogo = Constants.MATTERMOST_ICON_SVG;
+ let idCount = -1;
+ if (this.props.lastPostCount >= 0 && this.props.lastPostCount < Constants.TEST_ID_COUNT) {
+ idCount = this.props.lastPostCount;
+ }
+
const isEphemeral = Utils.isPostEphemeral(post);
const isPending = post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING;
const isSystemMessage = PostUtils.isSystemMessage(post);
@@ -523,64 +532,6 @@ export default class RhsComment extends React.Component {
);
}
- let flag;
- let flagFunc;
- let flagVisible = '';
- let flagTooltip = (
- <Tooltip id='flagTooltip'>
- <FormattedMessage
- id='flag_post.flag'
- defaultMessage='Flag for follow up'
- />
- </Tooltip>
- );
- if (this.props.isFlagged) {
- flagVisible = 'visible';
- flag = (
- <span
- className='icon'
- dangerouslySetInnerHTML={{__html: flagIcon}}
- />
- );
- flagFunc = this.unflagPost;
- flagTooltip = (
- <Tooltip id='flagTooltip'>
- <FormattedMessage
- id='flag_post.unflag'
- defaultMessage='Unflag'
- />
- </Tooltip>
- );
- } else {
- flag = (
- <span
- className='icon'
- dangerouslySetInnerHTML={{__html: flagIcon}}
- />
- );
- flagFunc = this.flagPost;
- }
-
- let flagTrigger;
- if (!isEphemeral) {
- flagTrigger = (
- <OverlayTrigger
- key={'commentflagtooltipkey' + flagVisible}
- delayShow={Constants.OVERLAY_TIME_DELAY}
- placement='top'
- overlay={flagTooltip}
- >
- <a
- href='#'
- className={'flag-icon__container ' + flagVisible}
- onClick={flagFunc}
- >
- {flag}
- </a>
- </OverlayTrigger>
- );
- }
-
let react;
let reactOverlay;
@@ -668,7 +619,13 @@ export default class RhsComment extends React.Component {
<li className='col'>
{this.renderTimeTag(post, timeOptions)}
{pinnedBadge}
- {flagTrigger}
+ <PostFlagIcon
+ idPrefix={'rhsCommentFlag'}
+ idCount={idCount}
+ postId={post.id}
+ isFlagged={this.props.isFlagged}
+ isEphemeral={isEphemeral}
+ />
</li>
{options}
</ul>
@@ -689,6 +646,7 @@ export default class RhsComment extends React.Component {
RhsComment.propTypes = {
post: React.PropTypes.object,
+ lastPostCount: React.PropTypes.number,
user: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object.isRequired,
compactDisplay: React.PropTypes.bool,
diff --git a/webapp/components/rhs_root_post.jsx b/webapp/components/rhs_root_post.jsx
index 65bc52f73..bf9748636 100644
--- a/webapp/components/rhs_root_post.jsx
+++ b/webapp/components/rhs_root_post.jsx
@@ -8,6 +8,7 @@ import FileAttachmentListContainer from './file_attachment_list_container.jsx';
import ProfilePicture from 'components/profile_picture.jsx';
import ReactionListContainer from 'components/post_view/components/reaction_list_container.jsx';
import RhsDropdown from 'components/rhs_dropdown.jsx';
+import PostFlagIcon from 'components/common/post_flag_icon.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
@@ -24,7 +25,7 @@ import ReactDOM from 'react-dom';
import Constants from 'utils/constants.jsx';
import DelayedAction from 'utils/delayed_action.jsx';
-import {Tooltip, OverlayTrigger, Overlay} from 'react-bootstrap';
+import {Overlay} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
@@ -203,7 +204,6 @@ export default class RhsRootPost extends React.Component {
const mattermostLogo = Constants.MATTERMOST_ICON_SVG;
var timestamp = user ? user.last_picture_update : 0;
var channel = ChannelStore.get(post.channel_id);
- const flagIcon = Constants.FLAG_ICON_SVG;
this.canDelete = PostUtils.canDeletePost(post);
this.canEdit = PostUtils.canEditPost(post, this.editDisableAction);
@@ -530,44 +530,6 @@ export default class RhsRootPost extends React.Component {
const profilePicContainer = (<div className='post__img'>{profilePic}</div>);
- let flag;
- let flagFunc;
- let flagVisible = '';
- let flagTooltip = (
- <Tooltip id='flagTooltip'>
- <FormattedMessage
- id='flag_post.flag'
- defaultMessage='Flag for follow up'
- />
- </Tooltip>
- );
- if (this.props.isFlagged) {
- flagVisible = 'visible';
- flag = (
- <span
- className='icon'
- dangerouslySetInnerHTML={{__html: flagIcon}}
- />
- );
- flagFunc = this.unflagPost;
- flagTooltip = (
- <Tooltip id='flagTooltip'>
- <FormattedMessage
- id='flag_post.unflag'
- defaultMessage='Unflag'
- />
- </Tooltip>
- );
- } else {
- flag = (
- <span
- className='icon'
- dangerouslySetInnerHTML={{__html: flagIcon}}
- />
- );
- flagFunc = this.flagPost;
- }
-
let pinnedBadge;
if (post.is_pinned) {
pinnedBadge = (
@@ -601,20 +563,11 @@ export default class RhsRootPost extends React.Component {
<li className='col'>
{this.renderTimeTag(post, timeOptions)}
{pinnedBadge}
- <OverlayTrigger
- key={'rootpostflagtooltipkey' + flagVisible}
- delayShow={Constants.OVERLAY_TIME_DELAY}
- placement='top'
- overlay={flagTooltip}
- >
- <a
- href='#'
- className={'flag-icon__container ' + flagVisible}
- onClick={flagFunc}
- >
- {flag}
- </a>
- </OverlayTrigger>
+ <PostFlagIcon
+ idPrefix={'rhsRootPostFlag'}
+ postId={post.id}
+ isFlagged={this.props.isFlagged}
+ />
</li>
<li className='col col__reply'>
{reactOverlay}
@@ -645,6 +598,7 @@ RhsRootPost.defaultProps = {
};
RhsRootPost.propTypes = {
post: React.PropTypes.object.isRequired,
+ lastPostCount: React.PropTypes.number,
user: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object.isRequired,
commentCount: React.PropTypes.number,
diff --git a/webapp/components/rhs_thread.jsx b/webapp/components/rhs_thread.jsx
index 174799878..82e54f6ff 100644
--- a/webapp/components/rhs_thread.jsx
+++ b/webapp/components/rhs_thread.jsx
@@ -352,7 +352,8 @@ export default class RhsThread extends React.Component {
let previousPostDay = rootPostDay;
const commentsLists = [];
- for (let i = 0; i < postsArray.length; i++) {
+ const postsLength = postsArray.length;
+ for (let i = 0; i < postsLength; i++) {
const comPost = postsArray[i];
let p;
if (UserStore.getCurrentId() === comPost.user_id) {
@@ -371,10 +372,7 @@ export default class RhsThread extends React.Component {
status = this.state.statuses[p.id] || 'offline';
}
- const keyPrefix = comPost.id ? comPost.id : comPost.pending_post_id;
-
const currentPostDay = Utils.getDateForUnixTicks(comPost.create_at);
-
if (currentPostDay.toDateString() !== previousPostDay.toDateString()) {
previousPostDay = currentPostDay;
commentsLists.push(
@@ -383,11 +381,14 @@ export default class RhsThread extends React.Component {
/>);
}
+ const keyPrefix = comPost.id ? comPost.id : comPost.pending_post_id;
+ const reverseCount = postsLength - i - 1;
commentsLists.push(
<div key={keyPrefix + 'commentKey'}>
<Comment
ref={comPost.id}
post={comPost}
+ lastPostCount={(reverseCount >= 0 && reverseCount < Constants.TEST_ID_COUNT) ? reverseCount : -1}
user={p}
currentUser={this.props.currentUser}
compactDisplay={this.state.compactDisplay}
@@ -431,12 +432,12 @@ export default class RhsThread extends React.Component {
className='post-right__scroll'
>
<DateSeparator
- date={rootPostDay.toDateString()}
+ date={rootPostDay}
/>
<RootPost
ref={selected.id}
post={selected}
- commentCount={postsArray.length}
+ commentCount={postsLength}
user={profile}
currentUser={this.props.currentUser}
compactDisplay={this.state.compactDisplay}
@@ -456,7 +457,7 @@ export default class RhsThread extends React.Component {
<CreateComment
channelId={selected.channel_id}
rootId={selected.id}
- latestPostId={postsArray.length > 0 ? postsArray[postsArray.length - 1].id : selected.id}
+ latestPostId={postsLength > 0 ? postsArray[postsLength - 1].id : selected.id}
/>
</div>
</div>
diff --git a/webapp/components/search_results.jsx b/webapp/components/search_results.jsx
index 682b04e2a..64e5a7c93 100644
--- a/webapp/components/search_results.jsx
+++ b/webapp/components/search_results.jsx
@@ -267,7 +267,7 @@ export default class SearchResults extends React.Component {
</div>
);
} else {
- ctls = results.order.map(function mymap(id) {
+ ctls = results.order.map(function searchResults(id, idx, arr) {
const post = results.posts[id];
let profile;
if (UserStore.getCurrentId() === post.user_id) {
@@ -285,12 +285,16 @@ export default class SearchResults extends React.Component {
if (this.state.flaggedPosts) {
isFlagged = this.state.flaggedPosts.get(post.id) === 'true';
}
+
+ const reverseCount = arr.length - idx - 1;
+
return (
<SearchResultsItem
key={post.id}
channel={this.state.channels.get(post.channel_id)}
compactDisplay={this.state.compactDisplay}
post={post}
+ lastPostCount={(reverseCount >= 0 && reverseCount < Constants.TEST_ID_COUNT) ? reverseCount : -1}
user={profile}
term={searchTerm}
isMentionSearch={this.props.isMentionSearch}
diff --git a/webapp/components/search_results_item.jsx b/webapp/components/search_results_item.jsx
index 09ea8c427..9e0eb51b0 100644
--- a/webapp/components/search_results_item.jsx
+++ b/webapp/components/search_results_item.jsx
@@ -13,12 +13,12 @@ import UserStore from 'stores/user_store.jsx';
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import {flagPost, unflagPost} from 'actions/post_actions.jsx';
+import PostFlagIcon from 'components/common/post_flag_icon.jsx';
import * as Utils from 'utils/utils.jsx';
import * as PostUtils from 'utils/post_utils.jsx';
import Constants from 'utils/constants.jsx';
-import {Tooltip, OverlayTrigger} from 'react-bootstrap';
const ActionTypes = Constants.ActionTypes;
import React from 'react';
@@ -114,7 +114,11 @@ export default class SearchResultsItem extends React.Component {
const timestamp = UserStore.getCurrentUser().last_picture_update;
const user = this.props.user || {};
const post = this.props.post;
- const flagIcon = Constants.FLAG_ICON_SVG;
+
+ let idCount = -1;
+ if (this.props.lastPostCount >= 0 && this.props.lastPostCount < Constants.TEST_ID_COUNT) {
+ idCount = this.props.lastPostCount;
+ }
if (channel) {
channelName = channel.display_name;
@@ -185,59 +189,13 @@ export default class SearchResultsItem extends React.Component {
</p>
);
} else {
- let flag;
- let flagFunc;
- let flagVisible = '';
- let flagTooltip = (
- <Tooltip id='flagTooltip'>
- <FormattedMessage
- id='flag_post.flag'
- defaultMessage='Flag for follow up'
- />
- </Tooltip>
- );
-
- if (this.props.isFlagged) {
- flagVisible = 'visible';
- flagTooltip = (
- <Tooltip id='flagTooltip'>
- <FormattedMessage
- id='flag_post.unflag'
- defaultMessage='Unflag'
- />
- </Tooltip>
- );
- flagFunc = this.unflagPost;
- flag = (
- <span
- className='icon'
- dangerouslySetInnerHTML={{__html: flagIcon}}
- />
- );
- } else {
- flag = (
- <span
- className='icon'
- dangerouslySetInnerHTML={{__html: flagIcon}}
- />
- );
- flagFunc = this.flagPost;
- }
-
flagContent = (
- <OverlayTrigger
- delayShow={Constants.OVERLAY_TIME_DELAY}
- placement='top'
- overlay={flagTooltip}
- >
- <a
- href='#'
- className={'flag-icon__container ' + flagVisible}
- onClick={flagFunc}
- >
- {flag}
- </a>
- </OverlayTrigger>
+ <PostFlagIcon
+ idPrefix={'searchPostFlag'}
+ idCount={idCount}
+ postId={post.id}
+ isFlagged={this.props.isFlagged}
+ />
);
rhsControls = (
@@ -364,6 +322,7 @@ export default class SearchResultsItem extends React.Component {
SearchResultsItem.propTypes = {
post: React.PropTypes.object,
+ lastPostCount: React.PropTypes.number,
user: React.PropTypes.object,
channel: React.PropTypes.object,
compactDisplay: React.PropTypes.bool,