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.