Login Register

SitePen

Syndicate content
SitePen Services and notes about Dojo, DWR, Cometd, JavaScript, and the Web
Updated: 1 day 26 min ago

Client/Server Model on the Web

Fri, 07/18/2008 - 14:48

Prior to the popularity of the web, client/server applications often involved the creation of native applications which were deployed to clients. In this model, developers had a great deal of freedom in determining which parts of the entire client/server application would be in the client and which in the server. Consequently, very mature models for client/server development emerged, and often well designed optimal distribution of processing and logic could be achieved. When the web took off, the client was no longer a viable application platform, it was really more of a document viewer. Consequently the user interface logic existed almost entirely on the server. However, the web has matured substantially and has proven itself to be a reasonable application platform. We can once again start utilizing more efficient and well-structured client/server model design. There are certainly still technical issues, but we are in a position to better to build true client/server applications now.

The client/server model can be categorized into three parts:

  • User Interface
  • Business or Application Logic
  • Data Management

Traditional web application development has distributed the implementation of the user interface across the network, with much of the user interface logic and code executed on the server (thin client, fat server). This has several key problems:clientserver.png

  • Poor distribution of processing - With a large number of clients, doing all the processing on the server is inefficient.
  • High user response latency - Traditional web applications are not responsive enough. High quality user interaction is very sensitive to latency, and very fast response is essential.
  • Difficult programming model - Programming a user interface across client/server is simply difficult. When every interaction with a user must involves a request/response, user interface design with this model is complicated and error prone. The vast number of web frameworks for simplifying web development testifies to this inherent difficulty. Some have mitigated this difficulty to some degree.
  • Increased vector of attack - Unorganized mingling of user interface code with business code can increase security risks. If access rules are distributed across user interface code, as user interface code grows and evolves, new vectors of attack emerge. With mixed code, new user interface features can easily create new security holes.
  • Heavy state management on the servers - When client user interface state information is maintained by the server, this requires a significant increase in resource utilization as server side sessions must be maintained with potentially large object structures within them. Usually these resources can’t be released until a session times out, which is often 30 minutes after a user actually leaves the web site. This can reduce performance and scalability.
  • Offline Difficulties - Adding offline capabilities to a web application can be a tremendous project when user interface code is predominantly on the server. The user interface code must be ported to run on the client in offline situations.
  • Reduced opportunity for interoperability - When client/server communication is composed of transferring internal parts of the user interface to the browser, it can be very difficult to understand this communication and utilize it for other applications.

With the massive move of development to the web, developers have frequently complained of the idiosyncrasies of different browsers and demanded more standards compliance. However, the new major shift in development is towards interconnectivity of different services and mashups. We will once again feel the pain of programming against differing APIs. However, we won’t have browser vendors to point our fingers at. This will be the fault of web developers for creating web applications with proprietary communication techniques.

Much of the Ajax movement has been related to the move of user interface code to the client. The maturing of the browser platform and the availability of HTTP client capabilities in the XMLHttpRequest object, have allowed much more comprehensive client side user interface implementations. However, with these new found capabilities, it is important to understand how to build client/server applications.

So how do you decide what code should run on the client and what should the run on the server? I have mentioned the problems with user interface code running on the server. Conversely, running business logic and/or data management on the client is simply not acceptable for security reasons. Therefore, quite simply, user interface code is best run on the browser, and application/business logic and data management is best run on the server side. We can take a valuable lesson from object oriented programming to guide this model. Good OO design involves creating objects that encapsulate most of their behavior and have a minimal surface area. It should be intuitive and easy to interact with a well designed object interface. Likewise, client and server interaction should be built on a well-designed interface. Designing for a modular reusable remote interface is often called service oriented architecture (SOA); data is communicated with a defined API, rather than incoherent chunks of user interface. A high quality client/server implementation should have a simple interface between the client and server. The client side user interface should encapsulate as much of the presentation and user interaction code as possible, and the server side code should encapsulate the security, behavior rules, and data interaction. Web applications should be a cleanly divided into two basic elements, the user interface and the web service, with a strong emphasis on minimal surface area between them.clientserver2.png

An excellent litmus test for a good client/server model is how easy is it to create a new user interface for the same application. A well designed client/server model should have clearly defined web services such that a new user interface could easily be designed without having to modify server side application logic. A new client could easily connect to the web services and utilize them. Communication should be primarily composed of data, not portions of user interface. The advantages of a clean client/server model where user interface logic and code is delegated to the browser:

  • Scalability - It is quite easy to observe the significant scalability advantage of client side processing. The more clients that use an application, the more client machines that are available, whereas the server processing capabilities remain constant (until you buy more servers).
  • Immediate user response - Client side code can immediately react to user input, rather than waiting for network transfers.
  • Organized programming model - The user interface is properly segmented from application business logic. Such a model provides a cleaner approach to security. When all requests go through user interface code, data can flow through various interfaces before security checks take place. This can make security analysis more complicated, with complex flows to analyze. On the other hand, with a clean web service interface, there is well-defined gateway for security to work on and security analysis is more straightforward, holes can be quickly found and corrected.
  • Client side state management - Maintaining transient session state information on the client reduces the memory load on the server. This also allows clients to leverage more RESTful interaction which can further improve scalability and caching opportunities.
  • Offline applications - If much of the code for an application is already built to run on the client, creating an offline version of the application will almost certainly be easier.
  • Interoperability - By using structured data with minimal APIs for interaction, it is much easier to connect additional consumers and producers to interact with existing systems.
Difficulties with the Client Server Model on the Web

There are certainly difficulties with applying the client/server model to the web. Accessibility and search engine optimization can certainly be particular challenges with the web services approach. Handling these issues may suggest a hybrid approach to web applications, some user interface generation may be done on the server to create search engine accessible pages. However, having a central architectural approach based around a client/server model, with extensions for handling search engines may be a more solid and future oriented technique for many complex web applications.

Our Efforts to Facilitate the Client Server Model

SitePen is certainly not alone in working to facilitate client/server architecture. However, since I am familiar with the projects we help create, I did want to mention our approaches to the client/server model:

DWR - From inception, DWR has provided an excellent framework for building client side user interfaces that can easily connect with server side business logic. DWR was years ahead of its time in establishing a framework that encouraged good client/server modeling. DWR has a solid structure for interacting with Java business logic objects. DWR has continued to progress, providing means for bi-directional Comet based communication (Reverse Ajax), and is adding more interoperability capabilities as well.

Dojo Toolkit - It should be obvious that building a good client-side user interface can benefit from a good toolkit, and Dojo has long provided just that. However, Dojo is more than just a library and set of widgets. Dojo provides real tools for building client/server applications. Dojo RPC can provides tools for connecting to web services, and can even auto-generate services based on SMD definitions. Dojo Data provides a powerful API for interacting with a data model. Dojo has lead the way with Comet technology, creating standards around browser based two-way communication. Recently we have built the JsonRestStore which allows one to connect to a REST web service and interact with it using the Dojo Data read and write API. This greatly simplifies the construction of user interfaces by simplifying the user interface-business logic interaction, and encouraging standards-based communication that can easily be used by others. Furthermore, Dojo provides comprehensive tools for robust data-driven applications; even templating can be done on the client instead of the server with Dojo’s DTL support.

The benefits of using standards-based client/server communication has facilitated integration with server frameworks like Zend, jabsorb, Persevere, and interoperability with other frameworks will be coming soon.

Cometd - Cometd provides real-time duplex communication between clients and servers. However, the distinguishing characteristic of the Cometd project is the focus on not only achieving Comet-style duplex communication, but doing so with an interoperable standard protocol, Bayeux. Comet uses a quintessential client/server approach. Any Cometd (Bayeux implementing) server can interact with any Cometd/Bayeux client. One can easily connect various different client implementations to a single server, by using the Bayeux standard.

Persevere - Persevere is a recently launched project, built with this service oriented client/server approach. Persevere is a web object database and application server with RESTful HTTP/JSON interfaces, allowing applications to quickly be built with a database backend that can be directly and securely accessed through Ajax. Persevere is focused on provided a comprehensive set of web services interaction capabilities through standard interoperable communication. Data can be accessed and modified with basic RESTful JSON interaction, clients can invoke methods on the server with simple JSON-RPC, and data can be queried with JSONQuery/JSONPath. With Dojo’s new REST data store, and SMD driven RPC services, Dojo clients can seamlessly build applications and interact with Persevere services using the Dojo APIs. Complex application logic can be added to the persisted objects in Persevere to facilitate building service oriented applications with a straightforward interface to the user interface code on the browser. Persevere is integrated with Rhino, so model and application logic can be written in JavaScript, providing a consistent language and environment for distributing client and server roles.

For more information about any of these open source projects, visit the SitePen Labs

Summary

As the web platform matures, as applications evolve to use more interactive and rich interfaces, and as web services increasingly interact, architecting web applications with an intelligent client/server model will become increasingly important. A properly designed client/server model will provide a foundation for modular, adaptable, and interoperable applications equipped for future growth.

JSONQuery: Data Querying Beyond JSONPath

Wed, 07/16/2008 - 07:04

A new data querying tool for has been added to Dojo 1.2. JSONQuery is a new module intended to succeed and improve upon the JSONPath module introduced in Dojo 1.1. JSONQuery provides a comprehensive set of data querying tools including filtering, recursive search, sorting, mapping, range selection, and flexible expressions with wildcard string comparisons and various operators.

JSONQuery provides safe evaluation with language agnostic expressions that prevents arbitrary code execution. It also uses intuitive result-based evaluation that allows successive query operations. Furthermore, the new JSONQuery module provides significant performance improvements, with 20-100x faster execution with the common filter operation on large arrays than the JSONPath module. JSONQuery generally supersets the functionality of JSONPath and provides syntax that matches and behaves like JavaScript where the syntax intersects for maximum ease of use.

Usage API

A JSONQuery can be executed with the following call:

results = dojox.json.query(query,object);

Where query is the JSONPath query to execute and object is the root object or array to query. You can also create a “compiled” evaluation function that can be reused for multiple evaluations by only passing a query string:

evaluator = dojox.json.query(query);

The evaluator function can be then be performed on a query on data by calling it with the data as a parameter:

