PageRenderTime 69ms CodeModel.GetById 41ms RepoModel.GetById 0ms app.codeStats 1ms

/webapp/components/search_results.jsx

https://gitlab.com/auchalet/mattermost
JSX | 197 lines | 168 code | 27 blank | 2 comment | 21 complexity | 0dff28e8a0e5680d7d94bda14d7621d5 MD5 | raw file
  1. // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
  2. // See License.txt for license information.
  3. import $ from 'jquery';
  4. import ChannelStore from 'stores/channel_store.jsx';
  5. import SearchStore from 'stores/search_store.jsx';
  6. import UserStore from 'stores/user_store.jsx';
  7. import SearchBox from './search_bar.jsx';
  8. import * as Utils from 'utils/utils.jsx';
  9. import SearchResultsHeader from './search_results_header.jsx';
  10. import SearchResultsItem from './search_results_item.jsx';
  11. import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
  12. function getStateFromStores() {
  13. const results = SearchStore.getSearchResults();
  14. const channels = new Map();
  15. if (results && results.order) {
  16. const channelIds = results.order.map((postId) => results.posts[postId].channel_id);
  17. for (const id of channelIds) {
  18. if (channels.has(id)) {
  19. continue;
  20. }
  21. channels.set(id, ChannelStore.get(id));
  22. }
  23. }
  24. return {
  25. results,
  26. channels,
  27. searchTerm: SearchStore.getSearchTerm()
  28. };
  29. }
  30. import React from 'react';
  31. export default class SearchResults extends React.Component {
  32. constructor(props) {
  33. super(props);
  34. this.mounted = false;
  35. this.onChange = this.onChange.bind(this);
  36. this.onUserChange = this.onUserChange.bind(this);
  37. this.resize = this.resize.bind(this);
  38. this.handleResize = this.handleResize.bind(this);
  39. const state = getStateFromStores();
  40. state.windowWidth = Utils.windowWidth();
  41. state.windowHeight = Utils.windowHeight();
  42. state.profiles = JSON.parse(JSON.stringify(UserStore.getProfiles()));
  43. this.state = state;
  44. }
  45. componentDidMount() {
  46. this.mounted = true;
  47. SearchStore.addSearchChangeListener(this.onChange);
  48. ChannelStore.addChangeListener(this.onChange);
  49. UserStore.addChangeListener(this.onUserChange);
  50. this.resize();
  51. window.addEventListener('resize', this.handleResize);
  52. if (!Utils.isMobile()) {
  53. $('.sidebar--right .search-items-container').perfectScrollbar();
  54. }
  55. }
  56. shouldComponentUpdate(nextProps, nextState) {
  57. if (!Utils.areObjectsEqual(this.props, nextProps)) {
  58. return true;
  59. }
  60. if (!Utils.areObjectsEqual(this.state, nextState)) {
  61. return true;
  62. }
  63. return false;
  64. }
  65. componentDidUpdate() {
  66. this.resize();
  67. }
  68. componentWillUnmount() {
  69. SearchStore.removeSearchChangeListener(this.onChange);
  70. ChannelStore.removeChangeListener(this.onChange);
  71. UserStore.removeChangeListener(this.onUserChange);
  72. this.mounted = false;
  73. window.removeEventListener('resize', this.handleResize);
  74. }
  75. handleResize() {
  76. this.setState({
  77. windowWidth: Utils.windowWidth(),
  78. windowHeight: Utils.windowHeight()
  79. });
  80. }
  81. onChange() {
  82. if (this.mounted) {
  83. this.setState(getStateFromStores());
  84. }
  85. }
  86. onUserChange() {
  87. this.setState({profiles: JSON.parse(JSON.stringify(UserStore.getProfiles()))});
  88. }
  89. resize() {
  90. $('#search-items-container').scrollTop(0);
  91. }
  92. render() {
  93. var results = this.state.results;
  94. var currentId = UserStore.getCurrentId();
  95. var searchForm = null;
  96. if (currentId) {
  97. searchForm = <SearchBox/>;
  98. }
  99. var noResults = (!results || !results.order || !results.order.length);
  100. const searchTerm = this.state.searchTerm;
  101. const profiles = this.state.profiles || {};
  102. var ctls = null;
  103. if (!searchTerm && noResults) {
  104. ctls = (
  105. <div className='sidebar--right__subheader'>
  106. <FormattedHTMLMessage
  107. id='search_results.usage'
  108. defaultMessage='<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>'
  109. />
  110. </div>
  111. );
  112. } else if (noResults) {
  113. ctls =
  114. (
  115. <div className='sidebar--right__subheader'>
  116. <h4>
  117. <FormattedMessage
  118. id='search_results.noResults'
  119. defaultMessage='NO RESULTS'
  120. />
  121. </h4>
  122. <FormattedHTMLMessage
  123. id='search_results.because'
  124. defaultMessage='<ul>
  125. <li>If you&#39;re searching a partial phrase (ex. searching "rea", looking for "reach" or "reaction"), append a * to your search term</li>
  126. <li>Due to the volume of results, two letter searches and common words like "this", "a" and "is" won&#39;t appear in search results</li>
  127. </ul>'
  128. />
  129. </div>
  130. );
  131. } else {
  132. ctls = results.order.map(function mymap(id) {
  133. const post = results.posts[id];
  134. let profile;
  135. if (UserStore.getCurrentId() === post.user_id) {
  136. profile = UserStore.getCurrentUser();
  137. } else {
  138. profile = profiles[post.user_id];
  139. }
  140. return (
  141. <SearchResultsItem
  142. key={post.id}
  143. channel={this.state.channels.get(post.channel_id)}
  144. post={post}
  145. user={profile}
  146. term={searchTerm}
  147. isMentionSearch={this.props.isMentionSearch}
  148. />
  149. );
  150. }, this);
  151. }
  152. return (
  153. <div className='sidebar--right__content'>
  154. <div className='search-bar__container sidebar--right__search-header'>{searchForm}</div>
  155. <div className='sidebar-right__body'>
  156. <SearchResultsHeader isMentionSearch={this.props.isMentionSearch}/>
  157. <div
  158. id='search-items-container'
  159. className='search-items-container'
  160. >
  161. {ctls}
  162. </div>
  163. </div>
  164. </div>
  165. );
  166. }
  167. }
  168. SearchResults.propTypes = {
  169. isMentionSearch: React.PropTypes.bool
  170. };