Files
app/server/src/main/kotlin/books/ui/BookEdit.kt
T
2026-10-21 23:47:44 +02:00

425 lines
16 KiB
Kotlin

package net.keinekekse.app.books.ui
import io.ktor.htmx.html.*
import kotlinx.coroutines.runBlocking
import kotlinx.html.*
import net.keinekekse.app.books.db.BookRepository
import net.keinekekse.app.books.edit.BooksSessionData
import net.keinekekse.app.books.model.BookType
import net.keinekekse.app.books.model.Languages
import net.keinekekse.app.core.auth.UserSession
fun FlowContent.bookEdit(
booksRepo: BookRepository,
session: UserSession<BooksSessionData>,
) {
session.data.publisherList = runBlocking {
booksRepo.allPublishers()
}
session.data.seriesList = runBlocking {
booksRepo.allSeries()
}
session.data.artistList = runBlocking {
booksRepo.allArtists()
}
session.data.tagList = runBlocking {
booksRepo.allTags()
}
div(classes = "flex flex-col m-8") {
form {
attributes.hx {
post = navBooksEdit.second
target = "#response"
swap = "innerHTML"
}
input(type = InputType.hidden, name = "sessionId") {
value = session.sessionId
}
input(type = InputType.hidden, name = "bookId") {
value = session.data.book.id.toString()
}
div(classes = "flex flex-row mb-5 h-9") {
div(classes = "w-30 content-center") {
+"Typ"
}
select(classes = "$cssTextInput w-40") {
name = "type"
autoFocus = true
for (type in BookType.entries) {
option {
if (type == session.data.book.type)
selected = true
value = type.ordinal.toString()
+type.name
}
}
}
}
div(classes = "flex flex-row mb-5 h-9") {
div(classes = "w-30 content-center") {
+"Titel"
}
input(classes = "$cssTextInput w-150") {
name = "title"
value = session.data.book.title
}
}
div(classes = "flex flex-row mb-5 h-9") {
div(classes = "w-30 content-center") {
+"Originaltitel"
}
input(classes = "$cssTextInput w-150") {
name = "originaltitle"
value = session.data.book.originalTitle ?: ""
}
}
div(classes = "flex flex-row mb-5 h-9") {
div(classes = "w-30 content-center") {
+"Untertitel"
}
input(classes = "$cssTextInput w-150") {
name = "subtitle"
value = session.data.book.subTitle ?: ""
}
}
div(classes = "flex flex-row mb-5 h-9") {
div(classes = "w-30 content-center") {
+"Sprache"
}
select(classes = "$cssTextInput w-16") {
name = "language"
for (language in Languages.entries) {
option {
if (language == session.data.book.language)
selected = true
value = language.ordinal.toString()
+language.name
}
}
}
div(classes = "w-45 pr-3 content-center text-end") {
+"Erscheinungsjahr"
}
input(classes = "$cssTextInput w-16") {
name = "year"
value = session.data.book.year.toString()
}
div(classes = "w-57 pr-3 content-center text-end") {
+"Jahr der Originalausgabe"
}
input(classes = "$cssTextInput w-16") {
name = "originalyear"
value = session.data.book.originalYear?.toString() ?: ""
}
}
div(classes = "flex flex-row mb-5 h-9") {
div(classes = "w-32 content-center") {
+"ISBN"
}
input(classes = "$cssTextInput w-40") {
name = "isbn"
value = session.data.book.isbn
}
div(classes = "w-26 pr-3 content-center text-end") {
+"Verlag"
}
select(classes = "$cssTextInput w-74") {
name = "publisher"
id = "publisher"
option {
value = "0"
+"---"
}
for (pub in session.data.publisherList) {
option {
if (pub.id == session.data.book.publisher.id)
selected = true
value = pub.id.toString()
+pub.name
}
}
}
button(classes = cssFormIcon) {
title = "Verlag hinzufügen"
// TODO
/*
type = ButtonType.button -> sonst wird "submit" angenommen und dann funktioniert
es nicht!
*/
type = ButtonType.button
// attributes["popovertarget"] = "publisherDialog"
// onClick = "document.getElementById('publisherDialog').showModal()"
attributes["command"] = "show-modal"
attributes["commandfor"] = "publisherDialog" //id
materialSymbolFormButton("add_box")
}
}
div(classes = "flex flex-row mb-5 h-9") {
div(classes = "w-30 content-center") {
+"Serie"
}
select(classes = "$cssTextInput w-100") {
name = "series"
option {
value = "0"
+"---"
}
for (serie in session.data.seriesList) {
option {
if (session.data.book.series != null && serie.id == session.data.book.series!!.id)
selected = true
value = serie.id.toString()
+serie.name
}
}
}
button(classes = cssFormIcon) {
title = "Serie hinzufügen"
materialSymbolFormButton("add_box")
}
div(classes = "w-20 pr-3 content-center text-end") {
+"Index"
}
input(classes = "$cssTextInput w-20") {
name = "seriesindex"
value = session.data.book.seriesIndex?.toString() ?: ""
}
}
div(classes = "flex flex-row mb-7") {
div(classes = "w-30 content-start pt-3") {
+"Künstler"
}
div(classes = "overflow-auto px-1 pb-1 h-40 w-82") {
tabIndex = "-1" // overflow setzt sonst einen Tabstopp
table {
// thead(classes = "$cssFixedTHead ") {
// tr {
// th(classes = "py-3 px-2") { +"Name" }
// th(classes = "py-3 px-2") { +"Rolle" }
// th(classes = "py-3 px-2") {
// button(classes = cssFormIcon) {
// title = "Künstler hinzufügen"
// materialSymbolFormButton("add_box")
// }
// }
// }
// }
tbody {
for ((artist, role) in session.data.book.artists) {
tr {
td(classes = "border-b-1 $borderTable px-2 py-1") {
+"${artist.name}, ${artist.givenName}"
}
td(classes = "border-b-1 $borderTable px-2 py-1") {
+role.role
}
td(classes = "border-b-1 $borderTable px-2 py-1") {
button(classes = cssFormIcon) {
// href = "${navBooksEdit.second}/${book.id}"
materialSymbolFormButton("Edit")
}
button(classes = cssFormIcon) {
materialSymbolFormButton("Delete")
}
}
}
}
}
}
}
button(classes = "$cssFormIcon self-start mt-2 ") {
title = "Künstler hinzufügen"
materialSymbolFormButton("add_box")
}
div(classes = "w-20 pr-3 content-start text-end pt-3") {
+"Tags"
}
div(classes = "overflow-auto px-1 pb-1 h-40 w-30") {
tabIndex = "-1" // overflow setzt sonst einen Tabstopp
table {
// thead(classes = "$cssFixedTHead ") {
// tr {
// th(classes = "py-3 px-2") { +"Tag" }
// th(classes = "py-3 px-2") {
// button(classes = cssFormIcon) {
// title = "Tag hinzufügen"
// materialSymbolFormButton("add_box")
// }
// }
// }
// }
tbody {
for (tag in session.data.book.tags) {
tr {
td(classes = "border-b-1 $borderTable px-2 py-1") {
+tag.tag
}
td(classes = "border-b-1 $borderTable px-2 py-1") {
button(classes = cssFormIcon) {
materialSymbolFormButton("Delete")
}
}
}
}
}
}
}
button(classes = "$cssFormIcon self-start mt-2") {
title = "Tag hinzufügen"
materialSymbolFormButton("add_box")
}
}
div(classes = "flex flex-row mb-5") {
div(classes = "w-30 content-center") {
+"Kommentar"
}
textArea(classes = "$cssTextInput w-150 h-18 resize-none") {
name = "comment"
spellCheck = true
+session.data.book.comments
}
}
// TODO parent
// evtl. switch oder <detail>
// Teil von Sammelband _____v / enthält (-> Link)
div(classes = "flex flex-row mb-5 h-9") {
div(classes = "w-30 content-center") {
+"Sammelband"
}
label(
classes = "w-10 justify-center grid grid-cols-[1.3em] " +
"focus-within:bg-orange-300 hover:bg-orange-300"
) {
input {
name = "sampler"
type = InputType.checkBox // liefert sampler=on || nix !
checked = session.data.book.isSampler
}
}
div(classes = "w-30 content-center text-end pr-3") {
+"Teil von"
}
select(classes = "$cssTextInput w-50") {
name = "parent"
option {
value = "0"
+"---"
}
// for (serie in session.data.seriesList) {
// option {
// if (session.data.book.series != null && serie.id == session.data.book.series!!.id)
// selected = true
// value = serie.id.toString()
// +serie.name
// }
// }
}
}
div(classes = "flex flex-row mb-5 mr-2 justify-end w-180") {
button(classes = "$cssButtonStd block mt-8 mr-10") {
type = ButtonType.button
onClick =
"window.history.back()"
+"Abbrechen"
}
button(classes = "$cssButtonPri block mt-8") {
type = ButtonType.submit
+"Speichern"
}
}
}
// TODO
dialog(
classes = "m-auto h-fit w-full max-w-md rounded-lg shadow-2xl border-2 " +
"$borderTable px-3 py-2 $bgBody $textBody $bgDialogBackdrop"
) {
id = "publisherDialog"
// attributes["popover"] = "true"
// attributes["closedby"] = "any"
form {
id = "publisherDialogForm"
attributes.hx {
post = "${navBooksEdit.second}/addpublisher"
target = "#publisher"
swap = "innerHTML"
validate = true
on(
event = "after-request",
script = "this.reset();document.getElementById('publisherDialog').close()"
)
}
input(type = InputType.hidden, name = "sessionId") {
value = session.sessionId
}
input(type = InputType.hidden, name = "bookId") {
value = session.data.book.id.toString()
}
div(classes = "flex flex-row mb-5 h-9") {
div(classes = "content-center pr-6 text-nowrap") {
+"Neuer Verlag:"
}
input(classes = "$cssTextInput w-75") {
name = "newpublisher"
required = true
value = ""
onBlur = """
const select = document.getElementById('publisher')
const optArray = Array.from(select.options)
if (optArray.some(opt => opt.text.toLowerCase() === this.value.toLowerCase() )) {
this.setCustomValidity('Dieser Verlag existiert bereits.');
} else {
this.setCustomValidity('');
}
"""
}
}
div(classes = "flex flex-row mb-5 mr-2 justify-end") {
button(classes = "$cssButtonStd block mt-8 mr-10") {
type = ButtonType.button
onClick =
"document.getElementById('publisherDialogForm').reset()"
attributes["commandfor"] = "publisherDialog"
attributes["command"] = "close"
+"Abbrechen"
}
button(classes = "$cssButtonPri block mt-8") {
type = ButtonType.submit
+"Speichern"
}
}
}
}
output { }
div {
id = "response"
}
}
}