Skip to content

Commit

Permalink
Read Frame Action when navigating programmatically
Browse files Browse the repository at this point in the history
  • Loading branch information
seanpdoyle committed Nov 24, 2021
1 parent b419c0d commit 335359a
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 13 deletions.
40 changes: 27 additions & 13 deletions src/core/frames/frame_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { FrameView } from "./frame_view"
import { LinkInterceptor, LinkInterceptorDelegate } from "./link_interceptor"
import { FrameRenderer } from "./frame_renderer"
import { session } from "../index"
import { isAction } from "../types"
import { Action, isAction } from "../types"

export class FrameController implements AppearanceObserverDelegate, FetchRequestDelegate, FormInterceptorDelegate, FormSubmissionDelegate, FrameElementDelegate, LinkInterceptorDelegate, ViewDelegate<Snapshot<FrameElement>> {
readonly element: FrameElement
Expand Down Expand Up @@ -86,13 +86,17 @@ export class FrameController implements AppearanceObserverDelegate, FetchRequest
this.currentURL = this.sourceURL
if (this.sourceURL) {
try {
const action = getVisitAction(this.element)
if (action) this.proposeVisitWithAction(this.element, action)
this.element.loaded = this.visit(expandURL(this.sourceURL))
this.appearanceObserver.stop()
await this.element.loaded
this.hasBeenLoaded = true
} catch (error) {
this.currentURL = previousURL
throw error
} finally {
this.fetchResponseLoaded = () => {}
}
}
}
Expand Down Expand Up @@ -260,23 +264,25 @@ export class FrameController implements AppearanceObserverDelegate, FetchRequest
frame.src = url
}

private proposeVisitIfNavigatedWithAction(frame: FrameElement, element: Element, submitter?: HTMLElement) {
const action = getAttribute("data-turbo-action", submitter, element, frame)

if (isAction(action)) {
const { visitCachedSnapshot } = new SnapshotSubstitution(frame)
frame.delegate.fetchResponseLoaded = (fetchResponse: FetchResponse) => {
if (frame.src) {
const { statusCode, redirected } = fetchResponse
const responseHTML = frame.ownerDocument.documentElement.outerHTML
const response = { statusCode, redirected, responseHTML }
private proposeVisitWithAction(frame: FrameElement, action: Action) {
const { visitCachedSnapshot } = new SnapshotSubstitution(frame)
frame.delegate.fetchResponseLoaded = (fetchResponse: FetchResponse) => {
if (frame.src) {
const { statusCode, redirected } = fetchResponse
const responseHTML = frame.ownerDocument.documentElement.outerHTML
const response = { statusCode, redirected, responseHTML }

session.visit(frame.src, { action, response, visitCachedSnapshot, willRender: false })
}
session.visit(frame.src, { action, response, visitCachedSnapshot, willRender: false })
}
}
}

private proposeVisitIfNavigatedWithAction(frame: FrameElement, element: Element, submitter?: HTMLElement) {
const action = getVisitAction(submitter, element, frame)

if (action) this.proposeVisitWithAction(frame, action)
}

private findFrameElement(element: Element, submitter?: HTMLElement) {
const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target")
return getFrameElementById(id) ?? this.element
Expand Down Expand Up @@ -411,6 +417,14 @@ class SnapshotSubstitution {
}
}

function getVisitAction(...elements: (Element|undefined)[]): Action | null {
const action = getAttribute("data-turbo-action", ...elements)

return isAction(action) ?
action :
null
}

function getFrameElementById(id: string | null) {
if (id != null) {
const element = document.getElementById(id)
Expand Down
13 changes: 13 additions & 0 deletions src/tests/functional/frame_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,19 @@ export class FrameTests extends TurboDriveTestCase {
this.assert.equal(await this.pathname, "/src/tests/fixtures/frames/frame.html")
}

async "test navigating turbo-frame[data-turbo-action=advance] programmatically pushes URL state"() {
await this.clickSelector("#add-turbo-action-to-frame")
await this.evaluate(
element => element.setAttribute("src", "/src/tests/fixtures/frames/frame.html"),
await this.querySelector("#frame")
)
await this.nextEventNamed("turbo:load")

this.assert.equal(await (await this.querySelector("h1")).getVisibleText(), "Frames")
this.assert.equal(await (await this.querySelector("#frame h2")).getVisibleText(), "Frame: Loaded")
this.assert.equal(await this.pathname, "/src/tests/fixtures/frames/frame.html")
}

async "test navigating turbo-frame[data-turbo-action=advance] to the same URL clears the [aria-busy] and [data-turbo-preview] state"() {
await this.clickSelector("#link-outside-frame-action-advance")
await this.nextEventNamed("turbo:load")
Expand Down

0 comments on commit 335359a

Please sign in to comment.