results = evaluator(object);

In situations where a single query may be executed multiple times, doing a single parse/compilation with dojox.json.query(query) and reusing the returned evaluation function will provide better performance. It is worth noting that dojox.json.query(query,object) is functionally equivalent to dojox.json.query(query)(object).

Query Syntax

JSONQuery evaluations begin with the provided object, which can referenced within queries with $. From the starting object, various operators can be successively applied, each operating on the result of the last operation. You may explicitly begin your query with $, but this is implicitly auto-inserted, so it is not necessary. This allows you to start queries with operators. JSONQuery uses syntax that is similar to JavaScript (with a number of extra operators), so a simple query could be performed like:

data = {foo:"bar"};
results = dojox.json.query("$.foo",data);
results -> "bar"
Query Capabilities

JSONQuery provides all the functionality of JSONPath, and additional query capabilities. By analogy, JSONQuery is to JSONPath, as XQuery is to XPath. In particular, JSONQuery provides the expressive equivalence of XQuery FLOWR expressions for mapping, sorting, and filtering object data. Several of the fundamental operators of JSONQuery follow the same syntax as JavaScript, as well behaving exactly as with JavaScript evaluation:

  • .property - This will return the provided property of the object
  • [expression] - This returns the property name/index defined by the evaluation of the provided expression

For example, the following JSONQuery will find the foo property of the 2nd item in the provided array (the $ is omitted):

[1].foo

The following operators are new in JSONQuery:

  • [?expression] - This will perform a filter operation on an array, returning all the items in an array that match the provided expression. This operator does not need to be in brackets, you can simply use ?expression, but since it does not have any containment, no operators can be used afterward when used without brackets. The following JSONQuery will find all the array items that have a price less than 15:

    [?price < 15]

    And to add a condition for the rating property to be greater than 3 (and omit the brackets):

    ?price < 15 & rating > 3
  • [/expression], [\expression], [/expression, /expression] - This performs a sort operation on an array, with sort based on the provide expression. Multiple comma delimited sort expressions can be provided for multiple sort orders (first being highest priority). / indicates ascending order and \ indicates descending order. For example to sort an array by lastName first and then firstName as the second priority:
    [/lastName,/firstName]
  • [=expression] - This performs a map operation on an array, creating a new array with each item being the evaluation of the expression for each item in the source array. For example, to create a list of the price value from an array of objects, we could use the query:
    [=price]

    You can also use object literals and and create a new array of objects that with a name and price properties generated from the source array:

    [={price:price,name:firstName + " " + lastName}]
  • expr = expr - Performs a comparison (like JavaScript’s ==). When comparing to a string, the comparison string may contain wildcards * (matches any number of characters) and ? (matches any single character). For example to find all objects in an array where the name starts with “Mr”, one could use the query:
    [?name='Mr*']
  • expr ~ expr - Performs a string comparison with case insensitivity. For example to find all objects in an array with the word “the” in the description regardless of case:
    [?description~'*the*']
  • ..[?expression] - This will perform a deep search filter operation on all the objects and subobjects of the current data. Rather than only searching an array, this will search property values, arrays, and their children.
  • $1, $2, $3... - This can be used to reference additional parameters passed to the query call. For example:
    results = dojox.json.query("[?firstName=$1&amp;lastName=$2]",
    					myData,"John","Doe");

    or it can be applied to the evaluator function:

    evaluator = dojox.json.query("[?firstName=$1&amp;lastName=$2]");
    results = evaluator(myData,"John","Doe");

The following operators from JSONPath are also supported:

  • [start:end:step] - This performs an array slice/range operation, returning the elements from the optional start index to the optional end index, stepping by the optional step parameters. For example to get the first ten items in an array:
    [0:10]
  • [expr,expr] - The union operator returns an array of all the property/index values from the evaluation of the comma delimited expressions.
  • .* or [*] - Returns the values of all the properties of the current object.
  • $ - This is the root object.
  • @ - This is the current object in filter, sort, and map expressions. Note that names are auto-converted to property references of the current object in expressions, but @ can be used for index access on the current object. The following queries are identical:
    [?name='Fred']
    [?@.name='Fred']
    [?@['name']='Fred']
  • ..property - Performs a recursive search for the given property name, returning an array of all values with such a property name in the current object and any subobjects.
  • +, -, /, *, &, |, %, (, ), <, >, <=, >=, != - These operators behave just as they do in JavaScript.

Multiple operators can be used successively to create complex queries. For example, to find all the objects from the array in the products property that have a price under 15 and then sort them by descending order of rating and show the first twenty items from the resultant list, we could query:

$.products[?price < 15][\rating][0:20]

Queries can use the regular operators to form general expressions based on more complex query operations. For example, to find the difference between the lowest priced item and the highest priced item in an array:

$.store.book[\price][0].price - $.store.book[/price][0].price
Summary

The new Dojo JSONQuery module provides a powerful tool for general purpose data querying, and can be used in variety of situations. The JSONQuery module is already used by Persevere to parse and execute queries in it’s server side JavaScript object storage environment. JSONQuery is a flexible and complete query format for handling large JSON/object data structures with an intuitive JavaScript-like syntax.

Dojo 1.2 Grid

Mon, 07/14/2008 - 07:34

With the release of Dojo 1.2 right around the corner, there’s an updated grid widget available. It offers new features and performance improvements over the existing grid including better Dojo data integration, simplified layout structures, and the ability to enable editing much more easily.

In order to make these improvements, we were forced to break backwards compatibility between the new grid and the old grid. This shouldn’t be a surprise since the grid is part of DojoX. We realized that enough people use, rely on, and extend the grid that we didn’t want to break applications based on Dojo 1.0 and 1.1, so both grids are available to you. The old grid will be available until Dojo 2.0, but it will not be improved in future versions of Dojo 1.x.

This article focuses on the use of the new grid widget. All of the examples presented in this article may be downloaded in a tarball so you can modify and follow along.

Logical File Layout

The new grid API has been organized according to the Dojo conventions. For instance, the old dojox.VirtualGrid is now dojox.grid._Grid, dojox.Grid is now dojox.grid.DataGrid, and dojox.grid.selection is now dojox.grid.Selection. The namespace that objects are in now also reflect where you can find them in the file system.

Dojo Data Integration

I mentioned that dojox.Grid is now dojox.grid.DataGrid, but why is it called DataGrid? The reason is that DataGrid natively supports dojo.data stores. In order to use dojo.data stores with the grid in previous releases, you needed the dojox.grid.data.DojoData model which would bridge the gap between the grid and the store. DataGrid has been engineered to remove that bridge. Instead of using stand-alone models to store data for the grid, any dojo.data store that implements the Dojo Data read API can be used. Additionally, DataGrid can use the write and notification API’s if they are available. Let’s look at an example (using the data from my previous grid tutorials modified to work with ItemFileReadStore):

var jsonStore = new dojo.data.ItemFileReadStore({ url: "json/gaskets.json" });
 
var grid = new dojox.grid.DataGrid({
	id: 'grid',
	query: { part_num: '*' },
	store: jsonStore,
	structure: layout
}, 'gridNode');

[Live Example]

This will load our JSON file from a URL and give us access to the data through the Dojo Data API. We then pass the store to the DataGrid constructor along with the query we want the grid to run against the store. We’ll get to defining a layout in a bit, but for now let’s look at some more things we can do with this new grid.

I mentioned notification API support. This means if the store changes, the grid will update. Let’s set up an example:

var jsonStore = new dojo.data.ItemFileWriteStore({ url: "json/gaskets.json" });
 
var grid = new dojox.grid.DataGrid({
	id: 'grid',
	query: { part_num: '*' },
	store: jsonStore,
	structure: layout
}, 'gridNode');
 
var updateGasketTypes = function(){
	jsonStore.fetch({
		query: { part_num: '??1?' },
		onComplete: function(items, result){
			dojo.forEach(items, function(item){
				jsonStore.setValue(item, "type", 2);
			});
		}
	});
}
<button onclick="updateGasketTypes();">Change gasket types</button>

[Live Example]

When the button is clicked, any item that has a ‘1′ in the third number of its part number will have its type changed to 2 and the grid will update its information.

Layout Structure Simplified

In previous versions of the grid, setting up how you wanted the grid to look was sometimes confusing. With this latest version we have tried to make setting up the look of the grid simpler while still allowing flexibility for those that need it. There are now two ways to lay out your grid: markup and programatically.

Layouts with markup

Previously the only way to set up your grid’s layout for use in markup was with a structure defined in a script block. Those days are long gone! Setting up a grid’s layout is now as simple as this:

<table id="gridNode" jsId="grid" dojoType="dojox.grid.DataGrid"
	   query="{ part_num: '*' }" store="jsonStore">
	<thead>
		<tr>
			<th field="part_num">Part Number</th>
			<th field="min_temp" width="100px">Minimum Temperature</th>
			<th field="max_temp" width="100px">Maximum Temperature</th>
			<th field="type" width="100px">Type</th>
			<th field="thick" width="5em">Thickness</th>
		</tr>
	</thead>
</table>

[Live Example]

One of the cool features of the grid is that you can group certain columns and lock them from scrolling horizontally. You can set that up with markup as well:

<table id="gridNode" jsId="grid" dojoType="dojox.grid.DataGrid"
	   query="{ part_num: '*' }" store="jsonStore">
	<colgroup span="1" noscroll="true"></colgroup>
	<colgroup span="4"></colgroup>
	<thead>
		<tr>
			<th field="part_num" width="300px">Part Number</th>
			<th field="min_temp" width="100px">Minimum Temperature</th>
			<th field="max_temp" width="100px">Maximum Temperature</th>
			<th field="type" width="100px">Type</th>
			<th field="thick" width="5em">Thickness</th>
		</tr>
	</thead>
</table>

[Live Example]

With colgroup we are able to lock the first column and allow the last four columns to be horizontally scrolled. You can even set up multiple rows within each row while spanning cells between rows and columns:

