2cb369d96166e0397ec4f2461f83db612a0a94ea
1 /*--------------------------------------------------|
3 | dTree 2.05 | www.destroydrop.com/javascript/tree/ |
5 |---------------------------------------------------|
7 | Copyright (c) 2002-2003 Geir Landr? |
11 | This script can be used freely as long as all |
13 | copyright messages are intact. |
17 | Updated: 17.04.2003 |
19 |--------------------------------------------------*/
25 function Node(id
, pid
, name
, url
, title
, target
, icon
, iconOpen
, open
) {
41 this.iconOpen
= iconOpen
;
43 this._io
= open
|| false;
60 // imagePath parameter added by SquirrelMail Team
61 function dTree(objName
, imagePath
) {
77 useStatusText
: false,
79 closeSameLevel
: false,
87 root
: imagePath
+'/base.gif',
89 folder
: imagePath
+'/folder.gif',
91 folderOpen
: imagePath
+'/folderopen.gif',
93 node
: imagePath
+'/page.gif',
95 empty
: imagePath
+'/empty.gif',
97 line
: imagePath
+'/line.gif',
99 join
: imagePath
+'/join.gif',
101 joinBottom
: imagePath
+'/joinbottom.gif',
103 plus
: imagePath
+'/plus.gif',
105 plusBottom
: imagePath
+'/plusbottom.gif',
107 minus
: imagePath
+'/minus.gif',
109 minusBottom
: imagePath
+'/minusbottom.gif',
111 nlPlus
: imagePath
+'/nolines_plus.gif',
113 nlMinus
: imagePath
+'/nolines_minus.gif'
123 this.root
= new Node(-1);
125 this.selectedNode
= null;
127 this.selectedFound
= false;
129 this.completed
= false;
131 this.imagePath
= imagePath
;
137 // Adds a new node to the node array
139 dTree
.prototype.add = function(id
, pid
, name
, url
, title
, target
, icon
, iconOpen
, open
) {
141 this.aNodes
[this.aNodes
.length
] = new Node(id
, pid
, name
, url
, title
, target
, icon
, iconOpen
, open
);
147 // Open/close all nodes
149 dTree
.prototype.openAll = function() {
155 dTree
.prototype.closeAll = function() {
163 // Outputs the tree to the page
165 dTree
.prototype.toString = function() {
167 var str
= '<div class="dtree">\n';
169 if (document
.getElementById
) {
171 if (this.config
.useCookies
) this.selectedNode
= this.getSelected();
173 str
+= this.addNode(this.root
);
175 } else str
+= 'Browser not supported.';
179 if (!this.selectedFound
) this.selectedNode
= null;
181 this.completed
= true;
189 // Creates the tree structure
191 dTree
.prototype.addNode = function(pNode
) {
197 if (this.config
.inOrder
) n
= pNode
._ai
;
199 for (n
; n
<this.aNodes
.length
; n
++) {
201 if (this.aNodes
[n
].pid
== pNode
.id
) {
203 var cn
= this.aNodes
[n
];
211 if (!cn
.target
&& this.config
.target
) cn
.target
= this.config
.target
;
213 if (cn
._hc
&& !cn
._io
&& this.config
.useCookies
) cn
._io
= this.isOpen(cn
.id
);
215 if (!this.config
.folderLinks
&& cn
._hc
) cn
.url
= null;
217 if (this.config
.useSelection
&& cn
.id
== this.selectedNode
&& !this.selectedFound
) {
221 this.selectedNode
= n
;
223 this.selectedFound
= true;
227 str
+= this.node(cn
, n
);
241 // Creates the node icon, url and text
243 dTree
.prototype.node = function(node
, nodeId
) {
245 var str
= '<div class="dTreeNode">' + this.indent(node
, nodeId
);
247 if (this.config
.useIcons
) {
249 if (!node
.icon
) node
.icon
= (this.root
.id
== node
.pid
) ? this.icon
.root
: ((node
._hc
) ? this.icon
.folder
: this.icon
.node
);
251 if (!node
.iconOpen
) node
.iconOpen
= (node
._hc
) ? this.icon
.folderOpen
: this.icon
.node
;
253 if (this.root
.id
== node
.pid
) {
255 node
.icon
= this.icon
.root
;
257 node
.iconOpen
= this.icon
.root
;
261 str
+= '<img id="i' + this.obj
+ nodeId
+ '" src="' + ((node
._io
) ? node
.iconOpen
: node
.icon
) + '" alt="" />';
267 str
+= '<a id="s' + this.obj
+ nodeId
+ '" class="' + ((this.config
.useSelection
) ? ((node
._is
? 'nodeSel' : 'node')) : 'node') + '" href="' + node
.url
+ '"';
269 if (node
.title
) str
+= ' title="' + node
.title
+ '"';
271 if (node
.target
) str
+= ' target="' + node
.target
+ '"';
273 if (this.config
.useStatusText
) str
+= ' onmouseover="window.status=\'' + node
.name
+ '\';return true;" onmouseout="window.status=\'\';return true;" ';
275 if (this.config
.useSelection
&& ((node
._hc
&& this.config
.folderLinks
) || !node
._hc
))
277 str
+= ' onclick="javascript: ' + this.obj
+ '.s(' + nodeId
+ ');"';
283 else if ((!this.config
.folderLinks
|| !node
.url
) && node
._hc
&& node
.pid
!= this.root
.id
)
285 str
+= '<a href="javascript: ' + this.obj
+ '.o(' + nodeId
+ ');" class="node">';
289 if (node
.url
|| ((!this.config
.folderLinks
|| !node
.url
) && node
._hc
)) str
+= '</a>';
295 str
+= '<div id="d' + this.obj
+ nodeId
+ '" class="clip" style="display:' + ((this.root
.id
== node
.pid
|| node
._io
) ? 'block' : 'none') + ';">';
297 str
+= this.addNode(node
);
311 // Adds the empty and line icons
313 dTree
.prototype.indent = function(node
, nodeId
) {
317 if (this.root
.id
!= node
.pid
) {
319 for (var n
=0; n
<this.aIndent
.length
; n
++)
321 str
+= '<img src="' + ( (this.aIndent
[n
] == 1 && this.config
.useLines
) ? this.icon
.line
: this.icon
.empty
) + '" alt="" />';
323 (node
._ls
) ? this.aIndent
.push(0) : this.aIndent
.push(1);
327 str
+= '<a href="javascript: ' + this.obj
+ '.o(' + nodeId
+ ');"><img id="j' + this.obj
+ nodeId
+ '" src="';
329 if (!this.config
.useLines
) str
+= (node
._io
) ? this.icon
.nlMinus
: this.icon
.nlPlus
;
331 else str
+= ( (node
._io
) ? ((node
._ls
&& this.config
.useLines
) ? this.icon
.minusBottom
: this.icon
.minus
) : ((node
._ls
&& this.config
.useLines
) ? this.icon
.plusBottom
: this.icon
.plus
) );
333 str
+= '" alt="" /></a>';
335 } else str
+= '<img src="' + ( (this.config
.useLines
) ? ((node
._ls
) ? this.icon
.joinBottom
: this.icon
.join
) : this.icon
.empty
) + '" alt="" />';
345 // Checks if a node has any children and if it is the last sibling
347 dTree
.prototype.setCS = function(node
) {
351 for (var n
=0; n
<this.aNodes
.length
; n
++) {
353 if (this.aNodes
[n
].pid
== node
.id
) node
._hc
= true;
355 if (this.aNodes
[n
].pid
== node
.pid
) lastId
= this.aNodes
[n
].id
;
359 if (lastId
==node
.id
) node
._ls
= true;
365 // Returns the selected node
367 dTree
.prototype.getSelected = function() {
369 var sn
= this.getCookie('cs' + this.obj
);
371 return (sn
) ? sn
: null;
377 // Highlights the selected node
379 dTree
.prototype.s = function(id
) {
381 if (!this.config
.useSelection
) return;
383 var cn
= this.aNodes
[id
];
385 if (cn
._hc
&& !this.config
.folderLinks
) return;
387 if (this.selectedNode
!= id
) {
389 if (this.selectedNode
|| this.selectedNode
==0) {
391 eOld
= document
.getElementById("s" + this.obj
+ this.selectedNode
);
393 eOld
.className
= "node";
397 eNew
= document
.getElementById("s" + this.obj
+ id
);
399 eNew
.className
= "nodeSel";
401 this.selectedNode
= id
;
403 if (this.config
.useCookies
) this.setCookie('cs' + this.obj
, cn
.id
);
411 // Toggle Open or close
413 dTree
.prototype.o = function(id
) {
415 var cn
= this.aNodes
[id
];
417 this.nodeStatus(!cn
._io
, id
, cn
._ls
);
421 if (this.config
.closeSameLevel
) this.closeLevel(cn
);
423 if (this.config
.useCookies
) this.updateCookie();
429 // Open or close all nodes
431 dTree
.prototype.oAll = function(status
) {
433 for (var n
=0; n
<this.aNodes
.length
; n
++) {
435 if (this.aNodes
[n
]._hc
&& this.aNodes
[n
].pid
!= this.root
.id
) {
437 this.nodeStatus(status
, n
, this.aNodes
[n
]._ls
)
439 this.aNodes
[n
]._io
= status
;
445 if (this.config
.useCookies
) this.updateCookie();
451 // Opens the tree to a specific node
453 dTree
.prototype.openTo = function(nId
, bSelect
, bFirst
) {
457 for (var n
=0; n
<this.aNodes
.length
; n
++) {
459 if (this.aNodes
[n
].id
== nId
) {
471 var cn
=this.aNodes
[nId
];
473 if (cn
.pid
==this.root
.id
|| !cn
._p
) return;
479 if (this.completed
&& cn
._hc
) this.nodeStatus(true, cn
._ai
, cn
._ls
);
481 if (this.completed
&& bSelect
) this.s(cn
._ai
);
483 else if (bSelect
) this._sn
=cn
._ai
;
485 this.openTo(cn
._p
._ai
, false, true);
491 // Closes all nodes on the same level as certain node
493 dTree
.prototype.closeLevel = function(node
) {
495 for (var n
=0; n
<this.aNodes
.length
; n
++) {
497 if (this.aNodes
[n
].pid
== node
.pid
&& this.aNodes
[n
].id
!= node
.id
&& this.aNodes
[n
]._hc
) {
499 this.nodeStatus(false, n
, this.aNodes
[n
]._ls
);
501 this.aNodes
[n
]._io
= false;
503 this.closeAllChildren(this.aNodes
[n
]);
513 // Closes all children of a node
515 dTree
.prototype.closeAllChildren = function(node
) {
517 for (var n
=0; n
<this.aNodes
.length
; n
++) {
519 if (this.aNodes
[n
].pid
== node
.id
&& this.aNodes
[n
]._hc
) {
521 if (this.aNodes
[n
]._io
) this.nodeStatus(false, n
, this.aNodes
[n
]._ls
);
523 this.aNodes
[n
]._io
= false;
525 this.closeAllChildren(this.aNodes
[n
]);
535 // Change the status of a node(open or closed)
537 dTree
.prototype.nodeStatus = function(status
, id
, bottom
) {
539 eDiv
= document
.getElementById('d' + this.obj
+ id
);
541 eJoin
= document
.getElementById('j' + this.obj
+ id
);
543 if (this.config
.useIcons
) {
545 eIcon
= document
.getElementById('i' + this.obj
+ id
);
547 eIcon
.src
= (status
) ? this.aNodes
[id
].iconOpen
: this.aNodes
[id
].icon
;
551 eJoin
.src
= (this.config
.useLines
)?
553 ((status
)?((bottom
)?this.icon
.minusBottom
:this.icon
.minus
):((bottom
)?this.icon
.plusBottom
:this.icon
.plus
)):
555 ((status
)?this.icon
.nlMinus
:this.icon
.nlPlus
);
557 eDiv
.style
.display
= (status
) ? 'block': 'none';
565 // [Cookie] Clears a cookie
567 dTree
.prototype.clearCookie = function() {
569 var now
= new Date();
571 var yesterday
= new Date(now
.getTime() - 1000 * 60 * 60 * 24);
573 this.setCookie('co'+this.obj
, 'cookieValue', yesterday
);
575 this.setCookie('cs'+this.obj
, 'cookieValue', yesterday
);
581 // [Cookie] Sets value in a cookie
583 dTree
.prototype.setCookie = function(cookieName
, cookieValue
, expires
, path
, domain
, secure
) {
587 escape(cookieName
) + '=' + escape(cookieValue
)
589 + (expires
? '; expires=' + expires
.toGMTString() : '')
591 + (path
? '; path=' + path
: '')
593 + (domain
? '; domain=' + domain
: '')
595 + (secure
? '; secure' : '');
601 // [Cookie] Gets a value from a cookie
603 dTree
.prototype.getCookie = function(cookieName
) {
605 var cookieValue
= '';
607 var posName
= document
.cookie
.indexOf(escape(cookieName
) + '=');
611 var posValue
= posName
+ (escape(cookieName
) + '=').length
;
613 var endPos
= document
.cookie
.indexOf(';', posValue
);
615 if (endPos
!= -1) cookieValue
= unescape(document
.cookie
.substring(posValue
, endPos
));
617 else cookieValue
= unescape(document
.cookie
.substring(posValue
));
621 return (cookieValue
);
627 // [Cookie] Returns ids of open nodes as a string
629 dTree
.prototype.updateCookie = function() {
633 for (var n
=0; n
<this.aNodes
.length
; n
++) {
635 if (this.aNodes
[n
]._io
&& this.aNodes
[n
].pid
!= this.root
.id
) {
639 str
+= this.aNodes
[n
].id
;
645 this.setCookie('co' + this.obj
, str
);
651 // [Cookie] Checks if a node id is in a cookie
653 dTree
.prototype.isOpen = function(id
) {
655 var aOpen
= this.getCookie('co' + this.obj
).split('.');
657 for (var n
=0; n
<aOpen
.length
; n
++)
659 if (aOpen
[n
] == id
) return true;
667 // If Push and pop is not implemented by the browser
669 if (!Array
.prototype.push
) {
671 Array
.prototype.push
= function array_push() {
673 for(var i
=0;i
<arguments
.length
;i
++)
675 this[this.length
]=arguments
[i
];
683 if (!Array
.prototype.pop
) {
685 Array
.prototype.pop
= function array_pop() {
687 lastElement
= this[this.length
-1];
689 this.length
= Math
.max(this.length
-1,0);