<div id="overlay" class="yui3-overlay-loading">
    <div class="yui3-widget-hd">Overlay Header</div>
    <div class="yui3-widget-bd">Overlay Body</div>
    <div class="yui3-widget-ft">Overlay Footer</div>
</div>

<button type="button" id="show">Show</button>
<button type="button" id="hide">Hide</button>
<button type="button" id="unplug">Unplug AnimPlugin</button>
<button type="button" id="plug">Plug AnimPlugin (duration:0.5)</button>

<script type="text/javascript">
YUI().use("overlay", "anim", "plugin", function(Y) {

    /* Animation Plugin Constructor */
    function AnimPlugin(config) {
        AnimPlugin.superclass.constructor.apply(this, arguments);
    }

    /* 
     * The namespace for the plugin. This will be the property on the widget, which will 
     * reference the plugin instance, when it's plugged in
     */
    AnimPlugin.NS = "fx";

    /*
     * The NAME of the AnimPlugin class. Used to prefix events generated
     * by the plugin class.
     */
    AnimPlugin.NAME = "animPlugin";

    /*
     * The default set of attributes for the AnimPlugin class.
     */
    AnimPlugin.ATTRS = {

        /*
         * Default duration. Used by the default animation implementations
         */
        duration : {
            value: 0.2
        },

        /*
         * Default animation instance used for showing the widget (opacity fade-in)
         */
        animVisible : {
            valueFn : function() {

                var host = this.get("host"),
                    boundingBox = host.get("boundingBox");

                var anim = new Y.Anim({
                    node: boundingBox,
                    to: { opacity: 1 },
                    duration: this.get("duration")
                });

                // Set initial opacity, to avoid initial flicker
                if (!host.get("visible")) {
                    boundingBox.setStyle("opacity", 0);
                }

                // Clean up, on destroy. Where supported, remove
                // opacity set using style. Else make 100% opaque
                anim.on("destroy", function() {
                    if (Y.UA.ie) {
                        this.get("node").setStyle("opacity", 1);
                    } else {
                        this.get("node").setStyle("opacity", "");
                    }
                });

                return anim;
            }
        },

        /*
         * Default animation instance used for hiding the widget (opacity fade-out)
         */
        animHidden : {
            valueFn : function() {
                return new Y.Anim({
                    node: this.get("host").get("boundingBox"),
                    to: { opacity: 0 },
                    duration: this.get("duration")
                });
            }
        }
    }

    /*
     * Extend the base plugin class
     */
    Y.extend(AnimPlugin, Y.Plugin.Base, {

        /*
         * Initialization code. Called when the 
         * plugin is instantiated (whenever it's 
         * plugged into the host)
         */
        initializer : function(config) {
            this._bindAnimVisible();
            this._bindAnimHidden();

            this.after("animVisibleChange", this._bindAnimVisible);
            this.after("animHiddenChange", this._bindAnimHidden);

            // Override default _uiSetVisible method, with custom animated method
            this.doBefore("_uiSetVisible", this._uiAnimSetVisible);
        },

        /*
         * Destruction code. Invokes destroy in the individual animation instances,
         * and lets them take care of cleaning up any state.
         */
        destructor : function() {
            this.get("animVisible").stop().destroy();
            this.get("animHidden").stop().destroy();
        },

        /*
         * The custom animation method, added by the plugin.
         *
         * This method replaces the default _uiSetVisible handler
         * Widget provides, by injecting itself before _uiSetVisible,
         * (using Plugins before method) and preventing the default
         * behavior.
         */
        _uiAnimSetVisible : function(val) {
            if (this.get("host").get("rendered")) {
                if (val) {
                    this.get("animHidden").stop();
                    this.get("animVisible").run();
                } else {
                    this.get("animVisible").stop();
                    this.get("animHidden").run();
                }
                return new Y.Do.Prevent("AnimPlugin prevented default show/hide");
            }
        },

        /*
         * The original Widget _uiSetVisible implementation
         */
        _uiSetVisible : function(val) {
            var host = this.get("host");
            var hiddenClass = host.getClassName("hidden");
            if (!val) {
                host.get("boundingBox").addClass(hiddenClass);
            } else {
                host.get("boundingBox").removeClass(hiddenClass);
            }
        },

        /* Sets up call to invoke original visibility handling when the animVisible animation is started */
        _bindAnimVisible : function() {
            var animVisible = this.get("animVisible");

            // Setup original visibility handling (for show) before starting to animate
            animVisible.on("start", Y.bind(function() {
                this._uiSetVisible(true);
            }, this));
        },

        /* Sets up call to invoke original visibility handling when the animHidden animation is complete */
        _bindAnimHidden : function() {
            var animHidden = this.get("animHidden");

            // Setup original visibility handling (for hide) after completing animation
            animHidden.after("end", Y.bind(function() {
                this._uiSetVisible(false);
            }, this));
        }
    });

    // Create a new Overlay instance, and add AnimPlugin with a default duration of 2 seconds
    var overlay = new Y.Overlay({
        srcNode: "#overlay",
        width:"13em",
        height:"10em",
        visible:false,
        shim:false,
        align: {
            node: "#show", 
            points: ["tl", "bl"]
        },
        plugins : [{fn:AnimPlugin, cfg:{duration:2}}]
    });
    overlay.render();

    Y.on("click", function() {
        overlay.show();
    }, "#show");

    Y.on("click", function() {
        overlay.hide();
    }, "#hide");

    Y.on("click", function() {
        overlay.unplug("fx");
    }, "#unplug");

    Y.on("click", function() {
        overlay.unplug("fx");
        overlay.plug(AnimPlugin, {duration:0.5});
    }, "#plug");

});
</script>
