Skip to content

Commit

Permalink
Merge pull request #1234 from seanpdoyle/extract-morphing
Browse files Browse the repository at this point in the history
Extract and re-use element morphing logic
  • Loading branch information
jorgemanrubia authored Jul 12, 2024
2 parents 14284e6 + 922e488 commit 2ef50c9
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 193 deletions.
122 changes: 0 additions & 122 deletions src/core/drive/morph_renderer.js

This file was deleted.

48 changes: 48 additions & 0 deletions src/core/drive/morphing_page_renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { FrameElement } from "../../elements/frame_element"
import { MorphingFrameRenderer } from "../frames/morphing_frame_renderer"
import { PageRenderer } from "./page_renderer"
import { dispatch } from "../../util"
import { morphElements } from "../morphing"

export class MorphingPageRenderer extends PageRenderer {
static renderElement(currentElement, newElement) {
morphElements(currentElement, newElement, {
callbacks: {
beforeNodeMorphed: element => !canRefreshFrame(element)
}
})

for (const frame of currentElement.querySelectorAll("turbo-frame")) {
if (canRefreshFrame(frame)) refreshFrame(frame)
}

dispatch("turbo:morph", { detail: { currentElement, newElement } })
}

async preservingPermanentElements(callback) {
return await callback()
}

get renderMethod() {
return "morph"
}

get shouldAutofocus() {
return false
}
}

function canRefreshFrame(frame) {
return frame instanceof FrameElement &&
frame.src &&
frame.refresh === "morph" &&
!frame.closest("[data-turbo-permanent]")
}

function refreshFrame(frame) {
frame.addEventListener("turbo:before-frame-render", ({ detail }) => {
detail.render = MorphingFrameRenderer.renderElement
}, { once: true })

frame.reload()
}
8 changes: 4 additions & 4 deletions src/core/drive/page_view.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { nextEventLoopTick } from "../../util"
import { View } from "../view"
import { ErrorRenderer } from "./error_renderer"
import { MorphRenderer } from "./morph_renderer"
import { MorphingPageRenderer } from "./morphing_page_renderer"
import { PageRenderer } from "./page_renderer"
import { PageSnapshot } from "./page_snapshot"
import { SnapshotCache } from "./snapshot_cache"
Expand All @@ -16,10 +16,10 @@ export class PageView extends View {
}

renderPage(snapshot, isPreview = false, willRender = true, visit) {
const shouldMorphPage = this.isPageRefresh(visit) && snapshot.shouldMorphPage
const rendererClass = shouldMorphPage ? MorphRenderer : PageRenderer
const shouldMorphPage = this.isPageRefresh(visit) && this.snapshot.shouldMorphPage
const rendererClass = shouldMorphPage ? MorphingPageRenderer : PageRenderer

const renderer = new rendererClass(this.snapshot, snapshot, PageRenderer.renderElement, isPreview, willRender)
const renderer = new rendererClass(this.snapshot, snapshot, rendererClass.renderElement, isPreview, willRender)

if (!renderer.shouldRender) {
this.forceReloaded = true
Expand Down
14 changes: 14 additions & 0 deletions src/core/frames/morphing_frame_renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { FrameRenderer } from "./frame_renderer"
import { morphChildren } from "../morphing"
import { dispatch } from "../../util"

export class MorphingFrameRenderer extends FrameRenderer {
static renderElement(currentElement, newElement) {
dispatch("turbo:before-frame-morph", {
target: currentElement,
detail: { currentElement, newElement }
})

morphChildren(currentElement, newElement)
}
}
66 changes: 66 additions & 0 deletions src/core/morphing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Idiomorph } from "idiomorph/dist/idiomorph.esm.js"
import { dispatch } from "../util"

export function morphElements(currentElement, newElement, { callbacks, ...options } = {}) {
Idiomorph.morph(currentElement, newElement, {
...options,
callbacks: new DefaultIdiomorphCallbacks(callbacks)
})
}

export function morphChildren(currentElement, newElement) {
morphElements(currentElement, newElement.children, {
morphStyle: "innerHTML"
})
}

class DefaultIdiomorphCallbacks {
#beforeNodeMorphed

constructor({ beforeNodeMorphed } = {}) {
this.#beforeNodeMorphed = beforeNodeMorphed || (() => true)
}

beforeNodeAdded = (node) => {
return !(node.id && node.hasAttribute("data-turbo-permanent") && document.getElementById(node.id))
}

beforeNodeMorphed = (currentElement, newElement) => {
if (currentElement instanceof Element) {
if (!currentElement.hasAttribute("data-turbo-permanent") && this.#beforeNodeMorphed(currentElement, newElement)) {
const event = dispatch("turbo:before-morph-element", {
cancelable: true,
target: currentElement,
detail: { currentElement, newElement }
})

return !event.defaultPrevented
} else {
return false
}
}
}

beforeAttributeUpdated = (attributeName, target, mutationType) => {
const event = dispatch("turbo:before-morph-attribute", {
cancelable: true,
target,
detail: { attributeName, mutationType }
})

return !event.defaultPrevented
}

beforeNodeRemoved = (node) => {
return this.beforeNodeMorphed(node)
}

afterNodeMorphed = (currentElement, newElement) => {
if (currentElement instanceof Element) {
dispatch("turbo:morph-element", {
target: currentElement,
detail: { currentElement, newElement }
})
}
}
}
65 changes: 0 additions & 65 deletions src/core/streams/actions/morph.js

This file was deleted.

8 changes: 6 additions & 2 deletions src/core/streams/stream_actions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { session } from "../"
import morph from "./actions/morph"
import { morphElements, morphChildren } from "../morphing"

export const StreamActions = {
after() {
Expand Down Expand Up @@ -40,6 +40,10 @@ export const StreamActions = {
},

morph() {
morph(this)
const morph = this.hasAttribute("children-only") ?
morphChildren :
morphElements

this.targetElements.forEach((targetElement) => morph(targetElement, this.templateContent))
}
}

0 comments on commit 2ef50c9

Please sign in to comment.