aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2019-04-02 22:26:26 +0200
committerRobert Jaros <rjaros@finn.pl>2019-04-02 22:26:26 +0200
commitfec7d0f45cb04d96d1d268653af8eb71e07b208a (patch)
tree6ac84f4fc1e0fdf1cf6d659644c1b2cc809c1398
parent7187d4209d81415af7b5c0bd62c011dd39905add (diff)
downloadkvision-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.kt107
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Widget.kt129
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() {