Widgets & Rich Internet Applications

Desktop widgets are lightweight client apps used with RIA to take optimum advantage of what the client and server have to offer.


August 02, 2007
URL:http://www.drdobbs.com/web-development/widgets-rich-internet-applications/201202699

Dana is a division scientist, one of BBN's principal contributors to the Ultra*Log project, and the primary architect of ACME (Agent-Automated Configuration Management Environment), a continuous integration, test, and assessment system.

Raymond is a software engineer with BBN Technologies and recently completed his first book, Professional Rich Internet Applications: AJAX and Beyond.


Rich Internet Applications (RIAs) increasingly developed as solutions to problems traditionally solved by applications executing on the client. Complex programs such as wordprocessors, spreadsheets, and e-mail clients are now maintained online, and executed entirely within the confines of web browsers. Consider the popularity of sites like Gmail, Google Maps, and Flickr.

Desktop widgets are lightweight client applications that can be used in conjunction with a RIA to incorporate the advantages of both the client and server. The advantage widgets offer for a RIA are the ability to interact with client systems, and to use resources available only on clients while avoiding the overhead required to develop a complete application from scratch. Examples of client interactions that are possible with widgets include:

The Desktop Widget Concept

So what exactly are desktop widgets? Well, they're small components executed within a larger engine application running on client platforms. Widgets typically provide simple, commonly used utility functions like calculators or battery-life meters. They are always resident when the engine is running; there's no need to launch them when the function is required.

Although there are different desktop widget engine implementations, they do have similarities. The engine provides a framework that reduces the code required for a widget. A widget specification is interpreted rather than compiled, and consists of a combination of a markup language (such as XML or HTML), a scripting language (such as JavaScript), and sometimes CSS.

The engine also handles aspects common to widgets simplifying the development of widgets. Widget developers are free to focus on defining the look-and-feel of widgets and implement functions that widgets are intended to perform, rather than focusing on the low-level details engineers typically address when developing applications.

Again, there are several implementations of desktop engines:

Yahoo! Widget Components

Depending on your environment, you must install a few components to develop and run Yahoo! Widgets. Regardless of environment, you need the Yahoo! Widget Engine (widgets.yahoo.com/download) to run widgets. If you want to develop widgets, you also need the Developer SDK if you're on Windows, or a widget converter application on a Mac. Both are available at the developer site (widgets.yahoo.com/workshop), which also contains a variety of other tools, templates, and tutorials for widget developers, regardless of platform. Of course, you also need a text editor, and you may want a graphics application such as Gimp or Photoshop because you typically need to create images for widgets.

After installing the engine and exploring available widgets, you see that widgets come packaged as .widget files. These are similar to archive files, and contain the files necessary to deploy and run widgets. They can be packed/unpacked using the widget converter, available as a widget or command-line version. When you unpack a widget, you see directory structure similar to this:


ClipNotes 
 - Contents
  - ClipNotes.kon
   - ClipNotes.js
    + Resources
     - background.png
      - upload-button.png
    ...


The top-level directory name corresponds to the name of the widget, and contains a single subdirectory, Contents. This typically contains two main elements—a Resources folder that contains images used by the widget, and a file with a ".kon" extension. This file looks like a normal XML file and contains the widget's specification. More complex widgets may also include JavaScript files for the code required by the widget. The motivation for this is akin to the motivation for separating the JavaScript from an HTML page. It separates the specification of the widget (or HTML page) from the processing logic.

Opening and examining widget specification files (.kon files) reveals aspects common to a widget specification. They are based on XML and start with the standard XML processing instruction followed by a widget element that contains one or more window elements. The window element generally contains a collection of elements that define the images, text fields, and text areas to include in the window. After the window specification, the widget's actions are defined. An action is a bit of JavaScript code that gets invoked when an associated triggering event occurs. Actions are typically followed by one or more preferences that let users tailor the widget, such as text font or color. Finally, an about-box element may contain child elements that define a window containing information about the widget and its developer. Listing One is the skeleton commonly seen in a widget specification file.

The Clip Notes Widget

Clip Notes is a widget that uploads notes to to web servers. Users can drag an image file, highlighted text, or URL into the widget (Figure 1), or type text into the widget. When users press the Upload button, the contents of the widget gets uploaded to a web server, which has a simple PHP application to save the uploaded note to a database. For viewing, there's another PHP script that reads the notes from the database, and displays them to users; see Figure 2.

[Click image to view at full size]

Figure 1: The Clip Notes widget with an image.

