123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- <!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-CellModel'>/**
- </span> *
- */
- Ext.define('Ext.selection.CellModel', {
- extend: 'Ext.selection.Model',
- alias: 'selection.cellmodel',
- requires: ['Ext.util.KeyNav'],
- isCellModel: true,
- <span id='Ext-selection-CellModel-cfg-enableKeyNav'> /**
- </span> * @cfg {Boolean} enableKeyNav
- * Turns on/off keyboard navigation within the grid.
- */
- enableKeyNav: true,
- <span id='Ext-selection-CellModel-cfg-preventWrap'> /**
- </span> * @cfg {Boolean} preventWrap
- * Set this configuration to true to prevent wrapping around of selection as
- * a user navigates to the first or last column.
- */
- preventWrap: false,
- // private property to use when firing a deselect when no old selection exists.
- noSelection: {
- row: -1,
- column: -1
- },
- constructor: function() {
- this.addEvents(
- <span id='Ext-selection-CellModel-event-deselect'> /**
- </span> * @event deselect
- * Fired after a cell is deselected
- * @param {Ext.selection.CellModel} this
- * @param {Ext.data.Model} record The record of the deselected cell
- * @param {Number} row The row index deselected
- * @param {Number} column The column index deselected
- */
- 'deselect',
- <span id='Ext-selection-CellModel-event-select'> /**
- </span> * @event select
- * Fired after a cell is selected
- * @param {Ext.selection.CellModel} this
- * @param {Ext.data.Model} record The record of the selected cell
- * @param {Number} row The row index selected
- * @param {Number} column The column index selected
- */
- 'select'
- );
- this.callParent(arguments);
- },
- bindComponent: function(view) {
- var me = this,
- grid = view.ownerCt;
- me.primaryView = view;
- me.views = me.views || [];
- me.views.push(view);
- me.bindStore(view.getStore(), true);
- view.on({
- cellmousedown: me.onMouseDown,
- refresh: me.onViewRefresh,
- scope: me
- });
- if (grid.optimizedColumnMove !== false) {
- grid.on('columnmove', me.onColumnMove, 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.set({
- tabIndex: -1
- });
- // view.el has tabIndex -1 to allow for
- // keyboard events to be passed to it.
- me.keyNav = new Ext.util.KeyNav({
- target: view.el,
- ignoreInputFields: true,
- up: me.onKeyUp,
- down: me.onKeyDown,
- right: me.onKeyRight,
- left: me.onKeyLeft,
- tab: me.onKeyTab,
- scope: me
- });
- },
- getHeaderCt: function() {
- var selection = this.getCurrentPosition(),
- view = selection ? selection.view : this.primaryView;
- return view.headerCt;
- },
- onKeyUp: function(e, t) {
- this.keyNavigation = true;
- this.move('up', e);
- this.keyNavigation = false;
- },
- onKeyDown: function(e, t) {
- this.keyNavigation = true;
- this.move('down', e);
- this.keyNavigation = false;
- },
- onKeyLeft: function(e, t) {
- this.keyNavigation = true;
- this.move('left', e);
- this.keyNavigation = false;
- },
- onKeyRight: function(e, t) {
- this.keyNavigation = true;
- this.move('right', e);
- this.keyNavigation = false;
- },
- move: function(dir, e) {
- var me = this,
- pos = me.getCurrentPosition(),
-
- // Calculate the new row and column position
- newPos = pos.view.walkCells(pos, dir, e, me.preventWrap);
- // If walk was successful, select new Position
- if (newPos) {
- newPos.view = pos.view;
- return me.setCurrentPosition(newPos);
- }
- // <debug>
- // Enforce code correctness in unbuilt source.
- return null;
- // </debug>
- },
- <span id='Ext-selection-CellModel-method-getCurrentPosition'> /**
- </span> * Returns the current position in the format {row: row, column: column}
- */
- getCurrentPosition: function() {
- return this.selection;
- },
- <span id='Ext-selection-CellModel-method-setCurrentPosition'> /**
- </span> * Sets the current position
- * @param {Object} position The position to set.
- */
- setCurrentPosition: function(pos) {
- var me = this;
- // onSelectChange uses lastSelection and nextSelection
- me.lastSelection = me.selection;
- if (me.selection) {
- me.onCellDeselect(me.selection);
- }
- if (pos) {
- me.nextSelection = new me.Selection(me);
- me.nextSelection.setPosition(pos);
- me.onCellSelect(me.nextSelection);
- // Deselect triggered by new selection will kill the selection property, so restore it here.
- return me.selection = me.nextSelection;
- }
- // <debug>
- // Enforce code correctness in unbuilt source.
- return null;
- // </debug>
- },
- // Keep selection model in consistent state upon record deletion.
- onStoreRemove: function(store, record, index) {
- var me = this,
- pos = me.getCurrentPosition();
- me.callParent(arguments);
- if (pos) {
- // Deleting the row containing the selection.
- // Attempt to reselect the same cell which has moved up if there is one
- if (pos.row == index) {
- if (index < store.getCount() - 1) {
- pos.setPosition(index, pos.column);
- me.setCurrentPosition(pos);
- } else {
- delete me.selection;
- }
- }
- // Deleting a row before the selection.
- // Move the selection up by one row
- else if (index < pos.row) {
- pos.setPosition(pos.row - 1, pos.column);
- me.setCurrentPosition(pos);
- }
- }
- },
- <span id='Ext-selection-CellModel-method-onMouseDown'> /**
- </span> * Set the current position based on where the user clicks.
- * @private
- */
- onMouseDown: function(view, cell, cellIndex, record, row, rowIndex, e) {
- this.setCurrentPosition({
- view: view,
- row: rowIndex,
- column: cellIndex
- });
- },
- // notify the view that the cell has been selected to update the ui
- // appropriately and bring the cell into focus
- onCellSelect: function(position, supressEvent) {
- if (position && position.row !== undefined && position.row > -1) {
- this.doSelect(position.view.getStore().getAt(position.row), /*keepExisting*/false, supressEvent);
- }
- },
- // notify view that the cell has been deselected to update the ui
- // appropriately
- onCellDeselect: function(position, supressEvent) {
- if (position && position.row !== undefined) {
- this.doDeselect(position.view.getStore().getAt(position.row), supressEvent);
- }
- },
- onSelectChange: function(record, isSelected, suppressEvent, commitFn) {
- var me = this,
- pos,
- eventName,
- view;
- if (isSelected) {
- pos = me.nextSelection;
- eventName = 'select';
- } else {
- pos = me.lastSelection || me.noSelection;
- eventName = 'deselect';
- }
- // CellModel may be shared between two sides of a Lockable.
- // The position must include a reference to the view in which the selection is current.
- // Ensure we use the view specifiied by the position.
- view = pos.view || me.primaryView;
- if ((suppressEvent || me.fireEvent('before' + eventName, me, record, pos.row, pos.column)) !== false &&
- commitFn() !== false) {
- if (isSelected) {
- view.onCellSelect(pos);
- view.onCellFocus(pos);
- } else {
- view.onCellDeselect(pos);
- delete me.selection;
- }
- if (!suppressEvent) {
- me.fireEvent(eventName, me, record, pos.row, pos.column);
- }
- }
- },
- // Tab key from the View's KeyNav, *not* from an editor.
- onKeyTab: function(e, t) {
- var me = this,
- editingPlugin = me.getCurrentPosition().view.editingPlugin;
- // If we were in editing mode, but just focused on a non-editable cell, behave as if we tabbed off an editable field
- if (editingPlugin && me.wasEditing) {
- me.onEditorTab(editingPlugin, e)
- } else {
- me.move(e.shiftKey ? 'left' : 'right', e);
- }
- },
- onEditorTab: function(editingPlugin, e) {
- var me = this,
- direction = e.shiftKey ? 'left' : 'right',
- position = me.move(direction, e);
- // Navigation had somewhere to go.... not hit the buffers.
- if (position) {
- // If we were able to begin editing clear the wasEditing flag. It gets set during navigation off an active edit.
- if (editingPlugin.startEditByPosition(position)) {
- me.wasEditing = false;
- }
- // If we could not continue editing...
- // Set a flag that we should go back into editing mode upon next onKeyTab call
- else {
- me.wasEditing = true;
- if (!position.columnHeader.dataIndex) {
- me.onEditorTab(editingPlugin, e);
- }
- }
- }
- },
- refresh: function() {
- var pos = this.getCurrentPosition(),
- selRowIdx;
- // Synchronize the current position's row with the row of the last selected record.
- if (pos && (selRowIdx = this.store.indexOf(this.selected.last())) !== -1) {
- pos.row = selRowIdx;
- }
- },
- <span id='Ext-selection-CellModel-method-onColumnMove'> /**
- </span> * @private
- * When grid uses {@link Ext.panel.Table#optimizedColumnMove optimizedColumnMove} (the default), this is added as a
- * {@link Ext.panel.Table#columnmove columnmove} handler to correctly maintain the
- * selected column using the same column header.
- *
- * If optimizedColumnMove === false, (which some grid Features set) then the view is refreshed,
- * so this is not added as a handler because the selected column.
- */
- onColumnMove: function(headerCt, header, fromIdx, toIdx) {
- var grid = headerCt.up('tablepanel');
- if (grid) {
- this.onViewRefresh(grid.view);
- }
- },
- onViewRefresh: function(view) {
- var me = this,
- pos = me.getCurrentPosition(),
- headerCt = view.headerCt,
- record, columnHeader;
- // Re-establish selection of the same cell coordinate.
- // DO NOT fire events because the selected
- if (pos && pos.view === view) {
- record = pos.record;
- columnHeader = pos.columnHeader;
- // After a refresh, recreate the selection using the same record and grid column as before
- if (!columnHeader.isDescendantOf(headerCt)) {
- // column header is not a child of the header container
- // this happens when the grid is reconfigured with new columns
- // make a best effor to select something by matching on id, then text, then dataIndex
- columnHeader = headerCt.queryById(columnHeader.id) ||
- headerCt.down('[text="' + columnHeader.text + '"]') ||
- headerCt.down('[dataIndex="' + columnHeader.dataIndex + '"]');
- }
- // If we have a columnHeader (either the column header that already exists in
- // the headerCt, or a suitable match that was found after reconfiguration)
- // AND the record still exists in the store (or a record matching the id of
- // the previously selected record) We are ok to go ahead and set the selection
- if (columnHeader && (view.store.indexOfId(record.getId()) !== -1)) {
- me.setCurrentPosition({
- row: record,
- column: columnHeader,
- view: view
- });
- }
- }
- },
- selectByPosition: function(position) {
- this.setCurrentPosition(position);
- }
- }, function() {
-
- // Encapsulate a single selection position.
- // Maintains { row: n, column: n, record: r, columnHeader: c}
- var Selection = this.prototype.Selection = function(model) {
- this.model = model;
- };
- // Selection row/record & column/columnHeader
- Selection.prototype.setPosition = function(row, col) {
- var me = this,
- view;
- // We were passed {row: 1, column: 2, view: myView}
- if (arguments.length === 1) {
-
- // SelectionModel is shared between both sides of a locking grid.
- // It can be positioned on either view.
- if (row.view) {
- me.view = view = row.view;
- }
- col = row.column;
- row = row.row;
- }
-
- // If setting the position without specifying a view, and the position is already without a view
- // use the owning Model's primary view
- if (!view) {
- me.view = view = me.model.primaryView;
- }
- // Row index passed
- if (typeof row === 'number') {
- me.row = row;
- me.record = view.store.getAt(row);
- }
- // row is a Record
- else if (row.isModel) {
- me.record = row;
- me.row = view.indexOf(row);
- }
- // row is a grid row
- else if (row.tagName) {
- me.record = view.getRecord(row);
- me.row = view.indexOf(me.record);
- }
-
- // column index passed
- if (typeof col === 'number') {
- me.column = col;
- me.columnHeader = view.getHeaderAtIndex(col);
- }
- // col is a column Header
- else {
- me.columnHeader = col;
- me.column = col.getIndex();
- }
- return me;
- }
- });</pre>
- </body>
- </html>
|