/* * FxQeue 2.0.2 * jQuery Advanced Effect Queues * Copyright 2007 John Resig, Luciano Germán Panaro * Released under the MIT and GPL licenses. */ (function(jQuery){ var fxQueue = function() { return { isFxQueue: true, paused: false, pause: function() { if (this[0]) { this.paused = true; var playing = (this[0].isScope)? this[0] : this[0].elem; playing.stop(); } }, stop: function() { if (this[0]) { this.paused = false; var playing = (this[0].isScope)? this[0] : this[0].elem; playing.stop(); this.length = 0; } }, start: function() { if (this[0]) { this.paused = false; this[0](); } }, getScope: function( scopeName ) { for (var i = 0; i < this.length; i++) { if ( this[i].isScope && this[i].called == scopeName ) return this[i]; } return false; } } }; var fxScope = function ( scopeName ) { var newScope = function() { for (var i=0; i < newScope.items.length; i++) { newScope.items[i](); } }; newScope.called = scopeName; newScope.isScope = true; newScope.finishedItems = 0; newScope.stop = function() { for (var i=0; i < newScope.items.length; i++) { newScope.items[i].elem.stop(); } }; newScope.items = []; return newScope; }; // We need to overload the default animate method var animate = jQuery.fn.animate; jQuery.fn.animate = function( props, speed, easing, callback ){ if (this.length < 1) return this; // Let normal animations just pass through if ( typeof speed == "object" && speed.queue === false ) { return animate.apply( this, arguments ); // We'll handle everything else } else { var options = (typeof speed == "object")? speed: jQuery.speed(speed, easing, callback); // Load in the default options var opts = jQuery.extend({ queue: "fx", position: "end", limit: -1, preDelay: 0, postDelay: 0, complete: function() {} }, options ); var elem = this; // Get the name of the queue var queueName = opts.queue; // A global queue is centered on 'document' var root = opts.queue != "fx" ? document : this; // Get the effect queue var queue = jQuery(root).queue( opts.queue ); // Extend the queue object if it's new. if ( !queue.isFxQueue ) { jQuery.extend(queue, fxQueue()); } // Build in the dequeue operation var complete = opts.complete; opts.complete = function(){ // Just dequeue once for every selection if(elem[0] == this) { var isScope = (queue[0] && queue[0].isScope); if (isScope) { var queueItems = queue[0].items; // Find the actual element in scope's items for ( var i=0; i < queueItems.length; i++) { if ( this == queueItems[i].elem[0] && !queueItems[i].finished ) { queueItems[i].finished = true; queue[0].finishedItems++; } } } // Dequeue setTimeout(function(){ // If it's not a scope, or if all scope items are finished if ( !isScope || (queue[0] && queue[0].finishedItems == queueItems.length) ) { jQuery(root).dequeue( queueName ); } }, opts.postDelay); } // Now let's apply the original callback function if (jQuery.isFunction(complete)) return complete.apply( this, arguments ); }; // We're overriding the default queueing behavior opts.queue = false; // The animation to queue var fn = function(){ setTimeout(function(){ jQuery(fn.elem).animate( props, opts ); }, opts.preDelay); }; fn.elem = this; // If scope exists, just add the animation and return var scope = queue.getScope( opts.scope ); if ( scope ) { scope.items.push( fn ); // Start the animation if the scope is already being played if ( queue[0].isScope && queue[0].called == opts.scope) fn(); return this; } // Restrict the animation to a specifically sized queue if ( opts.limit < 0 || queue.length < opts.limit) { var add = null; //What we are going to add into the queue if ( opts.scope ) { add = fxScope( opts.scope ); add.items.push(fn); } else { add = fn; } if ( opts.position == "end" ) { // Put the animation or scope in the right place on the queue queue.push( add ); } else if ( opts.position == "front" ) { // Front is actually or scope just after the current animation queue.splice( 1, 0, add ); } // If this is the first item in the queue, run immediately if ( queue.length == 1 ) queue[0](); } return this; } }; jQuery.fn.stop = function(clearQueue, gotoEnd, playNext){ var timers = jQuery.timers; if (clearQueue) this.queue([]); this.each(function(){ // go in reverse order so anything added to the queue during the loop is ignored for ( var i = timers.length - 1; i >= 0; i-- ) if ( timers[i].elem == this ) { if (gotoEnd) // force the next step to be the last timers[i](true); timers.splice(i, 1); } }); // start the next in the queue if the last step wasn't forced if (playNext) this.dequeue(); return this; }; // Remove from Speed the complete override, which we now do in Animate jQuery.speed = function(speed, easing, fn) { var opt = speed && speed.constructor == Object ? speed : { complete: fn || function() {} && easing || jQuery.isFunction( speed ) && speed, duration: speed, easing: fn && easing || easing && easing.constructor != Function && easing }; opt.duration = (opt.duration && opt.duration.constructor == Number ? opt.duration : { slow: 600, fast: 200 }[opt.duration]) || 400; return opt; }; // A simple global fx queue getter jQuery.fxqueue = function(queueName) { return jQuery(document).queue( queueName ); }; })(jQuery);