Skip to content

Commit

Permalink
Override Turbo Frame target from response
Browse files Browse the repository at this point in the history
  • Loading branch information
seanpdoyle committed Sep 7, 2021
1 parent 4383be4 commit b7564d6
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 16 deletions.
13 changes: 1 addition & 12 deletions src/core/drive/form_submission.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FetchRequest, FetchMethod, fetchMethodFromString, FetchRequestHeaders } from "../../http/fetch_request"
import { FetchResponse } from "../../http/fetch_response"
import { expandURL } from "../url"
import { dispatch } from "../../util"
import { dispatch, getCookieValue } from "../../util"
import { StreamMessage } from "../streams/stream_message"

export interface FormSubmissionDelegate {
Expand Down Expand Up @@ -181,17 +181,6 @@ function buildFormData(formElement: HTMLFormElement, submitter?: HTMLElement): F
return formData
}

function getCookieValue(cookieName: string | null) {
if (cookieName != null) {
const cookies = document.cookie ? document.cookie.split("; ") : []
const cookie = cookies.find((cookie) => cookie.startsWith(cookieName))
if (cookie) {
const value = cookie.split("=").slice(1).join("=")
return value ? decodeURIComponent(value) : undefined
}
}
}

function getMetaContent(name: string) {
const element: HTMLMetaElement | null = document.querySelector(`meta[name="${name}"]`)
return element && element.content
Expand Down
14 changes: 11 additions & 3 deletions src/core/frames/frame_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FrameElement, FrameElementDelegate, FrameLoadingStyle } from "../../ele
import { FetchMethod, FetchRequest, FetchRequestDelegate, FetchRequestHeaders } from "../../http/fetch_request"
import { FetchResponse } from "../../http/fetch_response"
import { AppearanceObserver, AppearanceObserverDelegate } from "../../observers/appearance_observer"
import { parseHTMLDocument } from "../../util"
import { deleteCookieValue, getCookieValue, parseHTMLDocument } from "../../util"
import { FormSubmission, FormSubmissionDelegate } from "../drive/form_submission"
import { Snapshot } from "../snapshot"
import { ViewDelegate } from "../view"
Expand Down Expand Up @@ -201,8 +201,16 @@ export class FrameController implements AppearanceObserverDelegate, FetchRequest
}

formSubmissionSucceededWithResponse(formSubmission: FormSubmission, response: FetchResponse) {
const frame = this.findFrameElement(formSubmission.formElement)
frame.delegate.loadResponse(response)
const turboFrameOverride = getCookieValue("Turbo-Frame")

if (turboFrameOverride == "_top") {
deleteCookieValue("Turbo-Frame")

session.visit(response.location, { action: "advance" })
} else {
const frame = this.findFrameElement(formSubmission.formElement)
frame.delegate.loadResponse(response)
}
}

formSubmissionFailedWithResponse(formSubmission: FormSubmission, fetchResponse: FetchResponse) {
Expand Down
5 changes: 5 additions & 0 deletions src/tests/fixtures/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ <h2>Frame: Form</h2>
<input type="hidden" name="path" value="/src/tests/fixtures/frames/form.html">
<input type="submit">
</form>
<form action="/__turbo/redirect" method="post" class="redirect turbo-frame-header">
<input type="hidden" name="cookies[Turbo-Frame]" value="_top">
<input type="hidden" name="path" value="/src/tests/fixtures/one.html">
<input type="submit">
</form>
<form action="/__turbo/messages" method="post" class="created">
<input type="hidden" name="content" value="Hello!">
<input type="submit" style="">
Expand Down
9 changes: 9 additions & 0 deletions src/tests/functional/form_submission_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,15 @@ export class FormSubmissionTests extends TurboDriveTestCase {
this.assert.equal(await title.getVisibleText(), "Frame: Unprocessable Entity")
}

async "test frame form submission response with Turbo-Frame cookie"() {
await this.clickSelector("#frame form.redirect.turbo-frame-header [type=submit]")
await this.nextBeat

const title = await this.querySelector("h1")
this.assert.equal(await title.getVisibleText(), "One")
this.assert.equal(await this.pathname, "/src/tests/fixtures/one.html")
}

async "test invalid frame form submission with internal server errror status"() {
await this.clickSelector("#frame form.internal_server_error input[type=submit]")
await this.nextBeat
Expand Down
5 changes: 4 additions & 1 deletion src/tests/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ router.use((request, response, next) => {
})

router.post("/redirect", (request, response) => {
const { path, sleep, ...query } = request.body
const { path, sleep, cookies, ...query } = request.body
const pathname = path ?? "/src/tests/fixtures/one.html"
const enctype = request.get("Content-Type")
if (enctype) {
query.enctype = enctype
}
if (typeof cookies == "object" && "Turbo-Frame" in cookies) {
response.cookie("Turbo-Frame", cookies["Turbo-Frame"], { path: "/", httpOnly: false })
}
setTimeout(() => response.redirect(303, url.format({ pathname, query })), parseInt(sleep || "0", 10))
})

Expand Down
17 changes: 17 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,20 @@ export function uuid() {
}
}).join("")
}

export function getCookieValue(cookieName: string | null) {
if (cookieName != null) {
const cookies = document.cookie ? document.cookie.split("; ") : []
const cookie = cookies.find((cookie) => cookie.startsWith(cookieName))
if (cookie) {
const value = cookie.split("=").slice(1).join("=")
return value ? decodeURIComponent(value) : undefined
}
}
}

export function deleteCookieValue(cookieName: string) {
const dateInThePast = new Date(0)

document.cookie = `${cookieName}=; expires=${dateInThePast.toUTCString()}`
}

0 comments on commit b7564d6

Please sign in to comment.