Monday, November 9, 2009

Droid: My Experience So Far

So I went ahead and bought a Droid this past Friday. I haven't had a huge amount of time to play with it yet, but I thought I'd share some of my experiences so far:

  • I'm not sold on the physical keyboard yet. The keys are very close together, so if you have decent-sized thumbs like I do, you have to really focus on your typing to avoid hitting two keys at once. Having said that, I have gotten better at it since my first day.

  • I like the on-screen keyboards. The haptic feedback (the slight vibration when you hit a key) is nice, and I like the row of word suggestions that's displayed under the typing area as you type. I prefer it over the virtual keyboard of my iPod Touch.

  • The screen is beautiful. I haven't had a chance to play any videos on it, but the application icons on the screen make the iPod icons look "soft" in comparison.

  • The web browser is on par with the Safari browser on the iPod (no real surprise, as they both employ the webkit engine). The Android browser does not have multi-touch, so you can't pinch the web pages, but it lets you double-tap on the page to magnify it and I find that sufficent. Web pages load about as quickly as I expected (a bit slower over 3G, obviously).

  • The new Google Maps Navigation with turn-by-turn directions is as cool as reported. I used it twice just to see how it worked, and it gave me perfect directions and was quick to recalculate the route when I went a different direction.

  • I like having the ability to have widgets on my screen for things like the weather and Twitter, but because the default UI for Android only gives you three screens to work with, you have to be judicious about which widgets you want to display (though it's easy to add and remove widgets).

  • I really like the notification system. If the Droid is "on" (i.e. the screen is lit), the notification/status bar at the top of the screen will denote if you have any new Gmail messages or Twitter updates with icons, and you can drag down the notification window to see a summary of what's going on. If the Droid screen is off/dark, and there are updates, an LED light in the upper right corner will flash. It even flashes different colors for different applications:  green if there's a new Gmail message, blue if Twidroid (my main Twitter app) has received new tweets.

  • Android phones do not have a set media management programs like iTunes, so you have two options for copying your media files onto your phone: you can simply mount the phone's SD card as a hard drive via USB and copy the files manually, or you can download a program like doubleTwist (Windows only) or Salling Media Sync (Windows/Mac) that inspects your iTunes library and playlists and copies any non-DRM media over to the Droid. I couldn't get doubleTwist to synch my files (I suspect it just needs to be updated to handle the Droid), but Salling Media Sync was able to copy over the iTunes playlists I selected.

  • Some Droid users have reported problems with the auto-focus on the camera for still shots.  I personally haven't experienced that problem. I was surprised that there was no way to specify what it was you wanted the lens to focus on within the shot: double-tapping on the screen causes it to zoom in rather than select the subject. Despite that, the few pictures I've taken look pretty good to me. There are one or two camera apps in the Android Marketplace, so I imagine that better camera applications will be developed for the Droid eventually.

  • Speaking of the Android Marketplace, it's easily accessible via the Marketplace app on the Droid. You can find apps by category or via the search bar, and each application is listed with a price (quite a few are free or donation-ware) and a rating. It's easy to download an app, try it out, and then uninstall/delete it if it's not to your liking.

  • The battery seems sufficient to me, though I probably haven't used it as heavily as some folks would. Since every app you turn on (and some apps start up automatically) stays on unless you explicitly kill it, having a program that can selectively turn off running apps like Advanced Task Killer if you don't want to waste power.  I also downloaded a widget that lets me selectively turn off the different radios/receivers on the Droid (WiFi, Bluetooth, GPS) if I'm not using them.

  • The ability to multitask is sweet. I had the music player on while I drove to work this morning when it occurred to me that I hadn't shut off the WiFi radio on the Droid. So while I was stopped at a traffic light, I hit the Home button, swiped over to the right screen where my radio manager widget was, turned off the WiFi, and went back to the music player, all without missing a note of the song.

If anyone has any questions about the Droid, feel free to ask, and I'll answer them if I can.

Saturday, October 24, 2009

How to Use the jQuery dirtyFields Plugin with FCKEditor

A commenter named Dean recently asked me if there was a way to use an FCKEditor field with my dirtyFields jQuery plugin.

When applied to a form or any container that contains HTML form elements, the dirtyFields plugin records the intial values or states of each form element, and then anytime the change event is triggered on any of those fields, the plugin functions compares the current value or state of the field to the recorded value/state and then applies certain CSS styles to certain page elements (as defined by the user) if that particular field has been changed.

There are two problems with trying to use an FCKEditor element with dirtyFields. The first is that the FCKEditor Javascript generates the page elements it uses to represent the editor window after the page has been loaded, after the jQuery document.ready event typically used when binding plugin functions and events to page elements. The second problem is that the editor content window (where the user does their typing) is contained in an <iframe> element, and as such the text within the editor window and any events triggered within that window aren't accessible to the dirtyFields plugin.

However, it is possible to get a handle on what's going on within the editor window by utilizing the FCKEditor API and then use some of the public functions within the dirtyFields plugin to make it work.

First the code, then the explanation:

<script type="text/javascript">
    function FCKeditor_OnComplete( editorInstance )
        {
            editorInstance.Events.AttachEvent( 'OnBlur' , checkForChanges ) ;
            $.fn.dirtyFields.setStartingTextValue($("#editorField"),$("#myForm"));
        }
			
    function checkForChanges( editorInstance )
        {
            $("#editorField").val(editorInstance.GetXHTML(true));
            $.fn.dirtyFields.updateTextState($("#editorField"),$("#myForm"));
        }
	
    $(document).ready(function() { 
	$("#myForm").dirtyFields();
       ...whatever other functions you want to run...
    });
</script>

<form name="myForm" id="myForm" method="post" action="something.cfm">
    <label id="lbl_editorField" for="editorField">FCKEditor Window:</label>
    <cfmodule
        template="/fckeditor/fckeditor.cfm"
        basePath="/fckeditor"
        instanceName="editorField"
        value=''
        width="600px"
        height="200px"
    >
    ...
</form>

A note about how I'm using FCKEditor in this example: the example is based off of a ColdFusion page I wrote in order to try this out, so I used the <cfmodule> tag to create the FCKEditor field. Programmers using version 8 or higher of ColdFusion can instantiate an FCKEditor field using the <cftextarea> tag, but I suspect the FCKEditor API calls will work the same in either case. 

As I said earlier, one of the problems was that the HTML elements created by FCKEditor were created after the page loaded. The FCKeditor_OnComplete() function solves this problem: it executes as soon as FCKEditor has finished creating the HTML elements needed to support the editor, and provides the instance of the editor as an object ("editorInstance" is simply the name assigned to the object in the FCKEditor API examples, so I followed their lead). One of the elements it creates is a hidden text field with an "id" attribute equal to the name of the FCKEditor instance. My example presupposes that the FCKEditor field in the form is named "editorField", in which case a hidden text field with an id of "editorField" now exists in the form.

The first line in the FCKEditor_OnComplete function binds the checkForChanges() function to the editor's "OnBlur" event, which means that any time the user navigates away from the editor window (either by pressing the Tab key or clicking on another page element with the cursor), the checkForChanges() event will fire (Note: for a while, I was convinced the API didn't provide a way of detecting a loss of focus because "OnBlur" isn't documented on the API page). The second line uses the dirtyFields setStartingTextValue() public function to record and save the value currently contained with the "editorField" hidden text field, so that dirtyFields has an initial value to compare any changes in the editor window against.

The checkForChanges() function also receives an instance of the editor as an object. The first line in the function uses the getXHTML() method of the editor object to retrieve the current contents of the editor window and copy it into the value of the "editorField" hidden text field. The second line calls the updateTextState() function of dirtyFields, which tells dirtyFields to compare the current value of the "editorField" hidden text field with the previous value recorded by the setStartingTextValue() function. If the values are different, the label associated with the "editorField" hidden text field will be styled to indicate that the content of the FCKEditor window is "dirty."

And that's all there is to it: even though the dirtyFields plugin can't interact with FCKEditor fields by default, the public functions provided by the plugin can be used in conjunction with the FCKEditor API to make it work.

Sunday, October 18, 2009

Creating a Reload Event-Handler for Model-Glue

The Model-Glue framework has a number of configuration settings that modify its behavior. Perhaps the most important of these settings is the "reload" setting. When the reload setting is set to "true", the framework itself will be reload on each request, and any changes you made to the Model-Glue, ColdSpring, or ORM settings of your application since the last reload will be implemented. When reload is set to "false," those framework files will not be reloaded, and any changes you might have made to them are ignored.

So the idea is that you would have the reload setting set to "true" during development so that any changes you make are processed in the next request. The drawback to being in this constant-reload mode is that it takes time to reload the framework, an amount of time that increases as you add event handlers, message broadcasts, and such to the ModelGlue.xml file and add more bean definitions to your ColdSpring file. It's for this very reason that the Model-Glue team state that it is "imperative" that you set reload to "false" when you put your application into production.

As the development of your application progresses, you'll reach a point where you don't want to reload the framework for every single request because you're spending too much time waiting between requests. At that point, you would set reload to "false", and manually force a reload of the framework when necessary by adding the reloadKey and reloadPassword to the URL of one of your page requests, like so:

http://www.myModelGlueApp.org/index.cfm?init=true

...where "init" is the reloadKey and "true" is the reloadPassword.

Many Model-Glue developers open a separate tab in their web browsers pointing a URL for their application that contains the reloadKey and reloadPassword and simply reload that page whenever they need the framework reloaded, rather than navigating away from the current page they're working on. I decided to go a slightly different route and create a reload event-handler that I could trigger from any page in my Model-Glue application and execute the reload event in a new browser tab or window.

The page layouts of my applications always include some sort of header area at the top of the page. In the header area, I added a hyperlink labeled "Reload MG" with a URL pointing at my reload event-handler:

<cfif viewState.getValue("appEnvironment") EQ "local">
    <cfset reloadURL= viewState.getValue("myself") & "performReload&init=true">
    <p align="right"><a href="#reloadURL#" target="_blank">Reload MG</a></p>
</cfif>

In my last blog post, I explained how my applications determine whether they're running in my local development environment or my remote production environment. The <cfif> statement ensures that the reload link only appears in the header when I'm running the application on my local box. Having the "target" of the hyperlink set to "_blank" ensures that the reloader page opens in a new tab or window.

The performReload event-handler is defined in the ModelGlue.xml file like so:

<event-handler name="performReload">
    <broadcasts />
    <results />
    <views>
        <include name="body" template="util/dspReload.cfm" />
    </views>
</event-handler>

The reload action is initiated by the presence of the reloadKey and reloadPassword in the URL, so there isn't a need to execute any additional controller or model code. The event-handler simply loads the dspReload.cfm page in my "util" directory. This is what the dspReload.cfm page looks like:

<h2>Page Should Close Automatically</h2>

<script type="text/javascript">
    window.close();
</script>

The single Javascript statement is pretty self-explanatory: close the current window.

So when I click on the "Reload MG" link at the top of any of my Model-Glue application pages, a new browser tab opens and the focus of the browser is on that new tab. I can return to my previous tab (where I'm working) and simply wait for the reload event to complete over in the new tab. Once it does complete, the Javascript executes and the new tab is closed: I don't have to close it myself.

So instead of keeping an open browser tab that I'd have click on, click the reload button for, and the click back to my previous tab, I can just click a link in my current page to spawn a reload tab and simply navigate back to my original tab. While it's not a huge improvement, I prefer it over maintaining a reload tab.

Saturday, October 17, 2009

Managing Environment-Specific Application Settings Via A ColdSpring Bean

When I develop my ColdFusion applications, I work in two different environments. I develop the applications on my local machine, then deploy them to the server when I reach particular milestones or when it's ready for limited user testing. Even though I mimic the server environment as best as I can on my local machine, there are still certain aspects of the application that are different when it executes on the server. For example, my local machine isn't configured to send and receive e-mail, but I want my application (when it's running in production) to send out an e-mail when certain functions are executed.

What I used to do to solve this problem was to run a series of functions via the onApplicationStart() function in Application.cfc that would determine where the application was running (development or production), record that fact in an application-scoped variable called "locale", and then set a series of additional application-scoped variables based on what the current environment was. I would then code certain aspects of my applications, such as those responsible for sending e-mail, to examine the value of the application.locale variable to determine if certain function should execute and then use any other application-level settings necessary for the actual execution (like the e-mail address associated with the application).

I recently started using Model-Glue as my application framework, and since Model-Glue uses ColdSpring to manage some of its internal settings, I decided to revise my technique to take advantage of ColdSpring as well.

Here is the code of the appConfig.cfc I created for managing the application settings:

The init() constructor function takes three structs as arguments: one that contains the universal application settings that are the same regardless of environment, one that contains the application configuration settings for my local/development environment, and one that contains the configuration settings specific to my remote/production environment. The universal settings are copied into the "config" struct in the variables scope, and then a call is made out to the determineEnvironment() function to determine the current application environment. The determineEnvironment() function uses the cgi.cf_template_path to determine if the current ColdFusion template is running on a Macintosh system (my work laptop is a Mac) and returns the name of the constructor argument that should be used to populate the rest of the "config" struct. The getConfig() function provides a means of retrieving the value of a configuration setting, while the setConfig() function allows you to change a configuration setting.

So populating this appConfig object with the correct application configuration settings is simply a matter of providing the three different configuration structs into the init() constructor argument. That's where ColdSpring comes into play: ColdSpring is ideal for managing and documenting the data and objects that need to be injected into singleton objects. Here is an example ColdSpring bean definition (within a ColdSpring.xml file) for the appConfig object:

As you can see, the ColdSpring bean definition contains three <constructor-arg> XML blocks, one for each argument to be passed into the appConfig.cfc during instantiation, and each constructor argument contains a <map> XML block that defines the struct variable for that argument.

What's the advantage of defining these settings in ColdSpring? Once the appConfig object is defined as a ColdSpring bean, I can inject an appConfig bean into any other singleton bean object I define in ColdSpring or retrieve appConfig from the ColdSpring beanFactory object (which is usually instantiated during application startup). Plus, Model-Glue makes it very easy to inject ColdSpring beans into any of your controller objects simply by passing a list of ColdSpring bean names into a "beans" attribute in either the controller's <cfcontroller> tag or the starting <controller> tag of the controller's XML block in the ModelGlue.xml file of the application (see the "How to Use Bean Injection" page on Model-Glue documentation site for more details on that).  And it makes sense to put my application configuration settings alongside the Model-Glue configuration settings in ColdSpring so there's only one file I need to refer to for my configuration data.

The end result? I end up with an appConfig object containing the correct application settings for the current environment that my code can retrieve variable settings from whenever a function's behavior is dependent upon the application environment.

This technique I've just outlined works for me because I'm a solo developer with only two application environments, a simple way of determining which environment an application is running in, and usually only a small number of environment-specific app settings to deal with. If you're working in a team or with multiple application environments, you made need a more robust approach.  One option you might want to consider is the Environment Config project on RIAForge.org. The project also lets you leverage ColdSpring to define environment-specific variables, but it provides more options for distinguishing between different application environments and more flexibility in how you structure and retrieve your application configuration information. It's still in beta at the moment, but it looks promising.

Thursday, October 1, 2009

Revision, Re-Release of My dirtyFields jQuery Plugin

I was pretty happy with the functionality of my original dirtyFields jQuery plugin, but as comments and questions about the plugin started coming in, I soon realized that there was a lot of room for improvement.  So I spent the last few weeks reworking the code to create a more flexible, more powerful version, one that completely replaces the original version.

The main purpose of the plugin remains the same:  it helps you show a user exactly which HTML form fields have been changed (made "dirty") since the page was last loaded or saved (text inputs, drop-downs, checkboxes, etc.).  But the new version of the plugin gives you more control over what page elements are affected when a particular form field is changed, provides callbacks that let you execute your own functions before and after a form field is processed by the plugin, and includes over a dozen public functions for manipulating individual form fields or the entire form (including functions that let you add the plugin event handler to any new form fields you add to the form dynamically after the page is loaded).

I created a website to go along with the new plugin that provides full documentation on all of the plugin settings, callbacks, and public functions and three working examples that demonstrate the plugin in action.  You can go there to learn all of the details:

https://bcswartz.github.io/dirtyFields-jQuery-Plugin/

Monday, September 28, 2009

Quick Tip: Accessing the Contents of a FCKEditor Box

Today I found myself needing a way to access the current contents of a FCKEditor instance on a web page via Javascript (I needed to create a "preview" dialog box that would show the user what the content would look like when published).  After some searching on Google, I learned that by instantiating FCKEditor on the page, I had access to the FCKEditor API and could access the content with the following statement:

var editorContent = FCKeditorAPI.GetInstance("postText").GetXHTML(true);

...where "postText" is the id value ("instanceName") of the editor.

Wednesday, September 9, 2009

jQuery Tip: Storing and Retrieving Object Properties with the Data() Function

The jQuery data() function allows you to store data "within" a DOM object by associating a property name with a value.  The first line of the code below assigns the value "bar" to the property name "foo" associated with the <form> element on the page, while the second line retrieves the stored value:

$("form").data("foo","bar");
...
var fooValue= $("form").data("foo");

It's a useful technique for adding metadata to a DOM element.

The jQuery plugin I'm currently working on associates several pieces of metadata with certain DOM elements on the page.  It occurred to me yesterday that it might be cleaner to store all of that metadata under one property (one namespace) in the DOM element, reducing the possibility of my plugin interfering with any other code might also store data using the data() function.  But I wasn't quite sure how I would retrieve the individual metadata values.

Turns out the solution is quite simple:  you can retrieve the object sorted in the namespace property, then reference the individual properties within the namespace using dot notation:

  var settings= {
     denoteDirtyForm: true,
     denoteDirtyOptions:false,
     trimText:true,
     dirtyFieldClass:"changedField"
  }
  ...
  $("form").data("myNamespace",settings);
  ...
  var showDirtyForm= $("form").data("myNamespace").denoteDirtyForm;
  var dirtyClass= $("form").data("myNamespance").dirtyFieldClass;

So it looks like there's no real limit to the amount or complexity of data you can associate with a DOM element using data().

Sunday, August 23, 2009

New jQuery Plugin dirtyFields: Bring Attention to Changed/Unsaved Fields

I just finished a project that included an administrative page where users could make changes to a parent record and numerous child records via multiple forms. All of the form submissions were done via AJAX, so I needed a way to illustrate which of the forms on the page contained changed or "dirty" data, and which forms had no unsaved changes.

This dirtyFields plugin is derived from the functions I wrote to handle that task in that project.

It applies a CSS class to a contextual DOM element associated with any form field that has been changed from its original value. For text inputs, <textarea>, and <select> elements, the <label> element associated with the field (via the "for" attribute) will be styled with the class. For <checkbox> and <radio> elements, you can specify the text associated with each element using "checkboxRadioTextTarget" plugin option (the default setting is "next span").

It works by storing the current value or state of each form field within the data store of the field using the jQuery data() function.  As the value or state of the form field is changed, its current value/state is compared to the one within its data store, and if they aren't equal the field is considered "dirty".  The plugin includes a function called "resetForm" that can be used after the form has been submitted to update the data store of each field with the new field value and mark all the form fields as clean.  There is also an option to apply a CSS class to the form itself to indicate whether or not it contains dirty fields.

(UPDATE: I've now added support for a "formIsDirty" callback function that can be used in conjunction with the "denoteFormDirty" option to run your own functions once a form has been determined to be clean or dirty.)

Links to a demo and documentation can be found below the following screenshot, which shows the style changes to the labels and text of form elements that have been changed:

Project homepage: https://bcswartz.github.io/dirtyFields-jQuery-Plugin/

Sunday, August 16, 2009

News and Impressions from CFUnited 2009

If you've been following my updates on Twitter, you know that I was at the CFUnited conference last week. I didn't post anything during the conference because, quite frankly, I didn't set aside any time to do so, and there was lot going on most of the time.

I'm not going to try and sum up everything that was presented at the conference: I'm not sure any one person can. But there were a number of news items and developments that came about either just before the conference or during the conference that I thought were worth pointing out:
  • ColdFusion 9 in the Cloud: In the opening CFUnited keynote, Ben Forta and the Adobe team announced that ColdFusion 9 would include licensing options for running ColdFusion in cloud environments, and that they would specifically support the use of ColdFusion 9 on Amazon's EC2 cloud environment. Details (sparse though they are) can be found on Ben's blog post on the subject. Though I'm not a fan boy of cloud computing, having this option is important for ColdFusion developers who have an idea for a high-traffic web application but don't have the money to invest in their own server farm.
  • 4CFF: 4CFF is the acronym for the For ColdFusion Foundation, a new non-profit foundations founded by several member of the CF community with the goal of providing assistance and resources to ColdFusion open-source projects and establishing a "professional membership society for the ColdFusion Community at large." I missed their unofficial announcement/presentation, so I can't provide any information about how they plan to move forward with their goals, but I think the idea of having a resource where CF programmers can get help with the non-programming challenges involved in starting and maintaining an open-source project is a good one.
  • Framework updates/changes: The final, production version of Model-Glue 3.0 (Gesture) was released just prior to the conference, while the beta release of ColdBox 3.0 was announced on the first day of the conference. But perhaps the most dramatic framework announcement was that Adam Haskell, previously the lead developer for the Fusebox framework, was going to resign from that role and lead the development of a new and separate version of Fusebox called FuseNG (Fusebox Next Generation), citing irreconcilable difference between himself and TeraTech, the Maryland-based CF development/training shop that currently controls the domain name and source code behind Fusebox. As a developer who uses Fusebox, I'm curious to see how this decision will play out. The current version of Fusebox is a very effective, usable, and mature framework, but Adam's a smart guy and it'll be interesting to see what he and the other developers involved in FuseNG will come up with.
  • The Merlin Manager beta: The final event on Friday at the conference was the Demo Derby, where developers got several minutes to show off a project of theirs. While all of the presentations were noteworthy (and in two instances quite humorous), the one I thought really needed to be brought to the attention of the CF community as a whole was John Mason's Merlin Manager. One of the announcements regarding ColdFusion 9 was that it would provide an AIR-powered desktop application that would let ColdFusion server administrators manage and compare multiple ColdFusion server instances from one dashboard. John's Merlin Manager is also an AIR-powered CF server manager, but it's built to work with ColdFusion 7 and 8 servers. He demonstrated how his app provided real-time status information for a server, how it let you store current server settings as a snapshot prior to making a settings change, and that it could compare the settings between two different servers, highlighting where the settings differed. Even though the project is still in beta, it looked very feature-complete and could be of real benefit to those CF shops that won't be upgrading to CF 9 anytime soon. John is looking for volunteers to participate in evaluating the beta: if you're interested, visit http://www.merlinmanager.com/ to sign up.
As for the conference as a whole, I have to echo everyone who's already commented about it on their blogs and via Twitter: it was an excellent, informative, and fun conference, the best I've ever attended. And that statement is coming from someone who, for various personal and professional reasons, wasn't all that worked up about attending. Everyone involved in the planning and execution of the conferences, especially the folks from Stellr and those presenters who stepped up to fill in for last-minute speaker cancellations (all the presenters deserve credit, but those folks especially) should be proud of the work they did.
For those folks who weren't able to attend, be aware that a number of the presenters will be posting their presentations online, either on their own blogs, SlideSix, or both, so keep an eye out for announcements about those (and note that some of those posting and announcements were made last week during the conference itself).

Saturday, August 8, 2009

Federal CTO Envisions a Purpose-Driven, Collaborative Internet

One of my favorite podcasts is Buzz Out Loud, a weekday live video stream and podcast from CNET.com that reports, analyzes, and banters about the tech news of the day. This past week, they conducted an interview with Federal CTO Aneesh Chopra, which I just finished listening to today.

The entire interview was quite interesting, but there were two particular discussions that struck me.

The first one was about broadband penetration: the Buzz Out Loud podcasters wanted to know what plans, if any, were being made to promote the rollout of broadband to those areas where such service was limited or unavailable. Chopra said that they hoped to address that issue with a national broadband plan due to be revealed in February 2010, but he said that his personal focus was more on encouraging innovation in developing applications that would further the adoption and development of a robust broadband infrastructure. In other words, it's not just about building the infrastructure for people, businesses, and government organizations to have, but creating compelling applications of that infrastructure that bring people on board and give them more reasons for wanting ubiquitous Internet access.

As web/Internet application developers, we tend to think of broadband, high bandwith, and Internet access as the infrastructure that allows us to build robust applications. It's kind of exciting to look at it the other way around, that creating useful, effective, compelling applications that people want (or perhaps even need) could promote and justify the expanse of the broadband infrastructure.

The second discussion was in response to a viewer question about the use of open source software within government agencies (SUSE and RedHat were specifically mentioned). Chopra said that that was really in the federal CIO's arena of concern, but that he personally was more interested in promoting the principles of "open collaboration" and the "sharing of intellectual property as we build value." He went on to explain that what he meant by that was that he didn't care so much if an application built for the government was built on a proprietary platform so long as that application became shared intellectual property between government agencies. That again was another point that I hadn't heard anyone make before.

I'd encourage anyone who has an interest in how the federal government hopes to leverage technology to the country's advantage to listen to this podcast episode. You can watch the video version or listen to the audio version, either streaming or as a download, at the following address:

http://www.cnet.com/8301-19709_1-10302978-10.html?tag=mncol;title

Wednesday, July 15, 2009

The Risk of Performing JavaScript Operations Around User-Generated HTML

Last year I wrote a ColdFusion application that included a page where an editor could take a list of short news abstracts and manipulate them (reorder them, place them in categories, add divider lines, create anchor links to highlighted stories, etc.) using a number of jQuery-powered JavaScript functions. It gives them a lot of control over the final layout, and they're pretty happy about it.

However, there have been occasions when this layout tool doesn't work at all. Why? Unclosed HTML tags in the abstract data.

The page they use to enter the news abstracts is comprised of several plain HTML text fields, a set of category checkboxes and two WYSIWYG textarea boxes (powered by JavaScript) for the abstract itself. I gave them the WYSIWYG boxes because I knew they would want to be able to do some basic HTML formatting on the abstract text (boldface, italics, etc.), and the WYSIWYG editors do produce solid, clean HTML.

What they do that gets them in trouble is they enter HTML tags (usually for italics) into the title form field, which is a normal HTML text field. Every once in awhile, they forget the closing tag or maybe just an angle bracket...the abstract itself saves correctly but when they get to the layout tool, that unclosed HTML tag messes up the entire DOM structure the layout tool is programmed to manipulate, rendering it non-functional.

They've now learned that when the header text of the various layout tools appears in italics, that usually means they've got an unclosed italics tag that needs fixing. It's easy enough to fix once they figure out which news item is responsible.

So a word of warning: if your JavaScript functions are designed to act upon HTML code that you yourself don't have complete control over (or the ability to make sure the HTML is clean and proper), consider the possibility that your JavaScript may end up breaking due to the content.

Saturday, May 23, 2009

In Defense of Twitter

Since I've already defended Twitter in two other people's blogs this past week, I figured I should write my own post on the matter. That way, if I feel inclined to comment on Twitter use again, I can just post the URL to this entry and leave it at that (save myself some typing).

I wasn't enamored with Twitter when I first checked it out. I wasn't interested in the mundane things people were doing at the moment, and I certainly didn't think anyone really cared what I was doing.

But at cfObjective() 2008, it quickly became clear that Twitter could help me connect with fellow conference-goers and clue me in on what was going on in particular sessions, where people were gathering to hang out or go out, etc. And I've used Twitter ever since: I'm not on it every waking moment and I don't feel like I'm disconnected when I'm not on it, but I do make use of it.

I really feel that the simple trick to getting value out of Twitter is to follow people whose Twitter posts ("tweets") provide some value to you: information, insight, humor, whatever. Most of the people I follow are ColdFusion/RIA/Web developers, and they'll post any interesting links about those topics that they encounter as they surf the web. It's almost like a people-powered RSS feed of tech articles, except that you're getting the information from people you know and respect rather than random people.

Sure, there are the occasional tweets about where people are or what they're having for lunch, the tidbits of daily life, but those can be easily ignored if you're not interested. And yes, it can be a distraction if you're getting live updates from Twitter via a desktop client like Twhirl or Tweetdeck, but there's a simple solution to that: turn it off while you're working, and turn it back on when you're taking a break.

I'm not trying to push Twitter on anyone--you can live without it--but I think folks should give it a serious try before deciding one way or the other.

Thursday, May 21, 2009

Mozilla Announces Jetpack, an API For Writing FireFox Adds-On with jQuery, HTML, and CSS

I found out about this last night from a tweet sent out by the jQuery Twitter account (which is probably a good indication that they like the idea).

The subject line pretty much says it all: Jetpack is designed to let current web developers use their existing skills with HTML, CSS, JavaScript, and jQuery to build Firefox add-ons/plugins without the need to mess with Firefox's XUL mark-up language. While JavaScript has always been part of the add-on development process, the inclusion of jQuery should make performing certain actions a whole lot easier.

You can learn more about Jetpack via the following URLs:

...the tutorials in the final link give you a good idea of the kinds of things Jetpack will allow you to do: the last example is a Jetpack add-on that will count and display the number of unread e-mails in your Gmail Inbox.

I want to give Jetpack a whirl, but I honestly can't think of any functionality I want to add to Firefox that I can't get from an existing plugin. Anyone have any suggestions for something to try with Jetpack?

It's interesting how web technologies keep being repurposed as a development option in other technologies (Adobe AIR, the upcoming Palm Pre's WebOS, and now Jetpack). Even though I'm not particularly interested in delving into all these different areas, I must say that I like the trend. :)

Saturday, May 9, 2009

Bug In How Safari 3.2.1 Renders the Links For RSS Feeds

One of my clients contacted me yesterday to tell me that there was a problem with reading their RSS feed in Safari (and only in Safari).

Over the next hour or so, I learned quite a bit about how the current version of Safari (3.2.1 as of this writing) handles RSS:

  • By default, Safari is configured to open up your default e-mail client to handle/read RSS feeds, resulting in a lot of head-scratching by your truly when I tried to navigate to the feed and ended up with a "Compose New Message" window in Thunderbird. While a lot of people do prefer the RSS-reading capabilities of their mail client over what the browser does with feeds, making that decision for the user is a questionable call on Apple's part, and some sort of alert/notice that this was the deal would have been nice.

  • A lot of browsers these days will apply a style to the RSS feed XML (probably using some sort of built-in XSL, I'm guessing) prior to display so that it's more human-readable and the hyperlinks for each news item are clickable. But you can still view the raw XML using the "View Source" option of the browser. Safari, on the other hand, transforms the feed into an HTML file with JavaScript, leaving no trace of the original XML. Again, another somewhat presumptuous decision by Apple to buck convention in order to enhance the user experience.

...Those two issues are annoyances rather than bugs. The problem affecting my client's RSS feed, however, is a bug in regards to how Safari is transforming the RSS data before displaying it to the user.

Each news item in an RSS feed can contain a number of elements/nodes, two of which are the <link> and <guid> elements. The <link> element is meant to contain the URL where the reader can access the full text of the item. The <guid> element contains a string that uniquely identifies that RSS feed item within the feed (like a primary key in a database).

If the <guid> element contains the "isPermaLink" attribute and that attribute value is set to "true", then that indicates that the <guid> element also contains a URL (a permanent one) to the full text of the item (one that might be different from the URL in the <link> element), and an RSS client could legitimately used the URL in the <guid> as the link to the story instead.

What I discovered, though, was that Safari was creating the hyperlink for each news item by combining the value of the <link> element in the <channel> node of the RSS feed with the value of the <guid> element of each item (which was simply a unique numeric value), even though the <guid> elements did NOT contain the "isPermaLink" parameter. So instead of using the value of the <link> element of each item as per the RSS specs, Safari ended up creating non-existent URLs.

The solution, of course, was simple: I just put the URL for each news item in the <guid> element as well as the <link> element. Point is, I shouldn't have had to.

Once I applied the solution, I did some searching to find out if this is a known problem that was being worked on. I found one mention of it in a generic tech support forum post published in 2008, so it looks like the problem has existed for awhile but hasn't gotten much attention (probably because most people read RSS feeds through actual RSS clients). I used Safari's built-in bug report mechanism to report it to Apple, but I don't hold out much hope for that having an impact.

Still, I thought it worth a post, on the off-chance this information might help someone else.

Wednesday, May 6, 2009

New AIR Application: focusTimer

A few weeks ago, Peter Bell wrote a blog post about the Pomodoro Technique, a time management technique that advocates setting aside a set amount of time to turn off all distractions (e-mail, IM, Twitter) and focusing on a single task. I had just recently starting adopting the practice of shutting down my e-mail client once in awhile so as not to be distracted by incoming messages, so the idea made a lot of sense to me.

Not having a physical kitchen timer like the Pomodoro folks use and finding my stopwatch to be somewhat inadequate, I decided to try and write an AIR application to fit my needs. And so the focusTimer was born.

It's a very simple app: set the amount of time you want to focus (the 25 minutes advocated by the Pomodoro folks is the default), and click the "Start" button. I didn't want to get caught up in checking to see how much time was left, so I added a button so I could toggle between seeing the time left and just a status message.

I wanted to keep the window small so that it could be moved out of the way, but I also wanted a strong visual cue for when the time was up, so the color of the window changes to green when you start the countdown, switches to yellow for the "2-minute warning", and ends in red when the timer runs out. In the two days I've been using it at work, I've found that I can move the window to the far end of my secondary monitor and still catch the color change out of the corner of my eye.

Finally, even though the idea is to block out all distractions, there are some interruptions that cannot be ignored, so the "Start" button toggles between a "Pause" button and a "Resume" button once the countdown has started. If your focus session goes completely off the rails, you can use the "Cancel" button to break out of it and start all over again.

Even though I wrote this AIR app primarily for myself, I figured other folks might find it useful, so it's now available for download up on RIAforge: http://focustimer.riaforge.org

Wednesday, April 29, 2009

Preventing Non-Existent Dates with JavaScript

When I say "non-existent dates", I mean dates like "April 31" or "June 31," an end-of-the-month date a user might enter if they don't take a moment to review the old "Thirty days hath September" mnemonic rhyme. All decent date pickers/selectors prevents users from entering letters or other inappropriate characters, but few of them bother to check if the date value itself is valid.

You could write a date validation script that took the month and day value submitted by the user and checked it against a list of the maximum number of days for each month, but then your code would also have to determine if the year selected by the user was a leap year in case the user entered "February 29" as their date of choice.

There's a more straightforward way to check the validity of the submitted date: create a JavaScript Date object using the year, month, and day submitted by the user, then extract the year, month, and day values from the newly created Date object and compare those integer values against the ones submitted by the user:

This works because JavaScript's date creation function will accept the integer values for a non-existent date like April 31, 2009 (4, 31, and 2009), but it will quietly translate it into it's real-life equivalent, in this case May 1, 2009. So the integer values pulled from the date object via the getFullYear(), getMonth(), and getDate() functions will not match the integers originally passed into the date creation function, and you know there's a problem.

Wednesday, March 25, 2009

Using jQuery Manipulation Functions (Append, Prepend, After, Before) To Reorder Items

I discovered something interesting quite by accident today. I was trying to figure out the best way to reorder certain <li> items based on the value of a particular trait (while ignoring those <li> items that didn't have that particular trait at all). I figured the best way to accomplish this was to:

  1. Select all of the items that had the trait and store them in an array
  2. Resort the contents of the array into a new array.
  3. Delete the selected items from the list (so as not to replicate them)
  4. Loop through the new array and add the items back into the list using the jQuery prepend() function to put them at the top of the list.

When I ran my first test of my code, I left out the deletion step so I could compare the original item order with the new item order, figuring I would have duplicates of the selected items.

However, I was surprised to discover that prepend() removed the original instances of the selected list items, leaving only the prepended copies. Essentially, it ended up moving the items rather than duplicating them.

There's nothing on the official documentation page that says that if you're prepending an item to a collection that already contains an instance of that item that it will remove the original item for you, but that's apparently what it's programmed to do.

I ran a quick test of some of the other related Manipulation functions (append(),after(),before()), and they all seem to behave that way as well.

Thought it was worth sharing. Certainly makes my reordering task a bit easier.

Friday, March 20, 2009

Using jQuery UI Sortables To Move Items From One List To Another

During my most recent project, my clients asked me to build a web-based tool that would help them place volunteers into various standing committees. Placements would be made based on the preferences of the volunteers (who were asked to choose up to three committees they would like to serve on), the vacancies created in each committee by outgoing members, and the desire to have a diversity of units and divisions represented in each committee.

I decided pretty quickly that the most natural way to represent this placement process on a web page would be to let them "physically" move a volunteer into a committee. I had built similar tools before (even before I started using jQuery), but never with more than two lists or collections, so I went to the jQuery UI site to see what my options were.

I started with the most obvious place to start, the Droppable interaction, but soon realized that a better choice for this task was the Sortables interaction.

The primary focus of the Sortable interaction is to let you reorder a collection of DOM elements by dragging them up-and-down through the collection. It's extremely easy to implement in its most basic form. If you wanted to make all of the <li> elements in a <ul> with an "id" attribute "listA" sortable, you can do it in one line:

$(document).ready() {
  $("#listA").sortable();
});

...you can see that code in action on the home page of the Sortables interaction.

What I discovered was that it was almost as easy to connect one Sortable list to another, so that in addition to being able to move reorder items within each list, you could drag items from one list to the other, simply by using the "connectWith" option:

$(document).ready() {
  $("#listA").sortable({
    connectWith: ['#listB']
   });

$("#listB").sortable({
   connectWith: ['#listA']
  });

});

...In the code above, the first sortable() function call makes listA sortable and uses the "connectWith" option to allow items from listA to be dragged into listB. The second sortable() function call lets you sort items in listB and drag items from listB over to listA (even items that originally belonged to listA). If you wanted the movement to only go in one direction (from listA to listB but not back again), you could leave out the "connectWith" option for listB.

Again, the jQuery UI site has a nice ready-made demo of this.

All well and good, but right now all this code does is create the visual effect of moving an item from one list to another. Actually recording the fact that a particular item was moved from one list to the other requires more code, code that is invoked whenever such a move takes place. Being the smart guys and gals that they are, the jQuery UI team built a couple of custom events into the Sortables interaction so you can run additional functions when a certain event has taken place. For my purposes, I only needed to utilize two of these events: receive and remove:

$(document).ready({
  $("#listB").sortable({
    connectWith: ['#listA'],
    receive: function(event, ui) {
       //Run this code whenever an item is dragged and dropped into this list 
       var itemText= ui.item.text();
alert(itemText + " just joined this list");
}, remove: function(event, ui){ //Run this code whenever an item is dragged and dropped out of this list var itemText= ui.item.text(); alert(itemText + " just left this list"); } }); });

...The code is, for the most part, self-explanatory, save for one line (repeated twice): var itemText= ui.item.text()

The ui object is a "prepared" object created by jQuery UI that holds a number of objects and data associated with the event that just took place. The item object within the ui object represents the item that was moved in or out of the list, so I can treat it as a jQuery object and retrieve the text of the item using the standard text() function. You can find a full list of the data contained in the ui object by clicking on the "Overview" tab at the bottom of the main Sortables interaction web page.

Two things worth mentioning at this point:

  • If one of your lists starts off empty, or if there's any chance that a user might remove all of the items from a list and then try to put items back into the now-empty list, you need to set a minimum height for that <ul>, so that even when empty, the <ul> is large enough to accomodate a single list element. In Firefox and Safari, you can set the minimum height using the min-height CSS style, but if you have to support IE 7, you'll have to add two additional height styles (like so):
    • min-height:50px;
      height:auto !important;
      height:50px;

  • In my early experiments with this, I found that if you drag an item of a list, the list item's width gets shrunk to the width of the longest unbroken string of text in the list item. I'm not sure why it does that, but you can negate that effect by either defining a set width for the <li> elements, or by defining a "helper" with a set width (a helper is a visual representation of the item being moved, using something graphical like an icon).

So, armed with this knowledge about the Sortables interaction, I was able to build the tool required by my clients. Every time a volunteer was moved into or out of a committee, the receive or remove event would make an AJAX call to update the volunteer's record (either providing the id of the committee they were placed in or removing it), and it would run a function that updated the vacancy count for that committee specific to that type of person and counted the overall number of vacancies for that committee (to determine if the committee had been "filled"). I also added a few toggles allowing them to hide extraneous information when they only wanted to see the data pertinent to doing placements for a particular committee. The final challenge was to scale everything so that the tool could be viewed with a projector, so that the members of the group responsible for making the placements could work on it collaboratively.

I wasn't comfortable sharing an exact copy of the tool I created, but I have posted a facsimile that's fairly close to it, minus any real-life data and any AJAX calls to save the placements between page reloads. You can view it here (Note: it doesn't work in IE 7):

https://bcswartz.github.io/jQuery-dragAndDrop-memberPlacement-demo/

...I provided instructions at the top, but quite honestly I think most IT-inclined folks could figure it out without them.

It's just one example of some of the really cool (yet practical) user interfaces made possible with jQuery and jQuery UI.

Wednesday, January 7, 2009

Introducing the tableFormSynch jQuery Plugin

These days, there are a number of options for creating tables where a user can click on a cell and edit the data in that cell using JavaScript (CFML's <cfgfid>, the Jeditable jQuery plugin, etc.). Those work fine for simple tables, but they're not great solutions when you want to:

  • Work with record data you're unwilling or unable to display in the table, lest the table become too long horizontally.
  • Update data related to the row record that could have multiple values (example: the list of skills an employee has).

My new plugin, tableFormSynch, is designed to provide a workable alternative for those situations. It works in conjunction with the jQuery metadata plugin (http://plugins.jquery.com/project/metadata) to bind a table to a form such that you can populate the form with the data stored in a particular row and then use the form to update the data and write it back to the row. It also has functions for creating a new row based on the data in the form, deleting a selected row, and clearing the form of all values. It works with all form elements, including checkboxes, radio buttons, and <select>.

Because the data for each table row is stored in metadata, you don't have to display all of the data in the cells of the row: show only the most important information in the row and show the rest of the information in the form. Values from multiple related records can be stored in the metadata as arrays and viewed/updated via the form using either checkboxes or multi-select <select> boxes.

The only thing you have to watch out for is to make sure that you replace any single-quotes and double-quotes in your data before inserting that data in the metadata string (the plugin documentation covers that in more detail).

The plugin doesn't perform any AJAX operations, so you're free to use your preferred AJAX functions to write and retrieve data from the server. The plugin also isn't particular about how you populate the data in your rows, so you could generate the rows using any server-side technology: CFML using <cfoutput>, <cfloop>, or an IBO, PHP, ASP, etc. You're also free to use your favorite functions for validating the form data. To view a demo and download the plugin, visit:

https://bcswartz.github.io/jQuery-tableFormSynch-plugin-demo