| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 | // @flow
import React, { Component } from 'react';
import Emoji from 'react-emoji-render';
import type { Dispatch } from 'redux';
import { connect } from '../../../base/redux';
import { sendMessage } from '../../actions';
import SmileysPanel from './SmileysPanel';
/**
 * The type of the React {@code Component} props of {@link ChatInput}.
 */
type Props = {
    /**
     * Invoked to send chat messages.
     */
    dispatch: Dispatch<any>,
    /**
     * Optional callback to get a reference to the chat input element.
     */
    getChatInputRef?: Function
};
/**
 * The type of the React {@code Component} state of {@link ChatInput}.
 */
type State = {
    /**
     * User provided nickname when the input text is provided in the view.
     */
    message: string,
    /**
     * Whether or not the smiley selector is visible.
     */
    showSmileysPanel: boolean
};
/**
 * Implements a React Component for drafting and submitting a chat message.
 *
 * @extends Component
 */
class ChatInput extends Component<Props, State> {
    _textArea: ?HTMLTextAreaElement;
    state = {
        message: '',
        showSmileysPanel: false
    };
    /**
     * Initializes a new {@code ChatInput} instance.
     *
     * @param {Object} props - The read-only properties with which the new
     * instance is to be initialized.
     */
    constructor(props: Props) {
        super(props);
        this._textArea = null;
        // Bind event handlers so they are only bound once for every instance.
        this._onDetectSubmit = this._onDetectSubmit.bind(this);
        this._onMessageChange = this._onMessageChange.bind(this);
        this._onSmileySelect = this._onSmileySelect.bind(this);
        this._onToggleSmileysPanel = this._onToggleSmileysPanel.bind(this);
        this._setTextAreaRef = this._setTextAreaRef.bind(this);
    }
    /**
     * Implements React's {@link Component#componentDidMount()}.
     *
     * @inheritdoc
     */
    componentDidMount() {
        /**
         * HTML Textareas do not support autofocus. Simulate autofocus by
         * manually focusing.
         */
        this.focus();
    }
    /**
     * Implements React's {@link Component#render()}.
     *
     * @inheritdoc
     * @returns {ReactElement}
     */
    render() {
        const smileysPanelClassName = `${this.state.showSmileysPanel
            ? 'show-smileys' : 'hide-smileys'} smileys-panel`;
        return (
            <div id = 'chat-input' >
                <div className = 'smiley-input'>
                    <div id = 'smileysarea'>
                        <div id = 'smileys'>
                            <Emoji
                                onClick = { this._onToggleSmileysPanel }
                                text = ':)' />
                        </div>
                    </div>
                    <div className = { smileysPanelClassName }>
                        <SmileysPanel
                            onSmileySelect = { this._onSmileySelect } />
                    </div>
                </div>
                <div className = 'usrmsg-form'>
                    <textarea
                        data-i18n = '[placeholder]chat.messagebox'
                        id = 'usermsg'
                        onChange = { this._onMessageChange }
                        onKeyDown = { this._onDetectSubmit }
                        placeholder = { 'Enter Text...' }
                        ref = { this._setTextAreaRef }
                        value = { this.state.message } />
                </div>
            </div>
        );
    }
    /**
     * Removes cursor focus on this component's text area.
     *
     * @returns {void}
     */
    blur() {
        this._textArea && this._textArea.blur();
    }
    /**
     * Place cursor focus on this component's text area.
     *
     * @returns {void}
     */
    focus() {
        this._textArea && this._textArea.focus();
    }
    _onDetectSubmit: (Object) => void;
    /**
     * Detects if enter has been pressed. If so, submit the message in the chat
     * window.
     *
     * @param {string} event - Keyboard event.
     * @private
     * @returns {void}
     */
    _onDetectSubmit(event) {
        if (event.keyCode === 13
            && event.shiftKey === false) {
            event.preventDefault();
            const trimmed = this.state.message.trim();
            if (trimmed) {
                this.props.dispatch(sendMessage(trimmed));
                this.setState({ message: '' });
            }
        }
    }
    _onMessageChange: (Object) => void;
    /**
     * Updates the known message the user is drafting.
     *
     * @param {string} event - Keyboard event.
     * @private
     * @returns {void}
     */
    _onMessageChange(event) {
        this.setState({ message: event.target.value });
    }
    _onSmileySelect: (string) => void;
    /**
     * Appends a selected smileys to the chat message draft.
     *
     * @param {string} smileyText - The value of the smiley to append to the
     * chat message.
     * @private
     * @returns {void}
     */
    _onSmileySelect(smileyText) {
        this.setState({
            message: `${this.state.message} ${smileyText}`,
            showSmileysPanel: false
        });
        this.focus();
    }
    _onToggleSmileysPanel: () => void;
    /**
     * Callback invoked to hide or show the smileys selector.
     *
     * @private
     * @returns {void}
     */
    _onToggleSmileysPanel() {
        this.setState({ showSmileysPanel: !this.state.showSmileysPanel });
        this.focus();
    }
    _setTextAreaRef: (?HTMLTextAreaElement) => void;
    /**
     * Sets the reference to the HTML TextArea.
     *
     * @param {HTMLAudioElement} textAreaElement - The HTML text area element.
     * @private
     * @returns {void}
     */
    _setTextAreaRef(textAreaElement: ?HTMLTextAreaElement) {
        this._textArea = textAreaElement;
        if (this.props.getChatInputRef) {
            this.props.getChatInputRef(textAreaElement);
        }
    }
}
export default connect()(ChatInput);
 |