Artifact d0527f77fa102d004186c830c424df392eb1f9d6
/* This file is a part of CanDyDOC fileset.
File is written by Victor Nakoryakov and placed into the public domain.
This file is javascript with classes that represents native style tree control. */
var pmNone = 0;
var pmPlus = 1;
var pmMinus = 2;
var hlNone = 0;
var hlGrey = 1;
var hlSelected = 2;
function TreeView(hrefMode)
{
this.domEntry = document.createElement("div");
this.children = new Array();
this.selection = null;
this.hrefMode = hrefMode;
this.createBranch = function(text, iconSrc)
{
var root = new TreeNode(text, iconSrc, this.hrefMode);
root.owner = this;
this.children[ this.children.length ] = root;
this.domEntry.appendChild( root.domEntry );
return root;
}
this.branch = function(text)
{
var ret = null;
for (var i = 0; i < this.children.length; ++i)
if (this.children[i].textElement.data == text)
{
ret = this.children[i];
break;
}
return ret;
}
this.domEntry.style.fontSize = "10px";
this.domEntry.style.cursor = "default";
this.domEntry.style.whiteSpace = "nowrap";
}
var idCounter = 0;
function TreeNode(text, iconSrc, hrefMode)
{
this.id = idCounter++;
this.parentNode = null;
this.children = new Array();
this.domEntry = document.createElement("div");
this.icon = document.createElement("img");
this.textElement = document.createTextNode(text);
this.textSpan = document.createElement("span");
this.lineDiv = document.createElement("div");
this.hierarchyImgs = new Array();
this.onclick = null;
function createIcon()
{
var img = document.createElement("img");
img.style.verticalAlign = "middle";
img.style.position = "relative";
img.style.top = "-1px";
img.width = 16;
img.height = 16;
return img;
}
function createHierarchyImage()
{
var img = createIcon();
img.pointsTop = false;
img.pointsBottom = false;
img.pointsRight = false;
img.pmState = pmNone;
return img;
}
function genHierarchyImageSrc(hierarchyImg)
{
var name = "";
if (hierarchyImg.pointsTop)
name += "t";
if (hierarchyImg.pointsBottom)
name += "b";
if (hierarchyImg.pointsRight)
name += "r";
if (hierarchyImg.pmState == pmPlus)
name += "p";
else if (hierarchyImg.pmState == pmMinus)
name += "m";
if (name == "")
name = "shim";
return "candydoc/img/tree/" + name + ".gif";
}
function setSrc(icon, src)
{
icon.src = src;
// After src change width and height are reseted in IE.
// Bug workaround:
icon.width = 16;
icon.height = 16;
}
this.createChild = function(text, iconSrc)
{
var child = new TreeNode(text, iconSrc, this.owner.hrefMode);
this.children[ this.children.length ] = child;
this.domEntry.appendChild( child.domEntry );
child.parentNode = this;
child.owner = this.owner;
// insert hierarchy images according to deepness level
// of created child.
if (this.children.length > 1)
{
// there were already added child before. So copy `level-1`
// hierarchy images from it.
var prevAddedChild = this.children[ this.children.length - 2 ];
for (var i = 0; i < prevAddedChild.hierarchyImgs.length - 1; ++i)
{
var prevAddedChildImg = prevAddedChild.hierarchyImgs[i];
var img = createHierarchyImage();
setSrc(img, prevAddedChildImg.src);
img.pointsTop = prevAddedChildImg.pointsTop;
img.pointsBottom = prevAddedChildImg.pointsBottom;
img.pointsRight = prevAddedChildImg.pointsRight;
img.pmState = prevAddedChildImg.pmState;
child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
child.lineDiv.insertBefore(img, child.icon);
}
// change last hierarchy image of prevAddedChild from |_ to |-
var lastHierarchyImg = prevAddedChild.hierarchyImgs[ prevAddedChild.hierarchyImgs.length - 1 ];
lastHierarchyImg.pointsBottom = true;
setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg));
// change hierarchy images of prevAddedChild's children on it's last
// level to |
prevAddedChild.addHierarchyTBLine(prevAddedChild.hierarchyImgs.length - 1);
}
else
{
// this is a first child. So copy `level-2`
// hierarchy images from parent, i.e. this.
for (var i = 0; i < this.hierarchyImgs.length - 1; ++i)
{
var parentImg = this.hierarchyImgs[i];
var img = createHierarchyImage();
setSrc(img, parentImg.src);
img.pointsTop = parentImg.pointsTop;
img.pointsBottom = parentImg.pointsBottom;
img.pointsRight = parentImg.pointsRight;
img.pmState = parentImg.pmState;
child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
child.lineDiv.insertBefore(img, child.icon);
}
if (this.hierarchyImgs.length > 0) // we are not root
{
// change last hierarchy image of parent (i.e. this): add minus to it
var lastHierarchyImg = this.hierarchyImgs[ this.hierarchyImgs.length - 1];
lastHierarchyImg.pmState = pmMinus;
setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg));
lastHierarchyImg.owner = this;
lastHierarchyImg.onclick = new Function("e", "this.owner.processPMClick(e);");
// make decision on image on `level-1`. It depends on parent's (ie this)
// image on same level.
var parentL1HierarchyImg = lastHierarchyImg;
var l1HierarchyImg = createHierarchyImage();
if (parentL1HierarchyImg.pointsBottom)
{
l1HierarchyImg.pointsTop = true;
l1HierarchyImg.pointsBottom = true;
}
setSrc(l1HierarchyImg, genHierarchyImageSrc(l1HierarchyImg));
child.hierarchyImgs[ child.hierarchyImgs.length ] = l1HierarchyImg;
child.lineDiv.insertBefore(l1HierarchyImg, child.icon);
}
}
// in any case on last level our child will have icon |_
var img = createHierarchyImage();
img.pointsTop = true;
img.pointsRight = true;
setSrc(img, genHierarchyImageSrc(img));
child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
child.lineDiv.insertBefore(img, child.icon);
return child;
}
this.lastChild = function()
{
return this.children[ this.children.length - 1 ];
}
this.child = function(text)
{
var ret = null;
for (var i = 0; i < this.children.length; ++i)
if (this.children[i].textElement.data == text)
{
ret = this.children[i];
break;
}
return ret;
}
this.addHierarchyTBLine = function(level)
{
for (var i = 0; i < this.children.length; ++i)
{
var img = this.children[i].hierarchyImgs[level];
img.pointsTop = true;
img.pointsBottom = true;
setSrc(img, genHierarchyImageSrc(img));
this.children[i].addHierarchyTBLine(level);
}
}
this.expand = function()
{
var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
if (img.pmState == pmPlus)
{
img.pmState = pmMinus;
setSrc(img, genHierarchyImageSrc(img));
for (var i = 0; i < this.children.length; ++i)
this.children[i].domEntry.style.display = "";
}
}
this.collapse = function()
{
var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
if (img.pmState == pmMinus)
{
img.pmState = pmPlus;
setSrc(img, genHierarchyImageSrc(img));
for (var i = 0; i < this.children.length; ++i)
this.children[i].domEntry.style.display = "none";
}
}
this.toggle = function()
{
var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
if (img.pmState == pmMinus)
this.collapse();
else
this.expand();
}
this.select = function()
{
if (this.owner.selection != this)
{
if (this.owner.selection)
this.owner.selection.setHighlight(hlNone);
this.owner.selection = this;
this.setHighlight(hlSelected);
}
}
this.setHighlight = function(mode)
{
if (mode == hlNone)
{
this.textSpan.style.backgroundColor = "";
this.textSpan.style.color = "";
this.textSpan.style.border = "";
}
else if (mode == hlGrey)
{
this.textSpan.style.backgroundColor = "#aaaaaa";
this.textSpan.style.color = "";
this.textSpan.style.border = "";
}
else if (mode == hlSelected)
{
this.textSpan.style.backgroundColor = "3399cc";
this.textSpan.style.color = "white";
this.textSpan.style.border = "dotted 1px red";
}
}
this.setOnclick = function(proc)
{
this.onclick = proc;
}
this.setRef = function(url)
{
if (this.anchor)
this.anchor.href = url;
}
this.processPMClick = function(e)
{
this.toggle();
// prevent this line selection, stop bubbling
if (e)
e.stopPropagation(); // Mozilla way
if (window.event)
window.event.cancelBubble = true; // IE way
}
this.processOnclick = function()
{
this.select();
if (this.onclick instanceof Function)
this.onclick();
}
///////////////////////////////////////////////////////////////////////////
if (iconSrc)
this.icon.src = iconSrc;
else
{
this.icon.width = 0;
this.icon.height = 0;
}
this.icon.style.verticalAlign = "middle";
this.icon.style.position = "relative";
this.icon.style.top = "-1px";
this.icon.style.paddingRight = "2px";
if (!hrefMode)
{
this.textSpan.appendChild( this.textElement );
}
else
{
this.anchor = document.createElement("a");
this.anchor.appendChild( this.textElement );
this.textSpan.appendChild( this.anchor );
}
this.lineDiv.appendChild( this.icon );
this.lineDiv.appendChild( this.textSpan );
this.domEntry.appendChild( this.lineDiv );
this.lineDiv.owner = this;
if (!hrefMode)
this.lineDiv.onclick = new Function("this.owner.processOnclick();");
}