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