Nano Tree : Tree « GUI Components « JavaScript DHTML






Nano Tree

 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>NanoTree</title>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">

<!-- std_treelook.css -->
<style REL="STYLESHEET" TYPE="text/css">
/* Tree Style */
.treetitle {
  padding:2px;
  cursor:default;
  
  font-family: Tahoma,Verdana,Arial, Helvetica, sans-serif;
  font-size: 11px;
  color: #000000;
}
.editednode {
  padding:2px;
  cursor:default;
  background-color: #FFFFFF;;
  color: #000000;
  
  font-family: Tahoma,Verdana,Arial, Helvetica, sans-serif;
  font-size: 11px;
}
.editednodeinput {
  background-color: #FFFFFF;;
  color: #000000;
  
  width: 150px;
  height: 17px;
  
  border-style: solid;
  border-width: 1px;
  border-color: #000000;
  
  font-family: Tahoma,Verdana,Arial, Helvetica, sans-serif;
  font-size: 11px;
}
.treetitleselectedfocused {
  padding:2px;
  cursor:default;
  background-color: highlight;
  color: highlighttext;
  
  font-family: Tahoma,Verdana,Arial, Helvetica, sans-serif;
  font-size: 11px;
}
.treetitleselectedblured {
  padding:2px;
  cursor:default;
  background-color: menu;
  color: windowtext;
  font-family: Tahoma,Verdana,Arial, Helvetica, sans-serif;
  font-size: 11px;
}
</style>

<!-- nanotree.js -->
<script type="text/javascript" language="JavaScript">
/**
* Original Author of this file: Martin Mouritzen. (martin@nano.dk)
*
*
* (Lack of) Documentation:
*
*
* If a finishedLoading method exists, it will be called when the tree is loaded.
* (good to display a div, etc.).
*
*
* You have to set the variable rootNode (as a TreeNode).
*
* You have to set a container element, this is the element in which the tree will be.
*
*
* TODO: 
* Save cookies better (only 1 cookie for each tree). Else the page will totally cookieclutter.
*
***********************************************************************
* Configuration variables.
************************************************************************/

// Should the rootNode be displayed.
var showRootNode = true;

// Should the dashed lines between nodes be shown.
var showLines = true;

// Should the nodes be sorted? (You can either specify a number, then it will be sorted by that, else it will
// be sorted alphabetically (by name).
var sortNodes = true;

// This is IMPORTANT... use an unique id for each document you use the tree in. (else they'll get mixed up).
var documentID = window.location.href;

// being read from cookie.
var nodesOpen = new Array();

// RootNode of the tree.
var rootNode;

// Container to display the Tree in.
var container;

// Shows/Hides subnodes on startup
var showAllNodesOnStartup = false;

// Is the roots dragable?
var dragable = false;


/************************************************************************
* The following is just instancevariables.
************************************************************************/
var href = '';

// rootNodeCallBack name (if null, it's not selectable).
var rootNodeCallBack = null;

// selectedNode
var selectedNode = null;

var states = '';
var statearray = new Array();

var treeNodeEdited = null;

var editaborted = false;

var floatDragElement = null;
var colouredElement = null;
var draggedNodeID = null;
var lastDraggedOnNodeID = null;


