mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
fix position of emoji picker (#6837)
This commit is contained in:
committed by
Joram Wilander
parent
4efb0f37b7
commit
81a893b556
@@ -31,18 +31,22 @@ export default class ChannelView extends React.Component {
|
||||
|
||||
this.state = this.getStateFromStores(props);
|
||||
}
|
||||
|
||||
getStateFromStores() {
|
||||
return {
|
||||
channelId: ChannelStore.getCurrentId(),
|
||||
tutorialStep: PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999)
|
||||
};
|
||||
}
|
||||
|
||||
isStateValid() {
|
||||
return this.state.channelId !== '';
|
||||
}
|
||||
|
||||
updateState() {
|
||||
this.setState(this.getStateFromStores(this.props));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
ChannelStore.addChangeListener(this.updateState);
|
||||
|
||||
@@ -53,14 +57,17 @@ export default class ChannelView extends React.Component {
|
||||
$('body').addClass('browser--ie');
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
ChannelStore.removeChangeListener(this.updateState);
|
||||
|
||||
$('body').removeClass('app__body');
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState(this.getStateFromStores(nextProps));
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
if (!Utils.areObjectsEqual(nextProps.params, this.props.params)) {
|
||||
return true;
|
||||
@@ -72,6 +79,11 @@ export default class ChannelView extends React.Component {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getChannelView = () => {
|
||||
return this.refs.channelView;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.tutorialStep <= TutorialSteps.INTRO_SCREENS) {
|
||||
return (<TutorialView/>);
|
||||
@@ -79,6 +91,7 @@ export default class ChannelView extends React.Component {
|
||||
|
||||
return (
|
||||
<div
|
||||
ref='channelView'
|
||||
id='app-content'
|
||||
className='app__content'
|
||||
>
|
||||
@@ -93,7 +106,7 @@ export default class ChannelView extends React.Component {
|
||||
className='post-create__container'
|
||||
id='post-create'
|
||||
>
|
||||
<CreatePost/>
|
||||
<CreatePost getChannelView={this.getChannelView}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ import Textbox from './textbox.jsx';
|
||||
import MsgTyping from './msg_typing.jsx';
|
||||
import FileUpload from './file_upload.jsx';
|
||||
import FilePreview from './file_preview.jsx';
|
||||
import EmojiPicker from './emoji_picker/emoji_picker.jsx';
|
||||
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
@@ -24,7 +24,6 @@ import * as PostActions from 'actions/post_actions.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {RootCloseWrapper} from 'react-overlays';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
@@ -54,12 +53,15 @@ export default class CreateComment extends React.Component {
|
||||
this.removePreview = this.removePreview.bind(this);
|
||||
this.getFileCount = this.getFileCount.bind(this);
|
||||
this.getFileUploadTarget = this.getFileUploadTarget.bind(this);
|
||||
this.getCreateCommentControls = this.getCreateCommentControls.bind(this);
|
||||
this.onPreferenceChange = this.onPreferenceChange.bind(this);
|
||||
this.focusTextbox = this.focusTextbox.bind(this);
|
||||
this.showPostDeletedModal = this.showPostDeletedModal.bind(this);
|
||||
this.hidePostDeletedModal = this.hidePostDeletedModal.bind(this);
|
||||
this.handlePostError = this.handlePostError.bind(this);
|
||||
this.handleEmojiClick = this.handleEmojiClick.bind(this);
|
||||
this.toggleEmojiPicker = this.toggleEmojiPicker.bind(this);
|
||||
this.hideEmojiPicker = this.hideEmojiPicker.bind(this);
|
||||
|
||||
PostStore.clearCommentDraftUploads();
|
||||
MessageHistoryStore.resetHistoryIndex('comment');
|
||||
@@ -81,10 +83,14 @@ export default class CreateComment extends React.Component {
|
||||
this.lastBlurAt = 0;
|
||||
}
|
||||
|
||||
toggleEmojiPicker = () => {
|
||||
toggleEmojiPicker() {
|
||||
this.setState({showEmojiPicker: !this.state.showEmojiPicker});
|
||||
}
|
||||
|
||||
hideEmojiPicker() {
|
||||
this.setState({showEmojiPicker: false});
|
||||
}
|
||||
|
||||
handleEmojiClick(emoji) {
|
||||
const emojiAlias = emoji.name || emoji.aliases[0];
|
||||
|
||||
@@ -470,6 +476,10 @@ export default class CreateComment extends React.Component {
|
||||
return this.refs.textbox;
|
||||
}
|
||||
|
||||
getCreateCommentControls() {
|
||||
return this.refs.createCommentControls;
|
||||
}
|
||||
|
||||
focusTextbox(keepFocus = false) {
|
||||
if (keepFocus || !Utils.isMobile()) {
|
||||
this.refs.textbox.focus();
|
||||
@@ -548,15 +558,38 @@ export default class CreateComment extends React.Component {
|
||||
addButtonClass += ' disabled';
|
||||
}
|
||||
|
||||
const fileUpload = (
|
||||
<FileUpload
|
||||
ref='fileUpload'
|
||||
getFileCount={this.getFileCount}
|
||||
getTarget={this.getFileUploadTarget}
|
||||
onFileUploadChange={this.handleFileUploadChange}
|
||||
onUploadStart={this.handleUploadStart}
|
||||
onFileUpload={this.handleFileUploadComplete}
|
||||
onUploadError={this.handleUploadError}
|
||||
postType='comment'
|
||||
channelId={this.props.channelId}
|
||||
/>
|
||||
);
|
||||
|
||||
let emojiPicker = null;
|
||||
if (this.state.showEmojiPicker) {
|
||||
if (Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW)) {
|
||||
emojiPicker = (
|
||||
<RootCloseWrapper onRootClose={this.toggleEmojiPicker}>
|
||||
<EmojiPicker
|
||||
<span>
|
||||
<EmojiPickerOverlay
|
||||
show={this.state.showEmojiPicker}
|
||||
container={this.props.getSidebarBody}
|
||||
target={this.getCreateCommentControls}
|
||||
onHide={this.hideEmojiPicker}
|
||||
onEmojiClick={this.handleEmojiClick}
|
||||
onHide={this.toggleEmojiPicker}
|
||||
rightOffset={15}
|
||||
topOffset={55}
|
||||
/>
|
||||
</RootCloseWrapper>
|
||||
<span
|
||||
className={'fa fa-smile-o icon--emoji-picker emoji-rhs'}
|
||||
onClick={this.toggleEmojiPicker}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -582,22 +615,13 @@ export default class CreateComment extends React.Component {
|
||||
id='reply_textbox'
|
||||
ref='textbox'
|
||||
/>
|
||||
<FileUpload
|
||||
ref='fileUpload'
|
||||
getFileCount={this.getFileCount}
|
||||
getTarget={this.getFileUploadTarget}
|
||||
onFileUploadChange={this.handleFileUploadChange}
|
||||
onUploadStart={this.handleUploadStart}
|
||||
onFileUpload={this.handleFileUploadComplete}
|
||||
onUploadError={this.handleUploadError}
|
||||
postType='comment'
|
||||
channelId={this.props.channelId}
|
||||
onEmojiClick={this.toggleEmojiPicker}
|
||||
emojiEnabled={this.state.emojiPickerEnabled}
|
||||
navBarName='rhs'
|
||||
/>
|
||||
|
||||
{emojiPicker}
|
||||
<span
|
||||
ref='createCommentControls'
|
||||
className='btn btn-file'
|
||||
>
|
||||
{fileUpload}
|
||||
{emojiPicker}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<MsgTyping
|
||||
@@ -629,5 +653,6 @@ export default class CreateComment extends React.Component {
|
||||
CreateComment.propTypes = {
|
||||
channelId: PropTypes.string.isRequired,
|
||||
rootId: PropTypes.string.isRequired,
|
||||
latestPostId: PropTypes.string
|
||||
latestPostId: PropTypes.string,
|
||||
getSidebarBody: PropTypes.func
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import FileUpload from './file_upload.jsx';
|
||||
import FilePreview from './file_preview.jsx';
|
||||
import PostDeletedModal from './post_deleted_modal.jsx';
|
||||
import TutorialTip from './tutorial/tutorial_tip.jsx';
|
||||
import EmojiPicker from './emoji_picker/emoji_picker.jsx';
|
||||
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
|
||||
|
||||
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
@@ -28,7 +28,6 @@ import ConfirmModal from './confirm_modal.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
|
||||
import {RootCloseWrapper} from 'react-overlays';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
const Preferences = Constants.Preferences;
|
||||
@@ -37,6 +36,7 @@ const ActionTypes = Constants.ActionTypes;
|
||||
const KeyCodes = Constants.KeyCodes;
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export const REACTION_PATTERN = /^(\+|-):([^:\s]+):\s*$/;
|
||||
export const EMOJI_PATTERN = /:[A-Za-z-_0-9]*:/g;
|
||||
@@ -60,6 +60,7 @@ export default class CreatePost extends React.Component {
|
||||
this.onPreferenceChange = this.onPreferenceChange.bind(this);
|
||||
this.getFileCount = this.getFileCount.bind(this);
|
||||
this.getFileUploadTarget = this.getFileUploadTarget.bind(this);
|
||||
this.getCreatePostControls = this.getCreatePostControls.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.handleBlur = this.handleBlur.bind(this);
|
||||
this.sendMessage = this.sendMessage.bind(this);
|
||||
@@ -111,6 +112,10 @@ export default class CreatePost extends React.Component {
|
||||
this.setState({showEmojiPicker: !this.state.showEmojiPicker});
|
||||
}
|
||||
|
||||
hideEmojiPicker = () => {
|
||||
this.setState({showEmojiPicker: false});
|
||||
}
|
||||
|
||||
doSubmit(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
@@ -500,6 +505,10 @@ export default class CreatePost extends React.Component {
|
||||
return this.refs.textbox;
|
||||
}
|
||||
|
||||
getCreatePostControls() {
|
||||
return this.refs.createPostControls;
|
||||
}
|
||||
|
||||
handleKeyDown(e) {
|
||||
if (this.state.ctrlSend && e.keyCode === KeyCodes.ENTER && e.ctrlKey === true) {
|
||||
this.postMsgKeyPress(e);
|
||||
@@ -693,23 +702,46 @@ export default class CreatePost extends React.Component {
|
||||
sendButtonClass += ' disabled';
|
||||
}
|
||||
|
||||
let emojiPicker = null;
|
||||
if (this.state.showEmojiPicker) {
|
||||
emojiPicker = (
|
||||
<RootCloseWrapper onRootClose={this.toggleEmojiPicker}>
|
||||
<EmojiPicker
|
||||
onHide={this.toggleEmojiPicker}
|
||||
onEmojiClick={this.handleEmojiClick}
|
||||
/>
|
||||
</RootCloseWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
let attachmentsDisabled = '';
|
||||
if (global.window.mm_config.EnableFileAttachments === 'false') {
|
||||
attachmentsDisabled = ' post-create--attachment-disabled';
|
||||
}
|
||||
|
||||
const fileUpload = (
|
||||
<FileUpload
|
||||
ref='fileUpload'
|
||||
getFileCount={this.getFileCount}
|
||||
getTarget={this.getFileUploadTarget}
|
||||
onFileUploadChange={this.handleFileUploadChange}
|
||||
onUploadStart={this.handleUploadStart}
|
||||
onFileUpload={this.handleFileUploadComplete}
|
||||
onUploadError={this.handleUploadError}
|
||||
postType='post'
|
||||
channelId=''
|
||||
/>
|
||||
);
|
||||
|
||||
let emojiPicker = null;
|
||||
if (Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW)) {
|
||||
emojiPicker = (
|
||||
<span>
|
||||
<EmojiPickerOverlay
|
||||
show={this.state.showEmojiPicker}
|
||||
container={this.props.getChannelView}
|
||||
target={this.getCreatePostControls}
|
||||
onHide={this.hideEmojiPicker}
|
||||
onEmojiClick={this.handleEmojiClick}
|
||||
rightOffset={15}
|
||||
topOffset={-7}
|
||||
/>
|
||||
<span
|
||||
className={'fa fa-smile-o icon--emoji-picker emoji-main'}
|
||||
onClick={this.toggleEmojiPicker}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<form
|
||||
id='create_post'
|
||||
@@ -734,22 +766,13 @@ export default class CreatePost extends React.Component {
|
||||
id='post_textbox'
|
||||
ref='textbox'
|
||||
/>
|
||||
<FileUpload
|
||||
ref='fileUpload'
|
||||
getFileCount={this.getFileCount}
|
||||
getTarget={this.getFileUploadTarget}
|
||||
onFileUploadChange={this.handleFileUploadChange}
|
||||
onUploadStart={this.handleUploadStart}
|
||||
onFileUpload={this.handleFileUploadComplete}
|
||||
onUploadError={this.handleUploadError}
|
||||
postType='post'
|
||||
channelId=''
|
||||
onEmojiClick={this.toggleEmojiPicker}
|
||||
emojiEnabled={this.state.emojiPickerEnabled}
|
||||
navBarName='main'
|
||||
/>
|
||||
|
||||
{emojiPicker}
|
||||
<span
|
||||
ref='createPostControls'
|
||||
className='btn btn-file'
|
||||
>
|
||||
{fileUpload}
|
||||
{emojiPicker}
|
||||
</span>
|
||||
</div>
|
||||
<a
|
||||
className={sendButtonClass}
|
||||
@@ -785,3 +808,7 @@ export default class CreatePost extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CreatePost.propTypes = {
|
||||
getChannelView: PropTypes.func
|
||||
};
|
||||
|
||||
@@ -31,11 +31,18 @@ const CATEGORIES = [
|
||||
export default class EmojiPicker extends React.Component {
|
||||
static propTypes = {
|
||||
style: PropTypes.object,
|
||||
rightOffset: PropTypes.number,
|
||||
topOffset: PropTypes.number,
|
||||
placement: PropTypes.oneOf(['top', 'bottom', 'left']),
|
||||
customEmojis: PropTypes.object,
|
||||
onEmojiClick: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
rightOffset: 0,
|
||||
topOffset: 0
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -299,13 +306,17 @@ export default class EmojiPicker extends React.Component {
|
||||
pickerStyle = {
|
||||
top: this.props.style.top,
|
||||
bottom: this.props.style.bottom,
|
||||
right: 1
|
||||
right: this.props.rightOffset
|
||||
};
|
||||
} else {
|
||||
pickerStyle = this.props.style;
|
||||
}
|
||||
}
|
||||
|
||||
if (pickerStyle && pickerStyle.top) {
|
||||
pickerStyle.top += this.props.topOffset;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className='emoji-picker'
|
||||
|
||||
@@ -13,7 +13,9 @@ export default class EmojiPickerOverlay extends React.PureComponent {
|
||||
container: PropTypes.func,
|
||||
target: PropTypes.func.isRequired,
|
||||
onEmojiClick: PropTypes.func.isRequired,
|
||||
onHide: PropTypes.func.isRequired
|
||||
onHide: PropTypes.func.isRequired,
|
||||
rightOffset: PropTypes.number,
|
||||
topOffset: PropTypes.number
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
@@ -55,7 +57,11 @@ export default class EmojiPickerOverlay extends React.PureComponent {
|
||||
target={this.props.target}
|
||||
animation={false}
|
||||
>
|
||||
<EmojiPicker onEmojiClick={this.props.onEmojiClick}/>
|
||||
<EmojiPicker
|
||||
onEmojiClick={this.props.onEmojiClick}
|
||||
rightOffset={this.props.rightOffset}
|
||||
topOffset={this.props.topOffset}
|
||||
/>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ class FileUpload extends React.Component {
|
||||
this.pasteUpload = this.pasteUpload.bind(this);
|
||||
this.keyUpload = this.keyUpload.bind(this);
|
||||
this.handleMaxUploadReached = this.handleMaxUploadReached.bind(this);
|
||||
this.emojiClick = this.emojiClick.bind(this);
|
||||
|
||||
this.state = {
|
||||
requests: {}
|
||||
@@ -230,10 +229,6 @@ class FileUpload extends React.Component {
|
||||
target.off('dragenter dragleave dragover drop dragster:enter dragster:leave dragster:over dragster:drop');
|
||||
}
|
||||
|
||||
emojiClick() {
|
||||
this.props.onEmojiClick();
|
||||
}
|
||||
|
||||
pasteUpload(e) {
|
||||
const {formatMessage} = this.props.intl;
|
||||
|
||||
@@ -377,19 +372,8 @@ class FileUpload extends React.Component {
|
||||
}
|
||||
|
||||
const channelId = this.props.channelId || ChannelStore.getCurrentId();
|
||||
|
||||
const uploadsRemaining = Constants.MAX_UPLOAD_FILES - this.props.getFileCount(channelId);
|
||||
|
||||
let emojiSpan;
|
||||
if (this.props.emojiEnabled) {
|
||||
emojiSpan = (
|
||||
<span
|
||||
className={'fa fa-smile-o icon--emoji-picker emoji-' + this.props.navBarName}
|
||||
onClick={this.emojiClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let fileDiv;
|
||||
if (global.window.mm_config.EnableFileAttachments === 'true') {
|
||||
fileDiv = (
|
||||
@@ -413,10 +397,9 @@ class FileUpload extends React.Component {
|
||||
return (
|
||||
<span
|
||||
ref='input'
|
||||
className={'btn btn-file' + (uploadsRemaining <= 0 ? ' btn-file__disabled' : '')}
|
||||
className={uploadsRemaining <= 0 ? ' btn-file__disabled' : ''}
|
||||
>
|
||||
{fileDiv}
|
||||
{emojiSpan}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -433,10 +416,7 @@ FileUpload.propTypes = {
|
||||
onFileUploadChange: PropTypes.func,
|
||||
onTextDrop: PropTypes.func,
|
||||
channelId: PropTypes.string,
|
||||
postType: PropTypes.string,
|
||||
onEmojiClick: PropTypes.func,
|
||||
navBarName: PropTypes.string,
|
||||
emojiEnabled: PropTypes.bool
|
||||
postType: PropTypes.string
|
||||
};
|
||||
|
||||
export default injectIntl(FileUpload, {withRef: true});
|
||||
|
||||
@@ -158,6 +158,7 @@ export default class PostInfo extends React.PureComponent {
|
||||
target={this.getDotMenu}
|
||||
onHide={this.hideEmojiPicker}
|
||||
onEmojiClick={this.reactEmojiClick}
|
||||
rightOffset={7}
|
||||
/>
|
||||
<a
|
||||
href='#'
|
||||
|
||||
@@ -335,6 +335,7 @@ export default class RhsComment extends React.Component {
|
||||
target={() => this.refs.dotMenu}
|
||||
container={this.props.getPostList}
|
||||
onEmojiClick={this.reactEmojiClick}
|
||||
rightOffset={15}
|
||||
/>
|
||||
<a
|
||||
href='#'
|
||||
|
||||
@@ -228,6 +228,7 @@ export default class RhsRootPost extends React.Component {
|
||||
target={() => this.refs.dotMenu}
|
||||
container={this.props.getPostList}
|
||||
onEmojiClick={this.reactEmojiClick}
|
||||
rightOffset={15}
|
||||
/>
|
||||
<a
|
||||
href='#'
|
||||
|
||||
@@ -320,6 +320,10 @@ export default class RhsThread extends React.Component {
|
||||
return this.refs.postListContainer;
|
||||
}
|
||||
|
||||
getSidebarBody = () => {
|
||||
return this.refs.sidebarbody;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.posts == null || this.props.selected == null) {
|
||||
return (
|
||||
@@ -403,7 +407,10 @@ export default class RhsThread extends React.Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='sidebar-right__body'>
|
||||
<div
|
||||
className='sidebar-right__body'
|
||||
ref='sidebarbody'
|
||||
>
|
||||
<FloatingTimestamp
|
||||
isScrolling={this.state.isScrolling}
|
||||
isMobile={Utils.isMobile()}
|
||||
@@ -460,6 +467,7 @@ export default class RhsThread extends React.Component {
|
||||
channelId={selected.channel_id}
|
||||
rootId={selected.id}
|
||||
latestPostId={postsLength > 0 ? postsArray[postsLength - 1].id : selected.id}
|
||||
getSidebarBody={this.getSidebarBody}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user