<table id="gridNode" jsId="grid" dojoType="dojox.grid.DataGrid"
	   query="{ part_num: '*' }" store="jsonStore">
	<thead>
		<tr>
			<th field="part_num" rowspan="2">Part Number</th>
			<th field="min_temp" width="100px">Minimum Temperature</th>
			<th field="max_temp" width="100px">Maximum Temperature</th>
			<th field="type" width="100px">Type</th>
		</tr>
		<tr>
			<th field="thick" colspan="3" width="5em">Thickness</th>
		</tr>
	</thead>
</table>

[Live Example]

You can even define formatters and getters for columns:

function formatDegrees(value){
	return value + '°';
}
 
function getODtoID(rowIndex, item){
	if(!item){
		return this.defaultValue;
	}
	var grid = dijit.byId('gridNode');
	var od = grid.model.getValue(item, "outer");
	var id = grid.model.getValue(item, "inner");
 
	return od - id;
}
<table id="gridNode" jsId="grid" dojoType="dojox.grid.DataGrid"
	   query="{ part_num: '*' }" store="jsonStore" rowSelector="20px">
	<thead>
		<tr>
			<th field="part_num">Part Number</th>
			<th field="min_temp" formatter="formatDegrees" width="100px">
				Minimum Temperature
			</th>
			<th field="max_temp" formatter="formatDegrees" width="100px">
				Maximum Temperature
			</th>
			<th field="type" width="50px">Type</th>
			<th field="thick" width="5em">Thickness</th>
			<th width="5em" get="getODtoID">OD to ID</th>
		</tr>
	</thead>
</table>

[Live Example]

Another popular Dojo grid feature is dojox.GridRowView. It provides a view at the left side of the grid that allows you to select rows easily. For Dojo 1.2, that has been renamed to dojox.grid._RowSelector and can be enabled by passing an option to the grid:

<table id="gridNode" jsId="grid" dojoType="dojox.grid.DataGrid"
	   query="{ part_num: '*' }" store="jsonStore" rowSelector="20px">
	<thead>
		<tr>
			<th field="part_num">Part Number</th>
			<th field="min_temp" width="100px">Minimum Temperature</th>
			<th field="max_temp" width="100px">Maximum Temperature</th>
			<th field="type" width="100px">Type</th>
			<th field="thick" width="5em">Thickness</th>
		</tr>
	</thead>
</table>

[Live Example]

By passing “20px” to the grid in the rowSelector attribute, we are telling the grid we want the row selector to be 20 pixels wide. You can also pass a boolean value (if it’s true, you get the default size) or any other valid css size.

Putting this all together, we can port our previous application to the new API. Just look at the source of here.

Programmatic Layouts

If markup isn’t your thing or you’re creating your grid on the fly you’ll be glad to know that we’ve simplified the structure you pass in to the grid to define the layout. Previously you were required to pass in a structure like this to get something similar to our first markup example:

var layout = [
	// view 0
	{
		cells: [[
			{ field: "part_num", name: "Part Number", width: 'auto' },
			{ field: "min_temp", name: "Minimum Temperature", 
				width: "100px" },
			{ field: "max_temp", name: "Maximum Temperature", 
				width: "100px" },
			{ field: "type", name: "Type", width: "100px" },
			{ field: "thick", name: "Thickness", width: "5em" }
		]]
	}
];
 
var grid = new dojox.grid.Grid({
	structure: layout,
	model: model
}, 'gridNode');

Now, you can trim it down to something like this:

var layout = [
	{ field: "part_num", name: "Part Number", width: 'auto' },
	{ field: "min_temp", name: "Minimum Temperature", width: "100px" },
	{ field: "max_temp", name: "Maximum Temperature", width: "100px" },
	{ field: "type", name: "Type", width: "100px" },
	{ field: "thick", name: "Thickness", width: "5em" }
];
 
var grid = new dojox.grid.DataGrid({
	query: { part_num: '*' },
	store: jsonStore,
	structure: layout
}, 'gridNode');

[Live Example]

Multiple rows of cells is also easier. Before we had to do this:

var layout = [
	// view 0
	{
		cells: [[
			{ field: "part_num", name: "Part Number", width: 'auto', 
				rowSpan: 2 },
			{ field: "min_temp", name: "Minimum Temperature", 
				width: "100px" },
			{ field: "max_temp", name: "Maximum Temperature", 
				width: "100px" },
			{ field: "type", name: "Type", width: "100px" }
		],[
			{ field: "thick", name: "Thickness", width: "5em", 
				colSpan: 3 }
		]]
	}
];
 
var grid = new dojox.grid.Grid({
	structure: layout,
	model: model
}, 'gridNode');

And now:

var layout = [[
	{ field: "part_num", name: "Part Number", width: 'auto', rowSpan: 2 },
	{ field: "min_temp", name: "Minimum Temperature", width: "100px" },
	{ field: "max_temp", name: "Maximum Temperature", width: "100px" },
	{ field: "type", name: "Type", width: "100px" }
],[
	{ field: "thick", name: "Thickness", width: "5em", 
		colSpan: 3 }
]];
 
var grid = new dojox.grid.DataGrid({
	query: { part_num: '*' },
	structure: layout,
	store: jsonStore
}, 'gridNode');

[Live Example]

If you want to add the row selector, just change the constructor call to this:

var grid = new dojox.grid.DataGrid({
	query: { part_num: '*' },
	structure: layout,
	store: jsonStore,
	rowSelector: '20px'
}, 'gridNode');

[Live Example]

Now you can see the application from my previous post ported to the new programmatic API.

Editing redefined

In order to edit a value in the old grid, you would have to pass an editor class to your cell definition. In the new grid, each cell has a default editor defined; all you have to do is add editable: true to your cell definition and use a store that implements the Dojo Data write API:

var jsonStore = new dojo.data.ItemFileWriteStore({ url: "json/gaskets.json" });
 
var layout= [
	{ field: "part_num", width: "auto", name: "Part Number" },
	{ field: "min_temp", width: "100px", name: "Minimum Temperature" },
	{ field: "max_temp", width: "100px", name: "Maximum Temperature" },
	{ field: "type", width: "100px", name: "Type" },
	{ field: "thick", width: "5em", name: "Thickness", editable: true }
];
 
var grid = new dojox.grid.DataGrid({
	query: { part_num: '*' },
	store: jsonStore,
	structure: layout,
	rowsPerPage: 20
}, 'gridNode');

[Live Example]

You can now edit the thickness property of each row of data. What if you don’t want to edit the data with a text box? Let’s say we want to set up a select to edit the type of gasket (cellType for the markup attribute name):

var layout= [
	{ field: "part_num", width: "auto", name: "Part Number" },
	{ field: "min_temp", width: "100px", name: "Minimum Temperature" },
	{ field: "max_temp", width: "100px", name: "Maximum Temperature" },
	{ field: "type", width: "100px", name: "Type", editable: true,
	  type: dojox.grid.cells.Select, options: [ '0', '1' ] },
	{ field: "thick", width: "5em", name: "Thickness", editable: true }
];

[Live Example]

Conclusion

The Dojo 1.2 Grid offers significant performance and API simplifications over previous versions of the Dojo Grid. As of Dojo version 1.2, you will be able to continue using the existing Dojo Grid, and also use the new Grid, even on the same page of an application if necessary. We highly recommend that you upgrade to the new version of the grid as soon as possible as the new feature set is worth the investment!

Touching and Gesturing on the iPhone

Fri, 07/11/2008 - 06:28

Everyone who owns an iPhone (or who has been holding out for an iPhone 3G) is bound to be excited about a lot of the new things the device can finally do, particularly the introduction of third-party applications. But those of us in the web development community have been itching for something further still: good web applications on the iPhone. This means we need a suitable replacement for mouse events. And boy did we get them! Though at first the APIs seem a little sketchy, once you’ve learned them you should be able to do amazing things in your application.

I’ll start with how to set up the iPhone console, since I found it invaluable while testing. Under Settings > Safari > Developer, you can turn it on or off. Simple log, error, and warn functions are provided (as part of the console object), all of which accept a single object.

My quest to understand the API led me to this Apple Developer Connection page that, while providing pretty thorough documentation about what’s available, left me a little confused about the details. Also, if you aren’t a member of ADC, trying to follow this link will leave you even more confused.

Clearing it Up

Apple introduced two new ideas with this API: touches and gestures. Touches are important for keeping track of how many fingers are on the screen, where they are, and what they’re doing. Gestures are important for determining what the user is doing when they have two fingers on the screen and are either pinching, pushing, or rotating them.

Touches

When you put a finger down on the screen, it kicks off the lifecycle of touch events. Each time a new finger touches the screen, a new touchstart event happens. As each finger lifts up, a touchend event happen. If, after touching the screen, you move any of your fingers around, touchmove events happen.

We have the following touch events:

  • touchstart: Happens every time a finger is placed on the screen
  • touchend: Happens every time a finger is removed from the screen
  • touchmove: Happens as a finger already placed on the screen is moved across the screen
  • touchcancel: The system can cancel events, but I’m not sure how this can happen. I thought it might happen when you receive something like an SMS during a drag, but I tested that with no success
node.ontouchstart = function(evt){
  console.log(evt.pageX + "/" + evt.pageY);
  // OH NO! These values are blank, this must be a bug
}

My first mistake was monitoring these events and trying to get location information from the events (pageX, pageY, etc). After consulting the ADC documentation again, I learned about three event lists that come attached to the object. But I wasn’t sure what they did, so I went back to testing, logging, and experimenting.

It helped when I figured out the problem the Apple developers were trying to solve. With a mouse, you really only have one point of contact: through the cursor. With your hand, you can keep two fingers held down on the left of the screen while you keep tapping the right side of the screen.

Our event object has a list, and this list contains information for every finger that’s currently touching the screen. It also contains two other lists, one which contains only the information for fingers that originated from the same node, and one which contains only the information for fingers that are associated with the current event. These lists are available to every touch event.

We have the following lists:

  • touches: A list of information for every finger currently touching the screen
  • targetTouches: Like touches, but is filtered to only the information for finger touches that started out within the same node
  • changedTouches: A list of information for every finger involved in the event (see below)

