",
 *   callback: function(){
 *     alert("test");
 *   }
 * });
 *
 * Configuration options:
 *
 * bottomPixels  integer          the number of pixels from the bottom of the page that triggers the event
 * fireOnce      boolean          only fire once until the execution of the current event is completed
 * fireDelay     integer          delay the subsequent firing, in milliseconds, 0 or false to disable delay
 * loader        string           the HTML to be displayed during loading
 * data          string|function  plain HTML data, can be either a string or a function that returns a string,
 *                                when passed as a function it accepts one argument: fire sequence (the number
 *                                of times the event triggered during the current page session)
 * insertAfter   string           jQuery selector syntax: where to put the loader as well as the plain HTML data
 * callback      function         callback function, accepts one argument: fire sequence (the number of times
 *                                the event triggered during the current page session)
 * resetCounter  function         resets the fire sequence counter if the function returns true, this function
 *                                could also perform hook actions since it is applied at the start of the event
 * ceaseFire     function         stops the event (no more endless scrolling) if the function returns true
 *
 * Usage tips:
 *
 * The plugin is more useful when used with the callback function, which can then make AJAX calls to retrieve content.
 * The fire sequence argument (for the callback function) is useful for 'pagination'-like features.
 */
(function($){
  $.fn.endlessScroll = function(options) {
    var defaults = {
      bottomPixels  : 50,
      fireOnce      : true,
      fireDelay     : 150,
      loader        : "
Loading...
",
      data          : "",
      insertAfter   : "div:last",
      resetCounter  : function() { return false; },
      callback      : function() { return true; },
      ceaseFire     : function() { return false; }
    };
    var options       = $.extend({}, defaults, options),
        firing        = true,
        fired         = false,
        fireSequence  = 0,
        is_scrollable;
    if (options.ceaseFire.apply(this) === true)
      firing = false;
    if (firing === true) {
      $(this).scroll(function() {
        if (options.ceaseFire.apply(this) === true) {
          firing = false;
          return; // Scroll will still get called, but nothing will happen
        }
        if (this == document || this == window) {
          is_scrollable = $(document).height() - $(window).height() <= $(window).scrollTop() + options.bottomPixels;
        } else {
          // calculates the actual height of the scrolling container
          var inner_wrap = $(".endless_scroll_inner_wrap", this);
          if (inner_wrap.length == 0)
            inner_wrap = $(this).wrapInner("
").find(".endless_scroll_inner_wrap");
          is_scrollable = inner_wrap.length > 0 &&
            (inner_wrap.height() - $(this).height() <= $(this).scrollTop() + options.bottomPixels);
        }
        if (is_scrollable && (options.fireOnce == false || (options.fireOnce == true && fired != true))) {
          if (options.resetCounter.apply(this) === true) fireSequence = 0;
          fired = true;
          fireSequence++;
          $(options.insertAfter).after("
" + options.loader + "
");
          data = typeof options.data == 'function' ? options.data.apply(this, [fireSequence]) : options.data;
          if (data !== false) {
            $(options.insertAfter).after("
" + data + "
");
            $("#endless_scroll_data").hide().fadeIn(250, function() {$(this).removeAttr("id");});
            options.callback.apply(this, [fireSequence]);
            if (options.fireDelay !== false || options.fireDelay !== 0) {
              $("body").after("
");
              // slight delay for preventing event firing twice
              $("#endless_scroll_marker").fadeTo(options.fireDelay, 1, function() {
                $(this).remove();
                fired = false;
              });
            }
            else
              fired = false;
          }
          $("#endless_scroll_loader").remove();
        }
      });
    }
  };
})(jQuery);