Code:
/*
* GroupHeaderGrid version 1.4 for Ext 3
*/
Ext.namespace("Ext.ux.plugins");
if(Ext.isWebKit){
Ext.grid.GridView.prototype.borderWidth = 0;
}
Ext.ux.plugins.GroupHeaderGrid = function(config) {
this.config = config;
};
Ext.extend(Ext.ux.plugins.GroupHeaderGrid, Ext.util.Observable, {
init: function(grid) {
Ext.applyIf(grid.colModel, this.config);
Ext.apply(grid.getView(), this.viewConfig);
},
viewConfig: {
initTemplates: function() {
this.constructor.prototype.initTemplates.apply(this, arguments);
var ts = this.templates || {};
if (!ts.gcell) {
ts.gcell = new Ext.XTemplate(
'<td class="x-grid3-hd x-grid3-gcell x-grid3-td-{id} ux-grid-hd-group-row-{row} {cls}" style="{style}">',
'<div {tooltip} class="x-grid3-hd-inner x-grid3-hd-{id}" unselectable="on" style="{istyle}">',
this.grid.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '',
'{value}</div></td>'
);
}
this.templates = ts;
this.hrowRe = new RegExp("ux-grid-hd-group-row-(\\d+)", "");
},
renderHeaders: function() {
var ts = this.templates, headers = [], cm = this.cm, rows = cm.rows, tstyle = 'width:' + this.getTotalWidth() + ';';
for (var row = 0, rlen = rows.length; row < rlen; row++) {
var r = rows[row], cells = [];
for (var i = 0, gcol = 0, len = r.length; i < len; i++) {
var group = r[i];
group.colspan = group.colspan || 1;
var id = this.getColumnId(group.dataIndex ? cm.findColumnIndex(group.dataIndex) : gcol);
var gs = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupStyle.call(this, group, gcol);
cells[i] = ts.gcell.apply({
cls: group.header ? 'ux-grid-hd-group-cell' : 'ux-grid-hd-nogroup-cell',
id: id,
row: row,
style: 'width:' + gs.width + ';' + (gs.hidden ? 'display:none;' : '') + (group.align ? 'text-align:' + group.align + ';' : ''),
tooltip: group.tooltip ? (Ext.QuickTips.isEnabled() ? 'ext:qtip' : 'title') + '="' + group.tooltip + '"' : '',
istyle: group.align == 'right' ? 'padding-right:16px' : '',
btn: this.grid.enableHdMenu && group.header,
value: group.header || ' '
});
gcol += group.colspan;
}
// hide the top header //custom
if(row==0)
{
headers[row] = ts.header.apply({
tstyle: tstyle + 'display: none;' ,
cells: cells.join('')
});
}
else
{
headers[row] = ts.header.apply({
tstyle: tstyle,
cells: cells.join('')
});
}
}
headers.push(this.constructor.prototype.renderHeaders.apply(this, arguments));
return headers.join('');
},
onColumnWidthUpdated : function(){
this.constructor.prototype.onColumnWidthUpdated.apply(this, arguments);
Ext.ux.plugins.GroupHeaderGrid.prototype.updateGroupStyles.call(this);
},
onAllColumnWidthsUpdated : function(){
this.constructor.prototype.onAllColumnWidthsUpdated.apply(this, arguments);
Ext.ux.plugins.GroupHeaderGrid.prototype.updateGroupStyles.call(this);
},
onColumnHiddenUpdated : function(){
this.constructor.prototype.onColumnHiddenUpdated.apply(this, arguments);
Ext.ux.plugins.GroupHeaderGrid.prototype.updateGroupStyles.call(this);
// this.updateGroupWidths();
},
// private
updateGroupWidths : function(){
if(!this.enableGrouping || !this.hasRows()){
return;
}
var tw = Math.max(this.cm.getTotalWidth(), this.el.dom.offsetWidth-this.getScrollOffset()) +'px';
var gs = this.getGroups();
for(var i = 0, len = gs.length; i < len; i++){
gs[i].firstChild.style.width = tw;
}
},
getHeaderCell : function(index){
return this.mainHd.query(this.cellSelector)[index];
},
findHeaderCell : function(el){
return el ? this.fly(el).findParent('td.x-grid3-hd', this.cellSelectorDepth) : false;
},
findHeaderIndex : function(el){
var cell = this.findHeaderCell(el);
return cell ? this.getCellIndex(cell) : false;
},
updateSortIcon : function(col, dir){
var sc = this.sortClasses;
var hds = this.mainHd.select(this.cellSelector).removeClass(sc);
hds.item(col).addClass(sc[dir == "DESC" ? 1 : 0]);
},
handleHdMenuClick : function(item){
var index = this.hdCtxIndex,
cm = this.cm,
ds = this.ds,
id = item.getItemId();
switch(id){
case 'asc':
ds.sort(cm.getDataIndex(index), 'ASC');
break;
case 'desc':
ds.sort(cm.getDataIndex(index), 'DESC');
break;
default:
if(id.substr(0, 5) == 'group'){
var i = id.split('-'),
row = parseInt(i[1], 10), col = parseInt(i[2], 10),
r = this.cm.rows[row], group, gcol = 0;
for (var i = 0, len = r.length; i < len; i++) {
group = r[i];
if (col >= gcol && col < gcol + group.colspan) {
break;
}
gcol += group.colspan;
}
if(item.checked){
var max = cm.getColumnsBy(this.isHideableColumn, this).length;
for (var i = gcol, len = gcol + group.colspan; i < len; i++){
if(!cm.isHidden(i)){
max--;
}
}
if(max < 1){
this.onDenyColumnHide();
return false;
}
}
for (var i = gcol, len = gcol + group.colspan; i < len; i++){
if(cm.config[i].fixed !== true && cm.config[i].hideable !== false){
cm.setHidden(i, item.checked);
}
}
}
else{
index = cm.getIndexById(id.substr(4));
if(index != -1){
if(item.checked && cm.getColumnsBy(this.isHideableColumn, this).length <= 1){
this.onDenyColumnHide();
return false;
}
cm.setHidden(index, item.checked);
}
}
item.checked = !item.checked; //custom
if(item.menu){
var updateChildren = function(menu){
menu.items.each(function(childItem){
if(!childItem.disabled){
childItem.setChecked(item.checked, true);
if(childItem.menu){
updateChildren(childItem.menu);
}
}
});
}
updateChildren(item.menu);
}
var parentMenu = item, parentItem;
while(parentMenu = parentMenu.parentMenu){
if (typeof console != 'undefined') { //// if condition //custom
console.log(parentMenu);
}
if(!parentMenu.parentMenu ||
!(parentItem = parentMenu.parentMenu.items.get(parentMenu.getItemId())) ||
!parentItem.setChecked){
break;
}
var checked = parentMenu.items.findIndexBy(function(m){
return m.checked;
}) >= 0;
parentItem.setChecked(checked, true);
}
item.checked = !item.checked;
}
return true;
},
// =-----------e
isHideableColumn : function(c){
return !c.hidden && !c.fixed;
},
beforeColMenuShow : function(){
var cm = this.cm, rows = this.cm.rows;
this.colMenu.removeAll();
for(var col = 0, clen = cm.getColumnCount(); col < clen; col++){
var menu = this.colMenu, text = cm.getColumnHeader(col);
if(cm.config[col].fixed !== true && cm.config[col].hideable !== false){
for (var row = 0, rlen = rows.length; row < rlen; row++) {
var r = rows[row], group, gcol = 0;
for (var i = 0, len = r.length; i < len; i++) {
group = r[i];
if (col >= gcol && col < gcol + group.colspan) {
break;
}
gcol += group.colspan;
}
if (group && group.header) {
if (cm.hierarchicalColMenu) {
var gid = 'group-' + row + '-' + gcol;
var item = menu.items.item(gid);
var submenu = item ? item.menu : null;
if (!submenu) {
submenu = new Ext.menu.Menu({itemId: gid+ '-hctx'});
submenu.on("itemclick", this.handleHdMenuClick, this);
var checked = false, disabled = true;
for(var c = gcol, lc = gcol + group.colspan; c < lc; c++){
if(!cm.isHidden(c)){
checked = true;
}
if(cm.config[c].hideable !== false){
disabled = false;
}
}
menu.add({
itemId: gid,
text: group.header,
menu: submenu,
hideOnClick:false,
checked: checked,
disabled: disabled
});
}
menu = submenu;
} else {
text = group.header + ' ' + text;
}
}
}
menu.add(new Ext.menu.CheckItem({
itemId: "col-"+cm.getColumnId(col),
text: text,
checked: !cm.isHidden(col),
hideOnClick:false,
disabled: cm.config[col].hideable === false
}));
}
}
},
renderUI : function(){
this.constructor.prototype.renderUI.apply(this, arguments);
// Ext.apply(this.columnDrop, Ext.ux.plugins.GroupHeaderGrid.prototype.columnDropConfig);
}
},
columnDropConfig : {
getTargetFromEvent : function(e){
var t = Ext.lib.Event.getTarget(e);
return this.view.findHeaderCell(t);
},
positionIndicator : function(h, n, e){
var data = Ext.ux.plugins.GroupHeaderGrid.prototype.getDragDropData.call(this, h, n, e);
if (data === false) {
return false;
}
var px = data.px + this.proxyOffsets[0];
this.proxyTop.setLeftTop(px, data.r.top + this.proxyOffsets[1]);
this.proxyTop.show();
this.proxyBottom.setLeftTop(px, data.r.bottom);
this.proxyBottom.show();
return data.pt;
},
onNodeDrop : function(n, dd, e, data){
var h = data.header;
if(h != n){
var d = Ext.ux.plugins.GroupHeaderGrid.prototype.getDragDropData.call(this, h, n, e);
var row = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupRowIndex.call(this.view, h);
// if (d === false) { //custom
// return false;
// }
// if (d.comment =="no") { //custom
// return false;
// }
var cm = this.grid.colModel, right = d.oldIndex < d.newIndex, rows = cm.rows;
for (var row = d.row, rlen = rows.length; row < rlen; row++) {
var r = rows[row], len = r.length, fromIx = 0, span = 1, toIx = len;
for (var i = 0, gcol = 0; i < len; i++) {
var group = r[i];
if (d.oldIndex >= gcol && d.oldIndex < gcol + group.colspan) {
fromIx = i;
}
if (d.oldIndex + d.colspan - 1 >= gcol && d.oldIndex + d.colspan - 1 < gcol + group.colspan) {
span = i - fromIx + 1;
}
if (d.newIndex >= gcol && d.newIndex < gcol + group.colspan) {
toIx = i;
}
gcol += group.colspan;
}
var groups = r.splice(fromIx, span);
rows[row] = r.splice(0, toIx - (right ? span : 0)).concat(groups).concat(r);
}
for (var c = 0; c < d.colspan; c++) {
var oldIx = d.oldIndex + (right ? 0 : c), newIx = d.newIndex + (right ? -1 : c);
var newparentGroup = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupSpan.call(this.view, row - 1, newIx); //custom
var oldparentGroup = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupSpan.call(this.view, row - 1, oldIx); //custom
var oldGroup = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupSpan.call(this.view, row, oldIx); //custom
var newGroup = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupSpan.call(this.view, row, newIx); //custom
//if the fields are of not same group
if(newparentGroup.header!=oldparentGroup.header)
{
return false;
}
//if the fields are of not same group //custom
if(newGroup.colspan!=oldGroup.colspan)
{
return false;
}
//if the fields are of not same group //custom
if(newparentGroup.colspan!=oldparentGroup.colspan)
{
return false;
}
cm.moveColumn(oldIx, newIx);
// this.grid.fireEvent("columnmove", oldIx, newIx); //custom
}
return true;
}
return false;
}
},
getGroupStyle: function(group, gcol) {
var width = 0, hidden = true;
for (var i = gcol, len = gcol + group.colspan; i < len; i++) {
if (!this.cm.isHidden(i)) {
var cw = this.cm.getColumnWidth(i);
if(typeof cw == 'number'){
width += cw;
}
hidden = false;
}
}
return {
width: (Ext.isBorderBox ? width : Math.max(width - this.borderWidth, 0)) + 'px',
hidden: hidden
};
},
updateGroupStyles: function(col) {
var tables = this.mainHd.query('.x-grid3-header-offset > table'), tw = this.getTotalWidth(), rows = this.cm.rows;
for (var row = 0; row < tables.length; row++) {
tables[row].style.width = tw;
if (row < rows.length) {
var cells = tables[row].firstChild.firstChild.childNodes;
for (var i = 0, gcol = 0; i < cells.length; i++) {
var group = rows[row][i];
if ((typeof col != 'number') || (col >= gcol && col < gcol + group.colspan)) {
var gs = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupStyle.call(this, group, gcol);
cells[i].style.width = gs.width;
cells[i].style.display = gs.hidden ? 'none' : '';
}
gcol += group.colspan;
}
}
}
},
getGroupRowIndex : function(el){
if(el){
var m = el.className.match(this.hrowRe);
if(m && m[1]){
return parseInt(m[1], 10);
}
}
return this.cm.rows.length;
},
getGroupSpan : function(row, col) {
if (row < 0) {
return {col: 0, colspan: this.cm.getColumnCount(), header:''};
}
var ghdr=''; // header return is custom
var r = this.cm.rows[row];
if (r) {
for(var i = 0, gcol = 0, len = r.length; i < len; i++) {
var group = r[i];
ghdr=group.header;
if (col >= gcol && col < gcol + group.colspan) {
return {col: gcol, colspan: group.colspan, header:ghdr};
}
gcol += group.colspan;
}
return {col: gcol, colspan: 0, header:ghdr};
}
return {col: col, colspan: 1, header:ghdr};
},
getDragDropData : function(h, n, e){
if (h.parentNode != n.parentNode) {
return false;
}
var cmt='';//comment to check before node drop
var cm = this.grid.colModel;
var x = Ext.lib.Event.getPageX(e);
var r = Ext.lib.Dom.getRegion(n.firstChild);
var px, pt;
if((r.right - x) <= (r.right-r.left)/2){
px = r.right+this.view.borderWidth;
pt = "after";
}
else{
px = r.left;
pt = "before";
}
var oldIndex = this.view.getCellIndex(h);
var newIndex = this.view.getCellIndex(n);
if(cm.isFixed(newIndex)){
return false;
}
var row = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupRowIndex.call(this.view, h);
var oldGroup = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupSpan.call(this.view, row, oldIndex);
var newGroup = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupSpan.call(this.view, row, newIndex);
oldIndex = oldGroup.col;
newIndex = newGroup.col + (pt == "after" ? newGroup.colspan : 0);
if(newIndex >= oldGroup.col && newIndex <= oldGroup.col + oldGroup.colspan){
return false;
}
var newparentGroup = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupSpan.call(this.view, row - 1, newIndex); //custom
var oldparentGroup = Ext.ux.plugins.GroupHeaderGrid.prototype.getGroupSpan.call(this.view, row - 1, oldIndex);
if(pt=='before') //custom
{
if(newparentGroup.colspan==oldparentGroup.colspan) //custom
{
if (newIndex < oldparentGroup.col || newIndex > oldparentGroup.col + oldparentGroup.colspan) {
return false;
}
}
}
return {
r: r,
px: px,
pt: pt,
row: row,
oldIndex: oldIndex,
newIndex: newIndex,
colspan: oldGroup.colspan,
comment:cmt
};
}
});