aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/reading/utils/Rx.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/reading/utils/Rx.scala')
-rw-r--r--src/main/scala/reading/utils/Rx.scala91
1 files changed, 66 insertions, 25 deletions
diff --git a/src/main/scala/reading/utils/Rx.scala b/src/main/scala/reading/utils/Rx.scala
index 76d05eb..a5b56ee 100644
--- a/src/main/scala/reading/utils/Rx.scala
+++ b/src/main/scala/reading/utils/Rx.scala
@@ -1,44 +1,85 @@
package reading.utils
+import java.util.concurrent.atomic.AtomicReference
+
+import scala.annotation.tailrec
+import scala.language.implicitConversions
import scala.util.{ Failure, Success }
import org.scalajs.dom.Element
-
-import scalatags.JsDom.all._
import rx._
+import scalacss.Defaults.StyleA
+import scalatags.JsDom.all._
-import Ctx.Owner.Unsafe._
+object RxUtils {
-object RxTag {
- def apply(r: Ctx.Data => HtmlTag): HtmlTag =
- rxMod(Rx(r(implicitly[Ctx.Data])))
+ implicit def rxFrag[T](n: Rx[T])(implicit f: T => Frag, ctx: Ctx.Owner): Frag = {
- private def rxMod(r: Rx[HtmlTag]): HtmlTag = {
- def rSafe = r.toTry match {
- case Success(v) => v.render
- case Failure(e) => span(e.toString, backgroundColor := "red").render
+ @tailrec def clearChildren(node: org.scalajs.dom.Node): Unit = {
+ if (node.firstChild != null) {
+ node.removeChild(node.firstChild)
+ clearChildren(node)
+ }
}
- var last = rSafe
- r.trigger {
- val newLast = rSafe
- Option(last.parentElement).foreach {
- _.replaceChild(newLast, last)
+
+ def fSafe: Frag = n match {
+ case r: Rx.Dynamic[T] => r.toTry match {
+ case Success(v) => v.render
+ case Failure(e) => span(e.getMessage, backgroundColor := "red").render
}
+ case v: Var[T] => v.now.render
+ }
+
+ var last = fSafe.render
+
+ val container = span(last).render
+
+ n.triggerLater {
+ val newLast = fSafe.render
+ //Rx[Seq[T]] can generate multiple children per propagate, so use clearChildren instead of replaceChild
+ clearChildren(container)
+ container.appendChild(newLast)
last = newLast
}
- span(
- bindNode(last)
- )
+ bindNode(container)
}
-}
-object RxAttr {
- def apply[Builder, T: AttrValue](attr: scalatags.generic.Attr, v: Rx[T]) = {
- val attrValue = new AttrValue[Rx[T]] {
- def apply(t: Element, a: Attr, r: Rx[T]): Unit = {
- val _ = r.trigger { implicitly[AttrValue[T]].apply(t, a, r.now) }
+ implicit def RxAttrValue[T: AttrValue](implicit ctx: Ctx.Owner) = new AttrValue[Rx.Dynamic[T]] {
+ def apply(t: Element, a: Attr, r: Rx.Dynamic[T]): Unit = {
+ r.trigger { implicitly[AttrValue[T]].apply(t, a, r.now) }
+ ()
+ }
+ }
+
+ implicit def RxStyleValue[T: StyleValue](implicit ctx: Ctx.Owner) = new StyleValue[Rx.Dynamic[T]] {
+ def apply(t: Element, s: Style, r: Rx.Dynamic[T]): Unit = {
+ r.trigger { implicitly[StyleValue[T]].apply(t, s, r.now) }
+ ()
+ }
+ }
+
+ implicit class bindRxStyle(rx: Rx[StyleA])(implicit ctx: Ctx.Owner) extends Modifier {
+ def applyTo(container: Element) = {
+ val atomicReference = new AtomicReference(rx.now)
+ applyStyle(container, atomicReference.get())
+ rx.triggerLater {
+ val current = rx.now
+ val previous = atomicReference.getAndSet(current)
+ removeStyle(container, previous)
+ applyStyle(container, current)
+ ()
}
+ ()
}
- scalatags.generic.AttrPair(attr, v, attrValue)
+
+ private def removeStyle(container: Element, style: StyleA): Unit =
+ style.classNameIterator.foreach { className =>
+ container.classList.remove(className.value)
+ }
+
+ private def applyStyle(container: Element, style: StyleA): Unit =
+ style.classNameIterator.foreach { className =>
+ container.classList.add(className.value)
+ }
}
}