diff options
Diffstat (limited to 'app/javascript/mastodon/components/autosuggest_textarea.js')
-rw-r--r-- | app/javascript/mastodon/components/autosuggest_textarea.js | 66 |
1 files changed, 24 insertions, 42 deletions
diff --git a/app/javascript/mastodon/components/autosuggest_textarea.js b/app/javascript/mastodon/components/autosuggest_textarea.js index 1c7ffe196..6f725885d 100644 --- a/app/javascript/mastodon/components/autosuggest_textarea.js +++ b/app/javascript/mastodon/components/autosuggest_textarea.js @@ -1,11 +1,12 @@ import React from 'react'; import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container'; -import AutosuggestShortcode from '../features/compose/components/autosuggest_shortcode'; +import AutosuggestEmoji from './autosuggest_emoji'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import { isRtl } from '../rtl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import Textarea from 'react-textarea-autosize'; +import classNames from 'classnames'; const textAtCursorMatchesToken = (str, caretPosition) => { let word; @@ -19,12 +20,11 @@ const textAtCursorMatchesToken = (str, caretPosition) => { word = str.slice(left, right + caretPosition); } - if (!word || word.trim().length < 2 || ['@', ':', '#'].indexOf(word[0]) === -1) { + if (!word || word.trim().length < 3 || ['@', ':'].indexOf(word[0]) === -1) { return [null, null]; } word = word.trim().toLowerCase(); - // was: .slice(1); - we leave the leading char there, handler can decide what to do based on it if (word.length > 0) { return [left + 1, word]; @@ -43,7 +43,6 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { onSuggestionSelected: PropTypes.func.isRequired, onSuggestionsClearRequested: PropTypes.func.isRequired, onSuggestionsFetchRequested: PropTypes.func.isRequired, - onLocalSuggestionsFetchRequested: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, onKeyUp: PropTypes.func, onKeyDown: PropTypes.func, @@ -67,13 +66,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { if (token !== null && this.state.lastToken !== token) { this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart }); - if (token[0] === ':') { - // faster debounce for shortcodes. - // hashtags have long debounce because they're fetched from server. - this.props.onLocalSuggestionsFetchRequested(token); - } else { - this.props.onSuggestionsFetchRequested(token); - } + this.props.onSuggestionsFetchRequested(token); } else if (token === null) { this.setState({ lastToken: null }); this.props.onSuggestionsClearRequested(); @@ -137,9 +130,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { } onSuggestionClick = (e) => { - // leave suggestion string unchanged if it's a hash / shortcode suggestion. convert account number to int. - const suggestionStr = e.currentTarget.getAttribute('data-index'); - const suggestion = [':', '#'].indexOf(suggestionStr[0]) !== -1 ? suggestionStr : Number(suggestionStr); + const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index')); e.preventDefault(); this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion); this.textarea.focus(); @@ -162,36 +153,39 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { } } - componentDidUpdate () { - if (this.refs.selected) { - if (this.refs.selected.scrollIntoViewIfNeeded) - this.refs.selected.scrollIntoViewIfNeeded(); - else - this.refs.selected.scrollIntoView({ behavior: 'auto', block: 'nearest' }); + renderSuggestion = (suggestion, i) => { + const { selectedSuggestion } = this.state; + let inner, key; + + if (typeof suggestion === 'object') { + inner = <AutosuggestEmoji emoji={suggestion} />; + key = suggestion.id; + } else { + inner = <AutosuggestAccountContainer id={suggestion} />; + key = suggestion; } + + return ( + <div role='button' tabIndex='0' key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}> + {inner} + </div> + ); } render () { const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus } = this.props; - const { suggestionsHidden, selectedSuggestion } = this.state; + const { suggestionsHidden } = this.state; const style = { direction: 'ltr' }; if (isRtl(value)) { style.direction = 'rtl'; } - let makeItem = (suggestion) => { - if (suggestion[0] === ':') return <AutosuggestShortcode shortcode={suggestion} />; - if (suggestion[0] === '#') return suggestion; // hashtag - - // else - accounts are always returned as IDs with no prefix - return <AutosuggestAccountContainer id={suggestion} />; - }; - return ( <div className='autosuggest-textarea'> <label> <span style={{ display: 'none' }}>{placeholder}</span> + <Textarea inputRef={this.setTextarea} className='autosuggest-textarea__textarea' @@ -209,19 +203,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { </label> <div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}> - {suggestions.map((suggestion, i) => ( - <div - ref={i === selectedSuggestion ? 'selected' : null} - role='button' - tabIndex='0' - key={suggestion} - data-index={suggestion} - className={`autosuggest-textarea__suggestions__item ${i === selectedSuggestion ? 'selected' : ''}`} - onMouseDown={this.onSuggestionClick} - > - {makeItem(suggestion)} - </div> - ))} + {suggestions.map(this.renderSuggestion)} </div> </div> ); |