summaryrefslogtreecommitdiffstats
path: root/webapp/components/search_bar.jsx
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2016-03-14 08:50:46 -0400
committerChristopher Speller <crspeller@gmail.com>2016-03-16 18:02:55 -0400
commit12896bd23eeba79884245c1c29fdc568cf21a7fa (patch)
tree4e7f83d3e2564b9b89d669e9f7905ff11768b11a /webapp/components/search_bar.jsx
parent29fe6a3d13c9c7aa490fffebbe5d1b5fdf1e3090 (diff)
downloadchat-12896bd23eeba79884245c1c29fdc568cf21a7fa.tar.gz
chat-12896bd23eeba79884245c1c29fdc568cf21a7fa.tar.bz2
chat-12896bd23eeba79884245c1c29fdc568cf21a7fa.zip
Converting to Webpack. Stage 1.
Diffstat (limited to 'webapp/components/search_bar.jsx')
-rw-r--r--webapp/components/search_bar.jsx210
1 files changed, 210 insertions, 0 deletions
diff --git a/webapp/components/search_bar.jsx b/webapp/components/search_bar.jsx
new file mode 100644
index 000000000..c8dbb9d3f
--- /dev/null
+++ b/webapp/components/search_bar.jsx
@@ -0,0 +1,210 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import $ from 'jquery';
+import ReactDOM from 'react-dom';
+import * as client from 'utils/client.jsx';
+import * as AsyncClient from 'utils/async_client.jsx';
+import SearchStore from 'stores/search_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 {intlShape, injectIntl, defineMessages, 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 {
+ constructor() {
+ super();
+ this.mounted = false;
+
+ this.onListenerChange = this.onListenerChange.bind(this);
+ this.handleUserInput = this.handleUserInput.bind(this);
+ this.handleUserFocus = this.handleUserFocus.bind(this);
+ this.handleUserBlur = this.handleUserBlur.bind(this);
+ this.performSearch = this.performSearch.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+
+ const state = this.getSearchTermStateFromStores();
+ state.focused = false;
+ 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;
+ }
+ 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) {
+ this.performSearch(newState.searchTerm, isMentionSearch);
+ }
+ }
+ }
+ clearFocus() {
+ $('.search-bar__container').removeClass('focused');
+ }
+ handleClose(e) {
+ e.preventDefault();
+
+ 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
+ });
+ }
+ handleUserInput(text) {
+ var term = text;
+ 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(
+ terms,
+ (data) => {
+ this.setState({isSearching: false});
+ if (utils.isMobile()) {
+ ReactDOM.findDOMNode(this.refs.search).value = '';
+ }
+
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_SEARCH,
+ results: data,
+ is_mention_search: isMentionSearch
+ });
+ },
+ (err) => {
+ this.setState({isSearching: false});
+ AsyncClient.dispatchError(err, 'search');
+ }
+ );
+ }
+ }
+ handleSubmit(e) {
+ e.preventDefault();
+ this.performSearch(this.state.searchTerm.trim());
+ }
+
+ render() {
+ var isSearching = null;
+ if (this.state.isSearching) {
+ isSearching = <span className={'glyphicon glyphicon-refresh glyphicon-refresh-animate'}></span>;
+ }
+
+ let helpClass = 'search-help-popover';
+ if (!this.state.searchTerm && this.state.focused) {
+ helpClass += ' visible';
+ }
+
+ return (
+ <div>
+ <div
+ className='sidebar__collapse'
+ onClick={this.handleClose}
+ >
+ <span className='fa fa-angle-left'></span>
+ </div>
+ <span
+ className='search__clear'
+ onClick={this.clearFocus}
+ >
+ <FormattedMessage
+ id='search_bar.cancel'
+ defaultMessage='Cancel'
+ />
+ </span>
+ <form
+ role='form'
+ className='search__form'
+ onSubmit={this.handleSubmit}
+ style={{overflow: 'visible'}}
+ autoComplete='off'
+ >
+ <span className='glyphicon glyphicon-search sidebar__search-icon'/>
+ <SuggestionBox
+ ref='search'
+ className='form-control search-bar'
+ placeholder={this.props.intl.formatMessage(holders.search)}
+ value={this.state.searchTerm}
+ onFocus={this.handleUserFocus}
+ onBlur={this.handleUserBlur}
+ onUserInput={this.handleUserInput}
+ listComponent={SearchSuggestionList}
+ providers={this.suggestionProviders}
+ />
+ {isSearching}
+ <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>
+ </form>
+ </div>
+ );
+ }
+}
+
+SearchBar.propTypes = {
+ intl: intlShape.isRequired
+};
+
+export default injectIntl(SearchBar);
+