mirror of
https://github.com/gotson/komga.git
synced 2025-12-20 07:23:34 +01:00
788 lines
30 KiB
Vue
788 lines
30 KiB
Vue
<template>
|
|
<v-dialog v-model="modal"
|
|
:fullscreen="$vuetify.breakpoint.xsOnly"
|
|
max-width="800"
|
|
@keydown.esc="dialogCancel"
|
|
>
|
|
<form novalidate>
|
|
<v-card>
|
|
<v-toolbar class="hidden-sm-and-up">
|
|
<v-btn icon @click="dialogCancel">
|
|
<v-icon>mdi-close</v-icon>
|
|
</v-btn>
|
|
<v-toolbar-title>{{ dialogTitle }}</v-toolbar-title>
|
|
<v-spacer/>
|
|
<v-toolbar-items>
|
|
<v-btn text color="primary" @click="dialogConfirm">{{ $t('dialog.edit_series.button_confirm') }}</v-btn>
|
|
</v-toolbar-items>
|
|
</v-toolbar>
|
|
|
|
<v-card-title class="hidden-xs-only">
|
|
<v-icon class="mx-4">mdi-pencil</v-icon>
|
|
{{ dialogTitle }}
|
|
</v-card-title>
|
|
|
|
<v-tabs :vertical="$vuetify.breakpoint.smAndUp" v-model="tab">
|
|
<v-tab class="justify-start">
|
|
<v-icon left class="hidden-xs-only">mdi-format-align-center</v-icon>
|
|
{{ $t('dialog.edit_series.tab_general') }}
|
|
</v-tab>
|
|
<v-tab class="justify-start">
|
|
<v-icon left class="hidden-xs-only">mdi-tag-multiple</v-icon>
|
|
{{ $t('dialog.edit_series.tab_tags') }}
|
|
</v-tab>
|
|
<v-tab class="justify-start" v-if="single">
|
|
<v-icon left class="hidden-xs-only">mdi-image</v-icon>
|
|
{{ $t('dialog.edit_series.tab_poster') }}
|
|
</v-tab>
|
|
|
|
<!-- Tab: General -->
|
|
<v-tab-item>
|
|
<v-card flat>
|
|
<v-container fluid>
|
|
|
|
<!-- Title -->
|
|
<v-row v-if="single">
|
|
<v-col cols="12">
|
|
<v-text-field v-model="form.title"
|
|
:label="$t('dialog.edit_series.field_title')"
|
|
filled
|
|
dense
|
|
:error-messages="requiredErrors('title')"
|
|
@input="$v.form.title.$touch()"
|
|
@blur="$v.form.title.$touch()"
|
|
@change="form.titleLock = true"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.titleLock ? 'secondary' : ''"
|
|
@click="form.titleLock = !form.titleLock"
|
|
>
|
|
{{ form.titleLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-text-field>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Sort Title -->
|
|
<v-row v-if="single">
|
|
<v-col cols="12">
|
|
<v-text-field v-model="form.titleSort"
|
|
:label="$t('dialog.edit_series.field_sort_title')"
|
|
filled
|
|
dense
|
|
:error-messages="requiredErrors('titleSort')"
|
|
@input="$v.form.titleSort.$touch()"
|
|
@blur="$v.form.titleSort.$touch()"
|
|
@change="form.titleSortLock = true"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.titleSortLock ? 'secondary' : ''"
|
|
@click="form.titleSortLock = !form.titleSortLock"
|
|
>
|
|
{{ form.titleSortLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-text-field>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Summary -->
|
|
<v-row v-if="single">
|
|
<v-col cols="12">
|
|
<v-textarea v-model="form.summary"
|
|
:label="$t('dialog.edit_series.field_summary')"
|
|
filled
|
|
dense
|
|
@input="$v.form.summary.$touch()"
|
|
@change="form.summaryLock = true"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.summaryLock ? 'secondary' : ''"
|
|
@click="form.summaryLock = !form.summaryLock"
|
|
>
|
|
{{ form.summaryLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-textarea>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<!-- Status -->
|
|
<v-col cols="6">
|
|
<v-select :items="seriesStatus"
|
|
v-model="form.status"
|
|
:label="$t('dialog.edit_series.field_status')"
|
|
filled
|
|
:placeholder="!single && mixed.status ? $t('dialog.edit_series.mixed') : ''"
|
|
@input="$v.form.status.$touch()"
|
|
@change="form.statusLock = true"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.statusLock ? 'secondary' : ''"
|
|
@click="form.statusLock = !form.statusLock"
|
|
>
|
|
{{ form.statusLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-select>
|
|
</v-col>
|
|
|
|
<!-- Language -->
|
|
<v-col cols="6">
|
|
<v-text-field v-model="form.language"
|
|
:label="$t('dialog.edit_series.field_language')"
|
|
filled
|
|
dense
|
|
:placeholder="!single && mixed.language ? $t('dialog.edit_series.mixed') : ''"
|
|
:error-messages="languageErrors"
|
|
:hint="$t('dialog.edit_series.field_language_hint')"
|
|
@input="$v.form.language.$touch()"
|
|
@change="form.languageLock = true"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.languageLock ? 'secondary' : ''"
|
|
@click="form.languageLock = !form.languageLock"
|
|
>
|
|
{{ form.languageLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-text-field>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Reading Direction -->
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<v-select v-model="form.readingDirection"
|
|
:items="readingDirections"
|
|
:label="$t('dialog.edit_series.field_reading_direction')"
|
|
clearable
|
|
filled
|
|
:placeholder="!single && mixed.readingDirection ? $t('dialog.edit_series.mixed') : ''"
|
|
@input="$v.form.readingDirection.$touch()"
|
|
@change="form.readingDirectionLock = true"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.readingDirectionLock ? 'secondary' : ''"
|
|
@click="form.readingDirectionLock = !form.readingDirectionLock"
|
|
>
|
|
{{ form.readingDirectionLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-select>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<!-- Publisher -->
|
|
<v-col cols="6">
|
|
<v-text-field v-model="form.publisher"
|
|
:label="$t('dialog.edit_series.field_publisher')"
|
|
filled
|
|
dense
|
|
:placeholder="!single && mixed.publisher ? $t('dialog.edit_series.mixed') : ''"
|
|
@input="$v.form.publisher.$touch()"
|
|
@change="form.publisherLock = true"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.publisherLock ? 'secondary' : ''"
|
|
@click="form.publisherLock = !form.publisherLock"
|
|
>
|
|
{{ form.publisherLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-text-field>
|
|
</v-col>
|
|
|
|
<!-- Age Rating -->
|
|
<v-col cols="6">
|
|
<v-text-field v-model="form.ageRating"
|
|
:label="$t('dialog.edit_series.field_age_rating')"
|
|
clearable
|
|
filled
|
|
dense
|
|
type="number"
|
|
:placeholder="!single && mixed.ageRating ? $t('dialog.edit_series.mixed') : ''"
|
|
:error-messages="ageRatingErrors"
|
|
@input="$v.form.ageRating.$touch()"
|
|
@blur="$v.form.ageRating.$touch()"
|
|
@change="form.ageRatingLock = true"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.ageRatingLock ? 'secondary' : ''"
|
|
@click="form.ageRatingLock = !form.ageRatingLock"
|
|
>
|
|
{{ form.ageRatingLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-text-field>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row v-if="single">
|
|
<!-- Total book count -->
|
|
<v-col cols="6">
|
|
<v-text-field v-model="form.totalBookCount"
|
|
:label="$t('dialog.edit_series.field_total_book_count')"
|
|
clearable
|
|
filled
|
|
dense
|
|
type="number"
|
|
:error-messages="totalBookCountErrors"
|
|
@input="$v.form.totalBookCount.$touch()"
|
|
@blur="$v.form.totalBookCount.$touch()"
|
|
@change="form.totalBookCountLock = true"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.totalBookCountLock ? 'secondary' : ''"
|
|
@click="form.totalBookCountLock = !form.totalBookCountLock"
|
|
>
|
|
{{ form.totalBookCountLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-text-field>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
</v-container>
|
|
</v-card>
|
|
</v-tab-item>
|
|
|
|
<!-- Tab: Tags -->
|
|
<v-tab-item>
|
|
<v-card flat>
|
|
<v-container fluid>
|
|
<v-alert v-if="!single"
|
|
type="warning"
|
|
outlined
|
|
dense
|
|
>{{ $t('dialog.edit_series.tags_notice_multiple_edit') }}
|
|
</v-alert>
|
|
|
|
<!-- Genres -->
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<span class="text-body-2">{{ $t('dialog.edit_series.field_genres') }}</span>
|
|
<v-combobox v-model="form.genres"
|
|
:items="genresAvailable"
|
|
@input="$v.form.genres.$touch()"
|
|
@change="form.genresLock = true"
|
|
hide-selected
|
|
chips
|
|
deletable-chips
|
|
multiple
|
|
filled
|
|
dense
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.genresLock ? 'secondary' : ''"
|
|
@click="form.genresLock = !form.genresLock"
|
|
>
|
|
{{ form.genresLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-combobox>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Tags -->
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<span class="text-body-2">{{ $t('dialog.edit_series.field_tags') }}</span>
|
|
<v-combobox v-model="form.tags"
|
|
:items="tagsAvailable"
|
|
@input="$v.form.tags.$touch()"
|
|
@change="form.tagsLock = true"
|
|
hide-selected
|
|
chips
|
|
deletable-chips
|
|
multiple
|
|
filled
|
|
dense
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon :color="form.tagsLock ? 'secondary' : ''"
|
|
@click="form.tagsLock = !form.tagsLock"
|
|
>
|
|
{{ form.tagsLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
|
</v-icon>
|
|
</template>
|
|
</v-combobox>
|
|
</v-col>
|
|
</v-row>
|
|
</v-container>
|
|
</v-card>
|
|
</v-tab-item>
|
|
|
|
<!-- Tab: Thumbnails -->
|
|
<v-tab-item v-if="single">
|
|
<v-card flat>
|
|
<v-container fluid>
|
|
<!-- Upload -->
|
|
<v-row>
|
|
<v-col class="pa-1">
|
|
<drop-zone ref="thumbnailsUpload" @on-input-change="addThumbnail" class="pa-8"/>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Gallery -->
|
|
<v-row>
|
|
<v-col
|
|
cols="6" sm="4" lg="3" class="pa-1"
|
|
v-for="(item, index) in [...poster.uploadQueue, ...poster.seriesThumbnails]"
|
|
:key="index"
|
|
>
|
|
<thumbnail-card
|
|
:item="item"
|
|
:selected="isThumbnailSelected(item)"
|
|
:toBeDeleted="isThumbnailToBeDeleted(item)"
|
|
@on-select-thumbnail="selectThumbnail"
|
|
@on-delete-thumbnail="deleteThumbnail"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
</v-container>
|
|
</v-card>
|
|
</v-tab-item>
|
|
</v-tabs>
|
|
|
|
<v-card-actions class="hidden-xs-only">
|
|
<v-spacer/>
|
|
<v-btn text @click="dialogCancel">{{ $t('dialog.edit_series.button_cancel') }}</v-btn>
|
|
<v-btn color="primary" @click="dialogConfirm">{{ $t('dialog.edit_series.button_confirm') }}</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</form>
|
|
</v-dialog>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import Vue from 'vue'
|
|
import {SeriesStatus} from '@/types/enum-series'
|
|
import {helpers, minValue, requiredIf} from 'vuelidate/lib/validators'
|
|
import {ReadingDirection} from '@/types/enum-books'
|
|
import {SeriesDto, SeriesThumbnailDto} from '@/types/komga-series'
|
|
import {ERROR, ErrorEvent} from '@/types/events'
|
|
import DropZone from '@/components/DropZone.vue'
|
|
import ThumbnailCard from '@/components/ThumbnailCard.vue'
|
|
|
|
const tags = require('language-tags')
|
|
|
|
const validLanguage = (value: string) => !helpers.req(value) || tags.check(value)
|
|
|
|
export default Vue.extend({
|
|
name: 'EditSeriesDialog',
|
|
components: {ThumbnailCard, DropZone},
|
|
data: () => {
|
|
return {
|
|
modal: false,
|
|
tab: 0,
|
|
form: {
|
|
status: '',
|
|
statusLock: false,
|
|
title: '',
|
|
titleLock: false,
|
|
titleSort: '',
|
|
titleSortLock: false,
|
|
summary: '',
|
|
summaryLock: false,
|
|
readingDirection: '',
|
|
readingDirectionLock: false,
|
|
publisher: '',
|
|
publisherLock: false,
|
|
ageRating: undefined as number | undefined,
|
|
ageRatingLock: false,
|
|
language: '',
|
|
languageLock: false,
|
|
genres: [],
|
|
genresLock: false,
|
|
tags: [],
|
|
tagsLock: false,
|
|
totalBookCount: undefined as number | undefined,
|
|
totalBookCountLock: false,
|
|
},
|
|
mixed: {
|
|
status: false,
|
|
readingDirection: false,
|
|
publisher: false,
|
|
ageRating: false,
|
|
language: false,
|
|
},
|
|
poster: {
|
|
selectedThumbnail: '',
|
|
uploadQueue: [] as File[],
|
|
deleteQueue: [] as SeriesThumbnailDto[],
|
|
seriesThumbnails: [] as SeriesThumbnailDto[],
|
|
},
|
|
genresAvailable: [] as string[],
|
|
tagsAvailable: [] as string[],
|
|
}
|
|
},
|
|
props: {
|
|
value: Boolean,
|
|
series: {
|
|
type: [Object as () => SeriesDto, Array as () => SeriesDto[]],
|
|
required: true,
|
|
},
|
|
},
|
|
watch: {
|
|
value(val) {
|
|
this.modal = val
|
|
},
|
|
modal(val) {
|
|
if(val) {
|
|
this.getThumbnails(this.series)
|
|
this.loadAvailableTags()
|
|
this.loadAvailableGenres()
|
|
} else {
|
|
this.dialogCancel()
|
|
}
|
|
},
|
|
series(val) {
|
|
this.dialogReset(val)
|
|
this.getThumbnails(val)
|
|
},
|
|
},
|
|
validations: {
|
|
form: {
|
|
title: {
|
|
required: requiredIf(function (this: any, model: any) {
|
|
return this.single
|
|
}),
|
|
},
|
|
titleSort: {
|
|
required: requiredIf(function (this: any, model: any) {
|
|
return this.single
|
|
}),
|
|
},
|
|
status: {
|
|
required: requiredIf(function (this: any, model: any) {
|
|
return this.single
|
|
}),
|
|
},
|
|
summary: {},
|
|
language: {
|
|
validLanguage: validLanguage,
|
|
},
|
|
genres: {},
|
|
tags: {},
|
|
ageRating: {minValue: minValue(0)},
|
|
readingDirection: {},
|
|
publisher: {},
|
|
totalBookCount: {minValue: minValue(1)},
|
|
},
|
|
},
|
|
computed: {
|
|
single(): boolean {
|
|
return !Array.isArray(this.series)
|
|
},
|
|
readingDirections(): any[] {
|
|
return Object.keys(ReadingDirection).map(x => (
|
|
{
|
|
text: this.$t(`enums.reading_direction.${x}`),
|
|
value: x,
|
|
}),
|
|
)
|
|
},
|
|
seriesStatus(): any[] {
|
|
return Object.keys(SeriesStatus).map(x => ({
|
|
text: this.$t(`enums.series_status.${x}`),
|
|
value: x,
|
|
}))
|
|
},
|
|
ageRatingErrors(): string[] {
|
|
const errors = [] as string[]
|
|
if (!this.$v.form?.ageRating?.$dirty) return errors
|
|
!this.$v?.form?.ageRating?.minValue && errors.push(this.$t('dialog.edit_series.field_age_rating_error').toString())
|
|
return errors
|
|
},
|
|
totalBookCountErrors(): string[] {
|
|
const errors = [] as string[]
|
|
if (!this.$v.form?.totalBookCount?.$dirty) return errors
|
|
!this.$v?.form?.totalBookCount?.minValue && errors.push(this.$t('dialog.edit_series.field_total_book_count_error').toString())
|
|
return errors
|
|
},
|
|
languageErrors(): string[] {
|
|
if (!this.$v.form?.language?.$dirty) return []
|
|
if (!this.$v?.form?.language?.validLanguage) return tags(this.form.language).errors().map((x: any) => x.message)
|
|
return []
|
|
},
|
|
dialogTitle(): string {
|
|
return this.single
|
|
? this.$t('dialog.edit_series.dialog_title_single', {series: this.$_.get(this.series, 'metadata.title')}).toString()
|
|
: this.$tc('dialog.edit_series.dialog_title_multiple', (this.series as SeriesDto[]).length)
|
|
},
|
|
},
|
|
methods: {
|
|
async loadAvailableTags() {
|
|
this.tagsAvailable = await this.$komgaReferential.getTags()
|
|
},
|
|
async loadAvailableGenres() {
|
|
this.genresAvailable = await this.$komgaReferential.getGenres()
|
|
},
|
|
requiredErrors(fieldName: string): string[] {
|
|
const errors = [] as string[]
|
|
const formField = this.$v.form!![fieldName] as any
|
|
if (!formField.$dirty) return errors
|
|
!formField.required && errors.push(this.$t('common.required').toString())
|
|
return errors
|
|
},
|
|
dialogReset(series: SeriesDto | SeriesDto[]) {
|
|
this.tab = 0
|
|
this.$v.$reset()
|
|
if (Array.isArray(series) && series.length === 0) return
|
|
if (Array.isArray(series) && series.length > 0) {
|
|
const status = this.$_.uniq(series.map(x => x.metadata.status))
|
|
this.form.status = status.length > 1 ? '' : status[0]
|
|
this.mixed.status = status.length > 1
|
|
|
|
const statusLock = this.$_.uniq(series.map(x => x.metadata.statusLock))
|
|
this.form.statusLock = statusLock.length > 1 ? false : statusLock[0]
|
|
|
|
const readingDirection = this.$_.uniq(series.map(x => x.metadata.readingDirection))
|
|
this.form.readingDirection = readingDirection.length > 1 ? '' : readingDirection[0]
|
|
this.mixed.readingDirection = readingDirection.length > 1
|
|
|
|
const readingDirectionLock = this.$_.uniq(series.map(x => x.metadata.readingDirectionLock))
|
|
this.form.readingDirectionLock = readingDirectionLock.length > 1 ? false : readingDirectionLock[0]
|
|
|
|
const ageRating = this.$_.uniq(series.map(x => x.metadata.ageRating))
|
|
this.form.ageRating = ageRating.length > 1 ? undefined : ageRating[0]
|
|
this.mixed.ageRating = ageRating.length > 1
|
|
|
|
const ageRatingLock = this.$_.uniq(series.map(x => x.metadata.ageRatingLock))
|
|
this.form.ageRatingLock = ageRatingLock.length > 1 ? false : ageRatingLock[0]
|
|
|
|
const publisher = this.$_.uniq(series.map(x => x.metadata.publisher))
|
|
this.form.publisher = publisher.length > 1 ? '' : publisher[0]
|
|
this.mixed.publisher = publisher.length > 1
|
|
|
|
const publisherLock = this.$_.uniq(series.map(x => x.metadata.publisherLock))
|
|
this.form.publisherLock = publisherLock.length > 1 ? false : publisherLock[0]
|
|
|
|
const language = this.$_.uniq(series.map(x => x.metadata.language))
|
|
this.form.language = language.length > 1 ? '' : language[0]
|
|
this.mixed.language = language.length > 1
|
|
|
|
const languageLock = this.$_.uniq(series.map(x => x.metadata.languageLock))
|
|
this.form.languageLock = languageLock.length > 1 ? false : languageLock[0]
|
|
|
|
this.form.genres = []
|
|
|
|
const genresLock = this.$_.uniq(series.map(x => x.metadata.genresLock))
|
|
this.form.genresLock = genresLock.length > 1 ? false : genresLock[0]
|
|
|
|
this.form.tags = []
|
|
|
|
const tagsLock = this.$_.uniq(series.map(x => x.metadata.tagsLock))
|
|
this.form.tagsLock = tagsLock.length > 1 ? false : tagsLock[0]
|
|
} else {
|
|
this.form.genres = []
|
|
this.form.tags = []
|
|
this.$_.merge(this.form, (series as SeriesDto).metadata)
|
|
this.poster.selectedThumbnail = ''
|
|
this.poster.deleteQueue = []
|
|
this.poster.uploadQueue = []
|
|
this.poster.seriesThumbnails = []
|
|
}
|
|
},
|
|
dialogCancel() {
|
|
this.$emit('input', false)
|
|
this.dialogReset(this.series)
|
|
},
|
|
async dialogConfirm() {
|
|
if (await this.editSeries()) {
|
|
this.$emit('input', false)
|
|
}
|
|
},
|
|
validateForm(): any {
|
|
if (!this.$v.$invalid) {
|
|
const metadata = {
|
|
statusLock: this.form.statusLock,
|
|
readingDirectionLock: this.form.readingDirectionLock,
|
|
ageRatingLock: this.form.ageRatingLock,
|
|
publisherLock: this.form.publisherLock,
|
|
languageLock: this.form.languageLock,
|
|
genresLock: this.form.genresLock,
|
|
tagsLock: this.form.tagsLock,
|
|
totalBookCountLock: this.form.totalBookCountLock,
|
|
}
|
|
|
|
if (this.$v.form?.status?.$dirty) {
|
|
this.$_.merge(metadata, {status: this.form.status})
|
|
}
|
|
|
|
if (this.$v.form?.readingDirection?.$dirty) {
|
|
this.$_.merge(metadata, {readingDirection: this.form.readingDirection ? this.form.readingDirection : null})
|
|
}
|
|
|
|
if (this.$v.form?.ageRating?.$dirty) {
|
|
this.$_.merge(metadata, {ageRating: this.form.ageRating})
|
|
}
|
|
|
|
if (this.$v.form?.publisher?.$dirty) {
|
|
this.$_.merge(metadata, {publisher: this.form.publisher})
|
|
}
|
|
|
|
if (this.$v.form?.genres?.$dirty) {
|
|
this.$_.merge(metadata, {genres: this.form.genres})
|
|
}
|
|
|
|
if (this.$v.form?.tags?.$dirty) {
|
|
this.$_.merge(metadata, {tags: this.form.tags})
|
|
}
|
|
|
|
if (this.$v.form?.language?.$dirty) {
|
|
this.$_.merge(metadata, {language: this.form.language})
|
|
}
|
|
|
|
if (this.single) {
|
|
this.$_.merge(metadata, {
|
|
titleLock: this.form.titleLock,
|
|
titleSortLock: this.form.titleSortLock,
|
|
summaryLock: this.form.summaryLock,
|
|
totalBookCountLock: this.form.totalBookCountLock,
|
|
})
|
|
|
|
if (this.$v.form?.title?.$dirty) {
|
|
this.$_.merge(metadata, {title: this.form.title})
|
|
}
|
|
|
|
if (this.$v.form?.titleSort?.$dirty) {
|
|
this.$_.merge(metadata, {titleSort: this.form.titleSort})
|
|
}
|
|
|
|
if (this.$v.form?.summary?.$dirty) {
|
|
this.$_.merge(metadata, {summary: this.form.summary})
|
|
}
|
|
|
|
if (this.$v.form?.totalBookCount?.$dirty) {
|
|
this.$_.merge(metadata, {totalBookCount: this.form.totalBookCount})
|
|
}
|
|
}
|
|
|
|
return metadata
|
|
}
|
|
return null
|
|
},
|
|
async editSeries(): Promise<boolean> {
|
|
if (this.single && this.poster.uploadQueue.length > 0) {
|
|
const series = this.series as SeriesDto
|
|
let hadErrors = false
|
|
for (const file of this.poster.uploadQueue.slice()) {
|
|
try {
|
|
await this.$komgaSeries.uploadThumbnail(series.id, file, file.name === this.poster.selectedThumbnail)
|
|
this.deleteThumbnail(file)
|
|
} catch (e) {
|
|
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
|
|
hadErrors = true
|
|
}
|
|
}
|
|
if (hadErrors) {
|
|
await this.getThumbnails(series)
|
|
return false
|
|
}
|
|
}
|
|
|
|
if (this.single && this.poster.selectedThumbnail !== '') {
|
|
const id = this.poster.selectedThumbnail
|
|
const series = this.series as SeriesDto
|
|
if (this.poster.seriesThumbnails.find(value => value.id === id)) {
|
|
this.$komgaSeries.markThumbnailAsSelected(series.id, id)
|
|
}
|
|
}
|
|
|
|
if (this.single && this.poster.deleteQueue.length > 0) {
|
|
this.poster.deleteQueue.forEach(toDelete => this.$komgaSeries.deleteThumbnail(toDelete.seriesId, toDelete.id))
|
|
}
|
|
|
|
const metadata = this.validateForm()
|
|
if (metadata) {
|
|
const toUpdate = (this.single ? [this.series] : this.series) as SeriesDto[]
|
|
for (const s of toUpdate) {
|
|
try {
|
|
await this.$komgaSeries.updateMetadata(s.id, metadata)
|
|
} catch (e) {
|
|
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
|
|
}
|
|
}
|
|
return true
|
|
} else return false
|
|
},
|
|
addThumbnail(files: File[]) {
|
|
let hasSelected = false
|
|
for (const file of files) {
|
|
if (!this.poster.uploadQueue.find(value => value.name === file.name)) {
|
|
this.poster.uploadQueue.push(file)
|
|
if (!hasSelected) {
|
|
this.selectThumbnail(file)
|
|
hasSelected = true
|
|
}
|
|
}
|
|
}
|
|
|
|
(this.$refs.thumbnailsUpload as any).reset()
|
|
},
|
|
async getThumbnails(series: SeriesDto | SeriesDto[]) {
|
|
if (Array.isArray(series)) return
|
|
|
|
const thumbnails = await this.$komgaSeries.getThumbnails(series.id)
|
|
|
|
this.selectThumbnail(thumbnails.find(x => x.selected))
|
|
|
|
this.poster.seriesThumbnails = thumbnails
|
|
},
|
|
isThumbnailSelected(item: File | SeriesThumbnailDto): boolean {
|
|
return item instanceof File ? item.name === this.poster.selectedThumbnail : item.id === this.poster.selectedThumbnail
|
|
},
|
|
selectThumbnail(item: File | SeriesThumbnailDto | undefined) {
|
|
if (!item) {
|
|
return
|
|
} else if (item instanceof File) {
|
|
this.poster.selectedThumbnail = item.name
|
|
} else {
|
|
const index = this.poster.deleteQueue.indexOf(item, 0)
|
|
if (index > -1) this.poster.deleteQueue.splice(index, 1)
|
|
|
|
this.poster.selectedThumbnail = item.id
|
|
}
|
|
},
|
|
isThumbnailToBeDeleted(item: File | SeriesThumbnailDto) {
|
|
if (item instanceof File) {
|
|
return false
|
|
} else {
|
|
return this.poster.deleteQueue.includes(item)
|
|
}
|
|
},
|
|
deleteThumbnail(item: File | SeriesThumbnailDto) {
|
|
if (item instanceof File) {
|
|
const index = this.poster.uploadQueue.indexOf(item, 0)
|
|
if (index > -1) {
|
|
this.poster.uploadQueue.splice(index, 1)
|
|
}
|
|
if (item.name === this.poster.selectedThumbnail) {
|
|
this.poster.selectedThumbnail = ''
|
|
}
|
|
} else {
|
|
// if thumbnail was marked for deletion, unmark it
|
|
if (this.isThumbnailToBeDeleted(item)) {
|
|
const index = this.poster.deleteQueue.indexOf(item, 0)
|
|
if (index > -1) {
|
|
this.poster.deleteQueue.splice(index, 1)
|
|
}
|
|
} else {
|
|
this.poster.deleteQueue.push(item)
|
|
if (item.id === this.poster.selectedThumbnail) this.poster.selectedThumbnail = ''
|
|
}
|
|
}
|
|
},
|
|
},
|
|
})
|
|
</script>
|
|
|
|
<style lang="sass" scoped>
|
|
@import 'src/styles/tabbed-dialog'
|
|
</style>
|