Over a million developers have joined DZone.

Quick and Easy AIR Apps with Dreamweaver CS3

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

The Adobe AIR extension for Dreamweaver CS3 makes it easy to build, package, and preview Adobe AIR applications with Adobe Dreamweaver CS3. You can use your existing web and Ajax development skills to build AIR applications that interact with the desktop in ways that web applications can not.

This tutorial demonstrates how to build a simple To Do List application with custom chrome. It also explain the functionality behind the application. The application is based on a single HTML page and JavaScript. Because it is also built on AIR, it can save and open to do lists using the local file system. It will use XML both internally to remember data and to be saved to the local file system as to do lists that can be shared.

Requirements

In order to make the most of this article, you need the following software and files:

Prerequisite knowledge

Basic knowledge of Dreamweaver, HTML, and Ajax development. If you haven't used the Adobe AIR extension for Dreamweaver CS3 yet, you may also want to refer to Scott Fegette's demo of how to set up and configure Adobe Dreamweaver CS3 to build, deploy, and preview Adobe AIR applications.

Starting off

Note: Be sure to download and install the Adobe AIR runtime and the Adobe AIR Extension for Dreamweaver CS3 before you start this project.

As is the case with most development environments, you begin by defining your project. In Dreamweaver, this means you create a new site for your AIR project.

Note: The samples ZIP file that accompanies this article includes the finished site files and assets for this project as well as the finished AIR application (todoit.air). You can import the finished site (to_do_list) files into Dreamweaver if you want to follow along with this tutorial without creating the files from scratch.

  1. Start Dreamweaver and select Site > Manage Sites to open the Manage Sites dialog box.
  2. Click the New button and select Site. The Site Definition dialog box appears.
  3. Specify a name for your site project (for example, to_do_list).
  4. Specify the Local root folder. Click the folder icon beside the input text box to browse your system for a folder.
  5. Click OK to close the dialog box. Click Done in the Manage Sites dialog box.

The next step is to create the user interface using a default HTML document. Later, you need to configure the AIR project, but I find it is quicker to create the default HTML document first.

To create a standard HTML document for the application's user interface, choose File > New > Basic Page > HTML, and then click Create to edit the document. Select File > Save and specify the file name for the document. This is the default interface that will be used when the application opens.

I named the default document ui.html, but you can name it anything you want. This document will be the first (and likely only) document that AIR loads for your application.

Here is the basic HTML structure for the project:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>To Do List</title>
<link type="text/css" href="todo.css" rel="stylesheet" />
<script type="text/javascript" src="assets/AIRAliases.js"></script>

<script type="text/javascript" src="assets/todo.js"></script>
</head>

<body>



</body>
</html>

Starting with the default HTML, you add the title (To Do List) and link in the resources needed by the application; for this application, you use the following three resources:

<link type="text/css" href="todo.css" rel="stylesheet" />
<script type="text/javascript" src="assets/AIRAliases.js"></script>
<script type="text/javascript" src="assets/todo.js"></script>

The todo.css style sheet controls the look and feel of the application as well as basic feedback such as changing colors when moving the mouse over a button. The todo.js file provides the interactive portion of your application, including responding to events, handling files, and working with data internally. The AIRAliases.js file is provided by Adobe to allow shortcuts to most of the AIR API. This will save you time in typing out long object names.

Note: You can find the todo.css and todo.js files in the assets folder of the to_do_list site sample files. The AIRAliases.js file is included with Adobe AIR Extension for Dreamweaver CS3—it will be automatically generated when you create an Adobe AIR project in Dreamweaver CS3.

Building and styling the user interface

The interface for the To Do List application is straightfoward. It has a text box for entering list items, two buttons on top and two buttons on the bottom. The buttons on top replace the interface widgets normally found in a desktop application, that is the minimize and close buttons. The buttons on the bottom are for adding new items to the list and to save the list to a file.

[img_assist|nid=2903|title=Figure 1. The To Do List user interface.|desc=|link=none|align=none|width=250|height=131]

In the default HTML document, define the text box, the buttons, and a document element for storing the items as follows:

<div id="nav">
<button id="btnmin"><img src="assets/min.jpg" /></button>
<button id="btnclose"><img src="assets/close.jpg" /></button>
</div>
<div id="dataentry">
<input id="itemtext" type="text" />
<input id="btnadd" type="submit" value="Add" />
<input id="btnsave" type="submit" value="Save" />
</div>
<div id="items"></div>

