Kavita/UI/Web/src/app/_single-module/edit-chapter-modal/edit-chapter-modal.component.html
Joe Milazzo 0ffe0228e5
Polish 4 (#3577)
Co-authored-by: Zeoic <zeorgaming@gmail.com>
Co-authored-by: Fesaa <77553571+Fesaa@users.noreply.github.com>
2025-03-01 15:17:57 -08:00

633 lines
33 KiB
HTML

<ng-container *transloco="let t; read: 'edit-chapter-modal'">
<div class="modal-container">
<div class="modal-header">
<h4 class="modal-title">{{t('title')}} <app-entity-title [libraryType]="libraryType" [entity]="chapter" [prioritizeTitleName]="false"></app-entity-title></h4>
<button type="button" class="btn-close" [attr.aria-label]="t('close')" (click)="close()"></button>
</div>
<div class="modal-body scrollable-modal" [ngClass]="{'d-flex': utilityService.getActiveBreakpoint() !== Breakpoint.Mobile}">
<form [formGroup]="editForm">
<ul ngbNav #nav="ngbNav" [(activeId)]="activeId" class="nav-pills" orientation="{{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? 'horizontal' : 'vertical'}}" style="min-width: 135px;">
<!-- General Tab -->
@if (user && accountService.hasAdminRole(user))
{
<li [ngbNavItem]="TabID.General">
<a ngbNavLink>{{t(TabID.General)}}</a>
<ng-template ngbNavContent>
<div class="row">
<div class="col-md-9 col-sm-12 mb-3">
<app-setting-item [title]="t('title-label')" [showEdit]="false" [toggleOnViewClick]="false">
<ng-template #view>
@if (editForm.get('titleName'); as formControl) {
<div class="input-group" [ngClass]="{'lock-active': chapter.titleNameLocked}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: chapter, field: 'titleNameLocked' }"></ng-container>
<input class="form-control" formControlName="titleName" type="text"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
@if (formControl.errors; as errors) {
<div class="invalid-feedback">
@if (errors.required) {
<div>{{t('required-field')}}</div>
}
</div>
}
</div>
}
</ng-template>
</app-setting-item>
</div>
<div class="col-md-3 col-sm-12 mb-3">
<app-setting-item [title]="t('sort-order-label')" [showEdit]="false" [toggleOnViewClick]="false">
<ng-template #view>
@if (editForm.get('sortOrder'); as formControl) {
<div class="input-group" [ngClass]="{'lock-active': chapter.sortOrderLocked}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: chapter, field: 'sortOrderLocked' }"></ng-container>
<input class="form-control" formControlName="sortOrder" type="number" min="0" step="0.1" inputmode="numeric"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
@if (formControl.errors; as errors) {
<div class="invalid-feedback">
@if (errors.required) {
<div>{{t('required-field')}}</div>
}
</div>
}
</div>
}
</ng-template>
</app-setting-item>
</div>
</div>
<div class="row">
<div class="col-md-9 col-sm-12 mb-3">
<app-setting-item [title]="t('isbn-label')" [showEdit]="false" [toggleOnViewClick]="false">
<ng-template #view>
@if (editForm.get('isbn'); as formControl) {
<div class="input-group" [ngClass]="{'lock-active': chapter.isbnLocked}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: chapter, field: 'isbnLocked' }"></ng-container>
<input class="form-control" formControlName="isbn" type="text"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
@if (formControl.errors; as errors) {
<div class="invalid-feedback">
@if (errors.required) {
<div>{{t('required-field')}}</div>
}
</div>
}
</div>
}
</ng-template>
</app-setting-item>
</div>
<div class="col-md-3 col-sm-12 mb-3">
<app-setting-item [title]="t('age-rating-label')" [showEdit]="false" [toggleOnViewClick]="false">
<ng-template #view>
@if (editForm.get('ageRating'); as formControl) {
<div class="input-group" [ngClass]="{'lock-active': chapter.ageRatingLocked}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: chapter, field: 'ageRatingLocked' }"></ng-container>
<select class="form-select" id="age-rating" formControlName="ageRating">
@for(opt of ageRatings; track opt.value) {
<option [value]="opt.value">{{opt.title | titlecase}}</option>
}
</select>
</div>
}
</ng-template>
</app-setting-item>
</div>
</div>
<div class="row">
<div class="col-lg-9 col-md-12">
<div class="mb-3">
<app-setting-item [title]="t('language-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updateLanguage($event)" [settings]="languageSettings"
[(locked)]="chapter.languageLocked" (onUnlock)="chapter.languageLocked = false"
(newItemAdded)="chapter.languageLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.title}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.title}} ({{item.isoCode}})
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-3 col-md-12">
<div class="mb-3">
<app-setting-item [title]="t('release-date-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<div class="input-group" [ngClass]="{'lock-active': chapter.releaseDateLocked}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: chapter, field: 'releaseDateLocked' }"></ng-container>
<input
class="form-control"
formControlName="releaseDate"
type="date"
/>
</div>
</ng-template>
</app-setting-item>
</div>
</div>
</div>
<div class="row">
<div class="mb-3" style="width: 100%">
<app-setting-item [title]="t('summary-label')" [showEdit]="false" [toggleOnViewClick]="false">
<ng-template #view>
@if (editForm.get('summary'); as formControl) {
<div class="input-group" [ngClass]="{'lock-active': chapter.summaryLocked}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: chapter, field: 'summaryLocked' }"></ng-container>
<textarea id="summary" class="form-control" formControlName="summary" rows="4"></textarea>
</div>
}
</ng-template>
</app-setting-item>
</div>
</div>
</ng-template>
</li>
}
<!-- Tags Tab -->
@if (user && accountService.hasAdminRole(user))
{
<li [ngbNavItem]="TabID.Tags">
<a ngbNavLink>{{t(TabID.Tags)}}</a>
<ng-template ngbNavContent>
<!-- genre & tag -->
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('genres-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updateGenres($event);chapter.genresLocked = true" [settings]="genreSettings"
[(locked)]="chapter.genresLocked" (onUnlock)="chapter.genresLocked = false"
(newItemAdded)="chapter.genresLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.title}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.title}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('tags-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updateTags($event);chapter.tagsLocked = true" [settings]="tagsSettings"
[(locked)]="chapter.tagsLocked" (onUnlock)="chapter.tagsLocked = false"
(newItemAdded)="chapter.tagsLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
</div>
<!-- imprint & publisher -->
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('imprint-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Imprint);chapter.imprintLocked = true" [settings]="getPersonsSettings(PersonRole.Imprint)"
[(locked)]="chapter.imprintLocked" (onUnlock)="chapter.imprintLocked = false"
(newItemAdded)="chapter.imprintLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('publisher-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Publisher);chapter.publisherLocked = true" [settings]="getPersonsSettings(PersonRole.Publisher)"
[(locked)]="chapter.publisherLocked" (onUnlock)="chapter.publisherLocked = false"
(newItemAdded)="chapter.publisherLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
</div>
<!-- team & location -->
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('team-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Team);chapter.teamLocked = true" [settings]="getPersonsSettings(PersonRole.Team)"
[(locked)]="chapter.teamLocked" (onUnlock)="chapter.teamLocked = false"
(newItemAdded)="chapter.teamLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('location-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Location);chapter.locationLocked = true" [settings]="getPersonsSettings(PersonRole.Location)"
[(locked)]="chapter.locationLocked" (onUnlock)="chapter.locationLocked = false"
(newItemAdded)="chapter.locationLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
</div>
<!-- character -->
<div class="row">
<div class="col-lg-12 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('character-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Character);chapter.characterLocked = true" [settings]="getPersonsSettings(PersonRole.Character)"
[(locked)]="chapter.characterLocked" (onUnlock)="chapter.characterLocked = false"
(newItemAdded)="chapter.characterLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
</div>
</ng-template>
</li>
}
<!-- People Tab -->
@if (user && accountService.hasAdminRole(user))
{
<li [ngbNavItem]="TabID.People">
<a ngbNavLink>{{t(TabID.People)}}</a>
<ng-template ngbNavContent>
<!-- writer & cover artist -->
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('writer-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Writer);chapter.writerLocked = true" [settings]="getPersonsSettings(PersonRole.Writer)"
[(locked)]="chapter.writerLocked" (onUnlock)="chapter.writerLocked = false"
(newItemAdded)="chapter.writerLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('cover-artist-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.CoverArtist);chapter.coverArtistLocked = true" [settings]="getPersonsSettings(PersonRole.CoverArtist)"
[(locked)]="chapter.coverArtistLocked" (onUnlock)="chapter.coverArtistLocked = false"
(newItemAdded)="chapter.coverArtistLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
</div>
<!-- penciller & colorist -->
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('penciller-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Penciller);chapter.pencillerLocked = true" [settings]="getPersonsSettings(PersonRole.Penciller)"
[(locked)]="chapter.pencillerLocked" (onUnlock)="chapter.pencillerLocked = false"
(newItemAdded)="chapter.pencillerLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('colorist-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Colorist);chapter.coloristLocked = true" [settings]="getPersonsSettings(PersonRole.Colorist)"
[(locked)]="chapter.coloristLocked" (onUnlock)="chapter.coloristLocked = false"
(newItemAdded)="chapter.coloristLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
</div>
<!-- inker & letterer -->
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('inker-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Inker);chapter.inkerLocked = true" [settings]="getPersonsSettings(PersonRole.Inker)"
[(locked)]="chapter.inkerLocked" (onUnlock)="chapter.inkerLocked = false"
(newItemAdded)="chapter.inkerLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('letterer-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Letterer);chapter.lettererLocked = true" [settings]="getPersonsSettings(PersonRole.Letterer)"
[(locked)]="chapter.lettererLocked" (onUnlock)="chapter.lettererLocked = false"
(newItemAdded)="chapter.lettererLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
</div>
<!-- translator -->
<div class="row">
<div class="col-lg-12 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('translator-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Translator);chapter.translatorLocked = true" [settings]="getPersonsSettings(PersonRole.Translator)"
[(locked)]="chapter.translatorLocked" (onUnlock)="chapter.translatorLocked = false"
(newItemAdded)="chapter.translatorLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>
<ng-template #optionItem let-item let-position="idx">
{{item.name}}
</ng-template>
</app-typeahead>
</ng-template>
</app-setting-item>
</div>
</div>
</div>
</ng-template>
</li>
}
<!-- Cover Tab -->
@if (user && accountService.hasAdminRole(user))
{
<li [ngbNavItem]="TabID.CoverImage">
<a ngbNavLink>{{t(TabID.CoverImage)}}</a>
<ng-template ngbNavContent>
<p class="alert alert-warning" role="alert">
{{t('cover-image-description')}}
</p>
<app-cover-image-chooser [(imageUrls)]="imageUrls" (imageSelected)="updateSelectedIndex($event)" (selectedBase64Url)="updateSelectedImage($event)"
[showReset]="chapter.coverImageLocked" (resetClicked)="handleReset()"></app-cover-image-chooser>
</ng-template>
</li>
}
<!-- Info Tab -->
<li [ngbNavItem]="TabID.Info">
<a ngbNavLink>{{t(TabID.Info)}}</a>
<ng-template ngbNavContent>
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('pages-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
{{t('pages-count', {num: chapter.pages | compactNumber})}}
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('words-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
{{t('words-count', {num: chapter.wordCount | compactNumber})}}
</ng-template>
</app-setting-item>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('read-time-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
{{chapter | readTime }}
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('size-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
{{size | bytes}}
</ng-template>
</app-setting-item>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('date-added-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
{{chapter.createdUtc | utcToLocalTime | translocoDate: {dateStyle: 'short', timeStyle: 'short' } | defaultDate}}
</ng-template>
</app-setting-item>
</div>
</div>
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('id-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
{{chapter.id}}
</ng-template>
</app-setting-item>
</div>
</div>
</div>
@if (WebLinks.length > 0) {
<div class="setting-section-break"></div>
<div class="container-fluid mb-3">
<div class="row">
<h6 class="section-title">{{t('links-label')}}</h6>
<div class="col-auto">
@for(link of WebLinks; track link) {
<a class="me-1" [href]="link | safeHtml" target="_blank" rel="noopener noreferrer" [title]="link">
<app-image height="24px" width="24px" aria-hidden="true" [imageUrl]="imageService.getWebLinkImage(link)"
[errorImage]="imageService.errorWebLinkImage"></app-image>
</a>
}
</div>
</div>
</div>
}
@if (accountService.isAdmin$ | async) {
<div class="row">
<app-setting-item [title]="t('files-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@for (file of chapter.files; track file.id) {
<div>
<span>{{file.filePath}}</span><span class="ms-2 me-2"></span><span>{{file.bytes | bytes}}</span>
</div>
}
</ng-template>
</app-setting-item>
</div>
}
</ng-template>
</li>
<!-- Progress Tab -->
<li [ngbNavItem]="TabID.Progress">
<a ngbNavLink>{{t(TabID.Progress)}}</a>
<ng-template ngbNavContent>
<app-edit-chapter-progress [chapter]="chapter"></app-edit-chapter-progress>
</ng-template>
</li>
<!-- Tasks Tab -->
<li [ngbNavItem]="TabID.Tasks">
<a ngbNavLink>{{t(TabID.Tasks)}}</a>
<ng-template ngbNavContent>
@for(task of tasks; track task.action) {
@if (accountService.canInvokeAction(user, task.action)) {
<div class="mt-3 mb-3">
<app-setting-button [subtitle]="task.description">
<button class="btn btn-{{task.action === Action.Delete ? 'danger' : 'secondary'}} btn-sm mb-2" (click)="runTask(task)">{{task.title}}</button>
</app-setting-button>
</div>
}
}
</ng-template>
</li>
</ul>
</form>
<div [ngbNavOutlet]="nav" class="tab-content {{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? 'mt-3' : 'ms-4 flex-fill'}}"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="close()">{{t('close')}}</button>
<button type="submit" class="btn btn-primary" [disabled]="!editForm.valid" (click)="save()">{{t('save')}}</button>
</div>
</div>
<ng-template #lock let-item="item" let-field="field">
<span class="input-group-text clickable" (click)="unlock(item, field)">
<i class="fa fa-lock" aria-hidden="true"></i>
<span class="visually-hidden">{{t('field-locked-alt')}}</span>
</span>
</ng-template>
</ng-container>