/ddoc/candydoc/tree.js
http://github.com/baryluk/cords · JavaScript · 374 lines · 296 code · 57 blank · 21 comment · 48 complexity · 02d45da25624946c40d4748d9abc3b42 MD5 · raw file
- /* 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();");
- }