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 rx._ import scalacss.Defaults.StyleA import scalatags.JsDom.all._ object RxUtils { implicit def rxFrag[T](n: Rx[T])(implicit f: T => Frag, ctx: Ctx.Owner): Frag = { @tailrec def clearChildren(node: org.scalajs.dom.Node): Unit = { if (node.firstChild != null) { node.removeChild(node.firstChild) clearChildren(node) } } 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 } bindNode(container) } 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) () } () } 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) } } }