Extjs Grouping Header Grid Plugins
Scripter/EXTJS / 2008. 3. 6. 11:17
그리드를 그리다 보면 기존 HTML을 이용해서 <thead>를 colspan, rowspan을 이용해서 컬럼을 그룹핑 해줄수 있었다. 그러나 extjs gridpanel에서 방법을 찾다가 해당 플러그인을 찾았다.
실제작성예
소스다운로드
마크업
00_main.js
groupingHeader.js
GroupHeaderPlugin-HdMenu.js
출처 : extjs forum
실제작성예
소스다운로드
마크업
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Example</title>
<link rel="stylesheet" type="text/css" href="http://techbug.tistory.com/resources/css/ext-all.css" />
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all.js"></script>
<script type="text/javascript" src="./GroupHeaderPlugin-HdMenu.js"></script>
<script type="text/javascript" src="./groupingHeader.js"></script>
<script type="text/javascript" src="./00_main.js"></script>
<style type="text/css">
.ext-ie .x-grid3 table,.ext-safari .x-grid3 table {
table-layout:auto;
}
.ux-grid-hd-group-cell {
background: #f9f9f9 url(../../resources/images/default/grid/grid3-hrow.gif) repeat-x 0 bottom;
height:24px;
border-right: 1px solid rgb(208 208 208) !important;
}
.ux-grid-hd-group-nocolspan-cell {
border-right: 1px solid rgb(208 208 208) !important;
}
</style>
</head>
<body></body>
</html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Example</title>
<link rel="stylesheet" type="text/css" href="http://techbug.tistory.com/resources/css/ext-all.css" />
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all.js"></script>
<script type="text/javascript" src="./GroupHeaderPlugin-HdMenu.js"></script>
<script type="text/javascript" src="./groupingHeader.js"></script>
<script type="text/javascript" src="./00_main.js"></script>
<style type="text/css">
.ext-ie .x-grid3 table,.ext-safari .x-grid3 table {
table-layout:auto;
}
.ux-grid-hd-group-cell {
background: #f9f9f9 url(../../resources/images/default/grid/grid3-hrow.gif) repeat-x 0 bottom;
height:24px;
border-right: 1px solid rgb(208 208 208) !important;
}
.ux-grid-hd-group-nocolspan-cell {
border-right: 1px solid rgb(208 208 208) !important;
}
</style>
</head>
<body></body>
</html>
00_main.js
var techbugTestMain = function(){
return {
init: function(){
//그리드판넬 그리기 ----------------------------------------
this.gridPanel = new mainGridPanel();
//메인화면 레이아웃 설정-----------------------------------
this.mainViewPort = new Ext.Viewport({
layout:'border',
border:false,
items:[ this.gridPanel ]
});
this.mainViewPort.doLayout();
this.mainViewPort.syncSize();
}// End of Init();
}// End of return
}();
Ext.EventManager.onDocumentReady(techbugTestMain.init, techbugTestMain, true);
return {
init: function(){
//그리드판넬 그리기 ----------------------------------------
this.gridPanel = new mainGridPanel();
//메인화면 레이아웃 설정-----------------------------------
this.mainViewPort = new Ext.Viewport({
layout:'border',
border:false,
items:[ this.gridPanel ]
});
this.mainViewPort.doLayout();
this.mainViewPort.syncSize();
}// End of Init();
}// End of return
}();
Ext.EventManager.onDocumentReady(techbugTestMain.init, techbugTestMain, true);
groupingHeader.js
mainGridPanel = function(){
//실제 데이타 들어가기
var cmm = new Ext.grid.ColumnModel([
{id:"one", header:'아이디',width:25, sortable:true},
{header:'No',width:25},
{header:'텍스트',width:50},
{header:'Info',width:50},
{header:'Special',width:60},
{header:'No',width:25},
{header:'Text',width:50},
{header:'Info',width:50},
{header:'Special',width:60},
{header:'Special',width:60},
{header:'Changed',width:50}
]);
//실제 만드는 부분
cmm.rows = [
[
{header:"", align:"center", rowspan:2},
{header:"연구소", colspan:4, align:"center"},
{header:"데꾸벅", colspan:4, align:"center"},
{header:"넥스트리", colspan:2, align:"center", rowspan:2}
],[
{header:"", align:"center"},
{header:"팀명", colspan:3, align:"center"},
{header:"", align:"center" },
{header:"소속팀", colspan:3, align:"center"}
]
];
//그리드의 초기설정값을 저장한다.
mainGridPanel.superclass.constructor.call(this, {
region: 'center',
border: false,
margins:'0 0 0 0',
cm: cmm,
width: cmm.getTotalWidth(),
store: new Ext.data.Store({
reader: new Ext.data.JsonReader({ //데이타 들어가는 부분
fields: []
}),
data: []
}),
enableColumnMove: false,
enableDragDrop: false,
enableHdMenu: false,
height:100,
view: new Ext.grid.GridView({forceFit:true}),
title:'Array Grid',
plugins: new Ext.ux.plugins.GroupHeaderGrid(),
tbar: [
{
text:"저장",
cls: 'x-btn-icon',
scope:this,
handler : function(){alert('저장')}
}
]
});
};
Ext.extend(mainGridPanel,Ext.grid.GridPanel, { });
//실제 데이타 들어가기
var cmm = new Ext.grid.ColumnModel([
{id:"one", header:'아이디',width:25, sortable:true},
{header:'No',width:25},
{header:'텍스트',width:50},
{header:'Info',width:50},
{header:'Special',width:60},
{header:'No',width:25},
{header:'Text',width:50},
{header:'Info',width:50},
{header:'Special',width:60},
{header:'Special',width:60},
{header:'Changed',width:50}
]);
//실제 만드는 부분
cmm.rows = [
[
{header:"", align:"center", rowspan:2},
{header:"연구소", colspan:4, align:"center"},
{header:"데꾸벅", colspan:4, align:"center"},
{header:"넥스트리", colspan:2, align:"center", rowspan:2}
],[
{header:"", align:"center"},
{header:"팀명", colspan:3, align:"center"},
{header:"", align:"center" },
{header:"소속팀", colspan:3, align:"center"}
]
];
//그리드의 초기설정값을 저장한다.
mainGridPanel.superclass.constructor.call(this, {
region: 'center',
border: false,
margins:'0 0 0 0',
cm: cmm,
width: cmm.getTotalWidth(),
store: new Ext.data.Store({
reader: new Ext.data.JsonReader({ //데이타 들어가는 부분
fields: []
}),
data: []
}),
enableColumnMove: false,
enableDragDrop: false,
enableHdMenu: false,
height:100,
view: new Ext.grid.GridView({forceFit:true}),
title:'Array Grid',
plugins: new Ext.ux.plugins.GroupHeaderGrid(),
tbar: [
{
text:"저장",
cls: 'x-btn-icon',
scope:this,
handler : function(){alert('저장')}
}
]
});
};
Ext.extend(mainGridPanel,Ext.grid.GridPanel, { });
GroupHeaderPlugin-HdMenu.js
/**
* Plugin for grouped column headers
* @class Ext.ux.plugins.GroupHeaderGrid
* @extends Ext.util.Observable
* @author ?vind Neshaug
*
* Based on the code in this thread: http://extjs.com/forum/showthread.php?t=12677
* Thanks to JEBriggs for starting up the code and resizing code from Clayton
* Thanks to JorisA for the idea of making this a plugin instead of an extension.
*
* Supports infinte number of grouped header rows
* Supports header group spanning of rows
*
*/
Ext.namespace("Ext.ux.plugins");
Ext.ux.plugins.GroupHeaderGrid = function(config) {
Ext.apply(this, config);
};
Ext.extend(Ext.ux.plugins.GroupHeaderGrid, Ext.util.Observable, {
// PLUGIN INIT
init: function(grid){
this.grid = grid;
this.view = this.grid.getView();
this.cm = this.grid.getColumnModel();
this.initTemplates();
this.view.renderHeaders.createInterceptor(this.renderHeaders(),this);
// testing of linking bands up with headers control structure
//this.linkBandsAndHeaders();
},
initTemplates: function(){
this.view.initTemplates.call(this);
if(!this.templates.groupedHeader){
this.templates.groupedHeader = new Ext.Template(
'<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
'<thead>{groupRows}',
'<tr class="x-grid3-hd-row">{cells}</tr></thead>',
'</table>'
);
}
if (!this.templates.groupRow){
this.templates.groupRow = new Ext.Template(
'<tr class="x-grid3-hd-row">{groupCells}</tr>'
);
}
if(!this.templates.groupCell){
this.templates.groupCell = new Ext.Template(
'<td id="{grId}" class="{cellClass}" rowspan="{rowspan}" colspan="{colspan}"><div class="x-grid3-hd-inner" unselectable="on" style="text-align:{align}">{header}</div></td>'
);
}
},
renderHeaders : function(cm){
if (cm){
this.cm = cm;
}
if(!this.cm.rows) {
return true;
}
else {
this.view.renderHeaders = this.renderGroupedHeaders.createDelegate(this);
this.view.getHeaderCell = this.getHeaderCell.createDelegate(this);
this.view.updateSortIcon = this.updateSortIcon.createDelegate(this);
this.view.getColumnWidth = this.getColumnWidth.createDelegate(this);
this.view.getColumnStyle = this.getColumnStyle.createDelegate(this);
this.view.getTotalWidth = this.getTotalWidth.createDelegate(this);
this.view.updateColumnHidden=this.updateColumnHidden.createDelegate(this);
this.view.renderHeaders();
this.colModel = this.cm;
this.headerBandLinks = this.linkBandsAndHeaders();
return false;
}
},
renderGroupedHeaders : function() {
var cm = this.cm;
var rows = this.cm.rows;
var groups;
var cellTemplate = this.templates.hcell;
var cellMarkup = [], sb = [], cellParams = {};
var groupCellMarkup = [];
var rowsMarkup = [];
for (var i = 0; i < rows.length; i++) {//create markup for rows
groups = rows[i];
for (var j = 0; j < groups.length; j++) {//create markup for group cells
groups[j].id="ext-ux-gen-"+i+"-"+j;
groupCellMarkup[groupCellMarkup.length] = this.renderGroupCell(groups[j]);
}
rowsMarkup[rowsMarkup.length] = this.renderGroupRows(groupCellMarkup.join(""));
var groupCellMarkup = [];
}
for(var i = 0, len = cm.getColumnCount(); i < len; i++){ // create markup for leaf cells
cellMarkup[cellMarkup.length] = this.renderHeaderCell(cm, i);
}
// use a different template
return this.templates.groupedHeader.apply({groupRows: rowsMarkup.join(""), cells: cellMarkup.join(""), tstyle:'width:'+this.view.getTotalWidth()+';'});
},
renderGroupCell : function(group,groupId) {
var template = this.templates.groupCell;
var cellClass;
var rowspan;
if (group.colspan < 2 || group.colspan === undefined){
cellClass = "ux-grid-hd-group-nocolspan-cell";
}
else {
cellClass = "ux-grid-hd-group-cell";
}
return template.apply({
header: group.header,
colspan: group.colspan,
align: group.align,
rowspan: group.rowspan,
cellClass: cellClass,
grId: group.id
});
},
renderGroupRows : function(groupCellMarkup) {
var template = this.templates.groupRow;
return template.apply({groupCells: groupCellMarkup});
},
renderHeaderCell : function(cm,index){
var template = this.templates.hcell;
var params = {};
params.id = cm.getColumnId(index);
params.value = cm.getColumnHeader(index) || "";
params.style = this.view.getColumnStyle(index, true);
if(cm.config[index].align == 'right'){
params.istyle = 'padding-right:16px';
}
return template.apply(params);
},
// from gridview, with minor fixes
getHeaderCell : function(index){
var hds = this.view.mainHd.select('.x-grid3-cell');
return (hds.item(index).dom);
},
updateSortIcon : function(col, dir){
var sc = this.view.sortClasses;
var hds = this.view.mainHd.select('.x-grid3-cell').removeClass(sc);
hds.item(col).addClass(sc[dir == "DESC" ? 1 : 0]);
},
getColumnWidth : function(col){
var w = this.cm.getColumnWidth(col);
if(typeof w == 'number'){
return (Ext.isBorderBox ? w : (w-this.view.borderWidth > 0 ? w-this.view.borderWidth:0)) + 'px';
}
return w;
},
getColumnStyle : function(col, isHeader){
var style = !isHeader ? (this.cm.config[col].css || '') : '';
style += 'width:'+this.view.getColumnWidth(col)+';';
if(this.cm.isHidden(col)){
style += 'display:none;';
}
var align = this.cm.config[col].align;
if(align){
style += 'text-align:'+align+';';
}
return style;
},
getTotalWidth : function(){
return this.cm.getTotalWidth()+'px';
},
updateColumnHidden : function(col, hidden){
var tw = this.getTotalWidth();
var bands = this.headerBandLinks[col]||[];
this.view.innerHd.firstChild.firstChild.style.width = tw;
var display = hidden ? 'none' : '';
var hd = this.getHeaderCell(col);
hd.style.display = display;
var ns = this.view.getRows();
for(var i = 0, len = ns.length; i < len; i++){
ns[i].style.width = tw;
ns[i].firstChild.style.width = tw;
ns[i].firstChild.rows[0].childNodes[col].style.display = display;
}
for(var i = 0, len = bands.length; i < len; i++){
var bandId = bands[i];
var band = Ext.getDom(bandId);
if (hidden){
if (band.colSpan < 2 || band.colSpan === undefined){
band.style.display = 'none';
}
else{
band.colSpan += -1;
}
}
else{
if ((band.colSpan < 2 || band.colSpan === undefined)&&band.style.display === 'none'){
band.style.display = '';
}
else{
band.colSpan += 1;
}
}
}
this.view.onColumnHiddenUpdated(col, hidden, tw);
delete this.view.lastViewWidth; // force recalc
this.view.layout();
},
linkBandsAndHeaders : function(){
var bandsWithHeader;
var cm = this.grid.getColumnModel();
var columnCount = this.cm.getColumnCount();
var headers = new Array(columnCount);
var headerBands = new Array(columnCount);
for (var i = 0;i<columnCount;i++){
headers[i] = i;
}
var nrOfRows = cm.rows.length;
for (var i = 0;i<nrOfRows;i++){
var headersInRow = cm.rows[i];
var headersInRowCount = headersInRow.length;
var headerCounter = 0;
for (var j = 0;j<headersInRowCount;j++){
while(headers[headerCounter] === null){
headerCounter++;
}
if (headersInRow[j].colspan < 2 || headersInRow[j].colspan === undefined){
headers[j] = null;
var bands = headerBands[headerCounter]||[];
bands[bands.length]=headersInRow[j].id;
headerBands[headerCounter]=bands;
headerCounter++;
}
else {
for (var k = 0;k<headersInRow[j].colspan;k++){
var bands = headerBands[headerCounter]||[];
bands[bands.length]=headersInRow[j].id;
headerBands[headerCounter]=bands;
headerCounter++;
}
}
}
headerCounter = 0;
}
return headerBands;
}
});
* Plugin for grouped column headers
* @class Ext.ux.plugins.GroupHeaderGrid
* @extends Ext.util.Observable
* @author ?vind Neshaug
*
* Based on the code in this thread: http://extjs.com/forum/showthread.php?t=12677
* Thanks to JEBriggs for starting up the code and resizing code from Clayton
* Thanks to JorisA for the idea of making this a plugin instead of an extension.
*
* Supports infinte number of grouped header rows
* Supports header group spanning of rows
*
*/
Ext.namespace("Ext.ux.plugins");
Ext.ux.plugins.GroupHeaderGrid = function(config) {
Ext.apply(this, config);
};
Ext.extend(Ext.ux.plugins.GroupHeaderGrid, Ext.util.Observable, {
// PLUGIN INIT
init: function(grid){
this.grid = grid;
this.view = this.grid.getView();
this.cm = this.grid.getColumnModel();
this.initTemplates();
this.view.renderHeaders.createInterceptor(this.renderHeaders(),this);
// testing of linking bands up with headers control structure
//this.linkBandsAndHeaders();
},
initTemplates: function(){
this.view.initTemplates.call(this);
if(!this.templates.groupedHeader){
this.templates.groupedHeader = new Ext.Template(
'<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
'<thead>{groupRows}',
'<tr class="x-grid3-hd-row">{cells}</tr></thead>',
'</table>'
);
}
if (!this.templates.groupRow){
this.templates.groupRow = new Ext.Template(
'<tr class="x-grid3-hd-row">{groupCells}</tr>'
);
}
if(!this.templates.groupCell){
this.templates.groupCell = new Ext.Template(
'<td id="{grId}" class="{cellClass}" rowspan="{rowspan}" colspan="{colspan}"><div class="x-grid3-hd-inner" unselectable="on" style="text-align:{align}">{header}</div></td>'
);
}
},
renderHeaders : function(cm){
if (cm){
this.cm = cm;
}
if(!this.cm.rows) {
return true;
}
else {
this.view.renderHeaders = this.renderGroupedHeaders.createDelegate(this);
this.view.getHeaderCell = this.getHeaderCell.createDelegate(this);
this.view.updateSortIcon = this.updateSortIcon.createDelegate(this);
this.view.getColumnWidth = this.getColumnWidth.createDelegate(this);
this.view.getColumnStyle = this.getColumnStyle.createDelegate(this);
this.view.getTotalWidth = this.getTotalWidth.createDelegate(this);
this.view.updateColumnHidden=this.updateColumnHidden.createDelegate(this);
this.view.renderHeaders();
this.colModel = this.cm;
this.headerBandLinks = this.linkBandsAndHeaders();
return false;
}
},
renderGroupedHeaders : function() {
var cm = this.cm;
var rows = this.cm.rows;
var groups;
var cellTemplate = this.templates.hcell;
var cellMarkup = [], sb = [], cellParams = {};
var groupCellMarkup = [];
var rowsMarkup = [];
for (var i = 0; i < rows.length; i++) {//create markup for rows
groups = rows[i];
for (var j = 0; j < groups.length; j++) {//create markup for group cells
groups[j].id="ext-ux-gen-"+i+"-"+j;
groupCellMarkup[groupCellMarkup.length] = this.renderGroupCell(groups[j]);
}
rowsMarkup[rowsMarkup.length] = this.renderGroupRows(groupCellMarkup.join(""));
var groupCellMarkup = [];
}
for(var i = 0, len = cm.getColumnCount(); i < len; i++){ // create markup for leaf cells
cellMarkup[cellMarkup.length] = this.renderHeaderCell(cm, i);
}
// use a different template
return this.templates.groupedHeader.apply({groupRows: rowsMarkup.join(""), cells: cellMarkup.join(""), tstyle:'width:'+this.view.getTotalWidth()+';'});
},
renderGroupCell : function(group,groupId) {
var template = this.templates.groupCell;
var cellClass;
var rowspan;
if (group.colspan < 2 || group.colspan === undefined){
cellClass = "ux-grid-hd-group-nocolspan-cell";
}
else {
cellClass = "ux-grid-hd-group-cell";
}
return template.apply({
header: group.header,
colspan: group.colspan,
align: group.align,
rowspan: group.rowspan,
cellClass: cellClass,
grId: group.id
});
},
renderGroupRows : function(groupCellMarkup) {
var template = this.templates.groupRow;
return template.apply({groupCells: groupCellMarkup});
},
renderHeaderCell : function(cm,index){
var template = this.templates.hcell;
var params = {};
params.id = cm.getColumnId(index);
params.value = cm.getColumnHeader(index) || "";
params.style = this.view.getColumnStyle(index, true);
if(cm.config[index].align == 'right'){
params.istyle = 'padding-right:16px';
}
return template.apply(params);
},
// from gridview, with minor fixes
getHeaderCell : function(index){
var hds = this.view.mainHd.select('.x-grid3-cell');
return (hds.item(index).dom);
},
updateSortIcon : function(col, dir){
var sc = this.view.sortClasses;
var hds = this.view.mainHd.select('.x-grid3-cell').removeClass(sc);
hds.item(col).addClass(sc[dir == "DESC" ? 1 : 0]);
},
getColumnWidth : function(col){
var w = this.cm.getColumnWidth(col);
if(typeof w == 'number'){
return (Ext.isBorderBox ? w : (w-this.view.borderWidth > 0 ? w-this.view.borderWidth:0)) + 'px';
}
return w;
},
getColumnStyle : function(col, isHeader){
var style = !isHeader ? (this.cm.config[col].css || '') : '';
style += 'width:'+this.view.getColumnWidth(col)+';';
if(this.cm.isHidden(col)){
style += 'display:none;';
}
var align = this.cm.config[col].align;
if(align){
style += 'text-align:'+align+';';
}
return style;
},
getTotalWidth : function(){
return this.cm.getTotalWidth()+'px';
},
updateColumnHidden : function(col, hidden){
var tw = this.getTotalWidth();
var bands = this.headerBandLinks[col]||[];
this.view.innerHd.firstChild.firstChild.style.width = tw;
var display = hidden ? 'none' : '';
var hd = this.getHeaderCell(col);
hd.style.display = display;
var ns = this.view.getRows();
for(var i = 0, len = ns.length; i < len; i++){
ns[i].style.width = tw;
ns[i].firstChild.style.width = tw;
ns[i].firstChild.rows[0].childNodes[col].style.display = display;
}
for(var i = 0, len = bands.length; i < len; i++){
var bandId = bands[i];
var band = Ext.getDom(bandId);
if (hidden){
if (band.colSpan < 2 || band.colSpan === undefined){
band.style.display = 'none';
}
else{
band.colSpan += -1;
}
}
else{
if ((band.colSpan < 2 || band.colSpan === undefined)&&band.style.display === 'none'){
band.style.display = '';
}
else{
band.colSpan += 1;
}
}
}
this.view.onColumnHiddenUpdated(col, hidden, tw);
delete this.view.lastViewWidth; // force recalc
this.view.layout();
},
linkBandsAndHeaders : function(){
var bandsWithHeader;
var cm = this.grid.getColumnModel();
var columnCount = this.cm.getColumnCount();
var headers = new Array(columnCount);
var headerBands = new Array(columnCount);
for (var i = 0;i<columnCount;i++){
headers[i] = i;
}
var nrOfRows = cm.rows.length;
for (var i = 0;i<nrOfRows;i++){
var headersInRow = cm.rows[i];
var headersInRowCount = headersInRow.length;
var headerCounter = 0;
for (var j = 0;j<headersInRowCount;j++){
while(headers[headerCounter] === null){
headerCounter++;
}
if (headersInRow[j].colspan < 2 || headersInRow[j].colspan === undefined){
headers[j] = null;
var bands = headerBands[headerCounter]||[];
bands[bands.length]=headersInRow[j].id;
headerBands[headerCounter]=bands;
headerCounter++;
}
else {
for (var k = 0;k<headersInRow[j].colspan;k++){
var bands = headerBands[headerCounter]||[];
bands[bands.length]=headersInRow[j].id;
headerBands[headerCounter]=bands;
headerCounter++;
}
}
}
headerCounter = 0;
}
return headerBands;
}
});
출처 : extjs forum
'Scripter > EXTJS' 카테고리의 다른 글
Extjs를 이용한 간단한 form submit (0) | 2008.03.14 |
---|---|
Extjs를 이용한 ExtPHP, PHP-Ext 프로젝트 오픈 (0) | 2008.03.07 |
Extjs 크로스 도메인 관련 (0) | 2008.02.28 |
Extjs 한국어로 나타내기 (locale설정) (9) | 2008.02.27 |
ExtJS을 이용한 RestFul한 통신하기 (2) | 2008.02.26 |