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