How to Customize An Application

Today's been an interesting day for me.

I found myself rereading this old blog entry from Jason Delmore from last year. It was about why Adobe doesn't give ColdFusion away for free like PHP or Ruby, which of course people still debate today although there's not really any reason to debate it anymore with there now being three separate free CFML engines in various stages of development (Railo, Open BlueDragon and SmithProject) and an upcoming CFML language standard committee.

Whatever your opinion on the idea of standards or for that matter committees, you can't argue that 2008 was anything but an eventful year for the ColdFusion community. Some of the news is just caching up to us like the announcement of the beta for the new Bolt IDE for ColdFusion. The community spoke and Adobe listened. Announcements regarding the features of CF9/Centaur (such as Hibernate ORM) are of course similarly exciting. And then there have been all the wow events in the community like Railo announcing their becoming part of the JBoss project and becoming free/open-source and Kristen Schofield announcing the free educational licensing for ColdFusion and releasing the evangelism kit that finally arms us with some great information for evangelizing the platform, allowing you to "be your own Ben Forta" as she described in her Max presentation. :)

These are all great things for the ColdFusion community, they will be great things for the CF Open Source community generally and personally I know they will be great things for the onTap framework community specifically as we grow rapidly over the next year or two.

ColdFusion is a bit unusual in the way it does things. Although it's not without its challenges as is the case with any language, CF has often been the first in new areas. Notably, CF was the first server of its kind to connect the web to databases seamlessly and easily over ten years ago when Allaire released the very first version. The onTap framework today is in some ways following in that pioneering spirit and right now I'd like to show you a few specific features that make it truly unique in today's CF open source community.

[More]

Page Breaks - thanks to Dan G. Switzer

I usually don't add a new feature right away. I usually will have it in my head for a little while and mull it over a fair amount before I start writing the code for it. Today was a bit of an exception. Dan Switzer, the sharp guy behind qForms posted this pretty simple concept on his blog for creating a word-processor-like page break. That is a page break that appears visually on the screen where the page break is going to occur when printed.

Now I'd used the CSS for page breaks before, but somehow it never occurred to me to do anything like this until Dan mentioned it. I guess I hadn't been to observant when using MS Word. :) And when I saw Dan's blog I smacked myself in the head, because it was so obvious. He did a great job of subtlely enhancing the user experience, so he gets kudos from me.

And given its simplicity I decided to go ahead and integrate it right away. You'll now find in the XHTML library that there's a new tap:pagebreak tag that will create these handy little things for you. Your code would look something like this:

<cf_html ...>
<div xmlns:tap="xml.tapogee.com">
<p>stuff here</p>

<p>stuff here</p>

<tap:pagebreak />

<p>more stuff</p>

<p>more stuff</p>
</div>
</cf_html>

I've only added two things to Dan's original code. One is I added @media aural to the CSS to hide the page break elements to screen readers. The other is that I made the "page break" label in the middle localized to the language in use.

Enjoy!

A New Rich Text Editor

I was looking for some information about how to set the value of a loaded FCKEditor instance. This is the first time I'd ever used FCKEditor even though I had previously created a TinyMCE plugin for the framework called tapMCE.

The problem with rich-text editors in general, whether you use TinyMCE or FCKEditor or something else is that they tend to be over complicated and far from "user-friendly" to anyone who's not a computer programmer... You and I of course are fine with them, because we're technically educated and familiar with all the HTML concepts that their gratuitous dialogs throw at us like "alternate text" and "vspace". But it's kind horrid to force our strange jargon on people who just want to put a picture in some content.

That problem actually was one of the things mentioned (aside from their being load-heavy) in the blog article where I found this newcomer.

It's called NicEdit and I'll likely be having a look at it soon along with all the other things on my todo list. I may just rebrand the tapMCE plugin to some other name like TapIWYG and retool it so that it becomes an integrator for a couple of different rich editors just to give people the options. That way it'd have a facade where you can specify the options for your whole app and then tweak them for individual editors in the XHTML syntax... and maybe even provide a facade for some common js integration needs like for example, how do you set the value of the editor, because it's probably different across them... so if you could just call a service from the IoC container and declare which input element to set and the value, then you could let the facade worry about the JS specifics. In much the same way that DataFaucet handles database specifics. Now that would be some slick SOA. :)

Spry is Inaptly Named

From Dictionary.com,

