diff options
Diffstat (limited to 'src/components/emoji-input/emoji-input.js')
| -rw-r--r-- | src/components/emoji-input/emoji-input.js | 250 |
1 files changed, 0 insertions, 250 deletions
diff --git a/src/components/emoji-input/emoji-input.js b/src/components/emoji-input/emoji-input.js deleted file mode 100644 index fab64a69..00000000 --- a/src/components/emoji-input/emoji-input.js +++ /dev/null @@ -1,250 +0,0 @@ -import Completion from '../../services/completion/completion.js' -import { take } from 'lodash' - -/** - * EmojiInput - augmented inputs for emoji and autocomplete support in inputs - * without having to give up the comfort of <input/> and <textarea/> elements - * - * Intended usage is: - * <EmojiInput v-model="something"> - * <input v-model="something"/> - * </EmojiInput> - * - * Works only with <input> and <textarea>. Intended to use with only one nested - * input. It will find first input or textarea and work with that, multiple - * nested children not tested. You HAVE TO duplicate v-model for both - * <emoji-input> and <input>/<textarea> otherwise it will not work. - * - * Be prepared for CSS troubles though because it still wraps component in a div - * while TRYING to make it look like nothing happened, but it could break stuff. - */ - -const EmojiInput = { - props: { - suggest: { - /** - * suggest: function (input: String) => Suggestion[] - * - * Function that takes input string which takes string (textAtCaret) - * and returns an array of Suggestions - * - * Suggestion is an object containing following properties: - * displayText: string. Main display text, what actual suggestion - * represents (user's screen name/emoji shortcode) - * replacement: string. Text that should replace the textAtCaret - * detailText: string, optional. Subtitle text, providing additional info - * if present (user's nickname) - * imageUrl: string, optional. Image to display alongside with suggestion, - * currently if no image is provided, replacement will be used (for - * unicode emojis) - * - * TODO: make it asynchronous when adding proper server-provided user - * suggestions - * - * For commonly used suggestors (emoji, users, both) use suggestor.js - */ - required: true, - type: Function - }, - value: { - /** - * Used for v-model - */ - required: true, - type: String - } - }, - data () { - return { - input: undefined, - highlighted: 0, - caret: 0, - focused: false, - blurTimeout: null - } - }, - computed: { - suggestions () { - const firstchar = this.textAtCaret.charAt(0) - if (this.textAtCaret === firstchar) { return [] } - const matchedSuggestions = this.suggest(this.textAtCaret) - if (matchedSuggestions.length <= 0) { - return [] - } - return take(matchedSuggestions, 5) - .map(({ imageUrl, ...rest }, index) => ({ - ...rest, - // eslint-disable-next-line camelcase - img: imageUrl || '', - highlighted: index === this.highlighted - })) - }, - showPopup () { - return this.focused && this.suggestions && this.suggestions.length > 0 - }, - textAtCaret () { - return (this.wordAtCaret || {}).word || '' - }, - wordAtCaret () { - if (this.value && this.caret) { - const word = Completion.wordAtPosition(this.value, this.caret - 1) || {} - return word - } - } - }, - mounted () { - const slots = this.$slots.default - if (!slots || slots.length === 0) return - const input = slots.find(slot => ['input', 'textarea'].includes(slot.tag)) - if (!input) return - this.input = input - this.resize() - input.elm.addEventListener('blur', this.onBlur) - input.elm.addEventListener('focus', this.onFocus) - input.elm.addEventListener('paste', this.onPaste) - input.elm.addEventListener('keyup', this.onKeyUp) - input.elm.addEventListener('keydown', this.onKeyDown) - input.elm.addEventListener('transitionend', this.onTransition) - input.elm.addEventListener('compositionupdate', this.onCompositionUpdate) - }, - unmounted () { - const { input } = this - if (input) { - input.elm.removeEventListener('blur', this.onBlur) - input.elm.removeEventListener('focus', this.onFocus) - input.elm.removeEventListener('paste', this.onPaste) - input.elm.removeEventListener('keyup', this.onKeyUp) - input.elm.removeEventListener('keydown', this.onKeyDown) - input.elm.removeEventListener('transitionend', this.onTransition) - input.elm.removeEventListener('compositionupdate', this.onCompositionUpdate) - } - }, - methods: { - replace (replacement) { - const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement) - this.$emit('input', newValue) - this.caret = 0 - }, - replaceText (e, suggestion) { - const len = this.suggestions.length || 0 - if (this.textAtCaret.length === 1) { return } - if (len > 0 || suggestion) { - const chosenSuggestion = suggestion || this.suggestions[this.highlighted] - const replacement = chosenSuggestion.replacement - const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement) - this.$emit('input', newValue) - this.highlighted = 0 - const position = this.wordAtCaret.start + replacement.length - - this.$nextTick(function () { - // Re-focus inputbox after clicking suggestion - this.input.elm.focus() - // Set selection right after the replacement instead of the very end - this.input.elm.setSelectionRange(position, position) - this.caret = position - }) - e.preventDefault() - } - }, - cycleBackward (e) { - const len = this.suggestions.length || 0 - if (len > 0) { - this.highlighted -= 1 - if (this.highlighted < 0) { - this.highlighted = this.suggestions.length - 1 - } - e.preventDefault() - } else { - this.highlighted = 0 - } - }, - cycleForward (e) { - const len = this.suggestions.length || 0 - if (len > 0) { - this.highlighted += 1 - if (this.highlighted >= len) { - this.highlighted = 0 - } - e.preventDefault() - } else { - this.highlighted = 0 - } - }, - onTransition (e) { - this.resize() - }, - onBlur (e) { - // Clicking on any suggestion removes focus from autocomplete, - // preventing click handler ever executing. - this.blurTimeout = setTimeout(() => { - this.focused = false - this.setCaret(e) - this.resize() - }, 200) - }, - onClick (e, suggestion) { - this.replaceText(e, suggestion) - }, - onFocus (e) { - if (this.blurTimeout) { - clearTimeout(this.blurTimeout) - this.blurTimeout = null - } - - this.focused = true - this.setCaret(e) - this.resize() - }, - onKeyUp (e) { - this.setCaret(e) - this.resize() - }, - onPaste (e) { - this.setCaret(e) - this.resize() - }, - onKeyDown (e) { - this.setCaret(e) - this.resize() - - const { ctrlKey, shiftKey, key } = e - if (key === 'Tab') { - if (shiftKey) { - this.cycleBackward(e) - } else { - this.cycleForward(e) - } - } - if (key === 'ArrowUp') { - this.cycleBackward(e) - } else if (key === 'ArrowDown') { - this.cycleForward(e) - } - if (key === 'Enter') { - if (!ctrlKey) { - this.replaceText(e) - } - } - }, - onInput (e) { - this.setCaret(e) - this.$emit('input', e.target.value) - }, - onCompositionUpdate (e) { - this.setCaret(e) - this.resize() - this.$emit('input', e.target.value) - }, - setCaret ({ target: { selectionStart } }) { - this.caret = selectionStart - }, - resize () { - const { panel } = this.$refs - if (!panel) return - const { offsetHeight, offsetTop } = this.input.elm - this.$refs.panel.style.top = (offsetTop + offsetHeight) + 'px' - } - } -} - -export default EmojiInput |
