Recently I wrote a developerWorks article about how to develop custom editor for IBM Case Manager 5.2.1 properties view. One small(?) problem is that the article is written in Japanese... However, an eclipse plugin, which comes with the article, is English version. It should work on Eclipse Juno, Kepler, or Luna + IBM Java 6 or 7. It allows you to create an IBM Case Manager 5.2 custom page widget project or an IBM Case Manager 5.2.1 custom properties view editor project. Simple setup / usage instruction is in README.txt file in the zip file. The zip file can be downloaded from https://ibm.biz/BdEgrW (If you can read Japanese, the article is here https://ibm.biz/BdEgsc )

In the tests folder of Dojo Mobile 1.7, there was a test file called test_screen-size-aware.html, which was an example of user interface that transforms its layout according to the screen size. If it is opened on a relatively larger screen (i.e. tables), two split views are displayed.

If it is opened on a smaller screen (i.e. smartphones), only one list view is displayed at a time.

If you look into test_screen-size-aware.html, you'll see a bunch of inline JavaScript code in the html. At startup time, dojox.mobile detects the current screen size, and publishes either of the following topics.

"/dojox/mobile/screenSize/tablet"
"/dojox/mobile/screenSize/phone"

The idea is to subscribe these topics and programmatically change the dom structure of the UI layout. If you are using a desktop browser, you can see how the layout changes by resizing the browser window.

The experimental ScreenSizeAware widget in the dojo-1.8 trunk is a module that was created by componentizing the code in test_screen-size-aware.html. It assumes your application has the following structure.

All you need to do is to require dojox.mobile.ScreenSizeAware and place the following tag somewhere in your application.

<span dojoType="dojox.mobile.ScreenSizeAware"></span>

Then the ScreenSizeAware widget magically transforms the UI layout according to the current screen size. No inline JavaScript code is necessary in your application html file.

There is another way to apply ScreenSizeAware to your application. In the above example, instead of placing the <span> tag, you can use the ScreenSizeAware property of FixedSplitter as below. In this case, you do not need to explicitly require dojox.mobile.ScreenSizeAware, because it is dynamically loaded by FixedSplitter.

You can also specify a class name of a screen-size-aware module with the screenSizeAwareClass property, whose default value is "dojox/mobile/ScreenSizeAware".

Either ways give the same result. However, from an authoring tool perspective, the <span> tag above is an invisible component, i.e. it has no visible UI. In general, handling invisible components on a visual editing tool could be a bit tricky. In such case, the screenSizeAware property may be more easier to handle. That's basically the reason why there are two ways of enabling ScreenSizeAware.

The current implementation of ScreenSizeAware is tied to the dom structure shown above. Perhaps we should investigate if there are other UI layout patterns and make it more flexible and extensible.

Note that this is about what is in the dojotoolkit trunk for dojo-1.8, there's no guarantee that it will be in the final release.

There are some API changes in dojox.mobile 1.8. The dojox.mobile.migrationAssist module was introduced to let the users know what need to be done for their dojox.mobile 1.6 or 1.7 based applications.

What is migrationAssist?

The migrationAssist is a dojo module that helps you migrate your dojox.mobile-1.6/1.7 applications to 1.8. To enable migrationAssist, all you need to do is require this module as shown in the examples below.

If you application uses deprecated or no longer available functions, this module detects them and displays messages in the browser console.

Also, it tries to dynamically fix them as much as possible so that the target application can work somehow. For example, dojox.mobile.View is no longer a container-type widget, and thus you cannot use addChild to add a child widget to View. This module dynamically inserts the addChild method into View in case the application is using it.

Note, however, that the purpose of migrationAssist is not to run the older applications as they are, but to assist migration.

Changes from 1.6/1.7 to 1.8

Carousel

Carousel has no backward compatibility, since it was experimental in 1.7.
The new Carousel supports dojo.store instead of dojo.data.

Heading

Heading is no longer a container.

IconItem

IconItem is no longer a container.

FixedSplitter

FixedSplitter.css is no longer in the themes/common folder.
It is in a device theme folder. (e.g. themes/iphone/FixedSplitter.css)

FlippableView

FlippableView was deprecated in 1.7, and removed in 1.8. Use SwapView instead.

ListItem

ListItem is no longer a container.

The sync property is no longer supported. It always behaves in the async manner.

The btnClass property is no longer supported. Use rightIcon instead.

The btnClass2 property is no longer supported. Use rightIcon2 instead.

RoundRect

RoundRect is no longer a container.

SpinWheel

SpinWheel.css is no longer in the themes/common folder.
It is in a device theme folder. (e.g. themes/iphone/SpinWheel.css)

SpinWheelSlot

getValue() is no longer supported. Use get("value") instead.

setValue() is no longer supported. Use set("value", newValue) instead.

