diff --git a/src/jsMain/kotlin/de/kif/frontend/views/calendar/Calendar.kt b/src/jsMain/kotlin/de/kif/frontend/views/calendar/Calendar.kt index a0dcbaa..3a6031e 100644 --- a/src/jsMain/kotlin/de/kif/frontend/views/calendar/Calendar.kt +++ b/src/jsMain/kotlin/de/kif/frontend/views/calendar/Calendar.kt @@ -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 }) diff --git a/src/jsMain/kotlin/de/westermann/kwebview/TouchPolyfill.kt b/src/jsMain/kotlin/de/westermann/kwebview/TouchPolyfill.kt new file mode 100644 index 0000000..52ff6ec --- /dev/null +++ b/src/jsMain/kotlin/de/westermann/kwebview/TouchPolyfill.kt @@ -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 = (0..length).map { item(it) }.filterNotNull() +fun TouchList.find(identifier: Int): Touch? = all().find { it.identifier == identifier } \ No newline at end of file diff --git a/src/jsMain/kotlin/de/westermann/kwebview/extensions.kt b/src/jsMain/kotlin/de/westermann/kwebview/extensions.kt index f461ae4..a34f22d 100644 --- a/src/jsMain/kotlin/de/westermann/kwebview/extensions.kt +++ b/src/jsMain/kotlin/de/westermann/kwebview/extensions.kt @@ -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 EventHandler.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)