Skip to content
Extraits de code Groupes Projets
autosuggest_textarea.js 5,63 ko
Newer Older
  • Learn to ignore specific revisions
  • import React from 'react';
    
    import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
    import ImmutablePropTypes from 'react-immutable-proptypes';
    
    import PropTypes from 'prop-types';
    
    import ImmutablePureComponent from 'react-immutable-pure-component';
    
    import Textarea from 'react-textarea-autosize';
    
    
    const textAtCursorMatchesToken = (str, caretPosition) => {
      let word;
    
      let left  = str.slice(0, caretPosition).search(/\S+$/);
      let right = str.slice(caretPosition).search(/\s/);
    
      if (right < 0) {
        word = str.slice(left);
      } else {
        word = str.slice(left, right + caretPosition);
      }
    
      if (!word || word.trim().length < 2 || word[0] !== '@') {
        return [null, null];
      }
    
      word = word.trim().toLowerCase().slice(1);
    
      if (word.length > 0) {
        return [left + 1, word];
      } else {
        return [null, null];
      }
    };
    
    
    export default class AutosuggestTextarea extends ImmutablePureComponent {
    
      static propTypes = {
        value: PropTypes.string,
        suggestions: ImmutablePropTypes.list,
        disabled: PropTypes.bool,
        placeholder: PropTypes.string,
        onSuggestionSelected: PropTypes.func.isRequired,
        onSuggestionsClearRequested: PropTypes.func.isRequired,
        onSuggestionsFetchRequested: PropTypes.func.isRequired,
        onChange: PropTypes.func.isRequired,
        onKeyUp: PropTypes.func,
        onKeyDown: PropTypes.func,
        onPaste: PropTypes.func.isRequired,
    
        autoFocus: PropTypes.bool,
    
        autoFocus: true,
    
      state = {
        suggestionsHidden: false,
        selectedSuggestion: 0,
        lastToken: null,
        tokenStart: 0,
      };
    
      onChange = (e) => {
    
        const [ tokenStart, token ] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart);
    
    
        if (token !== null && this.state.lastToken !== token) {
    
          this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart });
          this.props.onSuggestionsFetchRequested(token);
    
          this.setState({ lastToken: null });
          this.props.onSuggestionsClearRequested();
        }
    
        this.props.onChange(e);
    
      onKeyDown = (e) => {
    
        const { suggestions, disabled } = this.props;
        const { selectedSuggestion, suggestionsHidden } = this.state;
    
        if (disabled) {
          e.preventDefault();
          return;
        }
    
        switch(e.key) {
    
        case 'Escape':
          if (!suggestionsHidden) {
            e.preventDefault();
            this.setState({ suggestionsHidden: true });
          }
    
          break;
        case 'ArrowDown':
          if (suggestions.size > 0 && !suggestionsHidden) {
            e.preventDefault();
            this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
          }
    
          break;
        case 'ArrowUp':
          if (suggestions.size > 0 && !suggestionsHidden) {
            e.preventDefault();
            this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
          }
    
          break;
        case 'Enter':
        case 'Tab':
          // Select suggestion
          if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
            e.preventDefault();
            e.stopPropagation();
            this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
          }
    
          break;
    
    
        if (e.defaultPrevented || !this.props.onKeyDown) {
          return;
        }
    
        this.props.onKeyDown(e);
    
        this.setState({ suggestionsHidden: true });
    
      onSuggestionClick = (e) => {
    
        const suggestion = Number(e.currentTarget.getAttribute('data-index'));
    
        e.preventDefault();
        this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);
    
        this.textarea.focus();
    
    
      componentWillReceiveProps (nextProps) {
        if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) {
          this.setState({ suggestionsHidden: false });
        }
    
      setTextarea = (c) => {
    
      onPaste = (e) => {
    
        if (e.clipboardData && e.clipboardData.files.length === 1) {
    
          this.props.onPaste(e.clipboardData.files);
    
          e.preventDefault();
        }
    
        const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus } = this.props;
    
        const { suggestionsHidden, selectedSuggestion } = this.state;
    
        const style = { direction: 'ltr' };
    
    
        return (
          <div className='autosuggest-textarea'>
    
            <label>
              <span style={{ display: 'none' }}>{placeholder}</span>
              <Textarea
                inputRef={this.setTextarea}
                className='autosuggest-textarea__textarea'
                disabled={disabled}
                placeholder={placeholder}
                autoFocus={autoFocus}
                value={value}
                onChange={this.onChange}
                onKeyDown={this.onKeyDown}
                onKeyUp={onKeyUp}
                onBlur={this.onBlur}
                onPaste={this.onPaste}
                style={style}
              />
            </label>
    
            <div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
    
              {suggestions.map((suggestion, i) => (
    
                <div
                  role='button'
                  tabIndex='0'
                  key={suggestion}
    
                  data-index={suggestion}
    
                  className={`autosuggest-textarea__suggestions__item ${i === selectedSuggestion ? 'selected' : ''}`}
    
                  <AutosuggestAccountContainer id={suggestion} />
                </div>
              ))}
            </div>
          </div>
        );
      }