]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/src/grid/CellContext.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / grid / CellContext.js
CommitLineData
6527f429
DM
1/**\r
2 * Instances of this class encapsulate a position in a grid's row/column coordinate system.\r
3 *\r
4 * Cells are addressed using the owning {@link #record} and {@link #column} for robustness. \r
5 * the column may be moved, the store may be sorted, and the CellContext will still reference\r
6 * the same *logical* cell. Be aware that due to buffered rendering the *physical* cell may not exist.\r
7 *\r
8 * The {@link #setPosition} method however allows a numeric row and column to be passed in. These\r
9 * are immediately converted.\r
10 *\r
11 * Be careful not to make `CellContext` objects *too* persistent. If the owning record is removed, or the owning column\r
12 * is removed, the reference will be stale.\r
13 *\r
14 * Freshly created context objects, such as those exposed by events from the {Ext.grid.selection.SpreadsheetModel spreadsheet selection model}\r
15 * are safe to use until your application mutates the store, or changes the column set.\r
16 */\r
17Ext.define('Ext.grid.CellContext', {\r
18\r
19 /**\r
20 * @property {Boolean} isCellContext\r
21 * @readonly\r
22 * `true` in this class to identify an object as an instantiated CellContext, or subclass thereof.\r
23 */\r
24 isCellContext: true,\r
25\r
26 /**\r
27 * @readonly\r
28 * @property {Ext.grid.column.Column} column\r
29 * The grid column which owns the referenced cell.\r
30 */\r
31 \r
32 /**\r
33 * @readonly\r
34 * @property {Ext.data.Model} record\r
35 * The store record which maps to the referenced cell.\r
36 */\r
37\r
38 /**\r
39 * @readonly\r
40 * @property {Number} rowIdx\r
41 * The row number in the store which owns the referenced cell.\r
42 *\r
43 * *Be aware that after the initial call to {@link #setPosition}, this value may become stale due to subsequent store mutation.*\r
44 */\r
45\r
46 /**\r
47 * @readonly\r
48 * @property {Number} colIdx\r
49 * The column index in the owning View's leaf column set of the referenced cell.\r
50 *\r
51 * *Be aware that after the initial call to {@link #setPosition}, this value may become stale due to subsequent column mutation.*\r
52 */\r
53\r
54 /**\r
55 * Creates a new CellContext which references a {@link Ext.view.Table GridView}\r
56 * @param {Ext.view.Table} view The {@link Ext.view.Table GridView} for which the cell context is needed.\r
57 *\r
58 * To complete creation of a valid context, use the {@link #setPosition} method.\r
59 */\r
60 constructor: function(view) {\r
61 this.view = view;\r
62 },\r
63 \r
64 /**\r
65 * Binds this cell context to a logical cell defined by the {@link #record} and {@link #column}.\r
66 *\r
67 * @param {Number/Ext.data.Model} row The row index or record which owns the required cell.\r
68 * @param {Number/Ext.grid.column.Column} col The column index (In the owning View's leaf column set), or the owning {@link Ext.grid.column.Column column}.\r
69 *\r
70 * A one argument form may be used in the form of an array:\r
71 *\r
72 * [column, row]\r
73 *\r
74 * Or another CellContext may be passed.\r
75 *\r
76 * @return {Ext.grid.CellContext} this CellContext object.\r
77 */\r
78 setPosition: function(row, col) {\r
79 var me = this;\r
80\r
81 // We were passed {row: 1, column: 2, view: myView} or [2, 1]\r
82 if (arguments.length === 1) {\r
83 // A [column, row] array passed\r
84 if (row.length) {\r
85 col = row[0];\r
86 row = row[1];\r
87 }\r
88 else if (row.isCellContext) {\r
89 return me.setAll(row.view, row.rowIdx, row.colIdx, row.record, row.columnHeader);\r
90 }\r
91 // An object containing {row: r, column: c}\r
92 else {\r
93 if (row.view) {\r
94 me.view = row.view;\r
95 }\r
96 col = row.column;\r
97 row = row.row;\r
98 }\r
99 }\r
100\r
101 me.setRow(row);\r
102 me.setColumn(col);\r
103 return me;\r
104 },\r
105\r
106 setAll: function(view, recordIndex, columnIndex, record, columnHeader) {\r
107 var me = this;\r
108\r
109 me.view = view;\r
110 me.rowIdx = recordIndex;\r
111 me.colIdx = columnIndex;\r
112 me.record = record;\r
113 me.column = columnHeader;\r
114 return me;\r
115 },\r
116\r
117 setRow: function(row) {\r
118 var me = this,\r
119 dataSource = me.view.dataSource;\r
120 \r
121 if (row !== undefined) {\r
122 // Row index passed\r
123 if (typeof row === 'number') {\r
124 me.rowIdx = Math.max(Math.min(row, dataSource.getCount() - 1), 0);\r
125 me.record = dataSource.getAt(row);\r
126 }\r
127 // row is a Record\r
128 else if (row.isModel) {\r
129 me.record = row;\r
130 me.rowIdx = dataSource.indexOf(row);\r
131 }\r
132 // row is a grid row, or Element wrapping row\r
133 else if (row.tagName || row.isElement) {\r
134 me.record = me.view.getRecord(row);\r
135 me.rowIdx = dataSource.indexOf(me.record);\r
136 }\r
137 }\r
138 return me;\r
139 },\r
140 \r
141 setColumn: function(col) {\r
142 var me = this,\r
143 colMgr = me.view.getVisibleColumnManager();\r
144\r
145 // Maintainer:\r
146 // We MUST NOT update the context view with the column's view because this context\r
147 // may be for an Ext.locking.View which spans two grid views, and a column references\r
148 // its local grid view.\r
149 if (col !== undefined) {\r
150 if (typeof col === 'number') {\r
151 me.colIdx = col;\r
152 me.column = colMgr.getHeaderAtIndex(col);\r
153 } else if (col.isHeader) {\r
154 me.column = col;\r
155 // Must use the Manager's indexOf because view may be a locking view\r
156 // And Column#getVisibleIndex returns the index of the column within its own header.\r
157 me.colIdx = colMgr.indexOf(col);\r
158 }\r
159 }\r
160 return me;\r
161 },\r
162\r
163 /**\r
164 * Returns the cell object referenced *at the time of calling*. Note that grid DOM is transient, and \r
165 * the cell referenced may be removed from the DOM due to paging or buffered rendering or column or record removal.\r
166 *\r
167 * @param {Boolean} returnDom Pass `true` to return a DOM object instead of an {@link Ext.dom.Element Element).\r
168 * @return {HTMLElement/Ext.dom.Element} The cell referenced by this context.\r
169 */\r
170 getCell: function(returnDom) {\r
171 return this.view.getCellByPosition(this, returnDom);\r
172 },\r
173\r
174 /**\r
175 * Returns the row object referenced *at the time of calling*. Note that grid DOM is transient, and \r
176 * the row referenced may be removed from the DOM due to paging or buffered rendering or column or record removal.\r
177 *\r
178 * @param {Boolean} returnDom Pass `true` to return a DOM object instead of an {@link Ext.dom.Element Element).\r
179 * @return {HTMLElement/Ext.dom.Element} The grid row referenced by this context.\r
180 */\r
181 getRow: function(returnDom) {\r
182 var result = this.view.getRow(this.record);\r
183 return returnDom ? result : Ext.get(result);\r
184 },\r
185\r
186 /**\r
187 * Returns the view node object (the encapsulating element of a data row) referenced *at the time of\r
188 * calling*. Note that grid DOM is transient, and the node referenced may be removed from the DOM due\r
189 * to paging or buffered rendering or column or record removal.\r
190 *\r
191 * @param {Boolean} returnDom Pass `true` to return a DOM object instead of an {@link Ext.dom.Element Element).\r
192 * @return {HTMLElement/Ext.dom.Element} The grid item referenced by this context.\r
193 */\r
194 getNode: function(returnDom) {\r
195 var result = this.view.getNode(this.record);\r
196 return returnDom ? result : Ext.get(result);\r
197 },\r
198\r
199 /**\r
200 * Compares this CellContext object to another CellContext to see if they refer to the same cell.\r
201 * @param {Ext.grid.CellContext} other The CellContext to compare.\r
202 * @return {Boolean} `true` if the other cell context references the same cell as this.\r
203 */\r
204 isEqual: function(other) {\r
205 return (other && other.isCellContext && other.record === this.record && other.column === this.column);\r
206 },\r
207\r
208 /**\r
209 * Creates a clone of this CellContext.\r
210 *\r
211 * The clone may be retargeted without affecting the reference of this context.\r
212 * @return {Ext.grid.CellContext} A copy of this context, referencing the same cell.\r
213 */\r
214 clone: function() {\r
215 var me = this,\r
216 result = new me.self(me.view);\r
217\r
218 result.rowIdx = me.rowIdx;\r
219 result.colIdx = me.colIdx;\r
220 result.record = me.record;\r
221 result.column = me.column;\r
222 return result;\r
223 },\r
224\r
225 privates: {\r
226 isFirstColumn: function() {\r
227 var cell = this.getCell(true);\r
228\r
229 if (cell) {\r
230 return !cell.previousSibling;\r
231 }\r
232 },\r
233\r
234 isLastColumn: function() {\r
235 var cell = this.getCell(true);\r
236\r
237 if (cell) {\r
238 return !cell.nextSibling;\r
239 }\r
240 },\r
241\r
242 getLastColumnIndex: function() {\r
243 var row = this.getRow(true);\r
244\r
245 if (row) {\r
246 return row.lastChild.cellIndex;\r
247 }\r
248 return -1;\r
249 },\r
250\r
251 /**\r
252 * @private\r
253 * Navigates left or right within the current row.\r
254 * @param {Number} direction `-1` to go towards the row start or `1` to go towards row end\r
255 */\r
256 navigate: function(direction) {\r
257 var me = this,\r
258 columns = me.view.getVisibleColumnManager().getColumns();\r
259\r
260 switch (direction) {\r
261 case -1:\r
262 do {\r
263 // If we iterate off the start, wrap back to the end.\r
264 if (!me.colIdx) {\r
265 me.colIdx = columns.length - 1;\r
266 } else {\r
267 me.colIdx--;\r
268 }\r
269 me.setColumn(me.colIdx);\r
270 } while (!me.getCell(true))\r
271 break;\r
272 case 1:\r
273 do {\r
274 // If we iterate off the end, wrap back to the start.\r
275 if (me.colIdx >= columns.length) {\r
276 me.colIdx = 0;\r
277 } else {\r
278 me.colIdx++;\r
279 }\r
280 me.setColumn(me.colIdx);\r
281 } while (!me.getCell(true))\r
282 break;\r
283 }\r
284 }\r
285 },\r
286\r
287 statics: {\r
288 compare: function(c1, c2) {\r
289 return c1.rowIdx - c2.rowIdx || c1.colIdx - c2.colIdx;\r
290 }\r
291 }\r
292});