/*!

* jQuery throttle / debounce - v1.1 - 3/7/2010
* http://benalman.com/projects/jquery-throttle-debounce-plugin/
* 
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/

// Script: jQuery throttle / debounce: Sometimes, less is more! // // *Version: 1.1, Last updated: 3/7/2010* // // Project Home - benalman.com/projects/jquery-throttle-debounce-plugin/ // GitHub - github.com/cowboy/jquery-throttle-debounce/ // Source - github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.js // (Minified) - github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.min.js (0.7kb) // // About: License // // Copyright © 2010 “Cowboy” Ben Alman, // Dual licensed under the MIT and GPL licenses. // benalman.com/about/license/ // // About: Examples // // These working examples, complete with fully commented code, illustrate a few // ways in which this plugin can be used. // // Throttle - benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/ // Debounce - benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/ // // About: Support and Testing // // Information about what version or versions of jQuery this plugin has been // tested with, what browsers it has been tested in, and where the unit tests // reside (so you can test it yourself). // // jQuery Versions - none, 1.3.2, 1.4.2 // Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome 4-5, Opera 9.6-10.1. // Unit Tests - benalman.com/code/projects/jquery-throttle-debounce/unit/ // // About: Release History // // 1.1 - (3/7/2010) Fixed a bug in <jQuery.throttle> where trailing callbacks // executed later than they should. Reworked a fair amount of internal // logic as well. // 1.0 - (3/6/2010) Initial release as a stand-alone project. Migrated over // from jquery-misc repo v0.4 to jquery-throttle repo v1.0, added the // no_trailing throttle parameter and debounce functionality. // // Topic: Note for non-jQuery users // // jQuery isn't actually required for this plugin, because nothing internal // uses any jQuery methods or properties. jQuery is just used as a namespace // under which these methods can exist. // // Since jQuery isn't actually required for this plugin, if jQuery doesn't exist // when this plugin is loaded, the method described below will be created in // the `Cowboy` namespace. Usage will be exactly the same, but instead of // $.method() or jQuery.method(), you'll need to use Cowboy.method().

(function(window,undefined){

'$:nomunge'; // Used by YUI compressor.

// Since jQuery really isn't required for this plugin, use `jQuery` as the
// namespace only if it already exists, otherwise use the `Cowboy` namespace,
// creating it if necessary.
var $ = window.jQuery || window.Cowboy || ( window.Cowboy = {} ),

  // Internal method reference.
  jq_throttle;

// Method: jQuery.throttle
// 
// Throttle execution of a function. Especially useful for rate limiting
// execution of handlers on events like resize and scroll. If you want to
// rate-limit execution of a function to a single time, see the
// <jQuery.debounce> method.
// 
// In this visualization, | is a throttled-function call and X is the actual
// callback execution:
// 
// > Throttled with `no_trailing` specified as false or unspecified:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X    X    X    X    X    X        X    X    X    X    X    X
// > 
// > Throttled with `no_trailing` specified as true:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X    X    X    X    X             X    X    X    X    X
// 
// Usage:
// 
// > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback );
// > 
// > jQuery('selector').bind( 'someevent', throttled );
// > jQuery('selector').unbind( 'someevent', throttled );
// 
// This also works in jQuery 1.4+:
// 
// > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) );
// > jQuery('selector').unbind( 'someevent', callback );
// 
// Arguments:
// 
//  delay - (Number) A zero-or-greater delay in milliseconds. For event
//    callbacks, values around 100 or 250 (or even higher) are most useful.
//  no_trailing - (Boolean) Optional, defaults to false. If no_trailing is
//    true, callback will only execute every `delay` milliseconds while the
//    throttled-function is being called. If no_trailing is false or
//    unspecified, callback will be executed one final time after the last
//    throttled-function call. (After the throttled-function has not been
//    called for `delay` milliseconds, the internal counter is reset)
//  callback - (Function) A function to be executed after delay milliseconds.
//    The `this` context and all arguments are passed through, as-is, to
//    `callback` when the throttled-function is executed.
// 
// Returns:
// 
//  (Function) A new, throttled, function.

$.throttle = jq_throttle = function( delay, no_trailing, callback, debounce_mode ) {
  // After wrapper has stopped being called, this timeout ensures that
  // `callback` is executed at the proper times in `throttle` and `end`
  // debounce modes.
  var timeout_id,

    // Keep track of the last time `callback` was executed.
    last_exec = 0;

  // `no_trailing` defaults to falsy.
  if ( typeof no_trailing !== 'boolean' ) {
    debounce_mode = callback;
    callback = no_trailing;
    no_trailing = undefined;
  }

  // The `wrapper` function encapsulates all of the throttling / debouncing
  // functionality and when executed will limit the rate at which `callback`
  // is executed.
  function wrapper() {
    var that = this,
      elapsed = +new Date() - last_exec,
      args = arguments;

    // Execute `callback` and update the `last_exec` timestamp.
    function exec() {
      last_exec = +new Date();
      callback.apply( that, args );
    };

    // If `debounce_mode` is true (at_begin) this is used to clear the flag
    // to allow future `callback` executions.
    function clear() {
      timeout_id = undefined;
    };

    if ( debounce_mode && !timeout_id ) {
      // Since `wrapper` is being called for the first time and
      // `debounce_mode` is true (at_begin), execute `callback`.
      exec();
    }

    // Clear any existing timeout.
    timeout_id && clearTimeout( timeout_id );

    if ( debounce_mode === undefined && elapsed > delay ) {
      // In throttle mode, if `delay` time has been exceeded, execute
      // `callback`.
      exec();

    } else if ( no_trailing !== true ) {
      // In trailing throttle mode, since `delay` time has not been
      // exceeded, schedule `callback` to execute `delay` ms after most
      // recent execution.
      // 
      // If `debounce_mode` is true (at_begin), schedule `clear` to execute
      // after `delay` ms.
      // 
      // If `debounce_mode` is false (at end), schedule `callback` to
      // execute after `delay` ms.
      timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
    }
  };

  // Set the guid of `wrapper` function to the same of original callback, so
  // it can be removed in jQuery 1.4+ .unbind or .die by using the original
  // callback as a reference.
  if ( $.guid ) {
    wrapper.guid = callback.guid = callback.guid || $.guid++;
  }

  // Return the wrapper function.
  return wrapper;
};

// Method: jQuery.debounce
// 
// Debounce execution of a function. Debouncing, unlike throttling,
// guarantees that a function is only executed a single time, either at the
// very beginning of a series of calls, or at the very end. If you want to
// simply rate-limit execution of a function, see the <jQuery.throttle>
// method.
// 
// In this visualization, | is a debounced-function call and X is the actual
// callback execution:
// 
// > Debounced with `at_begin` specified as false or unspecified:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// >                          X                                 X
// > 
// > Debounced with `at_begin` specified as true:
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
// > X                                 X
// 
// Usage:
// 
// > var debounced = jQuery.debounce( delay, [ at_begin, ] callback );
// > 
// > jQuery('selector').bind( 'someevent', debounced );
// > jQuery('selector').unbind( 'someevent', debounced );
// 
// This also works in jQuery 1.4+:
// 
// > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) );
// > jQuery('selector').unbind( 'someevent', callback );
// 
// Arguments:
// 
//  delay - (Number) A zero-or-greater delay in milliseconds. For event
//    callbacks, values around 100 or 250 (or even higher) are most useful.
//  at_begin - (Boolean) Optional, defaults to false. If at_begin is false or
//    unspecified, callback will only be executed `delay` milliseconds after
//    the last debounced-function call. If at_begin is true, callback will be
//    executed only at the first debounced-function call. (After the
//    throttled-function has not been called for `delay` milliseconds, the
//    internal counter is reset)
//  callback - (Function) A function to be executed after delay milliseconds.
//    The `this` context and all arguments are passed through, as-is, to
//    `callback` when the debounced-function is executed.
// 
// Returns:
// 
//  (Function) A new, debounced, function.

$.debounce = function( delay, at_begin, callback ) {
  return callback === undefined
    ? jq_throttle( delay, at_begin, false )
    : jq_throttle( delay, callback, at_begin !== false );
};

})(this);