The dojo.moj.oe

As I mentioned in the dojo.moj.oe blog entry, I have every intention of fully tutorial-izing the demo. To continue from where we left off with the topic cookie and simultaneously start a series of small tutorials, I present to you: Mojo part I

We’ll be going step-by-step, though jumping directly into the javascript. You can view the source html of the demo to see how it’s setup, and go from there. It is ultimately:

<html>
<head>
    <title>Dojo Moj.oe</title>
    <link rel="stylesheet" href="mojo.css" />
</head>
<body>
    <div id="header"><img /></div>
    <div id="container"><!-- circles in here --></div>
    <div id="footer"><!-- text stuff --></div>
    <div><!-- other html hidden by css, used later --></div>
    <script src="js/dojotoolkit/dojo/dojo.js" type="text/javascript"></script>
    <script src="js/dojotoolkit/mojo/_base.js" type="text/javascript"></script>
</body>
</html>

There is very little HTML magic going on. It’s lots of simple markup, and some CSS to set colors
and whatnot. We’ll go into detail on those aspects too. In our #container div, we have other divs, each representing one of the circle nodes. The HTML for each of the circles looks something like:

     <div class="circleNode" id="box1">
           <img class="boxUnderlay" src="circle.png" />
           <h1 class="handle">Title</h1>
           <p>Lorem ipsum dolor.</p>
     </div>

In the mojo, there are four of these divs. each with a different purpose. This is enough to get through this portion of our tutorial, so we’ll move on.

We’ll be creating the mojo/_base.js file included in our html. Start by creating the file, and setting up some basic dojo calls. Because our mojo/ folder is a sibling to dojo/ and dijit/, it’s namespacing is automatic (meaning dojo.require(”mojo._base”) will automatically look in mojo/ for a _base.js), though we throw the dojo.provide in to make the build system happy.

This file will be our “bootstrap” file. we have code in here, and will put all our requires() here. When we build, _base.js will be replaced with all the dojo and mojo code needed, instantly optimizing our demo.

// define this file
dojo.provide("mojo._base");
// call in what we need
dojo.require("dojo.dnd.Moveable");
dojo.require("dojo.fx");
dojo.require("dojox.fx.easing");
// when onload happens, run our bootstrap
dojo.addOnLoad(function(){
    // this is our startup code for this demo
});

The first thing we want to setup in our addOnLoad function is the Drag and Drop code. We’ll be grabbing our circles by a drag handle, which will be the <h1> element inside the div. Inside the onload function, lets find each of the boxes, and setup dojo.dnd.Moveable on them.

    // in dojo.addOnLoad(function(){})
    dojo.query("#container > div").forEach(function(n){     // forEach div in #container as n:
         // our handle is the first h1 in this node
         var someNode = dojo.query("h1",n)[0];
         new dojo.dnd.Moveable(n, { handle: someNode });
     });

That’s cool, and our nodes move now, though they don’t snap back like the demo yet. This is where the topics come in. Moveable publishes two really great topics: /dnd/move/start and /dnd/move/end … The nature of topics is such that it doesn’t matter when we subscribe, but for the sake of argument, lets add two subscriptions immediately after our above dojo.query() call, where we setup the Moveable. Here, we’ll subscribe to /start and save our coordinate, and /end to animate the node back to our saved coordinates.

dojo.addOnLoad(function(){
     // setup moveable
     dojo.query("#container > div") /* do moveable stuff ... */
 
     var _z = null; // z-index storage
     var _coords = null; // coords storage
     dojo.subscribe("/dnd/move/start",function(e){
			// when drag starts, save the coords of the node we're pulling
			var n = e.node;
			_coords = dojo.coords(n);
			// and "bring to top"
			_z = dojo.style(n,"zIndex");
			dojo.style(n,"zIndex","888");
			// and make it partially opaque
			dojo.style(n,"opacity","0.65");
		});
 
		dojo.subscribe("/dnd/move/stop",function(e){
			// when it ends, reset z-index, opacity, and animate back to spot
			dojo.style(e.node,"opacity","1");
			if(_coords){
				dojo.fx.slideTo({
					node: e.node, // drag node
					top: _coords.t, // tmp top
					left: _coords.l, // tmp left
					easing: dojox.fx.easing.elasticOut,
					duration:950 // ms
				}).play(5); // small delay for performance?
				dojo.style(e.node,"zIndex",_z);
			}
		});	
 
});

The easing: dojox.fx.easing.elasticOut causes the animation to “bounce around” the end point (Out), giving us that elastic snappyness. We save our absolute top and left coords, and run the slideTo animation to the initial coordinates, changing the z-indexes of the node at both stops.

As seen above (and it’s a semi-common dojo paradigm), dojo.style is working as a getter and a setter for the z-index. passing two args to style() returns the value, passing three sets the style value. so:

var z = dojo.style(node,"zIndex");
console.log(z);
dojo.style(node,"zIndex",Math.floor(z/2)); // set the zIndex to half the orig zIndex

And one final note: when referencing hyphenated property names in javascript, you must used the mixedCase variation: z-index becomes zIndex, font-size becomes fontSize, etc, etc. Dojo even (as of 1.1) normalizes the few cases where style properties aren’t such. For instance, the “float” property is actually cssFloat in all sane browsers OR styleFloat in one less sane browser that starts with “I” and ends in “nternet Explorer”, but I won’t name names.

So far so good. We should have accomplished the snap back effect of the mojo demo. Next up: the fancy animations to show the circles onload.

One should note, you need Dojo version >= 1.1 to have the easing functions provided by dojox.fx.easing.

Tags: ,