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