Replaced CommandList with the new suggestion components

Этот коммит содержится в:
hmhealey
2015-12-01 10:54:53 -05:00
родитель 713115be51
Коммит 0c449ba5c9
5 изменённых файлов: 82 добавлений и 146 удалений

Просмотреть файл

@@ -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
};

68
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
});
}
}

Просмотреть файл

@@ -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'

Просмотреть файл

@@ -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);

Просмотреть файл

@@ -32,4 +32,8 @@
.command-desc {
color: #a7a8ab;
}
}
.command--selected {
background-color: #e8eaed;
}