spry –adjective, spry·er, spry·est or spri·er, spri·est.
active; nimble; agile; energetic; brisk.

Hmmm... agile... that's a good analogy - as in the Agile Manifesto... a couple of the key principles of Agile development as described on Wikipedia are "simplicity" and "regular adaptation to changing circumstances"... and key to the task of shortening development timelines is creating frameworks with loose coupling... Well what is loose coupling? Loose coupling (as compared to strong coupling) means there are very few places in which the code would need to be modified in order to inject or remove a particular item.

In the case of Spry as the example, here's some code from the Spry form validation demo (I've snipped out just the relevant bits):

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<link href="../css/screen.css" rel="stylesheet" type="text/css" media="all" />
<link href="../../widgets/textfieldvalidation/SpryValidationTextField.css" rel="stylesheet" type="text/css" />
<link href="../../widgets/selectvalidation/SpryValidationSelect.css" rel="stylesheet" type="text/css" />
<link href="../../widgets/textareavalidation/SpryValidationTextarea.css" rel="stylesheet" type="text/css" />
<link href="../../widgets/checkboxvalidation/SpryValidationCheckbox.css" rel="stylesheet" type="text/css" />
<link href="validation.css" rel="stylesheet" type="text/css" media="all" />

<script type="text/javascript" src="../../widgets/textfieldvalidation/SpryValidationTextField.js"></script>
<script type="text/javascript" src="../../widgets/selectvalidation/SpryValidationSelect.js"></script>
<script type="text/javascript" src="../../widgets/textareavalidation/SpryValidationTextarea.js"></script>
<script type="text/javascript" src="../../widgets/checkboxvalidation/SpryValidationCheckbox.js"></script>

</head>

<body>
<noscript><h1>This page requires JavaScript. Please enable JavaScript in your browser and reload this page.</h1></noscript>
      <form id="form1" name="form1" method="post">
      <div id="theTitle">
         <div class="formLabel">Title:</div>
         <input name="movieName" type="text" id="theMovieTitle" value="Conquistador" />
         <img src="images/ok.gif" title="Valid" alt="Valid" class="validMsg" border="0"/>
         <span class="textfieldRequiredMsg">Please enter a title.</span>
      </div>

      ...

      <div id="theDescription">
          <div class="formLabel">Description:</div>
               <textarea name="movieDescription" id="movieDescription" cols="45" rows="5">The story of a historian accompanying Cortez in his quest in the New World.</textarea>
               <span class="textareaRequiredMsg">Please enter a description.</span>
               <span class="textareaMinCharsMsg">Please enter at least 20 characters.</span>
      </div>

      ...

      <div class="buttons">
         <input type="submit" name="Submit" id="submit" value="Submit"/>
      </div>
</form>
</div>
</div>
</div>
</form>

<script type="text/javascript">
<!--
   var theTitle = new Spry.Widget.ValidationTextField("theTitle", "none", {useCharacterMasking:true, validateOn:["change"]});
   var theDate = new Spry.Widget.ValidationTextField("theDate", "date", {useCharacterMasking:true, format:"mm/dd/yyyy", hint:"mm/dd/yyyy", validateOn:["change"]});
   var theDuration = new Spry.Widget.ValidationTextField("theDuration", "integer", {useCharacterMasking:true, validateOn:["change"], allowNegative:false});
   var theRating = new Spry.Widget.ValidationSelect("theRating", {validateOn:["change"]});
   var theStudio = new Spry.Widget.ValidationSelect("theStudio", {validateOn:["change"]});
   var theDescription = new Spry.Widget.ValidationTextarea("theDescription", {useCharacterMasking:true, minChars:20, maxChars:180, counterType:"chars_count", counterId:"Countvalidta1", validateOn:["change"]});
   var checkboxes = new Spry.Widget.ValidationCheckbox("checkboxes", {validateOn:["change"], maxSelections:3});
//-->
</script>
</body>
</html>

Here's a reasonably comparable form using the onTap framework's xhtml library:

<cf_html>
<tap:form id="form1" name="form1" xmlns:tap="http://www.fusiontap.com">
   <input name="movieName" type="text" value="Conquistador" label="Title" tap:required="true" />

      ...

   <textarea name="movieDescription" tap:required="true" label="Description" cols="45" rows="5">The story of a historian accompanying Cortez in his quest in the New World.
<tap:validate type="length" min="20" max="180" />
</textarea>

      ...

   <button type="submit" name="Submit">Submit</button>
