3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
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.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * This class provides an abstract grid editing plugin on selected {@link Ext.grid.column.Column columns}.
17 * The editable columns are specified by providing an {@link Ext.grid.column.Column#editor editor}
18 * in the {@link Ext.grid.column.Column column configuration}.
20 * **Note:** This class should not be used directly. See {@link Ext.grid.plugin.CellEditing} and
21 * {@link Ext.grid.plugin.RowEditing}.
23 Ext.define('Ext.grid.plugin.Editing', {
24 alias: 'editing.editing',
27 'Ext.grid.column.Column',
32 observable: 'Ext.util.Observable'
36 * @cfg {Number} clicksToEdit
37 * The number of clicks on a grid required to display the editor.
42 defaultFieldXType: 'textfield',
47 constructor: function(config) {
49 Ext.apply(me, config);
52 // Doc'ed in separate editing plugins
55 // Doc'ed in separate editing plugins
58 // Doc'ed in separate editing plugins
61 me.mixins.observable.constructor.call(me);
62 // TODO: Deprecated, remove in 5.0
63 me.relayEvents(me, ['afteredit'], 'after');
67 init: function(grid) {
73 me.mon(grid, 'reconfigure', me.onReconfigure, me);
76 grid.relayEvents(me, ['beforeedit', 'edit', 'validateedit']);
77 // Marks the grid as editable, so that the SelectionModel
78 // can make appropriate decisions during navigation
79 grid.isEditable = true;
80 grid.editingPlugin = grid.view.editingPlugin = me;
84 * Fires after the grid is reconfigured
87 onReconfigure: function(){
88 this.initFieldAccessors(this.view.getGridColumns());
93 * AbstractComponent calls destroy on all its plugins at destroy time.
98 headerCt = grid.headerCt,
101 Ext.destroy(me.keyNav);
102 me.removeFieldAccessors(grid.getView().getGridColumns());
104 // Clear all listeners from all our events, clear all managed listeners we added to other Observables
107 delete me.grid.editingPlugin;
108 delete me.grid.view.editingPlugin;
116 getEditStyle: function() {
117 return this.editStyle;
121 initFieldAccessors: function(column) {
124 if (Ext.isArray(column)) {
125 Ext.Array.forEach(column, me.initFieldAccessors, me);
129 // Augment the Header class to have a getEditor and setEditor method
130 // Important: Only if the header does not have its own implementation.
131 Ext.applyIf(column, {
132 getEditor: function(record, defaultField) {
133 return me.getColumnField(this, defaultField);
136 setEditor: function(field) {
137 me.setColumnField(this, field);
143 removeFieldAccessors: function(column) {
146 if (Ext.isArray(column)) {
147 Ext.Array.forEach(column, me.removeFieldAccessors, me);
151 delete column.getEditor;
152 delete column.setEditor;
156 // remaps to the public API of Ext.grid.column.Column.getEditor
157 getColumnField: function(columnHeader, defaultField) {
158 var field = columnHeader.field;
160 if (!field && columnHeader.editor) {
161 field = columnHeader.editor;
162 delete columnHeader.editor;
165 if (!field && defaultField) {
166 field = defaultField;
170 if (Ext.isString(field)) {
171 field = { xtype: field };
173 if (Ext.isObject(field) && !field.isFormField) {
174 field = Ext.ComponentManager.create(field, this.defaultFieldXType);
175 columnHeader.field = field;
179 name: columnHeader.dataIndex
187 // remaps to the public API of Ext.grid.column.Column.setEditor
188 setColumnField: function(column, field) {
189 if (Ext.isObject(field) && !field.isFormField) {
190 field = Ext.ComponentManager.create(field, this.defaultFieldXType);
192 column.field = field;
196 initEvents: function() {
198 me.initEditTriggers();
199 me.initCancelTriggers();
203 initCancelTriggers: Ext.emptyFn,
206 initEditTriggers: function() {
209 clickEvent = me.clicksToEdit === 1 ? 'click' : 'dblclick';
212 me.mon(view, 'cell' + clickEvent, me.startEditByClick, me);
213 view.on('render', function() {
214 me.keyNav = Ext.create('Ext.util.KeyNav', view.el, {
215 enter: me.onEnterKey,
219 }, me, { single: true });
223 onEnterKey: function(e) {
226 selModel = grid.getSelectionModel(),
228 columnHeader = grid.headerCt.getHeaderAtIndex(0);
230 // Calculate editing start position from SelectionModel
231 // CellSelectionModel
232 if (selModel.getCurrentPosition) {
233 pos = selModel.getCurrentPosition();
234 record = grid.store.getAt(pos.row);
235 columnHeader = grid.headerCt.getHeaderAtIndex(pos.column);
239 record = selModel.getLastSelected();
241 me.startEdit(record, columnHeader);
245 onEscKey: function(e) {
250 startEditByClick: function(view, cell, colIdx, record, row, rowIdx, e) {
251 this.startEdit(record, view.getHeaderAtIndex(colIdx));
257 * Template method called before editing begins.
258 * @param {Object} context The current editing context
259 * @return {Boolean} Return false to cancel the editing process
261 beforeEdit: Ext.emptyFn,
264 * Starts editing the specified record, using the specified Column definition to define which field is being edited.
265 * @param {Ext.data.Model/Number} record The Store data record which backs the row to be edited, or index of the record in Store.
266 * @param {Ext.grid.column.Column/Number} columnHeader The Column object defining the column to be edited, or index of the column.
268 startEdit: function(record, columnHeader) {
270 context = me.getEditingContext(record, columnHeader);
272 if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', context) === false || context.cancel) {
276 me.context = context;
282 * Collects all information necessary for any subclasses to perform their editing functions.
284 * @param columnHeader
285 * @returns {Object} The editing context based upon the passed record and column
287 getEditingContext: function(record, columnHeader) {
293 view = grid.getView(),
296 // If they'd passed numeric row, column indices, look them up.
297 if (Ext.isNumber(record)) {
299 record = store.getAt(rowIdx);
301 rowIdx = store.indexOf(record);
303 if (Ext.isNumber(columnHeader)) {
304 colIdx = columnHeader;
305 columnHeader = grid.headerCt.getHeaderAtIndex(colIdx);
307 colIdx = columnHeader.getIndex();
310 value = record.get(columnHeader.dataIndex);
314 field: columnHeader.dataIndex,
316 row: view.getNode(rowIdx),
317 column: columnHeader,
324 * Cancels any active edit that is in progress.
326 cancelEdit: function() {
327 this.editing = false;
331 * Completes the edit if there is an active edit in progress.
333 completeEdit: function() {
336 if (me.editing && me.validateEdit()) {
337 me.fireEvent('edit', me.context);
345 validateEdit: function() {
347 context = me.context;
349 return me.fireEvent('validateedit', me, context) !== false && !context.cancel;