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