Animation Blind Singleton

A quick apology for not getting this article out sooner. I was having issues with wordpress: it lost part of the posting and repeatedly choked on the code sample. Anyway, sorry for the delay.

Todays article combines the Dom Search Experiment, discussed last week, with the Event Dispatcher, discussed last month, and YUI. The purpose of this widget is to allow designers to have complete control over which anchors trigger blind animations and what elements are associated with those triggers (ie. what element will animate), without having to write a single line of JavaScript.

To accomplish this goal the Blind Animator needs to be a standalone singleton object that responds to some design driven animation trigger. Event dispatcher is the perfect tool for this, because no events need to be attached to the anchors themselves, as a master click event is attached to the page. This master event will then dispatch to registered callback functions as necessary. The Singleton object need only register a callback on the generic trigger, animBlind, which will map to the class com_animBlind. So any anchor element on a page with the com_animBlind class will trigger a blind animation.

Since the Blind Animation Singleton will not know anything about the trigger anchor or what element should be animated, there needs to be a way to associate the anchor with the element to animate. For this the rel attribute of an anchor tag is used and the Dom Search Experiment (exec function). The rel attribute will contain the instructions string to be passed into the exec function. This way the designer can specify how to find the node to animate.

Lastly, a blind animation must be setup on the node to animate. For starters this means using the following DOM and styles:

Example 1: Styles And DOM Required for Blind Animation

<style>.blindWrap {

<div class="blindWrap"><div>Enter your Content HERE! This inner node needs to be displayed and have layout.</div></div>

The wrapping node blindWrap will have a height of ZERO and overflow hidden, so that its content is not displayed. However, the content itself (its first child) should be displayed normally so that it can be used to find the height dimension for the blind animation.

Putting this all together, is the Blind Animation Singleton object:

Example 2: Blind Animation Singleton

Core.Controller.AnimBlindSingleton = (function() {
	// constants
    var _CLASS_OPEN = open,
        _COM_ANIM_BLIND = animBlind,
        YUE = YAHOO.util.Event;

    // local namespace
    var _CE = YAHOO.util.CustomEvent,
        _ED = Core.Util.EventDispatcher,
		_F = function() {},
        _isAnimating = false,
        _queueAnim = [],
        _that = null;

    var toggle = function(node, link) {
        _queueAnim.push([node, link]);

        if (_isAnimating) {
            // nothing for now
        else {
            var isOpen = Dom.hasClass(node, _CLASS_OPEN),
                end = isOpen ? 0 : Dom.getDimension(Dom.getFirstChild(node)).height,
                start = Dom.getDimension(node, true, true).height,
                o = {isOpen: isOpen, link: link, node: node, scope: _that};

            _isAnimating = true;


            Dom.animate(node, {height: {from: start, to: end}}, 0.5, YAHOO.util.Easing.easeBoth, [
                {id: _onComplete, fx: function() {
                    _isAnimating = false;
                    Dom.toggleClass(link, _CLASS_OPEN, ! isOpen);
                    Dom.toggleClass(node, _CLASS_OPEN, ! isOpen);
                    if (_queueAnim.length) {toggle.apply(this, _queueAnim.shift());} // activate next element in the queue

    // manage global blind animations
    _ED.register(click, {id: _COM_ANIM_BLIND, callback: function(e) {
        var targ = YUE.getTarget(e),
            node = Dom. exec (targ, targ.rel);


        if (node) {
            toggle(node, targ);
        else {
            alert(JavaScript failure: issue with blind animation reference.);

    // public namespace
    _F.prototype = {

         * A Custom Event object fired at the start of the toggle process.
         * @property onToggle
         * @static
         * @final
         * @type {Object}
        onToggle: new _CE(_COM_ANIM_BLIND + Toggle, null, true, YAHOO.util.CustomEvent.FLAT),

         * A Custom Event object fired at the end of the toggle process.
         * @property onToggle
         * @static
         * @final
         * @type {Object}
        _onToggle: new _CE(_COM_ANIM_BLIND + Toggle, null, true, YAHOO.util.CustomEvent.FLAT)

    _that = new _F();
    return _that;

In addition to previously discussed features, the AnimBlindSingleton object has these features: a custom event fired before (onToggle) and after (_onToggle) the animation occurs, an animation queue, and will apply the class open. Advanced developers can subscribe to the custom events to execute a callback function when the animation starts or completes. An animation queue is used so that the user cannot trigger multiple blind animations at the same time, nor can they span a single trigger; this also prevents possible possible issues around animating again whilst in mid-animation. The open class is applied to the trigger and the animation element so that designers can change styles when the blind is opened, such as changing the trigger text from open to close.

So to recap, the benefits of using AnimBlindSingleton are that it is simple to use, requires no JavaScript, is completely standalone, and can be managed by the design. The biggest drawback is that since the singleton object doesnt know anything about its triggers or animation elements, there is no easy way to programmatically trigger the blind animation. However, you can use a click simulator on the triggering anchors to programmatically fire the blind animation.

Lastly, I put together a demo page to show AnimBlindSingleton in action.