diff --git a/src/core/streams/actions/morph.js b/src/core/streams/actions/morph.js new file mode 100644 index 000000000..ed92291e7 --- /dev/null +++ b/src/core/streams/actions/morph.js @@ -0,0 +1,68 @@ +import { Idiomorph } from "idiomorph/dist/idiomorph.esm" +import { dispatch } from "../../../util" + +export default function morph(streamElement) { + const morphStyle = streamElement.hasAttribute("children-only") ? "innerHTML" : "outerHTML" + streamElement.targetElements.forEach((element) => { + try { + Idiomorph.morph(element, streamElement.templateContent, { + morphStyle: morphStyle, + ignoreActiveValue: true, + callbacks: { + beforeNodeAdded, + beforeNodeMorphed, + beforeAttributeUpdated, + beforeNodeRemoved, + afterNodeMorphed, + }, + }) + } catch (e) { + console.error(e) + } + }) +} + +function beforeNodeAdded(node) { + return !(node.id && node.hasAttribute("data-turbo-permanent") && document.getElementById(node.id)) +} + +function beforeNodeRemoved(node) { + return beforeNodeAdded(node) +} + +function beforeNodeMorphed(target, newElement) { + if (target instanceof HTMLElement && !target.hasAttribute("data-turbo-permanent")) { + const event = dispatch("turbo:before-morph-element", { + cancelable: true, + detail: { + target, + newElement, + }, + }) + return !event.defaultPrevented + } + return false +} + +function beforeAttributeUpdated(attributeName, target, mutationType) { + const event = dispatch("turbo:before-morph-attribute", { + cancelable: true, + target, + detail: { + attributeName, + mutationType, + }, + }) + return !event.defaultPrevented +} + +function afterNodeMorphed(target, newElement) { + if (newElement instanceof HTMLElement) { + dispatch("turbo:morph-element", { + target, + detail: { + newElement, + }, + }) + } +} diff --git a/src/core/streams/stream_actions.js b/src/core/streams/stream_actions.js index 8dcac5803..e7fc68836 100644 --- a/src/core/streams/stream_actions.js +++ b/src/core/streams/stream_actions.js @@ -1,6 +1,5 @@ import { session } from "../" -import { Idiomorph } from "idiomorph/dist/idiomorph.esm.js" -import { dispatch } from "../../util" +import morph from "./actions/morph" export const StreamActions = { after() { @@ -41,73 +40,6 @@ export const StreamActions = { }, morph() { - this.targetElements.forEach((targetElement) => { - try { - const morphStyle = targetElement.getAttribute("data-turbo-morph-style") || "outerHTML" - Idiomorph.morph(targetElement, this.templateContent, { - morphStyle: morphStyle, - ignoreActiveValue: true, - callbacks: { - beforeNodeAdded, - beforeNodeMorphed, - beforeAttributeUpdated, - beforeNodeRemoved, - afterNodeMorphed - } - }) - - dispatch("turbo:morph", { - detail: { - currentElement: targetElement, - newElement: this.templateContent - } - }) - } catch (error) { - console.error(error) - } - }) - } -} - -const beforeNodeAdded = (node) => { - return !(node.id && node.hasAttribute("data-turbo-permanent") && document.getElementById(node.id)) -} - -const beforeNodeMorphed = (target, newElement) => { - if (target instanceof HTMLElement && !target.hasAttribute("data-turbo-permanent")) { - const event = dispatch("turbo:before-morph-element", { - cancelable: true, - detail: { - target, - newElement - } - }) - return !event.defaultPrevented - } - return false -} - -const beforeAttributeUpdated = (attributeName, target, mutationType) => { - const event = dispatch("turbo:before-morph-attribute", { - cancelable: true, - target, - detail: { - attributeName, - mutationType - } - }) - return !event.defaultPrevented -} - -const beforeNodeRemoved = beforeNodeMorphed - -const afterNodeMorphed = (target, newElement) => { - if (newElement instanceof HTMLElement) { - dispatch("turbo:morph-element", { - target, - detail: { - newElement - } - }) - } + morph(this) + }, } diff --git a/src/tests/unit/stream_element_tests.js b/src/tests/unit/stream_element_tests.js index f717c02c6..21fbfd68b 100644 --- a/src/tests/unit/stream_element_tests.js +++ b/src/tests/unit/stream_element_tests.js @@ -215,7 +215,7 @@ test("action=morph with data-turbo-morph-style='innerHTML'", async () => { const element = createStreamElement("morph", "hello", templateElement) const target = subject.find("div#hello") assert.equal(target?.textContent, "Hello Turbo") - target.setAttribute("data-turbo-morph-style", "innerHTML") + element.setAttribute("children-only", true) subject.append(element) @@ -225,4 +225,3 @@ test("action=morph with data-turbo-morph-style='innerHTML'", async () => { assert.ok(subject.find("div#hello > h1#hello-child-element")) assert.equal(subject.find("div#hello > h1#hello-child-element").textContent, "Hello Turbo Morphed") }) -