一棵JavaScript写的树- My FlyBean V1.00,支持动态的增加,删除,剪切,插入,克隆,复选框,回调等功能

<script language=javascript> /******************************************************************** * 程序: My FlyBean * 版本: 1.00 * 功能: web树视图 * 作者: 胡洲 huzhou-cq@163.com * * 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: 6px;" + "PADDING-LEFT: 6px;" + "PADDING-TOP: 1px;" + "HEIGHT: 19px"; 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 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 == "[object TreeNode]") { return node; } //没找到 return null; } /** * 树的图标资源 * 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; /******************************************** * 这段的源代码如下,因发表于Blog中而有所改动 * //图标资源的相对路径 * this.imageBase = "images/tree/"; * if(context != null) * { * if(context.charAt(context.length - 1) != "/") * { * this.imageBase = context + "/" + this.imageBase; * } * else * { * this.imageBase = context + this.imageBase; * } * } ************************************************/ this.imageBase = "/images/blog_csdn_net/whodsow/89278/o_"; //图标资源的URL this.images = new Array(19); 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"; /** * 添加图标资源到对象 * 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; } } /** * 构造树结点,这个函数应该由其父节点调。 * String text 节点文本 * String link 节点链接 * String id 节点id * Bean tree 树对象 * String target 节点链接的目标框架 */ function TreeNode(text, link, id, tree, target) { /** * 节点在树中的索引 通常情况下,这个值是-1是没有意义的。 * 但也许我们想通过一个简单的值来持有(与之发生关联)这 * 个节点对象,也就是说我们可以通过这个值从树中找到它关 * 联的这个节点对象,我们可通过一个节点在树中的索引来持 * 有这个对象。注意我们应该调这个方法,而不是直接访问这 * 个属性。 */ this.index = -1; this.getIndex = function() { if(this.index == -1) { this.index = this.tree.getNodeIndex(); this.tree.nodes[this.index] = this; } return this.index; } /****************************节点的家谱************************************/ /** * 节点所在树 */ this.tree = tree; this.getTree = function() { return this.tree; } /** * 节点的父节点 */ this.parentNode = null; this.setParentNode = function(node) { this.parentNode = node; } this.getParentNode = function() { return this.parentNode; } /** * 节点是否是根节点 */ this.isRoot = function() { return this.parentNode == this.tree; } /****************************连接树节点的枝********************************/ this.initBranch = function() { /** * 连接树节点的枝图标元素 */ this.branch = this.tree.doc.createElement("img"); /** * 连接树节点的枝图标在图标资源中的索引 */ this.branch.index = this.tree.images.LINE_L; this.branch.src = this.tree.images.getImage(this.branch.index); this.branch.width = 19; this.branch.height = 20; //枝连接的树节点对象 this.branch.node = this; /** * 单击枝图标事件,其结果是展开或收缩节点, * 显示或隐藏节点的所有子节点,更改节点图标, * 更改连接节点的树枝 */ this.branch.onclick = function() { var node = this.node; if(node == null) { return; } if(node.hasChild()) { if(node.model) { //当前节点收缩,展开所有子节点 node.expand(); } else { //当前节点展开,收缩所有子节点 node.collapse(); } } } } this.getBranch = function() { return this.branch; } this.setBranchIndex = function(index) { this.branch.index = index; this.changeBranch(); } this.getBranchIndex = function() { return this.branch.index; } /** * 设置树枝图标 * boolean hasChild 节点是否有子节点 * boolean isLastChild 当前节点是否是其父节点的最后一个子节点 */ this.setBranch = function(hasChild, isLastChild) { if(hasChild == null) { hasChild = this.hasChild(); } if(isLastChild == null) { isLastChild = this.getNextSibling() == null; } if(isLastChild) { this.branch.index = 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; } this.changeBranch(); } /** * 改变连接节点的枝图标 * 当节点在收缩和展开时,改变它的索引 */ this.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); } } /** * 隐藏枝图标 */ this.hideBranch = function() { if(this.branch.parentNode != null) { this.branch.parentNode.width = "1"; } this.branch.style.display = "none"; } /** * 显示枝图标 */ this.showBranch = function() { if(this.branch.parentNode != null) { this.branch.parentNode.width = "19"; } this.branch.style.display = "block"; } /****************************节点的图标************************************/ this.initImage = function() { /** * 节点图标对象 */ this.image = this.tree.doc.createElement("img"); //节点收缩时的图标在资源中的索引,展开时的索引比收缩时的索引大1 this.image.index = 0; this.image.src = null; this.image.width = 16; this.image.height = 15; this.image.style.cursor = "hand"; this.image.node = this; /** * 处理节点图标被单击事件 * 该事件将被处理成节点的链接被单击 */ this.image.onclick = function() { //节点 var node = this.node; if(node == null) { return; } node.link.click(); } //载入节点图标 this.setImage(false, true); } /** * 设置当前节点图标模式 * boolean model 值true代表节点收缩,false代表展开 */ this.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 图标是否更新 */ this.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); } } this.getImageIndex = function() { return this.image.index; } /** * 节点的复选框,如果树设置显示复选框属性,则显示 */ this.checkbox = null; this.setChecked = function(checked) { if(this.checkbox == null) { alert("节点没有复选框,不支持的操作!"); throw new Error("节点没有复选框,不支持的操作!"); } if(!(this.oncheck == null)) { var result = this.oncheck.call(this.oncheck, this, this.checkbox.checked); if(result == false) { return; } } checked = checked == null ? false : checked == true; if(checked) { var force = this.tree.getNodeCheckForce(); if((force & 0x2) == 2) { var checkboxs = this.getTable().getElementsByTagName("checkbox"); this.tree.setNodeCheckForce(0); for(var i = 0; i < checkboxs.length; i++) { if(checkboxs[i].node == this) { continue; } checkboxs[i].node.setChecked(true); } this.tree.setNodeCheckForce(force); } else { if((force & 0x1) == 1) { var nodes = this.getChildNodes(); this.tree.setNodeCheckForce(0); for(var i = 0; i < nodes.length; i++) { nodes[i].setChecked(true); } this.tree.setNodeCheckForce(force); } } } else { var force = this.tree.getNodeCheckForce(); if((force & 0x200) == 0x200) { var checkboxs = this.getTable().getElementsByTagName("checkbox"); this.tree.setNodeCheckForce(0); for(var i = 0; i < checkboxs.length; i++) { if(checkboxs[i].node == this) { continue; } checkboxs[i].node.setChecked(false); } this.tree.setNodeCheckForce(force); } else { if((force & 0x100) == 0x100) { var nodes = this.getChildNodes(); this.tree.setNodeCheckForce(0); for(var i = 0; i < nodes.length; i++) { nodes[i].setChecked(false); } this.tree.setNodeCheckForce(force); } } } this.checkbox.checked = checked; this.checkbox.firstChild.src = this.tree.getImages().getImageBase() + (this.checkbox.checked ? "check2.gif" : "check0.gif"); } this.getChecked = function() { if(this.checkbox == null) { return false; } return this.checkbox.checked; } /****************************节点的HTML对象********************************/ //创建节点的HTML对象 this.initTextNode = function() { /** * 文本节点对象 */ this.text = new Object(); this.text.text = this.tree.doc.createTextNode(text); //文本节点所在的表对象 this.text.table = null; //文本节点所在单元格 this.text.td = null; //创建HTML表对象 this.text.table = this.tree.doc.createElement("table"); this.text.table.border = "0"; this.text.table.cellSpacing = 0; this.text.table.cellPadding = 0; var tbody = this.tree.doc.createElement("tbody"); var tr = this.tree.doc.createElement("tr"); //节点的图标的单元格 var imageTD = this.tree.doc.createElement("td"); imageTD.appendChild(this.image); if(this.tree.getShowCheckbox()) { //复选框单元格 var cbTD = this.tree.doc.createElement("td"); cbTD.vAlign = "middle"; cbTD.style.paddingRight = "2px"; cbTD.style.paddingLeft = "2px"; this.checkbox = this.tree.doc.createElement("checkbox"); this.checkbox.checked = false; this.checkbox.node = this; var view = this.tree.doc.createElement("img"); view.src = this.tree.getImages().getImageBase() + "check0.gif"; this.checkbox.onclick = function() { this.node.setChecked(!this.checked); } this.checkbox.appendChild(view); cbTD.appendChild(this.checkbox); tr.appendChild(cbTD); } //节点文本单元格 this.text.td = this.tree.doc.createElement("td"); this.text.td.className = "tree___node_text_td"; this.text.td.noWrap = true; tr.appendChild(imageTD); tr.appendChild(this.text.td); tbody.appendChild(tr); this.text.table.appendChild(tbody); //文本节点table文档对象所属TreeNode this.text.table.node = this; /** * 处理节点被右击事件 */ this.text.table.oncontextmenu = function() { //节点对象 var node = this.node; if(node == null) { return; } if(!(node.oncontextmenu == null)) { //用当前节点作参数,回调指定的方法 return node.oncontextmenu.call(node.oncontextmenu, node); } } } this.setNodeValue = function(text) { this.text.text.nodeValue = text; } this.getNodeValue = function() { return this.text.text.nodeValue; } /****************************节点的链接************************************/ this.initLink = function() { //链接 this.link = this.tree.doc.createElement("a"); if(link == null) { this.link.disabled = true; } this.link.href = link == null ? "null" : link; /** * 链接的目标框架属性 */ this.link.target = target; this.link.className="tree___"; //链接所属节点 this.link.node = this; //链接的文本 this.link.appendChild(this.text.text); //添加链接对象到文本节点 this.text.td.appendChild(this.link); /** * 处理文本节点所在单元格上鼠标移动事件 */ this.link.onmouseover = function() { var td = this.parentNode; var node = this.node; if(node == null) { return; } if(node.getDynamicChildFlagNode()) { //节点是动态载入资源提示节点 return false; } td.className = "tree___node_text_td_mouseover"; return false; } this.link.onmouseout = function() { var td = this.parentNode; var node = this.node; if(node == null) { return; } if(node.getDynamicChildFlagNode()) { //节点是动态载入资源提示节点 return false; } if(node.getSelected()) { td.className = "tree___node_text_td_selected"; } else { td.className = "tree___node_text_td"; } return false; } /** * 处理节点被单击事件 */ this.link.onclick = function() { if(this.href == "null") { this.blur(); return false; } else { //节点 var node = this.node; if(node == null) { return; } if(!(node.onclick == null)) { //用当前节点作参数,回调指定的方法 var result = node.onclick.call(node.onclick, node); if(result == false) { //事件被取消 return false; } } //节点所在的树 var tree = node.tree; if(node.getDynamicChildFlagNode()) { //节点是动态载入资源提示节点 return false; } this.parentNode.className = "tree___node_text_td_selected"; if(!(tree.currentSelectedNode == null)) { tree.currentSelectedNode.text.td.className = "tree___node_text_td"; tree.currentSelectedNode.setSelected(false); } tree.currentSelectedNode = node; node.setSelected(true); this.blur(); } } } this.setLink = function(link) { this.link.href = link; } this.getLink = function() { return this.link.href; } this.setTarget = function(target) { this.link.target = target == null ? "" : target; } this.getTarget = function() { return this.link.target; } /****************************节点的状态************************************/ /** * model为true时,节点收缩,为false时,节点展开 */ this.model = true; this.getModel = function() { return this.model; } //节点是否被选中 this.selected = false; this.setSelected = function(selected) { this.selected = selected; } this.getSelected = function() { return this.selected; } /****************************节点视图***************************************/ //节点的表对象 this.table = null; this.getTable = function() { return this.table; } this.tbody = null; /** * 节点id */ this.id = id; this.setID = function(id) { this.id = id; this.table.id = this.id; } this.getID = function() { return this.id; } /** * 初使化视图 */ this.initView = function() { //创建连接节点的树枝 this.initBranch(); //创建节点的图标 this.initImage(); //创建节点的文本 this.initTextNode(); this.initLink(); //创建HTML表对象 this.table = this.tree.doc.createElement("table"); this.table.border = "0"; this.table.cellSpacing = 0; this.table.cellPadding = 0; if(this.id != null) { this.table.id = this.id; } this.tbody = this.tree.doc.createElement("tbody"); var tr = this.tree.doc.createElement("tr"); //连接节点的枝图标的单元格 var tdBranch = this.tree.doc.createElement("td"); tdBranch.width = 19; tdBranch.height = 20; tdBranch.appendChild(this.branch); //节点的单元格 var tdNode = this.tree.doc.createElement("td"); tdNode.height = 20; tdNode.vAlign = "bottom"; tdNode.appendChild(this.text.table); tr.appendChild(tdBranch); tr.appendChild(tdNode); this.tbody.appendChild(tr); this.table.appendChild(this.tbody); //表格所属节点对象 this.table.node = this; return this.table; } /****************************子节点***************************************/ //子节点 this.children = new Object(); //子节点数 this.children.count = 0; //第一个子节点 this.children.firstChild = null; this.getFirstChild = function() { return this.children.firstChild; } //最后一个子节点 this.children.lastChild = null; this.getLastChild = function() { return this.children.lastChild; } //子节点所在节点表对象中的行,收缩节点时,该对象将被隐藏 this.children.tr = null; //子节点容器 this.children.td = null; /** * 连接下一个节点的树枝的单元格 * 当节点有子节点时,这个属性才有意义 */ this.branchToNextNodeTD = null; /** * 节点的兄节点 */ this.previousSibling = null; this.getPreviousSibling = function() { return this.previousSibling; } /** * 节点的弟节点 */ this.nextSibling = null; this.getNextSibling = function() { return this.nextSibling; } /** * 设置节点连接弟节点的树枝 * boolean hasNextSibling 是否有弟节点 */ this.setBranchToNext = function(hasNextSibling) { if(hasNextSibling == null) { hasNextSibling = !(this.nextSibling == null); } //设置兄弟间树枝 if(hasNextSibling == true) { this.branchToNextNodeTD.background = this.tree.images.getImage(this.tree.images.LINE_I); } else { this.branchToNextNodeTD.background = null; } } /** * 节点是否有子节点 */ this.hasChild = function() { return this.children.firstChild != null; } /** * 子节点个数 */ this.getChildCount = function() { return this.children.count; } /** * 返回所有子节点对象 */ this.getChildNodes = function() { var nodes = new Array(this.children.count); var index = 0; var node = this.getFirstChild(); while(node != null) { nodes[index++] = node; node = node.getNextSibling(); } return nodes; } /** * 添加一个子节点到当前节点 * Object obj 如果这个参数是字符串,则视为节点的文本,它和其他参数一起作为 * 树节点的参数。如果参数是Node或TreeNode对象,则将其添加到当前 * 树节点,且忽略其他参数。 * String link 子节点的链接 * String id 子节点的id * String target 子节点的链接的目标框架 * * return 返回加入的子节点 * * 注意:如果当前节点准备动态载入子节点,则该操作将使当前节点不再动态载入子 * 节点 */ this.appendChild = function(obj, link, id, target) { if(obj == null) { return null; } //子节点对象 var node = null; //节点的文本 var text = null; //节点 if(obj == "[object 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(this.children.count == 0) { if(this.isRoot()) { //设置根节点树枝 this.setBranchIndex(this.tree.images.LINE_PLUS_ROOT); //根节点有子节点,显示树枝 this.showBranch(); } else { //设置节点树枝 this.setBranch(true); } //更新图标 this.setImage(true, true); if(this.children.tr == null) { //创建子节点容器 this.createChildrenTD(); } } if(target == null) { target = this.link.target; } //子节点的table文档对象 var ct = null; if(node == null) { //节点不存在,创建之 node = new TreeNode(text, link, id, this.tree, target); //初始化子节点的文档对象 ct = node.initView(); } else { ct = node.getTable(); node.parentNode = this; //设置树枝 node.setBranch(null, true); if(node.hasChild()) { if(this.getNextSibling() != null) { //设置兄弟间树枝 this.setBranchToNext(true); } } } //添加子节点的table文档对象到当前节点的文档对象中 this.children.td.appendChild(ct); this.children.count++; node.parentNode = this; //当前节点的最后一个子节点 var lastChild = this.children.lastChild; if(lastChild != null) { if(lastChild.getDynamicChildFlagNode()) { //最后一个子节点是动态子节点提示符,删之 this.children.td.removeChild(lastChild.table); this.children.count--; this.children.firstChild = null; } else { //设置节点的兄节点 node.previousSibling = lastChild; //最后一个节点的弟节点 lastChild.nextSibling = node; //设置最后一个节点的树枝 lastChild.setBranch(); if(lastChild.hasChild()) { //设置兄弟间树枝 lastChild.setBranchToNext(true); } } } //第一个子节点 if(this.children.firstChild == null) { this.children.firstChild = node; } //最后一个子节点 this.children.lastChild = node; return node; } /** * 动态子节点提示符节点 */ this.dynamicChildFlagNode = false; this.setDynamicChildFlagNode = function(flag) { this.dynamicChildFlagNode = flag == null ? false : flag == true; if(this.dynamicChildFlagNode == true) { if(!(this.checkbox == null)) { this.checkbox.parentNode.removeChild(this.checkbox); } } } this.getDynamicChildFlagNode = function() { return this.dynamicChildFlagNode; } /** * 为当前节点添加动态子节点 * String link 动态子节点资源的URL */ this.appendDynamicChild = function(link) { var node = this.appendChild("正在载入资源...", link); node.setDynamicChildFlagNode(true); node.image.style.display = "none"; node.link.disabled = true; //树中有动态子节点 this.tree.hasDynamicNode = true; return node; } /** * 创建子节点容器 */ this.createChildrenTD = function() { this.children.tr = this.tree.doc.createElement("tr"); //隐藏所有子节点 this.children.tr.style.display = "none"; //节点连接其弟节点的树枝 this.branchToNextNodeTD = this.tree.doc.createElement("td"); if(!this.isRoot() && this.parentNode != null && !(this.nextSibling == null)) { //当前节点并不是其父节点的最后一个子节点 //设置兄弟间树枝 this.setBranchToNext(true); } //子节点的容器 this.children.td = this.tree.doc.createElement("td"); this.children.tr.appendChild(this.branchToNextNodeTD); this.children.tr.appendChild(this.children.td); this.tbody.appendChild(this.children.tr); } /****************************操作节点**************************************/ /** * 展开节点 * boolean deep 是否展开子节点 */ this.expand = function(deep) { if(this.onexpand != null) { //用当前节点作参数,回调指定的方法 var result = this.onexpand.call(this.onexpand, this); if(result == false) { //事件被取消 return false; } } if(this.hasChild()) { if(this.model) { //当前节点收缩,展开所有子节点 //更新节点树枝 this.changeBranch(false); //节点图标 this.setImageModel(false); //显示所有子节点 this.children.tr.style.display = "block"; this.model = false; if(this.getLastChild().getDynamicChildFlagNode()) { this.tree.loadDynamicNodes(this); } } if(deep) { if(this.tree.hasDynamicNode) { //有动态子节点,不可深度展开 return; } //展开子节点 var nodes = this.getChildNodes(); for(var i = 0; i < nodes.length; i++) { nodes[i].expand(true); } } } } /** * 收缩节点 */ this.collapse = function() { if(this.oncollapse != null) { //用当前节点作参数,回调指定的方法 var result = this.oncollapse.call(this.oncollapse, this); if(result == false) { //事件被取消 return false; } } if(this.hasChild()) { if(!this.model) { //当前节点展开,收缩所有子节点 //更新节点树枝 this.changeBranch(true); //节点图标 this.setImageModel(true); //显示所有子节点 this.children.tr.style.display = "none"; this.model = true; } } } /** * 选中节点 */ this.select = function select() { this.link.click(); } /** * 用户自定义的数据对象,如果在克隆节点时 * 需克隆这个对象,则该对象应提供方法clone, * 该方法返回一个对象的克隆。如果对象中没 * 有提供clone方法,则在克隆节点时,将克隆 * 一个对本对象的引用 */ this.userObject = null; this.setUserObject = function setUserObject(obj) { this.userObject = obj; } this.getUserObject = function getUserObject() { return this.userObject; } /** * 对象信息 */ this.toString = function() { return "[object TreeNode]"; } this.valueOf = function() { return "[object TreeNode]"; } /** * 删除节点的子节点 * TreeNode child 子节点 * return 返回删除的子节点 */ this.removeChild = function(child) { if(child == null) { return null; } if(child.getParentNode() != this) { //要删除的节点并不是当前节点的子节点 return child; } //父节点设置为null child.parentNode = null; //child节点的table文档对象 var ct = child.table; //从文档Document中删除child节点的文档对象 ct.parentNode.removeChild(ct); if(child.hasChild()) { child.setBranchToNext(false); } //子节点的兄弟节点处理 var node = child.previousSibling; if(node != null) { node.nextSibling = child.nextSibling; node.setBranch(); 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.children.firstChild = child.nextSibling; } if(this.getLastChild() == child) { this.children.lastChild = child.previousSibling; } child.nextSibling = null; child.previousSibling = null; this.children.count--; if(this.children.count == 0) { //已经没有子节点 //节点图标 this.setImage(false, true); //显示所有子节点 this.children.tr.style.display = "none"; //节点当前收缩 this.model = true; //删除节点连接其弟节点的延长枝 this.setBranchToNext(false); //设置节点树枝 this.setBranch(); } //删除节点在树中的引用,释放资源 child.release(); //当前选中的节点 if(this.tree.currentSelectedNode == child) { this.tree.currentSelectedNode = null; child.text.td.className = "tree___node_text_td"; child.setSelected(false); } return child; } /** * 删除节点在树中的引用,释放资源 */ this.release = function() { var nodes = this.getChildNodes(); for(var i = 0; i < nodes.length; i++) { nodes[i].release(); } if(this.index != -1) { this.getTree().nodes[this.index] = null; } } /** * 克隆节点,并返回新结点 * boolean deep 是否克隆其子节点 * return 返回新节点 */ this.cloneNode = function(deep) { if(deep == null) { deep = false; } var text = this.getNodeValue(); var link = this.getLink(); var id = this.getID(); var target = this.getTarget(); var newNode = new TreeNode(text, link, id, this.tree, target); newNode.initView(); //clone其他数据 newNode.setChecked(this.getChecked()); 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 返回插入的新节点 */ this.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(newChild.hasChild()) { //设置兄弟间树枝 newChild.setBranchToNext(true); } newChild.setBranch(null, false); if(refChild.previousSibling == null) { this.children.firstChild = newChild; } else { refChild.previousSibling.nextSibling = newChild; } newChild.previousSibling = refChild.previousSibling; refChild.previousSibling = newChild; newChild.nextSibling = refChild; newChild.parentNode = this; this.children.count++; //树节点的文档对象插入 var pn = refChild.getTable().parentNode; pn.insertBefore(newChild.getTable(), refChild.getTable()); return newChild; } /** * 替换子节点 * TreeNode newChild 新的子节点 * TreeNode oldChild 将被替换的子节点 * * return 返回新的节点 */ this.replaceChild = function(newChild, oldChild) { if(oldChild == null) { return null; } if(oldChild == newChild) { return newChild; } this.insertBefore(newChild, oldChild); this.removeChild(oldChild); return newChild; } /** * 单击节点事件的处理方法,其定义可能是: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; /** * 模仿节点上的用户鼠标单击操作,如果调用这个方法,节点对象 * 将被模拟单击 */ this.click = function() { this.link.click(); } } /** * 构造树对象,并载入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.parentNode = parentNode; this.getParentNode = function() { return this.parentNode; } /** * 树的table文档对象 */ this.table = this.doc.createElement("table"); this.getTable = function() { return this.table; } /** * 树对象的id值,可以通过它从文档对象中找出树的table文档对象 */ this.id = id; if(this.id != null) { this.table.id = this.id; } this.getID = function() { return this.id; } this.setID = function(id) { this.id = id; this.table.id = id; } this.table.border = "0"; this.table.width = width == null ? 1 : width; this.table.height = height == null ? 1 : height; this.table.cellSpacing = 0; this.table.cellPadding = 4; this.table.tree = this; /** * 处理树被单击事件 */ this.table.onclick = function() { //树对象 var tree = this.tree; if(tree == null) { return; } if(tree.onclick != null) { //用树和节点作参数,回调指定的方法 return tree.onclick.call(tree.onclick, tree, getTreeNode()); } } /** * 处理树被右击事件 */ this.table.oncontextmenu = function() { //树对象 var tree = this.tree; if(tree == null) { return; } if(!(tree.oncontextmenu == null)) { //用树和节点作参数,回调指定的方法 return tree.oncontextmenu.call(tree.oncontextmenu, tree, getTreeNode()); } } var tbody = this.doc.createElement("tbody"); var tr = this.doc.createElement("tr"); /** * 树的节点的容器 */ this.bole = this.doc.createElement("td"); this.getBole = function() { return this.bole; } this.bole.vAlign = "top"; tr.appendChild(this.bole); tbody.appendChild(tr); this.table.appendChild(tbody); this.parentNode.appendChild(this.table); /** * 树样式 */ this.setStyle = function(className) { this.table.className = className; } this.getStyle = function() { return this.table.className; } /** * 树的图标资源 */ this.images = new ImageList(context); this.getImages = function() { return this.images; } /** * 树对象的样式表 */ this.styleSheet = new TreeStyleSheet(this.doc); this.getTreeStyleSheet = function() { return this.styleSheet; } /** * 树中节点的链接的缺省目标框架 */ this.target = target == null ? "" : target; this.getTarget = function getTarget() { return this.target; } this.setTarget = function setTarget(target) { this.target = target; } /** * 树中节点显示复选框 */ this.showCheckbox = showCheckbox == null ? false : showCheckbox == true; this.setShowCheckbox = function(sc) { if(sc == null) { sc = false; } this.showCheckbox = sc == true; } this.getShowCheckbox = function() { return this.showCheckbox == true; } /** * 树中节点复选框状态改变时,其影响子节点的程度, * 默认为没有影响 */ this.nodeCheckForce = 0; this.getNodeCheckForce = function() { return this.nodeCheckForce; } this.setNodeCheckForce = function(ncf) { this.nodeCheckForce = ncf; } //树中的节点对象 this.nodes = new Array(); /** * 根节点对象 */ this.root = null; this.getRootNode = function getRootNode() { return this.root; } /** * 创建根节点 */ this.appendRootNode = function(text, link, id, target) { if(this.root != null) { //只能有一个根节点 alert("树中只能有一个根节点!"); throw new Error("树中只能有一个根节点!"); } target = target == null ? this.target : target; var root = new TreeNode(text, link, id, this, target); root.parentNode = this; this.root = root; //初始化视图 var table = root.initView(); this.bole.appendChild(table); //根节点树枝隐藏 root.hideBranch(); return root; } /** * 节点索引 */ this.nodeIndex = 0; this.getNodeIndex = function getNodeIndex() { return this.nodeIndex++; } /** * 当前选中节点 */ this.currentSelectedNode = null; this.getSelectedNode = function() { return this.currentSelectedNode; } /** * 复选框选中的节点 */ this.getCheckedNodes = function() { if(this.showCheckbox == false) { return null; } var cbs = this.getTable().getElementsByTagName("checkbox"); var cns = new Array(); var index = 0; for(var i = 0; i < cbs.length; i++) { if(cbs[i].checked) { cns[index++] = cbs[i].node; } } return cns; } /****************************动态载入子节点********************************/ /** * 用于动态载入资源的ifram对象 */ this.dynamicWindow = null; /** * 树中拥有动态子节点标志 */ this.hasDynamicNode = false; /** * 动态载入子节点 * TreeNode node 要动态载入子节点的节点 * String src 资源URL */ this.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 = function() { //解锁 this.lock = false; if(this.list.length > 0) { this.load(this.list.shift()); } } /** * 载入节点的资源 */ this.dynamicWindow.load = function(node) { if(this.lock) { this.list.push(node); } else { this.lock = true; this.src = node.children.lastChild.link.href; //树中当前动态载入子节点的节点 this.treeParentNode = node; } } this.parentNode.appendChild(this.dynamicWindow); } this.dynamicWindow.load(node); } /** * 展开树 */ this.expand = function() { if(this.hasDynamicNode) { alert("树中有动态子节点,不可展开树!"); return; } if(this.root != null) { this.root.expand(true); } } /** * 根据节点的索引返回树中的节点对象 */ this.getNodeByIndex = function(index) { if(isNaN(index)) { alert("节点的索引必须是一个数值"); throw new Error("index不是一个有效的整数"); } if(index < 0) { alert("index不是一个有效的整数"); throw new Error("index不是一个有效的整数"); } return this.nodes[index]; } /** * 根据节点的id值检索节点对象, * 如果有多个节点的id值等于传入的参数,则返回这些节点构成的 * 数组 */ this.getNodeByID = function(id) { var node = this.doc.getElementById(id); if(node.length == null) { return node.node; } var nodes = new Array(); for(var i = 0; i < node.length; i++) { nodes[i] = node[i].node; } return nodes; } /** * 如果单击树中节点的事件上溯,则回调这个方法, * 其定义可能是:function(tree, node) * 事件处理器将把树对象和当前被单击的节点作为参数传入这个方法, * 如果单击事件不是在一个节点上发生,第二个参数将是null, * 如果这个方法返回false,事件将不再上溯 */ this.onclick = null; /** * 如果用鼠标右击树中节点的事件上溯,则回调这个方法, * 其定义可能是:function(tree, node) * 事件处理器将把树对象和当前被鼠标右击的节点作为参数传入这个方法, * 如果右击事件不是在一个节点上发生,第二个参数将是null, * 如果这个方法返回false,事件将不再上溯 */ this.oncontextmenu = null; /** * 删除树的根节点 * TreeNode root 子节点 */ this.removeChild = function(root) { if(root.getParentNode() != this) { //要删除的节点并不是当前树的根节点 return root; } //父节点设置为null root.parentNode = null; //root节点的table文档对象 var ct = root.table; //从文档Document中删除root节点的文档对象 ct.parentNode.removeChild(ct); //删除节点在树中的引用,释放资源 root.release(); //树中无根节点也 this.root = null; //当前选中的节点 if(this.currentSelectedNode == root) { this.currentSelectedNode = null; } return root; } /** * 对象信息 */ this.toString = function() { return "[object Tree]"; } this.valueOf = function() { return "[object Tree]"; } } /******************************************* * 下面的参数指明节点受其父节点复选框 * 选取状态的影响度,它们作为调用方法 * setFoce的参数 ******************************************/ //选中节点复选框时子节点不受其影响 FlyBean.UNAFFECTED_ON_CHECK = 0; //选中节点复选框时直接子节点受其影响 FlyBean.AFFECTED_ON_CHECK = 1; //选中节点复选框时所有子孙节点都受其影响 FlyBean.DEEP_AFFECTED_ON_CHECK = 2; //取消节点复选框时子节点不受其影响 FlyBean.UNAFFECTED_ON_CANCEL = 0; //取消节点复选框时直接子节点受其影响 FlyBean.AFFECTED_ON_CANCEL = 256; //取消节点复选框时所有子孙节点都受其影响 FlyBean.DEEP_AFFECTED_ON_CANCEL = 512; /************************************************* * 例: * //选中节点时,也选中其直接子节点 * 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); ************************************************/ </script> <script language=javascript> //文档树对象 var tree = new FlyBean("", "treeParent"); //树中节点链接缺省目标框架 tree.setTarget("mainFrame"); tree.setShowCheckbox(true); //节点复选框选中时,选中其所有的子孙节点, //节点复选框取消选中时,取消选中其直接子节点 tree.setNodeCheckForce(FlyBean.DEEP_AFFECTED_ON_CHECK | FlyBean.AFFECTED_ON_CANCEL); //根节点 var root = tree.appendRootNode("PSERP系统", "/pserp/welcome.jsp"); var node0 = root.appendChild("修改密码", "/pserp/user/changePassword.jsp"); var node = root.appendChild("注销", "/pserp/user/logoff.jsp"); var obj = new Object(); obj.id = "ssc"; obj.text = "string"; node.userObject = obj; node.setChecked(true); var node2 = root.appendChild("支111", "", "node2"); node2.appendDynamicChild("259549.aspx"); var node3 = root.appendChild("支111", "", "node2"); node3.appendDynamicChild("259549.aspx"); //隐藏根节点的枝线 root.hideBranch(); //展开根节点 root.expand(); function del() { var node = tree.getSelectedNode(); if(node == null) { return; } node.getParentNode().removeChild(node); } var cn = null; function cut() { var node = tree.getSelectedNode(); if(node == null) { return; } cn = node.getParentNode().removeChild(node); } function past() { var node = tree.getSelectedNode(); if(node == null) { return; } node.appendChild(cn); cn = null; } function insert() { var node = tree.getSelectedNode(); if(node == null) { return; } node.getParentNode().insertBefore(cn, node); cn = null; } function clone() { var node = tree.getSelectedNode(); if(node == null) { return; } cn = node.cloneNode(true); } function getCheckedNodes() { var nodes = tree.getCheckedNodes(); for(var i = 0; i < nodes.length; i++) { alert(nodes[i].getNodeValue()); } } </script>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值