/** * This class specializes `Ext.Editor` for the purpose of editing grid cells inline. This * class is not instantiated by user code but rather by `Ext.grid.plugin.CellEditing`. * @private * @since 6.5.0 */Ext.define('Ext.grid.CellEditor', { extend: 'Ext.Editor', xtype: 'celleditor', isCellEditor: true, floated: false, classCls: Ext.baseCSSPrefix + 'celleditor', config: { /** * @cfg {Boolean} autoPin * Determines if the row that the cell editor is attached to will pin to the top * and bottom when scrolling. * If `false` editing will be canceled when cell editor is scrolled off the list. */ autoPin: true }, relayedEvents: [ 'beforestartedit', 'startedit', 'beforecomplete', 'complete', 'canceledit', 'specialkey' ], swallowKeys: false, layout: 'fit', shadow: false, allowBlur: true, alignment: 'tl-tl', zIndex: 10, // Do not use the cell's rendered value useBoundValue: false, inheritUi: true, field: { inheritUi: true }, constructor: function(config) { var me = this, grid; me.callParent([config]); if (config.plugin) { grid = config.plugin.getGrid(); } if (grid) { grid.relayEvents(me, me.relayedEvents); } }, beforeEdit: function(el, value) { var me = this, ret; ret = me.callParent([ el, value ]); if (ret !== false) { ret = me.$activeLocation.beforeEdit(me); } return ret; }, /** * Starts editing at the passed {@link Ext.grid.Location location} using the passed value. * @param {Ext.grid.Location} location Where to start editing * @param {*} [value] The value to place in the editor. * @param {Boolean} [doFocus] `true` to focus the editor. * @return {Ext.grid.Location} The location where actionable mode was successfully started. */ startEdit: function(location, value, doFocus) { var me = this, cell, el, row, grid, result; if (location) { cell = location.cell; el = cell.el; value = value != null ? value : location.record.get(cell.dataIndex); // at this point we dont have focused el, so the location passed // as first param is our best idea of a location (will only be used // in the beforestart / start events). me.$activeLocation = location; // VERY important for focus management. // We must have an upward ownership link so that onFocusLeave // bubbles correctly. // This link must never be severed - it just is updated on each edit. me.ownerCmp = cell; // CellEditors are positioned and fitted within the cell using their CSS rules. me.render(el); me.callParent([el, value, doFocus]); // Superclass events may veto edit start. // If we are editing, set up our context. if (me.editing) { me.$activeRow = row = location.row; me.$activeGrid = grid = row.grid; me.editingPlugin.editing = true; // here we update the activeLocation to be used by the remaining events me.editingPlugin.location = me.$activeLocation = result = new Ext.grid.Location( grid, me.getField().getFocusEl() ); me.editingPlugin.activeEditor = me; grid.stickItem(row, { autoPin: me.getAutoPin() }); } else { // If the event was canceled during beforestartedit, // we should clear the location. me.$activeLocation = null; } } return result; }, onFocusLeave: function(e) { var me = this, location = me.$activeLocation, row = location && location.row, remainVisible = false, followItem = false, column, scrollRef; // FocusLeave result of destruction. Must not do anything. if (!me.editingPlugin.getGrid().destroying) { if (me.isCancelling) { me.cancelEdit(); } else { // In IE, scroll indicator is focusable. Because of which the editor looses focus // on scroll. if (Ext.isIE) { scrollRef = Ext.Component.from(e.target); if (scrollRef && scrollRef.isScrollIndicator) { me.isCancelling = false; return; } } // if the focus is moving within same row then set followItem as true if the // next cell is editable, otherwise, to remove the sticky item, send it as // false. if (row && e && row.isAncestor(e.fromComponent) && row.isAncestor(e.toComponent)) { column = row.getColumnByCell(e.toComponent); followItem = column.getEditable(); if (Ext.isEmpty(followItem)) { followItem = !!column.getEditor(); } } me.completeEdit(remainVisible, followItem); } } me.isCancelling = false; }, onFocusEnter: function(e) { // Force automatic focus reversion to go to our currently active cell. if (this.$activeLocation) { e.relatedTarget = e.fromElement = this.$activeLocation.getFocusEl('dom'); } this.callParent([e]); }, /** * @returns {Ext.grid.Location} The location where editing is active *if* editing is * active, else `null`. */ getLocation: function() { return this.$activeLocation; }, onSpecialKey: function(field, event) { var me = this; // Allow the NavigationModel handles the actual navigation. // When the CellEditing#activateCell finds this still active // it will complete the edit if the cancelling flag is not set if (event.getKey() === event.ESC) { me.isCancelling = true; } else { me.callParent([field, event]); } }, onEditComplete: function(remainVisible, cancelling, followItem) { var me = this, location = me.$activeLocation, value = me.getValue(), record, dataIndex, row, grid, sticky; me.callParent([remainVisible, cancelling, followItem]); if (location) { followItem = followItem || remainVisible; grid = location.row.grid; // If we are not coming from a cancelEdit, and the field's changed // then update the record. if (!cancelling && value !== me.startValue) { record = location.record; dataIndex = location.cell.dataIndex; if (record) { record.set(dataIndex, value); // The row may change due to auto sorting, so bring it into view // and refresh the location if (followItem) { grid.ensureVisible(location.record); } location.refresh(); } } if (!followItem) { row = location.row; sticky = !!row.$sticky; if (sticky) { grid.stickItem(row, null); } me.$stickyVisibility = me.$activeLocation = me.$activeRow = me.$activeGrid = null; me.editingPlugin.editing = false; me.editingPlugin.location = me.editingPlugin.activeEditor = null; } } }, // CellEditors are positioned and fitted within the cell using their CSS rules. realign: Ext.emptyFn, toggleBoundEl: function(visible) { var location = this.$activeLocation, cell, bodyEl; if (location && this.hideEl) { cell = location.cell; // If the location is still rendered... if (cell) { bodyEl = cell.bodyElement; bodyEl.setVisibility(visible); } } }});