infinite-scroll.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * Fuel UX Infinite Scroll
  3. * https://github.com/ExactTarget/fuelux
  4. *
  5. * Copyright (c) 2014 ExactTarget
  6. * Licensed under the BSD New license.
  7. */
  8. // -- BEGIN UMD WRAPPER PREFACE --
  9. // For more information on UMD visit:
  10. // https://github.com/umdjs/umd/blob/master/jqueryPlugin.js
  11. (function (factory) {
  12. if (typeof define === 'function' && define.amd) {
  13. // if AMD loader is available, register as an anonymous module.
  14. define(['jquery', 'fuelux/loader'], factory);
  15. } else {
  16. // OR use browser globals if AMD is not present
  17. factory(jQuery);
  18. }
  19. }(function ($) {
  20. // -- END UMD WRAPPER PREFACE --
  21. // -- BEGIN MODULE CODE HERE --
  22. var old = $.fn.infinitescroll;
  23. // INFINITE SCROLL CONSTRUCTOR AND PROTOTYPE
  24. var InfiniteScroll = function (element, options) {
  25. this.$element = $(element);
  26. this.$element.addClass('infinitescroll');
  27. this.options = $.extend({}, $.fn.infinitescroll.defaults, options);
  28. this.curScrollTop = this.$element.scrollTop();
  29. this.curPercentage = this.getPercentage();
  30. this.fetchingData = false;
  31. this.$element.on('scroll.fu.infinitescroll', $.proxy(this.onScroll, this));
  32. this.onScroll();
  33. };
  34. InfiniteScroll.prototype = {
  35. constructor: InfiniteScroll,
  36. destroy: function () {
  37. this.$element.remove();
  38. // any external bindings
  39. // [none]
  40. // empty elements to return to original markup
  41. this.$element.empty();
  42. return this.$element[0].outerHTML;
  43. },
  44. disable: function () {
  45. this.$element.off('scroll.fu.infinitescroll');
  46. },
  47. enable: function () {
  48. this.$element.on('scroll.fu.infinitescroll', $.proxy(this.onScroll, this));
  49. },
  50. end: function (content) {
  51. var end = $('<div class="infinitescroll-end"></div>');
  52. if (content) {
  53. end.append(content);
  54. } else {
  55. end.append('---------');
  56. }
  57. this.$element.append(end);
  58. this.disable();
  59. },
  60. getPercentage: function () {
  61. var height = (this.$element.css('box-sizing') === 'border-box') ? this.$element.outerHeight() : this.$element.height();
  62. var scrollHeight = this.$element.get(0).scrollHeight;
  63. return (scrollHeight > height) ? ((height / (scrollHeight - this.curScrollTop)) * 100) : 0;
  64. },
  65. fetchData: function (force) {
  66. var load = $('<div class="infinitescroll-load"></div>');
  67. var self = this;
  68. var moreBtn;
  69. var fetch = function () {
  70. var helpers = {
  71. percentage: self.curPercentage,
  72. scrollTop: self.curScrollTop
  73. };
  74. var $loader = $('<div class="loader"></div>');
  75. load.append($loader);
  76. $loader.loader();
  77. if (self.options.dataSource) {
  78. self.options.dataSource(helpers, function (resp) {
  79. var end;
  80. load.remove();
  81. if (resp.content) {
  82. self.$element.append(resp.content);
  83. }
  84. if (resp.end) {
  85. end = (resp.end !== true) ? resp.end : undefined;
  86. self.end(end);
  87. }
  88. self.fetchingData = false;
  89. });
  90. }
  91. };
  92. this.fetchingData = true;
  93. this.$element.append(load);
  94. if (this.options.hybrid && force !== true) {
  95. moreBtn = $('<button type="button" class="btn btn-primary"></button>');
  96. if (typeof this.options.hybrid === 'object') {
  97. moreBtn.append(this.options.hybrid.label);
  98. } else {
  99. moreBtn.append('<span class="glyphicon glyphicon-repeat"></span>');
  100. }
  101. moreBtn.on('click.fu.infinitescroll', function () {
  102. moreBtn.remove();
  103. fetch();
  104. });
  105. load.append(moreBtn);
  106. } else {
  107. fetch();
  108. }
  109. },
  110. onScroll: function (e) {
  111. this.curScrollTop = this.$element.scrollTop();
  112. this.curPercentage = this.getPercentage();
  113. if (!this.fetchingData && this.curPercentage >= this.options.percentage) {
  114. this.fetchData();
  115. }
  116. }
  117. };
  118. // INFINITE SCROLL PLUGIN DEFINITION
  119. $.fn.infinitescroll = function (option) {
  120. var args = Array.prototype.slice.call(arguments, 1);
  121. var methodReturn;
  122. var $set = this.each(function () {
  123. var $this = $(this);
  124. var data = $this.data('fu.infinitescroll');
  125. var options = typeof option === 'object' && option;
  126. if (!data) {
  127. $this.data('fu.infinitescroll', (data = new InfiniteScroll(this, options)));
  128. }
  129. if (typeof option === 'string') {
  130. methodReturn = data[option].apply(data, args);
  131. }
  132. });
  133. return (methodReturn === undefined) ? $set : methodReturn;
  134. };
  135. $.fn.infinitescroll.defaults = {
  136. dataSource: null,
  137. hybrid: false,//can be true or an object with structure: { 'label': (markup or jQuery obj) }
  138. percentage: 95//percentage scrolled to the bottom before more is loaded
  139. };
  140. $.fn.infinitescroll.Constructor = InfiniteScroll;
  141. $.fn.infinitescroll.noConflict = function () {
  142. $.fn.infinitescroll = old;
  143. return this;
  144. };
  145. // NO DATA-API DUE TO NEED OF DATA-SOURCE
  146. // -- BEGIN UMD WRAPPER AFTERWORD --
  147. }));
  148. // -- END UMD WRAPPER AFTERWORD --