Category: "Dojo"

AJAX Interaction Notes - dojo

Notes on using a dojo/RIA web interface to launch background (server-side) scripts.

  • File uploads can run under FF and IE with dojo.io.iframe.send, and it is a nice interface. There is another post on this blog, with sample code.
  • Synchronizing background server tasks with client launch and monitor requires the client to be able to identify script failure to execute, execute reporting whether the operation was successful or not.
  • Two-phase, asynchronous execution can be made much more secure by storing the second-phase action on the server. Thus, if the first-phase executes correctly, no information is required from the client to continue the operation. All data submitted can be disregarded.
  • Success or Error can be indicated with HTTP headers in cases where no data is required on the response.
  • Client-side redirects can be used to transition to the next phase after a successful run of one phase.
  • User should be alerted that scripts initiated through the web interface cannot be stopped (unless a mechanism is provided).
  • User should be able to return to a previously initiated scripts and view the output.
  • Background script output should be delivered to the initiator through an email. User should be able to suppress email.
  • Background scripts should deliver output in text only.
  • Server must be responsible for state management. Server must ensure background scripts do not collide with each other, or the data, and must provide an interface that allows the client to determine if administration should be readonly or prohibited when specific scripts are executing.
  • Server must be responsible for scheduling resource intensive tasks to prevent service interruptions.
  • An object is an excellent way to allow a single dialog box to submit data to different scripts without writing additional code. The object is then assigned to the AJAX content property.
  • Server must have intelligence to adjust state of client, for example hiding informational messages after termination, enabling buttons to allow continuation, and providing alerts for errors.
  • Initial error reporting can be limited to ‘Error’, a simple indication that something went wrong. After testing, common errors should be delivered with additional explanatory text.
  • Balance distribution of client side code. Although it is nice to split a page into many components that can stand alone, this increases the number of HTTP requests which has performance impacts. Building the javascript into a single file is one solution, bundling related code together is another. Templates should include only the elements that require template processing. Large sections of javascript should be removed. Use caching to improve performance.
  • Break server side code into components such that only the code required to execute is read. This doesn’t always work out perfectly, and there are impacts to opening alot of files as well, but the server impacts are less serious than the client side, because there is no data transfer.
  • Put some timing code into the application so you can see where the time goes. Use YSlow to improve page delivery performance.
  • Use FireBug to monitor traffic between client and server.
  • Use a log file to write out debugging information. Check the error_log frequently. Use echo, var_dump, and exit. Build graceful error reporting into the application from the beginning. This will make debugging much easier. Log all errors. Put a switch in to allow debug displays to be suppressed for production systems.
  • Use a tee (*nix command) to pipe script output to a file and into mail.
  • Document the entire process and describe it to the appropriate people. This will ensure you understand what is happening and that it is what is supposed to be done. Be ready to change.
  • Write a good test plan and use it.
  • Be mindful of security. Validate all inputs. Escape all command line parameters that are user submitted. Check for access privileges for all requests, at all times. Avoid divulging application details or data.
  • Copy script output to a temporary access area, do not grant access further into the server for output display. Identify script output with the script name and session id.
  • Have Apache execute as apache:apache, or nobody:nobody, and allow only those scripts that should be executed through the web to have execute permissions for that user.
  • Be persistent and creative.

dojo Fisheye Example

dojo’s Fisheye widget is fun. The link above is to a demo of the Fisheye widget.

Notes:



<div dojoType="dojox.widget.FisheyeList"
itemWidth="50" itemHeight="50"
itemMaxWidth="200" itemMaxHeight="200"
orientation="horizontal"
effectUnits="2"
itemPadding="10"
attachEdge="top"
labelEdge="bottom"
conservativeTrigger="false"
>


itemWidth and Height refer to the images when they are displayed initially, before the mouse hovers over them. You can use them to size the images as they are displayed.
itemMaxWidth and MaxHeight refer to the images when they are active or the mouse is hovering over them.

For best results, the images should be MaxWidth and MaxHeight dimensions, or larger. Images usually look better after they have been reduced, rather than expanding a small image. It is also easier to use square images, and make all the images the same size.

Check the CSS carefully if you find your list wrapping down to the next line. I found using min-width was helpful.

Credit/Thanks to:

http://dojotoolkit.org/demos/fisheye-demo
http://www.ajaxdaddy.com/demo-dojo-fisheye.html

milliseconds Add up in the Browser

dojo’s dynamic inclusion of the logic required to render pages is great. The line dojo.require("widget"), ensures that the code required to run “widget” will be ready to run.

There is a hidden cost to this - the underlying logic and requests to get the code from the server.

On a complex page that has a lot of widgets (more than 50% of the dijit widgets offered), it is worth considering the following tags:


<script type="text/javascript" src="dojo/dijit/dijit.js"></script>
<script type="text/javascript" src="dojo/dijit/dijit-all.js"></script>

Although dijit-all is large, it is compressed, and it has all the widgets. A single request can replace 50 or more requests. Each request has an overhead of about 15ms, even if the javascript is cached in the browser. It is definitely worth running a test with Firebug to see if you can realize any performance gains with this strategy.

The ideal solution is a custom build, but you can’t always solve problems the “best” way. Sourcing dijit.js and dijit-all.js, using a loading .gif, and configuring caching carefully reduced page load time to 1/3 of the initial value, and provided a more graceful load process.

dojo dijit Tri-State Checkbox Widget

The link above is a demonstration of a dojo dijit Tri-State Checkbox Widget. It includes a nice button interface to test the properties, methods, and events of the widget, some documentation, and a link so you can download the widget and the test code.

It has been integrated into a complex application and is working well.

Interesting notes on this widget:

  • Spent time exploring how to indicate an indeterminate state for a checkbox. The de facto standard is a small box within the box, so that is what is implemented.
  • Widget is actually a text input that can contain the values on, off, or indeterminate.
  • Used a blank.gif to create the space in the focus node.
  • Value can be set by using a boolean (true=on, false=off), number (0=off, 1=on, 2=indeterminate), or string (off,on,indeterminate)
  • Checked maps to on, unchecked is considered off
  • Value is sent to the server regardless of input state. This is different than a traditional checkbox, where the value is only sent if the checkbox is checked.
  • Tried to avoid duplicating effort, used inheritance as much as possible.
  • Realized that even a ’simple’ widget involves significant complexity, and thorough testing is important prior to integration into pages.
  • Discovered that building a widget for dojo 1 does not build a widget for 0.9 - had to build a second copy for 0.9 to integrate into an older application.
  • Appreciated the dojo / dijit architecture, it made adding the widget a nice, efficient process.

Generated profile.js for dojo Builds

To generate a profile.js file for dojo builds, you can use the following command string:

grep dojo.require * | sed “s/dojo\.require\ *(\ *\([\’\"][^\)]*\)).*/\1/” | awk ‘{l=length($0);if (FNR!=1) printf “\n,%s",$0; else printf “%s",$0;}’ > middle

Sample output:

"dojo.parser"
,"dijit.layout.ContentPane"
,"dijit.layout.TabContainer"
,"dijit.form.Button"
,"dijit.ColorPalette"

If this ouput is prefixed with (name the file top):

dependencies ={
    layers:  [
        {
        name: "mydojo.js",
        dependencies: [

and postfixed with (name the file bottom):

        ]
        }
    ],
    prefixes: [
        [ "dijit", "../dijit" ],
        [ "dojox", "../dojox" ]
    ]
};

It will yield a properly formatted profile.js file.

Use cat to assemble it, like so:

cat top middle bottom

Note that dojo.parser and other core elements don’t have to be specified, but it is simpler to leave them in.