diff options
author | Robert Jaros <rjaros@finn.pl> | 2019-04-02 22:26:26 +0200 |
---|---|---|
committer | Robert Jaros <rjaros@finn.pl> | 2019-04-02 22:26:26 +0200 |
commit | fec7d0f45cb04d96d1d268653af8eb71e07b208a (patch) | |
tree | 6ac84f4fc1e0fdf1cf6d659644c1b2cc809c1398 | |
parent | 7187d4209d81415af7b5c0bd62c011dd39905add (diff) | |
download | kvision-fec7d0f45cb04d96d1d268653af8eb71e07b208a.tar.gz kvision-fec7d0f45cb04d96d1d268653af8eb71e07b208a.tar.bz2 kvision-fec7d0f45cb04d96d1d268653af8eb71e07b208a.zip |
Support for tooltips and popovers.
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/core/PopupOptions.kt | 107 | ||||
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/core/Widget.kt | 129 |
2 files changed, 235 insertions, 1 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/PopupOptions.kt b/src/main/kotlin/pl/treksoft/kvision/core/PopupOptions.kt new file mode 100644 index 00000000..c929bea9 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/core/PopupOptions.kt @@ -0,0 +1,107 @@ +/* + * 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.core + +import pl.treksoft.kvision.utils.obj + +/** + * Tooltip / Popover placements. + */ +enum class Placement(internal val placement: String) { + AUTO("auto"), + TOP("top"), + BOTTOM("bottom"), + LEFT("left"), + RIGHT("right") +} + +/** + * Tooltip / Popover triggers. + */ +enum class Trigger(internal val trigger: String) { + CLICK("click"), + HOVER("hover"), + FOCUS("focus"), + MANUAL("manual") +} + +/** + * Tooltip options. + */ +data class TooltipOptions( + val title: String? = null, + val rich: Boolean? = null, + val animation: Boolean? = null, + val delay: Int? = null, + val placement: Placement? = null, + val triggers: List<Trigger>? = null, + val sanitize: Boolean? = null +) + +/** + * Convert TooltipOptions to JavaScript JSON object. + * @return JSON object + */ +fun TooltipOptions.toJs(): dynamic { + val trigger = this.triggers?.map { it.trigger }?.joinToString(" ") + return obj { + if (this@toJs.title != null) this.title = this@toJs.title + if (this@toJs.rich != null) this.html = this@toJs.rich + if (this@toJs.animation != null) this.animation = this@toJs.animation + if (this@toJs.delay != null) this.delay = this@toJs.delay + if (this@toJs.placement != null) this.placement = this@toJs.placement.placement + if (trigger != null) this.trigger = trigger + if (this@toJs.sanitize != null) this.sanitize = this@toJs.sanitize + } +} + +/** + * Popover options. + */ +data class PopoverOptions( + val content: String? = null, + val title: String? = null, + val rich: Boolean? = null, + val animation: Boolean? = null, + val delay: Int? = null, + val placement: Placement? = null, + val triggers: List<Trigger>? = null, + val sanitize: Boolean? = null +) + +/** + * Convert PopoverOptions to JavaScript JSON object. + * @return JSON object + */ +fun PopoverOptions.toJs(): dynamic { + val trigger = this.triggers?.map { it.trigger }?.joinToString(" ") + return obj { + if (this@toJs.content != null) this.content = this@toJs.content + if (this@toJs.title != null) this.title = this@toJs.title + if (this@toJs.rich != null) this.html = this@toJs.rich + if (this@toJs.animation != null) this.animation = this@toJs.animation + if (this@toJs.delay != null) this.delay = this@toJs.delay + if (this@toJs.placement != null) this.placement = this@toJs.placement.placement + if (trigger != null) this.trigger = trigger + if (this@toJs.sanitize != null) this.sanitize = this@toJs.sanitize + } +} diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt index 0d3f5c95..9bf84209 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt @@ -86,6 +86,12 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { protected var surroundingSpan by refreshOnUpdate(false) + private var tooltipSiblings: JQuery? = null + private var popoverSiblings: JQuery? = null + + protected var tooltipOptions: TooltipOptions? = null + protected var popoverOptions: PopoverOptions? = null + var eventTarget: Widget? = null private var vnode: VNode? = null @@ -225,7 +231,7 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { snattrs.add("id" to it) } title?.let { - snattrs.add("title" to it) + snattrs.add("title" to translate(it)) } role?.let { snattrs.add("role" to it) @@ -314,17 +320,20 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { } insert = { v -> vnode = v + afterInsertInternal(v) afterInsert(v) } postpatch = { ov, v -> vnode = v if (ov.elm !== v.elm) { + afterInsertInternal(v) afterInsert(v) } else { afterPostpatch(v) } } destroy = { + afterDestroyInternal() afterDestroy() vnode = null vnode @@ -425,6 +434,95 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { } /** + * Enables tooltip for the current widget. + * @param options tooltip options + * @return current widget + */ + open fun enableTooltip(options: TooltipOptions = TooltipOptions()): Widget { + this.tooltipOptions = options + getElementJQueryD()?.tooltip(options.copy(title = options.title?.let { translate(it) }).toJs()) + return this + } + + /** + * Shows tooltip for the current widget. + * @return current widget + */ + open fun showTooltip(): Widget { + if (this.tooltipOptions != null) { + getElementJQueryD()?.tooltip("show") + } + return this + } + + /** + * Hides tooltip for the current widget. + * @return current widget + */ + open fun hideTooltip(): Widget { + if (this.tooltipOptions != null) { + getElementJQueryD()?.tooltip("hide") + } + return this + } + + /** + * Disables tooltip for the current widget. + * @return current widget + */ + open fun disableTooltip(): Widget { + this.tooltipOptions = null + getElementJQueryD()?.tooltip("destroy") + return this + } + + /** + * Enables popover for the current widget. + * @param options popover options + * @return current widget + */ + open fun enablePopover(options: PopoverOptions = PopoverOptions()): Widget { + this.popoverOptions = options + getElementJQueryD()?.popover( + options.copy(title = options.title?.let { translate(it) }, + content = options.content?.let { translate(it) }).toJs() + ) + return this + } + + /** + * Shows popover for the current widget. + * @return current widget + */ + open fun showPopover(): Widget { + if (this.popoverOptions != null) { + getElementJQueryD()?.popover("show") + } + return this + } + + /** + * Hides popover for the current widget. + * @return current widget + */ + open fun hidePopover(): Widget { + if (this.popoverOptions != null) { + getElementJQueryD()?.popover("hide") + } + return this + } + + /** + * Disables popover for the current widget. + * @return current widget + */ + open fun disablePopover(): Widget { + this.popoverOptions = null + getElementJQueryD()?.popover("destroy") + return this + } + + /** * Toggles visibility of current widget. * @return current widget */ @@ -506,6 +604,23 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { } /** + * Internal method called after inserting Snabbdom vnode into the DOM. + */ + internal open fun afterInsertInternal(node: VNode) { + this.tooltipOptions?.let { + @Suppress("UnsafeCastFromDynamic") + getElementJQueryD().tooltip(it.copy(title = it.title?.let { translate(it) }).toJs()) + } + this.popoverOptions?.let { + @Suppress("UnsafeCastFromDynamic") + getElementJQueryD().popover( + it.copy(title = it.title?.let { translate(it) }, + content = it.content?.let { translate(it) }).toJs() + ) + } + } + + /** * Method called after inserting Snabbdom vnode into the DOM. */ protected open fun afterInsert(node: VNode) { @@ -518,6 +633,18 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { } /** + * Internal method called after destroying Snabbdom vnode. + */ + internal open fun afterDestroyInternal() { + this.tooltipOptions?.let { + getElementJQueryD().tooltip("destroy") + } + this.popoverOptions?.let { + getElementJQueryD().popover("destroy") + } + } + + /** * Method called after destroying Snabbdom vnode. */ protected open fun afterDestroy() { |