Darryl Lyons’ Blog

AJAX, ColdFusion and Web technology…

Entries Comments



Category: JavaScript


Simile Timeline: DHTML Timelines

2 July, 2006 (11:50) | JavaScript | By: Darryl Lyons

Simile Timeline is a pretty cool project from the guys at MIT. They have developed a flexible timeline widget in DHTML that can be rendered horizontally or vertically. It uses XML as the datasource, and seems to cope with large datasets quite well. For instance, one of the examples plots 2000 years of Jewish history.

I think I will be playing with this at work, as we want to plot client activity within our CRM.

Thanks to the guys at Ajaxian for finding this.

AJAX (On-Demand JavaScript) with ToScript()

24 June, 2006 (22:54) | AJAX, ColdFusion, JavaScript | By: Darryl Lyons

I recently discovered the neat little method toScript() had been added to ColdFusion 7.0. I immediately thought that this would have to be quicker at serialising ColdFusion variables into their JavaScript equivilent than any existing JSON serialisers.

It also occurred to me that ToScript() could be used as an alternative data delivery mechanism to XML or JSON for "AJAX-enabled" web applications.

Using ToScript() for AJAX

The easiest way to use ToScript() in an "AJAX" sense is to use the On-Demand JavaScript pattern.

I've posted about the On-Demand JavaScript pattern before, so I thought I would re-use that same code, but improve it a little so that it is cross-browser (tested in Mozilla 1.5.x, IE6) compatible, and a little less verbose.

There are a number of parts to this example:

  1. index.html: Contains an empty table, ready to populate, and the trigger to call the JavaScript.
  2. getData.cfm: Serialises a query as a JavaScript array of objects (structs).
  3. getData.js: Creates a SCRIPT tag on the fly that points to the getData.cfm template as its SRC.

You can also download this example.

index.html

This code simply includes the getData.js JavaScript file, and defines an empty table, awaiting population. I've put a link above the table to trigger the population based upon data returned from ColdFusion.

HTML:
  1. <title>AJAX with ToScript()</title>
  2.  
  3. <script src="getData.js"></script>
  4. *
  5. {
  6.         font-family: sans-serif;
  7.         font-size: 10pt;
  8. }
  9.  
  10. caption
  11. {
  12.         background-color: #333333;
  13.         font-weight: bold;
  14.         text-align: left;
  15.         color: white;
  16.                
  17. }
  18.  
  19. thead tr
  20. {
  21.         background-color: #CCCCCC;
  22.         font-weight: bold;
  23.         text-align: left;
  24.                
  25. }
  26.  
  27. tr
  28. {
  29.         background-color: whitesmoke;
  30. }
  31.  
  32. td, caption
  33. {
  34.         padding: 4px;
  35. }
  36. </style>
  37. </head>
  38.  
  39.  
  40. <a href="javascript:getArtists()">Call getArtists() method</a>
  41.  
  42. <br/><br/>
  43. <table id="artistTable">
  44.         <caption>Artists</caption>
  45.         <thead>
  46.                 <tr>
  47.                         <td>ID</td>
  48.                         <td>Last Name</td>
  49.                         <td>First Name</td>
  50.                         <td>City</td>
  51.                 </tr>
  52.         </thead>
  53.         <tbody>
  54.         </tbody>
  55. </table>
  56.  
  57. </body>
  58.  
  59. </html>

getData.js

The getDataFromServer(id, url, callback) method dynamically creates a SCRIPT tag., where the source is set to a combination of the url and callback arguments. When the SCRIPT tag has loaded, whatever inside it is evaluated, including the specified callback method reference. The callback is placed there by getData.cfm.

The getArtists() method simply calls getDataFromServer with specified parameters. Notice that the callback is set to populateArtists.

The populateArtists(data) method is called when the SCRIPT tag has finished loading. getData.cfm contains the qArtists JavaScript variable, and a call to populateArtists, with qArtists being passed as a parameter. The table on the page is then populated.