/**
* The TreeNode Object
* @param id unique id of this treenode
* @param name The title of this node
* @param icon The icon if this node (Can also be an array with 2 elements, the first one will represent the closed state, and the next one the open state)
* @param param A parameter, this can be pretty much anything. (eg. an array with information).
* @param orderNumber an orderNumber If one is given the nodes will be sorted by this (else they'll be sorted alphabetically (If sorting is on).
*/
function TreeNode(id,name,icon,param,orderNumber) {
  this.id = id;
  this.childs = new Array();
  this.name = (name == null ? 'unset name' : name);
  this.icon = (icon == null ? '' : icon);
  this.parent = null;
  this.handler = null;
  this.param = (param == null ? '' : param);
  this.orderNumber = (orderNumber == null ? -1 : orderNumber);
  
  this.openeventlisteners = new Array();
  this.editeventlisteners = new Array();
  this.moveeventlisteners = new Array();
  this.haschilds = false;
  this.editable = false;
  this.linestring = '';
  
  this.nextSibling = null;
  this.prevSibling = null;
  
  this.childsHasBeenFetched = false;

  this.getID = function() {
    return this.id;
  }
  this.setName = function(newname) {
    this.name = newname;
  }
  this.getName = function() {
    return this.name;
  }
  this.getParam = function() {
    return this.param;
  }
  this.setIcon = function(icon) {
    this.icon = icon;
  }
  this.getIcon = function() {
    if (typeof(this.icon) == 'object') {
      return this.icon[0];
    }
    return this.icon;
  }
  this.getOpenIcon = function() {
    if (typeof(this.icon) == 'object') {
      return this.icon[1];
    }
    return this.icon;
  }
  this.hasIcon = function () {
    return this.icon != '';
  }
  this.getOrderNumber = function() {
    return this.orderNumber;
  }
  this.addOpenEventListener = function(event) {
    this.openeventlisteners[this.openeventlisteners.length] = event;
  }
  this.gotOpenEventListeners = function() {
    return (this.openeventlisteners.length > 0);
  }
  this.addEditEventListener = function(event) {
    this.editeventlisteners[this.editeventlisteners.length] = event;
  }
  this.gotEditEventListeners = function() {
    return (this.editeventlisteners.length > 0);
  }
  this.addMoveEventListener = function(event) {
    this.moveeventlisteners[this.moveeventlisteners.length] = event;
  }
  this.gotMoveEventListeners = function() {
    return (this.moveeventlisteners.length > 0);
  }
  this.addChild = function(childNode) {
    var possiblePrevNode = this.childs[this.childs.length - 1]
    if (possiblePrevNode) {
      possiblePrevNode.nextSibling = childNode;
      childNode.prevSibling = possiblePrevNode;
      // alert(childNode.prevSibling);
    }

    this.childs[this.childs.length] = childNode;
    childNode.setParent(this);

    if (sortNodes) {
      function sortByOrder(a,b) {
        var order1 = a.getOrderNumber();
        var order2 = b.getOrderNumber();
        if (order1 == -1 || order2 == -1) {
          return a.getName().toLowerCase() > b.getName().toLowerCase() ? 1 : -1;
        }
        else {
          if (order1 == order2) {
            // If they got the same order number, then we'll sort by their title.
            return a.getName().toLowerCase() > b.getName().toLowerCase() ? 1 : -1;
          }
          else {
            return order1 - order2;
          }
        }
      }
      this.childs.sort(sortByOrder);
    }
  }
  this.removeChild = function(childNode) {
    var found = false;
    for (var i=0;i<this.childs.length;i++) {
      if (found) {
        this.childs[i] = this.childs[i + 1];
      }
      if (this.childs[i] == childNode) {
        if (i == (this.childs.length - 1)) {
          this.childs[i] = null;
        }
        else {
          this.childs[i] = this.childs[i + 1];
        }
        found = true;
      }
    }
    if (found) {
      this.childs.length = this.childs.length-1;
    }
  }
  this.resetChilds = function() {
    this.childs = new Array();
  }
  this.setHasChilds = function(hasChilds) {
    this.haschilds = hasChilds;
  }
  this.hasChilds = function() {
    if (this.haschilds == true) {
      return true;
    }
    return (this.childs.length > 0);
  }
  this.getChildCount = function() {
    return this.childs.length;
  }
  this.getFirstChild = function() {
    if (this.hasChilds()) {
      return this.childs[0];
    }
    return null;
  }
  this.gotHandler = function() {
    return this.handler != null;
  }
  this.setHandler = function(handler) {
    this.handler = handler;
  }
  this.getHandler = function() {
    return this.handler;
  }
  this.setParent = function(parent) {
    this.parent = parent;
  }
  this.getParent = function() {
    return this.parent;
  }
  this.getLineString = function() {
    return this.linestring;
  }
  this.setLineString = function(string) {
    this.linestring = string;
  }
  this.isEditable = function() {
    return this.editable;
  }
  this.setEditable = function(editable) {
    this.editable = editable;
  }
  
}
function getTreeNode(nodeID) {
  return findNodeWithID(rootNode,nodeID);
}
function findNodeWithID(node,nodeID) {
  if (node.getID() == nodeID) {
    return node;
  }
  else {
    if (node.hasChilds()) {
      for(var i=0;i<node.getChildCount();i++) {
        var value = findNodeWithID(node.childs[i],nodeID);
        if (value != false) {
          return value;
        }
      }
    }
    return false;
  }
}
function readStates() {
  //setCookie('tree' + documentID,'');
  states = getCookie('tree' + documentID);
  if (states != null) {
    var array = states.split(';');
    for(var i=0;i<array.length;i++) {
      var singlestate = array[i].split('|');
      statearray[i] = new Array();
      statearray[i]["key"] = singlestate[0];
      statearray[i]["state"]  = singlestate[1];
    }
  }
}
function getState(nodeID) {
  for(var i=0;i<statearray.length;i++) {
    if (statearray[i]["key"] == nodeID) {
      state = statearray[i]["state"];
      if (state == null || state == '') {
        state = 'closed';
      }
      return state;
    }
  }
  return "closed";
}
function writeStates(nodeID,newstate) {
  //alert(nodeID);
  var str = '';
  var found = false;
  for(var i=0;i<statearray.length;i++) {
    if (statearray[i]["key"] == nodeID) {
      statearray[i]["state"] = newstate;
      found = true;
    }
    if (statearray[i]["state"] != null) {
      str += statearray[i]["key"] + '|' + statearray[i]["state"] + ';';
    }
  }
  if (found == false) {
    statearray[statearray.length] = new Array();
    statearray[statearray.length - 1]["key"] = nodeID;
    statearray[statearray.length - 1]["state"] = newstate;
    if (newstate != null) {
      str += nodeID + '|' + newstate + ';';
    }
  }
  setCookie('tree' + documentID,str);
}
function showTree(path) {
  readStates();
  
  href = path;
  window.focus();
  window.onblur = blurSelection;
  window.onfocus = focusSelection;
  var str = '';
  str = '<div id="node' + rootNode.getID() + '" class="treetitle" style="display:' + (showRootNode == true ? 'block' : 'none') + '">';
  str += '<nobr>';
  if (rootNode.hasIcon()) {
    str += '<img src="' + rootNode.getIcon() + '" style="vertical-align:middle;">';
  }
  str += '<span style="vertical-align:middle;">&nbsp;' + rootNode.getName() + '</span>';
  str += '</nobr></div>';
  
  if (rootNode.hasChilds()) {
    for(i=0;i<rootNode.childs.length;i++) {
      nodeContents = showNode(rootNode.childs[i],(i == (rootNode.getChildCount() -1)));
      str = str + nodeContents;
    }
  }
  container.innerHTML = str;
  if (window.finishedLoading) {
    finishedLoading();
  }
}
/**
* Shows the given node, and subnodes.
*/
function showNode(treeNode,lastNode) {
  linestring = treeNode.getLineString();
  var state = getState(treeNode.getID());
  var str;
  str = '<div style="filter:alpha(opacity=100);" ondragenter="dragEnter(' + treeNode.getID() + ');" ondragleave="dragLeave();" ondragstart="startDrag(' + treeNode.getID() + ');" ondrag="dragMove();" ondragend="endDrag(' + treeNode.getID() + ')" id="node' + treeNode.getID() + '">';
  str += '<nobr>';
  for(var y=0;y<linestring.length;y++) {
    if (linestring.charAt(y) == 'I') {
      str += '<img src="' + href + 'nanoImages/' + (showLines ? 'line' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
    }
    else if (linestring.charAt(y) == 'B') {
      str += '<img src="' + href + 'nanoImages/white.gif" style="width:19px;height:20px;vertical-align:middle;">';
    }
  }
  if (treeNode.hasChilds()) {
    // If this is the first child of the rootNode, and showRootNode is false, we want to display a different icon.
    if (!showRootNode && (treeNode.getParent() == rootNode) && (treeNode.getParent().getFirstChild() == treeNode)) {
      if (!lastNode) {
        str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/' + (state == 'open' ? (showLines ? 'minus_no_root' : 'minus_nolines') : (showLines ? 'plus_no_root' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
      }
      else {
        str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/' + (state == 'open' ? 'minus_last' : 'plus_last') + '_no_root.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
      }
    }
    else {
      if (!lastNode) {
        str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/' + (state == 'open' ? (showLines ? 'minus' : 'minus_nolines') : (showLines ? 'plus' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
      }
      else {
        str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/' + (state == 'open' ? (showLines ? 'minus_last' : 'minus_nolines') : (showLines ? 'plus_last' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
      }
    }
  }
  else {
    // If this is the first child of the rootNode, and showRootNode is false, we want to display a different icon.
    if (!showRootNode && (treeNode.getParent() == rootNode) && (treeNode.getParent().getFirstChild() == treeNode)) {
      if (!lastNode) {
        str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/' + (showLines ? 't_no_root' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
      }
      else {
        str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/white.gif" style="width:19px;height:20px;vertical-align:middle;">';
      }
    }
    else {
      if (!lastNode) {
        str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/' + (showLines ? 't' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
      }
      else {
        str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/' + (showLines ? 'lastnode' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
      }
    }
  }
  iconStartImage = treeNode.getIcon();
  if (state != 'closed') {
    if (treeNode.hasChilds()) {
      iconStartImage = treeNode.getOpenIcon();
    }
  }
  
  str += '<img id="iconimage' + treeNode.getID() + '" src="' + iconStartImage + '" style="vertical-align:middle;" OnClick="selectNode(' + treeNode.getID() + ')">';
  str += '&nbsp;<span unselectable="ON" style="vertical-align:middle;" class="treetitle" ID="title' + treeNode.getID() + '" OnDblClick="handleNode(' + treeNode.getID() + ')" OnClick="selectNode(' + treeNode.getID() + ')">';
  str += treeNode.getName();
  str += '</span>';
  str += '</nobr>';
  str += '</div>';

  if (treeNode.hasChilds()) {
    if (state == 'open') {
      str += '<div id="node' + treeNode.getID() + 'sub" style="display:block;">';
      fireOpenEvent(treeNode);
      // alert('openevent: ' + treeNode.getName());
    }
    else {
      str += '<div id="node' + treeNode.getID() + 'sub" style="display:' + (showAllNodesOnStartup == true ? 'block;' : 'none;') + ';">';
    }
    var subgroupstr = '';
    var newChar = '';

    if (!lastNode) {
      newChar = 'I';
    }
    else {
      newChar = 'B';
    }
    for(var z=0;z<treeNode.getChildCount();z++) {
      treeNode.childs[z].setLineString(linestring + newChar);
    }
    for(var z=0;z<treeNode.getChildCount();z++) {
      subgroupstr += showNode(treeNode.childs[z],(z == (treeNode.getChildCount() -1)));
    }
    str += subgroupstr;
    str += '</div>';
  }
  else {
    str += '<div id="node' + treeNode.getID() + 'sub" style="display:none;">';
    str += '</div>';
  }
  return str;
}
/*
function mouseMove() {
  if (dragging) {
    alert('bob');
  }
}
function mouseUp() {
  if (dragging) {
    alert('dropped on something!');
  }
}
*/
function startDrag(nodeID) {
  if (!dragable) {
    return;
  }
  draggedNodeID = nodeID;
  
  var srcObj = window.event.srcElement;
  while(srcObj.tagName != 'DIV') {
    srcObj = srcObj.parentElement;
  }
  floatDragElement = document.createElement('DIV');

  floatDragElement.innerHTML = srcObj.innerHTML;
  floatDragElement.childNodes[0].removeChild(floatDragElement.childNodes[0].childNodes[0]);
  
  document.body.appendChild(floatDragElement);
  floatDragElement.style.zIndex = 100;
  floatDragElement.style.position = 'absolute';
  floatDragElement.style.filter='progid:DXImageTransform.Microsoft.Alpha(1,opacity=60);';
}
function findSpanChild(element) {
  if (element.tagName == 'SPAN') {
    return element;
  }
  else {
    if (element.childNodes) {
      for(var i=0;i<element.childNodes.length;i++) {
        var value = findSpanChild(element.childNodes[i]);
        if (value != false) {
          return value;
        }
      }
      return false;
    }
  }
}
function dragEnter(nodeID) {
  if (!dragable) {
    return;
  }
  lastDraggedOnNodeID = nodeID;
  
  if (colouredElement) {
    findSpanChild(colouredElement).className = 'treetitle';
  }
  colouredElement = window.event.srcElement;
  while(colouredElement.tagName != 'DIV') {
    colouredElement = colouredElement.parentElement;
    if (colouredElement.tagName == 'BODY') {
      // Something gone seriously wrong.
      alert('Drag failure, reached <BODY>!');
      return;
    }
  }  
  findSpanChild(colouredElement).className = 'treetitleselectedfocused';
}
function dragLeave() {
  if (!dragable) {
    return;
  }
}
function endDrag(nodeID) {
  if (!dragable) {
    return;
  }
  if (lastDraggedOnNodeID != null) {
    fireMoveEvent(getTreeNode(lastDraggedOnNodeID),draggedNodeID,lastDraggedOnNodeID);
  }
}
function dragProceed() {
  if (!dragable) {
    return;
  }
  var dragged = getTreeNode(draggedNodeID);
  var newparent = getTreeNode(lastDraggedOnNodeID);

  var oldparent = dragged.getParent();
  
  oldparent.removeChild(dragged);
  newparent.addChild(dragged);
  
  refreshNode(oldparent);
  refreshNode(newparent);
  
  _dragClean()
}
function dragCancel() {
  if (!dragable) {
    return;
  }
  _dragClean()
}
/**
* Don't call this yourself.
*/
function _dragClean() {
  if (!dragable) {
    return;
  }
  if (colouredElement) {
    findSpanChild(colouredElement).className = 'treetitle';
  }
  
  floatDragElement.parentElement.removeChild(floatDragElement);
  floatDragElement = null;
  colouredElement = null;
  draggedNodeID = null;
  lastDraggedOnNodeID = null;
}
function dragMove() {
  if (!dragable) {
    return;
  }
  floatDragElement.style.top = window.event.clientY;
  floatDragElement.style.left = window.event.clientX;
}
function editEnded() {
  if (treeNodeEdited != null) {
    // treeNodeEdited.getID();
    var editTitle = document.getElementById('title' + treeNodeEdited.getID());
    var input = editTitle.childNodes[0];
  
    var newValue = input.value;
    
    if (newValue == treeNodeEdited.getName()) {
      editTitle.innerHTML = newValue;
      treeNodeEdited = null;
      return;
    }
  
    fireEditEvent(treeNodeEdited,newValue);
    
    if (!editaborted) {
      treeNodeEdited.setName(newValue);
      editTitle.innerHTML = newValue;
    }
  
    treeNodeEdited = null;
  }
}
function selectNode(nodeID) {
  var treeNode = getTreeNode(nodeID);

  if (selectedNode != null) {
    if (selectedNode == nodeID) {
      if (treeNode.isEditable()) {
        if (treeNodeEdited == treeNode) {
          return;
        }
        treeNodeEdited = treeNode;
        var editTitle = document.getElementById('title' + treeNode.getID());
        editTitle.className = 'editednode';
        

        editTitle.innerHTML = '<input type="text" onKeypress="if (event.keyCode == 13) { this.onblur = null; editEnded(); }" name="editednode" class="editednodeinput">';
        var input = editTitle.childNodes[0];
        input.value = treeNode.getName();
        input.focus();
        input.select();
        input.onblur = editEnded;
      }
      return;
    }
    if (treeNodeEdited != null) {
      editEnded();
    }
    var oldNodeTitle = document.getElementById('title' + selectedNode);
    oldNodeTitle.className = 'treetitle';
  }
  selectedNode = nodeID;
  var nodetitle = document.getElementById('title' + selectedNode);
  nodetitle.className = 'treetitleselectedfocused';
  
  if (treeNode.gotHandler()) {
    eval(treeNode.getHandler() + '(getTreeNode(' + nodeID + '));');
  }
  else {
    standardClick(treeNode);
  }
}
function refreshNode(treeNode) {
  var submenu = document.getElementById('node' + treeNode.getID() + 'sub');
  var str = '';
  for(var i=0;i<treeNode.getChildCount();i++) {
    var parent = treeNode.getParent();
    if (!parent) {
      treeNode.childs[i].setLineString(treeNode.getLineString() + 'B');
    }
    else {
      if (parent.childs[parent.childs.length - 1] == treeNode) {
        treeNode.childs[i].setLineString(treeNode.getLineString() + 'B');
      }
      else {
        treeNode.childs[i].setLineString(treeNode.getLineString() + 'I');
      }
    }
    str += showNode(treeNode.childs[i],i == (treeNode.getChildCount() - 1));
  }
  var actionimage = document.getElementById('handler' + treeNode.getID());
  if (treeNode.getChildCount() == 0) {
    // TreeNode haven't got any children, make sure the right image is displayed.
    if (actionimage.src.indexOf('last') == -1) {
      actionimage.src = href + 'nanoImages/' + (showLines ? 't' : 'white') + '.gif';
    }
    else {
      actionimage.src = href + 'nanoImages/' + (showLines ? 'lastnode' : 'white') + '.gif';
    }
    actionimage.onclick = null;
    
    // Close the submenu
    if (submenu) {
      submenu.style.display = 'none';
    }
  }
  else {
    // We have children, make sure to display the + and - icon.
    if (actionimage.src.indexOf('plus') != -1) {
      // The TreeNode have already got children, and displays them.
    }
    else if (actionimage.src.indexOf('minus') != -1) {
      // The TreeNode have already got children, and displays them.
    }
    else {
      if (actionimage.src.indexOf('last') == -1) {
        actionimage.outerHTML = '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/' + (showLines ? 'plus' : 'plus_nolines') + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
      }
      else {
        actionimage.outerHTML = '<img id="handler' + treeNode.getID() + '" src="' + href + 'nanoImages/plus_last.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';
      }
    }
  }
  submenu.innerHTML = str;
}
function handleNode(nodeID) {
  var treeNode = getTreeNode(nodeID);  
  if (!treeNode.hasChilds()) { // No reason to handle a node without childs.
    return;
  }
  
  var submenu = document.getElementById('node' + nodeID + 'sub');
  
  var iconimageholder = document.getElementById('iconimage' + nodeID);
  var actionimage = document.getElementById('handler' + nodeID);

  // This will be used if showRootNode is set to false.
  var firstChildOfRoot = false;
  if (actionimage.src.indexOf('_no_root') != -1) {
    firstChildOfRoot = true;
  }
  
  if (submenu.style.display == 'none') {
    writeStates(nodeID,'open');
    fireOpenEvent(treeNode);
    submenu.style.display = 'block';

    iconimageholder.src = treeNode.getOpenIcon();
  
    if (actionimage.src.indexOf('last') == -1) {
      actionimage.src = href + 'nanoImages/' + ((firstChildOfRoot) ? 'minus_no_root' : (showLines ? 'minus' : 'minus_nolines')) + '.gif';
    }
    else {
      actionimage.src = href + 'nanoImages/' + ((firstChildOfRoot) ? 'minus_last_no_root' : (showLines ? 'minus_last' : 'minus_nolines')) + '.gif';
    }
  }
  else {
    writeStates(nodeID,'closed');
    submenu.style.display = 'none';
    
    iconimageholder.src = treeNode.getIcon();
    
    if (actionimage.src.indexOf('last') == -1) {
      actionimage.src = href + 'nanoImages/' + ((firstChildOfRoot) ? 'plus_no_root' : (showLines ? 'plus' : 'plus_nolines')) + '.gif';
    }
    else {
      actionimage.src = href + 'nanoImages/' + ((firstChildOfRoot) ? 'plus_last_no_root' : (showLines ? 'plus_last' : 'plus_nolines')) + '.gif';
    }
  }
}
function fireOpenEvent(treeNode) {
  if (treeNode.gotOpenEventListeners()) {
    for(var i=0;i<treeNode.openeventlisteners.length;i++) {
      eval(treeNode.openeventlisteners[i] + '(' + treeNode.getID() + ');');
    }
  }
}
function fireEditEvent(treeNode,newVal) {
  if (treeNode.gotEditEventListeners()) {
    for(var i=0;i<treeNode.editeventlisteners.length;i++) {
      eval(treeNode.editeventlisteners[i] + '(' + treeNode.getID() + ',\'' + escape(newVal) + '\');');
    }
  }
}
function fireMoveEvent(treeNode,draggedNodeID,droppedOnNodeID) {
  if (treeNode.gotMoveEventListeners()) {
    for(var i=0;i<treeNode.moveeventlisteners.length;i++) {
      eval(treeNode.moveeventlisteners[i] + '(' + draggedNodeID + ',' + droppedOnNodeID + ');');
    }
  }
}
function blurSelection() {
  if (selectedNode != null) {
    var oldNodeTitle = document.getElementById('title' + selectedNode);
    oldNodeTitle.className = 'treetitleselectedblured';
  }
}
function focusSelection() {
  if (selectedNode != null) {
    var oldNodeTitle = document.getElementById('title' + selectedNode);
    oldNodeTitle.className = 'treetitleselectedfocused';
  }
}
function getCookieVal (offset) {  
  var endstr = document.cookie.indexOf (";",offset);  
  if (endstr == -1) {
    endstr = document.cookie.length;
  }
  return unescape(document.cookie.substring(offset,endstr));
}
function getCookie (name) {  
  var arg = name + "=";
  var alen = arg.length;
  var clen = document.cookie.length;
  var i = 0;
  while (i < clen) {
    var j = i + alen;
    if (document.cookie.substring(i, j) == arg) {
      return getCookieVal(j);
    }
    i = document.cookie.indexOf(" ", i) + 1;
    if (i == 0) {
      break;
    }
  }
  return null;
}
function setCookie (name, value) {  
  var argv = setCookie.arguments;  
  var argc = setCookie.arguments.length;  
  var expires = (argc > 2) ? argv[2] : null;  
  var path = (argc > 3) ? argv[3] : null;  
  var domain = (argc > 4) ? argv[4] : null;  
  var secure = (argc > 5) ? argv[5] : false;  
  document.cookie = name + "=" + escape (value) + ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + ((path == null) ? "" : ("; path=" + path)) + ((domain == null) ? "" : ("; domain=" + domain)) + ((secure == true) ? "; secure" : "");
}
function expandNode() {
  var state = getState(selectedNode);
  if (state == 'open') {
    var currentTreeNode = getTreeNode(selectedNode);
    if (currentTreeNode.hasChilds()) {
      selectNode(currentTreeNode.childs[0].getID());
    }
  }
  else {
    handleNode(selectedNode);
  }
}
function subtractNode() {
  var state = getState(selectedNode);
  if (state == 'closed') {
    var currentTreeNode = getTreeNode(selectedNode);
    var parent = currentTreeNode.getParent();
    if (parent != null && parent != rootNode) {
      selectNode(parent.getID());
    }
  }
  else {
    handleNode(selectedNode);
  }
}
function selectPrevNode() {
  var currentTreeNode = getTreeNode(selectedNode);
  if (currentTreeNode.prevSibling != null) {

    var state = getState(currentTreeNode.prevSibling.getID());

    if (state == 'open' && currentTreeNode.prevSibling.hasChilds()) {
      // We have to find the last open child of the previoussiblings childs.
      var current = currentTreeNode.prevSibling.childs[currentTreeNode.prevSibling.childs.length - 1];
      var currentstate = 'open';
      while (current.hasChilds() && (getState(current.getID()) == 'open')) {
        current = current.childs[current.childs.length - 1];
      }
      selectNode(current.getID());
    }
    else {
      selectNode(currentTreeNode.prevSibling.getID());
    }
  }
  else {
    if (currentTreeNode.getParent() != null && currentTreeNode.getParent() != rootNode) {
      selectNode(currentTreeNode.getParent().getID());
    }
  }
}
function selectNextNode() {
  var currentTreeNode = getTreeNode(selectedNode);

  var state = getState(selectedNode);
  if (state == 'open' && currentTreeNode.hasChilds()) {
    selectNode(currentTreeNode.childs[0].getID());
  }  
  else {
    if (currentTreeNode.nextSibling != null) {
      selectNode(currentTreeNode.nextSibling.getID());
    }
    else {
      // Continue up the tree until we either hit null, or a parent which have a child.
      var parent = currentTreeNode;
      while ((parent = parent.getParent()) != rootNode) {
        if (parent.nextSibling != null) {
          selectNode(parent.nextSibling.getID());
          break;
        }
      }
      /*
      if (currentTreeNode.getParent().nextSibling != null) {
        selectNode(currentTreeNode.getParent().nextSibling.getID());
      }
      */
    }
  }
}
function keyDown(event) {
  if (window.event) {
    event = window.event;
  }
  if (event.keyCode == 38) { // Up
    selectPrevNode();
    return false;
  }
  else if (event.keyCode == 40) { // Down
    selectNextNode();
    return false;
  }
  else if (event.keyCode == 37) { // left
    subtractNode();
    return false;
  }
  else if (event.keyCode == 39) { // right
    expandNode();
    return false;
  }
}
document.onkeydown = keyDown;
</script>
<script type="text/javascript" language="JavaScript">
showRootNode = false;
sortNodes = false;
dragable = false;

/**
* Needed to initialize the tree.
* And to call showTree(imagePath); to actually show the tree.
* Alternatively this can be done in a script block at the bottom of the page.
* Though this method is somewhat cleaner.
*/
function init() {
  container = document.getElementById('examplediv');
  showTree('');
}
/**
* Called when a user clicks on a node.
* @param treeNode the TreeNode object which have been clicked.
*/
function standardClick(treeNode) {
  var mytext = document.getElementById('mytext');
  var param = treeNode.getParam();
  
  mytext.innerHTML = (param == '') ? treeNode.getName() : param;
}
function nodeEdited(treeNode) {

}
var closedGif = 'nanoImages/folder_closed.gif';
var openGif = 'nanoImages/folder_open.gif';
var pageIcon = 'nanoImages/page16x16.gif';
var userIcon = 'nanoImages/user_16x16.gif';
var helpIcon = 'nanoImages/help_16x16.gif';

rootNode = new TreeNode(1,'RootNode');

var node1 = new TreeNode(2,'subpage 1',helpIcon,'<P>This treenode can be renamed (Try to click onnce more on the node).<br>(You have to handle the renaming itself in a function though, since this is implementation specific. ie: Go down in a database and change the titel of a page).<br>A good example would be to open a PHP script to do the renaming, this can for example be done by setting location.href on a hidden iframe, or by setting the src attribute on a script element.</P>');
node1.setEditable(true);
node1.addEditEventListener('nodeEdited');

var node2 = new TreeNode(3,'subpage 2',new Array(closedGif,openGif));
  var node2a = new TreeNode(4,'1st subpage to Node 2',new Array(closedGif,openGif));
    var node2aa = new TreeNode(5,'subpage to subpage of Node2',new Array(closedGif,openGif));
      var node2aaa = new TreeNode(6,'Some child',pageIcon);
      var node2aab = new TreeNode(7,'Some child',pageIcon);
      var node2aac = new TreeNode(8,'Some child',pageIcon);
      node2aa.addChild(node2aaa);
      node2aa.addChild(node2aab);
      node2aa.addChild(node2aac);
    node2a.addChild(node2aa);
  var node2b = new TreeNode(9,'2nd subpage to Node 2',pageIcon);
  var node2c = new TreeNode(10,'3rd subpageto Node 2',pageIcon);
  node2.addChild(node2a);
  node2.addChild(node2b);
  node2.addChild(node2c);

var node3 = new TreeNode(11,'subpage 3',new Array(closedGif,openGif));
  var node3a = new TreeNode(12,'Yet another child',pageIcon);
  node3.addChild(node3a);

var node4 = new TreeNode(13,'subpage 4',userIcon);

// rootNode.addChild(node1);
rootNode.addChild(node2);
rootNode.addChild(node3);
// rootNode.addChild(node4);
</script>
<style type="text/css">
div,p,a {
  font-family: Verdana,Arial;
  font-size: 11px;
}
#exampletable {
  width: 100%;
  height: 100%;
}
#examplediv {
  width: 250px;
  height: 100%;
  overflow: auto;
}
.explanation {
  font-weight: bold;
  font-style: italic;
}
</style>
</head>
<body OnLoad="init();">
<table id="exampletable">
  <tr>
    <td valign="top" style="width: 250px;">
      <div id="examplediv"></div>
    </td>
    <td valign="top">
      <div style="background-color:#EEE;border-style:dashed;border-color:#000000;border-width:1px;padding:5px;">
        <div style="font-weight: bold;">NanoTree.</div>
        <div id="mytext">
        <p>NanoTree is a JavaScript tree, published under the <a href="http://www.gnu.org/copyleft/lesser.html">LGPL License</a>, which is developed to work in (at least) Internet Explorer and Mozilla<br>
        <p style="font-style:italic;">CopyRight Martin Mouritzen</p>
        </div>
      </div>
      <br>
    </td>
  </tr>
</table>
</body></html>

           
         
  








nanotree.zip( 15 k)

Related examples in the same category

1.Explorer based on tree
2.Yahoo! UI Library - Tree Control
3.Yahoo! UI Library - Tree Control 2
4.Tree Control
5.Dynamic TreeView Example
6.Yahoo! UI Library - Tree Control 3
7.Yahoo! UI Library - Tree Control 4
8.Yahoo! UI Library - Tree Control 5
9.Build a tree in JavaScript
10.Delete, insert items in a tree
11.Tree selection action handler
12.Expand, Collapse, Close, Open selected Tree item and branch
13.Change Tree Node Color and Icon
14.Checkbox tree node: checked, unchecked, get the checked items
15.Change tree expand and collapse icons
16.Drag and Drop between trees
17.Build tree from xml
18.Tree navigation bar
19.Navigation Tree
20.Navigation Tree menu based on XML
21.XML Tree
22.Building Collapsible Trees
23.Tree which accepts drag and drop event in JavaScript (IE)
24.Simple Tree in Javascript
25.Elegant simple tree
26.folder tree static