/** * jQuery.timers - Timer abstractions for jQuery * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com) * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/). * Date: 2009/08/13 * * @author Blair Mitchelmore * @version 1.1.3 * **/jQuery.fn.extend({	everyTime: function(interval, label, fn, times, belay) {		return this.each(function() {			jQuery.timer.add(this, interval, label, fn, times, belay);		});	},	oneTime: function(interval, label, fn) {		return this.each(function() {			jQuery.timer.add(this, interval, label, fn, 1);		});	},	stopTime: function(label, fn) {		return this.each(function() {			jQuery.timer.remove(this, label, fn);		});	}});jQuery.extend({	timer: {		global: [],		guid: 1,		dataKey: "jQuery.timer",		regex: /^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/,		powers: {			// Yeah this is major overkill...			'ms': 1,			'cs': 10,			'ds': 100,			's': 1000,			'das': 10000,			'hs': 100000,			'ks': 1000000		},		timeParse: function(value) {			if (value == undefined || value == null)				return null;			var result = this.regex.exec(jQuery.trim(value.toString()));			if (result[2]) {				var num = parseFloat(result[1]);				var mult = this.powers[result[2]] || 1;				return num * mult;			} else {				return value;			}		},		add: function(element, interval, label, fn, times, belay) {			var counter = 0;						if (jQuery.isFunction(label)) {				if (!times) 					times = fn;				fn = label;				label = interval;			}						interval = jQuery.timer.timeParse(interval);			if (typeof interval != 'number' || isNaN(interval) || interval <= 0)				return;			if (times && times.constructor != Number) {				belay = !!times;				times = 0;			}						times = times || 0;			belay = belay || false;						var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {});						if (!timers[label])				timers[label] = {};						fn.timerID = fn.timerID || this.guid++;						var handler = function() {				if (belay && this.inProgress) 					return;				this.inProgress = true;				if ((++counter > times && times !== 0) || fn.call(element, counter) === false)					jQuery.timer.remove(element, label, fn);				this.inProgress = false;			};						handler.timerID = fn.timerID;						if (!timers[label][fn.timerID])				timers[label][fn.timerID] = window.setInterval(handler,interval);						this.global.push( element );					},		remove: function(element, label, fn) {			var timers = jQuery.data(element, this.dataKey), ret;						if ( timers ) {								if (!label) {					for ( label in timers )						this.remove(element, label, fn);				} else if ( timers[label] ) {					if ( fn ) {						if ( fn.timerID ) {							window.clearInterval(timers[label][fn.timerID]);							delete timers[label][fn.timerID];						}					} else {						for ( var fn in timers[label] ) {							window.clearInterval(timers[label][fn]);							delete timers[label][fn];						}					}										for ( ret in timers[label] ) break;					if ( !ret ) {						ret = null;						delete timers[label];					}				}								for ( ret in timers ) break;				if ( !ret ) 					jQuery.removeData(element, this.dataKey);			}		}	}});jQuery(window).bind("unload", function() {	jQuery.each(jQuery.timer.global, function(index, item) {		jQuery.timer.remove(item);	});});