 /****************************************************************************
  * Code from comp.lang.javascript and (c) Michael Winter:
  * http://groups-beta.google.com/group/comp.lang.javascript/msg/3f287a2f20de1b10
  ***************************************************************************/
var fade = (function() {
    var global = this,
        objects = new Hashtable(),
        /* If it's determined that the host supports the application of an
         * opacity value either through opacity, or a proprietary property, this
         * variable will hold that property name.
         *
         * This should be left undefined. If it's not set when setOpacity is
         * called, hosts that implement DOM 2 Style, but not opacity, won't
         * attempt to modify the value.
         */
        property;
    function getOpacity(object) {var style;
        if(object.filters) {
            getOpacity = function(object) {
                return object.filters['DXImageTransform.Microsoft.Alpha'].Opacity;
            };
        } else if(global.getComputedStyle
         && (style = global.getComputedStyle(object, null))
         && style.getPropertyValue
         && (style.getPropertyValue(property = 'opacity')
         || style.getPropertyValue(property = '-moz-opacity')
         || style.getPropertyValue(property = '-khtml-opacity')))
        {
            getOpacity = function(object) {
                return parseFloat(
                    global.getComputedStyle(object, null).getPropertyValue(property)
                ) * 100;
            };
            style = null;
        } else {
            getOpacity = function() {return 100;};
        }
        return getOpacity(object);
    }
    function setOpacity(object, opacity) {
        if(object.filters) {
            setOpacity = function(object, opacity) {
                object.filters['DXImageTransform.Microsoft.Alpha'].Opacity = opacity;
            };
        /* If the property variable hasn't been set, an earlier call to getOpacity
         * determined that CSS opacity values aren't supported by the host.
         */
        } else if(property && object.style && object.style.setProperty) {
            setOpacity = function(object, opacity) {
                object.style.setProperty(property, opacity / 100, '');
            };
        } else {
            setOpacity = function() {};
        }
        setOpacity(object, opacity);
    }
    return function(object, targetOpacity, rate, delta) {
        var opacity = getOpacity(object);
        function stepFade() {var onTarget;
            opacity += delta;
            onTarget = (0 < delta) ?
                opacity >= targetOpacity
            : opacity <= targetOpacity;
            if(onTarget) {
                opacity = targetOpacity;
                objects.remove(object);
            }
            setOpacity(object, opacity);
            if(!onTarget) {objects.put(object, setTimeout(stepFade, rate));}
        }
        /* This function relies on the closure produced by the inner function
         * above. Though the closure could be preserved by exposing the inner
         * function publicly, it would cause clashes should the effect be active
         * on more than one element simultaneously. As such, any host that is
         * unable to accept a function argument to the setTimeout method will
         * silently fail.
         */
        stepFade.toString = function() {return ';';};
        /* If the element is already fading, stop the effect. */
        if(objects.containsKey(object)) {clearTimeout(objects.get(object));}
        /* This line prevents a bug in Gecko-based browsers where artifacts
         * appear when the opacity reaches 100%.
         */
        if(100 == targetOpacity) {--targetOpacity;}
        if(opacity > targetOpacity) {delta = -delta;}
        if(delta && rate) {objects.put(object, setTimeout(stepFade, rate));}
    }
})();
