Replaced CommandList with the new suggestion components
Этот коммит содержится в:
@@ -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
Обычный файл
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.
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import CommandList from './command_list.jsx';
|
|
||||||
import AtMentionProvider from './at_mention_provider.jsx';
|
import AtMentionProvider from './at_mention_provider.jsx';
|
||||||
|
import CommandProvider from './command_provider.jsx';
|
||||||
import SuggestionList from './suggestion_list.jsx';
|
import SuggestionList from './suggestion_list.jsx';
|
||||||
import SuggestionBox from './suggestion_box.jsx';
|
import SuggestionBox from './suggestion_box.jsx';
|
||||||
import ErrorStore from '../stores/error_store.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 TextFormatting from '../utils/text_formatting.jsx';
|
||||||
import * as Utils from '../utils/utils.jsx';
|
import * as Utils from '../utils/utils.jsx';
|
||||||
import Constants from '../utils/constants.jsx';
|
import Constants from '../utils/constants.jsx';
|
||||||
const KeyCodes = Constants.KeyCodes;
|
|
||||||
const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES;
|
const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES;
|
||||||
|
|
||||||
export default class Textbox extends React.Component {
|
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.onRecievedError = this.onRecievedError.bind(this);
|
||||||
this.handleKeyPress = this.handleKeyPress.bind(this);
|
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||||
this.handleKeyDown = this.handleKeyDown.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.resize = this.resize.bind(this);
|
||||||
this.handleFocus = this.handleFocus.bind(this);
|
this.handleFocus = this.handleFocus.bind(this);
|
||||||
this.handleBlur = this.handleBlur.bind(this);
|
this.handleBlur = this.handleBlur.bind(this);
|
||||||
@@ -32,9 +29,7 @@ export default class Textbox extends React.Component {
|
|||||||
connection: ''
|
connection: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
this.caret = -1;
|
this.suggestionProviders = [new AtMentionProvider(), new CommandProvider()];
|
||||||
|
|
||||||
this.suggestionProviders = [new AtMentionProvider()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getStateFromStores() {
|
getStateFromStores() {
|
||||||
@@ -68,48 +63,19 @@ export default class Textbox extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
if (this.caret >= 0) {
|
|
||||||
Utils.setCaretPosition(this.refs.message.getTextbox(), this.caret);
|
|
||||||
this.caret = -1;
|
|
||||||
}
|
|
||||||
this.resize();
|
this.resize();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
this.refs.commands.getSuggestedCommands(nextProps.messageText);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKeyPress(e) {
|
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);
|
this.props.onKeyPress(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown(e) {
|
handleKeyDown(e) {
|
||||||
if (e.keyCode === KeyCodes.BACKSPACE) {
|
if (this.props.onKeyDown) {
|
||||||
this.handleBackspace(e);
|
|
||||||
} else if (this.props.onKeyDown) {
|
|
||||||
this.props.onKeyDown(e);
|
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() {
|
resize() {
|
||||||
const e = this.refs.message.getTextbox();
|
const e = this.refs.message.getTextbox();
|
||||||
const w = ReactDOM.findDOMNode(this.refs.wrapper);
|
const w = ReactDOM.findDOMNode(this.refs.wrapper);
|
||||||
@@ -193,11 +159,6 @@ export default class Textbox extends React.Component {
|
|||||||
ref='wrapper'
|
ref='wrapper'
|
||||||
className='textarea-wrapper'
|
className='textarea-wrapper'
|
||||||
>
|
>
|
||||||
<CommandList
|
|
||||||
ref='commands'
|
|
||||||
addCommand={this.addCommand}
|
|
||||||
channelId={this.props.channelId}
|
|
||||||
/>
|
|
||||||
<SuggestionBox
|
<SuggestionBox
|
||||||
id={this.props.id}
|
id={this.props.id}
|
||||||
ref='message'
|
ref='message'
|
||||||
|
|||||||
@@ -223,11 +223,13 @@ class SuggestionStore extends EventEmitter {
|
|||||||
this.emitSuggestionsChanged(id);
|
this.emitSuggestionsChanged(id);
|
||||||
break;
|
break;
|
||||||
case ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS:
|
case ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS:
|
||||||
this.setMatchedPretext(id, other.matchedPretext);
|
if (other.matchedPretext === this.getMatchedPretext(id)) {
|
||||||
this.addSuggestions(id, other.terms, other.items, other.componentType);
|
// 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.ensureSelectionExists(id);
|
||||||
this.emitSuggestionsChanged(id);
|
this.emitSuggestionsChanged(id);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ActionTypes.SUGGESTION_SELECT_NEXT:
|
case ActionTypes.SUGGESTION_SELECT_NEXT:
|
||||||
this.selectNext(id);
|
this.selectNext(id);
|
||||||
|
|||||||
@@ -32,4 +32,8 @@
|
|||||||
|
|
||||||
.command-desc {
|
.command-desc {
|
||||||
color: #a7a8ab;
|
color: #a7a8ab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.command--selected {
|
||||||
|
background-color: #e8eaed;
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user