Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

turbo-frame[busy] attribute #156

Merged
merged 1 commit into from
Apr 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/core/frames/frame_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ export class FrameController implements AppearanceObserverDelegate, FetchRequest
// Form submission delegate

formSubmissionStarted(formSubmission: FormSubmission) {

const frame = this.findFrameElement(formSubmission.formElement)
frame.setAttribute("busy", "")
}

formSubmissionSucceededWithResponse(formSubmission: FormSubmission, response: FetchResponse) {
Expand All @@ -203,7 +204,8 @@ export class FrameController implements AppearanceObserverDelegate, FetchRequest
}

formSubmissionFinished(formSubmission: FormSubmission) {

const frame = this.findFrameElement(formSubmission.formElement)
frame.removeAttribute("busy")
}

// View delegate
Expand Down
7 changes: 6 additions & 1 deletion src/tests/fixtures/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,15 @@
</div>
<hr>
<div id="targets-frame">
<form action="/__turbo/redirect" method="post" data-turbo-frame="frame">
<form action="/__turbo/redirect" method="post" data-turbo-frame="frame" class="one">
<input type="hidden" name="path" value="/src/tests/fixtures/one.html">
<button type="submit">Submit</button>
</form>

<form action="/__turbo/redirect" method="post" data-turbo-frame="frame" class="frame">
<input type="hidden" name="path" value="/src/tests/fixtures/frames/frame.html">
<button type="submit">Submit</button>
</form>
</div>
<turbo-frame id="frame">
<h2>Frame: Form</h2>
Expand Down
8 changes: 8 additions & 0 deletions src/tests/fixtures/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@
function eventListener(event) {
eventLogs.push([event.type, event.detail])
}
window.mutationLogs = []

new MutationObserver((mutations) => {
for (const { attributeName, target } of mutations.filter(({ type }) => type == "attributes")) {
if (target instanceof Element) {
mutationLogs.push([attributeName, target.id, target.getAttribute(attributeName)])
}
}
}).observe(document, { subtree: true, childList: true, attributes: true })
})([
"turbo:before-cache",
"turbo:before-render",
Expand Down
19 changes: 18 additions & 1 deletion src/tests/functional/form_submission_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,23 @@ export class FormSubmissionTests extends TurboDriveTestCase {
this.assert.equal(await this.attributeForSelector("#frame", "src"), url.href, "redirects the target frame")
}

async "test frame form submission toggles the ancestor frame's [busy] attribute"() {
await this.clickSelector("#frame form.redirect input[type=submit]")

this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), "", "sets [busy] on the #frame")
this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), null, "removes [busy] from the #frame")
}

async "test frame form submission toggles the target frame's [busy] attribute"() {
await this.clickSelector('#targets-frame form.frame [type="submit"]')

this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), "", "sets [busy] on the #frame")

const title = await this.querySelector("#frame h2")
this.assert.equal(await title.getVisibleText(), "Frame: Loaded")
this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), null, "removes [busy] from the #frame")
}

async "test frame form submission with empty created response"() {
const htmlBefore = await this.outerHTMLForSelector("#frame")
const button = await this.querySelector("#frame form.created input[type=submit]")
Expand Down Expand Up @@ -300,7 +317,7 @@ export class FormSubmissionTests extends TurboDriveTestCase {

async "test form submission targets disabled frame"() {
this.remote.execute(() => document.getElementById("frame")?.setAttribute("disabled", ""))
await this.clickSelector('#targets-frame [type="submit"]')
await this.clickSelector('#targets-frame form.one [type="submit"]')
await this.nextBody

this.assert.equal(await this.pathname, "/src/tests/fixtures/one.html")
Expand Down
7 changes: 7 additions & 0 deletions src/tests/functional/frame_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ export class FrameTests extends TurboDriveTestCase {
this.assert.equal(otherEvents.length, 0, "no more events")
}

async "test following a link driving a frame toggles the [busy] attribute"() {
seanpdoyle marked this conversation as resolved.
Show resolved Hide resolved
await this.clickSelector("#hello a")

this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), "", "sets [busy] on the #frame")
this.assert.equal(await this.nextAttributeMutationNamed("frame", "busy"), null, "removes [busy] from the #frame")
}

async "test following a link to a page without a matching frame results in an empty frame"() {
await this.clickSelector("#missing a")
await this.nextBeat
Expand Down
12 changes: 12 additions & 0 deletions src/tests/helpers/turbo_drive_test_case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { RemoteChannel } from "./remote_channel"
import { Element } from "@theintern/leadfoot"

type EventLog = [string, any]
type MutationLog = [string, string | null, string | null]

export class TurboDriveTestCase extends FunctionalTestCase {
eventLogChannel: RemoteChannel<EventLog> = new RemoteChannel(this.remote, "eventLogs")
mutationLogChannel: RemoteChannel<MutationLog> = new RemoteChannel(this.remote, "mutationLogs")
lastBody?: Element

async beforeTest() {
Expand Down Expand Up @@ -38,6 +40,16 @@ export class TurboDriveTestCase extends FunctionalTestCase {
return !records.some(([name]) => name == eventName)
}

async nextAttributeMutationNamed(elementId: string, attributeName: string): Promise<string | null> {
let record: MutationLog | undefined
while (!record) {
const records = await this.mutationLogChannel.read(1)
record = records.find(([name, id]) => name == attributeName && id == elementId)
}
const attributeValue = record[2]
return attributeValue
}

get nextBody(): Promise<Element> {
return (async () => {
let body
Expand Down