Last active
April 23, 2023 12:57
-
-
Save bennadel/49c6b97d6e05d9637b1cf188de9ed691 to your computer and use it in GitHub Desktop.
Incrementally Applying Hotwire To An Existing ColdFusion Application
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"plugins": [ | |
"@babel/plugin-proposal-optional-chaining" | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Import application modules. | |
import { ApiClient } from "./api-client.js"; | |
// ----------------------------------------------------------------------------------- // | |
// ----------------------------------------------------------------------------------- // | |
export var apiClient = new ApiClient(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Import core modules. | |
import * as Turbo from "@hotwired/turbo"; | |
// ----------------------------------------------------------------------------------- // | |
// ----------------------------------------------------------------------------------- // | |
// By default, we don't want Turbo Drive to take over the navigation unless explicitly | |
// enabled within the ColdFusion markup. This way, we can baby-step our way towards a | |
// compatible Turbo Drive application. | |
Turbo.session.drive = false; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Scroll down to the desired element (via ID selector). | |
document.documentElement.addEventListener( | |
"turbo:load", | |
function handleLoad( event ) { | |
var searchParams = new URLSearchParams( location.search ); | |
var scrollTo = searchParams.get( "scrollTo" ); | |
if ( ! scrollTo ) { | |
return; | |
} | |
document.querySelector( `#${ scrollTo }` ) | |
?.scrollIntoView() | |
; | |
} | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--- | |
As various pages are updated to be Hotwire / Turbo Drive compatible, we | |
can add the "data-turbo" attribute to their nav links. This way, even if | |
most of the app is still powered by "old school" full page-refresh | |
navigation, Turbo Drive can still kick-in where it will be a value-add. | |
-- | |
Note that only the ABOUT page here is Turbo-enabled. | |
---> | |
<nav> | |
<a href="index.htm">Home</a> | |
<a href="about.htm" data-turbo="true">About</a> | |
<a href="contact.htm">Contact</a> | |
</nav> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfscript> | |
param name="url.quoteIndex" type="numeric" default=0; | |
quote = application.quoteService.getQuote( url.quoteIndex ); | |
</cfscript> | |
<cfmodule template="./tags/page.cfm" section="home"> | |
<cfoutput> | |
<h2> | |
Welcome to My Site | |
</h2> | |
<figure> | |
<blockquote> | |
#encodeForHtml( quote.text )# | |
</blockquote> | |
<figcaption> | |
← | |
<a href="index.htm?quoteIndex=#encodeForUrl( quote.prevID )#">Prev quote</a> | |
— | |
<a href="index.htm?quoteIndex=#encodeForUrl( quote.nextID )#">Next quote</a> | |
→ | |
</figcaption> | |
</figure> | |
</cfoutput> | |
</cfmodule> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--- | |
Even with Turbo Drive disabled by default, Turbo Frames still work. As such, | |
for navigation events that refresh the page, we can very easily wrap those | |
navigation elements in a Turbo Frame that advances the history. | |
---> | |
<turbo-frame id="quote-frame" data-turbo-action="advance"> | |
<figure> | |
<blockquote> | |
#encodeForHtml( quote.text )# | |
</blockquote> | |
<figcaption> | |
← | |
<a href="index.htm?quoteIndex=#encodeForUrl( quote.prevID )#">Prev quote</a> | |
— | |
<a href="index.htm?quoteIndex=#encodeForUrl( quote.nextID )#">Next quote</a> | |
→ | |
</figcaption> | |
</figure> | |
</turbo-frame> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--- | |
Even when Turbo Drive is disable by default, lazy-loaded Turbo Frames still | |
work. Which means, we can VERY EASILY lazy-load content into the current page. | |
---> | |
<turbo-frame id="lazy-frame" src="lazy.htm" loading="lazy"> | |
<!--- Placeholder content (or if script hasn't loaded). ---> | |
<a href="lazy.htm">Go to lazy content</a> → | |
</turbo-frame> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--- | |
This represents a "pre-Stimulus" widget. It will be bootstrapped by a page- | |
level Stimulus controller until it can be migrated to use Stimulus on its own. | |
---> | |
<p class="old-school"> | |
<button> | |
Clicked <span>0</span> Times | |
</button> | |
</p> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Import core modules. | |
import { Application } from "@hotwired/stimulus"; | |
import { Controller } from "@hotwired/stimulus"; | |
// ----------------------------------------------------------------------------------- // | |
// ----------------------------------------------------------------------------------- // | |
class AppController extends Controller { | |
/** | |
* I get called whenever the controller instance is bound to a host element. | |
*/ | |
connect() { | |
console.log( "App connected!" ); | |
// Wire-up all the features that have not yet been ported to their own Stimulus | |
// controllers. Keep in mind that these methods will be called on every page load. | |
setupOldSchoolThing(); | |
} | |
} | |
window.Stimulus = Application.start(); | |
// When not using the Ruby On Rails asset pipeline / build system, Stimulus doesn't know | |
// how to map controller classes to data-controller attributes. As such, we have to | |
// explicitly register the Controllers on Stimulus startup. | |
Stimulus.register( "app", AppController ); | |
// ----------------------------------------------------------------------------------- // | |
// ----------------------------------------------------------------------------------- // | |
function setupOldSchoolThing() { | |
// This setup method will be called on every page load. As such, it will only be | |
// applicable some of the time. If this page doesn't contain an old-school widget, | |
// exit out. | |
if ( ! document.querySelector( ".old-school" ) ) { | |
console.warn( "No old-school widget detected." ); | |
return; | |
} | |
var dom = Object.create( null ); | |
dom.container = document.querySelector( ".old-school" ); | |
dom.button = dom.container.querySelector( "button" ); | |
dom.counter = dom.button.querySelector( "span" ); | |
// Parse initial counter from the DOM state. | |
var clickCount = +dom.counter.textContent; | |
dom.button.addEventListener( | |
"click", | |
function handleClick() { | |
dom.counter.textContent = ++clickCount; | |
} | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Import vendor modules. | |
import { Controller } from "@hotwired/stimulus"; | |
// Import application modules. | |
import { apiClient } from "./injector.js"; | |
// ----------------------------------------------------------------------------------- // | |
// ----------------------------------------------------------------------------------- // | |
export class CommentFormController extends Controller { | |
// ... truncated ... | |
apiClient.makeRequest(); | |
// ... truncated ... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
document.documentElement.addEventListener( | |
"turbo:click", | |
function handleClick( event ) { | |
// If the user is clicking through to an old demo, don't let Turbo Drive manage | |
// the application visit - the demo will NOT BE Hotwire-compatible. Instead, let's | |
// prevent the default Turbo Drive behavior, allowing the event to fall through to | |
// the browser as a normal link navigation. | |
if ( event.detail.url.includes( "/resources/" ) ) { | |
event.preventDefault(); | |
} | |
} | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment