PageSourceSearch

https://gal2xy.github.io/js/utils.js

js gal2xy.github.io collected 2026-10-03 09:13:24 UTC 6,783 bytes, 231 lines download raw bytes

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.