TreeDropZone.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:11k
源码类别:

JavaScript

开发平台:

JavaScript

  1. /*!  * Ext JS Library 3.1.0  * Copyright(c) 2006-2009 Ext JS, LLC  * licensing@extjs.com  * http://www.extjs.com/license  */ /**
  2.  * @class Ext.tree.TreeDropZone
  3.  * @extends Ext.dd.DropZone
  4.  * @constructor
  5.  * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dropping
  6.  * @param {Object} config
  7.  */
  8. if(Ext.dd.DropZone){
  9.     
  10. Ext.tree.TreeDropZone = function(tree, config){
  11.     /**
  12.      * @cfg {Boolean} allowParentInsert
  13.      * Allow inserting a dragged node between an expanded parent node and its first child that will become a
  14.      * sibling of the parent when dropped (defaults to false)
  15.      */
  16.     this.allowParentInsert = config.allowParentInsert || false;
  17.     /**
  18.      * @cfg {String} allowContainerDrop
  19.      * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)
  20.      */
  21.     this.allowContainerDrop = config.allowContainerDrop || false;
  22.     /**
  23.      * @cfg {String} appendOnly
  24.      * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)
  25.      */
  26.     this.appendOnly = config.appendOnly || false;
  27.     Ext.tree.TreeDropZone.superclass.constructor.call(this, tree.getTreeEl(), config);
  28.     /**
  29.     * The TreePanel for this drop zone
  30.     * @type Ext.tree.TreePanel
  31.     * @property
  32.     */
  33.     this.tree = tree;
  34.     /**
  35.     * Arbitrary data that can be associated with this tree and will be included in the event object that gets
  36.     * passed to any nodedragover event handler (defaults to {})
  37.     * @type Ext.tree.TreePanel
  38.     * @property
  39.     */
  40.     this.dragOverData = {};
  41.     // private
  42.     this.lastInsertClass = "x-tree-no-status";
  43. };
  44. Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, {
  45.     /**
  46.      * @cfg {String} ddGroup
  47.      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only
  48.      * interact with other drag drop objects in the same group (defaults to 'TreeDD').
  49.      */
  50.     ddGroup : "TreeDD",
  51.     /**
  52.      * @cfg {String} expandDelay
  53.      * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node
  54.      * over the target (defaults to 1000)
  55.      */
  56.     expandDelay : 1000,
  57.     // private
  58.     expandNode : function(node){
  59.         if(node.hasChildNodes() && !node.isExpanded()){
  60.             node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
  61.         }
  62.     },
  63.     // private
  64.     queueExpand : function(node){
  65.         this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
  66.     },
  67.     // private
  68.     cancelExpand : function(){
  69.         if(this.expandProcId){
  70.             clearTimeout(this.expandProcId);
  71.             this.expandProcId = false;
  72.         }
  73.     },
  74.     // private
  75.     isValidDropPoint : function(n, pt, dd, e, data){
  76.         if(!n || !data){ return false; }
  77.         var targetNode = n.node;
  78.         var dropNode = data.node;
  79.         // default drop rules
  80.         if(!(targetNode && targetNode.isTarget && pt)){
  81.             return false;
  82.         }
  83.         if(pt == "append" && targetNode.allowChildren === false){
  84.             return false;
  85.         }
  86.         if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
  87.             return false;
  88.         }
  89.         if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
  90.             return false;
  91.         }
  92.         // reuse the object
  93.         var overEvent = this.dragOverData;
  94.         overEvent.tree = this.tree;
  95.         overEvent.target = targetNode;
  96.         overEvent.data = data;
  97.         overEvent.point = pt;
  98.         overEvent.source = dd;
  99.         overEvent.rawEvent = e;
  100.         overEvent.dropNode = dropNode;
  101.         overEvent.cancel = false;  
  102.         var result = this.tree.fireEvent("nodedragover", overEvent);
  103.         return overEvent.cancel === false && result !== false;
  104.     },
  105.     // private
  106.     getDropPoint : function(e, n, dd){
  107.         var tn = n.node;
  108.         if(tn.isRoot){
  109.             return tn.allowChildren !== false ? "append" : false; // always append for root
  110.         }
  111.         var dragEl = n.ddel;
  112.         var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
  113.         var y = Ext.lib.Event.getPageY(e);
  114.         var noAppend = tn.allowChildren === false || tn.isLeaf();
  115.         if(this.appendOnly || tn.parentNode.allowChildren === false){
  116.             return noAppend ? false : "append";
  117.         }
  118.         var noBelow = false;
  119.         if(!this.allowParentInsert){
  120.             noBelow = tn.hasChildNodes() && tn.isExpanded();
  121.         }
  122.         var q = (b - t) / (noAppend ? 2 : 3);
  123.         if(y >= t && y < (t + q)){
  124.             return "above";
  125.         }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
  126.             return "below";
  127.         }else{
  128.             return "append";
  129.         }
  130.     },
  131.     // private
  132.     onNodeEnter : function(n, dd, e, data){
  133.         this.cancelExpand();
  134.     },
  135.     
  136.     onContainerOver : function(dd, e, data) {
  137.         if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
  138.             return this.dropAllowed;
  139.         }
  140.         return this.dropNotAllowed;
  141.     },
  142.     // private
  143.     onNodeOver : function(n, dd, e, data){
  144.         var pt = this.getDropPoint(e, n, dd);
  145.         var node = n.node;
  146.         
  147.         // auto node expand check
  148.         if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
  149.             this.queueExpand(node);
  150.         }else if(pt != "append"){
  151.             this.cancelExpand();
  152.         }
  153.         
  154.         // set the insert point style on the target node
  155.         var returnCls = this.dropNotAllowed;
  156.         if(this.isValidDropPoint(n, pt, dd, e, data)){
  157.            if(pt){
  158.                var el = n.ddel;
  159.                var cls;
  160.                if(pt == "above"){
  161.                    returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
  162.                    cls = "x-tree-drag-insert-above";
  163.                }else if(pt == "below"){
  164.                    returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
  165.                    cls = "x-tree-drag-insert-below";
  166.                }else{
  167.                    returnCls = "x-tree-drop-ok-append";
  168.                    cls = "x-tree-drag-append";
  169.                }
  170.                if(this.lastInsertClass != cls){
  171.                    Ext.fly(el).replaceClass(this.lastInsertClass, cls);
  172.                    this.lastInsertClass = cls;
  173.                }
  174.            }
  175.        }
  176.        return returnCls;
  177.     },
  178.     // private
  179.     onNodeOut : function(n, dd, e, data){
  180.         this.cancelExpand();
  181.         this.removeDropIndicators(n);
  182.     },
  183.     // private
  184.     onNodeDrop : function(n, dd, e, data){
  185.         var point = this.getDropPoint(e, n, dd);
  186.         var targetNode = n.node;
  187.         targetNode.ui.startDrop();
  188.         if(!this.isValidDropPoint(n, point, dd, e, data)){
  189.             targetNode.ui.endDrop();
  190.             return false;
  191.         }
  192.         // first try to find the drop node
  193.         var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
  194.         return this.processDrop(targetNode, data, point, dd, e, dropNode);
  195.     },
  196.     
  197.     onContainerDrop : function(dd, e, data){
  198.         if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
  199.             var targetNode = this.tree.getRootNode();       
  200.             targetNode.ui.startDrop();
  201.             var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, 'append', e) : null);
  202.             return this.processDrop(targetNode, data, 'append', dd, e, dropNode);
  203.         }
  204.         return false;
  205.     },
  206.     
  207.     // private
  208.     processDrop: function(target, data, point, dd, e, dropNode){
  209.         var dropEvent = {
  210.             tree : this.tree,
  211.             target: target,
  212.             data: data,
  213.             point: point,
  214.             source: dd,
  215.             rawEvent: e,
  216.             dropNode: dropNode,
  217.             cancel: !dropNode,
  218.             dropStatus: false
  219.         };
  220.         var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
  221.         if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
  222.             target.ui.endDrop();
  223.             return dropEvent.dropStatus;
  224.         }
  225.     
  226.         target = dropEvent.target;
  227.         if(point == 'append' && !target.isExpanded()){
  228.             target.expand(false, null, function(){
  229.                 this.completeDrop(dropEvent);
  230.             }.createDelegate(this));
  231.         }else{
  232.             this.completeDrop(dropEvent);
  233.         }
  234.         return true;
  235.     },
  236.     // private
  237.     completeDrop : function(de){
  238.         var ns = de.dropNode, p = de.point, t = de.target;
  239.         if(!Ext.isArray(ns)){
  240.             ns = [ns];
  241.         }
  242.         var n;
  243.         for(var i = 0, len = ns.length; i < len; i++){
  244.             n = ns[i];
  245.             if(p == "above"){
  246.                 t.parentNode.insertBefore(n, t);
  247.             }else if(p == "below"){
  248.                 t.parentNode.insertBefore(n, t.nextSibling);
  249.             }else{
  250.                 t.appendChild(n);
  251.             }
  252.         }
  253.         n.ui.focus();
  254.         if(Ext.enableFx && this.tree.hlDrop){
  255.             n.ui.highlight();
  256.         }
  257.         t.ui.endDrop();
  258.         this.tree.fireEvent("nodedrop", de);
  259.     },
  260.     // private
  261.     afterNodeMoved : function(dd, data, e, targetNode, dropNode){
  262.         if(Ext.enableFx && this.tree.hlDrop){
  263.             dropNode.ui.focus();
  264.             dropNode.ui.highlight();
  265.         }
  266.         this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
  267.     },
  268.     // private
  269.     getTree : function(){
  270.         return this.tree;
  271.     },
  272.     // private
  273.     removeDropIndicators : function(n){
  274.         if(n && n.ddel){
  275.             var el = n.ddel;
  276.             Ext.fly(el).removeClass([
  277.                     "x-tree-drag-insert-above",
  278.                     "x-tree-drag-insert-below",
  279.                     "x-tree-drag-append"]);
  280.             this.lastInsertClass = "_noclass";
  281.         }
  282.     },
  283.     // private
  284.     beforeDragDrop : function(target, e, id){
  285.         this.cancelExpand();
  286.         return true;
  287.     },
  288.     // private
  289.     afterRepair : function(data){
  290.         if(data && Ext.enableFx){
  291.             data.node.ui.highlight();
  292.         }
  293.         this.hideProxy();
  294.     }    
  295. });
  296. }