The code powering m.abunchtell.com https://m.abunchtell.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

125 lines
3.5 KiB

  1. import PureRenderMixin from 'react-addons-pure-render-mixin';
  2. import ImmutablePropTypes from 'react-immutable-proptypes';
  3. import Autosuggest from 'react-autosuggest';
  4. import AutosuggestAccountContainer from '../containers/autosuggest_account_container';
  5. import AutosuggestStatusContainer from '../containers/autosuggest_status_container';
  6. import { debounce } from 'react-decoration';
  7. import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
  8. const messages = defineMessages({
  9. placeholder: { id: 'search.placeholder', defaultMessage: 'Search' }
  10. });
  11. const getSuggestionValue = suggestion => suggestion.value;
  12. const renderSuggestion = suggestion => {
  13. if (suggestion.type === 'account') {
  14. return <AutosuggestAccountContainer id={suggestion.id} />;
  15. } else if (suggestion.type === 'hashtag') {
  16. return <span>#{suggestion.id}</span>;
  17. } else {
  18. return <AutosuggestStatusContainer id={suggestion.id} />;
  19. }
  20. };
  21. const renderSectionTitle = section => (
  22. <strong><FormattedMessage id={`search.${section.title}`} defaultMessage={section.title} /></strong>
  23. );
  24. const getSectionSuggestions = section => section.items;
  25. const outerStyle = {
  26. padding: '10px',
  27. lineHeight: '20px',
  28. position: 'relative'
  29. };
  30. const iconStyle = {
  31. position: 'absolute',
  32. top: '18px',
  33. right: '20px',
  34. fontSize: '18px',
  35. pointerEvents: 'none'
  36. };
  37. const Search = React.createClass({
  38. contextTypes: {
  39. router: React.PropTypes.object
  40. },
  41. propTypes: {
  42. suggestions: React.PropTypes.array.isRequired,
  43. value: React.PropTypes.string.isRequired,
  44. onChange: React.PropTypes.func.isRequired,
  45. onClear: React.PropTypes.func.isRequired,
  46. onFetch: React.PropTypes.func.isRequired,
  47. onReset: React.PropTypes.func.isRequired,
  48. intl: React.PropTypes.object.isRequired
  49. },
  50. mixins: [PureRenderMixin],
  51. onChange (_, { newValue }) {
  52. if (typeof newValue !== 'string') {
  53. return;
  54. }
  55. this.props.onChange(newValue);
  56. },
  57. onSuggestionsClearRequested () {
  58. this.props.onClear();
  59. },
  60. @debounce(500)
  61. onSuggestionsFetchRequested ({ value }) {
  62. value = value.replace('#', '');
  63. this.props.onFetch(value.trim());
  64. },
  65. onSuggestionSelected (_, { suggestion }) {
  66. if (suggestion.type === 'account') {
  67. this.context.router.push(`/accounts/${suggestion.id}`);
  68. } else if(suggestion.type === 'hashtag') {
  69. this.context.router.push(`/timelines/tag/${suggestion.id}`);
  70. } else {
  71. this.context.router.push(`/statuses/${suggestion.id}`);
  72. }
  73. },
  74. render () {
  75. const inputProps = {
  76. placeholder: this.props.intl.formatMessage(messages.placeholder),
  77. value: this.props.value,
  78. onChange: this.onChange,
  79. className: 'search__input'
  80. };
  81. return (
  82. <div className='search' style={outerStyle}>
  83. <Autosuggest
  84. multiSection={true}
  85. suggestions={this.props.suggestions}
  86. focusFirstSuggestion={true}
  87. focusInputOnSuggestionClick={false}
  88. alwaysRenderSuggestions={false}
  89. onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
  90. onSuggestionsClearRequested={this.onSuggestionsClearRequested}
  91. onSuggestionSelected={this.onSuggestionSelected}
  92. getSuggestionValue={getSuggestionValue}
  93. renderSuggestion={renderSuggestion}
  94. renderSectionTitle={renderSectionTitle}
  95. getSectionSuggestions={getSectionSuggestions}
  96. inputProps={inputProps}
  97. />
  98. <div style={iconStyle}><i className='fa fa-search' /></div>
  99. </div>
  100. );
  101. },
  102. });
  103. export default injectIntl(Search);