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
|
||||
};
|
||||
Ссылка в новой задаче
Block a user