Ajax式的树形目录组件tree,支持无限层级+在线直观编辑功能——QFaces1.3(JSF)

QFaces1.3树形目录组件tree:
    应用环境:JSF1.2或更高版本
    浏览器:IE7,IE8,firefox3 下测试通过,IE6及其它浏览器我没有测试,实在是没有那么多时间及心情。
    组件特别:Ajax组件,无限层级,在线直观编辑。
                

    花了些时间给QFaces增加了一个新的组件——tree树形目录组件,这是最终效果图。对于树形目录组件,网上已经有不少的例子,包括MyFaces组件库中也有很方便的树形目录组件,我并不打算做一个与MyFaces一样的目录组件。所以这个组件仍然与其它QFaces组件一样有自己的一些特点,那就是支持无限分级以及在线编辑功能。
    以前有朋友问我如何使用MyFaces的tree2组件作类似无限层级的功能,我也不知道。后来自己也遇到某些有层级关系的录入功能时,录入界面很遭糕的设计方式。比如在录入产品类别的层级关系时,录入界面非常不直观,指定子类别时通常要手动填写或选择父类别,但又往往看不到上级类别之间的关系,所以如果在录入层级关系很深很复杂的情况下,就会很辛苦,又容易出错!使用树形目录方式录入,相比几乎就是一种享受,很直观!又很方便。

   

    同样,这也是一个JSF组件,在QFaces框架下制作的ajax组件,现在支持jsp及facelets视图技术。所以需要在JSF环境下使用。如果你并不使用JSF的话,并不要紧,后面会提供组件的大概制作思路及过程,如果你对javascript + div + css很熟悉的话,相信很快也会知道如何制作以应用于其它环境。不过我还是很推荐以JSF组件这种方式运行,它几乎可以封装掉组件95%+以上的复杂度,所以写完后使用起来非常简单。组件的JS写了800多行甚至内置了一个Tab组件:),到400左右行的时候几乎重写,在写编辑功能的时候遇到不少问题。大部分时间不是花在组件的逻辑,而是花在div+css上。如果可以只考虑一个浏览器那真是谢天谢地!不仅在多浏览器上,即使在单浏览器上也存在多版本。所以整浏览器兼容,已经整得让人很没精神。
下面先看一下组件的使用:
首先安装QFaces1.3组件包,关于下载QFaces组件包,安装及组件文档在我的其它文章中有,以下是组件的用法示例1:

前台而面,这里使用了facelets(组件同样适应于jsp页面)
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:h
="http://java.sun.com/jsf/html"
                xmlns:f
="http://java.sun.com/jsf/core"
                xmlns:q
="http://huliqing.name/qfaces"
                xmlns:ui
="http://java.sun.com/jsf/facelets"
                template
="/examples/template.xhtml">
    
<ui:define name="title">UITree</ui:define>
    
<ui:define name="content">
        
<div>
            
<q:tree listener="#{TreeBean.listener}" root="中国" />
        
</div>
    
</ui:define>
</ui:composition>
前台页面主要是引入了组件包,然后以最简单的方式使用组件,实际上只有listener属性是必要的。下面是listener这个属性所绑定的后面bean的方法。

public List<Node> listener(Node node) {
        ArrayList
<Node> nodes = new ArrayList<Node>();
        
if ("root".equals(node.getId())) { // 如果是根节点,则返回第一级子节点
            Node bj = new Node("bj""北京"true);
            Node sh 
= new Node("sh""上海"true);
            Node gd 
= new Node("gd""广东");
            Node hn 
= new Node("hn""河南");
            bj.setHref(
"http://www.google.com"); // 设置两个超链接信息
            sh.setHref("http://www.baidu.com");
            nodes.add(bj);
            nodes.add(sh);
            nodes.add(gd);
            nodes.add(hn);
        } 
else if ("gd".equals(node.getId())) {
            nodes.add(
new Node("gd_by""白云区"));
            nodes.add(
new Node("gd_yx""越秀区"true));
            nodes.add(
new Node("gd_th""天河区"true));
            nodes.add(
new Node("gd_hz""海珠区"true));
            nodes.add(
new Node("gd_lw""荔湾区"true));
        } 
else if ("hn".equals(node.getId())) {
            nodes.add(
new Node("hn_zz""郑州"true));
            nodes.add(
new Node("hn_ly""洛阳"true));
            nodes.add(
new Node("hn_ny""南阳"true));
        } 
else if ("gd_by".equals(node.getId())) {
            nodes.add(
new Node("gd_by_tx""棠下"true));
            nodes.add(
new Node("gd_by_sc""沙涌"));
            nodes.add(
new Node("gd_by_byjc""白云机场"true));
            nodes.add(
new Node("gd_by_wst""王圣堂"true));
        } 
else if ("gd_by_sc".equals(node.getId())) {
            nodes.add(
new Node("gd_by_tx_1x""1巷"true));
            nodes.add(
new Node("gd_by_tx_2x""2巷"true));
            nodes.add(
new Node("gd_by_tx_3x""3巷"true));
        }
        
return nodes;
}
listener所绑定的后台bean的侦听方法,方法签名如下: List<name.huliqing.qfaces.model.Node> listener(name.huliqing.qfaces.model.Node)实际上这个侦听方法也是非常简单,当用户在前台页面点击某节点之后,会通过ajax方法触发后台这个方法,被点击的节点的信息也会被传递到这个方法作为参数,所以根据这个参数就可以知道前台用户点击了那一个节点,然后返回相应的子节点列表就可以了。这也是一种lazy的载入方式,只有用户点击某一非叶节点的“+”图标后才载入并打该节点的子节点列表。但是载入一次之后,下次点击就不会再重新载入了,否则就会造成不必要的ajax请求负担,所以这样实现无限层级是很简单的。
上面这只是以最简单的用法示例,你还可以通过添加简单的属性以实现组件的在线编辑功能:

<q:tree listener="#{TreeBean.listener}" root="中国" showRoot="true" icon="/QFaces/res/image/node.gif" target="_blank"
                addListener
="#{TreeBean.addListener}"
                updateListener
="#{TreeBean.updateListener}"
                removeListener
="#{TreeBean.removeListener}"/>

下面是组件的可用属性说明:

属性

类型

说明

必需

id

String


root

String

根节点的“描述”文字

icon

String

目录树组件的默认图标路径

target

String

当节点有超链接属性时的默认打开方式,与hreftarget属性一样,如:”_blank”,”_top”,”_self”

showRoot

