function uiGnbHandler() { /** * .menu-first-depth, mouseenter일때 함수 작동 * 문서의 header 찾음 * secondDeptSelector의 각 자식요소의 갯수의 max를 받아서 * header에 data-sub에 넣고 이를 css에서 높이 결정을 함 * */ const headerSelector = document.getElementsByTagName('header')[0]; const secondDeptSelector = Array.from(headerSelector.getElementsByClassName('menu-second-depth')); const childrenLengthArray = secondDeptSelector.map((i) => i.children.length); const maxChildren = Math.max(...childrenLengthArray); headerSelector.setAttribute('open', 'true'); headerSelector.style.setProperty('--max-length', maxChildren) secondDeptSelector.forEach(element => { element.setAttribute('open', 'true'); }); headerSelector.addEventListener('mouseleave', () => { headerSelector.setAttribute('open', 'false'); secondDeptSelector.forEach(element => { element.setAttribute('open', 'false'); }); }); } function uiAttrOpen({ selector, state }) { if (state === 'set') { selector.setAttribute('open', ''); } else { selector.removeAttribute('open'); } } function uiTableCollapseHandler(event) { /** * 함수는 table > tbody > tr > td > details 위치에 onClick으로 작동해야함 * html ui구조는 table > tbody > tr > td > details > summary 구조 * details 태그의 open 상태에 따라 attribute의 open set 또는 remove */ const parentTd = event.target.offsetParent; const parentTr = parentTd.offsetParent; const isDetailOpen = parentTd.children[0].open; parentTr.toggleAttribute('open', !isDetailOpen); } function uiTableCollapseAllHandler(event) { const targetData = event.target.dataset; const dataSet = targetData.state; const tbodySelector = document.getElementsByTagName('tbody')[0]; const trSelector = Array.from(tbodySelector.querySelectorAll('tr')); const trWithDetails = trSelector.filter(tr => tr.querySelector('details')); trWithDetails.forEach(tr => { const details = tr.querySelector('details'); if (details) { dataSet === 'close' ? ( uiAttrOpen({ selector: tr, state: 'set' }), uiAttrOpen({ selector: details, state: 'set' }), event.target.setAttribute('data-state', 'open'), event.target.textContent = '전체 닫기' ) : ( uiAttrOpen({ selector: tr, state: 'remove' }), uiAttrOpen({ selector: details, state: 'remove' }), event.target.setAttribute('data-state', 'close'), event.target.textContent = '전체 열기' ) } }); } function uiModalOpenHandler(event) { const currentTarget = event.target; const targetModal = currentTarget.offsetParent; const isOpen = targetModal.dataset.state; if (isOpen !== undefined && isOpen === 'open') { targetModal.setAttribute('data-state', 'close'); } if (isOpen === undefined) { const getDataSet = currentTarget.dataset.modal; const modalElement = document.querySelector(`[data-modal="${getDataSet}"].modal`); if (modalElement) { modalElement.setAttribute('data-state', 'open'); } } } function uiScrollHandler(event) { const currentScrollPosition = document.scrollingElement.scrollTop; const indicatorSelector = document.getElementsByClassName('indicators')[0]; const articles = Array.from(indicatorSelector.getElementsByClassName('editor-article')); const indicatorLinks = Array.from(document.querySelectorAll('.editor-indicator a')); articles.forEach((article, index) => { const articleTop = article.offsetTop; const articleHeight = article.offsetHeight; const nextArticleTop = index < articles.length - 1 ? articles[index + 1].offsetTop : document.body.scrollHeight; if (currentScrollPosition >= articleTop && currentScrollPosition < nextArticleTop) { indicatorLinks.forEach(link => link.removeAttribute('current')); const correspondingLink = indicatorLinks.find(link => link.getAttribute('href') === `#${article.id}`); if (correspondingLink) { correspondingLink.setAttribute('current', ''); } } }); } function uiDropZoneHandler() { const dropZone = document.getElementById('dropZone'); const fileInput = document.getElementById('fileInput'); const fileList = document.getElementById('fileList'); dropZone.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', uiUpdateFileList); dropZone.addEventListener('dragover', (event) => { event.preventDefault(); dropZone.classList.add('hover'); }); dropZone.addEventListener('dragleave', () => dropZone.classList.remove('hover')); dropZone.addEventListener('drop', (event) => { event.preventDefault(); dropZone.classList.remove('hover'); const files = Array.from(event.dataTransfer.files); fileInput.files = new DataTransfer().files; Array.from(files).forEach(file => fileInput.files = new DataTransfer().files.add(file)); uiUpdateFileList(files); }); } function uiUpdateFileList(files = Array.from(fileInput.files)) { fileList.innerHTML = ''; Array.from(files).forEach(file => { const listItem = document.createElement('div'); listItem.textContent = `${file.name} - ${Math.round(file.size / 1024)} KB`; fileList.appendChild(listItem); }); } function uiEventCalendarHandler() { /** * 주요일정 캘린더 .event-dot 요소 찾아 배열 * * [HTML영역] *
* 로 되어 있어야함. * 각 요소 mouseenter가 되었을때 .event-hint 요소 생성 * dataSet의 data-title, data-desc을 가져와서 event-hint 요소에 출력 * style의 --background-color에 색상값을 넣으면 css변수를 이용하여 * event-dot의 동그라미 요소와 event-hint에 같이 색상 출력 * */ const eventDotElements = document.querySelectorAll('.event-dot'); eventDotElements.forEach((i) => { i.addEventListener('mouseenter', (j) => { const title = j.target.getAttribute('data-title'); const desc = j.target.getAttribute('data-desc'); const hintElement = document.createElement('div'); hintElement.classList.add('event-hint'); hintElement.innerHTML = `${title}
${desc}