Revert "serv_rssclient.c: style update"
[citadel.git] / webcit / static / nanotree.js
1 /**\r
2 * Original Author of this file: Martin Mouritzen. (martin@nano.dk)\r
3 *\r
4 *\r
5 * (Lack of) Documentation:\r
6 *\r
7 *\r
8 * If a finishedLoading method exists, it will be called when the tree is loaded.\r
9 * (good to display a div, etc.).\r
10 *\r
11 *\r
12 * You have to set the variable rootNode (as a TreeNode).\r
13 *\r
14 * You have to set a container element, this is the element in which the tree will be.\r
15 *\r
16 *\r
17 * TODO: \r
18 * Save cookies better (only 1 cookie for each tree). Else the page will totally cookieclutter.\r
19 *\r
20 ***********************************************************************\r
21 * Configuration variables.\r
22 ************************************************************************/\r
23 \r
24 // Should the rootNode be displayed.\r
25 var showRootNode = true;\r
26 \r
27 // Should the dashed lines between nodes be shown.\r
28 var showLines = true;\r
29 \r
30 // Should the nodes be sorted? (You can either specify a number, then it will be sorted by that, else it will\r
31 // be sorted alphabetically (by name).\r
32 var sortNodes = true;\r
33 \r
34 // This is IMPORTANT... use an unique id for each document you use the tree in. (else they'll get mixed up).\r
35 var documentID = window.location.href;\r
36 \r
37 // being read from cookie.\r
38 var nodesOpen = new Array();\r
39 \r
40 // RootNode of the tree.\r
41 var rootNode;\r
42 \r
43 // Container to display the Tree in.\r
44 var container;\r
45 \r
46 // Shows/Hides subnodes on startup\r
47 var showAllNodesOnStartup = false;\r
48 \r
49 // Is the roots dragable?\r
50 var dragable = false;\r
51 \r
52 \r
53 /************************************************************************\r
54 * The following is just instancevariables.\r
55 ************************************************************************/\r
56 var href = '';\r
57 \r
58 // rootNodeCallBack name (if null, it's not selectable).\r
59 var rootNodeCallBack = null;\r
60 \r
61 // selectedNode\r
62 var selectedNode = null;\r
63 \r
64 var states = '';\r
65 var statearray = new Array();\r
66 \r
67 var treeNodeEdited = null;\r
68 \r
69 var editaborted = false;\r
70 \r
71 var floatDragElement = null;\r
72 var colouredElement = null;\r
73 var draggedNodeID = null;\r
74 var lastDraggedOnNodeID = null;\r
75 \r
76 \r
77 /**\r
78 * The TreeNode Object\r
79 * @param id unique id of this treenode\r
80 * @param name The title of this node\r
81 * @param icon The icon if this node (Can also be an array with 2 elements, the first one will represent the closed state, and the next one the open state)\r
82 * @param param A parameter, this can be pretty much anything. (eg. an array with information).\r
83 * @param orderNumber an orderNumber If one is given the nodes will be sorted by this (else they'll be sorted alphabetically (If sorting is on).\r
84 */\r
85 function TreeNode(id,name,icon,param,orderNumber) {\r
86         this.id = id;\r
87         this.childs = new Array();\r
88         this.name = (name == null ? 'unset name' : name);\r
89         this.icon = (icon == null ? '' : icon);\r
90         this.parent = null;\r
91         this.handler = null;\r
92         this.param = (param == null ? '' : param);\r
93         this.orderNumber = (orderNumber == null ? -1 : orderNumber);\r
94         \r
95         this.openeventlisteners = new Array();\r
96         this.editeventlisteners = new Array();\r
97         this.moveeventlisteners = new Array();\r
98         this.haschilds = false;\r
99         this.editable = false;\r
100         this.linestring = '';\r
101         \r
102         this.nextSibling = null;\r
103         this.prevSibling = null;\r
104         \r
105         this.childsHasBeenFetched = false;\r
106 \r
107         this.getID = function() {\r
108                 return this.id;\r
109         }\r
110         this.setName = function(newname) {\r
111                 this.name = newname;\r
112         }\r
113         this.getName = function() {\r
114                 return this.name;\r
115         }\r
116         this.getParam = function() {\r
117                 return this.param;\r
118         }\r
119         this.setIcon = function(icon) {\r
120                 this.icon = icon;\r
121         }\r
122         this.getIcon = function() {\r
123                 if (typeof(this.icon) == 'object') {\r
124                         return this.icon[0];\r
125                 }\r
126                 return this.icon;\r
127         }\r
128         this.getOpenIcon = function() {\r
129                 if (typeof(this.icon) == 'object') {\r
130                         return this.icon[1];\r
131                 }\r
132                 return this.icon;\r
133         }\r
134         this.hasIcon = function () {\r
135                 return this.icon != '';\r
136         }\r
137         this.getOrderNumber = function() {\r
138                 return this.orderNumber;\r
139         }\r
140         this.addOpenEventListener = function(event) {\r
141                 this.openeventlisteners[this.openeventlisteners.length] = event;\r
142         }\r
143         this.gotOpenEventListeners = function() {\r
144                 return (this.openeventlisteners.length > 0);\r
145         }\r
146         this.addEditEventListener = function(event) {\r
147                 this.editeventlisteners[this.editeventlisteners.length] = event;\r
148         }\r
149         this.gotEditEventListeners = function() {\r
150                 return (this.editeventlisteners.length > 0);\r
151         }\r
152         this.addMoveEventListener = function(event) {\r
153                 this.moveeventlisteners[this.moveeventlisteners.length] = event;\r
154         }\r
155         this.gotMoveEventListeners = function() {\r
156                 return (this.moveeventlisteners.length > 0);\r
157         }\r
158         this.addChild = function(childNode) {\r
159                 var possiblePrevNode = this.childs[this.childs.length - 1]\r
160                 if (possiblePrevNode) {\r
161                         possiblePrevNode.nextSibling = childNode;\r
162                         childNode.prevSibling = possiblePrevNode;\r
163                         // alert(childNode.prevSibling);\r
164                 }\r
165 \r
166                 this.childs[this.childs.length] = childNode;\r
167                 childNode.setParent(this);\r
168 \r
169                 if (sortNodes) {\r
170                         function sortByOrder(a,b) {\r
171                                 var order1 = a.getOrderNumber();\r
172                                 var order2 = b.getOrderNumber();\r
173                                 if (order1 == -1 || order2 == -1) {\r
174                                         return a.getName().toLowerCase() > b.getName().toLowerCase() ? 1 : -1;\r
175                                 }\r
176                                 else {\r
177                                         if (order1 == order2) {\r
178                                                 // If they got the same order number, then we'll sort by their title.\r
179                                                 return a.getName().toLowerCase() > b.getName().toLowerCase() ? 1 : -1;\r
180                                         }\r
181                                         else {\r
182                                                 return order1 - order2;\r
183                                         }\r
184                                 }\r
185                         }\r
186                         this.childs.sort(sortByOrder);\r
187                 }\r
188         }\r
189         this.removeChild = function(childNode) {\r
190                 var found = false;\r
191                 for (var i=0;i<this.childs.length;i++) {\r
192                         if (found) {\r
193                                 this.childs[i] = this.childs[i + 1];\r
194                         }\r
195                         if (this.childs[i] == childNode) {\r
196                                 if (i == (this.childs.length - 1)) {\r
197                                         this.childs[i] = null;\r
198                                 }\r
199                                 else {\r
200                                         this.childs[i] = this.childs[i + 1];\r
201                                 }\r
202                                 found = true;\r
203                         }\r
204                 }\r
205                 if (found) {\r
206                         this.childs.length = this.childs.length-1;\r
207                 }\r
208         }\r
209         this.resetChilds = function() {\r
210                 this.childs = new Array();\r
211         }\r
212         this.setHasChilds = function(hasChilds) {\r
213                 this.haschilds = hasChilds;\r
214         }\r
215         this.hasChilds = function() {\r
216                 if (this.haschilds == true) {\r
217                         return true;\r
218                 }\r
219                 return (this.childs.length > 0);\r
220         }\r
221         this.getChildCount = function() {\r
222                 return this.childs.length;\r
223         }\r
224         this.getFirstChild = function() {\r
225                 if (this.hasChilds()) {\r
226                         return this.childs[0];\r
227                 }\r
228                 return null;\r
229         }\r
230         this.gotHandler = function() {\r
231                 return this.handler != null;\r
232         }\r
233         this.setHandler = function(handler) {\r
234                 this.handler = handler;\r
235         }\r
236         this.getHandler = function() {\r
237                 return this.handler;\r
238         }\r
239         this.setParent = function(parent) {\r
240                 this.parent = parent;\r
241         }\r
242         this.getParent = function() {\r
243                 return this.parent;\r
244         }\r
245         this.getLineString = function() {\r
246                 return this.linestring;\r
247         }\r
248         this.setLineString = function(string) {\r
249                 this.linestring = string;\r
250         }\r
251         this.isEditable = function() {\r
252                 return this.editable;\r
253         }\r
254         this.setEditable = function(editable) {\r
255                 this.editable = editable;\r
256         }\r
257         \r
258 }\r
259 function getTreeNode(nodeID) {\r
260         return findNodeWithID(rootNode,nodeID);\r
261 }\r
262 function findNodeWithID(node,nodeID) {\r
263         if (node.getID() == nodeID) {\r
264                 return node;\r
265         }\r
266         else {\r
267                 if (node.hasChilds()) {\r
268                         for(var i=0;i<node.getChildCount();i++) {\r
269                                 var value = findNodeWithID(node.childs[i],nodeID);\r
270                                 if (value != false) {\r
271                                         return value;\r
272                                 }\r
273                         }\r
274                 }\r
275                 return false;\r
276         }\r
277 }\r
278 function readStates() {\r
279         //setCookie('tree' + documentID,'');\r
280         states = getCookie('tree' + documentID);\r
281         if (states != null) {\r
282                 var array = states.split(';');\r
283                 for(var i=0;i<array.length;i++) {\r
284                         var singlestate = array[i].split('|');\r
285                         statearray[i] = new Array();\r
286                         statearray[i]["key"] = singlestate[0];\r
287                         statearray[i]["state"]  = singlestate[1];\r
288                 }\r
289         }\r
290 }\r
291 function getState(nodeID) {\r
292         for(var i=0;i<statearray.length;i++) {\r
293                 if (statearray[i]["key"] == nodeID) {\r
294                         state = statearray[i]["state"];\r
295                         if (state == null || state == '') {\r
296                                 state = 'closed';\r
297                         }\r
298                         return state;\r
299                 }\r
300         }\r
301         return "closed";\r
302 }\r
303 function writeStates(nodeID,newstate) {\r
304         //alert(nodeID);\r
305         var str = '';\r
306         var found = false;\r
307         for(var i=0;i<statearray.length;i++) {\r
308                 if (statearray[i]["key"] == nodeID) {\r
309                         statearray[i]["state"] = newstate;\r
310                         found = true;\r
311                 }\r
312                 if (statearray[i]["state"] != null) {\r
313                         str += statearray[i]["key"] + '|' + statearray[i]["state"] + ';';\r
314                 }\r
315         }\r
316         if (found == false) {\r
317                 statearray[statearray.length] = new Array();\r
318                 statearray[statearray.length - 1]["key"] = nodeID;\r
319                 statearray[statearray.length - 1]["state"] = newstate;\r
320                 if (newstate != null) {\r
321                         str += nodeID + '|' + newstate + ';';\r
322                 }\r
323         }\r
324         setCookie('tree' + documentID,str);\r
325 }\r
326 function showTree(path) {\r
327         readStates();\r
328         \r
329         href = path;\r
330         window.focus();\r
331         window.onblur = blurSelection;\r
332         window.onfocus = focusSelection;\r
333         var str = '';\r
334         str = '<div id="node' + rootNode.getID() + '" class="treetitle" style="display:' + (showRootNode == true ? 'block' : 'none') + '">';\r
335         str += '<nobr>';\r
336         if (rootNode.hasIcon()) {\r
337                 str += '<img src="' + rootNode.getIcon() + '" style="vertical-align:middle;">';\r
338         }\r
339         str += '<span style="vertical-align:middle;">&nbsp;' + rootNode.getName() + '</span>';\r
340         str += '</nobr></div>';\r
341         \r
342         if (rootNode.hasChilds()) {\r
343                 for(i=0;i<rootNode.childs.length;i++) {\r
344                         nodeContents = showNode(rootNode.childs[i],(i == (rootNode.getChildCount() -1)));\r
345                         str = str + nodeContents;\r
346                 }\r
347         }\r
348         container.innerHTML = str;\r
349         if (window.finishedLoading) {\r
350                 finishedLoading();\r
351         }\r
352 }\r
353 /**\r
354 * Shows the given node, and subnodes.\r
355 */\r
356 function showNode(treeNode,lastNode) {\r
357         linestring = treeNode.getLineString();\r
358         var state = getState(treeNode.getID());\r
359         var str;\r
360         str = '<div style="filter:alpha(opacity=100);" ondragenter="dragEnter(' + treeNode.getID() + ');" ondragleave="dragLeave();" ondragstart="startDrag(' + treeNode.getID() + ');" ondrag="dragMove();" ondragend="endDrag(' + treeNode.getID() + ')" id="node' + treeNode.getID() + '">';\r
361         str += '<nobr>';\r
362         for(var y=0;y<linestring.length;y++) {\r
363                 if (linestring.charAt(y) == 'I') {\r
364                         str += '<img src="' + href + 'static/' + (showLines ? 'line' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';\r
365                 }\r
366                 else if (linestring.charAt(y) == 'B') {\r
367                         str += '<img src="' + href + 'static/white.gif" style="width:19px;height:20px;vertical-align:middle;">';\r
368                 }\r
369         }\r
370         if (treeNode.hasChilds()) {\r
371                 // If this is the first child of the rootNode, and showRootNode is false, we want to display a different icon.\r
372                 if (!showRootNode && (treeNode.getParent() == rootNode) && (treeNode.getParent().getFirstChild() == treeNode)) {\r
373                         if (!lastNode) {\r
374                                 str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/' + (state == 'open' ? (showLines ? 'minus_no_root' : 'minus_nolines') : (showLines ? 'plus_no_root' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';\r
375                         }\r
376                         else {\r
377                                 str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/' + (state == 'open' ? 'minus_last' : 'plus_last') + '_no_root.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';\r
378                         }\r
379                 }\r
380                 else {\r
381                         if (!lastNode) {\r
382                                 str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/' + (state == 'open' ? (showLines ? 'minus' : 'minus_nolines') : (showLines ? 'plus' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';\r
383                         }\r
384                         else {\r
385                                 str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/' + (state == 'open' ? (showLines ? 'minus_last' : 'minus_nolines') : (showLines ? 'plus_last' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';\r
386                         }\r
387                 }\r
388         }\r
389         else {\r
390                 // If this is the first child of the rootNode, and showRootNode is false, we want to display a different icon.\r
391                 if (!showRootNode && (treeNode.getParent() == rootNode) && (treeNode.getParent().getFirstChild() == treeNode)) {\r
392                         if (!lastNode) {\r
393                                 str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/' + (showLines ? 't_no_root' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';\r
394                         }\r
395                         else {\r
396                                 str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/white.gif" style="width:19px;height:20px;vertical-align:middle;">';\r
397                         }\r
398                 }\r
399                 else {\r
400                         if (!lastNode) {\r
401                                 str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/' + (showLines ? 't' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';\r
402                         }\r
403                         else {\r
404                                 str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/' + (showLines ? 'lastnode' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';\r
405                         }\r
406                 }\r
407         }\r
408         iconStartImage = treeNode.getIcon();\r
409         if (state != 'closed') {\r
410                 if (treeNode.hasChilds()) {\r
411                         iconStartImage = treeNode.getOpenIcon();\r
412                 }\r
413         }\r
414         \r
415         str += '<img id="iconimage' + treeNode.getID() + '" src="' + iconStartImage + '" style="vertical-align:middle;" OnClick="selectNode(' + treeNode.getID() + ')">';\r
416         str += '&nbsp;<span unselectable="ON" style="vertical-align:middle;" class="treetitle" ID="title' + treeNode.getID() + '" OnDblClick="handleNode(' + treeNode.getID() + ')" OnClick="selectNode(' + treeNode.getID() + ')">';\r
417         str += treeNode.getName();\r
418         str += '</span>';\r
419         str += '</nobr>';\r
420         str += '</div>';\r
421 \r
422         if (treeNode.hasChilds()) {\r
423                 if (state == 'open') {\r
424                         str += '<div id="node' + treeNode.getID() + 'sub" style="display:block;">';\r
425                         fireOpenEvent(treeNode);\r
426                         // alert('openevent: ' + treeNode.getName());\r
427                 }\r
428                 else {\r
429                         str += '<div id="node' + treeNode.getID() + 'sub" style="display:' + (showAllNodesOnStartup == true ? 'block;' : 'none;') + ';">';\r
430                 }\r
431                 var subgroupstr = '';\r
432                 var newChar = '';\r
433 \r
434                 if (!lastNode) {\r
435                         newChar = 'I';\r
436                 }\r
437                 else {\r
438                         newChar = 'B';\r
439                 }\r
440                 for(var z=0;z<treeNode.getChildCount();z++) {\r
441                         treeNode.childs[z].setLineString(linestring + newChar);\r
442                 }\r
443                 for(var z=0;z<treeNode.getChildCount();z++) {\r
444                         subgroupstr += showNode(treeNode.childs[z],(z == (treeNode.getChildCount() -1)));\r
445                 }\r
446                 str += subgroupstr;\r
447                 str += '</div>';\r
448         }\r
449         else {\r
450                 str += '<div id="node' + treeNode.getID() + 'sub" style="display:none;">';\r
451                 str += '</div>';\r
452         }\r
453         return str;\r
454 }\r
455 /*\r
456 function mouseMove() {\r
457         if (dragging) {\r
458                 alert('bob');\r
459         }\r
460 }\r
461 function mouseUp() {\r
462         if (dragging) {\r
463                 alert('dropped on something!');\r
464         }\r
465 }\r
466 */\r
467 function startDrag(nodeID) {\r
468         if (!dragable) {\r
469                 return;\r
470         }\r
471         draggedNodeID = nodeID;\r
472         \r
473         var srcObj = window.event.srcElement;\r
474         while(srcObj.tagName != 'DIV') {\r
475                 srcObj = srcObj.parentElement;\r
476         }\r
477         floatDragElement = document.createElement('DIV');\r
478 \r
479         floatDragElement.innerHTML = srcObj.innerHTML;\r
480         floatDragElement.childNodes[0].removeChild(floatDragElement.childNodes[0].childNodes[0]);\r
481         \r
482         document.body.appendChild(floatDragElement);\r
483         floatDragElement.style.zIndex = 100;\r
484         floatDragElement.style.position = 'absolute';\r
485         floatDragElement.style.filter='progid:DXImageTransform.Microsoft.Alpha(1,opacity=60);';\r
486 }\r
487 function findSpanChild(element) {\r
488         if (element.tagName == 'SPAN') {\r
489                 return element;\r
490         }\r
491         else {\r
492                 if (element.childNodes) {\r
493                         for(var i=0;i<element.childNodes.length;i++) {\r
494                                 var value = findSpanChild(element.childNodes[i]);\r
495                                 if (value != false) {\r
496                                         return value;\r
497                                 }\r
498                         }\r
499                         return false;\r
500                 }\r
501         }\r
502 }\r
503 function dragEnter(nodeID) {\r
504         if (!dragable) {\r
505                 return;\r
506         }\r
507         lastDraggedOnNodeID = nodeID;\r
508         \r
509         if (colouredElement) {\r
510                 findSpanChild(colouredElement).className = 'treetitle';\r
511         }\r
512         colouredElement = window.event.srcElement;\r
513         while(colouredElement.tagName != 'DIV') {\r
514                 colouredElement = colouredElement.parentElement;\r
515                 if (colouredElement.tagName == 'BODY') {\r
516                         // Something gone seriously wrong.\r
517                         alert('Drag failure, reached <BODY>!');\r
518                         return;\r
519                 }\r
520         }       \r
521         findSpanChild(colouredElement).className = 'treetitleselectedfocused';\r
522 }\r
523 function dragLeave() {\r
524         if (!dragable) {\r
525                 return;\r
526         }\r
527 }\r
528 function endDrag(nodeID) {\r
529         if (!dragable) {\r
530                 return;\r
531         }\r
532         if (lastDraggedOnNodeID != null) {\r
533                 fireMoveEvent(getTreeNode(lastDraggedOnNodeID),draggedNodeID,lastDraggedOnNodeID);\r
534         }\r
535 }\r
536 function dragProceed() {\r
537         if (!dragable) {\r
538                 return;\r
539         }\r
540         var dragged = getTreeNode(draggedNodeID);\r
541         var newparent = getTreeNode(lastDraggedOnNodeID);\r
542 \r
543         var oldparent = dragged.getParent();\r
544         \r
545         oldparent.removeChild(dragged);\r
546         newparent.addChild(dragged);\r
547         \r
548         refreshNode(oldparent);\r
549         refreshNode(newparent);\r
550         \r
551         _dragClean()\r
552 }\r
553 function dragCancel() {\r
554         if (!dragable) {\r
555                 return;\r
556         }\r
557         _dragClean()\r
558 }\r
559 /**\r
560 * Don't call this yourself.\r
561 */\r
562 function _dragClean() {\r
563         if (!dragable) {\r
564                 return;\r
565         }\r
566         if (colouredElement) {\r
567                 findSpanChild(colouredElement).className = 'treetitle';\r
568         }\r
569         \r
570         floatDragElement.parentElement.removeChild(floatDragElement);\r
571         floatDragElement = null;\r
572         colouredElement = null;\r
573         draggedNodeID = null;\r
574         lastDraggedOnNodeID = null;\r
575 }\r
576 function dragMove() {\r
577         if (!dragable) {\r
578                 return;\r
579         }\r
580         floatDragElement.style.top = window.event.clientY;\r
581         floatDragElement.style.left = window.event.clientX;\r
582 }\r
583 function editEnded() {\r
584         if (treeNodeEdited != null) {\r
585                 // treeNodeEdited.getID();\r
586                 var editTitle = document.getElementById('title' + treeNodeEdited.getID());\r
587                 var input = editTitle.childNodes[0];\r
588         \r
589                 var newValue = input.value;\r
590                 \r
591                 if (newValue == treeNodeEdited.getName()) {\r
592                         editTitle.innerHTML = newValue;\r
593                         treeNodeEdited = null;\r
594                         return;\r
595                 }\r
596         \r
597                 fireEditEvent(treeNodeEdited,newValue);\r
598                 \r
599                 if (!editaborted) {\r
600                         treeNodeEdited.setName(newValue);\r
601                         editTitle.innerHTML = newValue;\r
602                 }\r
603         \r
604                 treeNodeEdited = null;\r
605         }\r
606 }\r
607 function selectNode(nodeID) {\r
608         var treeNode = getTreeNode(nodeID);\r
609 \r
610         if (selectedNode != null) {\r
611                 if (selectedNode == nodeID) {\r
612                         if (treeNode.isEditable()) {\r
613                                 if (treeNodeEdited == treeNode) {\r
614                                         return;\r
615                                 }\r
616                                 treeNodeEdited = treeNode;\r
617                                 var editTitle = document.getElementById('title' + treeNode.getID());\r
618                                 editTitle.className = 'editednode';\r
619                                 \r
620 \r
621                                 editTitle.innerHTML = '<input type="text" onKeypress="if (event.keyCode == 13) { this.onblur = null; editEnded(); }" name="editednode" class="editednodeinput">';\r
622                                 var input = editTitle.childNodes[0];\r
623                                 input.value = treeNode.getName();\r
624                                 input.focus();\r
625                                 input.select();\r
626                                 input.onblur = editEnded;\r
627                         }\r
628                         return;\r
629                 }\r
630                 if (treeNodeEdited != null) {\r
631                         editEnded();\r
632                 }\r
633                 var oldNodeTitle = document.getElementById('title' + selectedNode);\r
634                 oldNodeTitle.className = 'treetitle';\r
635         }\r
636         selectedNode = nodeID;\r
637         var nodetitle = document.getElementById('title' + selectedNode);\r
638         nodetitle.className = 'treetitleselectedfocused';\r
639         \r
640         if (treeNode.gotHandler()) {\r
641                 eval(treeNode.getHandler() + '(getTreeNode(' + nodeID + '));');\r
642         }\r
643         else {\r
644                 standardClick(treeNode);\r
645         }\r
646 }\r
647 function refreshNode(treeNode) {\r
648         var submenu = document.getElementById('node' + treeNode.getID() + 'sub');\r
649         var str = '';\r
650         for(var i=0;i<treeNode.getChildCount();i++) {\r
651                 var parent = treeNode.getParent();\r
652                 if (!parent) {\r
653                         treeNode.childs[i].setLineString(treeNode.getLineString() + 'B');\r
654                 }\r
655                 else {\r
656                         if (parent.childs[parent.childs.length - 1] == treeNode) {\r
657                                 treeNode.childs[i].setLineString(treeNode.getLineString() + 'B');\r
658                         }\r
659                         else {\r
660                                 treeNode.childs[i].setLineString(treeNode.getLineString() + 'I');\r
661                         }\r
662                 }\r
663                 str += showNode(treeNode.childs[i],i == (treeNode.getChildCount() - 1));\r
664         }\r
665         var actionimage = document.getElementById('handler' + treeNode.getID());\r
666         if (treeNode.getChildCount() == 0) {\r
667                 // TreeNode haven't got any children, make sure the right image is displayed.\r
668                 if (actionimage.src.indexOf('last') == -1) {\r
669                         actionimage.src = href + 'static/' + (showLines ? 't' : 'white') + '.gif';\r
670                 }\r
671                 else {\r
672                         actionimage.src = href + 'static/' + (showLines ? 'lastnode' : 'white') + '.gif';\r
673                 }\r
674                 actionimage.onclick = null;\r
675                 \r
676                 // Close the submenu\r
677                 if (submenu) {\r
678                         submenu.style.display = 'none';\r
679                 }\r
680         }\r
681         else {\r
682                 // We have children, make sure to display the + and - icon.\r
683                 if (actionimage.src.indexOf('plus') != -1) {\r
684                         // The TreeNode have already got children, and displays them.\r
685                 }\r
686                 else if (actionimage.src.indexOf('minus') != -1) {\r
687                         // The TreeNode have already got children, and displays them.\r
688                 }\r
689                 else {\r
690                         if (actionimage.src.indexOf('last') == -1) {\r
691                                 actionimage.outerHTML = '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/' + (showLines ? 'plus' : 'plus_nolines') + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';\r
692                         }\r
693                         else {\r
694                                 actionimage.outerHTML = '<img id="handler' + treeNode.getID() + '" src="' + href + 'static/plus_last.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(' + treeNode.getID() + ');">';\r
695                         }\r
696                 }\r
697         }\r
698         submenu.innerHTML = str;\r
699 }\r
700 function handleNode(nodeID) {\r
701         var treeNode = getTreeNode(nodeID);     \r
702         if (!treeNode.hasChilds()) { // No reason to handle a node without childs.\r
703                 return;\r
704         }\r
705         \r
706         var submenu = document.getElementById('node' + nodeID + 'sub');\r
707         \r
708         var iconimageholder = document.getElementById('iconimage' + nodeID);\r
709         var actionimage = document.getElementById('handler' + nodeID);\r
710 \r
711         // This will be used if showRootNode is set to false.\r
712         var firstChildOfRoot = false;\r
713         if (actionimage.src.indexOf('_no_root') != -1) {\r
714                 firstChildOfRoot = true;\r
715         }\r
716         \r
717         if (submenu.style.display == 'none') {\r
718                 writeStates(nodeID,'open');\r
719                 fireOpenEvent(treeNode);\r
720                 submenu.style.display = 'block';\r
721 \r
722                 iconimageholder.src = treeNode.getOpenIcon();\r
723         \r
724                 if (actionimage.src.indexOf('last') == -1) {\r
725                         actionimage.src = href + 'static/' + ((firstChildOfRoot) ? 'minus_no_root' : (showLines ? 'minus' : 'minus_nolines')) + '.gif';\r
726                 }\r
727                 else {\r
728                         actionimage.src = href + 'static/' + ((firstChildOfRoot) ? 'minus_last_no_root' : (showLines ? 'minus_last' : 'minus_nolines')) + '.gif';\r
729                 }\r
730         }\r
731         else {\r
732                 writeStates(nodeID,'closed');\r
733                 submenu.style.display = 'none';\r
734                 \r
735                 iconimageholder.src = treeNode.getIcon();\r
736                 \r
737                 if (actionimage.src.indexOf('last') == -1) {\r
738                         actionimage.src = href + 'static/' + ((firstChildOfRoot) ? 'plus_no_root' : (showLines ? 'plus' : 'plus_nolines')) + '.gif';\r
739                 }\r
740                 else {\r
741                         actionimage.src = href + 'static/' + ((firstChildOfRoot) ? 'plus_last_no_root' : (showLines ? 'plus_last' : 'plus_nolines')) + '.gif';\r
742                 }\r
743         }\r
744 }\r
745 function fireOpenEvent(treeNode) {\r
746         if (treeNode.gotOpenEventListeners()) {\r
747                 for(var i=0;i<treeNode.openeventlisteners.length;i++) {\r
748                         eval(treeNode.openeventlisteners[i] + '(' + treeNode.getID() + ');');\r
749                 }\r
750         }\r
751 }\r
752 function fireEditEvent(treeNode,newVal) {\r
753         if (treeNode.gotEditEventListeners()) {\r
754                 for(var i=0;i<treeNode.editeventlisteners.length;i++) {\r
755                         eval(treeNode.editeventlisteners[i] + '(' + treeNode.getID() + ',\'' + escape(newVal) + '\');');\r
756                 }\r
757         }\r
758 }\r
759 function fireMoveEvent(treeNode,draggedNodeID,droppedOnNodeID) {\r
760         if (treeNode.gotMoveEventListeners()) {\r
761                 for(var i=0;i<treeNode.moveeventlisteners.length;i++) {\r
762                         eval(treeNode.moveeventlisteners[i] + '(' + draggedNodeID + ',' + droppedOnNodeID + ');');\r
763                 }\r
764         }\r
765 }\r
766 function blurSelection() {\r
767         if (selectedNode != null) {\r
768                 var oldNodeTitle = document.getElementById('title' + selectedNode);\r
769                 oldNodeTitle.className = 'treetitleselectedblured';\r
770         }\r
771 }\r
772 function focusSelection() {\r
773         if (selectedNode != null) {\r
774                 var oldNodeTitle = document.getElementById('title' + selectedNode);\r
775                 oldNodeTitle.className = 'treetitleselectedfocused';\r
776         }\r
777 }\r
778 function getCookieVal (offset) {  \r
779         var endstr = document.cookie.indexOf (";",offset);  \r
780         if (endstr == -1) {\r
781                 endstr = document.cookie.length;\r
782         }\r
783         return unescape(document.cookie.substring(offset,endstr));\r
784 }\r
785 function getCookie (name) {  \r
786         var arg = name + "=";\r
787         var alen = arg.length;\r
788         var clen = document.cookie.length;\r
789         var i = 0;\r
790         while (i < clen) {\r
791                 var j = i + alen;\r
792                 if (document.cookie.substring(i, j) == arg) {\r
793                         return getCookieVal(j);\r
794                 }\r
795                 i = document.cookie.indexOf(" ", i) + 1;\r
796                 if (i == 0) {\r
797                         break;\r
798                 }\r
799         }\r
800         return null;\r
801 }\r
802 function setCookie (name, value) {  \r
803         var argv = setCookie.arguments;  \r
804         var argc = setCookie.arguments.length;  \r
805         var expires = (argc > 2) ? argv[2] : null;  \r
806         var path = (argc > 3) ? argv[3] : null;  \r
807         var domain = (argc > 4) ? argv[4] : null;  \r
808         var secure = (argc > 5) ? argv[5] : false;  \r
809         document.cookie = name + "=" + escape (value) + ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + ((path == null) ? "" : ("; path=" + path)) + ((domain == null) ? "" : ("; domain=" + domain)) + ((secure == true) ? "; secure" : "");\r
810 }\r
811 function expandNode() {\r
812         var state = getState(selectedNode);\r
813         if (state == 'open') {\r
814                 var currentTreeNode = getTreeNode(selectedNode);\r
815                 if (currentTreeNode.hasChilds()) {\r
816                         selectNode(currentTreeNode.childs[0].getID());\r
817                 }\r
818         }\r
819         else {\r
820                 handleNode(selectedNode);\r
821         }\r
822 }\r
823 function subtractNode() {\r
824         var state = getState(selectedNode);\r
825         if (state == 'closed') {\r
826                 var currentTreeNode = getTreeNode(selectedNode);\r
827                 var parent = currentTreeNode.getParent();\r
828                 if (parent != null && parent != rootNode) {\r
829                         selectNode(parent.getID());\r
830                 }\r
831         }\r
832         else {\r
833                 handleNode(selectedNode);\r
834         }\r
835 }\r
836 function selectPrevNode() {\r
837         var currentTreeNode = getTreeNode(selectedNode);\r
838         if (currentTreeNode.prevSibling != null) {\r
839 \r
840                 var state = getState(currentTreeNode.prevSibling.getID());\r
841 \r
842                 if (state == 'open' && currentTreeNode.prevSibling.hasChilds()) {\r
843                         // We have to find the last open child of the previoussiblings childs.\r
844                         var current = currentTreeNode.prevSibling.childs[currentTreeNode.prevSibling.childs.length - 1];\r
845                         var currentstate = 'open';\r
846                         while (current.hasChilds() && (getState(current.getID()) == 'open')) {\r
847                                 current = current.childs[current.childs.length - 1];\r
848                         }\r
849                         selectNode(current.getID());\r
850                 }\r
851                 else {\r
852                         selectNode(currentTreeNode.prevSibling.getID());\r
853                 }\r
854         }\r
855         else {\r
856                 if (currentTreeNode.getParent() != null && currentTreeNode.getParent() != rootNode) {\r
857                         selectNode(currentTreeNode.getParent().getID());\r
858                 }\r
859         }\r
860 }\r
861 function selectNextNode() {\r
862         var currentTreeNode = getTreeNode(selectedNode);\r
863 \r
864         var state = getState(selectedNode);\r
865         if (state == 'open' && currentTreeNode.hasChilds()) {\r
866                 selectNode(currentTreeNode.childs[0].getID());\r
867         }       \r
868         else {\r
869                 if (currentTreeNode.nextSibling != null) {\r
870                         selectNode(currentTreeNode.nextSibling.getID());\r
871                 }\r
872                 else {\r
873                         // Continue up the tree until we either hit null, or a parent which have a child.\r
874                         var parent = currentTreeNode;\r
875                         while ((parent = parent.getParent()) != rootNode) {\r
876                                 if (parent.nextSibling != null) {\r
877                                         selectNode(parent.nextSibling.getID());\r
878                                         break;\r
879                                 }\r
880                         }\r
881                         /*\r
882                         if (currentTreeNode.getParent().nextSibling != null) {\r
883                                 selectNode(currentTreeNode.getParent().nextSibling.getID());\r
884                         }\r
885                         */\r
886                 }\r
887         }\r
888 }\r
889 function keyDown(event) {\r
890         if (window.event) {\r
891                 event = window.event;\r
892         }\r
893         if (event.keyCode == 38) { // Up\r
894                 selectPrevNode();\r
895                 return false;\r
896         }\r
897         else if (event.keyCode == 40) { // Down\r
898                 selectNextNode();\r
899                 return false;\r
900         }\r
901         else if (event.keyCode == 37) { // left\r
902                 subtractNode();\r
903                 return false;\r
904         }\r
905         else if (event.keyCode == 39) { // right\r
906                 expandNode();\r
907                 return false;\r
908         }\r
909 }\r
910 document.onkeydown = keyDown;\r