/********************************************************************
* 程序: tree.js
* 功能: web树视图
* 作者: 胡洲
*
* Copyright 2004-2005 胡洲
*
*********************************************************************/
/*********************************************************************
* tree.js是用于显示资源的树状图,在创建树对象时,会为树指定一个图片
* 资源,缺省时图片资源在应用程序的根目录下的images/tree中,用户也可
* 以通过图片资源中的putImage方法来替换相应的图标。
* 如果节点的子节点需要动态载入,可以在节点中添加一动态载入的节点,如
* node.appendDynamicChild(url);
* url是子节点资源。在子节点资源中,可以通过
* var iframe = window.frameElement;
* var parentNode = iframe.treeParentNode;
* var node1 = parentNode.appendChild("test0", "test");
* parentNode.appendChild("test1", "test");
* parentNode.appendChild("test8", "test");
* parentNode.appendChild("test9", "test");
*
* //子节点载入完毕
* iframe.notify();
* 来动态载入子节点,注意在载入完毕时应调用notify方法来通知树动态载入
* 子节点完毕。
* 注意:一个树对象只能拥有一个根节点
*********************************************************************/
/**
* 树样式表对象
* Document doc 树所在的文档对象
*/
function TreeStyleSheet(doc)
{
this.doc = doc == null ? window.document : doc;
//样式表对象
this.styleSheet = this.doc.createStyleSheet();
//样式表中的rule对象
this.rules = new Array(6);
//rule选择符
var selectors = new Array(6);
selectors[0] = "A.tree___:link";
selectors[1] = "A.tree___:visited";
//注意a元素hover的style的定义必须在visited之后
selectors[2] = "A.tree___:hover";
selectors[3] = ".tree___node_text_td";
selectors[4] = ".tree___node_text_td_mouseover";
selectors[5] = ".tree___node_text_td_selected";
//rule的cssText
var values = new Array(6);
values[0] = values[1]
= "FONT-SIZE: 12px;"
+ "COLOR: #000000;"
+ "TEXT-DECORATION: none";
values[2]
= "FONT-SIZE: 12px;"
+ "COLOR: #cc0000;"
+ "TEXT-DECORATION: underline";
values[3] = values[4]
= "BORDER: none;"
+ "PADDING-RIGHT: 3px;"
+ "PADDING-LEFT: 2px;"
+ "PADDING-BOTTOM: 1px;"
+ "PADDING-TOP: 2px;";
//+ "HEIGHT: 16px";
values[5] = values[3] + ";BACKGROUND-COLOR: #6FACE3";
for(var i = 0; i < this.rules.length; i++)
{
//将rule加入到styleSheet
this.styleSheet.addRule(selectors[i], values[i]);
this.rules[i] = this.styleSheet.rules[i];
}
/********************************************
* 以下提供了获取树对象样式表中对象的方法,
* 可以通过这些方法来获取节点的样式,
* 并指定自己的样式
*******************************************/
//链接的缺省Style
this.getLinkStyle = function()
{
return this.rules[0];
}
//鼠标悬停于链接上时缺省Style
this.getLinkHoverStyle = function()
{
return this.rules[1];
}
//访问过的链接的缺省Style
this.getLinkVisitedStyle = function()
{
return this.rules[2];
}
//节点所在cell的缺省Style
this.getNodeStyle = function()
{
return this.rules[3];
}
//节点所在cell有鼠标移入时的缺省Style
this.getNodeMouseOverStyle = function()
{
return this.rules[4];
}
//节点选中时所在cell的缺省Style
this.getNodeSelectedStyle = function()
{
return this.rules[5];
}
}
/**
* 单击节点树枝
*/
function branchClick()
{
var node = this.parentNode.parentNode.parentNode.parentNode.node;
if(node == null)
{
return;
}
if(node.hasChild())
{
if(node.model)
{
//当前节点收缩,展开所有子节点
node.expand();
}
else
{
//当前节点展开,收缩所有子节点
node.collapse();
}
}
}
/**
* 处理节点图标被单击事件
* 该事件将被处理成节点的链接被单击
*/
function imageClick()
{
//节点
var node = this.parentNode.parentNode.parentNode.parentNode.node;
if(node == null)
{
return;
}
node.link.click();
}
/**
* 处理节点被单击事件
*/
function linkClick()
{
//节点
var node = getTreeNode();
if(node == null)
{
return;
}
//节点所在的树
var tree = node.getTree();
//被拖动了的节点
if(tree.dragedNode != null)
{
tree.dragedNode.link.parentNode.className = "tree___node_text_td";
}
if(this.href == "null")
{
node.expand();
this.blur();
return false;
}
else
{
if(!(node.onclick == null))
{
//用当前节点作参数,回调指定的方法
var result = node.onclick.call(node.onclick, node);
if(result == false)
{
//事件被取消
return false;
}
}
if(node.getDynamicChildFlagNode())
{
//节点是动态载入资源提示节点
return false;
}
this.parentNode.className = "tree___node_text_td_selected";
if(tree.currentSelectedNode != null && tree.currentSelectedNode != node)
{
tree.currentSelectedNode.link.parentNode.className
= "tree___node_text_td";
tree.currentSelectedNode.setSelected(false);
}
tree.currentSelectedNode = node;
node.setSelected(true);
this.blur();
}
}
/**
* 从事件中检索出当前事件的节点
*/
function getTreeNode()
{
var table = window.event.srcElement;
while(table.tagName == null || table.tagName != "TABLE")
{
table = table.parentNode;
if(table == null)
{
//没找到
return null;
}
}
var node = table.node;
if(node == null)
{
//没找到
return null;
}
if(node instanceof TreeNode)
{
return node;
}
//没找到
return null;
}
/**
* 从事件中检索出当前事件的节点的实体
*/
function getTreeNodeBody()
{
var td = window.event.srcElement;
while(td.tagName == null || td.tagName != "TD")
{
td = td.parentNode;
if(td == null)
{
//没找到
return null;
}
}
if(td.tagName == "TD" && td.name == "_TREE_NODE_BODY")
{
return td;
}
return null;
}
/**
* 节点开始拖动
*/
function nodeDragStart()
{
//当前节点
var node = getTreeNode();
var tree = node.getTree();
if(!tree.getNodeDragable())
{
//不允许拖
return;
}
if(tree.dragedNode != null)
{
tree.dragedNode.link.parentNode.className
= "tree___node_text_td";
tree.dragedNode = null
}
if(tree.currentSelectedNode != null)
{
tree.currentSelectedNode.link.parentNode.className
= "tree___node_text_td";
tree.currentSelectedNode.setSelected(false);
}
tree.currentDragedNode = node;
node.link.parentNode.className = "tree___node_text_td_selected";
}
/**
* 将一个拖动的节点在节点上晃来晃去时
*/
function nodeDragOver()
{
//当前节点
var node = getTreeNode();
var tree = node.getTree();
if(!tree.getNodeDragable())
{
//不允许拖
return;
}
if(tree.currentDragedNode == null)
{
return;
}
var cn = node;
while(node != null)
{
if(node == tree.currentDragedNode)
{
return;
}
if(node.isRoot())
{
break;
}
node = node.getParentNode();
}
//目标节点
cn.link.parentNode.className = "tree___node_text_td_selected";
window.event.returnValue = false;
}
/**
* 将一个节点拖出节点时
*/
function nodeDragLeave()
{
//当前节点
var node = getTreeNode();
var tree = node.getTree();
if(!tree.getNodeDragable())
{
//不允许拖
return;
}
if(node == tree.currentDragedNode)
{
return;
}
node.link.parentNode.className = "tree___node_text_td";
window.event.returnValue = false;
}
/**
* 将一个节点丢在当前节点
*/
function nodeDrop()
{
//当前节点
var node = getTreeNode();
var tree = node.getTree();
if(!tree.getNodeDragable())
{
//不允许拖
return;
}
if(tree.currentDragedNode == null)
{
//无被拖的节点
return;
}
//被拖的节点
var cdn = tree.currentDragedNode;
if(node == cdn)
{
return;
}
if(cdn.getParentNode() == node)
{
//拖入父节点,有什么意思
return;
}
//移动
cdn.getParentNode().removeChild(cdn);
//如果有动态载入子节点,先载入
node.expand();
node.appendChild(cdn);
node.expand();
node.link.parentNode.className = "tree___node_text_td";
//跟踪节点
tree.dragedNode = cdn;
}
/**
* 拖动节点完毕
*/
function nodeDragEnd()
{
//当前节点
var node = getTreeNode();
var tree = node.getTree();
if(!tree.getNodeDragable())
{
//不允许拖
return;
}
if(tree.dragedNode == node)
{
//移动成功
node.link.parentNode.className = "tree___node_text_td_selected";
}
else
{
node.link.parentNode.className = "tree___node_text_td";
}
//跟踪节点
tree.currentDragedNode = null;
}
/**
* 空方法
*/
function emptyFunction()
{
}
/**
* 树的图标资源
* String context 应用程序名称,树的缺省时图片资源在
* 应用程序的根目录下的images/tree,访问时以
* /context/images/tree/*.gif来访问
*/
function ImageList(context)
{
//节点图标索引
//空白图片
this.BLANK = 0;
//收缩的根节点的图标
this.ROOT_COLLAPSED_IMAGE = 1;
//展开的根节点的图标
this.ROOT_EXPANED_IMAGE = 2;
//收缩的节点(有子节点)的图标
this.NODE_COLLAPSED_IMAGE = 3;
//展开的节点(有子节点)的图标
this.NODE_EXPANED_IMAGE = 4;
//叶节点的图标
this.LEAF_IMAGE = 5;
//连接节点的枝图标资源
this.LINE = 6;
this.LINE_I = 7;
this.LINE_L = 8;
this.LINE_L_FALLEN = 9;
this.LINE_T = 10;
this.LINE_PLUS_ROOT = 11;
this.LINE_MINUS_ROOT = 12;
this.LINE_PLUS_ROOT_T = 13;
this.LINE_MINUS_ROOT_T = 14;
this.LINE_PLUS_L = 15;
this.LINE_MINUS_L = 16;
this.LINE_PLUS_T = 17;
this.LINE_MINUS_T = 18;
this.NODE_UNCHECKED = 19;
this.NODE_CHECKBOX_DISABLED = 20;
this.NODE_CHECKED = 21;
//图标资源的相对路径
this.imageBase = "images/tree/";
if(context != null)
{
if(context.charAt(context.length - 1) != "/")
{
this.imageBase = context + "/" + this.imageBase;
}
else
{
this.imageBase = context + this.imageBase;
}
}
//图标资源的URL
this.images = new Array(22);
this.images[this.BLANK]
= this.imageBase + "blank.gif";
this.images[this.ROOT_COLLAPSED_IMAGE]
= this.imageBase + "img_parent_collapsed.gif";
this.images[this.ROOT_EXPANED_IMAGE]
= this.imageBase + "img_parent_expanded.gif";
this.images[this.NODE_COLLAPSED_IMAGE]
= this.imageBase + "img_parent_collapsed.gif";
this.images[this.NODE_EXPANED_IMAGE]
= this.imageBase + "img_parent_expanded.gif";
this.images[this.LEAF_IMAGE]
= this.imageBase + "img_leaf.gif";
this.images[this.LINE]
= this.imageBase + "line.gif";
this.images[this.LINE_I]
= this.imageBase + "line_I.gif";
this.images[this.LINE_L]
= this.imageBase + "line_L.gif";
this.images[this.LINE_L_FALLEN]
= this.imageBase + "line_L2.gif";
this.images[this.LINE_T]
= this.imageBase + "line_T.gif";
this.images[this.LINE_PLUS_ROOT]
= this.imageBase + "line_plus_root.gif";
this.images[this.LINE_MINUS_ROOT]
= this.imageBase + "line_minus_root.gif";
this.images[this.LINE_PLUS_ROOT_T]
= this.imageBase + "line_plus_root_T.gif";
this.images[this.LINE_MINUS_ROOT_T]
= this.imageBase + "line_minus_root_T.gif";
this.images[this.LINE_PLUS_L]
= this.imageBase + "line_plus_L.gif";
this.images[this.LINE_MINUS_L]
= this.imageBase + "line_minus_L.gif";
this.images[this.LINE_PLUS_T]
= this.imageBase + "line_plus_T.gif";
this.images[this.LINE_MINUS_T]
= this.imageBase + "line_minus_T.gif";
this.images[this.NODE_UNCHECKED]
= this.imageBase + "check0.gif";
this.images[this.NODE_CHECKBOX_DISABLED]
= this.imageBase + "check1.gif";
this.images[this.NODE_CHECKED]
= this.imageBase + "check2.gif";
/**
* 添加图标资源到对象
* int index 图标在资源中的索引
* String src 图标的相对url
* int width 图标宽
* int heigth 图标高
*/
this.putImage = function(index, src, width, height)
{
this.images[index] = this.imageBase + src;
var img = new Image(width, height);
img.src = this.images[index];
}
/**
* 获取资源中的图标对象的src
* int index 图标在资源中的索引
*/
this.getImage = function(index)
{
return this.images[index];
}
this.setImageBase = function(URL)
{
this.imageBase = url
}
this.getImageBase = function()
{
return this.imageBase;
}
}
/**
* 构造树结点,这个函数应该由其父节点调。
* FlyBean tree 树对象
* String text 节点文本
* String link 节点链接
* String id 节点id
* String target 节点链接的目标框架
* String checked 节点的复选框选中状态
*/
function TreeNode(tree, text, link, id, target, checked)
{
/**
* 节点所在树
*/
this.tree = tree;
/**
* 节点文本
*/
this.text = text;
/**
* 节点链接
*/
this.link = link;
/**
* 节点id
*/
this.id = id;
/**
* 节点链接的目标窗口
*/
this.target = target;
/**
* 节点的选中状态
*/
this.checked = checked == true ? true : false;
/**
* 节点的父节点
*/
this.parentNode = null;
/**
* model为true时,节点收缩,为false时,节点展开
*/
this.model = true;
/**
* 节点是否被选中
*/
this.selected = false;
/**
* 节点的表对象
*/
this.tbody = null;
/**
* 节点的复选框
*/
this.checkbox = null;
/**
* 子节点
*/
this.childNodes = new Array();
/**
* 第一个子节点
*/
this.firstChild = null;
/**
* 最后一个子节点
*/
this.lastChild = null;
/**
* 连接下一个节点的树枝的单元格
* 当节点有子节点时,这个属性才有意义
*/
this.branchToNextNodeTD = null;
/**
* 节点的兄节点
*/
this.previousSibling = null;
/**
* 节点的弟节点
*/
this.nextSibling = null;
/**
* 动态子节点提示符节点
*/
this.dynamicChildFlagNode = false;
/**
* 用户自定义的数据对象,如果在克隆节点时
* 需克隆这个对象,则该对象应提供方法clone,
* 该方法返回一个对象的克隆。如果对象中没
* 有提供clone方法,则在克隆节点时,将克隆
* 一个对本对象的引用
*/
this.userObject = null;
/**
* 单击节点事件的处理方法,其定义可能是:function(node)
* 事件处理器将把当前被单击的节点作为第一个参数传入这个方法
* 如果这个方法返回false,事件将被取消
*/
this.onclick = null;
/**
* 鼠标右击节点事件的处理方法,其定义可能是:function(node)
* 事件处理器将把当前被右击的节点作为第一个参数传入这个方法
* 如果这个方法返回false,事件将被取消
*/
this.oncontextmenu = null;
/**
* 展开节点事件的处理方法,其定义可能是:function(node)
* 事件处理器将把发生事件的节点作为第一个参数传入这个方法
* 如果这个方法返回false,事件将被取消
*/
this.onexpand = null;
/**
* 收缩节点事件的处理方法,其定义可能是:function(node)
* 事件处理器将把发生事件的节点作为第一个参数传入这个方法
* 如果这个方法返回false,事件将被取消
*/
this.oncollapse = null;
/**
* 节点复选框单击事件的处理方法,其定义可能是:function(node, checked)
* 事件处理器将把发生事件的节点作为第一个参数,
* 复选框被单击前的选中状态作为第二个参数传入这个方法
* 如果这个方法返回false,事件将被取消
*/
this.oncheck = null;
}
/**
* 节点所在树
*/
TreeNode.prototype.getTree = function()
{
return this.tree;
}
/**
* 节点的父节点
*/
TreeNode.prototype.setParentNode = function(node)
{
this.parentNode = node;
}
TreeNode.prototype.getParentNode = function()
{
return this.parentNode;
}
/**
* 节点是否是根节点
*/
TreeNode.prototype.isRoot = function()
{
return this.parentNode == this.tree;
}
/**
* 节点的复选框被单击
*/
function checkboxClick()
{
//节点的表格对象
var table = this.parentNode.parentNode.parentNode.parentNode;
//节点对象
var node = table.node;
//处理树对象申明的节点被选取事件的处理方法
if(!(node.tree.oncheck == null))
{
var result = node.tree.oncheck.call(node.tree.oncheck,
node.tree, node, node.checkbox.checked);
if(result == false)
{
return;
}
}
//处理节点申明的节点被选取事件的处理方法
if(!(node.oncheck == null))
{
var result = node.oncheck.call(node.oncheck,
node, node.checkbox.checked);
if(result == false)
{
return;
}
}
node.setChecked(!this.checked);
}
/**
* 设置节点的文本值
*/
TreeNode.prototype.setNodeValue = function(text)
{
if(this.tbody != null)
{
this.text.nodeValue = text;
}
else
{
this.text = text;
}
}
/**
* 获取节点的文本值
*/
TreeNode.prototype.getNodeValue = function()
{
if(this.tbody != null)
{
return this.text.nodeValue;
}
return this.text;
}
/**
* 将构节点的视图对象,用TreeNode对象封装起来,
* 并返回这个视图对象
*/
TreeNode.prototype.wrapNode = function()
{
if(this.tbody != null)
{
return this.tbody.parentNode;
}
//构造文档对象
var node = this.tree.newTreeNode();
//节点的DOM对象
this.tbody = node.firstChild;
//this.table.id = id;
if(this.id != null)
{
node.id = this.id;
this.id = null;
}
node.node = this;
//树枝
this.branch = node.firstChild.firstChild.firstChild.firstChild;
//this.branch.node = this;
this.branch.onclick = branchClick;
//节点单元格
var td = node.firstChild.firstChild.childNodes[1];
td.ondragstart = nodeDragStart;
td.ondrop = nodeDrop;
td.ondragend = nodeDragEnd;
td.ondragover = nodeDragOver;
td.ondragleave = nodeDragLeave;
//节点图标
var fc = td.firstChild;
var span = null;
if(fc.checked != null)
{
//有复选框
this.checkbox = fc;
this.checkbox.checked = this.checked;
this.checkbox.onclick = checkboxClick;
this.image = td.childNodes[1];
span = td.childNodes[2];
}
else
{
this.image = fc;
span = td.childNodes[1];
}
span.firstChild.href = this.link;
if(this.link == null)
{
span.firstChild.disabled = true;
}
this.link = span.firstChild;
if(this.target != null)
{
this.link.target = this.target;
}
this.link.onclick = linkClick;
this.link.firstChild.nodeValue = this.text;
this.text = this.link.firstChild;
//this.image.node = this;
if(this.getDynamicChildFlagNode())
{
this.image.style.display = "none";
this.link.disabled = true;
}
else
{
this.image.onclick = imageClick;
this.setBranch();
}
return node;
}
/**
* 设置树树图标的索引
*/
TreeNode.prototype.setBranchIndex = function(index, flush)
{
this.branch.index = index;
if(flush == true)
{
this.changeBranch();
}
}
/**
* 设置树枝图标
* boolean hasChild 节点是否有子节点
* boolean isLastChild 当前节点是否是其父节点的最后一个子节点
*/
TreeNode.prototype.setBranch = function(hasChild, isLastChild, flush)
{
if(this.tbody == null)
{
return;
}
if(hasChild == null)
{
hasChild = this.hasChild();
}
if(isLastChild == null)
{
isLastChild = this.getNextSibling() == null;
}
if(isLastChild)
{
this.branch.index
= this.isRoot() ?
(hasChild ? this.tree.images.LINE_PLUS_ROOT
: this.tree.images.LINE)
: (hasChild ? this.tree.images.LINE_PLUS_L
: this.tree.images.LINE_L);
}
else
{
this.branch.index
= hasChild ? this.tree.images.LINE_PLUS_T
: this.tree.images.LINE_T;
}
if(flush == true)
{
this.changeBranch();
}
}
/**
* 改变连接节点的枝图标
* 当节点在收缩和展开时,改变它的索引
*/
TreeNode.prototype.changeBranch = function(model)
{
if(model == null)
{
model = this.model;
}
if(model)
{
this.branch.src = this.tree.images.getImage(this.branch.index);
}
else
{
this.branch.src = this.tree.images.getImage(this.branch.index + 1);
}
}
/**
* 隐藏枝图标
*/
TreeNode.prototype.hideBranch = function()
{
if(this.tbody == null)
{
alert("节点的父节点尚未展开,节点未载入文档对象,非法的操作!");
throw new Error("节点的父节点尚未展开,节点未载入文档对象,非法的操作!");
}
if(this.branch.parentNode != null)
{
this.branch.parentNode.width = "1";
}
this.branch.style.display = "none";
}
/**
* 显示枝图标
*/
TreeNode.prototype.showBranch = function()
{
if(this.tbody == null)
{
alert("节点的父节点尚未展开,节点未载入文档对象,非法的操作!");
throw new Error("节点的父节点尚未展开,节点未载入文档对象,非法的操作!");
}
if(this.branch.parentNode != null)
{
this.branch.parentNode.width = "19";
}
this.branch.style.display = "block";
}
/**
* 设置当前节点图标模式
* boolean model 值true代表节点收缩,false代表展开
*/
TreeNode.prototype.setImageModel = function(model)
{
if(model == null)
{
model = this.model;
}
this.image.src
= model ? this.tree.images.getImage(this.image.index)
: this.tree.images.getImage(this.image.index + 1);
}
/**
* 节点收缩时的图标索引
* boolean hasChild 节点是否有子节点
* boolean refresh 图标是否更新
*/
TreeNode.prototype.setImage = function(hasChild, refresh)
{
if(hasChild == null)
{
hasChild = false;
}
//节点收缩时的图标在资源中的索引,展开时的索引比收缩时的索引大1
this.image.index
= this.isRoot() ? this.tree.images.ROOT_COLLAPSED_IMAGE
: hasChild ? this.tree.images.NODE_COLLAPSED_IMAGE
: this.tree.images.LEAF_IMAGE;
if(refresh)
{
this.image.src = this.tree.images.getImage(this.image.index);
}
}
/**
* 节点id
*/
TreeNode.prototype.setID = function(id)
{
if(this.tbody == null)
{
this.id = id;
}
else
{
this.tbody.parentNode.id = id;
}
}
TreeNode.prototype.getID = function()
{
if(this.tbody == null)
{
return this.id;
}
else
{
return this.tbody.parentNode.id;
}
}
/**
* 节点链接
*/
TreeNode.prototype.setLink = function(link)
{
if(this.tbody != null)
{
this.link.href = link;
this.link.disabled = link == null;
}
else
{
this.link = link;
}
}
TreeNode.prototype.getLink = function()
{
if(this.tbody != null)
{
return this.link.href;
}
else
{
return this.link;
}
}
/**
* model为true时,节点收缩,为false时,节点展开
*/
TreeNode.prototype.getModel = function()
{
return this.model;
}
/**
* 节点是否被选中
*/
TreeNode.prototype.setSelected = function(selected)
{
this.selected = selected;
}
TreeNode.prototype.getSelected = function()
{
return this.selected;
}
/**
* 节点的复选框是否被选中状态。
* 如果树设置显示复选框属性,则显示节点的复选框
*/
TreeNode.prototype.setChecked = function(checked)
{
this.checked = checked;
//节点间的影响
var force = this.tree.getNodeCheckForce();
if(force > 0)
{
this.tree.setNodeCheckForce(0);
var temp = checked ? force : force >>> 8;
//影响父节点
if((temp & 0x08) == 0x08)
{
var parentNode = this.parentNode;
while(parentNode != null && parentNode == "[object TreeNode]")
{
parentNode.setChecked(checked);
parentNode = parentNode.parentNode;
}
}
else
{
if((temp & 0x04) == 0x04)
{
if(this.parentNode != null && this.parentNode == "[object TreeNode]")
{
this.parentNode.setChecked(checked);
}
}
}
if(this.hasChild())
{
//影响子节点
if((temp & 0x02) == 0x02)
{
if(checked)
{
this.tree.setNodeCheckForce(FlyBean.DEEP_AFFECTED_ON_CHECK);
}
else
{
this.tree.setNodeCheckForce(FlyBean.DEEP_AFFECTED_ON_CANCEL);
}
var nodes = this.getChildNodes();
for(var i = 0; i < nodes.length; i++)
{
nodes[i].setChecked(checked);
}
}
else
{
if((temp & 0x01) == 0x01)
{
var nodes = this.getChildNodes();
for(var i = 0; i < nodes.length; i++)
{
nodes[i].setChecked(checked);
}
}
}
}
//还原节点选取状态
this.tree.setNodeCheckForce(force);
}
if(this.checkbox != null)
{
this.checkbox.checked = checked;
if(checked)
{
this.checkbox.src
= this.tree.images.getImage(this.tree.images.NODE_CHECKED);
}
else
{
this.checkbox.src
= this.tree.images.getImage(this.tree.images.NODE_UNCHECKED);
}
}
}
/**
* 获取当前节点的选取状态或者获取节点及其子节点中选中的节点,
* 返回值取决于参数
* Array arr 结果集数组,如果这个参数不为空,
* 则将节点及其子节点中选中的节点作为元素放入这个数组中,
* 如果这个参数为空,则用boolean值返回当前节点的选取状态
*/
TreeNode.prototype.getChecked = function(arr)
{
var checked = false;
if(this.checkbox == null)
{
checked = this.checked;
}
else
{
checked = this.checkbox.checked;
}
if(arr == null)
{
return checked;
}
else
{
if(checked)
{
arr[arr.length] = this;
}
if(this.hasChild())
{
var nodes = this.getChildNodes();
for(var i = 0; i < nodes.length; i++)
{
nodes[i].getChecked(arr);
}
}
}
}
节点间关系//
/**
* 设置节点连接弟节点的树枝
* boolean hasNextSibling 是否有弟节点
*/
TreeNode.prototype.setBranchToNext = function(hasNextSibling)
{
if(this.childNodes.td == null)
{
return;
}
if(hasNextSibling == null)
{
hasNextSibling = !(this.nextSibling == null);
}
var td = this.tbody.childNodes[1].firstChild;
//设置兄弟间树枝
if(hasNextSibling == true)
{
td.background
= this.tree.images.getImage(this.tree.images.LINE_I);
}
else
{
td.background = null;
}
}
/**
* 节点的兄节点
*/
TreeNode.prototype.getPreviousSibling = function()
{
return this.previousSibling;
}
/**
* 节点的弟节点
*/
TreeNode.prototype.getNextSibling = function()
{
return this.nextSibling;
}
/**
* 节点是否有子节点
*/
TreeNode.prototype.hasChild = function()
{
return this.firstChild != null;
}
/**
* 节点是否有动态的子节点
*/
TreeNode.prototype.hasDynamicChild = function()
{
if(this.hasChild())
{
if(this.getFirstChild().getDynamicChildFlagNode())
{
return true;
}
}
return false;
}
/**
* 子节点个数
*/
TreeNode.prototype.getChildCount = function()
{
return this.childNodes.length;
}
/**
* 第一个子节点
*/
TreeNode.prototype.getFirstChild = function()
{
return this.firstChild;
}
/**
* 最后一个子节点
*/
TreeNode.prototype.getLastChild = function()
{
return this.lastChild;
}
/**
* 返回所有子节点对象
*/
TreeNode.prototype.getChildNodes = function()
{
return this.childNodes;
}
/**
* 返回节点的DOM对象
*/
TreeNode.prototype.getTable = function()
{
if(this.tbody == null)
{
alert("节点的父节点尚未展开,节点未载入文档对象!");
throw new Error("节点的父节点尚未展开,节点未载入文档对象!");
}
return this.tbody == null ? null : this.tbody.parentNode;
}
/**
* 添加一个子节点到当前节点
* Object obj 如果这个参数是字符串,则视为节点的文本,它和其他参数一起作为
* 树节点的参数。如果参数是Node或TreeNode对象,则将其添加到当前
* 树节点,且忽略其他参数。
* String link 子节点的链接
* String id 子节点的id
* String target 子节点的链接的目标框架
*
* return 返回加入的子节点
*
* 注意:如果当前节点准备动态载入子节点,则该操作将使当前节点不再动态载入子
* 节点
*/
TreeNode.prototype.appendChild = function(obj, link, id, target, checked)
{
if(obj == null)
{
return null;
}
var node = null;
//添加已有的节点对象
if(obj instanceof TreeNode)
{
if(obj.getTree() != this.getTree())
{
var message = "节点与其准父节点不属于同一个树对象";
alert(message);
throw new Error(message);
}
if(obj.getParentNode() != null)
{
var message = "当前节点已有父节点不能添加到其他节点下";
alert(message);
throw new Error(message);
}
node = obj;
}
else
{
text = obj;
//缺省的目标框架
if(target == null)
{
target = this.target;
}
}
if(this.childNodes.length == 0)
{
if(this.tbody != null)
{
if(this.isRoot())
{
//设置根节点树枝
this.setBranchIndex(this.tree.images.LINE_PLUS_ROOT, true);
//根节点有子节点,显示树枝
this.showBranch();
}
else
{
//设置节点树枝
this.setBranch(true, null, true);
}
//更新图标
this.setImage(true, true);
}
}
if(node == null)
{
//节点不存在,创建之
node = new TreeNode(this.tree, text, link, id, target, checked);
}
else
{
if(node.tbody != null)
{
//设置树枝
node.setBranch(null, true, true);
}
}
if(this.childNodes.td != null)
{
//当前节点已经展开,载入节点的视图
var dom = node.wrapNode();
this.childNodes.td.appendChild(dom);
node.loadImage();
}
if(node.getID() != null)
{
this.tree.addNode(node.getID(), node);
}
//当前节点的最后一个子节点
var lastChild = this.lastChild;
if(lastChild != null)
{
if(lastChild.getDynamicChildFlagNode())
{
//最后一个子节点是动态子节点提示符,删之
if(this.childNodes.td != null)
{
this.childNodes.td.removeChild(lastChild.getTable());
}
var index = this.childNodes.length - 1;
this.childNodes.splice(index, 1);
this.firstChild = null;
}
else
{
//设置节点的兄节点
node.previousSibling = lastChild;
//最后一个节点的弟节点
lastChild.nextSibling = node;
if(lastChild.tbody != null)
{
//设置最后一个节点的树枝
lastChild.setBranch(null, false, true);
if(lastChild.hasChild() && lastChild.childNodes.td != null)
{
//设置兄弟间树枝
lastChild.setBranchToNext(true);
}
}
}
}
this.childNodes[this.childNodes.length] = node;
node.parentNode = this;
//第一个子节点
if(this.firstChild == null)
{
this.firstChild = node;
}
//最后一个子节点
this.lastChild = node;
return node;
}
TreeNode.prototype.setDynamicChildFlagNode = function(flag)
{
this.dynamicChildFlagNode
= flag == null ? false : flag == true;
if(this.dynamicChildFlagNode == true)
{
if(!(this.checkbox == null))
{
this.checkbox.parentNode.removeChild(this.checkbox);
}
}
}
TreeNode.prototype.getDynamicChildFlagNode = function()
{
return this.dynamicChildFlagNode;
}
/**
* 为当前节点添加动态子节点
* String link 动态子节点资源的URL
*/
TreeNode.prototype.appendDynamicChild = function(link, text)
{
if(text == null)
{
text = "正在载入资源...";
}
var node = this.appendChild(text, link);
node.setDynamicChildFlagNode(true);
return node;
}
/**
* 创建子节点容器
*/
TreeNode.prototype.createChildrenTD = function()
{
var tr = this.tree.doc.createElement("tr");
//隐藏所有子节点
tr.style.display = "none";
this.tbody.appendChild(tr);
//节点连接其弟节点的树枝
var td = this.tree.doc.createElement("td");
tr.appendChild(td);
if(!this.isRoot()
&& this.parentNode != null
&& !(this.nextSibling == null))
{
//当前节点并不是其父节点的最后一个子节点
//设置兄弟间树枝
this.setBranchToNext(true);
}
//子节点的容器
this.childNodes.td = this.tree.doc.createElement("td");
tr.appendChild(this.childNodes.td);
}
/**
* 查找子节点的索引
*/
TreeNode.prototype.indexOf = function(node, fromIndex)
{
if(node == null)
{
return -1;
}
if(node.parentNode != this)
{
//不是当前节点的子节点
return -1;
}
if(fromIndex == null || isNaN(fromIndex))
{
fromIndex = 0;
}
var index = fromIndex;
for(; index < this.childNodes.length; index++)
{
if(this.childNodes[index] == node)
{
return index;
}
}
return -1;
}
/****************************操作节点**************************************/
/**
* 展开节点
* boolean deep 是否展开子节点
*/
TreeNode.prototype.expand = function(deep)
{
if(this.tbody == null || (deep != true && this.expand.caller != this.branch.onclick
&& this.expand.caller != this.link.onclick && !this.isRoot()))
{
//用户直接调用方法展开节点,先展开子节点
this.getParentNode().expand();
}
if(this.onexpand != null)
{
//用当前节点作参数,回调指定的方法
var result = this.onexpand.call(this.onexpand, this);
if(result == false)
{
//事件被取消
return false;
}
}
if(this.hasChild())
{
if(this.model)
{
//当前节点收缩,展开所有子节点
if(this.childNodes.td == null)
{
this.createChildrenTD();
for(var i = 0; i < this.childNodes.length; i++)
{
var node = this.childNodes[i];
if(node.tbody != null)
{
//已初始化的节点
node = node.tbody.parentNode;
}
else
{
node = node.wrapNode();
}
this.childNodes.td.appendChild(node);
this.childNodes[i].loadImage();
}
var isLastChild = this.getNextSibling() == null;
if(!isLastChild)
{
this.setBranchToNext(true);
}
}
//更新节点树枝
this.changeBranch(false);
//节点图标
this.setImageModel(false);
//显示所有子节点
this.childNodes.td.parentNode.style.display = "block";
this.model = false;
if(this.getLastChild().getDynamicChildFlagNode())
{
this.tree.loadDynamicNodes(this, deep);
}
}
if(deep)
{
if(this.tree.hasDynamicNode)
{
//有动态子节点,不可深度展开
return;
}
for(var i = 0; i < this.childNodes.length; i++)
{
this.childNodes[i].expand(true);
}
}
}
}
/**
* 收缩节点
*/
TreeNode.prototype.collapse = function()
{
if(this.oncollapse != null)
{
//用当前节点作参数,回调指定的方法
var result = this.oncollapse.call(this.oncollapse, this);
if(result == false)
{
//事件被取消
return false;
}
}
if(this.tbody != null && this.hasChild())
{
if(!this.model)
{
//当前节点展开,收缩所有子节点
//更新节点树枝
this.changeBranch(true);
//节点图标
this.setImageModel(true);
//显示所有子节点
this.tbody.childNodes[1].style.display = "none";
this.model = true;
}
}
}
/**
* 选中节点
*/
TreeNode.prototype.select = function select()
{
if(this.tbody == null)
{
alert("节点的父节点尚未展开,不可选中节点!");
throw new Error("节点的父节点尚未展开,不可选中节点!");
}
this.link.click();
}
/**
* 设置或访问用户绑定的数据
* 不应该将树对象所在的Document中的HTML对象绑定到树节点,
* 因为这可能造成资源的泄漏
*/
TreeNode.prototype.setUserObject = function setUserObject(obj)
{
this.userObject = obj;
}
TreeNode.prototype.getUserObject = function getUserObject()
{
return this.userObject;
}
/**
* 对象信息
*/
TreeNode.prototype.toString = function()
{
return "[object TreeNode]";
}
TreeNode.prototype.valueOf = function()
{
return "[object TreeNode]";
}
/**
* 模仿节点上的用户鼠标单击操作,如果调用这个方法,节点对象
* 将被模拟单击
*/
TreeNode.prototype.click = function()
{
if(this.tbody == null)
{
alert("节点的父节点尚未展开,不可单击节点!");
throw new Error("节点的父节点尚未展开,不可单击节点!");
}
this.link.click();
}
/**
* 删除节点的子节点
* TreeNode child 子节点
* return 返回删除的子节点
*/
TreeNode.prototype.removeChild = function(child)
{
if(child == null)
{
return null;
}
if(child.getParentNode() != this)
{
//要删除的节点并不是当前节点的子节点
return child;
}
var index = this.indexOf(child);
this.childNodes.splice(index, 1);
//child节点的table文档对象
var ct = child.tbody;
if(ct != null)
{
ct = ct.parentNode;
//从文档Document中删除child节点的文档对象
if(ct.parentNode != null)
{
ct.parentNode.removeChild(ct);
}
if(child.hasChild())
{
child.setBranchToNext(false);
}
}
//子节点的兄弟节点处理
var node = child.previousSibling;
if(node != null)
{
node.nextSibling = child.nextSibling;
if(node.tbody != null)
{
node.setBranch(null, null, true);
if(child.nextSibling == null)
{
//兄节点枝处理
if(node.hasChild())
{
node.setBranchToNext(false);
}
}
}
}
node = child.nextSibling;
if(node != null)
{
node.previousSibling = child.previousSibling;
}
//节点的子节点链处理
if(this.getFirstChild() == child)
{
this.firstChild = child.nextSibling;
}
if(this.getLastChild() == child)
{
this.lastChild = child.previousSibling;
}
if(this.childNodes.length == 0 && this.tbody != null)
{
//已经没有子节点
//节点当前收缩
this.model = true;
//节点图标
this.setImage(false, true);
//设置节点树枝
this.setBranch(false, null, true);
if(this.childNodes.td != null)
{
//显示所有子节点
this.tbody.childNodes[1].style.display = "none";
//删除节点连接其弟节点的延长枝
this.setBranchToNext(false);
}
}
//父节点设置为null
child.parentNode = null;
child.nextSibling = null;
child.previousSibling = null;
//删除节点在树中的引用,释放资源
child.release();
//当前选中的节点
if(this.tree.currentSelectedNode == child)
{
this.tree.currentSelectedNode = null;
if(child.tbody != null)
{
child.link.parentNode.className = "tree___node_text_td";
}
child.setSelected(false);
}
return child;
}
/**
* 删除节点在树中的引用,释放资源
*/
TreeNode.prototype.release = function()
{
var nodes = this.getChildNodes();
for(var i = 0; i < nodes.length; i++)
{
nodes[i].release();
}
if(this.getID() != null)
{
this.getTree().nodes[this.getID()] = null;
}
}
/**
* 克隆节点,并返回新结点
* boolean deep 是否克隆其子节点
* return 返回新节点
*/
TreeNode.prototype.cloneNode = function(deep)
{
//难度较大,且暂无需求,不支持
return null;
// if(deep == null)
// {
// deep = false;
// }
// var text = this.getNodeValue();
// var link = this.getLink();
// var id = this.getID();
// var target = this.getTarget();
// var checked = this.getChecked();
//
// var newNode = new TreeNode(this.tree, text, link, id, target, checked);
//
// if(this.userObject != null)
// {
// if(this.userObject.clone != null)
// {
// newNode.userObject
// = this.userObject.clone.call(this.userObject);
// }
// else
// {
// newNode.userObject = this.userObject
// }
// }
//
// if(this.dynamicChildFlagNode == true)
// {
// newNode.dynamicChildFlagNode = true;
// }
// else
// {
// if(deep == true)
// {
// if(this.hasChild())
// {
// var nodes = this.getChildNodes();
// for(var i = 0; i < nodes.length; i++)
// {
// var newChildNode = nodes[i].cloneNode(true);
// newNode.appendChild(newChildNode);
// }
// if(this.model == false)
// {
// newNode.expand();
// }
// }
// }
// }
// newNode.onclick = this.onclick;
// newNode.oncontextmenu = this.oncontextmenu;
// newNode.onexpand = this.onexpand;
// newNode.oncollapse = this.oncollapse;
// newNode.oncheck = this.oncheck;
//
// return newNode;
}
/**
* 插入子节点
* TreeNode newChild 要插入的子节点
* TreeNode refChild 要插入的子节点就是插入到这个节点之前,
* 如果其为null,则要插入的子节点添加到当
* 前节点的末尾
* return 返回插入的新节点
*/
TreeNode.prototype.insertBefore = function(newChild, refChild)
{
if(newChild == null)
{
return null;
}
if(refChild == null)
{
this.appendChild(newChild);
}
if(newChild.getTree() != this.getTree())
{
var message = "节点与其准父节点不属于同一个树对象";
alert(message);
throw new Error(message);
}
if(newChild.getParentNode() != null)
{
var message = "节点已有父节点不能添加到其他节点下";
alert(message);
throw new Error(message);
}
if(refChild.getParentNode() != this)
{
var message = "相对节点不是当前节点的子节点";
alert(message);
throw new Error(message);
}
if(newChild.tbody != null)
{
if(newChild.hasChild())
{
//设置兄弟间树枝
newChild.setBranchToNext(true);
}
newChild.setBranch(null, false, true);
}
if(refChild.previousSibling == null)
{
this.firstChild = newChild;
}
else
{
refChild.previousSibling.nextSibling = newChild;
}
newChild.previousSibling = refChild.previousSibling;
refChild.previousSibling = newChild;
newChild.nextSibling = refChild;
newChild.parentNode = this;
if(newChild.getID() != null)
{
newChild.tree.addNode(newChild.getID(), newChild);
}
//相对节点在父节点中的索引
var index = this.indexOf(refChild);
if(index == 0)
{
//加在最前面
this.childNodes.unshift(newChild);
}
else
{
//在数组中插入
this.childNodes.splice(index, 0, newChild);
}
if(this.childNodes.td != null)
{
//树节点的文档对象插入
var pn = refChild.getTable().parentNode;
var tb = newChild.wrapNode();
pn.insertBefore(tb, refChild.getTable());
newChild.loadImage();
}
return newChild;
}
/**
* 定位到节点
*/
TreeNode.prototype.locate = function()
{
var child = this;
if(!this.isRoot())
{
//先展开子节点
this.getParentNode().expand();
}
this.select();
}
/**
* 替换子节点
* TreeNode newChild 新的子节点
* TreeNode oldChild 将被替换的子节点
*
* return 返回被替换的子节点
*/
TreeNode.prototype.replaceChild = function(newChild, oldChild)
{
if(newChild == null)
{
return null;
}
if(oldChild == null)
{
return null;
}
if(newChild.getTree() != this.getTree())
{
var message = "节点与其准父节点不属于同一个树对象";
alert(message);
throw new Error(message);
}
if(newChild.getParentNode() != null)
{
var message = "节点已有父节点不能再作为其他节点的子节点";
alert(message);
throw new Error(message);
}
if(oldChild.getParentNode() != this)
{
var message = "要替换的节点不是当前节点的子节点";
alert(message);
throw new Error(message);
}
//在子节点集合中替换
var index = this.indexOf(oldChild);
this.childNodes[index] = newChild;
//父节点设置
oldChild.parentNode = null;
newChild.parentNode = this;
if(newChild.getID() != null)
{
newChild.tree.addNode(newChild.getID(), newChild);
}
if(this.childNodes.td != null)
{
//HTML文档对象替换
var ot = oldChild.tbody.parentNode;
var nt = newChild.wrapNode();
ot.parentNode.replaceChild(nt, ot);
newChild.loadImage();
//被替换的节点处理
if(oldChild.hasChild())
{
oldChild.setBranchToNext(false);
}
}
//子节点的兄弟节点处理
newChild.previousSibling = oldChild.previousSibling;
if(newChild.previousSibling != null)
{
newChild.previousSibling.nextSibling = newChild;
}
else
{
this.firstChild = newChild;
}
newChild.nextSibling = oldChild.nextSibling;
newChild.setBranch(null, null, true);
if(newChild.nextSibling != null)
{
//兄节点枝处理
if(newChild.hasChild())
{
newChild.setBranchToNext(true);
}
newChild.nextSibling.previousSibling = newChild;
}
else
{
this.lastChild = newChild;
}
oldChild.nextSibling = null;
oldChild.previousSibling = null;
//删除节点在树中的引用,释放资源
oldChild.release();
return oldChild;
}
/**
* 载入节点的图片
*/
TreeNode.prototype.loadImage = function()
{
//连接节点的树枝
this.branch.src = this.tree.images.getImage(this.branch.index);
//载入节点图标
this.setImage(this.hasChild(), true);
if(this.checkbox != null)
{
if(this.checked == true)
{
this.checkbox.src
= this.tree.images.getImage(this.tree.images.NODE_CHECKED);
}
else
{
this.checkbox.src
= this.tree.images.getImage(this.tree.images.NODE_UNCHECKED);
}
}
if(this.getDynamicChildFlagNode() == true)
{
this.image.style.display = "none";
this.link.disabled = true;
}
this.loadImage = emptyFunction;
}
/**
* 构造树对象,并载入CSS文件和树的图标资源
* String context 应用程序名称,树的缺省时图片资源在
* 应用程序的根目录下的images/tree,访问时以
* /context/images/tree/*.gif来访问,
* 如果它是null,则默认为"."
* String parentNodeID 树的父对象的ID,所谓的父对象,
* 其实是树所依赖的HTML对象的父节点,树将
* 显示在其中的对象,这个值是必须的
* Document doc,树对象的文档对象
* String id 树在文档对象中的id
* String target 链接的目标框架
* int width 树的宽
* int height 树的高
* boolean showCheckbox 节点是否带复选框
*
* 注意:产生树及其节点的代码中,没有用到诸如document.write
* 之类的方法,故可以在script标记中指定defer关键字,
* 以提高HTML的解析速度
*/
function FlyBean(context, parentNodeID, doc, id, target, width, height, showCheckbox)
{
if(context == null)
{
context = ".";
}
/**
* 树所在的文档对象
*/
this.doc = doc == null ? window.document : doc;
this.getDocument = function()
{
return this.doc;
}
//树的父节点处理
if(parentNodeID == null)
{
var message = "未知树对象的容器,请创建树时指明parentNodeID参数的值!";
alert(message);
throw new Error(message);
}
//父节点
var parentNode = this.doc.getElementById(parentNodeID);
if(parentNode == null
|| parentNode.nodeType == null
|| parentNode.nodeType != 1)//nodeType.Element = 1;
{
var message
= "不能从文档对象中查找出id为"
+ parentNodeID + "的元素!";
alert(message);
throw new Error(message);
}
/**
* 树的图标资源
*/
this.images = new ImageList(context);
/**
* 树对象的样式表
*/
this.styleSheet = new TreeStyleSheet(this.doc);
/**
* 树的节点的容器
*/
this.bole = null;
/**
* 节点母体
*/
this.treeNodeMother = null;
/**
* 树对象的id值,可以通过它从文档对象中找出树的table文档对象
*/
this.id = id;
/**
* 初始化树,这包括为树创建一个节点的容器,
* 和节点的母体,树中所有节点都是这个节点拷贝而来
*/
this.initTree = function(width, height, parentNode)
{
/**
* 树所在的table对象
*/
var table = this.doc.createElement("table");
table.border = "0";
table.width = width == null ? 1 : width;
table.height = height == null ? 1 : height;
table.cellSpacing = 0;
table.cellPadding = 4;
table.tree = this;
if(this.id != null)
{
table.id = this.id;
}
table.onclick = treeTableClick;
table.oncontextmenu = treeTableRClick;
var tbody = this.doc.createElement("tbody");
var tr = this.doc.createElement("tr");
this.bole = this.doc.createElement("td");
this.bole.vAlign = "top";
tr.appendChild(this.bole);
tbody.appendChild(tr);
table.appendChild(tbody);
parentNode.appendChild(table);
/**
* 树的节点的母体
*/
this.treeNodeMother = this.doc.createElement("table");
this.treeNodeMother.border = "0";
this.treeNodeMother.cellSpacing = "0";
this.treeNodeMother.cellPadding = "0";
tbody = this.doc.createElement("tbody");
tr = this.doc.createElement("tr");
//树枝单元格
var td = this.doc.createElement("td");
td.width = "19";
td.height = "20";
//树枝
var img = this.doc.createElement("img");
img.height = "20";
img.width = "19";
img.index = this.images.LINE_L;
//img.src = "images/tree/line_plus_root.gif";
td.appendChild(img);
tr.appendChild(td);
//节点单元格
td = this.doc.createElement("td");
td.name = "_TREE_NODE_BODY";
td.noWrap = true;
//td.style.paddingTop = "2px";
//td.valign="top";
//节点图标
img = this.doc.createElement("img");
img.index = this.images.LEAF_IMAGE;
//img.src = "images/tree/img_leaf.gif";
img.style.cursor = "hand";
img.align = "absbottom";
//img.style.marginTop = "2px";
img.style.marginRight = "2px";
td.appendChild(img);
var span = this.doc.createElement("span");
span.className = "tree___node_text_td";
//链接
var a = this.doc.createElement("a");
a.className = "tree___";
a.href = null;
//a.style.marginBottom = "0px";
//文本
var text = this.doc.createTextNode("node");
a.appendChild(text);
span.appendChild(a);
td.appendChild(span);
tr.appendChild(td);
tbody.appendChild(tr);
this.treeNodeMother.appendChild(tbody);
}
//初始化树的文档对象
this.initTree(width, height, parentNode);
this.initTree = null;
/**
* 树中节点的链接的缺省目标框架
*/
this.target = target;
/**
* 树中节点显示复选框
*/
this.showCheckbox
= showCheckbox == null ? false : showCheckbox == true;
/**
* 树中节点复选框状态改变时,其影响子节点的程度,
* 默认为没有影响
*/
this.nodeCheckForce = 0;
//树中的节点对象
this.nodes = new Array();
/**
* 根节点对象
*/
this.root = null;
/**
* 当前选中节点
*/
this.currentSelectedNode = null;
/**
* 树中节点是否可拖动,缺省是不可拖动
*/
this.nodeDragable = false;
/**
* 当前拖动的节点
*/
this.currentDragedNode = null;
/**
* 被拖动的节点
*/
this.dragedNode = null;
/**
* 拖动时的目标节点
*/
this.targetNode = null;
/**
* 用于动态载入资源的ifram对象
*/
this.dynamicWindow = null;
/**
* 如果单击树中节点的事件上溯,则回调这个方法,
* 其定义可能是:function(tree, node)
* 事件处理器将把树对象和当前被单击的节点作为参数传入这个方法,
* 如果单击事件不是在一个节点上发生,第二个参数将是null,
* 如果这个方法返回false,事件将不再上溯
*/
this.onclick = null;
/**
* 如果用鼠标右击树中节点的事件上溯,则回调这个方法,
* 其定义可能是:function(tree, node)
* 事件处理器将把树对象和当前被鼠标右击的节点作为参数传入这个方法,
* 如果右击事件不是在一个节点上发生,第二个参数将是null,
* 如果这个方法返回false,事件将不再上溯
*/
this.oncontextmenu = null;
/**
* 树中节点复选框单击事件的处理方法,
* 其定义可能是:function(tree, node, checked)
* 事件处理器将把发生事件的节点所在的树作为第一个参数,
* 节点作为第二个参数,
* 复选框被单击前的选中状态作为第三个参数传入这个方法
* 如果这个方法返回false,事件将被取消
*/
this.oncheck = null;
/**
* 如果树中节点允许被拖动(参见方法:getNodeDragable和
* setNodeDragable),当用户开始拖动树中节点时,回调这个方法,
* 其定义可能是:function(tree, node)
* 事件处理器将把树对象和当前将要被拖动的节点作为参数传入这个方法,
* 如果这个方法返回false,拖动被取消
*/
this.ondragstart = null;
this.ondragend = null;
/**
* 如果树中节点允许被拖动(参见方法:getNodeDragable和
* setNodeDragable),当用户拖动树中节点时,连续回调这个方法,
* 其定义可能是:function(tree, node)
* 事件处理器将把树对象和当前被拖动的节点作为参数传入这个方法,
* 如果这个方法返回false,拖动被取消
*/
this.ondrop = null;
this.ondragenter = null;
this.ondragleave = null;
}
/**
* 将树中节点加入到节点集合中,这方便通过节点
* id来查找节点
*/
FlyBean.prototype.addNode = function(id, node)
{
if(id == null)
{
return;
}
var temp = this.nodes[id];
if(temp == null)
{
this.nodes[id] = node;
}
else
{
if(temp == node)
{
return;
}
if(temp instanceof TreeNode)
{
var arr = new Array();
arr[0] = temp;
arr[1] = node;
this.nodes[id] = arr;
}
else
{
if(temp instanceof Array)
{
temp[temp.length] = node;
}
}
}
}
/**
* 添加根节点到树中,并返回它
*/
FlyBean.prototype.appendChild = function(text, link, id, target, checked)
{
return this.appendRootNode(text, link, id, target, checked);
}
/**
* 添加根节点到树中,并返回它
*/
FlyBean.prototype.appendRootNode = function(text, link, id, target, checked)
{
if(this.root != null)
{
//只能有一个根节点
alert("树中只能有一个根节点!");
throw new Error("树中只能有一个根节点!");
}
//假设添加一个已有的节点对象
var root = text;
//添加已有的节点对象
if(root instanceof TreeNode)
{
if(root.getTree() != this)
{
var message = "节点不是当前树的节点";
alert(message);
throw new Error(message);
}
if(root.getParentNode() != null)
{
var message = "当前节点已有父节点不能添加到树下";
alert(message);
throw new Error(message);
}
}
else
{
target = target == null ? this.target : target;
root = new TreeNode(this, text, link, id, target, checked);
}
root.parentNode = this;
var nodeDom = root.wrapNode();
this.root = root;
if(id != null)
{
this.addNode(id, root);
}
this.bole.appendChild(nodeDom);
root.loadImage();
//根节点树枝隐藏
//root.hideBranch();
return root;
}
/**
* 返回根节点
*/
FlyBean.prototype.getRootNode = function()
{
return this.root;
}
/**
* 处理树被单击事件
*/
function treeTableClick()
{
//树对象
var tree = this.tree;
if(tree == null)
{
return;
}
var td = getTreeNodeBody();
if(td == null)
{
return;
}
if(tree.onclick != null)
{
//用树和节点作参数,回调指定的方法
return tree.onclick.call(tree.onclick, tree, getTreeNode());
}
}
/**
* 处理树被右击事件
*/
function treeTableRClick()
{
//树对象
var tree = this.tree;
if(tree == null)
{
return;
}
var td = getTreeNodeBody();
if(td == null)
{
return;
}
if(!(tree.oncontextmenu == null))
{
//用树和节点作参数,回调指定的方法
return tree.oncontextmenu.call(tree.oncontextmenu,
tree, getTreeNode());
}
}
/**
* 树样式
*/
FlyBean.prototype.setStyle = function(className)
{
this.bole.parentNode.parentNode.parentNode.className = className;
}
FlyBean.prototype.getStyle = function()
{
return this.bole.parentNode.parentNode.parentNode.className;
}
/**
* 树的图标资源
*/
FlyBean.prototype.getImages = function()
{
return this.images;
}
/**
* 树对象的样式表
*/
FlyBean.prototype.getTreeStyleSheet = function()
{
return this.styleSheet;
}
/**
* 树的table文档对象
*/
FlyBean.prototype.getTable = function()
{
return this.bole.parentNode.parentNode.parentNode;
}
/**
* 树对象的id值,可以通过它从文档对象中找出树的table文档对象
*/
FlyBean.prototype.getID = function()
{
return this.id;
}
FlyBean.prototype.setID = function(id)
{
this.id = id;
this.bole.parentNode.parentNode.parentNode.id = id;
}
/**
* 树中节点的链接的缺省目标框架,这个属性的更改,
* 只会对即将加入的树节点的链接的目标框架起作用
*/
FlyBean.prototype.getTarget = function getTarget()
{
return this.target;
}
FlyBean.prototype.setTarget = function setTarget(target)
{
this.target = target;
}
/**
* 树中节点是否可以拖动属性,缺省状态下,树中的节点均
* 不可拖动
*/
FlyBean.prototype.getNodeDragable = function()
{
return this.nodeDragable;
}
FlyBean.prototype.setNodeDragable = function(able)
{
this.nodeDragable = able;
}
/**
* 树中节点显示复选框
*/
FlyBean.prototype.setShowCheckbox = function(sc)
{
var oldSet = this.showCheckbox;
if(sc == null)
{
sc = false;
}
this.showCheckbox = sc == true;
if(oldSet == true && this.showCheckbox == false)
{
//以前有复选框,除去
var checkboxes = this.treeNodeMother.getElementsByTagName("treeNodeMother");
if(checkboxes != null && checkboxes.length > 0)
{
this.treeNodeMother.removeChild(checkboxes[0]);
}
}
if(oldSet == false && this.showCheckbox == true)
{
//以前没有复选框,加上
var td = this.treeNodeMother.firstChild.firstChild.lastChild;
var ref = td.firstChild;
var img = this.doc.createElement("img");
img.height = "11";
img.width = "11";
img.align = "absmiddle";
img.style.marginLeft = "1px";
img.style.marginTop = "1px";
img.style.marginRight = "2px";
img.checked = "false";
td.insertBefore(img, ref);
}
}
FlyBean.prototype.getShowCheckbox = function()
{
return this.showCheckbox == true;
}
/**
* 树中节点复选框状态改变时,其影响子节点的程度,
* 默认为没有影响
*/
FlyBean.prototype.getNodeCheckForce = function()
{
return this.nodeCheckForce;
}
FlyBean.prototype.setNodeCheckForce = function(ncf)
{
this.nodeCheckForce = ncf;
}
/**
* 根节点对象
*/
FlyBean.prototype.getRootNode = function getRootNode()
{
return this.root;
}
/**
* 从节点的母体克隆一个节点,并返回它,用户不应该调用这个方法
*/
FlyBean.prototype.newTreeNode = function()
{
return this.treeNodeMother.cloneNode(true);
}
/**
* 在树中创建一个新节点,但这个节点不属于任何一个节点的子节点
*/
FlyBean.prototype.createTreeNode = function(text, link, id, target, checked)
{
return new TreeNode(this, text, link, id, target, checked);
}
/**
* 当前选中节点
*/
FlyBean.prototype.getSelectedNode = function()
{
return this.currentSelectedNode;
}
/**
* 复选框选中的节点,这个方法返回的是一个节点数组,
* 但不能确定数组中的元素的顺序与节点在树中的顺序
* 之间的关系
*/
FlyBean.prototype.getCheckedNodes = function()
{
if(this.showCheckbox == false || this.root == null)
{
return null;
}
var cns = new Array();
this.root.getChecked(cns);
return cns;
}
/**
* 某节点资源载入完毕
*/
function listNotify()
{
var node = this.treeParentNode.getLastChild();
if(node != null && node.getDynamicChildFlagNode())
{
//没有载入子节点,删除动态载入
this.treeParentNode.removeChild(node);
}
//解锁
this.lock = false;
this.treeParentNode = null;
this.src = "about:blank";
if(this.list.length > 0)
{
this.load(this.list.shift());
}
}
/**
* 载入节点的资源
*/
function loadNode(node)
{
if(this.lock)
{
this.list.push(node);
}
else
{
this.lock = true;
this.src = node.lastChild.link.href;
//树中当前动态载入子节点的节点
this.treeParentNode = node;
}
}
/**
* 动态载入子节点
* TreeNode node 要动态载入子节点的节点
* String src 资源URL
*/
FlyBean.prototype.loadDynamicNodes = function(node)
{
if(this.dynamicWindow == null)
{
this.dynamicWindow = this.doc.createElement("iframe");
this.dynamicWindow.height = 0;
this.dynamicWindow.width = 0;
//等待载入子节点队列
this.dynamicWindow.list = new Array();
//有资源正在被载入
this.dynamicWindow.lock = false;
/**
* 某节点资源载入完毕
*/
this.dynamicWindow.notify = listNotify;
/**
* 载入节点的资源
*/
this.dynamicWindow.load = loadNode;
this.bole.parentNode.parentNode.parentNode.parentNode.appendChild(this.dynamicWindow);
}
this.dynamicWindow.load(node);
}
/**
* 展开树
*/
FlyBean.prototype.expand = function()
{
if(this.root != null)
{
this.root.expand(true);
}
}
/**
* 根据节点的id值检索节点对象,
* 如果有多个节点的id值等于传入的参数,则返回这些节点构成的
* 数组
*/
FlyBean.prototype.getNodeByID = function(id)
{
if(id == null)
{
return null;
}
return this.nodes[id];
}
/**
* 删除树的根节点
* TreeNode root 子节点
*/
FlyBean.prototype.removeChild = function(root)
{
if(root.getParentNode() != this)
{
//要删除的节点并不是当前树的根节点
return root;
}
//父节点设置为null
root.parentNode = null;
//root节点的table文档对象
var ct = root.tbody.parentNode;
//从文档Document中删除root节点的文档对象
ct.parentNode.removeChild(ct);
//删除节点在树中的引用,释放资源
root.release();
//树中无根节点也
this.root = null;
//当前选中的节点
if(this.currentSelectedNode == root)
{
this.currentSelectedNode = null;
root.link.parentNode.className = "tree___node_text_td";
root.setSelected(false);
}
return root;
}
/**
* 对象信息
*/
FlyBean.prototype.toString = function()
{
return "[object Tree]";
}
FlyBean.prototype.valueOf = function()
{
return "[object Tree]";
}
/*******************************************
* 下面的参数指明节点受其父节点复选框
* 选取状态的影响度,它们作为调用方法
* setNodeCheckForce的参数
******************************************/
//选中节点复选框时子节点不受其影响
FlyBean.UNAFFECTED_ON_CHECK = 0x00;
//选中节点复选框时直接子节点受其影响
FlyBean.AFFECTED_ON_CHECK = 0x01;
//选中节点复选框时所有子孙节点都受其影响
FlyBean.DEEP_AFFECTED_ON_CHECK = 0x02;
//选中节点复选框时其直接父节点受其影响
FlyBean.PARENT_AFFECTED_ON_CHECK = 0x04;
//选中节点复选框时其父节点及祖先节点都受其影响
FlyBean.ANCESTOR_AFFECTED_ON_CHECK = 0x08;
//取消节点复选框时子节点不受其影响
FlyBean.UNAFFECTED_ON_CANCEL = 0x000;
//取消节点复选框时直接子节点受其影响
FlyBean.AFFECTED_ON_CANCEL = 0x100;
//取消节点复选框时所有子孙节点都受其影响
FlyBean.DEEP_AFFECTED_ON_CANCEL = 0x200;
//取消节点复选框时其直接父节点受其影响
FlyBean.PARENT_AFFECTED_ON_CANCEL = 0x400;
//取消节点复选框时其父节点及祖先节点都受其影响
FlyBean.ANCESTOR_AFFECTED_ON_CANCEL = 0x800;
/*************************************************
* 例:
* //选中节点时,也选中其直接子节点
* tree.setNodeCheckForce(FlyBean.AFFECTED_ON_CHECK);
*
* //取消节点时,取消其所有子孙节点
* tree.setNodeCheckForce(FlyBean.DEEP_AFFECTED_ON_CANCEL);
*
* //选中节点时,选中其所有子孙节点
* //取消节点时,不影响其子节点
* tree.setNodeCheckForce(FlyBean.DEEP_AFFECTED_ON_CHECK
* |FlyBean.DEEP_AFFECTED_ON_CANCEL);
************************************************/