Hybrid View

    Success! Looks like we've fixed this one. According to our records the fix was applied for EXTJS-7710 in 4.2.0.265.
  1. #1
    Sencha Premium Member
    Join Date
    Oct 2012
    Posts
    16
    Vote Rating
    0
    dwsnyder is on a distinguished road

      0  

    Default Grid.reconfigure() adds additional onspecialkey handler to cell editors

    Grid.reconfigure() adds additional onspecialkey handler to cell editors


    REQUIRED INFORMATION


    Ext version tested:
    • Ext 4.1.3 rev 548


    Browser versions tested against:
    • IE7
    • FF3.6 (firebug 1.6.2 installed)


    DOCTYPE tested against:
    • html


    Description:
    • Using the cell editing plugin on a Grid, if the Grid is reconfigured with a different Store, then using the tab key when the editor is active now skips ahead two cells instead of one. Each time the Grid is reconfigured, and additional cell will be jumped over.


    Steps to reproduce the problem:
    • Using the included test case, click in a cell to activate the editor. Press the tab key and notice the cursor advances to the next cell
    • Now click the "Store 2" button in the toolbar.
    • Click a cell to activate the editor. Press the tab key and the cursor now advances two cells.


    The result that was expected:
    • tab advances 1 cell after N calls to reconfigure()


    The result that occurs instead:
    • tab advances N cells after N calls to reconfigure()


    Test Case:

    Use this modified cell-editing.js with the Cell Editing example:

    Code:
        Ext.Loader.setConfig({
        enabled: true
    });
    Ext.Loader.setPath('Ext.ux', '../ux');
    
    Ext.require([
        'Ext.selection.CellModel',
        'Ext.grid.*',
        'Ext.data.*',
        'Ext.util.*',
        'Ext.state.*',
        'Ext.form.*',
        'Ext.ux.CheckColumn'
    ]);
    
    if (window.location.search.indexOf('scopecss') !== -1) {
        // We are using ext-all-scoped.css, so all rendered ExtJS Components must have a
        // reset wrapper round them to provide localized CSS resetting.
        Ext.scopeResetCSS = true;
    }
    
    Ext.onReady(function(){
        Ext.QuickTips.init();
     
        function formatDate(value){
            return value ? Ext.Date.dateFormat(value, 'M d, Y') : '';
        }
    
        Ext.define('Plant', {
            extend: 'Ext.data.Model',
            fields: [
                // the 'name' below matches the tag name to read, except 'availDate'
                // which is mapped to the tag 'availability'
                {name: 'common', type: 'string'},
                {name: 'botanical', type: 'string'},
                {name: 'light'},
                {name: 'price', type: 'float'},
                // dates can be automatically converted by specifying dateFormat
                {name: 'availDate', mapping: 'availability', type: 'date', dateFormat: 'm/d/Y'},
                {name: 'indoor', type: 'bool'}
            ]
        });
    
    
        // create the Data Stores
        var store1 = Ext.create('Ext.data.Store', {
            autoDestroy: false,
            model: 'Plant',
            data: [
                {common: 'Test1'},
                {common: 'Test2' }
            
            ], 
            sorters: [{
                property: 'common',
                direction:'ASC'
            }]
        });
    
        var store2 = Ext.create('Ext.data.Store', {
            autoDestroy: false,
            model: 'Plant',
            data: [
                {common: 'Test3'},
                {common: 'Test4' }
            
            ], 
            sorters: [{
                property: 'common',
                direction:'ASC'
            }]
        });
    
    
        var cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
            clicksToEdit: 1
        });
    
        // create the grid and specify what field you want
        // to use for the editor at each header.
        var grid = Ext.create('Ext.grid.Panel', {
            store: store1,
            columns: [{
                id: 'common',
                header: 'Common Name',
                dataIndex: 'common',
                flex: 1,
                editor: {
                    allowBlank: false
                }
            }, {
                header: 'Light',
                dataIndex: 'light',
                width: 130,
                editor: new Ext.form.field.ComboBox({
                    typeAhead: true,
                    triggerAction: 'all',
                    selectOnTab: true,
                    store: [
                        ['Shade','Shade'],
                        ['Mostly Shady','Mostly Shady'],
                        ['Sun or Shade','Sun or Shade'],
                        ['Mostly Sunny','Mostly Sunny'],
                        ['Sunny','Sunny']
                    ],
                    lazyRender: true,
                    listClass: 'x-combo-list-small'
                })
            }, {
                header: 'Price',
                dataIndex: 'price',
                width: 70,
                align: 'right',
                renderer: 'usMoney',
                editor: {
                    xtype: 'numberfield',
                    allowBlank: false,
                    minValue: 0,
                    maxValue: 100000
                }
            }, {
                header: 'Available',
                dataIndex: 'availDate',
                width: 95,
                renderer: formatDate,
                editor: {
                    xtype: 'datefield',
                    format: 'm/d/y',
                    minValue: '01/01/06',
                    disabledDays: [0, 6],
                    disabledDaysText: 'Plants are not available on the weekends'
                }
            }, {
                xtype: 'checkcolumn',
                header: 'Indoor?',
                dataIndex: 'indoor',
                width: 55,
                stopSelection: false
            }, {
                xtype: 'actioncolumn',
                width:30,
                sortable: false,
                items: [{
                    icon: '../shared/icons/fam/delete.gif',
                    tooltip: 'Delete Plant',
                    handler: function(grid, rowIndex, colIndex) {
                        store.removeAt(rowIndex); 
                    }
                }]
            }],
            selModel: {
                selType: 'cellmodel'
            },
            renderTo: 'editor-grid',
            width: 600,
            height: 300,
            title: 'Edit Plants?',
            frame: true,
            tbar: [{
                text: 'Add Plant',
                handler : function(){
                    // Create a model instance
                    var r = Ext.create('Plant', {
                        common: 'New Plant 1',
                        light: 'Mostly Shady',
                        price: 0,
                        availDate: Ext.Date.clearTime(new Date()),
                        indoor: false
                    });
                    grid.getStore().insert(0, r);
                    cellEditing.startEditByPosition({row: 0, column: 0});
                }
            },
            {
                text: 'Store1',
                handler : function(){
                    if (cellEditing.editing) {
                        cellEditing.completeEdit();
                    }
    
                    grid.reconfigure(store1);
                }
            },
            {
                text: 'Store2',
                handler : function(){
                    if (cellEditing.editing) {
                        cellEditing.completeEdit();
                    }
                    grid.reconfigure(store2);
                }
            }    
                ],
            plugins: [cellEditing]
        });
    
      
    });


    HELPFUL INFORMATION




    Debugging already done:
    • it looks like the Ext.form.Field objects used by the editor get an 'onspecialkey' handler added at some point in the reconfigure process--so the fields end up with N 'onspecialkey' handlers after N reconfigures, which causes the selectionModel to move over N cells. I haven't stepped through enough to find out at what point the handlers are added.


    Possible fix:
    • not provided


    Additional CSS used:
    • only default ext-all.css


    Operating System:
    • WinXP Pro

  2. #2
    Sencha Premium Member
    Join Date
    Oct 2012
    Posts
    16
    Vote Rating
    0
    dwsnyder is on a distinguished road

      0  

    Default possible fix

    possible fix


    This override seems to fix it:

    Code:
    Ext.define(null, {
        override: 'Ext.grid.plugin.CellEditing',
    
         getEditor: function(record, column) {
            var me = this,
                grid = column.up('tablepanel'),
                editors = me.editors,
                editorId = column.getItemId(),
                editor = editors.getByKey(editorId),
                listenerRemover;  // <--- new var
    
            // Editors are shared between editing plugins on both sides of a locked grid
            if (!editor && me.lockingPartner) {
                editor = me.lockingPartner.editors.getByKey(editorId);
            }
    
            if (!editor) {
                editor = column.getEditor(record);
                if (!editor) {
                    return false;
                }
    
                // Allow them to specify a CellEditor in the Column
                if (!(editor instanceof Ext.grid.CellEditor)) {
                    editor = new Ext.grid.CellEditor({
                        editorId: editorId,
                        field: editor,
                        isForTree: me.grid.isTree
                    });
                } else {
                    editor.ownerCt = me.grid;
                }
    
        
    /* begin changes */
    
                listenerRemover = editor.on({
                    destroyable: true,
                    scope: me,
                    specialkey: me.onSpecialKey,
                    complete: me.onEditComplete,
                    canceledit: me.cancelEdit
                });
    
                grid.on('reconfigure', listenerRemover.destroy, listenerRemover, { single: true}); 
    
    /* end changes */
    
                column.on('destroy', me.destroyEditor, me);
                editors.add(editor);
            }
            editor.editingPlugin = me;
    
            // 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.
            editor.ownerCt = grid;
            return editor;
        }
    
    });