TreeNodeUI.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:19k
源码类别:

中间件编程

开发平台:

JavaScript

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