/* Keep the map and its navigation inside a dismissible view. */ (() => { 'use strict'; const trigger = document.querySelector('.map-link'); const dialog = document.querySelector('#map-dialog'); if (!trigger || !dialog) return; const canvas = dialog.querySelector('.map-dialog-canvas'); const body = dialog.querySelector('.map-dialog-body'); const status = dialog.querySelector('.map-dialog-status'); const retry = dialog.querySelector('.map-dialog-retry'); const closeButton = dialog.querySelector('.map-dialog-close'); const historyKey = '__trontMapDialog'; const token = `map-${Date.now()}`; let frame, timer, savedScroll, savedStyle, waitingForBack = false; let backdropPressed = false; function showError() { clearTimeout(timer); frame?.remove(); frame = null; body.setAttribute('aria-busy', 'false'); status.hidden = false; status.querySelector('p').textContent = '지도를 불러오지 못했습니다. 연결 상태를 확인하고 다시 시도해 주세요.'; retry.hidden = false; } function loadMap() { clearTimeout(timer); frame?.remove(); body.setAttribute('aria-busy', 'true'); status.hidden = false; status.querySelector('p').textContent = '지도를 불러오는 중입니다.'; retry.hidden = true; frame = document.createElement('iframe'); frame.title = '구글 지도 — 트론트, IT융합산업빌딩 위치'; // The campus shares one street address; use the IT building's location. frame.src = 'https://maps.google.com/maps?hl=ko&q=35.8920895,128.6141078&z=17&output=embed'; frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox'); frame.referrerPolicy = 'no-referrer-when-downgrade'; const loadingFrame = frame; frame.addEventListener('load', () => { if (frame !== loadingFrame || !dialog.open) return; clearTimeout(timer); body.setAttribute('aria-busy', 'false'); status.hidden = true; }); frame.addEventListener('error', showError); canvas.replaceChildren(frame); timer = setTimeout(showError, 20000); } function openMap(addHistory = true) { if (dialog.open || waitingForBack) return; savedScroll = { x: scrollX, y: scrollY }; // Save the page's history entry before fixing the body resets scrollY to 0. if (addHistory) { try { history.pushState({ ...history.state, [historyKey]: token }, '', location.href); } catch { /* The close controls also work in local file previews. */ } } savedStyle = ['position', 'top', 'left', 'width', 'paddingRight'].map(key => [key, document.body.style[key]]); const scrollbar = innerWidth - document.documentElement.clientWidth; const padding = parseFloat(getComputedStyle(document.body).paddingRight) || 0; Object.assign(document.body.style, { position: 'fixed', top: `-${savedScroll.y}px`, left: `-${savedScroll.x}px`, width: '100%', paddingRight: `${padding + scrollbar}px` }); document.documentElement.classList.add('map-dialog-open'); dialog.showModal(); closeButton.focus({ preventScroll: true }); loadMap(); } function closeMap() { if (!dialog.open) return; clearTimeout(timer); frame?.remove(); frame = null; dialog.close(); savedStyle.forEach(([key, value]) => { document.body.style[key] = value; }); document.documentElement.classList.remove('map-dialog-open'); window.scrollTo({ left: savedScroll.x, top: savedScroll.y, behavior: 'instant' }); trigger.focus({ preventScroll: true }); } function dismiss() { closeMap(); if (history.state?.[historyKey] === token) { waitingForBack = true; history.back(); } } function isBackdrop(event) { const rect = dialog.getBoundingClientRect(); return event.target === dialog && (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom); } trigger.addEventListener('click', () => openMap()); closeButton.addEventListener('click', dismiss); retry.addEventListener('click', loadMap); dialog.addEventListener('cancel', event => { event.preventDefault(); dismiss(); }); dialog.addEventListener('pointerdown', event => { backdropPressed = isBackdrop(event); }); dialog.addEventListener('click', event => { if (backdropPressed && isBackdrop(event)) dismiss(); backdropPressed = false; }); window.addEventListener('popstate', event => { waitingForBack = false; if (event.state?.[historyKey] === token) openMap(false); else closeMap(); }); })();