/** * 썸네일 미리보기 확대 (길게 누르는 동안만 표시) */ (function initDeckPreviewHold() { /** @type {HTMLElement|null} */ let overlay = null; /** @type {number|null} */ let holdTimer = null; /** @type {number} */ const HOLD_THRESHOLD_MS = 280; /** * @returns {HTMLElement} */ function ensureOverlay() { if (!overlay) { overlay = document.createElement('div'); overlay.className = 'deck-preview-hold-overlay hidden'; overlay.setAttribute('role', 'dialog'); overlay.setAttribute('aria-modal', 'true'); overlay.innerHTML = '
'; document.body.appendChild(overlay); } return overlay; } /** * @param {string} src */ function show(src) { if (!src) return; const el = ensureOverlay(); const img = el.querySelector('img'); if (img) img.src = src; el.classList.remove('hidden'); } function clearHoldTimer() { if (holdTimer !== null) { window.clearTimeout(holdTimer); holdTimer = null; } } function hide() { clearHoldTimer(); if (overlay) overlay.classList.add('hidden'); } /** * @param {Event} e * @returns {HTMLElement|null} */ function findHoldTarget(e) { const target = e.target; if (!(target instanceof Element)) return null; return target.closest('[data-hold-preview]'); } /** * @param {HTMLElement} hold * @returns {string} */ function getPreviewSrc(hold) { return hold.dataset.previewSrc || ''; } /** * @param {PointerEvent} e * @param {HTMLElement|null} hold */ function releaseCapture(e, hold) { if (hold?.releasePointerCapture && e.pointerId !== undefined) { try { hold.releasePointerCapture(e.pointerId); } catch { /* ignore */ } } } function initGlobal() { if (document.documentElement.dataset.deckHoldInit === '1') return; document.documentElement.dataset.deckHoldInit = '1'; document.addEventListener( 'pointerdown', (e) => { const hold = findHoldTarget(e); if (!hold) return; const src = getPreviewSrc(hold); if (!src) return; clearHoldTimer(); holdTimer = window.setTimeout(() => { holdTimer = null; show(src); }, HOLD_THRESHOLD_MS); if (hold.setPointerCapture && e.pointerId !== undefined) { try { hold.setPointerCapture(e.pointerId); } catch { /* ignore */ } } }, true, ); document.addEventListener( 'pointerup', (e) => { const hold = findHoldTarget(e); releaseCapture(e, hold); hide(); }, true, ); document.addEventListener( 'pointercancel', () => { hide(); }, true, ); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') hide(); }); } /** * @param {HTMLElement} _container */ function bindHoldPreview(_container) { initGlobal(); } initGlobal(); window.UaDeckPreviewHold = { bindHoldPreview, hide }; })();