Compare commits
No commits in common. "19956ebafb929769a8d6b7c5c653d8b6e583e956" and "f5b937a293bc481e399f8de3294db96be31cd5ba" have entirely different histories.
19956ebafb
...
f5b937a293
23 changed files with 213 additions and 756 deletions
|
@ -3,7 +3,7 @@ host = "localhost"
|
||||||
port = 8080
|
port = 8080
|
||||||
|
|
||||||
[schedule]
|
[schedule]
|
||||||
reference = "2019-06-12"
|
reference = "2019-06-06"
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
wiki_url = "https://wiki.kif.rocks/w/index.php?title=KIF470:Arbeitskreise&action=raw"
|
wiki_url = "https://wiki.kif.rocks/w/index.php?title=KIF470:Arbeitskreise&action=raw"
|
||||||
|
|
|
@ -23,37 +23,6 @@ data class Post(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other == null || this::class != other::class) return false
|
|
||||||
|
|
||||||
other as Post
|
|
||||||
|
|
||||||
if (id != other.id) return false
|
|
||||||
if (name != other.name) return false
|
|
||||||
if (content != other.content) return false
|
|
||||||
if (url != other.url) return false
|
|
||||||
if (image != other.image) return false
|
|
||||||
if (pinned != other.pinned) return false
|
|
||||||
if (hideOnProjector != other.hideOnProjector) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun equalsIgnoreId(other: Post): Boolean = copy(id = null) == other.copy(id = null)
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = id?.hashCode() ?: 0
|
|
||||||
result = 31 * result + name.hashCode()
|
|
||||||
result = 31 * result + content.hashCode()
|
|
||||||
result = 31 * result + url.hashCode()
|
|
||||||
result = 31 * result + (image?.hashCode() ?: 0)
|
|
||||||
result = 31 * result + pinned.hashCode()
|
|
||||||
result = 31 * result + hideOnProjector.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val chars = "abcdefghijklmnopqrstuvwxyz"
|
private const val chars = "abcdefghijklmnopqrstuvwxyz"
|
||||||
private const val length = 32
|
private const val length = 32
|
||||||
|
|
|
@ -17,8 +17,6 @@ data class Room(
|
||||||
override val updateAt: Long = 0
|
override val updateAt: Long = 0
|
||||||
) : Model {
|
) : Model {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun createSearch() = SearchElement(
|
override fun createSearch() = SearchElement(
|
||||||
mapOf(
|
mapOf(
|
||||||
"name" to name
|
"name" to name
|
||||||
|
@ -28,36 +26,4 @@ data class Room(
|
||||||
"places" to places.toDouble()
|
"places" to places.toDouble()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other == null || this::class != other::class) return false
|
|
||||||
|
|
||||||
other as Room
|
|
||||||
|
|
||||||
if (id != other.id) return false
|
|
||||||
if (name != other.name) return false
|
|
||||||
if (places != other.places) return false
|
|
||||||
if (projector != other.projector) return false
|
|
||||||
if (internet != other.internet) return false
|
|
||||||
if (whiteboard != other.whiteboard) return false
|
|
||||||
if (blackboard != other.blackboard) return false
|
|
||||||
if (accessible != other.accessible) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun equalsIgnoreId(other: Room): Boolean = copy(id = null) == other.copy(id = null)
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = id?.hashCode() ?: 0
|
|
||||||
result = 31 * result + name.hashCode()
|
|
||||||
result = 31 * result + places
|
|
||||||
result = 31 * result + projector.hashCode()
|
|
||||||
result = 31 * result + internet.hashCode()
|
|
||||||
result = 31 * result + whiteboard.hashCode()
|
|
||||||
result = 31 * result + blackboard.hashCode()
|
|
||||||
result = 31 * result + accessible.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ data class Schedule(
|
||||||
override val updateAt: Long = 0
|
override val updateAt: Long = 0
|
||||||
) : Model {
|
) : Model {
|
||||||
|
|
||||||
|
|
||||||
override fun createSearch() = SearchElement(
|
override fun createSearch() = SearchElement(
|
||||||
mapOf(
|
mapOf(
|
||||||
"workgroup" to workGroup.name,
|
"workgroup" to workGroup.name,
|
||||||
|
@ -30,35 +29,6 @@ data class Schedule(
|
||||||
|
|
||||||
fun getAbsoluteStartTime(): Int = day * 60 * 24 + time
|
fun getAbsoluteStartTime(): Int = day * 60 * 24 + time
|
||||||
fun getAbsoluteEndTime(): Int = getAbsoluteStartTime() + workGroup.length
|
fun getAbsoluteEndTime(): Int = getAbsoluteStartTime() + workGroup.length
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other == null || this::class != other::class) return false
|
|
||||||
|
|
||||||
other as Schedule
|
|
||||||
|
|
||||||
if (id != other.id) return false
|
|
||||||
if (workGroup != other.workGroup) return false
|
|
||||||
if (room != other.room) return false
|
|
||||||
if (day != other.day) return false
|
|
||||||
if (time != other.time) return false
|
|
||||||
if (lockRoom != other.lockRoom) return false
|
|
||||||
if (lockTime != other.lockTime) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun equalsIgnoreId(other: Schedule): Boolean = copy(id = null) == other.copy(id = null)
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = id?.hashCode() ?: 0
|
|
||||||
result = 31 * result + workGroup.hashCode()
|
|
||||||
result = 31 * result + room.hashCode()
|
|
||||||
result = 31 * result + day
|
|
||||||
result = 31 * result + time
|
|
||||||
result = 31 * result + lockRoom.hashCode()
|
|
||||||
result = 31 * result + lockTime.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun timeOfDayToString(time: Int): String {
|
fun timeOfDayToString(time: Int): String {
|
||||||
|
|
|
@ -12,33 +12,9 @@ data class Track(
|
||||||
override val updateAt: Long = 0
|
override val updateAt: Long = 0
|
||||||
) : Model {
|
) : Model {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun createSearch() = SearchElement(
|
override fun createSearch() = SearchElement(
|
||||||
mapOf(
|
mapOf(
|
||||||
"name" to name
|
"name" to name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other == null || this::class != other::class) return false
|
|
||||||
|
|
||||||
other as Track
|
|
||||||
|
|
||||||
if (id != other.id) return false
|
|
||||||
if (name != other.name) return false
|
|
||||||
if (color != other.color) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun equalsIgnoreId(other: Track): Boolean = copy(id = null) == other.copy(id = null)
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = id?.hashCode() ?: 0
|
|
||||||
result = 31 * result + name.hashCode()
|
|
||||||
result = 31 * result + color.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,6 @@ data class User(
|
||||||
override val updateAt: Long = 0
|
override val updateAt: Long = 0
|
||||||
) : Model {
|
) : Model {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun checkPermission(permission: Permission): Boolean {
|
fun checkPermission(permission: Permission): Boolean {
|
||||||
return permission in permissions || Permission.ADMIN in permissions
|
return permission in permissions || Permission.ADMIN in permissions
|
||||||
}
|
}
|
||||||
|
@ -24,28 +22,4 @@ data class User(
|
||||||
"username" to username
|
"username" to username
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other == null || this::class != other::class) return false
|
|
||||||
|
|
||||||
other as User
|
|
||||||
|
|
||||||
if (id != other.id) return false
|
|
||||||
if (username != other.username) return false
|
|
||||||
if (password != other.password) return false
|
|
||||||
if (permissions != other.permissions) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun equalsIgnoreId(other: User): Boolean = copy(id = null) == other.copy(id = null)
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = id?.hashCode() ?: 0
|
|
||||||
result = 31 * result + username.hashCode()
|
|
||||||
result = 31 * result + password.hashCode()
|
|
||||||
result = 31 * result + permissions.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,50 +37,4 @@ data class WorkGroup(
|
||||||
"length" to length.toDouble()
|
"length" to length.toDouble()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other == null || this::class != other::class) return false
|
|
||||||
|
|
||||||
other as WorkGroup
|
|
||||||
|
|
||||||
if (id != other.id) return false
|
|
||||||
if (name != other.name) return false
|
|
||||||
if (description != other.description) return false
|
|
||||||
if (interested != other.interested) return false
|
|
||||||
if (track != other.track) return false
|
|
||||||
if (projector != other.projector) return false
|
|
||||||
if (resolution != other.resolution) return false
|
|
||||||
if (internet != other.internet) return false
|
|
||||||
if (whiteboard != other.whiteboard) return false
|
|
||||||
if (blackboard != other.blackboard) return false
|
|
||||||
if (accessible != other.accessible) return false
|
|
||||||
if (length != other.length) return false
|
|
||||||
if (language != other.language) return false
|
|
||||||
if (leader != other.leader) return false
|
|
||||||
if (constraints != other.constraints) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun equalsIgnoreId(other: WorkGroup): Boolean = copy(id = null) == other.copy(id = null)
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = id?.hashCode() ?: 0
|
|
||||||
result = 31 * result + name.hashCode()
|
|
||||||
result = 31 * result + description.hashCode()
|
|
||||||
result = 31 * result + interested
|
|
||||||
result = 31 * result + (track?.hashCode() ?: 0)
|
|
||||||
result = 31 * result + projector.hashCode()
|
|
||||||
result = 31 * result + resolution.hashCode()
|
|
||||||
result = 31 * result + internet.hashCode()
|
|
||||||
result = 31 * result + whiteboard.hashCode()
|
|
||||||
result = 31 * result + blackboard.hashCode()
|
|
||||||
result = 31 * result + accessible.hashCode()
|
|
||||||
result = 31 * result + length
|
|
||||||
result = 31 * result + language.hashCode()
|
|
||||||
result = 31 * result + leader.hashCode()
|
|
||||||
result = 31 * result + constraints.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package de.kif.frontend.views.board
|
package de.kif.frontend.views.board
|
||||||
|
|
||||||
import com.soywiz.klock.DateFormat
|
import de.kif.common.formatDateTime
|
||||||
import com.soywiz.klock.KlockLocale
|
import de.westermann.kwebview.iterator
|
||||||
import com.soywiz.klock.locale.german
|
|
||||||
import de.westermann.kwebview.interval
|
import de.westermann.kwebview.interval
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
import org.w3c.dom.get
|
import org.w3c.dom.get
|
||||||
|
@ -10,29 +9,21 @@ import kotlin.browser.document
|
||||||
import kotlin.js.Date
|
import kotlin.js.Date
|
||||||
|
|
||||||
fun initBoard() {
|
fun initBoard() {
|
||||||
//val boardSchedules = document.getElementsByClassName("board-schedules")[0] as HTMLElement
|
val boardSchedules = document.getElementsByClassName("board-schedules")[0] as HTMLElement
|
||||||
val dateView = document.getElementsByClassName("board-header-date")[0] as HTMLElement
|
val dateView = document.getElementsByClassName("board-header-date")[0] as HTMLElement
|
||||||
//val referenceTime = boardSchedules.dataset["reference"]?.toLongOrNull() ?: 0L
|
val referenceTime = boardSchedules.dataset["reference"]?.toLongOrNull() ?: 0L
|
||||||
|
|
||||||
/*
|
|
||||||
val scheduleList = mutableListOf<BoardSchedule>()
|
val scheduleList = mutableListOf<BoardSchedule>()
|
||||||
|
|
||||||
for (bs in boardSchedules.getElementsByClassName("board-schedule").iterator()) {
|
for (bs in boardSchedules.getElementsByClassName("board-schedule").iterator()) {
|
||||||
scheduleList += BoardSchedule(bs)
|
scheduleList += BoardSchedule(bs)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
interval(1000) {
|
interval(1000) {
|
||||||
|
val currentTime = Date.now().toLong()
|
||||||
|
dateView.innerText = formatDateTime(currentTime)
|
||||||
|
|
||||||
val currentTime = Date().let {
|
|
||||||
it.getHours().toString().padStart(2, '0') + ":" + it.getMinutes().toString().padStart(2, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
dateView.innerText = currentTime
|
|
||||||
|
|
||||||
/*
|
|
||||||
val now = referenceTime - currentTime / 1000
|
val now = referenceTime - currentTime / 1000
|
||||||
scheduleList.forEach { it.updateTime(now) }
|
scheduleList.forEach { it.updateTime(now) }
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,43 +13,33 @@ import kotlin.browser.window
|
||||||
|
|
||||||
class Calendar(calendar: HTMLElement) : View(calendar) {
|
class Calendar(calendar: HTMLElement) : View(calendar) {
|
||||||
|
|
||||||
var autoScroll = true
|
|
||||||
|
|
||||||
val day: Int = calendar.dataset["day"]?.toIntOrNull() ?: -1
|
val day: Int = calendar.dataset["day"]?.toIntOrNull() ?: -1
|
||||||
|
|
||||||
|
private val htmlTag = document.body as HTMLElement
|
||||||
val calendarTable = calendar.getElementsByClassName("calendar-table")[0] as HTMLElement
|
val calendarTable = calendar.getElementsByClassName("calendar-table")[0] as HTMLElement
|
||||||
private val calendarTableHeader = calendar.getElementsByClassName("calendar-header")[0] as HTMLElement
|
val calendarTableHeader = calendar.getElementsByClassName("calendar-header")[0] as HTMLElement
|
||||||
|
|
||||||
fun scrollVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
fun scrollVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
||||||
scrollAllVerticalBy(pixel, scrollBehavior)
|
htmlTag.scrollBy(ScrollToOptions(0.0, pixel, scrollBehavior))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scrollHorizontalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
fun scrollHorizontalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
||||||
scrollAllHorizontalBy(pixel, scrollBehavior)
|
calendarTable.scrollBy(ScrollToOptions(pixel, 0.0, scrollBehavior))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scrollVerticalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
fun scrollVerticalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
||||||
scrollAllVerticalTo(pixel, scrollBehavior)
|
htmlTag.scrollTo(ScrollToOptions(0.0, pixel, scrollBehavior))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scrollHorizontalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
fun scrollHorizontalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
||||||
scrollAllHorizontalTo(pixel, scrollBehavior)
|
calendarTable.scrollTo(ScrollToOptions(pixel, 0.0, scrollBehavior))
|
||||||
}
|
}
|
||||||
|
|
||||||
val editable = calendar.dataset["editable"]?.toBoolean() ?: false
|
val editable = calendar.dataset["editable"]?.toBoolean() ?: false
|
||||||
|
|
||||||
val body = CalendarBody(this, calendar.getElementsByClassName("calendar-body")[0] as HTMLElement)
|
val body = CalendarBody(this, calendar.getElementsByClassName("calendar-body")[0] as HTMLElement)
|
||||||
|
|
||||||
val orientation: Orientation = if (document.getElementsByClassName("time-to-room").length > 0) {
|
|
||||||
Orientation.TIME_TO_ROOM
|
|
||||||
} else {
|
|
||||||
Orientation.ROOM_TO_TIME
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
scroll += calendarTable
|
|
||||||
|
|
||||||
if (editable) {
|
if (editable) {
|
||||||
CalendarEdit(this, calendar.querySelector(".calendar-edit") as HTMLElement)
|
CalendarEdit(this, calendar.querySelector(".calendar-edit") as HTMLElement)
|
||||||
}
|
}
|
||||||
|
@ -70,8 +60,6 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
|
||||||
}
|
}
|
||||||
|
|
||||||
onWheel {
|
onWheel {
|
||||||
autoScroll = false
|
|
||||||
|
|
||||||
val multiplier = when (it.deltaMode) {
|
val multiplier = when (it.deltaMode) {
|
||||||
1 -> 16.0
|
1 -> 16.0
|
||||||
2 -> window.innerHeight.toDouble()
|
2 -> window.innerHeight.toDouble()
|
||||||
|
@ -107,56 +95,8 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Orientation {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Columns contains time
|
|
||||||
* Rows contains rooms
|
|
||||||
*
|
|
||||||
* Like the old kif tool
|
|
||||||
*/
|
|
||||||
TIME_TO_ROOM,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Columns contains rooms
|
|
||||||
* Rows contains time
|
|
||||||
*
|
|
||||||
* Like the congress schedule
|
|
||||||
*/
|
|
||||||
ROOM_TO_TIME
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private var scroll = listOf<HTMLElement>()
|
|
||||||
|
|
||||||
private fun scrollAllVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
|
||||||
println("scroll ${scroll.size} elemenets")
|
|
||||||
for (calendarTable in scroll) {
|
|
||||||
calendarTable.scrollBy(ScrollToOptions(0.0, pixel, scrollBehavior))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun scrollAllHorizontalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
|
||||||
for (calendarTable in scroll) {
|
|
||||||
calendarTable.scrollBy(ScrollToOptions(pixel, 0.0, scrollBehavior))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun scrollAllVerticalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
|
||||||
for (calendarTable in scroll) {
|
|
||||||
calendarTable.scrollTo(ScrollToOptions(0.0, pixel, scrollBehavior))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun scrollAllHorizontalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
|
||||||
for (calendarTable in scroll) {
|
|
||||||
calendarTable.scrollTo(ScrollToOptions(pixel, 0.0, scrollBehavior))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initCalendar() {
|
fun initCalendar() {
|
||||||
document.getElementsByClassName("calendar").iterator().forEach { Calendar(it) }
|
Calendar(document.getElementsByClassName("calendar")[0] as? HTMLElement ?: return)
|
||||||
}
|
}
|
|
@ -3,13 +3,9 @@ package de.kif.frontend.views.calendar
|
||||||
import de.kif.frontend.launch
|
import de.kif.frontend.launch
|
||||||
import de.kif.frontend.repository.ScheduleRepository
|
import de.kif.frontend.repository.ScheduleRepository
|
||||||
import de.westermann.kwebview.ViewCollection
|
import de.westermann.kwebview.ViewCollection
|
||||||
import de.westermann.kwebview.async
|
|
||||||
import de.westermann.kwebview.interval
|
import de.westermann.kwebview.interval
|
||||||
import de.westermann.kwebview.iterator
|
import de.westermann.kwebview.iterator
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
import org.w3c.dom.INSTANT
|
|
||||||
import org.w3c.dom.SMOOTH
|
|
||||||
import org.w3c.dom.ScrollBehavior
|
|
||||||
import kotlin.browser.document
|
import kotlin.browser.document
|
||||||
import kotlin.js.Date
|
import kotlin.js.Date
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
@ -85,44 +81,6 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun update(scroll: ScrollBehavior) {
|
|
||||||
val currentTime = Date().let {
|
|
||||||
it.getHours() * 60 + it.getMinutes()
|
|
||||||
}
|
|
||||||
val rowTime = (currentTime / 15) * 15
|
|
||||||
|
|
||||||
var activeRow: CalendarRow? = null
|
|
||||||
|
|
||||||
for (row in this) {
|
|
||||||
if (row.time == rowTime) {
|
|
||||||
row.classList.clear()
|
|
||||||
for (str in row.classList) {
|
|
||||||
if ("now" in str) {
|
|
||||||
row.classList -= str
|
|
||||||
}
|
|
||||||
}
|
|
||||||
row.classList += "calendar-row"
|
|
||||||
row.classList += "calendar-now"
|
|
||||||
row.classList += "calendar-now-${currentTime - rowTime}"
|
|
||||||
activeRow = row
|
|
||||||
} else {
|
|
||||||
for (str in row.classList) {
|
|
||||||
if ("now" in str) {
|
|
||||||
row.classList -= str
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (calendar.autoScroll && activeRow != null) {
|
|
||||||
if (calendar.orientation == Calendar.Orientation.ROOM_TO_TIME) {
|
|
||||||
calendar.scrollVerticalTo((activeRow.offsetTop).toDouble(), scroll)
|
|
||||||
} else {
|
|
||||||
calendar.scrollHorizontalTo((activeRow.offsetLeft - 100).toDouble(), scroll)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
calendarEntries = document.getElementsByClassName("calendar-entry")
|
calendarEntries = document.getElementsByClassName("calendar-entry")
|
||||||
.iterator().asSequence().map { CalendarEntry(this, it) }.toList()
|
.iterator().asSequence().map { CalendarEntry(this, it) }.toList()
|
||||||
|
@ -160,7 +118,6 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
|
||||||
updateRows()
|
updateRows()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleRepository.onDelete {
|
ScheduleRepository.onDelete {
|
||||||
for (entry in calendarEntries) {
|
for (entry in calendarEntries) {
|
||||||
if (entry.scheduleId == it) {
|
if (entry.scheduleId == it) {
|
||||||
|
@ -174,12 +131,31 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async {
|
|
||||||
update(ScrollBehavior.INSTANT)
|
|
||||||
}
|
|
||||||
|
|
||||||
interval(1000) {
|
interval(1000) {
|
||||||
update(ScrollBehavior.SMOOTH)
|
val currentTime = Date().let {
|
||||||
|
it.getHours() * 60 + it.getMinutes()
|
||||||
|
}
|
||||||
|
val rowTime = (currentTime / 15) * 15
|
||||||
|
|
||||||
|
for (row in this) {
|
||||||
|
if (row.time == rowTime) {
|
||||||
|
row.classList.clear()
|
||||||
|
for (str in row.classList) {
|
||||||
|
if ("now" in str) {
|
||||||
|
row.classList -= str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row.classList += "calendar-row"
|
||||||
|
row.classList += "calendar-now"
|
||||||
|
row.classList += "calendar-now-${currentTime - rowTime}"
|
||||||
|
} else {
|
||||||
|
for (str in row.classList) {
|
||||||
|
if ("now" in str) {
|
||||||
|
row.classList -= str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 13 KiB |
|
@ -1,73 +1,90 @@
|
||||||
@import "../config";
|
@import "../config";
|
||||||
|
|
||||||
.board {
|
.board-header {
|
||||||
top: 0;
|
line-height: 3rem;
|
||||||
left: 0;
|
flex-grow: 1;
|
||||||
position: absolute;
|
font-family: "Bungee", sans-serif;
|
||||||
width: 100%;
|
font-weight: normal;
|
||||||
height: 100%;
|
font-size: 1.1rem;
|
||||||
|
padding-left: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card {
|
||||||
|
background-color: var(--background-card-color);
|
||||||
|
box-shadow: 0 0.1rem 0.2rem var(--shadow-color);
|
||||||
|
border-radius: $border-radius;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board {
|
||||||
|
padding: 1rem 0.4rem 2rem;
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
height: calc(100vh - 0.5rem);
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
position: absolute;
|
flex-grow: 1;
|
||||||
left: 0;
|
flex-basis: 0;
|
||||||
top: 0;
|
padding: 0 0.4rem;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
& > div {
|
&:nth-child(1) {
|
||||||
position: relative;
|
flex-grow: 5;
|
||||||
overflow: hidden;
|
}
|
||||||
|
|
||||||
&:first-child {
|
&:nth-child(2) {
|
||||||
width: 70%;
|
flex-grow: 4;
|
||||||
float: left;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
&:nth-child(3) {
|
||||||
width: 30%;
|
flex-grow: 4;
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-header {
|
.board-twitter {
|
||||||
height: 8rem !important;
|
.board-card {
|
||||||
|
height: calc(100% - 1.3rem);
|
||||||
|
|
||||||
& > div {
|
& > * {
|
||||||
height: 100%;
|
margin-top: -1px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-content {
|
.board-post {
|
||||||
top: 8rem !important;
|
margin-bottom: 0.5rem;
|
||||||
bottom: 0;
|
|
||||||
height: auto !important;
|
.post-name {
|
||||||
|
top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
padding-top: 2.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-logo {
|
.board-schedule-box {
|
||||||
img {
|
margin-bottom: 0.5rem;
|
||||||
height: 6rem;
|
padding: 1rem;
|
||||||
width: 6rem;
|
padding-bottom: 0.5rem;
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
table {
|
||||||
left: 4rem;
|
border-collapse: collapse;
|
||||||
margin-top: -3rem;
|
|
||||||
margin-left: -3rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-running {
|
.board-card-header {
|
||||||
column-count: 2;
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-schedule {
|
.board-schedule {
|
||||||
line-height: 1.3rem;
|
line-height: 1.3rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
min-width: 10rem;
|
|
||||||
display: flex;
|
&:not(:last-child) {
|
||||||
border-bottom: solid 1px var(--table-border-color)
|
border-bottom: solid 1px var(--table-border-color)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-schedule-color {
|
.board-schedule-color {
|
||||||
|
@ -95,46 +112,4 @@
|
||||||
width: 4rem;
|
width: 4rem;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: var(--text-secondary-color)
|
color: var(--text-secondary-color)
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-calendar {
|
|
||||||
height: 100% !important;
|
|
||||||
margin-top: 0 !important;
|
|
||||||
|
|
||||||
.calendar-table {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-table-box {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.calendar-row {
|
|
||||||
width: 100% !important;
|
|
||||||
height: 0.7rem !important;
|
|
||||||
}
|
|
||||||
.calendar-cell {
|
|
||||||
&:not(:first-child) {
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
flex-basis: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.calendar-entry::after {
|
|
||||||
content: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.board-header-date {
|
|
||||||
position: absolute;
|
|
||||||
line-height: 2rem;
|
|
||||||
font-size: 2rem;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -1rem;
|
|
||||||
left: 8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.board-twitter {
|
|
||||||
& > * {
|
|
||||||
margin-top: -1px !important;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -50,16 +50,15 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
height: 100vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-table {
|
.calendar-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: scroll;
|
overflow-x: scroll;
|
||||||
|
overflow-y: visible;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: width $transitionTime;
|
transition: width $transitionTime;
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-edit {
|
.calendar-edit {
|
||||||
|
@ -302,6 +301,7 @@
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
|
height: max-content;
|
||||||
|
|
||||||
.calendar-header, .calendar-row {
|
.calendar-header, .calendar-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -325,15 +325,10 @@
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
background-color: var(--background-secondary-color);
|
|
||||||
z-index: 5;
|
|
||||||
border-bottom: solid 1px var(--table-border-color);
|
|
||||||
|
|
||||||
.calendar-cell:first-child {
|
.calendar-cell:first-child {
|
||||||
|
flex-grow: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 6rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-cell:not(:first-child) {
|
.calendar-cell:not(:first-child) {
|
||||||
|
@ -352,10 +347,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-body {
|
|
||||||
margin-top: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-row {
|
.calendar-row {
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
height: 1.3rem;
|
height: 1.3rem;
|
||||||
|
@ -447,7 +438,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-header {
|
.calendar-header {
|
||||||
|
|
||||||
.calendar-cell {
|
.calendar-cell {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 6rem;
|
width: 6rem;
|
||||||
|
|
|
@ -51,7 +51,6 @@ select:-moz-focusring {
|
||||||
line-height: 2.5rem;
|
line-height: 2.5rem;
|
||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
top: 1.6rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,13 +185,10 @@ form {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control {
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-basis: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-basis: 0;
|
||||||
|
|
||||||
&:not(:first-child) {
|
&:not(:first-child) {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
|
|
|
@ -108,7 +108,6 @@
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
@import "../config";
|
|
||||||
|
|
||||||
.wall {
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wall-box {
|
|
||||||
width: 100%;
|
|
||||||
height: calc(33.3333% - 1rem);
|
|
||||||
overflow: hidden;
|
|
||||||
border-bottom: solid 2px var(--input-border-color);
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
height: calc(33.3333% + 2rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:first-child) {
|
|
||||||
.calendar-row, .calendar-header {
|
|
||||||
.calendar-cell:first-child {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-row, .calendar-header {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
line-height: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-entry {
|
|
||||||
top: 0 !important;
|
|
||||||
margin-top: -0.5rem !important;
|
|
||||||
bottom: 0 !important;
|
|
||||||
}
|
|
||||||
.calendar-entry::after {
|
|
||||||
content: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-table-box {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-body {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-row {
|
|
||||||
width: 100%;
|
|
||||||
flex-basis: 0;
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-cell {
|
|
||||||
flex-basis: 0;
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
line-height: 2rem;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.wall-calendar {
|
|
||||||
margin-top: 0 !important;
|
|
||||||
height: 100% !important;
|
|
||||||
|
|
||||||
.calendar-table {
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,13 +3,12 @@
|
||||||
|
|
||||||
@include color-setting;
|
@include color-setting;
|
||||||
|
|
||||||
|
@import "components/board";
|
||||||
@import "components/calendar";
|
@import "components/calendar";
|
||||||
@import "components/form";
|
@import "components/form";
|
||||||
@import "components/menu";
|
@import "components/menu";
|
||||||
@import "components/overview";
|
@import "components/overview";
|
||||||
@import "components/table-layout";
|
@import "components/table-layout";
|
||||||
@import "components/board";
|
|
||||||
@import "components/wall";
|
|
||||||
|
|
||||||
body, html {
|
body, html {
|
||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color);
|
||||||
|
@ -144,7 +143,6 @@ a {
|
||||||
margin-top: -2rem;
|
margin-top: -2rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 48%;
|
top: 48%;
|
||||||
left: 0;
|
|
||||||
|
|
||||||
span {
|
span {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
|
@ -64,7 +64,6 @@ fun Application.main() {
|
||||||
account()
|
account()
|
||||||
|
|
||||||
board()
|
board()
|
||||||
wall()
|
|
||||||
|
|
||||||
workGroup()
|
workGroup()
|
||||||
track()
|
track()
|
||||||
|
|
|
@ -15,13 +15,13 @@ object Configuration {
|
||||||
|
|
||||||
private val config: Config
|
private val config: Config
|
||||||
|
|
||||||
private class ConfigDelegate<T>(val item: Item<T>) {
|
class ConfigDelegate<T>(val item: Item<T>) {
|
||||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
return config[item]
|
return config[item]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> c(item: Item<T>) = ConfigDelegate(item)
|
fun <T> c(item: Item<T>) = ConfigDelegate(item)
|
||||||
|
|
||||||
private object ServerSpec : ConfigSpec("server") {
|
private object ServerSpec : ConfigSpec("server") {
|
||||||
val host by required<String>()
|
val host by required<String>()
|
||||||
|
|
|
@ -2,7 +2,6 @@ package de.kif.backend.route
|
||||||
|
|
||||||
import de.kif.backend.Configuration
|
import de.kif.backend.Configuration
|
||||||
import de.kif.backend.repository.PostRepository
|
import de.kif.backend.repository.PostRepository
|
||||||
import de.kif.backend.repository.RoomRepository
|
|
||||||
import de.kif.backend.repository.ScheduleRepository
|
import de.kif.backend.repository.ScheduleRepository
|
||||||
import de.kif.backend.view.respondMain
|
import de.kif.backend.view.respondMain
|
||||||
import de.kif.common.model.Schedule
|
import de.kif.common.model.Schedule
|
||||||
|
@ -12,11 +11,10 @@ import kotlinx.css.CSSBuilder
|
||||||
import kotlinx.css.Color
|
import kotlinx.css.Color
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
fun Route.board() {
|
fun Route.board() {
|
||||||
get("/brett") {
|
get("/brett") {
|
||||||
|
val postList = PostRepository.all().asReversed()
|
||||||
val scheduleList = ScheduleRepository.all().map {
|
val scheduleList = ScheduleRepository.all().map {
|
||||||
it to it.getAbsoluteStartTime() * 60
|
it to it.getAbsoluteStartTime() * 60
|
||||||
}.sortedBy { it.second }
|
}.sortedBy { it.second }
|
||||||
|
@ -24,114 +22,53 @@ fun Route.board() {
|
||||||
val referenceTime = Configuration.Schedule.referenceDate.time / 1000
|
val referenceTime = Configuration.Schedule.referenceDate.time / 1000
|
||||||
val now = referenceTime - (Date().time / 1000)
|
val now = referenceTime - (Date().time / 1000)
|
||||||
|
|
||||||
val refDate = Configuration.Schedule.referenceDate
|
|
||||||
val todayDate = Date()
|
|
||||||
|
|
||||||
val refDay = refDate.time / (1000 * 60 * 60 * 24)
|
|
||||||
val todayDay = todayDate.time / (1000 * 60 * 60 * 24)
|
|
||||||
val day = (todayDay - refDay).toInt()
|
|
||||||
|
|
||||||
val list = ScheduleRepository.getByDay(day)
|
|
||||||
val rooms = RoomRepository.all()
|
|
||||||
val schedules = list.groupBy { it.room }.mapValues { (_, it) ->
|
|
||||||
it.associateBy {
|
|
||||||
it.time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var max = 0
|
|
||||||
var min = 24 * 60
|
|
||||||
for (s in list) {
|
|
||||||
max = max(max, s.time + s.workGroup.length)
|
|
||||||
min = min(min, s.time)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (min > max) {
|
|
||||||
val h1 = max
|
|
||||||
max = min
|
|
||||||
min = h1
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true) {
|
|
||||||
min = min(min, 0)
|
|
||||||
max = max(max, 24 * 60)
|
|
||||||
}
|
|
||||||
|
|
||||||
min = (min / 60 - 1) * 60
|
|
||||||
max = (max / 60 + 2) * 60
|
|
||||||
|
|
||||||
respondMain(true, true) { theme ->
|
respondMain(true, true) { theme ->
|
||||||
content {
|
content {
|
||||||
div("board") {
|
div("board") {
|
||||||
div("board-header") {
|
div("board-schedules") {
|
||||||
div("board-running") {
|
attributes["data-reference"] = referenceTime.toString()
|
||||||
|
|
||||||
|
div("board-header") {
|
||||||
|
+"Arbeitskreise"
|
||||||
|
}
|
||||||
|
|
||||||
|
div("board-card board-schedule-box") {
|
||||||
|
div("board-card-header") {
|
||||||
|
+"Aktuell"
|
||||||
|
}
|
||||||
|
table {
|
||||||
for ((schedule, time) in scheduleList) {
|
for ((schedule, time) in scheduleList) {
|
||||||
div("board-schedule") {
|
createBoardSchedule(schedule, time)
|
||||||
attributes["data-id"] = schedule.id.toString()
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
div("board-schedule-color") {
|
div("board-card board-schedule-box") {
|
||||||
span {
|
div("board-card-header") {
|
||||||
attributes["style"] = CSSBuilder().apply {
|
+"Später"
|
||||||
val c = schedule.workGroup.track?.color
|
}
|
||||||
if (c != null) {
|
table {
|
||||||
backgroundColor = Color(c.toString())
|
for ((schedule, time) in scheduleList) {
|
||||||
}
|
createBoardSchedule(schedule, time)
|
||||||
}.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div("board-schedule-time") {
|
|
||||||
attributes["data-time"] = time.toString()
|
|
||||||
attributes["data-duration"] = schedule.workGroup.length.toString()
|
|
||||||
|
|
||||||
|
|
||||||
val startTime = (time % MINUTES_OF_DAY).let {
|
|
||||||
if (it < 0) it + MINUTES_OF_DAY else it
|
|
||||||
}
|
|
||||||
val sm = (startTime % 60).toString().padStart(2, '0')
|
|
||||||
val sh = (startTime / 60).toString().padStart(2, '0')
|
|
||||||
val startTimeString = "$sh:$sm"
|
|
||||||
|
|
||||||
val endTime = ((time + schedule.workGroup.length) % MINUTES_OF_DAY).let {
|
|
||||||
if (it < 0) it + MINUTES_OF_DAY else it
|
|
||||||
}
|
|
||||||
val em = (endTime % 60).toString().padStart(2, '0')
|
|
||||||
val eh = (endTime / 60).toString().padStart(2, '0')
|
|
||||||
val endTimeString = "$eh:$em"
|
|
||||||
|
|
||||||
+"$startTimeString - $endTimeString"
|
|
||||||
}
|
|
||||||
|
|
||||||
div("board-schedule-name") {
|
|
||||||
+schedule.workGroup.name
|
|
||||||
}
|
|
||||||
|
|
||||||
div("board-schedule-room") {
|
|
||||||
+schedule.room.name
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div("board-logo") {
|
}
|
||||||
img("KIF 47.0", "/static/images/logo.svg")
|
|
||||||
div("board-header-date") {
|
div("board-posts") {
|
||||||
}
|
div("board-header") {
|
||||||
|
+"Neuigkeiten"
|
||||||
|
}
|
||||||
|
for (post in postList) {
|
||||||
|
createPost(post, false, "board-card board-post")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div("board-content") {
|
|
||||||
div("board-calendar calendar") {
|
div("board-twitter") {
|
||||||
div("calendar-table") {
|
div("board-header") {
|
||||||
renderCalendar(
|
+"Twitter"
|
||||||
CalendarOrientation.ROOM_TO_TIME,
|
|
||||||
day,
|
|
||||||
min,
|
|
||||||
max,
|
|
||||||
rooms,
|
|
||||||
schedules
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
div("board-twitter") {
|
div("board-card") {
|
||||||
unsafe {
|
unsafe {
|
||||||
raw("""
|
raw("""
|
||||||
<a
|
<a
|
||||||
|
@ -154,3 +91,50 @@ fun Route.board() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun TABLE.createBoardSchedule(schedule: Schedule, time: Int) {
|
||||||
|
tr("board-schedule") {
|
||||||
|
attributes["data-id"] = schedule.id.toString()
|
||||||
|
|
||||||
|
td("board-schedule-color") {
|
||||||
|
span {
|
||||||
|
attributes["style"] = CSSBuilder().apply {
|
||||||
|
val c = schedule.workGroup.track?.color
|
||||||
|
if (c != null) {
|
||||||
|
backgroundColor = Color(c.toString())
|
||||||
|
}
|
||||||
|
}.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td("board-schedule-time") {
|
||||||
|
attributes["data-time"] = time.toString()
|
||||||
|
attributes["data-duration"] = schedule.workGroup.length.toString()
|
||||||
|
|
||||||
|
|
||||||
|
val startTime = (time % MINUTES_OF_DAY).let {
|
||||||
|
if (it < 0) it + MINUTES_OF_DAY else it
|
||||||
|
}
|
||||||
|
val sm = (startTime % 60).toString().padStart(2, '0')
|
||||||
|
val sh = (startTime / 60).toString().padStart(2, '0')
|
||||||
|
val startTimeString = "$sh:$sm"
|
||||||
|
|
||||||
|
val endTime = ((time + schedule.workGroup.length) % MINUTES_OF_DAY).let {
|
||||||
|
if (it < 0) it + MINUTES_OF_DAY else it
|
||||||
|
}
|
||||||
|
val em = (endTime % 60).toString().padStart(2, '0')
|
||||||
|
val eh = (endTime / 60).toString().padStart(2, '0')
|
||||||
|
val endTimeString = "$eh:$em"
|
||||||
|
|
||||||
|
+"$startTimeString - $endTimeString"
|
||||||
|
}
|
||||||
|
|
||||||
|
td("board-schedule-name") {
|
||||||
|
+schedule.workGroup.name
|
||||||
|
}
|
||||||
|
|
||||||
|
td("board-schedule-room") {
|
||||||
|
+schedule.room.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ private fun DIV.calendarCell(schedule: Schedule?) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DIV.renderCalendar(
|
private fun DIV.renderCalendar(
|
||||||
orientation: CalendarOrientation,
|
orientation: CalendarOrientation,
|
||||||
day: Int,
|
day: Int,
|
||||||
from: Int,
|
from: Int,
|
||||||
|
@ -141,14 +141,7 @@ fun DIV.renderCalendar(
|
||||||
fun Route.calendar() {
|
fun Route.calendar() {
|
||||||
|
|
||||||
get("/calendar") {
|
get("/calendar") {
|
||||||
val refDate = Configuration.Schedule.referenceDate
|
call.respondRedirect("/calendar/0", true)
|
||||||
val todayDate = Date()
|
|
||||||
|
|
||||||
val refDay = refDate.time / (1000 * 60 * 60 * 24)
|
|
||||||
val todayDay = todayDate.time / (1000 * 60 * 60 * 24)
|
|
||||||
val day = todayDay - refDay
|
|
||||||
|
|
||||||
call.respondRedirect("/calendar/$day", false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get("/calendar/{day}/rtt") {
|
get("/calendar/{day}/rtt") {
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
package de.kif.backend.route
|
|
||||||
|
|
||||||
import de.kif.backend.repository.RoomRepository
|
|
||||||
import de.kif.backend.repository.ScheduleRepository
|
|
||||||
import de.kif.backend.view.respondMain
|
|
||||||
import de.kif.common.model.Room
|
|
||||||
import de.kif.common.model.Schedule
|
|
||||||
import io.ktor.routing.Route
|
|
||||||
import io.ktor.routing.get
|
|
||||||
import kotlinx.html.div
|
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
data class WallData(
|
|
||||||
val number: Int,
|
|
||||||
val schedules: Map<Room, Map<Int, Schedule>>,
|
|
||||||
val max: Int,
|
|
||||||
val min: Int
|
|
||||||
)
|
|
||||||
|
|
||||||
suspend fun genWallData(day: Int): WallData {
|
|
||||||
val list = ScheduleRepository.getByDay(day)
|
|
||||||
val schedules = RoomRepository.all().associateWith { emptyMap<Int, Schedule>() } + list.groupBy { it.room }.mapValues { (_, it) ->
|
|
||||||
it.associateBy {
|
|
||||||
it.time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var max = 0
|
|
||||||
var min = 24 * 60
|
|
||||||
for (s in list) {
|
|
||||||
max = max(max, s.time + s.workGroup.length)
|
|
||||||
min = min(min, s.time)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (min > max) {
|
|
||||||
val h1 = max
|
|
||||||
max = min
|
|
||||||
min = h1
|
|
||||||
}
|
|
||||||
|
|
||||||
min = (min / 60 - 1) * 60
|
|
||||||
max = (max / 60 + 2) * 60
|
|
||||||
|
|
||||||
return WallData(day, schedules, max, min)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Route.wall() {
|
|
||||||
get("/wand") {
|
|
||||||
|
|
||||||
val days = (0..2).map { genWallData(it) }
|
|
||||||
|
|
||||||
val min = days.map { it.min }.min() ?: days.first().min
|
|
||||||
val max = days.map { it.max }.max() ?: days.first().max
|
|
||||||
|
|
||||||
respondMain(true, true) {
|
|
||||||
content {
|
|
||||||
div("wall") {
|
|
||||||
for (day in days) {
|
|
||||||
div("wall-box") {
|
|
||||||
div("wall-calendar calendar") {
|
|
||||||
div("calendar-table") {
|
|
||||||
renderCalendar(
|
|
||||||
CalendarOrientation.TIME_TO_ROOM,
|
|
||||||
day.number,
|
|
||||||
min,
|
|
||||||
max,
|
|
||||||
day.schedules.keys.toList().sortedBy { it.id },
|
|
||||||
day.schedules
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -49,62 +49,33 @@ data class Backup(
|
||||||
suspend fun import(data: String) {
|
suspend fun import(data: String) {
|
||||||
val backup = Message.json.parse(serializer(), data)
|
val backup = Message.json.parse(serializer(), data)
|
||||||
|
|
||||||
backup.users.forEach { UserRepository.create(it); println("Import user ${it.username}") }
|
backup.users.forEach { UserRepository.create(it) }
|
||||||
backup.posts.forEach { PostRepository.create(it); println("Import post") }
|
backup.posts.forEach { PostRepository.create(it) }
|
||||||
|
|
||||||
val oldRooms = RoomRepository.all()
|
backup.rooms.forEach { RoomRepository.create(it) }
|
||||||
val newRooms = backup.rooms.filterNot { oldRooms.any { i -> i.equalsIgnoreId(it) } }
|
val roomMap = RoomRepository.all().associateWith { it.id!! }
|
||||||
val roomMap = (oldRooms.associateWith { it.id!! } +
|
|
||||||
newRooms.map {
|
|
||||||
val id = RoomRepository.create(it)
|
|
||||||
println("Import room ${it.name}")
|
|
||||||
it to id
|
|
||||||
}).toList()
|
|
||||||
|
|
||||||
val oldTracks = TrackRepository.all()
|
backup.tracks.forEach { TrackRepository.create(it) }
|
||||||
val newTracks = backup.tracks.filterNot { oldTracks.any { i -> i.equalsIgnoreId(it) } }
|
val trackMap =TrackRepository.all().associateWith { it.id!! }
|
||||||
val trackMap = (oldTracks.associateWith { it.id!! } +
|
|
||||||
newTracks.map {
|
|
||||||
val id = TrackRepository.create(it)
|
|
||||||
println("Import track ${it.name}")
|
|
||||||
it to id
|
|
||||||
}).toList()
|
|
||||||
|
|
||||||
val oldWorkGroups = WorkGroupRepository.all()
|
backup.workGroups.forEach {
|
||||||
val newWorkGroups = backup.workGroups.filterNot { oldWorkGroups.any { i -> i.equalsIgnoreId(it) } }
|
var workGroup = it
|
||||||
val workGroupMap = (oldWorkGroups.associateWith { it.id!! } +
|
val track = workGroup.track
|
||||||
newWorkGroups.mapNotNull {
|
if (track != null) {
|
||||||
var workGroup = it
|
workGroup = workGroup.copy(track = track.copy(id = trackMap[track] ?: return@forEach))
|
||||||
val track = workGroup.track
|
}
|
||||||
if (track != null) {
|
|
||||||
workGroup = workGroup.copy(track = track.copy(id = trackMap.firstOrNull { (i,_) -> i.equalsIgnoreId(track) }?.second ?: run {
|
|
||||||
println("Cannot import work group, due to missing track")
|
|
||||||
return@mapNotNull null
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
val id = WorkGroupRepository.create(workGroup)
|
WorkGroupRepository.create(workGroup)
|
||||||
println("Import work group ${it.name}")
|
}
|
||||||
it to id
|
val workGroupMap = WorkGroupRepository.all().associateWith { it.id!! }
|
||||||
}).toList()
|
|
||||||
|
|
||||||
val oldSchedules = ScheduleRepository.all()
|
backup.schedules.forEach {
|
||||||
val newSchedules = backup.schedules.filterNot { oldSchedules.any { i -> i.equalsIgnoreId(it) } }
|
|
||||||
newSchedules.forEach {
|
|
||||||
ScheduleRepository.create(
|
ScheduleRepository.create(
|
||||||
it.copy(
|
it.copy(
|
||||||
room = it.room.copy(id = roomMap.firstOrNull { (i,_) -> i.equalsIgnoreId(it.room) }?.second ?: run {
|
room = it.room.copy(id = roomMap[it.room] ?: return@forEach),
|
||||||
println("Cannot import schedule, due to missing room")
|
workGroup = it.workGroup.copy(id = workGroupMap[it.workGroup] ?: return@forEach)
|
||||||
return@forEach
|
|
||||||
}),
|
|
||||||
workGroup = it.workGroup.copy(id = workGroupMap.firstOrNull { (i,_) -> i.equalsIgnoreId(it.workGroup) }?.second ?: run {
|
|
||||||
println("Cannot import schedule, due to missing work group")
|
|
||||||
return@forEach
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
println("Import schedule day=${it.day}, time=${it.time}, work group=${it.workGroup.name}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue