You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ChatInput.js 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // @flow
  2. import React, { Component } from 'react';
  3. import Emoji from 'react-emoji-render';
  4. import TextareaAutosize from 'react-textarea-autosize';
  5. import type { Dispatch } from 'redux';
  6. import { translate } from '../../../base/i18n';
  7. import { connect } from '../../../base/redux';
  8. import { sendMessage } from '../../actions';
  9. import SmileysPanel from './SmileysPanel';
  10. /**
  11. * The type of the React {@code Component} props of {@link ChatInput}.
  12. */
  13. type Props = {
  14. /**
  15. * Invoked to send chat messages.
  16. */
  17. dispatch: Dispatch<any>,
  18. /**
  19. * Invoked to obtain translated strings.
  20. */
  21. t: Function
  22. };
  23. /**
  24. * The type of the React {@code Component} state of {@link ChatInput}.
  25. */
  26. type State = {
  27. /**
  28. * User provided nickname when the input text is provided in the view.
  29. */
  30. message: string,
  31. /**
  32. * Whether or not the smiley selector is visible.
  33. */
  34. showSmileysPanel: boolean
  35. };
  36. /**
  37. * Implements a React Component for drafting and submitting a chat message.
  38. *
  39. * @extends Component
  40. */
  41. class ChatInput extends Component<Props, State> {
  42. _textArea: ?HTMLTextAreaElement;
  43. state = {
  44. message: '',
  45. showSmileysPanel: false
  46. };
  47. /**
  48. * Initializes a new {@code ChatInput} instance.
  49. *
  50. * @param {Object} props - The read-only properties with which the new
  51. * instance is to be initialized.
  52. */
  53. constructor(props: Props) {
  54. super(props);
  55. this._textArea = null;
  56. // Bind event handlers so they are only bound once for every instance.
  57. this._onDetectSubmit = this._onDetectSubmit.bind(this);
  58. this._onMessageChange = this._onMessageChange.bind(this);
  59. this._onSmileySelect = this._onSmileySelect.bind(this);
  60. this._onToggleSmileysPanel = this._onToggleSmileysPanel.bind(this);
  61. this._setTextAreaRef = this._setTextAreaRef.bind(this);
  62. }
  63. /**
  64. * Implements React's {@link Component#componentDidMount()}.
  65. *
  66. * @inheritdoc
  67. */
  68. componentDidMount() {
  69. /**
  70. * HTML Textareas do not support autofocus. Simulate autofocus by
  71. * manually focusing.
  72. */
  73. this._focus();
  74. }
  75. /**
  76. * Implements React's {@link Component#render()}.
  77. *
  78. * @inheritdoc
  79. * @returns {ReactElement}
  80. */
  81. render() {
  82. const smileysPanelClassName = `${this.state.showSmileysPanel
  83. ? 'show-smileys' : 'hide-smileys'} smileys-panel`;
  84. return (
  85. <div id = 'chat-input' >
  86. <div className = 'smiley-input'>
  87. <div id = 'smileysarea'>
  88. <div id = 'smileys'>
  89. <Emoji
  90. onClick = { this._onToggleSmileysPanel }
  91. text = ':)' />
  92. </div>
  93. </div>
  94. <div className = { smileysPanelClassName }>
  95. <SmileysPanel
  96. onSmileySelect = { this._onSmileySelect } />
  97. </div>
  98. </div>
  99. <div className = 'usrmsg-form'>
  100. <TextareaAutosize
  101. id = 'usermsg'
  102. inputRef = { this._setTextAreaRef }
  103. maxRows = { 5 }
  104. minRows = { 2 }
  105. onChange = { this._onMessageChange }
  106. onKeyDown = { this._onDetectSubmit }
  107. placeholder = { this.props.t('chat.messagebox') }
  108. value = { this.state.message } />
  109. </div>
  110. </div>
  111. );
  112. }
  113. /**
  114. * Place cursor focus on this component's text area.
  115. *
  116. * @private
  117. * @returns {void}
  118. */
  119. _focus() {
  120. this._textArea && this._textArea.focus();
  121. }
  122. _onDetectSubmit: (Object) => void;
  123. /**
  124. * Detects if enter has been pressed. If so, submit the message in the chat
  125. * window.
  126. *
  127. * @param {string} event - Keyboard event.
  128. * @private
  129. * @returns {void}
  130. */
  131. _onDetectSubmit(event) {
  132. if (event.keyCode === 13
  133. && event.shiftKey === false) {
  134. event.preventDefault();
  135. const trimmed = this.state.message.trim();
  136. if (trimmed) {
  137. this.props.dispatch(sendMessage(trimmed));
  138. this.setState({ message: '' });
  139. }
  140. }
  141. }
  142. _onMessageChange: (Object) => void;
  143. /**
  144. * Updates the known message the user is drafting.
  145. *
  146. * @param {string} event - Keyboard event.
  147. * @private
  148. * @returns {void}
  149. */
  150. _onMessageChange(event) {
  151. this.setState({ message: event.target.value });
  152. }
  153. _onSmileySelect: (string) => void;
  154. /**
  155. * Appends a selected smileys to the chat message draft.
  156. *
  157. * @param {string} smileyText - The value of the smiley to append to the
  158. * chat message.
  159. * @private
  160. * @returns {void}
  161. */
  162. _onSmileySelect(smileyText) {
  163. this.setState({
  164. message: `${this.state.message} ${smileyText}`,
  165. showSmileysPanel: false
  166. });
  167. this._focus();
  168. }
  169. _onToggleSmileysPanel: () => void;
  170. /**
  171. * Callback invoked to hide or show the smileys selector.
  172. *
  173. * @private
  174. * @returns {void}
  175. */
  176. _onToggleSmileysPanel() {
  177. this.setState({ showSmileysPanel: !this.state.showSmileysPanel });
  178. this._focus();
  179. }
  180. _setTextAreaRef: (?HTMLTextAreaElement) => void;
  181. /**
  182. * Sets the reference to the HTML TextArea.
  183. *
  184. * @param {HTMLAudioElement} textAreaElement - The HTML text area element.
  185. * @private
  186. * @returns {void}
  187. */
  188. _setTextAreaRef(textAreaElement: ?HTMLTextAreaElement) {
  189. this._textArea = textAreaElement;
  190. }
  191. }
  192. export default translate(connect()(ChatInput));