You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

81 lines
2.4 KiB
Kotlin

package me.eater.threedom.dom
import me.eater.threedom.event.Event
import me.eater.threedom.generated.EventNames
class EventTree(block: EventTree.() -> Unit = {}) {
private val topLevel: MutableMap<String, MutableSet<(Event<*>) -> Unit>> =
mutableMapOf()
private val listeners: MutableMap<String, MutableMap<Long, MutableSet<(Event<*>) -> Unit>>> =
mutableMapOf()
private val nodes: MutableMap<Long, MutableSet<String>> = mutableMapOf()
init {
block(this)
}
fun addTopLevelEventListener(eventName: String, handler: (Event<*>) -> Unit) {
this.topLevel.getOrPut(eventName, ::mutableSetOf).add(handler)
}
fun addEventListener(eventName: String, target: INode<*>, handler: (Event<*>) -> Unit) {
this.listeners.getOrPut(eventName, ::mutableMapOf).getOrPut(target.nodeId, ::mutableSetOf).add(handler)
this.nodes.getOrPut(target.nodeId, ::mutableSetOf).add(eventName)
}
fun removeNode(node: INode<*>) {
val events = this.nodes.remove(node.nodeId) ?: return
for (event in events) {
this.listeners[event]?.remove(node.nodeId)
}
}
fun trigger(eventName: String, target: INode<*>, event: Event<*>) {
this.topLevel[eventName]?.let {
for (handler in it) {
handler(event)
if (!event.propagate) {
return
}
}
if (!event.bubble) {
return
}
}
val map = this.listeners[eventName] ?: return
var current: INode<*>? = target
while (current != null) {
val set = map[current.nodeId]
if (set != null) {
for (eventHandler in set) {
eventHandler(event)
if (!event.propagate) {
break
}
}
}
if (!event.bubble) {
break
}
current = current.parentNode
}
}
@Suppress("UNCHECKED_CAST")
inline fun <reified T> on(target: INode<*>, noinline block: (Event<T>) -> Unit) =
addEventListener(EventNames.getEventName<T>(), target, block as (Event<*>) -> Unit)
@Suppress("UNCHECKED_CAST")
inline fun <reified T> on(noinline block: (Event<T>) -> Unit) =
addTopLevelEventListener(EventNames.getEventName<T>(), block as (Event<*>) -> Unit)
}