From 7bf58894761742d4da8e6f52ce113ea7327e7114 Mon Sep 17 00:00:00 2001 From: Joris Date: Thu, 16 May 2019 09:40:02 +0200 Subject: Bootstrap --- client/src/router/Router.scala | 105 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 client/src/router/Router.scala (limited to 'client/src/router') diff --git a/client/src/router/Router.scala b/client/src/router/Router.scala new file mode 100644 index 0000000..60e5ef2 --- /dev/null +++ b/client/src/router/Router.scala @@ -0,0 +1,105 @@ +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) + + } + +} -- cgit v1.2.3