diff options
Diffstat (limited to 'src/main/scala/reading/utils/Rx.scala')
-rw-r--r-- | src/main/scala/reading/utils/Rx.scala | 91 |
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) + } } } |