To better understand what might be in these lists, let’s go over some examples quickly

  • When I put a finger down, all three lists will have the same information. It will be in changedTouches because putting the finger down is what caused the event
  • When I put a second finger down, touches will have two items, one for each finger. targetTouches will have two items only if the finger was placed in the same node as the first finger. changedTouches will have the information related to the second finger, because it’s what caused the event
  • If I put two fingers down at exactly the same time, it’s possible to have two items in changedTouches, one for each finger
  • If I move my fingers, the only list that will change is changedTouches and will contain information related to as many fingers as have moved (at least one).
  • When I lift a finger, it will be removed from touches, targetTouches and will appear in changedTouches since it’s what caused the event
  • Removing my last finger will leave touches and targetTouches empty, and changedTouches will contain information for the last finger

Using these lists, I can keep very close tabs on what the user is doing. Imagine creating a(nother) Super Mario clone in JavaScript. I’d be able to tell what direction the user currently has his or her thumb on, while also being able to watch for when the user wants to jump or shoot a fireball.

I’ve been saying that these lists contain information about the fingers touching the screen. These objects are very similar to what you’d normally see in an event object passed to an event handler A limited set of properties are available in these objects. Following is the full list of properties for these objects:

  • clientX: X coordinate of touch relative to the viewport (excludes scroll offset)
  • clientY: Y coordinate of touch relative to the viewport (excludes scroll offset)
  • screenX: Relative to the screen
  • screenY: Relative to the screen
  • pageX: Relative to the full page (includes scrolling)
  • pageY: Relative to the full page (includes scrolling)
  • target: Node the touch event originated from
  • identifier: An identifying number, unique to each touch event

For those of you coming from the normal web design world, in a normal mousemove event, the node passed in the target attribute is usually what the mouse is currently over. But in all iPhone touch events, the target is a reference to the originating node.

One of the annoyances of writing web applications for the iPhone has been that even if you set a viewport for your application, dragging your finger around will move the page around. Fortunately, the touchmove’s event object has a preventDefault() function (a standard DOM event function) that will make the page stay absolutely still while you move your finger around.

Drag and Drop with the Touch API

We don’t have to worry about keeping track of down/up events as we do with mousemove since the only way touchmove is triggered is after touchstart.

node.ontouchmove = function(e){
  if(e.touches.length == 1){ // Only deal with one finger
    var touch = e.touches[0]; // Get the information for finger #1
    var node = touch.target; // Find the node the drag started from
    node.style.position = "absolute";
    node.style.left = touch.pageX + "px";
    node.style.top = touch.pageY + "px";
  }
}
Gestures

This was much easier to figure out than the touch API. A gesture event occurs any time two fingers are touching the screen. If either finger lands in the node you’ve connected any of the gesture handlers (gesturestart, gesturechange, gestureend) to, you’ll start receiving the corresponding events.

scale and rotation are the two important keys of this event object. While scale gives you the multiplier the user has pinched or pushed in the gesture (relative to 1), rotation gives you the amount in degrees the user has rotated their fingers.

Resizing and Rotating with the Gestures API

We’ll be using WebKit’s transform property to rotate the node.

var width = 100, height = 200, rotation = ;
 
node.ongesturechange = function(e){
  var node = e.target;
  // scale and rotation are relative values,
  // so we wait to change our variables until the gesture ends
  node.style.width = (width * e.scale) + "px";
  node.style.height = (height * e.scale) + "px";
  node.style.webkitTransform = "rotate(" + ((rotation + e.rotation) % 360) + "deg)";
}
 
node.ongestureend = function(e){
  // Update the values for the next time a gesture happens
  width *= e.scale;
  height *= e.scale;
  rotation = (rotation + e.rotation) % 360;
}
Conflicts

Some readers might have noticed that a gesture is just a prettier way of looking at touch events. It’s completely true, and if you don’t handle things properly, you can end up with some odd behavior. Remember to keep track of what’s currently happening in a page, as you’ll probably want to let one of these two operations “win” when they come in conflict.

In Action

I put together a quick demo:

This is a simple application that showcases the incredible flexibility and power of these APIs. It’s a simple gray square that can have its colors and borders restyled, can be dragged around, and can be resized and rotated.

Load http://tinyurl.com/sp-iphone up on your iPhone and try the following:

  • Keep a finger over one of the colored squares, and put another finger on one of the border squares
  • Try the same thing using two colored squares or two border squares
  • Use one finger to drag the square around the page
  • Pinch and rotate the square
  • Start dragging the square, but put another finger down and turn it into a pinch and rotate. Lift one of your fingers back up, and resume dragging the square around
Can I Do X?

I’m not sure what sort of APIs we’ll be able to build on top of what Apple has provided for us. What I do know is that Apple has given us a very well thought out API.

mousedown and mouseup are events we can easily emulate with this new API. mousemove is a beast. First of all, we only get touch events after the finger has made contact (the equivalent of mousedown) while we get mousemove events regardless of whether the button is down or not. Also, preventing the page from jumping around isn’t something we can automate. Attach a handler to the document and the user wouldn’t be able to scroll at all!

Which brings us to DnD in general. Even though DnD only cares about mousemove in the context of the mouse button being down (the way that touchmove works), we don’t have any way to tell what node the user’s finger is over at the end of the drag (since target refers to the originating node). If a DnD system is to be used, it would have to be for registered drop targets who are aware of their position and size on the page.

Dojo Toolbox First Look

Tue, 07/08/2008 - 15:50

In the middle of May, we were given a mission: create a speedy, offline API documentation viewer and a graphical Dojo build tool. Here we are at the beginning of July, and the result is the Dojo Toolbox 1.0. This article is a first look at this new application.

Adobe® AIR™ has received a good deal of press attention over the past few months, and with good reason. It provides a way for web application developers to use the skills they already have to create cross-platform desktop applications. Starting with Dojo 1.1, Dojo has included support for AIR out-of-the-box. This made AIR an ideal target environment for the Dojo Toolbox.

The easiest way to get the Dojo Toolbox is from SitePen’s Dojo Toolbox page. There’s a widget on that page that can download the Adobe AIR runtime and the Dojo Toolbox quickly, and with a minimum of effort.

Installation of an AIR application is a breeze. When you double click the DojoToolbox.air file, you will see a security verification window like the one below:

Dojo Toolbox Install Security Check

Unlike a web application, AIR apps are able to access the files on your computer and have unrestricted access to the internet. For that reason, AIR applications are digitally signed so that you can decide if you trust the application’s publisher with this extra level of access.

We have signed the Dojo Toolbox with a certificate assigned to the Dojo Foundation by Thawte. So, installation of the Dojo Toolbox reflects that the publisher’s identity has been verified. The Dojo Toolbox requires access to your local file system, in order to be able to run builds, and to the internet in order to check for updates and to download the API documentation.

After you accept the security aspects of the installation, AIR asks you where you would like to place the newly installed app, presenting a default that is appropriate for your platform.

Dojo Toolbox Install Location Dialog

One thing you might already have noticed about AIR: its appearance is not the same as a native application. Though AIR apps have many of the capabilities of a native application, the way they are rendered is very much the same as a web application. If you imagine the incredible variety of appearances in web applications, you can imagine the diversity we’re likely to see in AIR applications.

The install process is easy, but updates are even easier. The Dojo Toolbox can check for updates for you and download and install an update with just a couple of clicks.

Unless you unchecked the checkbox on the installer screen, the Dojo Toolbox will launch as soon as it’s ready.

The Screencast

If you’d like to see, rather than read about, the Dojo Toolbox you can either install it for yourself, or take 5 minutes and watch the screencast:

The Dojo Toolbox Application

When you launch the Dojo Toolbox, you’re greeted with a small “launcher” window:

Dojo Toolbox Tool Launcher Window

You’ll notice right away that it’s not a native-looking window. That’s another nice feature of AIR: you can create “chromeless” windows that have their own distinctive look and feel.

The Dojo Toolbox is designed to be unobtrusive, so you can leave it sitting around and reach for it whenever you need it. You can drag the launcher around your desktop, and it will remember its position for the next time you launch it.

If you click on the Dojo logo, the launcher will expand so you can access the available tools. Currently, there are three: the API Viewer, Builder and Resources.

Dojo Toolbox Launcher Expanded

Let’s take a closer look at them in the order in which they’re presented.

API Viewer

The first time you launch the API Viewer, it will download the Dojo API documentation zip file and then uncompress it. This file is a version of api.dojotoolkit.org that has been reformatted specifically for the Dojo Toolbox.

When the API Viewer is ready, you’ll get a view of the Dojo API documentation that is similar to the one on the web.

Dojo Toolbox API Viewer

The navigation on the left allows you to easily find a module within the Dijit, Dojo and DojoX packages. Not surprisingly, choosing a module on the left will give you the docs for that module on the right. At the top of the window, there are left and right arrow buttons. Those are like the back and forward buttons in your browser.

One feature that you’re likely to use all the time is the search box at the top. Type in the name of a Dojo function (for example dojo.forEach) or the words that you’re looking for and you’ll get a list of matching help topics.

API Viewer Search Results

All of the topics that match any of the terms you enter will be displayed, sorted with a simple scoring mechanism. You can also search for topics that do not include a particular word by putting a “-” before the word.

The API Viewer gives you amazingly fast access to the wealth of information available in the Dojo API documentation. Even on an airplane!

Introducing the Builder

The Builder tool is the most complex tool in the current Dojo Toolbox. It has many options spread out over three tabs.

Dojo Toolbox Builder

You can productively use the Builder without touching most of those options. The goal with the Builder is to provide an easier way to take advantage of the power of Dojo’s build system, which was previously available only as a command-line tool.

Dojo’s build system can dramatically reduce page load time by cutting the number of requests that the browser needs to make and reducing how much data is sent on each of those requests. Internet Explorer has a default limit of just two simultaneous requests, which means that reducing the number of requests required can have a huge impact on page load time.

To use the Builder, there are just two things you need to provide it: the top directory of the copy of Dojo of which you wish to make a build, and the location of a profile file. Assuming that you already have a copy of Dojo that you have downloaded previously, you can click the “Select Directory…” button to choose the directory containing your Dojo. The Builder will remember that choice so that you can select it next time.

Next, you need a profile file. The profile describes how JavaScript modules will be collapsed into separate JavaScript files. You can learn more about creating profiles from the online Dojo Book. Once you have a profile available, you can click the “Select File…” button to select that profile for building. As with your Dojo directory, the Builder will remember which profile was last used for building, so that you can easily grab it again.

