[625] | 1 | /*! |
---|
| 2 | * Ext JS Library 3.0.0 |
---|
| 3 | * Copyright(c) 2006-2009 Ext JS, LLC |
---|
| 4 | * licensing@extjs.com |
---|
| 5 | * http://www.extjs.com/license |
---|
| 6 | */ |
---|
| 7 | /** |
---|
| 8 | * @class Ext.grid.CellSelectionModel |
---|
| 9 | * @extends Ext.grid.AbstractSelectionModel |
---|
| 10 | * This class provides the basic implementation for <i>single</i> <b>cell</b> selection in a grid. |
---|
| 11 | * The object stored as the selection contains the following properties: |
---|
| 12 | * <div class="mdetail-params"><ul> |
---|
| 13 | * <li><b>cell</b> : see {@link #getSelectedCell} |
---|
| 14 | * <li><b>record</b> : Ext.data.record The {@link Ext.data.Record Record} |
---|
| 15 | * which provides the data for the row containing the selection</li> |
---|
| 16 | * </ul></div> |
---|
| 17 | * @constructor |
---|
| 18 | * @param {Object} config The object containing the configuration of this model. |
---|
| 19 | */ |
---|
| 20 | Ext.grid.CellSelectionModel = function(config){ |
---|
| 21 | Ext.apply(this, config); |
---|
| 22 | |
---|
| 23 | this.selection = null; |
---|
| 24 | |
---|
| 25 | this.addEvents( |
---|
| 26 | /** |
---|
| 27 | * @event beforecellselect |
---|
| 28 | * Fires before a cell is selected, return false to cancel the selection. |
---|
| 29 | * @param {SelectionModel} this |
---|
| 30 | * @param {Number} rowIndex The selected row index |
---|
| 31 | * @param {Number} colIndex The selected cell index |
---|
| 32 | */ |
---|
| 33 | "beforecellselect", |
---|
| 34 | /** |
---|
| 35 | * @event cellselect |
---|
| 36 | * Fires when a cell is selected. |
---|
| 37 | * @param {SelectionModel} this |
---|
| 38 | * @param {Number} rowIndex The selected row index |
---|
| 39 | * @param {Number} colIndex The selected cell index |
---|
| 40 | */ |
---|
| 41 | "cellselect", |
---|
| 42 | /** |
---|
| 43 | * @event selectionchange |
---|
| 44 | * Fires when the active selection changes. |
---|
| 45 | * @param {SelectionModel} this |
---|
| 46 | * @param {Object} selection null for no selection or an object with two properties |
---|
| 47 | * <div class="mdetail-params"><ul> |
---|
| 48 | * <li><b>cell</b> : see {@link #getSelectedCell} |
---|
| 49 | * <li><b>record</b> : Ext.data.record<p class="sub-desc">The {@link Ext.data.Record Record} |
---|
| 50 | * which provides the data for the row containing the selection</p></li> |
---|
| 51 | * </ul></div> |
---|
| 52 | */ |
---|
| 53 | "selectionchange" |
---|
| 54 | ); |
---|
| 55 | |
---|
| 56 | Ext.grid.CellSelectionModel.superclass.constructor.call(this); |
---|
| 57 | }; |
---|
| 58 | |
---|
| 59 | Ext.extend(Ext.grid.CellSelectionModel, Ext.grid.AbstractSelectionModel, { |
---|
| 60 | |
---|
| 61 | /** @ignore */ |
---|
| 62 | initEvents : function(){ |
---|
| 63 | this.grid.on("cellmousedown", this.handleMouseDown, this); |
---|
| 64 | this.grid.getGridEl().on(Ext.EventManager.useKeydown ? "keydown" : "keypress", this.handleKeyDown, this); |
---|
| 65 | var view = this.grid.view; |
---|
| 66 | view.on("refresh", this.onViewChange, this); |
---|
| 67 | view.on("rowupdated", this.onRowUpdated, this); |
---|
| 68 | view.on("beforerowremoved", this.clearSelections, this); |
---|
| 69 | view.on("beforerowsinserted", this.clearSelections, this); |
---|
| 70 | if(this.grid.isEditor){ |
---|
| 71 | this.grid.on("beforeedit", this.beforeEdit, this); |
---|
| 72 | } |
---|
| 73 | }, |
---|
| 74 | |
---|
| 75 | //private |
---|
| 76 | beforeEdit : function(e){ |
---|
| 77 | this.select(e.row, e.column, false, true, e.record); |
---|
| 78 | }, |
---|
| 79 | |
---|
| 80 | //private |
---|
| 81 | onRowUpdated : function(v, index, r){ |
---|
| 82 | if(this.selection && this.selection.record == r){ |
---|
| 83 | v.onCellSelect(index, this.selection.cell[1]); |
---|
| 84 | } |
---|
| 85 | }, |
---|
| 86 | |
---|
| 87 | //private |
---|
| 88 | onViewChange : function(){ |
---|
| 89 | this.clearSelections(true); |
---|
| 90 | }, |
---|
| 91 | |
---|
| 92 | /** |
---|
| 93 | * Returns an array containing the row and column indexes of the currently selected cell |
---|
| 94 | * (e.g., [0, 0]), or null if none selected. The array has elements: |
---|
| 95 | * <div class="mdetail-params"><ul> |
---|
| 96 | * <li><b>rowIndex</b> : Number<p class="sub-desc">The index of the selected row</p></li> |
---|
| 97 | * <li><b>cellIndex</b> : Number<p class="sub-desc">The index of the selected cell. |
---|
| 98 | * Due to possible column reordering, the cellIndex should <b>not</b> be used as an |
---|
| 99 | * index into the Record's data. Instead, use the cellIndex to determine the <i>name</i> |
---|
| 100 | * of the selected cell and use the field name to retrieve the data value from the record:<pre><code> |
---|
| 101 | // get name |
---|
| 102 | var fieldName = grid.getColumnModel().getDataIndex(cellIndex); |
---|
| 103 | // get data value based on name |
---|
| 104 | var data = record.get(fieldName); |
---|
| 105 | * </code></pre></p></li> |
---|
| 106 | * </ul></div> |
---|
| 107 | * @return {Array} An array containing the row and column indexes of the selected cell, or null if none selected. |
---|
| 108 | */ |
---|
| 109 | getSelectedCell : function(){ |
---|
| 110 | return this.selection ? this.selection.cell : null; |
---|
| 111 | }, |
---|
| 112 | |
---|
| 113 | /** |
---|
| 114 | * If anything is selected, clears all selections and fires the selectionchange event. |
---|
| 115 | * @param {Boolean} preventNotify <tt>true</tt> to prevent the gridview from |
---|
| 116 | * being notified about the change. |
---|
| 117 | */ |
---|
| 118 | clearSelections : function(preventNotify){ |
---|
| 119 | var s = this.selection; |
---|
| 120 | if(s){ |
---|
| 121 | if(preventNotify !== true){ |
---|
| 122 | this.grid.view.onCellDeselect(s.cell[0], s.cell[1]); |
---|
| 123 | } |
---|
| 124 | this.selection = null; |
---|
| 125 | this.fireEvent("selectionchange", this, null); |
---|
| 126 | } |
---|
| 127 | }, |
---|
| 128 | |
---|
| 129 | /** |
---|
| 130 | * Returns <tt>true</tt> if there is a selection. |
---|
| 131 | * @return {Boolean} |
---|
| 132 | */ |
---|
| 133 | hasSelection : function(){ |
---|
| 134 | return this.selection ? true : false; |
---|
| 135 | }, |
---|
| 136 | |
---|
| 137 | /** @ignore */ |
---|
| 138 | handleMouseDown : function(g, row, cell, e){ |
---|
| 139 | if(e.button !== 0 || this.isLocked()){ |
---|
| 140 | return; |
---|
| 141 | } |
---|
| 142 | this.select(row, cell); |
---|
| 143 | }, |
---|
| 144 | |
---|
| 145 | /** |
---|
| 146 | * Selects a cell. Before selecting a cell, fires the |
---|
| 147 | * {@link #beforecellselect} event. If this check is satisfied the cell |
---|
| 148 | * will be selected and followed up by firing the {@link #cellselect} and |
---|
| 149 | * {@link #selectionchange} events. |
---|
| 150 | * @param {Number} rowIndex The index of the row to select |
---|
| 151 | * @param {Number} colIndex The index of the column to select |
---|
| 152 | * @param {Boolean} preventViewNotify (optional) Specify <tt>true</tt> to |
---|
| 153 | * prevent notifying the view (disables updating the selected appearance) |
---|
| 154 | * @param {Boolean} preventFocus (optional) Whether to prevent the cell at |
---|
| 155 | * the specified rowIndex / colIndex from being focused. |
---|
| 156 | * @param {Ext.data.Record} r (optional) The record to select |
---|
| 157 | */ |
---|
| 158 | select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){ |
---|
| 159 | if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){ |
---|
| 160 | this.clearSelections(); |
---|
| 161 | r = r || this.grid.store.getAt(rowIndex); |
---|
| 162 | this.selection = { |
---|
| 163 | record : r, |
---|
| 164 | cell : [rowIndex, colIndex] |
---|
| 165 | }; |
---|
| 166 | if(!preventViewNotify){ |
---|
| 167 | var v = this.grid.getView(); |
---|
| 168 | v.onCellSelect(rowIndex, colIndex); |
---|
| 169 | if(preventFocus !== true){ |
---|
| 170 | v.focusCell(rowIndex, colIndex); |
---|
| 171 | } |
---|
| 172 | } |
---|
| 173 | this.fireEvent("cellselect", this, rowIndex, colIndex); |
---|
| 174 | this.fireEvent("selectionchange", this, this.selection); |
---|
| 175 | } |
---|
| 176 | }, |
---|
| 177 | |
---|
| 178 | //private |
---|
| 179 | isSelectable : function(rowIndex, colIndex, cm){ |
---|
| 180 | return !cm.isHidden(colIndex); |
---|
| 181 | }, |
---|
| 182 | |
---|
| 183 | /** @ignore */ |
---|
| 184 | handleKeyDown : function(e){ |
---|
| 185 | if(!e.isNavKeyPress()){ |
---|
| 186 | return; |
---|
| 187 | } |
---|
| 188 | var g = this.grid, s = this.selection; |
---|
| 189 | if(!s){ |
---|
| 190 | e.stopEvent(); |
---|
| 191 | var cell = g.walkCells(0, 0, 1, this.isSelectable, this); |
---|
| 192 | if(cell){ |
---|
| 193 | this.select(cell[0], cell[1]); |
---|
| 194 | } |
---|
| 195 | return; |
---|
| 196 | } |
---|
| 197 | var sm = this; |
---|
| 198 | var walk = function(row, col, step){ |
---|
| 199 | return g.walkCells(row, col, step, sm.isSelectable, sm); |
---|
| 200 | }; |
---|
| 201 | var k = e.getKey(), r = s.cell[0], c = s.cell[1]; |
---|
| 202 | var newCell; |
---|
| 203 | |
---|
| 204 | switch(k){ |
---|
| 205 | case e.TAB: |
---|
| 206 | if(e.shiftKey){ |
---|
| 207 | newCell = walk(r, c-1, -1); |
---|
| 208 | }else{ |
---|
| 209 | newCell = walk(r, c+1, 1); |
---|
| 210 | } |
---|
| 211 | break; |
---|
| 212 | case e.DOWN: |
---|
| 213 | newCell = walk(r+1, c, 1); |
---|
| 214 | break; |
---|
| 215 | case e.UP: |
---|
| 216 | newCell = walk(r-1, c, -1); |
---|
| 217 | break; |
---|
| 218 | case e.RIGHT: |
---|
| 219 | newCell = walk(r, c+1, 1); |
---|
| 220 | break; |
---|
| 221 | case e.LEFT: |
---|
| 222 | newCell = walk(r, c-1, -1); |
---|
| 223 | break; |
---|
| 224 | case e.ENTER: |
---|
| 225 | if(g.isEditor && !g.editing){ |
---|
| 226 | g.startEditing(r, c); |
---|
| 227 | e.stopEvent(); |
---|
| 228 | return; |
---|
| 229 | } |
---|
| 230 | break; |
---|
| 231 | } |
---|
| 232 | if(newCell){ |
---|
| 233 | this.select(newCell[0], newCell[1]); |
---|
| 234 | e.stopEvent(); |
---|
| 235 | } |
---|
| 236 | }, |
---|
| 237 | |
---|
| 238 | acceptsNav : function(row, col, cm){ |
---|
| 239 | return !cm.isHidden(col) && cm.isCellEditable(col, row); |
---|
| 240 | }, |
---|
| 241 | |
---|
| 242 | onEditorKey : function(field, e){ |
---|
| 243 | var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor; |
---|
| 244 | if(k == e.TAB){ |
---|
| 245 | if(e.shiftKey){ |
---|
| 246 | newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this); |
---|
| 247 | }else{ |
---|
| 248 | newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this); |
---|
| 249 | } |
---|
| 250 | e.stopEvent(); |
---|
| 251 | }else if(k == e.ENTER){ |
---|
| 252 | ed.completeEdit(); |
---|
| 253 | e.stopEvent(); |
---|
| 254 | }else if(k == e.ESC){ |
---|
| 255 | e.stopEvent(); |
---|
| 256 | ed.cancelEdit(); |
---|
| 257 | } |
---|
| 258 | if(newCell){ |
---|
| 259 | g.startEditing(newCell[0], newCell[1]); |
---|
| 260 | } |
---|
| 261 | } |
---|
| 262 | }); |
---|