Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / examples / ux / DataView / Draggable.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.ux.DataView.Draggable
17  * @extends Object
18  * @author Ed Spencer
19  *
20 <pre><code>
21 Ext.create('Ext.view.View', {
22     mixins: {
23         draggable: 'Ext.ux.DataView.Draggable'
24     },
25
26     initComponent: function() {
27         this.mixins.draggable.init(this, {
28             ddConfig: {
29                 ddGroup: 'someGroup'
30             }
31         });
32
33         this.callParent(arguments);
34     }
35 });
36 </code></pre>
37  *
38  */
39 Ext.define('Ext.ux.DataView.Draggable', {
40     requires: 'Ext.dd.DragZone',
41
42     /**
43      * @cfg {String} ghostCls The CSS class added to the outermost element of the created ghost proxy
44      * (defaults to 'x-dataview-draggable-ghost')
45      */
46     ghostCls: 'x-dataview-draggable-ghost',
47
48     /**
49      * @cfg {Ext.XTemplate/Array} ghostTpl The template used in the ghost DataView
50      */
51     ghostTpl: [
52         '<tpl for=".">',
53             '{title}',
54         '</tpl>'
55     ],
56
57     /**
58      * @cfg {Object} ddConfig Config object that is applied to the internally created DragZone
59      */
60
61     /**
62      * @cfg {String} ghostConfig Config object that is used to configure the internally created DataView
63      */
64
65     init: function(dataview, config) {
66         /**
67          * @property dataview
68          * @type Ext.view.View
69          * The Ext.view.View instance that this DragZone is attached to
70          */
71         this.dataview = dataview;
72
73         dataview.on('render', this.onRender, this);
74
75         Ext.apply(this, {
76             itemSelector: dataview.itemSelector,
77             ghostConfig : {}
78         }, config || {});
79
80         Ext.applyIf(this.ghostConfig, {
81             itemSelector: 'img',
82             cls: this.ghostCls,
83             tpl: this.ghostTpl
84         });
85     },
86
87     /**
88      * @private
89      * Called when the attached DataView is rendered. Sets up the internal DragZone
90      */
91     onRender: function() {
92         var config = Ext.apply({}, this.ddConfig || {}, {
93             dvDraggable: this,
94             dataview   : this.dataview,
95             getDragData: this.getDragData,
96             getTreeNode: this.getTreeNode,
97             afterRepair: this.afterRepair,
98             getRepairXY: this.getRepairXY
99         });
100
101         /**
102          * @property dragZone
103          * @type Ext.dd.DragZone
104          * The attached DragZone instane
105          */
106         this.dragZone = Ext.create('Ext.dd.DragZone', this.dataview.getEl(), config);
107     },
108
109     getDragData: function(e) {
110         var draggable = this.dvDraggable,
111             dataview  = this.dataview,
112             selModel  = dataview.getSelectionModel(),
113             target    = e.getTarget(draggable.itemSelector),
114             selected, dragData;
115
116         if (target) {
117             if (!dataview.isSelected(target)) {
118                 selModel.select(dataview.getRecord(target));
119             }
120
121             selected = dataview.getSelectedNodes();
122             dragData = {
123                 copy: true,
124                 nodes: selected,
125                 records: selModel.getSelection(),
126                 item: true
127             };
128
129             if (selected.length == 1) {
130                 dragData.single = true;
131                 dragData.ddel = target;
132             } else {
133                 dragData.multi = true;
134                 dragData.ddel = draggable.prepareGhost(selModel.getSelection()).dom;
135             }
136
137             return dragData;
138         }
139
140         return false;
141     },
142
143     getTreeNode: function() {
144         // console.log('test');
145     },
146
147     afterRepair: function() {
148         this.dragging = false;
149
150         var nodes  = this.dragData.nodes,
151             length = nodes.length,
152             i;
153
154         //FIXME: Ext.fly does not work here for some reason, only frames the last node
155         for (i = 0; i < length; i++) {
156             Ext.get(nodes[i]).frame('#8db2e3', 1);
157         }
158     },
159
160     /**
161      * @private
162      * Returns the x and y co-ordinates that the dragged item should be animated back to if it was dropped on an
163      * invalid drop target. If we're dragging more than one item we don't animate back and just allow afterRepair
164      * to frame each dropped item.
165      */
166     getRepairXY: function(e) {
167         if (this.dragData.multi) {
168             return false;
169         } else {
170             var repairEl = Ext.get(this.dragData.ddel),
171                 repairXY = repairEl.getXY();
172
173             //take the item's margins and padding into account to make the repair animation line up perfectly
174             repairXY[0] += repairEl.getPadding('t') + repairEl.getMargin('t');
175             repairXY[1] += repairEl.getPadding('l') + repairEl.getMargin('l');
176
177             return repairXY;
178         }
179     },
180
181     /**
182      * Updates the internal ghost DataView by ensuring it is rendered and contains the correct records
183      * @param {Array} records The set of records that is currently selected in the parent DataView
184      * @return {Ext.view.View} The Ghost DataView
185      */
186     prepareGhost: function(records) {
187         var ghost = this.createGhost(records),
188             store = ghost.store;
189
190         store.removeAll();
191         store.add(records);
192
193         return ghost.getEl();
194     },
195
196     /**
197      * @private
198      * Creates the 'ghost' DataView that follows the mouse cursor during the drag operation. This div is usually a
199      * lighter-weight representation of just the nodes that are selected in the parent DataView. Delegates the creation
200      * of each selected item's element to {@link createGhostElement}
201      */
202     createGhost: function(records) {
203         if (!this.ghost) {
204             var ghostConfig = Ext.apply({}, this.ghostConfig, {
205                 store: Ext.create('Ext.data.Store', {
206                     model: records[0].modelName
207                 })
208             });
209
210             this.ghost = Ext.create('Ext.view.View', ghostConfig);
211
212             this.ghost.render(document.createElement('div'));
213         }
214
215         return this.ghost;
216     }
217 });
218