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.GridView |
---|
9 | * @extends Ext.util.Observable |
---|
10 | * <p>This class encapsulates the user interface of an {@link Ext.grid.GridPanel}. |
---|
11 | * Methods of this class may be used to access user interface elements to enable |
---|
12 | * special display effects. Do not change the DOM structure of the user interface.</p> |
---|
13 | * <p>This class does not provide ways to manipulate the underlying data. The data |
---|
14 | * model of a Grid is held in an {@link Ext.data.Store}.</p> |
---|
15 | * @constructor |
---|
16 | * @param {Object} config |
---|
17 | */ |
---|
18 | Ext.grid.GridView = function(config){ |
---|
19 | Ext.apply(this, config); |
---|
20 | // These events are only used internally by the grid components |
---|
21 | this.addEvents( |
---|
22 | /** |
---|
23 | * @event beforerowremoved |
---|
24 | * Internal UI Event. Fired before a row is removed. |
---|
25 | * @param {Ext.grid.GridView} view |
---|
26 | * @param {Number} rowIndex The index of the row to be removed. |
---|
27 | * @param {Ext.data.Record} record The Record to be removed |
---|
28 | */ |
---|
29 | "beforerowremoved", |
---|
30 | /** |
---|
31 | * @event beforerowsinserted |
---|
32 | * Internal UI Event. Fired before rows are inserted. |
---|
33 | * @param {Ext.grid.GridView} view |
---|
34 | * @param {Number} firstRow The index of the first row to be inserted. |
---|
35 | * @param {Number} lastRow The index of the last row to be inserted. |
---|
36 | */ |
---|
37 | "beforerowsinserted", |
---|
38 | /** |
---|
39 | * @event beforerefresh |
---|
40 | * Internal UI Event. Fired before the view is refreshed. |
---|
41 | * @param {Ext.grid.GridView} view |
---|
42 | */ |
---|
43 | "beforerefresh", |
---|
44 | /** |
---|
45 | * @event rowremoved |
---|
46 | * Internal UI Event. Fired after a row is removed. |
---|
47 | * @param {Ext.grid.GridView} view |
---|
48 | * @param {Number} rowIndex The index of the row that was removed. |
---|
49 | * @param {Ext.data.Record} record The Record that was removed |
---|
50 | */ |
---|
51 | "rowremoved", |
---|
52 | /** |
---|
53 | * @event rowsinserted |
---|
54 | * Internal UI Event. Fired after rows are inserted. |
---|
55 | * @param {Ext.grid.GridView} view |
---|
56 | * @param {Number} firstRow The index of the first inserted. |
---|
57 | * @param {Number} lastRow The index of the last row inserted. |
---|
58 | */ |
---|
59 | "rowsinserted", |
---|
60 | /** |
---|
61 | * @event rowupdated |
---|
62 | * Internal UI Event. Fired after a row has been updated. |
---|
63 | * @param {Ext.grid.GridView} view |
---|
64 | * @param {Number} firstRow The index of the row updated. |
---|
65 | * @param {Ext.data.record} record The Record backing the row updated. |
---|
66 | */ |
---|
67 | "rowupdated", |
---|
68 | /** |
---|
69 | * @event refresh |
---|
70 | * Internal UI Event. Fired after the GridView's body has been refreshed. |
---|
71 | * @param {Ext.grid.GridView} view |
---|
72 | */ |
---|
73 | "refresh" |
---|
74 | ); |
---|
75 | Ext.grid.GridView.superclass.constructor.call(this); |
---|
76 | }; |
---|
77 | |
---|
78 | Ext.extend(Ext.grid.GridView, Ext.util.Observable, { |
---|
79 | /** |
---|
80 | * Override this function to apply custom CSS classes to rows during rendering. You can also supply custom |
---|
81 | * parameters to the row template for the current row to customize how it is rendered using the <b>rowParams</b> |
---|
82 | * parameter. This function should return the CSS class name (or empty string '' for none) that will be added |
---|
83 | * to the row's wrapping div. To apply multiple class names, simply return them space-delimited within the string |
---|
84 | * (e.g., 'my-class another-class'). Example usage: |
---|
85 | <pre><code> |
---|
86 | viewConfig: { |
---|
87 | forceFit: true, |
---|
88 | showPreview: true, // custom property |
---|
89 | enableRowBody: true, // required to create a second, full-width row to show expanded Record data |
---|
90 | getRowClass: function(record, rowIndex, rp, ds){ // rp = rowParams |
---|
91 | if(this.showPreview){ |
---|
92 | rp.body = '<p>'+record.data.excerpt+'</p>'; |
---|
93 | return 'x-grid3-row-expanded'; |
---|
94 | } |
---|
95 | return 'x-grid3-row-collapsed'; |
---|
96 | } |
---|
97 | }, |
---|
98 | </code></pre> |
---|
99 | * @param {Record} record The {@link Ext.data.Record} corresponding to the current row. |
---|
100 | * @param {Number} index The row index. |
---|
101 | * @param {Object} rowParams A config object that is passed to the row template during rendering that allows |
---|
102 | * customization of various aspects of a grid row. |
---|
103 | * <p>If {@link #enableRowBody} is configured <b><tt></tt>true</b>, then the following properties may be set |
---|
104 | * by this function, and will be used to render a full-width expansion row below each grid row:</p> |
---|
105 | * <ul> |
---|
106 | * <li><code>body</code> : String <div class="sub-desc">An HTML fragment to be used as the expansion row's body content (defaults to '').</div></li> |
---|
107 | * <li><code>bodyStyle</code> : String <div class="sub-desc">A CSS style specification that will be applied to the expansion row's <tr> element. (defaults to '').</div></li> |
---|
108 | * </ul> |
---|
109 | * The following property will be passed in, and may be appended to: |
---|
110 | * <ul> |
---|
111 | * <li><code>tstyle</code> : String <div class="sub-desc">A CSS style specification that willl be applied to the <table> element which encapsulates |
---|
112 | * both the standard grid row, and any expansion row.</div></li> |
---|
113 | * </ul> |
---|
114 | * @param {Store} store The {@link Ext.data.Store} this grid is bound to |
---|
115 | * @method getRowClass |
---|
116 | * @return {String} a CSS class name to add to the row. |
---|
117 | */ |
---|
118 | /** |
---|
119 | * @cfg {Boolean} enableRowBody True to add a second TR element per row that can be used to provide a row body |
---|
120 | * that spans beneath the data row. Use the {@link #getRowClass} method's rowParams config to customize the row body. |
---|
121 | */ |
---|
122 | /** |
---|
123 | * @cfg {String} emptyText Default text (html tags are accepted) to display in the grid body when no rows |
---|
124 | * are available (defaults to ''). This value will be used to update the <tt>{@link #mainBody}</tt>: |
---|
125 | <pre><code> |
---|
126 | this.mainBody.update('<div class="x-grid-empty">' + this.emptyText + '</div>'); |
---|
127 | </code></pre> |
---|
128 | */ |
---|
129 | /** |
---|
130 | * @cfg {Boolean} headersDisabled True to disable the grid column headers (defaults to <tt>false</tt>). |
---|
131 | * Use the {@link Ext.grid.ColumnModel ColumnModel} <tt>{@link Ext.grid.ColumnModel#menuDisabled menuDisabled}</tt> |
---|
132 | * config to disable the <i>menu</i> for individual columns. While this config is true the |
---|
133 | * following will be disabled:<div class="mdetail-params"><ul> |
---|
134 | * <li>clicking on header to sort</li> |
---|
135 | * <li>the trigger to reveal the menu.</li> |
---|
136 | * </ul></div> |
---|
137 | */ |
---|
138 | /** |
---|
139 | * <p>A customized implementation of a {@link Ext.dd.DragZone DragZone} which provides default implementations |
---|
140 | * of the template methods of DragZone to enable dragging of the selected rows of a GridPanel. |
---|
141 | * See {@link Ext.grid.GridDragZone} for details.</p> |
---|
142 | * <p>This will <b>only</b> be present:<div class="mdetail-params"><ul> |
---|
143 | * <li><i>if</i> the owning GridPanel was configured with {@link Ext.grid.GridPanel#enableDragDrop enableDragDrop}: <tt>true</tt>.</li> |
---|
144 | * <li><i>after</i> the owning GridPanel has been rendered.</li> |
---|
145 | * </ul></div> |
---|
146 | * @property dragZone |
---|
147 | * @type {Ext.grid.GridDragZone} |
---|
148 | */ |
---|
149 | /** |
---|
150 | * @cfg {Boolean} deferEmptyText True to defer <tt>{@link #emptyText}</tt> being applied until the store's |
---|
151 | * first load (defaults to <tt>true</tt>). |
---|
152 | */ |
---|
153 | deferEmptyText : true, |
---|
154 | /** |
---|
155 | * @cfg {Number} scrollOffset The amount of space to reserve for the vertical scrollbar |
---|
156 | * (defaults to <tt>19</tt> pixels). |
---|
157 | */ |
---|
158 | scrollOffset : 19, |
---|
159 | /** |
---|
160 | * @cfg {Boolean} autoFill |
---|
161 | * Defaults to <tt>false</tt>. Specify <tt>true</tt> to have the column widths re-proportioned |
---|
162 | * when the grid is <b>initially rendered</b>. The |
---|
163 | * {@link Ext.grid.Column#width initially configured width}</tt> of each column will be adjusted |
---|
164 | * to fit the grid width and prevent horizontal scrolling. If columns are later resized (manually |
---|
165 | * or programmatically), the other columns in the grid will <b>not</b> be resized to fit the grid width. |
---|
166 | * See <tt>{@link #forceFit}</tt> also. |
---|
167 | */ |
---|
168 | autoFill : false, |
---|
169 | /** |
---|
170 | * @cfg {Boolean} forceFit |
---|
171 | * Defaults to <tt>false</tt>. Specify <tt>true</tt> to have the column widths re-proportioned |
---|
172 | * at <b>all times</b>. The {@link Ext.grid.Column#width initially configured width}</tt> of each |
---|
173 | * column will be adjusted to fit the grid width and prevent horizontal scrolling. If columns are |
---|
174 | * later resized (manually or programmatically), the other columns in the grid <b>will</b> be resized |
---|
175 | * to fit the grid width. See <tt>{@link #autoFill}</tt> also. |
---|
176 | */ |
---|
177 | forceFit : false, |
---|
178 | /** |
---|
179 | * @cfg {Array} sortClasses The CSS classes applied to a header when it is sorted. (defaults to <tt>["sort-asc", "sort-desc"]</tt>) |
---|
180 | */ |
---|
181 | sortClasses : ["sort-asc", "sort-desc"], |
---|
182 | /** |
---|
183 | * @cfg {String} sortAscText The text displayed in the "Sort Ascending" menu item (defaults to <tt>"Sort Ascending"</tt>) |
---|
184 | */ |
---|
185 | sortAscText : "Sort Ascending", |
---|
186 | /** |
---|
187 | * @cfg {String} sortDescText The text displayed in the "Sort Descending" menu item (defaults to <tt>"Sort Descending"</tt>) |
---|
188 | */ |
---|
189 | sortDescText : "Sort Descending", |
---|
190 | /** |
---|
191 | * @cfg {String} columnsText The text displayed in the "Columns" menu item (defaults to <tt>"Columns"</tt>) |
---|
192 | */ |
---|
193 | columnsText : "Columns", |
---|
194 | |
---|
195 | /** |
---|
196 | * @cfg {String} selectedRowClass The CSS class applied to a selected row (defaults to <tt>"x-grid3-row-selected"</tt>). An |
---|
197 | * example overriding the default styling: |
---|
198 | <pre><code> |
---|
199 | .x-grid3-row-selected {background-color: yellow;} |
---|
200 | </code></pre> |
---|
201 | * Note that this only controls the row, and will not do anything for the text inside it. To style inner |
---|
202 | * facets (like text) use something like: |
---|
203 | <pre><code> |
---|
204 | .x-grid3-row-selected .x-grid3-cell-inner { |
---|
205 | color: #FFCC00; |
---|
206 | } |
---|
207 | </code></pre> |
---|
208 | * @type String |
---|
209 | */ |
---|
210 | selectedRowClass : "x-grid3-row-selected", |
---|
211 | |
---|
212 | // private |
---|
213 | borderWidth : 2, |
---|
214 | tdClass : 'x-grid3-cell', |
---|
215 | hdCls : 'x-grid3-hd', |
---|
216 | markDirty : true, |
---|
217 | |
---|
218 | /** |
---|
219 | * @cfg {Number} cellSelectorDepth The number of levels to search for cells in event delegation (defaults to <tt>4</tt>) |
---|
220 | */ |
---|
221 | cellSelectorDepth : 4, |
---|
222 | /** |
---|
223 | * @cfg {Number} rowSelectorDepth The number of levels to search for rows in event delegation (defaults to <tt>10</tt>) |
---|
224 | */ |
---|
225 | rowSelectorDepth : 10, |
---|
226 | |
---|
227 | /** |
---|
228 | * @cfg {String} cellSelector The selector used to find cells internally (defaults to <tt>'td.x-grid3-cell'</tt>) |
---|
229 | */ |
---|
230 | cellSelector : 'td.x-grid3-cell', |
---|
231 | /** |
---|
232 | * @cfg {String} rowSelector The selector used to find rows internally (defaults to <tt>'div.x-grid3-row'</tt>) |
---|
233 | */ |
---|
234 | rowSelector : 'div.x-grid3-row', |
---|
235 | |
---|
236 | // private |
---|
237 | firstRowCls: 'x-grid3-row-first', |
---|
238 | lastRowCls: 'x-grid3-row-last', |
---|
239 | rowClsRe: /(?:^|\s+)x-grid3-row-(first|last|alt)(?:\s+|$)/g, |
---|
240 | |
---|
241 | /* -------------------------------- UI Specific ----------------------------- */ |
---|
242 | |
---|
243 | // private |
---|
244 | initTemplates : function(){ |
---|
245 | var ts = this.templates || {}; |
---|
246 | if(!ts.master){ |
---|
247 | ts.master = new Ext.Template( |
---|
248 | '<div class="x-grid3" hidefocus="true">', |
---|
249 | '<div class="x-grid3-viewport">', |
---|
250 | '<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset" style="{ostyle}">{header}</div></div><div class="x-clear"></div></div>', |
---|
251 | '<div class="x-grid3-scroller"><div class="x-grid3-body" style="{bstyle}">{body}</div><a href="#" class="x-grid3-focus" tabIndex="-1"></a></div>', |
---|
252 | '</div>', |
---|
253 | '<div class="x-grid3-resize-marker"> </div>', |
---|
254 | '<div class="x-grid3-resize-proxy"> </div>', |
---|
255 | '</div>' |
---|
256 | ); |
---|
257 | } |
---|
258 | |
---|
259 | if(!ts.header){ |
---|
260 | ts.header = new Ext.Template( |
---|
261 | '<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">', |
---|
262 | '<thead><tr class="x-grid3-hd-row">{cells}</tr></thead>', |
---|
263 | '</table>' |
---|
264 | ); |
---|
265 | } |
---|
266 | |
---|
267 | if(!ts.hcell){ |
---|
268 | ts.hcell = new Ext.Template( |
---|
269 | '<td class="x-grid3-hd x-grid3-cell x-grid3-td-{id} {css}" style="{style}"><div {tooltip} {attr} class="x-grid3-hd-inner x-grid3-hd-{id}" unselectable="on" style="{istyle}">', this.grid.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '', |
---|
270 | '{value}<img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" />', |
---|
271 | '</div></td>' |
---|
272 | ); |
---|
273 | } |
---|
274 | |
---|
275 | if(!ts.body){ |
---|
276 | ts.body = new Ext.Template('{rows}'); |
---|
277 | } |
---|
278 | |
---|
279 | if(!ts.row){ |
---|
280 | ts.row = new Ext.Template( |
---|
281 | '<div class="x-grid3-row {alt}" style="{tstyle}"><table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">', |
---|
282 | '<tbody><tr>{cells}</tr>', |
---|
283 | (this.enableRowBody ? '<tr class="x-grid3-row-body-tr" style="{bodyStyle}"><td colspan="{cols}" class="x-grid3-body-cell" tabIndex="0" hidefocus="on"><div class="x-grid3-row-body">{body}</div></td></tr>' : ''), |
---|
284 | '</tbody></table></div>' |
---|
285 | ); |
---|
286 | } |
---|
287 | |
---|
288 | if(!ts.cell){ |
---|
289 | ts.cell = new Ext.Template( |
---|
290 | '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}" tabIndex="0" {cellAttr}>', |
---|
291 | '<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on" {attr}>{value}</div>', |
---|
292 | '</td>' |
---|
293 | ); |
---|
294 | } |
---|
295 | |
---|
296 | for(var k in ts){ |
---|
297 | var t = ts[k]; |
---|
298 | if(t && typeof t.compile == 'function' && !t.compiled){ |
---|
299 | t.disableFormats = true; |
---|
300 | t.compile(); |
---|
301 | } |
---|
302 | } |
---|
303 | |
---|
304 | this.templates = ts; |
---|
305 | this.colRe = new RegExp("x-grid3-td-([^\\s]+)", ""); |
---|
306 | }, |
---|
307 | |
---|
308 | // private |
---|
309 | fly : function(el){ |
---|
310 | if(!this._flyweight){ |
---|
311 | this._flyweight = new Ext.Element.Flyweight(document.body); |
---|
312 | } |
---|
313 | this._flyweight.dom = el; |
---|
314 | return this._flyweight; |
---|
315 | }, |
---|
316 | |
---|
317 | // private |
---|
318 | getEditorParent : function(){ |
---|
319 | return this.scroller.dom; |
---|
320 | }, |
---|
321 | |
---|
322 | // private |
---|
323 | initElements : function(){ |
---|
324 | var E = Ext.Element; |
---|
325 | |
---|
326 | var el = this.grid.getGridEl().dom.firstChild; |
---|
327 | var cs = el.childNodes; |
---|
328 | |
---|
329 | this.el = new E(el); |
---|
330 | |
---|
331 | this.mainWrap = new E(cs[0]); |
---|
332 | this.mainHd = new E(this.mainWrap.dom.firstChild); |
---|
333 | |
---|
334 | if(this.grid.hideHeaders){ |
---|
335 | this.mainHd.setDisplayed(false); |
---|
336 | } |
---|
337 | |
---|
338 | this.innerHd = this.mainHd.dom.firstChild; |
---|
339 | this.scroller = new E(this.mainWrap.dom.childNodes[1]); |
---|
340 | if(this.forceFit){ |
---|
341 | this.scroller.setStyle('overflow-x', 'hidden'); |
---|
342 | } |
---|
343 | /** |
---|
344 | * <i>Read-only</i>. The GridView's body Element which encapsulates all rows in the Grid. |
---|
345 | * This {@link Ext.Element Element} is only available after the GridPanel has been rendered. |
---|
346 | * @type Ext.Element |
---|
347 | * @property mainBody |
---|
348 | */ |
---|
349 | this.mainBody = new E(this.scroller.dom.firstChild); |
---|
350 | |
---|
351 | this.focusEl = new E(this.scroller.dom.childNodes[1]); |
---|
352 | this.focusEl.swallowEvent("click", true); |
---|
353 | |
---|
354 | this.resizeMarker = new E(cs[1]); |
---|
355 | this.resizeProxy = new E(cs[2]); |
---|
356 | }, |
---|
357 | |
---|
358 | // private |
---|
359 | getRows : function(){ |
---|
360 | return this.hasRows() ? this.mainBody.dom.childNodes : []; |
---|
361 | }, |
---|
362 | |
---|
363 | // finder methods, used with delegation |
---|
364 | |
---|
365 | // private |
---|
366 | findCell : function(el){ |
---|
367 | if(!el){ |
---|
368 | return false; |
---|
369 | } |
---|
370 | return this.fly(el).findParent(this.cellSelector, this.cellSelectorDepth); |
---|
371 | }, |
---|
372 | |
---|
373 | /** |
---|
374 | * <p>Return the index of the grid column which contains the passed element.</p> |
---|
375 | * See also {@link #findRowIndex} |
---|
376 | * @param {Element} el The target element |
---|
377 | * @return The column index, or <b>false</b> if the target element is not within a row of this GridView. |
---|
378 | */ |
---|
379 | findCellIndex : function(el, requiredCls){ |
---|
380 | var cell = this.findCell(el); |
---|
381 | if(cell && (!requiredCls || this.fly(cell).hasClass(requiredCls))){ |
---|
382 | return this.getCellIndex(cell); |
---|
383 | } |
---|
384 | return false; |
---|
385 | }, |
---|
386 | |
---|
387 | // private |
---|
388 | getCellIndex : function(el){ |
---|
389 | if(el){ |
---|
390 | var m = el.className.match(this.colRe); |
---|
391 | if(m && m[1]){ |
---|
392 | return this.cm.getIndexById(m[1]); |
---|
393 | } |
---|
394 | } |
---|
395 | return false; |
---|
396 | }, |
---|
397 | |
---|
398 | // private |
---|
399 | findHeaderCell : function(el){ |
---|
400 | var cell = this.findCell(el); |
---|
401 | return cell && this.fly(cell).hasClass(this.hdCls) ? cell : null; |
---|
402 | }, |
---|
403 | |
---|
404 | // private |
---|
405 | findHeaderIndex : function(el){ |
---|
406 | return this.findCellIndex(el, this.hdCls); |
---|
407 | }, |
---|
408 | |
---|
409 | /** |
---|
410 | * Return the HtmlElement representing the grid row which contains the passed element. |
---|
411 | * @param {Element} el The target element |
---|
412 | * @return The row element, or null if the target element is not within a row of this GridView. |
---|
413 | */ |
---|
414 | findRow : function(el){ |
---|
415 | if(!el){ |
---|
416 | return false; |
---|
417 | } |
---|
418 | return this.fly(el).findParent(this.rowSelector, this.rowSelectorDepth); |
---|
419 | }, |
---|
420 | |
---|
421 | /** |
---|
422 | * <p>Return the index of the grid row which contains the passed element.</p> |
---|
423 | * See also {@link #findCellIndex} |
---|
424 | * @param {Element} el The target element |
---|
425 | * @return The row index, or <b>false</b> if the target element is not within a row of this GridView. |
---|
426 | */ |
---|
427 | findRowIndex : function(el){ |
---|
428 | var r = this.findRow(el); |
---|
429 | return r ? r.rowIndex : false; |
---|
430 | }, |
---|
431 | |
---|
432 | // getter methods for fetching elements dynamically in the grid |
---|
433 | |
---|
434 | /** |
---|
435 | * Return the <tt><div></tt> HtmlElement which represents a Grid row for the specified index. |
---|
436 | * @param {Number} index The row index |
---|
437 | * @return {HtmlElement} The div element. |
---|
438 | */ |
---|
439 | getRow : function(row){ |
---|
440 | return this.getRows()[row]; |
---|
441 | }, |
---|
442 | |
---|
443 | /** |
---|
444 | * Returns the grid's <tt><td></tt> HtmlElement at the specified coordinates. |
---|
445 | * @param {Number} row The row index in which to find the cell. |
---|
446 | * @param {Number} col The column index of the cell. |
---|
447 | * @return {HtmlElement} The td at the specified coordinates. |
---|
448 | */ |
---|
449 | getCell : function(row, col){ |
---|
450 | return this.getRow(row).getElementsByTagName('td')[col]; |
---|
451 | }, |
---|
452 | |
---|
453 | /** |
---|
454 | * Return the <tt><td></tt> HtmlElement which represents the Grid's header cell for the specified column index. |
---|
455 | * @param {Number} index The column index |
---|
456 | * @return {HtmlElement} The td element. |
---|
457 | */ |
---|
458 | getHeaderCell : function(index){ |
---|
459 | return this.mainHd.dom.getElementsByTagName('td')[index]; |
---|
460 | }, |
---|
461 | |
---|
462 | // manipulating elements |
---|
463 | |
---|
464 | // private - use getRowClass to apply custom row classes |
---|
465 | addRowClass : function(row, cls){ |
---|
466 | var r = this.getRow(row); |
---|
467 | if(r){ |
---|
468 | this.fly(r).addClass(cls); |
---|
469 | } |
---|
470 | }, |
---|
471 | |
---|
472 | // private |
---|
473 | removeRowClass : function(row, cls){ |
---|
474 | var r = this.getRow(row); |
---|
475 | if(r){ |
---|
476 | this.fly(r).removeClass(cls); |
---|
477 | } |
---|
478 | }, |
---|
479 | |
---|
480 | // private |
---|
481 | removeRow : function(row){ |
---|
482 | Ext.removeNode(this.getRow(row)); |
---|
483 | this.syncFocusEl(row); |
---|
484 | }, |
---|
485 | |
---|
486 | // private |
---|
487 | removeRows : function(firstRow, lastRow){ |
---|
488 | var bd = this.mainBody.dom; |
---|
489 | for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){ |
---|
490 | Ext.removeNode(bd.childNodes[firstRow]); |
---|
491 | } |
---|
492 | this.syncFocusEl(firstRow); |
---|
493 | }, |
---|
494 | |
---|
495 | // scrolling stuff |
---|
496 | |
---|
497 | // private |
---|
498 | getScrollState : function(){ |
---|
499 | var sb = this.scroller.dom; |
---|
500 | return {left: sb.scrollLeft, top: sb.scrollTop}; |
---|
501 | }, |
---|
502 | |
---|
503 | // private |
---|
504 | restoreScroll : function(state){ |
---|
505 | var sb = this.scroller.dom; |
---|
506 | sb.scrollLeft = state.left; |
---|
507 | sb.scrollTop = state.top; |
---|
508 | }, |
---|
509 | |
---|
510 | /** |
---|
511 | * Scrolls the grid to the top |
---|
512 | */ |
---|
513 | scrollToTop : function(){ |
---|
514 | this.scroller.dom.scrollTop = 0; |
---|
515 | this.scroller.dom.scrollLeft = 0; |
---|
516 | }, |
---|
517 | |
---|
518 | // private |
---|
519 | syncScroll : function(){ |
---|
520 | this.syncHeaderScroll(); |
---|
521 | var mb = this.scroller.dom; |
---|
522 | this.grid.fireEvent("bodyscroll", mb.scrollLeft, mb.scrollTop); |
---|
523 | }, |
---|
524 | |
---|
525 | // private |
---|
526 | syncHeaderScroll : function(){ |
---|
527 | var mb = this.scroller.dom; |
---|
528 | this.innerHd.scrollLeft = mb.scrollLeft; |
---|
529 | this.innerHd.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore) |
---|
530 | }, |
---|
531 | |
---|
532 | // private |
---|
533 | updateSortIcon : function(col, dir){ |
---|
534 | var sc = this.sortClasses; |
---|
535 | var hds = this.mainHd.select('td').removeClass(sc); |
---|
536 | hds.item(col).addClass(sc[dir == "DESC" ? 1 : 0]); |
---|
537 | }, |
---|
538 | |
---|
539 | // private |
---|
540 | updateAllColumnWidths : function(){ |
---|
541 | var tw = this.getTotalWidth(), |
---|
542 | clen = this.cm.getColumnCount(), |
---|
543 | ws = [], |
---|
544 | len, |
---|
545 | i; |
---|
546 | for(i = 0; i < clen; i++){ |
---|
547 | ws[i] = this.getColumnWidth(i); |
---|
548 | } |
---|
549 | this.innerHd.firstChild.style.width = this.getOffsetWidth(); |
---|
550 | this.innerHd.firstChild.firstChild.style.width = tw; |
---|
551 | this.mainBody.dom.style.width = tw; |
---|
552 | for(i = 0; i < clen; i++){ |
---|
553 | var hd = this.getHeaderCell(i); |
---|
554 | hd.style.width = ws[i]; |
---|
555 | } |
---|
556 | |
---|
557 | var ns = this.getRows(), row, trow; |
---|
558 | for(i = 0, len = ns.length; i < len; i++){ |
---|
559 | row = ns[i]; |
---|
560 | row.style.width = tw; |
---|
561 | if(row.firstChild){ |
---|
562 | row.firstChild.style.width = tw; |
---|
563 | trow = row.firstChild.rows[0]; |
---|
564 | for (var j = 0; j < clen; j++) { |
---|
565 | trow.childNodes[j].style.width = ws[j]; |
---|
566 | } |
---|
567 | } |
---|
568 | } |
---|
569 | |
---|
570 | this.onAllColumnWidthsUpdated(ws, tw); |
---|
571 | }, |
---|
572 | |
---|
573 | // private |
---|
574 | updateColumnWidth : function(col, width){ |
---|
575 | var w = this.getColumnWidth(col); |
---|
576 | var tw = this.getTotalWidth(); |
---|
577 | this.innerHd.firstChild.style.width = this.getOffsetWidth(); |
---|
578 | this.innerHd.firstChild.firstChild.style.width = tw; |
---|
579 | this.mainBody.dom.style.width = tw; |
---|
580 | var hd = this.getHeaderCell(col); |
---|
581 | hd.style.width = w; |
---|
582 | |
---|
583 | var ns = this.getRows(), row; |
---|
584 | for(var i = 0, len = ns.length; i < len; i++){ |
---|
585 | row = ns[i]; |
---|
586 | row.style.width = tw; |
---|
587 | if(row.firstChild){ |
---|
588 | row.firstChild.style.width = tw; |
---|
589 | row.firstChild.rows[0].childNodes[col].style.width = w; |
---|
590 | } |
---|
591 | } |
---|
592 | |
---|
593 | this.onColumnWidthUpdated(col, w, tw); |
---|
594 | }, |
---|
595 | |
---|
596 | // private |
---|
597 | updateColumnHidden : function(col, hidden){ |
---|
598 | var tw = this.getTotalWidth(); |
---|
599 | this.innerHd.firstChild.style.width = this.getOffsetWidth(); |
---|
600 | this.innerHd.firstChild.firstChild.style.width = tw; |
---|
601 | this.mainBody.dom.style.width = tw; |
---|
602 | var display = hidden ? 'none' : ''; |
---|
603 | |
---|
604 | var hd = this.getHeaderCell(col); |
---|
605 | hd.style.display = display; |
---|
606 | |
---|
607 | var ns = this.getRows(), row; |
---|
608 | for(var i = 0, len = ns.length; i < len; i++){ |
---|
609 | row = ns[i]; |
---|
610 | row.style.width = tw; |
---|
611 | if(row.firstChild){ |
---|
612 | row.firstChild.style.width = tw; |
---|
613 | row.firstChild.rows[0].childNodes[col].style.display = display; |
---|
614 | } |
---|
615 | } |
---|
616 | |
---|
617 | this.onColumnHiddenUpdated(col, hidden, tw); |
---|
618 | delete this.lastViewWidth; // force recalc |
---|
619 | this.layout(); |
---|
620 | }, |
---|
621 | |
---|
622 | // private |
---|
623 | doRender : function(cs, rs, ds, startRow, colCount, stripe){ |
---|
624 | var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount-1; |
---|
625 | var tstyle = 'width:'+this.getTotalWidth()+';'; |
---|
626 | // buffers |
---|
627 | var buf = [], cb, c, p = {}, rp = {tstyle: tstyle}, r; |
---|
628 | for(var j = 0, len = rs.length; j < len; j++){ |
---|
629 | r = rs[j]; cb = []; |
---|
630 | var rowIndex = (j+startRow); |
---|
631 | for(var i = 0; i < colCount; i++){ |
---|
632 | c = cs[i]; |
---|
633 | p.id = c.id; |
---|
634 | p.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : ''); |
---|
635 | p.attr = p.cellAttr = ""; |
---|
636 | p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds); |
---|
637 | p.style = c.style; |
---|
638 | if(Ext.isEmpty(p.value)){ |
---|
639 | p.value = " "; |
---|
640 | } |
---|
641 | if(this.markDirty && r.dirty && typeof r.modified[c.name] !== 'undefined'){ |
---|
642 | p.css += ' x-grid3-dirty-cell'; |
---|
643 | } |
---|
644 | cb[cb.length] = ct.apply(p); |
---|
645 | } |
---|
646 | var alt = []; |
---|
647 | if(stripe && ((rowIndex+1) % 2 === 0)){ |
---|
648 | alt[0] = "x-grid3-row-alt"; |
---|
649 | } |
---|
650 | if(r.dirty){ |
---|
651 | alt[1] = " x-grid3-dirty-row"; |
---|
652 | } |
---|
653 | rp.cols = colCount; |
---|
654 | if(this.getRowClass){ |
---|
655 | alt[2] = this.getRowClass(r, rowIndex, rp, ds); |
---|
656 | } |
---|
657 | rp.alt = alt.join(" "); |
---|
658 | rp.cells = cb.join(""); |
---|
659 | buf[buf.length] = rt.apply(rp); |
---|
660 | } |
---|
661 | return buf.join(""); |
---|
662 | }, |
---|
663 | |
---|
664 | // private |
---|
665 | processRows : function(startRow, skipStripe){ |
---|
666 | if(!this.ds || this.ds.getCount() < 1){ |
---|
667 | return; |
---|
668 | } |
---|
669 | var rows = this.getRows(); |
---|
670 | skipStripe = skipStripe || !this.grid.stripeRows; |
---|
671 | startRow = startRow || 0; |
---|
672 | Ext.each(rows, function(row, idx){ |
---|
673 | row.rowIndex = idx; |
---|
674 | row.className = row.className.replace(this.rowClsRe, ' '); |
---|
675 | if (!skipStripe && (idx + 1) % 2 === 0) { |
---|
676 | row.className += ' x-grid3-row-alt'; |
---|
677 | } |
---|
678 | }); |
---|
679 | // add first/last-row classes |
---|
680 | if(startRow === 0){ |
---|
681 | Ext.fly(rows[0]).addClass(this.firstRowCls); |
---|
682 | } |
---|
683 | Ext.fly(rows[rows.length - 1]).addClass(this.lastRowCls); |
---|
684 | }, |
---|
685 | |
---|
686 | afterRender : function(){ |
---|
687 | if(!this.ds || !this.cm){ |
---|
688 | return; |
---|
689 | } |
---|
690 | this.mainBody.dom.innerHTML = this.renderRows() || ' '; |
---|
691 | this.processRows(0, true); |
---|
692 | |
---|
693 | if(this.deferEmptyText !== true){ |
---|
694 | this.applyEmptyText(); |
---|
695 | } |
---|
696 | }, |
---|
697 | |
---|
698 | // private |
---|
699 | renderUI : function(){ |
---|
700 | |
---|
701 | var header = this.renderHeaders(); |
---|
702 | var body = this.templates.body.apply({rows:' '}); |
---|
703 | |
---|
704 | |
---|
705 | var html = this.templates.master.apply({ |
---|
706 | body: body, |
---|
707 | header: header, |
---|
708 | ostyle: 'width:'+this.getOffsetWidth()+';', |
---|
709 | bstyle: 'width:'+this.getTotalWidth()+';' |
---|
710 | }); |
---|
711 | |
---|
712 | var g = this.grid; |
---|
713 | |
---|
714 | g.getGridEl().dom.innerHTML = html; |
---|
715 | |
---|
716 | this.initElements(); |
---|
717 | |
---|
718 | // get mousedowns early |
---|
719 | Ext.fly(this.innerHd).on("click", this.handleHdDown, this); |
---|
720 | this.mainHd.on({ |
---|
721 | scope: this, |
---|
722 | mouseover: this.handleHdOver, |
---|
723 | mouseout: this.handleHdOut, |
---|
724 | mousemove: this.handleHdMove |
---|
725 | }); |
---|
726 | |
---|
727 | this.scroller.on('scroll', this.syncScroll, this); |
---|
728 | if(g.enableColumnResize !== false){ |
---|
729 | this.splitZone = new Ext.grid.GridView.SplitDragZone(g, this.mainHd.dom); |
---|
730 | } |
---|
731 | |
---|
732 | if(g.enableColumnMove){ |
---|
733 | this.columnDrag = new Ext.grid.GridView.ColumnDragZone(g, this.innerHd); |
---|
734 | this.columnDrop = new Ext.grid.HeaderDropZone(g, this.mainHd.dom); |
---|
735 | } |
---|
736 | |
---|
737 | if(g.enableHdMenu !== false){ |
---|
738 | this.hmenu = new Ext.menu.Menu({id: g.id + "-hctx"}); |
---|
739 | this.hmenu.add( |
---|
740 | {itemId:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"}, |
---|
741 | {itemId:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"} |
---|
742 | ); |
---|
743 | if(g.enableColumnHide !== false){ |
---|
744 | this.colMenu = new Ext.menu.Menu({id:g.id + "-hcols-menu"}); |
---|
745 | this.colMenu.on({ |
---|
746 | scope: this, |
---|
747 | beforeshow: this.beforeColMenuShow, |
---|
748 | itemclick: this.handleHdMenuClick |
---|
749 | }); |
---|
750 | this.hmenu.add('-', { |
---|
751 | itemId:"columns", |
---|
752 | hideOnClick: false, |
---|
753 | text: this.columnsText, |
---|
754 | menu: this.colMenu, |
---|
755 | iconCls: 'x-cols-icon' |
---|
756 | }); |
---|
757 | } |
---|
758 | this.hmenu.on("itemclick", this.handleHdMenuClick, this); |
---|
759 | } |
---|
760 | |
---|
761 | if(g.trackMouseOver){ |
---|
762 | this.mainBody.on({ |
---|
763 | scope: this, |
---|
764 | mouseover: this.onRowOver, |
---|
765 | mouseout: this.onRowOut |
---|
766 | }); |
---|
767 | } |
---|
768 | |
---|
769 | if(g.enableDragDrop || g.enableDrag){ |
---|
770 | this.dragZone = new Ext.grid.GridDragZone(g, { |
---|
771 | ddGroup : g.ddGroup || 'GridDD' |
---|
772 | }); |
---|
773 | } |
---|
774 | |
---|
775 | this.updateHeaderSortState(); |
---|
776 | |
---|
777 | }, |
---|
778 | |
---|
779 | // private |
---|
780 | layout : function(){ |
---|
781 | if(!this.mainBody){ |
---|
782 | return; // not rendered |
---|
783 | } |
---|
784 | var g = this.grid; |
---|
785 | var c = g.getGridEl(); |
---|
786 | var csize = c.getSize(true); |
---|
787 | var vw = csize.width; |
---|
788 | |
---|
789 | if(!g.hideHeaders && (vw < 20 || csize.height < 20)){ // display: none? |
---|
790 | return; |
---|
791 | } |
---|
792 | |
---|
793 | if(g.autoHeight){ |
---|
794 | this.scroller.dom.style.overflow = 'visible'; |
---|
795 | if(Ext.isWebKit){ |
---|
796 | this.scroller.dom.style.position = 'static'; |
---|
797 | } |
---|
798 | }else{ |
---|
799 | this.el.setSize(csize.width, csize.height); |
---|
800 | |
---|
801 | var hdHeight = this.mainHd.getHeight(); |
---|
802 | var vh = csize.height - (hdHeight); |
---|
803 | |
---|
804 | this.scroller.setSize(vw, vh); |
---|
805 | if(this.innerHd){ |
---|
806 | this.innerHd.style.width = (vw)+'px'; |
---|
807 | } |
---|
808 | } |
---|
809 | if(this.forceFit){ |
---|
810 | if(this.lastViewWidth != vw){ |
---|
811 | this.fitColumns(false, false); |
---|
812 | this.lastViewWidth = vw; |
---|
813 | } |
---|
814 | }else { |
---|
815 | this.autoExpand(); |
---|
816 | this.syncHeaderScroll(); |
---|
817 | } |
---|
818 | this.onLayout(vw, vh); |
---|
819 | }, |
---|
820 | |
---|
821 | // template functions for subclasses and plugins |
---|
822 | // these functions include precalculated values |
---|
823 | onLayout : function(vw, vh){ |
---|
824 | // do nothing |
---|
825 | }, |
---|
826 | |
---|
827 | onColumnWidthUpdated : function(col, w, tw){ |
---|
828 | //template method |
---|
829 | }, |
---|
830 | |
---|
831 | onAllColumnWidthsUpdated : function(ws, tw){ |
---|
832 | //template method |
---|
833 | }, |
---|
834 | |
---|
835 | onColumnHiddenUpdated : function(col, hidden, tw){ |
---|
836 | // template method |
---|
837 | }, |
---|
838 | |
---|
839 | updateColumnText : function(col, text){ |
---|
840 | // template method |
---|
841 | }, |
---|
842 | |
---|
843 | afterMove : function(colIndex){ |
---|
844 | // template method |
---|
845 | }, |
---|
846 | |
---|
847 | /* ----------------------------------- Core Specific -------------------------------------------*/ |
---|
848 | // private |
---|
849 | init : function(grid){ |
---|
850 | this.grid = grid; |
---|
851 | |
---|
852 | this.initTemplates(); |
---|
853 | this.initData(grid.store, grid.colModel); |
---|
854 | this.initUI(grid); |
---|
855 | }, |
---|
856 | |
---|
857 | // private |
---|
858 | getColumnId : function(index){ |
---|
859 | return this.cm.getColumnId(index); |
---|
860 | }, |
---|
861 | |
---|
862 | // private |
---|
863 | getOffsetWidth : function() { |
---|
864 | return (this.cm.getTotalWidth() + this.scrollOffset) + 'px'; |
---|
865 | }, |
---|
866 | |
---|
867 | // private |
---|
868 | renderHeaders : function(){ |
---|
869 | var cm = this.cm, |
---|
870 | ts = this.templates, |
---|
871 | ct = ts.hcell, |
---|
872 | cb = [], |
---|
873 | p = {}, |
---|
874 | len = cm.getColumnCount(), |
---|
875 | last = len - 1; |
---|
876 | |
---|
877 | for(var i = 0; i < len; i++){ |
---|
878 | p.id = cm.getColumnId(i); |
---|
879 | p.value = cm.getColumnHeader(i) || ""; |
---|
880 | p.style = this.getColumnStyle(i, true); |
---|
881 | p.tooltip = this.getColumnTooltip(i); |
---|
882 | p.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : ''); |
---|
883 | if(cm.config[i].align == 'right'){ |
---|
884 | p.istyle = 'padding-right:16px'; |
---|
885 | } else { |
---|
886 | delete p.istyle; |
---|
887 | } |
---|
888 | cb[cb.length] = ct.apply(p); |
---|
889 | } |
---|
890 | return ts.header.apply({cells: cb.join(""), tstyle:'width:'+this.getTotalWidth()+';'}); |
---|
891 | }, |
---|
892 | |
---|
893 | // private |
---|
894 | getColumnTooltip : function(i){ |
---|
895 | var tt = this.cm.getColumnTooltip(i); |
---|
896 | if(tt){ |
---|
897 | if(Ext.QuickTips.isEnabled()){ |
---|
898 | return 'ext:qtip="'+tt+'"'; |
---|
899 | }else{ |
---|
900 | return 'title="'+tt+'"'; |
---|
901 | } |
---|
902 | } |
---|
903 | return ""; |
---|
904 | }, |
---|
905 | |
---|
906 | // private |
---|
907 | beforeUpdate : function(){ |
---|
908 | this.grid.stopEditing(true); |
---|
909 | }, |
---|
910 | |
---|
911 | // private |
---|
912 | updateHeaders : function(){ |
---|
913 | this.innerHd.firstChild.innerHTML = this.renderHeaders(); |
---|
914 | this.innerHd.firstChild.style.width = this.getOffsetWidth(); |
---|
915 | this.innerHd.firstChild.firstChild.style.width = this.getTotalWidth(); |
---|
916 | }, |
---|
917 | |
---|
918 | /** |
---|
919 | * Focuses the specified row. |
---|
920 | * @param {Number} row The row index |
---|
921 | */ |
---|
922 | focusRow : function(row){ |
---|
923 | this.focusCell(row, 0, false); |
---|
924 | }, |
---|
925 | |
---|
926 | /** |
---|
927 | * Focuses the specified cell. |
---|
928 | * @param {Number} row The row index |
---|
929 | * @param {Number} col The column index |
---|
930 | */ |
---|
931 | focusCell : function(row, col, hscroll){ |
---|
932 | this.syncFocusEl(this.ensureVisible(row, col, hscroll)); |
---|
933 | if(Ext.isGecko){ |
---|
934 | this.focusEl.focus(); |
---|
935 | }else{ |
---|
936 | this.focusEl.focus.defer(1, this.focusEl); |
---|
937 | } |
---|
938 | }, |
---|
939 | |
---|
940 | resolveCell : function(row, col, hscroll){ |
---|
941 | if(typeof row != "number"){ |
---|
942 | row = row.rowIndex; |
---|
943 | } |
---|
944 | if(!this.ds){ |
---|
945 | return null; |
---|
946 | } |
---|
947 | if(row < 0 || row >= this.ds.getCount()){ |
---|
948 | return null; |
---|
949 | } |
---|
950 | col = (col !== undefined ? col : 0); |
---|
951 | |
---|
952 | var rowEl = this.getRow(row), |
---|
953 | cm = this.cm, |
---|
954 | colCount = cm.getColumnCount(), |
---|
955 | cellEl; |
---|
956 | if(!(hscroll === false && col === 0)){ |
---|
957 | while(col < colCount && cm.isHidden(col)){ |
---|
958 | col++; |
---|
959 | } |
---|
960 | cellEl = this.getCell(row, col); |
---|
961 | } |
---|
962 | |
---|
963 | return {row: rowEl, cell: cellEl}; |
---|
964 | }, |
---|
965 | |
---|
966 | getResolvedXY : function(resolved){ |
---|
967 | if(!resolved){ |
---|
968 | return null; |
---|
969 | } |
---|
970 | var s = this.scroller.dom, c = resolved.cell, r = resolved.row; |
---|
971 | return c ? Ext.fly(c).getXY() : [this.el.getX(), Ext.fly(r).getY()]; |
---|
972 | }, |
---|
973 | |
---|
974 | syncFocusEl : function(row, col, hscroll){ |
---|
975 | var xy = row; |
---|
976 | if(!Ext.isArray(xy)){ |
---|
977 | row = Math.min(row, Math.max(0, this.getRows().length-1)); |
---|
978 | xy = this.getResolvedXY(this.resolveCell(row, col, hscroll)); |
---|
979 | } |
---|
980 | this.focusEl.setXY(xy||this.scroller.getXY()); |
---|
981 | }, |
---|
982 | |
---|
983 | ensureVisible : function(row, col, hscroll){ |
---|
984 | var resolved = this.resolveCell(row, col, hscroll); |
---|
985 | if(!resolved || !resolved.row){ |
---|
986 | return; |
---|
987 | } |
---|
988 | |
---|
989 | var rowEl = resolved.row, |
---|
990 | cellEl = resolved.cell, |
---|
991 | c = this.scroller.dom, |
---|
992 | ctop = 0, |
---|
993 | p = rowEl, |
---|
994 | stop = this.el.dom; |
---|
995 | |
---|
996 | while(p && p != stop){ |
---|
997 | ctop += p.offsetTop; |
---|
998 | p = p.offsetParent; |
---|
999 | } |
---|
1000 | ctop -= this.mainHd.dom.offsetHeight; |
---|
1001 | |
---|
1002 | var cbot = ctop + rowEl.offsetHeight, |
---|
1003 | ch = c.clientHeight, |
---|
1004 | sbot = stop + ch; |
---|
1005 | |
---|
1006 | stop = parseInt(c.scrollTop, 10); |
---|
1007 | |
---|
1008 | |
---|
1009 | if(ctop < stop){ |
---|
1010 | c.scrollTop = ctop; |
---|
1011 | }else if(cbot > sbot){ |
---|
1012 | c.scrollTop = cbot-ch; |
---|
1013 | } |
---|
1014 | |
---|
1015 | if(hscroll !== false){ |
---|
1016 | var cleft = parseInt(cellEl.offsetLeft, 10); |
---|
1017 | var cright = cleft + cellEl.offsetWidth; |
---|
1018 | |
---|
1019 | var sleft = parseInt(c.scrollLeft, 10); |
---|
1020 | var sright = sleft + c.clientWidth; |
---|
1021 | if(cleft < sleft){ |
---|
1022 | c.scrollLeft = cleft; |
---|
1023 | }else if(cright > sright){ |
---|
1024 | c.scrollLeft = cright-c.clientWidth; |
---|
1025 | } |
---|
1026 | } |
---|
1027 | return this.getResolvedXY(resolved); |
---|
1028 | }, |
---|
1029 | |
---|
1030 | // private |
---|
1031 | insertRows : function(dm, firstRow, lastRow, isUpdate){ |
---|
1032 | var last = dm.getCount() - 1; |
---|
1033 | if(!isUpdate && firstRow === 0 && lastRow >= last){ |
---|
1034 | this.refresh(); |
---|
1035 | }else{ |
---|
1036 | if(!isUpdate){ |
---|
1037 | this.fireEvent("beforerowsinserted", this, firstRow, lastRow); |
---|
1038 | } |
---|
1039 | var html = this.renderRows(firstRow, lastRow), |
---|
1040 | before = this.getRow(firstRow); |
---|
1041 | if(before){ |
---|
1042 | if(firstRow === 0){ |
---|
1043 | Ext.fly(this.getRow(0)).removeClass(this.firstRowCls); |
---|
1044 | } |
---|
1045 | Ext.DomHelper.insertHtml('beforeBegin', before, html); |
---|
1046 | }else{ |
---|
1047 | var r = this.getRow(last - 1); |
---|
1048 | if(r){ |
---|
1049 | Ext.fly(r).removeClass(this.lastRowCls); |
---|
1050 | } |
---|
1051 | Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html); |
---|
1052 | } |
---|
1053 | if(!isUpdate){ |
---|
1054 | this.fireEvent("rowsinserted", this, firstRow, lastRow); |
---|
1055 | this.processRows(firstRow); |
---|
1056 | }else if(firstRow === 0 || firstRow >= last){ |
---|
1057 | //ensure first/last row is kept after an update. |
---|
1058 | Ext.fly(this.getRow(firstRow)).addClass(firstRow === 0 ? this.firstRowCls : this.lastRowCls); |
---|
1059 | } |
---|
1060 | } |
---|
1061 | this.syncFocusEl(firstRow); |
---|
1062 | }, |
---|
1063 | |
---|
1064 | // private |
---|
1065 | deleteRows : function(dm, firstRow, lastRow){ |
---|
1066 | if(dm.getRowCount()<1){ |
---|
1067 | this.refresh(); |
---|
1068 | }else{ |
---|
1069 | this.fireEvent("beforerowsdeleted", this, firstRow, lastRow); |
---|
1070 | |
---|
1071 | this.removeRows(firstRow, lastRow); |
---|
1072 | |
---|
1073 | this.processRows(firstRow); |
---|
1074 | this.fireEvent("rowsdeleted", this, firstRow, lastRow); |
---|
1075 | } |
---|
1076 | }, |
---|
1077 | |
---|
1078 | // private |
---|
1079 | getColumnStyle : function(col, isHeader){ |
---|
1080 | var style = !isHeader ? (this.cm.config[col].css || '') : ''; |
---|
1081 | style += 'width:'+this.getColumnWidth(col)+';'; |
---|
1082 | if(this.cm.isHidden(col)){ |
---|
1083 | style += 'display:none;'; |
---|
1084 | } |
---|
1085 | var align = this.cm.config[col].align; |
---|
1086 | if(align){ |
---|
1087 | style += 'text-align:'+align+';'; |
---|
1088 | } |
---|
1089 | return style; |
---|
1090 | }, |
---|
1091 | |
---|
1092 | // private |
---|
1093 | getColumnWidth : function(col){ |
---|
1094 | var w = this.cm.getColumnWidth(col); |
---|
1095 | if(typeof w == 'number'){ |
---|
1096 | return (Ext.isBorderBox ? w : (w-this.borderWidth > 0 ? w-this.borderWidth:0)) + 'px'; |
---|
1097 | } |
---|
1098 | return w; |
---|
1099 | }, |
---|
1100 | |
---|
1101 | // private |
---|
1102 | getTotalWidth : function(){ |
---|
1103 | return this.cm.getTotalWidth()+'px'; |
---|
1104 | }, |
---|
1105 | |
---|
1106 | // private |
---|
1107 | fitColumns : function(preventRefresh, onlyExpand, omitColumn){ |
---|
1108 | var cm = this.cm, i; |
---|
1109 | var tw = cm.getTotalWidth(false); |
---|
1110 | var aw = this.grid.getGridEl().getWidth(true)-this.scrollOffset; |
---|
1111 | |
---|
1112 | if(aw < 20){ // not initialized, so don't screw up the default widths |
---|
1113 | return; |
---|
1114 | } |
---|
1115 | var extra = aw - tw; |
---|
1116 | |
---|
1117 | if(extra === 0){ |
---|
1118 | return false; |
---|
1119 | } |
---|
1120 | |
---|
1121 | var vc = cm.getColumnCount(true); |
---|
1122 | var ac = vc-(typeof omitColumn == 'number' ? 1 : 0); |
---|
1123 | if(ac === 0){ |
---|
1124 | ac = 1; |
---|
1125 | omitColumn = undefined; |
---|
1126 | } |
---|
1127 | var colCount = cm.getColumnCount(); |
---|
1128 | var cols = []; |
---|
1129 | var extraCol = 0; |
---|
1130 | var width = 0; |
---|
1131 | var w; |
---|
1132 | for (i = 0; i < colCount; i++){ |
---|
1133 | if(!cm.isHidden(i) && !cm.isFixed(i) && i !== omitColumn){ |
---|
1134 | w = cm.getColumnWidth(i); |
---|
1135 | cols.push(i); |
---|
1136 | extraCol = i; |
---|
1137 | cols.push(w); |
---|
1138 | width += w; |
---|
1139 | } |
---|
1140 | } |
---|
1141 | var frac = (aw - cm.getTotalWidth())/width; |
---|
1142 | while (cols.length){ |
---|
1143 | w = cols.pop(); |
---|
1144 | i = cols.pop(); |
---|
1145 | cm.setColumnWidth(i, Math.max(this.grid.minColumnWidth, Math.floor(w + w*frac)), true); |
---|
1146 | } |
---|
1147 | |
---|
1148 | if((tw = cm.getTotalWidth(false)) > aw){ |
---|
1149 | var adjustCol = ac != vc ? omitColumn : extraCol; |
---|
1150 | cm.setColumnWidth(adjustCol, Math.max(1, |
---|
1151 | cm.getColumnWidth(adjustCol)- (tw-aw)), true); |
---|
1152 | } |
---|
1153 | |
---|
1154 | if(preventRefresh !== true){ |
---|
1155 | this.updateAllColumnWidths(); |
---|
1156 | } |
---|
1157 | |
---|
1158 | |
---|
1159 | return true; |
---|
1160 | }, |
---|
1161 | |
---|
1162 | // private |
---|
1163 | autoExpand : function(preventUpdate){ |
---|
1164 | var g = this.grid, cm = this.cm; |
---|
1165 | if(!this.userResized && g.autoExpandColumn){ |
---|
1166 | var tw = cm.getTotalWidth(false); |
---|
1167 | var aw = this.grid.getGridEl().getWidth(true)-this.scrollOffset; |
---|
1168 | if(tw != aw){ |
---|
1169 | var ci = cm.getIndexById(g.autoExpandColumn); |
---|
1170 | var currentWidth = cm.getColumnWidth(ci); |
---|
1171 | var cw = Math.min(Math.max(((aw-tw)+currentWidth), g.autoExpandMin), g.autoExpandMax); |
---|
1172 | if(cw != currentWidth){ |
---|
1173 | cm.setColumnWidth(ci, cw, true); |
---|
1174 | if(preventUpdate !== true){ |
---|
1175 | this.updateColumnWidth(ci, cw); |
---|
1176 | } |
---|
1177 | } |
---|
1178 | } |
---|
1179 | } |
---|
1180 | }, |
---|
1181 | |
---|
1182 | // private |
---|
1183 | getColumnData : function(){ |
---|
1184 | // build a map for all the columns |
---|
1185 | var cs = [], cm = this.cm, colCount = cm.getColumnCount(); |
---|
1186 | for(var i = 0; i < colCount; i++){ |
---|
1187 | var name = cm.getDataIndex(i); |
---|
1188 | cs[i] = { |
---|
1189 | name : (typeof name == 'undefined' ? this.ds.fields.get(i).name : name), |
---|
1190 | renderer : cm.getRenderer(i), |
---|
1191 | id : cm.getColumnId(i), |
---|
1192 | style : this.getColumnStyle(i) |
---|
1193 | }; |
---|
1194 | } |
---|
1195 | return cs; |
---|
1196 | }, |
---|
1197 | |
---|
1198 | // private |
---|
1199 | renderRows : function(startRow, endRow){ |
---|
1200 | // pull in all the crap needed to render rows |
---|
1201 | var g = this.grid, cm = g.colModel, ds = g.store, stripe = g.stripeRows; |
---|
1202 | var colCount = cm.getColumnCount(); |
---|
1203 | |
---|
1204 | if(ds.getCount() < 1){ |
---|
1205 | return ""; |
---|
1206 | } |
---|
1207 | |
---|
1208 | var cs = this.getColumnData(); |
---|
1209 | |
---|
1210 | startRow = startRow || 0; |
---|
1211 | endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow; |
---|
1212 | |
---|
1213 | // records to render |
---|
1214 | var rs = ds.getRange(startRow, endRow); |
---|
1215 | |
---|
1216 | return this.doRender(cs, rs, ds, startRow, colCount, stripe); |
---|
1217 | }, |
---|
1218 | |
---|
1219 | // private |
---|
1220 | renderBody : function(){ |
---|
1221 | var markup = this.renderRows() || ' '; |
---|
1222 | return this.templates.body.apply({rows: markup}); |
---|
1223 | }, |
---|
1224 | |
---|
1225 | // private |
---|
1226 | refreshRow : function(record){ |
---|
1227 | var ds = this.ds, index; |
---|
1228 | if(typeof record == 'number'){ |
---|
1229 | index = record; |
---|
1230 | record = ds.getAt(index); |
---|
1231 | if(!record){ |
---|
1232 | return; |
---|
1233 | } |
---|
1234 | }else{ |
---|
1235 | index = ds.indexOf(record); |
---|
1236 | if(index < 0){ |
---|
1237 | return; |
---|
1238 | } |
---|
1239 | } |
---|
1240 | this.insertRows(ds, index, index, true); |
---|
1241 | this.getRow(index).rowIndex = index; |
---|
1242 | this.onRemove(ds, record, index+1, true); |
---|
1243 | this.fireEvent("rowupdated", this, index, record); |
---|
1244 | }, |
---|
1245 | |
---|
1246 | /** |
---|
1247 | * Refreshs the grid UI |
---|
1248 | * @param {Boolean} headersToo (optional) True to also refresh the headers |
---|
1249 | */ |
---|
1250 | refresh : function(headersToo){ |
---|
1251 | this.fireEvent("beforerefresh", this); |
---|
1252 | this.grid.stopEditing(true); |
---|
1253 | |
---|
1254 | var result = this.renderBody(); |
---|
1255 | this.mainBody.update(result).setWidth(this.getTotalWidth()); |
---|
1256 | if(headersToo === true){ |
---|
1257 | this.updateHeaders(); |
---|
1258 | this.updateHeaderSortState(); |
---|
1259 | } |
---|
1260 | this.processRows(0, true); |
---|
1261 | this.layout(); |
---|
1262 | this.applyEmptyText(); |
---|
1263 | this.fireEvent("refresh", this); |
---|
1264 | }, |
---|
1265 | |
---|
1266 | // private |
---|
1267 | applyEmptyText : function(){ |
---|
1268 | if(this.emptyText && !this.hasRows()){ |
---|
1269 | this.mainBody.update('<div class="x-grid-empty">' + this.emptyText + '</div>'); |
---|
1270 | } |
---|
1271 | }, |
---|
1272 | |
---|
1273 | // private |
---|
1274 | updateHeaderSortState : function(){ |
---|
1275 | var state = this.ds.getSortState(); |
---|
1276 | if(!state){ |
---|
1277 | return; |
---|
1278 | } |
---|
1279 | if(!this.sortState || (this.sortState.field != state.field || this.sortState.direction != state.direction)){ |
---|
1280 | this.grid.fireEvent('sortchange', this.grid, state); |
---|
1281 | } |
---|
1282 | this.sortState = state; |
---|
1283 | var sortColumn = this.cm.findColumnIndex(state.field); |
---|
1284 | if(sortColumn != -1){ |
---|
1285 | var sortDir = state.direction; |
---|
1286 | this.updateSortIcon(sortColumn, sortDir); |
---|
1287 | } |
---|
1288 | }, |
---|
1289 | |
---|
1290 | // private |
---|
1291 | destroy : function(){ |
---|
1292 | if(this.colMenu){ |
---|
1293 | Ext.menu.MenuMgr.unregister(this.colMenu); |
---|
1294 | this.colMenu.destroy(); |
---|
1295 | delete this.colMenu; |
---|
1296 | } |
---|
1297 | if(this.hmenu){ |
---|
1298 | Ext.menu.MenuMgr.unregister(this.hmenu); |
---|
1299 | this.hmenu.destroy(); |
---|
1300 | delete this.hmenu; |
---|
1301 | } |
---|
1302 | if(this.grid.enableColumnMove){ |
---|
1303 | var dds = Ext.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id]; |
---|
1304 | if(dds){ |
---|
1305 | for(var dd in dds){ |
---|
1306 | if(!dds[dd].config.isTarget && dds[dd].dragElId){ |
---|
1307 | var elid = dds[dd].dragElId; |
---|
1308 | dds[dd].unreg(); |
---|
1309 | Ext.get(elid).remove(); |
---|
1310 | } else if(dds[dd].config.isTarget){ |
---|
1311 | dds[dd].proxyTop.remove(); |
---|
1312 | dds[dd].proxyBottom.remove(); |
---|
1313 | dds[dd].unreg(); |
---|
1314 | } |
---|
1315 | if(Ext.dd.DDM.locationCache[dd]){ |
---|
1316 | delete Ext.dd.DDM.locationCache[dd]; |
---|
1317 | } |
---|
1318 | } |
---|
1319 | delete Ext.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id]; |
---|
1320 | } |
---|
1321 | } |
---|
1322 | |
---|
1323 | if(this.dragZone){ |
---|
1324 | this.dragZone.unreg(); |
---|
1325 | } |
---|
1326 | |
---|
1327 | Ext.fly(this.innerHd).removeAllListeners(); |
---|
1328 | Ext.removeNode(this.innerHd); |
---|
1329 | |
---|
1330 | Ext.destroy(this.resizeMarker, this.resizeProxy, this.focusEl, this.mainBody, |
---|
1331 | this.scroller, this.mainHd, this.mainWrap, this.dragZone, |
---|
1332 | this.splitZone, this.columnDrag, this.columnDrop); |
---|
1333 | |
---|
1334 | this.initData(null, null); |
---|
1335 | Ext.EventManager.removeResizeListener(this.onWindowResize, this); |
---|
1336 | this.purgeListeners(); |
---|
1337 | }, |
---|
1338 | |
---|
1339 | // private |
---|
1340 | onDenyColumnHide : function(){ |
---|
1341 | |
---|
1342 | }, |
---|
1343 | |
---|
1344 | // private |
---|
1345 | render : function(){ |
---|
1346 | if(this.autoFill){ |
---|
1347 | var ct = this.grid.ownerCt; |
---|
1348 | if (ct && ct.getLayout()){ |
---|
1349 | ct.on('afterlayout', function(){ |
---|
1350 | this.fitColumns(true, true); |
---|
1351 | this.updateHeaders(); |
---|
1352 | }, this, {single: true}); |
---|
1353 | }else{ |
---|
1354 | this.fitColumns(true, true); |
---|
1355 | } |
---|
1356 | }else if(this.forceFit){ |
---|
1357 | this.fitColumns(true, false); |
---|
1358 | }else if(this.grid.autoExpandColumn){ |
---|
1359 | this.autoExpand(true); |
---|
1360 | } |
---|
1361 | |
---|
1362 | this.renderUI(); |
---|
1363 | }, |
---|
1364 | |
---|
1365 | /* --------------------------------- Model Events and Handlers --------------------------------*/ |
---|
1366 | // private |
---|
1367 | initData : function(ds, cm){ |
---|
1368 | if(this.ds){ |
---|
1369 | this.ds.un("load", this.onLoad, this); |
---|
1370 | this.ds.un("datachanged", this.onDataChange, this); |
---|
1371 | this.ds.un("add", this.onAdd, this); |
---|
1372 | this.ds.un("remove", this.onRemove, this); |
---|
1373 | this.ds.un("update", this.onUpdate, this); |
---|
1374 | this.ds.un("clear", this.onClear, this); |
---|
1375 | if(this.ds !== ds && this.ds.autoDestroy){ |
---|
1376 | this.ds.destroy(); |
---|
1377 | } |
---|
1378 | } |
---|
1379 | if(ds){ |
---|
1380 | ds.on({ |
---|
1381 | scope: this, |
---|
1382 | load: this.onLoad, |
---|
1383 | datachanged: this.onDataChange, |
---|
1384 | add: this.onAdd, |
---|
1385 | remove: this.onRemove, |
---|
1386 | update: this.onUpdate, |
---|
1387 | clear: this.onClear |
---|
1388 | }); |
---|
1389 | } |
---|
1390 | this.ds = ds; |
---|
1391 | |
---|
1392 | if(this.cm){ |
---|
1393 | this.cm.un("configchange", this.onColConfigChange, this); |
---|
1394 | this.cm.un("widthchange", this.onColWidthChange, this); |
---|
1395 | this.cm.un("headerchange", this.onHeaderChange, this); |
---|
1396 | this.cm.un("hiddenchange", this.onHiddenChange, this); |
---|
1397 | this.cm.un("columnmoved", this.onColumnMove, this); |
---|
1398 | } |
---|
1399 | if(cm){ |
---|
1400 | delete this.lastViewWidth; |
---|
1401 | cm.on({ |
---|
1402 | scope: this, |
---|
1403 | configchange: this.onColConfigChange, |
---|
1404 | widthchange: this.onColWidthChange, |
---|
1405 | headerchange: this.onHeaderChange, |
---|
1406 | hiddenchange: this.onHiddenChange, |
---|
1407 | columnmoved: this.onColumnMove |
---|
1408 | }); |
---|
1409 | } |
---|
1410 | this.cm = cm; |
---|
1411 | }, |
---|
1412 | |
---|
1413 | // private |
---|
1414 | onDataChange : function(){ |
---|
1415 | this.refresh(); |
---|
1416 | this.updateHeaderSortState(); |
---|
1417 | this.syncFocusEl(0); |
---|
1418 | }, |
---|
1419 | |
---|
1420 | // private |
---|
1421 | onClear : function(){ |
---|
1422 | this.refresh(); |
---|
1423 | this.syncFocusEl(0); |
---|
1424 | }, |
---|
1425 | |
---|
1426 | // private |
---|
1427 | onUpdate : function(ds, record){ |
---|
1428 | this.refreshRow(record); |
---|
1429 | }, |
---|
1430 | |
---|
1431 | // private |
---|
1432 | onAdd : function(ds, records, index){ |
---|
1433 | this.insertRows(ds, index, index + (records.length-1)); |
---|
1434 | }, |
---|
1435 | |
---|
1436 | // private |
---|
1437 | onRemove : function(ds, record, index, isUpdate){ |
---|
1438 | if(isUpdate !== true){ |
---|
1439 | this.fireEvent("beforerowremoved", this, index, record); |
---|
1440 | } |
---|
1441 | this.removeRow(index); |
---|
1442 | if(isUpdate !== true){ |
---|
1443 | this.processRows(index); |
---|
1444 | this.applyEmptyText(); |
---|
1445 | this.fireEvent("rowremoved", this, index, record); |
---|
1446 | } |
---|
1447 | }, |
---|
1448 | |
---|
1449 | // private |
---|
1450 | onLoad : function(){ |
---|
1451 | this.scrollToTop(); |
---|
1452 | }, |
---|
1453 | |
---|
1454 | // private |
---|
1455 | onColWidthChange : function(cm, col, width){ |
---|
1456 | this.updateColumnWidth(col, width); |
---|
1457 | }, |
---|
1458 | |
---|
1459 | // private |
---|
1460 | onHeaderChange : function(cm, col, text){ |
---|
1461 | this.updateHeaders(); |
---|
1462 | }, |
---|
1463 | |
---|
1464 | // private |
---|
1465 | onHiddenChange : function(cm, col, hidden){ |
---|
1466 | this.updateColumnHidden(col, hidden); |
---|
1467 | }, |
---|
1468 | |
---|
1469 | // private |
---|
1470 | onColumnMove : function(cm, oldIndex, newIndex){ |
---|
1471 | this.indexMap = null; |
---|
1472 | var s = this.getScrollState(); |
---|
1473 | this.refresh(true); |
---|
1474 | this.restoreScroll(s); |
---|
1475 | this.afterMove(newIndex); |
---|
1476 | this.grid.fireEvent('columnmove', oldIndex, newIndex); |
---|
1477 | }, |
---|
1478 | |
---|
1479 | // private |
---|
1480 | onColConfigChange : function(){ |
---|
1481 | delete this.lastViewWidth; |
---|
1482 | this.indexMap = null; |
---|
1483 | this.refresh(true); |
---|
1484 | }, |
---|
1485 | |
---|
1486 | /* -------------------- UI Events and Handlers ------------------------------ */ |
---|
1487 | // private |
---|
1488 | initUI : function(grid){ |
---|
1489 | grid.on("headerclick", this.onHeaderClick, this); |
---|
1490 | }, |
---|
1491 | |
---|
1492 | // private |
---|
1493 | initEvents : function(){ |
---|
1494 | }, |
---|
1495 | |
---|
1496 | // private |
---|
1497 | onHeaderClick : function(g, index){ |
---|
1498 | if(this.headersDisabled || !this.cm.isSortable(index)){ |
---|
1499 | return; |
---|
1500 | } |
---|
1501 | g.stopEditing(true); |
---|
1502 | g.store.sort(this.cm.getDataIndex(index)); |
---|
1503 | }, |
---|
1504 | |
---|
1505 | // private |
---|
1506 | onRowOver : function(e, t){ |
---|
1507 | var row; |
---|
1508 | if((row = this.findRowIndex(t)) !== false){ |
---|
1509 | this.addRowClass(row, "x-grid3-row-over"); |
---|
1510 | } |
---|
1511 | }, |
---|
1512 | |
---|
1513 | // private |
---|
1514 | onRowOut : function(e, t){ |
---|
1515 | var row; |
---|
1516 | if((row = this.findRowIndex(t)) !== false && !e.within(this.getRow(row), true)){ |
---|
1517 | this.removeRowClass(row, "x-grid3-row-over"); |
---|
1518 | } |
---|
1519 | }, |
---|
1520 | |
---|
1521 | // private |
---|
1522 | handleWheel : function(e){ |
---|
1523 | e.stopPropagation(); |
---|
1524 | }, |
---|
1525 | |
---|
1526 | // private |
---|
1527 | onRowSelect : function(row){ |
---|
1528 | this.addRowClass(row, this.selectedRowClass); |
---|
1529 | }, |
---|
1530 | |
---|
1531 | // private |
---|
1532 | onRowDeselect : function(row){ |
---|
1533 | this.removeRowClass(row, this.selectedRowClass); |
---|
1534 | }, |
---|
1535 | |
---|
1536 | // private |
---|
1537 | onCellSelect : function(row, col){ |
---|
1538 | var cell = this.getCell(row, col); |
---|
1539 | if(cell){ |
---|
1540 | this.fly(cell).addClass("x-grid3-cell-selected"); |
---|
1541 | } |
---|
1542 | }, |
---|
1543 | |
---|
1544 | // private |
---|
1545 | onCellDeselect : function(row, col){ |
---|
1546 | var cell = this.getCell(row, col); |
---|
1547 | if(cell){ |
---|
1548 | this.fly(cell).removeClass("x-grid3-cell-selected"); |
---|
1549 | } |
---|
1550 | }, |
---|
1551 | |
---|
1552 | // private |
---|
1553 | onColumnSplitterMoved : function(i, w){ |
---|
1554 | this.userResized = true; |
---|
1555 | var cm = this.grid.colModel; |
---|
1556 | cm.setColumnWidth(i, w, true); |
---|
1557 | |
---|
1558 | if(this.forceFit){ |
---|
1559 | this.fitColumns(true, false, i); |
---|
1560 | this.updateAllColumnWidths(); |
---|
1561 | }else{ |
---|
1562 | this.updateColumnWidth(i, w); |
---|
1563 | this.syncHeaderScroll(); |
---|
1564 | } |
---|
1565 | |
---|
1566 | this.grid.fireEvent("columnresize", i, w); |
---|
1567 | }, |
---|
1568 | |
---|
1569 | // private |
---|
1570 | handleHdMenuClick : function(item){ |
---|
1571 | var index = this.hdCtxIndex; |
---|
1572 | var cm = this.cm, ds = this.ds; |
---|
1573 | switch(item.itemId){ |
---|
1574 | case "asc": |
---|
1575 | ds.sort(cm.getDataIndex(index), "ASC"); |
---|
1576 | break; |
---|
1577 | case "desc": |
---|
1578 | ds.sort(cm.getDataIndex(index), "DESC"); |
---|
1579 | break; |
---|
1580 | default: |
---|
1581 | index = cm.getIndexById(item.itemId.substr(4)); |
---|
1582 | if(index != -1){ |
---|
1583 | if(item.checked && cm.getColumnsBy(this.isHideableColumn, this).length <= 1){ |
---|
1584 | this.onDenyColumnHide(); |
---|
1585 | return false; |
---|
1586 | } |
---|
1587 | cm.setHidden(index, item.checked); |
---|
1588 | } |
---|
1589 | } |
---|
1590 | return true; |
---|
1591 | }, |
---|
1592 | |
---|
1593 | // private |
---|
1594 | isHideableColumn : function(c){ |
---|
1595 | return !c.hidden && !c.fixed; |
---|
1596 | }, |
---|
1597 | |
---|
1598 | // private |
---|
1599 | beforeColMenuShow : function(){ |
---|
1600 | var cm = this.cm, colCount = cm.getColumnCount(); |
---|
1601 | this.colMenu.removeAll(); |
---|
1602 | for(var i = 0; i < colCount; i++){ |
---|
1603 | if(cm.config[i].fixed !== true && cm.config[i].hideable !== false){ |
---|
1604 | this.colMenu.add(new Ext.menu.CheckItem({ |
---|
1605 | itemId: "col-"+cm.getColumnId(i), |
---|
1606 | text: cm.getColumnHeader(i), |
---|
1607 | checked: !cm.isHidden(i), |
---|
1608 | hideOnClick:false, |
---|
1609 | disabled: cm.config[i].hideable === false |
---|
1610 | })); |
---|
1611 | } |
---|
1612 | } |
---|
1613 | }, |
---|
1614 | |
---|
1615 | // private |
---|
1616 | handleHdDown : function(e, t){ |
---|
1617 | if(Ext.fly(t).hasClass('x-grid3-hd-btn')){ |
---|
1618 | e.stopEvent(); |
---|
1619 | var hd = this.findHeaderCell(t); |
---|
1620 | Ext.fly(hd).addClass('x-grid3-hd-menu-open'); |
---|
1621 | var index = this.getCellIndex(hd); |
---|
1622 | this.hdCtxIndex = index; |
---|
1623 | var ms = this.hmenu.items, cm = this.cm; |
---|
1624 | ms.get("asc").setDisabled(!cm.isSortable(index)); |
---|
1625 | ms.get("desc").setDisabled(!cm.isSortable(index)); |
---|
1626 | this.hmenu.on("hide", function(){ |
---|
1627 | Ext.fly(hd).removeClass('x-grid3-hd-menu-open'); |
---|
1628 | }, this, {single:true}); |
---|
1629 | this.hmenu.show(t, "tl-bl?"); |
---|
1630 | } |
---|
1631 | }, |
---|
1632 | |
---|
1633 | // private |
---|
1634 | handleHdOver : function(e, t){ |
---|
1635 | var hd = this.findHeaderCell(t); |
---|
1636 | if(hd && !this.headersDisabled){ |
---|
1637 | this.activeHd = hd; |
---|
1638 | this.activeHdIndex = this.getCellIndex(hd); |
---|
1639 | var fly = this.fly(hd); |
---|
1640 | this.activeHdRegion = fly.getRegion(); |
---|
1641 | if(!this.cm.isMenuDisabled(this.activeHdIndex)){ |
---|
1642 | fly.addClass("x-grid3-hd-over"); |
---|
1643 | this.activeHdBtn = fly.child('.x-grid3-hd-btn'); |
---|
1644 | if(this.activeHdBtn){ |
---|
1645 | this.activeHdBtn.dom.style.height = (hd.firstChild.offsetHeight-1)+'px'; |
---|
1646 | } |
---|
1647 | } |
---|
1648 | } |
---|
1649 | }, |
---|
1650 | |
---|
1651 | // private |
---|
1652 | handleHdMove : function(e, t){ |
---|
1653 | if(this.activeHd && !this.headersDisabled){ |
---|
1654 | var hw = this.splitHandleWidth || 5; |
---|
1655 | var r = this.activeHdRegion; |
---|
1656 | var x = e.getPageX(); |
---|
1657 | var ss = this.activeHd.style; |
---|
1658 | if(x - r.left <= hw && this.cm.isResizable(this.activeHdIndex-1)){ |
---|
1659 | ss.cursor = Ext.isAir ? 'move' : Ext.isWebKit ? 'e-resize' : 'col-resize'; // col-resize not always supported |
---|
1660 | }else if(r.right - x <= (!this.activeHdBtn ? hw : 2) && this.cm.isResizable(this.activeHdIndex)){ |
---|
1661 | ss.cursor = Ext.isAir ? 'move' : Ext.isWebKit ? 'w-resize' : 'col-resize'; |
---|
1662 | }else{ |
---|
1663 | ss.cursor = ''; |
---|
1664 | } |
---|
1665 | } |
---|
1666 | }, |
---|
1667 | |
---|
1668 | // private |
---|
1669 | handleHdOut : function(e, t){ |
---|
1670 | var hd = this.findHeaderCell(t); |
---|
1671 | if(hd && (!Ext.isIE || !e.within(hd, true))){ |
---|
1672 | this.activeHd = null; |
---|
1673 | this.fly(hd).removeClass("x-grid3-hd-over"); |
---|
1674 | hd.style.cursor = ''; |
---|
1675 | } |
---|
1676 | }, |
---|
1677 | |
---|
1678 | // private |
---|
1679 | hasRows : function(){ |
---|
1680 | var fc = this.mainBody.dom.firstChild; |
---|
1681 | return fc && fc.nodeType == 1 && fc.className != 'x-grid-empty'; |
---|
1682 | }, |
---|
1683 | |
---|
1684 | // back compat |
---|
1685 | bind : function(d, c){ |
---|
1686 | this.initData(d, c); |
---|
1687 | } |
---|
1688 | }); |
---|
1689 | |
---|
1690 | |
---|
1691 | // private |
---|
1692 | // This is a support class used internally by the Grid components |
---|
1693 | Ext.grid.GridView.SplitDragZone = function(grid, hd){ |
---|
1694 | this.grid = grid; |
---|
1695 | this.view = grid.getView(); |
---|
1696 | this.marker = this.view.resizeMarker; |
---|
1697 | this.proxy = this.view.resizeProxy; |
---|
1698 | Ext.grid.GridView.SplitDragZone.superclass.constructor.call(this, hd, |
---|
1699 | "gridSplitters" + this.grid.getGridEl().id, { |
---|
1700 | dragElId : Ext.id(this.proxy.dom), resizeFrame:false |
---|
1701 | }); |
---|
1702 | this.scroll = false; |
---|
1703 | this.hw = this.view.splitHandleWidth || 5; |
---|
1704 | }; |
---|
1705 | Ext.extend(Ext.grid.GridView.SplitDragZone, Ext.dd.DDProxy, { |
---|
1706 | |
---|
1707 | b4StartDrag : function(x, y){ |
---|
1708 | this.view.headersDisabled = true; |
---|
1709 | var h = this.view.mainWrap.getHeight(); |
---|
1710 | this.marker.setHeight(h); |
---|
1711 | this.marker.show(); |
---|
1712 | this.marker.alignTo(this.view.getHeaderCell(this.cellIndex), 'tl-tl', [-2, 0]); |
---|
1713 | this.proxy.setHeight(h); |
---|
1714 | var w = this.cm.getColumnWidth(this.cellIndex); |
---|
1715 | var minw = Math.max(w-this.grid.minColumnWidth, 0); |
---|
1716 | this.resetConstraints(); |
---|
1717 | this.setXConstraint(minw, 1000); |
---|
1718 | this.setYConstraint(0, 0); |
---|
1719 | this.minX = x - minw; |
---|
1720 | this.maxX = x + 1000; |
---|
1721 | this.startPos = x; |
---|
1722 | Ext.dd.DDProxy.prototype.b4StartDrag.call(this, x, y); |
---|
1723 | }, |
---|
1724 | |
---|
1725 | |
---|
1726 | handleMouseDown : function(e){ |
---|
1727 | var t = this.view.findHeaderCell(e.getTarget()); |
---|
1728 | if(t){ |
---|
1729 | var xy = this.view.fly(t).getXY(), x = xy[0], y = xy[1]; |
---|
1730 | var exy = e.getXY(), ex = exy[0]; |
---|
1731 | var w = t.offsetWidth, adjust = false; |
---|
1732 | if((ex - x) <= this.hw){ |
---|
1733 | adjust = -1; |
---|
1734 | }else if((x+w) - ex <= this.hw){ |
---|
1735 | adjust = 0; |
---|
1736 | } |
---|
1737 | if(adjust !== false){ |
---|
1738 | this.cm = this.grid.colModel; |
---|
1739 | var ci = this.view.getCellIndex(t); |
---|
1740 | if(adjust == -1){ |
---|
1741 | if (ci + adjust < 0) { |
---|
1742 | return; |
---|
1743 | } |
---|
1744 | while(this.cm.isHidden(ci+adjust)){ |
---|
1745 | --adjust; |
---|
1746 | if(ci+adjust < 0){ |
---|
1747 | return; |
---|
1748 | } |
---|
1749 | } |
---|
1750 | } |
---|
1751 | this.cellIndex = ci+adjust; |
---|
1752 | this.split = t.dom; |
---|
1753 | if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){ |
---|
1754 | Ext.grid.GridView.SplitDragZone.superclass.handleMouseDown.apply(this, arguments); |
---|
1755 | } |
---|
1756 | }else if(this.view.columnDrag){ |
---|
1757 | this.view.columnDrag.callHandleMouseDown(e); |
---|
1758 | } |
---|
1759 | } |
---|
1760 | }, |
---|
1761 | |
---|
1762 | endDrag : function(e){ |
---|
1763 | this.marker.hide(); |
---|
1764 | var v = this.view; |
---|
1765 | var endX = Math.max(this.minX, e.getPageX()); |
---|
1766 | var diff = endX - this.startPos; |
---|
1767 | v.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff); |
---|
1768 | setTimeout(function(){ |
---|
1769 | v.headersDisabled = false; |
---|
1770 | }, 50); |
---|
1771 | }, |
---|
1772 | |
---|
1773 | autoOffset : function(){ |
---|
1774 | this.setDelta(0,0); |
---|
1775 | } |
---|
1776 | }); |
---|