All Downloads are FREE. Search and download functionalities are using the official Maven repository.

japgolly.scalajs.react.extra.router.RouterCtl.scala Maven / Gradle / Ivy

There is a newer version: 3.0.0-beta6
Show newest version
package japgolly.scalajs.react.extra.router

import japgolly.scalajs.react._
import japgolly.scalajs.react.vdom.html_<^._
import org.scalajs.dom.html

/**
 * Router controller. A client API to the router.
 *
 * @tparam Route A data type that indicates a route that can be navigated to.
 */
abstract class RouterCtl[Route] {
  def baseUrl: BaseUrl
  def byPath: RouterCtl[Path]
  def refresh: Callback
  def pathFor(route: Route): Path
  def set(route: Route, via: SetRouteVia): Callback

  final def set(route: Route): Callback =
    set(route, SetRouteVia.HistoryPush)

  final def urlFor(route: Route): AbsUrl =
    pathFor(route).abs(baseUrl)

  final def setEH(route: Route): ReactEvent => Callback =
    e => set(route).asEventDefault(e).void

  final def setOnClick(route: Route): TagMod =
    ^.onClick ==> setEH(route)

  final def onLinkClick(route: Route): ReactMouseEvent => CallbackOption[Unit] =
    e =>
      CallbackOption.unless(ReactMouseEvent targetsNewTab_? e) >>
        setEH(route)(e)

  final def setOnLinkClick(route: Route): TagMod =
    ^.onClick ==> onLinkClick(route).andThen(_.toCallback)

  final def link(route: Route): VdomTagOf[html.Anchor] =
    <.a(^.href := urlFor(route).value, setOnLinkClick(route))

  @deprecated("Use .onSetRun(callback).setOnClick(route)", "forever")
  final def setOnClick(route: Route, callback: Callback): TagMod =
    onSetRun(callback).setOnClick(route)

  @deprecated("Use .onSetRun(callback).setOnLinkClick(route)", "forever")
  final def setOnLinkClick(route: Route, callback: Callback): TagMod =
    onSetRun(callback).setOnLinkClick(route)

  @deprecated("Use .onSetRun(callback).link(route)", "forever")
  final def link(route: Route, callback: Callback): VdomTagOf[html.Anchor] =
    onSetRun(callback).link(route)

  final def contramap[B](f: B => Route): RouterCtl[B] =
    new RouterCtl.Contramap(this, f)

  /**
   * Change the behaviour of [[set()]] and all derivatives.
   *
   * For example, this can be used to set a component's state immediately before setting a new route.
   */
  final def onSet(f: (Route, Callback) => Callback): RouterCtl[Route] =
    new RouterCtl.ModCB(this, f)

  /**
   * Change the behaviour of [[set()]] and all derivatives.
   *
   * For example, this can be used to set a component's state immediately before setting a new route.
   */
  final def onSet(f: Callback => Callback): RouterCtl[Route] =
    onSet((_, cb) => f(cb))

  /** Return a new version of this that executes the specified callback after setting new routes. */
  final def onSetRun(f: Callback): RouterCtl[Route] =
    onSet(_ >> f)

  final def narrow[B <: Route]: RouterCtl[B] =
    contramap(b => b)
}

object RouterCtl {
  private lazy val reuse: Reusability[RouterCtl[Any]] =
    Reusability[RouterCtl[Any]] {
      case (a, b) if a eq b                       => true // First because most common case and fastest
      case (Contramap(ac, af), Contramap(bc, bf)) => (af eq bf) && reuse.test(ac, bc)
      case _                                      => false
    }

  implicit def reusability[A]: Reusability[RouterCtl[A]] =
    reuse.asInstanceOf[Reusability[RouterCtl[A]]]

  case class Contramap[A, B](u: RouterCtl[A], f: B => A) extends RouterCtl[B] {
    override def baseUrl                   = u.baseUrl
    override def byPath                    = u.byPath
    override def refresh                   = u.refresh
    override def pathFor(b: B)             = u pathFor f(b)
    override def set(b: B, v: SetRouteVia) = u.set(f(b), v)
  }

  case class ModCB[A](u: RouterCtl[A], f: (A, Callback) => Callback) extends RouterCtl[A] {
    override def baseUrl                   = u.baseUrl
    override def byPath                    = u.byPath
    override def refresh                   = u.refresh
    override def pathFor(a: A)             = u pathFor a
    override def set(a: A, v: SetRouteVia) = f(a, u.set(a, v))
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy