summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--web/react/components/command_list.jsx99
-rw-r--r--web/react/components/command_provider.jsx68
-rw-r--r--web/react/components/textbox.jsx45
-rw-r--r--web/react/stores/suggestion_store.jsx10
-rw-r--r--web/sass-files/sass/partials/_command-box.scss6
5 files changed, 82 insertions, 146 deletions
diff --git a/web/react/components/command_list.jsx b/web/react/components/command_list.jsx
deleted file mode 100644
index 7fc0f79cf..000000000
--- a/web/react/components/command_list.jsx
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import * as client from '../utils/client.jsx';
-
-export default class CommandList extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleClick = this.handleClick.bind(this);
- this.addFirstCommand = this.addFirstCommand.bind(this);
- this.isEmpty = this.isEmpty.bind(this);
- this.getSuggestedCommands = this.getSuggestedCommands.bind(this);
-
- this.state = {
- suggestions: [],
- cmd: ''
- };
- }
-
- handleClick(i) {
- this.props.addCommand(this.state.suggestions[i].suggestion);
- this.setState({suggestions: [], cmd: ''});
- }
-
- addFirstCommand() {
- if (this.state.suggestions.length === 0) {
- return;
- }
- this.handleClick(0);
- }
-
- isEmpty() {
- return this.state.suggestions.length === 0;
- }
-
- getSuggestedCommands(cmd) {
- if (!cmd || cmd.charAt(0) !== '/') {
- this.setState({suggestions: [], cmd: ''});
- return;
- }
-
- client.executeCommand(
- this.props.channelId,
- cmd,
- true,
- function success(data) {
- if (data.suggestions.length === 1 && data.suggestions[0].suggestion === cmd) {
- data.suggestions = [];
- }
- this.setState({suggestions: data.suggestions, cmd: cmd});
- }.bind(this),
- function fail() {
- }
- );
- }
-
- render() {
- if (this.state.suggestions.length === 0) {
- return (<div/>);
- }
-
- var suggestions = [];
-
- for (var i = 0; i < this.state.suggestions.length; i++) {
- if (this.state.suggestions[i].suggestion !== this.state.cmd) {
- suggestions.push(
- <div
- key={i}
- className='command-name'
- onClick={this.handleClick.bind(this, i)}
- >
- <div className='command__title'><strong>{this.state.suggestions[i].suggestion}</strong></div>
- <div className='command__desc'>{this.state.suggestions[i].description}</div>
- </div>
- );
- }
- }
-
- return (
- <div
- ref='mentionlist'
- className='command-box'
- style={{height: (suggestions.length * 56) + 2}}
- >
- {suggestions}
- </div>
- );
- }
-}
-
-CommandList.defaultProps = {
- channelId: null
-};
-
-CommandList.propTypes = {
- addCommand: React.PropTypes.func,
- channelId: React.PropTypes.string
-};
diff --git a/web/react/components/command_provider.jsx b/web/react/components/command_provider.jsx
new file mode 100644
index 000000000..0526e09b1
--- /dev/null
+++ b/web/react/components/command_provider.jsx
@@ -0,0 +1,68 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
+import * as Client from '../utils/client.jsx';
+import Constants from '../utils/constants.jsx';
+import SuggestionStore from '../stores/suggestion_store.jsx';
+
+class CommandSuggestion extends React.Component {
+ render() {
+ const {item, isSelection, onClick} = this.props;
+
+ let className = 'command-name';
+ if (isSelection) {
+ className += ' command--selected';
+ }
+
+ return (
+ <div
+ className={className}
+ onClick={onClick}
+ >
+ <div className='command__title'>
+ <string>{item.suggestion}</string>
+ </div>
+ <div className='command__desc'>
+ {item.description}
+ </div>
+ </div>
+ );
+ }
+}
+
+CommandSuggestion.propTypes = {
+ item: React.PropTypes.object.isRequired,
+ isSelection: React.PropTypes.bool,
+ onClick: React.PropTypes.func
+};
+
+export default class CommandProvider {
+ handlePretextChanged(suggestionId, pretext) {
+ if (pretext.startsWith('/')) {
+ SuggestionStore.setMatchedPretext(suggestionId, pretext);
+
+ Client.executeCommand(
+ '',
+ pretext,
+ true,
+ (data) => {
+ this.handleCommandsReceived(suggestionId, pretext, data.suggestions);
+ }
+ );
+ }
+ }
+
+ handleCommandsReceived(suggestionId, matchedPretext, commandSuggestions) {
+ const terms = commandSuggestions.map(({suggestion}) => suggestion);
+
+ AppDispatcher.handleServerAction({
+ type: Constants.ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS,
+ id: suggestionId,
+ matchedPretext,
+ terms,
+ items: commandSuggestions,
+ component: CommandSuggestion
+ });
+ }
+}
diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx
index fde8f64d3..b50575fc1 100644
--- a/web/react/components/textbox.jsx
+++ b/web/react/components/textbox.jsx
@@ -1,8 +1,8 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import CommandList from './command_list.jsx';
import AtMentionProvider from './at_mention_provider.jsx';
+import CommandProvider from './command_provider.jsx';
import SuggestionList from './suggestion_list.jsx';
import SuggestionBox from './suggestion_box.jsx';
import ErrorStore from '../stores/error_store.jsx';
@@ -10,7 +10,6 @@ import ErrorStore from '../stores/error_store.jsx';
import * as TextFormatting from '../utils/text_formatting.jsx';
import * as Utils from '../utils/utils.jsx';
import Constants from '../utils/constants.jsx';
-const KeyCodes = Constants.KeyCodes;
const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES;
export default class Textbox extends React.Component {
@@ -21,8 +20,6 @@ export default class Textbox extends React.Component {
this.onRecievedError = this.onRecievedError.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
- this.handleBackspace = this.handleBackspace.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);
@@ -32,9 +29,7 @@ export default class Textbox extends React.Component {
connection: ''
};
- this.caret = -1;
-
- this.suggestionProviders = [new AtMentionProvider()];
+ this.suggestionProviders = [new AtMentionProvider(), new CommandProvider()];
}
getStateFromStores() {
@@ -68,48 +63,19 @@ export default class Textbox extends React.Component {
}
componentDidUpdate() {
- if (this.caret >= 0) {
- Utils.setCaretPosition(this.refs.message.getTextbox(), this.caret);
- this.caret = -1;
- }
this.resize();
}
- componentWillReceiveProps(nextProps) {
- this.refs.commands.getSuggestedCommands(nextProps.messageText);
- }
-
handleKeyPress(e) {
- const text = this.refs.message.getTextbox().value;
-
- if (!this.refs.commands.isEmpty() && text.indexOf('/') === 0 && e.which === KeyCodes.ENTER) {
- this.refs.commands.addFirstCommand();
- e.preventDefault();
- return;
- }
-
this.props.onKeyPress(e);
}
handleKeyDown(e) {
- if (e.keyCode === KeyCodes.BACKSPACE) {
- this.handleBackspace(e);
- } else if (this.props.onKeyDown) {
+ if (this.props.onKeyDown) {
this.props.onKeyDown(e);
}
}
- handleBackspace() {
- const text = this.refs.message.getTextbox().value;
- if (text.indexOf('/') === 0) {
- this.refs.commands.getSuggestedCommands(text.substring(0, text.length - 1));
- }
- }
-
- addCommand(cmd) {
- this.props.onUserInput(cmd);
- }
-
resize() {
const e = this.refs.message.getTextbox();
const w = ReactDOM.findDOMNode(this.refs.wrapper);
@@ -193,11 +159,6 @@ export default class Textbox extends React.Component {
ref='wrapper'
className='textarea-wrapper'
>
- <CommandList
- ref='commands'
- addCommand={this.addCommand}
- channelId={this.props.channelId}
- />
<SuggestionBox
id={this.props.id}
ref='message'
diff --git a/web/react/stores/suggestion_store.jsx b/web/react/stores/suggestion_store.jsx
index 8e64d02a3..5bd13b02d 100644
--- a/web/react/stores/suggestion_store.jsx
+++ b/web/react/stores/suggestion_store.jsx
@@ -223,11 +223,13 @@ class SuggestionStore extends EventEmitter {
this.emitSuggestionsChanged(id);
break;
case ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS:
- this.setMatchedPretext(id, other.matchedPretext);
- this.addSuggestions(id, other.terms, other.items, other.componentType);
+ if (other.matchedPretext === this.getMatchedPretext(id)) {
+ // ensure the matched pretext hasn't changed so that we don't receive suggestions for outdated pretext
+ this.addSuggestions(id, other.terms, other.items, other.component);
- this.ensureSelectionExists(id);
- this.emitSuggestionsChanged(id);
+ this.ensureSelectionExists(id);
+ this.emitSuggestionsChanged(id);
+ }
break;
case ActionTypes.SUGGESTION_SELECT_NEXT:
this.selectNext(id);
diff --git a/web/sass-files/sass/partials/_command-box.scss b/web/sass-files/sass/partials/_command-box.scss
index 184fb55eb..b5ba26edf 100644
--- a/web/sass-files/sass/partials/_command-box.scss
+++ b/web/sass-files/sass/partials/_command-box.scss
@@ -32,4 +32,8 @@
.command-desc {
color: #a7a8ab;
-} \ No newline at end of file
+}
+
+.command--selected {
+ background-color: #e8eaed;
+}