// (2024.12.21, 차재복, Cha Jae Bok, http://www.ktword.co.kr)
// 용어해설 분류 `명칭 검색` 및 소스코드 `내용 검색`
// 호출 : [index.js] window.addEventListener (2)
function searchAction(e) {
// 입력 문자열 취득
let str, type;
if(e.type=='keypress') {
str = e.target.value;
type = e.target.dataset.type;
}
if(e.type=='click') {
str = e.target.previousElementSibling.value;
type = e.target.previousElementSibling.dataset.type;
}
// 문자열 전달 및 실행
searchActionDisplay(str, type);
}
function searchActionDisplay(str, type='bunryu') {
// 입력 valiadation
if(str.length<=0) { alert('분류 검색어 입력 요망!'); return; }
if(str.length<2) { alert('최소 2자 이상'); return; }
if(str.length>20) { alert('최대 20자 미만 (현재 : '+str.length+'자)'); return; }
// div (.srchResultDiv) 찾기 : ('bunryu' 또는 'source')
let div;
if(type=='bunryu')
div = document.querySelector('#resultTest');
else if(type=='source')
div = document.querySelector("#srcResultDiv[data-type='source']");
// div 보이기
if(!div) return;
else div.style.display = 'block';
// type 구분 : ('bunryu' 또는 'source')
// const type = div.dataset.type;
// ajax Promise 검색 요청 파라미터 설정
const url = '/test/navigation/naviFetch.php'; // naviFetch.php
const method = 'post';
let choice;
if(type=='bunryu') choice = 'bunryuSearch'; // naviFetch.php : bunryu_search_v2()
else if(type=='source') choice = 'srcSearch';
const parms = { 'choice' : choice, 'sh' : str };
// 서버로부터 검색 결과 가져오기
ajaxPromise(url, method, parms)
.then(
response => {
// 용어분류 검색
if(type=='bunryu') {
if(response.str) {
// div에 show, ajax 응답 결과 뿌리기
let outStr = " <span style='color:orange;line-height:180%;font-style:italic;'>";
outStr += "(해당 부분에 클릭하면, 용어해설 등 상세내용이 하단에 펼쳐 보여집니다) (검색어 : '"+ str +"')";
outStr += "</span><br>";
outStr += response.str;
div.innerHTML = outStr;
/*
// 응답 결과 중 매 줄 마다, idPath 찾고, 이곳에 이벤트 생성 및 이벤트 처리기 연결
const idPathFocusEvent = div.querySelectorAll('span.idPathFocusEvent');
idPathFocusEvent.forEach((elem) => {
elem.addEventListener('click', idPathFocusEventHandler);
});
*/
// 클릭 색깔 변화
const clickSpread = div.querySelectorAll('.clickSpread');
clickSpread.forEach((elem) => {
elem.addEventListener('click', clickColorChange);
});
} else {
// 결과 비었으면
let outStr = "<span style='color:red;margin-left:20px;'>"
outStr += "분류 검색 결과 없음" + " (검색어 : '"+ str +"')";
outStr += "</span>";
outStr += "<br>";
// if (str.includes(' ')) div.innerHTML = outStr + " (가급적 중간 빈 칸 없이 검색 요망)";
// else div.innerHTML = outStr;
div.innerHTML = outStr;
}
// 접속 통계 등록
stat_enroll('bunryuSearch',str);
// 소스 검색
} else if(type=='source') {
if(response.html) {
// div에 show, ajax 응답 결과 뿌리기
div.innerHTML = response.html;
} else {
let outStr = "<span style='color:red;margin-left:20px;'>"
outStr += "소스 검색 결과 없음" + " (검색어 : '"+ str +"')";
outStr += "</span>";
outStr += "<br>";
div.innerHTML = outStr;
}
// 응답 결과 중 출력된 요소들에 이벤트 핸들러 등록
const srcPathLineNo = div.querySelectorAll('.srcPathLineNo');
srcPathLineNo.forEach((elem) => {
elem.addEventListener('click', (e) => {
e.preventDefault();
// 기존 검색결과 요소들 색깔로 원래 환원 및 선택된 요소 만 빨간색
srcPathLineNo.forEach( (el) => el.style.color = '' );
e.target.style.color = 'red';
// 소스 트리에서, 기존 열려진 (ol 요소들,detail_view 창) 모두 닫기,
const startElem = document.getElementById('sourceStart');
startElem.querySelectorAll('.detail_view').forEach((view) => view.style.display='none');
// bullet 요소 화살표 방향 바꿈, idpath에 언급된 id 마다 차례로 open 시키고, 해당 line에 위치시킴
const path = e.target.dataset.path.split(',');
const idpath = ['0',...path];
const leafId = idpath.pop(); // 말단 노드 id
const line = e.target.dataset.line; // 줄 번호
let li;
asynctodo(idpath,startElem) // navi_search.js
// 추가적으로, 소스 코드 보기 화면 오픈
.then(
response => {
li = startElem.querySelector("li[data-id='"+leafId+"']");
return detailSourceView(li);
}, error => { alert(error); }
)
.then(
response => {
const startSecNo = parseInt((line-1) / 30);
const secBtn = li.querySelectorAll('.secBtn');
secBtn.forEach( (elem) => {
if(elem.dataset.bno==startSecNo) elem.style.fontWeight='bold';
else elem.style.fontWeight='normal';
});
const secDiv = li.querySelectorAll('.secDiv');
secDiv.forEach( (elem) => {
if(elem.dataset.dno==startSecNo) elem.style.display='block';
else elem.style.display='none';
});
let a = li.querySelector("a[data-id='"+leafId+"']");
a.focus();
}, error => { alert(error); }
);
});
});
// 접속 통계 등록
stat_enroll('sourceSrch',str);
}
// 닫기 버튼 처리
srchCloseBtn(div); // navi_search.js
},
error => { alert(error); }
);
}
// 검색 결과 닫기 버튼
// 호출 : [navi_search.js] searchAction(e)
function srchCloseBtn(div) {
// 혹시 기존 버튼 있으면 삭제
const oldBtn = div.parentNode.querySelector('.srcCloseBtn');
if(oldBtn) oldBtn.remove();
// div 직전에, 닫기 버튼 생성
const closeBtn1 = document.createElement('button');
closeBtn1.style.color = 'red';
closeBtn1.innerText = '닫 기';
closeBtn1.setAttribute('class','srcCloseBtn');
div.parentNode.insertBefore(closeBtn1,div);
// div 내 하단부에 닫기 버튼 생성
div.appendChild(document.createElement('br'));
const closeBtn2 = document.createElement('button');
closeBtn2.style.width = '30%';
closeBtn2.style.margin = '0px 10px 0px';
closeBtn2.style.color = 'red';
closeBtn2.innerText = ' 닫 기 ';
div.appendChild(closeBtn2);
// 닫기 이벤트 처리
[closeBtn1,closeBtn2].forEach( (elem) => {
elem.addEventListener('click', (e) => {
div.style.display = 'none';
closeBtn1.remove();
})
});
}
function clickColorChange(e) {
// 기존 요소들 색깔로 원래 환원
const bunryuElems = this.closest('div').querySelectorAll('.clickSpread');
if(bunryuElems) bunryuElems.forEach( elem => { elem.style.color = ''; });
// 선택된 요소 만 빨간색
this.style.color = 'red';
}
// search 항목별, idPath 처리 및 포커스 동작
// 호출 : [navi_search.js] searchAction(e)
// (분류 검색 후 나타난 div 내 각 항목별 event handler)
function idPathFocusEventHandler(e) {
// olStart를 기준으로, idpath 획득
const str = this.dataset.idpath;
const idPath = str.split(',');
// 분류 펼침
const startElem = document.getElementById('bunryuStart');
asynctodo(idPath, startElem);
const name = this.dataset.name;
// historyAdd(idPath, "", name);
}
// 직접 idPath 포커스 동작 수행 함수 => (li 요소 'bunryuStart'를 찾고, 비동기 수행)
// 호출 : 외부 .js 또는 html 요소에서 직접 호출 가능
function idPathFocusDirect(id_list, no, name) {
// 중복 요청 방지
if (isRequestInProgress) return;
isRequestInProgress = true;
const idPath = id_list.split(',');
const startElem = document.getElementById('bunryuStart');
if(no===undefined) no=0;
asynctodo(idPath, startElem, no, name);
}
// history 추가
function historyAdd(id_list, no, name='') {
const historyDiv = document.getElementById('history_div');
if (!historyDiv) return;
const newEntry = document.createElement('span');
let addText = '';
if (historyDiv.children.length==0) historyDiv.innerHTML = '<span>(이동 기록) : </span>';
let escapedText = name.replace(/'/g, "'").replace(/"/g, """);
addText = "<a href=\"javascript:idPathFocusDirect('"+id_list+"','"+no+"','"+escapedText+"')\">" + escapedText + "</a>";
if(historyDiv.children.length > 1) addText += " ← ";
newEntry.innerHTML = addText;
insertAfter(historyDiv.firstChild, newEntry); // common_utils.js
if (historyDiv.children.length > 30) {
historyDiv.removeChild(historyDiv.lastChild);
historyDiv.lastChild.innerHTML = historyDiv.lastChild.innerHTML.replace(" ← ","");
}
}
// 비동기 동작을 마치 동기 동작 처럼 수행함
// olStart 요소 밑에, idpath 배열 [id1,id2,id3 등...]에 언급된 id 마다 차례로 open 시킴
// async function asynctodo (idPath, olStart) {
async function asynctodo (idPath, startElem, no=null, namePara='') {
// 기존 열려진 ol 요소들 모두 닫기 및 bullet 요소 화살표 방향 바꿈
const openOlTreeAll = startElem.querySelectorAll('ol.tree');
openOlTreeAll.forEach( elem => { elem.style.display = 'none'; });
const openLiAll = startElem.querySelectorAll('a.bullet');
const openDivAll = startElem.querySelectorAll('div.detail_view');
/*
if(no===null) {
openLiAll.forEach( elem => { elem.innerText = '▷'; });
openDivAll.forEach( elem => { elem.style.display = 'none'; });
}
*/
// idpath에 언급된 id 마다 차례로 open 시킴
const ol = startElem.querySelector("ol[data-id='"+idPath[0]+"']");
if(ol) {
if(ol.style.display == 'none') ol.style.display = 'block';
} else
await fetchDataCreateOl(startElem);
let li; let id;
for(i=0; i < idPath.length; i++) {
li = startElem.querySelector("li[data-id='"+idPath[i]+"']");
if(!li) continue;
//console.log(li);
let olTree = li.querySelector('ol.tree');
if(olTree) {
if(olTree.style.display == 'none')
olTree.style.display = 'block';
} else {
if(!(li.dataset.child <= 0))
await fetchDataCreateOl(li);
}
let a = li.querySelector("a[data-id='"+idPath[i]+"']");
if(a) {
a.innerText = '▽';
a.focus();
}
id = idPath[i];
}
let name;
// 용어해설 가져와서, bullet 하향, div(out) 열고, 출력
if(no && no!="null") {
const tempOl = startElem.querySelector("ol.tree");
const tempLi = tempOl.querySelector("li[data-no='"+no+"']");
const bullet = tempLi.querySelector(".bullet");
if(bullet) bullet.focus();
// const out = startElem.querySelector("li[data-id='"+id+"'] div[class='detail_view']");
const out = tempOl.querySelector("li[data-no='"+no+"'] div[class='detail_view']");
detailViewOnDirect(no,bullet,out); // navi_vabe_moreShow.js
// detailSeparateViewDirect(no,bullet,out);
name = tempOl.querySelector("li[data-no='"+no+"'] span[class='title']").innerText;
}
// history 등록 ('bunryuStart'일 경우 만)
if(startElem.id=='bunryuStart') {
const id_list = idPath.join(',');
if(namePara)
historyAdd(id_list, no, namePara);
else if(li) {
name = li.querySelector('.title').innerText;
historyAdd(id_list, no, name);
}
}
// 중복 요청 방지 플래그 해제
isRequestInProgress = false;
}