기본적으로 grid의 View에 editor와 같이 다른 컴포넌트를 붙이기는 기존 소스보다 컴포넌트를 붙이는 소스가 더 많이 들어가는 경우가 있다.
데꾸벅의 경우도 프로젝트중 각각의 그리드 Row마다 progress bar를 붙여야 하는 경우가 생겼었는데..
포럼글을 뒤지다가 다음과 같은 좋은 사용자 플러그인이 있어 분석을 위해 소스를 까 보았다.
위 그림에서 보는바와 같이 그리드위에 버튼을 만들어 올릴때 new Ext.button이 아닌 new Ext.Action을 사용하여 사용자 플러그인을 사용한 소스이다.
소스 API 및
관련 포럼글
HTML
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="./css/icons.css">
<link rel="stylesheet" type="text/css" href="./css/Ext.ux.grid.RowActions.css">
<link rel="stylesheet" type="text/css" href="../../ext/ext-2.2/resources/css/ext-all.css" />
<script type="text/javascript" src="../../ext/ext-2.2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext/ext-2.2/ext-all.js"></script>
<script type="text/javascript" src="./js/Ext.ux.grid.RowActions.js"></script>
<script type="text/javascript" src="./js/Ext.ux.Toast.js"></script>
<script type="text/javascript" src="rowactions.js"></script>
</head>
<body></body>
</html>
JS
Ext.BLANK_IMAGE_URL = '';
Ext.ns('Example');
Example.version = '1.0';
Example.Grid = Ext.extend(Ext.grid.GridPanel, {
initComponent:function() {
// Create RowActions Plugin
this.action = new Ext.ux.grid.RowActions({
header:'Actions'
,autoWidth:true
,keepSelection:true
,actions:[{
iconIndex:'action1'
,qtipIndex:'qtip1'
,iconCls:'icon-open'
,tooltip:'Open'
},{
iconCls:'icon-wrench'
,tooltip:'Configure'
,qtipIndex:'qtip2'
,iconIndex:'action2'
,hideIndex:'hide2'
},{
iconIndex:'action3'
,qtipIndex:'qtip3'
,iconCls:'icon-user'
,tooltip:'User'
,style:'background-color:yellow'
}]
,groupActions:[{
iconCls:'icon-del-table'
,qtip:'Remove Table'
},{
iconCls:'icon-add-table'
,qtip:'Add Table - with callback'
,callback:function(grid, records, action, groupId) {
Ext.ux.Message.msg('Callback: icon-add-table'
, 'Group: <b>{0}</b>, action: <b>{1}</b>, records: <b>{2}</b>'
, groupId
, action
, records.length);
}
},{
iconCls:'icon-graph'
,qtip:'View Graph'
,align:'left'
}]
,callbacks:{
'icon-plus':function(grid, record, action, row, col) {
Ext.ux.Message.msg('Callback: icon-plus'
, 'You have clicked row: <b>{0}</b>, action: <b>{0}</b>'
, row
, action);
}
}
});
this.action.on({
action:function(grid, record, action, row, col) {
Ext.ux.Message.msg('Event: action', '클릭한 Row: <b>{0}</b>, 액션: <b>{1}</b>'
, row
, action);
}
,beforeaction:function() {
Ext.ux.Message.msg('Event: beforeaction', '핸들러에서 false반환시 액션취소.');
}
,beforegroupaction:function() {
Ext.ux.Message.msg('Event: beforegroupaction', '핸들러에서 false반환시 액션취소');
}
,groupaction:function(grid, records, action, groupId) {
Ext.ux.Message.msg('Event: groupaction', 'Group: <b>{0}</b>, action: <b>{1}</b>, records: <b>{2}</b>', groupId, action, records.length);
}
});
Ext.apply(this, {
store:new Ext.data.Store({
reader:new Ext.data.JsonReader({
id:'company'
,totalProperty:'totalCount'
,root:'rows'
,fields:[
{name: 'company'}
,{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
,{name: 'industry'}
,{name: 'desc'}
,{name: 'action1', type: 'string'}
,{name: 'action2', type: 'string'}
,{name: 'action3', type: 'string'}
,{name: 'qtip1', type: 'string'}
,{name: 'qtip2', type: 'string'}
,{name: 'qtip3', type: 'string'}
,{name: 'hide2', type: 'boolean'}
]
})
,proxy:new Ext.data.HttpProxy({url:'jsonData.json'})
,sortInfo:{field:'company', direction:'ASC'}
,listeners:{
load:{scope:this, fn:function() {
this.getSelectionModel().selectFirstRow();
}}
}
})
,columns:[
{id:'company',header: "Company", width: 40, sortable: true, dataIndex: 'company'}
,{header: "Industry", width: 20, sortable: true, dataIndex: 'industry'}
,{header: "Last Updated", width: 20, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
,this.action
]
,plugins:[this.action]
,loadMask:true
,viewConfig:{forceFit:true}
});
this.bbar = new Ext.PagingToolbar({
store:this.store
,displayInfo:true
,pageSize:10
});
Example.Grid.superclass.initComponent.apply(this, arguments);
}
,onRender:function() {
Example.Grid.superclass.onRender.apply(this, arguments);
this.store.load({params:{start:0, limit:10}});
}
});
//컴포넌트 등록
Ext.reg('techbuggrid', Example.Grid);
Ext.onReady(function() {
Ext.QuickTips.init();
var win = new Ext.Window({
width:600
,minWidth:320
,id:'agwin'
,height:400
,layout:'fit'
,border:false
,plain:true
,closable:false
,title:"그리드 Row Action 처리하기"
,items:{xtype:'techbuggrid',id:'actiongrid'}
});
win.show();
});
사용자 플러그인.JS
Ext.ns('Ext.ux.grid');
if('function' !== typeof RegExp.escape) {
RegExp.escape = function(s) {
if('string' !== typeof s) {
return s;
}
return s.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1');
};
}
Ext.ux.grid.RowActions = function(config) {
Ext.apply(this, config);
this.addEvents(
'beforeaction'
,'action'
,'beforegroupaction'
,'groupaction'
);
Ext.ux.grid.RowActions.superclass.constructor.call(this);
};
Ext.extend(Ext.ux.grid.RowActions, Ext.util.Observable, {
actionEvent:'click'
,autoWidth:true
,dataIndex:''
,header:''
,keepSelection:false
,menuDisabled:true
,sortable:false
,tplGroup:
'<tpl for="actions">'
+'<div class="ux-grow-action-item<tpl if="\'right\'===align"> ux-action-right</tpl> '
+'{cls}" style="{style}" qtip="{qtip}">{text}</div>'
+'</tpl>'
,tplRow:
'<div class="ux-row-action">'
+'<tpl for="actions">'
+'<div class="ux-row-action-item {cls} <tpl if="text">'
+'ux-row-action-text</tpl>" style="{hide}{style}" qtip="{qtip}">'
+'<tpl if="text"><span qtip="{qtip}">{text}</span></tpl></div>'
+'</tpl>'
+'</div>'
,hideMode:'visiblity'
,widthIntercept:4
,widthSlope:21
,init:function(grid) {
this.grid = grid;
if(!this.tpl) {
this.tpl = this.processActions(this.actions);
}
if(this.autoWidth) {
this.width = this.widthSlope * this.actions.length + this.widthIntercept;
this.fixed = true;
}
var view = grid.getView();
var cfg = {scope:this};
cfg[this.actionEvent] = this.onClick;
grid.afterRender = grid.afterRender.createSequence(function() {
view.mainBody.on(cfg);
grid.on('destroy', this.purgeListeners, this);
}, this);
if(!this.renderer) {
this.renderer = function(value, cell, record, row, col, store) {
cell.css += (cell.css ? ' ' : '') + 'ux-row-action-cell';
return this.tpl.apply(this.getData(value, cell, record, row, col, store));
}.createDelegate(this);
}
if(view.groupTextTpl && this.groupActions) {
view.interceptMouse = view.interceptMouse.createInterceptor(function(e) {
if(e.getTarget('.ux-grow-action-item')) {
return false;
}
});
view.groupTextTpl =
'<div class="ux-grow-action-text">' + view.groupTextTpl +'</div>'
+this.processActions(this.groupActions, this.tplGroup).apply()
;
}
if(true === this.keepSelection) {
grid.processEvent = grid.processEvent.createInterceptor(function(name, e) {
if('mousedown' === name) {
return !this.getAction(e);
}
}, this);
}
}
,getData:function(value, cell, record, row, col, store) {
return record.data || {};
}
,processActions:function(actions, template) {
var acts = [];
Ext.each(actions, function(a, i) {
if(a.iconCls && 'function' === typeof (a.callback || a.cb)) {
this.callbacks = this.callbacks || {};
this.callbacks[a.iconCls] = a.callback || a.cb;
}
var o = {
cls:a.iconIndex ? '{' + a.iconIndex + '}' : (a.iconCls ? a.iconCls : '')
,qtip:a.qtipIndex ? '{' + a.qtipIndex + '}' : (a.tooltip || a.qtip ? a.tooltip || a.qtip : '')
,text:a.textIndex ? '{' + a.textIndex + '}' : (a.text ? a.text : '')
,hide:a.hideIndex
? '<tpl if="' + a.hideIndex + '">'
+ ('display' === this.hideMode ? 'display:none' :'visibility:hidden') + ';</tpl>'
: (a.hide ? ('display' === this.hideMode ? 'display:none' :'visibility:hidden;') : '')
,align:a.align || 'right'
,style:a.style ? a.style : ''
};
acts.push(o);
}, this);
var xt = new Ext.XTemplate(template || this.tplRow);
return new Ext.XTemplate(xt.apply({actions:acts}));
}
,getAction:function(e) {
var action = false;
var t = e.getTarget('.ux-row-action-item');
if(t) {
action = t.className.replace(/ux-row-action-item /, '');
if(action) {
action = action.replace(/ ux-row-action-text/, '');
action = action.trim();
}
}
return action;
}
,onClick:function(e, target) {
var view = this.grid.getView();
var row = e.getTarget('.x-grid3-row');
var col = view.findCellIndex(target.parentNode.parentNode);
var action = this.getAction(e);
if(false !== row && false !== col && false !== action) {
var record = this.grid.store.getAt(row.rowIndex);
if(this.callbacks && 'function' === typeof this.callbacks[action]) {
this.callbacks[action](this.grid, record, action, row.rowIndex, col);
}
if(true !== this.eventsSuspended && false === this.fireEvent('beforeaction', this.grid, record, action, row.rowIndex, col)) {
return;
}
else if(true !== this.eventsSuspended) {
this.fireEvent('action', this.grid, record, action, row.rowIndex, col);
}
}
t = e.getTarget('.ux-grow-action-item');
if(t) {
var group = view.findGroup(target);
var groupId = group ? group.id.replace(/ext-gen[0-9]+-gp-/, '') : null;
var records;
if(groupId) {
var re = new RegExp(RegExp.escape(groupId));
records = this.grid.store.queryBy(function(r) {
return r._groupId.match(re);
});
records = records ? records.items : [];
}
action = t.className.replace(/ux-grow-action-item (ux-action-right )*/, '');
if('function' === typeof this.callbacks[action]) {
this.callbacks[action](this.grid, records, action, groupId);
}
if(true !== this.eventsSuspended && false === this.fireEvent('beforegroupaction', this.grid, records, action, groupId)) {
return false;
}
this.fireEvent('groupaction', this.grid, records, action, groupId);
}
}
});
Ext.reg('rowactions', Ext.ux.grid.RowActions);
요기 괜찮은 사용자 플러그인도 함 보세요