-/**\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();
+ }
+});
+