</tap:form>
</cf_html>

The marketing on the Adobe Labs site for Spry gets it pretty correct:

The Spry framework is a way to incorporate XML, JSON or HTML data into pages using HTML, CSS, and a minimal amount of JavaScript, without the need for refreshing the entire page. Spry also provides easy to build and style widgets, providing advanced page elements for end users. The Spry framework is HTML-centric, and easy to implement for users with basic knowledge of HTML, CSS and JavaScript. The framework was designed such that the markup is simple and the JavaScript is minimal. The Spry framework can be used by anyone who is authoring for the web in their tool of choice.

But as you see above, it doesn't really deliver on that claim... There are a horde of things that I could comment about in these samples, but the biggest one is simply the amount of code required and not merely the amount, but the way it's sprawled all over the template... Why could code not be put in just one or two places? Javascript makes it eminently available for Spry's form management tools to be very concise, just the way my onTap sample is.

For example:

  • Assuming that you're including a given Spry widget .js file, there's no reason why you should be required to separately include the CSS template for that widget -- the framework might just as easily check for the existence of a link tag with a spry-specific ID and if not present, include the default CSS file from an appropriate location automatically by manipulating the DOM at run-time.
  • Similarly, if you're including the form validation tools, there's no reason why it should require you to manually include a separate script for each type of validation you want (which could all be included in a similarly automated fashion based on what's found in forms on the page).
  • There's also no reason why it should require you to attach validation to the forms in an inline JavaScript block at the bottom. The framework might just as easily cycle through the forms on the page when the page loads and examine the DOM for each form to automatically assign the form validation on the basis of namespace attributes like spry:validateOn="change". Separating the validation from the form doesn't make it easier to do this stuff, it makes it harder!

To me, this is not "html-centric". An "html-centric" framework would be like ColdFusion with respect to having most of the instructions within the XHTML tags and attributes, the way I just showed.

The one thing I'll mention that may be a tad unfair, given that Spry is a pure JS/CSS framework, is that the onTap framework form doesn't require that you manually enter values in form fields (I rarely ever type value=) or create and place error messages for most validation. Because most validation is common across forms, there are default error message templates for each language, so all you have to do is provide the label (and I usually automate that too with XSLT). The warning that the page requires JavaScript is also similarly unnecessary (Section 508 non-complicance, sweet!), but that's because the onTap framework uses the same XHTML that drives the JavaScript validation to perform server-side validation (without resorting to the security nightmare of ColdFusion's built-in server-side validation), so there's not really anything Spry can do about that natively. The only way that could work with Spry is if someone built a server-side framework like the one in onTap and made it to spit out the Spry markup.

The long and the short of it is this: even if I were an EXPERT at Spry (which claims to be easy to learn), Spry forms still require a minimum of about 3-5 TIMES as much maintenance versus comparable forms built with the onTap framework. (And even in pure JS/CSS most of that maintenance could be eliminated if they'd chosen slightly different design principles.) To me, a 300%-500% increase in maintenance isn't "spry" development.

EnableCFOutputOnly

Hmmm.... another case of not having read the documentation.

From the documentation for the CFSETTING tag:

If you nest cfsetting tags: to make HTML output visible, you must match each enableCFoutputOnly = "Yes" statement with an enableCFoutputOnly = "No" statement. For example, after five enableCFoutputOnly = "Yes" statements, to enable HTML output, you must have five corresponding enableCFoutputOnly = "No" statements.

That explains why I'd been finding cfsetting "unreliable" for the purpose of setting the EnableCFOutputOnly flag, because I'd always assumed it was just an on/off thing. It also means I'll have to go back through the framework and find the places where I've used it, for example, the cf_html tag now automatically un-sets the EnableCFOutputOnly flag to eliminate the need to nest cfoutput tags in every cf_html instance, even when no variables are being used, which is something I used to do to ensure that the code wouldn't break if someone put cfoutputonly in their applicatin / onRequestStart. I'm pretty certain this will result in a new function:

<cffunction name="EnableOutputOnly" output="false" returntype="numeric">
<cfargument name="enable" type="boolean" required="false" default="true" />
<cfargument name="repeat" type="numeric" required="false" default="1" />

<cfif enable>

<cfloop index="repeat" from="#repeat#" to="1" step="-1">
<cfsetting enablecfoutputonly="true" />
</cfloop>

<cfreturn 0 />
<cfelse>
<cfset repeat = -1 />
<cfset enable = true />

<cfloop condition="enable">

<cfset repeat = repeat + 1 />
<cfsavecontent variable="enable">false</cfsavecontent>
<cfset enable = len(enable) />

</cfloop>

<cfreturn repeat />
</cfif>
</cffunction>

update: (later the same day) -- yeah, I saw this coming... it can't be a function, because it starts a new output buffer when it enters the function, which circumvents the enablecfoutputonly setting. So I just uploaded a new build with a custom tag that does this instead.

Small Select Bug Fix

I'm reminded that when ColdFusion 7 was released, it shipped with a small bug in the XForms implementation which caused multiple-select input elements to display with none selected if a user had previously selected multiple options. It had turned out to be something fairly simple, an oversight in their default XSL sheet and at the time I'd provided the fix for Jeff Small (although at the moment I can't find his blog entry where he posted it for everyone else -- send me the url if you have it and I'll post it here). I'm sure it was something the folks on the CF development team just hadn't antiscipated, after all how often do you use a multiple-select? (Of course, I say this expecting a quick response from the couple of folks who use them frequently.) :)

