Files
mostlymatter/webapp/components/search_bar.jsx
prixone fa40bfb9e6 Fixed @ not working on latest build due to... (#5878)
* Fixed @ not working on latest build due to...

On latest build the @ shortcut to search for mentions was not working due to missing parameters on the onListenerChange method, due to changes done previously to post_action and search_bar that were not made to the onListenerChange method.

* Update search_bar.jsx

added fix for when no notification options for mentions is defined by the user...
2017-03-31 09:53:19 -04:00

369 строки
12 KiB
JavaScript
Исходник Ответственный История

Этот файл содержит неоднозначные символы Юникода
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import * as GlobalActions from 'actions/global_actions.jsx';
import SearchStore from 'stores/search_store.jsx';
import UserStore from 'stores/user_store.jsx';
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
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 Constants from 'utils/constants.jsx';
import {getFlaggedPosts, performSearch} from 'actions/post_actions.jsx';
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
var ActionTypes = Constants.ActionTypes;
import {Tooltip, OverlayTrigger, Popover} from 'react-bootstrap';
import React from 'react';
export default class SearchBar extends React.Component {
constructor() {
super();
this.mounted = false;
this.onListenerChange = this.onListenerChange.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleUserFocus = this.handleUserFocus.bind(this);
this.handleClear = this.handleClear.bind(this);
this.handleUserBlur = this.handleUserBlur.bind(this);
this.handleSearch = this.handleSearch.bind(this);
this.handleSearchOnSuccess = this.handleSearchOnSuccess.bind(this);
this.handleSearchOnError = this.handleSearchOnError.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.searchMentions = this.searchMentions.bind(this);
this.getFlagged = this.getFlagged.bind(this);
const state = this.getSearchTermStateFromStores();
state.focused = false;
state.isPristine = true;
this.state = state;
this.suggestionProviders = [new SearchChannelProvider(), new SearchUserProvider()];
}
getSearchTermStateFromStores() {
var term = SearchStore.getSearchTerm() || '';
return {
searchTerm: term
};
}
componentDidMount() {
SearchStore.addSearchTermChangeListener(this.onListenerChange);
this.mounted = true;
if (Utils.isMobile()) {
setTimeout(() => {
document.querySelector('.app__body .sidebar--menu').classList.remove('visible');
});
}
}
componentWillUnmount() {
SearchStore.removeSearchTermChangeListener(this.onListenerChange);
this.mounted = false;
}
onListenerChange(doSearch, isMentionSearch) {
if (this.mounted) {
var newState = this.getSearchTermStateFromStores();
if (!Utils.areObjectsEqual(newState, this.state)) {
this.setState(newState);
}
if (doSearch && newState && newState.searchTerm.length) {
performSearch(
newState.searchTerm,
isMentionSearch,
() => {
this.handleSearchOnSuccess();
},
() => {
this.handleSearchOnError();
}
);
}
}
}
handleClose(e) {
e.preventDefault();
if (Utils.isMobile()) {
setTimeout(() => {
document.querySelector('.app__body .sidebar--menu').classList.add('visible');
});
}
AppDispatcher.handleServerAction({
type: ActionTypes.RECEIVED_SEARCH,
results: null
});
AppDispatcher.handleServerAction({
type: ActionTypes.RECEIVED_SEARCH_TERM,
term: null,
do_search: false,
is_mention_search: false
});
AppDispatcher.handleServerAction({
type: ActionTypes.RECEIVED_POST_SELECTED,
postId: null
});
}
handleChange(e) {
var term = e.target.value;
SearchStore.storeSearchTerm(term);
SearchStore.emitSearchTermChange(false);
this.setState({searchTerm: term});
}
handleUserBlur() {
this.setState({focused: false});
}
handleClear() {
this.setState({searchTerm: ''});
}
handleUserFocus() {
this.setState({focused: true});
}
handleSearch(terms, isMentionSearch) {
if (terms.length) {
this.setState({
isSearching: true,
isPristine: false
});
performSearch(
terms,
isMentionSearch,
() => {
this.handleSearchOnSuccess();
},
() => {
this.handleSearchOnError();
}
);
}
}
handleSearchOnSuccess() {
if (this.mounted) {
this.setState({isSearching: false});
if (Utils.isMobile() && this.search) {
this.search.value = '';
}
}
}
handleSearchOnError() {
if (this.mounted) {
this.setState({isSearching: false});
}
}
handleSubmit(e) {
e.preventDefault();
this.handleSearch(this.state.searchTerm.trim());
this.search.blur();
}
searchMentions(e) {
e.preventDefault();
const user = UserStore.getCurrentUser();
if (SearchStore.isMentionSearch) {
// Close
GlobalActions.toggleSideBarAction(false);
} else {
GlobalActions.emitSearchMentionsEvent(user);
}
}
getFlagged(e) {
e.preventDefault();
if (SearchStore.isFlaggedPosts) {
GlobalActions.toggleSideBarAction(false);
} else {
getFlaggedPosts();
}
}
renderHintPopover(helpClass) {
if (!this.props.isCommentsPage && Utils.isMobile() && this.state.isPristine) {
return false;
}
return (
<Popover
id='searchbar-help-popup'
placement='bottom'
className={helpClass}
>
<FormattedHTMLMessage
id='search_bar.usage'
defaultMessage='<h4>Search Options</h4><ul><li><span>Use </span><b>"quotation marks"</b><span> to search for phrases</span></li><li><span>Use </span><b>from:</b><span> to find posts from specific users and </span><b>in:</b><span> to find posts in specific channels</span></li></ul>'
/>
</Popover>
);
}
render() {
const flagIcon = Constants.FLAG_ICON_SVG;
var isSearching = null;
if (this.state.isSearching) {
isSearching = <span className={'fa fa-refresh fa-refresh-animate icon--refresh icon--rotate'}/>;
}
let helpClass = 'search-help-popover';
if (!this.state.searchTerm && this.state.focused) {
helpClass += ' visible';
}
const recentMentionsTooltip = (
<Tooltip id='recentMentionsTooltip'>
<FormattedMessage
id='channel_header.recentMentions'
defaultMessage='Recent Mentions'
/>
</Tooltip>
);
const flaggedTooltip = (
<Tooltip
id='flaggedTooltip'
className='text-nowrap'
>
<FormattedMessage
id='channel_header.flagged'
defaultMessage='Flagged Posts'
/>
</Tooltip>
);
let mentionBtn;
let flagBtn;
if (this.props.showMentionFlagBtns) {
mentionBtn = (
<div
className='dropdown channel-header__links'
style={{float: 'left', marginTop: '1px'}}
>
<OverlayTrigger
delayShow={Constants.OVERLAY_TIME_DELAY}
placement='bottom'
overlay={recentMentionsTooltip}
>
<a
href='#'
type='button'
onClick={this.searchMentions}
>
{'@'}
</a>
</OverlayTrigger>
</div>
);
flagBtn = (
<div
className='dropdown channel-header__links'
style={{float: 'left', marginTop: '1px'}}
>
<OverlayTrigger
delayShow={Constants.OVERLAY_TIME_DELAY}
placement='bottom'
overlay={flaggedTooltip}
>
<a
href='#'
type='button'
onClick={this.getFlagged}
>
<span
className='icon icon__flag'
dangerouslySetInnerHTML={{__html: flagIcon}}
/>
</a>
</OverlayTrigger>
</div>
);
}
let clearClass = 'sidebar__search-clear';
if (!this.state.isSearching && this.state.searchTerm && this.state.searchTerm.trim() !== '') {
clearClass += ' visible';
}
return (
<div>
<div
className='sidebar__collapse'
onClick={this.handleClose}
>
<span className='fa fa-angle-left'/>
</div>
<form
role='form'
className='search__form'
onSubmit={this.handleSubmit}
style={{overflow: 'visible'}}
autoComplete='off'
>
<span className='fa fa-search sidebar__search-icon'/>
<SuggestionBox
ref={(search) => {
this.search = search;
}}
className='form-control search-bar'
placeholder={Utils.localizeMessage('search_bar.search', 'Search')}
value={this.state.searchTerm}
onFocus={this.handleUserFocus}
onBlur={this.handleUserBlur}
onChange={this.handleChange}
listComponent={SearchSuggestionList}
providers={this.suggestionProviders}
type='search'
autoFocus={this.props.isFocus && this.state.searchTerm === ''}
/>
<div
className={clearClass}
onClick={this.handleClear}
>
<span
className='sidebar__search-clear-x'
aria-hidden='true'
>
{'×'}
</span>
</div>
{isSearching}
{this.renderHintPopover(helpClass)}
</form>
{mentionBtn}
{flagBtn}
</div>
);
}
}
SearchBar.defaultProps = {
showMentionFlagBtns: true,
isFocus: false
};
SearchBar.propTypes = {
showMentionFlagBtns: React.PropTypes.bool,
isCommentsPage: React.PropTypes.bool,
isFocus: React.PropTypes.bool
};