diff options
| author | Robert Jaros <rjaros@finn.pl> | 2020-06-06 23:59:31 +0200 |
|---|---|---|
| committer | Robert Jaros <rjaros@finn.pl> | 2020-06-06 23:59:31 +0200 |
| commit | 2993527f8297169ce91826a91bfcf168e79ccc88 (patch) | |
| tree | b13a5b677a631fa9bf3921bb26701a69716dfd39 /kvision-modules/kvision-onsenui/src | |
| parent | dd41d887f679b3bb92e75845270d9981f7443ee9 (diff) | |
| download | kvision-2993527f8297169ce91826a91bfcf168e79ccc88.tar.gz kvision-2993527f8297169ce91826a91bfcf168e79ccc88.tar.bz2 kvision-2993527f8297169ce91826a91bfcf168e79ccc88.zip | |
New kvision-onsenui modules. Support for main structural components of OnsenUI with DSL builders. Work in progress. (#126)
Diffstat (limited to 'kvision-modules/kvision-onsenui/src')
14 files changed, 2695 insertions, 0 deletions
diff --git a/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/KVManagerOnsenui.kt b/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/KVManagerOnsenui.kt new file mode 100644 index 00000000..d0d184ab --- /dev/null +++ b/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/KVManagerOnsenui.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision + +internal val kVManagerOnsenuiInit = KVManagerOnsenui.init() + +/** + * Internal singleton object which initializes and configures KVision OnsenUI module. + */ +internal object KVManagerOnsenui { + + internal val ons = require("onsenui/js/onsenui.min.js") + + internal fun init() {} +} diff --git a/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/onsenui/OnsenUi.kt b/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/onsenui/OnsenUi.kt new file mode 100644 index 00000000..9cbc960e --- /dev/null +++ b/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/onsenui/OnsenUi.kt @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pl.treksoft.kvision.onsenui + +import pl.treksoft.kvision.KVManagerOnsenui.ons + +/** + * Back button event type. + */ +external interface BackButtonEvent { + fun callParentHandler() +} + +/** + * Change orientation event event type. + */ +external interface OrientationEvent { + val isPortrait: Boolean +} + +/** + * Platform types. + */ +enum class Platform(internal val type: String) { + OPERA("opera"), + FIREFOX("firefox"), + SAFARI("safari"), + CHROME("chrome"), + IE("ie"), + EDGE("edge"), + ANDROID("android"), + BLACKBERRY("blackberry"), + IOS("ios"), + WP("wp") +} + +/** + * Contains global Onsen UI functions. + */ +@Suppress("UnsafeCastFromDynamic") +object OnsenUi { + + /** + * Whether OnsenUI engine is loaded and ready. + */ + fun isReady(): Boolean { + return ons.isReady() + } + + /** + * Whether app is running inside Cordova. + */ + fun isWebView(): Boolean { + return ons.isWebView() + } + + /** + * A function called when engine is loaded and ready. + */ + fun ready(callback: () -> Unit) { + ons.ready(callback) + } + + /** + * Set default listener for the device back button event. + */ + fun setDefaultDeviceBackButtonListener(listener: (event: dynamic) -> Unit) { + ons.setDefaultDeviceBackButtonListener(listener) + } + + /** + * Disable default handler for the device back button. + */ + fun disableDeviceBackButtonHandler() { + ons.disableDeviceBackButtonHandler() + } + + /** + * Enable default handler for the device back button. + */ + fun enableDeviceBackButtonHandler() { + ons.enableDeviceBackButtonHandler() + } + + /** + * Enable status bar fill on IOS7 and above (except iPhone X) + */ + fun enableAutoStatusBarFill() { + ons.enableAutoStatusBarFill() + } + + /** + * Disable status bar fill on IOS7 and above (except iPhone X) + */ + fun disableAutoStatusBarFill() { + ons.disableAutoStatusBarFill() + } + + /** + * Creates a static element similar to iOS/Android status bar. + */ + fun mockStatusBar() { + ons.mockStatusBar() + } + + /** + * Disable all animations. + */ + fun disableAnimations() { + ons.disableAnimations() + } + + /** + * Enable all animations. + */ + fun enableAnimations() { + ons.enableAnimations() + } + + /** + * Disable automatic styling. + */ + fun disableAutoStyling() { + ons.disableAutoStyling() + } + + /** + * Enable automatic styling. + */ + fun enableAutoStyling() { + ons.enableAutoStyling() + } + + /** + * Disable adding fa- prefix for icons. + */ + fun disableIconAutoPrefix() { + ons.disableIconAutoPrefix() + } + + /** + * Applies a scroll fix for iOS UIWebView. + */ + fun forceUIWebViewScrollFix(force: Boolean) { + ons.forceUIWebViewScrollFix(force) + } + + /** + * Force styling for the given platform. + */ + fun forcePlatformStyling(platform: Platform) { + ons.forcePlatformStyling(platform.type) + } + + /** + * Set styling for the given platform (preferred) + */ + fun platformSelect(platform: Platform) { + ons.platform.select(platform.type) + } + + /** + * Whether device is iPhone. + * @param forceActualPlatform return the actual platform. + */ + fun isIOS(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isIOS(forceActualPlatform) + } + + /** + * Whether device is Android. + * @param forceActualPlatform return the actual platform. + */ + fun isAndroid(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isAndroid(forceActualPlatform) + } + + /** + * Whether device is Android phone. + */ + fun isAndroidPhone(): Boolean { + return ons.platform.isAndroidPhone() + } + + /** + * Whether device is Android tablet. + */ + fun isAndroidTablet(): Boolean { + return ons.platform.isAndroidTablet() + } + + /** + * Whether device is UIWebView. + */ + fun isUIWebView(): Boolean { + return ons.platform.isUIWebView() + } + + /** + * Whether device is iOS Safari. + */ + fun isIOSSafari(): Boolean { + return ons.platform.isIOSSafari() + } + + /** + * Whether device is WKWebView. + */ + fun isWKWebView(): Boolean { + return ons.platform.isWKWebView() + } + + /** + * Whether device is iPhone. + */ + fun isIPhone(): Boolean { + return ons.platform.isIPhone() + } + + /** + * Whether device is iPhone X, XS, XS Max, or XR. + */ + fun isIPhoneX(): Boolean { + return ons.platform.isIPhoneX() + } + + /** + * Whether device is iPad. + */ + fun isIPad(): Boolean { + return ons.platform.isIPad() + } + + /** + * Whether device is BlackBerry. + * @param forceActualPlatform return the actual platform. + */ + fun isBlackBerry(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isBlackBerry(forceActualPlatform) + } + + /** + * Whether browser is Opera. + * @param forceActualPlatform return the actual platform. + */ + fun isOpera(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isOpera(forceActualPlatform) + } + + /** + * Whether browser is Firefox. + * @param forceActualPlatform return the actual platform. + */ + fun isFirefox(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isFirefox(forceActualPlatform) + } + + /** + * Whether browser is Safari. + * @param forceActualPlatform return the actual platform. + */ + fun isSafari(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isSafari(forceActualPlatform) + } + + /** + * Whether browser is Chrome. + * @param forceActualPlatform return the actual platform. + */ + fun isChrome(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isChrome(forceActualPlatform) + } + + /** + * Whether browser is IE. + * @param forceActualPlatform return the actual platform. + */ + fun isIE(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isIE(forceActualPlatform) + } + + /** + * Whether device is iOS 7 or above. + */ + fun isIOS7above(): Boolean { + return ons.platform.isIOS7above() + } + + /** + * Whether browser is Edge. + * @param forceActualPlatform return the actual platform. + */ + fun isEdge(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isEdge(forceActualPlatform) + } + + /** + * Whether device is Windows Phone. + * @param forceActualPlatform return the actual platform. + */ + fun isWP(forceActualPlatform: Boolean = false): Boolean { + return ons.platform.isWP(forceActualPlatform) + } + + /** + * Function called on orientation change event. + */ + fun onOrientationChange(callback: (OrientationEvent) -> Unit) { + ons.orientation.on("change", callback) + } + + /** + * Function called on a single orientation change event. + */ + fun onOrientationChangeOnce(callback: (OrientationEvent) -> Unit) { + ons.orientation.once("change", callback) + } + + /** + * Remove orientation change event listener/all listeners. + */ + fun offOrientationChange(callback: ((OrientationEvent) -> Unit)? = undefined) { + ons.orientation.off("change", callback) + } + + /** + * Whether orientation is portrait. + */ + fun isPortrait(): Boolean { + return ons.orientation.isPortrait() + } + + /** + * Whether orientation is landscape. + */ + fun isLandscape(): Boolean { + return ons.orientation.isLandscape() + } +} diff --git a/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/onsenui/core/BackButton.kt b/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/onsenui/core/BackButton.kt new file mode 100644 index 00000000..0832e74e --- /dev/null +++ b/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/onsenui/core/BackButton.kt @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pl.treksoft.kvision.onsenui.core + +import com.github.snabbdom.VNode +import org.w3c.dom.events.MouseEvent +import pl.treksoft.kvision.core.Component +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.html.Align +import pl.treksoft.kvision.html.Div +import pl.treksoft.kvision.utils.set + +/** + * A back button component designed to be placed inside the toolbar. + * + * @constructor Creates a back button component. + * @param content the content of the button. + * @param rich whether [content] can contain HTML code + * @param align text align + * @param classes a set of CSS class names + * @param init an initializer extension function + */ +@Suppress("LeakingThis") +open class BackButton( + content: String? = null, + rich: Boolean = false, + align: Align? = null, + classes: Set<String> = setOf(), + init: (BackButton.() -> Unit)? = null +) : Div(content, rich, align, classes) { + + /** + * A modifier attribute to specify custom styles. + */ + var modifier: String? by refreshOnUpdate() + + init { + init?.invoke(this) + } + + override fun render(elementName: String, children: Array<dynamic>): VNode { + return super.render("ons-back-button", children) + } + + override fun getSnAttrs(): List<StringPair> { + val sn = super.getSnAttrs().toMutableList() + modifier?.let { + sn.add("modifier" to it) + } + return sn + } + + override fun afterInsert(node: VNode) { + getElement()?.asDynamic()?.onClick = { + var component: Component? = this + while (component != null) { + component = component.parent + if (component is Navigator) { + component.popPage() + break + } + } + } + } + + /** + * A convenient helper for easy setting onClick event handler. + */ + open fun onClick(handler: BackButton.(MouseEvent) -> Unit): BackButton { + this.setEventListener<BackButton> { + click = { e -> + self.handler(e) + } + } + return this + } +} + +/** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ +fun Div.backButton( + content: String? = null, + rich: Boolean = false, + align: Align? = null, + classes: Set<String>? = null, + className: String? = null, + init: (BackButton.() -> Unit)? = null +): BackButton { + val backButton = BackButton(content, rich, align, classes ?: className.set, init) + this.add(backButton) + return backButton +} diff --git a/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/onsenui/core/Navigator.kt b/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/onsenui/core/Navigator.kt new file mode 100644 index 00000000..fdd7ad8c --- /dev/null +++ b/kvision-modules/kvision-onsenui/src/main/kotlin/pl/treksoft/kvision/onsenui/core/Navigator.kt @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package pl.treksoft.kvision.onsenui.core + +import com.github.snabbdom.VNode +import pl.treksoft.kvision.KVManagerOnsenui.ons +import pl.treksoft.kvision.core.Display +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.onsenui.BackButtonEvent +import pl.treksoft.kvision.onsenui.splitter.SplitterContent +import pl.treksoft.kvision.onsenui.tabbar.Tab +import pl.treksoft.kvision.panel.Root +import pl.treksoft.kvision.panel.SimplePanel +import pl.treksoft.kvision.utils.createInstance +import pl.treksoft.kvision.utils.obj +import pl.treksoft.kvision.utils.set +import kotlin.js.Promise + +/** + * Navigator animation types. + */ +enum class NavAnimation(internal val type: String) { + NONE("none"), + FADE("fade"), + LIFT("lift"), + SLIDE("slide"), + FADEMD("fade-md"), + LIFTMD("lift-md"), + SLIDEMD("slide-md"), + FADEIOS("fade-ios"), + LIFTIOS("lift-ios"), + SLIDEIOS("slide-ios") +} + +/** + * A navigator component. + * + * @constructor Creates a navigator component. + * @param animation an animation type. + * @param swipeable an iOS swipe to pop feature + * @param classes a set of CSS class names + * @param init an initializer extension function + */ +open class Navigator( + animation: NavAnimation? = null, + swipeable: Boolean? = null, + classes: Set<String> = setOf(), + init: (Navigator.() -> Unit)? = null +) : SimplePanel(classes) { + + /** + * An animation type. + */ + var animation: NavAnimation? by refreshOnUpdate(animation) + + /** + * An iOS swipe to pop feature. + */ + var swipeable: Boolean? by refreshOnUpdate(swipeable) + + /** + * The width of swipeable area calculated from the edge (in pixels). + */ + var swipeTargetWidth: Number? by refreshOnUpdate() + + /** + * Specify how much the page needs to be swiped before popping. + */ + var swipeThreshold: Number? by refreshOnUpdate() + + /** + * Device back button event listener function. + */ + protected var onDeviceBackButtonCallback: ((BackButtonEvent) -> Unit)? = null + + /** + * Swipe event listener function. + */ + protected var onSwipeCallback: ((Number) -> Unit)? = null + + internal val pagesMap = mutableMapOf<String, Page>() + + init { + @Suppress("LeakingThis") + init?.invoke(this) + } + + /** + * A dynamic property returning current top page. + */ + val topPage: dynamic + get() = getElement()?.asDynamic()?.topPage + + /** + * A dynamic property returning current pages stack. + */ + val pages: dynamic + get() = getElement()?.asDynamic()?.pages + + override fun render(): VNode { + return render("ons-navigator", childrenVNodes()) + } + + override fun getSnAttrs(): List<StringPair> { + val sn = super.getSnAttrs().toMutableList() + animation?.let { + sn.add("animation" to it.type) + } + if (swipeable == true) { + sn.add("swipeable" to "swipeable") + } + swipeTargetWidth?.let { + sn.add("swipe-target-width" to "${it}px") + } + swipeThreshold?.let { + sn.add("swipe-threshold" to it.toString()) + } + return sn + } + + @Suppress("UnsafeCastFromDynamic") + override fun afterInsert(node: VNode) { + node.elm.asDynamic().pageLoader = (ons.PageLoader as Any).createInstance<Any>({ o: dynamic, done: dynamic -> + @Suppress("UnsafeCastFromDynamic") + val page: Page = o.page + done(page.getElement()) + }, { }) + if (onDeviceBackButtonCallback != null) { + getElement()?.asDynamic()?.onDeviceBackButton = onDeviceBackButtonCallback + } + if (onSwipeCallback != null) { + getElement()?.asDynamic()?.onSwipe = onSwipeCallback + } + this.getElementJQuery()?.on("prepush") { e, _ -> + this.dispatchEvent("onsPrepush", obj { detail = e }) + } + this.getElementJQuery()?.on("prepop") { e, _ -> + this.dispatchEvent("onsPrepop", obj { detail = e }) + } + this.getElementJQuery()?.on("postpush") { e, _ -> + this.dispatchEvent("onsPostpush", obj { detail = e }) + } + this.getElementJQuery()?.on("postpop") { e, _ -> + this.dispatchEvent("onsPostpop", obj { detail = e }) + } + } + + /** + * Pushes the specified page into the stack. + * @param pageId a given page id + * @param options a parameter object + */ + open fun pushPage(pageId: String, options: dynamic = undefined): Promise<Unit>? { + return pagesMap[pageId]?.let { pushPage(it, options) } + } + + /** + * Pushes the specified page into the stack. + * @param page a given page + * @param options a parameter object + */ + open fun pushPage(page: Page, options: dynamic = undefined): Promise<Unit>? { + page.display = null + add(page) + @Suppress("UnsafeCastFromDynamic") + return getElement()?.asDynamic()?.pushPage(page, options).then { + refreshPageStack() + } + } + + /** + * Pops the current page from the page stack. + * @param options a parameter object + */ + @Suppress("UnsafeCastFromDynamic") + open fun popPage(options: dynamic = undefined): Promise<Unit>? { + return if (children.size > 1) { + getElement()?.asDynamic()?.popPage(options).then { + (children.last() as? Page)?.dispatchDestroyEvent() + children.removeAt(children.size - 1).clearParent() + refreshPageStack() + } + } else { + null + } + } + + /** + * Replaces the current top page with the specified one. + * @param pageId a given page id + * @param options a parameter object + */ + open fun replacePage(pageId: String, options: dynamic = undefined): Promise<Unit>? { + return pagesMap[pageId]?.let { replacePage(it, options) } + } + + /** + * Replaces the current top page with the specified one. + * @param page a given page + * @param options a parameter object + */ + open fun replacePage(page: Page, options: dynamic = undefined): Promise<Unit>? { + page.display = null + add(page) + @Suppress("UnsafeCastFromDynamic") + return getElement()?.asDynamic()?.replacePage(page, options).then { + if (children.size > 1) { + (children.elementAt(children.size - 2) as? Page)?.dispatchDestroyEvent() + children.removeAt(children.size - 2).clearParent() + } + refreshPageStack() + } + } + + /** + * Insert the specified page into the stack with at a position defined by the index argument. + * @param index an insertion index + * @param pageId a given page id + * @param options a parameter object + */ + open fun insertPage(index: Int, pageId: String, options: dynamic = undefined): Promise<Unit>? { + return pagesMap[pageId]?.let { insertPage(index, it, options) } + } + + /** + * Insert the specified page into the stack with at a position defined by the index argument. + * @param index an insertion index + * @param page a given page + * @param options a parameter object + */ + @Suppress("UnsafeCastFromDynamic") + open fun insertPage(index: Int, page: Page, options: dynamic = undefined): Promise<Unit>? { + return if (index >= 0 && index < children.size) { + children.add(index, page) + page.parent?.remove(page) + page.parent = this + refreshPageStack() + getElement()?.asDynamic()?.insertPage(index, page, options) + } else { + null + } + } + + /** + * Remove the specified page at a position in the stack defined by the index argument. + * @param index index to delete + * @param options a parameter object + */ + @Suppress("UnsafeCastFromDynamic") + open fun removePage(index: Int, options: dynamic = undefined): Promise<Unit>? { + return if (index >= 0 && index < children.size && children.size > 1) { + getElement()?.asDynamic()?.removePage(index, options).then { + (children[index] as? Page)?.dispatchDestroyEvent() + children.removeAt(index).clearParent() + refreshPageStack() + } + } else { + null + } + } + + /** + * Clears page stack and adds the specified page to the stack. + * @param pageId a given page id + * @param options a parameter object + */ + open fun resetToPage(pageId: String, options: dynamic = undefined): Promise<Unit>? { + return pagesMap[pageId]?.let { resetToPage(it, options) } + } + + /** + * Clears page stack and adds the specified page to the stack. + * @param page a given page + * @param options a parameter object + */ + @Suppress("UnsafeCastFromDynamic") + open fun resetToPage(page: Page, options: dynamic = undefined): Promise<Unit>? { + page.display = null + add(page) + return getElement()?.asDynamic()?.resetToPage(page, options).then { + children.take(children.size - 1).forEach { + (it as? Page)?.dispatchDestroyEvent() + it.clearParent() + } + children.clear() + children.add(page) + refresh() + } + } + + /** + * Brings the given page to the top of the page stack. + * @param index index of a page to move + * @param options a parameter object + */ + @Suppress("UnsafeCastFromDynamic") + open fun bringPageTop(index: Int, options: dynamic = undefined): Promise<Unit>? { + return if (index >= 0 && index < children.size) { + getElement()?.asDynamic()?.bringPageTop(index, options).then { + val page = children.removeAt(index).clearParent() + (page as? Page)?.display = null + add(page) + } + } else { + null + } + } + + protected fun refreshPageStack() { + if (children.isNotEmpty()) { + children.take(children.size - 1).forEach { (it as? Page)?.display = Display.NONE } + (children.lastOrNull() as? Page)?.display = null + } + } + + /** + * Sets device back button event listener. + * @param callback an event listener + */ + open fun onDeviceBackButton(callback: (event: BackButtonEvent) -> Unit) { + onDeviceBackButtonCallback = callback + getElement()?.asDynamic()?.onDeviceBackButton = callback + } + + /** + * Clears device back button event listener. + */ + open fun onDeviceBackButtonClear() { + onDeviceBackButtonCallback = null + getElement()?.asDynamic()?.onDeviceBackButton = undefined + } + + /** + * Sets swipe event listener. + * @param callback an event listener + */ + open fun onSwipe(callback: (ratio: Number) -> Unit) { + onSwipeCallback = callback + getElement()?.asDynamic()?.onSwipe = callback + } + + /** + * Clears swipe event listener. + */ + open fun onSwipeClear() { + onSwipeCallback = null + getElement()?.asDynamic()?.onSwipe = undefined + } + +} + +/** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ +fun Root.navigator( + animation: NavAnimation? = null, + swipeable: Boolean? = null, + classes: Set<String>? = null, + className: String? = null, + init: (Navigator.() -> Unit)? = null +): Navigator { + val navigator = Navigator(animation, swipeable, classes ?: className.set, init) + this.add(navigator) + return navigator +} + +/** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ +fun SplitterContent.navigator( + animation: NavAnimation? = null, + swipeable: Boolean? = null, + classes: Set<String>? = null, + className: String? = null, + init: (Navigator.() -> Unit)? = null +): Navigator |