[Click image to view at full size]

Figure 2: The Clip Notes viewer.

Widgets typically use images as the basis for visual components, rather than programmatic approaches available in Java, Ruby, or Python. This example uses images for the widget background and Upload button.

The main specification for the Clip Notes widget is maintained in ClipNotes.kon (Listing Two). This is an XML file responsible for establishing the widget's look-and-feel. Line 1 contains a processing instruction that tells the XML processor it's dealing with an XML file. Line 2 is a processing instruction specifying that a strict interpretation of XML should be used when parsing widgets. Similar to HTML, the widget parser doesn't require a widget to conform to all aspects of the XML specification by default. For example, you can specify an attribute value that isn't surrounded by quotes. This can cause problems if the widget must be parsed as an XML file, so it's generally better to set this flag to True.

The widget element primarily consists of the window specification (lines 4-24), two actions, and some preference information. Looking into the window specification in line 4 shows the basic attributes of the widget's window (the height/width are defined), and a set of child elements that establish the content of the widget. A few basic elements create the look-and-feel of a window. Images, text fields, and text areas are the most common elements, and each specification is positioned in the container window using horizontal/vertical offset attributes.

Turning to the actions defined after the window, the trigger attribute of each action indicates when it is executed. With the action element defined in lines 25-31, you can see that it is similar to a standard JavaScript event handler. The onload trigger causes the action to be executed when the widget is loaded, and the content of the action element is embedded JavaScript code. It is important to note that the JavaScript is defined in a CDATA section with <![CDATA[ ... ]]>. This ensures that the Widget Engine doesn't misinterpret any special characters like greater than (>) or less than (<) symbols in the script when parsing the widget file. It should be used for all JavaScript embedded in the .kon file.

The CDATA section of the embedded JavaScript reveals two interesting aspects of a widget. First on line 27, the include statement loads an external JavaScript file. This lets you keep the JavaScript and the XML specification separate. In this case, we include a single file, ClipNotes.js, that contains all the JavaScript functions. The log function in line 28 is a JavaScript extension provided by the Widget Engine and aids with widget debugging. When the widget's debug attribute is set to True, a console that captures log messages is loaded with the widget.

The final step in the onload script (line 29) calls the updateFromPreferences function in the external JavaScript file to load saved user preferences. This function is also called by the action defined on lines 32-36 which is triggered by an onPreferencesChanged event that fires when users change a preference value.

It is also possible to associate JavaScript outside of action elements. Windows and other visual components can associate a script with an event like a key press or standard mouse events. You can define child elements of the component that describes the event to capture, and the function, or embedded JavaScript, to execute when the event fires. The Clip Notes widget associates external JavaScript functions with key presses, and drag-and-drop events in the dropBox text area on lines 12-13, and captures when users press and release the Upload button on lines 21-22.

The JavaScript Specification

The JavaScript specification file ClipNotes.js contains all the functions for handling events—functions to handle user preferences, enable file drag-and-drop, and upload the note or image to servers.

Capturing User Preferences

Widget engines save you from implementing capabilities (like user-preference management) commonly required for applications. The engine includes a framework that automatically manages the storage/retrieval of a user's preferences for all of the user's widgets, and provides a simple mechanism that lets widget developers customize the preferences available to their widgets, and define the effect of changing each preference. All customized and default preferences are accessible via the same preferences dialog of the widget displayed when you right-click the widget and select "Widget Preferences..."

The engine also provides each widget with a default set of preferences that affect the widget window's behavior. These preferences let you adjust the level of the window (always on top), opacity, and whether the window position is locked.

Customizing the preferences available for widgets requires two additions to the widget specification. You must define one or more preference elements as a child of the widget, then add JavaScript that applies its values to the widget. The specification of preference elements causes new fields to appear in the widget preference dialog. Each preference can be assigned a name, type, and default value among optional attributes. The following lets users modify the font size of the widget:


<preference name="fontSizePref"
   title="Size" type="slider" 
   defaultValue="18"  ticks="10" 
   minLength="5" maxLength="35" 
   description="Select the text 
   size"/>


A key attribute to the preference element is the type attribute, which establishes the type of preference being captured (color, font, or file). The widget preference dialog uses the specified type when deciding what type of control to use to capture the preference. For example, if the preference captured is a color, the preference widget brings up a color palette that users can choose from, rather than make users type in a six-digit hexadecimal number for the color.