It's sort of come back to haunt me... In the previous versions of the onTap framework, I'd built in query-driven select input elements. The first iteration of these were unfortunately painfully slow. The problem at the time was that I was making it create a whole new html element structure for each option, instead of simply holding on to the query until display time. It turned out to be far too much overhead, and just as well most of the data in those structures was going unused anyway. So I then moved to the more logical approach of storing the query in the element structure for the select input and looping over them to create the options at time of display. This worked pretty well and even allowed me an easier way of fetching the current value of the select input by using the native ValueList() function. However, when setting the current value, I was still looping over each record in the query, like this:

<cfloop query="input.query">
<!--- get the value of the current option --->
<cfset thisvalue = input.query.inputvalue[currentrow] />
<!--- check to see if it's selected --->
<cfset isselected = ListFindNoCase(input.selected,thisvalue) />
<!--- reset the option selection --->
<cfset input.query.selected[currentrow] = iif(isselected,"thisvalue",de("")) />
</cfloop>

You can see from this code how I can then use ValueList(input.query.inputvalue) to fetch the list of currently selected options. Well this was great, and then shortly after I started working on version 3.0 of the framework I realized that there may be an even more efficient way. Instead of looping over the query one record at a time, I could set the entire query all at once and it could potentially be much more efficient. Something like this:

<!--- reset all the options --->
<cfset ArraySet(input.query["selected"],"",1,input.query.recordcount) />
<!--- get the indexes of the selected options --->
<cfset selected = getSelectedIndexes(input.query,input.selected) />
<!--- set the selected flag for selected options --->
<cfloop index="i" list="#selected#">
<cfset input.query.selected[i] = input.query.inputvalue[i] />
</cfloop>

So in this case the loop only processes one iteration for each selected option, instead of for each record in the query. In some cases where there are a lot of options in the list this can be much more efficient. I tested this after I implemented it and it is much more efficient when the select list is excessively large: hundreds of options or more, which may not be the best idea in the first place, but that's another blog. For most uses though, the efficiency probably won't change much from the last version.

The problem lies in that getSelectedIndexes() function (which is a simplification for the sake of the blog -- suffice to say that it creates a list of query indexes that should be selected without looping over the query). The algorithm I had for determining which query indexes were selected turned out to have a minor flaw in it and so where I had a query containing the values "en,en_CA,en_US" (and a few others), it was selecting all options beginning with "en", so the options for CA and US were being additionally selected when only "en" should have been. Of course I fixed this yesterday and uploaded a new build of the framework core code a few minutes ago.

I will give one caveat and that's the form tools do assume that you won't have any linefeed characters (ASCII char(10)) in your option values. So if for some reason you need that particular character in your data, you'll have to replace them with something else before displaying the form and after submitting it. Probably most people won't have any issues with that, since the inputvalue column will usually contain either integers, UUID strings or some other equivalent. Speaking of which, this is probably why I didn't catch this sooner, because I tend not to use autonumber / identity columns (though they're better supported now), and since most of my select elements contain a UUID equivalent, the values generally don't offer that kind of overlap.

What's On the Menu?

The office where I'm working currently, we have a lot of this

