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