Add direct edit for work groups and rooms
This commit is contained in:
parent
d08caf7b8b
commit
e88db9c75c
|
@ -1,8 +1,9 @@
|
||||||
package de.kif.frontend.views
|
package de.kif.frontend.views
|
||||||
|
|
||||||
import de.kif.common.Search
|
|
||||||
import de.kif.common.SearchElement
|
|
||||||
import de.kif.frontend.iterator
|
import de.kif.frontend.iterator
|
||||||
|
import de.kif.frontend.views.table.RoomTableLine
|
||||||
|
import de.kif.frontend.views.table.TableLine
|
||||||
|
import de.kif.frontend.views.table.WorkGroupTableLine
|
||||||
import de.westermann.kwebview.components.InputView
|
import de.westermann.kwebview.components.InputView
|
||||||
import org.w3c.dom.HTMLFormElement
|
import org.w3c.dom.HTMLFormElement
|
||||||
import org.w3c.dom.HTMLInputElement
|
import org.w3c.dom.HTMLInputElement
|
||||||
|
@ -17,16 +18,20 @@ fun initTableLayout() {
|
||||||
val table = document.getElementsByClassName("table-layout-table")[0] as HTMLTableElement
|
val table = document.getElementsByClassName("table-layout-table")[0] as HTMLTableElement
|
||||||
|
|
||||||
val list = table.getElementsByTagName("tr").iterator().asSequence().filter {
|
val list = table.getElementsByTagName("tr").iterator().asSequence().filter {
|
||||||
it.dataset.get("search") != null
|
it.dataset["search"] != null
|
||||||
}.associateWith {
|
}.map {
|
||||||
SearchElement.parse(it.dataset.get("search")!!)
|
when (it.dataset["edit"]) {
|
||||||
}
|
"workgroup" -> WorkGroupTableLine(it)
|
||||||
|
"room" -> RoomTableLine(it)
|
||||||
|
else -> TableLine(it)
|
||||||
|
}
|
||||||
|
}.toList()
|
||||||
|
|
||||||
val input = form.getElementsByTagName("input")[0] as HTMLInputElement
|
val input = form.getElementsByTagName("input")[0] as HTMLInputElement
|
||||||
val search = InputView.wrap(input)
|
val search = InputView.wrap(input)
|
||||||
search.valueProperty.onChange {
|
search.valueProperty.onChange {
|
||||||
for ((row, s) in list) {
|
for (row in list) {
|
||||||
row.style.display = if (Search.match(search.value, s)) "table-row" else "none"
|
row.search(search.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package de.kif.frontend.views.table
|
||||||
|
|
||||||
|
import de.kif.common.SearchElement
|
||||||
|
import de.kif.frontend.iterator
|
||||||
|
import de.kif.frontend.launch
|
||||||
|
import de.kif.frontend.repository.RepositoryDelegate
|
||||||
|
import de.kif.frontend.repository.RoomRepository
|
||||||
|
import de.westermann.kwebview.components.TextView
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
import org.w3c.dom.HTMLSpanElement
|
||||||
|
import org.w3c.dom.get
|
||||||
|
|
||||||
|
class RoomTableLine(view: HTMLElement) : TableLine(view) {
|
||||||
|
|
||||||
|
var lineId = dataset["id"]?.toLongOrNull() ?: -1
|
||||||
|
|
||||||
|
private val room =
|
||||||
|
RepositoryDelegate(RoomRepository, lineId)
|
||||||
|
|
||||||
|
private val spanRoomName: TextView
|
||||||
|
private val spanRoomPlaces: TextView
|
||||||
|
private val spanRoomProjector: TextView
|
||||||
|
|
||||||
|
override var searchElement: SearchElement = super.searchElement
|
||||||
|
|
||||||
|
init {
|
||||||
|
val spans = view.getElementsByTagName("span").iterator().asSequence().toList()
|
||||||
|
|
||||||
|
spanRoomName =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "room-name" } as HTMLSpanElement)
|
||||||
|
spanRoomPlaces =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "room-places" } as HTMLSpanElement)
|
||||||
|
spanRoomProjector =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "room-projector" } as HTMLSpanElement)
|
||||||
|
|
||||||
|
setupEditable(spanRoomName) {
|
||||||
|
launch {
|
||||||
|
val wg = room.get()
|
||||||
|
if (wg.name != it) {
|
||||||
|
RoomRepository.update(wg.copy(name = it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupEditable(spanRoomPlaces, "\\d+".toRegex()) {
|
||||||
|
val number = it.toIntOrNull() ?: return@setupEditable
|
||||||
|
launch {
|
||||||
|
val wg = room.get()
|
||||||
|
if (wg.places != number) {
|
||||||
|
RoomRepository.update(wg.copy(places = number))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupBoolean(spanRoomProjector) {
|
||||||
|
launch {
|
||||||
|
val wg = room.get()
|
||||||
|
RoomRepository.update(wg.copy(projector = !wg.projector))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RoomRepository.onUpdate {
|
||||||
|
if (it != lineId) return@onUpdate
|
||||||
|
|
||||||
|
launch {
|
||||||
|
val wg = RoomRepository.get(it) ?: return@launch
|
||||||
|
room.set(wg)
|
||||||
|
searchElement = wg.createSearch()
|
||||||
|
|
||||||
|
spanRoomName.text = wg.name
|
||||||
|
spanRoomPlaces.text = wg.places.toString()
|
||||||
|
spanRoomProjector.text = wg.projector.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
src/jsMain/kotlin/de/kif/frontend/views/table/TableLine.kt
Normal file
79
src/jsMain/kotlin/de/kif/frontend/views/table/TableLine.kt
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package de.kif.frontend.views.table
|
||||||
|
|
||||||
|
import de.kif.common.Search
|
||||||
|
import de.kif.common.SearchElement
|
||||||
|
import de.westermann.kwebview.View
|
||||||
|
import de.westermann.kwebview.components.ListView
|
||||||
|
import de.westermann.kwebview.components.TextView
|
||||||
|
import de.westermann.kwebview.components.textView
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
|
||||||
|
open class TableLine(line: HTMLElement) : View(line) {
|
||||||
|
|
||||||
|
open val searchElement: SearchElement = SearchElement.parse(dataset["search"]!!)
|
||||||
|
|
||||||
|
fun search(value: String) {
|
||||||
|
style.display = if (Search.match(value, searchElement)) "table-row" else "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun setupEditable(view: TextView, regex: Regex = ".*".toRegex(), onSave: (String) -> Unit) {
|
||||||
|
view.contentEditable = true
|
||||||
|
|
||||||
|
view.onKeyDown {
|
||||||
|
if (it.keyCode == 13) {
|
||||||
|
it.preventDefault()
|
||||||
|
|
||||||
|
view.blur()
|
||||||
|
return@onKeyDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view.onKeyUp {
|
||||||
|
view.classList["error"] = !regex.matches(view.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.onBlur {
|
||||||
|
view.classList["error"] = !regex.matches(view.text)
|
||||||
|
if (!view.classList["error"]) {
|
||||||
|
onSave(view.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun setupBoolean(view: TextView, onSave: () -> Unit) {
|
||||||
|
view.classList += "no-select"
|
||||||
|
view.tabIndex = 0
|
||||||
|
view.onDblClick {
|
||||||
|
onSave()
|
||||||
|
}
|
||||||
|
view.onKeyDown {
|
||||||
|
if (it.keyCode != 32) return@onKeyDown
|
||||||
|
onSave()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun <T : Any> setupList(view: TextView, list: List<T?>, transform: (T) -> String, onSave: (T?) -> Unit) {
|
||||||
|
view.classList += "no-select"
|
||||||
|
view.tabIndex = 0
|
||||||
|
|
||||||
|
val listView = ListView<TextView>()
|
||||||
|
listView.classList += "table-select-box"
|
||||||
|
|
||||||
|
for (elem in list) {
|
||||||
|
val text = if (elem == null) "" else transform(elem)
|
||||||
|
listView.textView(text) {
|
||||||
|
onClick {
|
||||||
|
onSave(elem)
|
||||||
|
view.blur()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view.onFocus {
|
||||||
|
view.html.appendChild(listView.html)
|
||||||
|
}
|
||||||
|
view.onBlur {
|
||||||
|
listView.html.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
package de.kif.frontend.views.table
|
||||||
|
|
||||||
|
import de.kif.common.SearchElement
|
||||||
|
import de.kif.common.model.Language
|
||||||
|
import de.kif.common.model.Track
|
||||||
|
import de.kif.frontend.iterator
|
||||||
|
import de.kif.frontend.launch
|
||||||
|
import de.kif.frontend.repository.RepositoryDelegate
|
||||||
|
import de.kif.frontend.repository.TrackRepository
|
||||||
|
import de.kif.frontend.repository.WorkGroupRepository
|
||||||
|
import de.westermann.kwebview.components.TextView
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
import org.w3c.dom.HTMLSpanElement
|
||||||
|
import org.w3c.dom.get
|
||||||
|
|
||||||
|
class WorkGroupTableLine(view: HTMLElement) : TableLine(view) {
|
||||||
|
|
||||||
|
var lineId = dataset["id"]?.toLongOrNull() ?: -1
|
||||||
|
|
||||||
|
private val workGroup =
|
||||||
|
RepositoryDelegate(WorkGroupRepository, lineId)
|
||||||
|
|
||||||
|
private val spanWorkGroupName: TextView
|
||||||
|
private val spanWorkGroupLength: TextView
|
||||||
|
private val spanWorkGroupInterested: TextView
|
||||||
|
private val spanWorkGroupTrack: TextView
|
||||||
|
private val spanWorkGroupProjector: TextView
|
||||||
|
private val spanWorkGroupResolution: TextView
|
||||||
|
private val spanWorkGroupLanguage: TextView
|
||||||
|
|
||||||
|
override var searchElement: SearchElement = super.searchElement
|
||||||
|
|
||||||
|
init {
|
||||||
|
val spans = view.getElementsByTagName("span").iterator().asSequence().toList()
|
||||||
|
|
||||||
|
spanWorkGroupName =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "workgroup-name" } as HTMLSpanElement)
|
||||||
|
spanWorkGroupLength =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "workgroup-length" } as HTMLSpanElement)
|
||||||
|
spanWorkGroupInterested =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "workgroup-interested" } as HTMLSpanElement)
|
||||||
|
spanWorkGroupTrack =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "workgroup-track" } as HTMLSpanElement)
|
||||||
|
spanWorkGroupProjector =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "workgroup-projector" } as HTMLSpanElement)
|
||||||
|
spanWorkGroupResolution =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "workgroup-resolution" } as HTMLSpanElement)
|
||||||
|
spanWorkGroupLanguage =
|
||||||
|
TextView.wrap(spans.first { it.dataset["editType"] == "workgroup-language" } as HTMLSpanElement)
|
||||||
|
|
||||||
|
setupEditable(spanWorkGroupName) {
|
||||||
|
launch {
|
||||||
|
val wg = workGroup.get()
|
||||||
|
if (wg.name != it) {
|
||||||
|
WorkGroupRepository.update(wg.copy(name = it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupEditable(spanWorkGroupLength, "\\d+".toRegex()) {
|
||||||
|
val number = it.toIntOrNull() ?: return@setupEditable
|
||||||
|
launch {
|
||||||
|
val wg = workGroup.get()
|
||||||
|
if (wg.length != number) {
|
||||||
|
WorkGroupRepository.update(wg.copy(length = number))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupEditable(spanWorkGroupInterested, "\\d+".toRegex()) {
|
||||||
|
val number = it.toIntOrNull() ?: return@setupEditable
|
||||||
|
launch {
|
||||||
|
val wg = workGroup.get()
|
||||||
|
if (wg.interested != number) {
|
||||||
|
WorkGroupRepository.update(wg.copy(interested = number))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupBoolean(spanWorkGroupProjector) {
|
||||||
|
launch {
|
||||||
|
val wg = workGroup.get()
|
||||||
|
WorkGroupRepository.update(wg.copy(projector = !wg.projector))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupBoolean(spanWorkGroupResolution) {
|
||||||
|
launch {
|
||||||
|
val wg = workGroup.get()
|
||||||
|
WorkGroupRepository.update(wg.copy(resolution = !wg.resolution))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupList(spanWorkGroupLanguage, Language.values().sortedBy { it.localeName }, { it.localeName }) {
|
||||||
|
if (it == null) return@setupList
|
||||||
|
launch {
|
||||||
|
val wg = workGroup.get()
|
||||||
|
if (wg.language == it) return@launch
|
||||||
|
WorkGroupRepository.update(wg.copy(language = it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch {
|
||||||
|
val tracks = listOf<Track?>(null) + TrackRepository.all()
|
||||||
|
|
||||||
|
setupList(spanWorkGroupTrack, tracks, { it.name }) {
|
||||||
|
launch x@{
|
||||||
|
val wg = workGroup.get()
|
||||||
|
if (wg.track == it) return@x
|
||||||
|
WorkGroupRepository.update(wg.copy(track = it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkGroupRepository.onUpdate {
|
||||||
|
if (it != lineId) return@onUpdate
|
||||||
|
|
||||||
|
launch {
|
||||||
|
val wg = WorkGroupRepository.get(it) ?: return@launch
|
||||||
|
workGroup.set(wg)
|
||||||
|
searchElement = wg.createSearch()
|
||||||
|
|
||||||
|
spanWorkGroupName.text = wg.name
|
||||||
|
spanWorkGroupLength.text = wg.length.toString()
|
||||||
|
spanWorkGroupInterested.text = wg.interested.toString()
|
||||||
|
spanWorkGroupTrack.text = wg.track?.name ?: ""
|
||||||
|
spanWorkGroupProjector.text = wg.projector.toString()
|
||||||
|
spanWorkGroupResolution.text = wg.resolution.toString()
|
||||||
|
spanWorkGroupLanguage.text = wg.language.localeName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,7 @@ package de.westermann.kwebview.components
|
||||||
import de.westermann.kobserve.Property
|
import de.westermann.kobserve.Property
|
||||||
import de.westermann.kobserve.ReadOnlyProperty
|
import de.westermann.kobserve.ReadOnlyProperty
|
||||||
import de.westermann.kobserve.property.property
|
import de.westermann.kobserve.property.property
|
||||||
import de.westermann.kwebview.KWebViewDsl
|
import de.westermann.kwebview.*
|
||||||
import de.westermann.kwebview.View
|
|
||||||
import de.westermann.kwebview.ViewCollection
|
|
||||||
import de.westermann.kwebview.createHtmlView
|
|
||||||
import org.w3c.dom.HTMLSpanElement
|
import org.w3c.dom.HTMLSpanElement
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,8 +12,9 @@ import org.w3c.dom.HTMLSpanElement
|
||||||
* @author lars
|
* @author lars
|
||||||
*/
|
*/
|
||||||
class TextView(
|
class TextView(
|
||||||
value: String = ""
|
value: String = "",
|
||||||
) : View(createHtmlView<HTMLSpanElement>()) {
|
view: HTMLSpanElement = createHtmlView()
|
||||||
|
) : View(view) {
|
||||||
|
|
||||||
override val html = super.html as HTMLSpanElement
|
override val html = super.html as HTMLSpanElement
|
||||||
|
|
||||||
|
@ -37,9 +35,26 @@ class TextView(
|
||||||
|
|
||||||
val textProperty: Property<String> = property(this::text)
|
val textProperty: Property<String> = property(this::text)
|
||||||
|
|
||||||
|
var contentEditable: Boolean
|
||||||
|
get() = html.isContentEditable
|
||||||
|
set(value) {
|
||||||
|
html.contentEditable = value.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var internalTabIndex by AttributeDelegate("tabIndex")
|
||||||
|
var tabIndex: Int?
|
||||||
|
get() = internalTabIndex?.toIntOrNull()
|
||||||
|
set(value) {
|
||||||
|
internalTabIndex = value?.toString()
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
text = value
|
text = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun wrap(view: HTMLSpanElement) = TextView(view.textContent ?: "", view)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@KWebViewDsl
|
@KWebViewDsl
|
||||||
|
|
|
@ -27,6 +27,8 @@ $bg-enabled-color: rgba($primary-color, .5);
|
||||||
$lever-disabled-color: $background-primary-color;
|
$lever-disabled-color: $background-primary-color;
|
||||||
$lever-enabled-color: $primary-color;
|
$lever-enabled-color: $primary-color;
|
||||||
|
|
||||||
|
$error-background-color: #FFCDD2;
|
||||||
|
|
||||||
body, html {
|
body, html {
|
||||||
color: $text-primary-color;
|
color: $text-primary-color;
|
||||||
background: $background-secondary-color;
|
background: $background-secondary-color;
|
||||||
|
@ -40,6 +42,10 @@ body, html {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-select {
|
||||||
|
@include no-select()
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
@ -248,6 +254,10 @@ a {
|
||||||
tr {
|
tr {
|
||||||
border-top: solid 1px rgba($text-primary-color, 0.1);
|
border-top: solid 1px rgba($text-primary-color, 0.1);
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
//background-color: rgba($text-primary-color, 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
&:first-child {
|
&:first-child {
|
||||||
background-color: rgba($text-primary-color, 0.06);
|
background-color: rgba($text-primary-color, 0.06);
|
||||||
height: 2.5rem;
|
height: 2.5rem;
|
||||||
|
@ -263,6 +273,34 @@ a {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:empty:before {
|
||||||
|
content: "\200b";
|
||||||
|
}
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
background-color: $error-background-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-select-box {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
background: $background-primary-color;
|
||||||
|
width: 100%;
|
||||||
|
border: solid 1px rgba($text-primary-color, 0.1);
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba($text-primary-color, 0.06);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control {
|
.form-control {
|
||||||
|
|
|
@ -2,10 +2,10 @@ package de.kif.backend.route
|
||||||
|
|
||||||
import de.kif.backend.authenticateOrRedirect
|
import de.kif.backend.authenticateOrRedirect
|
||||||
import de.kif.backend.repository.RoomRepository
|
import de.kif.backend.repository.RoomRepository
|
||||||
import de.kif.common.Search
|
|
||||||
import de.kif.backend.view.MainTemplate
|
import de.kif.backend.view.MainTemplate
|
||||||
import de.kif.backend.view.MenuTemplate
|
import de.kif.backend.view.MenuTemplate
|
||||||
import de.kif.backend.view.TableTemplate
|
import de.kif.backend.view.TableTemplate
|
||||||
|
import de.kif.common.Search
|
||||||
import de.kif.common.model.Permission
|
import de.kif.common.model.Permission
|
||||||
import de.kif.common.model.Room
|
import de.kif.common.model.Room
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
|
@ -17,11 +17,11 @@ import io.ktor.routing.Route
|
||||||
import io.ktor.routing.get
|
import io.ktor.routing.get
|
||||||
import io.ktor.routing.post
|
import io.ktor.routing.post
|
||||||
import io.ktor.util.toMap
|
import io.ktor.util.toMap
|
||||||
|
import kotlinx.css.CSSBuilder
|
||||||
|
import kotlinx.css.Display
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlin.collections.component1
|
import kotlin.collections.component1
|
||||||
import kotlin.collections.component2
|
import kotlin.collections.component2
|
||||||
import kotlin.collections.firstOrNull
|
|
||||||
import kotlin.collections.mapValues
|
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
fun Route.room() {
|
fun Route.room() {
|
||||||
|
@ -65,22 +65,38 @@ fun Route.room() {
|
||||||
|
|
||||||
for (u in list) {
|
for (u in list) {
|
||||||
val s = u.createSearch()
|
val s = u.createSearch()
|
||||||
if (Search.match(search, s)) {
|
entry {
|
||||||
entry {
|
attributes["style"] = CSSBuilder().apply {
|
||||||
attributes["data-search"] = s.stringify()
|
display = if (Search.match(search, s)) Display.tableRow else Display.none
|
||||||
td {
|
}.toString()
|
||||||
|
attributes["data-search"] = s.stringify()
|
||||||
|
attributes["data-edit"] = "room"
|
||||||
|
attributes["data-id"] = u.id.toString()
|
||||||
|
|
||||||
|
td {
|
||||||
|
span {
|
||||||
|
attributes["data-edit-type"] = "room-name"
|
||||||
|
|
||||||
+u.name
|
+u.name
|
||||||
}
|
}
|
||||||
td {
|
}
|
||||||
|
td {
|
||||||
|
span {
|
||||||
|
attributes["data-edit-type"] = "room-places"
|
||||||
|
|
||||||
+u.places.toString()
|
+u.places.toString()
|
||||||
}
|
}
|
||||||
td {
|
}
|
||||||
|
td {
|
||||||
|
span {
|
||||||
|
attributes["data-edit-type"] = "room-projector"
|
||||||
|
|
||||||
+u.projector.toString()
|
+u.projector.toString()
|
||||||
}
|
}
|
||||||
td(classes = "action") {
|
}
|
||||||
a("/room/${u.id}") {
|
td(classes = "action") {
|
||||||
i("material-icons") { +"edit" }
|
a("/room/${u.id}") {
|
||||||
}
|
i("material-icons") { +"edit" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ package de.kif.backend.route
|
||||||
|
|
||||||
import de.kif.backend.authenticateOrRedirect
|
import de.kif.backend.authenticateOrRedirect
|
||||||
import de.kif.backend.repository.TrackRepository
|
import de.kif.backend.repository.TrackRepository
|
||||||
import de.kif.common.Search
|
|
||||||
import de.kif.backend.view.MainTemplate
|
import de.kif.backend.view.MainTemplate
|
||||||
import de.kif.backend.view.MenuTemplate
|
import de.kif.backend.view.MenuTemplate
|
||||||
import de.kif.backend.view.TableTemplate
|
import de.kif.backend.view.TableTemplate
|
||||||
|
import de.kif.common.Search
|
||||||
import de.kif.common.model.Color
|
import de.kif.common.model.Color
|
||||||
import de.kif.common.model.Permission
|
import de.kif.common.model.Permission
|
||||||
import de.kif.common.model.Track
|
import de.kif.common.model.Track
|
||||||
|
@ -20,6 +20,7 @@ import io.ktor.routing.get
|
||||||
import io.ktor.routing.post
|
import io.ktor.routing.post
|
||||||
import io.ktor.util.toMap
|
import io.ktor.util.toMap
|
||||||
import kotlinx.css.CSSBuilder
|
import kotlinx.css.CSSBuilder
|
||||||
|
import kotlinx.css.Display
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
@ -119,22 +120,24 @@ fun Route.track() {
|
||||||
|
|
||||||
for (u in list) {
|
for (u in list) {
|
||||||
val s = u.createSearch()
|
val s = u.createSearch()
|
||||||
if (Search.match(search, s)) {
|
entry {
|
||||||
entry {
|
attributes["style"] = CSSBuilder().apply {
|
||||||
attributes["data-search"] = s.stringify()
|
display = if (Search.match(search, s)) Display.tableRow else Display.none
|
||||||
td {
|
}.toString()
|
||||||
+u.name
|
attributes["data-search"] = s.stringify()
|
||||||
}
|
td {
|
||||||
td {
|
+u.name
|
||||||
+u.color.toString()
|
}
|
||||||
}
|
td {
|
||||||
td(classes = "action") {
|
+u.color.toString()
|
||||||
a("/track/${u.id}") {
|
}
|
||||||
i("material-icons") { +"edit" }
|
td(classes = "action") {
|
||||||
}
|
a("/track/${u.id}") {
|
||||||
|
i("material-icons") { +"edit" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@ package de.kif.backend.route
|
||||||
import de.kif.backend.authenticateOrRedirect
|
import de.kif.backend.authenticateOrRedirect
|
||||||
import de.kif.backend.hashPassword
|
import de.kif.backend.hashPassword
|
||||||
import de.kif.backend.repository.UserRepository
|
import de.kif.backend.repository.UserRepository
|
||||||
import de.kif.common.Search
|
|
||||||
import de.kif.backend.view.MainTemplate
|
import de.kif.backend.view.MainTemplate
|
||||||
import de.kif.backend.view.MenuTemplate
|
import de.kif.backend.view.MenuTemplate
|
||||||
import de.kif.backend.view.TableTemplate
|
import de.kif.backend.view.TableTemplate
|
||||||
|
import de.kif.common.Search
|
||||||
import de.kif.common.model.Permission
|
import de.kif.common.model.Permission
|
||||||
import de.kif.common.model.User
|
import de.kif.common.model.User
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
|
@ -19,16 +19,12 @@ import io.ktor.routing.Route
|
||||||
import io.ktor.routing.get
|
import io.ktor.routing.get
|
||||||
import io.ktor.routing.post
|
import io.ktor.routing.post
|
||||||
import io.ktor.util.toMap
|
import io.ktor.util.toMap
|
||||||
|
import kotlinx.css.CSSBuilder
|
||||||
|
import kotlinx.css.Display
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlin.collections.component1
|
import kotlin.collections.component1
|
||||||
import kotlin.collections.component2
|
import kotlin.collections.component2
|
||||||
import kotlin.collections.filter
|
|
||||||
import kotlin.collections.firstOrNull
|
|
||||||
import kotlin.collections.joinToString
|
|
||||||
import kotlin.collections.mapNotNull
|
|
||||||
import kotlin.collections.mapValues
|
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.collections.toSet
|
|
||||||
|
|
||||||
fun Route.user() {
|
fun Route.user() {
|
||||||
get("/users") { param ->
|
get("/users") { param ->
|
||||||
|
@ -67,19 +63,20 @@ fun Route.user() {
|
||||||
|
|
||||||
for (u in list) {
|
for (u in list) {
|
||||||
val s = u.createSearch()
|
val s = u.createSearch()
|
||||||
if (Search.match(search, s)) {
|
entry {
|
||||||
entry {
|
attributes["style"] = CSSBuilder().apply {
|
||||||
attributes["data-search"] = s.stringify()
|
display = if (Search.match(search, s)) Display.tableRow else Display.none
|
||||||
td {
|
}.toString()
|
||||||
+u.username
|
attributes["data-search"] = s.stringify()
|
||||||
}
|
td {
|
||||||
td {
|
+u.username
|
||||||
+u.permissions.joinToString(", ") { it.toString().toLowerCase() }
|
}
|
||||||
}
|
td {
|
||||||
td(classes = "action") {
|
+u.permissions.joinToString(", ") { it.toString().toLowerCase() }
|
||||||
a("/user/${u.id}") {
|
}
|
||||||
i("material-icons") { +"edit" }
|
td(classes = "action") {
|
||||||
}
|
a("/user/${u.id}") {
|
||||||
|
i("material-icons") { +"edit" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,9 @@ fun Route.workGroup() {
|
||||||
th {
|
th {
|
||||||
+"Name"
|
+"Name"
|
||||||
}
|
}
|
||||||
|
th {
|
||||||
|
+"Length"
|
||||||
|
}
|
||||||
th {
|
th {
|
||||||
+"Interested"
|
+"Interested"
|
||||||
}
|
}
|
||||||
|
@ -69,9 +72,6 @@ fun Route.workGroup() {
|
||||||
th {
|
th {
|
||||||
+"Resolution"
|
+"Resolution"
|
||||||
}
|
}
|
||||||
th {
|
|
||||||
+"Length"
|
|
||||||
}
|
|
||||||
th {
|
th {
|
||||||
+"Language"
|
+"Language"
|
||||||
}
|
}
|
||||||
|
@ -87,26 +87,57 @@ fun Route.workGroup() {
|
||||||
display = if (Search.match(search, s)) Display.tableRow else Display.none
|
display = if (Search.match(search, s)) Display.tableRow else Display.none
|
||||||
}.toString()
|
}.toString()
|
||||||
attributes["data-search"] = s.stringify()
|
attributes["data-search"] = s.stringify()
|
||||||
|
attributes["data-edit"] = "workgroup"
|
||||||
|
attributes["data-id"] = u.id.toString()
|
||||||
|
|
||||||
td {
|
td {
|
||||||
+u.name
|
span {
|
||||||
|
attributes["data-edit-type"] = "workgroup-name"
|
||||||
|
|
||||||
|
+u.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
+u.interested.toString()
|
span {
|
||||||
|
attributes["data-edit-type"] = "workgroup-length"
|
||||||
|
|
||||||
|
+u.length.toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
+(u.track?.name ?: "")
|
span {
|
||||||
|
attributes["data-edit-type"] = "workgroup-interested"
|
||||||
|
|
||||||
|
+u.interested.toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
+u.projector.toString()
|
span {
|
||||||
|
attributes["data-edit-type"] = "workgroup-track"
|
||||||
|
|
||||||
|
+(u.track?.name ?: "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
+u.resolution.toString()
|
span {
|
||||||
|
attributes["data-edit-type"] = "workgroup-projector"
|
||||||
|
|
||||||
|
+u.projector.toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
+u.length.toString()
|
span {
|
||||||
|
attributes["data-edit-type"] = "workgroup-resolution"
|
||||||
|
|
||||||
|
+u.resolution.toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
+u.language.localeName
|
span {
|
||||||
|
attributes["data-edit-type"] = "workgroup-language"
|
||||||
|
|
||||||
|
+u.language.localeName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
td(classes = "action") {
|
td(classes = "action") {
|
||||||
a("/workgroup/${u.id}") {
|
a("/workgroup/${u.id}") {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import io.ktor.html.*
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
|
|
||||||
|
|
||||||
class TableTemplate() : Template<FlowContent> {
|
class TableTemplate(private val classes: String = "") : Template<FlowContent> {
|
||||||
|
|
||||||
var searchValue = ""
|
var searchValue = ""
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@ class TableTemplate() : Template<FlowContent> {
|
||||||
val entry = PlaceholderList<TABLE, TR>()
|
val entry = PlaceholderList<TABLE, TR>()
|
||||||
|
|
||||||
override fun FlowContent.apply() {
|
override fun FlowContent.apply() {
|
||||||
div("table-layout") {
|
val c = "table-layout" + if (classes.isEmpty()) "" else " $classes"
|
||||||
|
div(c) {
|
||||||
form(classes = "form-group table-layout-search") {
|
form(classes = "form-group table-layout-search") {
|
||||||
div("input-group") {
|
div("input-group") {
|
||||||
input(InputType.search, name = "search", classes = "form-control") {
|
input(InputType.search, name = "search", classes = "form-control") {
|
||||||
|
|
Loading…
Reference in a new issue