| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-grid-plugin-CellEditing'>/**</span> * The Ext.grid.plugin.CellEditing plugin injects editing at a cell level for a Grid. Only a single * cell will be editable at a time. The field that will be used for the editor is defined at the * {@link Ext.grid.column.Column#editor editor}. The editor can be a field instance or a field configuration. * * If an editor is not specified for a particular column then that cell will not be editable and it will * be skipped when activated via the mouse or the keyboard. * * The editor may be shared for each column in the grid, or a different one may be specified for each column. * An appropriate field type should be chosen to match the data structure that it will be editing. For example, * to edit a date, it would be useful to specify {@link Ext.form.field.Date} as the editor. * * ## Example * * A grid with editor for the name and the email columns: * *     @example *     Ext.create('Ext.data.Store', { *         storeId:'simpsonsStore', *         fields:['name', 'email', 'phone'], *         data:{'items':[ *             {"name":"Lisa", "email":"lisa@simpsons.com", "phone":"555-111-1224"}, *             {"name":"Bart", "email":"bart@simpsons.com", "phone":"555-222-1234"}, *             {"name":"Homer", "email":"home@simpsons.com", "phone":"555-222-1244"}, *             {"name":"Marge", "email":"marge@simpsons.com", "phone":"555-222-1254"} *         ]}, *         proxy: { *             type: 'memory', *             reader: { *                 type: 'json', *                 root: 'items' *             } *         } *     }); * *     Ext.create('Ext.grid.Panel', { *         title: 'Simpsons', *         store: Ext.data.StoreManager.lookup('simpsonsStore'), *         columns: [ *             {header: 'Name',  dataIndex: 'name', editor: 'textfield'}, *             {header: 'Email', dataIndex: 'email', flex:1, *                 editor: { *                     xtype: 'textfield', *                     allowBlank: false *                 } *             }, *             {header: 'Phone', dataIndex: 'phone'} *         ], *         selType: 'cellmodel', *         plugins: [ *             Ext.create('Ext.grid.plugin.CellEditing', { *                 clicksToEdit: 1 *             }) *         ], *         height: 200, *         width: 400, *         renderTo: Ext.getBody() *     }); * * This requires a little explanation. We're passing in `store` and `columns` as normal, but * we also specify a {@link Ext.grid.column.Column#field field} on two of our columns. For the * Name column we just want a default textfield to edit the value, so we specify 'textfield'. * For the Email column we customized the editor slightly by passing allowBlank: false, which * will provide inline validation. * * To support cell editing, we also specified that the grid should use the 'cellmodel' * {@link Ext.grid.Panel#selType selType}, and created an instance of the CellEditing plugin, * which we configured to activate each editor after a single click. * */Ext.define('Ext.grid.plugin.CellEditing', {    alias: 'plugin.cellediting',    extend: 'Ext.grid.plugin.Editing',    requires: ['Ext.grid.CellEditor', 'Ext.util.DelayedTask'],    constructor: function() {<span id='Ext-grid-plugin-CellEditing-event-beforeedit'>        /**</span>         * @event beforeedit         * Fires before cell editing is triggered. Return false from event handler to stop the editing.         *         * @param {Ext.grid.plugin.CellEditing} editor         * @param {Object} e An edit event with the following properties:         *         * - grid - The grid         * - record - The record being edited         * - field - The field name being edited         * - value - The value for the field being edited.         * - row - The grid table row         * - column - The grid {@link Ext.grid.column.Column Column} defining the column that is being edited.         * - rowIdx - The row index that is being edited         * - colIdx - The column index that is being edited         * - cancel - Set this to true to cancel the edit or return false from your handler.         */<span id='Ext-grid-plugin-CellEditing-event-edit'>        /**</span>         * @event edit         * Fires after a cell is edited. Usage example:         *         *     grid.on('edit', function(editor, e) {         *         // commit the changes right after editing finished         *         e.record.commit();         *     });         *         * @param {Ext.grid.plugin.CellEditing} editor         * @param {Object} e An edit event with the following properties:         *         * - grid - The grid         * - record - The record that was edited         * - field - The field name that was edited         * - value - The value being set         * - originalValue - The original value for the field, before the edit.         * - row - The grid table row         * - column - The grid {@link Ext.grid.column.Column Column} defining the column that was edited.         * - rowIdx - The row index that was edited         * - colIdx - The column index that was edited         */<span id='Ext-grid-plugin-CellEditing-event-validateedit'>        /**</span>         * @event validateedit         * Fires after a cell is edited, but before the value is set in the record. Return false from event handler to         * cancel the change.         *         * Usage example showing how to remove the red triangle (dirty record indicator) from some records (not all). By         * observing the grid's validateedit event, it can be cancelled if the edit occurs on a targeted row (for         * example) and then setting the field's new value in the Record directly:         *         *     grid.on('validateedit', function(editor, e) {         *       var myTargetRow = 6;         *         *       if (e.row == myTargetRow) {         *         e.cancel = true;         *         e.record.data[e.field] = e.value;         *       }         *     });         *         * @param {Ext.grid.plugin.CellEditing} editor         * @param {Object} e An edit event with the following properties:         *         * - grid - The grid         * - record - The record being edited         * - field - The field name being edited         * - value - The value being set         * - originalValue - The original value for the field, before the edit.         * - row - The grid table row         * - column - The grid {@link Ext.grid.column.Column Column} defining the column that is being edited.         * - rowIdx - The row index that is being edited         * - colIdx - The column index that is being edited         * - cancel - Set this to true to cancel the edit or return false from your handler.         */<span id='Ext-grid-plugin-CellEditing-event-canceledit'>        /**</span>         * @event canceledit         * Fires when the user started editing a cell but then cancelled the edit.         * @param {Ext.grid.plugin.CellEditing} editor         * @param {Object} e An edit event with the following properties:         *          * - grid - The grid         * - record - The record that was edited         * - field - The field name that was edited         * - value - The value being set         * - row - The grid table row         * - column - The grid {@link Ext.grid.column.Column Column} defining the column that was edited.         * - rowIdx - The row index that was edited         * - colIdx - The column index that was edited         */        this.callParent(arguments);        this.editors = new Ext.util.MixedCollection(false, function(editor) {            return editor.editorId;        });        this.editTask = new Ext.util.DelayedTask();    },    onReconfigure: function(){        this.editors.clear();        this.callParent();        },<span id='Ext-grid-plugin-CellEditing-method-destroy'>    /**</span>     * @private     * AbstractComponent calls destroy on all its plugins at destroy time.     */    destroy: function() {        var me = this;        me.editTask.cancel();        me.editors.each(Ext.destroy, Ext);        me.editors.clear();        me.callParent(arguments);    },        onBodyScroll: function() {        var me = this,            ed = me.getActiveEditor(),            scroll = me.view.el.getScroll();        // Scroll happened during editing...        if (ed && ed.editing) {            // Terminate editing only on vertical scroll. Horiz scroll can be caused by tabbing between cells.            if (scroll.top !== me.scroll.top) {                if (ed.field) {                    if (ed.field.triggerBlur) {                        ed.field.triggerBlur();                    } else {                        ed.field.blur();                    }                }            }            // Horiz scroll just requires that the editor be realigned.            else {                 ed.realign();            }        }        me.scroll = scroll;    },    // private    // Template method called from base class's initEvents    initCancelTriggers: function() {        var me   = this,            grid = me.grid,            view = grid.view;                    view.addElListener('mousewheel', me.cancelEdit, me);        me.mon(view, 'bodyscroll', me.onBodyScroll, me);        me.mon(grid, {            columnresize: me.cancelEdit,            columnmove: me.cancelEdit,            scope: me        });    },    isCellEditable: function(record, columnHeader) {        var me = this,            context = me.getEditingContext(record, columnHeader);        if (me.grid.view.isVisible(true) && context) {            columnHeader = context.column;            record = context.record;            if (columnHeader && me.getEditor(record, columnHeader)) {                return true;            }        }    },<span id='Ext-grid-plugin-CellEditing-method-startEdit'>    /**</span>     * Starts editing the specified record, using the specified Column definition to define which field is being edited.     * @param {Ext.data.Model} record The Store data record which backs the row to be edited.     * @param {Ext.grid.column.Column} columnHeader The Column object defining the column to be edited.     * @return `true` if editing was started, `false` otherwise.     */    startEdit: function(record, columnHeader) {        var me = this,            context = me.getEditingContext(record, columnHeader),            value, ed;        // Complete the edit now, before getting the editor's target        // cell DOM element. Completing the edit causes a row refresh.        // Also allows any post-edit events to take effect before continuing        me.completeEdit();        // Cancel editing if EditingContext could not be found (possibly because record has been deleted by an intervening listener), or if the grid view is not currently visible        if (!context || !me.grid.view.isVisible(true)) {            return false;        }        record = context.record;        columnHeader = context.column;        // See if the field is editable for the requested record        if (columnHeader && !columnHeader.getEditor(record)) {            return false;        }        value = record.get(columnHeader.dataIndex);        context.originalValue = context.value = value;        if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', me, context) === false || context.cancel) {            return false;        }        ed = me.getEditor(record, columnHeader);        // Whether we are going to edit or not, ensure the edit cell is scrolled into view        me.grid.view.cancelFocus();        me.view.focusCell({            row: context.rowIdx,            column: context.colIdx        });        if (ed) {            me.editTask.delay(15, me.showEditor, me, [ed, context, value]);            return true;        }        return false;    },    showEditor: function(ed, context, value) {        var me = this,            record = context.record,            columnHeader = context.column,            sm = me.grid.getSelectionModel(),            selection = sm.getCurrentPosition();        me.context = context;        me.setActiveEditor(ed);        me.setActiveRecord(record);        me.setActiveColumn(columnHeader);        // Select cell on edit only if it's not the currently selected cell        if (sm.selectByPosition && (!selection || selection.column !== context.colIdx || selection.row !== context.rowIdx)) {            sm.selectByPosition({                row: context.rowIdx,                column: context.colIdx            });        }        ed.startEdit(me.getCell(record, columnHeader), value);        me.editing = true;        me.scroll = me.view.el.getScroll();    },    completeEdit: function() {        var activeEd = this.getActiveEditor();        if (activeEd) {            activeEd.completeEdit();            this.editing = false;        }    },    // internal getters/setters    setActiveEditor: function(ed) {        this.activeEditor = ed;    },    getActiveEditor: function() {        return this.activeEditor;    },    setActiveColumn: function(column) {        this.activeColumn = column;    },    getActiveColumn: function() {        return this.activeColumn;    },    setActiveRecord: function(record) {        this.activeRecord = record;    },    getActiveRecord: function() {        return this.activeRecord;    },    getEditor: function(record, column) {        var me = this,            editors = me.editors,            editorId = column.getItemId(),            editor = editors.getByKey(editorId);        if (editor) {            return editor;        } else {            editor = column.getEditor(record);            if (!editor) {                return false;            }            // Allow them to specify a CellEditor in the Column            // Either way, the Editor is a floating Component, and must be attached to an ownerCt            // which it uses to traverse upwards to find a ZIndexManager at render time.            if (!(editor instanceof Ext.grid.CellEditor)) {                editor = new Ext.grid.CellEditor({                    editorId: editorId,                    field: editor,                    ownerCt: me.grid                });            } else {                editor.ownerCt = me.grid;            }            editor.editingPlugin = me;            editor.isForTree = me.grid.isTree;            editor.on({                scope: me,                specialkey: me.onSpecialKey,                complete: me.onEditComplete,                canceledit: me.cancelEdit            });            editors.add(editor);            return editor;        }    },        // inherit docs    setColumnField: function(column, field) {        var ed = this.editors.getByKey(column.getItemId());        Ext.destroy(ed, column.field);        this.editors.removeAtKey(column.getItemId());        this.callParent(arguments);    },<span id='Ext-grid-plugin-CellEditing-method-getCell'>    /**</span>     * Gets the cell (td) for a particular record and column.     * @param {Ext.data.Model} record     * @param {Ext.grid.column.Column} column     * @private     */    getCell: function(record, column) {        return this.grid.getView().getCell(record, column);    },    onSpecialKey: function(ed, field, e) {        var me = this,            grid = me.grid,            sm;                    if (e.getKey() === e.TAB) {            e.stopEvent();                        if (ed) {                // Allow the field to act on tabs before onEditorTab, which ends                // up calling completeEdit. This is useful for picker type fields.                ed.onEditorTab(e);            }                        sm = grid.getSelectionModel();            if (sm.onEditorTab) {                sm.onEditorTab(me, e);            }        }    },    onEditComplete : function(ed, value, startValue) {        var me = this,            grid = me.grid,            activeColumn = me.getActiveColumn(),            sm = grid.getSelectionModel(),            record;        if (activeColumn) {            record = me.context.record;            me.setActiveEditor(null);            me.setActiveColumn(null);            me.setActiveRecord(null);                if (!me.validateEdit()) {                return;            }            // Only update the record if the new value is different than the            // startValue. When the view refreshes its el will gain focus            if (!record.isEqual(value, startValue)) {                record.set(activeColumn.dataIndex, value);            }            // Restore focus back to the view's element.            if (sm.setCurrentPosition) {                sm.setCurrentPosition(sm.getCurrentPosition());            }            grid.getView().getEl(activeColumn).focus();            me.context.value = value;            me.fireEvent('edit', me, me.context);        }    },<span id='Ext-grid-plugin-CellEditing-method-cancelEdit'>    /**</span>     * Cancels any active editing.     */    cancelEdit: function() {        var me = this,            activeEd = me.getActiveEditor(),            viewEl = me.grid.getView().getEl(me.getActiveColumn());        me.setActiveEditor(null);        me.setActiveColumn(null);        me.setActiveRecord(null);        if (activeEd) {            activeEd.cancelEdit();            viewEl.focus();            me.callParent(arguments);        }    },<span id='Ext-grid-plugin-CellEditing-method-startEditByPosition'>    /**</span>     * Starts editing by position (row/column)     * @param {Object} position A position with keys of row and column.     */    startEditByPosition: function(position) {        // Coerce the edit column to the closest visible column        position.column = this.view.getHeaderCt().getVisibleHeaderClosestToIndex(position.column).getIndex();        return this.startEdit(position.row, position.column);    }});</pre></body></html>
 |