diff options
author | bonespiked <dngreene@gmail.com> | 2017-03-24 09:09:51 -0400 |
---|---|---|
committer | Jason Blais <jason@spinpunch.com> | 2017-03-24 09:09:51 -0400 |
commit | 28ad645153b206ba84ddc4935280eaed94bb0138 (patch) | |
tree | a5ddcc228b5cfdbd479078873a1bfede9f11cb1f /webapp/components/create_comment.jsx | |
parent | d0af931e6e57b78432d5527b6e7b0be36c538144 (diff) | |
download | chat-28ad645153b206ba84ddc4935280eaed94bb0138.tar.gz chat-28ad645153b206ba84ddc4935280eaed94bb0138.tar.bz2 chat-28ad645153b206ba84ddc4935280eaed94bb0138.zip |
Ticket 4665 - Emoji Picker (#5157)
* #4665 Added EmojiPicker
Work primarily by @broernr-de and @harrison on pre-release.mattermost.com
* Final fixes to handle custom emojis from internal review and single merge error
* ESLint fixes
* CSS changes and other code to support emoji picker in reply window
* Fix for file upload and emoji picker icon positions on post and comment.
RHS emoji picker appearing see-through at this time.
* Fix for two ESLint issues.
* covered most of feedback:
RHS emoji picker looks correct color-wise
RHS emoji picker dynamically positions against height of thread size (post + reply messages)
escape closes emoji window
search box focused on open
ESLint fixes against other files
oversized emoji preview fixes
* Adding in 'outside click' eventing to dismiss the emoji window
* Changing some formatting to fix mismatch between my local eslant rules and jenkins.
* adding alternative import method due to downstream testing errors
* yet another attempt to retain functionality and pass tests - skipping import of browser store
* fix for feedback items 5 and 7:
* move search to float on top with stylistic changes
* whitespace in the header (+1 squashed commit)
Squashed commits:
[6a26d32] changes that address items
1, 2, 6, 8, and 9 of latest feedback
* Fix for attachment preview location on mobile
* Fix for latest rounds of feedback
* fixing eslint issue
* making emojipicker sprite based, fixing alignments
* Fix for emoji quality, fixing some behavior (hover background and cursor settings)
undoing config changes
* Preview feature for emojis
* Adjustments to config file, and changing layout/design of attachment and emoji icon.
* manual revert from master branch for config.json
* reverting paperclip and fixing alignments. Additionally fixing inadvertent display of picker on mobile.
* CSS changes to try to fix the hover behavior - currently working for emoji picker (when enabled), but hover for attachment isn't working
* Made suggested changes by jwilander except for jQuery removal
* Adding hover for both icons
* removal of some usages of jQuery
* Fix for two layout issues on IE11/Edge
* UI improvements for emoji picker
* Fix for many minor display issues
* fix for additional appearance items
* fix to two minor UI items
* A little extra padding for IE11
* fix for IE11 scroll issue, and removing align attribute on img tag which was throwing js error
* fixes some display issues on firefox
* fix for uneven sides of emojis
* fix for eslint issues that I didn't introduce
* fix for missing bottom edge of RHS emojipicker. also fixing text overlapping icons on text area (including RHS)
* Update "emoji selector" to "emoji picker"
* changes for code review
- removal of ..getDOMNode
- use sprite imagery for emoji preview
- remove lastBlurAt from state as it wasn't used
* fixes for:
- fake custom emoji preview in picker
- RHS scrollbar on preview
* fix for minor alignment of preview emoji
Diffstat (limited to 'webapp/components/create_comment.jsx')
-rw-r--r-- | webapp/components/create_comment.jsx | 99 |
1 files changed, 95 insertions, 4 deletions
diff --git a/webapp/components/create_comment.jsx b/webapp/components/create_comment.jsx index 96280bbc1..899609ed0 100644 --- a/webapp/components/create_comment.jsx +++ b/webapp/components/create_comment.jsx @@ -15,6 +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 * as Utils from 'utils/utils.jsx'; import * as UserAgent from 'utils/user_agent.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; @@ -28,8 +29,7 @@ import {browserHistory} from 'react-router/es6'; const ActionTypes = Constants.ActionTypes; const KeyCodes = Constants.KeyCodes; -import {REACTION_PATTERN} from './create_post.jsx'; - +import {REACTION_PATTERN, EMOJI_PATTERN} from './create_post.jsx'; import React from 'react'; export default class CreateComment extends React.Component { @@ -56,6 +56,10 @@ export default class CreateComment extends React.Component { this.showPostDeletedModal = this.showPostDeletedModal.bind(this); this.hidePostDeletedModal = this.hidePostDeletedModal.bind(this); this.handlePostError = this.handlePostError.bind(this); + this.handleEmojiPickerClick = this.handleEmojiPickerClick.bind(this); + this.handleEmojiClick = this.handleEmojiClick.bind(this); + this.onKeyPress = this.onKeyPress.bind(this); + this.closeEmoji = this.closeEmoji.bind(this); PostStore.clearCommentDraftUploads(); MessageHistoryStore.resetHistoryIndex('comment'); @@ -69,24 +73,85 @@ export default class CreateComment extends React.Component { submitting: false, ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'), showPostDeletedModal: false, - enableAddButton + enableAddButton, + showEmojiPicker: false, + emojiOffset: 0, + emojiPickerEnabled: Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW) }; this.lastBlurAt = 0; } + closeEmoji(clickEvent) { + /* + if the user clicked something outside the component, except the RHS emojipicker icon + and the picker is open, then close it + */ + if (clickEvent && clickEvent.srcElement && + clickEvent.srcElement.className !== '' && + clickEvent.srcElement.className.indexOf('emoji-rhs') === -1 && + this.state.showEmojiPicker) { + this.setState({showEmojiPicker: !this.state.showEmojiPicker}); + } + } + + handleEmojiPickerClick() { + const threadHeight = document.getElementById('thread--root') ? document.getElementById('thread--root').offsetHeight : 0; + const messagesHeight = document.querySelector('div.post-right-comments-container') ? document.querySelector('div.post-right-comments-container').offsetHeight : 0; + + const totalHeight = threadHeight + messagesHeight; + let pickerOffset = 0; + if (totalHeight > 361) { + pickerOffset = -361; + } else { + pickerOffset = -1 * totalHeight; + } + this.setState({showEmojiPicker: !this.state.showEmojiPicker, emojiOffset: pickerOffset}); + } + + handleEmojiClick(emoji) { + const emojiAlias = emoji.name || emoji.aliases[0]; + + if (!emojiAlias) { + //Oops.. There went something wrong + return; + } + + if (this.state.message === '') { + this.setState({message: ':' + emojiAlias + ': ', showEmojiPicker: false}); + } else { + //check whether there is already a blank at the end of the current message + const newMessage = (/\s+$/.test(this.state.message)) ? + this.state.message + ':' + emojiAlias + ': ' : this.state.message + ' :' + emojiAlias + ': '; + + this.setState({message: newMessage, showEmojiPicker: false}); + } + + this.focusTextbox(); + } + componentDidMount() { PreferenceStore.addChangeListener(this.onPreferenceChange); + document.addEventListener('keydown', this.onKeyPress); + this.focusTextbox(); } componentWillUnmount() { PreferenceStore.removeChangeListener(this.onPreferenceChange); + document.removeEventListener('keydown', this.onKeyPress); + } + + onKeyPress(e) { + if (e.which === Constants.KeyCodes.ESCAPE && this.state.showEmojiPicker === true) { + this.setState({showEmojiPicker: !this.state.showEmojiPicker}); + } } onPreferenceChange() { this.setState({ - ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter') + ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'), + emojiPickerEnabled: Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW) }); } @@ -205,6 +270,14 @@ export default class CreateComment extends React.Component { GlobalActions.emitUserCommentedEvent(post); + const emojiResult = post.message.match(EMOJI_PATTERN); + if (emojiResult) { + // parse message and emit emoji event + emojiResult.forEach((emoji) => { + PostActions.emitEmojiPosted(emoji); + }); + } + PostActions.queuePost(post, false, null, (err) => { if (err.id === 'api.post.create_post.root_id.app_error') { @@ -502,6 +575,18 @@ export default class CreateComment extends React.Component { addButtonClass += ' disabled'; } + let emojiPicker = null; + if (this.state.showEmojiPicker) { + emojiPicker = ( + <EmojiPicker + onEmojiClick={this.handleEmojiClick} + topOrBottom='bottom' + emojiOffset={this.state.emojiOffset} + outsideClick={this.closeEmoji} + /> + ); + } + return ( <form onSubmit={this.handleSubmit}> <div className='post-create'> @@ -518,6 +603,7 @@ export default class CreateComment extends React.Component { value={this.state.message} onBlur={this.handleBlur} createMessage={Utils.localizeMessage('create_comment.addComment', 'Add a comment...')} + emojiEnabled={this.state.emojiPickerEnabled} initialText='' channelId={this.props.channelId} id='reply_textbox' @@ -532,7 +618,12 @@ export default class CreateComment extends React.Component { onUploadError={this.handleUploadError} postType='comment' channelId={this.props.channelId} + onEmojiClick={this.handleEmojiPickerClick} + emojiEnabled={this.state.emojiPickerEnabled} + navBarName='rhs' /> + + {emojiPicker} </div> </div> <MsgTyping |