/**************************************************** * ✅ ±âÁ¸ ÄÚµå À¯Áö (bluring / getUrl / goLocate) ****************************************************/ console.log('✅ main script file loaded'); function bluring() { try { if (event.srcElement.tagName === 'A' || event.srcElement.tagName === 'IMG') { document.body.focus(); } } catch (e) {} } try { document.onfocusin = bluring; } catch (e) {} var rurl = location.href; var purl = getUrl(rurl); function getUrl(url_str) { var real_url; if (url_str.indexOf('/') > 0) { real_url = url_str.split('/'); real_url = real_url[0] + '//' + real_url[2] + '/' + real_url[3] + '/'; } return real_url; } function goLocate(go_url) { document.location = purl + go_url; } /**************************************************** * ✅ (2) °í°´»ç ·Î°í ¹«ÇÑ ·Ñ¸µ (JS only, º¹Á¦´Â JS¿¡¼¸¸) ****************************************************/ function initCustomerLogoMarquee() { const viewport = document.querySelector('#customer .customer-logos'); if (!viewport) return; const items = Array.from(viewport.querySelectorAll('.logo-item')); if (items.length === 0) return; // ÀÌ¹Ì Æ®·¢ÀÌ ÀÖÀ¸¸é Áߺ¹ »ý¼º ¹æÁö if (viewport.querySelector('.customer-logos-track')) return; const track = document.createElement('div'); track.className = 'customer-logos-track'; items.forEach((el) => track.appendChild(el)); viewport.appendChild(track); items.forEach((el) => { const clone = el.cloneNode(true); clone.classList.add('logo-item-clone'); track.appendChild(clone); }); let running = true; const pxPerSec = 60; let lastTs = null; let x = 0; let oneSetWidth = 0; function refreshWidth() { oneSetWidth = track.scrollWidth / 2; if (!oneSetWidth) requestAnimationFrame(refreshWidth); } window.addEventListener('load', refreshWidth); refreshWidth(); function step(ts) { if (!running) return; if (lastTs == null) lastTs = ts; const dt = (ts - lastTs) / 1000; lastTs = ts; if (oneSetWidth > 0) { x -= pxPerSec * dt; if (Math.abs(x) >= oneSetWidth) { x += oneSetWidth; } track.style.transform = `translate3d(${x}px, 0, 0)`; } requestAnimationFrame(step); } requestAnimationFrame(step); document.addEventListener('visibilitychange', () => { if (document.hidden) { running = false; } else { running = true; lastTs = null; requestAnimationFrame(step); } }); window.addEventListener('resize', refreshWidth); } /**************************************************** * ✅ DOMContentLoaded ****************************************************/ document.addEventListener('DOMContentLoaded', function () { console.log('✅ DOMContentLoaded fired'); /********************** * ¸ð¹ÙÀÏ ¸Þ´º Åä±Û **********************/ const mobileMenuToggle = document.getElementById('mobileMenuToggle'); const mainMenu = document.getElementById('mainMenu'); if (mobileMenuToggle && mainMenu) { mobileMenuToggle.addEventListener('click', function () { mainMenu.classList.toggle('mobile-menu-open'); }); const menuItems = mainMenu.querySelectorAll('.navbar_items'); menuItems.forEach(function (item) { item.addEventListener('click', function () { mainMenu.classList.remove('mobile-menu-open'); }); }); } /********************** * 1) ºÎµå·¯¿î ½ºÅ©·Ñ **********************/ const scrollLinks = document.querySelectorAll('.js-scroll'); scrollLinks.forEach((link) => { link.addEventListener('click', function (e) { const targetId = this.getAttribute('href'); if (!targetId || !targetId.startsWith('#')) return; const targetEl = document.querySelector(targetId); if (!targetEl) return; e.preventDefault(); const topMenu = document.querySelector('#topmenu'); const topMenuHeight = topMenu ? topMenu.offsetHeight : 0; const targetPosition = targetEl.offsetTop - topMenuHeight; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); }); }); /********************** * 2) ½ºÅ©·Ñ ½Ã »ó´Ü ¸Þ´º ½ºÅ¸ÀÏ º¯°æ + 3) active Àû¿ë **********************/ const topMenu = document.querySelector('#topmenu'); const navItems = document.querySelectorAll('.navbar_items'); function updateTopMenuAndActive() { if (!topMenu) return; const currentScroll = window.pageYOffset; const topMenuHeight = topMenu.offsetHeight; // ¸Þ´º ½ºÅ¸ÀÏ if (currentScroll > 100) { topMenu.style.background = 'rgba(255,255,255,0.98)'; topMenu.style.boxShadow = '0 4px 20px rgba(0,0,0,0.1)'; } else { topMenu.style.background = 'rgba(255,255,255,0.98)'; topMenu.style.boxShadow = '0 2px 10px rgba(0,0,0,0.05)'; } // active °è»ê (contact´Â contact-section ¿µ¿ª¿¡¼ href="#contact"¸¦ active) const sections = document.querySelectorAll('section[id]'); let current = ''; sections.forEach((section) => { const isContact = section.id === 'contact-section'; const offset = isContact ? 200 : 100; const sectionTop = section.offsetTop - topMenuHeight - offset; const sectionBottom = sectionTop + section.clientHeight; if (currentScroll >= sectionTop && currentScroll < sectionBottom) { current = section.id; } }); navItems.forEach((item) => { item.classList.remove('active'); const href = item.getAttribute('href'); if (current === 'contact-section' && href === '#contact') { item.classList.add('active'); return; } if (href === '#' + current) { item.classList.add('active'); } }); } window.addEventListener('scroll', updateTopMenuAndActive); updateTopMenuAndActive(); /********************** * 5) °í°´»ç ·Î°í ¹«ÇÑ ·Ñ¸µ **********************/ initCustomerLogoMarquee(); }); /**************************************************** * ✅ Æ÷Æ®Æú¸®¿À ¸®½ºÆ® (Ä«Å×°í¸® ajax ±³Ã¼) ****************************************************/ (function () { function extractUrlFromOnclick(el) { const onclick = el && el.getAttribute && el.getAttribute('onclick'); if (!onclick) return null; const m = onclick.match(/linkMove\('([^']+)'\)/); return m ? m[1] : null; } function normalizeUrl(url) { const raw = String(url || '').replace(/&/g, '&'); try { return new URL(raw, location.href).toString(); } catch { return raw; } } async function fetchHtml(url) { const res = await fetch(url, { credentials: 'same-origin' }); const buf = await res.arrayBuffer(); let text = new TextDecoder('euc-kr').decode(buf); const m = text.match(/charsets*=\s*["']?([a-zA-Z0-9-_]+)["']?/i); const enc = m && m[1] ? m[1].toLowerCase() : ''; if (enc.includes('utf')) text = new TextDecoder('utf-8').decode(buf); return text; } function findListContainer(root) { let el = root.querySelector('#container_list'); if (el) return el; el = root.querySelector('[id^="container_list"]'); if (el) return el; el = root.querySelector('#portfolio .portfolio-board, .portfolio-board'); return el; } async function replaceBoardList(url) { const curScrollY = window.scrollY; const html = await fetchHtml(url); const doc = new DOMParser().parseFromString(html, 'text/html'); const newEl = findListContainer(doc); const curEl = findListContainer(document); if (!newEl || !curEl) { location.href = url; return; } curEl.innerHTML = newEl.innerHTML; history.replaceState(null, '', url); requestAnimationFrame(() => { window.scrollTo(0, curScrollY); }); } async function onCategoryClick(e) { const tab = e.target.closest('#category_navi > div'); if (!tab) return; const urlRaw = extractUrlFromOnclick(tab); if (!urlRaw) return; const url = normalizeUrl(urlRaw); e.preventDefault(); e.stopImmediatePropagation(); e.stopPropagation(); try { await replaceBoardList(url); } catch (err) { console.error(err); location.href = url; } } ['mousedown', 'touchstart', 'click'].forEach((evt) => { document.addEventListener(evt, onCategoryClick, true); }); // ⚠️ linkMove °ü·Ã ¿¡·¯°¡ ³ª´Â ȯ°æ¿¡¼´Â board.js Áߺ¹ ·Îµå °¡´É¼ºÀÌ Å. // ±×·¡µµ inline onclick ´ëÀÀÀ» À§ÇØ window.linkMove¸¦ "¼±¾ð"ÀÌ ¾Æ´Ï¶ó "ÇÁ·ÎÆÛƼ"·Î¸¸ ¼³Á¤. function lockedLinkMove(url) { const normalized = normalizeUrl(url); replaceBoardList(normalized).catch((err) => { console.error(err); location.href = normalized; }); return false; } try { // configurableÀº true·Î µÎ¾î, ±âÁ¸ ½ºÅ©¸³Æ®¿Í Ãæµ¹ ½Ã º¹±¸ °¡´ÉÇÏ°Ô Object.defineProperty(window, 'linkMove', { value: lockedLinkMove, writable: true, configurable: true, }); } catch (e) { window.linkMove = lockedLinkMove; } })(); /**************************************************** * ✅ Æ÷Æ®Æú¸®¿À ¸ð´Þ ****************************************************/ (function () { function ensureModal() { let overlay = document.querySelector('.pf-modal-overlay'); if (overlay) return overlay; overlay = document.createElement('div'); overlay.className = 'pf-modal-overlay'; overlay.innerHTML = `