X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/530ef4b6c5b943cfa68b779d11cf7de29aa878bf..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/docs/source/Editing.html diff --git a/docs/source/Editing.html b/docs/source/Editing.html new file mode 100644 index 00000000..b866990a --- /dev/null +++ b/docs/source/Editing.html @@ -0,0 +1,331 @@ +Sencha Documentation Project
+/**
+ * @class Ext.grid.plugin.Editing
+
+This class provides an abstract grid editing plugin on selected {@link Ext.grid.column.Column columns}.
+The editable columns are specified by providing an {@link Ext.grid.column.Column#editor editor}
+in the {@link Ext.grid.column.Column column configuration}.
+
+*Note:* This class should not be used directly. See {@link Ext.grid.plugin.CellEditing} and
+{@link Ext.grid.plugin.RowEditing}.
+
+ * @markdown
+ */
+Ext.define('Ext.grid.plugin.Editing', {
+    alias: 'editing.editing',
+
+    requires: [
+        'Ext.grid.column.Column',
+        'Ext.util.KeyNav'
+    ],
+
+    mixins: {
+        observable: 'Ext.util.Observable'
+    },
+
+    /**
+     * @cfg {Number} clicksToEdit
+     * The number of clicks on a grid required to display the editor (defaults to 2).
+     */
+    clicksToEdit: 2,
+
+    // private
+    defaultFieldXType: 'textfield',
+
+    // cell, row, form
+    editStyle: '',
+
+    constructor: function(config) {
+        var me = this;
+        Ext.apply(me, config);
+
+        me.addEvents(
+            // Doc'ed in separate editing plugins
+            'beforeedit',
+
+            // Doc'ed in separate editing plugins
+            'edit',
+
+            // Doc'ed in separate editing plugins
+            'validateedit'
+        );
+        me.mixins.observable.constructor.call(me);
+        // TODO: Deprecated, remove in 5.0
+        me.relayEvents(me, ['afteredit'], 'after');
+    },
+
+    // private
+    init: function(grid) {
+        var me = this;
+
+        me.grid = grid;
+        me.view = grid.view;
+        me.initEvents();
+        me.initFieldAccessors(me.view.getGridColumns());
+
+        grid.relayEvents(me, ['beforeedit', 'edit', 'validateedit']);
+        // Marks the grid as editable, so that the SelectionModel
+        // can make appropriate decisions during navigation
+        grid.isEditable = true;
+        grid.editingPlugin = grid.view.editingPlugin = me;
+    },
+
+    /**
+     * @private
+     * AbstractComponent calls destroy on all its plugins at destroy time.
+     */
+    destroy: function() {
+        var me = this,
+            grid = me.grid,
+            headerCt = grid.headerCt,
+            events = grid.events;
+
+        Ext.destroy(me.keyNav);
+        me.removeFieldAccessors(grid.getView().getGridColumns());
+
+        // Clear all listeners from all our events, clear all managed listeners we added to other Observables
+        me.clearListeners();
+
+        delete me.grid.editingPlugin;
+        delete me.grid.view.editingPlugin;
+        delete me.grid;
+        delete me.view;
+        delete me.editor;
+        delete me.keyNav;
+    },
+
+    // private
+    getEditStyle: function() {
+        return this.editStyle;
+    },
+
+    // private
+    initFieldAccessors: function(column) {
+        var me = this;
+
+        if (Ext.isArray(column)) {
+            Ext.Array.forEach(column, me.initFieldAccessors, me);
+            return;
+        }
+
+        // Augment the Header class to have a getEditor and setEditor method
+        // Important: Only if the header does not have its own implementation.
+        Ext.applyIf(column, {
+            getEditor: function(record, defaultField) {
+                return me.getColumnField(this, defaultField);
+            },
+
+            setEditor: function(field) {
+                me.setColumnField(this, field);
+            }
+        });
+    },
+
+    // private
+    removeFieldAccessors: function(column) {
+        var me = this;
+
+        if (Ext.isArray(column)) {
+            Ext.Array.forEach(column, me.removeFieldAccessors, me);
+            return;
+        }
+
+        delete column.getEditor;
+        delete column.setEditor;
+    },
+
+    // private
+    // remaps to the public API of Ext.grid.column.Column.getEditor
+    getColumnField: function(columnHeader, defaultField) {
+        var field = columnHeader.field;
+
+        if (!field && columnHeader.editor) {
+            field = columnHeader.editor;
+            delete columnHeader.editor;
+        }
+
+        if (!field && defaultField) {
+            field = defaultField;
+        }
+
+        if (field) {
+            if (Ext.isString(field)) {
+                field = { xtype: field };
+            }
+            if (Ext.isObject(field) && !field.isFormField) {
+                field = Ext.ComponentManager.create(field, this.defaultFieldXType);
+                columnHeader.field = field;
+            }
+
+            Ext.apply(field, {
+                name: columnHeader.dataIndex
+            });
+
+            return field;
+        }
+    },
+
+    // private
+    // remaps to the public API of Ext.grid.column.Column.setEditor
+    setColumnField: function(column, field) {
+        if (Ext.isObject(field) && !field.isFormField) {
+            field = Ext.ComponentManager.create(field, this.defaultFieldXType);
+        }
+        column.field = field;
+    },
+
+    // private
+    initEvents: function() {
+        var me = this;
+        me.initEditTriggers();
+        me.initCancelTriggers();
+    },
+
+    // @abstract
+    initCancelTriggers: Ext.emptyFn,
+
+    // private
+    initEditTriggers: function() {
+        var me = this,
+            view = me.view,
+            clickEvent = me.clicksToEdit === 1 ? 'click' : 'dblclick';
+
+        // Start editing
+        me.mon(view, 'cell' + clickEvent, me.startEditByClick, me);
+        view.on('render', function() {
+            me.keyNav = Ext.create('Ext.util.KeyNav', view.el, {
+                enter: me.onEnterKey,
+                esc: me.onEscKey,
+                scope: me
+            });
+        }, me, { single: true });
+    },
+
+    // private
+    onEnterKey: function(e) {
+        var me = this,
+            grid = me.grid,
+            selModel = grid.getSelectionModel(),
+            record,
+            columnHeader = grid.headerCt.getHeaderAtIndex(0);
+
+        // Calculate editing start position from SelectionModel
+        // CellSelectionModel
+        if (selModel.getCurrentPosition) {
+            pos = selModel.getCurrentPosition();
+            record = grid.store.getAt(pos.row);
+            columnHeader = grid.headerCt.getHeaderAtIndex(pos.column);
+        }
+        // RowSelectionModel
+        else {
+            record = selModel.getLastSelected();
+        }
+        me.startEdit(record, columnHeader);
+    },
+
+    // private
+    onEscKey: function(e) {
+        this.cancelEdit();
+    },
+
+    // private
+    startEditByClick: function(view, cell, colIdx, record, row, rowIdx, e) {
+        this.startEdit(record, view.getHeaderAtIndex(colIdx));
+    },
+
+    /**
+     * @private
+     * @abstract. Template method called before editing begins.
+     * @param {Object} context The current editing context
+     * @return {Boolean} Return false to cancel the editing process
+     */
+    beforeEdit: Ext.emptyFn,
+
+    /**
+     * Start editing the specified record, using the specified Column definition to define which field is being edited.
+     * @param {Model} record The Store data record which backs the row to be edited.
+     * @param {Model} columnHeader The Column object defining the column to be edited.
+     */
+    startEdit: function(record, columnHeader) {
+        var me = this,
+            context = me.getEditingContext(record, columnHeader);
+
+        if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', context) === false || context.cancel) {
+            return false;
+        }
+
+        me.context = context;
+        me.editing = true;
+    },
+
+    /**
+     * @private Collects all information necessary for any subclasses to perform their editing functions.
+     * @param record
+     * @param columnHeader
+     * @returns {Object} The editing context based upon the passed record and column
+     */
+    getEditingContext: function(record, columnHeader) {
+        var me = this,
+            grid = me.grid,
+            store = grid.store,
+            rowIdx,
+            colIdx,
+            view = grid.getView(),
+            value;
+
+        // If they'd passed numeric row, column indices, look them up.
+        if (Ext.isNumber(record)) {
+            rowIdx = record;
+            record = store.getAt(rowIdx);
+        } else {
+            rowIdx = store.indexOf(record);
+        }
+        if (Ext.isNumber(columnHeader)) {
+            colIdx = columnHeader;
+            columnHeader = grid.headerCt.getHeaderAtIndex(colIdx);
+        } else {
+            colIdx = columnHeader.getIndex();
+        }
+
+        value = record.get(columnHeader.dataIndex);
+        return {
+            grid: grid,
+            record: record,
+            field: columnHeader.dataIndex,
+            value: value,
+            row: view.getNode(rowIdx),
+            column: columnHeader,
+            rowIdx: rowIdx,
+            colIdx: colIdx
+        };
+    },
+
+    /**
+     * Cancel any active edit that is in progress.
+     */
+    cancelEdit: function() {
+        this.editing = false;
+    },
+
+    /**
+     * Complete the edit if there is an active edit in progress.
+     */
+    completeEdit: function() {
+        var me = this;
+
+        if (me.editing && me.validateEdit()) {
+            me.fireEvent('edit', me.context);
+        }
+
+        delete me.context;
+        me.editing = false;
+    },
+
+    // @abstract
+    validateEdit: function() {
+        var me = this,
+            context = me.context;
+
+        return me.fireEvent('validateedit', me, context) !== false && !context.cancel;
+    }
+});
\ No newline at end of file