1 | /*! |
---|
2 | * Ext JS Library 3.4.0 |
---|
3 | * Copyright(c) 2006-2011 Sencha Inc. |
---|
4 | * licensing@sencha.com |
---|
5 | * http://www.sencha.com/license |
---|
6 | */ |
---|
7 | /** |
---|
8 | * @class Ext.grid.GroupingView |
---|
9 | * @extends Ext.grid.GridView |
---|
10 | * Adds the ability for single level grouping to the grid. A {@link Ext.data.GroupingStore GroupingStore} |
---|
11 | * must be used to enable grouping. Some grouping characteristics may also be configured at the |
---|
12 | * {@link Ext.grid.Column Column level}<div class="mdetail-params"><ul> |
---|
13 | * <li><code>{@link Ext.grid.Column#emptyGroupText emptyGroupText}</code></li> |
---|
14 | * <li><code>{@link Ext.grid.Column#groupable groupable}</code></li> |
---|
15 | * <li><code>{@link Ext.grid.Column#groupName groupName}</code></li> |
---|
16 | * <li><code>{@link Ext.grid.Column#groupRender groupRender}</code></li> |
---|
17 | * </ul></div> |
---|
18 | * <p>Sample usage:</p> |
---|
19 | * <pre><code> |
---|
20 | var grid = new Ext.grid.GridPanel({ |
---|
21 | // A groupingStore is required for a GroupingView |
---|
22 | store: new {@link Ext.data.GroupingStore}({ |
---|
23 | autoDestroy: true, |
---|
24 | reader: reader, |
---|
25 | data: xg.dummyData, |
---|
26 | sortInfo: {field: 'company', direction: 'ASC'}, |
---|
27 | {@link Ext.data.GroupingStore#groupOnSort groupOnSort}: true, |
---|
28 | {@link Ext.data.GroupingStore#remoteGroup remoteGroup}: true, |
---|
29 | {@link Ext.data.GroupingStore#groupField groupField}: 'industry' |
---|
30 | }), |
---|
31 | colModel: new {@link Ext.grid.ColumnModel}({ |
---|
32 | columns:[ |
---|
33 | {id:'company',header: 'Company', width: 60, dataIndex: 'company'}, |
---|
34 | // {@link Ext.grid.Column#groupable groupable}, {@link Ext.grid.Column#groupName groupName}, {@link Ext.grid.Column#groupRender groupRender} are also configurable at column level |
---|
35 | {header: 'Price', renderer: Ext.util.Format.usMoney, dataIndex: 'price', {@link Ext.grid.Column#groupable groupable}: false}, |
---|
36 | {header: 'Change', dataIndex: 'change', renderer: Ext.util.Format.usMoney}, |
---|
37 | {header: 'Industry', dataIndex: 'industry'}, |
---|
38 | {header: 'Last Updated', renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'} |
---|
39 | ], |
---|
40 | defaults: { |
---|
41 | sortable: true, |
---|
42 | menuDisabled: false, |
---|
43 | width: 20 |
---|
44 | } |
---|
45 | }), |
---|
46 | |
---|
47 | view: new Ext.grid.GroupingView({ |
---|
48 | {@link Ext.grid.GridView#forceFit forceFit}: true, |
---|
49 | // custom grouping text template to display the number of items per group |
---|
50 | {@link #groupTextTpl}: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})' |
---|
51 | }), |
---|
52 | |
---|
53 | frame:true, |
---|
54 | width: 700, |
---|
55 | height: 450, |
---|
56 | collapsible: true, |
---|
57 | animCollapse: false, |
---|
58 | title: 'Grouping Example', |
---|
59 | iconCls: 'icon-grid', |
---|
60 | renderTo: document.body |
---|
61 | }); |
---|
62 | * </code></pre> |
---|
63 | * @constructor |
---|
64 | * @param {Object} config |
---|
65 | */ |
---|
66 | Ext.grid.GroupingView = Ext.extend(Ext.grid.GridView, { |
---|
67 | |
---|
68 | /** |
---|
69 | * @cfg {String} groupByText Text displayed in the grid header menu for grouping by a column |
---|
70 | * (defaults to 'Group By This Field'). |
---|
71 | */ |
---|
72 | groupByText : 'Group By This Field', |
---|
73 | /** |
---|
74 | * @cfg {String} showGroupsText Text displayed in the grid header for enabling/disabling grouping |
---|
75 | * (defaults to 'Show in Groups'). |
---|
76 | */ |
---|
77 | showGroupsText : 'Show in Groups', |
---|
78 | /** |
---|
79 | * @cfg {Boolean} hideGroupedColumn <tt>true</tt> to hide the column that is currently grouped (defaults to <tt>false</tt>) |
---|
80 | */ |
---|
81 | hideGroupedColumn : false, |
---|
82 | /** |
---|
83 | * @cfg {Boolean} showGroupName If <tt>true</tt> will display a prefix plus a ': ' before the group field value |
---|
84 | * in the group header line. The prefix will consist of the <tt><b>{@link Ext.grid.Column#groupName groupName}</b></tt> |
---|
85 | * (or the configured <tt><b>{@link Ext.grid.Column#header header}</b></tt> if not provided) configured in the |
---|
86 | * {@link Ext.grid.Column} for each set of grouped rows (defaults to <tt>true</tt>). |
---|
87 | */ |
---|
88 | showGroupName : true, |
---|
89 | /** |
---|
90 | * @cfg {Boolean} startCollapsed <tt>true</tt> to start all groups collapsed (defaults to <tt>false</tt>) |
---|
91 | */ |
---|
92 | startCollapsed : false, |
---|
93 | /** |
---|
94 | * @cfg {Boolean} enableGrouping <tt>false</tt> to disable grouping functionality (defaults to <tt>true</tt>) |
---|
95 | */ |
---|
96 | enableGrouping : true, |
---|
97 | /** |
---|
98 | * @cfg {Boolean} enableGroupingMenu <tt>true</tt> to enable the grouping control in the column menu (defaults to <tt>true</tt>) |
---|
99 | */ |
---|
100 | enableGroupingMenu : true, |
---|
101 | /** |
---|
102 | * @cfg {Boolean} enableNoGroups <tt>true</tt> to allow the user to turn off grouping (defaults to <tt>true</tt>) |
---|
103 | */ |
---|
104 | enableNoGroups : true, |
---|
105 | /** |
---|
106 | * @cfg {String} emptyGroupText The text to display when there is an empty group value (defaults to <tt>'(None)'</tt>). |
---|
107 | * May also be specified per column, see {@link Ext.grid.Column}.{@link Ext.grid.Column#emptyGroupText emptyGroupText}. |
---|
108 | */ |
---|
109 | emptyGroupText : '(None)', |
---|
110 | /** |
---|
111 | * @cfg {Boolean} ignoreAdd <tt>true</tt> to skip refreshing the view when new rows are added (defaults to <tt>false</tt>) |
---|
112 | */ |
---|
113 | ignoreAdd : false, |
---|
114 | /** |
---|
115 | * @cfg {String} groupTextTpl The template used to render the group header (defaults to <tt>'{text}'</tt>). |
---|
116 | * This is used to format an object which contains the following properties: |
---|
117 | * <div class="mdetail-params"><ul> |
---|
118 | * <li><b>group</b> : String<p class="sub-desc">The <i>rendered</i> value of the group field. |
---|
119 | * By default this is the unchanged value of the group field. If a <tt><b>{@link Ext.grid.Column#groupRenderer groupRenderer}</b></tt> |
---|
120 | * is specified, it is the result of a call to that function.</p></li> |
---|
121 | * <li><b>gvalue</b> : Object<p class="sub-desc">The <i>raw</i> value of the group field.</p></li> |
---|
122 | * <li><b>text</b> : String<p class="sub-desc">The configured header (as described in <tt>{@link #showGroupName})</tt> |
---|
123 | * if <tt>{@link #showGroupName}</tt> is <tt>true</tt>) plus the <i>rendered</i> group field value.</p></li> |
---|
124 | * <li><b>groupId</b> : String<p class="sub-desc">A unique, generated ID which is applied to the |
---|
125 | * View Element which contains the group.</p></li> |
---|
126 | * <li><b>startRow</b> : Number<p class="sub-desc">The row index of the Record which caused group change.</p></li> |
---|
127 | * <li><b>rs</b> : Array<p class="sub-desc">Contains a single element: The Record providing the data |
---|
128 | * for the row which caused group change.</p></li> |
---|
129 | * <li><b>cls</b> : String<p class="sub-desc">The generated class name string to apply to the group header Element.</p></li> |
---|
130 | * <li><b>style</b> : String<p class="sub-desc">The inline style rules to apply to the group header Element.</p></li> |
---|
131 | * </ul></div></p> |
---|
132 | * See {@link Ext.XTemplate} for information on how to format data using a template. Possible usage:<pre><code> |
---|
133 | var grid = new Ext.grid.GridPanel({ |
---|
134 | ... |
---|
135 | view: new Ext.grid.GroupingView({ |
---|
136 | groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})' |
---|
137 | }), |
---|
138 | }); |
---|
139 | * </code></pre> |
---|
140 | */ |
---|
141 | groupTextTpl : '{text}', |
---|
142 | |
---|
143 | /** |
---|
144 | * @cfg {String} groupMode Indicates how to construct the group identifier. <tt>'value'</tt> constructs the id using |
---|
145 | * raw value, <tt>'display'</tt> constructs the id using the rendered value. Defaults to <tt>'value'</tt>. |
---|
146 | */ |
---|
147 | groupMode: 'value', |
---|
148 | |
---|
149 | /** |
---|
150 | * @cfg {Function} groupRenderer This property must be configured in the {@link Ext.grid.Column} for |
---|
151 | * each column. |
---|
152 | */ |
---|
153 | |
---|
154 | /** |
---|
155 | * @cfg {Boolean} cancelEditOnToggle True to cancel any editing when the group header is toggled. Defaults to <tt>true</tt>. |
---|
156 | */ |
---|
157 | cancelEditOnToggle: true, |
---|
158 | |
---|
159 | // private |
---|
160 | initTemplates : function(){ |
---|
161 | Ext.grid.GroupingView.superclass.initTemplates.call(this); |
---|
162 | this.state = {}; |
---|
163 | |
---|
164 | var sm = this.grid.getSelectionModel(); |
---|
165 | sm.on(sm.selectRow ? 'beforerowselect' : 'beforecellselect', |
---|
166 | this.onBeforeRowSelect, this); |
---|
167 | |
---|
168 | if(!this.startGroup){ |
---|
169 | this.startGroup = new Ext.XTemplate( |
---|
170 | '<div id="{groupId}" class="x-grid-group {cls}">', |
---|
171 | '<div id="{groupId}-hd" class="x-grid-group-hd" style="{style}"><div class="x-grid-group-title">', this.groupTextTpl ,'</div></div>', |
---|
172 | '<div id="{groupId}-bd" class="x-grid-group-body">' |
---|
173 | ); |
---|
174 | } |
---|
175 | this.startGroup.compile(); |
---|
176 | |
---|
177 | if (!this.endGroup) { |
---|
178 | this.endGroup = '</div></div>'; |
---|
179 | } |
---|
180 | }, |
---|
181 | |
---|
182 | // private |
---|
183 | findGroup : function(el){ |
---|
184 | return Ext.fly(el).up('.x-grid-group', this.mainBody.dom); |
---|
185 | }, |
---|
186 | |
---|
187 | // private |
---|
188 | getGroups : function(){ |
---|
189 | return this.hasRows() ? this.mainBody.dom.childNodes : []; |
---|
190 | }, |
---|
191 | |
---|
192 | // private |
---|
193 | onAdd : function(ds, records, index) { |
---|
194 | if (this.canGroup() && !this.ignoreAdd) { |
---|
195 | var ss = this.getScrollState(); |
---|
196 | this.fireEvent('beforerowsinserted', ds, index, index + (records.length-1)); |
---|
197 | this.refresh(); |
---|
198 | this.restoreScroll(ss); |
---|
199 | this.fireEvent('rowsinserted', ds, index, index + (records.length-1)); |
---|
200 | } else if (!this.canGroup()) { |
---|
201 | Ext.grid.GroupingView.superclass.onAdd.apply(this, arguments); |
---|
202 | } |
---|
203 | }, |
---|
204 | |
---|
205 | // private |
---|
206 | onRemove : function(ds, record, index, isUpdate){ |
---|
207 | Ext.grid.GroupingView.superclass.onRemove.apply(this, arguments); |
---|
208 | var g = document.getElementById(record._groupId); |
---|
209 | if(g && g.childNodes[1].childNodes.length < 1){ |
---|
210 | Ext.removeNode(g); |
---|
211 | } |
---|
212 | this.applyEmptyText(); |
---|
213 | }, |
---|
214 | |
---|
215 | // private |
---|
216 | refreshRow : function(record){ |
---|
217 | if(this.ds.getCount()==1){ |
---|
218 | this.refresh(); |
---|
219 | }else{ |
---|
220 | this.isUpdating = true; |
---|
221 | Ext.grid.GroupingView.superclass.refreshRow.apply(this, arguments); |
---|
222 | this.isUpdating = false; |
---|
223 | } |
---|
224 | }, |
---|
225 | |
---|
226 | // private |
---|
227 | beforeMenuShow : function(){ |
---|
228 | var item, items = this.hmenu.items, disabled = this.cm.config[this.hdCtxIndex].groupable === false; |
---|
229 | if((item = items.get('groupBy'))){ |
---|
230 | item.setDisabled(disabled); |
---|
231 | } |
---|
232 | if((item = items.get('showGroups'))){ |
---|
233 | item.setDisabled(disabled); |
---|
234 | item.setChecked(this.canGroup(), true); |
---|
235 | } |
---|
236 | }, |
---|
237 | |
---|
238 | // private |
---|
239 | renderUI : function(){ |
---|
240 | var markup = Ext.grid.GroupingView.superclass.renderUI.call(this); |
---|
241 | |
---|
242 | if(this.enableGroupingMenu && this.hmenu){ |
---|
243 | this.hmenu.add('-',{ |
---|
244 | itemId:'groupBy', |
---|
245 | text: this.groupByText, |
---|
246 | handler: this.onGroupByClick, |
---|
247 | scope: this, |
---|
248 | iconCls:'x-group-by-icon' |
---|
249 | }); |
---|
250 | if(this.enableNoGroups){ |
---|
251 | this.hmenu.add({ |
---|
252 | itemId:'showGroups', |
---|
253 | text: this.showGroupsText, |
---|
254 | checked: true, |
---|
255 | checkHandler: this.onShowGroupsClick, |
---|
256 | scope: this |
---|
257 | }); |
---|
258 | } |
---|
259 | this.hmenu.on('beforeshow', this.beforeMenuShow, this); |
---|
260 | } |
---|
261 | return markup; |
---|
262 | }, |
---|
263 | |
---|
264 | processEvent: function(name, e){ |
---|
265 | Ext.grid.GroupingView.superclass.processEvent.call(this, name, e); |
---|
266 | var hd = e.getTarget('.x-grid-group-hd', this.mainBody); |
---|
267 | if(hd){ |
---|
268 | // group value is at the end of the string |
---|
269 | var field = this.getGroupField(), |
---|
270 | prefix = this.getPrefix(field), |
---|
271 | groupValue = hd.id.substring(prefix.length), |
---|
272 | emptyRe = new RegExp('gp-' + Ext.escapeRe(field) + '--hd'); |
---|
273 | |
---|
274 | // remove trailing '-hd' |
---|
275 | groupValue = groupValue.substr(0, groupValue.length - 3); |
---|
276 | |
---|
277 | // also need to check for empty groups |
---|
278 | if(groupValue || emptyRe.test(hd.id)){ |
---|
279 | this.grid.fireEvent('group' + name, this.grid, field, groupValue, e); |
---|
280 | } |
---|
281 | if(name == 'mousedown' && e.button == 0){ |
---|
282 | this.toggleGroup(hd.parentNode); |
---|
283 | } |
---|
284 | } |
---|
285 | |
---|
286 | }, |
---|
287 | |
---|
288 | // private |
---|
289 | onGroupByClick : function(){ |
---|
290 | var grid = this.grid; |
---|
291 | this.enableGrouping = true; |
---|
292 | grid.store.groupBy(this.cm.getDataIndex(this.hdCtxIndex)); |
---|
293 | grid.fireEvent('groupchange', grid, grid.store.getGroupState()); |
---|
294 | this.beforeMenuShow(); // Make sure the checkboxes get properly set when changing groups |
---|
295 | this.refresh(); |
---|
296 | }, |
---|
297 | |
---|
298 | // private |
---|
299 | onShowGroupsClick : function(mi, checked){ |
---|
300 | this.enableGrouping = checked; |
---|
301 | if(checked){ |
---|
302 | this.onGroupByClick(); |
---|
303 | }else{ |
---|
304 | this.grid.store.clearGrouping(); |
---|
305 | this.grid.fireEvent('groupchange', this, null); |
---|
306 | } |
---|
307 | }, |
---|
308 | |
---|
309 | /** |
---|
310 | * Toggle the group that contains the specific row. |
---|
311 | * @param {Number} rowIndex The row inside the group |
---|
312 | * @param {Boolean} expanded (optional) |
---|
313 | */ |
---|
314 | toggleRowIndex : function(rowIndex, expanded){ |
---|
315 | if(!this.canGroup()){ |
---|
316 | return; |
---|
317 | } |
---|
318 | var row = this.getRow(rowIndex); |
---|
319 | if(row){ |
---|
320 | this.toggleGroup(this.findGroup(row), expanded); |
---|
321 | } |
---|
322 | }, |
---|
323 | |
---|
324 | /** |
---|
325 | * Toggles the specified group if no value is passed, otherwise sets the expanded state of the group to the value passed. |
---|
326 | * @param {String} groupId The groupId assigned to the group (see getGroupId) |
---|
327 | * @param {Boolean} expanded (optional) |
---|
328 | */ |
---|
329 | toggleGroup : function(group, expanded){ |
---|
330 | var gel = Ext.get(group), |
---|
331 | id = Ext.util.Format.htmlEncode(gel.id); |
---|
332 | |
---|
333 | expanded = Ext.isDefined(expanded) ? expanded : gel.hasClass('x-grid-group-collapsed'); |
---|
334 | if(this.state[id] !== expanded){ |
---|
335 | if (this.cancelEditOnToggle !== false) { |
---|
336 | this.grid.stopEditing(true); |
---|
337 | } |
---|
338 | this.state[id] = expanded; |
---|
339 | gel[expanded ? 'removeClass' : 'addClass']('x-grid-group-collapsed'); |
---|
340 | } |
---|
341 | }, |
---|
342 | |
---|
343 | /** |
---|
344 | * Toggles all groups if no value is passed, otherwise sets the expanded state of all groups to the value passed. |
---|
345 | * @param {Boolean} expanded (optional) |
---|
346 | */ |
---|
347 | toggleAllGroups : function(expanded){ |
---|
348 | var groups = this.getGroups(); |
---|
349 | for(var i = 0, len = groups.length; i < len; i++){ |
---|
350 | this.toggleGroup(groups[i], expanded); |
---|
351 | } |
---|
352 | }, |
---|
353 | |
---|
354 | /** |
---|
355 | * Expands all grouped rows. |
---|
356 | */ |
---|
357 | expandAllGroups : function(){ |
---|
358 | this.toggleAllGroups(true); |
---|
359 | }, |
---|
360 | |
---|
361 | /** |
---|
362 | * Collapses all grouped rows. |
---|
363 | */ |
---|
364 | collapseAllGroups : function(){ |
---|
365 | this.toggleAllGroups(false); |
---|
366 | }, |
---|
367 | |
---|
368 | // private |
---|
369 | getGroup : function(v, r, groupRenderer, rowIndex, colIndex, ds){ |
---|
370 | var column = this.cm.config[colIndex], |
---|
371 | g = groupRenderer ? groupRenderer.call(column.scope, v, {}, r, rowIndex, colIndex, ds) : String(v); |
---|
372 | if(g === '' || g === ' '){ |
---|
373 | g = column.emptyGroupText || this.emptyGroupText; |
---|
374 | } |
---|
375 | return g; |
---|
376 | }, |
---|
377 | |
---|
378 | // private |
---|
379 | getGroupField : function(){ |
---|
380 | return this.grid.store.getGroupState(); |
---|
381 | }, |
---|
382 | |
---|
383 | // private |
---|
384 | afterRender : function(){ |
---|
385 | if(!this.ds || !this.cm){ |
---|
386 | return; |
---|
387 | } |
---|
388 | Ext.grid.GroupingView.superclass.afterRender.call(this); |
---|
389 | if(this.grid.deferRowRender){ |
---|
390 | this.updateGroupWidths(); |
---|
391 | } |
---|
392 | }, |
---|
393 | |
---|
394 | afterRenderUI: function () { |
---|
395 | Ext.grid.GroupingView.superclass.afterRenderUI.call(this); |
---|
396 | |
---|
397 | if (this.enableGroupingMenu && this.hmenu) { |
---|
398 | this.hmenu.add('-',{ |
---|
399 | itemId:'groupBy', |
---|
400 | text: this.groupByText, |
---|
401 | handler: this.onGroupByClick, |
---|
402 | scope: this, |
---|
403 | iconCls:'x-group-by-icon' |
---|
404 | }); |
---|
405 | |
---|
406 | if (this.enableNoGroups) { |
---|
407 | this.hmenu.add({ |
---|
408 | itemId:'showGroups', |
---|
409 | text: this.showGroupsText, |
---|
410 | checked: true, |
---|
411 | checkHandler: this.onShowGroupsClick, |
---|
412 | scope: this |
---|
413 | }); |
---|
414 | } |
---|
415 | |
---|
416 | this.hmenu.on('beforeshow', this.beforeMenuShow, this); |
---|
417 | } |
---|
418 | }, |
---|
419 | |
---|
420 | // private |
---|
421 | renderRows : function(){ |
---|
422 | var groupField = this.getGroupField(); |
---|
423 | var eg = !!groupField; |
---|
424 | // if they turned off grouping and the last grouped field is hidden |
---|
425 | if(this.hideGroupedColumn) { |
---|
426 | var colIndex = this.cm.findColumnIndex(groupField), |
---|
427 | hasLastGroupField = Ext.isDefined(this.lastGroupField); |
---|
428 | if(!eg && hasLastGroupField){ |
---|
429 | this.mainBody.update(''); |
---|
430 | this.cm.setHidden(this.cm.findColumnIndex(this.lastGroupField), false); |
---|
431 | delete this.lastGroupField; |
---|
432 | }else if (eg && !hasLastGroupField){ |
---|
433 | this.lastGroupField = groupField; |
---|
434 | this.cm.setHidden(colIndex, true); |
---|
435 | }else if (eg && hasLastGroupField && groupField !== this.lastGroupField) { |
---|
436 | this.mainBody.update(''); |
---|
437 | var oldIndex = this.cm.findColumnIndex(this.lastGroupField); |
---|
438 | this.cm.setHidden(oldIndex, false); |
---|
439 | this.lastGroupField = groupField; |
---|
440 | this.cm.setHidden(colIndex, true); |
---|
441 | } |
---|
442 | } |
---|
443 | return Ext.grid.GroupingView.superclass.renderRows.apply( |
---|
444 | this, arguments); |
---|
445 | }, |
---|
446 | |
---|
447 | // private |
---|
448 | doRender : function(cs, rs, ds, startRow, colCount, stripe){ |
---|
449 | if(rs.length < 1){ |
---|
450 | return ''; |
---|
451 | } |
---|
452 | |
---|
453 | if(!this.canGroup() || this.isUpdating){ |
---|
454 | return Ext.grid.GroupingView.superclass.doRender.apply(this, arguments); |
---|
455 | } |
---|
456 | |
---|
457 | var groupField = this.getGroupField(), |
---|
458 | colIndex = this.cm.findColumnIndex(groupField), |
---|
459 | g, |
---|
460 | gstyle = 'width:' + this.getTotalWidth() + ';', |
---|
461 | cfg = this.cm.config[colIndex], |
---|
462 | groupRenderer = cfg.groupRenderer || cfg.renderer, |
---|
463 | prefix = this.showGroupName ? (cfg.groupName || cfg.header)+': ' : '', |
---|
464 | groups = [], |
---|
465 | curGroup, i, len, gid; |
---|
466 | |
---|
467 | for(i = 0, len = rs.length; i < len; i++){ |
---|
468 | var rowIndex = startRow + i, |
---|
469 | r = rs[i], |
---|
470 | gvalue = r.data[groupField]; |
---|
471 | |
---|
472 | g = this.getGroup(gvalue, r, groupRenderer, rowIndex, colIndex, ds); |
---|
473 | if(!curGroup || curGroup.group != g){ |
---|
474 | gid = this.constructId(gvalue, groupField, colIndex); |
---|
475 | // if state is defined use it, however state is in terms of expanded |
---|
476 | // so negate it, otherwise use the default. |
---|
477 | this.state[gid] = !(Ext.isDefined(this.state[gid]) ? !this.state[gid] : this.startCollapsed); |
---|
478 | curGroup = { |
---|
479 | group: g, |
---|
480 | gvalue: gvalue, |
---|
481 | text: prefix + g, |
---|
482 | groupId: gid, |
---|
483 | startRow: rowIndex, |
---|
484 | rs: [r], |
---|
485 | cls: this.state[gid] ? '' : 'x-grid-group-collapsed', |
---|
486 | style: gstyle |
---|
487 | }; |
---|
488 | groups.push(curGroup); |
---|
489 | }else{ |
---|
490 | curGroup.rs.push(r); |
---|
491 | } |
---|
492 | r._groupId = gid; |
---|
493 | } |
---|
494 | |
---|
495 | var buf = []; |
---|
496 | for(i = 0, len = groups.length; i < len; i++){ |
---|
497 | g = groups[i]; |
---|
498 | this.doGroupStart(buf, g, cs, ds, colCount); |
---|
499 | buf[buf.length] = Ext.grid.GroupingView.superclass.doRender.call( |
---|
500 | this, cs, g.rs, ds, g.startRow, colCount, stripe); |
---|
501 | |
---|
502 | this.doGroupEnd(buf, g, cs, ds, colCount); |
---|
503 | } |
---|
504 | return buf.join(''); |
---|
505 | }, |
---|
506 | |
---|
507 | /** |
---|
508 | * Dynamically tries to determine the groupId of a specific value |
---|
509 | * @param {String} value |
---|
510 | * @return {String} The group id |
---|
511 | */ |
---|
512 | getGroupId : function(value){ |
---|
513 | var field = this.getGroupField(); |
---|
514 | return this.constructId(value, field, this.cm.findColumnIndex(field)); |
---|
515 | }, |
---|
516 | |
---|
517 | // private |
---|
518 | constructId : function(value, field, idx){ |
---|
519 | var cfg = this.cm.config[idx], |
---|
520 | groupRenderer = cfg.groupRenderer || cfg.renderer, |
---|
521 | val = (this.groupMode == 'value') ? value : this.getGroup(value, {data:{}}, groupRenderer, 0, idx, this.ds); |
---|
522 | |
---|
523 | return this.getPrefix(field) + Ext.util.Format.htmlEncode(val); |
---|
524 | }, |
---|
525 | |
---|
526 | // private |
---|
527 | canGroup : function(){ |
---|
528 | return this.enableGrouping && !!this.getGroupField(); |
---|
529 | }, |
---|
530 | |
---|
531 | // private |
---|
532 | getPrefix: function(field){ |
---|
533 | return this.grid.getGridEl().id + '-gp-' + field + '-'; |
---|
534 | }, |
---|
535 | |
---|
536 | // private |
---|
537 | doGroupStart : function(buf, g, cs, ds, colCount){ |
---|
538 | buf[buf.length] = this.startGroup.apply(g); |
---|
539 | }, |
---|
540 | |
---|
541 | // private |
---|
542 | doGroupEnd : function(buf, g, cs, ds, colCount){ |
---|
543 | buf[buf.length] = this.endGroup; |
---|
544 | }, |
---|
545 | |
---|
546 | // private |
---|
547 | getRows : function(){ |
---|
548 | if(!this.canGroup()){ |
---|
549 | return Ext.grid.GroupingView.superclass.getRows.call(this); |
---|
550 | } |
---|
551 | var r = [], |
---|
552 | gs = this.getGroups(), |
---|
553 | g, |
---|
554 | i = 0, |
---|
555 | len = gs.length, |
---|
556 | j, |
---|
557 | jlen; |
---|
558 | for(; i < len; ++i){ |
---|
559 | g = gs[i].childNodes[1]; |
---|
560 | if(g){ |
---|
561 | g = g.childNodes; |
---|
562 | for(j = 0, jlen = g.length; j < jlen; ++j){ |
---|
563 | r[r.length] = g[j]; |
---|
564 | } |
---|
565 | } |
---|
566 | } |
---|
567 | return r; |
---|
568 | }, |
---|
569 | |
---|
570 | // private |
---|
571 | updateGroupWidths : function(){ |
---|
572 | if(!this.canGroup() || !this.hasRows()){ |
---|
573 | return; |
---|
574 | } |
---|
575 | var tw = Math.max(this.cm.getTotalWidth(), this.el.dom.offsetWidth-this.getScrollOffset()) +'px'; |
---|
576 | var gs = this.getGroups(); |
---|
577 | for(var i = 0, len = gs.length; i < len; i++){ |
---|
578 | gs[i].firstChild.style.width = tw; |
---|
579 | } |
---|
580 | }, |
---|
581 | |
---|
582 | // private |
---|
583 | onColumnWidthUpdated : function(col, w, tw){ |
---|
584 | Ext.grid.GroupingView.superclass.onColumnWidthUpdated.call(this, col, w, tw); |
---|
585 | this.updateGroupWidths(); |
---|
586 | }, |
---|
587 | |
---|
588 | // private |
---|
589 | onAllColumnWidthsUpdated : function(ws, tw){ |
---|
590 | Ext.grid.GroupingView.superclass.onAllColumnWidthsUpdated.call(this, ws, tw); |
---|
591 | this.updateGroupWidths(); |
---|
592 | }, |
---|
593 | |
---|
594 | // private |
---|
595 | onColumnHiddenUpdated : function(col, hidden, tw){ |
---|
596 | Ext.grid.GroupingView.superclass.onColumnHiddenUpdated.call(this, col, hidden, tw); |
---|
597 | this.updateGroupWidths(); |
---|
598 | }, |
---|
599 | |
---|
600 | // private |
---|
601 | onLayout : function(){ |
---|
602 | this.updateGroupWidths(); |
---|
603 | }, |
---|
604 | |
---|
605 | // private |
---|
606 | onBeforeRowSelect : function(sm, rowIndex){ |
---|
607 | this.toggleRowIndex(rowIndex, true); |
---|
608 | } |
---|
609 | }); |
---|
610 | // private |
---|
611 | Ext.grid.GroupingView.GROUP_ID = 1000; |
---|