1/* auth.js â ASCDC WAF èªèéå端(宿´ç,å¥çèª auth-ui-mockup)ãæ¬å¨æº:GitLab dockerfile/auth-www-nginxã 2 åè½:i18n 16 èªã深淺主é¡ãåå鏿å¨(ä¾èªç³»/OS,åªç¨æ¬æ©æ¢æåå)ãèæ¯åæ(4 款,<link> åæå CSP)ã 3 çååæ(split/portrait/stage)ã坿æ³åéç·ã顯示/é±èå¯ç¢¼ãè¨ä½å¸³èãå·¦å´å»£å輪æ(èªåæ+é²åº¦æ¢+ç®é +swipe)ã 4 â 䏿æªè¡¨å®éåº(çè¡¨å® = PHP POST /validUser);ç¡å captcha/åæå/demoã 5 ð´ pre-auth éç:CSP ç¶æ style-src/font-src 'self',å ¨é é¶å¤é£åå(ç¡ Google Fonts);èæ¯ç¨åæº <link> åæã */ 6(function () { 7 "use strict"; 8 var LS = { lang: "ascdc.lang", theme: "ascdc.theme", account: "ascdc.account", remember: "ascdc.remember", bg: "ascdc.bg.v3", layout: "ascdc.layout.v3", font: "ascdc.font", formw: "ascdc.formw" }; 9 var I18N = null, META = null, STR = null, LANG = null, adsUpdate = null; 10 var AB = "/auth-assets"; 11 function lsGet(k){try{return window.localStorage.getItem(k);}catch(e){return null;}} 12 function lsSet(k,v){try{window.localStorage.setItem(k,v);}catch(e){}} 13 function lsDel(k){try{window.localStorage.removeItem(k);}catch(e){}} 14 15 function loadI18N() { 16 return fetch(AB + "/i18n.json", { credentials: "same-origin" }) 17 .then(function (r) { if (!r.ok) throw new Error("i18n " + r.status); return r.json(); }) 18 .catch(function () { return window.__I18N__ || null; }); 19 } 20 function canonLang(tag) { 21 if (!tag) return null; 22 tag = String(tag).toLowerCase(); 23 if (tag === "zh" || tag.indexOf("zh-tw") === 0 || tag.indexOf("zh-hant") === 0 || tag.indexOf("zh-hk") === 0 || tag.indexOf("zh-mo") === 0) return "zh-Hant"; 24 if (tag.indexOf("zh-cn") === 0 || tag.indexOf("zh-hans") === 0 || tag.indexOf("zh-sg") === 0) return "zh-Hans"; 25 if (tag.indexOf("zh") === 0) return "zh-Hant"; 26 if (tag === "tl" || tag.indexOf("tl-") === 0 || tag.indexOf("fil") === 0) return "fil"; 27 var codes = Object.keys(I18N.strings); 28 for (var i = 0; i < codes.length; i++) { if (codes[i].toLowerCase() === tag) return codes[i]; } 29 var two = tag.slice(0, 2); 30 for (var j = 0; j < codes.length; j++) { if (codes[j].indexOf("-") < 0 && codes[j].toLowerCase() === two) return codes[j]; } 31 return null; 32 } 33 function pickLang() { 34 var docLang = canonLang(document.documentElement.getAttribute("lang")); 35 if (docLang && I18N.strings[docLang]) return docLang; 36 var saved = lsGet(LS.lang); 37 if (saved && I18N.strings[saved]) return saved; 38 var nav = canonLang(navigator.language || "en"); 39 if (nav && I18N.strings[nav]) return nav; 40 return META.fallback || "en"; 41 } 42 function applyLang(code) { 43 LANG = code; STR = I18N.strings[code] || I18N.strings[META.fallback || "en"]; 44 var info = (META.languages || []).filter(function (l) { return l.code === code; })[0] || { dir: "ltr" }; 45 document.documentElement.lang = code; 46 document.documentElement.dir = info.dir || "ltr"; 47 document.querySelectorAll("[data-i18n]").forEach(function (el) { var v = STR[el.dataset.i18n]; if (v != null) el.textContent = v; }); 48 document.querySelectorAll("[data-i18n-ph]").forEach(function (el) { var v = STR[el.dataset.i18nPh]; if (v != null) el.placeholder = v; }); 49 document.querySelectorAll("[data-i18n-aria]").forEach(function (el) { var v = STR[el.dataset.i18nAria]; if (v != null) el.setAttribute("aria-label", v); }); 50 var sel = document.getElementById("langSelect"); if (sel) sel.value = code; 51 if (STR.brand) document.title = STR.brand; // åèªè¨å³ææ´æ°åé æ¨é¡ 52 refreshFonts(); // åèªè¨ â 便°èªç³»é建å忏 å® 53 if (adsUpdate) adsUpdate(); 54 } 55 function buildLang() { 56 var sel = document.getElementById("langSelect"); if (!sel) return; 57 sel.innerHTML = (META.languages || []).map(function (l) { return '<option value="' + l.code + '">' + l.name + "</option>"; }).join(""); 58 sel.value = LANG; 59 sel.addEventListener("change", function () { 60 lsSet(LS.lang, sel.value); 61 // SameSite=Lax(é Strict):è·¨ç« SSO(id.ascdc.twâ*.openmuseum.tw)å°å /validUser æ¯é 層 GET, 62 // Strict ææ£ä½ AUTH_LANG 使èªç³»éç½®åé è¨ãè AUTH session cookie ç SameSite çç¥ä¸è´ã 63 document.cookie = "AUTH_LANG=" + encodeURIComponent(sel.value) + "; Path=/; Max-Age=31536000; SameSite=Lax; Secure"; 64 applyLang(sel.value); 65 }); 66 } 67 68 function sysDark() { return window.matchMedia && matchMedia("(prefers-color-scheme: dark)").matches; } 69 function initTheme() { 70 var saved = lsGet(LS.theme); 71 if (saved === "dark" || saved === "light") document.documentElement.setAttribute("data-theme", saved); 72 var btn = document.getElementById("themeToggle"); if (!btn) return; 73 btn.addEventListener("click", function () { 74 var cur = document.documentElement.getAttribute("data-theme") || (sysDark() ? "dark" : "light"); 75 var next = cur === "dark" ? "light" : "dark"; 76 document.documentElement.setAttribute("data-theme", next); 77 lsSet(LS.theme, next); 78 }); 79 } 80 81 /* ---------- èæ¯åæ(4 款;åæº <link> åæ,CSP style-src 'self' å 許)---------- */ 82 var BG_ORDER = ["aurora", "ivory", "orbs", "blueprint"]; 83 var BG_NAMES = { aurora: "極å ç´ Aurora", ivory: "宣ç´å¢¨é» Ivory", orbs: "éè¬å æ Orbs", blueprint: "èæ¬æ ¼ç¶² Blueprint" }; 84 function applyBg(key) { 85 var link = document.getElementById("bg-link"); 86 if (key === "aurora") { if (link && link.parentNode) link.parentNode.removeChild(link); } // é è¨ aurora å¨ auth.css 87 else { 88 if (!link) { link = document.createElement("link"); link.id = "bg-link"; link.rel = "stylesheet"; document.head.appendChild(link); } 89 link.href = AB + "/bg-" + key + ".css"; 90 } 91 document.documentElement.setAttribute("data-bg", key); 92 } 93 function initBg() { 94 var controls = document.querySelector(".controls"); if (!controls) return; 95 var saved = lsGet(LS.bg); 96 var cur = (saved && BG_ORDER.indexOf(saved) >= 0) ? saved : BG_ORDER[0]; 97 applyBg(cur); 98 var btn = document.createElement("button"); 99 btn.className = "theme-toggle"; btn.type = "button"; btn.id = "bgToggle";
99 btn.setAttribute("aria-label", "Background"); 100 btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="3"/><path d="M3 15l5-5 4 4 3-3 6 6"/><circle cx="8.5" cy="8.5" r="1.4"/></svg>'; 101 btn.title = "èæ¯ / Background: " + (BG_NAMES[cur] || cur); 102 btn.addEventListener("click", function () { 103 var i = BG_ORDER.indexOf(document.documentElement.getAttribute("data-bg") || BG_ORDER[0]); 104 var next = BG_ORDER[(i + 1) % BG_ORDER.length]; 105 lsSet(LS.bg, next); applyBg(next); btn.title = "èæ¯ / Background: " + (BG_NAMES[next] || next); 106 }); 107 controls.appendChild(btn); 108 } 109 110 /* ---------- åå鏿å¨(ä¾èªç³»+OS,åªç¨ä½¿ç¨è æ¬æ©æ¢æåå)---------- 111 pre-auth èªèééç:CSP ç¶æ style-src/font-src 'self',çµä¸å¤é£è¼åå(ç¡ Google Fonts)ã 112 æ¶µèåèªç³»åçåå(Win æ£é»/é é»/游ã´ã·ãã¯/Malgun/LeelawadeeãMac èæ¹/Hiragino/AppleSD/Thonburi); 113 fonts.js 䏿¨ web: çéæºååä¸å¾å¿½ç¥ä¸é¡¯ç¤ºãä¸è¼å ¥ã */ 114 function detectOS() { 115 var p = ((navigator.userAgentData && navigator.userAgentData.platform) || navigator.platform || navigator.userAgent || "").toLowerCase(); 116 if (p.indexOf("win") >= 0) return "win"; 117 if (p.indexOf("mac") >= 0 || p.indexOf("iphone") >= 0 || p.indexOf("ipad") >= 0 || p.indexOf("ios") >= 0) return "mac"; 118 if (p.indexOf("android") >= 0) return "android"; 119 if (p.indexOf("linux") >= 0) return "linux"; 120 return "other"; 121 } 122 var fontSel = null, fontOS = "other"; 123 function fontMap() { try { return JSON.parse(lsGet(LS.font) || "{}") || {}; } catch (e) { return {}; } } 124 function applyFont(id) { 125 var o = (window.__FONTS__ || []).filter(function (x) { return x.id === id; })[0]; 126 var rs = document.documentElement.style; 127 // system / ä¸åå¨ / ä»»ä½ web åå â ä¸å¾å系統å,çµä¸å¤é£è¼åå(pre-auth éç) 128 if (!o || id === "system" || o.web) { rs.removeProperty("--font"); rs.removeProperty("--font-display"); return; } 129 rs.setProperty("--font", o.stack); rs.setProperty("--font-display", o.stack); 130 } 131 function fLabel(k, fb) { return (STR && STR[k]) || fb; } 132 function buildFontOptions() { 133 if (!fontSel) return; 134 var scripts = (window.__FONT_LANG_SCRIPTS__ || {})[LANG] || ["latin"]; 135 var list = window.__FONTS__ || []; 136 fontSel.innerHTML = ""; 137 var ogSys = document.createElement("optgroup"); ogSys.label = fLabel("font_system", "系統"); 138 var ogOS = document.createElement("optgroup"); ogOS.label = fLabel("font_builtin", "æ¬æ©åå"); 139 function opt(id, txt) { var e = document.createElement("option"); e.value = id; e.textContent = txt; return e; } 140 list.forEach(function (o) { 141 if (o.id === "system") { ogSys.appendChild(opt("system", fLabel("font_default", "系統é è¨"))); return; } 142 if (o.web) return; // éæºç¶²è·¯ååä¸é¡¯ç¤º(pre-auth ä¸å¤é£) 143 if (scripts.indexOf(o.script) < 0) return; 144 if (o.os === fontOS) ogOS.appendChild(opt(o.id, o.label)); 145 }); 146 fontSel.appendChild(ogSys); 147 if (ogOS.children.length) fontSel.appendChild(ogOS); 148 var saved = fontMap()[LANG] || "system", ok = false; 149 for (var i = 0; i < fontSel.options.length; i++) if (fontSel.options[i].value === saved) ok = true; 150 if (!ok) saved = "system"; 151 fontSel.value = saved; applyFont(saved); 152 } 153 function refreshFonts() { if (fontSel) buildFontOptions(); } 154 function initFonts() { 155 if (!(window.__FONTS__ || []).length) return; 156 var controls = document.querySelector(".controls"); if (!controls) return; 157 fontOS = detectOS(); 158 var wrap = document.createElement("div"); wrap.className = "lang-switch font-switch"; 159 fontSel = document.createElement("select"); fontSel.id = "fontSelect"; fontSel.setAttribute("aria-label", "Font"); 160 wrap.appendChild(fontSel); 161 var langWrap = controls.querySelector(".lang-switch"); 162 controls.insertBefore(wrap, langWrap ? langWrap.nextSibling : controls.firstChild); 163 buildFontOptions(); 164 fontSel.addEventListener("change", function () { 165 var m = fontMap(); m[LANG] = fontSel.value; lsSet(LS.font, JSON.stringify(m)); applyFont(fontSel.value); 166 }); 167 } 168 169 /* ---------- çååæ(split/portrait/stage;CSS å¨ auth.css)---------- */ 170 var LAYOUT_ORDER = ["split", "portrait", "stage"]; 171 var LAYOUT_NAMES = { split: "鿬 Split", portrait: "ç´å¹ Portrait", stage: "å ±é Stage" }; 172 function initLayout() { 173 if (!document.querySelector(".scene")) return; 174 var controls = document.querySelector(".controls"); if (!controls) return; 175 var saved = lsGet(LS.layout); 176 var cur = (saved && LAYOUT_ORDER.indexOf(saved) >= 0) ? saved : (document.body.getAttribute("data-layout") || LAYOUT_ORDER[0]); 177 document.body.setAttribute("data-layout", cur); 178 var btn = document.createElement("button"); 179 btn.className = "theme-toggle"; btn.type = "button"; btn.id = "layoutToggle"; btn.setAttribute("aria-label", "Layout"); 180 btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="18" rx="1.5"/><rect x="13" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="14" width="8" height="7" rx="1.5"/></svg>'; 181 btn.title = "çå / Layout: " + (LAYOUT_NAMES[cur] || cur); 182 btn.addEventListener("click", function () { 183 var i = LAYOUT_ORDER.indexOf(document.body.getAttribute("data-layout") || LAYOUT_ORDER[0]); 184 var next = LAYOUT_ORDER[(i + 1) % LAYOUT_ORDER.length]; 185 document.body.setAttribute("data-layout", next); 186 lsSet(LS.layout, next); btn.title = "çå / Layout: " + (LAYOUT_NAMES[next] || next); 187 window.dispatchEvent(new Event("resize")); 188 }); 189 controls.appendChild(btn); 190 } 191 192 /* ---------- 坿æ³åéç·(é»è ¦ç調æ´å³å´è¡¨å®å¯¬;éæéå)---------- */ 193 function initSplitter() { 194 var scene = document.querySelector(".scene"); if (!scene || scene.querySelector(".split-handle")) return; 195 var saved = parseInt(lsGet(LS.formw), 10); 196 if (saved) document.documentElement.style.setProperty("--form-w", saved + "px"); 197 var h = document.createElement("div"); h.className = "split-handle"; 198 h.setAttribute("role", "separator"); h.setAttribute("aria-label", "ææ³èª¿æ´å¯¬åº¦,éæéå"); 199 scene.appendChild(h); 200 var dragging = false;
201 function clampW(w) { var sw = scene.getBoundingClientRect().width; return Math.max(360, Math.min(Math.min(760, sw - 380), w)); } 202 h.addEventListener("pointerdown", function (e) { dragging = true; h.classList.add("dragging"); try { h.setPointerCapture(e.pointerId); } catch (_) {} document.body.style.userSelect = "none"; e.preventDefault(); }); 203 h.addEventListener("pointermove", function (e) { if (!dragging) return; var w = clampW(scene.getBoundingClientRect().right - e.clientX); document.documentElement.style.setProperty("--form-w", w + "px"); window.dispatchEvent(new Event("resize")); }); 204 function end() { if (!dragging) return; dragging = false; h.classList.remove("dragging"); document.body.style.userSelect = ""; var px = parseInt(getComputedStyle(document.documentElement).getPropertyValue("--form-w"), 10); if (px) lsSet(LS.formw, px); } 205 h.addEventListener("pointerup", end); h.addEventListener("pointercancel", end); 206 h.addEventListener("dblclick", function () { document.documentElement.style.removeProperty("--form-w"); lsDel(LS.formw); }); 207 } 208 209 function initForm() { 210 document.querySelectorAll(".show-pw, .toggle-pw").forEach(function (b) { 211 b.addEventListener("click", function () { 212 var inp = b.parentNode.querySelector("input[type=password],input[type=text][data-pw]"); 213 if (!inp) return; 214 var show = inp.type === "password"; 215 inp.type = show ? "text" : "password"; inp.setAttribute("data-pw", "1"); 216 b.classList.toggle("on", show); b.setAttribute("aria-pressed", show ? "true" : "false"); 217 }); 218 }); 219 var acc = document.getElementById("account"), rem = document.getElementById("remember"); 220 if (acc && rem) { 221 if (lsGet(LS.remember) === "1") { rem.checked = true; acc.value = lsGet(LS.account) || acc.value; } 222 var form = acc.form; 223 if (form) form.addEventListener("submit", function () { 224 if (rem.checked) { lsSet(LS.remember, "1"); lsSet(LS.account, acc.value); } 225 else { lsDel(LS.remember); lsDel(LS.account); } 226 }); 227 } 228 } 229 230 /* ---------- å·¦å´å»£å輪æ ---------- */ 231 function initAds() { 232 var data = window.__SHOWCASE__; if (!data || !data.items || !data.items.length) return; 233 var brand = document.querySelector(".scene-brand"); if (!brand || brand.querySelector(".sc-rail")) return; 234 var rail = document.createElement("div"); rail.className = "sc-rail"; 235 var track = document.createElement("div"); track.className = "sc-strip"; 236 var MAX_SHOW = 10, picked = data.items.slice(); // æ¯æ¬¡æå¤é¨æ©æ½ 10 å(FisherâYates) 237 if (picked.length > MAX_SHOW) { 238 for (var sh = picked.length - 1; sh > 0; sh--) { var jj = Math.floor(Math.random() * (sh + 1)); var tp = picked[sh]; picked[sh] = picked[jj]; picked[jj] = tp; } 239 picked = picked.slice(0, MAX_SHOW); 240 } 241 picked.forEach(function (it, i) { 242 var a = document.createElement("a"); a.className = "sc-slide" + (i === 0 ? " active" : ""); 243 a.href = it.link; a.target = "_blank"; a.rel = "noopener noreferrer"; a.dataset.idx = data.items.indexOf(it); 244 a.innerHTML = 245 '<span class="sc-cover" data-bg="' + it.img + '"></span>' + 246 '<span class="sc-photo" data-bg="' + it.img + '"></span>' + 247 '<img class="sc-om" src="' + (it.logo || data.om_logo) + '" alt="">' + 248 '<span class="sc-teaser"></span>' + 249 '<span class="sc-meta"><span class="sc-cat"></span><span class="sc-title"></span><span class="sc-sub"></span></span>'; 250 track.appendChild(a); 251 }); 252 var dots = document.createElement("div"); dots.className = "sc-dots"; 253 picked.forEach(function (_, i) { var d = document.createElement("button"); d.type = "button"; d.className = "sc-dot" + (i === 0 ? " on" : ""); d.setAttribute("aria-label", "ad " + (i + 1)); dots.appendChild(d); }); 254 var prog = document.createElement("div"); prog.className = "sc-progress"; var pbar = document.createElement("span"); pbar.className = "sc-progress-bar"; prog.appendChild(pbar); 255 var nav = document.createElement("div"); nav.className = "sc-nav"; 256 var prev = document.createElement("button"); prev.type = "button"; prev.className = "sc-nav-btn sc-prev"; prev.setAttribute("aria-label", "prev"); 257 prev.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 6 9 12 15 18"/></svg>'; 258 var next = document.createElement("button"); next.type = "button"; next.className = "sc-nav-btn sc-next"; next.setAttribute("aria-label", "next"); 259 next.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 6 15 12 9 18"/></svg>'; 260 nav.appendChild(prev); nav.appendChild(next); 261 var eb = document.createElement("a"); eb.className = "sc-eyebrow"; eb.href = data.site || "https://ascdc.sinica.edu.tw/databases"; eb.target = "_blank"; eb.rel = "noopener noreferrer"; 262 eb.innerHTML = '<span data-i18n="ad_eyebrow">' + ((STR && STR.ad_eyebrow) || "") + '</span><span class="x">ascdc.sinica.edu.tw â</span>'; 263 rail.appendChild(track); rail.appendChild(eb); rail.appendChild(nav); rail.appendChild(prog); rail.appendChild(dots); brand.appendChild(rail); 264 var slides = track.querySelectorAll(".sc-slide"), ds = dots.querySelectorAll(".sc-dot"), idx = 0, timer = null; 265 266 function pickTr(it) { var t = it.tr || {}; return t[LANG] || t[META.fallback || "en"] || t["en"] || t["zh-Hant"] || {}; } 267 function catText(it) { var m = { museum: "ad_cat_museum", curation: "ad_cat_curation", database: "ad_cat_database", platform: "ad_cat_platform", exhibition: "ad_cat_exhibition" }; var k = m[it.catKey] || "ad_cat_database"; return (STR && STR[k]) || it.catKey || ""; } 268 function updateAdsLang() { 269 for (var i = 0; i < slides.length; i++) { 270 var it = data.items[+slides[i].dataset.idx]; if (!it) continue; 271 var tr = pickTr(it), s = slides[i]; 272 var c = s.querySelector(".sc-cat"); if (c) c.textContent = catText(it); 273 var t = s.querySelector(".sc-title"); if (t) t.textContent = tr.title || ""; 274 var u = s.querySelector(".sc-sub"); if (u) u.textContent = tr.sub || ""; 275 var k = s.querySelector(".sc-teaser"); if (k) k.textContent = tr.teaser || ""; 276 } 277 } 278 updateAdsLang(); adsUpdate = updateAdsLang; 279 280 var ratios = []; 281 function lazyLoad(i) { 282 slides[i].querySelectorAll("[data-bg]").forEach(function (el) { el.style.backgroundImage = "url('" + el.getAttribute("data-bg") + "')"; el.removeAttribute("data-bg"); }); 283 if (ratios[i] == null) { ratios[i] = 0; var im = new Image(); im.onload = function () { ratios[i] = im.naturalHeight ? im.naturalWi
283dth / im.naturalHeight : 1; applyMode(i); }; im.src = picked[i].img; } 284 } 285 function panelRatio() { var r = rail.getBoundingClientRect(); return r.height ? r.width / r.height : 1; } 286 function applyMode(i) { 287 var rt = ratios[i]; if (!rt) return; 288 var pr = panelRatio(), o = rt > pr ? rt / pr : pr / rt; 289 var m = o <= 1.5 ? "m-cover" : (rt > pr ? "m-panx" : "m-pany"); 290 var ph = slides[i].querySelector(".sc-photo"); 291 if (ph && !ph.classList.contains(m)) { ph.classList.remove("m-cover", "m-panx", "m-pany"); ph.classList.add(m); } 292 } 293 function layoutAds() { for (var i = 0; i < slides.length; i++) applyMode(i); } 294 var raf; window.addEventListener("resize", function () { if (raf) cancelAnimationFrame(raf); raf = requestAnimationFrame(layoutAds); }); 295 296 var reduced = window.matchMedia && matchMedia("(prefers-reduced-motion: reduce)").matches; 297 function restartProgress() { 298 if (reduced) return; 299 pbar.style.animation = "none"; void pbar.offsetWidth; pbar.style.animation = "sc-progress 5s linear forwards"; 300 } 301 function go(n) { 302 idx = (n + slides.length) % slides.length; lazyLoad(idx); lazyLoad((idx + 1) % slides.length); 303 slides.forEach(function (s, i) { s.classList.toggle("active", i === idx); }); 304 ds.forEach(function (d, i) { d.classList.toggle("on", i === idx); }); 305 restartProgress(); 306 } 307 function start() { stop(); if (!reduced) { timer = setInterval(function () { go(idx + 1); }, 5000); restartProgress(); } } 308 function stop() { if (timer) { clearInterval(timer); timer = null; } } 309 ds.forEach(function (d, i) { d.addEventListener("click", function (e) { e.preventDefault(); go(i); start(); }); }); 310 prev.addEventListener("click", function (e) { e.preventDefault(); go(idx - 1); start(); }); 311 next.addEventListener("click", function (e) { e.preventDefault(); go(idx + 1); start(); }); 312 var sx = 0, sy = 0, swiping = false, swiped = false; 313 rail.addEventListener("pointerdown", function (e) { sx = e.clientX; sy = e.clientY; swiping = true; swiped = false; }); 314 rail.addEventListener("pointermove", function (e) { if (swiping && Math.abs(e.clientX - sx) > 10 && Math.abs(e.clientX - sx) > Math.abs(e.clientY - sy)) swiped = true; }); 315 rail.addEventListener("pointerup", function (e) { if (!swiping) return; swiping = false; var dx = e.clientX - sx, dy = e.clientY - sy; if (Math.abs(dx) > 45 && Math.abs(dx) > Math.abs(dy)) { go(dx < 0 ? idx + 1 : idx - 1); start(); } }); 316 rail.addEventListener("pointercancel", function () { swiping = false; }); 317 rail.addEventListener("click", function (e) { if (swiped) { e.preventDefault(); e.stopPropagation(); swiped = false; } }, true); 318 rail.addEventListener("mouseenter", stop); rail.addEventListener("mouseleave", start);
319 rail.addEventListener("focusin", stop); rail.addEventListener("focusout", start); 320 lazyLoad(0); if (!reduced) start(); 321 } 322 323 function boot() { 324 initTheme(); initForm(); initBg(); initLayout(); initSplitter(); 325 loadI18N().then(function (j) { 326 if (!j) { console.error("i18n load failed; form still usable"); return; } 327 I18N = j; META = j._meta; LANG = pickLang(); 328 applyLang(LANG); buildLang(); initFonts(); initAds(); 329 }).catch(function (e) { console.error("i18n error; form still usable", e); }); 330 } 331 if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", boot); else boot(); 332})();
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.