diff options
Diffstat (limited to 'webapp')
-rw-r--r-- | webapp/components/search_bar.jsx | 13 | ||||
-rw-r--r-- | webapp/components/search_results.jsx | 29 | ||||
-rw-r--r-- | webapp/components/search_results_header.jsx | 3 | ||||
-rw-r--r-- | webapp/components/sidebar_right/sidebar_right.jsx | 2 | ||||
-rwxr-xr-x | webapp/i18n/en.json | 1 | ||||
-rw-r--r-- | webapp/sass/components/_search.scss | 17 | ||||
-rw-r--r-- | webapp/sass/layout/_sidebar-right.scss | 9 | ||||
-rw-r--r-- | webapp/sass/responsive/_mobile.scss | 5 | ||||
-rw-r--r-- | webapp/stores/search_store.jsx | 16 |
9 files changed, 83 insertions, 12 deletions
diff --git a/webapp/components/search_bar.jsx b/webapp/components/search_bar.jsx index c635c5eb1..f2fed25ca 100644 --- a/webapp/components/search_bar.jsx +++ b/webapp/components/search_bar.jsx @@ -171,7 +171,16 @@ export default class SearchBar extends React.Component { handleSubmit(e) { e.preventDefault(); - this.handleSearch(this.state.searchTerm.trim()); + const terms = this.state.searchTerm.trim(); + + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_SEARCH_TERM, + term: terms, + do_search: true, + is_mention_search: false + }); + + this.handleSearch(terms); this.search.blur(); } @@ -221,7 +230,7 @@ export default class SearchBar extends React.Component { var isSearching = null; if (this.state.isSearching) { - isSearching = <span className={'fa fa-refresh fa-refresh-animate icon--refresh icon--rotate'}/>; + isSearching = <span className={'fa fa-spin fa-spinner'}/>; } let helpClass = 'search-help-popover'; diff --git a/webapp/components/search_results.jsx b/webapp/components/search_results.jsx index 1d1627950..1499c8abb 100644 --- a/webapp/components/search_results.jsx +++ b/webapp/components/search_results.jsx @@ -39,7 +39,8 @@ function getStateFromStores() { results, channels, searchTerm: SearchStore.getSearchTerm(), - flaggedPosts: PreferenceStore.getCategory(Constants.Preferences.CATEGORY_FLAGGED_POST) + flaggedPosts: PreferenceStore.getCategory(Constants.Preferences.CATEGORY_FLAGGED_POST), + loading: SearchStore.isLoading() }; } @@ -71,6 +72,7 @@ export default class SearchResults extends React.Component { componentDidMount() { this.mounted = true; + SearchStore.addSearchTermChangeListener(this.onSearchTermChange); SearchStore.addSearchChangeListener(this.onChange); ChannelStore.addChangeListener(this.onChange); PreferenceStore.addChangeListener(this.onPreferenceChange); @@ -113,6 +115,7 @@ export default class SearchResults extends React.Component { componentWillUnmount() { this.mounted = false; + SearchStore.removeSearchTermChangeListener(this.onSearchTermChange); SearchStore.removeSearchChangeListener(this.onChange); ChannelStore.removeChangeListener(this.onChange); PreferenceStore.removeChangeListener(this.onPreferenceChange); @@ -144,6 +147,14 @@ export default class SearchResults extends React.Component { }); } + onSearchTermChange(doSearch) { + if (this.mounted && doSearch) { + this.setState({ + loading: true + }); + } + } + onChange() { if (this.mounted) { this.setState(getStateFromStores()); @@ -175,7 +186,20 @@ export default class SearchResults extends React.Component { var ctls = null; - if (this.props.isFlaggedPosts && noResults) { + if (this.state.loading) { + ctls = + ( + <div className='sidebar--right__subheader'> + <div className='sidebar--right__loading'> + <i className='fa fa-spinner fa-spin'/> + <FormattedMessage + id='search_header.loading' + defaultMessage='Searching...' + /> + </div> + </div> + ); + } else if (this.props.isFlaggedPosts && noResults) { ctls = ( <div className='sidebar--right__subheader'> <ul> @@ -319,6 +343,7 @@ export default class SearchResults extends React.Component { isFlaggedPosts={this.props.isFlaggedPosts} isPinnedPosts={this.props.isPinnedPosts} channelDisplayName={this.props.channelDisplayName} + isLoading={this.state.loading} /> <div id='search-items-container' diff --git a/webapp/components/search_results_header.jsx b/webapp/components/search_results_header.jsx index 467b77e27..b3f77c413 100644 --- a/webapp/components/search_results_header.jsx +++ b/webapp/components/search_results_header.jsx @@ -148,5 +148,6 @@ SearchResultsHeader.propTypes = { shrink: PropTypes.func, isFlaggedPosts: PropTypes.bool, isPinnedPosts: PropTypes.bool, - channelDisplayName: PropTypes.string.isRequired + channelDisplayName: PropTypes.string.isRequired, + isLoading: PropTypes.bool.isRequired }; diff --git a/webapp/components/sidebar_right/sidebar_right.jsx b/webapp/components/sidebar_right/sidebar_right.jsx index 737254682..f7c0a6400 100644 --- a/webapp/components/sidebar_right/sidebar_right.jsx +++ b/webapp/components/sidebar_right/sidebar_right.jsx @@ -157,7 +157,7 @@ export default class SidebarRight extends React.Component { onSearchChange() { this.setState({ - searchVisible: SearchStore.getSearchResults() !== null, + searchVisible: SearchStore.getSearchResults() !== null || SearchStore.isLoading(), isMentionSearch: SearchStore.getIsMentionSearch(), isFlaggedPosts: SearchStore.getIsFlaggedPosts(), isPinnedPosts: SearchStore.getIsPinnedPosts() diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 77206c161..992af160f 100755 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -2061,6 +2061,7 @@ "search_item.jump": "Jump", "search_results.because": "<ul><li>If you're searching a partial phrase (ex. searching \"rea\", looking for \"reach\" or \"reaction\"), append a * to your search term.</li><li>Two letter searches and common words like \"this\", \"a\" and \"is\" won't appear in search results due to excessive results returned.</li></ul>", "search_results.noResults": "No results found. Try again?", + "search_results.searching": "Searching...", "search_results.usage": "<ul><li>Use <b>\"quotation marks\"</b> to search for phrases</li><li>Use <b>from:</b> to find posts from specific users and <b>in:</b> to find posts in specific channels</li></ul>", "search_results.usageFlag1": "You haven't flagged any messages yet.", "search_results.usageFlag2": "You can add a flag to messages and comments by clicking the ", diff --git a/webapp/sass/components/_search.scss b/webapp/sass/components/_search.scss index c9b8d4c02..4461b1da1 100644 --- a/webapp/sass/components/_search.scss +++ b/webapp/sass/components/_search.scss @@ -42,10 +42,6 @@ width: 40px; } -.search-form__container { - -} - .search__form { position: relative; @@ -71,15 +67,16 @@ width: 100%; } - .icon--refresh { + .fa-spin { @include opacity(0.5); + font-size: 1.2em; position: absolute; right: 27px; top: 27px; .search-bar__container & { right: 12px; - top: 11px; + top: 10px; } } } @@ -93,6 +90,14 @@ position: relative; } +.search-items-container div.loading { + text-align: center; +} + +.search-items-container img { + display: inline-block; +} + .search-results-header { border-bottom: $border-gray; color: #999999; diff --git a/webapp/sass/layout/_sidebar-right.scss b/webapp/sass/layout/_sidebar-right.scss index 6d31c1606..d7a18b587 100644 --- a/webapp/sass/layout/_sidebar-right.scss +++ b/webapp/sass/layout/_sidebar-right.scss @@ -224,6 +224,15 @@ text-transform: uppercase; } + .sidebar--right__loading { + @include opacity(.7); + text-align: center; + + .fa { + margin-right: 5px; + } + } + .sidebar--right__subheader { font-size: 1em; padding: .5em 1em 0; diff --git a/webapp/sass/responsive/_mobile.scss b/webapp/sass/responsive/_mobile.scss index 8f44a883f..d39797efb 100644 --- a/webapp/sass/responsive/_mobile.scss +++ b/webapp/sass/responsive/_mobile.scss @@ -1008,6 +1008,11 @@ margin-top: 9px; width: 100%; + .fa-spin { + font-size: 1.1em; + top: 9px; + } + .search-bar { font-size: 14px; height: 32px; diff --git a/webapp/stores/search_store.jsx b/webapp/stores/search_store.jsx index d57c630cb..dd9b6dbdf 100644 --- a/webapp/stores/search_store.jsx +++ b/webapp/stores/search_store.jsx @@ -24,6 +24,7 @@ class SearchStoreClass extends EventEmitter { this.isPinnedPosts = false; this.isVisible = false; this.searchTerm = ''; + this.loading = false; } emitChange() { @@ -157,6 +158,14 @@ class SearchStoreClass extends EventEmitter { results.order.splice(index, 1); } } + + setLoading(loading) { + this.loading = loading; + } + + isLoading() { + return this.loading; + } } var SearchStore = new SearchStoreClass(); @@ -173,10 +182,17 @@ SearchStore.dispatchToken = AppDispatcher.register((payload) => { // ignore pin posts update after switch to a new channel return; } + SearchStore.setLoading(false); SearchStore.storeSearchResults(action.results, action.is_mention_search, action.is_flagged_posts, action.is_pinned_posts); SearchStore.emitSearchChange(); break; case ActionTypes.RECEIVED_SEARCH_TERM: + if (action.do_search) { + // while a search is in progress, hide results from previous search + SearchStore.setLoading(true); + SearchStore.storeSearchResults(null, false, false, false); + SearchStore.emitSearchChange(); + } SearchStore.storeSearchTerm(action.term); SearchStore.emitSearchTermChange(action.do_search, action.is_mention_search); break; |