From e90645f2485505301e3c42e6e742b9704011307e Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 31 Mar 2022 14:48:15 +0600 Subject: [PATCH] Element#onActionOutside --- CHANGELOG.md | 3 ++ .../inmo/micro_utils/common/OnClickOutside.kt | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 common/src/jsMain/kotlin/dev/inmo/micro_utils/common/OnClickOutside.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index ba2d74c95b5..025a0fe4719 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 0.9.18 +* `Common` + * New extensions for `Element`: `Element#onActionOutside` and `Element#onClickOutside` + ## 0.9.17 * `Common`: diff --git a/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/OnClickOutside.kt b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/OnClickOutside.kt new file mode 100644 index 00000000000..b5b4840f99d --- /dev/null +++ b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/OnClickOutside.kt @@ -0,0 +1,38 @@ +package dev.inmo.micro_utils.common + +import kotlinx.browser.document +import org.w3c.dom.* +import org.w3c.dom.events.Event +import org.w3c.dom.events.EventListener + +fun Element.onActionOutside(type: String, options: dynamic = null, callback: (Event) -> Unit): EventListener { + lateinit var observer: MutationObserver + val listener = EventListener { + val elementsToCheck = mutableListOf(this@onActionOutside) + while (it.target != this@onActionOutside && elementsToCheck.isNotEmpty()) { + val childrenGettingElement = elementsToCheck.removeFirst() + for (i in 0 until childrenGettingElement.childElementCount) { + elementsToCheck.add(childrenGettingElement.children[i] ?: continue) + } + } + if (elementsToCheck.isEmpty()) { + callback(it) + } + } + if (options == null) { + document.addEventListener(type, listener) + } else { + document.addEventListener(type, listener, options) + } + observer = onRemoved { + if (options == null) { + document.removeEventListener(type, listener) + } else { + document.removeEventListener(type, listener, options) + } + observer.disconnect() + } + return listener +} + +fun Element.onClickOutside(options: dynamic = null, callback: (Event) -> Unit) = onActionOutside("click", options, callback)