3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.selection.RowModel
17 * @extends Ext.selection.Model
19 Ext.define('Ext.selection.RowModel', {
20 extend: 'Ext.selection.Model',
21 alias: 'selection.rowmodel',
22 requires: ['Ext.util.KeyNav'],
26 * Number of pixels to scroll to the left/right when pressing
32 * @cfg {Boolean} enableKeyNav
34 * Turns on/off keyboard navigation within the grid.
39 * @cfg {Boolean} [ignoreRightMouseSelection=true]
40 * True to ignore selections that are made when using the right mouse button if there are
41 * records that are already selected. If no records are selected, selection will continue
44 ignoreRightMouseSelection: true,
46 constructor: function(){
49 * @event beforedeselect
50 * Fired before a record is deselected. If any listener returns false, the
51 * deselection is cancelled.
52 * @param {Ext.selection.RowModel} this
53 * @param {Ext.data.Model} record The deselected record
54 * @param {Number} index The row index deselected
60 * Fired before a record is selected. If any listener returns false, the
61 * selection is cancelled.
62 * @param {Ext.selection.RowModel} this
63 * @param {Ext.data.Model} record The selected record
64 * @param {Number} index The row index selected
70 * Fired after a record is deselected
71 * @param {Ext.selection.RowModel} this
72 * @param {Ext.data.Model} record The deselected record
73 * @param {Number} index The row index deselected
79 * Fired after a record is selected
80 * @param {Ext.selection.RowModel} this
81 * @param {Ext.data.Model} record The selected record
82 * @param {Number} index The row index selected
86 this.callParent(arguments);
89 bindComponent: function(view) {
92 me.views = me.views || [];
94 me.bind(view.getStore(), true);
97 itemmousedown: me.onRowMouseDown,
101 if (me.enableKeyNav) {
106 initKeyNav: function(view) {
109 if (!view.rendered) {
110 view.on('render', Ext.Function.bind(me.initKeyNav, me, [view], 0), me, {single: true});
118 // view.el has tabIndex -1 to allow for
119 // keyboard events to be passed to it.
120 me.keyNav = new Ext.util.KeyNav(view.el, {
123 right: me.onKeyRight,
125 pageDown: me.onKeyPageDown,
126 pageUp: me.onKeyPageUp,
131 view.el.on(Ext.EventManager.getKeyEvent(), me.onKeyPress, me);
134 // Returns the number of rows currently visible on the screen or
135 // false if there were no rows. This assumes that all rows are
136 // of the same height and the first view is accurate.
137 getRowsVisible: function() {
138 var rowsVisible = false,
139 view = this.views[0],
140 row = view.getNode(0),
141 rowHeight, gridViewHeight;
144 rowHeight = Ext.fly(row).getHeight();
145 gridViewHeight = view.el.getHeight();
146 rowsVisible = Math.floor(gridViewHeight / rowHeight);
152 // go to last visible record in grid.
153 onKeyEnd: function(e, t) {
155 last = me.store.getAt(me.store.getCount() - 1);
159 me.selectRange(last, me.lastFocused || 0);
160 me.setLastFocused(last);
161 } else if (e.ctrlKey) {
162 me.setLastFocused(last);
169 // go to first visible record in grid.
170 onKeyHome: function(e, t) {
172 first = me.store.getAt(0);
176 me.selectRange(first, me.lastFocused || 0);
177 me.setLastFocused(first);
178 } else if (e.ctrlKey) {
179 me.setLastFocused(first);
181 me.doSelect(first, false);
186 // Go one page up from the lastFocused record in the grid.
187 onKeyPageUp: function(e, t) {
189 rowsVisible = me.getRowsVisible(),
196 selIdx = me.lastFocused ? me.store.indexOf(me.lastFocused) : 0;
197 prevIdx = selIdx - rowsVisible;
201 prevRecord = me.store.getAt(prevIdx);
203 currRec = me.store.getAt(selIdx);
204 me.selectRange(prevRecord, currRec, e.ctrlKey, 'up');
205 me.setLastFocused(prevRecord);
206 } else if (e.ctrlKey) {
208 me.setLastFocused(prevRecord);
210 me.doSelect(prevRecord);
216 // Go one page down from the lastFocused record in the grid.
217 onKeyPageDown: function(e, t) {
219 rowsVisible = me.getRowsVisible(),
226 selIdx = me.lastFocused ? me.store.indexOf(me.lastFocused) : 0;
227 nextIdx = selIdx + rowsVisible;
228 if (nextIdx >= me.store.getCount()) {
229 nextIdx = me.store.getCount() - 1;
231 nextRecord = me.store.getAt(nextIdx);
233 currRec = me.store.getAt(selIdx);
234 me.selectRange(nextRecord, currRec, e.ctrlKey, 'down');
235 me.setLastFocused(nextRecord);
236 } else if (e.ctrlKey) {
237 // some browsers, this means go thru browser tabs
240 me.setLastFocused(nextRecord);
242 me.doSelect(nextRecord);
247 // Select/Deselect based on pressing Spacebar.
248 // Assumes a SIMPLE selectionmode style
249 onKeyPress: function(e, t) {
250 if (e.getKey() === e.SPACE) {
253 record = me.lastFocused;
256 if (me.isSelected(record)) {
257 me.doDeselect(record, false);
259 me.doSelect(record, true);
265 // Navigate one record up. This could be a selection or
266 // could be simply focusing a record for discontiguous
267 // selection. Provides bounds checking.
268 onKeyUp: function(e, t) {
271 idx = me.store.indexOf(me.lastFocused),
275 // needs to be the filtered count as thats what
277 record = me.store.getAt(idx - 1);
278 if (e.shiftKey && me.lastFocused) {
279 if (me.isSelected(me.lastFocused) && me.isSelected(record)) {
280 me.doDeselect(me.lastFocused, true);
281 me.setLastFocused(record);
282 } else if (!me.isSelected(me.lastFocused)) {
283 me.doSelect(me.lastFocused, true);
284 me.doSelect(record, true);
286 me.doSelect(record, true);
288 } else if (e.ctrlKey) {
289 me.setLastFocused(record);
292 //view.focusRow(idx - 1);
295 // There was no lastFocused record, and the user has pressed up
297 //else if (this.selected.getCount() == 0) {
299 // this.doSelect(record);
300 // //view.focusRow(idx - 1);
304 // Navigate one record down. This could be a selection or
305 // could be simply focusing a record for discontiguous
306 // selection. Provides bounds checking.
307 onKeyDown: function(e, t) {
310 idx = me.store.indexOf(me.lastFocused),
313 // needs to be the filtered count as thats what
315 if (idx + 1 < me.store.getCount()) {
316 record = me.store.getAt(idx + 1);
317 if (me.selected.getCount() === 0) {
319 //view.focusRow(idx + 1);
320 } else if (e.shiftKey && me.lastFocused) {
321 if (me.isSelected(me.lastFocused) && me.isSelected(record)) {
322 me.doDeselect(me.lastFocused, true);
323 me.setLastFocused(record);
324 } else if (!me.isSelected(me.lastFocused)) {
325 me.doSelect(me.lastFocused, true);
326 me.doSelect(record, true);
328 me.doSelect(record, true);
330 } else if (e.ctrlKey) {
331 me.setLastFocused(record);
334 //view.focusRow(idx + 1);
339 scrollByDeltaX: function(delta) {
340 var view = this.views[0],
342 hScroll = section.horizontalScroller;
345 hScroll.scrollByDeltaX(delta);
349 onKeyLeft: function(e, t) {
350 this.scrollByDeltaX(-this.deltaScroll);
353 onKeyRight: function(e, t) {
354 this.scrollByDeltaX(this.deltaScroll);
357 // Select the record with the event included so that
358 // we can take into account ctrlKey, shiftKey, etc
359 onRowMouseDown: function(view, record, item, index, e) {
361 if (!this.allowRightMouseSelection(e)) {
364 this.selectWithEvent(record, e);
368 * Checks whether a selection should proceed based on the ignoreRightMouseSelection
371 * @param {Ext.EventObject} e The event
372 * @return {Boolean} False if the selection should not proceed
374 allowRightMouseSelection: function(e) {
375 var disallow = this.ignoreRightMouseSelection && e.button !== 0;
377 disallow = this.hasSelection();
382 // Allow the GridView to update the UI by
383 // adding/removing a CSS class from the row.
384 onSelectChange: function(record, isSelected, suppressEvent, commitFn) {
387 viewsLn = views.length,
389 rowIdx = store.indexOf(record),
390 eventName = isSelected ? 'select' : 'deselect',
393 if ((suppressEvent || me.fireEvent('before' + eventName, me, record, rowIdx)) !== false &&
394 commitFn() !== false) {
396 for (; i < viewsLn; i++) {
398 views[i].onRowSelect(rowIdx, suppressEvent);
400 views[i].onRowDeselect(rowIdx, suppressEvent);
404 if (!suppressEvent) {
405 me.fireEvent(eventName, me, record, rowIdx);
410 // Provide indication of what row was last focused via
412 onLastFocusChanged: function(oldFocused, newFocused, supressFocus) {
413 var views = this.views,
414 viewsLn = views.length,
420 rowIdx = store.indexOf(oldFocused);
422 for (; i < viewsLn; i++) {
423 views[i].onRowFocus(rowIdx, false);
429 rowIdx = store.indexOf(newFocused);
431 for (i = 0; i < viewsLn; i++) {
432 views[i].onRowFocus(rowIdx, true, supressFocus);
438 onEditorTab: function(editingPlugin, e) {
441 record = editingPlugin.getActiveRecord(),
442 header = editingPlugin.getActiveColumn(),
443 position = view.getPosition(record, header),
444 direction = e.shiftKey ? 'left' : 'right',
445 newPosition = view.walkCells(position, direction, e, this.preventWrap);
448 editingPlugin.startEditByPosition(newPosition);
452 selectByPosition: function(position) {
453 var record = this.store.getAt(position.row);