(function($){

$.fn.watch = function (props, func, interval, id) {
    /// <summary>
    /// Allows you to monitor changes in a specific
    /// CSS property of an element by polling the value.
    /// when the value changes a function is called.
    /// The function called is called in the context
    /// of the selected element (ie. this)
    /// </summary>    
    /// <param name="prop" type="String">CSS Properties to watch sep. by commas</param>    
    /// <param name="func" type="Function">
    /// Function called when the value has changed.
    /// </param>    
    /// <param name="interval" type="Number">
    /// Optional interval for browsers that don't support DOMAttrModified or propertychange events.
    /// Determines the interval used for setInterval calls.
    /// </param>
    /// <param name="id" type="String">A unique ID that identifies this watch instance on this element</param>  
    /// <returns type="jQuery" /> 
    if (!interval)
        interval = 100;
    if (!id)
        id = "_watcher";

    return this.each(function () {
        var _t = this;
        var el$ = $(this);
        var fnc = function () { __watcher.call(_t, id) };

        var data = { id: id,
            props: props.split(","),
            vals: [props.split(",").length],
            func: func,
            fnc: fnc,
            origProps: props,
            interval: interval,
            intervalId: null
        };
        // store initial props and values
        $.each(data.props, function (i) { data.vals[i] = el$.css(data.props[i]); });

        el$.data(id, data);

        hookChange(el$, id, data);
    });

    function hookChange(el$, id, data) {
        el$.each(function () {
            var el = $(this);
            if (typeof (el.get(0).onpropertychange) == "object")
                el.bind("propertychange." + id, data.fnc);
            else if ($.browser.mozilla)
                el.bind("DOMAttrModified." + id, data.fnc);
            else
                data.intervalId = setInterval(data.fnc, interval);
        });
    }
    function __watcher(id) {
        var el$ = $(this);
        var w = el$.data(id);
        if (!w) return;
        var _t = this;

        if (!w.func)
            return;

        // must unbind or else unwanted recursion may occur
        el$.unwatch(id);

        var changed = false;
        var i = 0;
        for (i; i < w.props.length; i++) {
            var newVal = el$.css(w.props[i]);
            if (w.vals[i] != newVal) {
                w.vals[i] = newVal;
                changed = true;
                break;
            }
        }
        if (changed)
            w.func.call(_t, w, i);

        // rebind event
        hookChange(el$, id, w);
    }
}
$.fn.unwatch = function (id) {
    this.each(function () {
        var el = $(this);
        var data = el.data(id);
        try {
            if (typeof (this.onpropertychange) == "object")
                el.unbind("propertychange." + id, data.fnc);
            else if ($.browser.mozilla)
                el.unbind("DOMAttrModified." + id, data.fnc);
            else
                clearInterval(data.intervalId);
        }
        // ignore if element was already unbound
        catch (e) { }
    });
    return this;
}

})(jQuery);