Because the To Do List application is based on an HTML document, you can use normal CSS to make it look and feel as you wish. Building the application on AIR provides even more flexibility. The Adobe AIR HTML rendering engine is powered by WebKit, which has a number of CSS extensions, including border radii and multiple backgrounds, that can make it easier to develop your user interface without complicated markup.

This application uses -webkit-border-radius to give the application a rounded feel without the use of graphics. It also uses a background graphic for a simple gradient on the entry and item elements. You can prevent the background from tiling by setting -webkit-background-size to 100%, which stretches the gradient to the size of the element.

#nav {
text-align:right;
padding-right:5px;
position:absolute;
right:0;
top:-4px;
}
#nav button {
color:#999;
background-color:#555;
-webkit-border-radius: 3px;
border:1px inset #777;
border-width:0 1px 1px;
padding:6px 6px 3px;
line-height:1;
cursor:pointer;
}

#dataentry {
background:url(bg.png) repeat-x 0 0;
padding:19px 5px 5px;
-webkit-background-size: 100%;
-webkit-border-radius: 5px;
text-align:center;
}

input[type=text] {
-webkit-border-radius: 5px;
font-size:14px;
width:95%;
padding:5px;
}

input[type=submit] {
color:#FFF;
background-color:#333;
border: 1px outset #999;
-webkit-border-radius: 9px;
width:50px;
border-color: #999 #000 #000 #999;
}

input[type=submit]:hover {
color:#FFF;
background-color:#912A2A;
}
.item {
margin:0 5px;
overflow:hidden;
padding:5px;
background:url(bg.png) repeat-x 0 0;
-webkit-background-size: 100%;
}

To give the buttons a "button" feel, the border-color along with the border-style rule creates the illusion of a bezel with light gray on the top and left edges and black on the right and bottom edges. You can also see the use of attribute selectors for your CSS rules. If you're not familiar with an attribute selector, it allows for elements to be styled based on the value of a particular attribute. For example, input[type=submit] will style any input where the type attribute is equal to submit, that is, <input type="submit" value="Save">.

Working within an isolated environment like AIR can be an extremely liberating experience since you can take advantage of these modern CSS features without having to worry about cross-browser support. You can also feel good knowing that your application should look the same on Windows, Mac OS X, and Linux. Just don't get frustrated when you go back into the browser world!

Adding interactivity

The To Do List application is relatively straightforward and the extended functionality provided by AIR and WebKit makes it easy to pull it together quickly and easily.

The application is structured with a single object named ToDo (defined in todo.js), which contains all the methods the application needs. Also, the following two helper functions have been added to simplify development:

var ToDo = { }

// Shortcut function to retrieve elements by ID
function $(id){
return document.getElementById(id);
}

// bind function for binding objects to function calls
Function.prototype.bind = function(o, args){
var fn = this;
return function(){
fn.apply(o, args || arguments);
}
}

The application has only a few interaction points: add, save, minimize application, close application, and remove item. When the application first opens, the init() function of the ToDo object adds event handlers for these events.

init:function(){
// perform any event bindings
$('btnadd').onclick = ToDo.addEvent.bind(ToDo);
$('btnsave').onclick = ToDo.save.bind(ToDo);
$('btnclose').onclick = ToDo.close.bind(ToDo);
$('btnmin').onclick = ToDo.minimize;

air.NativeApplication.nativeApplication.addEventListener(air.InvokeEvent.INVOKE,ToDo.open.bind(ToDo));
window.nativeWindow.addEventListener(air.Event.CLOSING,ToDo.close.bind(ToDo))

// initialize XML which auto-creates ITEMS root node
ToDo.items = document.implementation.createDocument("","items", null);

// add event handling to handle moving the application
document.body.onmousedown = function(e){
if(e.target.tagName != 'INPUT')
nativeWindow.startMove();
};
ToDo.fixAppSize();
}

Next, the init() function adds two important event handlers that handle the INVOKE and CLOSING events. The INVOKE event occurs any time a user clicks a .todo file to open it. The event is bound to the open() method of the ToDo object. The CLOSING event occurs any time a user tries to close the application using a keyboard shortcut or the taskbar. The application captures this event so that it can prompt the user to save any unsaved changes before the window is closed.

