4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-tree-ViewDropZone'>/**
19 </span> * @class Ext.tree.ViewDropZone
20 * @extends Ext.view.DropZone
23 Ext.define('Ext.tree.ViewDropZone', {
24 extend: 'Ext.view.DropZone',
26 <span id='Ext-tree-ViewDropZone-cfg-allowParentInsert'> /**
27 </span> * @cfg {Boolean} allowParentInsert
28 * Allow inserting a dragged node between an expanded parent node and its first child that will become a
29 * sibling of the parent when dropped (defaults to false)
31 allowParentInserts: false,
33 <span id='Ext-tree-ViewDropZone-cfg-allowContainerDrop'> /**
34 </span> * @cfg {String} allowContainerDrop
35 * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)
37 allowContainerDrops: false,
39 <span id='Ext-tree-ViewDropZone-cfg-appendOnly'> /**
40 </span> * @cfg {String} appendOnly
41 * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)
45 <span id='Ext-tree-ViewDropZone-cfg-expandDelay'> /**
46 </span> * @cfg {String} expandDelay
47 * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node
48 * over the target (defaults to 500)
52 indicatorCls: 'x-tree-ddindicator',
55 expandNode : function(node) {
57 if (!node.isLeaf() && !node.isExpanded()) {
59 this.expandProcId = false;
64 queueExpand : function(node) {
65 this.expandProcId = Ext.Function.defer(this.expandNode, this.expandDelay, this, [node]);
69 cancelExpand : function() {
70 if (this.expandProcId) {
71 clearTimeout(this.expandProcId);
72 this.expandProcId = false;
76 getPosition: function(e, node) {
78 record = view.getRecord(node),
80 noAppend = record.isLeaf(),
82 region = Ext.fly(node).getRegion(),
85 // If we are dragging on top of the root node of the tree, we always want to append.
86 if (record.isRoot()) {
90 // Return 'append' if the node we are dragging on top of is not a leaf else return false.
91 if (this.appendOnly) {
92 return noAppend ? false : 'append';
95 if (!this.allowParentInsert) {
96 noBelow = record.hasChildNodes() && record.isExpanded();
99 fragment = (region.bottom - region.top) / (noAppend ? 2 : 3);
100 if (y >= region.top && y < (region.top + fragment)) {
103 else if (!noBelow && (noAppend || (y >= (region.bottom - fragment) && y <= region.bottom))) {
111 isValidDropPoint : function(node, position, dragZone, e, data) {
112 if (!node || !data.item) {
116 var view = this.view,
117 targetNode = view.getRecord(node),
118 draggedRecords = data.records,
119 dataLength = draggedRecords.length,
120 ln = draggedRecords.length,
123 // No drop position, or dragged records: invalid drop point
124 if (!(targetNode && position && dataLength)) {
128 // If the targetNode is within the folder we are dragging
129 for (i = 0; i < ln; i++) {
130 record = draggedRecords[i];
131 if (record.isNode && record.contains(targetNode)) {
136 // Respect the allowDrop field on Tree nodes
137 if (position === 'append' && targetNode.get('allowDrop') === false) {
140 else if (position != 'append' && targetNode.parentNode.get('allowDrop') === false) {
144 // If the target record is in the dragged dataset, then invalid drop
145 if (Ext.Array.contains(draggedRecords, targetNode)) {
149 // @TODO: fire some event to notify that there is a valid drop possible for the node you're dragging
150 // Yes: this.fireViewEvent(blah....) fires an event through the owning View.
154 onNodeOver : function(node, dragZone, e, data) {
155 var position = this.getPosition(e, node),
156 returnCls = this.dropNotAllowed,
158 targetNode = view.getRecord(node),
159 indicator = this.getIndicator(),
163 // auto node expand check
165 if (position == 'append' && !this.expandProcId && !Ext.Array.contains(data.records, targetNode) && !targetNode.isLeaf() && !targetNode.isExpanded()) {
166 this.queueExpand(targetNode);
170 if (this.isValidDropPoint(node, position, dragZone, e, data)) {
172 this.currentPosition = position;
173 this.overRecord = targetNode;
175 indicator.setWidth(Ext.fly(node).getWidth());
176 indicatorY = Ext.fly(node).getY() - Ext.fly(view.el).getY() - 1;
179 * In the code below we show the proxy again. The reason for doing this is showing the indicator will
180 * call toFront, causing it to get a new z-index which can sometimes push the proxy behind it. We always
181 * want the proxy to be above, so calling show on the proxy will call toFront and bring it forward.
183 if (position == 'before') {
184 returnCls = targetNode.isFirst() ? Ext.baseCSSPrefix + 'tree-drop-ok-above' : Ext.baseCSSPrefix + 'tree-drop-ok-between';
185 indicator.showAt(0, indicatorY);
186 dragZone.proxy.show();
187 } else if (position == 'after') {
188 returnCls = targetNode.isLast() ? Ext.baseCSSPrefix + 'tree-drop-ok-below' : Ext.baseCSSPrefix + 'tree-drop-ok-between';
189 indicatorY += Ext.fly(node).getHeight();
190 indicator.showAt(0, indicatorY);
191 dragZone.proxy.show();
193 returnCls = Ext.baseCSSPrefix + 'tree-drop-ok-append';
194 // @TODO: set a class on the parent folder node to be able to style it
201 this.currentCls = returnCls;
205 onContainerOver : function(dd, e, data) {
206 return e.getTarget('.' + this.indicatorCls) ? this.currentCls : this.dropNotAllowed;
209 notifyOut: function() {
210 this.callParent(arguments);
214 handleNodeDrop : function(data, targetNode, position) {
217 parentNode = targetNode.parentNode,
218 store = view.getStore(),
221 insertionMethod, argList,
226 // If the copy flag is set, create a copy of the Models with the same IDs
228 records = data.records;
230 for (i = 0, len = records.length; i < len; i++) {
231 data.records.push(Ext.apply({}, records[i].data));
235 // Cancel any pending expand operation
238 // Grab a reference to the correct node insertion method.
239 // Create an arg list array intended for the apply method of the
240 // chosen node insertion method.
241 // Ensure the target object for the method is referenced by 'targetNode'
242 if (position == 'before') {
243 insertionMethod = parentNode.insertBefore;
244 argList = [null, targetNode];
245 targetNode = parentNode;
247 else if (position == 'after') {
248 if (targetNode.nextSibling) {
249 insertionMethod = parentNode.insertBefore;
250 argList = [null, targetNode.nextSibling];
253 insertionMethod = parentNode.appendChild;
256 targetNode = parentNode;
259 if (!targetNode.isExpanded()) {
260 needTargetExpand = true;
262 insertionMethod = targetNode.appendChild;
266 // A function to transfer the data into the destination tree
267 transferData = function() {
269 for (i = 0, len = data.records.length; i < len; i++) {
270 argList[0] = data.records[i];
271 node = insertionMethod.apply(targetNode, argList);
273 if (Ext.enableFx && me.dropHighlight) {
274 recordDomNodes.push(view.getNode(node));
278 // Kick off highlights after everything's been inserted, so they are
279 // more in sync without insertion/render overhead.
280 if (Ext.enableFx && me.dropHighlight) {
281 //FIXME: the check for n.firstChild is not a great solution here. Ideally the line should simply read
282 //Ext.fly(n.firstChild) but this yields errors in IE6 and 7. See ticket EXTJSIV-1705 for more details
283 Ext.Array.forEach(recordDomNodes, function(n) {
285 Ext.fly(n.firstChild ? n.firstChild : n).highlight(me.dropHighlightColor);
291 // If dropping right on an unexpanded node, transfer the data after it is expanded.
292 if (needTargetExpand) {
293 targetNode.expand(false, transferData);
295 // Otherwise, call the data transfer function immediately