Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / docs / source / GroupSummary.html
1 <html>
2 <head>
3   <title>The source code</title>
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
6 </head>
7 <body  onload="prettyPrint();">
8     <pre class="prettyprint lang-js">Ext.ns('Ext.ux.grid');\r
9 \r
10 <div id="cls-Ext.ux.grid.GroupSummary"></div>/**\r
11  * @class Ext.ux.grid.GroupSummary\r
12  * @extends Ext.util.Observable\r
13  * A GridPanel plugin that enables dynamic column calculations and a dynamically\r
14  * updated grouped summary row.\r
15  */\r
16 Ext.ux.grid.GroupSummary = Ext.extend(Ext.util.Observable, {\r
17     <div id="cfg-Ext.ux.grid.GroupSummary-summaryRenderer"></div>/**\r
18      * @cfg {Function} summaryRenderer Renderer example:<pre><code>\r
19 summaryRenderer: function(v, params, data){\r
20     return ((v === 0 || v > 1) ? '(' + v +' Tasks)' : '(1 Task)');\r
21 },\r
22      * </code></pre>\r
23      */\r
24     <div id="cfg-Ext.ux.grid.GroupSummary-summaryType"></div>/**\r
25      * @cfg {String} summaryType (Optional) The type of\r
26      * calculation to be used for the column.  For options available see\r
27      * {@link #Calculations}.\r
28      */\r
29 \r
30     constructor : function(config){\r
31         Ext.apply(this, config);\r
32         Ext.ux.grid.GroupSummary.superclass.constructor.call(this);\r
33     },\r
34     init : function(grid){\r
35         this.grid = grid;\r
36         var v = this.view = grid.getView();\r
37         v.doGroupEnd = this.doGroupEnd.createDelegate(this);\r
38 \r
39         v.afterMethod('onColumnWidthUpdated', this.doWidth, this);\r
40         v.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this);\r
41         v.afterMethod('onColumnHiddenUpdated', this.doHidden, this);\r
42         v.afterMethod('onUpdate', this.doUpdate, this);\r
43         v.afterMethod('onRemove', this.doRemove, this);\r
44 \r
45         if(!this.rowTpl){\r
46             this.rowTpl = new Ext.Template(\r
47                 '<div class="x-grid3-summary-row" style="{tstyle}">',\r
48                 '<table class="x-grid3-summary-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',\r
49                     '<tbody><tr>{cells}</tr></tbody>',\r
50                 '</table></div>'\r
51             );\r
52             this.rowTpl.disableFormats = true;\r
53         }\r
54         this.rowTpl.compile();\r
55 \r
56         if(!this.cellTpl){\r
57             this.cellTpl = new Ext.Template(\r
58                 '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}">',\r
59                 '<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on">{value}</div>',\r
60                 "</td>"\r
61             );\r
62             this.cellTpl.disableFormats = true;\r
63         }\r
64         this.cellTpl.compile();\r
65     },\r
66 \r
67     <div id="method-Ext.ux.grid.GroupSummary-toggleSummaries"></div>/**\r
68      * Toggle the display of the summary row on/off\r
69      * @param {Boolean} visible <tt>true</tt> to show the summary, <tt>false</tt> to hide the summary.\r
70      */\r
71     toggleSummaries : function(visible){\r
72         var el = this.grid.getGridEl();\r
73         if(el){\r
74             if(visible === undefined){\r
75                 visible = el.hasClass('x-grid-hide-summary');\r
76             }\r
77             el[visible ? 'removeClass' : 'addClass']('x-grid-hide-summary');\r
78         }\r
79     },\r
80 \r
81     renderSummary : function(o, cs){\r
82         cs = cs || this.view.getColumnData();\r
83         var cfg = this.grid.getColumnModel().config,\r
84             buf = [], c, p = {}, cf, last = cs.length-1;\r
85         for(var i = 0, len = cs.length; i < len; i++){\r
86             c = cs[i];\r
87             cf = cfg[i];\r
88             p.id = c.id;\r
89             p.style = c.style;\r
90             p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');\r
91             if(cf.summaryType || cf.summaryRenderer){\r
92                 p.value = (cf.summaryRenderer || c.renderer)(o.data[c.name], p, o);\r
93             }else{\r
94                 p.value = '';\r
95             }\r
96             if(p.value == undefined || p.value === "") p.value = "&#160;";\r
97             buf[buf.length] = this.cellTpl.apply(p);\r
98         }\r
99 \r
100         return this.rowTpl.apply({\r
101             tstyle: 'width:'+this.view.getTotalWidth()+';',\r
102             cells: buf.join('')\r
103         });\r
104     },\r
105 \r
106     /**\r
107      * @private\r
108      * @param {Object} rs\r
109      * @param {Object} cs\r
110      */\r
111     calculate : function(rs, cs){\r
112         var data = {}, r, c, cfg = this.grid.getColumnModel().config, cf;\r
113         for(var j = 0, jlen = rs.length; j < jlen; j++){\r
114             r = rs[j];\r
115             for(var i = 0, len = cs.length; i < len; i++){\r
116                 c = cs[i];\r
117                 cf = cfg[i];\r
118                 if(cf.summaryType){\r
119                     data[c.name] = Ext.ux.grid.GroupSummary.Calculations[cf.summaryType](data[c.name] || 0, r, c.name, data);\r
120                 }\r
121             }\r
122         }\r
123         return data;\r
124     },\r
125 \r
126     doGroupEnd : function(buf, g, cs, ds, colCount){\r
127         var data = this.calculate(g.rs, cs);\r
128         buf.push('</div>', this.renderSummary({data: data}, cs), '</div>');\r
129     },\r
130 \r
131     doWidth : function(col, w, tw){\r
132         var gs = this.view.getGroups(), s;\r
133         for(var i = 0, len = gs.length; i < len; i++){\r
134             s = gs[i].childNodes[2];\r
135             s.style.width = tw;\r
136             s.firstChild.style.width = tw;\r
137             s.firstChild.rows[0].childNodes[col].style.width = w;\r
138         }\r
139     },\r
140 \r
141     doAllWidths : function(ws, tw){\r
142         var gs = this.view.getGroups(), s, cells, wlen = ws.length;\r
143         for(var i = 0, len = gs.length; i < len; i++){\r
144             s = gs[i].childNodes[2];\r
145             s.style.width = tw;\r
146             s.firstChild.style.width = tw;\r
147             cells = s.firstChild.rows[0].childNodes;\r
148             for(var j = 0; j < wlen; j++){\r
149                 cells[j].style.width = ws[j];\r
150             }\r
151         }\r
152     },\r
153 \r
154     doHidden : function(col, hidden, tw){\r
155         var gs = this.view.getGroups(), s, display = hidden ? 'none' : '';\r
156         for(var i = 0, len = gs.length; i < len; i++){\r
157             s = gs[i].childNodes[2];\r
158             s.style.width = tw;\r
159             s.firstChild.style.width = tw;\r
160             s.firstChild.rows[0].childNodes[col].style.display = display;\r
161         }\r
162     },\r
163 \r
164     // Note: requires that all (or the first) record in the\r
165     // group share the same group value. Returns false if the group\r
166     // could not be found.\r
167     refreshSummary : function(groupValue){\r
168         return this.refreshSummaryById(this.view.getGroupId(groupValue));\r
169     },\r
170 \r
171     getSummaryNode : function(gid){\r
172         var g = Ext.fly(gid, '_gsummary');\r
173         if(g){\r
174             return g.down('.x-grid3-summary-row', true);\r
175         }\r
176         return null;\r
177     },\r
178 \r
179     refreshSummaryById : function(gid){\r
180         var g = Ext.getDom(gid);\r
181         if(!g){\r
182             return false;\r
183         }\r
184         var rs = [];\r
185         this.grid.getStore().each(function(r){\r
186             if(r._groupId == gid){\r
187                 rs[rs.length] = r;\r
188             }\r
189         });\r
190         var cs = this.view.getColumnData(),\r
191             data = this.calculate(rs, cs),\r
192             markup = this.renderSummary({data: data}, cs),\r
193             existing = this.getSummaryNode(gid);\r
194             \r
195         if(existing){\r
196             g.removeChild(existing);\r
197         }\r
198         Ext.DomHelper.append(g, markup);\r
199         return true;\r
200     },\r
201 \r
202     doUpdate : function(ds, record){\r
203         this.refreshSummaryById(record._groupId);\r
204     },\r
205 \r
206     doRemove : function(ds, record, index, isUpdate){\r
207         if(!isUpdate){\r
208             this.refreshSummaryById(record._groupId);\r
209         }\r
210     },\r
211 \r
212     <div id="method-Ext.ux.grid.GroupSummary-showSummaryMsg"></div>/**\r
213      * Show a message in the summary row.\r
214      * <pre><code>\r
215 grid.on('afteredit', function(){\r
216     var groupValue = 'Ext Forms: Field Anchoring';\r
217     summary.showSummaryMsg(groupValue, 'Updating Summary...');\r
218 });\r
219      * </code></pre>\r
220      * @param {String} groupValue\r
221      * @param {String} msg Text to use as innerHTML for the summary row.\r
222      */\r
223     showSummaryMsg : function(groupValue, msg){\r
224         var gid = this.view.getGroupId(groupValue),\r
225              node = this.getSummaryNode(gid);\r
226         if(node){\r
227             node.innerHTML = '<div class="x-grid3-summary-msg">' + msg + '</div>';\r
228         }\r
229     }\r
230 });\r
231 \r
232 //backwards compat\r
233 Ext.grid.GroupSummary = Ext.ux.grid.GroupSummary;\r
234 \r
235 \r
236 <div id="prop-Ext.ux.grid.GroupSummary-Calculations"></div>/**\r
237  * Calculation types for summary row:</p><div class="mdetail-params"><ul>\r
238  * <li><b><tt>sum</tt></b> : <div class="sub-desc"></div></li>\r
239  * <li><b><tt>count</tt></b> : <div class="sub-desc"></div></li>\r
240  * <li><b><tt>max</tt></b> : <div class="sub-desc"></div></li>\r
241  * <li><b><tt>min</tt></b> : <div class="sub-desc"></div></li>\r
242  * <li><b><tt>average</tt></b> : <div class="sub-desc"></div></li>\r
243  * </ul></div>\r
244  * <p>Custom calculations may be implemented.  An example of\r
245  * custom <code>summaryType=totalCost</code>:</p><pre><code>\r
246 // define a custom summary function\r
247 Ext.ux.grid.GroupSummary.Calculations['totalCost'] = function(v, record, field){\r
248     return v + (record.data.estimate * record.data.rate);\r
249 };\r
250  * </code></pre>\r
251  * @property Calculations\r
252  */\r
253 \r
254 Ext.ux.grid.GroupSummary.Calculations = {\r
255     'sum' : function(v, record, field){\r
256         return v + (record.data[field]||0);\r
257     },\r
258 \r
259     'count' : function(v, record, field, data){\r
260         return data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1);\r
261     },\r
262 \r
263     'max' : function(v, record, field, data){\r
264         var v = record.data[field];\r
265         var max = data[field+'max'] === undefined ? (data[field+'max'] = v) : data[field+'max'];\r
266         return v > max ? (data[field+'max'] = v) : max;\r
267     },\r
268 \r
269     'min' : function(v, record, field, data){\r
270         var v = record.data[field];\r
271         var min = data[field+'min'] === undefined ? (data[field+'min'] = v) : data[field+'min'];\r
272         return v < min ? (data[field+'min'] = v) : min;\r
273     },\r
274 \r
275     'average' : function(v, record, field, data){\r
276         var c = data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1);\r
277         var t = (data[field+'total'] = ((data[field+'total']||0) + (record.data[field]||0)));\r
278         return t === 0 ? 0 : t / c;\r
279     }\r
280 };\r
281 Ext.grid.GroupSummary.Calculations = Ext.ux.grid.GroupSummary.Calculations;\r
282 \r
283 <div id="cls-Ext.ux.grid.HybridSummary"></div>/**\r
284  * @class Ext.ux.grid.HybridSummary\r
285  * @extends Ext.ux.grid.GroupSummary\r
286  * Adds capability to specify the summary data for the group via json as illustrated here:\r
287  * <pre><code>\r
288 {\r
289     data: [\r
290         {\r
291             projectId: 100,     project: 'House',\r
292             taskId:    112, description: 'Paint',\r
293             estimate:    6,        rate:     150,\r
294             due:'06/24/2007'\r
295         },\r
296         ...\r
297     ],\r
298 \r
299     summaryData: {\r
300         'House': {\r
301             description: 14, estimate: 9,\r
302                    rate: 99, due: new Date(2009, 6, 29),\r
303                    cost: 999\r
304         }\r
305     }\r
306 }\r
307  * </code></pre>\r
308  *\r
309  */\r
310 Ext.ux.grid.HybridSummary = Ext.extend(Ext.ux.grid.GroupSummary, {\r
311     /**\r
312      * @private\r
313      * @param {Object} rs\r
314      * @param {Object} cs\r
315      */\r
316     calculate : function(rs, cs){\r
317         var gcol = this.view.getGroupField(),\r
318             gvalue = rs[0].data[gcol],\r
319             gdata = this.getSummaryData(gvalue);\r
320         return gdata || Ext.ux.grid.HybridSummary.superclass.calculate.call(this, rs, cs);\r
321     },\r
322 \r
323     <div id="method-Ext.ux.grid.HybridSummary-updateSummaryData"></div>/**\r
324      * <pre><code>\r
325 grid.on('afteredit', function(){\r
326     var groupValue = 'Ext Forms: Field Anchoring';\r
327     summary.showSummaryMsg(groupValue, 'Updating Summary...');\r
328     setTimeout(function(){ // simulate server call\r
329         // HybridSummary class implements updateSummaryData\r
330         summary.updateSummaryData(groupValue,\r
331             // create data object based on configured dataIndex\r
332             {description: 22, estimate: 888, rate: 888, due: new Date(), cost: 8});\r
333     }, 2000);\r
334 });\r
335      * </code></pre>\r
336      * @param {String} groupValue\r
337      * @param {Object} data data object\r
338      * @param {Boolean} skipRefresh (Optional) Defaults to false\r
339      */\r
340     updateSummaryData : function(groupValue, data, skipRefresh){\r
341         var json = this.grid.getStore().reader.jsonData;\r
342         if(!json.summaryData){\r
343             json.summaryData = {};\r
344         }\r
345         json.summaryData[groupValue] = data;\r
346         if(!skipRefresh){\r
347             this.refreshSummary(groupValue);\r
348         }\r
349     },\r
350 \r
351     <div id="method-Ext.ux.grid.HybridSummary-getSummaryData"></div>/**\r
352      * Returns the summaryData for the specified groupValue or null.\r
353      * @param {String} groupValue\r
354      * @return {Object} summaryData\r
355      */\r
356     getSummaryData : function(groupValue){\r
357         var json = this.grid.getStore().reader.jsonData;\r
358         if(json && json.summaryData){\r
359             return json.summaryData[groupValue];\r
360         }\r
361         return null;\r
362     }\r
363 });\r
364 \r
365 //backwards compat\r
366 Ext.grid.HybridSummary = Ext.ux.grid.HybridSummary;\r
367 </pre>
368 </body>
369 </html>