Aaron Greenlee.com | A Personal Journey.
You should follow me here.
This is the RSS subscription you have been looking for.
 
Wrecking Ball Media
A great team that is clearing the way for digital marketing.

Have you thought about joining the Central Florida Web Developers User Group?

A Look at ColdBox Resource Management

POSTED Tuesday, September 14, 2010  |   | DOWNLOAD CODE
Keywords: ColdBox

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

  1. Register the Request Context Decorator within your ColdBox config
  2. Save the following as your Request Context Decorator. Be sure you save it in the location you specified within your ColdBox config.
  3. Use the new methods in the Event object to add your JavaScript and CSS files.
  4. Iterate through the struct/array to render the HTML to include the assets.
Step 1: Register Request Context Decorator
<cfscript>
	// Register your RequestContextDecorator within your Coldbox.cfc
	// or your ColdBox XML file by telling ColdBox where the
	// CFC lives
	requestContextDecorator = "model.RequestContextDecorator";
</cfscript>
Step 2: Save the Request Context Decorator
/** 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;
	}
}
Step 3: Manage Assets within the application
<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>
Step 4a: Include CSS within Layout
<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>
Step 4b: Including JS within Layout/View
<!---
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.

Native ColdBox 3
<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.

blog comments powered by Disqus
You can send me email or work with
   me for digital marketing, web design
      and application development.

         I own proprietary web application development
         company and work with a leading digital marketing firm.
© 2009 - 2013 Aaron Greenlee. Powered by my own code on the ColdBox Framework.

This site is best viewed on Chrome, FireFox and Safari. Subscribe to my RSS feed.