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.web.js 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // @flow
  2. import React, { Component } from 'react';
  3. import { connect } from 'react-redux';
  4. import Emoji from 'react-emoji-render';
  5. import { sendMessage } from '../actions';
  6. import SmileysPanel from './SmileysPanel';
  7. /**
  8. * The type of the React {@code Component} props of {@link ChatInput}.
  9. */
  10. type Props = {
  11. /**
  12. * Invoked to send chat messages.
  13. */
  14. dispatch: Dispatch<*>,
  15. /**
  16. * Optional callback to get a reference to the chat input element.
  17. */
  18. getChatInputRef?: Function
  19. };
  20. /**
  21. * The type of the React {@code Component} state of {@link ChatInput}.
  22. */
  23. type State = {
  24. /**
  25. * User provided nickname when the input text is provided in the view.
  26. */
  27. message: string,
  28. /**
  29. * Whether or not the smiley selector is visible.
  30. */
  31. showSmileysPanel: boolean
  32. };
  33. /**
  34. * Implements a React Component for drafting and submitting a chat message.
  35. *
  36. * @extends Component
  37. */
  38. class ChatInput extends Component<Props, State> {
  39. _textArea: ?HTMLTextAreaElement;
  40. state = {
  41. message: '',
  42. showSmileysPanel: false
  43. };
  44. /**
  45. * Initializes a new {@code ChatInput} instance.
  46. *
  47. * @param {Object} props - The read-only properties with which the new
  48. * instance is to be initialized.
  49. */
  50. constructor(props: Props) {
  51. super(props);
  52. this._textArea = null;
  53. // Bind event handlers so they are only bound once for every instance.
  54. this._onDetectSubmit = this._onDetectSubmit.bind(this);
  55. this._onMessageChange = this._onMessageChange.bind(this);
  56. this._onSmileySelect = this._onSmileySelect.bind(this);
  57. this._onToggleSmileysPanel = this._onToggleSmileysPanel.bind(this);
  58. this._setTextAreaRef = this._setTextAreaRef.bind(this);
  59. }
  60. /**
  61. * Implements React's {@link Component#componentDidMount()}.
  62. *
  63. * @inheritdoc
  64. */
  65. componentDidMount() {
  66. /**
  67. * HTML Textareas do not support autofocus. Simulate autofocus by
  68. * manually focusing.
  69. */
  70. this.focus();
  71. }
  72. /**
  73. * Implements React's {@link Component#render()}.
  74. *
  75. * @inheritdoc
  76. * @returns {ReactElement}
  77. */
  78. render() {
  79. const smileysPanelClassName = `${this.state.showSmileysPanel
  80. ? 'show-smileys' : 'hide-smileys'} smileys-panel`;
  81. return (
  82. <div id = 'chat-input' >
  83. <div className = 'smiley-input'>
  84. <div id = 'smileysarea'>
  85. <div id = 'smileys'>
  86. <Emoji
  87. onClick = { this._onToggleSmileysPanel }
  88. text = ':)' />
  89. </div>
  90. </div>
  91. <div className = { smileysPanelClassName }>
  92. <SmileysPanel
  93. onSmileySelect = { this._onSmileySelect } />
  94. </div>
  95. </div>
  96. <div className = 'usrmsg-form'>
  97. <textarea
  98. data-i18n = '[placeholder]chat.messagebox'
  99. id = 'usermsg'
  100. onChange = { this._onMessageChange }
  101. onKeyDown = { this._onDetectSubmit }
  102. placeholder = { 'Enter Text...' }
  103. ref = { this._setTextAreaRef }
  104. value = { this.state.message } />
  105. </div>
  106. </div>
  107. );
  108. }
  109. /**
  110. * Removes cursor focus on this component's text area.
  111. *
  112. * @returns {void}
  113. */
  114. blur() {
  115. this._textArea && this._textArea.blur();
  116. }
  117. /**
  118. * Place cursor focus on this component's text area.
  119. *
  120. * @returns {void}
  121. */
  122. focus() {
  123. this._textArea && this._textArea.focus();
  124. }
  125. _onDetectSubmit: (Object) => void;
  126. /**
  127. * Detects if enter has been pressed. If so, submit the message in the chat
  128. * window.
  129. *
  130. * @param {string} event - Keyboard event.
  131. * @private
  132. * @returns {void}
  133. */
  134. _onDetectSubmit(event) {
  135. if (event.keyCode === 13
  136. && event.shiftKey === false) {
  137. event.preventDefault();
  138. this.props.dispatch(sendMessage(this.state.message));
  139. this.setState({ message: '' });
  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. if (this.props.getChatInputRef) {
  191. this.props.getChatInputRef(textAreaElement);
  192. }
  193. }
  194. }
  195. export default connect()(ChatInput);