/*! * Ext JS Library 3.3.0 * Copyright(c) 2006-2010 Ext JS, Inc. * licensing@extjs.com * http://www.extjs.com/license */ Ext.ns('Ext.ux.grid'); /** * @class Ext.ux.grid.GroupSummary * @extends Ext.util.Observable * A GridPanel plugin that enables dynamic column calculations and a dynamically * updated grouped summary row. */ Ext.ux.grid.GroupSummary = Ext.extend(Ext.util.Observable, { /** * @cfg {Function} summaryRenderer Renderer example:*/ /** * @cfg {String} summaryType (Optional) The type of * calculation to be used for the column. For options available see * {@link #Calculations}. */ constructor : function(config){ Ext.apply(this, config); Ext.ux.grid.GroupSummary.superclass.constructor.call(this); }, init : function(grid){ this.grid = grid; var v = this.view = grid.getView(); v.doGroupEnd = this.doGroupEnd.createDelegate(this); v.afterMethod('onColumnWidthUpdated', this.doWidth, this); v.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this); v.afterMethod('onColumnHiddenUpdated', this.doHidden, this); v.afterMethod('onUpdate', this.doUpdate, this); v.afterMethod('onRemove', this.doRemove, this); if(!this.rowTpl){ this.rowTpl = new Ext.Template( 'summaryRenderer: function(v, params, data){ return ((v === 0 || v > 1) ? '(' + v +' Tasks)' : '(1 Task)'); }, *
', '' ); this.rowTpl.disableFormats = true; } this.rowTpl.compile(); if(!this.cellTpl){ this.cellTpl = new Ext.Template( '', '
{cells} ', '', ' " ); this.cellTpl.disableFormats = true; } this.cellTpl.compile(); }, /** * Toggle the display of the summary row on/off * @param {Boolean} visible true to show the summary, false to hide the summary. */ toggleSummaries : function(visible){ var el = this.grid.getGridEl(); if(el){ if(visible === undefined){ visible = el.hasClass('x-grid-hide-summary'); } el[visible ? 'removeClass' : 'addClass']('x-grid-hide-summary'); } }, renderSummary : function(o, cs){ cs = cs || this.view.getColumnData(); var cfg = this.grid.getColumnModel().config, buf = [], c, p = {}, cf, last = cs.length-1; for(var i = 0, len = cs.length; i < len; i++){ c = cs[i]; cf = cfg[i]; p.id = c.id; p.style = c.style; p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : ''); if(cf.summaryType || cf.summaryRenderer){ p.value = (cf.summaryRenderer || c.renderer)(o.data[c.name], p, o); }else{ p.value = ''; } if(p.value == undefined || p.value === "") p.value = " "; buf[buf.length] = this.cellTpl.apply(p); } return this.rowTpl.apply({ tstyle: 'width:'+this.view.getTotalWidth()+';', cells: buf.join('') }); }, /** * @private * @param {Object} rs * @param {Object} cs */ calculate : function(rs, cs){ var data = {}, r, c, cfg = this.grid.getColumnModel().config, cf; for(var j = 0, jlen = rs.length; j < jlen; j++){ r = rs[j]; for(var i = 0, len = cs.length; i < len; i++){ c = cs[i]; cf = cfg[i]; if(cf.summaryType){ data[c.name] = Ext.ux.grid.GroupSummary.Calculations[cf.summaryType](data[c.name] || 0, r, c.name, data); } } } return data; }, doGroupEnd : function(buf, g, cs, ds, colCount){ var data = this.calculate(g.rs, cs); buf.push('', this.renderSummary({data: data}, cs), ''); }, doWidth : function(col, w, tw){ if(!this.isGrouped()){ return; } var gs = this.view.getGroups(), len = gs.length, i = 0, s; for(; i < len; ++i){ s = gs[i].childNodes[2]; s.style.width = tw; s.firstChild.style.width = tw; s.firstChild.rows[0].childNodes[col].style.width = w; } }, doAllWidths : function(ws, tw){ if(!this.isGrouped()){ return; } var gs = this.view.getGroups(), len = gs.length, i = 0, j, s, cells, wlen = ws.length; for(; i < len; i++){ s = gs[i].childNodes[2]; s.style.width = tw; s.firstChild.style.width = tw; cells = s.firstChild.rows[0].childNodes; for(j = 0; j < wlen; j++){ cells[j].style.width = ws[j]; } } }, doHidden : function(col, hidden, tw){ if(!this.isGrouped()){ return; } var gs = this.view.getGroups(), len = gs.length, i = 0, s, display = hidden ? 'none' : ''; for(; i < len; i++){ s = gs[i].childNodes[2]; s.style.width = tw; s.firstChild.style.width = tw; s.firstChild.rows[0].childNodes[col].style.display = display; } }, isGrouped : function(){ return !Ext.isEmpty(this.grid.getStore().groupField); }, // Note: requires that all (or the first) record in the // group share the same group value. Returns false if the group // could not be found. refreshSummary : function(groupValue){ return this.refreshSummaryById(this.view.getGroupId(groupValue)); }, getSummaryNode : function(gid){ var g = Ext.fly(gid, '_gsummary'); if(g){ return g.down('.x-grid3-summary-row', true); } return null; }, refreshSummaryById : function(gid){ var g = Ext.getDom(gid); if(!g){ return false; } var rs = []; this.grid.getStore().each(function(r){ if(r._groupId == gid){ rs[rs.length] = r; } }); var cs = this.view.getColumnData(), data = this.calculate(rs, cs), markup = this.renderSummary({data: data}, cs), existing = this.getSummaryNode(gid); if(existing){ g.removeChild(existing); } Ext.DomHelper.append(g, markup); return true; }, doUpdate : function(ds, record){ this.refreshSummaryById(record._groupId); }, doRemove : function(ds, record, index, isUpdate){ if(!isUpdate){ this.refreshSummaryById(record._groupId); } }, /** * Show a message in the summary row. *{value}', "* @param {String} groupValue * @param {String} msg Text to use as innerHTML for the summary row. */ showSummaryMsg : function(groupValue, msg){ var gid = this.view.getGroupId(groupValue), node = this.getSummaryNode(gid); if(node){ node.innerHTML = 'grid.on('afteredit', function(){ var groupValue = 'Ext Forms: Field Anchoring'; summary.showSummaryMsg(groupValue, 'Updating Summary...'); }); *
' + msg + ''; } } }); //backwards compat Ext.grid.GroupSummary = Ext.ux.grid.GroupSummary; /** * Calculation types for summary row:**
- sum :
*- count :
*- max :
*- min :
*- average :
*Custom calculations may be implemented. An example of * custom
summaryType=totalCost
:* @property Calculations */ Ext.ux.grid.GroupSummary.Calculations = { 'sum' : function(v, record, field){ return v + (record.data[field]||0); }, 'count' : function(v, record, field, data){ return data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1); }, 'max' : function(v, record, field, data){ var v = record.data[field]; var max = data[field+'max'] === undefined ? (data[field+'max'] = v) : data[field+'max']; return v > max ? (data[field+'max'] = v) : max; }, 'min' : function(v, record, field, data){ var v = record.data[field]; var min = data[field+'min'] === undefined ? (data[field+'min'] = v) : data[field+'min']; return v < min ? (data[field+'min'] = v) : min; }, 'average' : function(v, record, field, data){ var c = data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1); var t = (data[field+'total'] = ((data[field+'total']||0) + (record.data[field]||0))); return t === 0 ? 0 : t / c; } }; Ext.grid.GroupSummary.Calculations = Ext.ux.grid.GroupSummary.Calculations; /** * @class Ext.ux.grid.HybridSummary * @extends Ext.ux.grid.GroupSummary * Adds capability to specify the summary data for the group via json as illustrated here: *// define a custom summary function Ext.ux.grid.GroupSummary.Calculations['totalCost'] = function(v, record, field){ return v + (record.data.estimate * record.data.rate); }; *
* */ Ext.ux.grid.HybridSummary = Ext.extend(Ext.ux.grid.GroupSummary, { /** * @private * @param {Object} rs * @param {Object} cs */ calculate : function(rs, cs){ var gcol = this.view.getGroupField(), gvalue = rs[0].data[gcol], gdata = this.getSummaryData(gvalue); return gdata || Ext.ux.grid.HybridSummary.superclass.calculate.call(this, rs, cs); }, /** *{ data: [ { projectId: 100, project: 'House', taskId: 112, description: 'Paint', estimate: 6, rate: 150, due:'06/24/2007' }, ... ], summaryData: { 'House': { description: 14, estimate: 9, rate: 99, due: new Date(2009, 6, 29), cost: 999 } } } *
* @param {String} groupValue * @param {Object} data data object * @param {Boolean} skipRefresh (Optional) Defaults to false */ updateSummaryData : function(groupValue, data, skipRefresh){ var json = this.grid.getStore().reader.jsonData; if(!json.summaryData){ json.summaryData = {}; } json.summaryData[groupValue] = data; if(!skipRefresh){ this.refreshSummary(groupValue); } }, /** * Returns the summaryData for the specified groupValue or null. * @param {String} groupValue * @return {Object} summaryData */ getSummaryData : function(groupValue){ var reader = this.grid.getStore().reader, json = reader.jsonData, fields = reader.recordType.prototype.fields, v; if(json && json.summaryData){ v = json.summaryData[groupValue]; if(v){ return reader.extractValues(v, fields.items, fields.length); } } return null; } }); //backwards compat Ext.grid.HybridSummary = Ext.ux.grid.HybridSummary;grid.on('afteredit', function(){ var groupValue = 'Ext Forms: Field Anchoring'; summary.showSummaryMsg(groupValue, 'Updating Summary...'); setTimeout(function(){ // simulate server call // HybridSummary class implements updateSummaryData summary.updateSummaryData(groupValue, // create data object based on configured dataIndex {description: 22, estimate: 888, rate: 888, due: new Date(), cost: 8}); }, 2000); }); *