;(function () { 'use strict' var SECT_CLASS_RX = /^sect(\d)$/ var navContainer = document.querySelector('.nav-container') if (!navContainer) return var navToggle = document.querySelector('.nav-toggle') var panelToggle = document.getElementById('collapse-panel-btn') var nav = navContainer.querySelector('.nav') var navMenuToggle = navContainer.querySelector('.nav-menu-toggle') navToggle.addEventListener('click', showNav) navContainer.addEventListener('click', trapEvent) var menuPanel = navContainer.querySelector('[data-panel=menu]') if (!menuPanel) return var explorePanel = navContainer.querySelector('[data-panel=explore]') var backdrop = explorePanel.querySelector('.backdrop') var versionMenu = explorePanel.querySelector('.version-menu') var versions = versionMenu?.querySelectorAll('.component') var currentPageItem = menuPanel.querySelector('.is-current-page') var originalPageItem = currentPageItem if (currentPageItem) { activateCurrentPath(currentPageItem) scrollItemToMidpoint(menuPanel, currentPageItem.querySelector('.nav-link')) } else { menuPanel.scrollTop = 0 } find(menuPanel, '.nav-item-toggle').forEach(function (btn) { var li = btn.parentElement btn.addEventListener('click', toggleActive.bind(li)) var navItemSpan = findNextElement(btn, '.nav-text') if (navItemSpan) { navItemSpan.style.cursor = 'pointer' navItemSpan.addEventListener('click', toggleActive.bind(li)) } }) find(menuPanel, '.nav-link').forEach(function (link) { link.addEventListener('click', function (e) { var li = this.parentElement var currentDepth = parseInt(li.dataset.depth, 10) // 현재 nav-item의 depth 가져오기 // href가 '#'인 경우 (클릭한 항목이 단순 펼침 액션 대상일 때) if (this.getAttribute('href') === '#') { // 다음 depth의 항목을 찾음 (현재 depth + 1) var nextDepth = currentDepth + 1 var subNavList = li.querySelector('.nav-list') // 하위 리스트를 찾음 var firstSubNavItem = subNavList ? subNavList.querySelector('.nav-item[data-depth="' + nextDepth + '"] .nav-link') : null // 다음 depth의 항목이 있을 경우 if (firstSubNavItem && firstSubNavItem.href) { e.preventDefault() // 기본 동작 방지 toggleActive.call(li) // 펼쳐짐 액션 수행 window.location = firstSubNavItem.href // 다음 depth의 첫 항목으로 이동 } else { toggleActive.call(li) // 다음 depth 항목이 없을 경우 펼쳐짐 액션만 수행 } } else { toggleActive.call(li) // href가 '#'이 아닌 경우 그냥 펼쳐짐 액션만 수행 } }) }) if (navMenuToggle && menuPanel.querySelector('.nav-item-toggle')) { navMenuToggle.style.display = '' navMenuToggle.addEventListener('click', function () { var collapse = !this.classList.toggle('is-active') find(menuPanel, '.nav-item > .nav-item-toggle').forEach(function (btn) { collapse ? btn.parentElement.classList.remove('is-active') : btn.parentElement.classList.add('is-active') }) if (currentPageItem) { if (collapse) activateCurrentPath(currentPageItem) scrollItemToMidpoint(menuPanel, currentPageItem.querySelector('.nav-link')) } else { menuPanel.scrollTop = 0 } }) } if (explorePanel) { explorePanel.querySelector('.version-menu-toggle').addEventListener('click', function (e) { // NOTE logic assumes there are only two panels // find(nav, '[data-panel]').forEach(function (panel) { // panel.classList.toggle('is-active') // }) if (!versions.length) return versionMenu.classList.toggle('is-active') backdrop.classList.toggle('is-active') e.stopPropagation() // trap event }) } backdrop.addEventListener('click', function () { versionMenu.classList.remove('is-active') backdrop.classList.remove('is-active') }) document.documentElement.addEventListener('click', function () { versionMenu.classList.remove('is-active') backdrop.classList.remove('is-active') }) // NOTE prevent text from being selected by double click menuPanel.addEventListener('mousedown', function (e) { if (e.detail > 1) e.preventDefault() }) panelToggle.addEventListener('click', () => { navContainer.classList.remove('is-active') }) function onHashChange () { var navLink var hash = window.location.hash if (hash) { if (hash.indexOf('%')) hash = decodeURIComponent(hash) navLink = menuPanel.querySelector('.nav-link[href="' + hash + '"]') if (!navLink) { var targetNode = document.getElementById(hash.slice(1)) if (targetNode) { var current = targetNode var ceiling = document.querySelector('article.doc') while ((current = current.parentNode) && current !== ceiling) { var id = current.id // NOTE: look for section heading if (!id && (id = SECT_CLASS_RX.test(current.className))) id = (current.firstElementChild || {}).id if (id && (navLink = menuPanel.querySelector('.nav-link[href="#' + id + '"]'))) break } } } } var navItem if (navLink) { navItem = navLink.parentNode } else if (originalPageItem) { navLink = (navItem = originalPageItem).querySelector('.nav-link') } else { return } if (navItem === currentPageItem) return find(menuPanel, '.nav-item.is-active').forEach(function (el) { el.classList.remove('is-active', 'is-current-path', 'is-current-page') }) navItem.classList.add('is-current-page') currentPageItem = navItem activateCurrentPath(navItem) scrollItemToMidpoint(menuPanel, navLink) } if (menuPanel.querySelector('.nav-link[href^="#"]')) { if (window.location.hash) onHashChange() window.addEventListener('hashchange', onHashChange) } function activateCurrentPath (navItem) { var ancestorClasses var ancestor = navItem.parentNode while (!(ancestorClasses = ancestor.classList).contains('nav-menu')) { if (ancestor.tagName === 'LI' && ancestorClasses.contains('nav-item')) { ancestorClasses.add('is-active', 'is-current-path') } ancestor = ancestor.parentNode } navItem.classList.add('is-active') } function toggleActive () { if (this.classList.toggle('is-active')) { var padding = parseFloat(window.getComputedStyle(this).marginTop) var rect = this.getBoundingClientRect() var menuPanelRect = menuPanel.getBoundingClientRect() var overflowY = (rect.bottom - menuPanelRect.top - menuPanelRect.height + padding).toFixed() if (overflowY > 0) menuPanel.scrollTop += Math.min((rect.top - menuPanelRect.top - padding).toFixed(), overflowY) } } function showNav (e) { if (navToggle.classList.contains('is-active')) return hideNav(e) // trapEvent(e) // var html = document.documentElement // html.classList.add('is-clipped--nav') // navToggle.classList.add('is-active') navContainer.classList.add('is-active') // var bounds = nav.getBoundingClientRect() // var expectedHeight = window.innerHeight - Math.round(bounds.top) // if (Math.round(bounds.height) !== expectedHeight) nav.style.height = expectedHeight + 'px' // html.addEventListener('click', hideNav) } function hideNav (e) { trapEvent(e) var html = document.documentElement html.classList.remove('is-clipped--nav') navToggle.classList.remove('is-active') navContainer.classList.remove('is-active') html.removeEventListener('click', hideNav) } function trapEvent (e) { e.stopPropagation() } function scrollItemToMidpoint (panel, el) { var rect = panel.getBoundingClientRect() var effectiveHeight = rect.height var navStyle = window.getComputedStyle(nav) if (navStyle.position === 'sticky') effectiveHeight -= rect.top - parseFloat(navStyle.top) panel.scrollTop = Math.max(0, (el.getBoundingClientRect().height - effectiveHeight) * 0.5 + el.offsetTop) } function find (from, selector) { return [].slice.call(from.querySelectorAll(selector)) } function findNextElement (from, selector) { var el = from.nextElementSibling return el && selector ? el[el.matches ? 'matches' : 'msMatchesSelector'](selector) && el : el } })()