JavaScript:
  1. function getDataFromServer(id, url, callback)
  2. {
  3.         var oScript = document.getElementById(id);
  4.         var head = document.getElementsByTagName("head").item(0);
  5.        
  6.         if (oScript)
  7.         {
  8.                 // Destory object
  9.                 head.removeChild(oScript);
  10.         }
  11.        
  12.         // Create object
  13.         oScript = document.createElement("script");
  14.        
  15.         var dtRf = new Date();
  16.  
  17.         oScript.setAttribute("src",url + "?callback=" + callback + "&rf=" +dtRf.getTime());
  18.         oScript.setAttribute("id",id);
  19.  
  20.         head.appendChild(oScript);
  21.  
  22. }
  23.  
  24. function getArtists()
  25. {
  26.         getDataFromServer("artistData","getData.cfm","populateArtists");
  27. }
  28.  
  29. function populateArtists(data)
  30. {
  31.         var oTBody = document.getElementById("artistTable").tBodies[0];
  32.  
  33.         // Loop over the data in the JS array, and add to table
  34.         for (var i=0; i <data.length; i++)
  35.         {
  36.                 // Create a new TR element
  37.                 var oTR = document.createElement("TR");
  38.                 oTBody.appendChild(oTR);
  39.  
  40.                 // Create a call for each element in struct
  41.                 var oTD = document.createElement("TD");
  42.                 oTD.innerHTML = data[i].artistid;
  43.                 oTR.appendChild(oTD);
  44.  
  45.                 var oTD = document.createElement("TD");
  46.                 oTD.innerHTML = data[i].lastname;
  47.                 oTR.appendChild(oTD);
  48.                                
  49.                 var oTD = document.createElement("TD");
  50.                 oTD.innerHTML = data[i].firstname;
  51.                 oTR.appendChild(oTD);
  52.                
  53.                 var oTD = document.createElement("TD");
  54.                 oTD.innerHTML = data[i].city;   
  55.                 oTR.appendChild(oTD);
  56.                
  57.         }
  58. }

getData.cfm

This ColdFusion code queries the art gallery example database to return all of the artists. It then uses the new ColdFusion built-in function ToScript() to serialise the query into a JavaScript array of objects (structs).

You will also notice that I am placing #url.callback(qArtists)# directly after ToScript(). When this JavaScript is loaded (when the SCRIPT tag is added to the DOM), the JavaScript method specified as url.callback will be called. The method will be passed the the parameter qArtists, which is the JavaScript variable just created by ToScript().

CFM:
  1. <cfsetting enablecfoutputonly="true">
  2.  
  3. <cfquery datasource="cfartgallery" name="qData">
  4. SELECT *
  5. FROM artists
  6. ORDER BY lastname, firstname
  7. </cfquery>
  8.  
  9. <cfoutput>var #toScript(qData, "qArtists", false, true)# #url.callback#(qArtists);</cfoutput>

ToScript() vs. CFJSON

I decided to run a few tests comparing ToScript() to CFJSON. Not surprisingly, ToScript() came out on top. But can the output be used in place of JSON? No, it cannot. The key difference is that JSON is represented as a single statement, whereas ToScript() generates multiple statements. Therefore, you cannot simply run eval() on the ToScript() generated string to create a JavaScript object.

I will be really happy when the boys at Adobe create a ToJSON() method native to ColdFusion...

Drag & Drop sortable lists

23 June, 2006 (23:02) | JavaScript | By: Darryl Lyons

Found this some time ago, and recently a colleague of mine also came across it. This script allows you to decorate normal LI tags so that they become draggable, and also sortable. There is even an example that someone else put together to drag and drop between two lists.

I am going to use this script to allow people to configure the visibility and order of columns on a datagrid. All I have to do is put a checkbox inside the LI for the visibility toggle. Nice.

Apache release Extensible AJAX Platform (XAP)

23 June, 2006 (21:39) | AJAX, Java, JavaScript | By: Darryl Lyons

Apache have released an AJAX framework caled Extensible AJAX Platform (or XAP for short).

XAP is an XML-based declarative framework for building, deploying and maintaining rich, interactive Ajax powered web applications. It aims to reduce the need for scripting and help solve the development and maintenance challenges associated with large scale JavaScript programming.

Not too much content on the site yet. There are a few demonstrations available, along with the source. Will be interesting to see where this heads, given that XML-driven frameworks like Laszlo already exist.

Simple JavaScript Database

17 June, 2006 (12:13) | AJAX, JavaScript | By: Darryl Lyons

Found this ages ago, but didn't blog about it. This is a JavaScript database, complete with SQL query syntax support.

This example illustrates one way of creating a completely JavaScript database with AMASS storage.This was thrown together and just more or less illustrates the possibility of using AMASS storage and TrimPath query javascript in conjunction for an offline in browser database.

The AMASS storage library, like Dojo, uses a flash movie to store the data on the local machine. This is one of the things that interest me at the moment, as I am looking for a quick solution for local storage - either using AMASS, Dojo or an ActiveX (IE only).

Native XMLHTTPRequest support in IE7

11 June, 2006 (20:32) | AJAX, Browsers, JavaScript | By: Darryl Lyons

I had almost forgotten about XMLHTTPRequest being native in Internet Explorer 7. Has anyone done any benchmarks between native support and the ActiveX? I'd be interested in seeing if their is any difference, because I imagine they would just be piggy-backing the same technology.

