source: trunk/web/addons/job_monarch/lib/extjs-30/pkgs/pkg-grid-grouping-debug.js @ 625

Last change on this file since 625 was 625, checked in by ramonb, 15 years ago

lib/extjs-30:

  • new ExtJS 3.0
File size: 19.3 KB
Line 
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.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}</li>
14 * <li><code>{@link Ext.grid.Column#groupable groupable}</li>
15 * <li><code>{@link Ext.grid.Column#groupName groupName}</li>
16 * <li><code>{@link Ext.grid.Column#groupRender groupRender}</li>
17 * </ul></div>
18 * <p>Sample usage:</p>
19 * <pre><code>
20var 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 */
66Ext.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>
133var 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     * @cfg {Function} groupRenderer This property must be configured in the {@link Ext.grid.Column} for
144     * each column.
145     */
146
147    // private
148    gidSeed : 1000,
149
150    // private
151    initTemplates : function(){
152        Ext.grid.GroupingView.superclass.initTemplates.call(this);
153        this.state = {};
154
155        var sm = this.grid.getSelectionModel();
156        sm.on(sm.selectRow ? 'beforerowselect' : 'beforecellselect',
157                this.onBeforeRowSelect, this);
158
159        if(!this.startGroup){
160            this.startGroup = new Ext.XTemplate(
161                '<div id="{groupId}" class="x-grid-group {cls}">',
162                    '<div id="{groupId}-hd" class="x-grid-group-hd" style="{style}"><div class="x-grid-group-title">', this.groupTextTpl ,'</div></div>',
163                    '<div id="{groupId}-bd" class="x-grid-group-body">'
164            );
165        }
166        this.startGroup.compile();
167        this.endGroup = '</div></div>';
168    },
169
170    // private
171    findGroup : function(el){
172        return Ext.fly(el).up('.x-grid-group', this.mainBody.dom);
173    },
174
175    // private
176    getGroups : function(){
177        return this.hasRows() ? this.mainBody.dom.childNodes : [];
178    },
179
180    // private
181    onAdd : function(){
182        if(this.enableGrouping && !this.ignoreAdd){
183            var ss = this.getScrollState();
184            this.refresh();
185            this.restoreScroll(ss);
186        }else if(!this.enableGrouping){
187            Ext.grid.GroupingView.superclass.onAdd.apply(this, arguments);
188        }
189    },
190
191    // private
192    onRemove : function(ds, record, index, isUpdate){
193        Ext.grid.GroupingView.superclass.onRemove.apply(this, arguments);
194        var g = document.getElementById(record._groupId);
195        if(g && g.childNodes[1].childNodes.length < 1){
196            Ext.removeNode(g);
197        }
198        this.applyEmptyText();
199    },
200
201    // private
202    refreshRow : function(record){
203        if(this.ds.getCount()==1){
204            this.refresh();
205        }else{
206            this.isUpdating = true;
207            Ext.grid.GroupingView.superclass.refreshRow.apply(this, arguments);
208            this.isUpdating = false;
209        }
210    },
211
212    // private
213    beforeMenuShow : function(){
214        var item, items = this.hmenu.items, disabled = this.cm.config[this.hdCtxIndex].groupable === false;
215        if((item = items.get('groupBy'))){
216            item.setDisabled(disabled);
217        }
218        if((item = items.get('showGroups'))){
219            item.setDisabled(disabled);
220                    item.setChecked(!!this.getGroupField(), true);
221        }
222    },
223
224    // private
225    renderUI : function(){
226        Ext.grid.GroupingView.superclass.renderUI.call(this);
227        this.mainBody.on('mousedown', this.interceptMouse, this);
228
229        if(this.enableGroupingMenu && this.hmenu){
230            this.hmenu.add('-',{
231                itemId:'groupBy',
232                text: this.groupByText,
233                handler: this.onGroupByClick,
234                scope: this,
235                iconCls:'x-group-by-icon'
236            });
237            if(this.enableNoGroups){
238                this.hmenu.add({
239                    itemId:'showGroups',
240                    text: this.showGroupsText,
241                    checked: true,
242                    checkHandler: this.onShowGroupsClick,
243                    scope: this
244                });
245            }
246            this.hmenu.on('beforeshow', this.beforeMenuShow, this);
247        }
248    },
249
250    // private
251    onGroupByClick : function(){
252        this.grid.store.groupBy(this.cm.getDataIndex(this.hdCtxIndex));
253        this.beforeMenuShow(); // Make sure the checkboxes get properly set when changing groups
254    },
255
256    // private
257    onShowGroupsClick : function(mi, checked){
258        if(checked){
259            this.onGroupByClick();
260        }else{
261            this.grid.store.clearGrouping();
262        }
263    },
264
265    /**
266     * Toggles the specified group if no value is passed, otherwise sets the expanded state of the group to the value passed.
267     * @param {String} groupId The groupId assigned to the group (see getGroupId)
268     * @param {Boolean} expanded (optional)
269     */
270    toggleGroup : function(group, expanded){
271        this.grid.stopEditing(true);
272        group = Ext.getDom(group);
273        var gel = Ext.fly(group);
274        expanded = expanded !== undefined ?
275                expanded : gel.hasClass('x-grid-group-collapsed');
276
277        this.state[gel.dom.id] = expanded;
278        gel[expanded ? 'removeClass' : 'addClass']('x-grid-group-collapsed');
279    },
280
281    /**
282     * Toggles all groups if no value is passed, otherwise sets the expanded state of all groups to the value passed.
283     * @param {Boolean} expanded (optional)
284     */
285    toggleAllGroups : function(expanded){
286        var groups = this.getGroups();
287        for(var i = 0, len = groups.length; i < len; i++){
288            this.toggleGroup(groups[i], expanded);
289        }
290    },
291
292    /**
293     * Expands all grouped rows.
294     */
295    expandAllGroups : function(){
296        this.toggleAllGroups(true);
297    },
298
299    /**
300     * Collapses all grouped rows.
301     */
302    collapseAllGroups : function(){
303        this.toggleAllGroups(false);
304    },
305
306    // private
307    interceptMouse : function(e){
308        var hd = e.getTarget('.x-grid-group-hd', this.mainBody);
309        if(hd){
310            e.stopEvent();
311            this.toggleGroup(hd.parentNode);
312        }
313    },
314
315    // private
316    getGroup : function(v, r, groupRenderer, rowIndex, colIndex, ds){
317        var g = groupRenderer ? groupRenderer(v, {}, r, rowIndex, colIndex, ds) : String(v);
318        if(g === ''){
319            g = this.cm.config[colIndex].emptyGroupText || this.emptyGroupText;
320        }
321        return g;
322    },
323
324    // private
325    getGroupField : function(){
326        return this.grid.store.getGroupState();
327    },
328   
329    // private
330    afterRender : function(){
331        Ext.grid.GroupingView.superclass.afterRender.call(this);
332        if(this.grid.deferRowRender){
333            this.updateGroupWidths();
334        }
335    },
336
337    // private
338    renderRows : function(){
339        var groupField = this.getGroupField();
340        var eg = !!groupField;
341        // if they turned off grouping and the last grouped field is hidden
342        if(this.hideGroupedColumn) {
343            var colIndex = this.cm.findColumnIndex(groupField);
344            if(!eg && this.lastGroupField !== undefined) {
345                this.mainBody.update('');
346                this.cm.setHidden(this.cm.findColumnIndex(this.lastGroupField), false);
347                delete this.lastGroupField;
348            }else if (eg && this.lastGroupField === undefined) {
349                this.lastGroupField = groupField;
350                this.cm.setHidden(colIndex, true);
351            }else if (eg && this.lastGroupField !== undefined && groupField !== this.lastGroupField) {
352                this.mainBody.update('');
353                var oldIndex = this.cm.findColumnIndex(this.lastGroupField);
354                this.cm.setHidden(oldIndex, false);
355                this.lastGroupField = groupField;
356                this.cm.setHidden(colIndex, true);
357            }
358        }
359        return Ext.grid.GroupingView.superclass.renderRows.apply(
360                    this, arguments);
361    },
362
363    // private
364    doRender : function(cs, rs, ds, startRow, colCount, stripe){
365        if(rs.length < 1){
366            return '';
367        }
368        var groupField = this.getGroupField(),
369            colIndex = this.cm.findColumnIndex(groupField),
370            g;
371
372        this.enableGrouping = !!groupField;
373
374        if(!this.enableGrouping || this.isUpdating){
375            return Ext.grid.GroupingView.superclass.doRender.apply(
376                    this, arguments);
377        }
378        var gstyle = 'width:'+this.getTotalWidth()+';';
379
380        var gidPrefix = this.grid.getGridEl().id;
381        var cfg = this.cm.config[colIndex];
382        var groupRenderer = cfg.groupRenderer || cfg.renderer;
383        var prefix = this.showGroupName ?
384                     (cfg.groupName || cfg.header)+': ' : '';
385
386        var groups = [], curGroup, i, len, gid;
387        for(i = 0, len = rs.length; i < len; i++){
388            var rowIndex = startRow + i,
389                r = rs[i],
390                gvalue = r.data[groupField];
391               
392                g = this.getGroup(gvalue, r, groupRenderer, rowIndex, colIndex, ds);
393            if(!curGroup || curGroup.group != g){
394                gid = gidPrefix + '-gp-' + groupField + '-' + Ext.util.Format.htmlEncode(g);
395                // if state is defined use it, however state is in terms of expanded
396                                // so negate it, otherwise use the default.
397                                var isCollapsed  = typeof this.state[gid] !== 'undefined' ? !this.state[gid] : this.startCollapsed;
398                                var gcls = isCollapsed ? 'x-grid-group-collapsed' : ''; 
399                curGroup = {
400                    group: g,
401                    gvalue: gvalue,
402                    text: prefix + g,
403                    groupId: gid,
404                    startRow: rowIndex,
405                    rs: [r],
406                    cls: gcls,
407                    style: gstyle
408                };
409                groups.push(curGroup);
410            }else{
411                curGroup.rs.push(r);
412            }
413            r._groupId = gid;
414        }
415
416        var buf = [];
417        for(i = 0, len = groups.length; i < len; i++){
418            g = groups[i];
419            this.doGroupStart(buf, g, cs, ds, colCount);
420            buf[buf.length] = Ext.grid.GroupingView.superclass.doRender.call(
421                    this, cs, g.rs, ds, g.startRow, colCount, stripe);
422
423            this.doGroupEnd(buf, g, cs, ds, colCount);
424        }
425        return buf.join('');
426    },
427
428    /**
429     * Dynamically tries to determine the groupId of a specific value
430     * @param {String} value
431     * @return {String} The group id
432     */
433    getGroupId : function(value){
434        var gidPrefix = this.grid.getGridEl().id;
435        var groupField = this.getGroupField();
436        var colIndex = this.cm.findColumnIndex(groupField);
437        var cfg = this.cm.config[colIndex];
438        var groupRenderer = cfg.groupRenderer || cfg.renderer;
439        var gtext = this.getGroup(value, {data:{}}, groupRenderer, 0, colIndex, this.ds);
440        return gidPrefix + '-gp-' + groupField + '-' + Ext.util.Format.htmlEncode(value);
441    },
442
443    // private
444    doGroupStart : function(buf, g, cs, ds, colCount){
445        buf[buf.length] = this.startGroup.apply(g);
446    },
447
448    // private
449    doGroupEnd : function(buf, g, cs, ds, colCount){
450        buf[buf.length] = this.endGroup;
451    },
452
453    // private
454    getRows : function(){
455        if(!this.enableGrouping){
456            return Ext.grid.GroupingView.superclass.getRows.call(this);
457        }
458        var r = [];
459        var g, gs = this.getGroups();
460        for(var i = 0, len = gs.length; i < len; i++){
461            g = gs[i].childNodes[1].childNodes;
462            for(var j = 0, jlen = g.length; j < jlen; j++){
463                r[r.length] = g[j];
464            }
465        }
466        return r;
467    },
468
469    // private
470    updateGroupWidths : function(){
471        if(!this.enableGrouping || !this.hasRows()){
472            return;
473        }
474        var tw = Math.max(this.cm.getTotalWidth(), this.el.dom.offsetWidth-this.scrollOffset) +'px';
475        var gs = this.getGroups();
476        for(var i = 0, len = gs.length; i < len; i++){
477            gs[i].firstChild.style.width = tw;
478        }
479    },
480
481    // private
482    onColumnWidthUpdated : function(col, w, tw){
483        Ext.grid.GroupingView.superclass.onColumnWidthUpdated.call(this, col, w, tw);
484        this.updateGroupWidths();
485    },
486
487    // private
488    onAllColumnWidthsUpdated : function(ws, tw){
489        Ext.grid.GroupingView.superclass.onAllColumnWidthsUpdated.call(this, ws, tw);
490        this.updateGroupWidths();
491    },
492
493    // private
494    onColumnHiddenUpdated : function(col, hidden, tw){
495        Ext.grid.GroupingView.superclass.onColumnHiddenUpdated.call(this, col, hidden, tw);
496        this.updateGroupWidths();
497    },
498
499    // private
500    onLayout : function(){
501        this.updateGroupWidths();
502    },
503
504    // private
505    onBeforeRowSelect : function(sm, rowIndex){
506        if(!this.enableGrouping){
507            return;
508        }
509        var row = this.getRow(rowIndex);
510        if(row && !row.offsetParent){
511            var g = this.findGroup(row);
512            this.toggleGroup(g, true);
513        }
514    }
515});
516// private
517Ext.grid.GroupingView.GROUP_ID = 1000;
Note: See TracBrowser for help on using the repository browser.