/* HBMIC process page v2: language picker, full menu, one stage per screen, FAQ side sheet, motion (Anime.js loaded in ) */ (function () { 'use strict'; var root = document.getElementById('hbMain'); if (!root) return; var A = window.anime; var RM = matchMedia('(prefers-reduced-motion: reduce)').matches || !A; root.classList.add('pjs'); /* ---------- language (same rules as hbmic-translation-client.js) ---------- */ var LANGS = ['ko', 'en', 'zh-CN', 'ja', 'vi', 'id']; var SHORT = { 'ko': 'KO', 'en': 'EN', 'zh-CN': 'ZH', 'ja': 'JA', 'vi': 'VI', 'id': 'ID' }; function normLang(v) { v = String(v || '').toLowerCase().replace('_', '-'); if (v === 'zh' || v === 'zh-cn') return 'zh-CN'; for (var i = 0; i < LANGS.length; i++) if (LANGS[i].toLowerCase() === v || LANGS[i].toLowerCase() === v.split('-')[0]) return LANGS[i]; return ''; } function pageLang() { try { var u = normLang(new URL(location.href).searchParams.get('lang')); if (u) return u; } catch (e) {} var m = document.cookie.match(/(?:^|;\s*)googtrans=([^;]*)/); if (m) { var c = normLang(decodeURIComponent(m[1]).split('/')[2]); if (c) return c; } var f = String((navigator.languages && navigator.languages[0]) || navigator.language || '').replace('_', '-').toLowerCase().split('-'); var reg = f.length > 1 ? f[f.length - 1].toUpperCase() : ''; if (reg === 'KR' || f[0] === 'ko') return 'ko'; if (reg === 'CN') return 'zh-CN'; if (reg === 'JP' || f[0] === 'ja') return 'ja'; if (reg === 'VN' || f[0] === 'vi') return 'vi'; if (reg === 'ID' || f[0] === 'id') return 'id'; return 'en'; } (function initLang() { var box = root.querySelector('.hb-lang'); if (!box) return; var btn = box.querySelector('.hb-lang__btn'), list = box.querySelector('.hb-lang__list'), cur = box.querySelector('.hb-lang__cur'); function mark(l) { cur.textContent = SHORT[l] || 'KO'; root.querySelectorAll('.gtranslate_wrapper a[data-gt-lang]').forEach(function (a) { var on = normLang(a.getAttribute('data-gt-lang')) === l; a.classList.toggle('gt-current-lang', on); if (on) a.setAttribute('aria-current', 'true'); else a.removeAttribute('aria-current'); }); } function show(v) { list.hidden = !v; btn.setAttribute('aria-expanded', v ? 'true' : 'false'); } btn.addEventListener('click', function () { show(list.hidden); if (!list.hidden) { var a = list.querySelector('.gt-current-lang') || list.querySelector('a'); a.focus({ preventScroll: true }); } }); window.addEventListener('click', function (e) { var a = e.target && e.target.closest ? e.target.closest('.gtranslate_wrapper a[data-gt-lang]') : null; if (a) { e.preventDefault(); mark(normLang(a.getAttribute('data-gt-lang')) || 'ko'); show(false); return; } if (!box.contains(e.target)) show(false); }, true); box.addEventListener('keydown', function (e) { if (e.key === 'Escape' && !list.hidden) { show(false); btn.focus(); } }); mark(pageLang()); show(false); })(); /* ---------- full menu ---------- */ (function initMenu() { var btn = root.querySelector('.hb-menu-btn'), menu = root.querySelector('.hb-menu'); if (!btn || !menu) return; var close = menu.querySelector('.hb-menu__close'), links = menu.querySelectorAll('.hb-menu__list a'); var rows = menu.querySelectorAll('.hb-menu__in'), isOpen = false, busy = null; function open() { if (isOpen) return; isOpen = true; menu.hidden = false; btn.setAttribute('aria-expanded', 'true'); document.documentElement.style.overflow = 'hidden'; if (!RM) { if (busy) busy.pause(); A.utils.set(rows, { y: '110%' }); busy = A.createTimeline() .add(menu, { clipPath: ['inset(0% 0% 100% 0%)', 'inset(0% 0% 0% 0%)'], duration: 560, ease: 'inOutQuart' }) .add(rows, { y: ['110%', '0%'], duration: 760, ease: 'outExpo', delay: A.stagger(80) }, 260); } links[0].focus({ preventScroll: true }); } function shut(back) { if (!isOpen) return; isOpen = false; btn.setAttribute('aria-expanded', 'false'); document.documentElement.style.overflow = ''; function hide() { menu.hidden = true; menu.style.clipPath = ''; } if (!RM) { if (busy) busy.pause(); busy = A.animate(menu, { clipPath: 'inset(0% 0% 100% 0%)', duration: 420, ease: 'inOutQuart', onComplete: hide }); } else hide(); if (back !== false) btn.focus({ preventScroll: true }); } btn.addEventListener('click', open); close.addEventListener('click', function () { shut(); }); links.forEach(function (a) { a.addEventListener('click', function () { shut(false); }); }); menu.addEventListener('keydown', function (e) { if (e.key === 'Escape') { shut(); return; } if (e.key !== 'Tab') return; var f = Array.from(menu.querySelectorAll('button, a[href]')), first = f[0], lastF = f[f.length - 1]; if (e.shiftKey && document.activeElement === first) { e.preventDefault(); lastF.focus(); } else if (!e.shiftKey && document.activeElement === lastF) { e.preventDefault(); first.focus(); } }); })(); /* ---------- stages: one at a time ---------- */ var stages = Array.from(root.querySelectorAll('.pp-st')); var tabs = Array.from(root.querySelectorAll('.pp-steps a')); var bar = root.querySelector('.pp-steps'); var ids = stages.map(function (s) { return s.id; }); var cur = -1, running = []; function stop() { running.forEach(function (x) { try { x.pause(); } catch (e) {} }); running = []; stages.forEach(function (s) { parts(s).forEach(function (e) { if (e) { e.style.opacity = ''; e.style.transform = ''; } }); }); } /* every statement: same size, one line (PC). The line may run into the gutter up to the right column. */ function fit() { var on = stages[cur]; if (!on) return; root.style.removeProperty('--ppS'); root.classList.remove('pjs-fit'); if (innerWidth <= 900) return; var el = on.querySelector('.pp-s'), right = on.querySelector('.pp-r'); var base = parseFloat(getComputedStyle(el).fontSize); var gap = parseFloat(getComputedStyle(on).columnGap) || 32; var avail = right.getBoundingClientRect().left - el.getBoundingClientRect().left - gap; var pr = document.createElement('span'); pr.className = 'pp-s'; pr.style.cssText = 'position:absolute;visibility:hidden;white-space:nowrap;display:inline;font-size:' + base + 'px'; el.parentNode.appendChild(pr); var w = 0; stages.forEach(function (s) { pr.textContent = s.querySelector('.pp-s').textContent; w = Math.max(w, pr.getBoundingClientRect().width); }); pr.remove(); var fs = Math.min(base, Math.floor(base * avail / w * 10) / 10); root.style.setProperty('--ppS', fs + 'px'); root.classList.add('pjs-fit'); stages.forEach(function (s) { s.querySelector('.pp-s').style.maxWidth = 'none'; s.querySelector('.pp-s').style.width = Math.floor(avail) + 'px'; }); } function mark(i) { tabs.forEach(function (a, k) { if (k === i) a.setAttribute('aria-current', 'step'); else a.removeAttribute('aria-current'); }); if (bar) bar.style.setProperty('--p', i + 1); } function parts(s) { return [s.querySelector('.pp-count'), s.querySelector('.pp-q'), s.querySelector('.pp-d'), s.querySelector('.pp-faqw'), s.querySelector('.pp-ill'), s.querySelector('.pp-r')]; } function show(i, opts) { opts = opts || {}; if (i < 0 || i >= stages.length || i === cur) return; stop(); var prev = cur, dir = i > prev ? 1 : -1; cur = i; mark(i); if (!opts.noHash) history.replaceState(null, '', location.pathname + location.search + '#' + ids[i]); function swap() { stages.forEach(function (s, k) { s.classList.toggle('on', k === i); }); fit(); // phones: bring the new stage into view if (prev !== -1 && innerWidth <= 900) { var t = stages[i].getBoundingClientRect().top; if (t < 0) window.scrollBy(0, t - 8); } if (RM || prev === -1 && opts.first) return; running.push(A.animate(parts(stages[i]), { opacity: [0, 1], y: [14 * dir, 0], duration: 520, ease: 'outExpo', delay: A.stagger(50) })); } if (prev === -1 || RM) { swap(); return; } running.push(A.animate(parts(stages[prev]), { opacity: 0, y: -10 * dir, duration: 200, ease: 'inQuad', onComplete: function () { running = []; parts(stages[prev]).forEach(function (e) { if (e) { e.style.opacity = ''; e.style.transform = ''; } }); swap(); } })); } tabs.forEach(function (a, k) { a.addEventListener('click', function (e) { e.preventDefault(); show(k); }); }); root.querySelectorAll('.pp-next').forEach(function (n) { var h = n.getAttribute('href') || ''; if (h.charAt(0) !== '#') return; n.addEventListener('click', function (e) { e.preventDefault(); if (window.hbBurst) { var r = n.getBoundingClientRect(); window.hbBurst(r.right - 20, r.top + r.height / 2, 10); } show(ids.indexOf(h.slice(1))); }); }); /* ---------- FAQ side sheet ---------- */ var sheet = root.querySelector('.pp-sheet'), last = null; var faqs = sheet ? Array.from(sheet.querySelectorAll('.pp-faq')) : []; var sStage = sheet ? sheet.querySelector('.pp-sheet__stage') : null; function openSheet(i, from) { if (!sheet) return; last = from || document.activeElement; faqs.forEach(function (d) { d.hidden = d.getAttribute('data-i') !== String(i); }); if (sStage) sStage.textContent = stages[i].querySelector('.pp-count').textContent.replace(/\s*\/\s*06\s*/, ' '); sheet.hidden = false; document.documentElement.style.overflow = 'hidden'; requestAnimationFrame(function () { requestAnimationFrame(function () { sheet.classList.add('on'); sheet.querySelector('.pp-sheet__x').focus({ preventScroll: true }); }); }); } function closeSheet() { if (!sheet || sheet.hidden) return; sheet.classList.remove('on'); document.documentElement.style.overflow = ''; setTimeout(function () { sheet.hidden = true; if (last) last.focus({ preventScroll: true }); }, RM ? 0 : 450); } root.querySelectorAll('.pp-faqbtn').forEach(function (b) { b.addEventListener('click', function () { openSheet(stages.indexOf(b.closest('.pp-st')), b); }); }); if (sheet) { sheet.querySelector('.pp-sheet__x').addEventListener('click', closeSheet); sheet.querySelector('.pp-sheet__dim').addEventListener('click', closeSheet); sheet.addEventListener('keydown', function (e) { if (e.key === 'Escape') { closeSheet(); return; } if (e.key !== 'Tab') return; var f = Array.from(sheet.querySelectorAll('button, a[href]')).filter(function (x) { return x.offsetParent; }); if (!f.length) return; if (e.shiftKey && document.activeElement === f[0]) { e.preventDefault(); f[f.length - 1].focus(); } else if (!e.shiftKey && document.activeElement === f[f.length - 1]) { e.preventDefault(); f[0].focus(); } }); } /* keyboard: left/right arrows switch stages */ window.addEventListener('keydown', function (e) { if (sheet && !sheet.hidden) return; if (/INPUT|TEXTAREA|SELECT/.test((document.activeElement || {}).tagName || '')) return; if (root.querySelector('.hb-menu') && !root.querySelector('.hb-menu').hidden) return; if (e.key === 'ArrowRight') show(cur + 1); if (e.key === 'ArrowLeft') show(cur - 1); }); window.addEventListener('hashchange', function () { var k = ids.indexOf(location.hash.slice(1)); if (k > -1) show(k, { noHash: true }); }); var rz; window.addEventListener('resize', function () { clearTimeout(rz); rz = setTimeout(fit, 120); }); root.classList.remove('no-pjs'); show(Math.max(0, ids.indexOf(location.hash.slice(1))), { noHash: true, first: true }); if (document.fonts && document.fonts.ready) document.fonts.ready.then(fit); if (document.fonts && document.fonts.addEventListener) document.fonts.addEventListener('loadingdone', function () { fit(); }); if (RM) return; A.animate(root.querySelector('.pp-bar'), { opacity: [0, 1], y: [24, 0], duration: 900, ease: 'outExpo', delay: 200 }); A.animate(parts(stages[cur]), { opacity: [0, 1], y: [18, 0], duration: 900, ease: 'outExpo', delay: A.stagger(70, { start: 100 }) }); })(); /* 11/9 21:05: two scroll stops (first screen / footer) with a fast glide. Replaces CSS scroll-snap, whose speed cannot be set. Used only when the page is one screen + a footer shorter than the screen. */ (function () { 'use strict'; var H = document.documentElement; var isProc = !!document.querySelector('.hb-proc'); var RMs = matchMedia('(prefers-reduced-motion: reduce)').matches; var DUR = 360, raf = 0, lock = 0, ty = 0; function max() { return Math.max(0, H.scrollHeight - innerHeight); } function on() { var m = max(); return m > 0 && m < innerHeight && (!isProc || innerWidth > 900); } function busyUI(t) { if (!t || !t.closest) return false; if (t.closest('.pp-sheet, .hb-menu, .hb-lang__list, input, textarea, select')) return true; return false; } function inner(t, dir) { // a scrollable box under the pointer that can still scroll that way keeps the wheel var r = t && t.closest ? t.closest('.pp-r') : null; if (!r || r.scrollHeight <= r.clientHeight + 1) return false; return dir > 0 ? r.scrollTop + r.clientHeight < r.scrollHeight - 1 : r.scrollTop > 0; } function go(to) { cancelAnimationFrame(raf); var from = window.pageYOffset, d = to - from; if (Math.abs(d) < 1) return; if (RMs) { window.scrollTo(0, to); return; } var t0 = performance.now(); (function step(t) { var p = Math.min(1, (t - t0) / DUR), e = 1 - Math.pow(1 - p, 3); window.scrollTo(0, from + d * e); if (p < 1) raf = requestAnimationFrame(step); else raf = 0; })(t0); } function toward(dir) { var now = Date.now(); if (now < lock) return; var target = dir > 0 ? max() : 0; if (Math.abs(target - window.pageYOffset) < 1) return; lock = now + DUR + 120; go(target); } window.addEventListener('wheel', function (e) { if (!on() || e.ctrlKey || busyUI(e.target) || Math.abs(e.deltaY) < Math.abs(e.deltaX)) return; var dir = e.deltaY > 0 ? 1 : -1; if (inner(e.target, dir)) return; e.preventDefault(); toward(dir); }, { passive: false }); window.addEventListener('touchstart', function (e) { ty = e.touches[0].clientY; }, { passive: true }); window.addEventListener('touchmove', function (e) { if (!on() || busyUI(e.target)) return; e.preventDefault(); }, { passive: false }); window.addEventListener('touchend', function (e) { if (!on() || busyUI(e.target)) return; var dy = ty - e.changedTouches[0].clientY; if (Math.abs(dy) > 24) toward(dy > 0 ? 1 : -1); }, { passive: true }); window.addEventListener('keydown', function (e) { if (!on() || busyUI(e.target) || busyUI(document.activeElement)) return; var k = e.key, dir = 0; if (k === 'PageDown' || k === 'ArrowDown' || k === 'End' || (k === ' ' && !e.shiftKey)) dir = 1; if (k === 'PageUp' || k === 'ArrowUp' || k === 'Home' || (k === ' ' && e.shiftKey)) dir = -1; if (!dir) return; if (k === ' ' && /BUTTON|A/.test((document.activeElement || {}).tagName || '')) return; e.preventDefault(); toward(dir); }); // scrollbar drag or anything else: settle on the nearer stop var st = 0; window.addEventListener('scroll', function () { if (!on() || raf) return; clearTimeout(st); st = setTimeout(function () { if (raf) return; var y = window.pageYOffset, m = max(); if (y > 0 && y < m) go(y > m / 2 ? m : 0); }, 160); }, { passive: true }); })(); /* 11/11 12:10 translated page: when the big sentence has no Korean, mark #hbMain with pp-tr (see hbmain.css) and re-check whenever the translator changes text */ (function(){var r=document.getElementById('hbMain');if(!r||!r.classList.contains('hb-proc'))return;var t=null; function chk(){var s=r.querySelector('.pp-s');var tr=!!s&&!/[\uAC00-\uD7A3]/.test(s.textContent);if(tr!==r.classList.contains('pp-tr')){r.classList.toggle('pp-tr',tr);window.dispatchEvent(new Event('resize'))}} chk();try{new MutationObserver(function(){clearTimeout(t);t=setTimeout(chk,150)}).observe(r,{subtree:true,characterData:true,childList:true})}catch(e){}})(); /* 11/11 14:40 photo reveal test (stage 01 only): photo layer over the drawing, visible only around the mouse; touch = whole photo while pressed */ (function(){var M={1:1};var figs=document.querySelectorAll('#hbMain .pp-ill'); Array.prototype.forEach.call(figs,function(f){var im=f.querySelector('img');if(!im)return;var m=/proc0(\d)\.webp/.exec(im.getAttribute('src')||'');if(!m||!M[m[1]])return; var d=document.createElement('div');d.className='pp-ph';d.setAttribute('data-n',m[1]);d.setAttribute('aria-hidden','true');f.appendChild(d); function pos(e){var r=f.getBoundingClientRect();d.style.setProperty('--x',(e.clientX-r.left)+'px');d.style.setProperty('--y',(e.clientY-r.top)+'px');d.style.setProperty('--r',Math.round(Math.max(90,r.width*.24))+'px')} f.addEventListener('pointermove',function(e){if(e.pointerType==='mouse'){pos(e);d.classList.add('on')}}); f.addEventListener('pointerleave',function(e){if(e.pointerType==='mouse')d.classList.remove('on')}); f.addEventListener('pointerdown',function(e){if(e.pointerType!=='mouse'){d.classList.add('on');d.classList.add('all')}}); ['pointerup','pointercancel','pointerleave'].forEach(function(t){f.addEventListener(t,function(e){if(e.pointerType!=='mouse'){d.classList.remove('on');d.classList.remove('all')}})}); f.addEventListener('contextmenu',function(e){if(d.classList.contains('all'))e.preventDefault()}); });})();