Archive for the 'cfml' Category

More on Railo announcement

Railo 3.1 will be distributed under the LGPL2 license. Professional and Community versions to merge and be hosted at JBoss.org.

JBoss.org provides a home for the development of software in open source by an open community. Including source repository, issue tracking, wiki, forums, etc.

Possible integration with Hibernate - the popular JBoss ORM - JBoss Cache, JBoss Clustering, etc.

Looking at my future hosting requirements I’m keen to see how OpenDB and Railo can perform, not purely based on cost but also as to how extensible they have both now become.

2nd CFML Engine goes Open Source

Sitting in the Railo keynote at Scotch and they’ve just announced that they’re going Open Source with JBoss.org.

Interesting times.

Merge Sort an Array of Structures in ColdFusion

After a recent spell of doing lots of prototyping, I’m finally getting back to some proper coding. I have an array of structures that I’d been sorting on a particular key (price) using a quick bubble sort algorithm. However, with real data on the site it was randomly returning errors and proving fairly unstable.

I knew there were better algorithms out there, so I thought I’d try a Merge Sort, and wrote a version in cfscript… posted here for your pleasure :-)

<cfscript>
	/**
	 * Sorts an array of structures using the Merge Sort algorithm.
	 *
	 * @param arr 	 The array to sort. (Required)
	 * @param key 	 Structure Key to sort by (Required)
	 * @return Returns an array.
	 * @author Anthony Cooper (ant@outsrc.co.uk)
	 * @version 1, 8 Feb 2008
	 */

	function MergeSort( arr, key ) {
	    var leftArray = ArrayNew( 1 );
	    var rightArray = ArrayNew( 1 );
	    var result = ArrayNew( 1 );
	    var middle = 0;
	    var i = 0;

	    if ( ArrayLen( arr ) LTE 1 ) {
	    	return arr;
	    }
	    else {
			middle = Ceiling( ArrayLen( arr ) / 2 );
			for ( i = 1; i LTE middle; i++ ) {
				ArrayAppend( leftArray, arr[ i ] );
			}
			for ( i = ( middle + 1 ); i LTE ArrayLen( arr ); i++ ) {
				ArrayAppend( rightArray, arr[ i ] );
			}
			leftArray = MergeSort( leftArray, key );
			rightArray = MergeSort( rightArray, key );
			result = Merge( leftArray, rightArray, key );

			return result;
	    }
	}

	function Merge( leftArray, rightArray, key ) {
		var result = ArrayNew( 1 );

		while ( ArrayLen( leftArray ) > 0 AND ArrayLen( rightArray ) > 0 ) {
			if ( leftArray[ 1 ][ key ] <= rightArray[ 1 ][ key ] ) {
				ArrayAppend( result, leftArray[ 1 ] );
				ArrayDeleteAt( leftArray, 1 );
			}
			else {
				ArrayAppend( result, rightArray[ 1 ] );
				ArrayDeleteAt( rightArray, 1 );
			}
		}
		if ( ArrayLen( leftArray ) > 0 ) {
			result = ArrayJoin( result, leftArray );
		}
		if ( ArrayLen( rightArray ) > 0 ) {
			result = ArrayJoin( result, rightArray );
		}

		return result;
	}

	function ArrayJoin( firstArray, secondArray ) {
		var i = 0;
		for ( i = 1; i <= ArrayLen( secondArray ); i++ ) {
			ArrayAppend( firstArray, secondArray[ i ] );
		}
		return firstArray;
	}
</cfscript>

And here’s how you’d use it…

<cfscript>
	products = ArrayNew( 1 );

	products[1] = { name = "Jacket", price = "2999" };
	products[2] = { name = "Shoes", price = "2199" };
	products[3] = { name = "Slacks", price = "1999" };

	sortedProducts = MergeSort( products, "price" );
</cfscript>

Disclaimer: I’m not claiming this is perfect, and I know it could be improved upon and sort direction etc added. But it was a quick solution to my problem. I’d be interested in others feedback.

Styling a cftooltip

cftooltip is a handy tag for quickly creating some tooltip text, however, the style of it didn’t fit in with my application. After a little digging around I found the class in yui.css that styles it, .yui-tt. You need to put the style inline with the html so the browser reads it after the default style, like so:

<style type="text/css">
  .yui-tt {
    color: #444;
    font-size:110%;
    border: 1px solid #444;
    background-color: #FFC;
    padding: 10px;
    width:250px;
  }
</style>

Strange error - missing “cfmessage_en_US_.js”

I just moved a site from staging to the live server and ran into this strange CF error:

