PageSourceSearch

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

js kee02p.github.io collected 2026-10-03 09:27:09 UTC 7,153 bytes, 245 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  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.