<!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-selection-RowModel'>/** </span> * Implements row based navigation via keyboard. * * Must synchronize across grid sections. */ Ext.define('Ext.selection.RowModel', { extend: 'Ext.selection.Model', alias: 'selection.rowmodel', requires: ['Ext.util.KeyNav'], <span id='Ext-selection-RowModel-property-deltaScroll'> /** </span> * @private * Number of pixels to scroll to the left/right when pressing * left/right keys. */ deltaScroll: 5, <span id='Ext-selection-RowModel-cfg-enableKeyNav'> /** </span> * @cfg {Boolean} enableKeyNav * * Turns on/off keyboard navigation within the grid. */ enableKeyNav: true, <span id='Ext-selection-RowModel-cfg-ignoreRightMouseSelection'> /** </span> * @cfg {Boolean} [ignoreRightMouseSelection=false] * True to ignore selections that are made when using the right mouse button if there are * records that are already selected. If no records are selected, selection will continue * as normal */ ignoreRightMouseSelection: false, constructor: function() { this.addEvents( <span id='Ext-selection-RowModel-event-beforedeselect'> /** </span> * @event beforedeselect * Fired before a record is deselected. If any listener returns false, the * deselection is cancelled. * @param {Ext.selection.RowModel} this * @param {Ext.data.Model} record The deselected record * @param {Number} index The row index deselected */ 'beforedeselect', <span id='Ext-selection-RowModel-event-beforeselect'> /** </span> * @event beforeselect * Fired before a record is selected. If any listener returns false, the * selection is cancelled. * @param {Ext.selection.RowModel} this * @param {Ext.data.Model} record The selected record * @param {Number} index The row index selected */ 'beforeselect', <span id='Ext-selection-RowModel-event-deselect'> /** </span> * @event deselect * Fired after a record is deselected * @param {Ext.selection.RowModel} this * @param {Ext.data.Model} record The deselected record * @param {Number} index The row index deselected */ 'deselect', <span id='Ext-selection-RowModel-event-select'> /** </span> * @event select * Fired after a record is selected * @param {Ext.selection.RowModel} this * @param {Ext.data.Model} record The selected record * @param {Number} index The row index selected */ 'select' ); this.views = []; this.callParent(arguments); }, bindComponent: function(view) { var me = this; me.views = me.views || []; me.views.push(view); me.bindStore(view.getStore(), true); view.on({ itemmousedown: me.onRowMouseDown, scope: me }); if (me.enableKeyNav) { me.initKeyNav(view); } }, initKeyNav: function(view) { var me = this; if (!view.rendered) { view.on('render', Ext.Function.bind(me.initKeyNav, me, [view], 0), me, {single: true}); return; } // view.el has tabIndex -1 to allow for // keyboard events to be passed to it. view.el.set({ tabIndex: -1 }); // Drive the KeyNav off the View's itemkeydown event so that beforeitemkeydown listeners may veto me.keyNav = new Ext.util.KeyNav({ target: view, ignoreInputFields: true, eventName: 'itemkeydown', processEvent: function(view, record, node, index, event) { event.record = record; event.recordIndex = index; return event; }, up: me.onKeyUp, down: me.onKeyDown, right: me.onKeyRight, left: me.onKeyLeft, pageDown: me.onKeyPageDown, pageUp: me.onKeyPageUp, home: me.onKeyHome, end: me.onKeyEnd, space: me.onKeySpace, enter: me.onKeyEnter, scope: me }); }, // Returns the number of rows currently visible on the screen or // false if there were no rows. This assumes that all rows are // of the same height and the first view is accurate. getRowsVisible: function() { var rowsVisible = false, view = this.views[0], row = view.getNode(0), rowHeight, gridViewHeight; if (row) { rowHeight = Ext.fly(row).getHeight(); gridViewHeight = view.el.getHeight(); rowsVisible = Math.floor(gridViewHeight / rowHeight); } return rowsVisible; }, // go to last visible record in grid. onKeyEnd: function(e) { var me = this, last = me.store.getAt(me.store.getCount() - 1); if (last) { if (e.shiftKey) { me.selectRange(last, me.lastFocused || 0); me.setLastFocused(last); } else if (e.ctrlKey) { me.setLastFocused(last); } else { me.doSelect(last); } } }, // go to first visible record in grid. onKeyHome: function(e) { var me = this, first = me.store.getAt(0); if (first) { if (e.shiftKey) { me.selectRange(first, me.lastFocused || 0); me.setLastFocused(first); } else if (e.ctrlKey) { me.setLastFocused(first); } else { me.doSelect(first, false); } } }, // Go one page up from the lastFocused record in the grid. onKeyPageUp: function(e) { var me = this, rowsVisible = me.getRowsVisible(), selIdx, prevIdx, prevRecord; if (rowsVisible) { selIdx = e.recordIndex; prevIdx = selIdx - rowsVisible; if (prevIdx < 0) { prevIdx = 0; } prevRecord = me.store.getAt(prevIdx); if (e.shiftKey) { me.selectRange(prevRecord, e.record, e.ctrlKey, 'up'); me.setLastFocused(prevRecord); } else if (e.ctrlKey) { e.preventDefault(); me.setLastFocused(prevRecord); } else { me.doSelect(prevRecord); } } }, // Go one page down from the lastFocused record in the grid. onKeyPageDown: function(e) { var me = this, rowsVisible = me.getRowsVisible(), selIdx, nextIdx, nextRecord; if (rowsVisible) { selIdx = e.recordIndex; nextIdx = selIdx + rowsVisible; if (nextIdx >= me.store.getCount()) { nextIdx = me.store.getCount() - 1; } nextRecord = me.store.getAt(nextIdx); if (e.shiftKey) { me.selectRange(nextRecord, e.record, e.ctrlKey, 'down'); me.setLastFocused(nextRecord); } else if (e.ctrlKey) { // some browsers, this means go thru browser tabs // attempt to stop. e.preventDefault(); me.setLastFocused(nextRecord); } else { me.doSelect(nextRecord); } } }, // Select/Deselect based on pressing Spacebar. // Assumes a SIMPLE selectionmode style onKeySpace: function(e) { var me = this, record = me.lastFocused; if (record) { if (me.isSelected(record)) { me.doDeselect(record, false); } else { me.doSelect(record, true); } } }, onKeyEnter: Ext.emptyFn, // Navigate one record up. This could be a selection or // could be simply focusing a record for discontiguous // selection. Provides bounds checking. onKeyUp: function(e) { var me = this, idx = me.store.indexOf(me.lastFocused), record; if (idx > 0) { // needs to be the filtered count as thats what // will be visible. record = me.store.getAt(idx - 1); if (e.shiftKey && me.lastFocused) { if (me.isSelected(me.lastFocused) && me.isSelected(record)) { me.doDeselect(me.lastFocused, true); me.setLastFocused(record); } else if (!me.isSelected(me.lastFocused)) { me.doSelect(me.lastFocused, true); me.doSelect(record, true); } else { me.doSelect(record, true); } } else if (e.ctrlKey) { me.setLastFocused(record); } else { me.doSelect(record); //view.focusRow(idx - 1); } } // There was no lastFocused record, and the user has pressed up // Ignore?? //else if (this.selected.getCount() == 0) { // // this.doSelect(record); // //view.focusRow(idx - 1); //} }, // Navigate one record down. This could be a selection or // could be simply focusing a record for discontiguous // selection. Provides bounds checking. onKeyDown: function(e) { var me = this, idx = me.store.indexOf(me.lastFocused), record; // needs to be the filtered count as thats what // will be visible. if (idx + 1 < me.store.getCount()) { record = me.store.getAt(idx + 1); if (me.selected.getCount() === 0) { if (!e.ctrlKey) { me.doSelect(record); } else { me.setLastFocused(record); } //view.focusRow(idx + 1); } else if (e.shiftKey && me.lastFocused) { if (me.isSelected(me.lastFocused) && me.isSelected(record)) { me.doDeselect(me.lastFocused, true); me.setLastFocused(record); } else if (!me.isSelected(me.lastFocused)) { me.doSelect(me.lastFocused, true); me.doSelect(record, true); } else { me.doSelect(record, true); } } else if (e.ctrlKey) { me.setLastFocused(record); } else { me.doSelect(record); //view.focusRow(idx + 1); } } }, scrollByDeltaX: function(delta) { var view = this.views[0], section = view.up(), hScroll = section.horizontalScroller; if (hScroll) { hScroll.scrollByDeltaX(delta); } }, onKeyLeft: function(e) { this.scrollByDeltaX(-this.deltaScroll); }, onKeyRight: function(e) { this.scrollByDeltaX(this.deltaScroll); }, // Select the record with the event included so that // we can take into account ctrlKey, shiftKey, etc onRowMouseDown: function(view, record, item, index, e) { if (!this.allowRightMouseSelection(e)) { return; } if (e.button === 0 || !this.isSelected(record)) { this.selectWithEvent(record, e); } }, <span id='Ext-selection-RowModel-method-allowRightMouseSelection'> /** </span> * Checks whether a selection should proceed based on the ignoreRightMouseSelection * option. * @private * @param {Ext.EventObject} e The event * @return {Boolean} False if the selection should not proceed */ allowRightMouseSelection: function(e) { var disallow = this.ignoreRightMouseSelection && e.button !== 0; if (disallow) { disallow = this.hasSelection(); } return !disallow; }, // Allow the GridView to update the UI by // adding/removing a CSS class from the row. onSelectChange: function(record, isSelected, suppressEvent, commitFn) { var me = this, views = me.views, viewsLn = views.length, store = me.store, rowIdx = store.indexOf(record), eventName = isSelected ? 'select' : 'deselect', i = 0; if ((suppressEvent || me.fireEvent('before' + eventName, me, record, rowIdx)) !== false && commitFn() !== false) { for (; i < viewsLn; i++) { if (isSelected) { views[i].onRowSelect(rowIdx, suppressEvent); } else { views[i].onRowDeselect(rowIdx, suppressEvent); } } if (!suppressEvent) { me.fireEvent(eventName, me, record, rowIdx); } } }, // Provide indication of what row was last focused via // the gridview. onLastFocusChanged: function(oldFocused, newFocused, supressFocus) { var views = this.views, viewsLn = views.length, store = this.store, rowIdx, i = 0; if (oldFocused) { rowIdx = store.indexOf(oldFocused); if (rowIdx != -1) { for (; i < viewsLn; i++) { views[i].onRowFocus(rowIdx, false); } } } if (newFocused) { rowIdx = store.indexOf(newFocused); if (rowIdx != -1) { for (i = 0; i < viewsLn; i++) { views[i].onRowFocus(rowIdx, true, supressFocus); } } } this.callParent(); }, onEditorTab: function(editingPlugin, e) { var me = this, view = me.views[0], record = editingPlugin.getActiveRecord(), header = editingPlugin.getActiveColumn(), position = view.getPosition(record, header), direction = e.shiftKey ? 'left' : 'right'; do { position = view.walkCells(position, direction, e, me.preventWrap); } while(position && !view.headerCt.getHeaderAtIndex(position.column).getEditor()); if (position) { editingPlugin.startEditByPosition(position); } }, <span id='Ext-selection-RowModel-method-getCurrentPosition'> /** </span> * Returns position of the first selected cell in the selection in the format {row: row, column: column} */ getCurrentPosition: function() { var firstSelection = this.selected.items[0]; if (firstSelection) { return { row: this.store.indexOf(firstSelection), column: 0 }; } }, selectByPosition: function(position) { var record = this.store.getAt(position.row); this.select(record); }, <span id='Ext-selection-RowModel-method-selectNext'> /** </span> * Selects the record immediately following the currently selected record. * @param {Boolean} [keepExisting] True to retain existing selections * @param {Boolean} [suppressEvent] Set to false to not fire a select event * @return {Boolean} `true` if there is a next record, else `false` */ selectNext: function(keepExisting, suppressEvent) { var me = this, store = me.store, selection = me.getSelection(), record = selection[selection.length - 1], index = store.indexOf(record) + 1, success; if(index === store.getCount() || index === 0) { success = false; } else { me.doSelect(index, keepExisting, suppressEvent); success = true; } return success; }, <span id='Ext-selection-RowModel-method-selectPrevious'> /** </span> * Selects the record that precedes the currently selected record. * @param {Boolean} [keepExisting] True to retain existing selections * @param {Boolean} [suppressEvent] Set to false to not fire a select event * @return {Boolean} `true` if there is a previous record, else `false` */ selectPrevious: function(keepExisting, suppressEvent) { var me = this, selection = me.getSelection(), record = selection[0], index = me.store.indexOf(record) - 1, success; if (index < 0) { success = false; } else { me.doSelect(index, keepExisting, suppressEvent); success = true; } return success; } });</pre> </body> </html>