Revert "Merge branch 'fix/no-autocomplete-in-non-post-forms' into 'develop'" See merge request pleroma/pleroma-fe!582feature/image-description-authoring
commit
8625a612cd
@ -1,150 +0,0 @@
|
|||||||
import Completion from '../../services/completion/completion.js'
|
|
||||||
import { take, filter, map } from 'lodash'
|
|
||||||
|
|
||||||
const AutoCompleteInput = {
|
|
||||||
props: [
|
|
||||||
'id',
|
|
||||||
'classObj',
|
|
||||||
'value',
|
|
||||||
'placeholder',
|
|
||||||
'autoResize',
|
|
||||||
'multiline',
|
|
||||||
'drop',
|
|
||||||
'dragoverPrevent',
|
|
||||||
'paste',
|
|
||||||
'keydownMetaEnter',
|
|
||||||
'keyupCtrlEnter'
|
|
||||||
],
|
|
||||||
components: {},
|
|
||||||
mounted () {
|
|
||||||
this.autoResize && this.resize(this.$refs.textarea)
|
|
||||||
const textLength = this.$refs.textarea.value.length
|
|
||||||
this.$refs.textarea.setSelectionRange(textLength, textLength)
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
caret: 0,
|
|
||||||
highlighted: 0,
|
|
||||||
text: this.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
users () {
|
|
||||||
return this.$store.state.users.users
|
|
||||||
},
|
|
||||||
emoji () {
|
|
||||||
return this.$store.state.instance.emoji || []
|
|
||||||
},
|
|
||||||
customEmoji () {
|
|
||||||
return this.$store.state.instance.customEmoji || []
|
|
||||||
},
|
|
||||||
textAtCaret () {
|
|
||||||
return (this.wordAtCaret || {}).word || ''
|
|
||||||
},
|
|
||||||
wordAtCaret () {
|
|
||||||
const word = Completion.wordAtPosition(this.text, this.caret - 1) || {}
|
|
||||||
return word
|
|
||||||
},
|
|
||||||
candidates () {
|
|
||||||
const firstchar = this.textAtCaret.charAt(0)
|
|
||||||
if (firstchar === '@') {
|
|
||||||
const query = this.textAtCaret.slice(1).toUpperCase()
|
|
||||||
const matchedUsers = filter(this.users, (user) => {
|
|
||||||
return user.screen_name.toUpperCase().startsWith(query) ||
|
|
||||||
user.name && user.name.toUpperCase().startsWith(query)
|
|
||||||
})
|
|
||||||
if (matchedUsers.length <= 0) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
return map(take(matchedUsers, 5), ({screen_name, name, profile_image_url_original}, index) => ({
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
screen_name: `@${screen_name}`,
|
|
||||||
name: name,
|
|
||||||
img: profile_image_url_original,
|
|
||||||
highlighted: index === this.highlighted
|
|
||||||
}))
|
|
||||||
} else if (firstchar === ':') {
|
|
||||||
if (this.textAtCaret === ':') { return }
|
|
||||||
const matchedEmoji = filter(this.emoji.concat(this.customEmoji), (emoji) => emoji.shortcode.startsWith(this.textAtCaret.slice(1)))
|
|
||||||
if (matchedEmoji.length <= 0) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return map(take(matchedEmoji, 5), ({shortcode, image_url, utf}, index) => ({
|
|
||||||
screen_name: `:${shortcode}:`,
|
|
||||||
name: '',
|
|
||||||
utf: utf || '',
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
img: utf ? '' : this.$store.state.instance.server + image_url,
|
|
||||||
highlighted: index === this.highlighted
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
setCaret ({target: {selectionStart}}) {
|
|
||||||
this.caret = selectionStart
|
|
||||||
},
|
|
||||||
cycleBackward (e) {
|
|
||||||
const len = this.candidates.length || 0
|
|
||||||
if (len > 0) {
|
|
||||||
e.preventDefault()
|
|
||||||
this.highlighted -= 1
|
|
||||||
if (this.highlighted < 0) {
|
|
||||||
this.highlighted = this.candidates.length - 1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.highlighted = 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cycleForward (e) {
|
|
||||||
const len = this.candidates.length || 0
|
|
||||||
if (len > 0) {
|
|
||||||
if (e.shiftKey) { return }
|
|
||||||
e.preventDefault()
|
|
||||||
this.highlighted += 1
|
|
||||||
if (this.highlighted >= len) {
|
|
||||||
this.highlighted = 0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.highlighted = 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
replace (replacement) {
|
|
||||||
this.text = Completion.replaceWord(this.text, this.wordAtCaret, replacement)
|
|
||||||
const el = this.$el.querySelector('textarea')
|
|
||||||
el.focus()
|
|
||||||
this.caret = 0
|
|
||||||
},
|
|
||||||
replaceCandidate (e) {
|
|
||||||
const len = this.candidates.length || 0
|
|
||||||
if (this.textAtCaret === ':' || e.ctrlKey) { return }
|
|
||||||
if (len > 0) {
|
|
||||||
e.preventDefault()
|
|
||||||
const candidate = this.candidates[this.highlighted]
|
|
||||||
const replacement = candidate.utf || (candidate.screen_name + ' ')
|
|
||||||
this.text = Completion.replaceWord(this.text, this.wordAtCaret, replacement)
|
|
||||||
const el = this.$el.querySelector('textarea') || this.$el.querySelector('input')
|
|
||||||
el.focus()
|
|
||||||
this.caret = 0
|
|
||||||
this.highlighted = 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
resize (e) {
|
|
||||||
const target = e.target || e
|
|
||||||
if (!(target instanceof window.Element)) { return }
|
|
||||||
const vertPadding = Number(window.getComputedStyle(target)['padding-top'].substr(0, 1)) +
|
|
||||||
Number(window.getComputedStyle(target)['padding-bottom'].substr(0, 1))
|
|
||||||
// Auto is needed to make textbox shrink when removing lines
|
|
||||||
target.style.height = 'auto'
|
|
||||||
target.style.height = `${target.scrollHeight - vertPadding}px`
|
|
||||||
if (target.value === '') {
|
|
||||||
target.style.height = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AutoCompleteInput
|
|
@ -1,104 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div style="display: flex; flex-direction: column;">
|
|
||||||
<textarea
|
|
||||||
v-if="multiline"
|
|
||||||
ref="textarea"
|
|
||||||
rows="1"
|
|
||||||
:value="text" :class="classObj" :id="id" :placeholder="placeholder"
|
|
||||||
@input="text = $event.target.value, $emit('input', $event.target.value), autoResize && resize($event)"
|
|
||||||
@click="setCaret"
|
|
||||||
@keyup="setCaret"
|
|
||||||
@keydown.down="cycleForward"
|
|
||||||
@keydown.up="cycleBackward"
|
|
||||||
@keydown.shift.tab="cycleBackward"
|
|
||||||
@keydown.tab="cycleForward"
|
|
||||||
@keydown.enter="replaceCandidate"
|
|
||||||
@drop="drop && drop()"
|
|
||||||
@dragover.prevent="dragoverPrevent && dragoverPrevent()"
|
|
||||||
@paste="paste && paste()"
|
|
||||||
@keydown.meta.enter="keydownMetaEnter && keydownMetaEnter()"
|
|
||||||
@keyup.ctrl.enter="keyupCtrlEnter && keyupCtrlEnter()">
|
|
||||||
</textarea>
|
|
||||||
<input
|
|
||||||
v-else
|
|
||||||
ref="textarea"
|
|
||||||
:value="text" :class="classObj" :id="id" :placeholder="placeholder"
|
|
||||||
@input="text = $event.target.value, $emit('input', $event.target.value), autoResize && resize($event)"
|
|
||||||
@click="setCaret"
|
|
||||||
@keyup="setCaret"
|
|
||||||
@keydown.down="cycleForward"
|
|
||||||
@keydown.up="cycleBackward"
|
|
||||||
@keydown.shift.tab="cycleBackward"
|
|
||||||
@keydown.tab="cycleForward"
|
|
||||||
@keydown.enter="replaceCandidate"
|
|
||||||
@drop="drop && drop()"
|
|
||||||
@dragover.prevent="dragoverPrevent && dragoverPrevent()"
|
|
||||||
@paste="paste && paste()"
|
|
||||||
@keydown.meta.enter="keydownMetaEnter && keydownMetaEnter()"
|
|
||||||
@keyup.ctrl.enter="keyupCtrlEnter && keyupCtrlEnter()"/>
|
|
||||||
<div style="position:relative;" v-if="candidates">
|
|
||||||
<div class="autocomplete-panel">
|
|
||||||
<div v-for="candidate in candidates" @click="replace(candidate.utf || (candidate.screen_name + ' '))">
|
|
||||||
<div class="autocomplete" :class="{ highlighted: candidate.highlighted }">
|
|
||||||
<span v-if="candidate.img"><img :src="candidate.img"></img></span>
|
|
||||||
<span v-else>{{candidate.utf}}</span>
|
|
||||||
<span>{{candidate.screen_name}}<small>{{candidate.name}}</small></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./autocomplete_input.js"></script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import '../../_variables.scss';
|
|
||||||
|
|
||||||
.autocomplete-panel {
|
|
||||||
margin: 0 0.5em 0 0.5em;
|
|
||||||
border-radius: $fallback--tooltipRadius;
|
|
||||||
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1;
|
|
||||||
box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
|
|
||||||
// this doesn't match original but i don't care, making it uniform.
|
|
||||||
box-shadow: var(--popupShadow);
|
|
||||||
min-width: 75%;
|
|
||||||
background: $fallback--bg;
|
|
||||||
background: var(--bg, $fallback--bg);
|
|
||||||
color: $fallback--lightText;
|
|
||||||
color: var(--lightText, $fallback--lightText);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete {
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0.2em 0.4em 0.2em 0.4em;
|
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.4);
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: $fallback--avatarRadius;
|
|
||||||
border-radius: var(--avatarRadius, $fallback--avatarRadius);
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
line-height: 24px;
|
|
||||||
margin: 0 0.1em 0 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
margin-left: .5em;
|
|
||||||
color: $fallback--faint;
|
|
||||||
color: var(--faint, $fallback--faint);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.highlighted {
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--lightBg, $fallback--fg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
Loading…
Reference in new issue