Mega Code Archive

 
Categories / JavaScript DHTML / GUI Components
 

Tree table Demo

<html> <head> <title>Document sans titre</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <!-- extendedArray.js --> <script type="text/javascript"> function array_contains(obj) {   for (var i = 0; i < this.length; i++)   {      if (this[i] == obj) return i;   }   return -1; } Array.prototype.contains = array_contains; function array_remove(obj) {     var index = this.contains(obj);     if(index > -1)         this.splice(index, 1); } Array.prototype.remove = array_remove; // using this function ensure that you won't add an element which already exists in the array function array_add(obj) {     var index = this.contains(obj);     if(index == -1)         this.push(obj); } Array.prototype.add = array_add; function array_to_string() {     var result = '';   for (var i = 0; i < this.length; i++)   {      result += this[i] + " ; ";      //log(this[i]);   }   return result; } Array.prototype.to_string = array_to_string; </script> <!-- treetable.js --> <script type="text/javascript"> var open_nodes = new Array(); // ICONS var FOLDER_CLSD_PIC = "treeTableImages/icon_arrowfolderclosed1_sml.gif"; var FOLDER_OPEN_PIC = "treeTableImages/icon_arrowfolderopen2_sml.gif"; var DOC_PIC = "treeTableImages/icon_doc_sml.gif"; // highlighting var normalColor = '#E6F2FF'; var highlightColor = '#C6D2DF'; // Regular Expressions // specify how the id are encoded to represent the path of the tree // ususally we just need to change TREE_PATH_SEP var RE_PATH = "[0-9]+";  var TREE_PATH_SEP  = '.'; // This method should be called when a click occurs on the folder icon (or something equivalent!) // e is the event and elm is the element on which the event occured function toggleRows(e, elm) {     // first we check if we moved the mouse during the click as it signifies that it is a dnd and not a click   if(mouseMoved(e))     return;     var toggledRow = find_ancestor('tr', elm);     var id = toggledRow.id;  // the id of the row we are toggling (it contains the path)     var name = toggledRow.getAttribute('name');     var rows = find_ancestor('table', elm).getElementsByTagName("TR");     // regular expression representing the id of the children of toggledRow     var idToggledRE = id.slice(0, id.length) + RE_PATH;     if(open_nodes.contains(name) > -1) // the element was opened -> closing     {         elm.style.backgroundImage = "url("+FOLDER_CLSD_PIC+")";         for (var i = 0; i < rows.length; i++)         {           var currentRow = rows[i];           if (matchStart(currentRow.id, idToggledRE, false)) // if currentRow is a child of toggledRow           {               currentRow.style.display = "none";           }       }       open_nodes.remove(name);     }     else // opening     {         // trick to avoid a problem of display after a restore when a folder become a doc as he is empty         if(elm.getAttribute("class") != 'folder'){             open_nodes.remove(name);             return;         }         elm.style.backgroundImage = "url("+FOLDER_OPEN_PIC+")";         for (var i = 0; i < rows.length; i++)         {           var currentRow = rows[i];           var currentIconLink = currentRow.getElementsByTagName("A")[0];           if (matchStart(currentRow.id, idToggledRE, true)) // if currentRow is a child of toggledRow           {               if (document.all)                   currentRow.style.display = "block"; //IE4+ specific code                else                   currentRow.style.display = "table-row";                                   // this is just to be sure that we have the right icon (maybe not necessary)                if(currentIconLink.getAttribute("class") != 'folder')                   currentIconLink.style.backgroundImage = "url("+DOC_PIC+")";                                // reopen the rows which where already opened                 if (open_nodes.contains(currentRow.getAttribute('name')) > -1)                {                   open_nodes.remove(currentRow.getAttribute('name'));                   toggleRows(null, currentIconLink);                }           }       }       open_nodes.add(name);     }     // ignore the selectRow event as it was a toggling event     ignoreSelectRowEvt = true; } // return the first element of the collection with an attribute 'name' correponding to name function findElementByName(collection, name) {     for (var i = 0; i < collection.length; i++)     {         if(collection[i].getAttribute('name') == name){             return collection[i];         }     } } // pattern is a string containing a regular expression without the '/' at the beginning and the end // returns true if target begin with pattern, false else. Moreover if matchDirectChildrenOnly=true // we return false if the target is not a direct child. function matchStart(target, pattern, matchDirectChildrenOnly) {    var patternObj = eval("/^"+pattern+"/");    if (!target.match(patternObj)) return false;    if (!matchDirectChildrenOnly) return true;    var extendedPattern = eval("/^"+pattern+"["+TREE_PATH_SEP+"]"+RE_PATH+"/");    if (target.match(extendedPattern)) return false;    return true; } function collapseAllRows() {    var rows = document.getElementsByTagName("TR");    var pattern = eval("/^[0-9]+["+TREE_PATH_SEP+"]"+RE_PATH+"/");    var patternFirstLevel = eval("/^"+RE_PATH+"["+TREE_PATH_SEP+"]$/");    for (var j = 0; j < rows.length; j++)    {       var r = rows[j];       if (r.id.match(pattern))       {          r.style.display = "none";          if(r.getElementsByTagName("A")[0].getAttribute('class')=='folder')             r.getElementsByTagName("A")[0].style.backgroundImage = "url("+FOLDER_CLSD_PIC+")";     else        r.getElementsByTagName("A")[0].style.backgroundImage = "url("+DOC_PIC+")";       }else if (r.id.match(patternFirstLevel))       {          r.getElementsByTagName("A")[0].style.backgroundImage = "url("+FOLDER_CLSD_PIC+")";       }    }    open_nodes = new Array(); } function openAllRows() {    var rows = document.getElementsByTagName("TR");    var pattern = eval("/^"+RE_PATH+"["+TREE_PATH_SEP+"]/");    var patternFirstLevel = eval("/^"+RE_PATH+"["+TREE_PATH_SEP+"]$/");    var firstLevelRows = new Array();    open_nodes = new Array();    for (var i = 0; i < rows.length; i++)    {       var r = rows[i];       if (r.id.match(patternFirstLevel))       {          firstLevelRows.push(r);       }       else if (r.id.match(pattern))       {          open_nodes.add(r.getAttribute('name'));       }    }    for (var j = 0; j < firstLevelRows.length; j++)       toggleRows(null,firstLevelRows[j].getElementsByTagName("A")[0]); } // restore the state of the tree depending on open_nodes // take all the nodes of first level and for each reopen or close it depending on  // the open_nodes list. Moreover we call toggleRows to restore the state of the children nodes. function restore(){   var rows = document.getElementsByTagName("TR");      var pattern = eval("/^"+RE_PATH+"["+TREE_PATH_SEP+"]$/");   for (var j = 0; j < rows.length; j++)   {      var r = rows[j];      if (r.id.match(pattern)) // first level       {       // as toggleRows() will check open_nodes to know wheter it has to open or close the node,        // we have to do the opposite before because we just want to restore the state and not to really toggle it         if (open_nodes.contains(r.getAttribute('name')) > -1)            open_nodes.remove(r.getAttribute('name'));         else            open_nodes.add(r.getAttribute('name'));         toggleRows(null, r.getElementsByTagName("A")[0]);      }   } } // This method should be used with an onclick event for your tables rows (TR) // in order to have them visually selected var selectedRow; var ignoreSelectRowEvt = false; // set this variable to true if you want to ignore the next selectRow event function selectRow(row) {     if(ignoreSelectRowEvt){         ignoreSelectRowEvt = false;         return;     }     if(selectedRow)         selectedRow.style.backgroundColor = normalColor;          // if we are deselecting     if(selectedRow && selectedRow.id == row.id)     {         selectedRow = null;     }else{         selectedRow = row;         row.style.backgroundColor = highlightColor;     } } </script> <!-- utils.js --> <script type="text/javascript"> // return the first ancestor tag (tagAnc) of obj function find_ancestor(tagAnc, obj) {    var exit = false;    var parent = obj;    while (!exit)    {       parent = parent.parentNode;       if (parent.tagName == tagAnc.toLowerCase() || parent.tagName == tagAnc.toUpperCase())          return parent;       if (parent.tagName == 'HTML' || parent.tagName == 'html')          return null;    } } function log(txt, divName) {    if (!divName) var divName = 'console';    $(divName).innerHTML += '<br>' + txt; } var clicX = 0; var clicY = 0; function storeMouseXY(e) {    if (!e) var e = window.event;    if (e.pageX || e.pageY)   {     clicX = e.pageX;     clicY = e.pageY;   }   else if (e.clientX || e.clientY)   {     clicX = e.clientX + document.body.scrollLeft;     clicY = e.clientY + document.body.scrollTop;   } } // return true if the mouse moved more than 3 pixels in one direction between the beginning // of the event and the end of the envent // WARNING : in order to use this method you should use onmousedown="storeMouseXY(event); in the  // element where is called mouseMoved... function mouseMoved(e) {   if(e){       var oldx = clicX, oldy = clicY;       storeMouseXY(e);       if(Math.abs(clicX-oldx) > 3 || Math.abs(clicY-oldy) > 3)           return true;     }   return false; } // get the id of the obj, i.e. the corresponding id in the db function getDB_ID(obj) {    // look for a parent TR    var parentTR;    if (obj.tagName == 'tr' || obj.tagName == 'TR')       parentTR = obj;    else       parentTR = find_ancestor('tr', obj);   return parentTR.id;    // look for a child with name ops    var children = parentTR.getElementsByTagName('td');    var ops = null;    for (var i = 0; i < children.length; i++)    {       if (children[i].getAttribute('name') && children[i].getAttribute('name').toUpperCase() == 'OPS')       {          ops = children[i];          break;       }    }    return ops.firstChild.value; } </script>  <style media="all" rel="Stylesheet" type="text/css"> .folder { background: url(../treeTableImages/icon_arrowfolderclosed1_sml.gif)  no-repeat; float: left; height: 15px; width: 33px; padding-right: 3px; ! important} .doc { background: url(../treeTableImages/icon_doc_sml.gif) no-repeat; float: left; height: 15px; width: 15px; padding-right: 3px; margin-left: 0px; ! important} .tier0 {   margin-left: 0; } .tier1 {   margin-left: 1.5em; } .tier2 {   margin-left: 3em; } .tier3 {   margin-left: 4.5em; } .tier4 {   margin-left: 6em; } .tier5 {   margin-left: 7.5em; } .tier6 {   margin-left: 9em; } .tier7 {   margin-left: 10.5em; } .tier8 {   margin-left: 12em; } .tier9 {   margin-left: 13.5em; } </style> </head> <body onload="collapseAllRows();"> <table width="100%" border="1">   <tr id="0." name="r1">      <td>     <div class="tier0">       <a href="#" onclick="toggleRows(event, this)" onmousedown="storeMouseXY(event); return false;" class="folder"></a>     </div>   </td>     <td>a1</td>     <td>a2</td>     <td>a3</td>     <td>a4</td>   </tr>   <tr id="0.0." name="r2">      <td><div class="tier1"><a href="#" onclick="toggleRows(event, this)" onmousedown="storeMouseXY(event); return false;" class="folder"></a></div></td>     <td>b1</td>     <td>b2</td>     <td>b3</td>     <td>b4</td>   </tr>   <tr id="0.0.0." name="r3">      <td><div class="tier2"><a href="#" onclick="toggleRows(event, this)" onmousedown="storeMouseXY(event); return false;" class="folder"></a></div></td>     <td>c1</td>     <td>c2</td>     <td>c3</td>     <td>c4</td>   </tr>   <tr id="0.0.0.0." name="r4">      <td><div class="tier3"><a href="#" onclick="toggleRows(event, this)" onmousedown="storeMouseXY(event); return false;" class="doc"></a></div></td>     <td>d1</td>     <td>d2</td>     <td>d3</td>     <td>d4</td>   </tr> </table> </body> </html>                     treetable.zip( 10 k)