jelt
22 May 2008, 7:21 AM
Hi everyone, today i come to share with you my first extension.
Live Demo available here (http://ext4sap.free.fr/GWC-grid.html)
GridConfigWindow is a little plugin to have all common grid config parameters in an unique window. (see screenshot)
It add a button to call the window (top or bottom toolbar of the grid, you choose).
In the window, you can define :
- order of the columns
- size of each column
- columns displayed
- the sort column and the sort order
Change are applied only when you push "apply" button.
This plugin use the wonderfull Ext.ux.Sortable plugin : http://www.extjs.com/forum/showthread.php?t=29033
Usage : Use it as a plugin of the gridpanel, it add a button on bottom or top toolbar if asked.
/**
* Grid Config Window plugin for Ext.grid.GridPanel
* @author Jelt
* @copyright No thanks
* @date 21. May 2008
* @version 2008-05-27 15:00:00 - Jelt
* include Ext.ux.Sortable 0.45, by Rowan
* http://www.extjs.com/forum/showthread.php?t=29033
*/
Ext.namespace('Ext.ux', 'Ext.ux.grid');
Ext.ux.grid.ConfigWindow = function(config) {
Ext.apply(this, config);
Ext.ux.grid.ConfigWindow.superclass.constructor.call(this);
};
Ext.extend(Ext.ux.grid.ConfigWindow, Ext.util.Observable, {
// options
position:'top' // position Where to display the button. Valid values are 'top', 'bottom' and ''. Use '' to not display button (window can be called by the showWindow() function)
,iconCls:'icon-magnifier' // Icon class for menu button
,windowMaximizable:true // Display window maximize icon
,sortColumn:true
,displayColumn:true
,sizeColumn:true
// Localisation
,buttonText:'Layout' // Text to display on menu button
,buttonTipText:'Configure layout of the grid' // Text to display as input tooltip
,windowTitle:'Grid Layout Configuration' //Text of the config window
,windowButtonApplyText:'Apply' //Text of the Aplpy button in window
,windowButtonCancelText:'Cancel' //Text of the Aplpy button in window
,windowHeaderFieldText:'Field Order'
,windowHeaderSizeText:'Size'
,windowHeaderDisplayText:'Display'
,windowHeaderSortText:'Sort<br>A / D'
,init:function(grid) {
if (this.buttonTipText != '') { // Be sure quicktip is enabled if required
Ext.QuickTips.init();
}
this.grid = grid;
this.GCW_id = Ext.id();
if (this.position != '') { // Draw button if required
grid.onRender = grid.onRender.createSequence(this.onRender, this);
}
}
,onRender:function() {
var grid = this.grid;
var tb = 'bottom' == this.position ? grid.bottomToolbar : grid.topToolbar;
if(0 < tb.items.getCount()) { tb.addSeparator(); }
this.layoutButton = new Ext.Button({
text: this.buttonText
, cls: 'x-btn-text-icon details'
,iconCls:this.iconCls
,tooltip:this.buttonTipText
});
tb.add(this.layoutButton);
this.layoutButton.on('click',function() { this.showWindow();},this);
}
,hideWindow:function() { // Hide config window
this.config_window.hide();
this.sortable1.disable();
}
,showWindow:function() { // Display config window
var myCols = this.grid.getColumnModel();
var myStore = this.grid.getStore();
var div_width = 303 //470;
var win_width = 343 //510;
if (this.sizeColumn){
div_width += 52;
win_width += 52;
}
if (this.displayColumn){
div_width += 62;
win_width += 62;
}
if (this.sortColumn){
div_width += 52;
win_width += 52;
}
li_template = '<div id="'+this.GCW_id+'_li_{0}" style="border:1px dotted #999999;width:'+div_width+';vertical-align:center"><table><tr class="x-grid3-row"><td width="300" id="handle_'+this.GCW_id+'_li_{0}" class="handle">{1}</td>';
if (this.sizeColumn){
li_template += '<td width="50" align="center" class="x-small-editor"><input type="text" id="'+this.GCW_id+'_sz_{0}" size=3 class="x-form-field"></td>';
}
if (this.displayColumn){
li_template += '<td width="60" align="center"><input type="checkbox" id="'+this.GCW_id+'_cb_{0}"></td>';
}
if (this.sortColumn){
li_template += '<td width="50" align="center"><input type="radio" name="sort_field_order" value="A_{0}" id="'+this.GCW_id+'_sort_{0}_A"> <input type="radio" name="sort_field_order" value="D_{0}" id="'+this.GCW_id+'_sort_{0}_D"></td>';
}
li_template += '</tr></table></div>';
// header
var config_ul_inner_array = new Array('<table class="x-grid3-header"><tr class="x-grid3-hd-row"><td width="299">'+this.windowHeaderFieldText+'</td>');
if (this.sizeColumn){
config_ul_inner_array[config_ul_inner_array.length] = '<td width="48" align="center">'+this.windowHeaderSizeText+'</td>';
}
if (this.displayColumn){
config_ul_inner_array[config_ul_inner_array.length] = '<td align="center" width="58">'+this.windowHeaderDisplayText+'</td>';
}
if (this.sortColumn){
config_ul_inner_array[config_ul_inner_array.length] = '<td align="center" width="49">'+this.windowHeaderSortText+'</td>';
}
config_ul_inner_array[config_ul_inner_array.length] = '</tr></table>';
// items
for (j=0;j<myCols.config.length;j++){
config_ul_inner_array[config_ul_inner_array.length] = String.format(li_template, myCols.config[j].dataIndex,myCols.config[j].header);
}
if (!this.config_window) {
Ext.util.CSS.createStyleSheet('.GCW_window .x-panel-body{overflow-y:auto;} .handle {cursor : move;}');
this.config_window = new Ext.Window({
title:this.windowTitle
,cls:'GCW_window'
,maximizable:this.windowMaximizable,autoScroll:true
,plain:true,closeAction:'hide'
,layout:'fit',modal:true
,resizable:true, shadow:false
,width: win_width, height: 280
,items:new Ext.Panel({ html:'<form name="'+this.GCW_id+'_config_form"><div id="'+this.GCW_id+'_div_content"></div></form>' }) // applyTo:'config_div'})
,buttonAlign:'center'
// Apply button
,buttons: [{text:this.windowButtonApplyText,handler:function(){
this.hideWindow();
// Sort
if (this.sortColumn){
for (var i=0; i<document.forms[this.GCW_id+"_config_form"].elements["sort_field_order"].length;i++) {
if (document.forms[this.GCW_id+"_config_form"].elements["sort_field_order"][i].checked) {
var field = document.forms[this.GCW_id+"_config_form"].elements["sort_field_order"][i].value;
if (field.substr(0,1)=='A'){
field = field.substr(2,32);
if ((!myStore.sortInfo)||(myStore.sortInfo.field != field)||(myStore.sortInfo.direction != 'ASC')) {
myStore.sort(field,'ASC');
}
} else {
field = field.substr(2,32);
if ((!myStore.sortInfo)||(myStore.sortInfo.field != field)||(myStore.sortInfo.direction != 'DESC')) {
myStore.sort(field,'DESC');
}
}
break;
}
}
}
// order, hidden, size
var list_sorted = this.sortable1.serialise();
var config_new = new Array();
var to_bypass = 4 + this.GCW_id.length;
for (var i=0;i<list_sorted.length;i++){
var field = list_sorted[i].id.substr(to_bypass,30);
if (myCols.config[i].dataIndex == field){
j = i;
} else {
for (var j=0;j<myCols.config.length;j++){
if (myCols.config[j].dataIndex == field){
break;
}
}
}
config_new[config_new.length] = myCols.config[j];
if (this.sizeColumn){
config_new[i].width = parseInt(Ext.getDom(this.GCW_id+'_sz_'+field).value); // set column width
}
if (this.displayColumn){
config_new[i].hidden = !Ext.getDom(this.GCW_id+'_cb_'+field).checked; // set column hidden
}
}
myCols.setConfig( config_new );
// Cancel button
}.createDelegate(this)},{ text: this.windowButtonCancelText, handler: function(){ this.hideWindow() }.createDelegate(this) }] });
this.config_window.render(document.body);
}
Ext.getDom(this.GCW_id+'_div_content').innerHTML = config_ul_inner_array.join('');
if (!this.sortable1) {
this.sortable1 = new Ext.ux.Sortable({
tagName:'div',container : this.GCW_id+'_div_content'
,handles : true });
} else {
this.sortable1.enable();
}
// values
if ((this.displayColumn)||(this.sizeColumn)){
for (j=0;j<myCols.config.length;j++){
if (this.displayColumn){
Ext.getDom(this.GCW_id+'_cb_'+myCols.config[j].dataIndex).checked = !myCols.config[j].hidden; // display fields
if (myCols.config[j].hideable==false)
Ext.getDom(this.GCW_id+'_cb_'+myCols.config[j].dataIndex).disabled = true;
}
if (this.sizeColumn){
Ext.getDom(this.GCW_id+'_sz_'+myCols.config[j].dataIndex).value=myCols.config[j].width; // size
if (myCols.config[j].resizable==false)
Ext.getDom(this.GCW_id+'_sz_'+myCols.config[j].dataIndex).disabled = true;
}
if (this.sortColumn){
if (myCols.config[j].sortable==false){
Ext.getDom(this.GCW_id+'_sort_'+myCols.config[j].dataIndex+'_A').disabled = true;
Ext.getDom(this.GCW_id+'_sort_'+myCols.config[j].dataIndex+'_D').disabled = true;
}
}
}
}
if (this.sortColumn){
if ((myStore.sortInfo)&&(myStore.sortInfo.field)&&(myStore.sortInfo.direction)){
if (myStore.sortInfo.direction == 'ASC'){ // sort
Ext.getDom(this.GCW_id+'_sort_'+myStore.sortInfo.field+'_A').checked=true;
} else {
Ext.getDom(this.GCW_id+'_sort_'+myStore.sortInfo.field+'_D').checked=true;
}
}
}
this.config_window.show();
} //EO showWindow:function
});
// include Sortable.js 0.45
Ext.namespace('Ext.ux');
Ext.ux.Sortable = function(obj){
var config = Ext.applyIf(obj,{
container : document.body,
className : null,
tagName : 'li',
handles : false,
contextMenu : false,
dragGroups : [
'default'
],
autoEnable : true,
horizontal : false
});
this.ddGroups = {};
Ext.applyIf(this,config);
this._buildQueryString();
this.addEvents (
'serialise',
'serialize',
'enable',
'disable',
'enableElement',
'disableElement'
);
this._createDragDrop();
if(this.dragGroups.length > 1){
this.addToDDGroup(this.dragGroups);
} else {
this.ddGroups[this.dragGroups]=true;
}
//automatically start the DD
if(this.autoEnable){
this.enable();
}
this.serialize = this.serialise;
}
Ext.extend(Ext.ux.Sortable,Ext.util.Observable, {
/**
* Function creates the queryString for use in all functions
* @private
*/
_buildQueryString : function(){
this.queryString = '';
if(this.tagName){
this.queryString += this.tagName.toLowerCase();
}
if(this.className){
this.queryString += '.'+this.className;
}
},
/**
* creates the DragZone and DropTarget
* @private
*/
_createDragDrop : function(){
this.dragZone = new Ext.dd.SortableDragZone(this.container, {ddGroup : this.dragGroups[0], scroll:false, containerScroll:true, queryString : this.queryString});
this.dropZone = new Ext.dd.SortableDropZone(this.container, {ddGroup : this.dragGroups[0], queryString : this.queryString, handles : this.handles, horizontal : this.horizontal});
},
/**
* Function gets the items in the list area
* @public
* @param {Boolean} flag Switch flag to fire event or not
* @returns {Array} An array ob DOM references to the nodes contained in the sortable list
*/
serialise : function(flag){
if(flag || flag == undefined){
this.fireEvent('serialise', this);
this.fireEvent('serialize', this);
}
return Ext.query(this.queryString,this.container);
},
/**
* Function enables DD on the container element
* is a long function to stop evaluation inside loops
* @public
*/
enable : function(){
this.drags = this.serialise(false);
var i = this.drags.length-1;
if(this.handles && this.contextMenu){
while(i >= 0){
Ext.dd.Registry.register(this.drags[i], {
isHandle:false,
handles : [
'handle_' + this.drags[i].id
],
ddGroups : this.ddGroups
}
);
Ext.fly('handle_' + this.drags[i].id).on('contextmenu', this.contextMenu, this, {preventDefault: true});
--i;
}
} else if (this.handles) {
while(i >= 0){
Ext.dd.Registry.register(this.drags[i], {
isHandle:false,
handles : [
'handle_' + this.drags[i].id
],
ddGroups : this.ddGroups
}
);
--i;
}
} else if(this.contextMenu){
while(i >= 0){
Ext.dd.Registry.register(
this.drags[i],
{
ddGroups : this.ddGroups
}
);
Ext.fly(this.drags[i].id).on('contextmenu', this.contextMenu, this, {preventDefault: true});
--i;
}
} else {
while(i >= 0){
Ext.dd.Registry.register(
this.drags[i],
{
ddGroups : this.ddGroups
}
);
--i;
}
}
this.dropZone.unlock();
this.dragZone.unlock();
this.fireEvent('enable', this);
},
/**
* Disable all DD and remove contextMenu listeners
* @public
*/
disable : function(){
this.drags = this.serialise(false);
var i = this.drags.length-1;
if(this.contextMenu){
while(i >= 0){
Ext.dd.Registry.unregister(this.drags[i]);
Ext.fly('handle_' + this.drags[i].id).un('contextmenu', this.contextMenu);
--i;
}
} else {
while(i >= 0){
Ext.dd.Registry.unregister(this.drags[i]);
--i;
}
}
this.dropZone.lock();
this.dragZone.lock();
this.fireEvent('disable', this);
},
/**
* Function enables a single Elements DD within the container
* @public
* @param {String} id The Id of the element you want to add to the DD list
*/
enableElement :function(id){
if(this.handles && this.contextMenu){
Ext.dd.Registry.register(id, {
isHandle:false,
handles : [
'handle_' + id
],
ddGroups : this.ddGroups
}
);
Ext.fly('handle_' + id).on('contextmenu', this.contextMenu, this, {preventDefault: true});
} else if (this.handles) {
Ext.dd.Registry.register(id, {
isHandle:false,
handles : [
'handle_' + id
],
ddGroups : this.ddGroups
}
);
} else if(this.contextMenu){
Ext.dd.Registry.register(id,{
ddGroup : this.ddGroups
});
Ext.fly('handle_' + id).un('contextmenu', this.contextMenu);
} else {
Ext.dd.Registry.register(id,{
ddGroups : this.ddGroups
});
}
this.fireEvent('enableElement', this);
},
/**
* Function disables a single Elements DD within the container
* @public
* @param {String} id The Id of the element you want to disable in the list
*/
disableElement : function(id){
Ext.dd.Registry.unregister(id);
if(this.contextMenu){
Ext.fly('handle_' + id).un('contextmenu', this.contextMenu);
}
this.fireEvent('disableElement', this);
},
/**
* Function switches DD Group from the current one
* @public
* @param {String/Array} The DD Group(s) you want to swap the list from
* @param {String/Array} The DD Group(s) you want to swap the list to
*/
swapDDGroup : function(from,to){
this.removeFromDDGroup(from);
this.addToDDGroup(to);
this.enable();
},
/**
* Function adds elements to a particular DD Group
* @public
* @param {String/Array} DD group(s) you want to add your list to
*/
addToDDGroup : function(groupName,enable){
if(typeof groupName != 'string'){
var i = groupName.length-1;
while(i>=0){
this.ddGroups[groupName[i]]=true;
this.dragZone.addToGroup(groupName[i]);
this.dropZone.addToGroup(groupName[i]);
--i;
}
} else {
this.ddGroups[groupName]=true;
this.dragZone.addToGroup(groupName);
this.dropZone.addToGroup(groupName);
}
if(typeof enable !== 'undefined' || enable){
this.enable();
}
},
/**
* Function removes a list from a particular DD Group
* @public
* @param {String/Array} DD group(s) you want to remove your list from
*/
removeFromDDGroup : function(groupName, enable){
if(typeof groupName != 'string'){
var i = groupName.length-1;
while(i>=0){
this.ddGroups[groupName[i]]=false;
this.dragZone.removeFromGroup(groupName[i]);
this.dropZone.removeFromGroup(groupName[i]);
--i;
}
} else {
this.ddGroups[groupName]=false;
this.dragZone.removeFromGroup(groupName);
this.dropZone.removeFromGroup(groupName);
}
if(typeof enable !== 'undefined' || enable){
this.enable();
}
}
});
Ext.dd.SortableDragZone = function(el, config){
Ext.dd.DragZone.superclass.constructor.call(this, el, config);
};
Ext.extend(Ext.dd.SortableDragZone, Ext.dd.DragZone, {
onInitDrag : function(x, y){
var dragged = this.dragData.ddel.cloneNode(true);
dragged.id='';
if(Ext.isIE){ //IE fix for checkbox and radio
var array_cb = Ext.fly(this.dragData.ddel).select('input[type="checkbox"]');
var array_rb = Ext.fly(this.dragData.ddel).select('input[type="radio"]');
var i = 0;
if (array_cb.elements!=0){
Ext.fly(dragged).select('input[type="checkbox"]').each(function() {
this.dom.defaultChecked = array_cb.elements[i].checked;
i++;
});
}
if (array_rb.elements!=0){
i = 0;
Ext.fly(dragged).select('input[type="radio"]').each(function() {
this.dom.defaultChecked = array_rb.elements[i].checked;
i++;
});
}
}
this.proxy.update(dragged);
this.onStartDrag(x, y);
this.dragData.ddel.style.visibility='hidden';
return true;
},
afterRepair : function(){
this.dragData.ddel.style.visibility='';
this.dragging = false;
},
getRepairXY : function(e){
//uncomment this to show animation
return Ext.Element.fly(this.dragData.ddel).getXY();
},
getNodeData : function(e){
e = Ext.EventObject.setEvent(e);
var target = e.getTarget(this.queryString);
if(target){
this.dragData.ddel = target.parentNode; // the img element
this.dragData.single = true;
return this.dragData;
}
return false;
},
onEndDrag : function(data, e){ }
});
Ext.dd.SortableDropZone = function(el, config){
Ext.dd.DropZone.superclass.constructor.call(this, el, config);
};
Ext.extend(Ext.dd.SortableDropZone, Ext.dd.DropZone, {
notifyEnter : function(source, e, data){
this.srcEl = Ext.get(data.ddel);
if(this._testDDGroup()){
if(this.srcEl !== null){
if(this.srcEl.dom.parentNode !== this.el.dom){
if(!Ext.query(this.queryString,this.el).length > 0 && this.srcEl.is(this.queryString)){
this.srcEl.appendTo(this.el);
}
}
//add DD ok class to proxy
if(this.overClass){
this.el.addClass(this.overClass);
}
return this.dropAllowed;
}
}
},
onContainerOver : function(dd, e, data){
if(this._testDDGroup()){
return this.dropAllowed;
}
},
notifyOver : function(dd, e, data){
if(this._testDDGroup()){
var x;
var n = this.getTargetFromEvent(e);
if(!n){
if(this.lastOverNode){
this.onNodeOut(this.lastOverNode, dd, e, data);
this.lastOverNode = null;
}
return this.onContainerOver(dd, e, data);
}
if(this.lastOverNode != n){
if(this.lastOverNode){
this.onNodeOut(this.lastOverNode, dd, e, data);
}
this.onNodeEnter(n, dd, e, data);
this.lastOverNode = n;
}
return this.onNodeOver(n, dd, e, data);
}
},
onNodeOver : function(n, dd, e, data){
if(this._testDDGroup()){
if(this.horizonatal) {
var x = e.getPageX();
if (x < this.lastX) {
this.goingPrevious = true;
} else if (x > this.lastX) {
this.goingPrevious = false;
}
this.lastX = x;
} else {
var y = e.getPageY();
if (y < this.lastY) {
this.goingPrevious = true;
} else if (y > this.lastY) {
this.goingPrevious = false;
}
this.lastY = y;
}
var destEl = Ext.get(n.ddel);
if((Ext.isIE)&&(this.srcEl !== null)){ //IE fix for checkbox and radio
this.srcEl.select('input[type="checkbox"]').each(function() {
this.dom.defaultChecked = this.dom.checked;
});
this.srcEl.select('input[type="radio"]').each(function() {
this.dom.defaultChecked = this.dom.checked;
});
}
if (this.goingPrevious) {
this.srcEl.insertBefore(destEl);
} else {
this.srcEl.insertAfter(destEl);
}
return this.dropAllowed;
} else {
return this.dropNotAllowed;
}
},
notifyDrop : function(dd, e, data){
if(this._testDDGroup){
if(this.srcEl !== null){
this.srcEl.setStyle('visibility','');
// refresh the drag drop manager
Ext.dd.DragDropMgr.refreshCache(this.groupName);
}
return true;
}
},
_testDDGroup : function(){
var groupTest = Ext.dd.Registry.getTarget(this.srcEl.id).ddGroups;
var result = false;
for(this.groups in groupTest){
if(groupTest[this.groups]){
result=true;
}
}
return result;
}
});
//Ext override to stop error when unloading a page
Ext.dd.DragDropMgr._remove = function(oDD) {
if(oDD){
for (var g in oDD.groups) {
if(this.ids[g]){
if (g && this.ids[g][oDD.id]) {
delete this.ids[g][oDD.id];
}
}
}
delete this.handleIds[oDD.id];
}
}
example :
Replace the array-grid.js by this one :
/*
* Ext JS Library 2.1
* Copyright(c) 2006-2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
Ext.onReady(function(){
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
var myData = [
['3m Co',71.72,0.02,0.03,'9/1 12:00am'],
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am'],
['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am'],
['American Express Company',52.55,0.01,0.02,'9/1 12:00am'],
['American International Group, Inc.',64.13,0.31,0.49,'9/1 12:00am'],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am'],
['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am'],
['Caterpillar Inc.',67.27,0.92,1.39,'9/1 12:00am'],
['Citigroup, Inc.',49.37,0.02,0.04,'9/1 12:00am'],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am'],
['Exxon Mobil Corp',68.1,-0.43,-0.64,'9/1 12:00am'],
['General Electric Company',34.14,-0.08,-0.23,'9/1 12:00am'],
['General Motors Corporation',30.27,1.09,3.74,'9/1 12:00am'],
['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am'],
['Honeywell Intl Inc',38.77,0.05,0.13,'9/1 12:00am'],
['Intel Corporation',19.88,0.31,1.58,'9/1 12:00am'],
['International Business Machines',81.41,0.44,0.54,'9/1 12:00am'],
['Johnson & Johnson',64.72,0.06,0.09,'9/1 12:00am'],
['JP Morgan & Chase & Co',45.73,0.07,0.15,'9/1 12:00am'],
['McDonald\'s Corporation',36.76,0.86,2.40,'9/1 12:00am'],
['Merck & Co., Inc.',40.96,0.41,1.01,'9/1 12:00am'],
['Microsoft Corporation',25.84,0.14,0.54,'9/1 12:00am'],
['Pfizer Inc',27.96,0.4,1.45,'9/1 12:00am'],
['The Coca-Cola Company',45.07,0.26,0.58,'9/1 12:00am'],
['The Home Depot, Inc.',34.64,0.35,1.02,'9/1 12:00am'],
['The Procter & Gamble Company',61.91,0.01,0.02,'9/1 12:00am'],
['United Technologies Corporation',63.26,0.55,0.88,'9/1 12:00am'],
['Verizon Communications',35.57,0.39,1.11,'9/1 12:00am'],
['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am']
];
// example of custom renderer function
function change(val){
if(val > 0){
return '<span style="color:green;">' + val + '</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '</span>';
}
return val;
}
// example of custom renderer function
function pctChange(val){
if(val > 0){
return '<span style="color:green;">' + val + '%</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}
// create the data store
var store = new Ext.data.SimpleStore({
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
]
});
store.loadData(myData);
// create the Grid
var grid = new Ext.grid.GridPanel({
store: store,
columns: [
{id:'company',header: "Company", width: 160, sortable: true, dataIndex: 'company'},
{header: "Price", width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'},
{header: "Change", width: 75, sortable: true, renderer: change, dataIndex: 'change'},
{header: "% Change", width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange'},
{header: "Last Updated", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
],
stripeRows: true,
autoExpandColumn: 'company',
height:350,
width:600,
tbar:new Ext.Toolbar(),
plugins:new Ext.ux.grid.ConfigWindow(),
title:'Array Grid'
});
grid.render('grid-example');
grid.getSelectionModel().selectFirstRow();
});
edit 26/05/2008 : Now compatible with sortable 0.45, included,multi grid problem corrected
edit 27/05/2008 : add params to disable sort/size/display columns. Manage unresizable/unsortable/unhideable grid columns.
edit 30/05/2008 : Live demo
Live Demo available here (http://ext4sap.free.fr/GWC-grid.html)
GridConfigWindow is a little plugin to have all common grid config parameters in an unique window. (see screenshot)
It add a button to call the window (top or bottom toolbar of the grid, you choose).
In the window, you can define :
- order of the columns
- size of each column
- columns displayed
- the sort column and the sort order
Change are applied only when you push "apply" button.
This plugin use the wonderfull Ext.ux.Sortable plugin : http://www.extjs.com/forum/showthread.php?t=29033
Usage : Use it as a plugin of the gridpanel, it add a button on bottom or top toolbar if asked.
/**
* Grid Config Window plugin for Ext.grid.GridPanel
* @author Jelt
* @copyright No thanks
* @date 21. May 2008
* @version 2008-05-27 15:00:00 - Jelt
* include Ext.ux.Sortable 0.45, by Rowan
* http://www.extjs.com/forum/showthread.php?t=29033
*/
Ext.namespace('Ext.ux', 'Ext.ux.grid');
Ext.ux.grid.ConfigWindow = function(config) {
Ext.apply(this, config);
Ext.ux.grid.ConfigWindow.superclass.constructor.call(this);
};
Ext.extend(Ext.ux.grid.ConfigWindow, Ext.util.Observable, {
// options
position:'top' // position Where to display the button. Valid values are 'top', 'bottom' and ''. Use '' to not display button (window can be called by the showWindow() function)
,iconCls:'icon-magnifier' // Icon class for menu button
,windowMaximizable:true // Display window maximize icon
,sortColumn:true
,displayColumn:true
,sizeColumn:true
// Localisation
,buttonText:'Layout' // Text to display on menu button
,buttonTipText:'Configure layout of the grid' // Text to display as input tooltip
,windowTitle:'Grid Layout Configuration' //Text of the config window
,windowButtonApplyText:'Apply' //Text of the Aplpy button in window
,windowButtonCancelText:'Cancel' //Text of the Aplpy button in window
,windowHeaderFieldText:'Field Order'
,windowHeaderSizeText:'Size'
,windowHeaderDisplayText:'Display'
,windowHeaderSortText:'Sort<br>A / D'
,init:function(grid) {
if (this.buttonTipText != '') { // Be sure quicktip is enabled if required
Ext.QuickTips.init();
}
this.grid = grid;
this.GCW_id = Ext.id();
if (this.position != '') { // Draw button if required
grid.onRender = grid.onRender.createSequence(this.onRender, this);
}
}
,onRender:function() {
var grid = this.grid;
var tb = 'bottom' == this.position ? grid.bottomToolbar : grid.topToolbar;
if(0 < tb.items.getCount()) { tb.addSeparator(); }
this.layoutButton = new Ext.Button({
text: this.buttonText
, cls: 'x-btn-text-icon details'
,iconCls:this.iconCls
,tooltip:this.buttonTipText
});
tb.add(this.layoutButton);
this.layoutButton.on('click',function() { this.showWindow();},this);
}
,hideWindow:function() { // Hide config window
this.config_window.hide();
this.sortable1.disable();
}
,showWindow:function() { // Display config window
var myCols = this.grid.getColumnModel();
var myStore = this.grid.getStore();
var div_width = 303 //470;
var win_width = 343 //510;
if (this.sizeColumn){
div_width += 52;
win_width += 52;
}
if (this.displayColumn){
div_width += 62;
win_width += 62;
}
if (this.sortColumn){
div_width += 52;
win_width += 52;
}
li_template = '<div id="'+this.GCW_id+'_li_{0}" style="border:1px dotted #999999;width:'+div_width+';vertical-align:center"><table><tr class="x-grid3-row"><td width="300" id="handle_'+this.GCW_id+'_li_{0}" class="handle">{1}</td>';
if (this.sizeColumn){
li_template += '<td width="50" align="center" class="x-small-editor"><input type="text" id="'+this.GCW_id+'_sz_{0}" size=3 class="x-form-field"></td>';
}
if (this.displayColumn){
li_template += '<td width="60" align="center"><input type="checkbox" id="'+this.GCW_id+'_cb_{0}"></td>';
}
if (this.sortColumn){
li_template += '<td width="50" align="center"><input type="radio" name="sort_field_order" value="A_{0}" id="'+this.GCW_id+'_sort_{0}_A"> <input type="radio" name="sort_field_order" value="D_{0}" id="'+this.GCW_id+'_sort_{0}_D"></td>';
}
li_template += '</tr></table></div>';
// header
var config_ul_inner_array = new Array('<table class="x-grid3-header"><tr class="x-grid3-hd-row"><td width="299">'+this.windowHeaderFieldText+'</td>');
if (this.sizeColumn){
config_ul_inner_array[config_ul_inner_array.length] = '<td width="48" align="center">'+this.windowHeaderSizeText+'</td>';
}
if (this.displayColumn){
config_ul_inner_array[config_ul_inner_array.length] = '<td align="center" width="58">'+this.windowHeaderDisplayText+'</td>';
}
if (this.sortColumn){
config_ul_inner_array[config_ul_inner_array.length] = '<td align="center" width="49">'+this.windowHeaderSortText+'</td>';
}
config_ul_inner_array[config_ul_inner_array.length] = '</tr></table>';
// items
for (j=0;j<myCols.config.length;j++){
config_ul_inner_array[config_ul_inner_array.length] = String.format(li_template, myCols.config[j].dataIndex,myCols.config[j].header);
}
if (!this.config_window) {
Ext.util.CSS.createStyleSheet('.GCW_window .x-panel-body{overflow-y:auto;} .handle {cursor : move;}');
this.config_window = new Ext.Window({
title:this.windowTitle
,cls:'GCW_window'
,maximizable:this.windowMaximizable,autoScroll:true
,plain:true,closeAction:'hide'
,layout:'fit',modal:true
,resizable:true, shadow:false
,width: win_width, height: 280
,items:new Ext.Panel({ html:'<form name="'+this.GCW_id+'_config_form"><div id="'+this.GCW_id+'_div_content"></div></form>' }) // applyTo:'config_div'})
,buttonAlign:'center'
// Apply button
,buttons: [{text:this.windowButtonApplyText,handler:function(){
this.hideWindow();
// Sort
if (this.sortColumn){
for (var i=0; i<document.forms[this.GCW_id+"_config_form"].elements["sort_field_order"].length;i++) {
if (document.forms[this.GCW_id+"_config_form"].elements["sort_field_order"][i].checked) {
var field = document.forms[this.GCW_id+"_config_form"].elements["sort_field_order"][i].value;
if (field.substr(0,1)=='A'){
field = field.substr(2,32);
if ((!myStore.sortInfo)||(myStore.sortInfo.field != field)||(myStore.sortInfo.direction != 'ASC')) {
myStore.sort(field,'ASC');
}
} else {
field = field.substr(2,32);
if ((!myStore.sortInfo)||(myStore.sortInfo.field != field)||(myStore.sortInfo.direction != 'DESC')) {
myStore.sort(field,'DESC');
}
}
break;
}
}
}
// order, hidden, size
var list_sorted = this.sortable1.serialise();
var config_new = new Array();
var to_bypass = 4 + this.GCW_id.length;
for (var i=0;i<list_sorted.length;i++){
var field = list_sorted[i].id.substr(to_bypass,30);
if (myCols.config[i].dataIndex == field){
j = i;
} else {
for (var j=0;j<myCols.config.length;j++){
if (myCols.config[j].dataIndex == field){
break;
}
}
}
config_new[config_new.length] = myCols.config[j];
if (this.sizeColumn){
config_new[i].width = parseInt(Ext.getDom(this.GCW_id+'_sz_'+field).value); // set column width
}
if (this.displayColumn){
config_new[i].hidden = !Ext.getDom(this.GCW_id+'_cb_'+field).checked; // set column hidden
}
}
myCols.setConfig( config_new );
// Cancel button
}.createDelegate(this)},{ text: this.windowButtonCancelText, handler: function(){ this.hideWindow() }.createDelegate(this) }] });
this.config_window.render(document.body);
}
Ext.getDom(this.GCW_id+'_div_content').innerHTML = config_ul_inner_array.join('');
if (!this.sortable1) {
this.sortable1 = new Ext.ux.Sortable({
tagName:'div',container : this.GCW_id+'_div_content'
,handles : true });
} else {
this.sortable1.enable();
}
// values
if ((this.displayColumn)||(this.sizeColumn)){
for (j=0;j<myCols.config.length;j++){
if (this.displayColumn){
Ext.getDom(this.GCW_id+'_cb_'+myCols.config[j].dataIndex).checked = !myCols.config[j].hidden; // display fields
if (myCols.config[j].hideable==false)
Ext.getDom(this.GCW_id+'_cb_'+myCols.config[j].dataIndex).disabled = true;
}
if (this.sizeColumn){
Ext.getDom(this.GCW_id+'_sz_'+myCols.config[j].dataIndex).value=myCols.config[j].width; // size
if (myCols.config[j].resizable==false)
Ext.getDom(this.GCW_id+'_sz_'+myCols.config[j].dataIndex).disabled = true;
}
if (this.sortColumn){
if (myCols.config[j].sortable==false){
Ext.getDom(this.GCW_id+'_sort_'+myCols.config[j].dataIndex+'_A').disabled = true;
Ext.getDom(this.GCW_id+'_sort_'+myCols.config[j].dataIndex+'_D').disabled = true;
}
}
}
}
if (this.sortColumn){
if ((myStore.sortInfo)&&(myStore.sortInfo.field)&&(myStore.sortInfo.direction)){
if (myStore.sortInfo.direction == 'ASC'){ // sort
Ext.getDom(this.GCW_id+'_sort_'+myStore.sortInfo.field+'_A').checked=true;
} else {
Ext.getDom(this.GCW_id+'_sort_'+myStore.sortInfo.field+'_D').checked=true;
}
}
}
this.config_window.show();
} //EO showWindow:function
});
// include Sortable.js 0.45
Ext.namespace('Ext.ux');
Ext.ux.Sortable = function(obj){
var config = Ext.applyIf(obj,{
container : document.body,
className : null,
tagName : 'li',
handles : false,
contextMenu : false,
dragGroups : [
'default'
],
autoEnable : true,
horizontal : false
});
this.ddGroups = {};
Ext.applyIf(this,config);
this._buildQueryString();
this.addEvents (
'serialise',
'serialize',
'enable',
'disable',
'enableElement',
'disableElement'
);
this._createDragDrop();
if(this.dragGroups.length > 1){
this.addToDDGroup(this.dragGroups);
} else {
this.ddGroups[this.dragGroups]=true;
}
//automatically start the DD
if(this.autoEnable){
this.enable();
}
this.serialize = this.serialise;
}
Ext.extend(Ext.ux.Sortable,Ext.util.Observable, {
/**
* Function creates the queryString for use in all functions
* @private
*/
_buildQueryString : function(){
this.queryString = '';
if(this.tagName){
this.queryString += this.tagName.toLowerCase();
}
if(this.className){
this.queryString += '.'+this.className;
}
},
/**
* creates the DragZone and DropTarget
* @private
*/
_createDragDrop : function(){
this.dragZone = new Ext.dd.SortableDragZone(this.container, {ddGroup : this.dragGroups[0], scroll:false, containerScroll:true, queryString : this.queryString});
this.dropZone = new Ext.dd.SortableDropZone(this.container, {ddGroup : this.dragGroups[0], queryString : this.queryString, handles : this.handles, horizontal : this.horizontal});
},
/**
* Function gets the items in the list area
* @public
* @param {Boolean} flag Switch flag to fire event or not
* @returns {Array} An array ob DOM references to the nodes contained in the sortable list
*/
serialise : function(flag){
if(flag || flag == undefined){
this.fireEvent('serialise', this);
this.fireEvent('serialize', this);
}
return Ext.query(this.queryString,this.container);
},
/**
* Function enables DD on the container element
* is a long function to stop evaluation inside loops
* @public
*/
enable : function(){
this.drags = this.serialise(false);
var i = this.drags.length-1;
if(this.handles && this.contextMenu){
while(i >= 0){
Ext.dd.Registry.register(this.drags[i], {
isHandle:false,
handles : [
'handle_' + this.drags[i].id
],
ddGroups : this.ddGroups
}
);
Ext.fly('handle_' + this.drags[i].id).on('contextmenu', this.contextMenu, this, {preventDefault: true});
--i;
}
} else if (this.handles) {
while(i >= 0){
Ext.dd.Registry.register(this.drags[i], {
isHandle:false,
handles : [
'handle_' + this.drags[i].id
],
ddGroups : this.ddGroups
}
);
--i;
}
} else if(this.contextMenu){
while(i >= 0){
Ext.dd.Registry.register(
this.drags[i],
{
ddGroups : this.ddGroups
}
);
Ext.fly(this.drags[i].id).on('contextmenu', this.contextMenu, this, {preventDefault: true});
--i;
}
} else {
while(i >= 0){
Ext.dd.Registry.register(
this.drags[i],
{
ddGroups : this.ddGroups
}
);
--i;
}
}
this.dropZone.unlock();
this.dragZone.unlock();
this.fireEvent('enable', this);
},
/**
* Disable all DD and remove contextMenu listeners
* @public
*/
disable : function(){
this.drags = this.serialise(false);
var i = this.drags.length-1;
if(this.contextMenu){
while(i >= 0){
Ext.dd.Registry.unregister(this.drags[i]);
Ext.fly('handle_' + this.drags[i].id).un('contextmenu', this.contextMenu);
--i;
}
} else {
while(i >= 0){
Ext.dd.Registry.unregister(this.drags[i]);
--i;
}
}
this.dropZone.lock();
this.dragZone.lock();
this.fireEvent('disable', this);
},
/**
* Function enables a single Elements DD within the container
* @public
* @param {String} id The Id of the element you want to add to the DD list
*/
enableElement :function(id){
if(this.handles && this.contextMenu){
Ext.dd.Registry.register(id, {
isHandle:false,
handles : [
'handle_' + id
],
ddGroups : this.ddGroups
}
);
Ext.fly('handle_' + id).on('contextmenu', this.contextMenu, this, {preventDefault: true});
} else if (this.handles) {
Ext.dd.Registry.register(id, {
isHandle:false,
handles : [
'handle_' + id
],
ddGroups : this.ddGroups
}
);
} else if(this.contextMenu){
Ext.dd.Registry.register(id,{
ddGroup : this.ddGroups
});
Ext.fly('handle_' + id).un('contextmenu', this.contextMenu);
} else {
Ext.dd.Registry.register(id,{
ddGroups : this.ddGroups
});
}
this.fireEvent('enableElement', this);
},
/**
* Function disables a single Elements DD within the container
* @public
* @param {String} id The Id of the element you want to disable in the list
*/
disableElement : function(id){
Ext.dd.Registry.unregister(id);
if(this.contextMenu){
Ext.fly('handle_' + id).un('contextmenu', this.contextMenu);
}
this.fireEvent('disableElement', this);
},
/**
* Function switches DD Group from the current one
* @public
* @param {String/Array} The DD Group(s) you want to swap the list from
* @param {String/Array} The DD Group(s) you want to swap the list to
*/
swapDDGroup : function(from,to){
this.removeFromDDGroup(from);
this.addToDDGroup(to);
this.enable();
},
/**
* Function adds elements to a particular DD Group
* @public
* @param {String/Array} DD group(s) you want to add your list to
*/
addToDDGroup : function(groupName,enable){
if(typeof groupName != 'string'){
var i = groupName.length-1;
while(i>=0){
this.ddGroups[groupName[i]]=true;
this.dragZone.addToGroup(groupName[i]);
this.dropZone.addToGroup(groupName[i]);
--i;
}
} else {
this.ddGroups[groupName]=true;
this.dragZone.addToGroup(groupName);
this.dropZone.addToGroup(groupName);
}
if(typeof enable !== 'undefined' || enable){
this.enable();
}
},
/**
* Function removes a list from a particular DD Group
* @public
* @param {String/Array} DD group(s) you want to remove your list from
*/
removeFromDDGroup : function(groupName, enable){
if(typeof groupName != 'string'){
var i = groupName.length-1;
while(i>=0){
this.ddGroups[groupName[i]]=false;
this.dragZone.removeFromGroup(groupName[i]);
this.dropZone.removeFromGroup(groupName[i]);
--i;
}
} else {
this.ddGroups[groupName]=false;
this.dragZone.removeFromGroup(groupName);
this.dropZone.removeFromGroup(groupName);
}
if(typeof enable !== 'undefined' || enable){
this.enable();
}
}
});
Ext.dd.SortableDragZone = function(el, config){
Ext.dd.DragZone.superclass.constructor.call(this, el, config);
};
Ext.extend(Ext.dd.SortableDragZone, Ext.dd.DragZone, {
onInitDrag : function(x, y){
var dragged = this.dragData.ddel.cloneNode(true);
dragged.id='';
if(Ext.isIE){ //IE fix for checkbox and radio
var array_cb = Ext.fly(this.dragData.ddel).select('input[type="checkbox"]');
var array_rb = Ext.fly(this.dragData.ddel).select('input[type="radio"]');
var i = 0;
if (array_cb.elements!=0){
Ext.fly(dragged).select('input[type="checkbox"]').each(function() {
this.dom.defaultChecked = array_cb.elements[i].checked;
i++;
});
}
if (array_rb.elements!=0){
i = 0;
Ext.fly(dragged).select('input[type="radio"]').each(function() {
this.dom.defaultChecked = array_rb.elements[i].checked;
i++;
});
}
}
this.proxy.update(dragged);
this.onStartDrag(x, y);
this.dragData.ddel.style.visibility='hidden';
return true;
},
afterRepair : function(){
this.dragData.ddel.style.visibility='';
this.dragging = false;
},
getRepairXY : function(e){
//uncomment this to show animation
return Ext.Element.fly(this.dragData.ddel).getXY();
},
getNodeData : function(e){
e = Ext.EventObject.setEvent(e);
var target = e.getTarget(this.queryString);
if(target){
this.dragData.ddel = target.parentNode; // the img element
this.dragData.single = true;
return this.dragData;
}
return false;
},
onEndDrag : function(data, e){ }
});
Ext.dd.SortableDropZone = function(el, config){
Ext.dd.DropZone.superclass.constructor.call(this, el, config);
};
Ext.extend(Ext.dd.SortableDropZone, Ext.dd.DropZone, {
notifyEnter : function(source, e, data){
this.srcEl = Ext.get(data.ddel);
if(this._testDDGroup()){
if(this.srcEl !== null){
if(this.srcEl.dom.parentNode !== this.el.dom){
if(!Ext.query(this.queryString,this.el).length > 0 && this.srcEl.is(this.queryString)){
this.srcEl.appendTo(this.el);
}
}
//add DD ok class to proxy
if(this.overClass){
this.el.addClass(this.overClass);
}
return this.dropAllowed;
}
}
},
onContainerOver : function(dd, e, data){
if(this._testDDGroup()){
return this.dropAllowed;
}
},
notifyOver : function(dd, e, data){
if(this._testDDGroup()){
var x;
var n = this.getTargetFromEvent(e);
if(!n){
if(this.lastOverNode){
this.onNodeOut(this.lastOverNode, dd, e, data);
this.lastOverNode = null;
}
return this.onContainerOver(dd, e, data);
}
if(this.lastOverNode != n){
if(this.lastOverNode){
this.onNodeOut(this.lastOverNode, dd, e, data);
}
this.onNodeEnter(n, dd, e, data);
this.lastOverNode = n;
}
return this.onNodeOver(n, dd, e, data);
}
},
onNodeOver : function(n, dd, e, data){
if(this._testDDGroup()){
if(this.horizonatal) {
var x = e.getPageX();
if (x < this.lastX) {
this.goingPrevious = true;
} else if (x > this.lastX) {
this.goingPrevious = false;
}
this.lastX = x;
} else {
var y = e.getPageY();
if (y < this.lastY) {
this.goingPrevious = true;
} else if (y > this.lastY) {
this.goingPrevious = false;
}
this.lastY = y;
}
var destEl = Ext.get(n.ddel);
if((Ext.isIE)&&(this.srcEl !== null)){ //IE fix for checkbox and radio
this.srcEl.select('input[type="checkbox"]').each(function() {
this.dom.defaultChecked = this.dom.checked;
});
this.srcEl.select('input[type="radio"]').each(function() {
this.dom.defaultChecked = this.dom.checked;
});
}
if (this.goingPrevious) {
this.srcEl.insertBefore(destEl);
} else {
this.srcEl.insertAfter(destEl);
}
return this.dropAllowed;
} else {
return this.dropNotAllowed;
}
},
notifyDrop : function(dd, e, data){
if(this._testDDGroup){
if(this.srcEl !== null){
this.srcEl.setStyle('visibility','');
// refresh the drag drop manager
Ext.dd.DragDropMgr.refreshCache(this.groupName);
}
return true;
}
},
_testDDGroup : function(){
var groupTest = Ext.dd.Registry.getTarget(this.srcEl.id).ddGroups;
var result = false;
for(this.groups in groupTest){
if(groupTest[this.groups]){
result=true;
}
}
return result;
}
});
//Ext override to stop error when unloading a page
Ext.dd.DragDropMgr._remove = function(oDD) {
if(oDD){
for (var g in oDD.groups) {
if(this.ids[g]){
if (g && this.ids[g][oDD.id]) {
delete this.ids[g][oDD.id];
}
}
}
delete this.handleIds[oDD.id];
}
}
example :
Replace the array-grid.js by this one :
/*
* Ext JS Library 2.1
* Copyright(c) 2006-2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
Ext.onReady(function(){
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
var myData = [
['3m Co',71.72,0.02,0.03,'9/1 12:00am'],
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am'],
['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am'],
['American Express Company',52.55,0.01,0.02,'9/1 12:00am'],
['American International Group, Inc.',64.13,0.31,0.49,'9/1 12:00am'],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am'],
['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am'],
['Caterpillar Inc.',67.27,0.92,1.39,'9/1 12:00am'],
['Citigroup, Inc.',49.37,0.02,0.04,'9/1 12:00am'],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am'],
['Exxon Mobil Corp',68.1,-0.43,-0.64,'9/1 12:00am'],
['General Electric Company',34.14,-0.08,-0.23,'9/1 12:00am'],
['General Motors Corporation',30.27,1.09,3.74,'9/1 12:00am'],
['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am'],
['Honeywell Intl Inc',38.77,0.05,0.13,'9/1 12:00am'],
['Intel Corporation',19.88,0.31,1.58,'9/1 12:00am'],
['International Business Machines',81.41,0.44,0.54,'9/1 12:00am'],
['Johnson & Johnson',64.72,0.06,0.09,'9/1 12:00am'],
['JP Morgan & Chase & Co',45.73,0.07,0.15,'9/1 12:00am'],
['McDonald\'s Corporation',36.76,0.86,2.40,'9/1 12:00am'],
['Merck & Co., Inc.',40.96,0.41,1.01,'9/1 12:00am'],
['Microsoft Corporation',25.84,0.14,0.54,'9/1 12:00am'],
['Pfizer Inc',27.96,0.4,1.45,'9/1 12:00am'],
['The Coca-Cola Company',45.07,0.26,0.58,'9/1 12:00am'],
['The Home Depot, Inc.',34.64,0.35,1.02,'9/1 12:00am'],
['The Procter & Gamble Company',61.91,0.01,0.02,'9/1 12:00am'],
['United Technologies Corporation',63.26,0.55,0.88,'9/1 12:00am'],
['Verizon Communications',35.57,0.39,1.11,'9/1 12:00am'],
['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am']
];
// example of custom renderer function
function change(val){
if(val > 0){
return '<span style="color:green;">' + val + '</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '</span>';
}
return val;
}
// example of custom renderer function
function pctChange(val){
if(val > 0){
return '<span style="color:green;">' + val + '%</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}
// create the data store
var store = new Ext.data.SimpleStore({
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
]
});
store.loadData(myData);
// create the Grid
var grid = new Ext.grid.GridPanel({
store: store,
columns: [
{id:'company',header: "Company", width: 160, sortable: true, dataIndex: 'company'},
{header: "Price", width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'},
{header: "Change", width: 75, sortable: true, renderer: change, dataIndex: 'change'},
{header: "% Change", width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange'},
{header: "Last Updated", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
],
stripeRows: true,
autoExpandColumn: 'company',
height:350,
width:600,
tbar:new Ext.Toolbar(),
plugins:new Ext.ux.grid.ConfigWindow(),
title:'Array Grid'
});
grid.render('grid-example');
grid.getSelectionModel().selectFirstRow();
});
edit 26/05/2008 : Now compatible with sortable 0.45, included,multi grid problem corrected
edit 27/05/2008 : add params to disable sort/size/display columns. Manage unresizable/unsortable/unhideable grid columns.
edit 30/05/2008 : Live demo