Switch

When you place it in a ListItem, class="mblItemSwitch" is no longer necessary.

View

View is no longer a container.

TabBar

In 1.7 or older, barType="segmentedControl" produced different UI according to the
current theme. In the iphone theme, it was a segmented control. But in other themes,
it was tabs with or without icons. In 1.8, however, barType="segmentedControl"
always produces a segmented control UI regardless of the current theme.
If you still need the old behavior,

barType:{"iphone_theme":"segmentedControl","*":"tallTab"}

should produce a segmented control for the iphone theme, and a tall tab bar for
the other themes. You need to use deviceTheme.js to specify barType that way.
Also, if you want to hide tab icons on the segmented control in the iphone theme,
you could apply css like this:

stopParser

To support dojox.mvc, the stopParser feature was added to dojox.mobile.parser. If a widget has the stopParser flag, the parser stops parsing its child widgets. dojo.parser has this capability, but dojox.mobile.parser didn't have it to keep the code size minimum.

New data-dojo-type syntax

dojox.mobile.parser now accepts the new data-dojo-type syntax like data-dojo-type="dijit/form/Button".

Dojo Mobile 1.7 has a simple bookmarkable functionality based on dojo.hash. If you require dojo.hash in your application, the function is enabled. If a transition destination value (the value of the moveTo property) has a hash sign ('#') before the id (e.g. #view1), the view transition updates the hash in the browser URL so that the user can bookmark the destination view. Also, in this case, the user can use the browser's back/forward button to navigate through the views in the browser history.

As you can imagine, this can support only a simple navigation between the top level sibling views. It cannot support more complex UI layout scenarios such as nested views, splitted views, or dynamically created views, because the hash fragment value is only a single identifier.

To mitigate this limitation, the bookmarkable function has been enhanced to be able to manage multiple view state. The new bookmarkable is enabled if you require dojox.mobile.bookmarkable. When you made a view transition, dojox.mobile searches for all the selected views in the page, and sets a new fragment id that consists of a comma-separated list of the found views to the browser's current URL. When you move back to this page, dojox.mobile sees the list of selected views and restore the selected state. Note that 'selected' does not necessarily mean the view is 'visible'. For example, there may be a currently hidden view that has child views. One of the child views must be 'selected', but it is not 'visible' since its parent is currently hidden. Sibling views always have one and only one selected view.

With this enhancement, the bookmarkable function should be able to handle cases where views are nested or split. However, it cannot support dynamic views created by the ListItem and other _ItemBase-based item's url property. Even if the created view's IDs are pushed to the browser URL's fragment id, dojox.mobile can never know URL of the external content from its view id.

Another small enhancement is that if you set mblForceBookmarkable:true to djConfig, and require dojox.mobile.bookmarkable, all the view transitions are stored in the browser history regardless of whether the value of moveTo has '#' prefix or not.

You may want to connect to onorientationchange or onresize to call resize() so that the variable pane fills the available remaining space even after the orientation is changed or the browser window is resized.

Changing the UI layout depending on orientation

By combining the above two new enhancements together, you can change the UI layout depending on the device orientation. In the following example, if the device orientation is portrait, the window is split vertically. If the orientation is then changed to landscape, the window is split horizontally.

Dojo Mobile 1.7 has ability to load external view content and create a new target view dynamically. The _ItemBase class, a base class of ListItem, IconItem, etc., has the "url" property, which allows you to specify a URL of external data that will be a new view content after making a view transition. Two data formats, html and JSON, are supported, and their content handlers are implemented in dojox/mobile/ViewController. Unfortunately, however, those handlers are not customizable. The user has no choice but to use html fragment or a particular JSON format.

To allow the user to customize data handlers, ViewContoller is being refactored to modularize the handlers, and now the data handlers are structured as follows:

The data handlers consist of the following components:

DataHandler

FileTypeMap

DataSource

ContentTypeMap

ContentHandler

All of the above components are loaded dynamically at run-time. You do not need to explicitly requre them in your application. If your application does not use the "url" property of _ItemBase, they will never be loaded.

The DataHandler Class

DataHandler provides an interface between content data and content handlers. DataHandler calls DataSource to retrieve data, and calls ContentHandler to parse the data and create a new view. DataHandler is called from ViewController.

The FileTypeMap Interface

FileTypeMap provides a map that can be used to determine content type by the URL of the content data.

The DataSource Interface

DataSource encapsulates access to the view content data. It is called from DataHandler.

The ContentTypeMap Class

ContentTypeMap provides a map that can be used to determine content handler class by a content type.

The ContentHandler Interface

ContentHandler parses the given data, and creates a new view with the data at the specified position.

The Overall Control-Flow

ViewController accesses FileTypeMap to get a content type (e.g. "html" or "json") by a file name suffix.

ViewController creates a DataSource with the url property.

ViewController creates DataHandler with the created DataSource.

ViewController calls DataHandler.processData() with the content type.

DataHandler accesses ContentTypeMap to get a ContentHandler class name by the given content type.

DataHandler calls DataSource.getData().

DataSource gets external content.

DataHandler creates the ContentHandler class.

DataHandler calls ContentHandler.parse() to parse the content.

ContentHandler.parse() parses the content.

ContentHandler.parse() creates a new view.

DataHandler calls a callback that is defined in ViewController.

The callback makes a view transition to the new view.

How to replace DataHandler

The default DataHandler class name is "dojox/mobile/dh/DataHandler", which is defined as the dataHandlerClass property in ViewController. It can be overridden by adding the dataHandlerClass property to transitionOptions. Below is an example of specifying your own DataHandler in ListItem.

How to replace FileTypeMap

The default FileTypeMap class name is "dojox/mobile/dh/SuffixFileTypeMap", which is defined as the fileTypeMapClass property in ViewController. It can be overridden by adding the fileTypeMapClass property to transitionOptions. Below is an example of specifying your own FileTypeMap in ListItem.

How to replace DataSource

The default DataSource class name is "dojox/mobile/dh/UrlDataSource", which is defined as the dataSourceClass property in ViewController. It can be overridden by adding the dataSourceClass property to transitionOptions. Below is an example of specifying your own DataSource in ListItem.

How to replace ContentTypeMap

Usually, ContentTypeMap does not need to be replaced. If you have your own DataHandler, however, you can have your own ContentTypeMap as well, since DataHandler has dependency on ContentTypeMap.

How to override ContentType

Usually, content type is determined by looking up the matching entry in a ContentTypeMap. If you want to skip the look-up, and explicitly specify a particular content type, you can give the contentType property to transitionOptions. Below is an example of specifying a content type in ListItem.

How to register ContentType

Content type is determined by a FileTypeMap. For example, SuffixFileTypeMap uses the file name suffix to determine content type. For SuffixFileTypeMap, you can register "suffix to content type" entries into the map. SuffixFileTypeMap is a singleton module. You can simply get its module return value and use the add() method to register your entries.

If a given suffix does not match any of the entries in the map, ViewController uses "html" as the default content type.

How to register ContentHandler

Which ContentHandler to use is managed by ContentTypeMap. In your application, you can register "content type to content handler class" entries into the map. ContentTypeMap is a singleton module. You can simply get its module return value and use the add() method to register your entries.

Lazy-loading of widget code

In Dojo Mobile 1.7, all the widget code used in external content had to be loaded and available before creating an external view. Both HtmlContentHandler and JsonContentHandler now support dynamic loading of necessary widget code. You no longer have to explicitly require widget code that will be used in external views.

Script execution

The HtmlScriptContentHandler handler allows you to have <script> tags in an external content. If you use relative path, such as src="hello.js", the path is relative from your application's main html page. You can place <script> tags anywhere you like, since all the <script> blocks are removed from html text before creating DOM elements.

You can change the default content handler for html to HtmlScriptContentHandler as shown in the example below.

dojox.mobile.View inherits from dijit._Container, but some people pointed out that it should not be a container-type widget. This is because container-type dojo widget requires all the children to be dojo widgets. But View is often used to place plain text or plain html fragments on it. So, to allow such plain children, we are changing View to a non-container widget.

Even if View becomes a non-container widget, you can still have child dojo widgets on it. One thing we need to be aware of, however, is that we no longer can use addChild/removeChild to manage child widgets, since they are implemented in dijit._Container. You can instead use placeAt to add a widget to a View. For example, the code below

In addition to dojox.mobile.ContentPane, two very simple pane widgets, dojox.mobile.Container and dojox.mobile.Pane, were added to Dojo Mobile 1.8.

dojox.mobile.Pane

dojox.mobile.Pane is a <div> wrapper widget, which does NOT inherit from dijit._Container. It doesn't do anything but to call resize() of each child widget. The entire implementation code is as follows:

Because it does not inherit from dijit._Container, you cannot use addChild() or removeChild() to manage child widgets, but you can place any html fragment in it. So, if your content is an inline html fragment, which may or may not include dojo widgets, you can use dojox.mobile.Pane.

dojox.mobile.Container

dojox.mobile.Container is a container-type widget, which inherits from dojox.mobile.Pane and dijit._Container. dojox.mobile.FixedSplitterPane, which was now deprecated, had the same functionality. The entire implementation code is as follows:

In general, dojo's container widgets that inherit from dijit._Container take only dojo widgets as children. So, if your content consists of ONLY dojo widgets, and does not contain html fragment (plain text and/or html tags), you can use dojox.mobile.Container. You can use addChild() and removeChild() to manage child widgets.

ContentPane

dojox.mobile.ContentPane is a pane widget, which does NOT inherit from dijit._Container. It has ability to load external content in it using dojo/_base/xhr. So, if your content is an external html fragment, which may or may not include dojo widgets, you can use dojox.mobile.ContentPane. This widget can handle inline html fragment as well, but in that case, dojox.mobile.Pane should be fine. This widget is much smaller than dijit.layout.ContentPane, though it has only basic fuctionality.

Ordinary Widget

ProgressIndicator became an ordinary widget that inherits from _WidgetBase. That means, technically, you can instantiate it declaratively as well as programmatically. As shown below, if you specify startSpinning="true", it starts spinning at startup. You can of course start it programmatically by calling the start() method afterward.

Position Customizable

By default, ProgressIndicator is absolute positioned and center aligned, since it was originally intended to be used as an indicator for the entire view updates. If you specify center="false", however, the position becomes relative, and center-align is not applied, and thus it behaves like ordinary div nodes.

You should now be able to use ProgressIndicator in various places. For example, the example below displays a ProgressIndicator on a Heading.

The onClick handler of Dojo Mobile widgets (e.g. dojox.mobile.ListItem) has been changed a bit recently. Now the default action is in _onClick(), and onClick is an empty stub function for user defined function. _onClick() is directly connected to the onclick event handler of a dom node, and it calls onClick(). If onClick() returns false, it skips the default action. The rough outline is as follows:

This way, you can add your custom click action easily without subclassing a widget. For example, you can define your custom click handler, and set it to ListItem through data-dojo-props as shown below. If you click on the ListItem, you will see an alert() dialog first, and then a view transition (=default action) will occur.

This may be a bit deep, but the result is not what you would expect. You will see the alert() dialog twice. One is from the _onClick handler, another is from the dom node's native onclick handler. This happens with both dojo.parser and dojox.mobile.parser. Currently this issue is under discussion. It may be solved soon, or may be not.

If your custom handler returns false as below, after you see the alert() dialog, no transition occurs, since the default action is skipped.

dojox.mobile.deviceTheme is an automatic device theme (iphone, android, blackberry, or custom) loader, which was introduced in dojo-1.7. It programmatically loads theme css files according to the browser User Agent string. It is useful when you want to automatically apply a device-specific theme to your application rather than hard-coding <link> tags (or @import rules) to load a particular theme in your application.

Usage is quite simple. All you need to do is just to require dojox.mobile.deviceTheme with either dojo.require() or the require() API. While it is being evaluated, deviceTheme embeds the <link> tags into the <head> section. By default, it tries to load an all-in-one theme file, such as themes/iphone/iphone.css.

One important thing you should be aware of here is that loading of the css files is performed asynchronously by the browser after deviceTheme embeds the <link> tags. In most cases, it is done after loading of dojo module files (*.js). That means, dojo widget initialization may be performed without necessary css files applied, and after the initialization, finally styles are applied to the constructed widget dom tree. This won't be a problem as long as the layout calculation of the widget is performed by the browser. However, if the initialization logic accesses dom node dimensions to programmatically calculate the layout based on them like the following example, you get wrong layout because you can't get expected node dimensions without styles applied.

One idea is to require deviceTheme first just like the sample code above. You may get a better result with it, but only when you are lucky. Unfortunately, this can't be a general solution. A better workaround would be to have a separate <script> block as below.

As far as I tested, this brings much better result. If you have a layout problem that comes from deviceTheme, I think it's worth trying this technique.

However, we still can't guarantee that all the theme css files are loaded prior to dojo module initialization. So, a new enhancement that has been added recently to the dojo-1.8 trunk is to be able to load without dojo. That means you can load deviceTheme.js with a <scrip> tag BEFORE loading of dojo.js as below.

In this case, if the detected device is iPhone for example, these files will be loaded by deviceTheme.

dojox/mobile/themes/iphone/base.css

dojox/mobile/themes/iphone/TabBar.css

One drawback, however, is that deviceTheme.js cannot be included in a build, if you load it with a script tag.

Incidentally, now the updated deviceTheme.js can be loaded without dojo, but it can still be used as a dojo module, and can be loaded with dojo.require() or require() as before.

One more important thing I would like to add is easier customization. Sometimes you may want to override the given styles in your html file like this:

<style>.mblButton { font-size: 16px;}</style>

With dojo-1.7 deviceTheme, unfortunately this is ignored and has no effects because <link> tags are appended as last children of the <head> element, and thus they win your custom styles. The new deviceTheme prepends <link> tags to the <head> to solve this issue.

Note that this is about what is in the dojotoolkit trunk for dojo-1.8, there's no guarantee that it will be in the final release.