fix position of emoji picker (#6837)

This commit is contained in:
Saturnino Abril
2017-07-06 04:21:04 +08:00
committed by Joram Wilander
parent 4efb0f37b7
commit 81a893b556
10 changed files with 155 additions and 82 deletions

View File

@@ -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>
);

View File

@@ -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
};

View File

@@ -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
};

View File

@@ -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'

View File

@@ -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>
);
}

View File

@@ -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});

View File

@@ -158,6 +158,7 @@ export default class PostInfo extends React.PureComponent {
target={this.getDotMenu}
onHide={this.hideEmojiPicker}
onEmojiClick={this.reactEmojiClick}
rightOffset={7}
/>
<a
href='#'

View File

@@ -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='#'

View File

@@ -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='#'

View File

@@ -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>