| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592 | <!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-Editing'>/**</span> * 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}. */Ext.define('Ext.grid.plugin.Editing', {    alias: 'editing.editing',    extend: 'Ext.AbstractPlugin',    requires: [        'Ext.grid.column.Column',        'Ext.util.KeyNav'    ],    mixins: {        observable: 'Ext.util.Observable'    },<span id='Ext-grid-plugin-Editing-cfg-clicksToEdit'>    /**</span>     * @cfg {Number} clicksToEdit     * The number of clicks on a grid required to display the editor.     * The only accepted values are **1** and **2**.     */    clicksToEdit: 2,<span id='Ext-grid-plugin-Editing-cfg-triggerEvent'>    /**</span>     * @cfg {String} triggerEvent     * The event which triggers editing. Supercedes the {@link #clicksToEdit} configuration. Maybe one of:     *     *  * cellclick     *  * celldblclick     *  * cellfocus     *  * rowfocus     */    triggerEvent: undefined,    // private    defaultFieldXType: 'textfield',    // cell, row, form    editStyle: '',    constructor: function(config) {        var me = this;        me.addEvents(<span id='Ext-grid-plugin-Editing-event-beforeedit'>            /**</span>             * @event beforeedit             * Fires before editing is triggered. Return false from event handler to stop the editing.             *             * @param {Ext.grid.plugin.Editing} 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.             * - originalValue - Alias for value (only when using {@link Ext.grid.plugin.CellEditing CellEditing}).             */            'beforeedit',<span id='Ext-grid-plugin-Editing-event-edit'>            /**</span>             * @event edit             * Fires after a editing. Usage example:             *             *     grid.on('edit', function(editor, e) {             *         // commit the changes right after editing finished             *         e.record.commit();             *     });             *             * @param {Ext.grid.plugin.Editing} 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             * - originalValue - The original value for the field, before the edit (only when using {@link Ext.grid.plugin.CellEditing CellEditing})             * - originalValues - The original values for the field, before the edit (only when using {@link Ext.grid.plugin.RowEditing RowEditing})             * - newValues - The new values being set (only when using {@link Ext.grid.plugin.RowEditing RowEditing})             * - view - The grid view (only when using {@link Ext.grid.plugin.RowEditing RowEditing})             * - store - The grid store (only when using {@link Ext.grid.plugin.RowEditing RowEditing})             */            'edit',<span id='Ext-grid-plugin-Editing-event-validateedit'>            /**</span>             * @event validateedit             * Fires after editing, 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.rowIdx == myTargetRow) {             *         e.cancel = true;             *         e.record.data[e.field] = e.value;             *       }             *     });             *             * @param {Ext.grid.plugin.Editing} 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             * - 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.             * - originalValue - The original value for the field, before the edit (only when using {@link Ext.grid.plugin.CellEditing CellEditing})             * - originalValues - The original values for the field, before the edit (only when using {@link Ext.grid.plugin.RowEditing RowEditing})             * - newValues - The new values being set (only when using {@link Ext.grid.plugin.RowEditing RowEditing})             * - view - The grid view (only when using {@link Ext.grid.plugin.RowEditing RowEditing})             * - store - The grid store (only when using {@link Ext.grid.plugin.RowEditing RowEditing})             */            'validateedit',<span id='Ext-grid-plugin-Editing-event-canceledit'>            /**</span>             * @event canceledit             * Fires when the user started editing but then cancelled the edit.             * @param {Ext.grid.plugin.Editing} 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             * - view - The grid view             * - store - The grid store             */            'canceledit'        );        me.callParent(arguments);        me.mixins.observable.constructor.call(me);        // TODO: Deprecated, remove in 5.0        me.on("edit", function(editor, e) {            me.fireEvent("afteredit", editor, e);        });    },    // private    init: function(grid) {        var me = this;        me.grid = grid;        me.view = grid.view;        me.initEvents();        me.mon(grid, 'reconfigure', me.onReconfigure, me);        me.onReconfigure();        grid.relayEvents(me, [<span id='Ext-panel-Table-event-beforeedit'>            /**</span>             * @event beforeedit             * Forwarded event from Ext.grid.plugin.Editing.             * @member Ext.panel.Table             * @inheritdoc Ext.grid.plugin.Editing#beforeedit             */            'beforeedit',<span id='Ext-panel-Table-event-edit'>            /**</span>             * @event edit             * Forwarded event from Ext.grid.plugin.Editing.             * @member Ext.panel.Table             * @inheritdoc Ext.grid.plugin.Editing#edit             */            'edit',<span id='Ext-panel-Table-event-validateedit'>            /**</span>             * @event validateedit             * Forwarded event from Ext.grid.plugin.Editing.             * @member Ext.panel.Table             * @inheritdoc Ext.grid.plugin.Editing#validateedit             */            'validateedit',<span id='Ext-panel-Table-event-canceledit'>            /**</span>             * @event canceledit             * Forwarded event from Ext.grid.plugin.Editing.             * @member Ext.panel.Table             * @inheritdoc Ext.grid.plugin.Editing#canceledit             */            'canceledit'        ]);        // Marks the grid as editable, so that the SelectionModel        // can make appropriate decisions during navigation        grid.isEditable = true;        grid.editingPlugin = grid.view.editingPlugin = me;    },<span id='Ext-grid-plugin-Editing-method-onReconfigure'>    /**</span>     * Fires after the grid is reconfigured     * @private     */    onReconfigure: function() {        this.initFieldAccessors(this.view.getGridColumns());    },<span id='Ext-grid-plugin-Editing-method-destroy'>    /**</span>     * @private     * AbstractComponent calls destroy on all its plugins at destroy time.     */    destroy: function() {        var me = this,            grid = me.grid;        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(columns) {        columns = [].concat(columns);        var me   = this,            c,            cLen = columns.length,            column;        for (c = 0; c < cLen; c++) {            column = columns[c];            Ext.applyIf(column, {                getEditor: function(record, defaultField) {                    return me.getColumnField(this, defaultField);                },                setEditor: function(field) {                    me.setColumnField(this, field);                }            });        }    },    // private    removeFieldAccessors: function(columns) {        columns = [].concat(columns);        var c,            cLen = columns.length,            column;        for (c = 0; c < cLen; c++) {            column = columns[c];            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 (!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;        // Listen for the edit trigger event.        if (me.triggerEvent == 'cellfocus') {            me.mon(view, 'cellfocus', me.onCellFocus, me);        } else if (me.triggerEvent == 'rowfocus') {            me.mon(view, 'rowfocus', me.onRowFocus, me);        } else {            // Prevent the View from processing when the SelectionModel focuses.            // This is because the SelectionModel processes the mousedown event, and            // focusing causes a scroll which means that the subsequent mouseup might            // take place at a different document XY position, and will therefore            // not trigger a click.            // This Editor must call the View's focusCell method directly when we recieve a request to edit            if (view.selModel.isCellModel) {                view.onCellFocus = Ext.Function.bind(me.beforeViewCellFocus, me);            }            // Listen for whichever click event we are configured to use            me.mon(view, me.triggerEvent || ('cell' + (me.clicksToEdit === 1 ? 'click' : 'dblclick')), me.onCellClick, me);        }                // add/remove header event listeners need to be added immediately because        // columns can be added/removed before render        me.initAddRemoveHeaderEvents()        // wait until render to initialize keynav events since they are attached to an element        view.on('render', me.initKeyNavHeaderEvents, me, {single: true});    },    // Override of View's method so that we can pre-empt the View's processing if the view is being triggered by a mousedown    beforeViewCellFocus: function(position) {        // Pass call on to view if the navigation is from the keyboard, or we are not going to edit this cell.        if (this.view.selModel.keyNavigation || !this.editing || !this.isCellEditable || !this.isCellEditable(position.row, position.columnHeader)) {            this.view.focusCell.apply(this.view, arguments);        }    },    // private. Used if we are triggered by the rowfocus event    onRowFocus: function(record, row, rowIdx) {        this.startEdit(row, 0);    },    // private. Used if we are triggered by the cellfocus event    onCellFocus: function(record, cell, position) {        this.startEdit(position.row, position.column);    },    // private. Used if we are triggered by a cellclick event    onCellClick: function(view, cell, colIdx, record, row, rowIdx, e) {        // cancel editing if the element that was clicked was a tree expander        if(!view.expanderSelector || !e.getTarget(view.expanderSelector)) {            this.startEdit(record, view.getHeaderAtIndex(colIdx));        }    },    initAddRemoveHeaderEvents: function(){        var me = this;        me.mon(me.grid.headerCt, {            scope: me,            add: me.onColumnAdd,            remove: me.onColumnRemove        });    },    initKeyNavHeaderEvents: function() {        var me = this;        me.keyNav = Ext.create('Ext.util.KeyNav', me.view.el, {            enter: me.onEnterKey,            esc: me.onEscKey,            scope: me        });    },        // private    onColumnAdd: function(ct, column) {        if (column.isHeader) {            this.initFieldAccessors(column);        }    },    // private    onColumnRemove: function(ct, column) {        if (column.isHeader) {            this.removeFieldAccessors(column);        }    },    // private    onEnterKey: function(e) {        var me = this,            grid = me.grid,            selModel = grid.getSelectionModel(),            record,            pos,            columnHeader = grid.headerCt.getHeaderAtIndex(0);        // Calculate editing start position from SelectionModel        // CellSelectionModel        if (selModel.getCurrentPosition) {            pos = selModel.getCurrentPosition();            if (pos) {                record = grid.store.getAt(pos.row);                columnHeader = grid.headerCt.getHeaderAtIndex(pos.column);            }        }        // RowSelectionModel        else {            record = selModel.getLastSelected();        }        // If there was a selection to provide a starting context...        if (record && columnHeader) {            me.startEdit(record, columnHeader);        }    },    // private    onEscKey: function(e) {        this.cancelEdit();    },<span id='Ext-grid-plugin-Editing-method-beforeEdit'>    /**</span>     * @private     * @template     * 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,<span id='Ext-grid-plugin-Editing-method-startEdit'>    /**</span>     * Starts editing the specified record, using the specified Column definition to define which field is being edited.     * @param {Ext.data.Model/Number} record The Store data record which backs the row to be edited, or index of the record in Store.     * @param {Ext.grid.column.Column/Number} columnHeader The Column object defining the column to be edited, or index of the column.     */    startEdit: function(record, columnHeader) {        var me = this,            context = me.getEditingContext(record, columnHeader);        if (context == null || me.beforeEdit(context) === false || me.fireEvent('beforeedit', me, context) === false || context.cancel || !me.grid.view.isVisible(true)) {            return false;        }        me.context = context;<span id='Ext-grid-plugin-Editing-property-editing'>        /**</span>         * @property {Boolean} editing         * Set to `true` while the editing plugin is active and an Editor is visible.         */        me.editing = true;    },    // TODO: Have this use a new class Ext.grid.CellContext for use here, and in CellSelectionModel<span id='Ext-grid-plugin-Editing-method-getEditingContext'>    /**</span>     * @private     * Collects all information necessary for any subclasses to perform their editing functions.     * @param record     * @param columnHeader     * @returns {Object/undefined} The editing context based upon the passed record and column     */    getEditingContext: function(record, columnHeader) {        var me = this,            grid = me.grid,            view = grid.getView(),            node = view.getNode(record),            rowIdx, colIdx;        // An intervening listener may have deleted the Record        if (!node) {            return;        }        // Coerce the column index to the closest visible column        columnHeader = grid.headerCt.getVisibleHeaderClosestToIndex(Ext.isNumber(columnHeader) ? columnHeader : columnHeader.getIndex());        // No corresponding column. Possible if all columns have been moved to the other side of a lockable grid pair        if (!columnHeader) {            return;        }        colIdx = columnHeader.getIndex();        if (Ext.isNumber(record)) {            // look up record if numeric row index was passed            rowIdx = record;            record = view.getRecord(node);        } else {            rowIdx = view.indexOf(node);        }        return {            grid   : grid,            record : record,            field  : columnHeader.dataIndex,            value  : record.get(columnHeader.dataIndex),            row    : view.getNode(rowIdx),            column : columnHeader,            rowIdx : rowIdx,            colIdx : colIdx        };    },<span id='Ext-grid-plugin-Editing-method-cancelEdit'>    /**</span>     * Cancels any active edit that is in progress.     */    cancelEdit: function() {        var me = this;        me.editing = false;        me.fireEvent('canceledit', me, me.context);    },<span id='Ext-grid-plugin-Editing-method-completeEdit'>    /**</span>     * Completes the edit if there is an active edit in progress.     */    completeEdit: function() {        var me = this;        if (me.editing && me.validateEdit()) {            me.fireEvent('edit', me, 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;    }});</pre></body></html>
 |