As you start adding preferences to widgets, you may need to separate them into different panels on the preference dialog. You do this by adding a preferenceGroup element as a child of the widget, and including a reference to the preferenceGroup element in the preference element with the group attribute. Although useful, it's not always necessary to define a preference group for widget preferences. If you decide not to define your preferences within a specific group, they're automatically placed in a group named "General."

Returning to Listing Two, we've defined three preferences in a single group for the Clip Notes widget on lines 37-43. These let users modify the background color, and the font and color of the text as in Figure 3.

[Click image to view at full size]

Figure 3: The Clip Notes Preference dialog.

In Listing Two, the external function updateFromPreferences is called when the widget is loaded (line 29) and the preference is changed (line 34). This function is defined in ClipNotes.js (see Listing Three). The updateFromPreferences function updates the look of the widget based on values provided by users. If no value is provided, the default is automatically used. To do this, the function accesses a global preferences object available to the widget. The preferences object has a separate property for each preference object defined for the widget. Each preference object includes properties that describe the preference, such as the value and defaultValue, among others. The Widget Engine manages the preferences objects, so they always reflect the user's most recent selections, and are even automatically saved and reloaded when the machine is restarted or the widget is reloaded.

File Drag-and-Drop

Enabling widgets to handle file or text drag-and-drop only involves defining a new event handler that's triggered on a drag-and-drop event. In Listing Two, the event handler function handleDrop is executed when a file (or some text) is dragged and dropped in the text area. Although not required for basic drag-and-drop, the widget calls the related handleTypedNote function when users press a key in the dropBox text area. This is done by these elements from lines 12-13 of Listing Two:

 
<textarea name="dropBox" ...> 
  ...
  <onKeyPress function=
      "handleTypedNote"/>
  <onDragDrop function=
      "handleDrop"/>
  ...


The functions that handle the drag-and-drop and key press events are defined in the external JavaScript file ClipNotes.js and in Listing Four. The most interesting function is handleDrop in lines 3-15. It shows you the basics for capturing text or files dropped into an area. The system.event property is a global property that contains details about the most recent event, such as drag-and-drop or mouse-click events. In this case, the event is an onDragDrop event, and includes the array, system.event.data, with two pertinent properties. Index zero of the array contains the type of element that was dropped (a collection of files, or bit of text), and is used in line 10 to establish the type of upload to perform (either a file upload, or note upload). Index one of the array contains the details of the element dropped (the name and path of the dropped file, or text dropped), and on line 8 becomes the new text displayed in the text area.

The other two functions in Listing Four serve to support drag-and-drop handling. Since the Clip Note widget should only upload image files, it uses the validateFile function (line 23-25) to check the filename on line 10. If the file is not an image, it's treated as text.

The final function handleTypedNote in lines 17-21 is executed when users type into the text area, and simply changes the type of upload back to note. This is necessary when users drag images into the text area, then modify the text in the area.

Interacting with the RIA to Upload Files

Finally, we examine how to upload the note or text file to a server. Before looking at the JavaScript, recall the specification of the event handlers for the Upload button image in Listing Two:


<image name="uploadButtonImg" ...>
  <onMouseDown function=
    "handleUploadPress"/>
  <onMouseUp function=
    "handleUploadRelease"/>
</image>


The Upload button image has two associated event handlers. The handleUploadPress function, invoked when the mouse button is pressed, replaces the source of the upload image to give the visual effect of a button press. The handleUploadRelease function, invoked when users release the mouse button, sends the contents of the text area to a PHP script that stores the data in the database.

The primary responsibility of handleUploadRelease is to use a URL object to make the request to servers. The URL is created in line 9 and given the location of the PHP script on line 10. When uploading images, addPostFile sends the image file with the request (line 12). When uploading text or a URL, the data is associated with an argument (theNote) on line 15, and sent as normal post data. An asynchronous request to the server is finally made on line 18, and associated with a callback function uploadCallback. Just before sending the request, users are notified that a request is being made with an update to the status label (lines 13 and 16).

After the PHP script finishes updating the database and downloading the image, it generates a response that contains the string "success" or a failure message. This response causes the callback function to be executed, which updates the status label to indicate the server's response: server error (line 25), upload success (line 31), or upload failure (line 33).

Conclusion

The RIA model is a powerful model for developing applications. Integrating a RIA with small desktop applications can greatly enhance the overall user experience, but it is often impractical to develop a fully functional utility program from scratch. A desktop widget can alleviate these concerns by providing a low-cost approach to developing small effective desktop utilities that bridge the gap between the RIA and the desktop.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.