JavaScript DHTML/GUI Components/Tree Table

Материал из Web эксперт
Перейти к: навигация, поиск

Tree table Demo

   <source lang="html4strict">

<html> <head> <title>Document sans titre</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<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>

<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>

<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 += "
" + 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();">

     <a href="#" onclick="toggleRows(event, this)" onmousedown="storeMouseXY(event); return false;" class="folder"></a>
a1 a2 a3 a4
<a href="#" onclick="toggleRows(event, this)" onmousedown="storeMouseXY(event); return false;" class="folder"></a>
b1 b2 b3 b4
<a href="#" onclick="toggleRows(event, this)" onmousedown="storeMouseXY(event); return false;" class="folder"></a>
c1 c2 c3 c4
<a href="#" onclick="toggleRows(event, this)" onmousedown="storeMouseXY(event); return false;" class="doc"></a>
d1 d2 d3 d4

</body> </html>


      </source>
   
  

<A href="http://www.wbex.ru/Code/JavaScriptDownload/treetable.zip">treetable.zip( 10 k)</a>