The init() function also creates an XML document to hold the list items. The createDocument method takes three parameters. The first is an XML namespace, which you won't need. The second is the name of the root node; in this case, it's items. The final parameter is for specifying a custom document type definition, which we also don't need.

An onmousedown event handler is added, which allows the user to drag the application around.

Finally, init() calls fixAppSize()to adjust the size of the native Window to match that of the HTML document. As items are added to or removed from the list, the HTML document will change size. The nativeWindow must change with it to keep the HTML document from getting clipped.

fixAppSize:function(){
// set the height to the length of the HTML
nativeWindow.height = document.body.offsetHeight;
}

Adding an item

Adding an item to the list invokes the add() event handler.

add:function(txt){
var id = 'a' + (new Date()).va lueOf();
if(txt == '') return false;

// create a new item shell
var item = document.createElement('div');
item.className = 'item';
item.id = id ;

var closeWidget = document.createElement('div');
closeWidget.className = 'close';
closeWidget.onclick = ToDo.remove.bind(ToDo);
item.appendChild(closeWidget);

var itemText = document.createElement('div');
itemText.className = 'text';
itemText.innerHTML = txt;
item.appendChild(itemText);

$('items').appendChild(item);

// create the XML node
var xmlItem = document.createElement('item');
xmlItem.setAttribute('id', id );
xmlItem.appendChild( document.createTextNode(txt) );
ToDo.items.getElementsByTagName('items')[0].appendChild( xmlItem );

// reset the text box
$('itemtext').value = '';
ToDo.hasChanged = true;
ToDo.fixAppSize();
}

The add() event handler does two things. First, it adds the new DOM elements to the HTML document and then it adds a new XML node to the items XML object. When a to do list is saved, this internal representation of the to do list is written to a file.

The event handler then clears the input text box, preparing it to accept the next list item. The handler sets the hasChanged property to true. When the application is closed, this property is used to determine if the user should be prompted to save changes.

Removing an item

Removing an item from the list is straightforward. The remove() event handler simply removes the element from the HTML DOM and from the XML DOM.

remove:function(evt){
// grab the event target and then go to its parent, the Item
var id = evt.target.parentNode.getAttribute('id');
evt.target.parentNode.parentNode.removeChild(evt.target.parentNode);
var xmlNode = ToDo.items.evaluate("//item[@id='"+ id +"']", ToDo.items).iterateNext()
xmlNode.parentNode.removeChild( xmlNode );

ToDo.hasChanged = true;
ToDo.fixAppSize();
}

Removing the node from the XML DOM is different than you might expect. You're using XPath to retrieve an item from the document where the id attribute matches. Then you remove that node using the removeChild method of the parentNode. In XML terms, the id attribute doesn't have any special meaning like it does in XHTML where it's used as a unique identifier. For that reason, getElementById won't work and you'll get a Node not found error. XPath lets you address parts of an XML document.

Opening a file

When a user double-clicks a .todo file, the To Do List application is launched if it is not already open, and the open() method is invoked.

open:function(evt){
if( evt.arguments.length == 1 )
{
if(evt.currentDirectory)
{
ToDo.currentDirectory = evt.currentDirectory;
}
ToDo.currentFile = evt.arguments[0];
var file = new air.File(ToDo.currentFile);
if(file.exists)
{
var fileStream = new air.FileStream();
var byteData = new air.ByteArray();
fileStream.open(file, air.FileMode.READ);
fileStream.readBytes(byteData, 0, file.size);
fileStream.close();

if(byteData.length > 0)
{
var s = byteData.readUTFBytes(byteData.length);
var parser=new DOMParser();
var doc=parser.parseFromString(s,"text/xml");
var items = doc.getElementsByTagName('item');
for(var i=0;i<items.length;i++)
{
ToDo.add(items[i].childNodes[0].data);
}
}
}
}
ToDo.hasChanged = false;

}

When the application is launched by double-clicking an existing .todo file the file object of the .todo file is passed as an argument to open(). If the file does indeed exist, open() uses the FileStream and ByteArray objects of the AIR API to read in the file. Once the document is loaded, the DOMParser class (from WebKit) is used to parse the string into an XML object. From there, the code loops through the items, adding them to the list.

Because the add() method sets the hasChanged property to true, open() must explicitly set it back to false after adding the items.

