Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / examples / dd / field-to-grid-dd.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 Ext.require(['*']);
16
17 // A DropZone which cooperates with DragZones whose dragData contains
18 // a "field" property representing a form Field. Fields may be dropped onto
19 // grid data cells containing a matching data type.
20 Ext.define('Ext.ux.CellFieldDropZone', {
21     extend: 'Ext.dd.DropZone',
22
23     constructor: function(){},
24
25 //  Call the DropZone constructor using the View's scrolling element
26 //  only after the grid has been rendered.
27     init: function(grid) {
28         var me = this;
29
30         if (grid.rendered) {
31             me.grid = grid;
32             grid.getView().on({
33                 render: function(v) {
34                     me.view = v;
35                     Ext.ux.CellFieldDropZone.superclass.constructor.call(me, me.view.el);
36                 },
37                 single: true
38             });
39         } else {
40             grid.on('render', me.init, me, {single: true});
41         }
42     },
43
44 //  Scroll the main configured Element when we drag close to the edge
45     containerScroll: true,
46
47     getTargetFromEvent: function(e) {
48         var me = this,
49             v = me.view;
50
51 //      Ascertain whether the mousemove is within a grid cell
52         var cell = e.getTarget(v.cellSelector);
53         if (cell) {
54
55 //          We *are* within a grid cell, so ask the View exactly which one,
56 //          Extract data from the Model to create a target object for
57 //          processing in subsequent onNodeXXXX methods. Note that the target does
58 //          not have to be a DOM element. It can be whatever the noNodeXXX methods are
59 //          programmed to expect.
60             var row = v.findItemByChild(cell),
61                 columnIndex = cell.cellIndex;
62
63             if (row && Ext.isDefined(columnIndex)) {
64                 return {
65                     node: cell,
66                     record: v.getRecord(row),
67                     fieldName: me.grid.columns[columnIndex].dataIndex
68                 };
69             }
70         }
71     },
72
73 //  On Node enter, see if it is valid for us to drop the field on that type of column.
74     onNodeEnter: function(target, dd, e, dragData) {
75         delete this.dropOK;
76         if (!target) {
77             return;
78         }
79
80 //      Check that a field is being dragged.
81         var f = dragData.field;
82         if (!f) {
83             return;
84         }
85
86 //      Check whether the data type of the column being dropped on accepts the
87 //      dragged field type. If so, set dropOK flag, and highlight the target node.
88         var type = target.record.fields.get(target.fieldName).type,
89             types = Ext.data.Types;
90         switch(type){
91             case types.FLOAT:
92             case types.INT:
93                 if (!f.isXType('numberfield')) {
94                     return;
95                 }
96                 break;
97             case types.DATE:
98                 if (!f.isXType('datefield')) {
99                     return;
100                 }
101                 break;
102             case types.BOOL:
103                 if (!f.isXType('checkbox')) {
104                     return;
105                 }
106         }
107         this.dropOK = true;
108         Ext.fly(target.node).addCls('x-drop-target-active');
109     },
110
111 //  Return the class name to add to the drag proxy. This provides a visual indication
112 //  of drop allowed or not allowed.
113     onNodeOver: function(target, dd, e, dragData) {
114         return this.dropOK ? this.dropAllowed : this.dropNotAllowed;
115     },
116
117 //  highlight the target node.
118     onNodeOut: function(target, dd, e, dragData) {
119         Ext.fly(target.node).removeCls('x-drop-target-active');
120     },
121
122 //  Process the drop event if we have previously ascertained that a drop is OK.
123     onNodeDrop: function(target, dd, e, dragData) {
124         if (this.dropOK) {
125             target.record.set(target.fieldName, dragData.field.getValue());
126             return true;
127         }
128     }
129 });
130
131 //  A class which makes Fields within a Panel draggable.
132 //  the dragData delivered to a cooperating DropZone's methods contains
133 //  the dragged Field in the property "field".
134 Ext.define('Ext.ux.PanelFieldDragZone', {
135
136     extend: 'Ext.dd.DragZone',
137
138     constructor: function(){},
139
140 //  Call the DRagZone's constructor. The Panel must have been rendered.
141     init: function(panel) {
142         if (panel.nodeType) {
143             Ext.ux.PanelFieldDragZone.superclass.init.apply(this, arguments);
144         } else {
145             if (panel.rendered) {
146                 Ext.ux.PanelFieldDragZone.superclass.constructor.call(this, panel.getEl());
147                 var i = Ext.fly(panel.getEl()).select('input');
148                 i.unselectable();
149             } else {
150                 panel.on('afterlayout', this.init, this, {single: true});
151             }
152         }
153     },
154
155     scroll: false,
156
157 //  On mousedown, we ascertain whether it is on one of our draggable Fields.
158 //  If so, we collect data about the draggable object, and return a drag data
159 //  object which contains our own data, plus a "ddel" property which is a DOM
160 //  node which provides a "view" of the dragged data.
161     getDragData: function(e) {
162         var t = e.getTarget('input');
163         if (t) {
164             e.stopEvent();
165
166 //          Ugly code to "detach" the drag gesture from the input field.
167 //          Without this, Opera never changes the mouseover target from the input field
168 //          even when dragging outside of the field - it just keeps selecting.
169             if (Ext.isOpera) {
170                 Ext.fly(t).on('mousemove', function(e1){
171                     t.style.visibility = 'hidden';
172                     Ext.defer(function(){
173                         t.style.visibility = '';
174                     }, 1);
175                 }, null, {single:true});
176             }
177
178 //          Get the data we are dragging: the Field
179 //          create a ddel for the drag proxy to display
180             var f = Ext.ComponentQuery.query('field[inputEl]{inputEl.id=="' + t.id + '"}')[0];
181             var d = document.createElement('div');
182             d.className = 'x-form-text';
183             d.appendChild(document.createTextNode(t.value));
184             Ext.fly(d).setWidth(f.getEl().getWidth());
185             return {
186                 field: f,
187                 ddel: d
188             };
189         }
190     },
191
192 //  The coordinates to slide the drag proxy back to on failed drop.
193     getRepairXY: function() {
194         return this.dragData.field.getEl().getXY();
195     }
196 });
197
198 Ext.onReady(function(){
199
200     var myData = [
201         ['3m Co',71.72,0.02,0.03,'9/1 12:00am'],
202         ['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am'],
203         ['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am'],
204         ['American Express Company',52.55,0.01,0.02,'9/1 12:00am'],
205         ['American International Group, Inc.',64.13,0.31,0.49,'9/1 12:00am'],
206         ['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am'],
207         ['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am'],
208         ['Caterpillar Inc.',67.27,0.92,1.39,'9/1 12:00am'],
209         ['Citigroup, Inc.',49.37,0.02,0.04,'9/1 12:00am'],
210         ['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am'],
211         ['Exxon Mobil Corp',68.1,-0.43,-0.64,'9/1 12:00am'],
212         ['General Electric Company',34.14,-0.08,-0.23,'9/1 12:00am'],
213         ['General Motors Corporation',30.27,1.09,3.74,'9/1 12:00am'],
214         ['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am'],
215         ['Honeywell Intl Inc',38.77,0.05,0.13,'9/1 12:00am'],
216         ['Intel Corporation',19.88,0.31,1.58,'9/1 12:00am'],
217         ['International Business Machines',81.41,0.44,0.54,'9/1 12:00am'],
218         ['Johnson & Johnson',64.72,0.06,0.09,'9/1 12:00am'],
219         ['JP Morgan & Chase & Co',45.73,0.07,0.15,'9/1 12:00am'],
220         ['McDonald\'s Corporation',36.76,0.86,2.40,'9/1 12:00am'],
221         ['Merck & Co., Inc.',40.96,0.41,1.01,'9/1 12:00am'],
222         ['Microsoft Corporation',25.84,0.14,0.54,'9/1 12:00am'],
223         ['Pfizer Inc',27.96,0.4,1.45,'9/1 12:00am'],
224         ['The Coca-Cola Company',45.07,0.26,0.58,'9/1 12:00am'],
225         ['The Home Depot, Inc.',34.64,0.35,1.02,'9/1 12:00am'],
226         ['The Procter & Gamble Company',61.91,0.01,0.02,'9/1 12:00am'],
227         ['United Technologies Corporation',63.26,0.55,0.88,'9/1 12:00am'],
228         ['Verizon Communications',35.57,0.39,1.11,'9/1 12:00am'],
229         ['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am']
230     ];
231
232     // example of custom renderer function
233     function change(val){
234         if(val > 0){
235             return '<span style="color:green;">' + val + '</span>';
236         }else if(val < 0){
237             return '<span style="color:red;">' + val + '</span>';
238         }
239         return val;
240     }
241
242     // example of custom renderer function
243     function pctChange(val){
244         if(val > 0){
245             return '<span style="color:green;">' + val + '%</span>';
246         }else if(val < 0){
247             return '<span style="color:red;">' + val + '%</span>';
248         }
249         return val;
250     }
251
252     // create the data store
253     var store = Ext.create('Ext.data.ArrayStore', {
254         fields: [
255            {name: 'company'},
256            {name: 'price', type: 'float'},
257            {name: 'change', type: 'float'},
258            {name: 'pctChange', type: 'float'},
259            {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
260         ],
261         data: myData
262     });
263
264     var helpWindow = Ext.create('Ext.Window', {
265         title: 'Source code',
266         width: 920,
267         height: 500,
268         closeAction: 'hide',
269         layout: 'fit',
270         items: {
271             hideLabel: true,
272             xtype: 'textarea',
273             readOnly: true
274         },
275         listeners: {
276             render: function(w) {
277                 Ext.Ajax.request({
278                     url: 'field-to-grid-dd.js',
279                     success: function(r) {
280                         w.items.first().setValue(r.responseText);
281                     }
282                 });
283             }
284         }
285     });
286
287     // create the Grid
288     var grid = Ext.create('Ext.grid.Panel', {
289         store: store,
290         columns: [
291             {id:'company',header: "Company", width: 160, sortable: true, dataIndex: 'company'},
292             {header: "Price", width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'},
293             {header: "Change", width: 75, sortable: true, renderer: change, dataIndex: 'change'},
294             {header: "% Change", width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange'},
295             {header: "Last Updated", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
296         ],
297         plugins: Ext.create('Ext.ux.CellFieldDropZone'),
298         stripeRows: true,
299         autoExpandColumn: 'company',
300         height:350,
301         width:600,
302         title:'Array Grid',
303         dockedItems: [{
304             dock: 'bottom',
305             xtype: 'toolbar',
306             items: {
307                 text: 'View Source',
308                 handler: function() {
309                     helpWindow.show();
310                 }
311             }
312         }]
313     });
314
315     grid.render('grid-example');
316
317     var f = Ext.create('Ext.Panel', {
318         frame: true,
319         width: 600,
320         plugins: Ext.create('Ext.ux.PanelFieldDragZone'),
321         labelWidth: 150,
322         items: [{
323             xtype: 'textfield',
324             fieldLabel: 'Drag this text',
325             value: 'test'
326         },{
327             xtype: 'numberfield',
328             fieldLabel: 'Drag this number',
329             value: '1.2'
330         },{
331             xtype: 'datefield',
332             fieldLabel: 'Drag this date',
333             value: new Date()
334         }],
335         renderTo: Ext.getBody()
336     });
337 });
338