Mega Code Archive

 
Categories / JavaScript DHTML / GUI Components
 

Simple Tree in Javascript

<html> <head> <title>:: Tree Sample ::</title>   <style type="text/css">   body {   padding: 0;   margin: 0; } .tree ul, .tree li {   list-style-type: none;   margin: 0 0 0 2px;   padding: 0;   display: block; } .tree ul ul {   margin-left: 16px; } .tree a.selected {   background-color: lavender; } .tree .collapsed ul, .tree .collapsed span {   display: none; } .tree span {   display: block;   margin: 0 0 0 16px;   padding: 0;   color: Gray;   cursor: default;   font-size: smaller; } .tree img {   border: none;   text-align: left;   vertical-align: middle;   margin-right: 2px; } .tree img.plusminus {   width: 9px;   height: 9px; } .tree a, .tree a:link, .tree a:visited, .tree a:active {   font-size: 10pt;   color: navy;   font-family: Verdana;   text-decoration: none;   text-align: left;   margin: 0 2px 0 2px; } .tree a:hover {   text-decoration: underline;   color: Blue; }   </style> <script type="text/javascript"> /*     _______________________            ______________________     XML DOM Tree Component             Browsers support:              Version 1.5                -> Internet Explorer                                         -> Mozilla     _____________________________       -> Opera     Features:                           -> Firefox      -> Server Side Independency        -> Konqueror      -> Cross Browser Support      -> Dynamic Loading      -> XML Source      -> Easy Customization                               ______________________________                                   Serghei Egoricev (c) 2006                                     egoricev [at] gmail.com */ // CSS import Tree = function() {} /*   Use double click for navigate, single click for expand */ Tree.useDblClicks = true; // NOT IMPLEMENTED Tree.saveNodesStateInCookies = true; /*   CSS classes */ Tree.expandedClassName = ""; Tree.collapsedClassName = "collapsed"; Tree.selectedClassName = "selected"; Tree.plusMinusClassName = "plusminus"; Tree.treeClass = "tree"; /*   Images */ Tree.collapsedImage = "treeimg/collapsed.gif"; Tree.expandedImage = "treeimg/expanded.gif"; Tree.noChildrenImage = "treeimg/treenochild.gif"; /*   Xml Attributes */ Tree.xmlCaption = "caption"; Tree.xmlUrl = "url"; Tree.xmlTarget = "target"; Tree.xmlRetreiveUrl = "retreiveUrl"; Tree.xmlIcon = "icon"; Tree.xmlExpanded = "expanded"; /*   Text for loading */ Tree.loadingText = "Loading ..."; /*   Private members */ Tree.obj = null; Tree.instanceCount = 0; Tree.instancePrefix = "alder"; Tree.cookiePrefix = "alder"; Tree.dwnldQueue = new Array; Tree.dwnldCheckTimeout = 100; /*   Interval handler. Ckecks for new nodes loaded.   Adds loaded nodes to the tree. */ Tree.checkLoad = function () {   var i, httpReq;   for (i = 0; i<Tree.dwnldQueue.length; i++)     if ((httpReq = Tree.dwnldQueue[i][0]).readyState == 4 /*COMPLETED*/)     {       var node = Tree.dwnldQueue[i][1];       // unqueue loaded item       Tree.dwnldQueue.splice(i, 1);       Tree.appendLoadedNode(httpReq, node);       if (Tree.saveNodesStateInCookies)         Tree.openAllSaved(Tree.getId(node));     } // if   // will call next time, not all nodes were loaded   if (Tree.dwnldQueue.length != 0)     window.setTimeout(Tree.checkLoad, Tree.dwnldCheckTimeout); } /*   Adds loaded node to tree. */ Tree.appendLoadedNode = function (httpReq, node) {   // create DomDocument from loaded text   var xmlDoc = Tree.loadXml(httpReq.responseText);   // create tree nodes from xml loaded   var newNode = Tree.convertXml2NodeList(xmlDoc.documentElement);   // Add loading error handling here must be added   Tree.appendNode(node, newNode); } /*   Event handler when node is clicked.   Navigates node link, and makes node selected. */ Tree.NodeClick = function (event) {   var node = event.srcElement /*IE*/ || event.target /*DOM*/;   // <li><a><img> - <img> is capturing the event   while (node.tagName != "A")     node = node.parentNode;   node.blur();   node = node.parentNode;   Tree.obj = Tree.getObj(node);   Tree.expandNode(node);   Tree.selectNode(node); } /*   Event handler when plus/minus icon is clicked.   Desides whenever node should be expanded or collapsed. */ Tree.ExpandCollapseNode = function (event) {   var anchorClicked = event.srcElement /*IE*/ || event.target /*DOM*/;   // <li><a><img> - <img> is capturing the event   while (anchorClicked.tagName != "A")     anchorClicked  = anchorClicked.parentNode;   anchorClicked.blur();   var node = anchorClicked.parentNode;   // node has no children, and cannot be expanded or collapsed   if (node.empty)     return;   Tree.obj = Tree.getObj(node);   if (Tree.isNodeCollapsed(node))     Tree.expandNode(node);   else     Tree.collapseNode(node);   // cancelling the event to prevent navigation.   if (event.preventDefault == undefined)   { // IE     event.cancelBubble = true;     event.returnValue = false;   } // if   else   { // DOM     event.preventDefault();     event.cancelBubble = true;   } // else } /*   Determines if specified node is selected. */ Tree.isNodeSelected = function (node) {   return (node.isSelected == true) || (Tree.obj.selectedNode == node); } /*   Determines if specified node is expanded. */ Tree.isNodeExpanded = function (node) {   return (Tree.expandedClassName == node.className) || (node.expanded == true); } /*   Determines if specified node is collapsed. */ Tree.isNodeCollapsed = function (node) {   return (Tree.collapsedClassName == node.className) || (node.collapsed == true); } /*   Determines if node currently selected is at same   level as node specified (has same root). */ Tree.isSelectedNodeAtSameLevel = function (node) {   if (Tree.obj.selectedNode == null) // no node currently selected     return false;   var i, currentNode, children = node.parentNode.childNodes; // all nodes at same level (li->ul->childNodes)   for (i = 0; i < children.length; i++)     if ((currentNode = children[i]) != node && Tree.isNodeSelected(currentNode))       return true;   return false; } /*   Mark node as selected and unmark prevoiusly selected.   Node is marked with attribute and <a> is marked with css style   to avoid mark <li> twise with css style expanded and selected. */ Tree.selectNode = function (node) {   if (Tree.isNodeSelected(node)) // already marked     return;   if (Tree.obj.selectedNode != null)   {// unmark previously selected node.     Tree.obj.selectedNode.isSelected = false;     // remove css style from anchor     Tree.getNodeAnchor(Tree.obj.selectedNode).className = "";   } // if   // collapse selected node if at same level   if (Tree.isSelectedNodeAtSameLevel(node))     Tree.collapseNode(Tree.obj.selectedNode);   // mark node as selected   Tree.obj.selectedNode = node;   node.isSelected = true;   Tree.getNodeAnchor(node).className = Tree.selectedClassName; } /*   Expand collapsed node. Loads children nodes if needed. */ Tree.expandNode = function (node, avoidSaving) {   if (node.empty)     return;   Tree.getNodeImage(node).src = Tree.expandedImage;   node.className = Tree.expandedClassName;   node.expanded = true;   node.collapsed = false;   if (Tree.areChildrenNotLoaded(node))     Tree.loadChildren(node);   if (Tree.saveNodesStateInCookies && !avoidSaving)     Tree.saveOpenedNode(node); } /*   Collapse expanded node. */ Tree.collapseNode = function (node, avoidSaving) {   if (node.empty)     return;   Tree.getNodeImage(node).src = Tree.collapsedImage;   node.className = Tree.collapsedClassName;   node.collapsed = true;   node.expanded = false;   if (Tree.saveNodesStateInCookies && !avoidSaving)     Tree.saveClosedNode(node); } /*   Returns plus/minus <img> for node specified. */ Tree.getNodeImage = function (node) {   return node.getElementsByTagName("IMG")[0]; } /*   Returns retreiveUrl for node specified. */ Tree.getNodeRetreiveUrl = function (node) {   return node.getElementsByTagName("A")[0].href; } /*   Returns node link <a> element (<li><a><img></a><a>) */ Tree.getNodeAnchor = function (node) {   return node.getElementsByTagName("A")[1]; } /*   Cancel loading children nodes. */ Tree.CancelLoad = function (event) {    var i, node = event.srcElement /*IE*/ || event.target /*DOM*/;   while (node.tagName != "LI")     node = node.parentNode;   // search node in queue   for (i = 0; i<Tree.dwnldQueue.length; i++)     if (Tree.dwnldQueue[i][1] == node)     {       // remove from queue       Tree.dwnldQueue.splice(i, 1);       // collapse node       Tree.collapseNode(node);     } // if } /*   Loads text from url specified and returns it as result. */ Tree.loadUrl = function (url, async) {   // create request object   var httpReq = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");   // prepare request   httpReq.open("GET" /* method */, url /* url */, async == true /* async */, null /* login */, null /* password */);   // send request   httpReq.send(null);   return async == true? httpReq : httpReq.responseText; } /*   Creates XmlDom document from xml text string. */ Tree.loadXml = function (xmlString) {   var xmlDoc;   if (window.DOMParser) /*Mozilla*/     xmlDoc = new DOMParser().parseFromString(xmlString, "text/xml");   else   {     if (document.implementation && document.implementation.createDocument)       xmlDoc = document.implementation.createDocument("","", null); /*Konqueror*/     else       xmlDoc = new ActiveXObject("Microsoft.XmlDom"); /*IE*/          xmlDoc.async = false;     xmlDoc.loadXML(xmlString);   } // else   return xmlDoc; } /*   Determines if children are loaded for node specified. */ Tree.areChildrenNotLoaded = function (node) {   return Tree.getNodeSpan(node) != null; } /*   Finds loading span for node. */ Tree.getNodeSpan = function (node) {   var span = node.getElementsByTagName("SPAN");   return (span.length > 0 && (span = span[0]).parentNode == node) ? span : null; } /*   Enqueue load of children nodes for node specified. */ Tree.loadChildren = function (node) {   // get url with children   var url = Tree.getNodeRetreiveUrl(node);   // retreive xml text from url   var httpReq = Tree.loadUrl(url, true);   // enqueue node loading   if (Tree.dwnldQueue.push(new Array (httpReq, node)) == 1)     window.setTimeout(Tree.checkLoad, Tree.dwnldCheckTimeout); } /*   Creates HTML nodes list from XML nodes. */ Tree.convertXml2NodeList = function (xmlElement) {   var ul = document.createElement("UL");   var i, node, children = xmlElement.childNodes;   var index = 0;   for (i = 0; i<children.length; i++)     if ((node = children[i]).nodeType == 1 /* ELEMENT_NODE */)       ul.appendChild(Tree.convertXml2Node(node)).nodeIndex = index++;   return ul; } /*   Adds event handler */ Tree.addEvent = function (obj, fn, ev) {   if (ev == undefined) ev = "click"; // defaulting event to onclick   if (obj.addEventListener)     obj.addEventListener(ev, fn, false);   else     if (obj.attachEvent)       obj.attachEvent("on"+ev, fn);     else       obj.onclick = fn; } /*   Determines if xml node has child nodes inside. */ Tree.hasXmlNodeChildren = function (xmlElement) {   var i, children = xmlElement.childNodes;   for (i = 0; i<children.length; i++)     if ((node = children[i]).nodeType == 1 /* ELEMENT_NODE */)       return true;   return false; } /*   Appends newly created node to node specified.   Simply replace loading <span> at new node. */ Tree.appendNode = function (node, newNode) {   node.replaceChild(newNode, Tree.getNodeSpan(node)); } /*   Creates tree object. Loads it content from url specified. */ Tree.prototype.Create = function (url, obj) {   var div = document.createElement("DIV");   div.id = Tree.instancePrefix + Tree.instanceCount++;   div.className = Tree.treeClass;   var xml = Tree.loadUrl(url, false);   var xmlDoc = Tree.loadXml(xml);   var newNode = Tree.convertXml2NodeList(xmlDoc.documentElement);   div.appendChild(newNode);   if (obj != undefined)   {     if (obj.appendChild) // is node       obj.appendChild(div);     else if (document.getElementById(obj)) // is node id       document.getElementById(obj).appendChild(div);   } // if   else     document.body.appendChild(div);   if (Tree.saveNodesStateInCookies)     Tree.openAllSaved(div.id); } /*   Creates HTML tree node (<li>) from xml element. */ Tree.convertXml2Node = function (xmlElement) {   var li = document.createElement("LI");   var a1 = document.createElement("A");   var a2 = document.createElement("A");   var i1 = document.createElement("IMG");   var i2 = document.createElement("IMG");   var hasChildNodes = Tree.hasXmlNodeChildren(xmlElement);   var retreiveUrl = xmlElement.getAttribute(Tree.xmlRetreiveUrl);      // plus/minus icon   i1.className = Tree.plusMinusClassName;   a1.appendChild(i1);   Tree.addEvent(a1, Tree.ExpandCollapseNode);      // plus/minus link   a1.href = retreiveUrl != null && retreiveUrl.length != 0 ? retreiveUrl : "about:blank";   li.appendChild(a1);      // node icon   i2.src = xmlElement.getAttribute(Tree.xmlIcon);   a2.appendChild(i2);      // node link   a2.href = xmlElement.getAttribute(Tree.xmlUrl);   a2.target = xmlElement.getAttribute(Tree.xmlTarget);   a2.title = xmlElement.getAttribute(Tree.xmlCaption);   a2.appendChild(document.createTextNode(xmlElement.getAttribute(Tree.xmlCaption)));   Tree.addEvent(a2, Tree.NodeClick);   li.appendChild(a2);      // loading span   if (!hasChildNodes && retreiveUrl != null && retreiveUrl.length != 0)   {     var span = document.createElement("SPAN");     span.innerHTML = Tree.loadingText;     Tree.addEvent(span, Tree.CancelLoad);     li.appendChild(span);   } // if      // add children   if (hasChildNodes)     li.appendChild(Tree.convertXml2NodeList(xmlElement));   if (hasChildNodes || retreiveUrl != null && retreiveUrl.length != 0)   {     if (xmlElement.getAttribute(Tree.xmlExpanded))       Tree.expandNode(li, true);     else       Tree.collapseNode(li, true);   } // if   else   {     i1.src = Tree.noChildrenImage; // no children     li.empty = true;   } // else   return li; } /*   Retreives current tree object. */ Tree.getObj = function (node) {   var obj = node;   while (obj != null && obj.tagName != "DIV")     obj = obj.parentNode;   return obj; } Tree.getId = function (node) {   var obj = Tree.getObj(node);   if (obj)     return obj.id;   return ""; } /*   Retreives unique id for tree node. */ Tree.getNodeId = function (node) {   var id = "";   var obj = node;   while (obj != null && obj.tagName != "DIV")   {     if (obj.tagName == "LI" && obj.nodeIndex != null)       id = "_" + obj.nodeIndex + id;     obj = obj.parentNode;   } // while //  if (obj != null && obj.tagName == "DIV") //    id = obj.id + "_" + id;   return id; } /*   Saves node as opened for reload. */ Tree.saveOpenedNode = function (node) {   var treeId = Tree.getId(node);   var state = Tree.getAllNodesSavedState(treeId);   var nodeState = Tree.getNodeId(node) + ",";   if (state.indexOf(nodeState) == -1)   {     state += nodeState;     Tree.setAllNodesSavedState(treeId, state);   } // if } /*   Saves node as closed for reload. */ Tree.saveClosedNode = function (node) {   var treeId = Tree.getId(node);   var state = Tree.getAllNodesSavedState(treeId);   state = state.replace(new RegExp(Tree.getNodeId(node) + ",", "g"), "");   Tree.setAllNodesSavedState(treeId, state); } Tree.getAllNodesSavedState = function (treeId) {   var state = Tree.getCookie(Tree.cookiePrefix + "_" + treeId);   return state == null ? "" : state; } Tree.setAllNodesSavedState = function (treeId, state) {   Tree.setCookie(Tree.cookiePrefix + "_" + treeId, state); } /*   Enques list of all opened nodes */ Tree.openAllSaved = function(treeId) {   var nodes = Tree.getAllNodesSavedState(treeId).split(",");   var i;   for (i=0; i<nodes.length; i++)   {     var node = Tree.getNodeById(treeId, nodes[i]);     if (node && Tree.isNodeCollapsed(node))       Tree.expandNode(node);   } // for } Tree.getNodeById = function(treeId, nodeId) {   var node = document.getElementById(treeId);   if (!node)     return null;   var path = nodeId.split("_");   var i;   for (i=1; i<path.length; i++)   {     if (node != null)     {       node = node.firstChild;       while (node != null && node.tagName != "UL")         node = node.nextSibling;     } // if     if (node != null)       node = node.childNodes[path[i]];     else       break;   } // for   return node; } Tree.setCookie = function(sName, sValue) {   document.cookie = sName + "=" + escape(sValue) + ";"; } Tree.getCookie = function(sName) {   var a = document.cookie.split("; ");   for (var i=0; i < a.length; i++)   {     var aa = a[i].split("=");     if (sName == aa[0])        return unescape(aa[1]);   } // for   return null; } </script> </head> <body> <div id="tree"></div> <hr/> <script type="text/javascript"> new Tree().Create("tree.xml", "tree"); new Tree().Create("tree.xml"); </script> </body> </html>                          SimpleTree.zip( 7 k)