summaryrefslogtreecommitdiffstats
path: root/web/react/components/textbox.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components/textbox.jsx')
-rw-r--r--web/react/components/textbox.jsx282
1 files changed, 169 insertions, 113 deletions
diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx
index efd2dd810..0408a262d 100644
--- a/web/react/components/textbox.jsx
+++ b/web/react/components/textbox.jsx
@@ -1,66 +1,93 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
-var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
-var PostStore = require('../stores/post_store.jsx');
-var CommandList = require('./command_list.jsx');
-var ErrorStore = require('../stores/error_store.jsx');
-var AsyncClient = require('../utils/async_client.jsx');
-
-var utils = require('../utils/utils.jsx');
-var Constants = require('../utils/constants.jsx');
-var ActionTypes = Constants.ActionTypes;
+const AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
+const PostStore = require('../stores/post_store.jsx');
+const CommandList = require('./command_list.jsx');
+const ErrorStore = require('../stores/error_store.jsx');
+const AsyncClient = require('../utils/async_client.jsx');
+
+const Utils = require('../utils/utils.jsx');
+const Constants = require('../utils/constants.jsx');
+const ActionTypes = Constants.ActionTypes;
+
+export default class Textbox extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.getStateFromStores = this.getStateFromStores.bind(this);
+ this.onListenerChange = this.onListenerChange.bind(this);
+ this.onRecievedError = this.onRecievedError.bind(this);
+ this.onTimerInterrupt = this.onTimerInterrupt.bind(this);
+ this.updateMentionTab = this.updateMentionTab.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ this.handleKeyPress = this.handleKeyPress.bind(this);
+ this.handleKeyDown = this.handleKeyDown.bind(this);
+ this.handleBackspace = this.handleBackspace.bind(this);
+ this.checkForNewMention = this.checkForNewMention.bind(this);
+ this.addMention = this.addMention.bind(this);
+ this.addCommand = this.addCommand.bind(this);
+ this.resize = this.resize.bind(this);
+ this.handleFocus = this.handleFocus.bind(this);
+ this.handleBlur = this.handleBlur.bind(this);
+ this.handlePaste = this.handlePaste.bind(this);
+
+ this.state = {
+ mentionText: '-1',
+ mentions: [],
+ connection: '',
+ timerInterrupt: null
+ };
+
+ this.caret = -1;
+ this.addedMention = false;
+ this.doProcessMentions = false;
+ this.mentions = [];
+ }
+ getStateFromStores() {
+ const error = ErrorStore.getLastError();
-function getStateFromStores() {
- var error = ErrorStore.getLastError();
+ if (error) {
+ return {message: error.message};
+ }
- if (error) {
- return {message: error.message};
+ return {message: null};
}
- return {message: null};
-}
-
-module.exports = React.createClass({
- displayName: 'Textbox',
- caret: -1,
- addedMention: false,
- doProcessMentions: false,
- mentions: [],
- componentDidMount: function() {
+ componentDidMount() {
PostStore.addAddMentionListener(this.onListenerChange);
ErrorStore.addChangeListener(this.onRecievedError);
this.resize();
this.updateMentionTab(null);
- },
- componentWillUnmount: function() {
+ }
+ componentWillUnmount() {
PostStore.removeAddMentionListener(this.onListenerChange);
ErrorStore.removeChangeListener(this.onRecievedError);
- },
- onListenerChange: function(id, username) {
+ }
+ onListenerChange(id, username) {
if (id === this.props.id) {
this.addMention(username);
}
- },
- onRecievedError: function() {
- var errorState = getStateFromStores();
+ }
+ onRecievedError() {
+ const errorState = this.getStateFromStores();
- if (this.state.timerInterrupt != null) {
+ if (this.state.timerInterrupt !== null) {
window.clearInterval(this.state.timerInterrupt);
this.setState({timerInterrupt: null});
}
if (errorState.message === 'There appears to be a problem with your internet connection') {
this.setState({connection: 'bad-connection'});
- var timerInterrupt = window.setInterval(this.onTimerInterrupt, 5000);
+ const timerInterrupt = window.setInterval(this.onTimerInterrupt, 5000);
this.setState({timerInterrupt: timerInterrupt});
} else {
this.setState({connection: ''});
}
- },
- onTimerInterrupt: function() {
- //Since these should only happen when you have no connection and slightly briefly after any
- //performance hit should not matter
+ }
+ onTimerInterrupt() {
+ // Since these should only happen when you have no connection and slightly briefly after any
+ // performance hit should not matter
if (this.state.connection === 'bad-connection') {
AppDispatcher.handleServerAction({
type: ActionTypes.RECIEVED_ERROR,
@@ -72,10 +99,10 @@ module.exports = React.createClass({
window.clearInterval(this.state.timerInterrupt);
this.setState({timerInterrupt: null});
- },
- componentDidUpdate: function() {
+ }
+ componentDidUpdate() {
if (this.caret >= 0) {
- utils.setCaretPosition(this.refs.message.getDOMNode(), this.caret);
+ Utils.setCaretPosition(React.findDOMNode(this.refs.message), this.caret);
this.caret = -1;
}
if (this.doProcessMentions) {
@@ -83,40 +110,35 @@ module.exports = React.createClass({
this.doProcessMentions = false;
}
this.resize();
- },
- componentWillReceiveProps: function(nextProps) {
+ }
+ componentWillReceiveProps(nextProps) {
if (!this.addedMention) {
this.checkForNewMention(nextProps.messageText);
}
- var text = this.refs.message.getDOMNode().value;
+ const text = React.findDOMNode(this.refs.message).value;
if (nextProps.channelId !== this.props.channelId || nextProps.messageText !== text) {
this.doProcessMentions = true;
}
this.addedMention = false;
this.refs.commands.getSuggestedCommands(nextProps.messageText);
this.resize();
- },
- getInitialState: function() {
- return {mentionText: '-1', mentions: [], connection: '', timerInterrupt: null};
- },
- updateMentionTab: function(mentionText) {
- var self = this;
-
+ }
+ updateMentionTab(mentionText) {
// using setTimeout so dispatch isn't called during an in progress dispatch
- setTimeout(function() {
+ setTimeout(function updateMentionTabAfterTimeout() {
AppDispatcher.handleViewAction({
type: ActionTypes.RECIEVED_MENTION_DATA,
- id: self.props.id,
+ id: this.props.id,
mention_text: mentionText
});
- }, 1);
- },
- handleChange: function() {
- this.props.onUserInput(this.refs.message.getDOMNode().value);
+ }.bind(this), 1);
+ }
+ handleChange() {
+ this.props.onUserInput(React.findDOMNode(this.refs.message).value);
this.resize();
- },
- handleKeyPress: function(e) {
- var text = this.refs.message.getDOMNode().value;
+ }
+ handleKeyPress(e) {
+ const text = React.findDOMNode(this.refs.message).value;
if (!this.refs.commands.isEmpty() && text.indexOf('/') === 0 && e.which === 13) {
this.refs.commands.addFirstCommand();
@@ -125,10 +147,10 @@ module.exports = React.createClass({
}
if (!this.doProcessMentions) {
- var caret = utils.getCaretPosition(this.refs.message.getDOMNode());
- var preText = text.substring(0, caret);
- var lastSpace = preText.lastIndexOf(' ');
- var lastAt = preText.lastIndexOf('@');
+ const caret = Utils.getCaretPosition(React.findDOMNode(this.refs.message));
+ const preText = text.substring(0, caret);
+ const lastSpace = preText.lastIndexOf(' ');
+ const lastAt = preText.lastIndexOf('@');
if (caret > lastAt && lastSpace < lastAt) {
this.doProcessMentions = true;
@@ -136,18 +158,18 @@ module.exports = React.createClass({
}
this.props.onKeyPress(e);
- },
- handleKeyDown: function(e) {
- if (utils.getSelectedText(this.refs.message.getDOMNode()) !== '') {
+ }
+ handleKeyDown(e) {
+ if (Utils.getSelectedText(React.findDOMNode(this.refs.message)) !== '') {
this.doProcessMentions = true;
}
if (e.keyCode === 8) {
this.handleBackspace(e);
}
- },
- handleBackspace: function() {
- var text = this.refs.message.getDOMNode().value;
+ }
+ handleBackspace() {
+ const text = React.findDOMNode(this.refs.message).value;
if (text.indexOf('/') === 0) {
this.refs.commands.getSuggestedCommands(text.substring(0, text.length - 1));
}
@@ -156,21 +178,21 @@ module.exports = React.createClass({
return;
}
- var caret = utils.getCaretPosition(this.refs.message.getDOMNode());
- var preText = text.substring(0, caret);
- var lastSpace = preText.lastIndexOf(' ');
- var lastAt = preText.lastIndexOf('@');
+ const caret = Utils.getCaretPosition(React.findDOMNode(this.refs.message));
+ const preText = text.substring(0, caret);
+ const lastSpace = preText.lastIndexOf(' ');
+ const lastAt = preText.lastIndexOf('@');
if (caret > lastAt && (lastSpace > lastAt || lastSpace === -1)) {
this.doProcessMentions = true;
}
- },
- checkForNewMention: function(text) {
- var caret = utils.getCaretPosition(this.refs.message.getDOMNode());
+ }
+ checkForNewMention(text) {
+ const caret = Utils.getCaretPosition(React.findDOMNode(this.refs.message));
- var preText = text.substring(0, caret);
+ const preText = text.substring(0, caret);
- var atIndex = preText.lastIndexOf('@');
+ const atIndex = preText.lastIndexOf('@');
// The @ character not typed, so nothing to do.
if (atIndex === -1) {
@@ -178,8 +200,8 @@ module.exports = React.createClass({
return;
}
- var lastCharSpace = preText.lastIndexOf(String.fromCharCode(160));
- var lastSpace = preText.lastIndexOf(' ');
+ const lastCharSpace = preText.lastIndexOf(String.fromCharCode(160));
+ const lastSpace = preText.lastIndexOf(' ');
// If there is a space after the last @, nothing to do.
if (lastSpace > atIndex || lastCharSpace > atIndex) {
@@ -188,43 +210,43 @@ module.exports = React.createClass({
}
// Get the name typed so far.
- var name = preText.substring(atIndex + 1, preText.length).toLowerCase();
+ const name = preText.substring(atIndex + 1, preText.length).toLowerCase();
this.updateMentionTab(name);
- },
- addMention: function(name) {
- var caret = utils.getCaretPosition(this.refs.message.getDOMNode());
+ }
+ addMention(name) {
+ const caret = Utils.getCaretPosition(React.findDOMNode(this.refs.message));
- var text = this.props.messageText;
+ const text = this.props.messageText;
- var preText = text.substring(0, caret);
+ const preText = text.substring(0, caret);
- var atIndex = preText.lastIndexOf('@');
+ const atIndex = preText.lastIndexOf('@');
// The @ character not typed, so nothing to do.
if (atIndex === -1) {
return;
}
- var prefix = text.substring(0, atIndex);
- var suffix = text.substring(caret, text.length);
+ const prefix = text.substring(0, atIndex);
+ const suffix = text.substring(caret, text.length);
this.caret = prefix.length + name.length + 2;
this.addedMention = true;
this.doProcessMentions = true;
- this.props.onUserInput(prefix + '@' + name + ' ' + suffix);
- },
- addCommand: function(cmd) {
- var elm = this.refs.message.getDOMNode();
+ this.props.onUserInput(`${prefix}@${name} ${suffix}`);
+ }
+ addCommand(cmd) {
+ const elm = React.findDOMNode(this.refs.message);
elm.value = cmd;
this.handleChange();
- },
- resize: function() {
- var e = this.refs.message.getDOMNode();
- var w = this.refs.wrapper.getDOMNode();
+ }
+ resize() {
+ const e = React.findDOMNode(this.refs.message);
+ const w = React.findDOMNode(this.refs.wrapper);
- var lht = parseInt($(e).css('lineHeight'), 10);
- var lines = e.scrollHeight / lht;
- var mod = 15;
+ const lht = parseInt($(e).css('lineHeight'), 10);
+ const lines = e.scrollHeight / lht;
+ let mod = 15;
if (lines < 2.5 || this.props.messageText === '') {
mod = 30;
@@ -237,28 +259,62 @@ module.exports = React.createClass({
$(e).css({height: 'auto', 'overflow-y': 'scroll'}).height(167);
$(w).css({height: 'auto'}).height(167);
}
- },
- handleFocus: function() {
- var elm = this.refs.message.getDOMNode();
+ }
+ handleFocus() {
+ const elm = React.findDOMNode(this.refs.message);
if (elm.title === elm.value) {
elm.value = '';
}
- },
- handleBlur: function() {
- var elm = this.refs.message.getDOMNode();
+ }
+ handleBlur() {
+ const elm = React.findDOMNode(this.refs.message);
if (elm.value === '') {
elm.value = elm.title;
}
- },
- handlePaste: function() {
+ }
+ handlePaste() {
this.doProcessMentions = true;
- },
- render: function() {
+ }
+ render() {
return (
- <div ref='wrapper' className='textarea-wrapper'>
- <CommandList ref='commands' addCommand={this.addCommand} channelId={this.props.channelId} />
- <textarea id={this.props.id} ref='message' className={'form-control custom-textarea ' + this.state.connection} spellCheck='true' autoComplete='off' autoCorrect='off' rows='1' maxLength={Constants.MAX_POST_LEN} placeholder={this.props.createMessage} value={this.props.messageText} onInput={this.handleChange} onChange={this.handleChange} onKeyPress={this.handleKeyPress} onKeyDown={this.handleKeyDown} onFocus={this.handleFocus} onBlur={this.handleBlur} onPaste={this.handlePaste} />
+ <div
+ ref='wrapper'
+ className='textarea-wrapper'
+ >
+ <CommandList
+ ref='commands'
+ addCommand={this.addCommand}
+ channelId={this.props.channelId}
+ />
+ <textarea
+ id={this.props.id}
+ ref='message'
+ className={`form-control custom-textarea ${this.state.connection}`}
+ spellCheck='true'
+ autoComplete='off'
+ autoCorrect='off'
+ rows='1'
+ maxLength={Constants.MAX_POST_LEN}
+ placeholder={this.props.createMessage}
+ value={this.props.messageText}
+ onInput={this.handleChange}
+ onChange={this.handleChange}
+ onKeyPress={this.handleKeyPress}
+ onKeyDown={this.handleKeyDown}
+ onFocus={this.handleFocus}
+ onBlur={this.handleBlur}
+ onPaste={this.handlePaste}
+ />
</div>
);
}
-});
+}
+
+Textbox.propTypes = {
+ id: React.PropTypes.string.isRequired,
+ channelId: React.PropTypes.string,
+ messageText: React.PropTypes.string.isRequired,
+ onUserInput: React.PropTypes.func.isRequired,
+ onKeyPress: React.PropTypes.func.isRequired,
+ createMessage: React.PropTypes.string.isRequired
+};