Boolean

是否自动载入根节点的子节点,默认false,当为true时,组件载入后会自动载入第一级列表。

listener

Method

该参数绑定到后台bean的侦听方法中,方法签名如下: List<Node> listener(Node),该方法处理用户前台的点击事件,当用户点击某节点时,该节点会被传送到后台作为listener的参数,listener返回该节点的所有子节点列表。这个参数是必须的。

Node类型必须是name.huliqing.qfaces.model.Node

addListener

Method

该参数绑定到后台bean的侦听方法中,方法签名如下:Boolean addListener(Node),此方法用于支持组件的在线编辑功能添加子节点的功能,当用户为某个节点添加子节点时,子节点会被传送到addListener中作为参数Node, addListener处理该新添加的子节点,并返回true/false以表示成功或失败。

updateListener

Method

该参数绑定到后台bean的侦听方法中,方法签名如下:Boolean updateListener(Node),用于支持节点的在线更新,当用户编辑了某一个节点时,该节点会被传送到后台updateListener方法,updateListener处理更新的节点后返回true/false表示成功与否。

removeListener

Method

该参数绑定到后台bean的侦听方法中,方法签名如下:Boolean removeListener(Node),用于支持节点的删除功能,参考addListener, updateListener













































-------------------------------------------------------------- 分割线,关于Tree树形目录组件的制作
实际上作一个树形目录组件并没有看起来那么复杂,甚至很简单。通过使用html标签:
<ul>
    
<li>层级1</li>
    
<li>层级1</li>
    
<li>层级1
        <ul>
            
<li>层级2</li>
            
<li>层级2</li>
        
</ul>
    
</li>
</ul>

就可以实现比较简单的树形结构,并且它已经帮你在层级间进行了错位,只是中间没有连接线,这种用法很普遍。很多网站多用这种方式制作menu菜单,结合点js就可以适现很不错的效果,当鼠标放到第一级菜单时出现第二级菜单,甚至出现一些滑动效果,看起来效果就很棒。开始时我也使用了这种方法,很简单的实现了不错的效果,但是后面还是发现无法满足这种目录树结构要求,或者是不够自由的原因,所以改用了全div的方式,后面在编辑功能的时候要求很准确方便的获得节点的信息及很方便的控制这个位置。



这是制作过程中的一些截图,它们的大致结构就是:主div中包含了title及content两个子div, content与title增加一些错位,通过css的margin-left就可以实现,然后content继续包含子级的主div(一个列表),而title区域包含该节点的部分信息(由四个小div组成),正常情况下隐藏content区域,当用户点击title区域中的"+"标志之后显示content区域,同时用这个节点的子节点信息创建一系列的主div(即包含title及content结构的div)添加到这个content区域中,这样就形成了错落有致的结构,同时过程中配合一些js以改变"+"号图标的变换。大致的结构及思路就是这样,过程中可能会遇到很多细节上的问题,不过细心调整下来还是可以实现自己想要的效果的。另一种方法可以简单的使用table实现这种树形结构,使用table的层层嵌套会简单得多,并且还可以避免在多浏览器上可能出现的表现不一的样式。使用div在这里并没有体现出比table好到哪里,但我还是比较固执,当然也吃了div+css的不少苦头,
    实现这种结构之后,只要知道如何用ajax请求信息,问题就不会很难了,只要当用户点击节点之后获取该节点的信息,然后到后台请求该节点的子节点列表,回前台为每个子节点创建相应的包含title+content的div,并appendChild到父节点的content区域就可以了。只要对js + div + css足够了解,那么创建完美的web2.0式的友好组件就不是什么难事了,只要有足够耐心。
下面是对组件的一些扩展,在线编辑功能的一些截图,从边框线中可以看到大致的结构。


         



