a0224dcffc
String refs will be deprecated in the next React releases, since they have some performance issues
170 lines
4.6 KiB
JavaScript
Executable File
170 lines
4.6 KiB
JavaScript
Executable File
import React, { Component, PropTypes } from 'react';
|
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
import { findDOMNode } from 'react-dom';
|
|
import cx from 'classnames';
|
|
import styles from './styles';
|
|
|
|
import MessageFormActions from './message-form-actions/component';
|
|
import TextareaAutosize from 'react-autosize-textarea';
|
|
import Button from '../../button/component';
|
|
|
|
const propTypes = {
|
|
};
|
|
|
|
const defaultProps = {
|
|
};
|
|
|
|
const messages = defineMessages({
|
|
submitLabel: {
|
|
id: 'app.chat.submitLabel',
|
|
description: 'Chat submit button label',
|
|
},
|
|
inputLabel: {
|
|
id: 'app.chat.inputLabel',
|
|
description: 'Chat message input label',
|
|
},
|
|
inputPlaceholder: {
|
|
id: 'app.chat.inputPlaceholder',
|
|
description: 'Chat message input placeholder',
|
|
},
|
|
errorMinMessageLength: {
|
|
id: 'app.chat.errorMinMessageLength',
|
|
},
|
|
errorMaxMessageLength: {
|
|
id: 'app.chat.errorMaxMessageLength',
|
|
},
|
|
});
|
|
|
|
class MessageForm extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
message: '',
|
|
error: '',
|
|
hasErrors: false,
|
|
};
|
|
|
|
this.handleMessageChange = this.handleMessageChange.bind(this);
|
|
this.handleMessageKeyDown = this.handleMessageKeyDown.bind(this);
|
|
this.handleSubmit = this.handleSubmit.bind(this);
|
|
|
|
}
|
|
|
|
handleMessageKeyDown(e) {
|
|
//TODO Prevent send message pressing enter on mobile and/or virtual keyboard
|
|
if (e.keyCode === 13 && !e.shiftKey) {
|
|
e.preventDefault();
|
|
|
|
let event = new Event('submit', {
|
|
bubbles: true,
|
|
cancelable: true,
|
|
});
|
|
|
|
this.form.dispatchEvent(event);
|
|
}
|
|
}
|
|
|
|
handleMessageChange(e) {
|
|
const { intl } = this.props;
|
|
|
|
const message = e.target.value;
|
|
let error = '';
|
|
|
|
const { minMessageLength, maxMessageLength, } = this.props;
|
|
|
|
if (message.length < minMessageLength) {
|
|
error = intl.formatMessage(messages.errorMinMessageLength,
|
|
{ 0: minMessageLength - message.length });
|
|
}
|
|
|
|
if (message.length > maxMessageLength) {
|
|
error = intl.formatMessage(messages.errorMaxMessageLength,
|
|
{ 0: message.length - maxMessageLength });
|
|
}
|
|
|
|
this.setState({
|
|
message,
|
|
error,
|
|
});
|
|
}
|
|
|
|
handleSubmit(e) {
|
|
e.preventDefault();
|
|
|
|
const { disabled, minMessageLength, maxMessageLength, } = this.props;
|
|
let message = this.state.message.trim();
|
|
|
|
if (disabled
|
|
|| message.length === 0
|
|
|| message.length < minMessageLength
|
|
|| message.length > maxMessageLength) {
|
|
this.setState({ hasErrors: true, });
|
|
return false;
|
|
}
|
|
|
|
// Sanitize. See: http://shebang.brandonmintern.com/foolproof-html-escaping-in-javascript/
|
|
|
|
let div = document.createElement('div');
|
|
div.appendChild(document.createTextNode(message));
|
|
message = div.innerHTML;
|
|
|
|
return this.props.handleSendMessage(message)
|
|
.then(() => this.setState({
|
|
message: '',
|
|
hasErrors: false,
|
|
}));
|
|
}
|
|
|
|
render() {
|
|
const { intl, chatTitle, chatName, disabled,
|
|
minMessageLength, maxMessageLength, } = this.props;
|
|
|
|
const { hasErrors, error } = this.state;
|
|
|
|
return (
|
|
<form
|
|
ref={(ref) => { this.form = ref; }}
|
|
className={cx(this.props.className, styles.form)}
|
|
onSubmit={this.handleSubmit}>
|
|
<div className={styles.wrapper}>
|
|
<TextareaAutosize
|
|
className={styles.input}
|
|
id="message-input"
|
|
placeholder={intl.formatMessage(messages.inputPlaceholder, { 0: chatName })}
|
|
aria-controls={this.props.chatAreaId}
|
|
aria-label={intl.formatMessage(messages.inputLabel, { 0: chatTitle })}
|
|
aria-invalid={ hasErrors ? 'true' : 'false' }
|
|
aria-describedby={ hasErrors ? 'message-input-error' : null }
|
|
autoCorrect="off"
|
|
autoComplete="off"
|
|
spellCheck="true"
|
|
disabled={disabled}
|
|
value={this.state.message}
|
|
onChange={this.handleMessageChange}
|
|
onKeyDown={this.handleMessageKeyDown}
|
|
/>
|
|
<Button
|
|
className={styles.sendButton}
|
|
aria-label={intl.formatMessage(messages.submitLabel)}
|
|
type="submit"
|
|
disabled={disabled}
|
|
label={intl.formatMessage(messages.submitLabel)}
|
|
hideLabel={true}
|
|
icon="send"
|
|
onClick={() => null}
|
|
/>
|
|
</div>
|
|
<div className={styles.info}>
|
|
{ hasErrors ? <span id="message-input-error">{error}</span> : null }
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|
|
}
|
|
|
|
MessageForm.propTypes = propTypes;
|
|
MessageForm.defaultProps = defaultProps;
|
|
|
|
export default injectIntl(MessageForm);
|