summaryrefslogtreecommitdiffstats
path: root/webapp
diff options
context:
space:
mode:
authorSaturnino Abril <saturnino.abril@gmail.com>2017-07-06 04:21:04 +0800
committerJoram Wilander <jwawilander@gmail.com>2017-07-05 16:21:04 -0400
commit81a893b556bbd4e5a73dd41b3dad92915cb06119 (patch)
treef455a019b374d619be4d88e4ddb1398d9864689d /webapp
parent4efb0f37b701aa8e875e541cc4f121c264e4d8ab (diff)
downloadchat-81a893b556bbd4e5a73dd41b3dad92915cb06119.tar.gz
chat-81a893b556bbd4e5a73dd41b3dad92915cb06119.tar.bz2
chat-81a893b556bbd4e5a73dd41b3dad92915cb06119.zip
fix position of emoji picker (#6837)
Diffstat (limited to 'webapp')
-rw-r--r--webapp/components/channel_view.jsx15
-rw-r--r--webapp/components/create_comment.jsx75
-rw-r--r--webapp/components/create_post.jsx83
-rw-r--r--webapp/components/emoji_picker/emoji_picker.jsx13
-rw-r--r--webapp/components/emoji_picker/emoji_picker_overlay.jsx10
-rw-r--r--webapp/components/file_upload.jsx24
-rw-r--r--webapp/components/post_view/post_info/post_info.jsx1
-rw-r--r--webapp/components/rhs_comment.jsx1
-rw-r--r--webapp/components/rhs_root_post.jsx1
-rw-r--r--webapp/components/rhs_thread/rhs_thread.jsx10
10 files changed, 153 insertions, 80 deletions
diff --git a/webapp/components/channel_view.jsx b/webapp/components/channel_view.jsx
index 6c2157ffd..4a5ac8969 100644
--- a/webapp/components/channel_view.jsx
+++ b/webapp/components/channel_view.jsx
@@ -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>
);
diff --git a/webapp/components/create_comment.jsx b/webapp/components/create_comment.jsx
index 2ddc828cc..1a2bbeeae 100644
--- a/webapp/components/create_comment.jsx
+++ b/webapp/components/create_comment.jsx
@@ -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
};
diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx
index e7fafc514..56f392292 100644
--- a/webapp/components/create_post.jsx
+++ b/webapp/components/create_post.jsx
@@ -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 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 (this.state.showEmojiPicker) {
+ if (Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW)) {
emojiPicker = (
- <RootCloseWrapper onRootClose={this.toggleEmojiPicker}>
- <EmojiPicker
- onHide={this.toggleEmojiPicker}
+ <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}
/>
- </RootCloseWrapper>
+ </span>
);
}
- let attachmentsDisabled = '';
- if (global.window.mm_config.EnableFileAttachments === 'false') {
- attachmentsDisabled = ' post-create--attachment-disabled';
- }
-
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
+};
diff --git a/webapp/components/emoji_picker/emoji_picker.jsx b/webapp/components/emoji_picker/emoji_picker.jsx
index 2a5b84747..a047c1277 100644
--- a/webapp/components/emoji_picker/emoji_picker.jsx
+++ b/webapp/components/emoji_picker/emoji_picker.jsx
@@ -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'
diff --git a/webapp/components/emoji_picker/emoji_picker_overlay.jsx b/webapp/components/emoji_picker/emoji_picker_overlay.jsx
index 09cc0a36c..0a289a242 100644
--- a/webapp/components/emoji_picker/emoji_picker_overlay.jsx
+++ b/webapp/components/emoji_picker/emoji_picker_overlay.jsx
@@ -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>
);
}
diff --git a/webapp/components/file_upload.jsx b/webapp/components/file_upload.jsx
index 17bb50a2b..0b32ab66e 100644
--- a/webapp/components/file_upload.jsx
+++ b/webapp/components/file_upload.jsx
@@ -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});
diff --git a/webapp/components/post_view/post_info/post_info.jsx b/webapp/components/post_view/post_info/post_info.jsx
index c07a58bc7..36e0ea431 100644
--- a/webapp/components/post_view/post_info/post_info.jsx
+++ b/webapp/components/post_view/post_info/post_info.jsx
@@ -158,6 +158,7 @@ export default class PostInfo extends React.PureComponent {
target={this.getDotMenu}
onHide={this.hideEmojiPicker}
onEmojiClick={this.reactEmojiClick}
+ rightOffset={7}
/>
<a
href='#'
diff --git a/webapp/components/rhs_comment.jsx b/webapp/components/rhs_comment.jsx
index 11d64f871..8fcf3edf8 100644
--- a/webapp/components/rhs_comment.jsx
+++ b/webapp/components/rhs_comment.jsx
@@ -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='#'
diff --git a/webapp/components/rhs_root_post.jsx b/webapp/components/rhs_root_post.jsx
index 83f50b6ea..48512d591 100644
--- a/webapp/components/rhs_root_post.jsx
+++ b/webapp/components/rhs_root_post.jsx
@@ -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='#'
diff --git a/webapp/components/rhs_thread/rhs_thread.jsx b/webapp/components/rhs_thread/rhs_thread.jsx
index 50f5f0aa3..bbf61af19 100644
--- a/webapp/components/rhs_thread/rhs_thread.jsx
+++ b/webapp/components/rhs_thread/rhs_thread.jsx
@@ -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>