Bugfixes calendar auto scroll

This commit is contained in:
Lars Westermann 2019-06-14 11:59:19 +02:00
parent 5cf089dd72
commit 73c4190231
Signed by: lars.westermann
GPG key ID: 9D417FA5BB9D5E1D
3 changed files with 126 additions and 39 deletions

View file

@ -3,15 +3,16 @@ package de.kif.frontend.views.calendar
import de.kif.frontend.launch
import de.kif.frontend.repository.RoomRepository
import de.kif.frontend.repository.ScheduleRepository
import de.westermann.kwebview.View
import de.westermann.kwebview.createHtmlView
import de.westermann.kwebview.iterator
import de.westermann.kwebview.*
import de.westermann.robots.website.toolkit.view.TouchEvent
import org.w3c.dom.*
import org.w3c.dom.events.Event
import org.w3c.dom.events.EventListener
import org.w3c.dom.events.MouseEvent
import org.w3c.dom.events.WheelEvent
import kotlin.browser.document
import kotlin.browser.window
import kotlin.js.Date
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@ -80,6 +81,41 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
}
}
private fun scroll(horizontal: Double, vertical: Double, event: Event? = null) {
var horizontalScroll = horizontal
var verticalScroll = vertical
if (verticalScroll > 0) {
val x = html.offsetTop - htmlBody.scrollTop
if (x > 0) {
val bodyScroll = min(x, verticalScroll)
verticalScroll -= bodyScroll
htmlBody.scrollBy(ScrollToOptions(0.0, bodyScroll, ScrollBehavior.INSTANT))
} else {
if (calendarTable.scrollTop + calendarTable.clientHeight + 5 >= calendarTable.scrollHeight) {
htmlBody.scrollBy(ScrollToOptions(0.0, verticalScroll, ScrollBehavior.INSTANT))
}
}
} else if (verticalScroll < 0) {
val x = html.offsetTop - htmlBody.scrollTop
if (x < 0) {
val bodyScroll = max(x, verticalScroll)
verticalScroll -= bodyScroll
htmlBody.scrollBy(ScrollToOptions(0.0, bodyScroll, ScrollBehavior.INSTANT))
} else {
if (calendarTable.scrollTop == 0.0) {
htmlBody.scrollBy(ScrollToOptions(0.0, verticalScroll, ScrollBehavior.INSTANT))
}
}
}
scrollHorizontalBy(horizontalScroll, ScrollBehavior.INSTANT)
scrollVerticalBy(verticalScroll, ScrollBehavior.INSTANT)
event?.preventDefault()
event?.stopPropagation()
}
init {
scroll += calendarTable
@ -113,52 +149,61 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
}
}
onWheel {
document.addEventListener("wheel", EventListener {
val event = it as? WheelEvent ?: return@EventListener
autoScroll = false
val multiplier = when (it.deltaMode) {
val multiplier = when (event.deltaMode) {
1 -> 16.0
2 -> window.innerHeight.toDouble()
else -> 1.0
}
var verticalScroll = it.deltaY * multiplier
scroll(event.deltaX * multiplier, event.deltaY * multiplier, event)
})
if (verticalScroll > 0) {
val x = html.offsetTop - htmlBody.scrollTop
if (x > 0) {
val bodyScroll = min(x, verticalScroll)
verticalScroll -= bodyScroll
htmlBody.scrollBy(ScrollToOptions(0.0, bodyScroll, ScrollBehavior.INSTANT))
} else {
if (calendarTable.scrollTop + calendarTable.clientHeight + 5 >= calendarTable.scrollHeight) {
htmlBody.scrollBy(ScrollToOptions(0.0, verticalScroll, ScrollBehavior.INSTANT))
}
}
} else if (verticalScroll < 0) {
val x = html.offsetTop - htmlBody.scrollTop
if (x < 0) {
val bodyScroll = max(x, verticalScroll)
verticalScroll -= bodyScroll
htmlBody.scrollBy(ScrollToOptions(0.0, bodyScroll, ScrollBehavior.INSTANT))
} else {
if (calendarTable.scrollTop == 0.0) {
htmlBody.scrollBy(ScrollToOptions(0.0, verticalScroll, ScrollBehavior.INSTANT))
}
}
}
var mousePoint: Point? = null
scrollHorizontalBy(it.deltaX * multiplier, ScrollBehavior.INSTANT)
scrollVerticalBy(verticalScroll, ScrollBehavior.INSTANT)
it.preventDefault()
}
onMouseDown {
document.addEventListener("mousedown", EventListener {
val event = it as? MouseEvent ?: return@EventListener
mousePoint = event.toPoint()
})
document.addEventListener("mouseup", EventListener {
mousePoint = null
})
document.addEventListener("mousemove", EventListener {
val event = it as? MouseEvent ?: return@EventListener
autoScroll = false
}
html.addEventListener("touchstart", EventListener {
val mp = mousePoint ?: return@EventListener
val p = event.toPoint()
scroll(mp.x - p.x, mp.y - p.y, event)
mousePoint = p
})
document.addEventListener("touchstart", EventListener {
val event = it as? TouchEvent ?: return@EventListener
mousePoint = event.toPoint()
})
document.addEventListener("touchend", EventListener {
mousePoint = null
})
document.addEventListener("touchmove", EventListener {
val event = it as? TouchEvent ?: return@EventListener
autoScroll = false
val mp = mousePoint ?: return@EventListener
val p = event.toPoint() ?: return@EventListener
scroll(mp.x - p.x, mp.y - p.y, event)
mousePoint = p
})
document.addEventListener("scroll", EventListener {
autoScroll = false
})

View file

@ -0,0 +1,39 @@
package de.westermann.robots.website.toolkit.view
import org.w3c.dom.events.EventTarget
import org.w3c.dom.events.UIEvent
/**
* @author lars
*/
open external class TouchEvent(type: String) : UIEvent {
open val changedTouches: TouchList
open val targetTouches: TouchList
open val touches: TouchList
open val ctrlKey: Boolean
open val shiftKey: Boolean
open val altKey: Boolean
open val metaKey: Boolean
fun getModifierState(keyArg: String): Boolean
}
open external class TouchList() {
open val length: Int
open fun item(index: Int): Touch?
}
open external class Touch() {
open val identifier: Int
open val target: EventTarget
open val screenX: Int
open val screenY: Int
open val clientX: Int
open val clientY: Int
open val pageX: Int
open val pageY: Int
}
operator fun TouchList.get(index: Int) = item(index)
fun TouchList.all(): List<Touch> = (0..length).map { item(it) }.filterNotNull()
fun TouchList.find(identifier: Int): Touch? = all().find { it.identifier == identifier }

View file

@ -1,6 +1,8 @@
package de.westermann.kwebview
import de.westermann.kobserve.event.EventHandler
import de.westermann.robots.website.toolkit.view.TouchEvent
import de.westermann.robots.website.toolkit.view.get
import org.w3c.dom.*
import org.w3c.dom.events.Event
import org.w3c.dom.events.EventListener
@ -72,6 +74,7 @@ inline fun <reified T> EventHandler<T>.bind(element: HTMLElement, event: String)
}
fun MouseEvent.toPoint(): Point = Point(clientX, clientY)
fun TouchEvent.toPoint(): Point? = touches[0]?.let { Point(it.clientX, it.clientY) }
fun DOMRect.toDimension(): Dimension = Dimension(x, y, width, height)
fun Number.format(digits: Int): String = this.asDynamic().toFixed(digits)