Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / docs / source / Editing.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js">
19 <span id='Ext-grid-plugin-Editing'>/**
20 </span> * @class Ext.grid.plugin.Editing
21
22 This class provides an abstract grid editing plugin on selected {@link Ext.grid.column.Column columns}.
23 The editable columns are specified by providing an {@link Ext.grid.column.Column#editor editor}
24 in the {@link Ext.grid.column.Column column configuration}.
25
26 *Note:* This class should not be used directly. See {@link Ext.grid.plugin.CellEditing} and
27 {@link Ext.grid.plugin.RowEditing}.
28
29  * @markdown
30  */
31 Ext.define('Ext.grid.plugin.Editing', {
32     alias: 'editing.editing',
33
34     requires: [
35         'Ext.grid.column.Column',
36         'Ext.util.KeyNav'
37     ],
38
39     mixins: {
40         observable: 'Ext.util.Observable'
41     },
42
43 <span id='Ext-grid-plugin-Editing-cfg-clicksToEdit'>    /**
44 </span>     * @cfg {Number} clicksToEdit
45      * The number of clicks on a grid required to display the editor (defaults to 2).
46      */
47     clicksToEdit: 2,
48
49     // private
50     defaultFieldXType: 'textfield',
51
52     // cell, row, form
53     editStyle: '',
54
55     constructor: function(config) {
56         var me = this;
57         Ext.apply(me, config);
58
59         me.addEvents(
60             // Doc'ed in separate editing plugins
61             'beforeedit',
62
63             // Doc'ed in separate editing plugins
64             'edit',
65
66             // Doc'ed in separate editing plugins
67             'validateedit'
68         );
69         me.mixins.observable.constructor.call(me);
70         // TODO: Deprecated, remove in 5.0
71         me.relayEvents(me, ['afteredit'], 'after');
72     },
73
74     // private
75     init: function(grid) {
76         var me = this;
77
78         me.grid = grid;
79         me.view = grid.view;
80         me.initEvents();
81         me.mon(grid, 'reconfigure', me.onReconfigure, me);
82         me.onReconfigure();
83
84         grid.relayEvents(me, ['beforeedit', 'edit', 'validateedit']);
85         // Marks the grid as editable, so that the SelectionModel
86         // can make appropriate decisions during navigation
87         grid.isEditable = true;
88         grid.editingPlugin = grid.view.editingPlugin = me;
89     },
90     
91 <span id='Ext-grid-plugin-Editing-method-onReconfigure'>    /**
92 </span>     * Fires after the grid is reconfigured
93      * @private
94      */
95     onReconfigure: function(){
96         this.initFieldAccessors(this.view.getGridColumns());
97     },
98
99 <span id='Ext-grid-plugin-Editing-method-destroy'>    /**
100 </span>     * @private
101      * AbstractComponent calls destroy on all its plugins at destroy time.
102      */
103     destroy: function() {
104         var me = this,
105             grid = me.grid,
106             headerCt = grid.headerCt,
107             events = grid.events;
108
109         Ext.destroy(me.keyNav);
110         me.removeFieldAccessors(grid.getView().getGridColumns());
111
112         // Clear all listeners from all our events, clear all managed listeners we added to other Observables
113         me.clearListeners();
114
115         delete me.grid.editingPlugin;
116         delete me.grid.view.editingPlugin;
117         delete me.grid;
118         delete me.view;
119         delete me.editor;
120         delete me.keyNav;
121     },
122
123     // private
124     getEditStyle: function() {
125         return this.editStyle;
126     },
127
128     // private
129     initFieldAccessors: function(column) {
130         var me = this;
131
132         if (Ext.isArray(column)) {
133             Ext.Array.forEach(column, me.initFieldAccessors, me);
134             return;
135         }
136
137         // Augment the Header class to have a getEditor and setEditor method
138         // Important: Only if the header does not have its own implementation.
139         Ext.applyIf(column, {
140             getEditor: function(record, defaultField) {
141                 return me.getColumnField(this, defaultField);
142             },
143
144             setEditor: function(field) {
145                 me.setColumnField(this, field);
146             }
147         });
148     },
149
150     // private
151     removeFieldAccessors: function(column) {
152         var me = this;
153
154         if (Ext.isArray(column)) {
155             Ext.Array.forEach(column, me.removeFieldAccessors, me);
156             return;
157         }
158
159         delete column.getEditor;
160         delete column.setEditor;
161     },
162
163     // private
164     // remaps to the public API of Ext.grid.column.Column.getEditor
165     getColumnField: function(columnHeader, defaultField) {
166         var field = columnHeader.field;
167
168         if (!field &amp;&amp; columnHeader.editor) {
169             field = columnHeader.editor;
170             delete columnHeader.editor;
171         }
172
173         if (!field &amp;&amp; defaultField) {
174             field = defaultField;
175         }
176
177         if (field) {
178             if (Ext.isString(field)) {
179                 field = { xtype: field };
180             }
181             if (Ext.isObject(field) &amp;&amp; !field.isFormField) {
182                 field = Ext.ComponentManager.create(field, this.defaultFieldXType);
183                 columnHeader.field = field;
184             }
185
186             Ext.apply(field, {
187                 name: columnHeader.dataIndex
188             });
189
190             return field;
191         }
192     },
193
194     // private
195     // remaps to the public API of Ext.grid.column.Column.setEditor
196     setColumnField: function(column, field) {
197         if (Ext.isObject(field) &amp;&amp; !field.isFormField) {
198             field = Ext.ComponentManager.create(field, this.defaultFieldXType);
199         }
200         column.field = field;
201     },
202
203     // private
204     initEvents: function() {
205         var me = this;
206         me.initEditTriggers();
207         me.initCancelTriggers();
208     },
209
210     // @abstract
211     initCancelTriggers: Ext.emptyFn,
212
213     // private
214     initEditTriggers: function() {
215         var me = this,
216             view = me.view,
217             clickEvent = me.clicksToEdit === 1 ? 'click' : 'dblclick';
218
219         // Start editing
220         me.mon(view, 'cell' + clickEvent, me.startEditByClick, me);
221         view.on('render', function() {
222             me.keyNav = Ext.create('Ext.util.KeyNav', view.el, {
223                 enter: me.onEnterKey,
224                 esc: me.onEscKey,
225                 scope: me
226             });
227         }, me, { single: true });
228     },
229
230     // private
231     onEnterKey: function(e) {
232         var me = this,
233             grid = me.grid,
234             selModel = grid.getSelectionModel(),
235             record,
236             columnHeader = grid.headerCt.getHeaderAtIndex(0);
237
238         // Calculate editing start position from SelectionModel
239         // CellSelectionModel
240         if (selModel.getCurrentPosition) {
241             pos = selModel.getCurrentPosition();
242             record = grid.store.getAt(pos.row);
243             columnHeader = grid.headerCt.getHeaderAtIndex(pos.column);
244         }
245         // RowSelectionModel
246         else {
247             record = selModel.getLastSelected();
248         }
249         me.startEdit(record, columnHeader);
250     },
251
252     // private
253     onEscKey: function(e) {
254         this.cancelEdit();
255     },
256
257     // private
258     startEditByClick: function(view, cell, colIdx, record, row, rowIdx, e) {
259         this.startEdit(record, view.getHeaderAtIndex(colIdx));
260     },
261
262 <span id='Ext-grid-plugin-Editing-property-beforeEdit'>    /**
263 </span>     * @private
264      * @abstract. Template method called before editing begins.
265      * @param {Object} context The current editing context
266      * @return {Boolean} Return false to cancel the editing process
267      */
268     beforeEdit: Ext.emptyFn,
269
270 <span id='Ext-grid-plugin-Editing-method-startEdit'>    /**
271 </span>     * Start editing the specified record, using the specified Column definition to define which field is being edited.
272      * @param {Model} record The Store data record which backs the row to be edited.
273      * @param {Model} columnHeader The Column object defining the column to be edited.
274      */
275     startEdit: function(record, columnHeader) {
276         var me = this,
277             context = me.getEditingContext(record, columnHeader);
278
279         if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', context) === false || context.cancel) {
280             return false;
281         }
282
283         me.context = context;
284         me.editing = true;
285     },
286
287 <span id='Ext-grid-plugin-Editing-method-getEditingContext'>    /**
288 </span>     * @private Collects all information necessary for any subclasses to perform their editing functions.
289      * @param record
290      * @param columnHeader
291      * @returns {Object} The editing context based upon the passed record and column
292      */
293     getEditingContext: function(record, columnHeader) {
294         var me = this,
295             grid = me.grid,
296             store = grid.store,
297             rowIdx,
298             colIdx,
299             view = grid.getView(),
300             value;
301
302         // If they'd passed numeric row, column indices, look them up.
303         if (Ext.isNumber(record)) {
304             rowIdx = record;
305             record = store.getAt(rowIdx);
306         } else {
307             rowIdx = store.indexOf(record);
308         }
309         if (Ext.isNumber(columnHeader)) {
310             colIdx = columnHeader;
311             columnHeader = grid.headerCt.getHeaderAtIndex(colIdx);
312         } else {
313             colIdx = columnHeader.getIndex();
314         }
315
316         value = record.get(columnHeader.dataIndex);
317         return {
318             grid: grid,
319             record: record,
320             field: columnHeader.dataIndex,
321             value: value,
322             row: view.getNode(rowIdx),
323             column: columnHeader,
324             rowIdx: rowIdx,
325             colIdx: colIdx
326         };
327     },
328
329 <span id='Ext-grid-plugin-Editing-method-cancelEdit'>    /**
330 </span>     * Cancel any active edit that is in progress.
331      */
332     cancelEdit: function() {
333         this.editing = false;
334     },
335
336 <span id='Ext-grid-plugin-Editing-method-completeEdit'>    /**
337 </span>     * Complete the edit if there is an active edit in progress.
338      */
339     completeEdit: function() {
340         var me = this;
341
342         if (me.editing &amp;&amp; me.validateEdit()) {
343             me.fireEvent('edit', me.context);
344         }
345
346         delete me.context;
347         me.editing = false;
348     },
349
350     // @abstract
351     validateEdit: function() {
352         var me = this,
353             context = me.context;
354
355         return me.fireEvent('validateedit', me, context) !== false &amp;&amp; !context.cancel;
356     }
357 });</pre>
358 </body>
359 </html>