source: trunk/web/addons/job_monarch/lib/extjs-30/src/widgets/tree/TreeNodeUI.js @ 625

Last change on this file since 625 was 625, checked in by ramonb, 15 years ago

lib/extjs-30:

  • new ExtJS 3.0
File size: 18.6 KB
Line 
1/*!
2 * Ext JS Library 3.0.0
3 * Copyright(c) 2006-2009 Ext JS, LLC
4 * licensing@extjs.com
5 * http://www.extjs.com/license
6 */
7/**
8 * @class Ext.tree.TreeNodeUI
9 * This class provides the default UI implementation for Ext TreeNodes.
10 * The TreeNode UI implementation is separate from the
11 * tree implementation, and allows customizing of the appearance of
12 * tree nodes.<br>
13 * <p>
14 * If you are customizing the Tree's user interface, you
15 * may need to extend this class, but you should never need to instantiate this class.<br>
16 * <p>
17 * This class provides access to the user interface components of an Ext TreeNode, through
18 * {@link Ext.tree.TreeNode#getUI}
19 */
20Ext.tree.TreeNodeUI = function(node){
21    this.node = node;
22    this.rendered = false;
23    this.animating = false;
24    this.wasLeaf = true;
25    this.ecc = 'x-tree-ec-icon x-tree-elbow';
26    this.emptyIcon = Ext.BLANK_IMAGE_URL;
27};
28
29Ext.tree.TreeNodeUI.prototype = {
30    // private
31    removeChild : function(node){
32        if(this.rendered){
33            this.ctNode.removeChild(node.ui.getEl());
34        } 
35    },
36
37    // private
38    beforeLoad : function(){
39         this.addClass("x-tree-node-loading");
40    },
41
42    // private
43    afterLoad : function(){
44         this.removeClass("x-tree-node-loading");
45    },
46
47    // private
48    onTextChange : function(node, text, oldText){
49        if(this.rendered){
50            this.textNode.innerHTML = text;
51        }
52    },
53
54    // private
55    onDisableChange : function(node, state){
56        this.disabled = state;
57                if (this.checkbox) {
58                        this.checkbox.disabled = state;
59                }       
60        if(state){
61            this.addClass("x-tree-node-disabled");
62        }else{
63            this.removeClass("x-tree-node-disabled");
64        } 
65    },
66
67    // private
68    onSelectedChange : function(state){
69        if(state){
70            this.focus();
71            this.addClass("x-tree-selected");
72        }else{
73            //this.blur();
74            this.removeClass("x-tree-selected");
75        }
76    },
77
78    // private
79    onMove : function(tree, node, oldParent, newParent, index, refNode){
80        this.childIndent = null;
81        if(this.rendered){
82            var targetNode = newParent.ui.getContainer();
83            if(!targetNode){//target not rendered
84                this.holder = document.createElement("div");
85                this.holder.appendChild(this.wrap);
86                return;
87            }
88            var insertBefore = refNode ? refNode.ui.getEl() : null;
89            if(insertBefore){
90                targetNode.insertBefore(this.wrap, insertBefore);
91            }else{
92                targetNode.appendChild(this.wrap);
93            }
94            this.node.renderIndent(true, oldParent != newParent);
95        }
96    },
97
98/**
99 * Adds one or more CSS classes to the node's UI element.
100 * Duplicate classes are automatically filtered out.
101 * @param {String/Array} className The CSS class to add, or an array of classes
102 */
103    addClass : function(cls){
104        if(this.elNode){
105            Ext.fly(this.elNode).addClass(cls);
106        }
107    },
108
109/**
110 * Removes one or more CSS classes from the node's UI element.
111 * @param {String/Array} className The CSS class to remove, or an array of classes
112 */
113    removeClass : function(cls){
114        if(this.elNode){
115            Ext.fly(this.elNode).removeClass(cls); 
116        }
117    },
118
119    // private
120    remove : function(){
121        if(this.rendered){
122            this.holder = document.createElement("div");
123            this.holder.appendChild(this.wrap);
124        } 
125    },
126
127    // private
128    fireEvent : function(){
129        return this.node.fireEvent.apply(this.node, arguments); 
130    },
131
132    // private
133    initEvents : function(){
134        this.node.on("move", this.onMove, this);
135
136        if(this.node.disabled){
137            this.addClass("x-tree-node-disabled");
138                        if (this.checkbox) {
139                                this.checkbox.disabled = true;
140                        }           
141        }
142        if(this.node.hidden){
143            this.hide();
144        }
145        var ot = this.node.getOwnerTree();
146        var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
147        if(dd && (!this.node.isRoot || ot.rootVisible)){
148            Ext.dd.Registry.register(this.elNode, {
149                node: this.node,
150                handles: this.getDDHandles(),
151                isHandle: false
152            });
153        }
154    },
155
156    // private
157    getDDHandles : function(){
158        return [this.iconNode, this.textNode, this.elNode];
159    },
160
161/**
162 * Hides this node.
163 */
164    hide : function(){
165        this.node.hidden = true;
166        if(this.wrap){
167            this.wrap.style.display = "none";
168        }
169    },
170
171/**
172 * Shows this node.
173 */
174    show : function(){
175        this.node.hidden = false;
176        if(this.wrap){
177            this.wrap.style.display = "";
178        } 
179    },
180
181    // private
182    onContextMenu : function(e){
183        if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
184            e.preventDefault();
185            this.focus();
186            this.fireEvent("contextmenu", this.node, e);
187        }
188    },
189
190    // private
191    onClick : function(e){
192        if(this.dropping){
193            e.stopEvent();
194            return;
195        }
196        if(this.fireEvent("beforeclick", this.node, e) !== false){
197            var a = e.getTarget('a');
198            if(!this.disabled && this.node.attributes.href && a){
199                this.fireEvent("click", this.node, e);
200                return;
201            }else if(a && e.ctrlKey){
202                e.stopEvent();
203            }
204            e.preventDefault();
205            if(this.disabled){
206                return;
207            }
208
209            if(this.node.attributes.singleClickExpand && !this.animating && this.node.isExpandable()){
210                this.node.toggle();
211            }
212
213            this.fireEvent("click", this.node, e);
214        }else{
215            e.stopEvent();
216        }
217    },
218
219    // private
220    onDblClick : function(e){
221        e.preventDefault();
222        if(this.disabled){
223            return;
224        }
225        if(this.checkbox){
226            this.toggleCheck();
227        }
228        if(!this.animating && this.node.isExpandable()){
229            this.node.toggle();
230        }
231        this.fireEvent("dblclick", this.node, e);
232    },
233
234    onOver : function(e){
235        this.addClass('x-tree-node-over');
236    },
237
238    onOut : function(e){
239        this.removeClass('x-tree-node-over');
240    },
241
242    // private
243    onCheckChange : function(){
244        var checked = this.checkbox.checked;
245                // fix for IE6
246                this.checkbox.defaultChecked = checked;         
247        this.node.attributes.checked = checked;
248        this.fireEvent('checkchange', this.node, checked);
249    },
250
251    // private
252    ecClick : function(e){
253        if(!this.animating && this.node.isExpandable()){
254            this.node.toggle();
255        }
256    },
257
258    // private
259    startDrop : function(){
260        this.dropping = true;
261    },
262   
263    // delayed drop so the click event doesn't get fired on a drop
264    endDrop : function(){ 
265       setTimeout(function(){
266           this.dropping = false;
267       }.createDelegate(this), 50); 
268    },
269
270    // private
271    expand : function(){
272        this.updateExpandIcon();
273        this.ctNode.style.display = "";
274    },
275
276    // private
277    focus : function(){
278        if(!this.node.preventHScroll){
279            try{this.anchor.focus();
280            }catch(e){}
281        }else{
282            try{
283                var noscroll = this.node.getOwnerTree().getTreeEl().dom;
284                var l = noscroll.scrollLeft;
285                this.anchor.focus();
286                noscroll.scrollLeft = l;
287            }catch(e){}
288        }
289    },
290
291/**
292 * Sets the checked status of the tree node to the passed value, or, if no value was passed,
293 * toggles the checked status. If the node was rendered with no checkbox, this has no effect.
294 * @param {Boolean} (optional) The new checked status.
295 */
296    toggleCheck : function(value){
297        var cb = this.checkbox;
298        if(cb){
299            cb.checked = (value === undefined ? !cb.checked : value);
300            this.onCheckChange();
301        }
302    },
303
304    // private
305    blur : function(){
306        try{
307            this.anchor.blur();
308        }catch(e){} 
309    },
310
311    // private
312    animExpand : function(callback){
313        var ct = Ext.get(this.ctNode);
314        ct.stopFx();
315        if(!this.node.isExpandable()){
316            this.updateExpandIcon();
317            this.ctNode.style.display = "";
318            Ext.callback(callback);
319            return;
320        }
321        this.animating = true;
322        this.updateExpandIcon();
323       
324        ct.slideIn('t', {
325           callback : function(){
326               this.animating = false;
327               Ext.callback(callback);
328            },
329            scope: this,
330            duration: this.node.ownerTree.duration || .25
331        });
332    },
333
334    // private
335    highlight : function(){
336        var tree = this.node.getOwnerTree();
337        Ext.fly(this.wrap).highlight(
338            tree.hlColor || "C3DAF9",
339            {endColor: tree.hlBaseColor}
340        );
341    },
342
343    // private
344    collapse : function(){
345        this.updateExpandIcon();
346        this.ctNode.style.display = "none";
347    },
348
349    // private
350    animCollapse : function(callback){
351        var ct = Ext.get(this.ctNode);
352        ct.enableDisplayMode('block');
353        ct.stopFx();
354
355        this.animating = true;
356        this.updateExpandIcon();
357
358        ct.slideOut('t', {
359            callback : function(){
360               this.animating = false;
361               Ext.callback(callback);
362            },
363            scope: this,
364            duration: this.node.ownerTree.duration || .25
365        });
366    },
367
368    // private
369    getContainer : function(){
370        return this.ctNode; 
371    },
372
373    // private
374    getEl : function(){
375        return this.wrap; 
376    },
377
378    // private
379    appendDDGhost : function(ghostNode){
380        ghostNode.appendChild(this.elNode.cloneNode(true));
381    },
382
383    // private
384    getDDRepairXY : function(){
385        return Ext.lib.Dom.getXY(this.iconNode);
386    },
387
388    // private
389    onRender : function(){
390        this.render();   
391    },
392
393    // private
394    render : function(bulkRender){
395        var n = this.node, a = n.attributes;
396        var targetNode = n.parentNode ? 
397              n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
398       
399        if(!this.rendered){
400            this.rendered = true;
401
402            this.renderElements(n, a, targetNode, bulkRender);
403
404            if(a.qtip){
405               if(this.textNode.setAttributeNS){
406                   this.textNode.setAttributeNS("ext", "qtip", a.qtip);
407                   if(a.qtipTitle){
408                       this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
409                   }
410               }else{
411                   this.textNode.setAttribute("ext:qtip", a.qtip);
412                   if(a.qtipTitle){
413                       this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
414                   }
415               } 
416            }else if(a.qtipCfg){
417                a.qtipCfg.target = Ext.id(this.textNode);
418                Ext.QuickTips.register(a.qtipCfg);
419            }
420            this.initEvents();
421            if(!this.node.expanded){
422                this.updateExpandIcon(true);
423            }
424        }else{
425            if(bulkRender === true) {
426                targetNode.appendChild(this.wrap);
427            }
428        }
429    },
430
431    // private
432    renderElements : function(n, a, targetNode, bulkRender){
433        // add some indent caching, this helps performance when rendering a large tree
434        this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
435
436        var cb = typeof a.checked == 'boolean';
437
438        var href = a.href ? a.href : Ext.isGecko ? "" : "#";
439        var buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">',
440            '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
441            '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />',
442            '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
443            cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
444            '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ',
445             a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',n.text,"</span></a></div>",
446            '<ul class="x-tree-node-ct" style="display:none;"></ul>',
447            "</li>"].join('');
448
449        var nel;
450        if(bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())){
451            this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
452        }else{
453            this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
454        }
455       
456        this.elNode = this.wrap.childNodes[0];
457        this.ctNode = this.wrap.childNodes[1];
458        var cs = this.elNode.childNodes;
459        this.indentNode = cs[0];
460        this.ecNode = cs[1];
461        this.iconNode = cs[2];
462        var index = 3;
463        if(cb){
464            this.checkbox = cs[3];
465                        // fix for IE6
466                        this.checkbox.defaultChecked = this.checkbox.checked;                                           
467            index++;
468        }
469        this.anchor = cs[index];
470        this.textNode = cs[index].firstChild;
471    },
472
473/**
474 * Returns the &lt;a> element that provides focus for the node's UI.
475 * @return {HtmlElement} The DOM anchor element.
476 */
477    getAnchor : function(){
478        return this.anchor;
479    },
480   
481/**
482 * Returns the text node.
483 * @return {HtmlNode} The DOM text node.
484 */
485    getTextEl : function(){
486        return this.textNode;
487    },
488   
489/**
490 * Returns the icon &lt;img> element.
491 * @return {HtmlElement} The DOM image element.
492 */
493    getIconEl : function(){
494        return this.iconNode;
495    },
496
497/**
498 * Returns the checked status of the node. If the node was rendered with no
499 * checkbox, it returns false.
500 * @return {Boolean} The checked flag.
501 */
502    isChecked : function(){
503        return this.checkbox ? this.checkbox.checked : false; 
504    },
505
506    // private
507    updateExpandIcon : function(){
508        if(this.rendered){
509            var n = this.node, c1, c2;
510            var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
511            var hasChild = n.hasChildNodes();
512            if(hasChild || n.attributes.expandable){
513                if(n.expanded){
514                    cls += "-minus";
515                    c1 = "x-tree-node-collapsed";
516                    c2 = "x-tree-node-expanded";
517                }else{
518                    cls += "-plus";
519                    c1 = "x-tree-node-expanded";
520                    c2 = "x-tree-node-collapsed";
521                }
522                if(this.wasLeaf){
523                    this.removeClass("x-tree-node-leaf");
524                    this.wasLeaf = false;
525                }
526                if(this.c1 != c1 || this.c2 != c2){
527                    Ext.fly(this.elNode).replaceClass(c1, c2);
528                    this.c1 = c1; this.c2 = c2;
529                }
530            }else{
531                if(!this.wasLeaf){
532                    Ext.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
533                    delete this.c1;
534                    delete this.c2;
535                    this.wasLeaf = true;
536                }
537            }
538            var ecc = "x-tree-ec-icon "+cls;
539            if(this.ecc != ecc){
540                this.ecNode.className = ecc;
541                this.ecc = ecc;
542            }
543        }
544    },
545   
546    // private
547    onIdChange: function(id){
548        if(this.rendered){
549            this.elNode.setAttribute('ext:tree-node-id', id);
550        }
551    },
552
553    // private
554    getChildIndent : function(){
555        if(!this.childIndent){
556            var buf = [];
557            var p = this.node;
558            while(p){
559                if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
560                    if(!p.isLast()) {
561                        buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
562                    } else {
563                        buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
564                    }
565                }
566                p = p.parentNode;
567            }
568            this.childIndent = buf.join("");
569        }
570        return this.childIndent;
571    },
572
573    // private
574    renderIndent : function(){
575        if(this.rendered){
576            var indent = "";
577            var p = this.node.parentNode;
578            if(p){
579                indent = p.ui.getChildIndent();
580            }
581            if(this.indentMarkup != indent){ // don't rerender if not required
582                this.indentNode.innerHTML = indent;
583                this.indentMarkup = indent;
584            }
585            this.updateExpandIcon();
586        }
587    },
588
589    destroy : function(){
590        if(this.elNode){
591            Ext.dd.Registry.unregister(this.elNode.id);
592        }
593        delete this.elNode;
594        delete this.ctNode;
595        delete this.indentNode;
596        delete this.ecNode;
597        delete this.iconNode;
598        delete this.checkbox;
599        delete this.anchor;
600        delete this.textNode;
601       
602        if (this.holder){
603             delete this.wrap;
604             Ext.removeNode(this.holder);
605             delete this.holder;
606        }else{
607            Ext.removeNode(this.wrap);
608            delete this.wrap;
609        }
610    }
611};
612
613/**
614 * @class Ext.tree.RootTreeNodeUI
615 * This class provides the default UI implementation for <b>root</b> Ext TreeNodes.
616 * The RootTreeNode UI implementation allows customizing the appearance of the root tree node.<br>
617 * <p>
618 * If you are customizing the Tree's user interface, you
619 * may need to extend this class, but you should never need to instantiate this class.<br>
620 */
621Ext.tree.RootTreeNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
622    // private
623    render : function(){
624        if(!this.rendered){
625            var targetNode = this.node.ownerTree.innerCt.dom;
626            this.node.expanded = true;
627            targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
628            this.wrap = this.ctNode = targetNode.firstChild;
629        }
630    },
631    collapse : Ext.emptyFn,
632    expand : Ext.emptyFn
633});
Note: See TracBrowser for help on using the repository browser.