And that’s all you absolutely have to choose before you can run a build. Click the “Build It!” button, and you’re off to the races.

Running a build in the Dojo Toolbox

While the build is running, you will see a progress meter with a short description of what is happening. In addition, you get a log window that displays the log output of the build. That is the same log output you get when running the Java build.

The amount of time it takes to run a build in the Dojo Toolbox is comparable to how long is spent on a build using the traditional Java-based build tool.

Speaking of the Java-based build tool, the mysterious-sounding “Command” button will give you the command line options to use with the Java build tool.

Dojo build tool command line options

That means you can use the Builder as a graphical front end to the command line build tool, making it easy to run automated builds.

Build Options

Dojo’s build system can handle sophisticated needs. With so many options available, it can be difficult to know what each one is all about.

Luckily, help is built in to the Builder tool. You’ll notice that many of the field names are underlined. If you click those underlined headings, you’ll see a Tooltip that describes what that setting is for.

Builder Option Tooltip

The text for these Tooltips is from the command line build tool help, so these will always stay in sync.

I want to mention a very important option: the ShrinkSafe option. ShrinkSafe is Dojo’s tool that compresses JavaScript files by eliminating excess whitespace and removing comments. ShrinkSafe is “safe”, unlike some other JavaScript compression tools, because it works off of the syntax tree produced by a customized version of Rhino, the JavaScript engine written in Java. Rhino is not available within the AIR environment.

As of this writing, the only ShrinkSafe optimization choice available is “none”. We left the option on the page, however, because we are actively working on providing two options for using ShrinkSafe with the AIR-based build. The first is “Remote ShrinkSafe”, which will use the ShrinkSafe web service to compress the files. We also recognize that many people might not want their custom JavaScript files being passed across the Internet. For this reason, we are also working on a “Local ShrinkSafe” option which will use a small Java-based service running on your computer for the compression.

The Resources Tool

The third tool in the Dojo Toolbox is called, simply, “Resources”.

Resources Tool

Resources provides you with a consolidated, quick click-and-go list of some amazingly useful sources of knowledge and help for working with Dojo. We’ll be keeping this resource list up-to-date as new articles are published and new tools are created.

After 1.0

We’re very excited to be offering this new, simple way to help you get more out of Dojo. And 1.0 is really just the beginning. We have tons of ideas for new tools and features for the Dojo Toolbox, and I’m sure you do, too.

Download the Dojo Toolbox today to take advantage of the great features today. Then, join us on the Dojo Toolbox mailing list and tell us how we can make this open source application even better.

Adobe, the Adobe logo and Adobe AIR are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries.

Amazon S3 + Dojo

Thu, 07/03/2008 - 07:03

Dojo’s improved RPC and new REST services can be used with a wide array of web services. One particular use is Amazon’s Simple Storage Service (S3). Dojo can connect to Amazon S3’s with a trivial proxy and be used as a normal RPC service. Not only that, Amazon S3 is a REST service and therefore it can be used as a data store with Dojo’s new REST implementation of dojo.data, JsonRestStore. You can read and write to your S3 database using the convenient Dojo Data API, and use the data store in Dojo widgets.

s3store.png

Getting Started

To get started with Dojo + S3:

  • First, you must be signed up to use Amazon S3.
  • Dojo uses a simple proxy to communicate with S3 (doing so directly from the browser would be insecure). The proxy PHP script, proxy.example-php, located in /dojox/rpc/s3/, must be renamed to proxy.php to be used.
  • The proxy requires PHP 5 (other languages hopefully will be added) and the following modules:
  • Next you must enter your Amazon access key and secret access key into the proxy.php file on line 3 and 4:
    $accessKey = "access key";
    $secretAccessKey = "secret access key";

Now we can start using Dojo services to connect to S3. You use the Dojo RPC service with the “PROXIED-PATH” envelope:

dojo.require("dojox.rpc.Service");
dojo.require("dojox.rpc.ProxiedPath");
var s3Buckets = new dojox.rpc.Service({
	target:"http://s3.amazonaws.com/",
	proxyUrl:"../s3/proxy.php", // the path to the proxy
	transport:"REST",
	envelope:"PROXIED-PATH",
	contentType:"application/json",
	services:{
		myBucket:{ // name of the service (usually the bucket)
			target:"myBucket", // enter you bucket here
			parameters:[{type:"string"}]
		}
	}
});

To use the S3 as a Dojo data store you can use the S3Store module. First setup an RPC service as shown above and then pass the RPC service to the S3JsonRestStore:

dojo.require("dojox.data.S3Store");
// and create a store for it
s3Store = new dojox.data.S3Store({service:s3Buckets.myBucket});

You can then use the s3Store as a normal Read/Write Dojo Data store. And since the S3Store is an extension of the JsonRestStore, you can use all the additional features of that store including fast, compact syntax, referencing, and offline capabilities are coming soon. With the S3Store you can build sophisticated apps with very thin server architecture; UI logic can be handled on the browser, and database storage can be delegated to Amazon’s S3. This is just one of the many new features available with Dojo 1.2.

Dojo In 6K

Wed, 07/02/2008 - 01:44

Some sites can defer most, if not all, of their JavaScript-driven progressive enhancements until well after the page has loaded. Even so-called “lightweight” libraries like JQuery are far too heavy for some environments…not because they (like Dojo) pull in all the code needed to use them, but because they do it all up-front. Often the best time to pay the expense of loading, parsing, and executing JavaScript code is when the user takes an action that needs the enhancement to run. Dojo already gives you the best tools available anywhere to defer loading modules until you actually use them; other than those provided by dojo.js itself…but what about dojo.js? What if even the small size of Dojo is too big for your page? This need to load as fast as possible and defer work is never greater than in mobile applications. The best-performing thing to do is always to hand-write all the code you’ll need and never use more script than that…but there are complications. Not being able to share your code between developers (let alone between pages) can be a huge disadvantage. The code is also likely to be slow, buggy, and unmaintainable. There’s a real reason why toolkits like Dojo are so incredibly popular: they make much of this pain go away at the cost of initial download size. Why would anyone want to invite the pain back?

So we need some middle ground: a common, expected API surface area combined with a trivial initial footprint to ensure that pages load as fast as possible. How small could we make such a thing? Turns out, 6K.

Dojo has, for many versions now, provided the ability to use the build system to cut out parts of dojo.js which weren’t in use by the application and load them later. In fact, everything but the package loader and the few functions it needs to operate are located in source packages in the dojo/_base/ directory. When running Dojo from source, these files get pulled in with dojo.require() the same way that any other module might. One possible option then is to use the build system to create a custom version of dojo.js which includes just the modules your application uses at page load. But we’re still faced with the essential problem created by hand-rolling everything: it becomes much harder to work with Dojo. You no longer know what functions and classes might be provided by the dojo.js file loaded in the header of your page, meaning that the advantages of maintainability, shared team knowledge, and dependability are reduced. Code developed for this situation is littered with statements like dojo.require("dojo._base.array"); in order to ensure that the right modules are available.

A better solution might be one which preserves the super-lightweight foot-print of including just the Dojo loader but which also provides access to the full, rich API that is provided by the stock dojo.js without developers needing to spend a lot of time worrying whether a particular base module has already been loaded.

Enter the stub loader.

I’ve prototyped an alternate dojo.js which you can download as part of a build (256K tarball, includes tests) of just Core (the stuff in the dojo.* namespace). When served gzipped, this new version of dojo.js weighs in at roughly 6K, yet it provides the full API of the normal dojo.js, provided off of the AOL CDN at roughly 24K, or 4x the size. Instead of including all of the modules in Dojo’s baseline set of functionality, this new version instead pulls in just the bootstrapping code for the module system and then creates stub functions and constructors for all of the functionality which isn’t included. When a function is first called, the stub loader ensures that dojo.require() is called to pull in the appropriate functionality synchronously. The result is an API which behaves exactly as though all of dojo.js had been loaded up front but which defers loading until the code is actually used.

On an iPhone with a clean cache the stubbed-out dojo.js cut in half the time required to load and evaluate. Sure, it’ll take more time on the network when parts of the toolkit are actually used (say, in response to a click event), but for mobile device scenarios, it’s going to be hard to beat the flexibility and speed of the stub loader when pulling Dojo into a page.

The code to implement this strategy can now be viewed. If you view that file, you’ll note that the first several lines read like this:

dojo.provide("dojo._base");
dojo.provide("dojo._base.browser");
dojo.provide("dojo._base._stubs");

This implies that if some other code subsequently calls dojo.require("dojo._base");, as the build system normally would, then no code will be loaded. In a source version of Dojo, dojo/_base.js reads as such:

dojo.provide("dojo._base");
dojo.require("dojo._base.lang");
dojo.require("dojo._base.declare");
dojo.require("dojo._base.connect");
dojo.require("dojo._base.Deferred");
dojo.require("dojo._base.json");
dojo.require("dojo._base.array");
dojo.require("dojo._base.Color");
dojo.requireIf(dojo.isBrowser, "dojo._base.browser");

By loading our stub loader instead, all of the modules in dojo._base.* which would normally be included are left out of the build and replaced with their stub counterparts. To get some bit of code included in a build instead of the stub, we’d then just add the corresponding require (e.g., dojo.require("dojo._base.lang")) at the top of dojo/_base/_stubs.js, at which point the corresponding stub functions won’t be generated.

In a build which uses dojo/_base/stubs.js, extra code is not loaded until the functions and constructors which are stubbed out there are actually called. You can drop this file into your dojo/_base/ directory if you’re working with Dojo from source and then use the following profile definition to create your own stubbed-out dojo.js. I placed mine in util/buildscripts/profiles/stubs.profile.js:

dependencies = {
	layers: [
		{
			name: "dojo.js",
			customBase: true,
			dependencies: [
				"dojo._base._stubs"
			]
		},
		// your layers here!
	],
 
	prefixes: [
		// uncomment these to copy dijit and dojox into your build output
		// [ "dijit", "../dijit" ],
		// [ "dojox", "../dojox" ]
	]
};

