Wednesday, February 27, 2008

ColdFusion 8's Image Functions + jQuery= A UI For Adding Text and Color Blocks Into An Image file

One of the new features in ColdFusion 8 is the ability to manipulate images using ColdFusion tags and functions. For example, the code below (all server-side code) will take an image file on the server, overlay it with text, and create a brand new image file in temp space and display it to the browser:

<!---Assign the image file to the carImage variable--->
<cfimage name = "carImage" action="read" source="ferrari.gif"/>
<!---Add the text "Fast car!" to the image and place it 10 pixels from the left and 15 from the top--->
<cfset ImageDrawText(carImage, "Fast car!, 10, 15)>
<!---Display the new image--->
<cfimage source="#carImage#" action="writeToBrowser">

A week ago, an idea popped into my head: "What if you could create a UI tool that would let a user decide what text should appear on the image and where it should appear?"

I decided to try and answer that question. The result: a working proof-of-concept that lets you add text and blocks of color anywhere on a selected image using a UI tool powered by jQuery JavaScript functions. When you're done manipulating the image, you submit the data defining your changes to ColdFusion via an AJAX call, and ColdFusion creates a new image in temp space based on that data and displays it. You can save the new image down to your computer or store the data you submitted in the database so the image you made can be reproduced without permanently storing a new image file.

The fact that it only took me a week to do this (no more than 25 hours) is a testament to both the power and simplicity of ColdFusion and jQuery.

The GitHub repository containing the code can be found at https://github.com/bcswartz/imageCaptionator-ColdFusion

You can watch a YouTube video of the application in action at https://youtu.be/JcLnO6zB3MM

Thursday, February 21, 2008

Changing Individual CSS Styles with jQuery

Back when I was writing my own custom JavaScript functions, I learned that there wasn't a single, simple way to change the individual style settings (like "font-weight:bold") for an HTML element that worked on every browser. My solution was to change the CSS classes assigned to the element instead: I wrote a library function that would allow me to add, remove, or replace any class assigned to an HTML element and simply created as many class definitions as I needed in order to accommodate the style changes. It was actually a pretty effective workaround because it let me effectively change multiple styles with one function call.

When I started using jQuery, I quickly learned about the "addClass" and "removeClass" core functions, which I could use instead of my library function:

$("#missionStatement").addClass("importantTextClass");
$("#userProfile").removeClass("hideTextClass"); 

...So I continued with my routine of changing styles by changing classes, even though sometimes I only needed to change or remove a single style setting. No harm, no foul.

But changing classes wouldn't work for the wacky little project I've been working on recently: I needed to be able to change several styles for an HTML element individually, and writing a class to handle every permutation of the possible style combinations was impractical.

So I went to the jQuery web site, hopeful that the brilliant folks at jQuery had something that could help me out.

And they did: the "css" core function allows you to read or set any individual style or styles:

if ($("#missionStatement").css("font-weight")== "400" || $("#missionStatement").css("font-weight")== "normal")
 {
   $("#userProfile").css("display","none");    
   $("#missionStatement").css({ fontSize:"24px", fontWeight:"bold" });
  } 

Have I mentioned that I love jQuery? :)

Tuesday, February 19, 2008

Thoughts on Future Trends in Computing

At our staff meeting today, my manager told us our director was looking for input on emerging "21st century" technologies and technology trends, and to send him our thoughts so he could pass them along. Here's what I sent:

  • The introduction of applications that have both a web and and desktop front-end to access server-side data, with the desktop application provide offline functionality and data storage that can then be synchronized with the back-end data. Examples of this upcoming movement are Adobe AIR, Google Gears, and the Mozilla Prism project.
  • Increased portability of programming languages to other platforms. It's now possible to code .NET or Java application in dynamic languages such as Python or Ruby.
  • Increasing development of RIAs (Rich Internet Applications) based on AJAX, Adobe Flex, Microsoft Silverlight, and JavaFX. RIAs allow for more engaging and more powerful user interfaces and (in the case of the latter 3 technologies) make it easier to integrate audio-visual material into applications.
  • The continued growth of "cloud computing," where organizations store their non-critical data on external servers maintained by a third party but controlled and accessed by the organization over the Internet. The chief example of this is Amazon's S3 data service.
  • The continued trend of exposing the social (people-based) connections between data started by the social networking sites. The social networks themselves may stop growing, but the idea of using a person as a focal point for otherwise unrelated data is going to stick around.

...Hardly earth-shattering predictions, but other than within my particular unit, my organization isn't that hip to web trends.

Sunday, February 17, 2008

Some Design Considerations When Building A Web App for iPhone/iPod Use

I recently finished a small project that involved optimizing some simple web applications for use on an iPhone/iPod Touch. I won't bore you with the specifics of the project (unless someone asks) but here are some things I learned during the experience:

  • There is no touch analog for click-and-drag (probably because dragging is an action reserved for moving around the page), so drag-and-drops will not work and you cannot select text for copying, cutting or pasting. This means the dragging tools/effects implemented in the various JavaScript libraries (jQuery, Yahoo YUI, etc.) won't work.
  • There's really no way to "hover" over an element with your finger, so any CSS style initiated by hovering will not come into play.
  • Because fingers are less precise than a mouse cursor, you have to make sure there is enough space between different clickable elements (links, checkboxes, etc.) so that the user can easily click only on what they want to click on. So if you have a vertical list of hyperlinks, you may want to put at least one line of space between them.
  • When you click on a text field, textarea, or select box, the page zooms in and either a keyboard or a list of drop-down choices appears at the bottom of the screen. Once you make your choice/enter your text and tap the "Done" button, the zoom doesn't reverse, so you end up still focused on the input element. That means if you have a submit button off to the left or right, you have to tap and scroll the page to it in order to tap it. If your application is designed to be viewable in the iPhone/iPod without the need for zooming, you might be able to negate this effect by disallowing all zooming (haven't tried this yet).
  • Selecting a choice from a drop-down box does not fire off the onChange JavaScript event for that box, probably because the action is intercepted in order to allow the iPhone/iPod to do the actions described in the previous bullet. The onChange event for text boxes might be similarly affected.