下面提供这个tree组件相关的js代码供参考,部分看不到的代码在QFaces组件包中的QFaces.js中,主要是发送及获取ajax请求信息而已,不影响,本来有比较完整的中文注释,但发布后出现中文乱码,问题还没有解决,暂时用英文勉强注释了。没有完整的开发过程,只能当参考了。

  1 var QFacesTree = new Object();
  2 QFacesTree.trees = new Array();
  3 // Find a tree by clientId
  4 QFacesTree.getTree = function(clientId) {
  5     if (QFacesTree.trees[clientId] == null) {
  6         QFacesTree.trees[clientId] = new Array();
  7     }
  8     return QFacesTree.trees[clientId];
  9 }
 10 function QFacesTreeNode() {
 11     this.id = null;
 12     this.des = null;
 13     this.icon = null;
 14     this.href = null;
 15     this.parent = null;
 16     this.lastChild = null;
 17     this.level = 0;
 18     this.clientId = null;
 19     this.loaded = false;
 20     this.display = false;
 21     this.leaf = false;
 22     // children = [array1[node.clientId,node], array2[node.clientId, node]]
 23     this.children = new Array();
 24     this.childNum = -1;
 25     this.addEnabled = false;
 26     this.updateEnabled = false;
 27     this.removeEnabled = false;
 28     // Put children
 29     this.putChildren = function(children) {
 30         if (children == null || children.length <= 0return;
 31         for (var i = 0; i < children.length; i++) {
 32             this.putChild(children[i]);
 33         }
 34     }
 35     // Put child
 36     this.putChild = function(child) {
 37         this.childNum++;
 38         child.parent = this;
 39         child.clientId = this.clientId + ":" + this.childNum;
 40         child.level = this.level + 1;
 41         child.addEnabled = this.addEnabled;
 42         child.updateEnabled = this.updateEnabled;
 43         child.removeEnabled = this.removeEnabled;
 44         var nodeArr = new Array(2);
 45         nodeArr[0= child.clientId;
 46         nodeArr[1= child;
 47         this.children.push(nodeArr);
 48         this.lastChild = child;
 49         this.leaf = false;
 50     }
 51     // Remove child by node's clientId
 52     this.removeChild = function(clientId) {
 53         if (this.children == null || this.children.length <= 0return;
 54         var tempChildren = new Array();
 55         for (var i = 0; i < this.children.length; i++) {
 56             var nodeArr = this.children[i];
 57             if (nodeArr[0== clientId) {
 58             // ignore
 59             } else {
 60                 tempChildren.push(nodeArr);
 61                 this.lastChild = nodeArr[1];
 62             }
 63         }
 64         this.children = tempChildren;
 65         if (this.children.length <= 0) {
 66             this.leaf = true;
 67         }
 68     }
 69     // Get children
 70     this.getChildren = function() {
 71         if (this.children == null || this.children.length <= 0return null;
 72         var nodes = new Array();
 73         for (var i = 0; i < this.children.length; i++) {
 74             var childNodeArr = this.children[i];
 75             nodes.push(childNodeArr[1]);
 76         }
 77         return nodes;
 78     }
 79     // Get last child
 80     this.getLastChild = function() {
 81         if (this.children != null && this.children.length > 0) {
 82             var lastChildArr = this.children[this.children.length - 1]
 83             return lastChildArr[1];
 84         } else {
 85             return null;
 86         }
 87     }
 88     this.isLastChild = function() {
 89         if (this.parent == nullreturn true;
 90         var last = this.parent.lastChild;
 91         return (this.clientId == last.clientId);
 92     }
 93     this.getChildNum = function() {
 94         return (this.childNum + 1);
 95     }
 96     // Clone the this node to a new node.
 97     this.clone = function(node) {
 98         node.id = this.id;
 99         node.des = this.des;
100         node.icon = this.icon;
101         node.parent = this.parent;
102         node.lastChild = this.lastChild;
103         node.level = this.level;
104         node.clientId = this.clientId;
105         node.loaded = this.loaded;
106         node.display = this.display;
107         node.leaf = this.leaf;
108         node.href = this.href;
109         node.children = this.children;
110         node.childNum = this.childNum;
111         node.addEnabled = this.addEnabled;
112         node.updateEnabled = this.updateEnabled;
113         node.removeEnabled = this.removeEnabled;
114         return node;
115     }
116 }
117 // icon,target(_blank,_top,_self)
118 function qfaces_UITree_startDisplay(clientId, componentClass, listenerExp,
119     addListenerExp, updateListenerExp, removeListenerExp,icon, target) {
120     var tree = QFacesTree.getTree(clientId);
121     // Initialization
122     if (tree[clientId] == null) {
123         var componentObj = QFaces.getComponentObj(clientId);
124         componentObj.componentClass = componentClass;
125         componentObj.listenerExp = listenerExp;
126         componentObj.addListenerExp = addListenerExp;
127         componentObj.updateListenerExp = updateListenerExp;
128         componentObj.removeListenerExp = removeListenerExp;
129         componentObj.icon = icon;
130         componentObj.target = target;
131         var root = new QFacesTreeNode();
132         root.id = "root";
133         root.des = "QFaces Tree";
134         root.level = 0;
135         root.clientId = clientId;
136         if (addListenerExp != "") root.addEnabled = true;
137         if (updateListenerExp != "") root.updateEnabled = true;
138         if (removeListenerExp != "") root.removeEnabled = true;
139         tree[clientId] = root;
140     }
141     qfaces_UITree_displayNode(clientId, clientId);
142 }
143 // Request child nodes by Ajax.
144 function qfaces_UITree_displayNode(clientId, nodeId) {
145     var componentObj = QFaces.getComponentObj(clientId);
146     var tree = QFacesTree.getTree(clientId);
147     // The current node which the users "onclick"
148     var node = tree[nodeId];
149     if (node.loaded != null && node.loaded) {
150         qfaces_UITree_toggleNode(node, clientId, null);
151     } else {
152         var obj = QFaces.getObj(clientId);
153         obj = qfaces_UITree_putNodeInformation(obj, node, clientId);
154         obj.put("listenerExp", componentObj.listenerExp);
155         var process = function () {
156             // Important*****
157             node.loaded = true;
158             // Restore nodes by XML data which return from server
159             var childrenNode = qfaces_UITree_restoreNodes(obj.request.responseXML);
160             // Create element view
161             if (childrenNode != null && childrenNode.length > 0) {
162                 for (var i = 0; i < childrenNode.length; i++) {
163                     qfaces_UITree_appendChildElement(node, childrenNode[i], clientId, tree);
164                 }
165             }
166             qfaces_UITree_toggleNode(node, clientId, null);
167         }
168         obj.setProcess(process);
169         obj.get();
170     }
171 }
172 function qfaces_UITree_appendChildElement(parent, newNode, clientId, tree) {
173     // 1.Important***:to reset the old last child's toggle image,and make the full info of the child
174     var oldLastChild = parent.lastChild;
175     parent.putChild(newNode);
176     // 2.Important***:Save the node to the tree,
177     tree[newNode.clientId] = newNode;
178     // 3.Append child node.
179     var parent_content = QFaces.getComponent(parent.clientId + ":content");
180     if (parent_content == null) {
181         qfaces_UITree_showEditMessage(clientId, "Node not found!");
182         return;
183     }
184     parent_content.appendChild(qfaces_UITree_createChildElement(newNode, clientId));
185     // 4.Reset toggle flag image.
186     if (oldLastChild != null) {
187         qfaces_UITree_resetToggleFlag(oldLastChild, clientId);
188     }
189     // 5.Check new node's state and reset parent's action
190     qfaces_UITree_resetToggleFlag(newNode, clientId);
191     qfaces_UITree_resetToggleAction(newNode, clientId);
192     qfaces_UITree_resetToggleAction(parent, clientId);
193     // 6.Repair,make a line
194     if (parent.isLastChild()) {
195         parent_content.style.cssText = "margin:0 0 0 19px;border:0px;";
196     } else {
197         parent_content.style.cssText = "margin:0 0 0 19px;border:0px;border-left:1px solid #CECBBD;";
198     }
199 }
200 function qfaces_UITree_createChildElement(node, clientId) {
201     var componentObj = QFaces.getComponentObj(clientId);
202     var child = document.createElement("div");
203     var child_title = document.createElement("div"); 
204     var child_content = document.createElement("div");
205     var child_title_toggle = document.createElement("div");
206     var child_title_icon = document.createElement("div");
207     var child_title_des = document.createElement("div");
208     var child_title_edit = document.createElement("div");
209     var child_title_toggle_img = document.createElement("img");
210     var child_title_clear = document.createElement("div");
211 
212     // Style
213     child_title.style.cssText = "";
214     child_title_toggle.style.cssText = "float:left;padding:0px;width:20px;margin-left:10px;";
215     child_title_icon.style.cssText = "float:left;padding:0px;height:20px;";
216     child_title_des.style.cssText = "float:left;padding:0px;height:20px;";
217     child_title_edit.style.cssText = "float:left;padding:0px;width:20px;height:20px;";
218     child_title_clear.style.cssText = "clear:both;height:1px;padding:0px;font-size:0px;margin:-2 0 0 0px;border:0px solid red;"
219     child_content.style.cssText = "margin:0 0 0 19px;display:none;border:0px;border-left:1px solid #CECBBD;";
220 
221     // Set id
222     child.setAttribute("id", node.clientId);
223     child_title.setAttribute("id", node.clientId + ":title");
224     child_content.setAttribute("id", node.clientId + ":content");
225     child_title_toggle.setAttribute("id", node.clientId + ":title:toggle");
226     child_title_icon.setAttribute("id", node.clientId + ":title:icon");
227     child_title_des.setAttribute("id", node.clientId + ":title:des");
228     child_title_edit.setAttribute("id", node.clientId + ":title:edit");
229     child_title_toggle_img.setAttribute("id", node.clientId + ":title:toggle:img");
230     child_title_toggle_img.setAttribute("src", qfaces_UITree_getToggleFlagSrc(node, clientId));
231     
232     // Set node info: icon
233     if (node.icon != null && node.icon != "null") {
234         var icon = document.createElement("img");
235         icon.setAttribute("src", node.icon);
236         child_title_icon.appendChild(icon);
237     } else if (componentObj.icon != null && componentObj.icon != "null"){
238         var _icon = document.createElement("img");
239         _icon.setAttribute("src", componentObj.icon);
240         child_title_icon.appendChild(_icon);
241     }
242     // Set
243     if (node.href != null && node.href != "null" && node.href != "") {
244         var href = document.createElement("a");
245         href.setAttribute("href", node.href);
246         href.setAttribute("target", componentObj.target);
247         href.appendChild(document.createTextNode(node.des));
248         child_title_des.appendChild(href);
249     } else {
250         child_title_des.appendChild(document.createTextNode(node.des));
251     }
252 
253     // Set edit listener
254     if (node.addEnabled || node.updateEnabled || node.removeEnabled) {
255         var child_title_edit_img = document.createElement("img");
256         child_title_edit_img.setAttribute("id", node.clientId + ":title:edit:img");
257         child_title_edit_img.setAttribute("src", QFaces.getComponent(clientId + ":tree_edit_flag").value);
258         if (document.all) {
259             child_title_edit_img.onclick = function () {
260                 qfaces_UITree_showEditPanel(clientId, node.clientId, event);
261             }
262         } else {
263             child_title_edit_img.setAttribute("onclick""qfaces_UITree_showEditPanel('" + clientId + "', '" + node.clientId + "', event);");
264         }
265         child_title_edit.appendChild(child_title_edit_img);
266     }
267     
268     child.appendChild(child_title);
269     child.appendChild(child_content);
270     child_title.appendChild(child_title_toggle);
271     child_title.appendChild(child_title_icon);
272     child_title.appendChild(child_title_des);
273     child_title.appendChild(child_title_edit);
274     child_title.appendChild(child_title_clear);
275     child_title_toggle.appendChild(child_title_toggle_img);
276     child_content.appendChild(qfaces_UITree_createClearElement());
277     return child;
278 }
279 function qfaces_UITree_updateChildElement(node, clientId) {
280     var componentObj = QFaces.getComponentObj(clientId);
281     var title_des = QFaces.getComponent(node.clientId + ":title:des");
282     // Set
283     title_des.removeChild(title_des.firstChild);
284     if (node.href != null && node.href != "null" && node.href != "") {
285         var href = document.createElement("a");
286         href.setAttribute("href", node.href);
287         href.setAttribute("target", componentObj.target);
288         href.appendChild(document.createTextNode(node.des));
289         title_des.appendChild(href);
290     } else {
291         title_des.appendChild(document.createTextNode(node.des));
292     }
293 }
294 function qfaces_UITree_resetToggleFlag(node, clientId) {
295     var toggle = QFaces.getComponent(node.clientId + ":title:toggle:img");
296     toggle.setAttribute("src", qfaces_UITree_getToggleFlagSrc(node, clientId));
297 }
298 function qfaces_UITree_resetToggleAction(node, clientId) {
299     var toggle = QFaces.getComponent(node.clientId + ":title:toggle:img");
300     if (!node.leaf) {
301         // Maybe not support IE6
302         toggle.onclick = function () {
303             qfaces_UITree_displayNode(clientId, node.clientId);
304         }
305     }
306 }
307 function qfaces_UITree_getToggleFlagSrc(node, clientId) {
308     if (node.isLastChild()) {
309         if (node.leaf) {
310             return QFaces.getComponent(clientId + ":tree_last_none").value;
311         } else {
312             return node.display ? QFaces.getComponent(clientId + ":tree_last_hide").value : QFaces.getComponent(clientId + ":tree_last_show").value;
313         }
314     } else {
315         if (node.leaf) {
316             return QFaces.getComponent(clientId + ":tree_middle_none").value;
317         } else {
318             return node.display ? QFaces.getComponent(clientId + ":tree_middle_hide").value : QFaces.getComponent(clientId + ":tree_middle_show").value;
319         }
320     }
321 }
322 // Put the general info of the node.
323 function qfaces_UITree_putNodeInformation(obj, node, clientId) {
324     var componentObj = QFaces.getComponentObj(clientId);
325     var levelCount = 0;
326     var temp = node;
327     while (temp != null) {
328         obj.put("id" + levelCount, temp.id);
329         obj.put("des" + levelCount, temp.des);
330         obj.put("leaf" + levelCount, temp.leaf);
331         obj.put("href" + levelCount, temp.href);
332         levelCount++;
333         temp = temp.parent;
334     }
335     obj.put("levelCount", levelCount);
336     obj.put("componentClass", componentObj.componentClass);
337     return obj;
338 }
339 // Toggle a node's children,display = true/false/null, null mean's "auto"
340 function qfaces_UITree_toggleNode(node, clientId, display) {
341     var children = document.getElementById(node.clientId + ":content");
342     if (children == null) {
343     // alert("child content not found!");
344     }
345     if (display == null) {
346         children.style.display = node.display ? "none" : "block";
347         node.display = !node.display;
348     } else {
349         if (display) {
350             children.style.display = "block";
351             node.display = true;
352         } else {
353             children.style.display = "none";
354             node.display = false;
355         }
356     }
357     qfaces_UITree_resetToggleFlag(node, clientId);
358 }
359 // Restore nodes
360 function qfaces_UITree_restoreNodes(responseXML) {
361     if (responseXML == nullreturn null;
362     var nodeArr = new Array();
363     var nodes = responseXML.documentElement;
364     var nodeList = null;
365     if (nodes != null) {
366         nodeList = nodes.getElementsByTagName("node");
367     }
368     if (nodeList != null) {
369         for (var i = 0; i < nodeList.length; i++) {
370             var ele = nodeList[i];
371             var node =new QFacesTreeNode();
372             node.id = ele.getAttribute("id");
373             node.des = ele.getAttribute("des");
374             node.leaf = (ele.getAttribute("leaf"== "true" ? true : false);
375             node.href = ele.getAttribute("href");
376             nodeArr[i] = node;
377         }
378     }
379     return nodeArr;
380 }
381 // ============================================================= editable
382 function qfaces_UITree_showEditMessage(clientId, message) {
383     var messageObj = QFaces.getComponent(clientId + ":editMainPanel:title:des");
384     messageObj.innerHTML = "Main Edit Panel [" + message + "]";
385 }
386 function qfaces_UITree_showEditPanel(clientId, clientIdNode, event) {
387     event = event ? event : window.event;
388     var editMainPanel = QFaces.getComponent(clientId + ":editMainPanel");
389     var tree = QFacesTree.getTree(clientId);
390     var node = tree[clientIdNode];
391     if (editMainPanel == null) {
392         editMainPanel = qfaces_UITree_createEditMainPanel(clientId);
393         QFaces.getComponent(clientId).appendChild(editMainPanel);
394         // Let the edit panel could dragable.
395         QFaces.toDragEnabled(clientId + ":editMainPanel");
396     }
397     // Reset the edit panel's content by a new node click(edit).
398     qfaces_UITree_resetEditMainPanel(clientId, node);
399     if (editMainPanel.style.display == "none") {
400         editMainPanel.style.top = event.clientY;
401         editMainPanel.style.left = event.clientX + 20;
402     }
403     QFaces.toShowByAlpha(clientId + ":editMainPanel"0.1);
404 }
405 function qfaces_UITree_hideEditPanel(clientId) {
406     QFaces.toHiddenByAlpha(clientId + ":editMainPanel"1);
407 }
408 function qfaces_UITree_resetEditMainPanel(clientId, node) {
409     var editMainPanel_content = QFaces.getComponent(clientId + ":editMainPanel:content");
410     while (editMainPanel_content.hasChildNodes()) {
411         editMainPanel_content.removeChild(editMainPanel_content.firstChild);
412     }
413     editMainPanel_content.appendChild(qfaces_UITree_createEditPanelNode(clientId, node));
414 }
415 function qfaces_UITree_createClearElement() {
416     var clear = document.createElement("div");
417     clear.style.cssText = "clear:both;height:1px;padding:0px;font-size:0px;border:0px;";
418     return clear;
419 }
420 // Create the "Edit main panel"
421 function qfaces_UITree_createEditMainPanel(clientId) {
422     var editMainPanel = document.createElement("div");
423     var editMainPanel_title = document.createElement("div");
424     var editMainPanel_content = document.createElement("div");
425 
426     var editMainPanel_title_des = document.createElement("div");
427     var editMainPanel_title_close = document.createElement("div");
428     var editMainPanel_title_close_img = document.createElement("img");
429     // set attribute
430     editMainPanel.setAttribute("id", clientId + ":editMainPanel");
431     editMainPanel_title.setAttribute("id", clientId + ":editMainPanel:title");
432     editMainPanel_content.setAttribute("id", clientId + ":editMainPanel:content");
433     editMainPanel_title_des.setAttribute("id", clientId + ":editMainPanel:title:des");
434     // css
435     editMainPanel.style.cssText = "width:405px;height:265px;display:none;" +
436     "padding:0px;margin:0px;position:absolute;overflow:hidden;" +
437     "font-size:13px;font-weight:normal;" +
438     "border:5px solid #90A6B1;background:#AFBCC4;";
439     editMainPanel_title.style.cssText = "height:30px;line-height:30px;background:#E3E3E3;margin-bottom:5px;";
440     editMainPanel_title_des.style.cssText = "margin-left:10px;float:left;color:orange;font-weight:Bold;";
441     editMainPanel_title_close.style.cssText = "text-align:right;";
442     editMainPanel_title_close_img.style.cssText = "width:78px;height:25px;";
443 
444     // set title content
445     editMainPanel_title_des.innerHTML = "Main Edit Panel"
446     editMainPanel_title_close_img.setAttribute("src", QFaces.getComponent(clientId + ":tree_panel_close").value);
447     if (document.all) {
448         editMainPanel_title_close_img.onclick = function () { // For IE
449             qfaces_UITree_hideEditPanel(clientId);
450         }
451     } else {
452         editMainPanel_title_close_img.setAttribute("onclick""qfaces_UITree_hideEditPanel('" + clientId + "');");
453     }
454     // message
455     var messageFlag = document.createElement("img");
456     messageFlag.setAttribute("src", QFaces.getComponent(clientId + ":tree_processing").value);
457 
458     editMainPanel_title_close.appendChild(editMainPanel_title_close_img);
459     editMainPanel_title.appendChild(editMainPanel_title_des);
460     editMainPanel_title.appendChild(editMainPanel_title_close);
461     editMainPanel.appendChild(editMainPanel_title);
462     editMainPanel.appendChild(editMainPanel_content);
463 
464     return editMainPanel;
465 }
466 
467 // Create panel
468 function qfaces_UITree_createEditPanelNode(clientId, node) {
469     var editContent = document.createElement("div");
470     var editContent_menu = document.createElement("div");
471     var editContent_content = document.createElement("div");
472 
473     var id_menu = node.clientId + ":menu";
474     var id_panel = node.clientId + ":panel";
475     var id_menu_info = node.clientId + ":menu:info";
476 
477     var id_panel_info = node.clientId + ":panel:info";
478     var id_panel_add = node.clientId + ":panel:add";
479     var id_panel_update = node.clientId + ":panel:update";
480     var id_panel_remove = node.clientId + ":panel:remove";
481 
482     var editContent_menu_info = qfaces_UITree_createEditPanelNode_menu("Node Info", id_panel_info, true);
483     var editContent_menu_add = qfaces_UITree_createEditPanelNode_menu("Create Child", id_panel_add);
484     var editContent_menu_update = qfaces_UITree_createEditPanelNode_menu("Update Node", id_panel_update);
485     var editContent_menu_remove = qfaces_UITree_createEditPanelNode_menu("Remove Node", id_panel_remove);
486 
487     var editContent_content_info = qfaces_UITree_createEditPanelNode_info(clientId, node, id_panel_info);
488     var editContent_content_add = qfaces_UITree_createEditPanelNode_add(clientId, node, id_panel_add);
489     var editContent_content_update = qfaces_UITree_createEditPanelNode_update(clientId, node, id_panel_update);
490     var editContent_content_remove = qfaces_UITree_createEditPanelNode_remove(clientId, node, id_panel_remove);
491 
492     editContent_menu.setAttribute("id", id_menu);
493     editContent_content.setAttribute("id", id_panel);
494     editContent_menu_info.setAttribute("id", id_menu_info);
495     
496     // css
497     editContent.style.cssText = "border:0px solid black;";
498     editContent_menu.style.cssText = "float:left;width:100px;text-align:right;margin-left:7px;";
499     if (document.all) {
500         editContent_content.style.cssText = "float:left;width:283px;height:213px;margin-left:-1px;" +
501     "border:1px solid #90A6B1;background:white;";
502     } else {
503         editContent_content.style.cssText = "float:left;width:290px;height:220px;margin-left:-1px;" +
504     "border:1px solid #90A6B1;background:white;";
505     }
506 
507     editContent_menu.appendChild(editContent_menu_info);
508     editContent_content.appendChild(editContent_content_info);
509 
510     if (node.addEnabled) {
511         editContent_menu.appendChild(editContent_menu_add);
512         editContent_content.appendChild(editContent_content_add);
513     }
514     if (node.updateEnabled) {
515         editContent_menu.appendChild(editContent_menu_update);
516         editContent_content.appendChild(editContent_content_update);
517     }
518     if (node.removeEnabled) {
519         editContent_menu.appendChild(editContent_menu_remove);
520         editContent_content.appendChild(editContent_content_remove);
521     }
522     editContent.appendChild(editContent_menu);
523     editContent.appendChild(editContent_content);
524     editContent.appendChild(qfaces_UITree_createClearElement());
525     return editContent;
526 }
527 // Create a tab menu: label -> tab title,relativePanelId -> the relative panel's id
528 function qfaces_UITree_createEditPanelNode_menu(label, relativePanelId, active) {
529     var menu = document.createElement("div");
530     var style_out = "margin:10 0px;height:22px;line-height:20px;padding:2px;position:relative;" +
531     "border:1px solid #90A6B1;";
532     var style_over = style_out + "background:white;color:orange;font-size:110%;cursor:pointer;";
533     var style_click = style_over + "border-right:1px solid white;";
534     var fun_over = function() {
535         this.style.cssText = style_over;
536     }
537     var fun_out = function() {
538         this.style.cssText = style_out;
539     }
540     menu.innerHTML = label;
541     menu.style.cssText = style_out;
542     menu.onmouseover = fun_over;
543     menu.onmouseout = fun_out;
544     menu.onclick = function() {
545         var children = this.parentNode.childNodes;
546         if (children != null && children.length > 0) {
547             for (var i = 0; i < children.length; i++) {
548                 var child = children.item(i);
549                 child.style.cssText = style_out;
550                 child.onmouseover = fun_over;
551                 child.onmouseout = fun_out;
552             }
553         }
554         var relativePanel = QFaces.getComponent(relativePanelId);
555         if (relativePanel == nullreturn;
556         var childrenPanel = relativePanel.parentNode.childNodes;
557         if (childrenPanel != null && childrenPanel.length > 0) {
558             for (var n = 0; n < childrenPanel.length; n++) {
559                 childrenPanel.item(n).style.display = "none";
560             }
561         }
562         relativePanel.style.display = "block";
563         this.onmouseout = this.onmouseover = null;
564         this.style.cssText = style_click;
565     }
566     if (active) {
567         menu.onmouseout = menu.onmouseover = null;
568         menu.style.cssText = style_click;
569         var relativePanel = QFaces.getComponent(relativePanelId);
570         if (relativePanel != null)
571             relativePanel.style.display = "block";
572     }
573     return menu;
574 }
575 function qfaces_UITree_createEditPanelNode_info(clientId, node, panelId) {
576     var info = document.createElement("div");
577     var node_id = document.createElement("div");
578     var node_des = document.createElement("div");
579     var node_leaf = document.createElement("div");
580     var node_parent = document.createElement("div");
581     var node_level = document.createElement("div");
582     var node_clientId = document.createElement("div");
583     var node_children = document.createElement("div");
584     var node_edit_add = document.createElement("div");
585     var node_edit_update = document.createElement("div");
586     var node_edit_remove = document.createElement("div");
587     info.setAttribute("id", panelId);
588 
589     var info_style = "margin:3px 0px 0px 10px;padding:0px;"
590     node_id.innerHTML = "Id: " + node.id;
591     node_des.innerHTML = "Des: " + node.des;
592     node_leaf.innerHTML = "Leaf: " + (node.leaf ? "Yes" : "No");
593     node_parent.innerHTML = "Parent: " + (node.parent != null ? node.parent.id : "Null");
594     node_clientId.innerHTML = "ClientID: " + node.clientId;
595     node_level.innerHTML = "Level: " + node.level;
596     node_children.innerHTML = "Children: " + (node.leaf ? node.children.length : (node.loaded ? node.children.length : "unknow"));
597     node_edit_add.innerHTML = "Add: " + (node.addEnabled ? "Yes" : "No");
598     node_edit_update.innerHTML = "Update: " + (node.updateEnabled ? "Yes" : "No");
599     node_edit_remove.innerHTML = "Remove: " + (node.removeEnabled ? "Yes" : "No");
600 
601     node_id.style.cssText =
602     node_des.style.cssText =
603     node_leaf.style.cssText =
604     node_parent.style.cssText =
605     node_level.style.cssText =
606     node_clientId.style.cssText =
607     node_children.style.cssText =
608     node_edit_add.style.cssText =
609     node_edit_update.style.cssText =
610     node_edit_remove.style.cssText = info_style;
611 
612     info.appendChild(node_id);
613     info.appendChild(node_des);
614     info.appendChild(node_leaf);
615     info.appendChild(node_parent);
616     info.appendChild(node_clientId);
617     info.appendChild(node_level);
618     info.appendChild(node_children);
619     info.appendChild(node_edit_add);
620     info.appendChild(node_edit_update);
621     info.appendChild(node_edit_remove);
622 
623     return info;
624 }
625 // The panel of "Add"
626 function qfaces_UITree_createEditPanelNode_add(clientId, node, panelId) {
627     var nodeAdd = document.createElement("div");
628     
629     var label_title = document.createElement("div");
630     var label_nodeId = document.createElement("div");
631     var label_nodeDes = document.createElement("div");
632     var label_nodeHref = document.createElement("div");
633     var input_nodeId = document.createElement("input");
634     var input_nodeDes = document.createElement("input");
635     var input_nodeHref = document.createElement("input");
636     var submit = document.createElement("input");
637 
638     nodeAdd.setAttribute("id", panelId);
639     input_nodeId.setAttribute("id", node.clientId + ":panel:add:newNodeId");
640     input_nodeDes.setAttribute("id", node.clientId + ":panel:add:newNodeDes");
641     input_nodeHref.setAttribute("id", node.clientId + ":panel:add:newNodeHref");
642 
643     input_nodeId.setAttribute("type""text");
644     input_nodeDes.setAttribute("type""text");
645     input_nodeHref.setAttribute("type""text");
646     input_nodeId.setAttribute("value", node.id + "-" + node.getChildNum());
647     submit.setAttribute("type""button");
648     submit.setAttribute("value""Submit");
649     submit.onclick = function () {
650         qfaces_UITree_ajaxRequestAddNode(clientId, node.clientId);
651     }
652 
653     label_title.innerHTML = "Create new child node for :\"" + node.id + "\"";
654     label_nodeId.innerHTML = "Node ID: ";
655     label_nodeDes.innerHTML = "Des: ";
656     label_nodeHref.innerHTML = "Href: ";
657 
658     // css
659     nodeAdd.style.cssText = "display:none;padding:3px;";
660     label_title.style.cssText = "margin:3px 3px;";
661     label_nodeId.style.cssText = "float:left;width:70px;text-align:right;margin-top:15px;";
662     label_nodeDes.style.cssText = "float:left;width:70px;text-align:right;margin-top:15px;";
663     label_nodeHref.style.cssText = "float:left;width:70px;text-align:right;margin-top:15px;";
664     
665     input_nodeId.style.cssText = "width:150px;margin-top:15px;";
666     input_nodeDes.style.cssText = "width:150px;margin-top:15px;";
667     input_nodeHref.style.cssText = "width:150px;margin-top:15px;";
668     submit.style.cssText = "margin:20px 0px 0px 200px;";
669     
670     nodeAdd.appendChild(label_title);
671     nodeAdd.appendChild(label_nodeId);
672     nodeAdd.appendChild(input_nodeId);
673     nodeAdd.appendChild(label_nodeDes);
674     nodeAdd.appendChild(input_nodeDes);
675     nodeAdd.appendChild(label_nodeHref);
676     nodeAdd.appendChild(input_nodeHref);
677     nodeAdd.appendChild(submit);
678     nodeAdd.appendChild(qfaces_UITree_createClearElement());
679     return nodeAdd;
680 }
681 // Process the request of "Add"
682 function qfaces_UITree_ajaxRequestAddNode(clientId, clientIdNode) {
683     var componentObj = QFaces.getComponentObj(clientId);
684     var tree = QFacesTree.getTree(clientId);
685     var parent = tree[clientIdNode];
686     var newNode = new QFacesTreeNode();
687     var objNodeId = QFaces.getComponent(parent.clientId + ":panel:add:newNodeId");
688     var objNodeDes = QFaces.getComponent(parent.clientId + ":panel:add:newNodeDes");
689     var objNodeHref = QFaces.getComponent(parent.clientId + ":panel:add:newNodeHref");
690     newNode.id = objNodeId.value;
691     newNode.des = objNodeDes.value;
692     newNode.href = objNodeHref.value;
693     newNode.leaf = true;
694     // Important***:don't put the newNode to the parent
695     newNode.parent = parent;
696     if (newNode.des == "") {
697         objNodeDes.focus();
698         objNodeDes.style.background = "red";
699         return;
700     } else {
701         objNodeDes.style.background = "";
702     }
703     var obj = QFaces.getObj(clientId);
704     obj = qfaces_UITree_putNodeInformation(obj, newNode, clientId);
705     obj.put("addListenerExp", componentObj.addListenerExp);
706     var process = function () {
707         if (obj.request.responseText != null && obj.request.responseText == "true" ) {
708             qfaces_UITree_appendChildElement(parent, newNode, clientId, tree);
709             qfaces_UITree_toggleNode(parent, clientId, true);
710             QFaces.getComponent(parent.clientId + ":panel:add:newNodeId").value = parent.id + "-" + parent.getChildNum();
711             QFaces.getComponent(parent.clientId + ":panel:add:newNodeDes").value = "";
712             QFaces.getComponent(parent.clientId + ":panel:add:newNodeHref").value = "";
713             qfaces_UITree_showEditMessage(clientId, "Add Successful");
714         } else {
715             qfaces_UITree_showEditMessage(clientId, "Add Failure");
716         }
717     }
718     qfaces_UITree_showEditMessage(clientId, "Add Processing");
719     obj.setProcess(process);
720     obj.get();
721 }
722 // Create the panel of "Update"
723 function qfaces_UITree_createEditPanelNode_update(clientId, node, panelId) {
724     var update = document.createElement("div");
725     var label_title = document.createElement("div");
726     var label_nodeDes = document.createElement("div");
727     var label_nodeHref = document.createElement("div");
728     var input_nodeDes = document.createElement("input");
729     var input_nodeHref = document.createElement("input");
730     var submit = document.createElement("input");
731     update.setAttribute("id", panelId);
732     input_nodeDes.setAttribute("id", node.clientId + ":panel:update:nodeDes");
733     input_nodeHref.setAttribute("id", node.clientId + ":panel:update:nodeHref");
734 
735     input_nodeDes.setAttribute("type""text");
736     input_nodeHref.setAttribute("type""text");
737     submit.setAttribute("type""button");
738 
739     input_nodeDes.setAttribute("value", node.des);
740     input_nodeHref.setAttribute("value", node.href);
741     submit.setAttribute("value""Submit");
742     submit.onclick = function () {
743         qfaces_UITree_ajaxRequestUpdateNode(clientId, node.clientId);
744     }
745 
746     label_title.innerHTML = "Update node: " + node.id;
747     label_nodeDes.innerHTML = "Des: ";
748     label_nodeHref.innerHTML = "Href: ";
749 
750     // css
751     label_title.style.cssText = "margin:5px 0 0 5px;";
752     label_nodeDes.style.cssText = label_nodeHref.style.cssText = "margin:20px 0 0 0px;width:80px;float:left;text-align:right;";
753     input_nodeDes.style.cssText = input_nodeHref.style.cssText = "margin:15px 0 0 0px;width:180px;";
754     submit.style.cssText = "margin:60px 0 0 200px;";
755 
756     update.appendChild(label_title);
757     update.appendChild(label_nodeDes);
758     update.appendChild(input_nodeDes);
759     update.appendChild(label_nodeHref);
760     update.appendChild(input_nodeHref);
761 
762     update.appendChild(submit);
763     update.style.display = "none";
764     return update;
765 }
766 // Process the request of "Update"
767 function qfaces_UITree_ajaxRequestUpdateNode(clientId, clientIdNode) {
768     var componentObj = QFaces.getComponentObj(clientId);
769     var tree = QFacesTree.getTree(clientId);
770     var nodeToUpdate = tree[clientIdNode];
771 
772     // Clone the current node to a new one, and set new value
773     var newNode = new QFacesTreeNode();
774     newNode = nodeToUpdate.clone(newNode);
775     newNode.des = QFaces.getComponent(nodeToUpdate.clientId + ":panel:update:nodeDes").value;
776     newNode.href = QFaces.getComponent(nodeToUpdate.clientId + ":panel:update:nodeHref").value;
777     // put node's info
778     var obj = QFaces.getObj(clientId);
779     obj = qfaces_UITree_putNodeInformation(obj, newNode, clientId);
780     obj.put("updateListenerExp", componentObj.updateListenerExp);
781     var process = function () {
782         if (obj.request.responseText != null && obj.request.responseText == "true" ) {
783             nodeToUpdate = newNode.clone(nodeToUpdate);
784             qfaces_UITree_updateChildElement(nodeToUpdate, clientId);
785             qfaces_UITree_showEditMessage(clientId, "Update Successful");
786         } else {
787             qfaces_UITree_showEditMessage(clientId, "Update Failure");
788         }
789     }
790     qfaces_UITree_showEditMessage(clientId, "Update Processing");
791     obj.setProcess(process);
792     obj.get();
793 }
794 // Create panel "Remove"
795 function qfaces_UITree_createEditPanelNode_remove(clientId, node, panelId) {
796     var remove = document.createElement("div");
797     var real_nodeId = document.createElement("div");
798     var real_nodeDes = document.createElement("div");
799     var submit = document.createElement("input");
800     remove.setAttribute("id", panelId);
801 
802     real_nodeId.innerHTML = "Node:" + node.id;
803     real_nodeDes.innerHTML = "Description:" + node.des;
804     submit.setAttribute("type""button");
805     submit.setAttribute("value""Are you real to delete it?");
806     submit.onclick = function () {
807         qfaces_UITree_ajaxRequestRemoveNode(clientId, node.clientId);
808     }
809 
810     remove.style.display = "none";
811     real_nodeId.style.cssText = "margin:10px 0 0 5px;";
812     real_nodeDes.style.cssText = "margin:10px 0 0 5px;";
813     submit.style.cssText = "margin:80px 0 0 50px";
814 
815     remove.appendChild(real_nodeId);
816     remove.appendChild(real_nodeDes);
817     remove.appendChild(submit);
818     return remove;
819 }
820 function qfaces_UITree_ajaxRequestRemoveNode(clientId, clientIdNode) {
821     var componentObj = QFaces.getComponentObj(clientId);
822     var tree = QFacesTree.getTree(clientId);
823     var nodeToRemove = tree[clientIdNode];
824 
825     var obj = QFaces.getObj(clientId);
826     obj = qfaces_UITree_putNodeInformation(obj, nodeToRemove, clientId);
827     obj.put("removeListenerExp", componentObj.removeListenerExp);
828     var process = function () {
829         if (obj.request.responseText != null && obj.request.responseText == "true" ) {
830             var parent = nodeToRemove.parent;
831             var parent_content;
832             var nodeToRemove_ele;
833             if (parent != null) {
834                 // Remove child from parent
835                 parent.removeChild(nodeToRemove.clientId);
836                 // Remove child element from view.
837                 parent_content = QFaces.getComponent(parent.clientId + ":content");
838                 nodeToRemove_ele = QFaces.getComponent(nodeToRemove.clientId);
839                 parent_content.removeChild(nodeToRemove_ele);
840                 // Reset toggle flag.
841                 qfaces_UITree_resetToggleFlag(parent.lastChild, clientId);
842                 qfaces_UITree_showEditMessage(clientId, "Remove Successful");
843             } else {
844                 qfaces_UITree_showEditMessage(clientId, "Remove Failure");
845             }
846         }
847     }
848     qfaces_UITree_showEditMessage(clientId, "Remove Processing");
849     obj.setProcess(process);
850     obj.get();
851 }
852 

QQ:31703299
huliqing@live.com

QFaces 下载页面 -- 基于JSF的Ajax增强框架。





- huliqing@huliqing.name
- http://www.huliqing.name

posted on 2009-04-12 18:30 huliqing 阅读(3915) 评论(4)  编辑  收藏 所属分类: JSF

评论

# re: Ajax式的树形目录组件tree,支持无限层级+在线直观编辑功能——QFaces1.3(JSF)[未登录] 2009-04-12 18:46 TiGERTiAN

很不错,支持支持。  回复  更多评论   

# re: Ajax式的树形目录组件tree,支持无限层级+在线直观编辑功能——QFaces1.3(JSF) 2009-04-12 21:24 huliqing

@TiGERTiAN
谢谢:)  回复  更多评论   

# re: Ajax式的树形目录组件tree,支持无限层级+在线直观编辑功能——QFaces1.3(JSF) 2010-06-30 19:50 foren

这个东东非常好,
但我是初学者,
看半天也没有学会怎么用。。。
要是把使用方法写个完整的例子就好了。。。。
比如我的工程里面,不能识别node.getId()方法,
还有,那个监听方法是怎么用的,都没搞懂。。。  回复  更多评论   

# re: Ajax式的树形目录组件tree,支持无限层级+在线直观编辑功能——QFaces1.3(JSF) 2011-03-01 13:40 zm

楼主 能否把源码发给我 看看啊,
邮箱:zhoumeng_live@163.com
万分感激  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

公告

文章原创,欢迎转载
——转载请注明出处及原文链接

随笔分类(60)

随笔档案(33)

最新评论

评论排行榜