[CLOSED] Keyboard Navigation in GridPanel with CheckboxselectionModel,

  1. #1

    [CLOSED] Keyboard Navigation in GridPanel with CheckboxselectionModel,

    Hi,

    Quick questions related to "KeyNav = true" and "Multi" selection mode.

    1. By default when using Keyboard navigation mode, the selected/focused row is checked.
    - I would like the selected row not to be checked by default.

    2. Keyboard navigation always clear current checked items.
    - I would like the keyboard navigation keep current checked rows.


    You can emulate my desired behavior (point 2). by holding control key and navigating. (shift is still working, space is still checking/unchecking rows and current selection stays if we move from row to row by keyboard)

    Thank you
    Last edited by Daniil; Dec 31, 2014 at 1:09 PM. Reason: [CLOSED]
  2. #2
    Hi Matt,

    As far as I can see there are no such settings to get the behavior that you need.

    The logic is in the Ext.selection.Model's afterKeyNavigate method. You can investigate and could try to override.
    http://docs-origin.sencha.com/extjs/...terKeyNavigate
  3. #3
    Daniil, Thank you for the hint.

    So simple to implement it once you really get into sencha source code. :)
    Implemented my behavior. If anyone needs help with that, please ask, I will post the changes.
  4. #4
    hi @matt
    please post the sample.may be this is helpful for others.
  5. #5

    My solution

    Hi,

    Sorry for late answer... but ExtJs 5 gave me a bit of headache :)

    So my solution is based on the idea of emulating Ctrl key pressed all the time. I took two methods from ExtJs4 source code of the selection model:

    - afterKeyNavigate
    - selectWithEvent

    I have added bool member which I called "freeSelection" that allow to turn off/on that feature. It is not proper override of the selection but a bit of hack (I needed that feature only for one grid panel in my app so did not override whole selection model class)


    Mainly I have changed e.ctrlKey to e.ctrlKey || me.freeSelection.


    Ext.define("MyApp.MyGrid.MySelection", {
    
    	// Private
    	// Called after a new record has been navigated to by a keystroke.
    	// Event is passed so that shift and ctrl can be handled.
    	afterKeyNavigate: function (e, record) {
    		var me = this,
                recIdx,
                fromIdx,
                isSelected = me.isSelected(record),
                from = (me.selectionStart && me.isSelected(me.lastFocused)) ? me.selectionStart : (me.selectionStart = me.lastFocused),
                key = e.getCharCode(),
                isSpace = key === e.SPACE,
                direction = key === e.UP || key === e.PAGE_UP ? 'up' : (key === e.DOWN || key === e.DOWN ? 'down' : null);
    
    		switch (me.selectionMode) {
    			case 'MULTI':
    
    				if (isSpace) {
    					// SHIFT+SPACE, select range
    					if (e.shiftKey) {
    						me.selectRange(from, record, e.ctrlKey || me.freeSelection);
    					} else {
    						// SPACE pessed on a selected item: deselect but leave it focused.
    						// e.ctrlKey means "keep existing"
    						if (isSelected) {
    							me.doDeselect(record, e.ctrlKey || me.freeSelection);
    
    							// This record is already focused. To get the focus effect put on it (as opposed to selected)
    							// we have to focus null first.
    							me.setLastFocused(null);
    							me.setLastFocused(record);
    						}
    							// SPACE on an unselected item: select it
    						else {
    							me.doSelect(record, e.ctrlKey || me.freeSelection);
    						}
    					}
    				}
    
    					// SHIFT-navigate selects intervening rows from the last selected (or last focused) item and target item
    				else if (e.shiftKey && from) {
    
    					// If we are going back *into* the selected range, we deselect.
    					fromIdx = me.store.indexOf(from);
    					recIdx = me.store.indexOf(record);
    
    					// If we are heading back TOWARDS the start rec - deselect skipped range...
    					if (direction === 'up' && fromIdx <= recIdx) {
    						me.deselectRange(me.lastFocused, recIdx + 1);
    					}
    					else if (direction === 'down' && fromIdx >= recIdx) {
    						me.deselectRange(me.lastFocused, recIdx - 1);
    					}
    
    						// If we are heading AWAY from start point, or no CTRL key, so just select the range and let the CTRL control "keepExisting"...
    					else if (from !== record) {
    						me.selectRange(from, record, e.ctrlKey || me.freeSelection);
    					}
    					me.lastSelected = record;
    					me.setLastFocused(record);
    				}
    
    					// CTRL-navigate onto a selected item just focuses it
    				else if ((e.ctrlKey || me.freeSelection) && isSelected) {
    					me.setLastFocused(record);
    				}
    
    					// CTRL-navigate, just move focus
    				else if (e.ctrlKey || me.freeSelection) {
    					me.setLastFocused(record);
    				}
    
    					// Just navigation - select the target
    				else {
    					me.doSelect(record, false);
    				}
    				break;
    			case 'SIMPLE':
    				if (isSelected) {
    					me.doDeselect(record);
    				} else {
    					me.doSelect(record, true);
    				}
    				break;
    			case 'SINGLE':
    				// Space hit
    				if (isSpace) {
    					if (isSelected) {
    						me.doDeselect(record);
    						me.setLastFocused(record);
    					} else {
    						me.doSelect(record);
    					}
    				}
    
    					// CTRL-navigation: just move focus
    				else if (e.ctrlKey || me.freeSelection) {
    					me.setLastFocused(record);
    				}
    
    					// if allowDeselect is on and this record isSelected, deselect it
    				else if (me.allowDeselect && isSelected) {
    					me.doDeselect(record);
    				}
    
    					// select the record and do NOT maintain existing selections
    				else {
    					me.doSelect(record, false);
    				}
    				break;
    		}
    
    		// selectionStart is a start point for shift/mousedown to create a range from.
    		// If the mousedowned record was not already selected, then it becomes the
    		// start of any range created from now on.
    		// If we drop to no records selected, then there is no range start any more.
    		if (!e.shiftKey) {
    			if (me.isSelected(record)) {
    				me.selectionStart = record;
    			}
    		}
    	},
    
    
    
    	// Provides differentiation of logic between MULTI, SIMPLE and SINGLE
    	// selection modes. Requires that an event be passed so that we can know
    	// if user held ctrl or shift.
    	selectWithEvent: function (record, e) {
    		var me = this,
                isSelected = me.isSelected(record),
                shift = e.shiftKey,
                ctrl = e.ctrlKey,
                start = me.selectionStart,
                selected = me.getSelection(),
                len = selected.length,
                allowDeselect = me.allowDeselect,
                toDeselect, i, item;
    
    		switch (me.selectionMode) {
    			case 'MULTI':
    				if (shift && start) {
    					me.selectRange(start, record, ctrl);
    				} else if (ctrl && isSelected) {
    					me.doDeselect(record, false);
    				} else if (ctrl) {
    					me.doSelect(record, true, false);
    				} else if (isSelected && !shift && !ctrl && len > 1) {
    
    					if (!me.freeSelection) {
    
    						toDeselect = [];
    
    						for (i = 0; i < len; ++i) {
    							item = selected[i];
    							if (item !== record) {
    								toDeselect.push(item);
    							}
    						}
    
    						me.doDeselect(toDeselect);
    					}
    				} else if (!isSelected) {
    
    					if (!me.freeSelection) {
    						me.doSelect(record, false);
    					}
    					else {
    						me.setLastFocused(record);
    					}				
    				}
    				break;
    			case 'SIMPLE':
    				if (isSelected) {
    					me.doDeselect(record);
    				} else {
    					me.doSelect(record, true);
    				}
    				break;
    			case 'SINGLE':
    				if (allowDeselect && !ctrl) {
    					allowDeselect = me.toggleOnClick;
    				}
    				if (allowDeselect && isSelected) {
    					me.doDeselect(record);
    				} else {
    					me.doSelect(record, false);
    				}
    				break;
    		}
    
    		// selectionStart is a start point for shift/mousedown to create a range from.
    		// If the mousedowned record was not already selected, then it becomes the
    		// start of any range created from now on.
    		// If we drop to no records selected, then there is no range start any more.
    		if (!shift) {
    			if (me.isSelected(record)) {
    				me.selectionStart = record;
    			} else {
    				me.selectionStart = null;
    			}
    		}
    	}	
    });

    Once you have the code in place I replace these methods in selection model:

    	
    var selection = myGrid.getSelectionModel();
    
    selection.freeSelection = true;
    selection.afterKeyNavigate = me.afterKeyNavigate;
    selection.selectWithEvent = me.selectWithEvent;
    "me" is instance of MyApp.MyGrid.MySelection


    The solution is kind of workaround... and I have not tested it thoroughly yet as I have decided to move on to ExtJS5. Once I have got this done (maybe in a better way) in ExtJS 5 I will create thread in Ext.Net 3.0.

    Hope that you give you some head start how to archive the desired effect.
    Last edited by matt; Jan 06, 2015 at 10:46 AM.

Similar Threads

  1. [CLOSED] Grid Panel Row Expander Keyboard navigation issue
    By RajivDutt in forum 2.x Premium Help
    Replies: 7
    Last Post: Feb 07, 2014, 4:00 AM
  2. [CLOSED] GridPanel Editing using Keyboard
    By RajivDutt in forum 2.x Premium Help
    Replies: 1
    Last Post: Dec 24, 2013, 7:18 AM
  3. Replies: 1
    Last Post: Jan 25, 2012, 8:14 AM
  4. [CLOSED] TabPanel Keyboard Navigation
    By softmachine2011 in forum 1.x Premium Help
    Replies: 1
    Last Post: Nov 14, 2011, 8:52 AM
  5. [CLOSED] ComboBox keyboard navigation for grouped results
    By prointernet in forum 1.x Premium Help
    Replies: 2
    Last Post: Jul 12, 2011, 10:35 AM

Tags for this Thread

Posting Permissions