Security: The requested template has been denied access to
C:\Inetpub\wwwroot\CFIDE\scripts\ajax\messages\cfmessage_en_US_.js.

The following is the internal exception message: access denied (java.io.FilePermission
C:\Inetpub\wwwroot\CFIDE\scripts\ajax\messages\cfmessage_en_US_.js read)

I knew it was related to the CF AJAX tags I’d been using, but I just couldn’t figure out why. I tried it on Windows and everything worked just fine, but not on a Mac, in any browser or even with IE7 in Parallels. And this wasn’t some client side error, it actually stopped page processing. After, lots of emails back and forth with the hosting company and I was still no closer. The weirdest thing was that the “cfmessage_en_US_.js” file doesn’t even exist!

I figured it could be down to some locale info being sent by my machine in the HTTP Header. So I tried setting the locale in Application.cfc and that did the trick. Must be some strange bug in CF as I can’t think of any other explanation.

<cfset SetLocale("English (UK)") />

I’d be interested to hear if anyone else has run into this.

Toggle state of a db record with cfajaxproxy

I’m really getting into the AJAX thing now with CF8 and tweaking my Admin apps to make them more user-friendly and avoid big page reloads.

Many of my database tables have an isActive field to determine whether a record should appear on the public site. Until now I’ve relied on users editing the entire record to set the state of this but if you’ve got a few updates to do you soon get dizzy going between lists and forms and keeping track of where you’re up to. For me, this is where AJAX can make a big difference.

The following example might not be perfect but it gives an idea of what’s possible.

1. The JS stuff

Being a fusebox user, I have this in a single generic fuse that I can use with any page. We create the Javascript proxy to the CFC and then write a couple of JS functions to handle the asynchronous call and response.

<!--- Create a JS proxy for our component --->
<cfajaxproxy cfc="components.ajaxToggleActive" jsclassname="ajaxToggle" />

<script type="text/javascript">
	//<![CDATA[
	function toggleState( table, id ) {
		//Set table cell to ... to show it's in progress
		var displayState = document.getElementById('active_' + id);
		displayState.innerHTML = '...';

		//Call component to toggle state
		var t = new ajaxToggle();
		t.setCallbackHandler( toggleResult );
		t.change( table, id );
	}

	function toggleResult( response ) {
		//Set table cell to represent new state
		var displayState = document.getElementById( 'active_' + response.ID );
		displayState.innerHTML = ( response.STATE == 1 ? 'Yes' : 'No' );
	}
	// ]]>
</script>

2. In the table cell

In the record list, display page, or wherever, we just need to call the toggleState function. Note also the a tag has an id attribute so we can change the content of it with JS.

<a href="javascript:toggleState('vehicle','#rsData.id#')" id="active_#rsData.id#">#YesNoFormat( rsData.isActive )#</a>

3. The CFC

This CFC just has the one method to toggle the status of an isActive field in the specified table.

<cfcomponent output="false">

	<cffunction name="change" output="false" access="remote">
		<cfargument name="table" default="" />
		<cfargument name="id" default="" />

		<cfset var rsState = "" />
		<cfset var result = StructNew() />

		<!--- Toggle field --->
		<cftry>
			<cfquery datasource="#application.dsn#">
				UPDATE
					#arguments.table#
				SET
					isActive = 1 - isActive
				WHERE
					id = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
			</cfquery>

			<!--- Check user exists --->
	 		<cfquery name="rsState" datasource="#application.dsn#">
				SELECT
					isActive
				FROM
					#arguments.table#
				WHERE
					id = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
			</cfquery>

			<cfset result = { id = arguments.id, state = rsState.isActive } />

			<cfcatch />
		</cftry>
		<cfreturn result />
	</cffunction>

</cfcomponent>

4. The Result

Toggle Active Your users can simply click the Yes/No option to switch items on and off without lots of page loads.


cfajaxproxy returning ColdFusion structures

I’ve been tinkering with cfajaxproxy recently to pimp up some of the pages in an Admin application. One thing I couldn’t figure out was how to access a returned ColdFusion structure in Javascript. However, as with most things, it’s easy if you know the answer… all struct keys become UPPERCASE !

e.g.

<cfreturn { id = arguments.id, state = rsState.isActive } />

In javascript would be:

alert( myVar.ID + ' ' + myVar.STATE );

Maybe it’s just me that didn’t realize this, but I haven’t read it in the CF Docs anywhere :-S

cfdocument font issues - again

When I updated some sites to CF8 I noticed that the font and table sizes went a little crazy. I tried a few things but in the end had to fix each page so it looked OK. Having applied CF8 Hot Fix 1 it seems that the sizes have changed again - lets hope that’s the last of it!