-
Notifications
You must be signed in to change notification settings - Fork 430
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
Infer renderElement
during Renderer
construction
#1028
Infer renderElement
during Renderer
construction
#1028
Conversation
dbca3a0
to
6afdcf4
Compare
@afcapel this aims to simplify the Renderer constructor and interface. |
2d63f41
to
9d8a361
Compare
1cde83d
to
8e6de8f
Compare
Follow-up to [][] Related to [hotwired#1192][] The `morphElements` function --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement, delegate)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `Morph` class. The `Morph` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `Morph` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a delegate responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `PageMorphRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `FrameMorphRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `PageMorphRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `PageMorphRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `PageMorphRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `FrameMorphRenderer` class to define the `FrameMorphRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = (currentElement, newElement) => { window.Turbo.morphElements(currentElement, newElement, { ... }) } } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morphElements` function --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement, delegate)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `Morph` class. The `Morph` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `Morph` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a delegate responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `PageMorphRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `FrameMorphRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `PageMorphRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `PageMorphRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `PageMorphRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `FrameMorphRenderer` class to define the `FrameMorphRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = (currentElement, newElement) => { window.Turbo.morphElements(currentElement, newElement, { ... }) } } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morphElements` function --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement, delegate)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphDelegate` class. The `IdomorphDelegate` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphDelegate` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a delegate responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `PageMorphRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `FrameMorphRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `PageMorphRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `PageMorphRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `PageMorphRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `FrameMorphRenderer` class to define the `FrameMorphRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = (currentElement, newElement) => { window.Turbo.morphElements(currentElement, newElement, { ... }) } } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morphElements` function --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement, delegate)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphDelegate` class. The `IdomorphDelegate` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphDelegate` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a delegate responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `PageMorphRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `FrameMorphRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `PageMorphRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `PageMorphRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `PageMorphRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `FrameMorphRenderer` class to define the `FrameMorphRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = (currentElement, newElement) => { window.Turbo.morphElements(currentElement, newElement, { ... }) } } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morphElements` function --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement, delegate)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphDelegate` class. The `IdomorphDelegate` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphDelegate` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a delegate responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `PageMorphRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `FrameMorphRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `PageMorphRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `PageMorphRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `PageMorphRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `FrameMorphRenderer` class to define the `FrameMorphRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = (currentElement, newElement) => { window.Turbo.morphElements(currentElement, newElement, { ... }) } } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morphElements` function --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement, delegate)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphDelegate` class. The `IdomorphDelegate` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphDelegate` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a delegate responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `PageMorphRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `FrameMorphRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `PageMorphRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `PageMorphRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `PageMorphRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `FrameMorphRenderer` class to define the `FrameMorphRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = (currentElement, newElement) => { window.Turbo.morphElements(currentElement, newElement, { ... }) } } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morphElements` function --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement, delegate)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphDelegate` class. The `IdomorphDelegate` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphDelegate` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a delegate responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `PageMorphRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `FrameMorphRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `PageMorphRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `PageMorphRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `PageMorphRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `FrameMorphRenderer` class to define the `FrameMorphRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = (currentElement, newElement) => { window.Turbo.morphElements(currentElement, newElement, { ... }) } } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morphElements` function --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement, delegate)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphDelegate` class. The `IdomorphDelegate` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphDelegate` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a delegate responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `PageMorphRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `FrameMorphRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `PageMorphRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `PageMorphRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `PageMorphRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `FrameMorphRenderer` class to define the `FrameMorphRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = (currentElement, newElement) => { window.Turbo.morphElements(currentElement, newElement, { ... }) } } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morph{Page,Frames,Elements}` functions --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphCallbacks` class. The `IdomorphCallbacks` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphCallbacks` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a callback responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `MorphingPageRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `MorphingFrameRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `MorphingPageRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `MorphingPageRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `MorphingPageRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `MorphingFrameRenderer` class to define the `MorphingFrameRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = Turbo.morphPage } }) addEventListener("turbo:before-frame-render", (event) => { const someCriteriaForMorphingAFrame = ... if (someCriteriaForMorphingAFrame) { event.detail.render = Turbo.morphFrames } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morph{Page,Frames,Elements}` functions --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphCallbacks` class. The `IdomorphCallbacks` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphCallbacks` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a callback responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `MorphingPageRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `MorphingFrameRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `MorphingPageRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `MorphingPageRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `MorphingPageRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `MorphingFrameRenderer` class to define the `MorphingFrameRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = Turbo.morphPage } }) addEventListener("turbo:before-frame-render", (event) => { const someCriteriaForMorphingAFrame = ... if (someCriteriaForMorphingAFrame) { event.detail.render = Turbo.morphFrames } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morph{Page,Frames,Elements}` functions --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphCallbacks` class. The `IdomorphCallbacks` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphCallbacks` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a callback responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `MorphingPageRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `MorphingFrameRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `MorphingPageRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `MorphingPageRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `MorphingPageRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `MorphingFrameRenderer` class to define the `MorphingFrameRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = Turbo.morphPage } }) addEventListener("turbo:before-frame-render", (event) => { const someCriteriaForMorphingAFrame = ... if (someCriteriaForMorphingAFrame) { event.detail.render = Turbo.morphFrames } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morph{Page,Frames,Elements}` functions --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphCallbacks` class. The `IdomorphCallbacks` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphCallbacks` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a callback responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `MorphingPageRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `MorphingFrameRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `MorphingPageRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `MorphingPageRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `MorphingPageRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `MorphingFrameRenderer` class to define the `MorphingFrameRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = Turbo.morphPage } }) addEventListener("turbo:before-frame-render", (event) => { const someCriteriaForMorphingAFrame = ... if (someCriteriaForMorphingAFrame) { event.detail.render = Turbo.morphFrames } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1185][] Related to [hotwired#1192][] The `morph{Page,Frames,Elements}` functions --- Introduce a new `src/core/morphing` module to expose a centralized and re-usable `morphElements(currentElement, newElement)` function to be invoked across the various morphing contexts. Next, move the logic from the `MorphRenderer` into a module-private `IdomorphCallbacks` class. The `IdomorphCallbacks` class (like its `MorphRenderer` predecessor) wraps a call to `Idiomorph` based on its own set of callbacks. The bulk of the logic remains in the `IdomorphCallbacks` class, including checks for `[data-turbo-permanent]`. To serve as a seam for integration, the class retains a reference to a callback responsible for: * providing options for the `Idiomorph` * determining whether or not a node should be skipped while morphing The `MorphingPageRenderer` skips `<turbo-frame refresh="morph">` elements so that it can override their rendering to use morphing. Similarly, the `MorphingFrameRenderer` provides the `morphStyle: "innerHTML"` option to morph its children. Changes to the renderers --- To integrate with the new module, first rename the `MorphRenderer` to `MorphingPageRenderer` to set a new precedent that communicates the level of the document the morphing is scoped to. With that change in place, define the static `MorphingPageRenderer.renderElement` to mirror the other existing renderer static functions (like [PageRenderer.renderElement][], [ErrorRenderer.renderElement][], and [FrameRenderer.renderElement][]). This integrates with the changes proposed in [hotwired#1028][]. Next, modify the rest of the `MorphingPageRenderer` to integrate with its `PageRenderer` ancestor in a way that invokes the static `renderElement` function. This involves overriding the `preservingPermanentElements(callback)` method. In theory, morphing has implications on the concept of "permanence". In practice, morphing has the `[data-turbo-permanent]` attribute receive special treatment during morphing. Following the new precedent, introduce a new `MorphingFrameRenderer` class to define the `MorphingFrameRenderer.renderElement` function that invokes the `morphElements` function with `newElement.children` and `morphStyle: "innerHTML"`. Changes to the StreamActions --- The extraction of the `morphElements` function makes entirety of the `src/core/streams/actions/morph.js` module redundant. This commit removes that module and invokes `morphElements` directly within the `StreamActions.morph` function. Future possibilities --- In the future, additional changes could be made to expose the morphing capabilities as part of the `window.Turbo` interface. For example, applications could experiment with supporting [Page Refresh-style morphing for pages with different URL pathnames][hotwired#1177] by overriding the rendering mechanism in `turbo:before-render`: ```js addEventListener("turbo:before-render", (event) => { const someCriteriaForMorphing = ... if (someCriteriaForMorphing) { event.detail.render = Turbo.morphPage } }) addEventListener("turbo:before-frame-render", (event) => { const someCriteriaForMorphingAFrame = ... if (someCriteriaForMorphingAFrame) { event.detail.render = Turbo.morphFrames } }) ``` [hotwired#1185]: hotwired#1185 (comment) [hotwired#1192]: hotwired#1192 [PageRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/page_renderer.js#L5-L11 [ErrorRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/drive/error_renderer.js#L5-L9 [FrameRenderer.renderElement]: https://github.com/hotwired/turbo/blob/9fb05e3ed3ebb15fe7b13f52941f25df425e3d15/src/core/frames/frame_renderer.js#L5-L16 [hotwired#1028]: hotwired#1028 [hotwired#1177]: hotwired#1177
Follow-up to [hotwired#1192][] Closes [hotwired#1303][] Remove the argument from all `Renderer` subclass constructor call sites. In its place, define the default value for the `Renderer.renderElement` property based on the `static renderElement(currentElement, newElement)` defined by the inheriting class. By automatically determining which `renderElement` implementation based on class, this commit enables a simpler Frame morphing strategy. Instead of attaching one-time event listeners, this commit maintains a private `#shouldMorphFrame` property that is set, then un-set during the rendering lifecycle of a frame. Similarly, this commit implements the `MorphingFrameRenderer.preservingPermanentElements` method in the same style as the `MorphingPageRenderer.preservingPermanentElements`. Since _instances_ of `MorphingFrameRenderer` are now being used instead of the static `MorphingFrameRenderer.renderElement`, we're able to utilize an instance method instead of passing around an additional anonymous function (which is the implementation that [hotwired#1303][] proposed). [hotwired#1192]: hotwired#1192 [hotwired#1303]: hotwired#1303 Co-authored-by: Micah Geisel <micah@botandrose.com>
8e6de8f
to
03549a9
Compare
renderElement
from Renderer
constructorrenderElement
during Renderer
construction
@jorgemanrubia @brunoprietog while this is an older PR, I've re-purposed the changes to follow up #1192 and to resolve a bug documented by #1303. It's ready for review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seanpdoyle Nice! Much better. +1 from me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice one @seanpdoyle, thanks.
Follow-up to #1192
Closes #1303
Remove the argument from all
Renderer
subclass constructor call sites.In its place, define the default value for the
Renderer.renderElement
property based on the
static renderElement(currentElement, newElement)
defined by the inheriting class.
By automatically determining which
renderElement
implementation basedon class, this commit enables a simpler Frame morphing strategy. Instead
of attaching one-time event listeners, this commit maintains a private
#shouldMorphFrame
property that is set, then un-set during therendering lifecycle of a frame.
Similarly, this commit implements the
MorphingFrameRenderer.preservingPermanentElements
method in the samestyle as the
MorphingPageRenderer.preservingPermanentElements
. Sinceinstances of
MorphingFrameRenderer
are now being used instead of thestatic
MorphingFrameRenderer.renderElement
, we're able to utilize aninstance method instead of passing around an additional anonymous
function (which is the implementation that #1303 proposed).
Co-authored-by: Micah Geisel micah@botandrose.com