Tuesday, February 12, 2008

Data Storage Forecast: Only Partly Cloudy

Over the past few weeks, the idea of moving data off of desktops and locally-controlled database servers and "into the cloud" (onto shared data hosting services like Amazon's S3) has been gaining more attention. A guy named Nicholas Carr went so far as to predict the demise of the IT department as businesses essentially outsource their data processing/data retention (NetworkWorld, 1/7/08).

There's no doubt that individuals store more data online these days than they used to because of the rise of applications like Facebook, Flickr, and Google Calendar. Any data that has a social aspect to it gains value by being "out there" for others to view and interact with.

There are also business processes that involve collaboration with other business partners, where arrangements are made to exchange information or tangible goods via a buyer/seller dynamic. Again, it makes sense that the data and even the applications that power such collaborations could be managed and hosted by a third party.

But there will always be a desire to keep certain data close to the vest, even if that means maintaining an internal hardware and network infrastructure. Colleges and universities are not going to outsource their student data to a third party, and medical institutions are obligated by law to safeguard medical information. Banks will probably take a pass on shared data hosting as well. Even if cloud computing becomes more accepted and reliable, there will always be groups and individuals unwilling to give up that control despite any cost savings.

Thursday, February 7, 2008

Switching Between Sets of Database Tables On The Fly

Ever need to tell your ColdFusion app to run select queries against a different set of tables while you do something to the original set (like perform a batch update)?

I did. Here's how I did it.

First, I gave each table in each set a two-part name, two words separated by an underscore. The first part of the name was descriptive of the data in the table ("chapters","sections", etc.) while the second part of the name identified the data set the table belonged to ("live", "archive", whatever). So the "chapters_live" and the "chapters_archive" tables were exactly the same in structure.

Then I created an application variable called "application.tableSuffix" and set its initial value to "live".

(Can you see where this is leading?)

Finally, I changed my select queries to use table names comprised of the first, data-descriptive part of the table name, the underscore, and the value of application.tableSuffix:

<cfquery name="showChapters" datasource="ds">
   select chapterTitle, chapterIntro
   from chapters_#application.tableSuffix#
   order by chapterOrder ASC
</cfquery>

Once that was done, I could change the table set my select queries ran against at any time by simply changing the value of application.tableSuffix. Two things worth noting:

  • This technique only makes sense if only one set of tables can be updated by the user: if users can make changes to either set, you'll have to figure out how to resolve the differences between the data in each set.
  • If the switch could potentially be in place for awhile, you might want to store the current tableSuffix value in a database record or a file and then retrieve that data in the onApplicationStart method of your Application.cfc file so that the current value is preserved even if the application scope expires.

Tuesday, January 22, 2008

Techniques for Providing Instructions Within a Web Application

Some of the processes you find in web applications are fairly standard. Most folks can fill out a contact form, or fill out a survey, or make a calendar entry without the need for too much explanation. But what do you do when the form involves business rules that the user may or may not know, or presents the user with a number of options?

I always try to make sure the tools and the pages I put in my web applications are fairly self-explanatory, especially those tools and pages that only the administrative users of the application interact with.

The folks who end up using and administering my applications (my clients) are almost never technical people, so I start off each administrative page with a brief explanation of what the page does and how you save any information entered on the page. Once they've used the page, they can always skip over the intro and go right into the form or tool.

If the overall form requires a bit of explanation, something that can fit into a few short sentences, I'll put that explanation right after the basic description. If certain form fields require special instructions (like the requirements for choosing a sufficiently-strong password), I'll put the instructions right next to or under the input field, so that they focus on the instructions right when they need them.

Sometimes, though, there's too much to explain and still fit on the page without using up a lot of screen real-estate. In those cases, I'll present the explanation via a JavaScript pop-up window that comes up when the user clicks on a help symbol like a question mark icon.

I try not to use too many of the help icons on a single page, but it's a great way to present additional information to only those folks that need help, without getting in the way of experienced users.

Up until now, those techniques were sufficient to provide my clients with the guidance they needed to use their new application. But my latest project has taken help documentation one step further.

This project allows my clients to create news articles for the web using a JavaScript WYSIWYG editor, so in the prototype I added a few help icons to the editing page in order to explain how to use the editor, how to upload images files, etc. When I showed my clients the editing page and the help icons, I told them I would give them the ability to edit the help text that was displayed in the pop-up windows (so they could phrase the help in a way that made the most sense to them).

They liked that idea, but they had an even better one: they wanted to write their own in-application user manual, so that the primary users of the application could write procedural instructions (instructions not necessarily pertaining to the use of the application) that would guide other users in the office whenever they needed to fill in for the primary users.

So I built a tool to let them write chapters for their manual: they have a simple text field for entering a chapter title and a WYSIWYG editor box for entering the chapter content. They can also rearrange the order of the chapters on the master page using a variation of my jQuery-powered list rearrangement tool (see related entry). The header of the application hosts the "uber" help icon they click to bring up their manual in a large pop-up window, where the chapters are listed as hyperlinks that load the corresponding chapter content into the right-hand content area via an AJAX call.

Only time will tell if they actually write their own manual, but if they do, I may include a manual-writing tool in future applications. If your clients are willing to write some of the documentation for an application, it's a good way to get them further invested in the project, and it can end up saving you some work in the process.