Fixed input handlers used by Textbox and SuggestionBox components to properly update when typing quickly (#3598)
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
47535ed0c7
Коммит
500b2dce10
@@ -21,7 +21,7 @@ export default class SwitchChannelModal extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.onUserInput = this.onUserInput.bind(this);
|
||||
this.onInput = this.onInput.bind(this);
|
||||
this.onShow = this.onShow.bind(this);
|
||||
this.onHide = this.onHide.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
@@ -57,8 +57,8 @@ export default class SwitchChannelModal extends React.Component {
|
||||
this.props.onHide();
|
||||
}
|
||||
|
||||
onUserInput(message) {
|
||||
this.setState({text: message});
|
||||
onInput(e) {
|
||||
this.setState({text: e.target.value});
|
||||
}
|
||||
|
||||
handleKeyDown(e) {
|
||||
@@ -122,7 +122,7 @@ export default class SwitchChannelModal extends React.Component {
|
||||
ref='search'
|
||||
className='form-control focused'
|
||||
type='input'
|
||||
onUserInput={this.onUserInput}
|
||||
onInput={this.onInput}
|
||||
value={this.state.text}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
listComponent={SuggestionList}
|
||||
|
||||
@@ -19,33 +19,14 @@ import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
const KeyCodes = Constants.KeyCodes;
|
||||
|
||||
const holders = defineMessages({
|
||||
commentLength: {
|
||||
id: 'create_comment.commentLength',
|
||||
defaultMessage: 'Comment length must be less than {max} characters.'
|
||||
},
|
||||
comment: {
|
||||
id: 'create_comment.comment',
|
||||
defaultMessage: 'Add Comment'
|
||||
},
|
||||
addComment: {
|
||||
id: 'create_comment.addComment',
|
||||
defaultMessage: 'Add a comment...'
|
||||
},
|
||||
commentTitle: {
|
||||
id: 'create_comment.commentTitle',
|
||||
defaultMessage: 'Comment'
|
||||
}
|
||||
});
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class CreateComment extends React.Component {
|
||||
export default class CreateComment extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -53,7 +34,7 @@ class CreateComment extends React.Component {
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.commentMsgKeyPress = this.commentMsgKeyPress.bind(this);
|
||||
this.handleUserInput = this.handleUserInput.bind(this);
|
||||
this.handleInput = this.handleInput.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.handleUploadClick = this.handleUploadClick.bind(this);
|
||||
this.handleUploadStart = this.handleUploadStart.bind(this);
|
||||
@@ -76,8 +57,7 @@ class CreateComment extends React.Component {
|
||||
previews: draft.previews,
|
||||
submitting: false,
|
||||
ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'),
|
||||
showPostDeletedModal: false,
|
||||
typing: false
|
||||
showPostDeletedModal: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -126,7 +106,15 @@ class CreateComment extends React.Component {
|
||||
}
|
||||
|
||||
if (post.message.length > Constants.CHARACTER_LIMIT) {
|
||||
this.setState({postError: this.props.intl.formatMessage(holders.commentLength, {max: Constants.CHARACTER_LIMIT})});
|
||||
this.setState({
|
||||
postError: (
|
||||
<FormattedMessage
|
||||
id='create_comment.commentLength'
|
||||
defaultMessage='Comment length must be less than {max} characters.'
|
||||
values={{max: Constants.CHARACTER_LIMIT}}
|
||||
/>
|
||||
)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -175,8 +163,7 @@ class CreateComment extends React.Component {
|
||||
submitting: false,
|
||||
postError: null,
|
||||
previews: [],
|
||||
serverError: null,
|
||||
typing: false
|
||||
serverError: null
|
||||
});
|
||||
}
|
||||
|
||||
@@ -192,15 +179,16 @@ class CreateComment extends React.Component {
|
||||
GlobalActions.emitLocalUserTypingEvent(this.props.channelId, this.props.rootId);
|
||||
}
|
||||
|
||||
handleUserInput(messageText) {
|
||||
handleInput(e) {
|
||||
const messageText = e.target.value;
|
||||
|
||||
const draft = PostStore.getCommentDraft(this.props.rootId);
|
||||
draft.message = messageText;
|
||||
PostStore.storeCommentDraft(this.props.rootId, draft);
|
||||
|
||||
$('.post-right__scroll').parent().scrollTop($('.post-right__scroll')[0].scrollHeight);
|
||||
|
||||
const typing = messageText !== '';
|
||||
this.setState({messageText, typing});
|
||||
this.setState({messageText});
|
||||
}
|
||||
|
||||
handleKeyDown(e) {
|
||||
@@ -220,7 +208,7 @@ class CreateComment extends React.Component {
|
||||
AppDispatcher.handleViewAction({
|
||||
type: ActionTypes.RECEIVED_EDIT_POST,
|
||||
refocusId: '#reply_textbox',
|
||||
title: this.props.intl.formatMessage(holders.commentTitle),
|
||||
title: Utils.localizeMessage('create_comment.commentTitle', 'Comment'),
|
||||
message: lastPost.message,
|
||||
postId: lastPost.id,
|
||||
channelId: lastPost.channel_id,
|
||||
@@ -319,7 +307,7 @@ class CreateComment extends React.Component {
|
||||
componentWillReceiveProps(newProps) {
|
||||
if (newProps.rootId !== this.props.rootId) {
|
||||
const draft = PostStore.getCommentDraft(newProps.rootId);
|
||||
this.setState({messageText: draft.message, uploadsInProgress: draft.uploadsInProgress, previews: draft.previews, typing: false});
|
||||
this.setState({messageText: draft.message, uploadsInProgress: draft.uploadsInProgress, previews: draft.previews});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +383,6 @@ class CreateComment extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='post-create'>
|
||||
@@ -405,12 +392,11 @@ class CreateComment extends React.Component {
|
||||
>
|
||||
<div className='post-body__cell'>
|
||||
<Textbox
|
||||
onUserInput={this.handleUserInput}
|
||||
onInput={this.handleInput}
|
||||
onKeyPress={this.commentMsgKeyPress}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
messageText={this.state.messageText}
|
||||
typing={this.state.typing}
|
||||
createMessage={formatMessage(holders.addComment)}
|
||||
createMessage={Utils.localizeMessage('create_comment.addComment', 'Add a comment...')}
|
||||
initialText=''
|
||||
supportsCommands={false}
|
||||
id='reply_textbox'
|
||||
@@ -436,7 +422,7 @@ class CreateComment extends React.Component {
|
||||
<input
|
||||
type='button'
|
||||
className='btn btn-primary comment-btn pull-right'
|
||||
value={formatMessage(holders.comment)}
|
||||
value={Utils.localizeMessage('create_comment.comment', 'Add Comment')}
|
||||
onClick={this.handleSubmit}
|
||||
/>
|
||||
{uploadsInProgressText}
|
||||
@@ -455,9 +441,6 @@ class CreateComment extends React.Component {
|
||||
}
|
||||
|
||||
CreateComment.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
channelId: React.PropTypes.string.isRequired,
|
||||
rootId: React.PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(CreateComment);
|
||||
};
|
||||
@@ -23,7 +23,7 @@ import PreferenceStore from 'stores/preference_store.jsx';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedHTMLMessage} from 'react-intl';
|
||||
import {FormattedHTMLMessage} from 'react-intl';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
const Preferences = Constants.Preferences;
|
||||
@@ -31,24 +31,9 @@ const TutorialSteps = Constants.TutorialSteps;
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
const KeyCodes = Constants.KeyCodes;
|
||||
|
||||
const holders = defineMessages({
|
||||
comment: {
|
||||
id: 'create_post.comment',
|
||||
defaultMessage: 'Comment'
|
||||
},
|
||||
post: {
|
||||
id: 'create_post.post',
|
||||
defaultMessage: 'Post'
|
||||
},
|
||||
write: {
|
||||
id: 'create_post.write',
|
||||
defaultMessage: 'Write a message...'
|
||||
}
|
||||
});
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class CreatePost extends React.Component {
|
||||
export default class CreatePost extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -57,7 +42,7 @@ class CreatePost extends React.Component {
|
||||
this.getCurrentDraft = this.getCurrentDraft.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.postMsgKeyPress = this.postMsgKeyPress.bind(this);
|
||||
this.handleUserInput = this.handleUserInput.bind(this);
|
||||
this.handleInput = this.handleInput.bind(this);
|
||||
this.handleUploadClick = this.handleUploadClick.bind(this);
|
||||
this.handleUploadStart = this.handleUploadStart.bind(this);
|
||||
this.handleFileUploadComplete = this.handleFileUploadComplete.bind(this);
|
||||
@@ -87,8 +72,7 @@ class CreatePost extends React.Component {
|
||||
ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'),
|
||||
fullWidthTextBox: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN,
|
||||
showTutorialTip: false,
|
||||
showPostDeletedModal: false,
|
||||
typing: false
|
||||
showPostDeletedModal: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -133,7 +117,7 @@ class CreatePost extends React.Component {
|
||||
|
||||
MessageHistoryStore.storeMessageInHistory(this.state.messageText);
|
||||
|
||||
this.setState({submitting: true, serverError: null, typing: false});
|
||||
this.setState({submitting: true, serverError: null});
|
||||
|
||||
if (post.message.indexOf('/') === 0) {
|
||||
ChannelActions.executeCommand(
|
||||
@@ -223,9 +207,9 @@ class CreatePost extends React.Component {
|
||||
GlobalActions.emitLocalUserTypingEvent(this.state.channelId, '');
|
||||
}
|
||||
|
||||
handleUserInput(messageText) {
|
||||
const typing = messageText !== '';
|
||||
this.setState({messageText, typing});
|
||||
handleInput(e) {
|
||||
const messageText = e.target.value;
|
||||
this.setState({messageText});
|
||||
|
||||
const draft = PostStore.getCurrentDraft();
|
||||
draft.message = messageText;
|
||||
@@ -372,7 +356,7 @@ class CreatePost extends React.Component {
|
||||
if (this.state.channelId !== channelId) {
|
||||
const draft = this.getCurrentDraft();
|
||||
|
||||
this.setState({channelId, messageText: draft.messageText, initialText: draft.messageText, submitting: false, typing: false, serverError: null, postError: null, previews: draft.previews, uploadsInProgress: draft.uploadsInProgress});
|
||||
this.setState({channelId, messageText: draft.messageText, initialText: draft.messageText, submitting: false, serverError: null, postError: null, previews: draft.previews, uploadsInProgress: draft.uploadsInProgress});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,8 +392,13 @@ class CreatePost extends React.Component {
|
||||
if (!lastPost) {
|
||||
return;
|
||||
}
|
||||
const {formatMessage} = this.props.intl;
|
||||
var type = (lastPost.root_id && lastPost.root_id.length > 0) ? formatMessage(holders.comment) : formatMessage(holders.post);
|
||||
|
||||
let type;
|
||||
if (lastPost.root_id && lastPost.root_id.length > 0) {
|
||||
type = Utils.localizeMessage('create_post.comment', 'Comment');
|
||||
} else {
|
||||
type = Utils.localizeMessage('create_post.post', 'Post');
|
||||
}
|
||||
|
||||
AppDispatcher.handleViewAction({
|
||||
type: ActionTypes.RECEIVED_EDIT_POST,
|
||||
@@ -519,12 +508,11 @@ class CreatePost extends React.Component {
|
||||
<div className='post-create-body'>
|
||||
<div className='post-body__cell'>
|
||||
<Textbox
|
||||
onUserInput={this.handleUserInput}
|
||||
onInput={this.handleInput}
|
||||
onKeyPress={this.postMsgKeyPress}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
messageText={this.state.messageText}
|
||||
typing={this.state.typing}
|
||||
createMessage={this.props.intl.formatMessage(holders.write)}
|
||||
createMessage={Utils.localizeMessage('create_post.write', 'Write a message...')}
|
||||
channelId={this.state.channelId}
|
||||
id='post_textbox'
|
||||
ref='textbox'
|
||||
@@ -565,10 +553,4 @@ class CreatePost extends React.Component {
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CreatePost.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(CreatePost);
|
||||
}
|
||||
@@ -11,31 +11,25 @@ import BrowserStore from 'stores/browser_store.jsx';
|
||||
import PostStore from 'stores/post_store.jsx';
|
||||
import MessageHistoryStore from 'stores/message_history_store.jsx';
|
||||
import PreferenceStore from 'stores/preference_store.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
var KeyCodes = Constants.KeyCodes;
|
||||
|
||||
const holders = defineMessages({
|
||||
editPost: {
|
||||
id: 'edit_post.editPost',
|
||||
defaultMessage: 'Edit the post...'
|
||||
}
|
||||
});
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class EditPostModal extends React.Component {
|
||||
export default class EditPostModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleEdit = this.handleEdit.bind(this);
|
||||
this.handleEditInput = this.handleEditInput.bind(this);
|
||||
this.handleEditKeyPress = this.handleEditKeyPress.bind(this);
|
||||
this.handleEditPostEvent = this.handleEditPostEvent.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.handleInput = this.handleInput.bind(this);
|
||||
this.onPreferenceChange = this.onPreferenceChange.bind(this);
|
||||
this.onModalHidden = this.onModalHidden.bind(this);
|
||||
this.onModalShow = this.onModalShow.bind(this);
|
||||
@@ -43,8 +37,9 @@ class EditPostModal extends React.Component {
|
||||
this.onModalHide = this.onModalHide.bind(this);
|
||||
this.onModalKeyDown = this.onModalKeyDown.bind(this);
|
||||
|
||||
this.state = {editText: '', originalText: '', title: '', post_id: '', channel_id: '', comments: 0, refocusId: '', typing: false};
|
||||
this.state = {editText: '', originalText: '', title: '', post_id: '', channel_id: '', comments: 0, refocusId: ''};
|
||||
}
|
||||
|
||||
handleEdit() {
|
||||
var updatedPost = {};
|
||||
updatedPost.message = this.state.editText.trim();
|
||||
@@ -82,10 +77,13 @@ class EditPostModal extends React.Component {
|
||||
|
||||
$('#edit_post').modal('hide');
|
||||
}
|
||||
handleEditInput(editMessage) {
|
||||
const typing = editMessage !== '';
|
||||
this.setState({editText: editMessage, typing});
|
||||
|
||||
handleInput(e) {
|
||||
this.setState({
|
||||
editText: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
handleEditKeyPress(e) {
|
||||
if (!this.state.ctrlSend && e.which === KeyCodes.ENTER && !e.shiftKey && !e.altKey) {
|
||||
e.preventDefault();
|
||||
@@ -97,6 +95,7 @@ class EditPostModal extends React.Component {
|
||||
this.handleSubmit(e);
|
||||
}
|
||||
}
|
||||
|
||||
handleEditPostEvent(options) {
|
||||
this.setState({
|
||||
editText: options.message || '',
|
||||
@@ -105,25 +104,28 @@ class EditPostModal extends React.Component {
|
||||
post_id: options.postId || '',
|
||||
channel_id: options.channelId || '',
|
||||
comments: options.comments || 0,
|
||||
refocusId: options.refocusId || '',
|
||||
typing: false
|
||||
refocusId: options.refocusId || ''
|
||||
});
|
||||
|
||||
$(ReactDOM.findDOMNode(this.refs.modal)).modal('show');
|
||||
}
|
||||
|
||||
handleKeyDown(e) {
|
||||
if (this.state.ctrlSend && e.keyCode === KeyCodes.ENTER && e.ctrlKey === true) {
|
||||
this.handleEdit(e);
|
||||
}
|
||||
}
|
||||
|
||||
onPreferenceChange() {
|
||||
this.setState({
|
||||
ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter')
|
||||
});
|
||||
}
|
||||
|
||||
onModalHidden() {
|
||||
this.setState({editText: '', originalText: '', title: '', channel_id: '', post_id: '', comments: 0, refocusId: '', error: '', typing: false});
|
||||
}
|
||||
|
||||
onModalShow(e) {
|
||||
var button = e.relatedTarget;
|
||||
if (!button) {
|
||||
@@ -140,9 +142,11 @@ class EditPostModal extends React.Component {
|
||||
typing: false
|
||||
});
|
||||
}
|
||||
|
||||
onModalShown() {
|
||||
this.refs.editbox.focus();
|
||||
}
|
||||
|
||||
onModalHide() {
|
||||
if (this.state.refocusId !== '') {
|
||||
setTimeout(() => {
|
||||
@@ -150,11 +154,13 @@ class EditPostModal extends React.Component {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onModalKeyDown(e) {
|
||||
if (e.which === Constants.KeyCodes.ESCAPE) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
$(this.refs.modal).on('hidden.bs.modal', this.onModalHidden);
|
||||
$(this.refs.modal).on('show.bs.modal', this.onModalShow);
|
||||
@@ -164,6 +170,7 @@ class EditPostModal extends React.Component {
|
||||
PostStore.addEditPostListener(this.handleEditPostEvent);
|
||||
PreferenceStore.addChangeListener(this.onPreferenceChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
$(this.refs.modal).off('hidden.bs.modal', this.onModalHidden);
|
||||
$(this.refs.modal).off('show.bs.modal', this.onModalShow);
|
||||
@@ -173,6 +180,7 @@ class EditPostModal extends React.Component {
|
||||
PostStore.removeEditPostListner(this.handleEditPostEvent);
|
||||
PreferenceStore.removeChangeListener(this.onPreferenceChange);
|
||||
}
|
||||
|
||||
render() {
|
||||
var error = (<div className='form-group'><br/></div>);
|
||||
if (this.state.error) {
|
||||
@@ -212,12 +220,11 @@ class EditPostModal extends React.Component {
|
||||
</div>
|
||||
<div className='edit-modal-body modal-body'>
|
||||
<Textbox
|
||||
onUserInput={this.handleEditInput}
|
||||
onInput={this.handleInput}
|
||||
onKeyPress={this.handleEditKeyPress}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
messageText={this.state.editText}
|
||||
typing={this.state.typing}
|
||||
createMessage={this.props.intl.formatMessage(holders.editPost)}
|
||||
createMessage={Utils.localizeMessage('edit_post.editPost', 'Edit the post...')}
|
||||
supportsCommands={false}
|
||||
id='edit_textbox'
|
||||
ref='editbox'
|
||||
@@ -252,9 +259,3 @@ class EditPostModal extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EditPostModal.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(EditPostModal);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import $ from 'jquery';
|
||||
import ReactDOM from 'react-dom';
|
||||
import client from 'utils/web_client.jsx';
|
||||
import Client from 'utils/web_client.jsx';
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import SearchStore from 'stores/search_store.jsx';
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
@@ -11,30 +11,23 @@ import SuggestionBox from './suggestion/suggestion_box.jsx';
|
||||
import SearchChannelProvider from './suggestion/search_channel_provider.jsx';
|
||||
import SearchSuggestionList from './suggestion/search_suggestion_list.jsx';
|
||||
import SearchUserProvider from './suggestion/search_user_provider.jsx';
|
||||
import * as utils from 'utils/utils.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
|
||||
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
|
||||
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
import {Popover} from 'react-bootstrap';
|
||||
|
||||
const holders = defineMessages({
|
||||
search: {
|
||||
id: 'search_bar.search',
|
||||
defaultMessage: 'Search'
|
||||
}
|
||||
});
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class SearchBar extends React.Component {
|
||||
export default class SearchBar extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.mounted = false;
|
||||
|
||||
this.onListenerChange = this.onListenerChange.bind(this);
|
||||
this.handleUserInput = this.handleUserInput.bind(this);
|
||||
this.handleInput = this.handleInput.bind(this);
|
||||
this.handleUserFocus = this.handleUserFocus.bind(this);
|
||||
this.handleUserBlur = this.handleUserBlur.bind(this);
|
||||
this.performSearch = this.performSearch.bind(this);
|
||||
@@ -46,24 +39,28 @@ class SearchBar extends React.Component {
|
||||
|
||||
this.suggestionProviders = [new SearchChannelProvider(), new SearchUserProvider()];
|
||||
}
|
||||
|
||||
getSearchTermStateFromStores() {
|
||||
var term = SearchStore.getSearchTerm() || '';
|
||||
return {
|
||||
searchTerm: term
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
SearchStore.addSearchTermChangeListener(this.onListenerChange);
|
||||
this.mounted = true;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
SearchStore.removeSearchTermChangeListener(this.onListenerChange);
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
onListenerChange(doSearch, isMentionSearch) {
|
||||
if (this.mounted) {
|
||||
var newState = this.getSearchTermStateFromStores();
|
||||
if (!utils.areObjectsEqual(newState, this.state)) {
|
||||
if (!Utils.areObjectsEqual(newState, this.state)) {
|
||||
this.setState(newState);
|
||||
}
|
||||
if (doSearch) {
|
||||
@@ -71,9 +68,11 @@ class SearchBar extends React.Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearFocus() {
|
||||
$('.search-bar__container').removeClass('focused');
|
||||
}
|
||||
|
||||
handleClose(e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -94,30 +93,34 @@ class SearchBar extends React.Component {
|
||||
postId: null
|
||||
});
|
||||
}
|
||||
handleUserInput(text) {
|
||||
var term = text;
|
||||
|
||||
handleInput(e) {
|
||||
var term = e.target.value;
|
||||
SearchStore.storeSearchTerm(term);
|
||||
SearchStore.emitSearchTermChange(false);
|
||||
this.setState({searchTerm: term});
|
||||
}
|
||||
|
||||
handleUserBlur() {
|
||||
this.setState({focused: false});
|
||||
}
|
||||
|
||||
handleUserFocus() {
|
||||
$('.search-bar__container').addClass('focused');
|
||||
|
||||
this.setState({focused: true});
|
||||
}
|
||||
|
||||
performSearch(terms, isMentionSearch) {
|
||||
if (terms.length) {
|
||||
this.setState({isSearching: true});
|
||||
|
||||
client.search(
|
||||
Client.search(
|
||||
terms,
|
||||
isMentionSearch,
|
||||
(data) => {
|
||||
this.setState({isSearching: false});
|
||||
if (utils.isMobile()) {
|
||||
if (Utils.isMobile()) {
|
||||
ReactDOM.findDOMNode(this.refs.search).value = '';
|
||||
}
|
||||
|
||||
@@ -134,6 +137,7 @@ class SearchBar extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
this.performSearch(this.state.searchTerm.trim());
|
||||
@@ -178,11 +182,11 @@ class SearchBar extends React.Component {
|
||||
<SuggestionBox
|
||||
ref='search'
|
||||
className='form-control search-bar'
|
||||
placeholder={this.props.intl.formatMessage(holders.search)}
|
||||
placeholder={Utils.localizeMessage('search_bar.search', 'Search')}
|
||||
value={this.state.searchTerm}
|
||||
onFocus={this.handleUserFocus}
|
||||
onBlur={this.handleUserBlur}
|
||||
onUserInput={this.handleUserInput}
|
||||
onInput={this.handleInput}
|
||||
listComponent={SearchSuggestionList}
|
||||
providers={this.suggestionProviders}
|
||||
type='search'
|
||||
@@ -202,11 +206,4 @@ class SearchBar extends React.Component {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SearchBar.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(SearchBar);
|
||||
|
||||
}
|
||||
@@ -21,8 +21,8 @@ export default class SuggestionBox extends React.Component {
|
||||
|
||||
this.handleDocumentClick = this.handleDocumentClick.bind(this);
|
||||
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleCompleteWord = this.handleCompleteWord.bind(this);
|
||||
this.handleInput = this.handleInput.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.handlePretextChanged = this.handlePretextChanged.bind(this);
|
||||
|
||||
@@ -70,27 +70,24 @@ export default class SuggestionBox extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(e) {
|
||||
handleInput(e) {
|
||||
const textbox = ReactDOM.findDOMNode(this.refs.textbox);
|
||||
const caret = Utils.getCaretPosition(textbox);
|
||||
const pretext = textbox.value.substring(0, caret);
|
||||
|
||||
GlobalActions.emitSuggestionPretextChanged(this.suggestionId, pretext);
|
||||
|
||||
if (this.props.onUserInput) {
|
||||
this.props.onUserInput(textbox.value);
|
||||
}
|
||||
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(e);
|
||||
if (this.props.onInput) {
|
||||
this.props.onInput(e);
|
||||
}
|
||||
}
|
||||
|
||||
handleCompleteWord(term, matchedPretext) {
|
||||
const textbox = ReactDOM.findDOMNode(this.refs.textbox);
|
||||
const textbox = this.refs.textbox;
|
||||
const caret = Utils.getCaretPosition(textbox);
|
||||
const text = textbox.value;
|
||||
const pretext = text.substring(0, caret);
|
||||
|
||||
let prefix;
|
||||
if (pretext.endsWith(matchedPretext)) {
|
||||
prefix = pretext.substring(0, pretext.length - matchedPretext.length);
|
||||
@@ -104,10 +101,17 @@ export default class SuggestionBox extends React.Component {
|
||||
|
||||
const suffix = text.substring(caret);
|
||||
|
||||
if (this.props.onUserInput) {
|
||||
this.props.onUserInput(prefix + term + ' ' + suffix);
|
||||
this.refs.textbox.value = prefix + term + ' ' + suffix;
|
||||
|
||||
if (this.props.onInput) {
|
||||
// fake an input event to send back to parent components
|
||||
const e = {
|
||||
target: this.refs.textbox
|
||||
};
|
||||
|
||||
// don't call handleInput or we'll get into an event loop
|
||||
this.props.onInput(e);
|
||||
}
|
||||
this.refs.textbox.value = (prefix + term + ' ' + suffix);
|
||||
|
||||
// set the caret position after the next rendering
|
||||
window.requestAnimationFrame(() => {
|
||||
@@ -144,18 +148,15 @@ export default class SuggestionBox extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const newProps = Object.assign({}, this.props, {
|
||||
onChange: this.handleChange,
|
||||
onKeyDown: this.handleKeyDown
|
||||
});
|
||||
|
||||
let textbox = null;
|
||||
if (this.props.type === 'input') {
|
||||
textbox = (
|
||||
<input
|
||||
ref='textbox'
|
||||
type='text'
|
||||
{...newProps}
|
||||
{...this.props}
|
||||
onInput={this.handleInput}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
/>
|
||||
);
|
||||
} else if (this.props.type === 'search') {
|
||||
@@ -163,7 +164,9 @@ export default class SuggestionBox extends React.Component {
|
||||
<input
|
||||
ref='textbox'
|
||||
type='search'
|
||||
{...newProps}
|
||||
{...this.props}
|
||||
onInput={this.handleInput}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
/>
|
||||
);
|
||||
} else if (this.props.type === 'textarea') {
|
||||
@@ -171,7 +174,9 @@ export default class SuggestionBox extends React.Component {
|
||||
<TextareaAutosize
|
||||
id={this.suggestionId}
|
||||
ref='textbox'
|
||||
{...newProps}
|
||||
{...this.props}
|
||||
onInput={this.handleInput}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -213,12 +218,10 @@ SuggestionBox.propTypes = {
|
||||
listComponent: React.PropTypes.func.isRequired,
|
||||
type: React.PropTypes.oneOf(['input', 'textarea', 'search']).isRequired,
|
||||
value: React.PropTypes.string.isRequired,
|
||||
onUserInput: React.PropTypes.func,
|
||||
providers: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||
listStyle: React.PropTypes.string,
|
||||
|
||||
// explicitly name any input event handlers we override and need to manually call
|
||||
onChange: React.PropTypes.func,
|
||||
onKeyDown: React.PropTypes.func,
|
||||
onHeightChange: React.PropTypes.func
|
||||
onInput: React.PropTypes.func,
|
||||
onKeyDown: React.PropTypes.func
|
||||
};
|
||||
|
||||
@@ -176,11 +176,6 @@ export default class Textbox extends React.Component {
|
||||
</div>
|
||||
);
|
||||
|
||||
const otherProps = {};
|
||||
if (!this.props.typing) {
|
||||
otherProps.value = this.props.messageText;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref='wrapper'
|
||||
@@ -194,7 +189,7 @@ export default class Textbox extends React.Component {
|
||||
spellCheck='true'
|
||||
maxLength={Constants.MAX_POST_LEN}
|
||||
placeholder={this.props.createMessage}
|
||||
onUserInput={this.props.onUserInput}
|
||||
onInput={this.props.onInput}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onHeightChange={this.handleHeightChange}
|
||||
@@ -202,7 +197,7 @@ export default class Textbox extends React.Component {
|
||||
listComponent={SuggestionList}
|
||||
providers={this.suggestionProviders}
|
||||
channelId={this.props.channelId}
|
||||
{...otherProps}
|
||||
value={this.props.messageText}
|
||||
/>
|
||||
<div
|
||||
ref='preview'
|
||||
@@ -239,10 +234,9 @@ Textbox.propTypes = {
|
||||
id: React.PropTypes.string.isRequired,
|
||||
channelId: React.PropTypes.string,
|
||||
messageText: React.PropTypes.string.isRequired,
|
||||
onUserInput: React.PropTypes.func.isRequired,
|
||||
onInput: React.PropTypes.func.isRequired,
|
||||
onKeyPress: React.PropTypes.func.isRequired,
|
||||
createMessage: React.PropTypes.string.isRequired,
|
||||
onKeyDown: React.PropTypes.func,
|
||||
supportsCommands: React.PropTypes.bool.isRequired,
|
||||
typing: React.PropTypes.bool.isRequired
|
||||
supportsCommands: React.PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
Ссылка в новой задаче
Block a user