+<html>\r
+<head>\r
+ <title>The source code</title>\r
+ <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
+ <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
+</head>\r
+<body onload="prettyPrint();">\r
+ <pre class="prettyprint lang-js"><div id="cls-Ext.tree.TreeDropZone"></div>/**\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
+ <div id="cfg-Ext.tree.TreeDropZone-allowParentInsert"></div>/**\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
+ <div id="cfg-Ext.tree.TreeDropZone-allowContainerDrop"></div>/**\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
+ <div id="cfg-Ext.tree.TreeDropZone-appendOnly"></div>/**\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
+ <div id="prop-Ext.tree.TreeDropZone-tree"></div>/**\r
+ * The TreePanel for this drop zone\r
+ * @type Ext.tree.TreePanel\r
+ * @property\r
+ */\r
+ this.tree = tree;\r
+ <div id="prop-Ext.tree.TreeDropZone-dragOverData"></div>/**\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
+ <div id="cfg-Ext.tree.TreeDropZone-ddGroup"></div>/**\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
+ <div id="cfg-Ext.tree.TreeDropZone-expandDelay"></div>/**\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
+}</pre> \r
+</body>\r
+</html>
\ No newline at end of file