3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4 <title>The source code</title>
5 <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6 <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8 <body onload="prettyPrint();">
9 <pre class="prettyprint lang-js">/*!
10 * Ext JS Library 3.3.1
11 * Copyright(c) 2006-2010 Sencha Inc.
12 * licensing@sencha.com
13 * http://www.sencha.com/license
15 <div id="cls-Ext.tree.TreeNodeUI"></div>/**
16 * @class Ext.tree.TreeNodeUI
17 * This class provides the default UI implementation for Ext TreeNodes.
18 * The TreeNode UI implementation is separate from the
19 * tree implementation, and allows customizing of the appearance of
22 * If you are customizing the Tree's user interface, you
23 * may need to extend this class, but you should never need to instantiate this class.<br>
25 * This class provides access to the user interface components of an Ext TreeNode, through
26 * {@link Ext.tree.TreeNode#getUI}
28 Ext.tree.TreeNodeUI = Ext.extend(Object, {
30 constructor : function(node){
36 ecc: 'x-tree-ec-icon x-tree-elbow',
37 emptyIcon: Ext.BLANK_IMAGE_URL
42 removeChild : function(node){
44 this.ctNode.removeChild(node.ui.getEl());
49 beforeLoad : function(){
50 this.addClass("x-tree-node-loading");
54 afterLoad : function(){
55 this.removeClass("x-tree-node-loading");
59 onTextChange : function(node, text, oldText){
61 this.textNode.innerHTML = text;
66 onIconClsChange : function(node, cls, oldCls){
68 Ext.fly(this.iconNode).replaceClass(oldCls, cls);
73 onIconChange : function(node, icon){
75 //'<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
76 var empty = Ext.isEmpty(icon);
77 this.iconNode.src = empty ? this.emptyIcon : icon;
78 Ext.fly(this.iconNode)[empty ? 'removeClass' : 'addClass']('x-tree-node-inline-icon');
83 onTipChange : function(node, tip, title){
85 var hasTitle = Ext.isDefined(title);
86 if(this.textNode.setAttributeNS){
87 this.textNode.setAttributeNS("ext", "qtip", tip);
89 this.textNode.setAttributeNS("ext", "qtitle", title);
92 this.textNode.setAttribute("ext:qtip", tip);
94 this.textNode.setAttribute("ext:qtitle", title);
101 onHrefChange : function(node, href, target){
103 this.anchor.href = this.getHref(href);
104 if(Ext.isDefined(target)){
105 this.anchor.target = target;
111 onClsChange : function(node, cls, oldCls){
113 Ext.fly(this.elNode).replaceClass(oldCls, cls);
118 onDisableChange : function(node, state){
119 this.disabled = state;
121 this.checkbox.disabled = state;
123 this[state ? 'addClass' : 'removeClass']('x-tree-node-disabled');
127 onSelectedChange : function(state){
130 this.addClass("x-tree-selected");
133 this.removeClass("x-tree-selected");
138 onMove : function(tree, node, oldParent, newParent, index, refNode){
139 this.childIndent = null;
141 var targetNode = newParent.ui.getContainer();
142 if(!targetNode){//target not rendered
143 this.holder = document.createElement("div");
144 this.holder.appendChild(this.wrap);
147 var insertBefore = refNode ? refNode.ui.getEl() : null;
149 targetNode.insertBefore(this.wrap, insertBefore);
151 targetNode.appendChild(this.wrap);
153 this.node.renderIndent(true, oldParent != newParent);
157 <div id="method-Ext.tree.TreeNodeUI-addClass"></div>/**
158 * Adds one or more CSS classes to the node's UI element.
159 * Duplicate classes are automatically filtered out.
160 * @param {String/Array} className The CSS class to add, or an array of classes
162 addClass : function(cls){
164 Ext.fly(this.elNode).addClass(cls);
168 <div id="method-Ext.tree.TreeNodeUI-removeClass"></div>/**
169 * Removes one or more CSS classes from the node's UI element.
170 * @param {String/Array} className The CSS class to remove, or an array of classes
172 removeClass : function(cls){
174 Ext.fly(this.elNode).removeClass(cls);
181 this.holder = document.createElement("div");
182 this.holder.appendChild(this.wrap);
187 fireEvent : function(){
188 return this.node.fireEvent.apply(this.node, arguments);
192 initEvents : function(){
193 this.node.on("move", this.onMove, this);
195 if(this.node.disabled){
196 this.onDisableChange(this.node, true);
198 if(this.node.hidden){
201 var ot = this.node.getOwnerTree();
202 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
203 if(dd && (!this.node.isRoot || ot.rootVisible)){
204 Ext.dd.Registry.register(this.elNode, {
206 handles: this.getDDHandles(),
213 getDDHandles : function(){
214 return [this.iconNode, this.textNode, this.elNode];
217 <div id="method-Ext.tree.TreeNodeUI-hide"></div>/**
221 this.node.hidden = true;
223 this.wrap.style.display = "none";
227 <div id="method-Ext.tree.TreeNodeUI-show"></div>/**
231 this.node.hidden = false;
233 this.wrap.style.display = "";
238 onContextMenu : function(e){
239 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
242 this.fireEvent("contextmenu", this.node, e);
247 onClick : function(e){
252 if(this.fireEvent("beforeclick", this.node, e) !== false){
253 var a = e.getTarget('a');
254 if(!this.disabled && this.node.attributes.href && a){
255 this.fireEvent("click", this.node, e);
257 }else if(a && e.ctrlKey){
265 if(this.node.attributes.singleClickExpand && !this.animating && this.node.isExpandable()){
269 this.fireEvent("click", this.node, e);
276 onDblClick : function(e){
281 if(this.fireEvent("beforedblclick", this.node, e) !== false){
285 if(!this.animating && this.node.isExpandable()){
288 this.fireEvent("dblclick", this.node, e);
292 onOver : function(e){
293 this.addClass('x-tree-node-over');
297 this.removeClass('x-tree-node-over');
301 onCheckChange : function(){
302 var checked = this.checkbox.checked;
304 this.checkbox.defaultChecked = checked;
305 this.node.attributes.checked = checked;
306 this.fireEvent('checkchange', this.node, checked);
310 ecClick : function(e){
311 if(!this.animating && this.node.isExpandable()){
317 startDrop : function(){
318 this.dropping = true;
321 // delayed drop so the click event doesn't get fired on a drop
322 endDrop : function(){
323 setTimeout(function(){
324 this.dropping = false;
325 }.createDelegate(this), 50);
330 this.updateExpandIcon();
331 this.ctNode.style.display = "";
336 if(!this.node.preventHScroll){
337 try{this.anchor.focus();
341 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
342 var l = noscroll.scrollLeft;
344 noscroll.scrollLeft = l;
349 <div id="method-Ext.tree.TreeNodeUI-toggleCheck"></div>/**
350 * Sets the checked status of the tree node to the passed value, or, if no value was passed,
351 * toggles the checked status. If the node was rendered with no checkbox, this has no effect.
352 * @param {Boolean} value (optional) The new checked status.
354 toggleCheck : function(value){
355 var cb = this.checkbox;
357 cb.checked = (value === undefined ? !cb.checked : value);
358 this.onCheckChange();
370 animExpand : function(callback){
371 var ct = Ext.get(this.ctNode);
373 if(!this.node.isExpandable()){
374 this.updateExpandIcon();
375 this.ctNode.style.display = "";
376 Ext.callback(callback);
379 this.animating = true;
380 this.updateExpandIcon();
383 callback : function(){
384 this.animating = false;
385 Ext.callback(callback);
388 duration: this.node.ownerTree.duration || .25
393 highlight : function(){
394 var tree = this.node.getOwnerTree();
395 Ext.fly(this.wrap).highlight(
396 tree.hlColor || "C3DAF9",
397 {endColor: tree.hlBaseColor}
402 collapse : function(){
403 this.updateExpandIcon();
404 this.ctNode.style.display = "none";
408 animCollapse : function(callback){
409 var ct = Ext.get(this.ctNode);
410 ct.enableDisplayMode('block');
413 this.animating = true;
414 this.updateExpandIcon();
417 callback : function(){
418 this.animating = false;
419 Ext.callback(callback);
422 duration: this.node.ownerTree.duration || .25
427 getContainer : function(){
431 <div id="method-Ext.tree.TreeNodeUI-getEl"></div>/**
432 * Returns the element which encapsulates this node.
433 * @return {HtmlElement} The DOM element. The default implementation uses a <code><li></code>.
440 appendDDGhost : function(ghostNode){
441 ghostNode.appendChild(this.elNode.cloneNode(true));
445 getDDRepairXY : function(){
446 return Ext.lib.Dom.getXY(this.iconNode);
450 onRender : function(){
455 render : function(bulkRender){
456 var n = this.node, a = n.attributes;
457 var targetNode = n.parentNode ?
458 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
461 this.rendered = true;
463 this.renderElements(n, a, targetNode, bulkRender);
466 this.onTipChange(n, a.qtip, a.qtipTitle);
468 a.qtipCfg.target = Ext.id(this.textNode);
469 Ext.QuickTips.register(a.qtipCfg);
472 if(!this.node.expanded){
473 this.updateExpandIcon(true);
476 if(bulkRender === true) {
477 targetNode.appendChild(this.wrap);
483 renderElements : function(n, a, targetNode, bulkRender){
484 // add some indent caching, this helps performance when rendering a large tree
485 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
487 var cb = Ext.isBoolean(a.checked),
489 href = this.getHref(a.href),
490 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">',
491 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
492 '<img alt="" src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />',
493 '<img alt="" src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
494 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
495 '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ',
496 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',n.text,"</span></a></div>",
497 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
500 if(bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())){
501 this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
503 this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
506 this.elNode = this.wrap.childNodes[0];
507 this.ctNode = this.wrap.childNodes[1];
508 var cs = this.elNode.childNodes;
509 this.indentNode = cs[0];
511 this.iconNode = cs[2];
514 this.checkbox = cs[3];
516 this.checkbox.defaultChecked = this.checkbox.checked;
519 this.anchor = cs[index];
520 this.textNode = cs[index].firstChild;
524 * @private Gets a normalized href for the node.
525 * @param {String} href
527 getHref : function(href){
528 return Ext.isEmpty(href) ? (Ext.isGecko ? '' : '#') : href;
531 <div id="method-Ext.tree.TreeNodeUI-getAnchor"></div>/**
532 * Returns the <a> element that provides focus for the node's UI.
533 * @return {HtmlElement} The DOM anchor element.
535 getAnchor : function(){
539 <div id="method-Ext.tree.TreeNodeUI-getTextEl"></div>/**
540 * Returns the text node.
541 * @return {HtmlNode} The DOM text node.
543 getTextEl : function(){
544 return this.textNode;
547 <div id="method-Ext.tree.TreeNodeUI-getIconEl"></div>/**
548 * Returns the icon <img> element.
549 * @return {HtmlElement} The DOM image element.
551 getIconEl : function(){
552 return this.iconNode;
555 <div id="method-Ext.tree.TreeNodeUI-isChecked"></div>/**
556 * Returns the checked status of the node. If the node was rendered with no
557 * checkbox, it returns false.
558 * @return {Boolean} The checked flag.
560 isChecked : function(){
561 return this.checkbox ? this.checkbox.checked : false;
565 updateExpandIcon : function(){
570 cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow",
571 hasChild = n.hasChildNodes();
572 if(hasChild || n.attributes.expandable){
575 c1 = "x-tree-node-collapsed";
576 c2 = "x-tree-node-expanded";
579 c1 = "x-tree-node-expanded";
580 c2 = "x-tree-node-collapsed";
583 this.removeClass("x-tree-node-leaf");
584 this.wasLeaf = false;
586 if(this.c1 != c1 || this.c2 != c2){
587 Ext.fly(this.elNode).replaceClass(c1, c2);
588 this.c1 = c1; this.c2 = c2;
592 Ext.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-collapsed");
598 var ecc = "x-tree-ec-icon "+cls;
600 this.ecNode.className = ecc;
607 onIdChange: function(id){
609 this.elNode.setAttribute('ext:tree-node-id', id);
614 getChildIndent : function(){
615 if(!this.childIndent){
619 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
621 buf.unshift('<img alt="" src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
623 buf.unshift('<img alt="" src="'+this.emptyIcon+'" class="x-tree-icon" />');
628 this.childIndent = buf.join("");
630 return this.childIndent;
634 renderIndent : function(){
637 p = this.node.parentNode;
639 indent = p.ui.getChildIndent();
641 if(this.indentMarkup != indent){ // don't rerender if not required
642 this.indentNode.innerHTML = indent;
643 this.indentMarkup = indent;
645 this.updateExpandIcon();
649 destroy : function(){
651 Ext.dd.Registry.unregister(this.elNode.id);
654 Ext.each(['textnode', 'anchor', 'checkbox', 'indentNode', 'ecNode', 'iconNode', 'elNode', 'ctNode', 'wrap', 'holder'], function(el){
656 Ext.fly(this[el]).remove();
664 <div id="cls-Ext.tree.RootTreeNodeUI"></div>/**
665 * @class Ext.tree.RootTreeNodeUI
666 * This class provides the default UI implementation for <b>root</b> Ext TreeNodes.
667 * The RootTreeNode UI implementation allows customizing the appearance of the root tree node.<br>
669 * If you are customizing the Tree's user interface, you
670 * may need to extend this class, but you should never need to instantiate this class.<br>
672 Ext.tree.RootTreeNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
676 var targetNode = this.node.ownerTree.innerCt.dom;
677 this.node.expanded = true;
678 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
679 this.wrap = this.ctNode = targetNode.firstChild;
682 collapse : Ext.emptyFn,