얼마전에 자바스크립트로 Tree메뉴를 만들일이 있어서 찾았던 Destroydrop.com의 소스를, 제가 진행하고있는 ajax 환경에 적용하기가 힘들어 나름대로 고쳐 서 사용 했습니다. 고치다보니 원본과 많이 달라졌군요 ㅎㅎ 자바스크립트를 처음 시작하셨거나 아직 api 찾아가면서 소스 수정에 어려움이 있는 분들에게 도움이 될까해서 올려봅니다.
바뀐점
- div 태그 안에서 함수를 실행하는것이 아니라 ID로 div를 찾아서 그 안에 태그를 삽입함
- 노드를 클릭하면 링크가 걸리는게 아니라 함수가 실행되도록 함(노드배열의 4번째 인자를 전달함)

소스보기..
<html>
<head>
<title>Tree</title>
<style type="text/css">
.tree {
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size: 11px;
padding: 10px;
white-space: nowrap;
}
.tree img {
border: 0px;
height: 18px;
vertical-align: text-bottom;
}
.tree a {
color: #000;
text-decoration: none;
}
.tree a:hover {
color: #345373;
}
</style>
<script type="text/javascript">
<!--
/**************************************************************************
Copyright (c) 2001-2003 Geir Landr?(drop@destroydrop.com)
JavaScript Tree - www.destroydrop.com/hjavascripts/tree/
Version 0.96
This script can be used freely as long as all copyright messages are
intact.
**************************************************************************/
// 수정 및 주석 : Nayuta
var treeString = ""; //트리 메뉴의 태그가 저장될 변수
var treeMenuArry = new Array; //트리 정보를 저장할 배열
var treeOpenNodes = new Array(); //오픈되는 트리 정보
var treeIcons = new Array(6); //트리 아이콘 배열
function createTreeArry(i,j){
// nodeId | parentNodeId | nodeName | nodeUrl
treeMenuArry[0] = "1|0|Page 1|#";
treeMenuArry[1] = "2|1|Page 1.1|#";
treeMenuArry[2] = "3|1|Page 1.2|#";
treeMenuArry[3] = "4|3|Page 1.2.1|#";
treeMenuArry[4] = "5|1|Page 1.3|#";
treeMenuArry[5] = "6|2|Page 1.1.1|#";
treeMenuArry[6] = "7|6|Page 1.1.1.1|#";
treeMenuArry[7] = "8|6|Page 1.1.1.2|#";
treeMenuArry[8] = "9|1|Page 1.4|#";
treeMenuArry[9] = "10|9|Page 1.4.1|#";
treeMenuArry[10] = "11|0|Page 2|#";
createTree(i,j); //세로 메뉴 생성 스트링 얻기
}
// 첫번째 트리 노드 생성
function createTree(startNode, openNode) {
if (treeMenuArry.length > 0) {
preloadIcons(); //트리 앞의 이미지 생성
if (startNode == null) startNode = 0;
if (openNode != 0 || openNode != null) setOpenNodes(openNode);
if (startNode !=0) {
var nodeValues = treeMenuArry[getArrayId(startNode)].split("|");
treeString += "<img src=\"img/folderopen.gif\" align=\"absbottom\" alt=\"\" />" + replaceAll(nodeValues[2], '#rlftkd6137','|') + "<br />";
} else treeString += "<img src=\"img/base.gif\" align=\"absbottom\" alt=\"\" />M E N U<br />";
var recursedNodes = new Array();
addNode(startNode, recursedNodes); //노드 추가
}
document.getElementById('treeMenu').insertAdjacentHTML('beforeEnd',treeString);
}
// 트리 아이콘 생성
function preloadIcons() {
treeIcons[0] = new Image();
treeIcons[0].src = 'img/plus.gif';
treeIcons[1] = new Image();
treeIcons[1].src = 'img/plusbottom.gif';
treeIcons[2] = new Image();
treeIcons[2].src = 'img/minus.gif';
treeIcons[3] = new Image();
treeIcons[3].src = 'img/minusbottom.gif';
treeIcons[4] = new Image();
treeIcons[4].src = 'img/folder.gif';
treeIcons[5] = new Image();
treeIcons[5].src = 'img/folderopen.gif';
}
// 노드의 아이디로 배열 변호 추출
function getArrayId(node) {
for (i=0; i<treeMenuArry.length; i++) {
var nodeValues = treeMenuArry[i].split("|");
if (nodeValues[0]==node) return i;
}
}
// 배열에 열리는 노드의 아이디 부터 그 노드의 부모들을 순서대로 저장
function setOpenNodes(openNode) {
for (i=0; i<treeMenuArry.length; i++) {
var nodeValues = treeMenuArry[i].split("|");
if (nodeValues[0] == openNode) {
treeOpenNodes.push(nodeValues[0]);
setOpenNodes(nodeValues[1]);
}
}
}
// 트리에 노드 추가
var treeString = "";
function addNode(parentNode, recursedNodes) {
for (var i = 0; i < treeMenuArry.length; i++) {
var nodeValues = treeMenuArry[i].split("|");
if (nodeValues[1] == parentNode) {
// 현재 돌고있는 노드의 속성을 검사
var ls = lastSibling(nodeValues[0], nodeValues[1]); // 해당 노드가 마지막 노드인지 검사
var hcn = hasChildNode(nodeValues[0]); // 해당 노드에 자식이 있는지 검사
var ino = isNodeOpen(nodeValues[0]); // 해당 노드가 오픈 노드인지 검사
ino = true; //무조건 오픈 시켜줌
// 노드의 계단 구조를 만들어주기 위해 공백과 세로 라인을 넣어줌
for (g=0; g<recursedNodes.length; g++) {
if (recursedNodes[g] == 1) treeString += "<img src=\"img/line.gif\" align=\"absbottom\" alt=\"\" />";
else treeString += "<img src=\"img/empty.gif\" align=\"absbottom\" alt=\"\" />";
}
// 다음 생성 노드 앞의 공백을 넣기 위해 배열에 저장
if (ls) recursedNodes.push(0);
else recursedNodes.push(1);
// 노드에 맞는 트리 연결 모양을 붙여줌
if (hcn) {
if (ls) {
treeString += "<a href=\"javascript: oc(" + nodeValues[0] + ", 1);\"><img id=\"join" + nodeValues[0] + "\" src=\"img/";
if (ino) treeString += "minus";
else treeString += "plus";
treeString += "bottom.gif\" align=\"absbottom\" alt=\"Open/Close node\" /></a>";
} else {
treeString += "<a href=\"javascript: oc(" + nodeValues[0] + ", 0);\"><img id=\"join" + nodeValues[0] + "\" src=\"img/";
if (ino) treeString += "minus";
else treeString += "plus";
treeString += ".gif\" align=\"absbottom\" alt=\"Open/Close node\" /></a>";
}
} else {
if (ls) treeString += "<img src=\"img/joinbottom.gif\" align=\"absbottom\" alt=\"\" />";
else treeString += "<img src=\"img/join.gif\" align=\"absbottom\" alt=\"\" />";
}
// 노드에 맞는 아이콘을 붙여줌
if (hcn) {
treeString += "<img id=\"icon" + nodeValues[0] + "\" src=\"img/folder";
if (ino) treeString += "open";
treeString += ".gif\" align=\"absbottom\" alt=\"Folder\" />";
} else treeString += "<img id=\"icon" + nodeValues[0] + "\" src=\"img/page.gif\" align=\"absbottom\" alt=\"Page\" />";
//노드에 메뉴링크 이벤트 붙여줌
treeString += '<a href="javascript:void(0);" onclick="treeMenuClick(this);" id="';
treeString += nodeValues[3] +'"';
treeString += ">";
// 노드 이름 넣음
treeString += replaceAll(nodeValues[2], '#rlftkd6137','|');
// 링크 태그 닫아줌
treeString += "</a><br />";
// 열고 닫기 기능을 수행하는 DIV를 넣어주고 자식 노드가 있을때는 자식 노드를 div안에서 생성해줌
if (hcn) {
treeString += "<div id=\"div" + nodeValues[0] + "\"";
if (!ino) treeString += " style=\"display: none;\"";
treeString += ">";
addNode(nodeValues[0], recursedNodes);
treeString += "</div>";
}
// 배열의 마지막 원소를 제거
recursedNodes.pop();
}
}
}
// 해당 노드가 오픈시켜줘야 하는 노드인지 검사 해 주는 함수
function isNodeOpen(node) {
for (i=0; i<treeOpenNodes.length; i++)
if (treeOpenNodes[i]==node) return true;
return false;
}
// 해당 노드에 자식 노드가 있는지 검사 해 주는 함수
function hasChildNode(parentNode) {
for (i=0; i< treeMenuArry.length; i++) {
var nodeValues = treeMenuArry[i].split("|");
if (nodeValues[1] == parentNode) return true;
}
return false;
}
// 형제중 마지막 형제인지 검사해 주는 함수
function lastSibling (node, parentNode) {
var lastChild = 0;
for (i=0; i< treeMenuArry.length; i++) {
var nodeValues = treeMenuArry[i].split("|");
if (nodeValues[1] == parentNode)
lastChild = nodeValues[0];
}
if (lastChild==node) return true;
return false;
}
// 노드의 열고 닫기
function oc(node, bottom) {
var theDiv = document.getElementById("div" + node);
var theJoin = document.getElementById("join" + node);
var theIcon = document.getElementById("icon" + node);
if (theDiv.style.display == 'none') {
if (bottom==1) theJoin.src = treeIcons[3].src;
else theJoin.src = treeIcons[2].src;
theIcon.src = treeIcons[5].src;
theDiv.style.display = '';
} else {
if (bottom==1) theJoin.src = treeIcons[1].src;
else theJoin.src = treeIcons[0].src;
theIcon.src = treeIcons[4].src;
theDiv.style.display = 'none';
}
}
// 메뉴 함수
function treeMenuClick(ele){
var funVar = replaceAll(ele.id, '#rlftkd6137', '|');
// funVar를 가지고 필요한 함수를 구현 합니다.
}
function replaceAll(str, searchStr, replaceStr){
while(str.indexOf(searchStr) != -1)
{
str = str.replace(searchStr, replaceStr);
}
return str;
}
//-->
</script>
</head>
<body onload="createTreeArry();">
<div align="left" id="treeMenu" class="tree"></div>
</body>
</html>
다시 Destroydrop.com에 가보니 버전이 많이 업그레이드 됐네요. 제가 저걸 수정한 지도 얼마 안됐는데..(난 멀 받은거지 ... --;;) 저는 0.96 버전을 수정한 거고 현재 최신 버전은 2.05입니다. 잠깐 살펴본 바로는 쿠키로 노드 상태를 저장하고 노드를 한꺼번에 열어주고 닫아주는 등 몇가지 기능이 추가 됐네요. (기능만 추가 된 것이 아니라 거의 모든 함수들이 클래스로 바꼈습니다.)
Tree.zip
댓글 없음:
댓글 쓰기