Artifact Content
Not logged in

Artifact d0527f77fa102d004186c830c424df392eb1f9d6


     1  /* This file is a part of CanDyDOC fileset.
     2     File is written by Victor Nakoryakov and placed into the public domain.
     3  
     4     This file is javascript with classes that represents native style tree control. */
     5     
     6  var pmNone = 0;
     7  var pmPlus = 1;
     8  var pmMinus = 2;
     9  
    10  var hlNone = 0;
    11  var hlGrey = 1;
    12  var hlSelected = 2;
    13  
    14  function TreeView(hrefMode)
    15  {
    16      this.domEntry = document.createElement("div");
    17      this.children = new Array();
    18      this.selection = null;
    19      this.hrefMode = hrefMode;
    20      
    21      this.createBranch = function(text, iconSrc)
    22      {
    23          var root = new TreeNode(text, iconSrc, this.hrefMode);
    24          root.owner = this;
    25          this.children[ this.children.length ] = root;
    26          this.domEntry.appendChild( root.domEntry );
    27          return root;
    28      }
    29      
    30      this.branch = function(text)
    31      {
    32          var ret = null;
    33          for (var i = 0; i < this.children.length; ++i)
    34              if (this.children[i].textElement.data == text)
    35              {
    36                  ret = this.children[i];
    37                  break;
    38              }
    39              
    40          return ret;
    41      }
    42      
    43      this.domEntry.style.fontSize = "10px";
    44      this.domEntry.style.cursor = "default";
    45      this.domEntry.style.whiteSpace = "nowrap";
    46  }
    47  
    48  var idCounter = 0;
    49  function TreeNode(text, iconSrc, hrefMode)
    50  {
    51      this.id             = idCounter++;
    52      this.parentNode     = null;
    53      this.children       = new Array();
    54      this.domEntry       = document.createElement("div");
    55      this.icon           = document.createElement("img");
    56      this.textElement    = document.createTextNode(text);
    57      this.textSpan       = document.createElement("span");
    58      this.lineDiv        = document.createElement("div");
    59      this.hierarchyImgs  = new Array();
    60      this.onclick        = null;
    61      
    62      function createIcon()
    63      {
    64          var img = document.createElement("img");
    65          img.style.verticalAlign = "middle";
    66          img.style.position = "relative";
    67          img.style.top = "-1px";
    68          img.width = 16;
    69          img.height = 16;
    70          return img;
    71      }
    72      
    73      function createHierarchyImage()
    74      {
    75          var img = createIcon();
    76          img.pointsTop = false;
    77          img.pointsBottom = false;
    78          img.pointsRight = false;
    79          img.pmState = pmNone;
    80          return img;
    81      }
    82      
    83      function genHierarchyImageSrc(hierarchyImg)
    84      {
    85          var name = "";
    86          if (hierarchyImg.pointsTop)
    87              name += "t";
    88              
    89          if (hierarchyImg.pointsBottom)
    90              name += "b";
    91              
    92          if (hierarchyImg.pointsRight)
    93              name += "r";
    94              
    95          if (hierarchyImg.pmState == pmPlus)
    96              name += "p";
    97          else if (hierarchyImg.pmState == pmMinus)
    98              name += "m";
    99          
   100          if (name == "")
   101              name = "shim";
   102          
   103          return "candydoc/img/tree/" + name + ".gif";
   104      }
   105      
   106      function setSrc(icon, src)
   107      {
   108          icon.src = src;
   109          // After src change width and height are reseted in IE.
   110          // Bug workaround:
   111          icon.width = 16;
   112          icon.height = 16;
   113      }
   114      
   115      this.createChild = function(text, iconSrc)
   116      {
   117          var child = new TreeNode(text, iconSrc, this.owner.hrefMode);
   118          this.children[ this.children.length ] = child;
   119          this.domEntry.appendChild( child.domEntry );
   120          child.parentNode = this;
   121          child.owner = this.owner;
   122          
   123          // insert hierarchy images according to deepness level
   124          // of created child.
   125          
   126          if (this.children.length > 1)
   127          {
   128              // there were already added child before. So copy `level-1`
   129              // hierarchy images from it.
   130              
   131              var prevAddedChild = this.children[ this.children.length - 2 ];
   132              
   133              for (var i = 0; i < prevAddedChild.hierarchyImgs.length - 1; ++i)
   134              {
   135                  var prevAddedChildImg = prevAddedChild.hierarchyImgs[i];
   136                  var img = createHierarchyImage();
   137                  setSrc(img, prevAddedChildImg.src);
   138                  img.pointsTop = prevAddedChildImg.pointsTop;
   139                  img.pointsBottom = prevAddedChildImg.pointsBottom;
   140                  img.pointsRight = prevAddedChildImg.pointsRight;
   141                  img.pmState = prevAddedChildImg.pmState;
   142                  
   143                  child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
   144                  child.lineDiv.insertBefore(img, child.icon);
   145              }
   146              
   147              // change last hierarchy image of prevAddedChild from |_ to |-
   148              var lastHierarchyImg = prevAddedChild.hierarchyImgs[ prevAddedChild.hierarchyImgs.length - 1 ];
   149              lastHierarchyImg.pointsBottom = true;
   150              setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg));
   151                          
   152              // change hierarchy images of prevAddedChild's children on it's last
   153              // level to |
   154              prevAddedChild.addHierarchyTBLine(prevAddedChild.hierarchyImgs.length - 1);
   155          }
   156          else
   157          {
   158              // this is a first child. So copy `level-2`
   159              // hierarchy images from parent, i.e. this.
   160              
   161              for (var i = 0; i < this.hierarchyImgs.length - 1; ++i)
   162              {
   163                  var parentImg = this.hierarchyImgs[i];
   164                  var img = createHierarchyImage();
   165                  setSrc(img, parentImg.src);
   166                  img.pointsTop = parentImg.pointsTop;
   167                  img.pointsBottom = parentImg.pointsBottom;
   168                  img.pointsRight = parentImg.pointsRight;
   169                  img.pmState = parentImg.pmState;
   170                  
   171                  child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
   172                  child.lineDiv.insertBefore(img, child.icon);
   173              }
   174              
   175              if (this.hierarchyImgs.length > 0) // we are not root
   176              {
   177                  // change last hierarchy image of parent (i.e. this): add minus to it
   178                  var lastHierarchyImg = this.hierarchyImgs[ this.hierarchyImgs.length - 1];
   179                  lastHierarchyImg.pmState = pmMinus;
   180                  setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg));
   181                  lastHierarchyImg.owner = this;
   182                  lastHierarchyImg.onclick = new Function("e", "this.owner.processPMClick(e);");
   183                  
   184                  // make decision on image on `level-1`. It depends on parent's (ie this)
   185                  // image on same level.
   186                  var parentL1HierarchyImg = lastHierarchyImg;
   187                  var l1HierarchyImg = createHierarchyImage();
   188                  if (parentL1HierarchyImg.pointsBottom)
   189                  {
   190                      l1HierarchyImg.pointsTop = true;
   191                      l1HierarchyImg.pointsBottom = true;
   192                  }
   193                  setSrc(l1HierarchyImg, genHierarchyImageSrc(l1HierarchyImg));
   194                  child.hierarchyImgs[ child.hierarchyImgs.length ] = l1HierarchyImg;
   195                  child.lineDiv.insertBefore(l1HierarchyImg, child.icon);
   196              }
   197          }
   198          
   199          // in any case on last level our child will have icon |_
   200          var img = createHierarchyImage();
   201          img.pointsTop = true;
   202          img.pointsRight = true;
   203          setSrc(img, genHierarchyImageSrc(img));
   204          
   205          child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
   206          child.lineDiv.insertBefore(img, child.icon);
   207          
   208          return child;
   209      }
   210      
   211      this.lastChild = function()
   212      {
   213          return this.children[ this.children.length - 1 ];
   214      }
   215      
   216      this.child = function(text)
   217      {
   218          var ret = null;
   219          for (var i = 0; i < this.children.length; ++i)
   220              if (this.children[i].textElement.data == text)
   221              {
   222                  ret = this.children[i];
   223                  break;
   224              }
   225              
   226          return ret;
   227      }
   228      
   229      this.addHierarchyTBLine = function(level)
   230      {
   231          for (var i = 0; i < this.children.length; ++i)
   232          {
   233              var img = this.children[i].hierarchyImgs[level];
   234              img.pointsTop = true;
   235              img.pointsBottom = true;
   236              setSrc(img, genHierarchyImageSrc(img));
   237              this.children[i].addHierarchyTBLine(level);
   238          }
   239      }
   240      
   241      this.expand = function()
   242      {
   243          var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
   244          
   245          if (img.pmState == pmPlus)
   246          {
   247              img.pmState = pmMinus;
   248              setSrc(img, genHierarchyImageSrc(img));
   249              
   250              for (var i = 0; i < this.children.length; ++i)
   251                  this.children[i].domEntry.style.display = "";
   252          }
   253      }
   254      
   255      this.collapse = function()
   256      {
   257          var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
   258          
   259          if (img.pmState == pmMinus)
   260          {
   261              img.pmState = pmPlus;
   262              setSrc(img, genHierarchyImageSrc(img));
   263              
   264              for (var i = 0; i < this.children.length; ++i)
   265                  this.children[i].domEntry.style.display = "none";
   266          }
   267      }
   268      
   269      this.toggle = function()
   270      {
   271          var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
   272          if (img.pmState == pmMinus)
   273              this.collapse();
   274          else
   275              this.expand();
   276      }
   277      
   278      this.select = function()
   279      {
   280          if (this.owner.selection != this)
   281          {
   282              if (this.owner.selection)
   283                  this.owner.selection.setHighlight(hlNone);
   284                  
   285              this.owner.selection = this;
   286              this.setHighlight(hlSelected);
   287          }
   288      }
   289      
   290      this.setHighlight = function(mode)
   291      {
   292          if (mode == hlNone)
   293          {
   294              this.textSpan.style.backgroundColor = "";
   295              this.textSpan.style.color = "";
   296              this.textSpan.style.border = "";
   297          }
   298          else if (mode == hlGrey)
   299          {
   300              this.textSpan.style.backgroundColor = "#aaaaaa";
   301              this.textSpan.style.color = "";
   302              this.textSpan.style.border = "";
   303          }
   304          else if (mode == hlSelected)
   305          {
   306              this.textSpan.style.backgroundColor = "3399cc";
   307              this.textSpan.style.color = "white";
   308              this.textSpan.style.border = "dotted 1px red";
   309          }
   310      }
   311      
   312      this.setOnclick = function(proc)
   313      {
   314          this.onclick = proc;
   315      }
   316      
   317      this.setRef = function(url)
   318      {
   319          if (this.anchor)
   320              this.anchor.href = url;
   321      }
   322      
   323      this.processPMClick = function(e)
   324      {
   325          this.toggle();
   326          
   327          // prevent this line selection, stop bubbling
   328          if (e)
   329              e.stopPropagation(); // Mozilla way
   330          if (window.event)
   331              window.event.cancelBubble = true; // IE way
   332      }
   333      
   334      this.processOnclick = function()
   335      {
   336          this.select();
   337          if (this.onclick instanceof Function)
   338              this.onclick();
   339      }
   340      
   341      ///////////////////////////////////////////////////////////////////////////
   342      if (iconSrc)
   343          this.icon.src = iconSrc;
   344      else
   345      {
   346          this.icon.width = 0;
   347          this.icon.height = 0;
   348      }
   349      
   350      this.icon.style.verticalAlign = "middle";
   351      this.icon.style.position = "relative";
   352      this.icon.style.top = "-1px";
   353      this.icon.style.paddingRight = "2px";
   354      
   355      if (!hrefMode)
   356      {
   357          this.textSpan.appendChild( this.textElement );
   358      }
   359      else
   360      {
   361          this.anchor = document.createElement("a");
   362          this.anchor.appendChild( this.textElement );
   363          this.textSpan.appendChild( this.anchor );
   364      }
   365      
   366      this.lineDiv.appendChild( this.icon );
   367      this.lineDiv.appendChild( this.textSpan );
   368      this.domEntry.appendChild( this.lineDiv );
   369      
   370      this.lineDiv.owner = this;
   371      
   372      if (!hrefMode)
   373          this.lineDiv.onclick = new Function("this.owner.processOnclick();");
   374  }