1/* global Fluid, CONFIG */ 2 3window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; 4 5Fluid.utils = { 6 7 listenScroll: function(callback) { 8 var dbc = new Debouncer(callback); 9 window.addEventListener('scroll', dbc, false); 10 dbc.handleEvent(); 11 return dbc; 12 }, 13 14 unlistenScroll: function(callback) { 15 window.removeEventListener('scroll', callback); 16 }, 17 18 listenDOMLoaded(callback) { 19 if (document.readyState !== 'loading') { 20 callback(); 21 } else { 22 document.addEventListener('DOMContentLoaded', function () { 23 callback(); 24 }); 25 } 26 }, 27 28 scrollToElement: function(target, offset) { 29 var of = jQuery(target).offset(); 30 if (of) { 31 jQuery('html,body').animate({ 32 scrollTop: of.top + (offset || 0), 33 easing : 'swing' 34 }); 35 } 36 }, 37 38 elementVisible: function(element, offsetFactor) { 39 offsetFactor = offsetFactor && offsetFactor >= 0 ? offsetFactor : 0; 40 var rect = element.getBoundingClientRect(); 41 const viewportHeight = window.innerHeight || document.documentElement.clientHeight; 42 return ( 43 (rect.top >= 0 && rect.top <= viewportHeight * (1 + offsetFactor) + rect.height / 2) || 44 (rect.bottom >= 0 && rect.bottom <= viewportHeight * (1 + offsetFactor) + rect.height / 2) 45 ); 46 }, 47 48 waitElementVisible: function(selectorOrElement, callback, offsetFactor) { 49 var runningOnBrowser = typeof window !== 'undefined'; 50 var isBot = (runningOnBrowser && !('onscroll' in window)) 51 || (typeof navigator !== 'undefined' && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent)); 52 if (!runningOnBrowser || isBot) { 53 return; 54 } 55 56 offsetFactor = offsetFactor && offsetFactor >= 0 ? offsetFactor : 0; 57 58 function waitInViewport(element) { 59 Fluid.utils.listenDOMLoaded(function() { 60 if (Fluid.utils.elementVisible(element, offsetFactor)) { 61 callback(); 62 return; 63 } 64 if ('IntersectionObserver' in window) { 65 var io = new IntersectionObserver(function(entries, ob) { 66 if (entries[0].isIntersecting) { 67 callback(); 68 ob.disconnect(); 69 } 70 }, { 71 threshold : [0], 72 rootMargin: (window.innerHeight || document.documentElement.clientHeight) * offsetFactor + 'px' 73 }); 74 io.observe(element); 75 } else { 76 var wrapper = Fluid.utils.listenScroll(function() { 77 if (Fluid.utils.elementVisible(element, offsetFactor)) { 78 Fluid.utils.unlistenScroll(wrapper); 79 callback(); 80 } 81 }); 82 } 83 }); 84 } 85 86 if (typeof selectorOrElement === 'string') { 87 this.waitElementLoaded(selectorOrElement, function(element) { 88 waitInViewport(element); 89 }); 90 } else { 91 waitInViewport(selectorOrElement); 92 } 93 }, 94 95 waitElementLoaded: function(selector, callback) { 96 var runningOnBrowser = typeof window !== 'undefined'; 97 var isBot = (runningOnBrowser && !('onscroll' in window)) 98 || (typeof navigator !== 'undefined' && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent)); 99 if (!runningOnBrowser || isBot) { 100 return; 101 } 102 103 if ('MutationObserver' in window) { 104 var mo = new MutationObserver(function(records, ob) { 105 var ele = document.querySelector(selector); 106 if (ele) { 107 callback(ele); 108 ob.disconnect(); 109 } 110 }); 111 mo.observe(document, { childList: true, subtree: true }); 112 } else { 113 Fluid.utils.listenDOMLoaded(function() { 114 var waitLoop = function() { 115 var ele = document.querySelector(selector); 116 if (ele) { 117 callback(ele); 118 } else { 119 setTimeout(waitLoop, 100); 120 } 121 }; 122 waitLoop(); 123 }); 124 } 125 }, 126 127 createScript: function(url, onload) { 128 var s = document.createElement('script'); 129 s.setAttribute('src', url); 130 s.setAttribute('type', 'text/javascript'); 131 s.setAttribute('charset', 'UTF-8'); 132 s.async = false;
133 if (typeof onload === 'function') { 134 if (window.attachEvent) { 135 s.onreadystatechange = function() { 136 var e = s.readyState; 137 if (e === 'loaded' || e === 'complete') { 138 s.onreadystatechange = null; 139 onload(); 140 } 141 }; 142 } else { 143 s.onload = onload; 144 } 145 } 146 var ss = document.getElementsByTagName('script'); 147 var e = ss.length > 0 ? ss[ss.length - 1] : document.head || document.documentElement; 148 e.parentNode.insertBefore(s, e.nextSibling); 149 }, 150 151 createCssLink: function(url) { 152 var l = document.createElement('link'); 153 l.setAttribute('rel', 'stylesheet'); 154 l.setAttribute('type', 'text/css'); 155 l.setAttribute('href', url); 156 var e = document.getElementsByTagName('link')[0] 157 || document.getElementsByTagName('head')[0] 158 || document.head || document.documentElement; 159 e.parentNode.insertBefore(l, e); 160 }, 161 162 loadComments: function(selector, loadFunc) { 163 var ele = document.querySelector('#comments[lazyload]'); 164 if (ele) { 165 var callback = function() { 166 loadFunc(); 167 ele.removeAttribute('lazyload'); 168 }; 169 Fluid.utils.waitElementVisible(selector, callback, CONFIG.lazyload.offset_factor); 170 } else { 171 loadFunc(); 172 } 173 }, 174 175 getBackgroundLightness(selectorOrElement) { 176 var ele = selectorOrElement; 177 if (typeof selectorOrElement === 'string') { 178 ele = document.querySelector(selectorOrElement); 179 } 180 var view = ele.ownerDocument.defaultView; 181 if (!view) { 182 view = window; 183 } 184 var rgbArr = view.getComputedStyle(ele).backgroundColor.replace(/rgba*\(/, '').replace(')', '').split(/,\s*/); 185 if (rgbArr.length < 3) { 186 return 0; 187 } 188 var colorCast = (0.213 * rgbArr[0]) + (0.715 * rgbArr[1]) + (0.072 * rgbArr[2]); 189 return colorCast === 0 || colorCast > 255 / 2 ? 1 : -1; 190 }, 191 192 retry(handler, interval, times) { 193 if (times <= 0) { 194 return; 195 } 196 var next = function() { 197 if (--times >= 0 && !handler()) { 198 setTimeout(next, interval); 199 } 200 }; 201 setTimeout(next, interval); 202 } 203 204}; 205 206/** 207 * Handles debouncing of events via requestAnimationFrame 208 * @see http://www.html5rocks.com/en/tutorials/speed/animations/ 209 * @param {Function} callback The callback to handle whichever event 210 */ 211function Debouncer(callback) { 212 this.callback = callback; 213 this.ticking = false; 214} 215 216Debouncer.prototype = { 217 constructor: Debouncer, 218 219 /** 220 * dispatches the event to the supplied callback 221 * @private 222 */ 223 update: function() { 224 this.callback && this.callback(); 225 this.ticking = false; 226 }, 227 228 /** 229 * ensures events don't get stacked 230 * @private 231 */ 232 requestTick: function() { 233 if (!this.ticking) { 234 requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))); 235 this.ticking = true; 236 } 237 }, 238 239 /** 240 * Attach this as the event listeners 241 */ 242 handleEvent: function() { 243 this.requestTick(); 244 } 245};
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.