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:
summaryRenderer: function(v, params, data){
return ((v === 0 || v > 1) ? '(' + v +' Tasks)' : '(1 Task)');
},
*
*/
/**
* @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;
this.cm = grid.getColumnModel();
this.view = grid.getView();
var v = this.view;
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(
'','
'',
'{cells}',
'
);
this.rowTpl.disableFormats = true;
}
this.rowTpl.compile();
if(!this.cellTpl){
this.cellTpl = new Ext.Template(
'',
'{value}',
""
);
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.cm.config;
var 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.cm.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){
var gs = this.view.getGroups(), s;
for(var i = 0, len = gs.length; 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){
var gs = this.view.getGroups(), s, cells, wlen = ws.length;
for(var i = 0, len = gs.length; i < len; i++){
s = gs[i].childNodes[2];
s.style.width = tw;
s.firstChild.style.width = tw;
cells = s.firstChild.rows[0].childNodes;
for(var j = 0; j < wlen; j++){
cells[j].style.width = ws[j];
}
}
},
doHidden : function(col, hidden, tw){
var gs = this.view.getGroups(), s, display = hidden ? 'none' : '';
for(var i = 0, len = gs.length; 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;
}
},
// 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 = document.getElementById(gid);
if(!g){
return false;
}
var rs = [];
this.grid.store.each(function(r){
if(r._groupId == gid){
rs[rs.length] = r;
}
});
var cs = this.view.getColumnData();
var data = this.calculate(rs, cs);
var markup = this.renderSummary({data: data}, cs);
var 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.
*
grid.on('afteredit', function(){
var groupValue = 'Ext Forms: Field Anchoring';
summary.showSummaryMsg(groupValue, 'Updating Summary...');
});
*
* @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);
var node = this.getSummaryNode(gid);
if(node){
node.innerHTML = '' + 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
* customsummaryType=totalCost
:
// define a custom summary function
Ext.ux.grid.GroupSummary.Calculations['totalCost'] = function(v, record, field){
return v + (record.data.estimate * record.data.rate);
};
*
* @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:
*
{
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
}
}
}
*
*
*/
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();
var gvalue = rs[0].data[gcol];
var gdata = this.getSummaryData(gvalue);
return gdata || Ext.ux.grid.HybridSummary.superclass.calculate.call(this, rs, cs);
},
/**
*
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);
});
*
* @param {String} groupValue
* @param {Object} data data object
* @param {Boolean} skipRefresh (Optional) Defaults to false
*/
updateSummaryData : function(groupValue, data, skipRefresh){
var json = this.grid.store.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 json = this.grid.store.reader.jsonData;
if(json && json.summaryData){
return json.summaryData[groupValue];
}
return null;
}
});
//backwards compat
Ext.grid.HybridSummary = Ext.ux.grid.HybridSummary;