And would normally build with:


%> cd dojo_repo/util/buildscripts/
%> ./build.sh profile=stubs action=clean,release copyTests=false cssOptimize=comments optimize=shrinksafe
clean: Deleting: ../../release/dojo
release: Using profile: profiles/stubs.profile.js
...

A Quick JavaScript Load Profiler

Tue, 07/01/2008 - 20:02

I was doing some research on script loading speed tests. Each script load required the page to be refreshed, making it difficult to log the time to Firebug and get an average. It was certainly too much trouble to write some PHP scripts and connect to a database; and possibly even worse would be having to pull out a pencil and paper and write the times down. I’m not even sure I have a pencil.

The obvious solution was to write the data to a cookie. I also thought the solution was universal enough to blog about so others could use it too.

The first thing we need is a timer. Firebug has a timer, but it doesn’t return the results so that they can be saved. The timer will be a singleton since we will only need one instance holding all of the data, and it will be a global object so we can access it anywhere. The code is quite simple:

dojo.provide("mikespace.timer");
timer = {
	_map:{},
	start: function(msg){
		this._map[msg] = new Date().getTime();
	},
	end:   function(msg){
		this._map[msg] = new Date().getTime() - this._map[msg];
		return this._map[msg];
	},
	show: function(msg){
		console.log( "---------> " + msg + ": " + this._map[msg]);	
	}
};
// usage:
// timer.start("first test");
// var time = timer.end("first test);

This code is in a directory (or package) named mikespace. As you can see, the times are set and retrieved based on the label parameter, and stored in a hash map. There’s also a show() method - although I’m not going to use it here, I use this often. When conducting speed tests in an application, the timers are usually sprinkled everywhere throughout the code and show in various places in the log messages. By just calling timer.end() I store the time, and after all of the tests have been run, I call timer.show(msg) for each test, and log them all in one place.

Next we need our cookie aggregator. This too could be a singleton, but after considering that there could be multiple tests in a page, I decided to make it a PODO (Plain Old Dojo Object). Here is the full code for cookieData, and I’ll explain after:

dojo.provide("mikespace.cookieData");
dojo.require("dojo.cookie");
 
dojo.declare("mikespace.cookieData", null, {
	cookieName:"scriptTests",
	expires:1,
	testData:[],
	constructor: function(args){
		for (var nm in args){
			this[nm] = args[nm];	
		}
	},
	loadData: function(){
		this.cookie = dojo.cookie(this.cookieName);
		if(this.cookie){
			this.testData = dojo.fromJson(dojo.cookie(this.cookieName));
		}
	},
	getData: function(){
		return this.testData;
	},
	showData: function(){
		console.log("Test Name:", this.cookieName);
 
		var data = this.getData();
		var avr = 0;
		var amt = 0;
		dojo.forEach(data, function(d, i){
			console.log(i, "test:", d);
			avr+=d;
			amt++;
		});
 
		console.log("Average:", Math.ceil(avr/amt));
	},
	saveData: function(data){
		this.testData.push(data);
		 dojo.cookie(
			this.cookieName, 
			dojo.toJson(this.testData),
			{ expires: this.expires }
		);
	},
	clearData: function(){
		dojo.cookie(
			this.cookieName, 
			dojo.toJson([]), 
			{ expires: this.expires }
		);
	},
	deleteCookie: function(){
		dojo.cookie(this.cookieName, null, { expires: -1 });
	}
});

I’m utilizing dojo.cookie, so it is required. I declare mikespace.cookieData, and I’m not extending anything (like dijit._Widget), so the second parameter is null. Because I’m not using dijit._Widget, I’m mixing in the arguments object myself in the constructor. I then instantiate a few variables. expires is set to one day, which could be left as-is if you don’t want to leave the cookie hanging around on your system when your done. Or set it to an arbitrarily large number and use the deleteCookie() method.

The rest of the code should be quite easy to understand. in loadData() we check if the cookie exists, and if not, we create one with new data. In showData() I log each test and number it, so I can easily see how many tests I’ve run, and then I show the average. The showData() method could obviously be any kind of code, including parsing tests within tests. And semantically, it probably should be outside of this cookieData; if we wanted to just use it as a getter and setter and then create another object for displaying the results.

Now we’ll create our HTML page where we will run the tests. After including the Dojo script tag, and the djConfig, I register the mikespace namespace, and then require the files:

dojo.registerModulePath("mikespace", "../../tests/mikespace");
dojo.require("mikespace.timer");
dojo.require("mikespace.cookieData");

Now we’ll build our test. The test I’m conducting is how long it takes to load a script, and I chose dojox.data.jsonPathStore, because it’s nice and big and has a few dependencies. I modified the script to call the end of the test, after it loaded it’s dependent scripts:

...
dojo.require("dojo.date.stamp");
 
if(window.endTest){
	window.endTest();
}
...

And our test functions:

startTest = function(){
	timer.start("script loaded");
}
 
endTest = function(){
	var time = timer.end("script loaded");
	var testName = "dojox.data.jsonPathStore Load";
 
	var c = new mikespace.cookieData({cookieName:testName});
	//c.clearData();
	c.loadData();
	c.saveData(time);
	c.showData();
}

When endTest() is called, the cookieData object is created and the test data is saved and logged. Since the timer has already ended, the amount of time it takes to create this object is not factored into the results. If I want to start the test over, I uncomment c.cleardata() and refresh the page.

Finally, to launch our test, start the timer and load the script:

startTest();
 
dojo.require("dojox.data.jsonPathStore");

Refresh the page ten times and you have a legitimate average of how long it takes to load the script.

cookietestdataresults.png

And there you have a quick and dirty method for logging tests that involve page refreshes. This example could be taken even farther, enclosing the startTest() and endTest() in its own PODO which requires the timer and cookieData. Then it’s a simple matter of dropping in the one require to conduct some quick tests.

Connect to the Mobile Web with SMS

Mon, 06/30/2008 - 07:03

SMS is a great way to push small amounts of text to mobile users. But what happens when your application needs to send more than 140 characters of information? Most modern phones, including Apple’s iPhone, support the ability to launch the mobile web browser using the URL embedded in the SMS message. Your application can create a short URL that points to the content you need to send and send the URL in the body of the SMS instead of the content itself. The user experience varies from phone to phone. On the iPhone, the user simply touches the link; on other phones, there is usually a menu option that will activate the url.

sms_url.jpg The URL is subject to the same size limits as any other SMS message. Keeping the URL as short as possible is key, allowing you to send descriptive text along with the message to give the user an idea as to what they will be viewing when they click the link. URL shortening services like tinyurl will keep your URL to around 25 characters. Twitter users are no doubt familiar with this idea, whether they send Tweets from their phone or not.

The web page that the URL points to needs to detect the capabilities of the mobile device and return the appropriate markup. In the case of the iPhone, a full HTML page can be returned, but for many phones, the content needs to be limited to the XHTML mobile profile, or as a worst case with the oldest of phones, WML might be the only supported markup. Device capability databases like WURFL will allow you to look at the user-agent of the devices and return the appropriate markup.

Make sure that your users actually want to receive the SMS before you send it. Most users have to pay for each SMS message, so filling up their phone with messages without their permission is not a good idea. Allow your users to opt-in to receiving SMS messages and allow them to place a maximum cap on the number of messages they can get per day or month. Also include a verification system that ensures that your user actually controls the phone number they give you. This can be as simple as sending an SMS message with a PIN number that they then feed back into your signup form. Lastly, include disclaimer text that lets the user know that standard text messaging rates apply to any messages you send them. Adding these safeguards will help to ensure that your users only receive the messages they want.

Adding SMS notification with embedded URLs has many advantages: you can reach your users wherever they are, provide links to detailed rich content, increase awareness of your mobile web offering, and drive additional traffic deep into your mobile web site. If your application already works on mobile devices and you already have the infrastructure in-place to send email or SMS alerts, then sending URLs in SMS messages is a simple addition that can add significant value to your users. A great example for this is the airline industry. Instead of just sending a user an SMS with their gate information and arrival and departure time, they could also send a link to a convenient, mobile optimized “My Flight” page that would include other essential details such as seat assignment, arrival time, airline phone number, first class update options, and airport map.

Web Service to dojo.data Store in 4 Easy Steps

Thu, 06/26/2008 - 02:12

A very useful feature of Dojo is the dojox.data.ServiceStore data store. It allows you to layer a dojo.data API on top of any web service, opening up a world of uses from your own client-side components. Kris Zyp briefly mentioned the topic in his recent article on JsonRestStore, and the past couple of weeks have seen a bunch of refinements to the component to get it ready for next month’s Dojo 1.2 release. Let’s take a quick look at how to make it work with the web service of your choice.

Building the WikipediaStore

Dojo recently received a new data store that demonstrates exactly what we want: dojox.data.WikipediaStore. It does just what it sounds like, turning Wikipedia into a simple object you can query from your code. Building it with Dojo’s handy dojox.rpc package makes for a simple, compact, DRY implementation.

In only four steps:

  1. Create the web service object
  2. Declare the new data store, inheriting from ServiceStore
  3. Give it a fetch method
  4. Give it a _processResults method

That’s all there is to it.

Step 1: Create the web service object

Probably the simplest way to build an object that can talk to a web service is to create a Service Mapping Description (SMD) for the web service, and let dojox.rpc.Service do the heavy lifting. Since Wikipedia’s API can speak JSONP, it’s a natural fit. The SMD doesn’t need to be thorough, since it’s not necessarily meant for human consumption; the wikipedia.smd only defines a single API endpoint and lets the data store worry about how to talk to it:

{
    "SMDVersion": "2.0",
    "id": "http://en.wikipedia.org/w/api.php",
    "description": "Wikipedia API",
 
    transport: "JSONP",
    envelope: "URL",
    additionalParameters: true,
    target: "http://en.wikipedia.org/w/api.php",
    parameters: [
        { name: "format", optional: false, "default": "json" }
    ],
 
    services: {
        query: {
            parameters: [
                { name: "action", type: "string", "default": "parse" }
            ]
        }
    }
}

This simple specification is enough to let you do something like the following, which stuffs the content of Wikipedia’s Dojo Toolkit page into the current page:

