1/** 2 * 'scrolledintoview', 'scrolledoutofview' events. 3 * Scrolled into/outof view for elements/selectors 4 * 5 * // detect elment is in view 6 * $elm.isInView() : true/false 7 * 8 * // enable watching scroll into/outof view for elements 9 * $.registerOnScrolledIntoView(elm) 10 * $.registerOnScrolledIntoView($elm) 11 * $.registerOnScrolledIntoView('selector') 12 * 13 * // on scrolled into view 14 * $elm.on('scrolledintoview', function(){}) 15 * $(document).on('scrolledintoview', 'selector', function(){}); 16 * 17 * // on scrolled out of view 18 * $elm.on('scrolledoutofview', function(){}) 19 * $(document).on('scrolledoutofview', 'selector', function(){}); 20 * 21 * $elm.off('scrolledintoview') 22 * $elm.off('scrolledoutofview') 23 * $(document).off('scrolledintoview', 'selector'); 24 * $(document).off('scrolledoutofview', 'selector'); 25 * + 26 * // disable watching scroll into/outof view for elements 27 * $.unregisterOnScrolledIntoView(elm) 28 * $.unregisterOnScrolledIntoView($elm) 29 * $.unregisterOnScrolledIntoView('selector') 30 * 31 */ 32 33(function($){ 34 35var DEBUG = (location.search.indexOf('_cs=0') != -1); 36 37if ($.registerOnScrolledIntoView) { return; } 38console.log('jquery-onscrolledintoview.js loaded.'); 39 40var VH = $(window).height(); 41$(window).on('resize', function(){ 42 VH = $(window).height(); 43}); 44var ST = $(window).scrollTop(), LAST_ST = ST, SCROLLING_DOWN = false, SCROLLING_UP = false; 45$(window).on('scroll', function(){ 46 ST = $(window).scrollTop(); 47 SCROLLING_DOWN = ST > LAST_ST; 48 SCROLLING_UP = ST < LAST_ST; 49 LAST_ST = ST; 50}); 51 52// offset, heightåè¨ç®æå°ééms 53var METRICS_EXPIRE_MS = 100; 54 55$.fn.isInView = function(offset){ 56 // offset = window position offset 57 offset = offset === undefined ? 0 : offset; 58 var $elm = $(this), 59 metrics = $(this).data('metrics'), 60 now = new Date().getTime(); 61 if (!metrics || metrics.expire < now ) { 62 metrics = { 63 expire: now + METRICS_EXPIRE_MS, 64 offset:$elm.offset(), 65 height:$elm.outerHeight() 66 }; 67 $elm.data('metrics', metrics); 68 } 69 70 if (!metrics.offset || !metrics.height) { 71 return false; 72 } 73 74 var et = metrics.offset.top, eb = et + metrics.height; 75 var ret = et < ST + VH + offset && eb > ST + offset && $elm.is(':visible'); 76 77 // parents scroll 78 79 // check overflowed in parents 80 if (ret) { 81 var $p = $elm.parentsUntil('body').filter(function(){ 82 return this.clientHeight != this.scrollHeight 83 && $(this).css('overflow') != 'visible'; 84 }) 85 .each(function(){ 86 87 // DEBUG && console.log('isInView:checking hidden parent', this); 88 89 var $c = $(this), 90 metrics = $c.data('metrics'), 91 now = new Date().getTime(); 92 93 if (!metrics || metrics.expire < now ) { 94 metrics = {
95 expire: now + METRICS_EXPIRE_MS, 96 offset:$c.offset(), 97 height:$c.outerHeight() 98 }; 99 $c.data('metrics', metrics); 100 } 101 102 var pt = metrics.offset.top, 103 pb = pt + metrics.height; 104 105 if (et > pb || eb < pt ){ 106 // hidden by parent scroll 107 108 // DEBUG && console.log('isInView:hidden by parent', this); 109 110 ret = false; 111 return false; 112 } 113 }); 114 } 115 116 // DEBUG && console.log('isInView:' + ret, $elm); 117 118 return ret; 119} 120 121var WATCHING_SELECTORS = []; 122var WATCH_INTERVAL = 1000/30; // 30fps 123 124var WATCHING_SELECTOR = ''; 125var $WATCHING_ELEMENTS = $(); 126 127$.registerOnScrolledIntoView = function(target){ 128 if (typeof target == 'string') { 129 if ($.inArray(target, WATCHING_SELECTORS) == -1){ 130 WATCHING_SELECTORS.push(target); 131 WATCHING_SELECTOR = WATCHING_SELECTORS.join(','); 132 } 133 } else { 134 $WATCHING_ELEMENTS.add($(target)); 135 $(target).on('remove DOMNodeRemoved', function(ev){ 136 $.unregisterOnScrolledIntoView(ev.target); 137 }); 138 } 139 checkInView(); 140}; 141 142$.unregisterOnScrolledIntoView = function(target){ 143 if (typeof target == 'string') { 144 var idx = $.inArray(target, WATCHING_SELECTORS); 145 if (idx == -1){ 146 WATCHING_SELECTORS.splice(idx, 1); 147 WATCHING_SELECTOR = WATCHING_SELECTORS.join(','); 148 } 149 } else { 150 target = $(target); 151 $WATCHING_ELEMENTS = $WATCHING_ELEMENTS.filter(function(){ 152 return !target.is(this); 153 }); 154 } 155 checkInView(); 156}; 157 158if (window.IntersectionObserver && window.MutationObserver) { 159 function isTarget(node) { 160 return (WATCHING_SELECTOR && node.matches(WATCHING_SELECTOR)) 161 || !!($WATCHING_ELEMENTS.filter(function(){return $(this).is(node)})[0]); 162 } 163 var intersection_observer = new IntersectionObserver(function(entries){ 164 entries.forEach(function(entry){ 165 if (entry.isIntersecting) { 166 DEBUG && console.log('onscrolledintoview:scrolled into view', entry.target); 167 $(entry.target).trigger('scrolledintoview'); 168 } else { 169 DEBUG && console.log('onscrolledintoview:scrolled outof view', entry.target); 170 $(entry.target).trigger('scrolledoutofview'); 171 } 172 }) 173 }, { 174 root: null, 175 rootMargin: "0px", 176 threshold: 0, 177 }); 178 var mutation_observer = new MutationObserver(function(mutations){ 179 mutations.forEach(function(mutation){ 180 mutation.addedNodes.forEach(function(node){ 181 if (node.nodeType == node.ELEMENT_NODE) { 182 if (isTarget(node)) { 183 DEBUG && console.log('onscrolledintoview:io.observe', node) 184 intersection_observer.observe(node); 185 } else { 186 $(node).find(WATCHING_SELECTOR).each(function(){ 187 DEBUG && console.log('onscrolledintoview:io.observe', this) 188 intersection_observer.observe(this); 189 }); 190 } 191 } 192 }); 193 mutation.removedNodes.forEach(function(node){ 194 if (node.nodeType == node.ELEMENT_NODE) { 195 if (isTarget(node)) { 196 DEBUG && console.log('onscrolledintoview:io.unobserve', node) 197 intersection_observer.unobserve(node); 198 } else { 199 $(node).find(WATCHING_SELECTOR).each(function(){ 200 DEBUG && console.log('onscrolledintoview:io.unobserve', this) 201 intersection_observer.unobserve(this); 202 }); 203 } 204 } 205 }); 206 }) 207 }); 208 $(function(){ 209 mutation_observer.observe(document.body, { 210 childList:true, 211 subtree:true, 212 }); 213 }); 214 $.registerOnScrolledIntoView = function(target){ 215 DEBUG && console.log('onscrolledintoview:register:' + target); 216 if (typeof target == 'string') { 217 if ($.inArray(target, WATCHING_SELECTORS) == -1){ 218 WATCHING_SELECTORS.push(target); 219 WATCHING_SELECTOR = WATCHING_SELECTORS.join(','); 220 DEBUG && console.log('onscrolledintoview:WATCHING_SELECTOR=' + WATCHING_SELECTOR); 221 } 222 $(target).each(function(){ 223 DEBUG && console.log('onscrolledintoview:io.observe', this) 224 intersection_observer.observe(this); 225 }); 226 } else { 227 $WATCHING_ELEMENTS.add($(target)); 228 $(target).on('remove DOMNodeRemoved', function(ev){ 229 $.unregisterOnScrolledIntoView(ev.target); 230 }); 231 $(target).each(function(){ 232 DEBUG && console.log('onscrolledintoview:io.observe', this); 233 intersection_observer.observe(this); 234 }) 235 } 236 checkInView(); 237 }; 238 239 $.unregisterOnScrolledIntoView = function(target){ 240 DEBUG && console.log('onscrolledintoview:unregister:' + target); 241 if (typeof target == 'string') { 242 var idx = $.inArray(target, WATCHING_SELECTORS); 243 if (idx == -1){ 244 WATCHING_SELECTORS.splice(idx, 1); 245 WATCHING_SELECTOR = WATCHING_SELECTORS.join(','); 246 DEBUG && console.log('onscrolledintoview:WATCHING_SELECTOR=' + WATCHING_SELECTOR); 247 } 248 $(target).each(function(){ 249 DEBUG && console.log('onscrolledintoview:io.unobserve', this); 250 intersection_observer.unobserve(this); 251 }); 252 } else { 253 target = $(target); 254 $WATCHING_ELEMENTS = $WATCHING_ELEMENTS.filter(function(){ 255 return !target.is(this); 256 }); 257 $(target).each(function(){ 258 DEBUG && console.log('onscrolledintoview:io.unobserve', this); 259 intersection_observer.unobserve(this); 260 }); 261 } 262 checkInView(); 263 }; 264 return; 265} 266 267 268// ã¹ã¯ãã¼ã«ããªãµã¤ãºä¸ãã©ãããæ¤ç¥ 269var ONSCROLL_MS = 1000/33; // 33fps 270 271var scrolling = false, _t; 272$(window).on('scroll resize', function(){ 273 clearTimeout(_t); 274 scrolling = true; 275 _t = setTimeout(function(){ 276 scrolling = false;
277 }, ONSCROLL_MS); 278}); 279 280// ã¹ã¯ãã¼ã«ããªãµã¤ãºä¸ã®å ´åã®ã¿ãviewã«å ¥ã£ã¦ããããã§ã㯠281var REFRESH_INTERVAL = 1000/4; // 4fps 282var _REFRESH_CNT = Math.floor(REFRESH_INTERVAL / ONSCROLL_MS); 283 284var _refresh = _REFRESH_CNT; 285setInterval(function(){ 286 if (scrolling || _refresh == 0) { 287 checkInView(); 288 } 289 _refresh--; 290 if (_refresh < 0) { 291 _refresh = _REFRESH_CNT; 292 } 293}, ONSCROLL_MS); 294 295function checkInView() { 296 var $target = $(WATCHING_SELECTOR).add($WATCHING_ELEMENTS); 297 $target.each(function(){ 298 var $elm = $(this), in_view_old = $elm.data('in_view') || {}; 299 300 // 1ç»é¢ä¸ãã¸ã£ã¹ãã1ç»é¢ä¸ãå¤å® 301 var in_view = { 302 above:$elm.isInView(-VH), 303 just:$elm.isInView(), 304 below:$elm.isInView(VH) 305 }; 306 307 if (!in_view_old.just && in_view.just ) { 308 DEBUG && console.log('scrolledintoview', $elm); 309 $elm.trigger('scrolledintoview'); 310 } else if (in_view_old.just && !in_view.just) { 311 DEBUG && console.log('scrolledoutofview', $elm); 312 $elm.trigger('scrolledoutofview'); 313 } 314 if (SCROLLING_DOWN) { 315 // ã¹ã¯ãã¼ã«ãã¦ã³æã«1ç»é¢ä¸ã«å ¥ã£ã 316 if (!in_view_old.below && in_view.below) { 317 DEBUG && console.log('scrollingintoview:below', $elm); 318 $elm.trigger('scrollingintoview'); 319 } 320 } else if (SCROLLING_UP) { 321 // ã¹ã¯ãã¼ã«ã¢ããæã«1ç»é¢ä¸ã«å ¥ã£ã 322 if (!in_view_old.above && in_view.above) { 323 DEBUG && console.log('scrollingintoview:above', $elm); 324 $elm.trigger('scrollingintoview'); 325 } 326 } 327 328 $elm.data('in_view', in_view); 329 }); 330} 331 332})(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.