Adobe AIR Dojo Toolkit Compatibility Project - Bugs

4 downloads 799 Views 79KB Size Report
svn co http://svn.dojotoolkit.org/dojo/view/anon/all/trunk dojo. Dojo's Package System. At the heart of the Dojo Toolkit is a package system that allows code to be ...
Adobe AIR Dojo Toolkit Compatibility Project Dojo Toolkit in the AIR Runtime The goal of this project is to identify and resolve any issues with the Dojo Toolkit running in the AIR application sandbox. There are several features that need to work within the application sandbox including: !

dojo.require() pre-onload

!

dojo.require() post-onload

!

dojo.addOnLoad()

!

dojo.query()

!

dojo.parser

!

dojo.fx

!

Dijit widget system

!

AIR dojox.storage provider

Creating the Environment Start by installed the Adobe AIR runtime. Then installed the Adobe AIR SDK. Inside the SDK folder is a bin folder containing the adl command used to execute our AIR application. By adding this bin folder to your path, you'll be able to execute the adl command from anywhere. Start by creating an empty folder. Next we need to get the latest Dojo code from Dojo's public Subversion repository. svn co http://svn.dojotoolkit.org/dojo/view/anon/all/trunk dojo

Dojo's Package System At the heart of the Dojo Toolkit is a package system that allows code to be loaded on demand. There are two loader mechanisms in Dojo: a default loader and a cross-domain (xdomain) loader. The default loader uses XmlHttpRequest (XHR) to retrieve the code. Once the code is downloaded, it is evaluated using eval(). This method is synchronous, so when a package is pulled down, it's dependencies are also pulled down and executed. The xdomain loader uses script tags to retrieve the code. This eliminates the need for having to evaluate the code after downloading. This method is asynchronous, so the xdomain loader has additional functionality for checking when the script has completely downloaded and to defer the declaration of the package until it's dependencies have been loaded.

debugAtAllCosts Dojo has a configuration parameter called “debugAtAllCosts” which forces the use of the xdomain loader. This becomes useful when debugging applications since the file's contents are not eval()'d, thus preventing the Javascript runtime environment from being confused which line an error occurred.

This feature does not work properly regardless of sandbox or loader. It is not required for developing Dojo applications.

dojo.require() Using Default Loader in Application Sandbox Pre-onload The default loader uses XHR to read in the contents of a package, then evaluates it. This functionality works as expected. Post-onload When the default loader gets the contents of a package, it evaluates the contents. Because eval() is prohibited post-onload, dojo.require() cannot function post-onload. If dojo.require() is absolutely necessary post-onload, the xdomain loader is your only option. Otherwise simply define all your dojo.require()'s before or during onload which is analogous to other programming languages which require you to define all external code dependencies via an import/include at the beginning of the code file.

dojo.require() Using Default Loader in Non-Application Sandbox The default loader functions properly both pre-onload and post-onload.

dojo.require() Using Xdomain Loader In order to use xdomain loader, you must perform a custom build. Before running a custom build, there is a quick change that needs to be made to the xdomain loader in the file: dojo/_base/_loader/loader_xd.js There is a call to setInterval() that must be changed from: this._xdTimer = setInterval("dojo._xdWatchInFlight();", 100); to var _self = this; this._xdTimer = setInterval(function(){dojo._xdWatchInFlight.apply(_self);}, 100); Additionally, the _loadUri() function needs to strip the app:/ protocol from the beginning of the URI since the app:/ protocol is unavailable in the non-application sandbox. if (dojo.isAIR) { xdUri = xdUri.replace("app:/", "/"); } Next you need to define a build profile which tells the build system which files to bundle in the build. We are not concerned with combining packages into a single file as much as we are in the xdomain loader and generation of .xd versions of each package. The difference in the .xd files is the package's contents are wrapped in a function call that allows the package's execution to be deferred until it's dependencies have been loaded. A build profile may look like the following: // my-build-profile.js dependencies = { layers: [ {

},

name: "dojo.js", dependencies: [ "dojo.parser", "dijit.dijit" ]

], prefixes: [ [ "dijit", "../dijit" ], [ "dojox", "../dojox" ] ] } To run the build, execute the following from the command line: cd dojo/util/buildscripts ./build.sh profileFile=../../../my-build-profile.js action=clean,release releaseDir=../../../ releaseName=MyBuild loader=xdomain xdDojoPath=app:/MyBuild Now you can reference the build in your code by including the following: dojo.require() will work pre-onload and post-onload.

dojo.addOnLoad() dojo.addOnLoad() registers callback functions to be executed when the page loads. The default loader properly executes the callback functions before the page's onload event is fired. The xdomain loader on the other hand fires the onload callbacks after the body's onload has fired. This causes problems for the xdomain loader in the application sandbox if parseOnLoad is enabled since Dojo will be unable to parse and eval() the data post-onload.