dojo.require("dojo.io.script"); // for cross domain JSONP
dojo.require("dojox.rpc.Service");
 
dojo.addOnLoad(function(){
    var mu = dojo.moduleUrl("dojox.rpc.SMDLibrary", "wikipedia.smd");
    var wikipedia = new dojox.rpc.Service(mu);
 
    wikipedia.query({
        action: "parse",
        page: "Main Page"
    }).addCallback(this, function(article){
        dojo.body().innerHTML = article.parse.text["*"];
    });
});

Once we have this, we just need to wrap it in a data store.

Step 2: Declare the new data store

Out of the box, the ServiceStore does just about everything you likely need; however, it doesn’t automatically understand how to format queries for your service, nor does it automatically know the format of the incoming data. It simply acts as a bus, passing through whatever it is given. That’s acceptable if you don’t mind enforcing the underlying web service’s structure on people who use the data store, but for Wikipedia, it doesn’t take much to clean things up a little.

The declaration for the new store is pretty basic. It’s just the common dojo.declare approach (the real code has a tiny bit more than this, but this is the idea):

dojo.provide("dojox.data.WikipediaStore");
 
dojo.require("dojo.io.script");
dojo.require("dojox.rpc.Service");
dojo.require("dojox.data.ServiceStore");
 
dojo.declare("dojox.data.WikipediaStore", dojox.data.ServiceStore,{
    constructor: function(){
        var mu = dojo.moduleUrl("dojox.rpc.SMDLibrary", "wikipedia.smd");
        var svc = new dojox.rpc.Service(mu);
        this.service = svc.query;
 
        // this lets ServiceStore's getLabel(), fetchItemByIdentity(),
        // etc. all work correctly
        this.idAttribute = this.labelAttribute = "title";
    },
    fetch: function(/* object */ request){
        // to come
    },
    _processResults: function(results, def){
        // to come
    }
});

We haven’t done much yet, but we’re already halfway done! All that’s left is to shuttle data back and forth.

Step 3: Give it a fetch method

The dojo.data API uses the fetch method to query data stores, but it leaves it up to the store to determine the actual format of the query. The ServiceStore can pass query data right through to the underlying web API, but since we don’t want our data store’s users to have to know the Wikipedia API itself, we can define our own convention for creating queries and map that to the real API.

WikipediaStore defines two basic operations, query (to do full text searches) and parse (to load page data).

  • The query operation will be called thusly:
    store.fetch({
        query: {
            action: "query",
            text: "dojo"
        },
        // onItem, onComplete, etc...
    });
  • For parse, we want to be able to do the following:
    store.fetch({
        query: {
            // action: "parse", -- this is the default, so we can leave it out
            title: "Dojo Toolkit"
        },
        // onItem, onComplete, etc...
    });

So we define our own fetch that takes the request object passed in and massages it a little bit to transform our custom query structure into something that will work for Wikipedia’s API (by virtue of the dojox.rpc.Service). After doing this in-place modification, we call the ServiceStore’s fetch to do the actual RPC call:

fetch: function(/* object */ request){
    var rq = dojo.mixin({}, request.query);
    if(rq && (!rq.action || rq.action === "parse")){
        // api.php?action=parse&page=PAGE_TITLE
 
        // default to a single page fetch
        rq.action = "parse";
        rq.page = rq.title;
        delete rq.title;
 
    }else if(rq.action === "query"){
        // api.php?action=query&list=search&srwhat=text&srsearch=SEARCH_TEXT
 
        // perform a full text search on page content
        rq.list = "search";
        rq.srwhat = "text";
        rq.srsearch = rq.text;
        if(request.start){
            rq.sroffset = request.start-1;
        }
        if(request.count){
            rq.srlimit = request.count >= 500 ? 500 : request.count;
        }
        delete rq.text;
    }
    request.query = rq;
    return this.inherited(arguments);
}

Now we can use our simplified dojo.data query format above to retrieve data.

Step 4: Give it a _processResults method

Once we’ve requested data, the store needs to know how to process it. That’s where the _processResults function is useful.

_processResults: function(results, def){
    if(results.parse){
        // loading a complete page
        results.parse.title = dojo.queryToObject(def.ioArgs.url.split("?")[1]).page;
        results = [results.parse];
 
    }else if(results.query && results.query.search){
        // loading some search results; all we have here is page titles,
        // so we mark our items as incomplete
        results = results.query.search;
        var _thisStore = this;
        for(i in results){
            results[i]._loadObject = function(callback){
                _thisStore.fetch({
                    query: { action:"parse", title:this.title },
                    onItem: callback
                });
                delete this._loadObject;
            }
        }
    }
    return this.inherited(arguments);
}

The theory here is simple; it’s the same process as with fetch, just in reverse. We receive JSON data from Wikipedia, and we need to restructure it such that when we call the ServiceStore’s _processResults at the end, it’ll set up the internal object correctly.

The most interesting thing about our _processResults function is thection with the _loadObject callback. When we do a search on Wikipedia, all we get back is a list of page titles in request.query.search; we can use these to create stub objects, but there obviously isn’t enough data here to really use. We’d like to be able to fill in the stub object with something like store.loadItem({ item: someStubItem }), and that’s exactly what _loadObject allows: it tells ServiceStore how to load individual items (ServiceStore even supports lazy loading of objects, but only with transports that can be made synchronous; since JSONP always runs asynchronously, WikipediaStore can’t take advantage of it).

That’s really all there is to it; WikipediaStore seamlessly integrates Wikipedia into our apps. The Wikipedia store demo shows how to use it.

Integrating with Dijit

Of course, one of the big advantages of using the dojo.data API is that quite a few Dijit components can already grok it. For example, one of the demos for the Grid is built around pulling in data from Yahoo. Using the same principles as the WikipediaStore, this demo creates a YahooStore that wraps the Yahoo webSearch API endpoint. By implementing custom fetch and _processResults functions (see the component source), we get a beautifully Yahoo-ish grid.

Yahoo search ServiceStore grid demo screenshot

(Image shamelessly borrowed from Kris Zyp’s article on JsonRestStore)

So put together an SMD, a dojo.declare, and a couple of functions for your web service and create your own Dojo data store. When you can easily turn web services into data stores, the web is your oyster!

Creating Dojo Widgets with Inline Templates

Tue, 06/24/2008 - 21:59

I recently came across a situation where I needed to manage a set of nodes and widgets to perform a number of visual operations as well as manage some data between the client and a server back end. While this was a custom operation, it was common to a number of different places within the app. Initially, things were quite simple and I managed with a few functions and connections primarily using dojo.query(). In the end, I ended up with a simple way to make a dijit._Templated widget that uses its source node as a template instead.

Widgets can easily take advantage of existing source nodes to define how they might end up rendering. They might use the source nodes to define a data set. They could be widgets that manage a number of child widgets as is done with the various Dijit Layout widgets. However, under normal circumstances, a widget’s source node is replaced by the nodes generated from its template or the original source nodes are moved to a container node within your template. What we are looking for is a way to define a flyweight widget that can encapsulate behaviors and data, provides for dynamic template generation, and retains the utility of dojoAttachPoints and dojoAttachEvents from the templating system.

The good news is that it is very easy to do. Let’s look at a normal templated widget declaration:

dojo.declare("my.widget",[dijit._Widget,dijit._Templated],{
	templateString: '<div><div dojoAttachPoint="container"></div>
		<div dojoAttachEvent="onMouseOver:mouseOver">Go</div></div></div>"',
	postCreate: function(){
		// do something after I'm ready. Note: My children might not be 
		// ready yet, so dont' access them here!
	},
	startup: function(){
		// This fires after my children are available
	}
});

This is is a simple widget that does not do much. As you can see, it will end up creating a div containing two child divs at its declared location on the page. The first of these children has a dojoAttachtPoint attribute, which will create a reference to this DOM node at this.container in the widget instance. The second div has a dojoAttachEvent attribute which will connect that DOM node’s onMouseOver event to the widgets this.mouseOver() method.

There are numerous examples of using templates inside of Dijit and plenty of articles over at Dojo Campus or even here at the SitePen blog! But that’s not what we want as it is too static. Our templates will be defined as part of the Instance declaration instead of the widgets JavaScript declaration. To accomplish this goal, we simply need to declare the widget, and then override the buildRendering() and startup() methods provided by the dijit.Templated widget. We want to do something like this on our page:

<div dojoType="my.fly">
	<div dojoAttachPoint="container">Some Stuff</div>
	<button dojoType="dijit.form.button" dojoAttachEvent="onClick: go">
		Go!
	</button>
	<button dojoType="dijit.form.button" dojoAttachEvent="onClick: stop">
		Stop!
	</button>
</div>

So now we have a template:

<div dojoAttachPoint="container">Some Stuff</div>
<button dojoType="dijit.form.button" dojoAttachEvent="onClick: go">
	Go!
</button>
<button dojoType="dijit.form.button" dojoAttachEvent="onClick: stop">
	Stop!
</button>

The instance of my.fly will have a reference to the div at this.container, and the buttons, when clicked will call the fly’s go() or stop() methods respectively. As you can see there isn’t really any difference between this and a normal template provided by string or in a template HTML file. However, it’s easy for complex servers to generate a bunch of HTML and then wrap it with a fly widget to maintain it.

Let’s look inside my.fly to see how it ticks.

dojo.declare("my.fly", [dijit._Widget, dijit._Templated],{
	buildRendering: function(){
		// we already have the srcNodeRef, so lets just
                // keep it and use it as the domNode
		this.domNode = this.srcNodeRef;
 
		// call this._attachTemplateNodes to parse the template,
                // which is actually just the srcnode
		// this method is provided by the _Templated mixin
		this._attachTemplateNodes(this.domNode);
	},
 
	startup: function(){
		var node=this.domNode;
		this._supportingWidgets = [];
 
		// use a dojo.query to find all the child nodes that are widgets
		// and then get references to those widgets.  The widgets are
		// collected into this._supportingWidgets
 
		dojo.query("[widgetId]", node).forEach(function(n){
			if(n==node){return;}
			var id = dojo.attr(n,"widgetId");
			if (!id){return;}
			this._supportingWidgets.push(dijit.byId(id));
		}, this);
 
		// parse the widgets for dojoAttachPoints and dojoAttachEvents. 
		// Unlike the parse done in buildRendering, we're only going 
		// through the array of widgets in this._supportingWidgets;
 
		this._attachTemplateNodes(this._supportingWidgets, function(n,p){
			return n[p];
		});
	},
 
	go: function(){
		// do someting
	},
 
	stop: function(){
		//stop doing whatever it was go made me do.
	}
});

