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) } }