text: /*!
   * Ext JS Library 3.3.0
   * Copyright(c) 2006-2010 Ext JS, Inc.
   * licensing@extjs.com
   * http://www.extjs.com/license
   */
  /**
   * @class Ext.tree.TreeDropZone
   * @extends Ext.dd.DropZone
   * @constructor
   * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dropping
   * @param {Object} config
   */
  if(Ext.dd.DropZone){
      
  Ext.tree.TreeDropZone = function(tree, config){
      /**
       * @cfg {Boolean} allowParentInsert
       * Allow inserting a dragged node between an expanded parent node and its first child that will become a
       * sibling of the parent when dropped (defaults to false)
       */
      this.allowParentInsert = config.allowParentInsert || false;
      /**
       * @cfg {String} allowContainerDrop
       * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)
       */
      this.allowContainerDrop = config.allowContainerDrop || false;
      /**
       * @cfg {String} appendOnly
       * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)
       */
      this.appendOnly = config.appendOnly || false;
  
      Ext.tree.TreeDropZone.superclass.constructor.call(this, tree.getTreeEl(), config);
      /**
      * The TreePanel for this drop zone
      * @type Ext.tree.TreePanel
      * @property
      */
      this.tree = tree;
      /**
      * Arbitrary data that can be associated with this tree and will be included in the event object that gets
      * passed to any nodedragover event handler (defaults to {})
      * @type Ext.tree.TreePanel
      * @property
      */
      this.dragOverData = {};
      // private
      this.lastInsertClass = "x-tree-no-status";
  };
  
  Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, {
      /**
       * @cfg {String} ddGroup
       * A named drag drop group to which this object belongs.  If a group is specified, then this object will only
       * interact with other drag drop objects in the same group (defaults to 'TreeDD').
       */
      ddGroup : "TreeDD",
  
      /**
       * @cfg {String} expandDelay
       * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node
       * over the target (defaults to 1000)
       */
      expandDelay : 1000,
  
      // private
      expandNode : function(node){
          if(node.hasChildNodes() && !node.isExpanded()){
              node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
          }
      },
  
      // private
      queueExpand : function(node){
          this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
      },
  
      // private
      cancelExpand : function(){
          if(this.expandProcId){
              clearTimeout(this.expandProcId);
              this.expandProcId = false;
          }
      },
  
      // private
      isValidDropPoint : function(n, pt, dd, e, data){
          if(!n || !data){ return false; }
          var targetNode = n.node;
          var dropNode = data.node;
          // default drop rules
          if(!(targetNode && targetNode.isTarget && pt)){
              return false;
          }
          if(pt == "append" && targetNode.allowChildren === false){
              return false;
          }
          if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
              return false;
          }
          if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
              return false;
          }
          // reuse the object
          var overEvent = this.dragOverData;
          overEvent.tree = this.tree;
          overEvent.target = targetNode;
          overEvent.data = data;
          overEvent.point = pt;
          overEvent.source = dd;
          overEvent.rawEvent = e;
          overEvent.dropNode = dropNode;
          overEvent.cancel = false;  
          var result = this.tree.fireEvent("nodedragover", overEvent);
          return overEvent.cancel === false && result !== false;
      },
  
      // private
      getDropPoint : function(e, n, dd){
          var tn = n.node;
          if(tn.isRoot){
              return tn.allowChildren !== false ? "append" : false; // always append for root
          }
          var dragEl = n.ddel;
          var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
          var y = Ext.lib.Event.getPageY(e);
          var noAppend = tn.allowChildren === false || tn.isLeaf();
          if(this.appendOnly || tn.parentNode.allowChildren === false){
              return noAppend ? false : "append";
          }
          var noBelow = false;
          if(!this.allowParentInsert){
              noBelow = tn.hasChildNodes() && tn.isExpanded();
          }
          var q = (b - t) / (noAppend ? 2 : 3);
          if(y >= t && y < (t + q)){
              return "above";
          }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
              return "below";
          }else{
              return "append";
          }
      },
  
      // private
      onNodeEnter : function(n, dd, e, data){
          this.cancelExpand();
      },
      
      onContainerOver : function(dd, e, data) {
          if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
              return this.dropAllowed;
          }
          return this.dropNotAllowed;
      },
  
      // private
      onNodeOver : function(n, dd, e, data){
          var pt = this.getDropPoint(e, n, dd);
          var node = n.node;
          
          // auto node expand check
          if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
              this.queueExpand(node);
          }else if(pt != "append"){
              this.cancelExpand();
          }
          
          // set the insert point style on the target node
          var returnCls = this.dropNotAllowed;
          if(this.isValidDropPoint(n, pt, dd, e, data)){
             if(pt){
                 var el = n.ddel;
                 var cls;
                 if(pt == "above"){
                     returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
                     cls = "x-tree-drag-insert-above";
                 }else if(pt == "below"){
                     returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
                     cls = "x-tree-drag-insert-below";
                 }else{
                     returnCls = "x-tree-drop-ok-append";
                     cls = "x-tree-drag-append";
                 }
                 if(this.lastInsertClass != cls){
                     Ext.fly(el).replaceClass(this.lastInsertClass, cls);
                     this.lastInsertClass = cls;
                 }
             }
         }
         return returnCls;
      },
  
      // private
      onNodeOut : function(n, dd, e, data){
          this.cancelExpand();
          this.removeDropIndicators(n);
      },
  
      // private
      onNodeDrop : function(n, dd, e, data){
          var point = this.getDropPoint(e, n, dd);
          var targetNode = n.node;
          targetNode.ui.startDrop();
          if(!this.isValidDropPoint(n, point, dd, e, data)){
              targetNode.ui.endDrop();
              return false;
          }
          // first try to find the drop node
          var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
          return this.processDrop(targetNode, data, point, dd, e, dropNode);
      },
      
      onContainerDrop : function(dd, e, data){
          if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
              var targetNode = this.tree.getRootNode();       
              targetNode.ui.startDrop();
              var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, 'append', e) : null);
              return this.processDrop(targetNode, data, 'append', dd, e, dropNode);
          }
          return false;
      },
      
      // private
      processDrop: function(target, data, point, dd, e, dropNode){
          var dropEvent = {
              tree : this.tree,
              target: target,
              data: data,
              point: point,
              source: dd,
              rawEvent: e,
              dropNode: dropNode,
              cancel: !dropNode,
              dropStatus: false
          };
          var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
          if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
              target.ui.endDrop();
              return dropEvent.dropStatus;
          }
      
          target = dropEvent.target;
          if(point == 'append' && !target.isExpanded()){
              target.expand(false, null, function(){
                  this.completeDrop(dropEvent);
              }.createDelegate(this));
          }else{
              this.completeDrop(dropEvent);
          }
          return true;
      },
  
      // private
      completeDrop : function(de){
          var ns = de.dropNode, p = de.point, t = de.target;
          if(!Ext.isArray(ns)){
              ns = [ns];
          }
          var n;
          for(var i = 0, len = ns.length; i < len; i++){
              n = ns[i];
              if(p == "above"){
                  t.parentNode.insertBefore(n, t);
              }else if(p == "below"){
                  t.parentNode.insertBefore(n, t.nextSibling);
              }else{
                  t.appendChild(n);
              }
          }
          n.ui.focus();
          if(Ext.enableFx && this.tree.hlDrop){
              n.ui.highlight();
          }
          t.ui.endDrop();
          this.tree.fireEvent("nodedrop", de);
      },
  
      // private
      afterNodeMoved : function(dd, data, e, targetNode, dropNode){
          if(Ext.enableFx && this.tree.hlDrop){
              dropNode.ui.focus();
              dropNode.ui.highlight();
          }
          this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
      },
  
      // private
      getTree : function(){
          return this.tree;
      },
  
      // private
      removeDropIndicators : function(n){
          if(n && n.ddel){
              var el = n.ddel;
              Ext.fly(el).removeClass([
                      "x-tree-drag-insert-above",
                      "x-tree-drag-insert-below",
                      "x-tree-drag-append"]);
              this.lastInsertClass = "_noclass";
          }
      },
  
      // private
      beforeDragDrop : function(target, e, id){
          this.cancelExpand();
          return true;
      },
  
      // private
      afterRepair : function(data){
          if(data && Ext.enableFx){
              data.node.ui.highlight();
          }
          this.hideProxy();
      }    
  });
  
  }