This flyweight mixin provides the above buildRendering() and startup() methods for easy reuse among a variety of flyweight widgets. Also included in this download are an example widget and test file, making it extremely easy to try this out with your application.

Replacing the Flash Flickr Badge with Dojo

Mon, 06/23/2008 - 07:04

A few weeks ago, some of the guys at SitePen were commenting that I was using Flash on my personal web site for a Flickr Badge. I responded that if Dojo had similar functionality, I would easily replace the badge. A couple of weeks later, Peter Higgins and Bryan Forbes of SitePen rose to the task and created dojox.image.FlickrBadge.

This weekend I had a chance to put their work to the test, and I’m impressed. Using the new Flickr badge is quite easy:

<head>
...
<link rel="stylesheet" href="/dojo/dojox/image/resources/image.css" />
<style type="text/css">
	img.thing { width:50px; height:50px; }
</style>
...
</head>
<body>
...
<div dojoType="dojox.image.FlickrBadge" rows="8" cols="3" username="dylans" 
	tags="dojotoolkit,italy"></div>
...
<script type="text/javascript" src="/dojo/dojo/dojo.js" 
	djConfig="parseOnLoad: true"></script>
<script type="text/javascript">
	dojo.require("dojox.image.FlickrBadge"); 
</script>
</body>

FlickrBadge. There are a number of configurable parameters, most of which are optional:

  • apikey: your Flickr API key
  • columns: # of columns of images to display
  • rows: # of rows of images to display
  • searchText: free text search of title, description, and tags
  • setid: id of a Flickr set to use in displaying images
  • tags: a comma separated list of tags or an array of tags to grab from Flickr
  • userid: your flickr userid (saves a lookup request)
  • username: your flickr username

Give them a try and create a badge that’s just right for your site.

Performance Optimizations

The badge included to this point is a great start, but it requires a number of JavaScript files to be loaded prior to the completion of page rendering, so I started making tweaks to improve performance. The next logical step is to create a Dojo build to layer all of the non-core Dojo code required for this module into a single file. First, I’ll create a very simple profile file for my build:

dependencies = {
	layers: [
		{
			name: "badge.js",
			resourceName: "dojo.badge",
			layerDependencies: [
			"dojo.js"
			],
			dependencies: [
				"dojox.image.FlickrBadge"
			]
		}
	],
 
	prefixes: [
		[ "dijit", "../dijit" ],
		[ "dojox", "../dojox" ]
	]
}

And then I ran the build with the following configuration options:

./build.sh action=release optimize=shrinksafe profile=dylan 
	cssOptimize=comments.keepLines cssImportIgnore=../dijit.css 
	version=1.2.pre

This reduced the number of requests by compressing a number of JavaScript files into badge.js. However, it still required a decent amount of additional JavaScript to load before the page renders. Fortunately, I’m using the latest Dojo trunk, and Dojo 1.2 has a new mechanism for lazy-loading a built layer! That’s right, just point to a layer as you would any Dojo module, and defer loading until later. All with a simple, single line of JavaScript:

dojo.addOnLoad(function(){ dojo.require("dojo.badge"); 
	dojo.addOnLoad(function(){ initBadge(); })});

A couple of notes:

  • the nested dojo.addOnLoad is the new way to add a load callback for a lazy-loaded layer
  • my use of dojo.badge as the resourceName is not a coincidence… it follows Dojo’s standard naming conventions, looking for the file badge.js as dojo/badge.js automatically

Finally, inside initBadge, I decided to turn off Dojo’s parser, and instead make an explicit widget instantiation on the node to replace, in order to reduce code execution time:

function initBadge(){
	console.log("init");
	new dojox.image.FlickrBadge({rows: 8, cols: 3, username: "dylans", 
		tags:"italy,dojotoolkit"},"flickrSidebox").startup();
}

That leaves us with this performance-optimized code fragment:

<head>
...
<link rel="stylesheet" href="/dojo/dojox/image/resources/image.css" />
<style type="text/css">
	img.thing { width:50px; height:50px; }
</style>
...
</head>
<body>
...
<div id="flickrSidebox"></div>
...
<script type="text/javascript" src="/dojo/dojo/dojo.js"></script>
<script type="text/javascript">
	function initBadge(){
		new dojox.image.FlickrBadge({rows: 8, cols: 3, 
			username: "dylans", tags:"italy,dojotoolkit"},
			"flickrSidebox").startup();
	}
	dojo.addOnLoad(function(){ dojo.require("dojo.badge"); 
		dojo.addOnLoad(initBadge)});
</script>

In a future release, I’d like to see us add an option to randomize which images get selected from the set, rather than the first X results from a query. This is a complaint I have with the official Flickr Badge as well, and the API itself which generally returns the first X entries. dojox.image now has a number of great features: Lightbox, Badge, Gallery, Magnifer, and SlideShow. dojox.image.FlickrBadge uses the new dojox.data.FlickrRestStore, a Dojo Data store implementation that makes it extremely easy and flexible to work between Flickr data sources and Dijits.

Dojo + jabsorb

Wed, 06/18/2008 - 07:01

jabsorb is lightweight Ajax framework that uses JSON-RPC to communicate method calls from JavaScript to the Java server. Because of Dojo’s pluggable RPC and SMD capabilities, Dojo can easily be used to communicate method calls to the jabsorb server framework. Together, Dojo and jabsorb provide a very simple solution for integrating a UI with a Java back-end. Here we will see a quick demonstration of making a Java object available for remote calls from Dojo.

First, we build a Java class that will return a polite hello to whomever called it:

public class Hello {
   public String sayHello(String who)
   {
     return "hello " + who;
   }
}

Next, we expose an object instance of this class to the jabsorb framework in JSP:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
		"http://www.w3.org/TR/html4/loose.dtd">
<jsp:useBean id="JSONRPCBridge" scope="session"
		class="org.jabsorb.JSONRPCBridge"/>
<jsp:useBean id="hello" scope="session"
		class="org.jabsorb.test.Hello"/>
<% JSONRPCBridge.registerObject("hello", hello); %>
<html>...

Here we register an object called “hello” which is an instance of the Hello class. The jabsorb method naming convention defines that in order to call the sayHello method on the hello object, we call the method “hello.sayHello” using JSON-RPC. Now we create an RPC service in Dojo. We use an SMD definition to define the service that is available jabsorb:

dojo.require("dojox.rpc.Service");
dojo.require("dojox.rpc.JsonRPC");
var services = new dojox.rpc.Service({
	target:"/jabsorb-1.2/JSON-RPC",
	transport:"POST",
	envelope:"JSON-RPC-1.0",
	contentType:"application/json",
	services:{
		"hello.sayHello":{ // this is the method that we created in jabsorb
			returns:{"type":"string"},
			parameters:[{"type":"string"}]
		}
	}
});

We now have a services object that we can use to call the hello object. We can call the sayHello method on the server by calling the “hello.sayHello” method on the services object:

var deferred = services["hello.sayHello"]("Fred");
	deferred.addCallback(function(result) {
		alert(result);
	})

This calls the sayHello method with argument of “Fred”, which will return “hello Fred”. When the response is received from the server, the deferred object will be fulfilled, and the alert will give the friendly response.

In Dojo 1.2, we have provided “namespaced” service resolution, so this method would be available as services.hello.sayHello rather than services["hello.sayHello"]:

var deferred = services.hello.sayHello("Fred");

jabsorb is an easy to use server framework for handling remote method calls to Java objects using JSON-RPC. With Dojo’s pluggable service architecture, it is simple to connect Dojo to jabsorb to interact with existing Java code. jabsorb is one of a growing number of server frameworks that integrates well with Dojo.

JSON Referencing in Dojo

Tue, 06/17/2008 - 07:04

references.png
Non-trivial data often has structures that cannot be well-defined with normal linear, acyclic data descriptions. Data that consists of cycles, many-to-one relationships, and non-local references often requires custom strategies for serialization and transfer of the data over JSON. Dojo 1.2 has added support for JSON referencing with the dojox.json.ref module. This module provides support for several forms of referencing including circular, multiple, inter-message, and lazy referencing using id, path, and combined referencing forms.

These references can be automatically generated on serialization and resolved on deserialization. JSON referencing is designed to decouple the topology of data structures from the meaning of the data structures in a way that is consistent with runtime object models of modern OO languages (foremost JavaScript). Separating graph connectedness concerns allows referencing and dereferencing to be handled by dojox.json.ref with minimal or no knowledge of and integration with higher level JSON consumers and producers, and permits more extensive JavaScript serialization capabilities.

dojox.json.ref API

First we will look at how to use the new module to serialize JavaScript objects. Perhaps the simplest data structure that requires referencing is a circular reference. We can easily create an object with a circular reference in JavaScript:

var obj = {};
obj.me = obj;

Most JSON libraries cannot serialize such an object, and will generally result in a stack overflow error. However, we can serialize this with dojox.json.ref:

var jsonWithCircularRef = dojox.json.ref.toJson(obj);

And de-serialize the JSON back to an object:

obj = dojox.json.ref.fromJson(jsonWithCircularRef);
obj.me == obj // -> true, the reproduced object will
	//have a property named "me" with a value of itself.

Another common data topology is multiple references:

var me = {
	name:"Kris",
	father:{name:"Bill"},
	mother:{name:"Karen"}};
me.father.wife = me.mother;
var jsonMe = dojox.json.ref.toJson(me); // serialize me
var newMe = dojox.json.ref.fromJson(jsonMe); // de-serialize me
newMe.father.wife == newMe.mother // -> true, the reproduced object will
			// properly reproduce both references to the same object.
JSON Referencing Convention

Now we will look at how to create JSON with references that can be parsed and resolved by dojox.json.ref. Th