source: sandbox/expresso/novos_templates/phpgwapi/js/dftree/dftree.js @ 773

Revision 773, 15.8 KB checked in by niltonneto, 15 years ago (diff)

Resolve #475

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1/* Dynamic Folder Tree
2 * Generates DHTML tree dynamically (on the fly).
3 * License: GNU LGPL
4 *
5 * Copyright (c) 2004, Vinicius Cubas Brand, Raphael Derosso Pereira
6 * {viniciuscb,raphaelpereira} at users.sourceforge.net
7 * All rights reserved.
8 *
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24/*
25 * Chanded by Joao Alfredo Knopik Junior
26 * joao.alfredo at gmail.com
27 */
28
29// NODE
30//Usage: a = new dNode({id:2, caption:'tree root', url:'http://www.w3.org'});
31function dNode(arrayProps) {
32        //mandatory fields
33        this.id;          //node id
34        this.caption;     //node caption
35
36        //optional fields
37        this.url;         //url to open
38        this.target;      //target to open url
39        this.onClick;     //javascript to execute onclick
40        this.onOpen;      //javascript to execute when a node of the tree opens
41        this.onClose;     //javascript to execute when a node of the tree closes
42        this.onFirstOpen; //javascript to execute only on the first open
43        this.iconClosed;  //img.src of closed icon
44        this.iconOpen;    //img.src of open icon
45        this.runJS = true;       //(bool) if true, runs the on* props defined above
46        this.plusSign = true;    //(bool) if the plus sign will appear or not
47        this.captionClass = 'l'; //(string) the class for this node's caption
48
49
50        //The parameters below are private
51        this._opened = false; //already opened
52        this._io = false; //is opened
53
54        this._children = []; //references to children
55        this._parent; //pointer to parent
56        this._myTree; //pointer to myTree
57        this._drawn = false;
58
59        for (var i in arrayProps)
60        {
61                if (i.charAt(0) != '_')
62                {
63                        eval('this.'+i+' = arrayProps[\''+i+'\'];');
64                }
65        }
66}
67
68//changes node state from open to closed, and vice-versa
69dNode.prototype.changeState = function()
70{
71        if (this._io)
72        {
73                this.close();
74        }
75        else
76        {
77                this.open();
78        }
79
80        //cons = COokie of Node Status
81        //setCookie("cons"+this.id,this._io);
82}
83
84dNode.prototype.open = function () {
85        if (!this._io)
86        {
87                if (!this._opened && this.runJS && this.onFirstOpen != null)
88                {
89                        eval(this.onFirstOpen);
90                }
91                else if (this.runJS && this.onOpen != null)
92                {
93                        eval(this.onOpen);
94                }
95
96                this._debug = true;
97                this._opened = true;
98                this._io = true;
99                this._refresh();
100        }
101}
102
103
104dNode.prototype.close = function() {
105        if (this._io)
106        {
107                if (this.runJS && this.onClose != null)
108                {
109                        eval(this.onClose);
110                }
111                this._io = false;
112                this._refresh();
113        }
114}
115
116//alter node label and other properties
117dNode.prototype.alter = function(arrayProps)
118{
119        for (var i in arrayProps)
120        {
121                if (i != 'id' && i.charAt(0) != '_')
122                {
123                        eval('this.'+i+' = arrayProps[\''+i+'\'];');
124                }
125        }
126}
127
128//css and dhtml refresh part
129dNode.prototype._refresh = function() {
130        var nodeDiv      = getObjectById("n"+this.id+this._myTree.name);
131        var plusSpan     = getObjectById("p"+this.id+this._myTree.name);
132        var captionSpan  = getObjectById("l"+this.id+this._myTree.name);
133        var childrenDiv  = getObjectById("ch"+this.id+this._myTree.name);
134
135        if (nodeDiv != null)
136        {
137                //Handling open and close: checks this._io and changes class as needed
138                if (!this._io) //just closed
139                {
140                        childrenDiv.className = "closed";
141                }
142                else //just opened
143                {
144                        //prevents IE undesired behaviour when displaying empty DIVs
145/*                      if (this._children.length > 0)
146                        {*/
147                                childrenDiv.className = "opened";
148                //      }
149                }
150
151                plusSpan.innerHTML = this._properPlus();
152
153                captionSpan.innerHTML = this.caption;
154        }
155
156//alter onLoad, etc
157
158}
159
160//gets the proper plus for this moment
161dNode.prototype._properPlus = function()
162{
163        if (!this._io)
164        {
165                if (this._myTree.useIcons)
166                {
167                        return (this.plusSign)?imageHTML(this._myTree.icons.plus):"";
168                }
169                else
170                {
171                        return (this.plusSign)?"+":" ";
172                }
173        }
174        else
175        {
176                if (this._myTree.useIcons)
177                {
178                        return (this.plusSign)?imageHTML(this._myTree.icons.minus):"";
179                }
180                else
181                {
182                        return (this.plusSign)?"-":" ";
183                }
184        }
185}
186
187//changes node to selected style class. Perform further actions.
188dNode.prototype._select = function()
189{
190        var captionSpan;
191
192        if (this._myTree._selected)
193        {
194                this._myTree._selected._unselect();
195        }
196        this._myTree._selected = this;
197       
198        captionSpan  = getObjectById("l"+this.id+this._myTree.name);
199       
200        if(document.getElementById("div_tree") != null){
201                if(ttree.FOLDER != ""){
202                        ttree.FOLDER = "";
203                }
204                ttree.FOLDER = this.id;
205        }
206       
207        if(document.getElementById("div_folders_search") != null){
208                if(EsearchE.name_box_search != ""){
209                        EsearchE.name_box_search = "";
210                }
211                EsearchE.name_box_search = this.id;
212        }
213
214        //changes class to selected link
215        if (captionSpan)
216        {
217                captionSpan.className = 'sl';
218        }
219
220}
221
222//changes node background color.
223dNode.prototype._onMouseOver = function()
224{
225        var captionSpan;
226        if ((this.id != 'root') && (this.id != 'user') && (this.id !='local_root')){
227                captionSpan = getObjectById("l"+this.id+this._myTree.name);
228                captionSpan.style.backgroundColor = 'white';
229                captionSpan.style.border = '1px solid black';
230                captionSpan.style.paddingTop = '0px';
231                captionSpan.style.paddingBottom = '0px';
232        }
233}
234//changes node background color.
235dNode.prototype._onMouseOut = function()
236{
237        var captionSpan;
238        if ((this.id != 'root') && (this.id != 'user') && (this.id !='local_root')){
239                captionSpan = getObjectById("l"+this.id+this._myTree.name);
240                captionSpan.style.backgroundColor = '';
241                captionSpan.style.border = '0px';
242                captionSpan.style.paddingTop = '1px';
243                captionSpan.style.paddingBottom = '1px';
244        }
245}
246
247//changes node to unselected style class. Perform further actions.
248dNode.prototype._unselect = function()
249{
250        var captionSpan  = getObjectById("l"+this.id+this._myTree.name);
251
252        this._myTree._lastSelected = this._myTree._selected;
253        this._myTree._selected = null;
254
255        //changes class to selected link
256        if (captionSpan)
257        {
258                captionSpan.className = this.captionClass;
259        }
260}
261
262
263//state can be open or closed
264//warning: if drawed node is not child or root, bugs will happen
265dNode.prototype._draw = function()
266{
267        var str;
268        var _this = this;
269        var divN, divCH, spanP, spanL, parentChildrenDiv;
270        var myClass = (this._io)? "opened" : "closed";
271        var myPlus = this._properPlus();
272        var append = true;
273        var captionOnClickEvent = null;
274//      var cook;
275
276        var plusEventHandler = function(){
277                _this.changeState();
278        }
279
280        var captionEventHandler = function(){
281                eval(captionOnClickEvent);
282        }
283
284/*      if (this.myTree.followCookies)
285        {
286                this._io = getCookie("cons"+this.id);
287        }*/
288
289        //FIXME put this in a separate function, as this will be necessary in
290        //various parts
291
292        if (this.onClick) //FIXME when onclick && url
293        {
294                captionEventHandler = function () { _this._select(); typeof(_this.onClick) == 'function' ? _this.onClick() : eval(_this.onClick); };
295        }
296        else if (this.url && this.target)
297        {
298                captionEventHandler = function () { _this._select(); window.open(_this.url,_this.target); };
299        }
300        else if (this.url)
301        {
302                captionEventHandler = function () { _this._select(); window.location=_this.url; };
303        }
304        else //Nao tem onClick
305        {
306                if ((this.id != 'root') && (this.id != 'user') && (this.id !='local_root')) //e nao seja raiz(root) ou pastas compartilhadas(user).
307                        captionEventHandler = function () { _this._select();};
308        }
309       
310        //The div of this node
311        divN = document.createElement('div');
312        divN.id = 'n'+this.id+this._myTree.name;
313        //divN.className = 'son';
314        divN.className = (!this._parent) ? 'root' : 'son';
315        //divN.style.border = '1px solid black';
316       
317        //The span that holds the plus/minus sign
318        spanP = document.createElement('span');
319        spanP.id = 'p'+this.id+this._myTree.name;
320        spanP.className = 'plus';
321        spanP.onclick = plusEventHandler;
322        spanP.innerHTML = myPlus;
323        //spanP.style.border = '1px solid green';
324
325        //The span that holds the label/caption
326        spanL = document.createElement('span');
327        spanL.id = 'l'+this.id+this._myTree.name;
328        spanL.className = this.captionClass;
329        spanL.onclick = captionEventHandler;
330        spanL.onmouseover = function () { _this._onMouseOver(); };
331        spanL.onmouseout = function () { _this._onMouseOut(); };
332//      spanL.style.border = '1px solid #f7f7f7';
333        spanL.innerHTML = this.caption;
334        //spanL.style.border = '1px solid red';
335
336        //The div that holds the children
337        divCH = document.createElement('div');
338        divCH.id = 'ch'+this.id+this._myTree.name;
339        divCH.className = myClass;
340        //divCH.style.border = '1px solid blue';
341       
342//      div.innerHTML = str;
343        divN.appendChild(spanP);
344        divN.appendChild(spanL);
345        divN.appendChild(divCH);
346       
347
348        if (this._parent != null)
349        {
350                parentChildrenDiv = getObjectById("ch"+this._parent.id+this._myTree.name);
351        }
352        else //is root
353        {
354                parentChildrenDiv = getObjectById("dftree_"+this._myTree.name);
355        }
356       
357        if (parentChildrenDiv)
358        {
359                parentChildrenDiv.appendChild(divN);
360        }
361}
362
363// TREE
364//Usage: t = new dFTree({name:t, caption:'tree root', url:'http://www.w3.org'});
365function dFTree(arrayProps) {
366        //mandatory fields
367        this.name;      //the value of this must be the name of the object
368
369        //optional fields
370        this.is_dynamic = true;   //tree is dynamic, i.e. updated on the fly
371        this.followCookies = true;//use previous state (o/c) of nodes
372        this.useIcons = false;     //use icons or not
373       
374
375        //arrayProps[icondir]: Icons Directory
376        iconPath = (arrayProps['icondir'] != null)? arrayProps['icondir'] : '';
377
378        this.icons = {
379                root        : iconPath+'/foldertree_base.gif',
380                folder      : iconPath+'/foldertree_folder.gif',
381                folderOpen  : iconPath+'/foldertree_folderopen.gif',
382                node        : iconPath+'/foldertree_folder.gif',
383                empty       : iconPath+'/foldertree_empty.gif',
384                line        : iconPath+'/foldertree_line.gif',
385                join        : iconPath+'/foldertree_join.gif',
386                joinBottom  : iconPath+'/foldertree_joinbottom.gif',
387                plus        : iconPath+'/foldertree_plus.gif',
388                plusBottom  : iconPath+'/foldertree_plusbottom.gif',
389                minus       : iconPath+'/foldertree_minus.gif',
390                minusBottom : iconPath+'/foldertree_minusbottom.gif',
391                nlPlus      : iconPath+'/foldertree_nolines_plus.gif',
392                nlMinus     : iconPath+'/foldertree_nolines_minus.gif'
393        };
394
395        //private
396        this._root = false; //reference to root node
397        this._aNodes = [];
398        this._lastSelected; //The last selected node
399        this._selected; //The actual selected node
400        this._folderPr = [];
401
402        for (var i in arrayProps)
403        {
404                if (i.charAt(0) != '_')
405                {
406                        eval('this.'+i+' = arrayProps[\''+i+'\'];');
407                }
408        }
409}
410
411dFTree.prototype.draw = function(dest_element) {
412        var main_div;
413       
414        if (!getObjectById("dftree_"+this.name) && dest_element)
415        {
416                main_div = document.createElement('div');
417                main_div.id = 'dftree_'+this.name;
418                dest_element.appendChild(main_div);
419                this._drawn = true;
420        }
421
422        if (this._root != false)
423        {
424                this._root._draw();
425                this._drawBranch(this._root._children);
426        }
427
428}
429
430//Transforms tree in HTML code
431dFTree.prototype.toString = function() {
432        var str = '';
433
434        if (!getObjectById("dftree_"+this.name))
435        {
436                str = '<div id="dftree_'+this.name+'"></div>';
437        }
438        return str;
439
440/*      if (this.root != false)
441        {
442                this.root._draw();
443                this._drawBranch(this.root.children);
444        }*/
445}
446
447//Recursive function, draws children
448dFTree.prototype._drawBranch = function(childrenArray) {
449        var a=0;
450        for (a;a<childrenArray.length;a++)
451        {
452                childrenArray[a]._draw();
453                this._drawBranch(childrenArray[a]._children);
454        }
455}
456
457//add into a position
458dFTree.prototype.add = function(node,pid) {
459        var auxPos;
460        var addNode = false;
461
462        if (typeof (auxPos = this._searchNode(node.id)) != "number")
463        {
464                // if parent exists, add node as its child
465                if (typeof (auxPos = this._searchNode(pid)) == "number")
466                {
467                        node._parent = this._aNodes[auxPos];
468                        this._aNodes[auxPos]._children[this._aNodes[auxPos]._children.length] = node;
469                        addNode = true;
470                }
471                else //if parent cannot be found and there is a tree root, ignores node
472                {
473                        if (!this._root)
474                        {
475                                this._root = node;
476                                addNode = true;
477                        }
478                }
479                if (addNode)
480                {
481                        this._aNodes[this._aNodes.length] = node;
482                        node._myTree = this;
483                        if (this.is_dynamic && this._drawn)
484                        {
485                                node._draw();
486                        }
487                }
488                else
489                {
490                        this._folderPr[this._folderPr.length] = node.id ;
491                }
492               
493        }
494        else {
495                var arrayProps = new Array();
496
497                arrayProps['id'] = node.id;
498                arrayProps['caption'] = node.caption;
499
500                arrayProps['url'] = node.url;
501                arrayProps['target'] = node.target;
502                arrayProps['onClick'] = node.onClick;
503                arrayProps['onOpen'] = node.onOpen;
504                arrayProps['onClose'] = node.onClose;
505                arrayProps['onFirstOpen'] = node.onFirstOpen;
506                arrayProps['iconClosed'] = node.iconClosed;
507                arrayProps['iconOpen'] = node.iconOpen;
508                arrayProps['runJS'] = node.runJS;
509                arrayProps['plusSign'] = node.plusSign;
510                arrayProps['captionClass'] = node.captionClass;
511
512                delete node;
513
514                this.alter(arrayProps);
515        }
516
517}
518
519//arrayProps: same properties of Node
520dFTree.prototype.alter = function(arrayProps) {
521        this.getNodeById(arrayProps['id']).alter(arrayProps);
522}
523
524dFTree.prototype.getNodeById = function(nodeid) {
525        return this._aNodes[this._searchNode(nodeid)];
526}
527
528dFTree.prototype.openTo = function(nodeid)
529{
530        var node = this.getNodeById(nodeid);
531
532        if (node && node._parent)
533        {
534                node._parent.open();
535                this.openTo(node._parent.id);
536        }
537}
538
539//Searches for a node in the node array, returning the position of the array 4it
540dFTree.prototype._searchNode = function(id) {
541        var a=0;
542        for (a;a<this._aNodes.length;a++)
543        {
544                if (this._aNodes[a].id == id)
545                {
546                        return a;
547                }
548        }
549        return false;
550}
551// By jakjr, retorna um array com os ids de todas as pastas (nodes)
552dFTree.prototype.getNodesList = function(imapDelimiter) {
553        var a=0;
554        var nodes=[];
555        for (a;a<this._aNodes.length;a++)
556        {
557                var node = this.getNodeById(this._aNodes[a].id);
558                nodes[a]=[];
559                nodes[a].id = node.id;
560                nodes[a].parent = node._parent ? node._parent.id : 'root';
561                var tmp = node.id.split(imapDelimiter);
562                var tmp_caption = node.caption.split("<");
563
564                if (tmp[tmp.length-1] == 'INBOX')
565                        nodes[a].caption = get_lang('Inbox');
566                else if (tmp[tmp.length-1] == 'user')
567                        nodes[a].caption = get_lang("Shared Folders");
568                else
569                        nodes[a].caption = tmp_caption[0];
570                //nodes[a].caption = tmp[tmp.length-1] == 'INBOX' ? get_lang('Inbox') : tmp[tmp.length-1];
571                nodes[a].plusSign = node.plusSign;
572        }
573        return nodes;
574}
575
576//Auxiliar functions
577//For multi-browser compatibility
578function getObjectById(name)
579{   
580    if (document.getElementById)
581    {
582        return document.getElementById(name);
583    }
584    else if (document.all)
585    {
586        return document.all[name];
587    }
588    else if (document.layers)
589    {
590        return document.layers[name];
591    }
592    return false;
593}
594
595// [Cookie] Clears a cookie
596function clearCookie(cookieName) {
597        var now = new Date();
598        var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);
599        this.setCookie(cookieName, 'cookieValue', yesterday);
600        this.setCookie(cookieName, 'cookieValue', yesterday);
601};
602
603// [Cookie] Sets value in a cookie
604function setCookie(cookieName, cookieValue, expires, path, domain, secure) {
605        document.cookie =
606                escape(cookieName) + '=' + escape(cookieValue)
607                + (expires ? '; expires=' + expires.toGMTString() : '')
608                + (path ? '; path=' + path : '')
609                + (domain ? '; domain=' + domain : '')
610                + (secure ? '; secure' : '');
611};
612
613// [Cookie] Gets a value from a cookie
614function getCookie(cookieName) {
615        var cookieValue = '';
616        var posName = document.cookie.indexOf(escape(cookieName) + '=');
617        if (posName != -1) {
618                var posValue = posName + (escape(cookieName) + '=').length;
619                var endPos = document.cookie.indexOf(';', posValue);
620                if (endPos != -1)
621                {
622                        cookieValue = unescape(document.cookie.substring(posValue, endPos));
623                }
624                else
625                {
626                        cookieValue = unescape(document.cookie.substring(posValue));
627                }
628        }
629        return (cookieValue);
630};
631
632
633function imageHTML(src,attributes) {
634        if (attributes != null)
635        {
636                attributes = '';
637        }
638        return "<img "+attributes+" src=\""+src+"\">";
639}
Note: See TracBrowser for help on using the repository browser.