No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 

225 líneas
6.2 KiB

  1. /**
  2. * Extend jquery with a scrollspy plugin.
  3. * This watches the window scroll and fires events when elements are scrolled into viewport.
  4. *
  5. * throttle() and getTime() taken from Underscore.js
  6. * https://github.com/jashkenas/underscore
  7. *
  8. * @author Copyright 2013 John Smart
  9. * @license https://raw.github.com/thesmart/jquery-scrollspy/master/LICENSE
  10. * @see https://github.com/thesmart
  11. * @version 0.1.2
  12. */
  13. (function($) {
  14. var jWindow = $(window);
  15. var elements = [];
  16. var elementsInView = [];
  17. var isSpying = false;
  18. var ticks = 0;
  19. var offset = {
  20. top : 0,
  21. right : 0,
  22. bottom : 0,
  23. left : 0,
  24. }
  25. /**
  26. * Find elements that are within the boundary
  27. * @param {number} top
  28. * @param {number} right
  29. * @param {number} bottom
  30. * @param {number} left
  31. * @return {jQuery} A collection of elements
  32. */
  33. function findElements(top, right, bottom, left) {
  34. var hits = $();
  35. $.each(elements, function(i, element) {
  36. var elTop = element.offset().top,
  37. elLeft = element.offset().left,
  38. elRight = elLeft + element.width(),
  39. elBottom = elTop + element.height();
  40. var isIntersect = !(elLeft > right ||
  41. elRight < left ||
  42. elTop > bottom ||
  43. elBottom < top);
  44. if (isIntersect) {
  45. hits.push(element);
  46. }
  47. });
  48. return hits;
  49. }
  50. /**
  51. * Called when the user scrolls the window
  52. */
  53. function onScroll() {
  54. // unique tick id
  55. ++ticks;
  56. // viewport rectangle
  57. var top = jWindow.scrollTop(),
  58. left = jWindow.scrollLeft(),
  59. right = left + jWindow.width(),
  60. bottom = top + jWindow.height();
  61. // determine which elements are in view
  62. var intersections = findElements(top+offset.top, right+offset.right, bottom+offset.bottom, left+offset.left);
  63. $.each(intersections, function(i, element) {
  64. var lastTick = element.data('scrollSpy:ticks');
  65. if (typeof lastTick != 'number') {
  66. // entered into view
  67. element.triggerHandler('scrollSpy:enter');
  68. }
  69. // update tick id
  70. element.data('scrollSpy:ticks', ticks);
  71. });
  72. // determine which elements are no longer in view
  73. $.each(elementsInView, function(i, element) {
  74. var lastTick = element.data('scrollSpy:ticks');
  75. if (typeof lastTick == 'number' && lastTick !== ticks) {
  76. // exited from view
  77. element.triggerHandler('scrollSpy:exit');
  78. element.data('scrollSpy:ticks', null);
  79. }
  80. });
  81. // remember elements in view for next tick
  82. elementsInView = intersections;
  83. }
  84. /**
  85. * Called when window is resized
  86. */
  87. function onWinSize() {
  88. jWindow.trigger('scrollSpy:winSize');
  89. }
  90. /**
  91. * Get time in ms
  92. * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
  93. * @type {function}
  94. * @return {number}
  95. */
  96. var getTime = (Date.now || function () {
  97. return new Date().getTime();
  98. });
  99. /**
  100. * Returns a function, that, when invoked, will only be triggered at most once
  101. * during a given window of time. Normally, the throttled function will run
  102. * as much as it can, without ever going more than once per `wait` duration;
  103. * but if you'd like to disable the execution on the leading edge, pass
  104. * `{leading: false}`. To disable execution on the trailing edge, ditto.
  105. * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
  106. * @param {function} func
  107. * @param {number} wait
  108. * @param {Object=} options
  109. * @returns {Function}
  110. */
  111. function throttle(func, wait, options) {
  112. var context, args, result;
  113. var timeout = null;
  114. var previous = 0;
  115. options || (options = {});
  116. var later = function () {
  117. previous = options.leading === false ? 0 : getTime();
  118. timeout = null;
  119. result = func.apply(context, args);
  120. context = args = null;
  121. };
  122. return function () {
  123. var now = getTime();
  124. if (!previous && options.leading === false) previous = now;
  125. var remaining = wait - (now - previous);
  126. context = this;
  127. args = arguments;
  128. if (remaining <= 0) {
  129. clearTimeout(timeout);
  130. timeout = null;
  131. previous = now;
  132. result = func.apply(context, args);
  133. context = args = null;
  134. } else if (!timeout && options.trailing !== false) {
  135. timeout = setTimeout(later, remaining);
  136. }
  137. return result;
  138. };
  139. };
  140. /**
  141. * Enables ScrollSpy using a selector
  142. * @param {jQuery|string} selector The elements collection, or a selector
  143. * @param {Object=} options Optional.
  144. throttle : number -> scrollspy throttling. Default: 100 ms
  145. offsetTop : number -> offset from top. Default: 0
  146. offsetRight : number -> offset from right. Default: 0
  147. offsetBottom : number -> offset from bottom. Default: 0
  148. offsetLeft : number -> offset from left. Default: 0
  149. * @returns {jQuery}
  150. */
  151. $.scrollSpy = function(selector, options) {
  152. selector = $(selector);
  153. selector.each(function(i, element) {
  154. elements.push($(element));
  155. });
  156. options = options || {
  157. throttle: 100
  158. };
  159. offset.top = options.offsetTop || 0;
  160. offset.right = options.offsetRight || 0;
  161. offset.bottom = options.offsetBottom || 0;
  162. offset.left = options.offsetLeft || 0;
  163. var throttledScroll = throttle(onScroll, options.throttle || 100);
  164. var readyScroll = function(){
  165. $(document).ready(throttledScroll);
  166. };
  167. if (!isSpying) {
  168. jWindow.on('scroll', readyScroll);
  169. jWindow.on('resize', readyScroll);
  170. isSpying = true;
  171. }
  172. // perform a scan once, after current execution context, and after dom is ready
  173. setTimeout(readyScroll, 0);
  174. return selector;
  175. };
  176. /**
  177. * Listen for window resize events
  178. * @param {Object=} options Optional. Set { throttle: number } to change throttling. Default: 100 ms
  179. * @returns {jQuery} $(window)
  180. */
  181. $.winSizeSpy = function(options) {
  182. $.winSizeSpy = function() { return jWindow; }; // lock from multiple calls
  183. options = options || {
  184. throttle: 100
  185. };
  186. return jWindow.on('resize', throttle(onWinSize, options.throttle || 100));
  187. };
  188. /**
  189. * Enables ScrollSpy on a collection of elements
  190. * e.g. $('.scrollSpy').scrollSpy()
  191. * @param {Object=} options Optional.
  192. throttle : number -> scrollspy throttling. Default: 100 ms
  193. offsetTop : number -> offset from top. Default: 0
  194. offsetRight : number -> offset from right. Default: 0
  195. offsetBottom : number -> offset from bottom. Default: 0
  196. offsetLeft : number -> offset from left. Default: 0
  197. * @returns {jQuery}
  198. */
  199. $.fn.scrollSpy = function(options) {
  200. return $.scrollSpy($(this), options);
  201. };
  202. })(jQuery);