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