PageSourceSearch

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

js eacls.github.io collected 2026-10-03 09:06:23 UTC 7,695 bytes, 278 lines download raw bytes

1const btf = {
2  debounce: function (func, wait, immediate) {
3    let timeout
4    return function () {
5      const context = this
6      const args = arguments
7      const later = function () {
8        timeout = null
9        if (!immediate) func.apply(context, args)
10      }
11      const callNow = immediate && !timeout
12      clearTimeout(timeout)
13      timeout = setTimeout(later, wait)
14      if (callNow) func.apply(context, args)
15    }
16  },
17
18  throttle: function (func, wait, options) {
19    let timeout, context, args
20    let previous = 0
21    if (!options) options = {}
22
23    const later = function () {
24      previous = options.leading === false ? 0 : new Date().getTime()
25      timeout = null
26      func.apply(context, args)
27      if (!timeout) context = args = null
28    }
29
30    const throttled = function () {
31      const now = new Date().getTime()
32      if (!previous && options.leading === false) previous = now
33      const remaining = wait - (now - previous)
34      context = this
35      args = arguments
36      if (remaining <= 0 || remaining > wait) {
37        if (timeout) {
38          clearTimeout(timeout)
39          timeout = null
40        }
41        previous = now
42        func.apply(context, args)
43        if (!timeout) context = args = null
44      } else if (!timeout && options.trailing !== false) {
45        timeout = setTimeout(later, remaining)
46      }
47    }
48
49    return throttled
50  },
51
52  sidebarPaddingR: () => {
53    const innerWidth = window.innerWidth
54    const clientWidth = document.body.clientWidth
55    const paddingRight = innerWidth - clientWidth
56    if (innerWidth !== clientWidth) {
57      document.body.style.paddingRight = paddingRight + 'px'
58    }
59  },
60
61  snackbarShow: (text, showAction = false, duration = 2000) => {
62    const { position, bgLight, bgDark } = GLOBAL_CONFIG.Snackbar
63    const bg = document.documentElement.getAttribute('data-theme') === 'light' ? bgLight : bgDark
64    Snackbar.show({
65      text: text,
66      backgroundColor: bg,
67      showAction: showAction,
68      duration: duration,
69      pos: position,
70      customClass: 'snackbar-css'
71    })
72  },
73
74  diffDate: (d, more = false) => {
75    const dateNow = new Date()
76    const datePost = new Date(d)
77    const dateDiff = dateNow.getTime() - datePost.getTime()
78    const minute = 1000 * 60
79    const hour = minute * 60
80    const day = hour * 24
81    const month = day * 30
82
83    let result
84    if (more) {
85      const monthCount = dateDiff / month
86      const dayCount = dateDiff / day
87      const hourCount = dateDiff / hour
88      const minuteCount = dateDiff / minute
89
90      if (monthCount > 12) {
91        result = datePost.toLocaleDateString().replace(/\//g, '-')
92      } else if (monthCount >= 1) {
93        result = parseInt(monthCount) + ' ' + GLOBAL_CONFIG.date_suffix.month
94      } else if (dayCount >= 1) {
95        result = parseInt(dayCount) + ' ' + GLOBAL_CONFIG.date_suffix.day
96      } else if (hourCount >= 1) {
97        result = parseInt(hourCount) + ' ' + GLOBAL_CONFIG.date_suffix.hour
98      } else if (minuteCount >= 1) {
99        result = parseInt(minuteCount) + ' ' + GLOBAL_CONFIG.date_suffix.min
100      } else {
101        result = GLOBAL_CONFIG.date_suffix.just
102      }
103    } else {
104      result = parseInt(dateDiff / day)
105    }
106    return result
107  },
108
109  loadComment: (dom, callback) => {
110    if ('IntersectionObserver' in window) {
111      const observerItem = new IntersectionObserver((entries) => {
112        if (entries[0].isIntersecting) {
113          callback()
114          observerItem.disconnect()
115        }
116      }, { threshold: [0] })
117      observerItem.observe(dom)
118    } else {
119      callback()
120    }
121  },
122
123  scrollToDest: (pos, time = 500) => {
124    const currentPos = window.pageYOffset
125    if (currentPos > pos) pos = pos - 70
126
127    if ('scrollBehavior' in document.documentElement.style) {
128      window.scrollTo({
129        top: pos,
130        behavior: 'smooth'
131      })
132      return
133    }
134
135    let start = null
136    pos = +pos
137    window.requestAnimationFrame(function step (currentTime) {
138      start = !start ? currentTime : start
139      const progress = currentTime - start
140      if (currentPos < pos) {
141        window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos)
142      } else {
143        window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time))
144      }
145      if (progress < time) {
146        window.requestAnimationFrame(step)
147      } else {
148        window.scrollTo(0, pos)
149      }
150    })
151  },
152
153  animateIn: (ele, text) => {
154    ele.style.display = 'block'
155    ele.style.animation = text
156  },
157
158  animateOut: (ele, text) => {
159    ele.addEventListener('animationend', function f () {
160      ele.style.display = ''
161      ele.style.animation = ''
162      ele.removeEventListener('animationend', f)
163    })
164    ele.style.animation = text
165  },
166
167  getParents: (elem, selector) => {
168    for (; elem && elem !== document; elem = elem.parentNode) {
169      if (elem.matches(selector)) return elem
170    }
171    return null
172  },
173
174  siblings: (ele, selector) => {
175    return [...ele.parentNode.children].filter((child) => {
176      if (selector) {
177        return child !== ele && child.matches(selector)
178      }
179      return child !== ele
180    })
181  },
182
183  /**
184   * @param {*} selector
185   * @param {*} eleType the type of create element
186   * @param {*} options object key: value
187   */
188  wrap: (selector, eleType, options) => {
189    const creatEle = document.createElement(eleType)
190    for (const [key, value] of Object.entries(options)) {
191      creatEle.setAttribute(key, value)
192    }
193    selector.parentNode.insertBefore(creatEle, selector)
194    creatEle.appendChild(selector)
195  },
196
197  unwrap: el => {
198    const elParentNode = el.parentNode
199    if (elParentNode !== document.body) {
200      elParentNode.parentNode.insertBefore(el, elParentNode)
201      elParentNode.parentNode.removeChild(elParentNode)
202    }
203  },
204
205  isHidden: ele => ele.offsetHeight === 0 && ele.offsetWidth === 0,
206
207  getEleTop: ele => {
208    let actualTop = ele.offsetTop
209    let current = ele.offsetParent
210
211    while (current !== null) {
212      actualTop += current.offsetTop
213      current = current.offsetParent
214    }
215
216    return actualTop
217  },
218
219  loadLightbox: ele => {
220    const service = GLOBAL_CONFIG.lightbox
221
222    if (service === 'mediumZoom') {
223      const zoom = mediumZoom(ele)
224      zoom.on('open', e => {
225        const photoBg = document.documentElement.getAttribute('data-theme') === 'dark' ? '#121212' : '#fff'
226        zoom.update({
227          background: photoBg
228        })
229      })
230    }
231
232    if (service === 'fancybox') {
233      ele.forEach(i => {
234        if (i.parentNode.tagName !== 'A') {
235          const dataSrc = i.dataset.lazySrc || i.src
236          const dataCaption = i.title || i.alt || ''
237          btf.wrap(i, 'a', { href: dataSrc, 'data-fancybox': 'gallery', 'data-caption': dataCaption, 'data-thumb'
237: dataSrc })
238        }
239      })
240
241      if (!window.fancyboxRun) {
242        Fancybox.bind('[data-fancybox]', {
243          Hash: false,
244          Thumbs: {
245            autoStart: false
246          }
247        })
248        window.fancyboxRun = true
249      }
250    }
251  },
252
253  initJustifiedGallery: function (selector) {
254    selector.forEach(function (i) {
255      if (!btf.isHidden(i)) {
256        fjGallery(i, {
257          itemSelector: '.fj-gallery-item',
258          rowHeight: 220,
259          gutter: 4,
260          onJustify: function () {
261            this.$container.style.opacity = '1'
262          }
263        })
264      }
265    })
266  },
267
268  updateAnchor: (anchor) => {
269    if (anchor !== window.location.hash) {
270      if (!anchor) anchor = location.pathname
271      const title = GLOBAL_CONFIG_SITE.title
272      window.history.replaceState({
273        url: location.href,
274        title: title
275      }, title, anchor)
276    }
277  }
278}

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.