Separate emoji editing and upload into a separate component
Handle all state in that component
This commit is contained in:
parent
aa49838355
commit
8a030d935b
@ -7,8 +7,7 @@ import Select from 'components/select/select.vue'
|
||||
import Popover from 'components/popover/popover.vue'
|
||||
import ConfirmModal from 'components/confirm_modal/confirm_modal.vue'
|
||||
import ModifiedIndicator from '../helpers/modified_indicator.vue'
|
||||
|
||||
const newEmojiUploadBase = { shortcode: '', file: '', upload: [] }
|
||||
import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue'
|
||||
|
||||
const EmojiTab = {
|
||||
components: {
|
||||
@ -19,24 +18,31 @@ const EmojiTab = {
|
||||
Select,
|
||||
Popover,
|
||||
ConfirmModal,
|
||||
ModifiedIndicator
|
||||
ModifiedIndicator,
|
||||
EmojiEditingPopover
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
knownLocalPacks: { },
|
||||
knownRemotePacks: { },
|
||||
editedParts: { },
|
||||
editedMetadata: { },
|
||||
packName: '',
|
||||
newPackName: '',
|
||||
deleteModalVisible: false,
|
||||
newEmojiUpload: clone(newEmojiUploadBase),
|
||||
remotePackInstance: '',
|
||||
remotePackDownloadAs: ''
|
||||
}
|
||||
},
|
||||
|
||||
provide () {
|
||||
return {
|
||||
// Functions
|
||||
emojiAddr: this.emojiAddr,
|
||||
displayError: this.displayError
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
pack () {
|
||||
return this.packName !== '' ? this.knownPacks[this.packName] : undefined
|
||||
@ -58,11 +64,6 @@ const EmojiTab = {
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
newEmojiUploadPreview () {
|
||||
if (this.newEmojiUpload.upload.length > 0) {
|
||||
return URL.createObjectURL(this.newEmojiUpload.upload[0])
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -82,27 +83,6 @@ const EmojiTab = {
|
||||
}
|
||||
},
|
||||
|
||||
uploadEmoji () {
|
||||
this.$refs.addEmojiPopover.hidePopover()
|
||||
|
||||
this.$store.state.api.backendInteractor.addNewEmojiFile({
|
||||
packName: this.packName,
|
||||
file: this.newEmojiUpload.upload[0],
|
||||
shortcode: this.newEmojiUpload.shortcode,
|
||||
filename: this.newEmojiUpload.file
|
||||
}).then(resp => resp.json()).then(resp => {
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return
|
||||
}
|
||||
|
||||
this.pack.files = resp
|
||||
this.sortPackFiles(this.packName)
|
||||
|
||||
this.newEmojiUpload = clone(newEmojiUploadBase)
|
||||
})
|
||||
},
|
||||
|
||||
createEmojiPack () {
|
||||
this.$store.state.api.backendInteractor.createEmojiPack(
|
||||
{ name: this.newPackName }
|
||||
@ -132,7 +112,6 @@ const EmojiTab = {
|
||||
}
|
||||
}).then(done => {
|
||||
delete this.editedMetadata[this.packName]
|
||||
delete this.editedParts[this.packName]
|
||||
|
||||
this.deleteModalVisible = false
|
||||
this.packName = ''
|
||||
@ -162,68 +141,9 @@ const EmojiTab = {
|
||||
})
|
||||
},
|
||||
|
||||
revertEmoji (shortcode) {
|
||||
// Delete current changes and overwrite them with defaults. If the window is closed, they'll get cleared anyway
|
||||
delete this.editedParts[this.packName][shortcode]
|
||||
this.editEmoji(shortcode)
|
||||
},
|
||||
editEmoji (shortcode) {
|
||||
if (this.editedParts[this.packName] === undefined) { this.editedParts[this.packName] = {} }
|
||||
|
||||
if (this.editedParts[this.packName][shortcode] === undefined) {
|
||||
this.editedParts[this.packName][shortcode] = {
|
||||
shortcode, file: this.pack.files[shortcode]
|
||||
}
|
||||
}
|
||||
},
|
||||
deleteEmoji (shortcode) {
|
||||
this.editedParts[this.packName][shortcode].deleteModalVisible = false
|
||||
|
||||
this.$store.state.api.backendInteractor.deleteEmojiFile(
|
||||
{ packName: this.packName, shortcode }
|
||||
).then(resp => resp.json()).then(resp => {
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return
|
||||
}
|
||||
|
||||
this.pack.files = resp
|
||||
delete this.editedParts[this.packName][shortcode]
|
||||
|
||||
this.sortPackFiles(this.packName)
|
||||
})
|
||||
},
|
||||
closedEditedEmoji (shortcode) {
|
||||
const edited = this.editedParts[this.packName][shortcode]
|
||||
|
||||
if (edited.shortcode === shortcode && edited.file === this.pack.files[shortcode]) {
|
||||
delete this.editedParts[this.packName][shortcode]
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
saveEditedEmoji (shortcode) {
|
||||
if (this.closedEditedEmoji(shortcode)) return
|
||||
|
||||
const edited = this.editedParts[this.packName][shortcode]
|
||||
|
||||
this.$store.state.api.backendInteractor.updateEmojiFile(
|
||||
{ packName: this.packName, shortcode, newShortcode: edited.shortcode, newFilename: edited.file, force: false }
|
||||
).then(resp => {
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return Promise.reject(resp.error)
|
||||
}
|
||||
|
||||
return resp.json()
|
||||
}).then(resp => {
|
||||
this.pack.files = resp
|
||||
delete this.editedParts[this.packName][shortcode]
|
||||
|
||||
this.sortPackFiles(this.packName)
|
||||
})
|
||||
updatePackFiles (newFiles) {
|
||||
this.pack.files = newFiles
|
||||
this.sortPackFiles(this.packName)
|
||||
},
|
||||
|
||||
loadPacksPaginated (listFunction) {
|
||||
|
@ -39,17 +39,6 @@
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.emoji-tab-edit-popover {
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
|
||||
.emoji {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.emoji-tab-popover-input {
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
|
@ -97,38 +97,44 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div v-if="packName !== ''">
|
||||
<div v-if="pack">
|
||||
<div class="pack-info-wrapper">
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<div>
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.description') }}
|
||||
<ModifiedIndicator :changed="metaEdited('description')" message-key="admin_dash.emoji.metadata_changed" />
|
||||
</div>
|
||||
<textarea
|
||||
v-model="packMeta.description"
|
||||
:disabled="pack.remote !== undefined"
|
||||
class="bio resize-height" />
|
||||
|
||||
<textarea
|
||||
v-model="packMeta.description"
|
||||
:disabled="pack.remote !== undefined"
|
||||
class="bio resize-height" />
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.homepage') }}
|
||||
<ModifiedIndicator :changed="metaEdited('homepage')" message-key="admin_dash.emoji.metadata_changed" />
|
||||
</div>
|
||||
|
||||
<input
|
||||
class="emoji-info-input" v-model="packMeta.homepage"
|
||||
:disabled="pack.remote !== undefined">
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.fallback_src') }}
|
||||
<ModifiedIndicator :changed="metaEdited('fallback-src')" message-key="admin_dash.emoji.metadata_changed" />
|
||||
</div>
|
||||
<input class="emoji-info-input" v-model="packMeta['fallback-src']" :disabled="pack.remote !== undefined">
|
||||
|
||||
<input class="emoji-info-input" v-model="packMeta['fallback-src']" :disabled="pack.remote !== undefined">
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<div>{{ $t('admin_dash.emoji.fallback_sha256') }}</div>
|
||||
<input :disabled="true" class="emoji-info-input" v-model="packMeta['fallback-src-sha256']">
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.fallback_sha256') }}
|
||||
|
||||
<input :disabled="true" class="emoji-info-input" v-model="packMeta['fallback-src-sha256']">
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox :disabled="pack.remote !== undefined" v-model="packMeta['share-files']">
|
||||
@ -218,132 +224,30 @@
|
||||
{{ $t('admin_dash.emoji.files') }}
|
||||
|
||||
<ModifiedIndicator v-if="pack"
|
||||
:changed="editedParts[packName] && Object.keys(editedParts[packName]).length > 0"
|
||||
:changed="$refs.emojiPopovers && $refs.emojiPopovers.some(p => p.isEdited)"
|
||||
message-key="admin_dash.emoji.emoji_changed"/>
|
||||
</h4>
|
||||
|
||||
<div class="emoji-list" v-if="pack">
|
||||
<Popover
|
||||
<EmojiEditingPopover
|
||||
v-if="pack.remote === undefined"
|
||||
ref="addEmojiPopover"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
bound-to-selector=".emoji-tab"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
placement="bottom" new-upload
|
||||
:title="$t('admin_dash.emoji.adding_new')"
|
||||
:packName="packName" @updatePackFiles="updatePackFiles"
|
||||
>
|
||||
<template #trigger>
|
||||
<FAIcon icon="plus" size="2x" :title="$t('admin_dash.emoji.add_file')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<h3>
|
||||
{{ $t('admin_dash.emoji.adding_new') }}
|
||||
</h3>
|
||||
</EmojiEditingPopover>
|
||||
|
||||
<StillImage
|
||||
class="emoji" v-if="newEmojiUploadPreview"
|
||||
:src="newEmojiUploadPreview"
|
||||
/>
|
||||
<div v-else class="emoji"></div>
|
||||
|
||||
<div class="emoji-tab-popover-input">
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
class="emoji-tab-popover-file"
|
||||
@change="newEmojiUpload.upload = $event.target.files"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<div>{{ $t('admin_dash.emoji.shortcode') }}</div>
|
||||
<input class="emoji-data-input"
|
||||
v-model="newEmojiUpload.shortcode"
|
||||
:placeholder="$t('admin_dash.emoji.new_shortcode')">
|
||||
</div>
|
||||
|
||||
<div class="emoji-tab-popover-input">
|
||||
<div>{{ $t('admin_dash.emoji.filename') }}</div>
|
||||
<input class="emoji-data-input"
|
||||
v-model="newEmojiUpload.file"
|
||||
:placeholder="$t('admin_dash.emoji.new_filename')">
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
:disabled="this.newEmojiUpload.upload.length == 0"
|
||||
@click="uploadEmoji">
|
||||
{{ $t('admin_dash.emoji.save') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
|
||||
<Popover
|
||||
<EmojiEditingPopover
|
||||
placement="top" ref="emojiPopovers"
|
||||
v-for="(file, shortcode) in pack.files" :key="shortcode"
|
||||
trigger="click"
|
||||
:title="$t('admin_dash.emoji.editing', [shortcode])"
|
||||
:disabled="pack.remote !== undefined"
|
||||
placement="top"
|
||||
:class="{'emoji-unsaved': editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined}"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
bound-to-selector=".emoji-list"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
@show="editEmoji(shortcode)"
|
||||
@close="closedEditedEmoji(shortcode)"
|
||||
:shortcode="shortcode" :file="file" :packName="packName"
|
||||
@updatePackFiles="updatePackFiles"
|
||||
>
|
||||
<template #content>
|
||||
<h3>
|
||||
{{ $t('admin_dash.emoji.editing', [shortcode]) }}
|
||||
</h3>
|
||||
|
||||
<StillImage class="emoji" :src="emojiAddr(file)" />
|
||||
|
||||
<div v-if="editedParts[packName] !== undefined && editedParts[packName][shortcode] !== undefined">
|
||||
<div class="emoji-tab-popover-input">
|
||||
<label for="emoji-edit-shortcode">{{ $t('admin_dash.emoji.shortcode') }}</label>
|
||||
<input id="emoji-edit-shortcode" class="emoji-data-input"
|
||||
v-model="editedParts[packName][shortcode].shortcode">
|
||||
</div>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<label for="emoji-edit-filename">{{ $t('admin_dash.emoji.filename') }}</label>
|
||||
<input id="emoji-edit-filename" class="emoji-data-input"
|
||||
v-model="editedParts[packName][shortcode].file">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="saveEditedEmoji(shortcode)">
|
||||
{{ $t('admin_dash.emoji.save') }}
|
||||
</button>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="editedParts[packName][shortcode].deleteModalVisible = true">
|
||||
{{ $t('admin_dash.emoji.delete') }}
|
||||
</button>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="revertEmoji(shortcode)">
|
||||
{{ $t('admin_dash.emoji.revert') }}
|
||||
</button>
|
||||
<ConfirmModal
|
||||
v-if="editedParts[packName][shortcode].deleteModalVisible"
|
||||
:title="$t('admin_dash.emoji.delete_title')"
|
||||
:cancel-text="$t('status.delete_confirm_cancel_button')"
|
||||
:confirm-text="$t('status.delete_confirm_accept_button')"
|
||||
@cancelled="editedParts[packName][shortcode].deleteModalVisible = false"
|
||||
@accepted="deleteEmoji(shortcode)" >
|
||||
{{ $t('admin_dash.emoji.delete_confirm', [shortcode]) }}
|
||||
</ConfirmModal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #trigger>
|
||||
<StillImage
|
||||
class="emoji"
|
||||
@ -352,7 +256,7 @@
|
||||
:alt="`:${shortcode}:`"
|
||||
/>
|
||||
</template>
|
||||
</Popover>
|
||||
</EmojiEditingPopover>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
|
207
src/components/settings_modal/helpers/emoji_editing_popover.vue
Normal file
207
src/components/settings_modal/helpers/emoji_editing_popover.vue
Normal file
@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<Popover
|
||||
trigger="click"
|
||||
:placement="placement"
|
||||
bound-to-selector=".emoji-list"
|
||||
popover-class="emoji-tab-edit-popover popover-default"
|
||||
ref="emojiPopover"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:offset="{ y: 5 }"
|
||||
:disabled="disabled"
|
||||
:class="{'emoji-unsaved': isEdited}"
|
||||
>
|
||||
<template #trigger>
|
||||
<slot name="trigger" />
|
||||
</template>
|
||||
<template #content>
|
||||
<h3>
|
||||
{{ title }}
|
||||
</h3>
|
||||
|
||||
<StillImage class="emoji" v-if="emojiPreview" :src="emojiPreview" />
|
||||
<div v-else class="emoji"></div>
|
||||
|
||||
<div class="emoji-tab-popover-input" v-if="newUpload">
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
class="emoji-tab-popover-file"
|
||||
@change="uploadFile = $event.target.files">
|
||||
</div>
|
||||
<div>
|
||||
<div class="emoji-tab-popover-input">
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.shortcode') }}
|
||||
<input class="emoji-data-input"
|
||||
v-model="editedShortcode"
|
||||
:placeholder="$t('admin_dash.emoji.new_shortcode')">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="emoji-tab-popover-input">
|
||||
<label>
|
||||
{{ $t('admin_dash.emoji.filename') }}
|
||||
|
||||
<input class="emoji-data-input"
|
||||
v-model="editedFile"
|
||||
:placeholder="$t('admin_dash.emoji.new_filename')">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="button button-default btn"
|
||||
type="button"
|
||||
:disabled="uploadFile.length == 0"
|
||||
@click="newUpload ? uploadEmoji() : saveEditedEmoji()">
|
||||
{{ $t('admin_dash.emoji.save') }}
|
||||
</button>
|
||||
|
||||
<template v-if="!newUpload">
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="deleteModalVisible = true">
|
||||
{{ $t('admin_dash.emoji.delete') }}
|
||||
</button>
|
||||
<button
|
||||
class="button button-default btn emoji-tab-popover-button"
|
||||
type="button"
|
||||
@click="revertEmoji">
|
||||
{{ $t('admin_dash.emoji.revert') }}
|
||||
</button>
|
||||
<ConfirmModal
|
||||
v-if="deleteModalVisible"
|
||||
:title="$t('admin_dash.emoji.delete_title')"
|
||||
:cancel-text="$t('status.delete_confirm_cancel_button')"
|
||||
:confirm-text="$t('status.delete_confirm_accept_button')"
|
||||
@cancelled="deleteModalVisible = false"
|
||||
@accepted="deleteEmoji" >
|
||||
{{ $t('admin_dash.emoji.delete_confirm', [shortcode]) }}
|
||||
</ConfirmModal>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Popover from 'components/popover/popover.vue'
|
||||
import ConfirmModal from 'components/confirm_modal/confirm_modal.vue'
|
||||
import StillImage from 'components/still-image/still-image.vue'
|
||||
|
||||
export default {
|
||||
components: { Popover, ConfirmModal, StillImage },
|
||||
data () {
|
||||
return {
|
||||
uploadFile: [],
|
||||
editedShortcode: this.shortcode,
|
||||
editedFile: this.file,
|
||||
deleteModalVisible: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
emojiPreview () {
|
||||
if (this.newUpload && this.uploadFile.length > 0) {
|
||||
return URL.createObjectURL(this.uploadFile[0])
|
||||
} else if (!this.newUpload) {
|
||||
return this.emojiAddr(this.file)
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
isEdited () {
|
||||
return !this.newUpload && (this.editedShortcode !== this.shortcode || this.editedFile !== this.file)
|
||||
}
|
||||
},
|
||||
inject: ['emojiAddr', 'displayError'],
|
||||
methods: {
|
||||
saveEditedEmoji () {
|
||||
if (!this.isEdited) return
|
||||
|
||||
this.$store.state.api.backendInteractor.updateEmojiFile(
|
||||
{ packName: this.packName, shortcode: this.shortcode, newShortcode: this.editedShortcode, newFilename: this.editedFile, force: false }
|
||||
).then(resp => {
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return Promise.reject(resp.error)
|
||||
}
|
||||
|
||||
return resp.json()
|
||||
}).then(resp => this.$emit('updatePackFiles', resp))
|
||||
},
|
||||
uploadEmoji () {
|
||||
this.$store.state.api.backendInteractor.addNewEmojiFile({
|
||||
packName: this.packName,
|
||||
file: this.uploadFile[0],
|
||||
shortcode: this.editedShortcode,
|
||||
filename: this.editedFile
|
||||
}).then(resp => resp.json()).then(resp => {
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return
|
||||
}
|
||||
|
||||
this.$emit('updatePackFiles', resp)
|
||||
this.$refs.emojiPopover.hidePopover()
|
||||
|
||||
this.editedFile = ''
|
||||
this.editedShortcode = ''
|
||||
this.uploadFile = []
|
||||
})
|
||||
},
|
||||
revertEmoji () {
|
||||
this.editedFile = this.file
|
||||
this.editedShortcode = this.shortcode
|
||||
},
|
||||
deleteEmoji () {
|
||||
this.deleteModalVisible = false
|
||||
|
||||
this.$store.state.api.backendInteractor.deleteEmojiFile(
|
||||
{ packName: this.packName, shortcode: this.editedShortcode }
|
||||
).then(resp => resp.json()).then(resp => {
|
||||
if (resp.error !== undefined) {
|
||||
this.displayError(resp.error)
|
||||
return
|
||||
}
|
||||
|
||||
this.$emit('updatePackFiles', resp)
|
||||
})
|
||||
}
|
||||
},
|
||||
props: {
|
||||
placement: String,
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
newUpload: Boolean,
|
||||
|
||||
title: String,
|
||||
packName: String,
|
||||
shortcode: {
|
||||
type: String,
|
||||
// Only exists when this is not a new upload
|
||||
default: ''
|
||||
},
|
||||
file: {
|
||||
type: String,
|
||||
// Only exists when this is not a new upload
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.emoji-tab-edit-popover {
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
|
||||
.emoji {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user