diff --git a/src/core/drive/morph_renderer.js b/src/core/drive/morph_renderer.js index 8f8181464..7d99d76e4 100644 --- a/src/core/drive/morph_renderer.js +++ b/src/core/drive/morph_renderer.js @@ -26,6 +26,8 @@ export class MorphRenderer extends Renderer { } #morphElements(currentElement, newElement, morphStyle = "outerHTML") { + this.isMorphingTurboFrame = this.#isFrameReloadedWithMorph(currentElement) + Idiomorph.morph(currentElement, newElement, { morphStyle: morphStyle, callbacks: { @@ -40,8 +42,8 @@ export class MorphRenderer extends Renderer { this.#remoteFrames().forEach((frame) => { if (this.#isFrameReloadedWithMorph(frame)) { this.#renderFrameWithMorph(frame) + frame.reload() } - frame.reload() }) } @@ -56,7 +58,7 @@ export class MorphRenderer extends Renderer { target: currentElement, detail: { currentElement, newElement } }) - this.#morphElements(currentElement, newElement, "innerHTML") + this.#morphElements(currentElement, newElement) } #shouldRemoveElement = (node) => { @@ -65,7 +67,7 @@ export class MorphRenderer extends Renderer { #shouldMorphElement = (node) => { if (node instanceof HTMLElement) { - return !node.hasAttribute("data-turbo-permanent") + return !node.hasAttribute("data-turbo-permanent") && (this.isMorphingTurboFrame || !this.#isFrameReloadedWithMorph(node)) } else { return true } diff --git a/src/tests/functional/page_refresh_tests.js b/src/tests/functional/page_refresh_tests.js index 73c0f4c5f..cb3a9ddd7 100644 --- a/src/tests/functional/page_refresh_tests.js +++ b/src/tests/functional/page_refresh_tests.js @@ -41,6 +41,23 @@ test("uses morphing to update remote frames marked with refresh='morph'", async // Only the frame marked with refresh="morph" uses morphing expect(await nextEventOnTarget(page, "refresh-morph", "turbo:before-frame-morph")).toBeTruthy() expect(await noNextEventOnTarget(page, "refresh-reload", "turbo:before-frame-morph")).toBeTruthy() + + await expect(page.locator("#refresh-morph")).toHaveText("Loaded morphed frame") + // Regular turbo-frames also gets reloaded since their complete attribute is removed + await expect(page.locator("#refresh-reload")).toHaveText("Loaded reloadable frame") +}) + +test("frames marked with refresh='morph' are excluded from full page morphing", async ({ page }) => { + await page.goto("/src/tests/fixtures/page_refresh.html") + + await page.evaluate(() => document.getElementById("refresh-morph").setAttribute("data-modified", "true")) + + await page.click("#form-submit") + await nextEventNamed(page, "turbo:render", { renderMethod: "morph" }) + await nextBeat() + + await expect(page.locator("#refresh-morph")).toHaveAttribute("data-modified", "true") + await expect(page.locator("#refresh-morph")).toHaveText("Loaded morphed frame") }) test("it preserves the scroll position when the turbo-refresh-scroll meta tag is 'preserve'", async ({ page }) => {