package yoga.router
import scala.scalajs.js
import scala.scalajs.js.URIUtils
import scala.xml.Node
import java.net.URI
import mhtml.Var
import org.scalajs.dom.raw.{ Element, Node => RawNode }
import org.scalajs.dom.{ document, window, Event, MouseEvent }
import yoga.model.Route
import yoga.view.index.Index
import yoga.view.licence.LicencePage
import yoga.view.notFound.NotFound
object Router {
private val route: Var[Route] = Var(parseRoute(Path.current()))
def render(): Node =
document.addEventListener("click", Handler.click)
window.addEventListener("popstate", Handler.popState)
}
mhtml-onumnount={ (n: RawNode) =>
document.removeEventListener("click", Handler.click)
window.removeEventListener("popstate", Handler.popState)
}
>
{route.map {
case Route.Index => Index()
case Route.Licence(uri) => LicencePage(uri)
case Route.NotFound => NotFound()
}}
object Path {
val index: String = "/"
def licence(uri: URI): String = s"/licence/${uri}"
def current(): String =
URIUtils.decodeURI(s"${window.location.pathname}${window.location.search}")
}
private def parseRoute(path: String): Route =
pathAndParams(path) match {
case (List(), _) => Route.Index
case (List("licence", uri), _) => Route.Licence(URI.create(uri))
case _ => Route.NotFound
}
private def pathAndParams(path: String): (List[String], List[String]) = {
println(path)
def splitPath(path: String) = path.split("/").drop(1).toList
path.split('?') match {
case Array(path) => (splitPath(path), Nil)
case Array(path, params) => (splitPath(path), params.split("&").toList)
}
}
private object Handler {
lazy val click: js.Function1[MouseEvent, Unit] =
routeTransitionOnAnchorClick { path =>
route := parseRoute(path)
window.history.pushState(null, "", path)
}
lazy val popState: js.Function1[Event, Unit] =
_ => route := parseRoute(Path.current())
}
private def routeTransitionOnAnchorClick(goTo: String => Unit)(event: MouseEvent): Unit =
if (event.button == 0)
Dom.findSelfOrParent("a", event.target.asInstanceOf[RawNode]) match {
case Some(node) =>
val elem = node.asInstanceOf[Element]
if (elem.getAttribute("data-nav") != "ignore") {
event.preventDefault()
val href = elem.getAttribute("href")
if (href != Path.current()) goTo(href)
}
case _ =>
}
private object Dom {
@annotation.tailrec
def findSelfOrParent(nodeName: String, current: RawNode): Option[RawNode] =
if (current.nodeName.toString.toLowerCase == nodeName.toLowerCase)
Some(current)
else if (current.parentNode == null)
None
else
findSelfOrParent(nodeName, current.parentNode)
}
}