123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /* global Fluid, CONFIG */
- window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
- Fluid.utils = {
- listenScroll: function(callback) {
- var dbc = new Debouncer(callback);
- window.addEventListener('scroll', dbc, false);
- dbc.handleEvent();
- return dbc;
- },
- unlistenScroll: function(callback) {
- window.removeEventListener('scroll', callback);
- },
- listenDOMLoaded(callback) {
- if (document.readyState !== 'loading') {
- callback();
- } else {
- document.addEventListener('DOMContentLoaded', function () {
- callback();
- });
- }
- },
- scrollToElement: function(target, offset) {
- var of = jQuery(target).offset();
- if (of) {
- jQuery('html,body').animate({
- scrollTop: of.top + (offset || 0),
- easing : 'swing'
- });
- }
- },
- elementVisible: function(element, offsetFactor) {
- offsetFactor = offsetFactor && offsetFactor >= 0 ? offsetFactor : 0;
- var rect = element.getBoundingClientRect();
- const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
- return (
- (rect.top >= 0 && rect.top <= viewportHeight * (1 + offsetFactor) + rect.height / 2) ||
- (rect.bottom >= 0 && rect.bottom <= viewportHeight * (1 + offsetFactor) + rect.height / 2)
- );
- },
- waitElementVisible: function(selectorOrElement, callback, offsetFactor) {
- var runningOnBrowser = typeof window !== 'undefined';
- var isBot = (runningOnBrowser && !('onscroll' in window))
- || (typeof navigator !== 'undefined' && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent));
- if (!runningOnBrowser || isBot) {
- return;
- }
- offsetFactor = offsetFactor && offsetFactor >= 0 ? offsetFactor : 0;
- function waitInViewport(element) {
- Fluid.utils.listenDOMLoaded(function() {
- if (Fluid.utils.elementVisible(element, offsetFactor)) {
- callback();
- return;
- }
- if ('IntersectionObserver' in window) {
- var io = new IntersectionObserver(function(entries, ob) {
- if (entries[0].isIntersecting) {
- callback();
- ob.disconnect();
- }
- }, {
- threshold : [0],
- rootMargin: (window.innerHeight || document.documentElement.clientHeight) * offsetFactor + 'px'
- });
- io.observe(element);
- } else {
- var wrapper = Fluid.utils.listenScroll(function() {
- if (Fluid.utils.elementVisible(element, offsetFactor)) {
- Fluid.utils.unlistenScroll(wrapper);
- callback();
- }
- });
- }
- });
- }
- if (typeof selectorOrElement === 'string') {
- this.waitElementLoaded(selectorOrElement, function(element) {
- waitInViewport(element);
- });
- } else {
- waitInViewport(selectorOrElement);
- }
- },
- waitElementLoaded: function(selector, callback) {
- var runningOnBrowser = typeof window !== 'undefined';
- var isBot = (runningOnBrowser && !('onscroll' in window))
- || (typeof navigator !== 'undefined' && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent));
- if (!runningOnBrowser || isBot) {
- return;
- }
- if ('MutationObserver' in window) {
- var mo = new MutationObserver(function(records, ob) {
- var ele = document.querySelector(selector);
- if (ele) {
- callback(ele);
- ob.disconnect();
- }
- });
- mo.observe(document, { childList: true, subtree: true });
- } else {
- Fluid.utils.listenDOMLoaded(function() {
- var waitLoop = function() {
- var ele = document.querySelector(selector);
- if (ele) {
- callback(ele);
- } else {
- setTimeout(waitLoop, 100);
- }
- };
- waitLoop();
- });
- }
- },
- createScript: function(url, onload) {
- var s = document.createElement('script');
- s.setAttribute('src', url);
- s.setAttribute('type', 'text/javascript');
- s.setAttribute('charset', 'UTF-8');
- s.async = false;
- if (typeof onload === 'function') {
- if (window.attachEvent) {
- s.onreadystatechange = function() {
- var e = s.readyState;
- if (e === 'loaded' || e === 'complete') {
- s.onreadystatechange = null;
- onload();
- }
- };
- } else {
- s.onload = onload;
- }
- }
- var ss = document.getElementsByTagName('script');
- var e = ss.length > 0 ? ss[ss.length - 1] : document.head || document.documentElement;
- e.parentNode.insertBefore(s, e.nextSibling);
- },
- createCssLink: function(url) {
- var l = document.createElement('link');
- l.setAttribute('rel', 'stylesheet');
- l.setAttribute('type', 'text/css');
- l.setAttribute('href', url);
- var e = document.getElementsByTagName('link')[0]
- || document.getElementsByTagName('head')[0]
- || document.head || document.documentElement;
- e.parentNode.insertBefore(l, e);
- },
- loadComments: function(selector, loadFunc) {
- var ele = document.querySelector('#comments[lazyload]');
- if (ele) {
- var callback = function() {
- loadFunc();
- ele.removeAttribute('lazyload');
- };
- Fluid.utils.waitElementVisible(selector, callback, CONFIG.lazyload.offset_factor);
- } else {
- loadFunc();
- }
- },
- getBackgroundLightness(selectorOrElement) {
- var ele = selectorOrElement;
- if (typeof selectorOrElement === 'string') {
- ele = document.querySelector(selectorOrElement);
- }
- var view = ele.ownerDocument.defaultView;
- if (!view) {
- view = window;
- }
- var rgbArr = view.getComputedStyle(ele).backgroundColor.replace(/rgba*\(/, '').replace(')', '').split(/,\s*/);
- if (rgbArr.length < 3) {
- return 0;
- }
- var colorCast = (0.213 * rgbArr[0]) + (0.715 * rgbArr[1]) + (0.072 * rgbArr[2]);
- return colorCast === 0 || colorCast > 255 / 2 ? 1 : -1;
- },
- retry(handler, interval, times) {
- if (times <= 0) {
- return;
- }
- var next = function() {
- if (--times >= 0 && !handler()) {
- setTimeout(next, interval);
- }
- };
- setTimeout(next, interval);
- }
- };
- /**
- * Handles debouncing of events via requestAnimationFrame
- * @see http://www.html5rocks.com/en/tutorials/speed/animations/
- * @param {Function} callback The callback to handle whichever event
- */
- function Debouncer(callback) {
- this.callback = callback;
- this.ticking = false;
- }
- Debouncer.prototype = {
- constructor: Debouncer,
- /**
- * dispatches the event to the supplied callback
- * @private
- */
- update: function() {
- this.callback && this.callback();
- this.ticking = false;
- },
- /**
- * ensures events don't get stacked
- * @private
- */
- requestTick: function() {
- if (!this.ticking) {
- requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
- this.ticking = true;
- }
- },
- /**
- * Attach this as the event listeners
- */
- handleEvent: function() {
- this.requestTick();
- }
- };
|