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
|
当节点有超链接属性时的默认打开方式,与href的target属性一样,如:”_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 <= 0) return;
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 <= 0) return;
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 <= 0) return 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 == null) return 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 == null) return 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 == null) return;
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
- huliqing@huliqing.name
- http://www.huliqing.name