Skip to content

Commit

Permalink
Merge pull request #278 from UdashFramework/url-change-safety
Browse files Browse the repository at this point in the history
Handle anchor without href
  • Loading branch information
ddworak authored Apr 23, 2019
2 parents f6d1878 + 1bd0f99 commit b6f3f9a
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 25 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ lazy val selenium = jvmProject(project)

Test / parallelExecution := false,
Test / compile := (Test / compile)
.dependsOn(LocalProject("selenium-js") / compileAndOptimizeStatics).value,
.dependsOn(LocalProject("selenium-js") / compileStatics).value,

libraryDependencies ++= Dependencies.seleniumJvmDeps.value
)
Expand Down
43 changes: 19 additions & 24 deletions core/.js/src/main/scala/io/udash/routing/UrlChangeProvider.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package io.udash.routing

import com.avsystem.commons.misc.Opt
import com.avsystem.commons._
import io.udash.core.Url
import io.udash.properties.MutableBufferRegistration
import io.udash.utils.Registration
import org.scalajs.dom
import org.scalajs.dom.raw.HashChangeEvent
import org.scalajs.dom.raw.{HTMLAnchorElement, HashChangeEvent}
import org.scalajs.dom.{Element, Location}

import scala.scalajs.js
Expand All @@ -31,6 +31,7 @@ trait UrlChangeProvider {

/** Used for routing based on the URL part following # sign. */
object WindowUrlFragmentChangeProvider extends UrlChangeProvider {

import dom.{document, window}

private val callbacks: js.Array[Url => Unit] = js.Array()
Expand All @@ -54,6 +55,7 @@ object WindowUrlFragmentChangeProvider extends UrlChangeProvider {
* Don't forget to configure your web server to handle frontend routes. You may find "rewrite rules" mechanism useful.
*/
object WindowUrlPathChangeProvider extends UrlChangeProvider {

import dom.{document, window}
import org.scalajs.dom.experimental.{URL => JSUrl}
import org.scalajs.dom.raw.{MouseEvent, Node, PopStateEvent}
Expand Down Expand Up @@ -91,28 +93,21 @@ object WindowUrlPathChangeProvider extends UrlChangeProvider {

override def initialize(): Unit = {
window.document.addEventListener("click", (event: MouseEvent) => {
def findLink(el: Node): Element =
if (el == null) null
else if (el.nodeName.toLowerCase() == "a") el.asInstanceOf[Element]
else findLink(el.parentNode)

val target = findLink(event.target.asInstanceOf[Node])
if (target != null) {
val href = target.getAttribute("href")
val location = window.location
val newUrl = new JSUrl(href, location.toString)
val (samePath, sameHash, sameOrigin) =
(isSamePath(location, newUrl), isSameHash(location, newUrl), isSameOrigin(location, newUrl))
val ignore = shouldIgnoreClick(event, target, href, samePath, sameHash, sameOrigin)

if (!ignore) {
if (!samePath) {
val url = Url(href)
changeFragment(url)
event.target.opt
.collect { case node: Node => node }
.flatMap(Iterator.iterate(_)(_.parentNode).takeWhile(_ != null).collectFirstOpt { case a: HTMLAnchorElement => a })
.filter(_.getAttribute("href") != null)
.foreach { target =>
val href = target.getAttribute("href")
val location = window.location
val newUrl = new JSUrl(href, location.toString)
val (samePath, sameHash, sameOrigin) =
(isSamePath(location, newUrl), isSameHash(location, newUrl), isSameOrigin(location, newUrl))
if (!shouldIgnoreClick(event, target, href, samePath, sameHash, sameOrigin)) {
if (!samePath) changeFragment(Url(href))
event.preventDefault()
}
event.preventDefault()
}
}
})

window.addEventListener("popstate", (_: PopStateEvent) => callbacks.foreach(_.apply(currentFragment)))
Expand All @@ -126,11 +121,11 @@ object WindowUrlPathChangeProvider extends UrlChangeProvider {
}

override def changeFragment(url: Url): Unit = {
window.history.pushState(js.Dynamic.literal(url = url.value), "", url.value)
window.history.pushState(null, "", url.value)
val withoutHash = Url(url.value.takeWhile(_ != '#'))
callbacks.foreach(_.apply(withoutHash))
}

override def currentFragment: Url =
Url(Option(window.history.state).map(_.asInstanceOf[js.Dynamic].url.asInstanceOf[String]).getOrElse(window.location.pathname))
Url(window.history.state.opt.map(_.asInstanceOf[js.Dynamic].url.toString).getOrElse(window.location.pathname))
}

0 comments on commit b6f3f9a

Please sign in to comment.