<div>
[&nbsp;<a ...>main</a>
<cfif xyz>&nbsp;|&nbsp;<a ...>users</a></cfif>
&nbsp;|&nbsp;<a ...>documents</a>&nbsp;]
</div>

I imagine a lot of you are already familiar with this sort of thing... Probably most of you don't think much of it, but this sort of thing can be problematic. Primarily what I'm talking about here is the brackets [ ] surrounding the menu and the pipes in between the menu items. This style of display has been pretty popular at a lot of the places I've worked, but then I've also seen a lot of cases where an item in the menu isn't displayed for one reason or another and you get || in the menu, i.e.

main |  | documents ]

Instead of

main | documents ]

Or sometimes an extra pipe on either end like this

main | documents  | ]

And I know a lot of people think "so what?" ... but the point here isn't that it ever happens. No amount of experience or education prevents us from making mistakes. The most brilliant programmers still create typos and contribute code containing seemingly simple mistakes, because whatever we might want to think about our abilities, we're still human. That's why I always cringe when I hear managers berate people for "not testing your code" -- but every manager I've ever met does it. People make mistakes and sometimes that means code going to production with a bug - PERIOD. Their being human doesn't require they be made to feel like crap. If the software going to production is too error prone it's almost always because the company doesn't have a good Quality Assurance (QA) team and/or continue to demand that changes be made at break-neck speeds and refuse to set reasonable deadlines. (In my experience most companies have *NO* QA team, and demand break-neck deadlines in addition, which is a whole other rant.)

No my point about this in particular is that display bugs of this variety are pretty common when the code is formed the way you see it up above. It's the same reason why I wouldn't want a hot-key for "delete" right next to a hot-key for "save". It's about taking simple steps to make some of these common mistakes less common. This is why the framework offers the features to support this:

<cf_html>
<div tap:open="[" tap:close="]"
tap:childdelimiter="|"
style="white-space:nowrap;">

<a ...>main</a>
<cfif xyz>
<a ...>users</a>
</cfif>
<a ...>documents</a>
</div>
</cf_html>

Now this code will produce basically the same menu above, however, it will also ensure that you don't accidentally leave any pipes in or out of conditional statements to produce that display bug up above. It also has some other advantages, for example it involves fewer keystrokes and no duplication (you only enter the pipe character once). And then there are the extended advantages that you can use a combination of the framework's native XSLT features and/or the native internationalization features to easily replace the pipes and brackets for special needs or for branding for clients who would prefer a different look and feel (because we're a way's off from being able to control that text with CSS across the common browsers).

The other thing I'll point out here is that I removed all the &nbsp; character entities. This is of course not a framework issue, but I think its important for people to know. The style attribute white-space:nowrap; takes care of this for us by eliminating the need to use non-breaking spaces to prevent wrapping, which has a number of advantages, not the least of which being that you don't have to type all those entities... although ultimately I wouldn't prefer to place that in an inline style attribute, I would move it out to an external style sheet.

So long story short, the above code is cleaner and less error prone.

Enjoy!

New AJAX Feature - <tap:div />

So I just added an item to the framework's default stylesheet for <tap:div /> and also added it to the documentation for the xhtml tag library (which incidentally shows up both under function libraries and custom tags in the docs). You know all the underlying structure was already there, it just wasn't plugged together this way, but now you can use tap:div basically the same way the CFDIV tag works in ColdFusion 8 -- any links inside the div will fetch content via a framework gateway element (AJAX). So here's the code I tested it with.

<cfparam name="attributes.submitted" type="string" default="" />
<cfset attributes.submitted = val(attributes.submitted) />

<cf_html>
<div xmlns:tap="http://www.fusiontap.com" style="margin:20px; text-align:center;">
<tap:div>
<a href="?">
<tap:url name="submitted" value="attributes.submitted+1" />
click me!
</a>
<div>You clicked the link <tap:variable name="attributes.submitted" /> times.</div>
</tap:div>
</div>
</cf_html>

So all the XSL sheet is doing is a real simple copy of the div and its attributes and then adding a tap:gateway inside with a gaterespond event that imports the returned content to the gateway's parent element. So it's the same as if you had written this:

<div>
<tap:gateway>
<tap:event name="gaterespond">
<tap:import target="javascript:element.parentNode" />
</tap:event>

... links go here ...
</tap:gateway>
</div>

I love it when a new feature comes so easily. :)

BlogCFC was created by Raymond Camden. This blog is running version 5.5.006. | Protected by Akismet | Blog with WordPress