There are lots of great ways to manage your JavaScript and CSS assets. If you are managing JavaScript you may want to look into RequireJS which delegates the resource management to the client. You can achieve the same client-side management in CSS by using the @import declaration within your style sheets. To manage assets on the server using ColdFusion I had previously released a plugin for ColdBox called ScriptInclude. I have since stopped using it in favor of the following decorations to the ColdBox Request Context and wanted to take a moment to share with the community. Finally, I also wanted to share a new feature found in ColdBox 3 to help achieve similar results.
How to get this working within your ColdBox Application
- Register the Request Context Decorator within your ColdBox config
- Save the following as your Request Context Decorator. Be sure you save it in the location you specified within your ColdBox config.
- Use the new methods in the Event object to add your JavaScript and CSS files.
- Iterate through the struct/array to render the HTML to include the assets.
<cfscript> // Register your RequestContextDecorator within your Coldbox.cfc // or your ColdBox XML file by telling ColdBox where the // CFC lives requestContextDecorator = "model.RequestContextDecorator"; </cfscript>
/** Request Context Decorator enhances and augments the EVENT object for our ColdBox applications. */
component
name = 'RequestContextDecorator'
extends = 'coldbox.system.web.context.RequestContextDecorator' {
public void function configure () {
// Prepare our data structure to
// hold and organize assets such as JavaScript/CSS
buildAssetScaffold();
return;
}
/** Allow assets to be loaded into the queue */
public void function addAsset( required string path
,string method='queue'
,boolean fullPathProvided = false) {
// Grab the Request Context from within the Event Object
var prc = getRequestContext().getCollection(private = true);
// Organize by the file extention
var type = listLast(path, '.');
// Replace the following with the relative directories from your
// web root
if (!fullPathProvided)
path = (type == 'css')
? '/assets/style/' & path
: '/assets/script/' & path;
// Prevent duplicates
if (!arrayContains(prc.assets[method][type], path))
arrayAppend(prc.assets[method][type], path);
return;
}
/** Allow multiple assets to be loaded into the queue */
public void function addAssets(required string paths
,string method = 'queue'
,boolean fullPathProvided = false) {
var list = listToArray(paths, ',');
// Add each path individually
var n = arraylen(list);
var i = 0;
for (i=1; i <= n; i++)
addAsset(path=trim(list[i])
,method=method
,fullPathProvided=fullPathProvided);
return;
}
/** Allow assets to be returned from the queue */
public array function getAssets(required string type
,string method = 'queue') {
var prc = getRequestContext().getCollection(private = true);
return prc.assets[method][type];
}
/** Allow assets to be returned from the queue */
public void function clearAssets() {
buildAssetScaffold();
return; ;
}
// Private ----------------------------------------------------------------------
/** Used to help construct the foundation to manage assets. */
private void function buildAssetScaffold() {
var prc = getRequestContext().getCollection(private = true);
prc.assets = {};
// The queue allows the assets to be include by path into the page.
prc.assets.queue = { js = [], css = []};
// Includes allow the content of an asset to be injected into the page.
prc.assets.include.js = [];
return;
}
}
<cfscript>
/** This is an example event handler */
public void function index (required Event) {
var rc = Event.getCollection();
var prc = Event.getCollection(private=true);
// Adding multiple assets in a single call
Event.addAssets('core.css
,cufon-yui.js
,lib/time.js
,lib/string.js
,manager.css
,smoothness/jquery-ui-1.7.2.custom.css
,jquery-ui-1.7.2.custom.min.js');
// Adding a single asset using the full path
// You can also include a list of full paths like the above example
Event.addAsset( path='http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js'
,fullPathProvided=true);
// Add a single asset
Event.addAsset('feature_preview.css');
}
</cfscript>
<cfscript>
cssAssets = Event.getAssets(type='css');
cssLength = arrayLen(cssAssets);
if (cssLength > 0)
for(i=1; i <= cssLength; i++)
writeOutput('<link href="#cssAssets[i]#" type="text/css" rel="stylesheet" />');
</cfscript>
<!--- Include javascript content directly Useful for items like Google Analytics ---> <cfloop array="#Event.getAssets(type='js',method='include')#" index='content'> <script type='text/javascript'>#content#</script> </cfloop> <!--- Include JavaScript assets by path ---> <cfloop array="#Event.getAssets(type='js')#" index='src'> <script type='text/javascript' src='#src#'></script> </cfloop>
Another Way Native to ColdBox 3
ColdBox 3 introduces the HTML Helper Plugin which can also manage assets. The HTML Helper plugin’s addAsset method reproduces much of the above functionality without requiring modifications to your ColdBox Config, Request Context Decorator or Layout Files! Less configuration on your part! The following example will automatically inject the link to include the resource within the <head> element.
<cfscript>
/** This is an example event handler */
public void function index (required Event) {
var rc = Event.getCollection();
var prc = Event.getCollection(private=true);
// Get the HTML Helper Plugin
var HTMLHelper = getPlugin('HTMLHelper');
HTMLHelper.addAsset('assets/style/core.css');
HTMLHelper.addAsset('assets/style/manager.css');
HTMLHelper.addAsset('assets/style/smoothness/jquery-ui-1.7.2.custom.css');
HTMLHelper.addAsset('assets/style/feature_preview.css');
HTMLHelper.addAsset('assets/script/cufon-yui.js');
HTMLHelper.addAsset('assets/script/lib/time.js');
HTMLHelper.addAsset('assets/script/lib/string.js');
HTMLHelper.addAsset('assets/script/jquery-ui-1.7.2.custom.min.js');
HTMLHelper.addAsset('http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js');
}
</cfscript>Which Method is Best?
The first method offers the most flexibility. All we are really doing is including some methods within the Event object to manage paths in an array. The assets all exist within the private request collection (prc.assets). You can modify the code presented in Step 4 to use the JSMin plugin and minify your JavaScript/CSS or perform other tasks to meet your own unique needs.
The second method is much eaiser to work with but sacrifices some of your control. It is always nice to use conventional ColdBox methods.