Essentially IE7 will now allow you to do this (which is consistent with Mozilla/Firefox and Safari):

JavaScript:
  1. var o = new XMLHttpRequest();
  2. o.open(method, url, async);
  3. o.onreadystatechange = function_pointer;
  4. o.send();

Instead of this:

JavaScript:
  1. var o = new ActiveXObject("Microsoft.XMLHTTP");
  2. o.open(method, url, async);
  3. o.onreadystatechange = function_pointer;
  4. o.send();

CFjsmin - JavaScript Compressor

8 June, 2006 (21:21) | ColdFusion, JavaScript | By: Darryl Lyons

CFjsmin (beta) is a ColdFusion component that compresses JavaScript files too a fraction of their original size (sometimes more than 50%). It achieves this by removing all non-essential whitespace and comments.

The component is also useful for packaging multiple JavaScript files into one compressed script file. This can lead to further improvements in speed. Internet Explorer only downloads two assets at a time when loading a page, so the less JavaScript files you have got, the quicker the site will load (we have over 200 individual files in our AJAX application at work, so it really helps us).

I am using a Java class called jsmin, by John Reilly, to actually do the grunt work. I modified the source a little so that it would accept file input/output streams, thus enabling the ability to merge multiple source files into the one destination file. Because CFFILE is not being used to achieve this, you will find it is pretty quick even when dealing with lots of files.

I am providing the component as a "beta" release, so if you find any issues or have suggestions for improvements, please let me know.

I hope this helps you!

Download

CFjsmin v1.0.0

Usage

CFM:
  1.  
  2. <cfscript>
  3.         // Usage 1: Simple usage
  4.         // NOTE: Destination file MUST be different! If it is the same as the source filename, then
  5.         // the source file will be overwritten.
  6.         oJSMin.compress("sourceFile.js", "compressedFile.js");
  7.  
  8.         // Usage 2: Explicitly specifying the destination file
  9.         oJSMin.setDestinationFile("compressedFile.js");
  10.         oJSMin.compress("sourceFile.js");
  11.         oJSMin.closeDestinationFile();
  12.        
  13.         // Usage 3: Creating a merged javascript file from multiple source files
  14.         oJSMin.setDestinationFile("compressedFile.js");
  15.  
  16.         oJSMin.compress("sourceFile.js");
  17.         oJSMin.compress("sourceFile2.js");
  18.         oJSMin.compress("sourceFile3.js");
  19.         oJSMin.compress("sourceFile4.js");
  20.        
  21.         oJSMin.closeDestinationFile();
  22. </cfscript>
  23.  

Example output

JavaScript:
  1.  
  2. // Before
  3. function foo()
  4. {
  5.  
  6.         // Some comments
  7.         var a = 2;
  8.        
  9.         // Some more comments
  10. }
  11.  
  12. // After
  13. function foo()
  14. {var a=2;}
  15.  

Dojo JavaScript Toolkit 0.3 released

4 June, 2006 (11:07) | AJAX, JavaScript | By: Darryl Lyons

Dojo Foundation have released 0.3 of their JavaScript toolkit. Some interesting features caught my attention, especially the local file storage class, that uses Flash's offline storage abilities. Some interesting experiments with data caching could be had here.

JSMin JavaScript compressor

4 June, 2006 (10:54) | JavaScript | By: Darryl Lyons

If you've ever wanted a simple JavaScript compressor, then I would recommend JSmin. It is a set of classes (Java, C, etc) that take an input file as a parameter, and then output compressed JavaScript code.

JSMin is a filter which removes comments and unnecessary whitespace from JavaScript files. It typically reduces filesize by half, resulting in faster downloads. It also encourages a more expressive programming style because it eliminates the download cost of clean, literate self-documentation.

There is a Java class available too. I've modified the Java class to output to a file location. Using this you can create one merged JavaScript file - quite useful if you have a lot of "class" files in your JavaScript project. I'll post the modified source soon for anyone that is interested. I've been using this code for quite a while with no problems, and can be called from directly within ColdFusion.

Dojo also has a compressor based on Rhino, but I not been able to get it working as successfully (the documentation is pretty limited on it).

JSEclipse - Javascript plugin for Eclipse

1 June, 2006 (06:28) | Eclipse, JavaScript | By: Darryl Lyons

I've been using the free NRG JavaScript plugin for Eclipse for a little while now, and I've recently discovered that a new version of the plugin is available. It is now a commercial plugin called JSEclipse, and has had a whole swag of new features added to it. Some include:

  • Contextual code completion (uses Rhino for better accuracy)
  • Content Outline
  • Support for major JavaScript libraries, like Dojo and Prototype
  • Code templates (these are cool)
  • JSDoc support
  • Syntax based code folding
  • Reference library