001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
// (2022.8.31, 차재복, Cha Jae Bok, http://www.ktword.co.kr) // navi 메뉴의 subtree별 DOM 구조 : div[treeDiv] > span[subMenu] > ①a[bullet] ②span[title] ③div[treeDiv] function startDropdown(topElement) { // dropdown start div 찾음 // let startDropdown = topElem.getElementById('dropdownDiv'); let startDropdown = topElement.querySelector('div#dropdownDiv'); if(startDropdown) { // menutype에 따라, 서브메뉴 선택 처리 let pathDivs = startDropdown.getElementsByClassName('treeDiv'); for(let i=0; i<pathDivs.length; i++) { // menutype에 따라, div별로 처리 chooseSubMenu(pathDivs[i]); // short_navi.js } } } // 기능 : mobile 여부에 따라, 다른 이벤트 메뉴 설정 function chooseSubMenu(out) { let menuType = out.dataset.menutype; let menus = out.querySelectorAll('span.subMenu'); if(menus.length < 1) return; // 찾아낸 sub Menu별로, mobile 여부에 따라, 각 항목별 다른 이벤트 설정 for(let i=0; i<menus.length; i++) { if(menuType == 'clickMenu') clickMenuEvent(menus[i]); // short_navi.js if(menuType == 'moverMenu') moverMenuEvent(menus[i]); // short_navi.js } } // 기능 : mouse click 때, sub menu 나타나는 이벤트 function clickMenuEvent(menu) { // mouse click 이벤트리스너 생성 menu.addEventListener('click', function(e) { // 최하단 이벤트 하나 만 가능, 이벤트의 상단 진행 금지 e.stopPropagation(); // 현재 이외 주위 노드(span) 있으면 disable 시킴 let siblings = this.parentNode.querySelectorAll('span.subMenu'); if(siblings.length > 1) { for(let i=0; i < siblings.length; i++) { if(siblings[i].dataset.id != this.dataset.id) { let childDiv = siblings[i].querySelector('div.treeDiv'); if(childDiv) childDiv.style.display = 'none'; normalMenu(siblings[i]); // short_navi.js } } } let childDiv = this.querySelector('div.treeDiv'); // 이미 자식 div 있으면, if (childDiv) { // toggle 효과 // div 만 숨기기 if (childDiv.style.display == 'flex') { childDiv.style.display = 'none'; normalMenu(this); // short_navi.js // div 만 나타내기 및 강조 } else { childDiv.style.display = 'flex'; strongMenu(this); // short_navi.js } return; // 자식 div 없으면, 새로이 div 생성하고 셋팅 } else { strongMenu(this); // short_navi.js // div 생성 let out = document.createElement('div'); // div에 menutype 및 class=treeDiv 설정 out.dataset.menutype = 'clickMenu'; out.setAttribute('class','treeDiv'); // span 맨끝 자식으로 div 붙임 menu.appendChild(out); // 스타일 지정 out = setStyle(out); // short_navi.js // out 위치 셋팅 out.style.top = ( this.dataset.direction=='v' ? this.getBoundingClientRect().height : 0 )+'px'; out.style.left = ( this.dataset.direction=='v' ? 0 : this.clientWidth )+'px'; // scroll 조절 // let location = this.offsetTop; // window.scrollTo({top:location, behavior:'smooth'}); fillOut(this.dataset.id, out); // short_navi.js } }, false); // 이벤트 전파를 버블링(상위 방향)으로 셋팅 } // mouse over 때, sub menu가 나타나는 이벤트 function moverMenuEvent(menu) { // menu 산하에 자식 노드를 미리 생성하고 붙여둠 let out = document.createElement('div'); // div에 우선적으로 inline-block 셋팅 (줄바꿈 방지) out.style.display = 'inline-block'; // div에 menutype 및 class=treeDiv 설정 out.dataset.menutype = 'moverMenu'; out.setAttribute('class','treeDiv'); menu.appendChild(out); // mouseover 이벤트리스너 생성 menu.addEventListener('mouseover', function(e) { // 선택된 menu 강조 strongMenu(this); // short_navi.js // out 스타일 지정 out = setStyle(out); // short_navi.js // out 위치 셋팅 out.style.top = ( this.dataset.direction=='v' ? this.getBoundingClientRect().height : 0 )+'px'; out.style.left = ( this.dataset.direction=='v' ? 0 : this.clientWidth )+'px'; // out 내부 자식 있으면 복귀 if(out.hasChildNodes()) return false; // out 내부 자식 없으면 표출 else { // out 내부에 링크 데이터 표출 및 submenu 이벤트 설정 fillOut(this.dataset.id, out); } }, true); // 이벤트 전파를 캡쳐링(하위 방향)으로 셋팅 // mouseoout 이벤트리스너 생성 menu.addEventListener('mouseout', function(e) { // menu 글자 강조된 것을 제거 normalMenu(this); // short_navi.js // 화면에서 사라짐 this.querySelector('div.treeDiv').style.display = 'none'; }); } // menu span 미 선택 비 강조 function normalMenu(span) { span.style.backgroundColor = 'white'; let bullet = span.querySelector('span.bullet'); bullet.innerHTML = bullet.innerText.replace('▽','▷'); } // menu span 선택 강조 function strongMenu(span) { span.style.backgroundColor = 'gainsboro'; let bullet = span.querySelector('span.bullet'); bullet.innerText = bullet.innerText.replace('▷','▽'); } // menu div 스타일링 function setStyle(out){ out.style.margin = '0px'; out.style.padding = '5px 0px 5px'; out.style.backgroundColor = 'white'; out.style.border = '1px gray solid'; out.style.maxWidth = 'max-content'; out.style.whiteSpace = 'pre'; out.style.zIndex = '3'; out.style.position = 'absolute'; out.style.display = 'flex'; out.style.flexDirection = 'column'; out.style.alignItems = 'stretch'; return out; } // menu 내 항목 리스트 (서버에서 ajax promise 형태로 가져와서, 이들을 표출) function fillOut(id, out) { // ajax promise 호출 (서버로부터 데이터 가져오기) let url = '/test/navigation/naviFetch.php?choice=treeView&id=' + id; let method = 'get'; ajaxPromise(url, method) // common_utils.js // 가져온 결과에 대한 데이터 가공 .then( response => { // 만일, out 하부에 자식 노드 있으면, 복귀 if(out.hasChildNodes()) return out; // 서버로부터 가져온 데이터를 가지고 out에 표출 out = dispListInOut (response.data, out); // short_navi.js // mobile 여부에 따라, out 내 해당 sunMenu class 항목 찾기,div 생성,이벤트 설정 chooseSubMenu(out); // short_navi.js }, error => { alert(error); } ); } // menu 내 항목 리스트의 세부 표출 내용 function dispListInOut (data, out) { let cnt = 1; for (const value of data) { const menuSpan = document.createElement('span'); menuSpan.style.position = 'relative'; menuSpan.style.display = 'block'; menuSpan.style.padding = '3px 7px 3px'; menuSpan.style.margin = '0px'; menuSpan.dataset.direction = 'h'; if(value.item_type=='no') { let a = document.createElement('a'); let href = '/test/view/view.php'; // 만일, top div data-href가 있으면, href를 셋팅한 것으로 씀 let topDivHref = out.closest('div[data-href]'); if(topDivHref) href = topDivHref.dataset.href; a.href = href + '?no='+value.id; a.innerHTML = " " + cnt + ". " + value.name; menuSpan.appendChild(a); cnt += 1; } else { menuSpan.dataset.id = value.id; menuSpan.setAttribute('class','subMenu'); let bulletSpan = document.createElement('span'); bulletSpan.setAttribute('class','bullet'); bulletSpan.innerText = '▷'; menuSpan.appendChild(bulletSpan); let textSpan = document.createElement('span'); textSpan.setAttribute('class','title'); textSpan.innerHTML = ' ' + value.name; menuSpan.appendChild(textSpan); } out.appendChild(menuSpan); } return out; }