create DotMenu components and add dotmenu IDs to posts at center and RHS (#6642)
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
5b017171cd
Коммит
0e89d9be1d
197
webapp/components/dot_menu/dot_menu.jsx
Обычный файл
197
webapp/components/dot_menu/dot_menu.jsx
Обычный файл
@@ -0,0 +1,197 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
import $ from 'jquery';
|
||||||
|
import React, {Component} from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import DotMenuFlag from './dot_menu_flag.jsx';
|
||||||
|
import DotMenuItem from './dot_menu_item.jsx';
|
||||||
|
import DotMenuEdit from './dot_menu_edit.jsx';
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
export default class DotMenu extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
idPrefix: PropTypes.string.isRequired,
|
||||||
|
idCount: PropTypes.number,
|
||||||
|
post: PropTypes.object.isRequired,
|
||||||
|
commentCount: PropTypes.number,
|
||||||
|
isFlagged: PropTypes.bool,
|
||||||
|
handleCommentClick: PropTypes.func,
|
||||||
|
handleDropdownOpened: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
idCount: -1,
|
||||||
|
post: {},
|
||||||
|
commentCount: 0,
|
||||||
|
isFlagged: false
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.handleDropdownOpened = this.handleDropdownOpened.bind(this);
|
||||||
|
this.canDelete = false;
|
||||||
|
this.canEdit = false;
|
||||||
|
this.editDisableAction = new DelayedAction(this.handleEditDisable);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
$('#' + this.props.idPrefix + '_dropdown' + this.props.post.id).on('shown.bs.dropdown', this.handleDropdownOpened);
|
||||||
|
$('#' + this.props.idPrefix + '_dropdown' + this.props.post.id).on('hidden.bs.dropdown', () => this.props.handleDropdownOpened(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDropdownOpened() {
|
||||||
|
this.props.handleDropdownOpened(true);
|
||||||
|
|
||||||
|
const position = $('#post-list').height() - $(this.refs.dropdownToggle).offset().top;
|
||||||
|
const dropdown = $(this.refs.dropdown);
|
||||||
|
|
||||||
|
if (position < dropdown.height()) {
|
||||||
|
dropdown.addClass('bottom');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEditDisable() {
|
||||||
|
this.canEdit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const isSystemMessage = PostUtils.isSystemMessage(this.props.post);
|
||||||
|
const isMobile = Utils.isMobile();
|
||||||
|
this.canDelete = PostUtils.canDeletePost(this.props.post);
|
||||||
|
this.canEdit = PostUtils.canEditPost(this.props.post, this.editDisableAction);
|
||||||
|
|
||||||
|
if (this.props.idPrefix === Constants.CENTER && (!isMobile && isSystemMessage && !this.canDelete && !this.canEdit)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.idPrefix === Constants.RHS && (this.props.post.state === Constants.POST_FAILED || this.props.post.state === Constants.POST_LOADING)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let type = 'Post';
|
||||||
|
if (this.props.post.root_id && this.props.post.root_id.length > 0) {
|
||||||
|
type = 'Comment';
|
||||||
|
}
|
||||||
|
|
||||||
|
const idPrefix = this.props.idPrefix + 'DotMenu';
|
||||||
|
|
||||||
|
let dotMenuFlag = null;
|
||||||
|
if (isMobile) {
|
||||||
|
dotMenuFlag = (
|
||||||
|
<DotMenuFlag
|
||||||
|
idPrefix={idPrefix + 'Flag'}
|
||||||
|
idCount={this.props.idCount}
|
||||||
|
postId={this.props.post.id}
|
||||||
|
isFlagged={this.props.isFlagged}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dotMenuReply = null;
|
||||||
|
let dotMenuPermalink = null;
|
||||||
|
let dotMenuPin = null;
|
||||||
|
if (!isSystemMessage) {
|
||||||
|
if (this.props.idPrefix === Constants.CENTER) {
|
||||||
|
dotMenuReply = (
|
||||||
|
<DotMenuItem
|
||||||
|
idPrefix={idPrefix + 'Reply'}
|
||||||
|
idCount={this.props.idCount}
|
||||||
|
handleOnClick={this.props.handleCommentClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dotMenuPermalink = (
|
||||||
|
<DotMenuItem
|
||||||
|
idPrefix={idPrefix + 'Permalink'}
|
||||||
|
idCount={this.props.idCount}
|
||||||
|
post={this.props.post}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
dotMenuPin = (
|
||||||
|
<DotMenuItem
|
||||||
|
idPrefix={idPrefix + 'Pin'}
|
||||||
|
idCount={this.props.idCount}
|
||||||
|
post={this.props.post}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dotMenuDelete = null;
|
||||||
|
if (this.canDelete) {
|
||||||
|
dotMenuDelete = (
|
||||||
|
<DotMenuItem
|
||||||
|
idPrefix={idPrefix + 'Delete'}
|
||||||
|
idCount={this.props.idCount}
|
||||||
|
post={this.props.post}
|
||||||
|
commentCount={type === 'Post' ? this.props.commentCount : 0}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dotMenuEdit = null;
|
||||||
|
if (this.canEdit) {
|
||||||
|
dotMenuEdit = (
|
||||||
|
<DotMenuEdit
|
||||||
|
idPrefix={idPrefix + 'Edit'}
|
||||||
|
idCount={this.props.idCount}
|
||||||
|
post={this.props.post}
|
||||||
|
type={type}
|
||||||
|
commentCount={type === 'Post' ? this.props.commentCount : 0}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dotMenuId = null;
|
||||||
|
if (this.props.idCount > -1) {
|
||||||
|
dotMenuId = Utils.createSafeId(idPrefix + this.props.idCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.idPrefix === Constants.RHS_ROOT) {
|
||||||
|
dotMenuId = idPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id={dotMenuId}
|
||||||
|
className='dropdown'
|
||||||
|
ref='dotMenu'
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
id={this.props.idPrefix + '_dropdown' + this.props.post.id}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
ref='dropdownToggle'
|
||||||
|
href='#'
|
||||||
|
className='dropdown-toggle post__dropdown theme'
|
||||||
|
type='button'
|
||||||
|
data-toggle='dropdown'
|
||||||
|
aria-expanded='false'
|
||||||
|
/>
|
||||||
|
<div className='dropdown-menu__content'>
|
||||||
|
<ul
|
||||||
|
ref='dropdown'
|
||||||
|
className='dropdown-menu'
|
||||||
|
role='menu'
|
||||||
|
>
|
||||||
|
{dotMenuReply}
|
||||||
|
{dotMenuFlag}
|
||||||
|
{dotMenuPermalink}
|
||||||
|
{dotMenuPin}
|
||||||
|
{dotMenuDelete}
|
||||||
|
{dotMenuEdit}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
58
webapp/components/dot_menu/dot_menu_edit.jsx
Обычный файл
58
webapp/components/dot_menu/dot_menu_edit.jsx
Обычный файл
@@ -0,0 +1,58 @@
|
|||||||
|
// 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 PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import * as Utils from 'utils/utils.jsx';
|
||||||
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
|
export default function DotMenuEdit(props) {
|
||||||
|
let editId = null;
|
||||||
|
if (props.idCount > -1) {
|
||||||
|
editId = Utils.createSafeId(props.idPrefix + props.idCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.idPrefix.indexOf(Constants.RHS_ROOT) === 0) {
|
||||||
|
editId = props.idPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
id={Utils.createSafeId(editId)}
|
||||||
|
key={props.idPrefix}
|
||||||
|
role='presentation'
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href='#'
|
||||||
|
role='menuitem'
|
||||||
|
data-toggle='modal'
|
||||||
|
data-target='#edit_post'
|
||||||
|
data-refocusid={props.idPrefix.indexOf(Constants.CENTER) === 0 ? '#post_textbox' : '#reply_textbox'}
|
||||||
|
data-title={props.idPrefix.indexOf(Constants.CENTER) === 0 ? props.type : Utils.localizeMessage('rhs_comment.comment', 'Comment')}
|
||||||
|
data-message={props.post.message}
|
||||||
|
data-postid={props.post.id}
|
||||||
|
data-channelid={props.post.channel_id}
|
||||||
|
data-comments={props.commentCount}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='post_info.edit'
|
||||||
|
defaultMessage='Edit'
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DotMenuEdit.propTypes = {
|
||||||
|
idPrefix: PropTypes.string.isRequired,
|
||||||
|
idCount: PropTypes.number,
|
||||||
|
post: PropTypes.object,
|
||||||
|
type: PropTypes.string,
|
||||||
|
commentCount: PropTypes.number
|
||||||
|
};
|
||||||
|
|
||||||
|
DotMenuEdit.defaultProps = {
|
||||||
|
idCount: -1
|
||||||
|
};
|
||||||
70
webapp/components/dot_menu/dot_menu_flag.jsx
Обычный файл
70
webapp/components/dot_menu/dot_menu_flag.jsx
Обычный файл
@@ -0,0 +1,70 @@
|
|||||||
|
// 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 PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import {flagPost, unflagPost} from 'actions/post_actions.jsx';
|
||||||
|
import * as Utils from 'utils/utils.jsx';
|
||||||
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
|
function formatMessage(isFlagged) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id={isFlagged ? 'rhs_root.mobile.unflag' : 'rhs_root.mobile.flag'}
|
||||||
|
defaultMessage={isFlagged ? 'Unflag' : 'Flag'}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DotMenuFlag(props) {
|
||||||
|
function onFlagPost(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
flagPost(props.postId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUnflagPost(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
unflagPost(props.postId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const flagFunc = props.isFlagged ? onUnflagPost : onFlagPost;
|
||||||
|
|
||||||
|
let flagId = null;
|
||||||
|
if (props.idCount > -1) {
|
||||||
|
flagId = Utils.createSafeId(props.idPrefix + props.idCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.idPrefix.indexOf(Constants.RHS_ROOT) === 0) {
|
||||||
|
flagId = props.idPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={props.idPrefix}
|
||||||
|
role='presentation'
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
id={flagId}
|
||||||
|
href='#'
|
||||||
|
onClick={flagFunc}
|
||||||
|
>
|
||||||
|
{formatMessage(props.isFlagged)}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DotMenuFlag.propTypes = {
|
||||||
|
idCount: PropTypes.number,
|
||||||
|
idPrefix: PropTypes.string.isRequired,
|
||||||
|
postId: PropTypes.string.isRequired,
|
||||||
|
isFlagged: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
DotMenuFlag.defaultProps = {
|
||||||
|
idCount: -1,
|
||||||
|
postId: '',
|
||||||
|
isFlagged: false
|
||||||
|
};
|
||||||
107
webapp/components/dot_menu/dot_menu_item.jsx
Обычный файл
107
webapp/components/dot_menu/dot_menu_item.jsx
Обычный файл
@@ -0,0 +1,107 @@
|
|||||||
|
// 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 PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import {unpinPost, pinPost} from 'actions/post_actions.jsx';
|
||||||
|
import {showGetPostLinkModal, showDeletePostModal} from 'actions/global_actions.jsx';
|
||||||
|
import * as Utils from 'utils/utils.jsx';
|
||||||
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
|
export default function DotMenuItem(props) {
|
||||||
|
function handlePermalink(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
showGetPostLinkModal(props.post);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleUnpinPost(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
unpinPost(props.post.channel_id, props.post.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePinPost(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
pinPost(props.post.channel_id, props.post.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDeletePost(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
showDeletePostModal(props.post, props.commentCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
const attrib = {};
|
||||||
|
attrib.idPrefix = props.idPrefix;
|
||||||
|
attrib.class = '';
|
||||||
|
|
||||||
|
switch (props.idPrefix.substring((props.idPrefix.indexOf('DotMenu') + 7))) {
|
||||||
|
case 'Reply':
|
||||||
|
attrib.class = 'link__reply theme';
|
||||||
|
attrib.onClick = props.handleOnClick;
|
||||||
|
attrib.formattedMessageId = 'post_info.reply';
|
||||||
|
attrib.formattedDefaultMessage = 'Reply';
|
||||||
|
break;
|
||||||
|
case 'Permalink':
|
||||||
|
attrib.onClick = handlePermalink;
|
||||||
|
attrib.formattedMessageId = 'post_info.permalink';
|
||||||
|
attrib.formattedDefaultMessage = 'Permalink';
|
||||||
|
attrib.post = props.post;
|
||||||
|
break;
|
||||||
|
case 'Pin':
|
||||||
|
attrib.onClick = props.post.is_pinned ? handleUnpinPost : handlePinPost;
|
||||||
|
attrib.formattedMessageId = props.post.is_pinned ? 'post_info.unpin' : 'post_info.pin';
|
||||||
|
attrib.formattedDefaultMessage = props.post.is_pinned ? 'Un-pin from channel' : 'Pin from channel';
|
||||||
|
attrib.post = props.post;
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
attrib.onClick = handleDeletePost;
|
||||||
|
attrib.formattedMessageId = 'post_info.del';
|
||||||
|
attrib.formattedDefaultMessage = 'Delete';
|
||||||
|
attrib.commentCount = props.commentCount;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
let itemId = null;
|
||||||
|
if (props.idCount > -1) {
|
||||||
|
itemId = Utils.createSafeId(props.idPrefix + props.idCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrib.idPrefix.indexOf(Constants.RHS_ROOT) === 0) {
|
||||||
|
itemId = attrib.idPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
id={Utils.createSafeId(itemId)}
|
||||||
|
key={attrib.idPrefix}
|
||||||
|
role='presentation'
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href='#'
|
||||||
|
role='menuitem'
|
||||||
|
onClick={attrib.onClick}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id={attrib.formattedMessageId}
|
||||||
|
defaultMessage={attrib.formattedDefaultMessage}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DotMenuItem.propTypes = {
|
||||||
|
idPrefix: PropTypes.string.isRequired,
|
||||||
|
idCount: PropTypes.number,
|
||||||
|
post: PropTypes.object,
|
||||||
|
handleOnClick: PropTypes.func,
|
||||||
|
type: PropTypes.string,
|
||||||
|
commentCount: PropTypes.number
|
||||||
|
};
|
||||||
|
|
||||||
|
DotMenuItem.defaultProps = {
|
||||||
|
idPrefix: '',
|
||||||
|
idCount: -1
|
||||||
|
};
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import $ from 'jquery';
|
|
||||||
|
|
||||||
import PostTime from './post_time.jsx';
|
import PostTime from './post_time.jsx';
|
||||||
import PostFlagIcon from 'components/common/post_flag_icon.jsx';
|
import PostFlagIcon from 'components/common/post_flag_icon.jsx';
|
||||||
|
import DotMenu from 'components/dot_menu/dot_menu.jsx';
|
||||||
|
|
||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||||
import * as PostActions from 'actions/post_actions.jsx';
|
import * as PostActions from 'actions/post_actions.jsx';
|
||||||
@@ -13,7 +12,6 @@ import CommentIcon from 'components/common/comment_icon.jsx';
|
|||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import * as PostUtils from 'utils/post_utils.jsx';
|
import * as PostUtils from 'utils/post_utils.jsx';
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
import DelayedAction from 'utils/delayed_action.jsx';
|
|
||||||
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
|
|
||||||
@@ -26,257 +24,15 @@ export default class PostInfo extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.handleDropdownOpened = this.handleDropdownOpened.bind(this);
|
|
||||||
this.handlePermalink = this.handlePermalink.bind(this);
|
|
||||||
this.removePost = this.removePost.bind(this);
|
this.removePost = this.removePost.bind(this);
|
||||||
this.flagPost = this.flagPost.bind(this);
|
|
||||||
this.unflagPost = this.unflagPost.bind(this);
|
|
||||||
this.pinPost = this.pinPost.bind(this);
|
|
||||||
this.unpinPost = this.unpinPost.bind(this);
|
|
||||||
this.reactEmojiClick = this.reactEmojiClick.bind(this);
|
this.reactEmojiClick = this.reactEmojiClick.bind(this);
|
||||||
|
|
||||||
this.canEdit = false;
|
|
||||||
this.canDelete = false;
|
|
||||||
this.editDisableAction = new DelayedAction(this.handleEditDisable);
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
showEmojiPicker: false,
|
showEmojiPicker: false,
|
||||||
reactionPickerOffset: 21
|
reactionPickerOffset: 21
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDropdownOpened() {
|
|
||||||
this.props.handleDropdownOpened(true);
|
|
||||||
|
|
||||||
const position = $('#post-list').height() - $(this.refs.dropdownToggle).offset().top;
|
|
||||||
const dropdown = $(this.refs.dropdown);
|
|
||||||
|
|
||||||
if (position < dropdown.height()) {
|
|
||||||
dropdown.addClass('bottom');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEditDisable() {
|
|
||||||
this.canEdit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
$('#post_dropdown' + this.props.post.id).on('shown.bs.dropdown', this.handleDropdownOpened);
|
|
||||||
$('#post_dropdown' + this.props.post.id).on('hidden.bs.dropdown', () => this.props.handleDropdownOpened(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
createDropdown(isSystemMessage) {
|
|
||||||
const post = this.props.post;
|
|
||||||
|
|
||||||
var type = 'Post';
|
|
||||||
if (post.root_id && post.root_id.length > 0) {
|
|
||||||
type = 'Comment';
|
|
||||||
}
|
|
||||||
|
|
||||||
var dropdownContents = [];
|
|
||||||
var dataComments = 0;
|
|
||||||
if (type === 'Post') {
|
|
||||||
dataComments = this.props.commentCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSystemMessage) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='replyLink'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
className='link__reply theme'
|
|
||||||
href='#'
|
|
||||||
onClick={this.props.handleCommentClick}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='post_info.reply'
|
|
||||||
defaultMessage='Reply'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Utils.isMobile()) {
|
|
||||||
if (this.props.isFlagged) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='mobileFlag'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.unflagPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.mobile.unflag'
|
|
||||||
defaultMessage='Unflag'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='mobileFlag'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.flagPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.mobile.flag'
|
|
||||||
defaultMessage='Flag'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSystemMessage) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='copyLink'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.handlePermalink}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='post_info.permalink'
|
|
||||||
defaultMessage='Permalink'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.props.post.is_pinned) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='unpinLink'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.unpinPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='post_info.unpin'
|
|
||||||
defaultMessage='Un-pin from channel'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='pinLink'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.pinPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='post_info.pin'
|
|
||||||
defaultMessage='Pin to channel'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.canDelete) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='deletePost'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
role='menuitem'
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
GlobalActions.showDeletePostModal(post, dataComments);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='post_info.del'
|
|
||||||
defaultMessage='Delete'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.canEdit) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='editPost'
|
|
||||||
role='presentation'
|
|
||||||
className={this.canEdit ? 'dropdown-submenu' : 'dropdown-submenu hide'}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
role='menuitem'
|
|
||||||
data-toggle='modal'
|
|
||||||
data-target='#edit_post'
|
|
||||||
data-refocusid='#post_textbox'
|
|
||||||
data-title={type}
|
|
||||||
data-message={post.message}
|
|
||||||
data-postid={post.id}
|
|
||||||
data-channelid={post.channel_id}
|
|
||||||
data-comments={dataComments}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='post_info.edit'
|
|
||||||
defaultMessage='Edit'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dropdownContents.length === 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
id={'post_dropdown' + this.props.post.id}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
ref='dropdownToggle'
|
|
||||||
href='#'
|
|
||||||
className='dropdown-toggle post__dropdown theme'
|
|
||||||
type='button'
|
|
||||||
data-toggle='dropdown'
|
|
||||||
aria-expanded='false'
|
|
||||||
/>
|
|
||||||
<div className='dropdown-menu__content'>
|
|
||||||
<ul
|
|
||||||
ref='dropdown'
|
|
||||||
className='dropdown-menu'
|
|
||||||
role='menu'
|
|
||||||
>
|
|
||||||
{dropdownContents}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePermalink(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
GlobalActions.showGetPostLinkModal(this.props.post);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleEmojiPicker = () => {
|
toggleEmojiPicker = () => {
|
||||||
const showEmojiPicker = !this.state.showEmojiPicker;
|
const showEmojiPicker = !this.state.showEmojiPicker;
|
||||||
|
|
||||||
@@ -306,26 +62,6 @@ export default class PostInfo extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pinPost(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
PostActions.pinPost(this.props.post.channel_id, this.props.post.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
unpinPost(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
PostActions.unpinPost(this.props.post.channel_id, this.props.post.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
flagPost(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
PostActions.flagPost(this.props.post.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
unflagPost(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
PostActions.unflagPost(this.props.post.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
reactEmojiClick(emoji) {
|
reactEmojiClick(emoji) {
|
||||||
const pickerOffset = 21;
|
const pickerOffset = 21;
|
||||||
this.setState({showEmojiPicker: false, reactionPickerOffset: pickerOffset});
|
this.setState({showEmojiPicker: false, reactionPickerOffset: pickerOffset});
|
||||||
@@ -345,9 +81,6 @@ export default class PostInfo extends React.Component {
|
|||||||
idCount = this.props.lastPostCount;
|
idCount = this.props.lastPostCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.canDelete = PostUtils.canDeletePost(post);
|
|
||||||
this.canEdit = PostUtils.canEditPost(post, this.editDisableAction);
|
|
||||||
|
|
||||||
const isEphemeral = Utils.isPostEphemeral(post);
|
const isEphemeral = Utils.isPostEphemeral(post);
|
||||||
const isPending = post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING;
|
const isPending = post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING;
|
||||||
const isSystemMessage = PostUtils.isSystemMessage(post);
|
const isSystemMessage = PostUtils.isSystemMessage(post);
|
||||||
@@ -395,20 +128,25 @@ export default class PostInfo extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (!isPending) {
|
} else if (!isPending) {
|
||||||
const dropdown = this.createDropdown(isSystemMessage);
|
const dotMenu = (
|
||||||
|
<DotMenu
|
||||||
|
idPrefix={Constants.CENTER}
|
||||||
|
idCount={idCount}
|
||||||
|
post={this.props.post}
|
||||||
|
commentCount={this.props.commentCount}
|
||||||
|
isFlagged={this.props.isFlagged}
|
||||||
|
handleCommentClick={this.props.handleCommentClick}
|
||||||
|
handleDropdownOpened={this.props.handleDropdownOpened}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
if (dropdown) {
|
if (dotMenu) {
|
||||||
options = (
|
options = (
|
||||||
<div
|
<div
|
||||||
ref='dotMenu'
|
ref='dotMenu'
|
||||||
className='col col__reply'
|
className='col col__reply'
|
||||||
>
|
>
|
||||||
<div
|
{dotMenu}
|
||||||
className='dropdown'
|
|
||||||
ref='dotMenu'
|
|
||||||
>
|
|
||||||
{dropdown}
|
|
||||||
</div>
|
|
||||||
{react}
|
{react}
|
||||||
{comments}
|
{comments}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import PendingPostOptions from 'components/post_view/components/pending_post_opt
|
|||||||
import PostMessageContainer from 'components/post_view/components/post_message_container.jsx';
|
import PostMessageContainer from 'components/post_view/components/post_message_container.jsx';
|
||||||
import ProfilePicture from 'components/profile_picture.jsx';
|
import ProfilePicture from 'components/profile_picture.jsx';
|
||||||
import ReactionListContainer from 'components/post_view/components/reaction_list_container.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 PostFlagIcon from 'components/common/post_flag_icon.jsx';
|
||||||
|
import DotMenu from 'components/dot_menu/dot_menu.jsx';
|
||||||
|
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
||||||
|
|
||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||||
import {flagPost, unflagPost, pinPost, unpinPost, addReaction} from 'actions/post_actions.jsx';
|
import {flagPost, unflagPost, pinPost, unpinPost, addReaction} from 'actions/post_actions.jsx';
|
||||||
@@ -17,19 +18,13 @@ import TeamStore from 'stores/team_store.jsx';
|
|||||||
|
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import * as PostUtils from 'utils/post_utils.jsx';
|
import * as PostUtils from 'utils/post_utils.jsx';
|
||||||
|
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
import DelayedAction from 'utils/delayed_action.jsx';
|
|
||||||
|
|
||||||
import {FormattedMessage} from 'react-intl';
|
|
||||||
|
|
||||||
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
|
||||||
|
|
||||||
import loadingGif from 'images/load.gif';
|
import loadingGif from 'images/load.gif';
|
||||||
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {FormattedMessage} from 'react-intl';
|
||||||
import {Link} from 'react-router/es6';
|
import {Link} from 'react-router/es6';
|
||||||
|
|
||||||
export default class RhsComment extends React.Component {
|
export default class RhsComment extends React.Component {
|
||||||
@@ -45,10 +40,6 @@ export default class RhsComment extends React.Component {
|
|||||||
this.reactEmojiClick = this.reactEmojiClick.bind(this);
|
this.reactEmojiClick = this.reactEmojiClick.bind(this);
|
||||||
this.handleDropdownOpened = this.handleDropdownOpened.bind(this);
|
this.handleDropdownOpened = this.handleDropdownOpened.bind(this);
|
||||||
|
|
||||||
this.canEdit = false;
|
|
||||||
this.canDelete = false;
|
|
||||||
this.editDisableAction = new DelayedAction(this.handleEditDisable);
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
currentTeamDisplayName: TeamStore.getCurrent().name,
|
currentTeamDisplayName: TeamStore.getCurrent().name,
|
||||||
width: '',
|
width: '',
|
||||||
@@ -75,10 +66,6 @@ export default class RhsComment extends React.Component {
|
|||||||
GlobalActions.showGetPostLinkModal(this.props.post);
|
GlobalActions.showGetPostLinkModal(this.props.post);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEditDisable() {
|
|
||||||
this.canEdit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
removePost() {
|
removePost() {
|
||||||
GlobalActions.emitRemovePost(this.props.post);
|
GlobalActions.emitRemovePost(this.props.post);
|
||||||
}
|
}
|
||||||
@@ -160,173 +147,6 @@ export default class RhsComment extends React.Component {
|
|||||||
unpinPost(this.props.post.channel_id, this.props.post.id);
|
unpinPost(this.props.post.channel_id, this.props.post.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
createDropdown(isSystemMessage) {
|
|
||||||
const post = this.props.post;
|
|
||||||
|
|
||||||
if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.canDelete = PostUtils.canDeletePost(post);
|
|
||||||
this.canEdit = PostUtils.canEditPost(post, this.editDisableAction);
|
|
||||||
|
|
||||||
var dropdownContents = [];
|
|
||||||
|
|
||||||
if (Utils.isMobile()) {
|
|
||||||
if (this.props.isFlagged) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='mobileFlag'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.unflagPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.mobile.unflag'
|
|
||||||
defaultMessage='Unflag'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='mobileFlag'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.flagPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.mobile.flag'
|
|
||||||
defaultMessage='Flag'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSystemMessage) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='rhs-root-permalink'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.handlePermalink}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_comment.permalink'
|
|
||||||
defaultMessage='Permalink'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (post.is_pinned) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='rhs-comment-unpin'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.unpinPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.unpin'
|
|
||||||
defaultMessage='Un-pin from channel'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='rhs-comment-pin'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.pinPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.pin'
|
|
||||||
defaultMessage='Pin to channel'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.canDelete) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
role='presentation'
|
|
||||||
key='delete-button'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
role='menuitem'
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
GlobalActions.showDeletePostModal(post, 0);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_comment.del'
|
|
||||||
defaultMessage='Delete'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.canEdit) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
role='presentation'
|
|
||||||
key='edit-button'
|
|
||||||
className={this.canEdit ? '' : 'hide'}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
role='menuitem'
|
|
||||||
data-toggle='modal'
|
|
||||||
data-target='#edit_post'
|
|
||||||
data-refocusid='#reply_textbox'
|
|
||||||
data-title={Utils.localizeMessage('rhs_comment.comment', 'Comment')}
|
|
||||||
data-message={post.message}
|
|
||||||
data-postid={post.id}
|
|
||||||
data-channelid={post.channel_id}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_comment.edit'
|
|
||||||
defaultMessage='Edit'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dropdownContents.length === 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RhsDropdown
|
|
||||||
dropdownContents={dropdownContents}
|
|
||||||
handleDropdownOpened={this.handleDropdownOpened}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
timeTag(post, timeOptions) {
|
timeTag(post, timeOptions) {
|
||||||
return (
|
return (
|
||||||
<time
|
<time
|
||||||
@@ -575,12 +395,22 @@ export default class RhsComment extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (!isSystemMessage) {
|
} else if (!isSystemMessage) {
|
||||||
|
const dotMenu = (
|
||||||
|
<DotMenu
|
||||||
|
idPrefix={Constants.RHS}
|
||||||
|
idCount={idCount}
|
||||||
|
post={this.props.post}
|
||||||
|
isFlagged={this.props.isFlagged}
|
||||||
|
handleDropdownOpened={this.handleDropdownOpened}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
options = (
|
options = (
|
||||||
<div
|
<div
|
||||||
ref='dotMenu'
|
ref='dotMenu'
|
||||||
className='col col__reply'
|
className='col col__reply'
|
||||||
>
|
>
|
||||||
{this.createDropdown(isSystemMessage)}
|
{dotMenu}
|
||||||
{react}
|
{react}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import React, {Component} from 'react';
|
|
||||||
import {Dropdown} from 'react-bootstrap';
|
|
||||||
|
|
||||||
import RhsDropdownButton from 'components/rhs_dropdown_button.jsx';
|
|
||||||
import RhsDropdownMenu from 'components/rhs_dropdown_menu.jsx';
|
|
||||||
|
|
||||||
import * as Agent from 'utils/user_agent.jsx';
|
|
||||||
|
|
||||||
export default class RhsDropdown extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
dropdownContents: PropTypes.array.isRequired,
|
|
||||||
handleDropdownOpened: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
showDropdown: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleDropdown = () => {
|
|
||||||
const showDropdown = !this.state.showDropdown;
|
|
||||||
if (this.props.handleDropdownOpened) {
|
|
||||||
this.props.handleDropdownOpened(showDropdown);
|
|
||||||
}
|
|
||||||
if (Agent.isMobile() || Agent.isMobileApp()) {
|
|
||||||
const scroll = document.querySelector('.scrollbar--view');
|
|
||||||
if (showDropdown) {
|
|
||||||
scroll.style.overflow = 'hidden';
|
|
||||||
} else {
|
|
||||||
scroll.style.overflow = 'scroll';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({showDropdown});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
id='rhs_dropdown'
|
|
||||||
open={this.state.showDropdown}
|
|
||||||
onToggle={this.toggleDropdown}
|
|
||||||
>
|
|
||||||
<RhsDropdownButton
|
|
||||||
bsRole='toggle'
|
|
||||||
onClick={this.toggleDropdown}
|
|
||||||
/>
|
|
||||||
<RhsDropdownMenu>
|
|
||||||
{this.props.dropdownContents}
|
|
||||||
</RhsDropdownMenu>
|
|
||||||
</Dropdown>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import React, {PureComponent} from 'react';
|
|
||||||
|
|
||||||
export default class RhsDropdownButton extends PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
onClick: PropTypes.func.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
className='post__dropdown dropdown-toggle'
|
|
||||||
onClick={this.props.onClick}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See License.txt for license information.
|
|
||||||
|
|
||||||
import {Dropdown} from 'react-bootstrap';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export default class RhsDropdownMenu extends Dropdown.Menu {
|
|
||||||
constructor(props) { //eslint-disable-line no-useless-constructor
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className='dropdown-menu__content'
|
|
||||||
onClick={this.props.onClose}
|
|
||||||
>
|
|
||||||
{super.render()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,8 +7,8 @@ import PostMessageContainer from 'components/post_view/components/post_message_c
|
|||||||
import FileAttachmentListContainer from './file_attachment_list_container.jsx';
|
import FileAttachmentListContainer from './file_attachment_list_container.jsx';
|
||||||
import ProfilePicture from 'components/profile_picture.jsx';
|
import ProfilePicture from 'components/profile_picture.jsx';
|
||||||
import ReactionListContainer from 'components/post_view/components/reaction_list_container.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 PostFlagIcon from 'components/common/post_flag_icon.jsx';
|
||||||
|
import DotMenu from 'components/dot_menu/dot_menu.jsx';
|
||||||
|
|
||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
@@ -44,8 +44,6 @@ export default class RhsRootPost extends React.Component {
|
|||||||
this.reactEmojiClick = this.reactEmojiClick.bind(this);
|
this.reactEmojiClick = this.reactEmojiClick.bind(this);
|
||||||
this.handleDropdownOpened = this.handleDropdownOpened.bind(this);
|
this.handleDropdownOpened = this.handleDropdownOpened.bind(this);
|
||||||
|
|
||||||
this.canEdit = false;
|
|
||||||
this.canDelete = false;
|
|
||||||
this.editDisableAction = new DelayedAction(this.handleEditDisable);
|
this.editDisableAction = new DelayedAction(this.handleEditDisable);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -75,10 +73,6 @@ export default class RhsRootPost extends React.Component {
|
|||||||
GlobalActions.showGetPostLinkModal(this.props.post);
|
GlobalActions.showGetPostLinkModal(this.props.post);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEditDisable() {
|
|
||||||
this.canEdit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
if (nextProps.status !== this.props.status) {
|
if (nextProps.status !== this.props.status) {
|
||||||
return true;
|
return true;
|
||||||
@@ -225,18 +219,10 @@ export default class RhsRootPost extends React.Component {
|
|||||||
var timestamp = user ? user.last_picture_update : 0;
|
var timestamp = user ? user.last_picture_update : 0;
|
||||||
var channel = ChannelStore.get(post.channel_id);
|
var channel = ChannelStore.get(post.channel_id);
|
||||||
|
|
||||||
this.canDelete = PostUtils.canDeletePost(post);
|
|
||||||
this.canEdit = PostUtils.canEditPost(post, this.editDisableAction);
|
|
||||||
|
|
||||||
const isEphemeral = Utils.isPostEphemeral(post);
|
const isEphemeral = Utils.isPostEphemeral(post);
|
||||||
const isPending = post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING;
|
const isPending = post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING;
|
||||||
const isSystemMessage = PostUtils.isSystemMessage(post);
|
const isSystemMessage = PostUtils.isSystemMessage(post);
|
||||||
|
|
||||||
var type = 'Post';
|
|
||||||
if (post.root_id.length > 0) {
|
|
||||||
type = 'Comment';
|
|
||||||
}
|
|
||||||
|
|
||||||
var channelName;
|
var channelName;
|
||||||
if (channel) {
|
if (channel) {
|
||||||
if (channel.type === 'D') {
|
if (channel.type === 'D') {
|
||||||
@@ -274,158 +260,6 @@ export default class RhsRootPost extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var dropdownContents = [];
|
|
||||||
|
|
||||||
if (Utils.isMobile()) {
|
|
||||||
if (this.props.isFlagged) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='mobileFlag'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.unflagPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.mobile.unflag'
|
|
||||||
defaultMessage='Unflag'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='mobileFlag'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.flagPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.mobile.flag'
|
|
||||||
defaultMessage='Flag'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSystemMessage) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='rhs-root-permalink'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.handlePermalink}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.permalink'
|
|
||||||
defaultMessage='Permalink'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (post.is_pinned) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='rhs-root-unpin'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.unpinPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.unpin'
|
|
||||||
defaultMessage='Un-pin from channel'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='rhs-root-pin'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.pinPost}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.pin'
|
|
||||||
defaultMessage='Pin to channel'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.canDelete) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='rhs-root-delete'
|
|
||||||
role='presentation'
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
role='menuitem'
|
|
||||||
onClick={() => GlobalActions.showDeletePostModal(post, this.props.commentCount)}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.del'
|
|
||||||
defaultMessage='Delete'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.canEdit) {
|
|
||||||
dropdownContents.push(
|
|
||||||
<li
|
|
||||||
key='rhs-root-edit'
|
|
||||||
role='presentation'
|
|
||||||
className={this.canEdit ? '' : 'hide'}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
role='menuitem'
|
|
||||||
data-toggle='modal'
|
|
||||||
data-target='#edit_post'
|
|
||||||
data-refocusid='#reply_textbox'
|
|
||||||
data-title={type}
|
|
||||||
data-message={post.message}
|
|
||||||
data-postid={post.id}
|
|
||||||
data-channelid={post.channel_id}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='rhs_root.edit'
|
|
||||||
defaultMessage='Edit'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var rootOptions = '';
|
|
||||||
if (dropdownContents.length > 0) {
|
|
||||||
rootOptions = (
|
|
||||||
<RhsDropdown
|
|
||||||
dropdownContents={dropdownContents}
|
|
||||||
handleDropdownOpened={this.handleDropdownOpened}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let fileAttachment = null;
|
let fileAttachment = null;
|
||||||
if (post.file_ids && post.file_ids.length > 0) {
|
if (post.file_ids && post.file_ids.length > 0) {
|
||||||
fileAttachment = (
|
fileAttachment = (
|
||||||
@@ -559,6 +393,15 @@ export default class RhsRootPost extends React.Component {
|
|||||||
hour12: !this.props.useMilitaryTime
|
hour12: !this.props.useMilitaryTime
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const dotMenu = (
|
||||||
|
<DotMenu
|
||||||
|
idPrefix={Constants.RHS_ROOT}
|
||||||
|
post={this.props.post}
|
||||||
|
isFlagged={this.props.isFlagged}
|
||||||
|
handleDropdownOpened={this.handleDropdownOpened}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id='thread--root'
|
id='thread--root'
|
||||||
@@ -584,7 +427,7 @@ export default class RhsRootPost extends React.Component {
|
|||||||
ref='dotMenu'
|
ref='dotMenu'
|
||||||
className='col col__reply'
|
className='col col__reply'
|
||||||
>
|
>
|
||||||
{rootOptions}
|
{dotMenu}
|
||||||
{react}
|
{react}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -956,7 +956,10 @@ export const Constants = {
|
|||||||
ANIMATION_TIMEOUT: 1000,
|
ANIMATION_TIMEOUT: 1000,
|
||||||
SEARCH_TIMEOUT_MILLISECONDS: 100,
|
SEARCH_TIMEOUT_MILLISECONDS: 100,
|
||||||
DIAGNOSTICS_SEGMENT_KEY: 'fwb7VPbFeQ7SKp3wHm1RzFUuXZudqVok',
|
DIAGNOSTICS_SEGMENT_KEY: 'fwb7VPbFeQ7SKp3wHm1RzFUuXZudqVok',
|
||||||
TEST_ID_COUNT: 10
|
TEST_ID_COUNT: 10,
|
||||||
|
CENTER: 'center',
|
||||||
|
RHS: 'rhs',
|
||||||
|
RHS_ROOT: 'rhsroot'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Constants;
|
export default Constants;
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user