1 /*--------------------------------------------------|
2 | dTree 2.05 | www.destroydrop.com/javascript/tree/ |
3 |---------------------------------------------------|
4 | Copyright (c) 2002-2003 Geir Landr? |
6 | This script can be used freely as long as all |
7 | copyright messages are intact. |
9 | Updated: 17.04.2003 |
10 |--------------------------------------------------*/
13 function Node(id
, pid
, name
, url
, title
, target
, icon
, iconOpen
, open
) {
21 this.iconOpen
= iconOpen
;
22 this._io
= open
|| false;
30 // Tree object// imagePath parameter added by SquirrelMail Team
31 function dTree(objName
, imagePath
) {
39 useStatusText
: false,
40 closeSameLevel
: false,
44 root
: imagePath
+'/base.png',
45 folder
: imagePath
+'/folder.png',
46 folderOpen
: imagePath
+'/folderopen.png',
47 node
: imagePath
+'/page.png',
48 empty
: imagePath
+'/empty.png',
49 line
: imagePath
+'/line.png',
50 join
: imagePath
+'/join.png',
51 joinBottom
: imagePath
+'/joinbottom.png',
52 plus
: imagePath
+'/plus_mid.png',
53 plusBottom
: imagePath
+'/plusbottom.png',
54 minus
: imagePath
+'/minus_mid.png',
55 minusBottom
: imagePath
+'/minusbottom.png',
56 nlPlus
: imagePath
+'/nolines_plus.png',
57 nlMinus
: imagePath
+'/nolines_minus.png'
62 this.root
= new Node(-1);
63 this.selectedNode
= null;
64 this.selectedFound
= false;
65 this.completed
= false; this.imagePath
= imagePath
;
68 // Adds a new node to the node array
69 dTree
.prototype.add = function(id
, pid
, name
, url
, title
, target
, icon
, iconOpen
, open
) {
70 this.aNodes
[this.aNodes
.length
] = new Node(id
, pid
, name
, url
, title
, target
, icon
, iconOpen
, open
);
73 // Open/close all nodes
74 dTree
.prototype.openAll = function() {
77 dTree
.prototype.closeAll = function() {
81 // Outputs the tree to the page
82 dTree
.prototype.toString = function() {
83 var str
= '<div class="dtree">\n';
84 if (document
.getElementById
) {
85 if (this.config
.useCookies
) this.selectedNode
= this.getSelected();
86 str
+= this.addNode(this.root
);
87 } else str
+= 'Browser not supported.';
89 if (!this.selectedFound
) this.selectedNode
= null;
90 this.completed
= true;
94 // Creates the tree structure
95 dTree
.prototype.addNode = function(pNode
) {
98 if (this.config
.inOrder
) n
= pNode
._ai
;
99 for (n
; n
<this.aNodes
.length
; n
++) {
100 if (this.aNodes
[n
].pid
== pNode
.id
) {
101 var cn
= this.aNodes
[n
];
105 if (!cn
.target
&& this.config
.target
) cn
.target
= this.config
.target
;
106 if (cn
._hc
&& !cn
._io
&& this.config
.useCookies
) cn
._io
= this.isOpen(cn
.id
);
107 if (!this.config
.folderLinks
&& cn
._hc
) cn
.url
= null;
108 if (this.config
.useSelection
&& cn
.id
== this.selectedNode
&& !this.selectedFound
) {
110 this.selectedNode
= n
;
111 this.selectedFound
= true;
113 str
+= this.node(cn
, n
);
120 // Creates the node icon, url and text
121 dTree
.prototype.node = function(node
, nodeId
) {
122 var str
= '<div class="dTreeNode">' + this.indent(node
, nodeId
);
123 if (this.config
.useIcons
) {
124 if (!node
.icon
) node
.icon
= (this.root
.id
== node
.pid
) ? this.icon
.root
: ((node
._hc
) ? this.icon
.folder
: this.icon
.node
);
125 if (!node
.iconOpen
) node
.iconOpen
= (node
._hc
) ? this.icon
.folderOpen
: this.icon
.node
;
126 if (this.root
.id
== node
.pid
) {
127 node
.icon
= this.icon
.root
;
128 node
.iconOpen
= this.icon
.root
;
130 str
+= '<img id="i' + this.obj
+ nodeId
+ '" src="' + ((node
._io
) ? node
.iconOpen
: node
.icon
) + '" alt="" />';
133 str
+= '<a id="s' + this.obj
+ nodeId
+ '" class="' + ((this.config
.useSelection
) ? ((node
._is
? 'nodeSel' : 'node')) : 'node') + '" href="' + node
.url
+ '"';
134 if (node
.title
) str
+= ' title="' + node
.title
+ '"';
135 if (node
.target
) str
+= ' target="' + node
.target
+ '"';
136 if (this.config
.useStatusText
) str
+= ' onmouseover="window.status=\'' + node
.name
+ '\';return true;" onmouseout="window.status=\'\';return true;" ';
137 if (this.config
.useSelection
&& ((node
._hc
&& this.config
.folderLinks
) || !node
._hc
))
138 str
+= ' onclick="javascript: ' + this.obj
+ '.s(' + nodeId
+ ');"';
141 else if ((!this.config
.folderLinks
|| !node
.url
) && node
._hc
&& node
.pid
!= this.root
.id
)
142 str
+= '<a href="javascript: ' + this.obj
+ '.o(' + nodeId
+ ');" class="node">';
144 if (node
.url
|| ((!this.config
.folderLinks
|| !node
.url
) && node
._hc
)) str
+= '</a>';
147 str
+= '<div id="d' + this.obj
+ nodeId
+ '" class="clip" style="display:' + ((this.root
.id
== node
.pid
|| node
._io
) ? 'block' : 'none') + ';">';
148 str
+= this.addNode(node
);
155 // Adds the empty and line icons
156 dTree
.prototype.indent = function(node
, nodeId
) {
158 if (this.root
.id
!= node
.pid
) {
159 for (var n
=0; n
<this.aIndent
.length
; n
++)
160 str
+= '<img src="' + ( (this.aIndent
[n
] == 1 && this.config
.useLines
) ? this.icon
.line
: this.icon
.empty
) + '" alt="" />';
161 (node
._ls
) ? this.aIndent
.push(0) : this.aIndent
.push(1);
163 str
+= '<a href="javascript: ' + this.obj
+ '.o(' + nodeId
+ ');"><img id="j' + this.obj
+ nodeId
+ '" src="';
164 if (!this.config
.useLines
) str
+= (node
._io
) ? this.icon
.nlMinus
: this.icon
.nlPlus
;
165 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
) );
166 str
+= '" alt="" /></a>';
167 } else str
+= '<img src="' + ( (this.config
.useLines
) ? ((node
._ls
) ? this.icon
.joinBottom
: this.icon
.join
) : this.icon
.empty
) + '" alt="" />';
172 // Checks if a node has any children and if it is the last sibling
173 dTree
.prototype.setCS = function(node
) {
175 for (var n
=0; n
<this.aNodes
.length
; n
++) {
176 if (this.aNodes
[n
].pid
== node
.id
) node
._hc
= true;
177 if (this.aNodes
[n
].pid
== node
.pid
) lastId
= this.aNodes
[n
].id
;
179 if (lastId
==node
.id
) node
._ls
= true;
182 // Returns the selected node
183 dTree
.prototype.getSelected = function() {
184 var sn
= this.getCookie('cs' + this.obj
);
185 return (sn
) ? sn
: null;
188 // Highlights the selected node
189 dTree
.prototype.s = function(id
) {
190 if (!this.config
.useSelection
) return;
191 var cn
= this.aNodes
[id
];
192 if (cn
._hc
&& !this.config
.folderLinks
) return;
193 if (this.selectedNode
!= id
) {
194 if (this.selectedNode
|| this.selectedNode
==0) {
195 eOld
= document
.getElementById("s" + this.obj
+ this.selectedNode
);
196 eOld
.className
= "node";
198 eNew
= document
.getElementById("s" + this.obj
+ id
);
199 eNew
.className
= "nodeSel";
200 this.selectedNode
= id
;
201 if (this.config
.useCookies
) this.setCookie('cs' + this.obj
, cn
.id
);
205 // Toggle Open or close
206 dTree
.prototype.o = function(id
) {
207 var cn
= this.aNodes
[id
];
208 this.nodeStatus(!cn
._io
, id
, cn
._ls
);
210 if (this.config
.closeSameLevel
) this.closeLevel(cn
);
211 if (this.config
.useCookies
) this.updateCookie();
214 // Open or close all nodes
215 dTree
.prototype.oAll = function(status
) {
216 for (var n
=0; n
<this.aNodes
.length
; n
++) {
217 if (this.aNodes
[n
]._hc
&& this.aNodes
[n
].pid
!= this.root
.id
) {
218 this.nodeStatus(status
, n
, this.aNodes
[n
]._ls
)
219 this.aNodes
[n
]._io
= status
;
222 if (this.config
.useCookies
) this.updateCookie();
225 // Opens the tree to a specific node
226 dTree
.prototype.openTo = function(nId
, bSelect
, bFirst
) {
228 for (var n
=0; n
<this.aNodes
.length
; n
++) {
229 if (this.aNodes
[n
].id
== nId
) {
235 var cn
=this.aNodes
[nId
];
236 if (cn
.pid
==this.root
.id
|| !cn
._p
) return;
239 if (this.completed
&& cn
._hc
) this.nodeStatus(true, cn
._ai
, cn
._ls
);
240 if (this.completed
&& bSelect
) this.s(cn
._ai
);
241 else if (bSelect
) this._sn
=cn
._ai
;
242 this.openTo(cn
._p
._ai
, false, true);
245 // Closes all nodes on the same level as certain node
246 dTree
.prototype.closeLevel = function(node
) {
247 for (var n
=0; n
<this.aNodes
.length
; n
++) {
248 if (this.aNodes
[n
].pid
== node
.pid
&& this.aNodes
[n
].id
!= node
.id
&& this.aNodes
[n
]._hc
) {
249 this.nodeStatus(false, n
, this.aNodes
[n
]._ls
);
250 this.aNodes
[n
]._io
= false;
251 this.closeAllChildren(this.aNodes
[n
]);
256 // Closes all children of a node
257 dTree
.prototype.closeAllChildren = function(node
) {
258 for (var n
=0; n
<this.aNodes
.length
; n
++) {
259 if (this.aNodes
[n
].pid
== node
.id
&& this.aNodes
[n
]._hc
) {
260 if (this.aNodes
[n
]._io
) this.nodeStatus(false, n
, this.aNodes
[n
]._ls
);
261 this.aNodes
[n
]._io
= false;
262 this.closeAllChildren(this.aNodes
[n
]);
267 // Change the status of a node(open or closed)
268 dTree
.prototype.nodeStatus = function(status
, id
, bottom
) {
269 eDiv
= document
.getElementById('d' + this.obj
+ id
);
270 eJoin
= document
.getElementById('j' + this.obj
+ id
);
271 if (this.config
.useIcons
) {
272 eIcon
= document
.getElementById('i' + this.obj
+ id
);
273 eIcon
.src
= (status
) ? this.aNodes
[id
].iconOpen
: this.aNodes
[id
].icon
;
275 eJoin
.src
= (this.config
.useLines
)?
276 ((status
)?((bottom
)?this.icon
.minusBottom
:this.icon
.minus
):((bottom
)?this.icon
.plusBottom
:this.icon
.plus
)):
277 ((status
)?this.icon
.nlMinus
:this.icon
.nlPlus
);
278 eDiv
.style
.display
= (status
) ? 'block': 'none';
282 // [Cookie] Clears a cookie
283 dTree
.prototype.clearCookie = function() {
284 var now
= new Date();
285 var yesterday
= new Date(now
.getTime() - 1000 * 60 * 60 * 24);
286 this.setCookie('co'+this.obj
, 'cookieValue', yesterday
);
287 this.setCookie('cs'+this.obj
, 'cookieValue', yesterday
);
290 // [Cookie] Sets value in a cookie
291 dTree
.prototype.setCookie = function(cookieName
, cookieValue
, expires
, path
, domain
, secure
) {
293 escape(cookieName
) + '=' + escape(cookieValue
)
294 + (expires
? '; expires=' + expires
.toGMTString() : '')
295 + (path
? '; path=' + path
: '')
296 + (domain
? '; domain=' + domain
: '')
297 + (secure
? '; secure' : '');
300 // [Cookie] Gets a value from a cookie
301 dTree
.prototype.getCookie = function(cookieName
) {
302 var cookieValue
= '';
303 var posName
= document
.cookie
.indexOf(escape(cookieName
) + '=');
305 var posValue
= posName
+ (escape(cookieName
) + '=').length
;
306 var endPos
= document
.cookie
.indexOf(';', posValue
);
307 if (endPos
!= -1) cookieValue
= unescape(document
.cookie
.substring(posValue
, endPos
));
308 else cookieValue
= unescape(document
.cookie
.substring(posValue
));
310 return (cookieValue
);
313 // [Cookie] Returns ids of open nodes as a string
314 dTree
.prototype.updateCookie = function() {
316 for (var n
=0; n
<this.aNodes
.length
; n
++) {
317 if (this.aNodes
[n
]._io
&& this.aNodes
[n
].pid
!= this.root
.id
) {
319 str
+= this.aNodes
[n
].id
;
322 this.setCookie('co' + this.obj
, str
);
325 // [Cookie] Checks if a node id is in a cookie
326 dTree
.prototype.isOpen = function(id
) {
327 var aOpen
= this.getCookie('co' + this.obj
).split('.');
328 for (var n
=0; n
<aOpen
.length
; n
++)
329 if (aOpen
[n
] == id
) return true;
333 // If Push and pop is not implemented by the browser
334 if (!Array
.prototype.push
) {
335 Array
.prototype.push
= function array_push() {
336 for(var i
=0;i
<arguments
.length
;i
++)
337 this[this.length
]=arguments
[i
];
341 if (!Array
.prototype.pop
) {
342 Array
.prototype.pop
= function array_pop() {
343 lastElement
= this[this.length
-1];
344 this.length
= Math
.max(this.length
-1,0);