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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. onChange = { this._onMessageChange }
  105. onKeyDown = { this._onDetectSubmit }
  106. placeholder = { this.props.t('chat.messagebox') }
  107. value = { this.state.message } />
  108. </div>
  109. </div>
  110. );
  111. }
  112. /**
  113. * Place cursor focus on this component's text area.
  114. *
  115. * @private
  116. * @returns {void}
  117. */
  118. _focus() {
  119. this._textArea && this._textArea.focus();
  120. }
  121. _onDetectSubmit: (Object) => void;
  122. /**
  123. * Detects if enter has been pressed. If so, submit the message in the chat
  124. * window.
  125. *
  126. * @param {string} event - Keyboard event.
  127. * @private
  128. * @returns {void}
  129. */
  130. _onDetectSubmit(event) {
  131. if (event.keyCode === 13
  132. && event.shiftKey === false) {
  133. event.preventDefault();
  134. const trimmed = this.state.message.trim();
  135. if (trimmed) {
  136. this.props.dispatch(sendMessage(trimmed));
  137. this.setState({ message: '' });
  138. }
  139. }
  140. }
  141. _onMessageChange: (Object) => void;
  142. /**
  143. * Updates the known message the user is drafting.
  144. *
  145. * @param {string} event - Keyboard event.
  146. * @private
  147. * @returns {void}
  148. */
  149. _onMessageChange(event) {
  150. this.setState({ message: event.target.value });
  151. }
  152. _onSmileySelect: (string) => void;
  153. /**
  154. * Appends a selected smileys to the chat message draft.
  155. *
  156. * @param {string} smileyText - The value of the smiley to append to the
  157. * chat message.
  158. * @private
  159. * @returns {void}
  160. */
  161. _onSmileySelect(smileyText) {
  162. this.setState({
  163. message: `${this.state.message} ${smileyText}`,
  164. showSmileysPanel: false
  165. });
  166. this._focus();
  167. }
  168. _onToggleSmileysPanel: () => void;
  169. /**
  170. * Callback invoked to hide or show the smileys selector.
  171. *
  172. * @private
  173. * @returns {void}
  174. */
  175. _onToggleSmileysPanel() {
  176. this.setState({ showSmileysPanel: !this.state.showSmileysPanel });
  177. this._focus();
  178. }
  179. _setTextAreaRef: (?HTMLTextAreaElement) => void;
  180. /**
  181. * Sets the reference to the HTML TextArea.
  182. *
  183. * @param {HTMLAudioElement} textAreaElement - The HTML text area element.
  184. * @private
  185. * @returns {void}
  186. */
  187. _setTextAreaRef(textAreaElement: ?HTMLTextAreaElement) {
  188. this._textArea = textAreaElement;
  189. }
  190. }
  191. export default translate(connect()(ChatInput));