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 | * Software License Agreement (BSD License) |
---|
11 | * Copyright (c) 2008, Nige "Animal" White |
---|
12 | * All rights reserved. |
---|
13 | * |
---|
14 | * Redistribution and use in source and binary forms, with or without modification, |
---|
15 | * are permitted provided that the following conditions are met: |
---|
16 | * |
---|
17 | * * Redistributions of source code must retain the above copyright notice, |
---|
18 | * this list of conditions and the following disclaimer. |
---|
19 | * * Redistributions in binary form must reproduce the above copyright notice, |
---|
20 | * this list of conditions and the following disclaimer in the documentation |
---|
21 | * and/or other materials provided with the distribution. |
---|
22 | * * Neither the name of the original author nor the names of its contributors |
---|
23 | * may be used to endorse or promote products derived from this software |
---|
24 | * without specific prior written permission. |
---|
25 | * |
---|
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
---|
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
---|
28 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
29 | * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
---|
30 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
31 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
---|
32 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
---|
33 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
35 | * POSSIBILITY OF SUCH DAMAGE. |
---|
36 | */ |
---|
37 | /** |
---|
38 | * @class Ext.ux.DDView |
---|
39 | * <p>A DnD-enabled version of {@link Ext.DataView}. Drag/drop is implemented by adding |
---|
40 | * {@link Ext.data.Record}s to the target DDView. If copying is not being performed, |
---|
41 | * the original {@link Ext.data.Record} is removed from the source DDView.</p> |
---|
42 | * @constructor |
---|
43 | * Create a new DDView |
---|
44 | * @param {Object} config The configuration properties. |
---|
45 | */ |
---|
46 | Ext.ux.DDView = function(config) { |
---|
47 | if (!config.itemSelector) { |
---|
48 | var tpl = config.tpl; |
---|
49 | if (this.classRe.test(tpl)) { |
---|
50 | config.tpl = tpl.replace(this.classRe, 'class=$1x-combo-list-item $2$1'); |
---|
51 | } |
---|
52 | else { |
---|
53 | config.tpl = tpl.replace(this.tagRe, '$1 class="x-combo-list-item" $2'); |
---|
54 | } |
---|
55 | config.itemSelector = ".x-combo-list-item"; |
---|
56 | } |
---|
57 | Ext.ux.DDView.superclass.constructor.call(this, Ext.apply(config, { |
---|
58 | border: false |
---|
59 | })); |
---|
60 | }; |
---|
61 | |
---|
62 | Ext.extend(Ext.ux.DDView, Ext.DataView, { |
---|
63 | /** |
---|
64 | * @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone (defaults to undefined). |
---|
65 | */ |
---|
66 | /** |
---|
67 | * @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone (defaults to undefined). |
---|
68 | */ |
---|
69 | /** |
---|
70 | * @cfg {Boolean} copy Causes drag operations to copy nodes rather than move (defaults to false). |
---|
71 | */ |
---|
72 | /** |
---|
73 | * @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move (defaults to false). |
---|
74 | */ |
---|
75 | /** |
---|
76 | * @cfg {String} sortDir Sort direction for the view, 'ASC' or 'DESC' (defaults to 'ASC'). |
---|
77 | */ |
---|
78 | sortDir: 'ASC', |
---|
79 | |
---|
80 | // private |
---|
81 | isFormField: true, |
---|
82 | classRe: /class=(['"])(.*)\1/, |
---|
83 | tagRe: /(<\w*)(.*?>)/, |
---|
84 | reset: Ext.emptyFn, |
---|
85 | clearInvalid: Ext.form.Field.prototype.clearInvalid, |
---|
86 | |
---|
87 | // private |
---|
88 | afterRender: function() { |
---|
89 | Ext.ux.DDView.superclass.afterRender.call(this); |
---|
90 | if (this.dragGroup) { |
---|
91 | this.setDraggable(this.dragGroup.split(",")); |
---|
92 | } |
---|
93 | if (this.dropGroup) { |
---|
94 | this.setDroppable(this.dropGroup.split(",")); |
---|
95 | } |
---|
96 | if (this.deletable) { |
---|
97 | this.setDeletable(); |
---|
98 | } |
---|
99 | this.isDirtyFlag = false; |
---|
100 | this.addEvents( |
---|
101 | "drop" |
---|
102 | ); |
---|
103 | }, |
---|
104 | |
---|
105 | // private |
---|
106 | validate: function() { |
---|
107 | return true; |
---|
108 | }, |
---|
109 | |
---|
110 | // private |
---|
111 | destroy: function() { |
---|
112 | this.purgeListeners(); |
---|
113 | this.getEl().removeAllListeners(); |
---|
114 | this.getEl().remove(); |
---|
115 | if (this.dragZone) { |
---|
116 | if (this.dragZone.destroy) { |
---|
117 | this.dragZone.destroy(); |
---|
118 | } |
---|
119 | } |
---|
120 | if (this.dropZone) { |
---|
121 | if (this.dropZone.destroy) { |
---|
122 | this.dropZone.destroy(); |
---|
123 | } |
---|
124 | } |
---|
125 | }, |
---|
126 | |
---|
127 | /** |
---|
128 | * Allows this class to be an Ext.form.Field so it can be found using {@link Ext.form.BasicForm#findField}. |
---|
129 | */ |
---|
130 | getName: function() { |
---|
131 | return this.name; |
---|
132 | }, |
---|
133 | |
---|
134 | /** |
---|
135 | * Loads the View from a JSON string representing the Records to put into the Store. |
---|
136 | * @param {String} value The JSON string |
---|
137 | */ |
---|
138 | setValue: function(v) { |
---|
139 | if (!this.store) { |
---|
140 | throw "DDView.setValue(). DDView must be constructed with a valid Store"; |
---|
141 | } |
---|
142 | var data = {}; |
---|
143 | data[this.store.reader.meta.root] = v ? [].concat(v) : []; |
---|
144 | this.store.proxy = new Ext.data.MemoryProxy(data); |
---|
145 | this.store.load(); |
---|
146 | }, |
---|
147 | |
---|
148 | /** |
---|
149 | * Returns the view's data value as a list of ids. |
---|
150 | * @return {String} A parenthesised list of the ids of the Records in the View, e.g. (1,3,8). |
---|
151 | */ |
---|
152 | getValue: function() { |
---|
153 | var result = '('; |
---|
154 | this.store.each(function(rec) { |
---|
155 | result += rec.id + ','; |
---|
156 | }); |
---|
157 | return result.substr(0, result.length - 1) + ')'; |
---|
158 | }, |
---|
159 | |
---|
160 | getIds: function() { |
---|
161 | var i = 0, result = new Array(this.store.getCount()); |
---|
162 | this.store.each(function(rec) { |
---|
163 | result[i++] = rec.id; |
---|
164 | }); |
---|
165 | return result; |
---|
166 | }, |
---|
167 | |
---|
168 | /** |
---|
169 | * Returns true if the view's data has changed, else false. |
---|
170 | * @return {Boolean} |
---|
171 | */ |
---|
172 | isDirty: function() { |
---|
173 | return this.isDirtyFlag; |
---|
174 | }, |
---|
175 | |
---|
176 | /** |
---|
177 | * Part of the Ext.dd.DropZone interface. If no target node is found, the |
---|
178 | * whole Element becomes the target, and this causes the drop gesture to append. |
---|
179 | */ |
---|
180 | getTargetFromEvent : function(e) { |
---|
181 | var target = e.getTarget(); |
---|
182 | while ((target !== null) && (target.parentNode != this.el.dom)) { |
---|
183 | target = target.parentNode; |
---|
184 | } |
---|
185 | if (!target) { |
---|
186 | target = this.el.dom.lastChild || this.el.dom; |
---|
187 | } |
---|
188 | return target; |
---|
189 | }, |
---|
190 | |
---|
191 | /** |
---|
192 | * Create the drag data which consists of an object which has the property "ddel" as |
---|
193 | * the drag proxy element. |
---|
194 | */ |
---|
195 | getDragData : function(e) { |
---|
196 | var target = this.findItemFromChild(e.getTarget()); |
---|
197 | if(target) { |
---|
198 | if (!this.isSelected(target)) { |
---|
199 | delete this.ignoreNextClick; |
---|
200 | this.onItemClick(target, this.indexOf(target), e); |
---|
201 | this.ignoreNextClick = true; |
---|
202 | } |
---|
203 | var dragData = { |
---|
204 | sourceView: this, |
---|
205 | viewNodes: [], |
---|
206 | records: [], |
---|
207 | copy: this.copy || (this.allowCopy && e.ctrlKey) |
---|
208 | }; |
---|
209 | if (this.getSelectionCount() == 1) { |
---|
210 | var i = this.getSelectedIndexes()[0]; |
---|
211 | var n = this.getNode(i); |
---|
212 | dragData.viewNodes.push(dragData.ddel = n); |
---|
213 | dragData.records.push(this.store.getAt(i)); |
---|
214 | dragData.repairXY = Ext.fly(n).getXY(); |
---|
215 | } else { |
---|
216 | dragData.ddel = document.createElement('div'); |
---|
217 | dragData.ddel.className = 'multi-proxy'; |
---|
218 | this.collectSelection(dragData); |
---|
219 | } |
---|
220 | return dragData; |
---|
221 | } |
---|
222 | return false; |
---|
223 | }, |
---|
224 | |
---|
225 | // override the default repairXY. |
---|
226 | getRepairXY : function(e){ |
---|
227 | return this.dragData.repairXY; |
---|
228 | }, |
---|
229 | |
---|
230 | // private |
---|
231 | collectSelection: function(data) { |
---|
232 | data.repairXY = Ext.fly(this.getSelectedNodes()[0]).getXY(); |
---|
233 | if (this.preserveSelectionOrder === true) { |
---|
234 | Ext.each(this.getSelectedIndexes(), function(i) { |
---|
235 | var n = this.getNode(i); |
---|
236 | var dragNode = n.cloneNode(true); |
---|
237 | dragNode.id = Ext.id(); |
---|
238 | data.ddel.appendChild(dragNode); |
---|
239 | data.records.push(this.store.getAt(i)); |
---|
240 | data.viewNodes.push(n); |
---|
241 | }, this); |
---|
242 | } else { |
---|
243 | var i = 0; |
---|
244 | this.store.each(function(rec){ |
---|
245 | if (this.isSelected(i)) { |
---|
246 | var n = this.getNode(i); |
---|
247 | var dragNode = n.cloneNode(true); |
---|
248 | dragNode.id = Ext.id(); |
---|
249 | data.ddel.appendChild(dragNode); |
---|
250 | data.records.push(this.store.getAt(i)); |
---|
251 | data.viewNodes.push(n); |
---|
252 | } |
---|
253 | i++; |
---|
254 | }, this); |
---|
255 | } |
---|
256 | }, |
---|
257 | |
---|
258 | /** |
---|
259 | * Specify to which ddGroup items in this DDView may be dragged. |
---|
260 | * @param {String} ddGroup The DD group name to assign this view to. |
---|
261 | */ |
---|
262 | setDraggable: function(ddGroup) { |
---|
263 | if (ddGroup instanceof Array) { |
---|
264 | Ext.each(ddGroup, this.setDraggable, this); |
---|
265 | return; |
---|
266 | } |
---|
267 | if (this.dragZone) { |
---|
268 | this.dragZone.addToGroup(ddGroup); |
---|
269 | } else { |
---|
270 | this.dragZone = new Ext.dd.DragZone(this.getEl(), { |
---|
271 | containerScroll: true, |
---|
272 | ddGroup: ddGroup |
---|
273 | }); |
---|
274 | // Draggability implies selection. DragZone's mousedown selects the element. |
---|
275 | if (!this.multiSelect) { this.singleSelect = true; } |
---|
276 | |
---|
277 | // Wire the DragZone's handlers up to methods in *this* |
---|
278 | this.dragZone.getDragData = this.getDragData.createDelegate(this); |
---|
279 | this.dragZone.getRepairXY = this.getRepairXY; |
---|
280 | this.dragZone.onEndDrag = this.onEndDrag; |
---|
281 | } |
---|
282 | }, |
---|
283 | |
---|
284 | /** |
---|
285 | * Specify from which ddGroup this DDView accepts drops. |
---|
286 | * @param {String} ddGroup The DD group name from which to accept drops. |
---|
287 | */ |
---|
288 | setDroppable: function(ddGroup) { |
---|
289 | if (ddGroup instanceof Array) { |
---|
290 | Ext.each(ddGroup, this.setDroppable, this); |
---|
291 | return; |
---|
292 | } |
---|
293 | if (this.dropZone) { |
---|
294 | this.dropZone.addToGroup(ddGroup); |
---|
295 | } else { |
---|
296 | this.dropZone = new Ext.dd.DropZone(this.getEl(), { |
---|
297 | owningView: this, |
---|
298 | containerScroll: true, |
---|
299 | ddGroup: ddGroup |
---|
300 | }); |
---|
301 | |
---|
302 | // Wire the DropZone's handlers up to methods in *this* |
---|
303 | this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this); |
---|
304 | this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this); |
---|
305 | this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this); |
---|
306 | this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this); |
---|
307 | this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this); |
---|
308 | } |
---|
309 | }, |
---|
310 | |
---|
311 | // private |
---|
312 | getDropPoint : function(e, n, dd){ |
---|
313 | if (n == this.el.dom) { return "above"; } |
---|
314 | var t = Ext.lib.Dom.getY(n), b = t + n.offsetHeight; |
---|
315 | var c = t + (b - t) / 2; |
---|
316 | var y = Ext.lib.Event.getPageY(e); |
---|
317 | if(y <= c) { |
---|
318 | return "above"; |
---|
319 | }else{ |
---|
320 | return "below"; |
---|
321 | } |
---|
322 | }, |
---|
323 | |
---|
324 | // private |
---|
325 | isValidDropPoint: function(pt, n, data) { |
---|
326 | if (!data.viewNodes || (data.viewNodes.length != 1)) { |
---|
327 | return true; |
---|
328 | } |
---|
329 | var d = data.viewNodes[0]; |
---|
330 | if (d == n) { |
---|
331 | return false; |
---|
332 | } |
---|
333 | if ((pt == "below") && (n.nextSibling == d)) { |
---|
334 | return false; |
---|
335 | } |
---|
336 | if ((pt == "above") && (n.previousSibling == d)) { |
---|
337 | return false; |
---|
338 | } |
---|
339 | return true; |
---|
340 | }, |
---|
341 | |
---|
342 | // private |
---|
343 | onNodeEnter : function(n, dd, e, data){ |
---|
344 | if (this.highlightColor && (data.sourceView != this)) { |
---|
345 | this.el.highlight(this.highlightColor); |
---|
346 | } |
---|
347 | return false; |
---|
348 | }, |
---|
349 | |
---|
350 | // private |
---|
351 | onNodeOver : function(n, dd, e, data){ |
---|
352 | var dragElClass = this.dropNotAllowed; |
---|
353 | var pt = this.getDropPoint(e, n, dd); |
---|
354 | if (this.isValidDropPoint(pt, n, data)) { |
---|
355 | if (this.appendOnly || this.sortField) { |
---|
356 | return "x-tree-drop-ok-below"; |
---|
357 | } |
---|
358 | |
---|
359 | // set the insert point style on the target node |
---|
360 | if (pt) { |
---|
361 | var targetElClass; |
---|
362 | if (pt == "above"){ |
---|
363 | dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above"; |
---|
364 | targetElClass = "x-view-drag-insert-above"; |
---|
365 | } else { |
---|
366 | dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below"; |
---|
367 | targetElClass = "x-view-drag-insert-below"; |
---|
368 | } |
---|
369 | if (this.lastInsertClass != targetElClass){ |
---|
370 | Ext.fly(n).replaceClass(this.lastInsertClass, targetElClass); |
---|
371 | this.lastInsertClass = targetElClass; |
---|
372 | } |
---|
373 | } |
---|
374 | } |
---|
375 | return dragElClass; |
---|
376 | }, |
---|
377 | |
---|
378 | // private |
---|
379 | onNodeOut : function(n, dd, e, data){ |
---|
380 | this.removeDropIndicators(n); |
---|
381 | }, |
---|
382 | |
---|
383 | // private |
---|
384 | onNodeDrop : function(n, dd, e, data){ |
---|
385 | if (this.fireEvent("drop", this, n, dd, e, data) === false) { |
---|
386 | return false; |
---|
387 | } |
---|
388 | var pt = this.getDropPoint(e, n, dd); |
---|
389 | var insertAt = (this.appendOnly || (n == this.el.dom)) ? this.store.getCount() : n.viewIndex; |
---|
390 | if (pt == "below") { |
---|
391 | insertAt++; |
---|
392 | } |
---|
393 | |
---|
394 | // Validate if dragging within a DDView |
---|
395 | if (data.sourceView == this) { |
---|
396 | // If the first element to be inserted below is the target node, remove it |
---|
397 | if (pt == "below") { |
---|
398 | if (data.viewNodes[0] == n) { |
---|
399 | data.viewNodes.shift(); |
---|
400 | } |
---|
401 | } else { // If the last element to be inserted above is the target node, remove it |
---|
402 | if (data.viewNodes[data.viewNodes.length - 1] == n) { |
---|
403 | data.viewNodes.pop(); |
---|
404 | } |
---|
405 | } |
---|
406 | |
---|
407 | // Nothing to drop... |
---|
408 | if (!data.viewNodes.length) { |
---|
409 | return false; |
---|
410 | } |
---|
411 | |
---|
412 | // If we are moving DOWN, then because a store.remove() takes place first, |
---|
413 | // the insertAt must be decremented. |
---|
414 | if (insertAt > this.store.indexOf(data.records[0])) { |
---|
415 | insertAt--; |
---|
416 | } |
---|
417 | } |
---|
418 | |
---|
419 | // Dragging from a Tree. Use the Tree's recordFromNode function. |
---|
420 | if (data.node instanceof Ext.tree.TreeNode) { |
---|
421 | var r = data.node.getOwnerTree().recordFromNode(data.node); |
---|
422 | if (r) { |
---|
423 | data.records = [ r ]; |
---|
424 | } |
---|
425 | } |
---|
426 | |
---|
427 | if (!data.records) { |
---|
428 | alert("Programming problem. Drag data contained no Records"); |
---|
429 | return false; |
---|
430 | } |
---|
431 | |
---|
432 | for (var i = 0; i < data.records.length; i++) { |
---|
433 | var r = data.records[i]; |
---|
434 | var dup = this.store.getById(r.id); |
---|
435 | if (dup && (dd != this.dragZone)) { |
---|
436 | if(!this.allowDup && !this.allowTrash){ |
---|
437 | Ext.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1); |
---|
438 | return true |
---|
439 | } |
---|
440 | var x=new Ext.data.Record(); |
---|
441 | r.id=x.id; |
---|
442 | delete x; |
---|
443 | } |
---|
444 | if (data.copy) { |
---|
445 | this.store.insert(insertAt++, r.copy()); |
---|
446 | } else { |
---|
447 | if (data.sourceView) { |
---|
448 | data.sourceView.isDirtyFlag = true; |
---|
449 | data.sourceView.store.remove(r); |
---|
450 | } |
---|
451 | if(!this.allowTrash)this.store.insert(insertAt++, r); |
---|
452 | } |
---|
453 | if(this.sortField){ |
---|
454 | this.store.sort(this.sortField, this.sortDir); |
---|
455 | } |
---|
456 | this.isDirtyFlag = true; |
---|
457 | } |
---|
458 | this.dragZone.cachedTarget = null; |
---|
459 | return true; |
---|
460 | }, |
---|
461 | |
---|
462 | // private |
---|
463 | onEndDrag: function(data, e) { |
---|
464 | var d = Ext.get(this.dragData.ddel); |
---|
465 | if (d && d.hasClass("multi-proxy")) { |
---|
466 | d.remove(); |
---|
467 | //delete this.dragData.ddel; |
---|
468 | } |
---|
469 | }, |
---|
470 | |
---|
471 | // private |
---|
472 | removeDropIndicators : function(n){ |
---|
473 | if(n){ |
---|
474 | Ext.fly(n).removeClass([ |
---|
475 | "x-view-drag-insert-above", |
---|
476 | "x-view-drag-insert-left", |
---|
477 | "x-view-drag-insert-right", |
---|
478 | "x-view-drag-insert-below"]); |
---|
479 | this.lastInsertClass = "_noclass"; |
---|
480 | } |
---|
481 | }, |
---|
482 | |
---|
483 | /** |
---|
484 | * Add a delete option to the DDView's context menu. |
---|
485 | * @param {String} imageUrl The URL of the "delete" icon image. |
---|
486 | */ |
---|
487 | setDeletable: function(imageUrl) { |
---|
488 | if (!this.singleSelect && !this.multiSelect) { |
---|
489 | this.singleSelect = true; |
---|
490 | } |
---|
491 | var c = this.getContextMenu(); |
---|
492 | this.contextMenu.on("itemclick", function(item) { |
---|
493 | switch (item.id) { |
---|
494 | case "delete": |
---|
495 | this.remove(this.getSelectedIndexes()); |
---|
496 | break; |
---|
497 | } |
---|
498 | }, this); |
---|
499 | this.contextMenu.add({ |
---|
500 | icon: imageUrl || AU.resolveUrl("/images/delete.gif"), |
---|
501 | id: "delete", |
---|
502 | text: AU.getMessage("deleteItem") |
---|
503 | }); |
---|
504 | }, |
---|
505 | |
---|
506 | /** |
---|
507 | * Return the context menu for this DDView. |
---|
508 | * @return {Ext.menu.Menu} The context menu |
---|
509 | */ |
---|
510 | getContextMenu: function() { |
---|
511 | if (!this.contextMenu) { |
---|
512 | // Create the View's context menu |
---|
513 | this.contextMenu = new Ext.menu.Menu({ |
---|
514 | id: this.id + "-contextmenu" |
---|
515 | }); |
---|
516 | this.el.on("contextmenu", this.showContextMenu, this); |
---|
517 | } |
---|
518 | return this.contextMenu; |
---|
519 | }, |
---|
520 | |
---|
521 | /** |
---|
522 | * Disables the view's context menu. |
---|
523 | */ |
---|
524 | disableContextMenu: function() { |
---|
525 | if (this.contextMenu) { |
---|
526 | this.el.un("contextmenu", this.showContextMenu, this); |
---|
527 | } |
---|
528 | }, |
---|
529 | |
---|
530 | // private |
---|
531 | showContextMenu: function(e, item) { |
---|
532 | item = this.findItemFromChild(e.getTarget()); |
---|
533 | if (item) { |
---|
534 | e.stopEvent(); |
---|
535 | this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true); |
---|
536 | this.contextMenu.showAt(e.getXY()); |
---|
537 | } |
---|
538 | }, |
---|
539 | |
---|
540 | /** |
---|
541 | * Remove {@link Ext.data.Record}s at the specified indices. |
---|
542 | * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove. |
---|
543 | */ |
---|
544 | remove: function(selectedIndices) { |
---|
545 | selectedIndices = [].concat(selectedIndices); |
---|
546 | for (var i = 0; i < selectedIndices.length; i++) { |
---|
547 | var rec = this.store.getAt(selectedIndices[i]); |
---|
548 | this.store.remove(rec); |
---|
549 | } |
---|
550 | }, |
---|
551 | |
---|
552 | /** |
---|
553 | * Double click fires the {@link #dblclick} event. Additionally, if this DDView is draggable, and there is only one other |
---|
554 | * related DropZone that is in another DDView, it drops the selected node on that DDView. |
---|
555 | */ |
---|
556 | onDblClick : function(e){ |
---|
557 | var item = this.findItemFromChild(e.getTarget()); |
---|
558 | if(item){ |
---|
559 | if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) { |
---|
560 | return false; |
---|
561 | } |
---|
562 | if (this.dragGroup) { |
---|
563 | var targets = Ext.dd.DragDropMgr.getRelated(this.dragZone, true); |
---|
564 | |
---|
565 | // Remove instances of this View's DropZone |
---|
566 | while (targets.indexOf(this.dropZone) !== -1) { |
---|
567 | targets.remove(this.dropZone); |
---|
568 | } |
---|
569 | |
---|
570 | // If there's only one other DropZone, and it is owned by a DDView, then drop it in |
---|
571 | if ((targets.length == 1) && (targets[0].owningView)) { |
---|
572 | this.dragZone.cachedTarget = null; |
---|
573 | var el = Ext.get(targets[0].getEl()); |
---|
574 | var box = el.getBox(true); |
---|
575 | targets[0].onNodeDrop(el.dom, { |
---|
576 | target: el.dom, |
---|
577 | xy: [box.x, box.y + box.height - 1] |
---|
578 | }, null, this.getDragData(e)); |
---|
579 | } |
---|
580 | } |
---|
581 | } |
---|
582 | }, |
---|
583 | |
---|
584 | // private |
---|
585 | onItemClick : function(item, index, e){ |
---|
586 | // The DragZone's mousedown->getDragData already handled selection |
---|
587 | if (this.ignoreNextClick) { |
---|
588 | delete this.ignoreNextClick; |
---|
589 | return; |
---|
590 | } |
---|
591 | |
---|
592 | if(this.fireEvent("beforeclick", this, index, item, e) === false){ |
---|
593 | return false; |
---|
594 | } |
---|
595 | if(this.multiSelect || this.singleSelect){ |
---|
596 | if(this.multiSelect && e.shiftKey && this.lastSelection){ |
---|
597 | this.select(this.getNodes(this.indexOf(this.lastSelection), index), false); |
---|
598 | } else if (this.isSelected(item) && e.ctrlKey) { |
---|
599 | this.deselect(item); |
---|
600 | }else{ |
---|
601 | this.deselect(item); |
---|
602 | this.select(item, this.multiSelect && e.ctrlKey); |
---|
603 | this.lastSelection = item; |
---|
604 | } |
---|
605 | e.preventDefault(); |
---|
606 | } |
---|
607 | return true; |
---|
608 | } |
---|
609 | }); |
---|