The code powering m.abunchtell.com https://m.abunchtell.com
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

183 Zeilen
5.2 KiB

  1. import CharacterCounter from './character_counter';
  2. import Button from '../../../components/button';
  3. import PureRenderMixin from 'react-addons-pure-render-mixin';
  4. import ImmutablePropTypes from 'react-immutable-proptypes';
  5. import ReplyIndicator from './reply_indicator';
  6. import UploadButton from './upload_button';
  7. import Autosuggest from 'react-autosuggest';
  8. import AutosuggestAccountContainer from '../../compose/containers/autosuggest_account_container';
  9. import { debounce } from 'react-decoration';
  10. import UploadButtonContainer from '../containers/upload_button_container';
  11. import { injectIntl } from 'react-intl';
  12. const getTokenForSuggestions = (str, caretPosition) => {
  13. let word;
  14. let left = str.slice(0, caretPosition).search(/\S+$/);
  15. let right = str.slice(caretPosition).search(/\s/);
  16. if (right < 0) {
  17. word = str.slice(left);
  18. } else {
  19. word = str.slice(left, right + caretPosition);
  20. }
  21. if (!word || word.trim().length < 2 || word[0] !== '@') {
  22. return null;
  23. }
  24. word = word.trim().toLowerCase().slice(1);
  25. if (word.length > 0) {
  26. return word;
  27. } else {
  28. return null;
  29. }
  30. };
  31. const getSuggestionValue = suggestionId => suggestionId;
  32. const renderSuggestion = suggestionId => <AutosuggestAccountContainer id={suggestionId} />;
  33. const textareaStyle = {
  34. display: 'block',
  35. boxSizing: 'border-box',
  36. width: '100%',
  37. height: '100px',
  38. resize: 'none',
  39. border: 'none',
  40. color: '#282c37',
  41. padding: '10px',
  42. fontFamily: 'Roboto',
  43. fontSize: '14px',
  44. margin: '0'
  45. };
  46. const renderInputComponent = inputProps => (
  47. <textarea {...inputProps} placeholder='What is on your mind?' className='compose-form__textarea' style={textareaStyle} />
  48. );
  49. const ComposeForm = React.createClass({
  50. propTypes: {
  51. text: React.PropTypes.string.isRequired,
  52. suggestion_token: React.PropTypes.string,
  53. suggestions: React.PropTypes.array,
  54. is_submitting: React.PropTypes.bool,
  55. is_uploading: React.PropTypes.bool,
  56. in_reply_to: ImmutablePropTypes.map,
  57. onChange: React.PropTypes.func.isRequired,
  58. onSubmit: React.PropTypes.func.isRequired,
  59. onCancelReply: React.PropTypes.func.isRequired,
  60. onClearSuggestions: React.PropTypes.func.isRequired,
  61. onFetchSuggestions: React.PropTypes.func.isRequired,
  62. onSuggestionSelected: React.PropTypes.func.isRequired
  63. },
  64. mixins: [PureRenderMixin],
  65. handleChange (e) {
  66. if (typeof e.target.value === 'undefined' || typeof e.target.value === 'number') {
  67. return;
  68. }
  69. this.props.onChange(e.target.value);
  70. },
  71. handleKeyUp (e) {
  72. if (e.keyCode === 13 && e.ctrlKey) {
  73. this.props.onSubmit();
  74. }
  75. },
  76. handleSubmit () {
  77. this.props.onSubmit();
  78. },
  79. componentDidUpdate (prevProps) {
  80. if (prevProps.text !== this.props.text || prevProps.in_reply_to !== this.props.in_reply_to) {
  81. const textarea = this.autosuggest.input;
  82. if (textarea) {
  83. textarea.focus();
  84. }
  85. }
  86. },
  87. onSuggestionsClearRequested () {
  88. this.props.onClearSuggestions();
  89. },
  90. @debounce(500)
  91. onSuggestionsFetchRequested ({ value }) {
  92. const textarea = this.autosuggest.input;
  93. if (textarea) {
  94. const token = getTokenForSuggestions(value, textarea.selectionStart);
  95. if (token !== null) {
  96. this.props.onFetchSuggestions(token);
  97. } else {
  98. this.props.onClearSuggestions();
  99. }
  100. }
  101. },
  102. onSuggestionSelected (e, { suggestionValue }) {
  103. const textarea = this.autosuggest.input;
  104. if (textarea) {
  105. this.props.onSuggestionSelected(textarea.selectionStart, suggestionValue);
  106. }
  107. },
  108. setRef (c) {
  109. this.autosuggest = c;
  110. },
  111. render () {
  112. const { intl } = this.props;
  113. let replyArea = '';
  114. const disabled = this.props.is_submitting || this.props.is_uploading;
  115. if (this.props.in_reply_to) {
  116. replyArea = <ReplyIndicator status={this.props.in_reply_to} onCancel={this.props.onCancelReply} />;
  117. }
  118. const inputProps = {
  119. placeholder: intl.formatMessage({ id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' }),
  120. value: this.props.text,
  121. onKeyUp: this.handleKeyUp,
  122. onChange: this.handleChange,
  123. disabled: disabled
  124. };
  125. return (
  126. <div style={{ padding: '10px' }}>
  127. {replyArea}
  128. <Autosuggest
  129. ref={this.setRef}
  130. suggestions={this.props.suggestions}
  131. focusFirstSuggestion={true}
  132. onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
  133. onSuggestionsClearRequested={this.onSuggestionsClearRequested}
  134. onSuggestionSelected={this.onSuggestionSelected}
  135. getSuggestionValue={getSuggestionValue}
  136. renderSuggestion={renderSuggestion}
  137. renderInputComponent={renderInputComponent}
  138. inputProps={inputProps}
  139. />
  140. <div style={{ marginTop: '10px', overflow: 'hidden' }}>
  141. <div style={{ float: 'right' }}><Button text={intl.formatMessage({ id: 'compose_form.publish', defaultMessage: 'Publish' })} onClick={this.handleSubmit} disabled={disabled} /></div>
  142. <div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={this.props.text} /></div>
  143. <UploadButtonContainer style={{ paddingTop: '4px' }} />
  144. </div>
  145. </div>
  146. );
  147. }
  148. });
  149. export default injectIntl(ComposeForm);