Saving a file

Saving a file is handled in two parts. The first displays a browse dialog box that allows the user to specify where to save the file. This is a standard OS dialog box that you do not have much control over.

save:function(){
var fileFilter = new air.FileFilter("To Do Lists", "*.todo");
ToDo.currentDirectory.addEventListener(air.Event.SELECT, ToDo.fileSaved.bind(ToDo) );
ToDo.currentDirectory.browseForSave("Save To-do List");
}

When the user specifies a file, the fileSaved event handler is invoked.

fileSaved:function(evt){
var newFile = evt.target;

var serializer = new XMLSerializer();
var packet = serializer.serializeToString(ToDo.items);

var fileStream = new air.FileStream();
var bytes = new air.ByteArray();
bytes.writeUTFBytes(packet);
fileStream.open(newFile, air.FileMode.WRITE);
fileStream.writeBytes(bytes, 0, bytes.length);
fileStream.close();
ToDo.hasChanged = false;
if(ToDo.closeAfterSave) ToDo.close();
}

The event handler uses the WebKit class XMLSerializer to convert the internal XML representation of the list into a string that can be written to a file. If the event handler was invoked because the user clicked the Close button, then the application will close.

Minimizing the application

Minimizing the application is straightforward. As mentioned above, you've attached an event handler to the minimize button to run a minimize function. The minimize function runs the minimize method on the nativeWindow object.

minimize:function(){
window.nativeWindow.minimize();
}

Closing the application

The last piece to this puzzle is handling the closing of the application.

close:function(evt){
if(ToDo.hasChanged)
{
var shouldSave = confirm("Do you want to save your changes?");
if(shouldSave)
{
ToDo.closeAfterSave = true;
evt.preventDefault();
ToDo.save.call(ToDo);
return;
}
}

air.NativeApplication.nativeApplication.exit();

}

When a user closes the application, close() checks to see if any changes have been made. If not, it just proceeds to close the application. If changes have been made, it prompts the user using a standard JavaScript confirm dialog box. If the user clicks OK, the application prevents the default action—stopping the application from closing right away—to allow the save process to complete. Once the save is complete, the close() function is called again by fileSaved(). This time, there are no changes and the application closes immediately.

Specifying the AIR application and installer settings

Now that the HTML document is built and ready to go, the next step is to configure the AIR application. Choose Site > AIR Application Settings to open the AIR Application and Installer Settings dialog box (see Figure 2).

[img_assist|nid=2904|title=|desc=Figure 2. The AIR Application and Settings dialog box.|link=none|align=none|width=536|height=666]

Although only the fields marked with an asterisk (*) are required, there are several others that you'll likely want to edit.


  • The ID text box can be in any format, but many developers use the domain name reversed with the application name added to the end. For example, the To Do List application would use "com.example.todoit" as the ID.
  • The Version detail, which also can be in any format, is an identifier that tells users what version of the application they are installing and using.
  • The Select icon images button enables you to include custom images for your application.
  • Any files that you add to your project must be added through the Included files section of this dialog box. You can specify a folder to include in your project by clicking the folder icon and selecting where your assets are stored. For this project, the following files will be placed in the assets folder:

    • AIRAliases.js: Provides shortcuts to the AIR API.
    • bg.jpg: This graphic will be used as a background for the entry interface and for each item on the list.
    • close.jpg and min.jpg: These are the graphics for the close and minimize buttons.
    • todo.css: The is the style sheet for the application. The look and feel of the application is defined via CSS.
    • todo.js: The is the JavaScript file that makes the application actually do what you want it to do.
  • Because the To Do List application uses custom chrome, select Custom Chrome (transparent) as the Window style. There are two style options available: opaque and transparent. Transparency is required for the custom shapes used in this application.

Most importantly, you need to specify a digital certificate for the application. Every application must be digitally signed to identify the person or company who built it. To specify a digital signature, click the Digital Signature: Set button in the AIR Application and Installer Settings dialog box. This opens the Digital Signature dialog box (see Figure 3).

Note: Signing your application is important to instill trust, much like an SSL certificate for a web server allows for secure web sites and instills trust in users providing private information like their credit card information. People will feel more comfortable installing an application if it comes from a source they trust. For more information on obtaining digital certificates, refer to Todd Prekaski's Digitally signing Adobe AIR applications.

