impress.js: make past, present and future classes work with non-linear steps

Currently the class changes in the impress:stepenter and impress:stepleave
events assume you're going linearly through the presentation.  This means that
they add the wrong classes if you go back by one (or even just reload the
presentation).  This shows up starkly if you use the class.past|future css
modifiers.  Fix this by detecting how the step is being done and adjusting
accordingly in impress:stepenter.

Also introduce data-duration parameter to control the delay timing of steps.

Signed-off-by: James Bottomley <JBottomley@Parallels.com>
diff --git a/js/impress.js b/js/impress.js
index 25f1c33..a967226 100644
--- a/js/impress.js
+++ b/js/impress.js
@@ -252,6 +252,9 @@
         
         // array of step elements
         var steps = null;
+
+	// last index of stepenter event
+	var lastidx = null;
         
         // configuration options
         var config = null;
@@ -312,7 +315,8 @@
                         z: toNumber(data.rotateZ || data.rotate)
                     },
                     scale: toNumber(data.scale, 1),
-                    el: el
+                    el: el,
+		    duration: toNumber(data.duration, 0)
                 };
             
             if ( !el.id ) {
@@ -498,6 +502,8 @@
 		    var cel = lastBuild[j];
 		    cel.classList.add("active");
 		    body.classList.add("impress-on-" + cel.id);
+		    onStepEnter(cel);
+		    onStepLeave(cel);
 		}
 	    }
 
@@ -531,7 +537,7 @@
 	    // built outs have no transition duration because that
 	    // would delay any animation being done in the build
             if (isBuild && !jumpStep ) {
-		duration = 0;
+		duration = step.duration;
 	    } else {
 		duration = toNumber(duration, config.transitionDuration);
 	    }
@@ -651,10 +657,34 @@
             });
             
             root.addEventListener("impress:stepenter", function (event) {
+		var idx = steps.indexOf(event.target);
+		// lastidx is a global
+
                 event.target.classList.remove("past");
                 event.target.classList.remove("future");
                 event.target.classList.add("present");
-            }, false);
+		if (lastidx != null) {
+		    if ( idx == lastidx - 1 ) {
+			// step back => lastidx is one in future
+			var el = steps[lastidx];
+			el.classList.remove("past");
+			el.classList.add("future");
+		    } else if ( idx != lastidx + 1) {
+			// nightmare scenario: we stepped into somewhere random
+			for (var i = 0; i < idx; i++) {
+			    var el = steps[i];
+			    el.classList.remove("future");
+			    el.classList.add("past");
+			}
+			for (var i = idx + 1; i < steps.length; i++) {
+			    var el = steps[i];
+			    el.classList.remove("past");
+			    el.classList.add("future");
+			}
+		    }
+		}
+		lastidx = idx;
+	    }, false);
             
             root.addEventListener("impress:stepleave", function (event) {
                 event.target.classList.remove("present");