dojo.query() Dojo has a query function that is used to search the DOM for nodes. The default query function works for simple queries such as “div” or “li > a”. However, the default query function is unable to find nodes based on a specific attribute. For example, the default query function is unable to locate the element Click Me using the query “[dojoType]”. To fix this, the query function must be changed to use the step query function in the file: dojo/_base/query.js Locate and uncomment the line that says: _getQueryFunc = getStepQueryFunc;

dojo.fx Dojo's FX library works as expected in both application and non-application sandboxes as well as with both the default and xdomain loaders.

dojo.parser Dojo's parser scans the DOM using dojo.query() for declarative markup. If markup is found, it is evaluated. The parser can either be invoked automatically when the page loads or manually.

The parser can be executed onload by specifying the following in the djConfig: The parser will then scan the DOM for declarations such as: Click me! dojo.declare("tests.parser.SaySomething", null, { sayWhat: "", constructor: function(args, node){ dojo.mixin(this, args); }, sayIt: function() { alert(this.sayWhat); } });
alert(this.sayWhat.split("").reverse().join("")); alert("sayIt() was called!");
The parser works in both application and non-application sandboxes as well as with the default loader. When using the xdomain loader, the parser works as expected in the non-application sandbox. However, the xdomain loader fails in the application sandbox because the parser cannot eval() post-onload.

Dijit Widget System Dijit widgets work both declaratively and programatically using the both the default loader in both application and non-application sandboxes. Dijit does not work properly with the xdomain loader since parser doesn't fire correctly.

AIR dojox.storage Providers There are 3 new storage providers that leverage the AIR's API: ! ! !

dojox.storage.AirFileStorageProvider dojox.storage.AirDBStorageProvider dojox.storage.AirEncryptedLocalStorageProvider

When using a the xdomain loader, dojox.storage is unavailable until onload unless dojox.storage and the providers you wish to use are in the xdomain build. These 3 AIR specific storage providers are only available in the application sandbox. It would take a large amount of abstraction to each provider with respect to the AIR API calls plus a significant sized snippet of code in the parent window to perform the storage operation. AirFileStorageProvider The AirFileStorageProvider store the data in flat files in the app-storage directory. For example, a key of “MyKey”, value of “Hello World!”, and namespace of “MyNamespace” would create the file app-storage:/__DOJO_STORAGE/MyNamespace/MyKey which contains the text “Hello World!”.

This storage provider allows for large amounts of data to be stored. Not only can strings be stored, but also objects thanks to AIR's serialize/de-serialize functionality. On the downside, data is not encrypted on disk. It would be trivial however to encrypt the information using dojox.crypto before storing the data. AirDBStorageProvider The AirDBStorageProvider leverage's AIR's embedded database. When the provider is initialized, a database file is created in the app-storage directory and the Dojo storage table is created. The table holds the namespace, key, and value. This provider is similar to the AirFileStorageProvider in which it can store large amounts, but it cannot store serialized objects because there is no way to de-serialize them due to eval() being unavailable post-onload. The database file is not encrypted, but you could encrypted the data using dojo.crypto prior to storing the data. One advantage of the AirDBStorageProvider is there is only one file written to disk whereas the AirFileStorageProvider writes a file for each key/value. AirEncryptedLocalStorageProvider The AirEncryptedLocalStorageProvider uses AIR's encrypted local data store functions. Data, such as passwords, will be encrypted when being stored and decrypted when being retrieved. Similar to the AirEncryptedLocalStorageProvider, objects cannot be stored because they cannot be de-serialized with an eval(). One limitation of the AIR's encrypted local data store is it does not provide a way to enumerate keys. To solve this, the AirEncryptedLocalStorageProvider creates a registry using AIR's encrypted local data store to track the namespaces and keys.

Default vs. Xdomain Loader The default loader cannot dojo.require() post-onload, however the xdomain loader can. The xdomain loader requires a custom build, which in turn requires Java runtime environment installed. The default loader does not require a build, but would work if it was a custom build. If you are using the xdomain loader, unless the package you are requiring is already in the build, you cannot reliably access it until onload is fired. There may be caching issues with the xdomain loader pulling in code that not already in the build on subsequent requests, which causes out of order execution of code before dependencies have loaded. It is recommended to bundle all needed packages into the xdomain build. The xdomain loader fires dojo.addOnLoad() callbacks after onload which causes Dojo's parser in the application sandbox to fail because it cannot eval() post onload.

Application vs. Non-Application Sandbox The non-application sandbox does not recognize the app-storage:/ and app:/ protocols. Due to the lack of eval() post-onload, the xdomain loader doesn't work in the application sandbox when the parser is used.

Known Issues The following are limitations of running Dojo in the Adobe AIR environment:

!

Only use declarative syntax when you can guarantee its evaluation will be performed preonload or during onload. Avoid using to define functionality that hooks into widget. Rather define the function using the traditional method, then connect to the hook you are interested after the widget has been created.

Summary The changes required to integrate Dojo into the AIR runtime are fairly minimal. There was no noticeable performance issues when not using a build. AIR is very fast at loading scripts and other resources. For most projects, it will be the easiest to use the default loader within the application sandbox provided you could declare all dojo.require()'s before or during onload.