Skip to content

Commit

Permalink
Introduce turbo:before-frame-render event
Browse files Browse the repository at this point in the history
The problem
---

Similar to `turbo:before-render` events and the `<body>` element,
rendering `<turbo-frame>` events is opaque and isn't extensible.

The solution
---

Publish a `turbo:before-frame-render` event, dispatch it with a
`render()` function property in addition to the `resume()`.

This way, consumer applications can override rendering in the same style
as `turbo:before-render` events.
  • Loading branch information
seanpdoyle committed Oct 31, 2021
1 parent 1902259 commit b8ecfc7
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 3 deletions.
13 changes: 10 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 { dispatch, parseHTMLDocument } from "../../util"
import { FormSubmission, FormSubmissionDelegate } from "../drive/form_submission"
import { Snapshot } from "../snapshot"
import { ViewDelegate, ViewRenderOptions } from "../view"
Expand Down Expand Up @@ -217,8 +217,15 @@ export class FrameController implements AppearanceObserverDelegate, FetchRequest

// View delegate

allowsImmediateRender(snapshot: Snapshot, options: ViewRenderOptions<FrameElement>) {
return true
allowsImmediateRender({ element: newFrame }: Snapshot, options: ViewRenderOptions<FrameElement>) {
const event = dispatch("turbo:before-frame-render", { detail: { newFrame, ...options }, cancelable: true })
const { defaultPrevented, detail: { render } } = event

if (this.view.renderer && render) {
this.view.renderer.renderElement = render
}

return !defaultPrevented
}

viewRenderedSnapshot(snapshot: Snapshot, isPreview: boolean) {
Expand Down
18 changes: 18 additions & 0 deletions src/tests/functional/rendering_tests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TurboDriveTestCase } from "../helpers/turbo_drive_test_case"
import { Element } from "@theintern/leadfoot"
import { FrameElement } from "../../elements/frame_element"

export class RenderingTests extends TurboDriveTestCase {
async setup() {
Expand Down Expand Up @@ -163,6 +164,23 @@ export class RenderingTests extends TurboDriveTestCase {
this.assert(await permanentElement.equals(await this.permanentElement))
}

async "test before-frame-render event supports custom render function within turbo-frames"() {
await this.evaluate(() => addEventListener("turbo:before-frame-render", (event: Event) => {
if (event instanceof CustomEvent) {
const { render } = event.detail
event.detail.render = (c: FrameElement, n: FrameElement) => {
n.insertAdjacentHTML("beforeend", `<span id="custom-rendered">Custom Rendered Frame</span>`)
render(c, n)
}
}
}))

await this.clickSelector("#permanent-in-frame-element-link")
await this.nextBeat

this.assert.ok(await this.querySelector("#frame #custom-rendered"), "renders with custom function")
}

async "test preserves permanent elements within turbo-frames"() {
let permanentElement = await this.querySelector("#permanent-in-frame")
this.assert.equal(await permanentElement.getVisibleText(), "Rendering")
Expand Down

0 comments on commit b8ecfc7

Please sign in to comment.