waypoints.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. (function($, wp, wps, window, undefined) {
  2. '$:nomunge';
  3. var $w = $(window),
  4. waypoints = [],
  5. oldScroll = -99999,
  6. didScroll = false,
  7. didResize = false,
  8. eventName = 'waypoint.reached',
  9. methods = {
  10. init: function(f, options) {
  11. this.each(function() {
  12. var $this = $(this),
  13. ndx = waypointIndex($this),
  14. base = ndx < 0 ? $.fn[wp].defaults: waypoints[ndx].options,
  15. opts = $.extend({},
  16. base, options);
  17. opts.offset = opts.offset === "bottom-in-view" ?
  18. function() {
  19. return $[wps]('viewportHeight') - $(this).outerHeight();
  20. }: opts.offset;
  21. if (ndx < 0) {
  22. waypoints.push({
  23. element: $this,
  24. offset: $this.offset().top,
  25. options: opts
  26. });
  27. }
  28. else {
  29. waypoints[ndx].options = opts;
  30. }
  31. f && $this.bind(eventName, f);
  32. });
  33. $[wps]('refresh');
  34. return this;
  35. },
  36. remove: function() {
  37. return this.each(function() {
  38. var ndx = waypointIndex($(this));
  39. if (ndx >= 0) {
  40. waypoints.splice(ndx, 1);
  41. }
  42. });
  43. },
  44. destroy: function() {
  45. return this.unbind(eventName)[wp]('remove');
  46. }
  47. };
  48. function waypointIndex(el) {
  49. var i = waypoints.length - 1;
  50. while (i >= 0 && waypoints[i].element[0] !== el[0]) {
  51. i -= 1;
  52. }
  53. return i;
  54. }
  55. function triggerWaypoint(way, dir) {
  56. way.element.trigger(eventName, dir)
  57. if (way.options.triggerOnce) {
  58. way.element[wp]('destroy');
  59. }
  60. }
  61. function doScroll() {
  62. var newScroll = $w.scrollTop(),
  63. isDown = newScroll > oldScroll,
  64. pointsHit = $.grep(waypoints,
  65. function(el, i) {
  66. return isDown ? (el.offset > oldScroll && el.offset <= newScroll) : (el.offset <= oldScroll && el.offset > newScroll);
  67. });
  68. if (!oldScroll || !newScroll) {
  69. $[wps]('refresh');
  70. }
  71. oldScroll = newScroll;
  72. if (!pointsHit.length) return;
  73. if ($[wps].settings.continuous) {
  74. $.each(isDown ? pointsHit: pointsHit.reverse(),
  75. function(i, point) {
  76. triggerWaypoint(point, [isDown ? 'down': 'up']);
  77. });
  78. }
  79. else {
  80. triggerWaypoint(pointsHit[isDown ? pointsHit.length - 1: 0], [isDown ? 'down': 'up']);
  81. }
  82. }
  83. $.fn[wp] = function(method) {
  84. if (methods[method]) {
  85. return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  86. }
  87. else if (typeof method === "function" || !method) {
  88. return methods.init.apply(this, arguments);
  89. }
  90. else if (typeof method === "object") {
  91. return methods.init.apply(this, [null, method]);
  92. }
  93. else {
  94. $.error('Method ' + method + ' does not exist on jQuery' + wp);
  95. }
  96. };
  97. $.fn[wp].defaults = {
  98. offset: 0,
  99. triggerOnce: false
  100. };
  101. var jQMethods = {
  102. refresh: function() {
  103. $.each(waypoints,
  104. function(i, o) {
  105. var adjustment = 0,
  106. oldOffset = o.offset;
  107. if (typeof o.options.offset === "function") {
  108. adjustment = o.options.offset.apply(o.element);
  109. }
  110. else if (typeof o.options.offset === "string") {
  111. var amount = parseFloat(o.options.offset),
  112. adjustment = o.options.offset.indexOf("%") ? Math.ceil($[wps]('viewportHeight') * (amount / 100)) : amount;
  113. }
  114. else {
  115. adjustment = o.options.offset;
  116. }
  117. o.offset = o.element.offset().top - adjustment;
  118. if (oldScroll > oldOffset && oldScroll <= o.offset) {
  119. triggerWaypoint(o, ['up']);
  120. }
  121. else if (oldScroll < oldOffset && oldScroll >= o.offset) {
  122. triggerWaypoint(o, ['down']);
  123. }
  124. });
  125. waypoints.sort(function(a, b) {
  126. return a.offset - b.offset;
  127. });
  128. },
  129. viewportHeight: function() {
  130. return (window.innerHeight ? window.innerHeight: $w.height());
  131. },
  132. aggregate: function() {
  133. var points = $();
  134. $.each(waypoints,
  135. function(i, e) {
  136. points = points.add(e.element);
  137. });
  138. return points;
  139. }
  140. };
  141. $[wps] = function(method) {
  142. if (jQMethods[method]) {
  143. return jQMethods[method].apply(this);
  144. }
  145. else {
  146. return jQMethods["aggregate"]();
  147. }
  148. };
  149. $[wps].settings = {
  150. continuous: true,
  151. resizeThrottle: 200,
  152. scrollThrottle: 100
  153. };
  154. $w.scroll(function() {
  155. if (!didScroll) {
  156. didScroll = true;
  157. window.setTimeout(function() {
  158. doScroll();
  159. didScroll = false;
  160. },
  161. $[wps].settings.scrollThrottle);
  162. }
  163. }).resize(function() {
  164. if (!didResize) {
  165. didResize = true;
  166. window.setTimeout(function() {
  167. $[wps]('refresh');
  168. didResize = false;
  169. },
  170. $[wps].settings.resizeThrottle);
  171. }
  172. }).load(function() {
  173. $[wps]('refresh');
  174. doScroll();
  175. });
  176. })(jQuery, 'waypoint', 'waypoints', this);