[img_assist|nid=2905|title=|desc=Figure 3. The Digital Signature dialog box.|link=none|align=none|width=650|height=323]

If you don't have a certificate already, you can create a self-signed certificate, by clicking the Create button on the Digital Signature dialog box (see Figure 4).

[img_assist|nid=2906|title=|desc=Figure 4. The Self-Signed Digital Certificate dialog box.|link=none|align=none|width=581|height=405]

To sign a publicly released AIR application, you should use a certificate from an authority such as Verisign or Thawte, which confirms your identity to users of your application.

The To Do List application uses files for saving and opening to do lists. To set up a custom file type association for these files, click the Edit list button next to the Associated File Types option, then click the plus (+) button to add a file type. Enter the name for the file type and the extension (do not include the preceding dot), for example, todo (see Figure 5).

[img_assist|nid=2907|title=|desc=Figure 5. The Associated File Types dialog box.|link=none|align=none|width=409|height=247]

That's it. You've specified the key settings for your AIR application.

Debugging and packaging the application

As you develop your application, you'll need to test it to ensure that everything is working properly. This is typically done periodically during development. Rarely has there been a developer who could develop an application in its entirety and run it without an error to be found.

In Dreamweaver CS3 you can preview the application in two ways:

  1. Choose Site > AIR Application Settings, and then click Preview to test the application.

    You can use this option no matter which document is active, but no errors are shown in the Results pane.

  2. Choose File > Preview in Browser, and then select Preview in Adobe AIR.

    When using this option, JavaScript errors will appear in the Results pane. However, you have to make sure an HTML document from your project is the currently active document.

Another tool that can be helpful in debugging applications is the AIR HTML Introspector. Copy AIRIntrospector.js into your project and link to it from your ui.html document.

Note: The AIRIntrospector.js file is part of the Adobe AIR SDK. You can find a copy of the AIRIntrospector.js file in the assets folder of the sample files that accompany this article. The Adobe AIR SDK also includes everything you need to use the seamless badge install feature, explained in David Tucker's article, Deploying Adobe AIR applications seamlessly with badge install.

<script type="text/javascript" src="AIRIntrospector.js"></script>

The AIR Introspector can be accessed while the application is running using the F12 key. Any error messages thrown from within the application will appear in the Console tab of AIR Introspector. The AIR Introspector also provides functions for inspecting code during the execution process.

You can use the log() method to send objects to the console tab. For example:

var test = "Debug message";
air.Introspector.Console.log(test);

In addition to log(), there are warn(), info(), and error() methods that work like log() but also display a color-coded icon.

You should remove AIRIntrospector.js before distributing a packaged AIR application.

Packaging the application for distribution

The last critical step to the process is packaging the application for distribution.

Here again, the Adobe AIR extension for Dreamweaver CS3 simplifies the process. Choose Site > AIR Application Settings, and then click Create AIR File. You can also choose Site > Create AIR File.

The application is compiled and packaged into a redistributable AIR file (with the .air extension) using the application and installer settings and the certificate you specified.

Note: For more information on deploying your application to the web, including using the badge install feature, see Deploying Adobe AIR applications seamlessly with badge install.

Where to go from here

You've gone through the steps of creating a To Do list application using Dreamweaver CS3 along with the Adobe AIR extension for Dreamweaver CS3. You've seen how to apply custom chrome, work with opening and saving files to the local file system, and learned how to package your file to share with others.

Don't stop there, though. There's plenty more that you can add to this application. You could add a date field to remind yourself when items are due and add alerts to let you know when you're getting behind. Or take the interface to the next level by adding animation to the add and remove process. You can use the jQuery, Mootools, YUI, and ExtJS libraries to add new functionality quickly and easily. Also be sure to check out Christian Cantrell's inspirational experiments with Adobe AIR.

About the author

Jonathan Snook is a freelance developer from Ottawa, Canada. With over a decade of experience on the web, Jonathan continues to design and build web and desktop applications for clients around the world. He's also author of Accelerated DOM Scripting with Ajax, APIs, and Libraries and co-author of The Art & Science of CSS. Jonathan contributes to magazines online and off such as UK's .net magazine and Digital Web Magazine. He also contributes regularly to his own blog at Snook.ca.

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:

Published at DZone with permission of Jonathan Snook. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}