Skip to content

Commit

Permalink
Merge pull request #292 from hotwired/same-page-refresh
Browse files Browse the repository at this point in the history
Perform same-page visit proposals without recreating the current destination
  • Loading branch information
jayohms authored Feb 23, 2024
2 parents b5ba032 + fff0fb6 commit c0d05e7
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 13 deletions.
18 changes: 11 additions & 7 deletions turbo/src/main/assets/js/turbo_bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,18 @@
// Adapter interface

visitProposedToLocation(location, options) {
if (window.Turbo && typeof Turbo.navigator.locationWithActionIsSamePage === "function") {
if (Turbo.navigator.locationWithActionIsSamePage(location, options.action)) {
if (window.Turbo && Turbo.navigator.locationWithActionIsSamePage(location, options.action)) {
// Scroll to the anchor on the page
TurboSession.visitProposalScrollingToAnchor(location.toString(), JSON.stringify(options))
Turbo.navigator.view.scrollToAnchorFromLocation(location)
return
} else if (window.Turbo && Turbo.navigator.location?.href === location.href) {
// Refresh the page without native proposal
TurboSession.visitProposalRefreshingPage(location.toString(), JSON.stringify(options))
this.visitLocationWithOptionsAndRestorationIdentifier(location, JSON.stringify(options), Turbo.navigator.restorationIdentifier)
} else {
// Propose the visit
TurboSession.visitProposedToLocation(location.toString(), JSON.stringify(options))
}
}

TurboSession.visitProposedToLocation(location.toString(), JSON.stringify(options))
}

// Turbolinks 5
Expand All @@ -114,7 +118,7 @@
}

visitStarted(visit) {
TurboSession.visitStarted(visit.identifier, visit.hasCachedSnapshot(), visit.location.toString())
TurboSession.visitStarted(visit.identifier, visit.hasCachedSnapshot(), visit.isPageRefresh || false, visit.location.toString())
this.currentVisit = visit
this.issueRequestForVisitWithIdentifier(visit.identifier)
this.changeHistoryForVisitWithIdentifier(visit.identifier)
Expand Down
41 changes: 38 additions & 3 deletions turbo/src/main/kotlin/dev/hotwire/turbo/session/TurboSession.kt
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class TurboSession internal constructor(
// Callbacks from Turbo JS Core

/**
* Called by Turbo bridge when a new visit is initiated.
* Called by Turbo bridge when a new visit is proposed.
*
* Warning: This method is public so it can be used as a Javascript Interface.
* You should never call this directly as it could lead to unintended behavior.
Expand All @@ -195,6 +195,38 @@ class TurboSession internal constructor(
callback { it.visitProposedToLocation(location, options) }
}

/**
* Called by Turbo bridge when a new visit proposal will refresh the
* current page.
*
* Warning: This method is public so it can be used as a Javascript Interface.
* You should never call this directly as it could lead to unintended behavior.
*
* @param location The location to visit.
* @param optionsJson A JSON block to be serialized into [TurboVisitOptions].
*/
@JavascriptInterface
fun visitProposalRefreshingPage(location: String, optionsJson: String) {
val options = TurboVisitOptions.fromJSON(optionsJson) ?: return
logEvent("visitProposalRefreshingPage", "location" to location, "options" to options)
}

/**
* Called by Turbo bridge when a new visit proposal will scroll to an anchor
* on the same page.
*
* Warning: This method is public so it can be used as a Javascript Interface.
* You should never call this directly as it could lead to unintended behavior.
*
* @param location The location to visit.
* @param optionsJson A JSON block to be serialized into [TurboVisitOptions].
*/
@JavascriptInterface
fun visitProposalScrollingToAnchor(location: String, optionsJson: String) {
val options = TurboVisitOptions.fromJSON(optionsJson) ?: return
logEvent("visitProposalScrollingToAnchor", "location" to location, "options" to options)
}

/**
* Called by Turbo bridge when a new visit has just started.
*
Expand All @@ -206,11 +238,14 @@ class TurboSession internal constructor(
* @param location The location being visited.
*/
@JavascriptInterface
fun visitStarted(visitIdentifier: String, visitHasCachedSnapshot: Boolean, location: String) {
fun visitStarted(visitIdentifier: String, visitHasCachedSnapshot: Boolean,
visitIsPageRefresh: Boolean, location: String
) {
logEvent(
"visitStarted", "location" to location,
"visitIdentifier" to visitIdentifier,
"visitHasCachedSnapshot" to visitHasCachedSnapshot
"visitHasCachedSnapshot" to visitHasCachedSnapshot,
"visitIsPageRefresh" to visitIsPageRefresh
)

currentVisit?.identifier = visitIdentifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,25 @@ class TurboSessionTest {
@Test
fun visitProposedToLocationFiresCallback() {
val options = TurboVisitOptions()
val newLocation = "${visit.location}/page"

session.currentVisit = visit
session.visitProposedToLocation(visit.location, options.toJson())
session.visitProposedToLocation(newLocation, options.toJson())

verify(callback).visitProposedToLocation(visit.location, options)
verify(callback).visitProposedToLocation(newLocation, options)
}

@Test
fun visitStartedSavesCurrentVisitIdentifier() {
val visitIdentifier = "12345"

session.currentVisit = visit.copy(identifier = visitIdentifier)
session.visitStarted(visitIdentifier, true, "https://turbo.hotwired.dev")
session.visitStarted(
visitIdentifier = visitIdentifier,
visitHasCachedSnapshot = true,
visitIsPageRefresh = false,
location = "https://turbo.hotwired.dev"
)

assertThat(session.currentVisit?.identifier).isEqualTo(visitIdentifier)
}
Expand Down

0 comments on commit c0d05e7

Please sign in to comment.