This is a continuation of the article Project - AutoPlayDom. The project was renamed to DomTaskPlayer, because the new name is semantically more correct, as the object plays through a series of Dom related tasks. The full source code is available at http://www.mattsnider.com/assets/js/widget/DomTaskPlayer.js. The source code has drastically changed from last week, as supporting backwards navigation through the already played DomTasks, required a massive redesign of the code.
For starters the "DomTaskPlayer.add" method has changed, to accept a collection of step
objects, which will contain task
objects, which will contain action
objects:
Example 1: A Step Object
var step = { _isValid: false, // used internally, updated after firstnextcall name: , // what this step is tasks: [ // an array of tasks { // task action: [ {fx: function() {}, method: , params: [], reverseMethod: , reverseFx: function() {}}, // action … ], search: [ {fx: function() {}, method: , params: []}, // action … ], reverse: [] // internally managed }, … ] };
A step
object is a collection of task
objects and a name
to label the step. The task
object is a collection of search action
objects (to find the node(s) to apply actions to), and a collection of action action
objects (actually describing how to change the nodes found when searching). There is no limit to the number of tasks per step and actions per task. When the "DomTaskPlayer.next" method is called an internal collection of action
objects are attached to the reverse list, explaining how to reverse the current step.
The next
and previous
methods have been simplified, delegating the work to smaller more targeted internal assertion and action functions.
Example 2: DomTaskPlayer.next
next: function() { // go to the next position if (_that.hasNext()) { _index += 1; var step = _steps[_index]; // already validated and found nodes, no need to assert if (step._isValid) { _array_walk(step.tasks, function(task) { // iterate on the tasks _array_walk(task.action, _execute_action); // iterate on the actions }); } else { _array_walk(step.tasks, function(task) { // iterate on the tasks _assert_valid_task(task); var tobj = {}; _array_walk(task.search, _execute_search, tobj); _array_walk(task.action, function(action) { // iterate on the actions _assert_valid_action(action); // validates and/or setsaction.fx; assures action.params is an array _assert_user_reversible(action); // user fx is reversible action.nodes = tobj.nodes; _execute_action(action); }); }); step._isValid = true; } _that.onStepChange.fire([step,next]); } },
This method first asserts that there is a next step available, then grabs the step from the internal step array. If the step has the internal variable _isValid
set to true, then the method knows that it has previously already validated this step and can skip the search actions, executing the action tasks on cached DOM nodes. Otherwise, it iterates through each task and asserts that the tasks are valid. Afterwards, it searches the DOM using the search action
objects, producing an object with key nodes
. Then it iterates on the action action
objects and asserts they are valid and reversible. If no errors have been thrown, terminating the flow, then the method actually executes the action
objects. As each action
object is executed, the internal methods create the reverse actions, which will be used with the previous
method.
In addition, to supporting previous
and the massive revisions to next
, there is now a build-in, public method initKeyListeners
that hijacks the arrow keys (and a
- left arrow, s
- down arrow, d
- right arrow, w
- up arrow) to call one of the public action methods of DomTaskPlayer (previous
, stop
, next
, play
). The developer can require that any combination of Ctrl
, Alt
, or Shift
be pressed as well, so not to be obtrusive.
Example 3: DomTaskPlayer.initKeyListeners
initKeyListeners: function(forceCtrl, forceShift, forceAlt) { _YE.on(document,keydown, function(e) { if (forceCtrl && ! e.ctrlKey) {return;} // may trigger browser events if (forceShift && ! e.shiftKey) {return;} if (forceAlt && ! e.altKey) {return;} _YE.preventDefault(e); // stop browser events switch (_YE.getCharCode(e)) { case _YK.DOWN: case 83: // s _that.stop(); break; case _YK.LEFT: case 65: // a _that.previous(); break; case _YK.RIGHT: case 68: // d _that.next(); break; case _YK.UP: case 87: // w _that.play(); break; default: // do nothing } }); _that.initKeyListeners = function() {}; },
At the end of initKeyListeners
the method is set to empty function, thereby preventing the developer from accidentally attaching these key listeners more than once. This method can be called anytime after the DomTaskPlayer object has been initialized and it is recommended that at least two special keys be set to true, such as Shift
and Ctrl
:
Example 4: Calling initKeyListeners
yourDomTaskPlayerObject.initKeyListeners(true, true);
In Example 4, the user will need to hold Shift
+ Ctrl
+ ArrowKey to trigger the desired method.
Most importantly, this tool is easy to use; see Dom Task Player Test Page. Although easy to use, this tool is very complicated, please let me know if something does not work for you or are having trouble getting it working.
Lastly, please keep in mind that order of operations are very important with tasks, so if you first apply a class that changes the background, then change the background with a style directly in the same step
object, then the reverse operation will be confused and apply the wrong background color.