1(() => { 2 const utilsFn = { 3 throttle: (func, wait, { leading = true, trailing = true } = {}) => { 4 let timeout, 5 previous = 0; 6 const later = (context, args) => { 7 timeout = previous = leading === false ? 0 : Date.now(); 8 func.apply(context, args); 9 }; 10 return function () { 11 const now = Date.now(); 12 if (!previous && leading === false) previous = now; 13 const remaining = wait - (now - previous); 14 if (remaining <= 0 || remaining > wait) { 15 if (timeout) clearTimeout(timeout); 16 later(this, arguments); 17 } else if (!timeout && trailing !== false) { 18 timeout = setTimeout(() => later(this, arguments), remaining); 19 } 20 }; 21 }, 22 fadeIn: (ele, time) => { 23 ele.style.display = "block"; 24 ele.style.animation = `to_show ${time}s`; 25 }, 26 fadeOut: (ele, time) => { 27 const resetStyles = () => { 28 ele.style.display = "none"; 29 ele.style.animation = ""; 30 ele.removeEventListener("animationend", resetStyles); 31 }; 32 ele.addEventListener("animationend", resetStyles); 33 ele.style.animation = `to_hide ${time}s`; 34 }, 35 snackbarShow: (text, showAction = false, duration = 5000) => { 36 Snackbar.show({ text, showAction, duration, pos: "top-center" }); 37 }, 38 copy: async (text) => { 39 const message = await navigator.clipboard 40 .writeText(text) 41 .then(() => GLOBAL_CONFIG.lang.copy.success) 42 .catch(() => GLOBAL_CONFIG.lang.copy.error); 43 utils.snackbarShow(message, false, 2000); 44 }, 45 getEleTop: (ele) => { 46 let actualTop = ele.offsetTop; 47 while (ele.offsetParent) { 48 ele = ele.offsetParent; 49 actualTop += ele.offsetTop; 50 } 51 return actualTop; 52 }, 53 siblings: (ele, selector) => { 54 return [...ele.parentNode.children].filter( 55 (child) => child !== ele && (!selector || child.matches(selector)) 56 ); 57 }, 58 randomNum: (length) => Math.floor(Math.random() * length), 59 timeDiff: (timeObj, today) => 60 Math.floor((today.getTime() - timeObj.getTime()) / (1000 * 3600 * 24)), 61 scrollToDest: (pos, time = 500) => { 62 const currentPos = window.pageYOffset; 63 const isNavFixed = document 64 .getElementById("page-header") 65 .classList.contains("nav-fixed"); 66 pos = currentPos > pos || isNavFixed ? pos - 70 : pos; 67 68 if ("scrollBehavior" in document.documentElement.style) { 69 window.scrollTo({ top: pos, behavior: "smooth" }); 70 return; 71 } 72 73 const distance = pos - currentPos; 74 const step = (currentTime) => { 75 const progress = currentTime - (start || currentTime); 76 if (progress < time) { 77 window.scrollTo(0, currentPos + (distance * progress) / time); 78 window.requestAnimationFrame(step); 79 } else { 80 window.scrollTo(0, pos); 81 } 82 }; 83 84 window.requestAnimationFrame(step); 85 }, 86 isMobile: () => 87 /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( 88 navigator.userAgent 89 ), 90 isHidden: (e) => e.offsetHeight === 0 && e.offsetWidth === 0, 91 animateIn: (ele, text) => { 92 Object.assign(ele.style, { display: "block", animation: text }); 93 }, 94 animateOut: (ele, text) => { 95 const resetAnimation = () => { 96 ele.style.display = ""; 97 ele.style.animation = ""; 98 ele.removeEventListener("animationend", resetAnimation); 99 }; 100 ele.addEventListener("animationend", resetAnimation); 101 ele.style.animation = text; 102 }, 103 wrap: (selector, eleType, options) => { 104 const createEle = document.createElement(eleType); 105 Object.entries(options).forEach(([key, value]) => 106 createEle.setAttribute(key, value) 107 ); 108 selector.parentNode.insertBefore(createEle, selector); 109 createEle.appendChild(selector); 110 }, 111 lazyloadImg: () => { 112 window.lazyLoadInstance = new LazyLoad({ 113 elements_selector: "img", 114 threshold: 0, 115 data_src: "lazy-src", 116 callback_error: (img) => (img.src = GLOBAL_CONFIG.lazyload.error), 117 }); 118 }, 119 lightbox: function (selector) { 120 const lightboxType = GLOBAL_CONFIG.lightbox; 121 const options = { 122 class: "fancybox", 123 "data-fancybox": "gallery", 124 }; 125 126 if (lightboxType === "mediumZoom") { 127 mediumZoom && 128 mediumZoom(selector, { background: "var(--efu-card-bg)" }); 129 } else if (lightboxType === "fancybox") { 130 selector.forEach((i) => { 131 if (i.parentNode.tagName !== "A") { 132 options.href = options["data-thumb"] = i.dataset.lazySrc || i.src; 133 options["data-caption"] = i.title || i.alt || ""; 134 utils.wrap(i, "a", options); 135 } 136 }); 137 138 if (!window.fancyboxRun) { 139 Fancybox.bind("[data-fancybox]", { 140 Hash: false, 141 animated: true, 142 Thumbs: { showOnStart: false }, 143 Images: { Panzoom: { maxScale: 4 } }, 144 Carousel: { transition: "slide" }, 145 Toolbar: { 146 display: { 147 left: ["infobar"], 148 middle: [ 149 "zoomIn", 150 "zoomOut", 151 "toggle1to1", 152 "rotateCCW", 153 "rotateCW", 154 "flipX", 155 "flipY", 156 ], 157 right: ["slideshow", "thumbs", "close"], 158 }, 159 }, 160 }); 161 window.fancyboxRun = true; 162 } 163 } 164 }, 165 diffDate: (d, more = false) => { 166 const dateNow = new Date(); 167 const datePost = new Date(d); 168 const dateDiff = dateNow - datePost; 169 const minute = 60000; 170 const hour = 3600000; 171 const day = 86400000;
172 const month = 2592000000; 173 const { time } = GLOBAL_CONFIG.lang; 174 175 const dayCount = Math.floor(dateDiff / day); 176 if (!more) return dayCount; 177 178 const minuteCount = Math.floor(dateDiff / minute); 179 const hourCount = Math.floor(dateDiff / hour); 180 const monthCount = Math.floor(dateDiff / month); 181 182 if (monthCount > 12) return datePost.toISOString().slice(0, 10); 183 if (monthCount >= 1) return `${monthCount} ${time.month}`; 184 if (dayCount >= 1) return `${dayCount} ${time.day}`; 185 if (hourCount >= 1) return `${hourCount} ${time.hour}`; 186 if (minuteCount >= 1) return `${minuteCount} ${time.min}`; 187 return time.just; 188 }, 189 loadComment: (dom, callback) => { 190 const observerItem = 191 "IntersectionObserver" in window 192 ? new IntersectionObserver( 193 (entries) => { 194 if (entries[0].isIntersecting) { 195 callback(); 196 observerItem.disconnect(); 197 } 198 }, 199 { threshold: [0] } 200 ) 201 : null; 202 203 observerItem ? observerItem.observe(dom) : callback(); 204 }, 205 escapeHtml: (unsafe) => 206 unsafe.replace( 207 /[&<"']/g, 208 (m) => 209 ({ 210 "&": "&", 211 "<": "<", 212 '"': """, 213 "'": "'", 214 }[m]) 215 ), 216 }; 217 window.utils = { ...window.utils, ...utilsFn }; 218})();
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.