Već sam napravio jedan grid, za pregled komentara, i on izgleda ovako:

Pri kreiranju sam koristio onaj Module Pattern.
E sad, problem je što će i ostali grid-ovi biti jako slični ovom. Naravno, razlikovaće se samo column modeli, data record-i, i sl. Takođe, neki će imati taj Paging toolbar, a neki ne. Ali ja sad ne znam kako da idem dalje, odnosno, kako je najbolje da odradim ove ostale grid-ove, a da pritom pazim na rejuzabiliti... Ok, znam da mogu da idem jednostavno copy-paste koda od ovog grid-a, pa da napravim odogovarajuće izmene, al' to mi je najgluplje rešenje.

Jako mi je konfuzno to OOP u JS-u... :S Ne znam uopšte u kom pravcu da krenem. Verovatno bih trebao da radim neko izvođenje, samo ne znam iz koje komponente, kako, šta...

Evo koda od ovog grid-a sa slike, ako vam išta znači:
Ext.namespace('WFAdminManage');
WFAdminManage.comments = function() {
/******************/
/*--Private Area--*/
/*--Private Variables--*/
var dataRecord; //Ext data record.
var dataReader; //Ext data reader.
var dataStore; //Ext data store.
var colModel; //Column model.
var grid; //Grid object.
function setupDataSource() {
dataRecord = Ext.data.Record.create([
{name: 'id', type: 'int', mapping: 'id'},
{name: 'WFItemTitle', type: 'string', mapping: 'title'},
{name: 'authorName', type: 'string', mapping: 'author_name'},
{name: 'authorEmail', type: 'string', mapping: 'author_email'},
{name: 'authorUrl', type: 'string', mapping: 'author_url'},
{name: 'authorIp', type: 'string', mapping: 'author_ip'},
{name: 'text', type: 'string', mapping: 'text'},
{name: 'datetime', type: 'date', mapping: 'datetime'},
{name: 'status', type: 'string', mapping: 'status'}
]);
dataReader = new Ext.data.JsonReader({
root: 'results',
totalProperty: 'total',
id: 'id'
},
dataRecord
);
dataStore = new Ext.data.Store({
id: 'dataStore',
proxy: new Ext.data.HttpProxy({
url: $('#base_url').val() + '/front-end/admin_show_grids_handler.php',
method: 'POST'
}),
baseParams:{action: 'comments', cond: 'not_spam'},
reader: dataReader
});
dataStore.load({params:{start:0, limit:20}});
}
function getColumnModel() {
if (!colModel) { //Only need to create columnModel if it doesn't already exist.
function renderAuthorInfo(value, p, record) {
var newNotify = '';
if (record.data.status == 'awaiting') {
newNotify = '<b>new!</b>';
}
if (record.data.authorUrl.length > 0) {
return String.format('<span style = "font-size: 14px; font-weight: bold;">
<a href="' + $('#base_url').val() + '/admin/manage/comment/{1}">{0}</a>
</span> ' + newNotify + '<br /> ({2} | {3} | {4})',
value, record.data.id, record.data.authorUrl, record.data.authorEmail, record.data.authorIp);
}
else {
return String.format('<span style = "font-size: 14px; font-weight: bold;">
<a href="' + $('#base_url').val() + '/admin/manage/comment/{1}">{0}</a>
</span> ' + newNotify + '<br /> ({2} | {3})',
value, record.data.id, record.data.authorEmail, record.data.authorIp);
}
}
function renderDate(value, p, record) {
return String.format(value.dateFormat('d/m/Y'));
}
function renderActions(value, p, record) {
var status = '<a href="javascript: setStatus(\'ready\', ' + record.data.id + ');">Unapprove</a>';
if (record.data.status != 'approved') {
status = '<a href="javascript: setStatus(\'approved\', ' + record.data.id + ');">Approve</a>';
}
return String.format(status + ' |
<a href="javascript: markAsSpam(' + record.data.id + ');">Mark as spam</a> |
<a href="javascript: deleteComment(' + record.data.id + ');">Delete</a>'
);
}
this.sm = new Ext.grid.CheckboxSelectionModel();
colModel = new Ext.grid.ColumnModel([
sm,
{
header: 'Comment',
width: 430,
dataIndex: 'authorName',
renderer: renderAuthorInfo
},
{
header: 'Date',
width: 100,
dataIndex: 'datetime',
renderer: renderDate,
sortable: true
},
{
header: 'Actions',
width: 200,
dataIndex: 'id',
renderer: renderActions
}
]);
}
return colModel;
}
function buildGrid() {
function refreshGrid() {
dataStore.reload();
};
var pagingBar = new Ext.PagingToolbar({
pageSize: 20,
store: dataStore,
displayInfo: true,
displayMsg: 'Displaying comments {0} - {1} of {2}',
emptyMsg: 'There is no any comment in your webfolio.'
});
grid = new Ext.grid.GridPanel({
el:'comments_grid',
width:730,
height:560,
store:dataStore,
cm:getColumnModel(),
disableSelection:true,
sm:this.sm,
viewConfig: {
forceFit:true,
enableRowBody:true,
showPreview:true,
getRowClass : function(record, rowIndex, p, store){
if (this.showPreview) {
p.body = '<div style = "margin-left: 3px;">
<p>' + record.data.text + '</p>
<p style = " padding-top: 2px; border-top: 1px dashed;">
In ' + record.data.WFItemTitle + ', ' + record.data.datetime.dateFormat('d/m/Y, H:i') + '
</p>
</div>';
return 'x-grid3-row-expanded';
}
return 'x-grid3-row-collapsed';
}
},
tbar:[
{
text:'Approve',
tooltip:'Approve selected comments.',
handler: ''
},
'-',
{
text:'Unapprove',
tooltip:'Unapprove selected comments.',
handler: ''
},
'-',
{
text:'Mark as spam',
tooltip:'Mark selected comments as spam.',
handler: ''
},
'-',
{
text:'Delete',
tooltip:'Delete selected comments.',
handler: ''
},
'-',
{
pressed:true,
enableToggle:true,
text:'Details',
tooltip:'Show/hide text of a comment.',
cls:'x-btn-text-icon details',
toggleHandler: function(btn, pressed){
var view = grid.getView();
view.showPreview = pressed;
view.refresh();
}
}
],
bbar: pagingBar
});
grid.render();
}
/*--Private Area--*/
/******************/
/*****************/
/*--Public Area--*/
return {
init : function() {
this.getGrid();
},
getGrid: function() {
Ext.QuickTips.init(); //Enables Quicktips.
setupDataSource();
buildGrid();
},
}
/*--Public Area--*/
/*****************/
}();
Kol'ko sam shvatio, ovo što sam ja uradio je neki singleton, a ne znam šta bih trebao da uradim pa da od svega ovoga napravim neku osnovu, koju će moći da koriste ostali grid-ovi.