4 // email: dowdybrown@yahoo.com
\r
6 // Requires prototype.js and ricoCommon.js
\r
8 // each node in nodeIndex is an Array with 6+n positions
\r
9 // node[0] is 0/1 when the node is closed/open
\r
10 // node[1] is 0/1 when the folder is closed/open
\r
11 // node[2] is 1 if the node is a leaf node
\r
12 // node[3] is the node id
\r
13 // node[4] is the node description
\r
14 // node[5] is 1 when the node is selectable, 0 otherwise
\r
15 // node[6]...node[6+n] are the child nodes
\r
17 Rico.TreeControl = Class.create();
\r
19 Rico.TreeControl.prototype = {
\r
21 initialize: function(id,url,options) {
\r
22 Object.extend(this, new Rico.Popup({ignoreClicks:true}));
\r
23 Object.extend(this.options, {
\r
24 nodeIdDisplay:'none', // first, last, tooltip, or none
\r
25 showCheckBox: false,
\r
27 showPlusMinus: true,
\r
28 defaultAction: this.nodeClick.bindAsEventListener(this),
\r
31 leafIcon: Rico.imgDir+'doc.gif'
\r
33 Object.extend(this.options, options || {});
\r
35 this.FirstChildNode=6;
\r
41 this.dataSource=url;
\r
42 this.close=this.closePopup;
\r
45 atLoad : function() {
\r
46 var imgsrc = new Array("node.gif","nodelast.gif","folderopen.gif","folderclosed.gif");
\r
47 for (i=0;i<imgsrc.length;i++) {
\r
48 this.img[i] = new Image
\r
49 this.img[i].src = Rico.imgDir+imgsrc[i]
\r
50 //this.img[i].src = Rico.imgDir + imgsrc[i]
\r
52 this.treeDiv=document.createElement("div");
\r
53 this.treeDiv.id=this.id;
\r
54 this.treeDiv.className='ricoTree';
\r
55 this.treeDiv.style.height=this.options.height;
\r
56 this.treeDiv.style.width=this.options.width;
\r
57 this.container=document.createElement("div");
\r
58 this.container.style.display="none"
\r
59 this.container.className='ricoTreeContainer';
\r
60 this.container.appendChild(this.treeDiv);
\r
61 document.body.appendChild(this.container);
\r
62 this.setDiv(this.container);
\r
66 // Building the data in the tree
\r
69 if (this.nodeCount==0) this.loadXMLDoc();
\r
72 loadXMLDoc: function(branchPin) {
\r
73 var parms="id="+this.id;
\r
74 if (branchPin) parms+="&Parent="+branchPin;
\r
75 Rico.writeDebugMsg('Tree loadXMLDoc:\n'+parms+'\n'+this.dataSource);
\r
76 new Ajax.Request(this.dataSource, {parameters:parms,method:'get',onComplete:this.processResponse.bind(this)});
\r
79 processResponse: function(request) {
\r
80 var response = request.responseXML.getElementsByTagName("ajax-response");
\r
81 if (response == null || response.length != 1) return;
\r
82 var rowsElement = response[0].getElementsByTagName('rows')[0];
\r
83 var trs = rowsElement.getElementsByTagName("tr");
\r
84 //alert('processResponse: '+trs.length);
\r
85 for ( var i=0 ; i < trs.length; i++ ) {
\r
86 var cells = trs[i].getElementsByTagName("td");
\r
87 if (cells.length != 5) continue;
\r
88 // cells[0]=parent node id
\r
90 // cells[2]=description
\r
91 // cells[3]=L/zero (leaf), C/non-zero (container)
\r
92 // cells[4]= 0->not selectable, 1->selectable (use default action), otherwise the node is selectable and cells[4] contains the action
\r
94 for (var j=0; j<cells.length; j++)
\r
95 content[j]=this.getContent(cells[j]);
\r
96 //content[j]=RicoUtil.getContentAsString(cells[j]);
\r
97 var node=this.addNode(content[3],content[1],content[2],content[4]);
\r
98 if (this.foldersTree==0) {
\r
99 this.foldersTree = node;
\r
103 var parentNode=this.nodeIndex[content[0]]
\r
104 if (typeof parentNode=='undefined')
\r
105 alert('ERROR!\nReceived invalid response from server - could not find parent in existing tree:\n'+content[0]);
\r
107 parentNode.push(node);
\r
110 if (this.nodeCount==1 && node[2])
\r
111 this.loadXMLDoc(node[3]);
\r
116 getContent: function(cell) {
\r
117 if (cell.innerHTML) return cell.innerHTML;
\r
118 switch (cell.childNodes.length) {
\r
120 case 1: return cell.firstChild.nodeValue;
\r
121 default: return cell.childNodes[1].nodeValue;
\r
126 // NodeType is "C" or non-zero (container), or "L" or zero (leaf)
\r
127 // id is the unique identifier for the node
\r
128 // desc is the text displayed to the user
\r
129 addNode: function(NodeType,id,desc,selectable) {
\r
131 //alert("addNode: " + desc + " (" + selectable + ")")
\r
132 arrayAux = new Array
\r
135 arrayAux[2] = (NodeType=='0' || NodeType.toUpperCase()=='L' ? 0 : 1)
\r
138 arrayAux[5] = parseInt(selectable);
\r
139 this.nodeIndex[id]=arrayAux
\r
145 RemoveAllChildren: function(obj) {
\r
146 while (obj.hasChildNodes()) {
\r
147 this.RemoveAllChildren(obj.childNodes[0])
\r
148 obj.removeChild(obj.childNodes[0])
\r
152 redrawTree: function() {
\r
153 //alert('redrawTree');
\r
154 this.RemoveAllChildren(this.treeDiv)
\r
155 this.redrawNode(this.foldersTree, 0, 1, [])
\r
158 DisplayImages: function(row,arNames) {
\r
160 for(i=0;i<arNames.length;i++) {
\r
161 img = document.createElement("img")
\r
162 img.src=Rico.imgDir+arNames[i] + ".gif"
\r
163 td=row.insertCell(-1)
\r
164 td.appendChild(img)
\r
168 redrawNode: function(foldersNode, level, lastNode, leftSide) {
\r
170 //alert("redrawNode at level " + level + " (" + foldersNode[3] + ")")
\r
172 tab = document.createElement("table")
\r
176 row=tab.insertRow(0)
\r
177 this.DisplayImages(row,leftSide)
\r
178 var newLeft=leftSide.slice(0);
\r
180 var suffix=lastNode ? 'last' : '';
\r
181 if (this.options.showPlusMinus && foldersNode[2])
\r
182 this.showPlusMinus(row.insertCell(-1),foldersNode,suffix);
\r
184 this.NodeImage(row.insertCell(-1),suffix)
\r
185 newLeft.push(lastNode ? "nodeblank" : "nodeline")
\r
187 if (this.options.showFolders)
\r
188 this.showFolders(row.insertCell(-1),foldersNode);
\r
189 if (this.options.showCheckBox && foldersNode[5])
\r
190 this.showCheckBox(row.insertCell(-1),foldersNode);
\r
191 this.displayLabel(row,foldersNode)
\r
192 this.treeDiv.appendChild(tab)
\r
194 if (foldersNode.length > this.FirstChildNode && foldersNode[0]) {
\r
195 //there are sub-nodes and the folder is open
\r
196 for (var i=this.FirstChildNode; i<foldersNode.length;i++)
\r
197 this.redrawNode(foldersNode[i], level+1, (i==foldersNode.length-1 ? 1 : 0), newLeft)
\r
201 NodeImage: function(td, suffix) {
\r
203 img = document.createElement("img")
\r
204 img.src=Rico.imgDir+"node"+suffix+".gif"
\r
205 td.appendChild(img)
\r
209 showPlusMinus: function(td,foldersNode,suffix) {
\r
210 var img = document.createElement("img")
\r
211 img.name=foldersNode[3];
\r
212 img.style.cursor='pointer';
\r
213 if (foldersNode.length > this.FirstChildNode)
\r
214 img.onclick=this.openBranch.bindAsEventListener(this);
\r
216 img.onclick=this.getChildren.bindAsEventListener(this);
\r
217 var prefix=foldersNode[1] ? "nodem" : "nodep"
\r
218 img.src=Rico.imgDir+prefix+suffix+".gif";
\r
219 td.appendChild(img)
\r
222 showFolders: function(td,foldersNode) {
\r
223 var img = document.createElement("img")
\r
224 if (!foldersNode[2]) {
\r
225 img.src=this.options.leafIcon;
\r
227 img.name=foldersNode[3];
\r
228 img.style.cursor='pointer';
\r
229 if (foldersNode.length > this.FirstChildNode)
\r
230 img.onclick=this.openBranch.bindAsEventListener(this);
\r
232 img.onclick=this.getChildren.bindAsEventListener(this);
\r
233 img.src=Rico.imgDir+(foldersNode[1] ? "folderopen.gif" : "folderclosed.gif");
\r
235 td.appendChild(img)
\r
238 showCheckBox: function(td,foldersNode) {
\r
239 var inp=document.createElement("input")
\r
240 inp.type="checkbox"
\r
241 inp.name=foldersNode[3]
\r
242 td.appendChild(inp)
\r
245 displayLabel: function(row,foldersNode) {
\r
246 if (foldersNode[5]) {
\r
247 var span=document.createElement('a');
\r
249 span.onclick=this.options.defaultAction;
\r
251 var span=document.createElement('p');
\r
253 span.id=this.id+"__"+foldersNode[3];
\r
254 var desc=foldersNode[4];
\r
255 switch (this.options.nodeIdDisplay) {
\r
256 case 'last': desc+=' ('+foldersNode[3]+')'; break;
\r
257 case 'first': desc=foldersNode[3]+' - '+desc; break;
\r
258 case 'tooltip': span.title=foldersNode[3]; break;
\r
260 span.appendChild(document.createTextNode(desc))
\r
261 var td=row.insertCell(-1)
\r
262 td.appendChild(span)
\r
265 //when a parent is closed all children also are
\r
266 closeFolders: function(foldersNode) {
\r
268 if (foldersNode[2]) {
\r
269 for (i=this.FirstChildNode; i< foldersNode.length; i++)
\r
270 this.closeFolders(foldersNode[i])
\r
276 nodeClick: function(e) {
\r
277 var node=Event.element(e);
\r
278 if (this.returnValue) {
\r
280 var i=v.indexOf('__');
\r
281 if (i>=0) v=v.substr(i+2);
\r
282 this.returnValue(v,node.innerHTML);
\r
287 //recurse over the tree structure
\r
288 //called by openbranch
\r
289 clickOnFolderRec: function(foldersNode, folderName) {
\r
291 if (foldersNode[3] == folderName) {
\r
292 if (foldersNode[0]) {
\r
293 this.closeFolders(foldersNode)
\r
298 } else if (foldersNode[2]) {
\r
299 for (i=this.FirstChildNode; i< foldersNode.length; i++)
\r
300 this.clickOnFolderRec(foldersNode[i], folderName)
\r
304 openBranch: function(e) {
\r
305 var node=Event.element(e);
\r
306 this.clickOnFolderRec(this.foldersTree, node.name)
\r
307 this.timeOutId = setTimeout(this.redrawTree.bind(this),100)
\r
310 getChildren: function(e) {
\r
311 var node=Event.element(e);
\r
312 this.loadXMLDoc(node.name)
\r
318 Rico.includeLoaded('ricoTree.js');