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