///// Creating the tree component // p_div: ID of the div where the tree will be rendered; // p_backColor: Background color of the region where the tree is being rendered; // p_contextMenu: Object containing all the context menus. Set null for no context menu; function createTree(p_div,p_backColor,p_contextMenu) { var tree = { name: 'tree', div: p_div, ulElement: null, childNodes: [], backcolor: p_backColor, contextMenu: p_contextMenu, selectedNode: null, nodeCounter: 0, contextMenuDiv: null, rendered: false, ///// Creating a new node // p_text: Text displayed on the node; // p_expanded: True or false, indicating wether the node starts expanded or not; // p_icon: Relative path to the icon displayed with the node. Set null if the node has no icon; // p_parentNode: Reference to the parent node. Set null to create the node on the root; // p_tag: Tag is used to store additional information on the node. All node attributes are visible when programming events and context menu actions; // p_contextmenu: Name of the context menu, which is one of the attributes of the p_contextMenu object created with the tree; createNode: function(p_text,p_expanded, p_icon, p_parentNode,p_tag,p_contextmenu) { v_tree = this; node = { id: 'node_' + this.nodeCounter, text: p_text, icon: p_icon, parent: p_parentNode, expanded : p_expanded, childNodes : [], tag : p_tag, contextMenu: p_contextmenu, elementLi: null, ///// Removing the node and all its children removeNode: function() { v_tree.removeNode(this); }, ///// Expanding or collapsing the node, depending on the expanded value toggleNode: function(p_event) { v_tree.toggleNode(this); }, ///// Expanding the node expandNode: function(p_event) { v_tree.expandNode(this); }, ///// Expanding the node and its children recursively expandSubtree: function() { v_tree.expandSubtree(this); }, ///// Changing the node text // p_text: New text; setText: function(p_text) { v_tree.setText(this,p_text); }, ///// Collapsing the node collapseNode: function() { v_tree.collapseNode(this); }, ///// Collapsing the node and its children recursively collapseSubtree: function() { v_tree.collapseSubtree(this); }, ///// Deleting all child nodes removeChildNodes: function() { v_tree.removeChildNodes(this); }, ///// Creating a new child node; // p_text: Text displayed; // p_expanded: True or false, indicating wether the node starts expanded or not; // p_icon: Icon; // p_tag: Tag; // p_contextmenu: Context Menu; createChildNode: function(p_text,p_expanded,p_icon,p_tag,p_contextmenu) { return v_tree.createNode(p_text,p_expanded,p_icon,this,p_tag,p_contextmenu); } } this.nodeCounter++; if (this.rendered) { if (p_parentNode==undefined) { this.drawNode(this.ulElement,node); this.adjustLines(this.ulElement,false); } else { var v_ul = p_parentNode.elementLi.getElementsByTagName("ul")[0]; if (p_parentNode.childNodes.length==0) { if (p_parentNode.expanded) { p_parentNode.elementLi.getElementsByTagName("ul")[0].style.display = 'block'; v_img = p_parentNode.elementLi.getElementsByTagName("img")[0]; v_img.style.visibility = "visible"; v_img.src = 'images/collapse.png'; v_img.id = 'toggle_off'; } else { p_parentNode.elementLi.getElementsByTagName("ul")[0].style.display = 'none'; v_img = p_parentNode.elementLi.getElementsByTagName("img")[0]; v_img.style.visibility = "visible"; v_img.src = 'images/expand.png'; v_img.id = 'toggle_on'; } } this.drawNode(v_ul,node); this.adjustLines(v_ul,false); } } if (p_parentNode==undefined) { this.childNodes.push(node); node.parent=this; } else p_parentNode.childNodes.push(node); return node; }, ///// Render the tree; drawTree: function() { this.rendered = true; var div_tree = document.getElementById(this.div); div_tree.innerHTML = ''; ulElement = createSimpleElement('ul',this.name,'tree'); this.ulElement = ulElement; for (var i=0; i 0) { if (!p_node.expanded) v_ul.style.display = 'none'; for (var i=0; i0) { this.expandSubtree(this.childNodes[i]); } } }, ///// Expanding all nodes inside the subtree that have parameter 'p_node' as root // p_node: Subtree root; expandSubtree: function(p_node) { this.expandNode(p_node); for (var i=0; i0) { this.expandSubtree(p_node.childNodes[i]); } } }, ///// Collapsing all tree nodes collapseTree: function() { for (var i=0; i0) { this.collapseSubtree(this.childNodes[i]); } } }, ///// Collapsing all nodes inside the subtree that have parameter 'p_node' as root // p_node: Subtree root; collapseSubtree: function(p_node) { this.collapseNode(p_node); for (var i=0; i0) { this.collapseSubtree(p_node.childNodes[i]); } } }, ///// Expanding node // p_node: Reference to the node; expandNode: function(p_node) { if (p_node.childNodes.length>0 && p_node.expanded==false) { if (this.nodeBeforeOpenEvent!=undefined) this.nodeBeforeOpenEvent(p_node); var img=p_node.elementLi.getElementsByTagName("img")[0]; p_node.expanded = true; img.id="toggle_off"; img.src = 'images/collapse.png'; elem_ul = img.parentElement.getElementsByTagName("ul")[0]; elem_ul.style.display = 'block'; if (this.nodeAfterOpenEvent!=undefined) this.nodeAfterOpenEvent(p_node); } }, ///// Collapsing node // p_node: Reference to the node; collapseNode: function(p_node) { if (p_node.childNodes.length>0 && p_node.expanded==true) { var img=p_node.elementLi.getElementsByTagName("img")[0]; p_node.expanded = false; if (this.nodeBeforeCloseEvent!=undefined) this.nodeBeforeCloseEvent(p_node); img.id="toggle_on"; img.src = 'images/expand.png'; elem_ul = img.parentElement.getElementsByTagName("ul")[0]; elem_ul.style.display = 'none'; } }, ///// Toggling node // p_node: Reference to the node; toggleNode: function(p_node) { if (p_node.childNodes.length>0) { if (p_node.expanded) p_node.collapseNode(); else p_node.expandNode(); } }, ///// Double clicking node // p_node: Reference to the node; doubleClickNode: function(p_node) { this.toggleNode(p_node); }, ///// Selecting node // p_node: Reference to the node; selectNode: function(p_node) { var span = p_node.elementLi.getElementsByTagName("span")[0]; span.className = 'node_selected'; if (this.selectedNode!=null && this.selectedNode!=p_node) this.selectedNode.elementLi.getElementsByTagName("span")[0].className = 'node'; this.selectedNode = p_node; }, ///// Deleting node // p_node: Reference to the node; removeNode: function(p_node) { var index = p_node.parent.childNodes.indexOf(p_node); if (p_node.elementLi.className=="last" && index!=0) { p_node.parent.childNodes[index-1].elementLi.className += "last"; p_node.parent.childNodes[index-1].elementLi.style.backgroundColor = this.backcolor; } p_node.elementLi.parentNode.removeChild(p_node.elementLi); p_node.parent.childNodes.splice(index, 1); if (p_node.parent.childNodes.length==0) { var v_img = p_node.parent.elementLi.getElementsByTagName("img")[0]; v_img.style.visibility = "hidden"; } }, ///// Deleting all node children // p_node: Reference to the node; removeChildNodes: function(p_node) { if (p_node.childNodes.length>0) { var v_ul = p_node.elementLi.getElementsByTagName("ul")[0]; var v_img = p_node.elementLi.getElementsByTagName("img")[0]; v_img.style.visibility = "hidden"; p_node.childNodes = []; v_ul.innerHTML = ""; } }, ///// Rendering context menu when mouse right button is pressed over a node. This function should no be called directly // p_event: Event triggered when right clicking; // p_node: Reference to the node; nodeContextMenu: function(p_event,p_node) { if (p_event.button==2) { p_event.preventDefault(); p_event.stopPropagation(); if (p_node.contextMenu!=undefined) { v_tree = this; var v_menu = this.contextMenu[p_node.contextMenu]; var v_div; if (this.contextMenuDiv==null) { v_div = createSimpleElement('ul','ul_cm','menu'); document.body.appendChild(v_div); } else v_div = this.contextMenuDiv; v_div.innerHTML = ''; var v_left = p_event.pageX-5; var v_right = p_event.pageY-5; v_div.style.display = 'block'; v_div.style.position = 'absolute'; v_div.style.left = v_left + 'px'; v_div.style.top = v_right + 'px'; for (var i=0; i0) { lists = [ tree ]; if (p_recursive) { for (var i = 0; i < tree.getElementsByTagName("ul").length; i++) { var check_ul = tree.getElementsByTagName("ul")[i]; if (check_ul.childNodes.length!=0) lists[lists.length] = check_ul; } } } for (var i = 0; i < lists.length; i++) { var item = lists[i].lastChild; while (!item.tagName || item.tagName.toLowerCase() != "li") { item = item.previousSibling; } item.className += "last"; item.style.backgroundColor = this.backcolor; item = item.previousSibling; if (item!=null) if (item.tagName.toLowerCase() == "li") { item.className = ""; item.style.backgroundColor = 'transparent'; } } } } window.onclick = function() { if (tree.contextMenuDiv!=null) tree.contextMenuDiv.style.display = 'none'; } return tree; } // Helper Functions //Create a HTML element specified by parameter 'p_type' function createSimpleElement(p_type,p_id,p_class) { element = document.createElement(p_type); if (p_id!=undefined) element.id = p_id; if (p_class!=undefined) element.className = p_class; return element; } //Create img element function createImgElement(p_id,p_class,p_src) { element = document.createElement('img'); if (p_id!=undefined) element.id = p_id; if (p_class!=undefined) element.className = p_class; if (p_src!=undefined) element.src = p_src; return element; }