PDA

View Full Version : [2.0] grid with locking column [NEW: Update 5]



Pages : 1 [2]

Condor
22 Jul 2009, 5:34 AM
version 5 was specifically made for Ext 2.2 and up and won't work with Ext 2.1.

You'll have to look at the differences between version 4 and 5 and create a version "4.5" that contains all fixes from version 5, but not the Ext 2.2 integration (the afterRender stuff).

badgerd
22 Jul 2009, 9:34 PM
I have implemented this solution with CheckboxSelectionModel in place as the first column, however the checkbox selection is only allowing me to select one record at a time.

I have checked firebug and it is saying the singleSelect value is correctly set to be false.

How can I make it so that it selects multiple records or "select all" with the top check box?

roderick.wu
23 Jul 2009, 7:40 AM
Hi, Condor, it seems the issue still there after merging 5.0 with 4.0.... could you take a look?
For update 5, in the getColumnData function, cm.getColumnCount() is always n more than the columns I defined, n=the count of the locked columns.



getColumnData : function(){
var cs = [], cm = this.cm, colCount = cm.getColumnCount();
alert(colCount);
for(var i = 0; i < colCount; i++){
var name = cm.getDataIndex(i);
cs[i] = {
name : (typeof name == 'undefined' ? this.ds.fields.get(i).name : name),
renderer : cm.getRenderer(i),
id : cm.getColumnId(i),
style : this.getColumnStyle(i),
locked : cm.isLocked(i)
};
}
return cs;
},

avia4us
24 Jul 2009, 9:25 AM
There are 4 moderate issues I found and I would like to ask anybody to say how to fix that or where to find more updated version.

Here is the list (first column is fixed):
1. Try to expand the width of a Locked column
Result: width of a Locked column remains the same, but instead:
- on the right of the Locked column there is a white space
- the Second column expands which is not intended, when you try to expand the first column.

2. If there are icons-images(just 13 pixels in height) in the rows - all the cells and rows are auto-expanded in height, but the rows in the Locked column remain the same height as default, which makes a bad effect - rows in the Locked column do not match the rows in the other (not locked) columns. Then row number 25, 26, 27 in the Locked column correspond rows 23, 24, 25 in the notLocked columns.

There are some other issues, but they are smaller, once I get the exact instructions on how to reproduce I will post them here.

Condor
1 Aug 2009, 6:58 AM
I've created a new version of the LockingGridPanel extension for Ext 3.0.0 (here (http://www.extjs.com/forum/showthread.php?t=76324)).

This new version also fixes the horizontal scroll when clicking on a locked cell (but I don't think I will be backporting this fix to this Ext 2.x extension).

archrajan
5 Aug 2009, 7:36 AM
Hi Condor:
When i try to use your code along with the patch to the columnLock, i get the the error
this.cm.rows is undefined.
if i use the regular GroupHeaderGrid, it works fine, but ofcourse, columnLock will not work.




After applying the previous fixes you can use the following LockedGroupHeaderGrid plugin:


Ext.namespace("Ext.ux.plugins");

Ext.ux.plugins.LockedGroupHeaderGrid = function(config) {
Ext.apply(this, config);
};

Ext.extend(Ext.ux.plugins.LockedGroupHeaderGrid, Ext.util.Observable, {
init: function(grid) {
var v = grid.getView();
v.beforeMethod('initTemplates', this.initTemplates);
v.renderHeaders = this.renderHeaders.createDelegate(v, [v.renderHeaders]);
v.afterMethod('onColumnWidthUpdated', this.updateGroupStyles);
v.afterMethod('onAllColumnWidthsUpdated', this.updateGroupStyles);
v.afterMethod('onColumnHiddenUpdated', this.updateGroupStyles);
v.getHeaderCell = this.getHeaderCell;
v.updateSortIcon = this.updateSortIcon;
v.getGroupStyle = this.getGroupStyle;
},

initTemplates: function() {
var ts = this.templates || {};
if (!ts.gcell) {
ts.gcell = new Ext.Template(
'<td class="x-grid3-hd {cls} x-grid3-td-{id}" style="{style}">',
'<div {tooltip} class="x-grid3-hd-inner x-grid3-hd-{id}" unselectable="on" style="{istyle}">{value}</div>',
'</td>'
);
}
this.templates = ts;
},

renderHeaders: function(renderHeaders) {
var ts = this.templates, rows = [[], []], tw = this.cm.getTotalWidth(), lw = this.cm.getTotalLockedWidth();
for (var i = 0; i < this.cm.rows.length; i++) {
var r = this.cm.rows[i], cells = [[], []], col = 0;
for (var j = 0; j < r.length; j++) {
var c = r[j];
c.colspan = c.colspan || 1;
c.col = col;
var l = this.cm.isLocked(col) ? 1 : 0;
col += c.colspan;
var gs = this.getGroupStyle(c);
cells[l][j] = ts.gcell.apply({
id: c.id || i + '-' + col,
cls: c.header ? 'ux-grid-hd-group-cell' : 'ux-grid-hd-nogroup-cell',
style: 'width:' + gs.width + ';' + (gs.hidden ? 'display:none;' : '') + (c.align ? 'text-align:' + c.align + ';' : ''),
tooltip: c.tooltip ? (Ext.QuickTips.isEnabled() ? 'ext:qtip' : 'title') + '="' + c.tooltip + '"' : '',
value: c.header || '*',
istyle: c.align == 'right' ? 'padding-right:16px' : ''
});
}
rows[0][i] = ts.header.apply({
tstyle: 'width:' + (tw - lw) + 'px;',
cells: cells[0].join('')
});
rows[1][i] = ts.header.apply({
tstyle: 'width:' + lw + 'px;',
cells: cells[1].join('')
});
}
var h = renderHeaders.call(this);
rows[0][rows.length] = h[0];
rows[1][rows.length] = h[1];
return [rows[0].join(''), rows[1].join('')];
},

getGroupStyle: function(c) {
var w = 0, h = true;
for (var i = c.col; i < c.col + c.colspan; i++) {
if (!this.cm.isHidden(i)) {
var cw = this.cm.getColumnWidth(i);
if(typeof cw == 'number'){
w += cw;
}
h = false;
}
}
return {
width: (Ext.isBorderBox ? w : Math.max(w - this.borderWidth, 0)) + 'px',
hidden: h
}
},

updateGroupStyles: function(col) {
var tables = [this.mainHd.query('.x-grid3-header-offset > table'), this.lockedHd.query('.x-grid3-header-offset > table')], tw = this.cm.getTotalWidth(), lw = this.cm.getTotalLockedWidth();
for (var i = 0; i < tables[0].length; i++) {
tables[0][i].style.width = (tw - lw) + 'px';
tables[1][i].style.width = lw + 'px';
if (i < this.cm.rows.length) {
var cells = [], c = [tables[1][i].firstChild.firstChild.childNodes, tables[0][i].firstChild.firstChild.childNodes];
for (l = 0; l < 2; l++) {
for (j = 0; j < c[l].length; j++) {
cells.push(c[l][j]);
}
}
for (var j = 0; j < cells.length; j++) {
var c = this.cm.rows[i][j];
if ((typeof col != 'number') || (col >= c.col && col < c.col + c.colspan)) {
var gs = this.getGroupStyle(c);
cells[j].style.width = gs.width;
cells[j].style.display = gs.hidden ? 'none' : '';
}
}
}
}
},

getHeaderCell : function(index){
var locked = this.cm.getLockedCount();
if(index < locked){
return this.lockedHd.query('td.x-grid3-cell')[index];
} else {
return this.mainHd.query('td.x-grid3-cell')[(index-locked)];
}
},

updateSortIcon : function(col, dir){
var sc = this.sortClasses;
var clen = this.cm.getColumnCount();
var lclen = this.cm.getLockedCount();
var hds = this.mainHd.select('td.x-grid3-cell').removeClass(sc);
var lhds = this.lockedHd.select('td.x-grid3-cell').removeClass(sc);
if(lclen > 0 && col < lclen)
lhds.item(col).addClass(sc[dir == "DESC" ? 1 : 0]);
else
hds.item(col-lclen).addClass(sc[dir == "DESC" ? 1 : 0]);
}
});

(see original GroupHeaderGrid plugin thread (http://extjs.com/forum/showthread.php?t=22337) for usage example)

hhanna
6 Aug 2009, 12:01 PM
I'm using Ext 2.2 and the LockingEditorGridPanel from _update5 and have a problem: the headers are out of alignment with the columns.

I can get the headers to align properly by "hiding" one of the columns. When stepping through the code, there is a spot in the updateColumnHidden method that calculates and applies the proper header width, thereby creating perfect alignment.



updateColumnHidden : function(col, hidden){
var tw = this.cm.getTotalWidth();
var lw = this.cm.getTotalLockedWidth();
var lclen = this.cm.getLockedCount();
this.innerHd.firstChild.firstChild.style.width = tw + 'px';
var display = hidden ? 'none' : '';
var hd = this.getHeaderCell(col);
hd.style.display = display;
var ns, gw;
if(col < lclen) {
ns = this.getLockedRows();
gw = lw;
this.lockedHd.dom.firstChild.firstChild.style.width = gw + 'px';
this.mainWrap.dom.style.left= this.cm.getTotalLockedWidth() + 'px';
} else {
ns = this.getRows();
gw = tw - lw;
col -= lclen;
this.innerHd.firstChild.firstChild.style.width = gw + 'px';
}
....
I've tried a bunch of different things over the past few days and am now at wits end. I'd like the headers to align properly from the start. Any ideas on how to do this?

I believe I've added fixes mentioned in previous posts. Below is the code from my columnLock.js file:



Ext.grid.LockingGridPanel = Ext.extend(Ext.grid.GridPanel,{
getView : function(){
if(!this.view){
this.view = new Ext.grid.LockingGridView(this.viewConfig);
}
return this.view;
},

initComponent : function(){
if(!this.cm) {
this.cm = new Ext.grid.LockingColumnModel(this.columns);
delete this.columns;
}
Ext.grid.LockingGridPanel.superclass.initComponent.call(this);
}
});

Ext.grid.LockingEditorGridPanel = Ext.extend(Ext.grid.EditorGridPanel,{
getView : function(){
if(!this.view){
this.view = new Ext.grid.LockingGridView(this.viewConfig);
}
return this.view;
}
//,render: function(id) { Ext.grid.LockingGridPanel.superclass.render.call(this, id); this.getView().refresh(true); }

,initComponent : function(){
if(!this.cm) {
this.cm = new Ext.grid.LockingColumnModel(this.columns);
delete this.columns;
}
Ext.grid.LockingEditorGridPanel.superclass.initComponent.call(this);

}
});

Ext.grid.LockingGridView = Ext.extend(Ext.grid.GridView, {

lockText : "Lock",
unlockText : "Unlock",

initTemplates : function(){
if(!this.templates){
this.templates = {};
}
if(!this.templates.master){
this.templates.master = new Ext.Template(
'<div class="x-grid3" hidefocus="true">',
'<div class="x-grid3-locked">',
'<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset">{lockedHeader}</div></div><div class="x-clear"></div></div>',
'<div class="x-grid3-scroller"><div class="x-grid3-body">{lockedBody}</div><div class="x-grid3-scroll-spacer"></div></div>',
'</div>',
'<div class="x-grid3-viewport">',
'<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset">{header}</div></div><div class="x-clear"></div></div>',
'<div class="x-grid3-scroller"><div class="x-grid3-body">{body}</div><a href="#" class="x-grid3-focus" tabIndex="-1"></a></div>',
'</div>',
'<div class="x-grid3-resize-marker"> </div>',
'<div class="x-grid3-resize-proxy"> </div>',
'</div>'
);
}
Ext.grid.LockingGridView.superclass.initTemplates.call(this);
},

initElements : function(){
var E = Ext.Element;
var el = this.grid.getGridEl();
el = el.dom.firstChild;
var cs = el.childNodes;
this.el = new E(el);
this.lockedWrap = new E(cs[0]);
this.lockedHd = new E(this.lockedWrap.dom.firstChild);
this.lockedInnerHd = this.lockedHd.dom.firstChild;
this.lockedScroller = new E(this.lockedWrap.dom.childNodes[1]);
this.lockedBody = new E(this.lockedScroller.dom.firstChild);
this.mainWrap = new E(cs[1]);
this.mainHd = new E(this.mainWrap.dom.firstChild);
this.innerHd = this.mainHd.dom.firstChild;
this.scroller = new E(this.mainWrap.dom.childNodes[1]);
if(this.forceFit){
this.scroller.setStyle('overflow-x', 'hidden');
}
this.mainBody = new E(this.scroller.dom.firstChild);
this.focusEl = new E(this.scroller.dom.childNodes[1]);
this.focusEl.swallowEvent("click", true);
this.resizeMarker = new E(cs[2]);
this.resizeProxy = new E(cs[3]);
},

getLockedRows : function(){
return this.hasRows() ? this.lockedBody.dom.childNodes : [];
},

getLockedRow : function(row){
return this.getLockedRows()[row];
},

getCell : function(rowIndex, colIndex){
var locked = this.cm.getLockedCount();
var row;
if(colIndex < locked){
row = this.getLockedRow(rowIndex);
}else{
row = this.getRow(rowIndex);
colIndex -= locked;
}
return row.getElementsByTagName('td')[colIndex];
},

getHeaderCell : function(index){
var locked = this.cm.getLockedCount();
if(index < locked){
return this.lockedHd.dom.getElementsByTagName('td')[index];
} else {
return this.mainHd.dom.getElementsByTagName('td')[(index-locked)];
}
},

scrollToTop : function(){
Ext.grid.LockingGridView.superclass.scrollToTop.call(this);
this.syncScroll();
},

syncScroll : function(e){
Ext.grid.LockingGridView.superclass.syncScroll.call(this, e);
var mb = this.scroller.dom;
this.lockedScroller.dom.scrollTop = mb.scrollTop;
},

processRows : function(startRow, skipStripe){
if(this.ds.getCount() < 1){
return;
}
skipStripe = skipStripe || !this.grid.stripeRows;
startRow = startRow || 0;
var cls = ' x-grid3-row-alt ';
var rows = this.getRows();
var lrows = this.getLockedRows();
for(var i = startRow, len = rows.length; i < len; i++){
var row = rows[i];
var lrow = lrows[i];
row.rowIndex = i;
lrow.rowIndex = i;
if(!skipStripe){
var isAlt = ((i+1) % 2 === 0);
var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
if(isAlt == hasAlt){
continue;
}
if(isAlt){
row.className += " x-grid3-row-alt";
lrow.className += " x-grid3-row-alt";
}else{
row.className = row.className.replace("x-grid3-row-alt", "");
lrow.className = lrow.className.replace("x-grid3-row-alt", "");
}
}
}
},

updateSortIcon : function(col, dir){
var sc = this.sortClasses;
var clen = this.cm.getColumnCount();
var lclen = this.cm.getLockedCount();
var hds = this.mainHd.select('td').removeClass(sc);
var lhds = this.lockedHd.select('td').removeClass(sc);
if(lclen > 0 && col < lclen){
lhds.item(col).addClass(sc[dir == "DESC" ? 1 : 0]);
}else{
hds.item(col-lclen).addClass(sc[dir == "DESC" ? 1 : 0]);
}
},

updateColumnHidden : function(col, hidden){
var tw = this.cm.getTotalWidth();
var lw = this.cm.getTotalLockedWidth();
var lclen = this.cm.getLockedCount();
this.innerHd.firstChild.firstChild.style.width = tw + 'px';
var display = hidden ? 'none' : '';
var hd = this.getHeaderCell(col);
hd.style.display = display;
var ns, gw;
if(col < lclen) {
ns = this.getLockedRows();
gw = lw;
this.lockedHd.dom.firstChild.firstChild.style.width = gw + 'px';
this.mainWrap.dom.style.left= this.cm.getTotalLockedWidth() + 'px';
} else {
ns = this.getRows();
gw = tw - lw;
col -= lclen;
this.innerHd.firstChild.firstChild.style.width = gw + 'px';
}
for(var i = 0, len = ns.length; i < len; i++){
ns[i].style.width = gw + 'px';
ns[i].firstChild.style.width = gw + 'px';
ns[i].firstChild.rows[0].childNodes[col].style.display = display;
}
this.onColumnHiddenUpdated(col, hidden, tw);
delete this.lastViewWidth;
this.layout();
},

syncHeaderHeight : function() {
if(this.lockedInnerHd === undefined || this.innerHd === undefined){
return;
}
this.lockedInnerHd.firstChild.firstChild.style.height = "auto";
this.innerHd.firstChild.firstChild.style.height = "auto";
var height = (this.lockedInnerHd.firstChild.firstChild.offsetHeight > this.innerHd.firstChild.firstChild.offsetHeight) ?
this.lockedInnerHd.firstChild.firstChild.offsetHeight : this.innerHd.firstChild.firstChild.offsetHeight;
this.lockedInnerHd.firstChild.firstChild.style.height = height + 'px';
this.innerHd.firstChild.firstChild.style.height = height + 'px';
},

doRender : function(cs, rs, ds, startRow, colCount, stripe){
var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount-1;
var tw = this.cm.getTotalWidth();
var lw = this.cm.getTotalLockedWidth();
var clen = this.cm.getColumnCount();
var lclen = this.cm.getLockedCount();
var tstyle = 'width:'+this.getTotalWidth()+';';
var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {tstyle: tstyle}, r;
for(var j = 0, len = rs.length; j < len; j++){
r = rs[j]; cb = []; lcb = [];
var rowIndex = (j+startRow);
for(var i = 0; i < colCount; i++){
c = cs[i];
p.id = c.id;
p.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
p.attr = p.cellAttr = "";
p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
p.style = c.style;
if(p.value === undefined || p.value === ""){
p.value = " ";
}
if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
p.css += ' x-grid3-dirty-cell';
}
if(c.locked){
lcb[lcb.length] = ct.apply(p);
}else{
cb[cb.length] = ct.apply(p);
}
}
var alt = [];
if(stripe && ((rowIndex+1) % 2 === 0)){
alt[0] = "x-grid3-row-alt";
}
if(r.dirty){
alt[1] = " x-grid3-dirty-row";
}
rp.cols = colCount;
if(this.getRowClass){
alt[2] = this.getRowClass(r, rowIndex, rp, ds);
}
rp.alt = alt.join(" ");
rp.cells = lcb.join("");
rp.tstyle = 'width:'+lw+'px;';
lbuf[lbuf.length] = rt.apply(rp);
rp.cells = cb.join("");
rp.tstyle = 'width:'+(tw-lw)+'px;';
buf[buf.length] = rt.apply(rp);
}
return [buf.join(""), lbuf.join("")];
},

layout : function(){
if(!this.mainBody){
return;
}
var g = this.grid;
var c = g.getGridEl(), cm = this.cm,
expandCol = g.autoExpandColumn,
gv = this;
var lw = cm.getTotalLockedWidth();
var csize = c.getSize(true);
var vw = csize.width;
if (vw < 20 || csize.height < 20) {
return;
}
this.syncHeaderHeight();
if(g.autoHeight){
this.scroller.dom.style.overflow = 'visible';
this.lockedScroller.dom.style.overflow = 'visible';
}else{
this.el.setSize(csize.width, csize.height);
var vh = csize.height - this.mainHd.getHeight();
this.lockedScroller.setSize(lw, vh);
this.scroller.setSize(vw-lw, vh);
if(this.innerHd){
this.innerHd.style.width = (vw)+'px';
}
}
if(this.forceFit){
if(this.lastViewWidth != vw){
this.fitColumns(false, false);
this.lastViewWidth = vw;
}
}else {
this.autoExpand();
lw = cm.getTotalLockedWidth();
}
this.mainWrap.dom.style.left = lw +'px';
this.onLayout(vw, vh);
},

renderHeaders : function(){
var cm = this.cm, ts = this.templates;
var ct = ts.hcell;
var tw = this.cm.getTotalWidth();
var lw = this.cm.getTotalLockedWidth();
var cb = [], lb = [], sb = [], lsb = [], p = {};
for(var i = 0, len = cm.getColumnCount(); i < len; i++){
p.id = cm.getColumnId(i);
p.value = cm.getColumnHeader(i) || "";
p.style = this.getColumnStyle(i, true);
p.tooltip = this.getColumnTooltip(i);
if(cm.config[i].align == 'right'){
p.istyle = 'padding-right:16px';
}
if(cm.isLocked(i)) {
lb[lb.length] = ct.apply(p);
} else {
cb[cb.length] = ct.apply(p);
}
}

return [ts.header.apply({cells: cb.join(""), tstyle:'width:'+(tw-lw)+';'}),
ts.header.apply({cells: lb.join(""), tstyle:'width:'+(lw)+';'})];
},

getColumnTooltip : function(i) {
var tt = this.cm.getColumnTooltip(i);
if (tt) {
if (Ext.QuickTips.isEnabled()) {
return 'ext:qtip="'+tt+'"';
} else {
return 'title="'+tt+'"';
}
}
return "";
},

updateHeaders : function(){
var hd = this.renderHeaders();
this.innerHd.firstChild.innerHTML = hd[0];
this.lockedInnerHd.firstChild.innerHTML = hd[1];
},

insertRows : function(dm, firstRow, lastRow, isUpdate){
if(firstRow === 0 && lastRow == dm.getCount()-1){
this.refresh();
}else{
if(!isUpdate){
this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
}
var html = this.renderRows(firstRow, lastRow);
var before = this.getRow(firstRow);
if(before){
Ext.DomHelper.insertHtml('beforeBegin', before, html[0]);
} else {
Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html[0]);
}
var beforeLocked = this.getLockedRow(firstRow);
if (beforeLocked) {
Ext.DomHelper.insertHtml('beforeBegin', beforeLocked, html[1]);
}else{
Ext.DomHelper.insertHtml('beforeEnd', this.lockedBody.dom, html[1]);
}
if(!isUpdate){
this.fireEvent("rowsinserted", this, firstRow, lastRow);
this.processRows(firstRow);
}
}
},

removeRow : function(row) {
Ext.removeNode(this.getRow(row));
if (this.cm.getLockedCount() > 0) {
Ext.removeNode(this.getLockedRow(row));
}
},

getColumnData : function(){
var cs = [], cm = this.cm, colCount = cm.getColumnCount();
for(var i = 0; i < colCount; i++){
var name = cm.getDataIndex(i);
cs[i] = {
name : (typeof name == 'undefined' ? this.ds.fields.get(i).name : name),
renderer : cm.getRenderer(i),
id : cm.getColumnId(i),
style : this.getColumnStyle(i),
locked : cm.isLocked(i)
};
}
return cs;
},

renderBody : function(){
var markup = this.renderRows();
return [this.templates.body.apply({rows: markup[0]}), this.templates.body.apply({rows: markup[1]})];
},

refresh : function(headersToo){
this.fireEvent("beforerefresh", this);
this.grid.stopEditing();
var result = this.renderBody();
this.mainBody.update(result[0]);
this.lockedBody.update(result[1]);
if(headersToo === true){
this.updateHeaders();
this.updateHeaderSortState();
}
this.processRows(0, true);
this.layout();
this.applyEmptyText();
this.fireEvent("refresh", this);
},

handleLockChange : function(){
this.refresh(true);
},

onDenyColumnHide : function(){
},

onColumnLock : function(){
this.handleLockChange.apply(this, arguments);
},

addRowClass : function(row, cls){
var r = this.getRow(row);
if(r){
this.fly(r).addClass(cls);
r = this.getLockedRow(row);
this.fly(r).addClass(cls);
}
},

removeRowClass : function(row, cls){
var r = this.getRow(row);
if(r){
this.fly(r).removeClass(cls);
r = this.getLockedRow(row);
this.fly(r).removeClass(cls);
}
},

handleHdMenuClick : function(item){
var index = this.hdCtxIndex;
var cm = this.cm, ds = this.ds, lc;
switch(item.id){
case "asc":
ds.sort(cm.getDataIndex(index), "ASC");
break;
case "desc":
ds.sort(cm.getDataIndex(index), "DESC");
break;
case "lock":
lc = cm.getLockedCount();
if(cm.getColumnCount(true) <= lc+1){
this.onDenyColumnLock();
return;
}
if(lc != index){
cm.setLocked(index, true, true);
cm.moveColumn(index, lc);
this.grid.fireEvent("columnmove", index, lc);
}else{
cm.setLocked(index, true);
}
break;
case "unlock":
lc = cm.getLockedCount();
if((lc-1) != index){
cm.setLocked(index, false, true);
cm.moveColumn(index, lc-1);
this.grid.fireEvent("columnmove", index, lc-1);
}else{
cm.setLocked(index, false);
}
break;
default:
index = cm.getIndexById(item.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);
}
}
return true;
},

handleHdDown : function(e, t){
if(Ext.fly(t).hasClass('x-grid3-hd-btn')){
e.stopEvent();
var hd = this.findHeaderCell(t);
Ext.fly(hd).addClass('x-grid3-hd-menu-open');
var index = this.getCellIndex(hd);
this.hdCtxIndex = index;
var ms = this.hmenu.items, cm = this.cm;
ms.get("asc").setDisabled(!cm.isSortable(index));
ms.get("desc").setDisabled(!cm.isSortable(index));
if(this.grid.enableColLock !== false){
ms.get("lock").setDisabled(cm.isLocked(index));
ms.get("unlock").setDisabled(!cm.isLocked(index));
}
this.hmenu.on("hide", function(){
Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
}, this, {single:true});
this.hmenu.show(t, "tl-bl?");
}
},

renderUI : function(){
var header = this.renderHeaders();
var body = this.templates.body.apply({rows:''});
var html = this.templates.master.apply({
body: body,
header: header[0],
lockedBody: body,
lockedHeader: header[1]
});
var g = this.grid;
g.getGridEl().dom.innerHTML = html;
this.initElements();
Ext.fly(this.innerHd).on("click", this.handleHdDown, this);
Ext.fly(this.lockedInnerHd).on("click", this.handleHdDown, this);
this.mainHd.on("mouseover", this.handleHdOver, this);
this.mainHd.on("mouseout", this.handleHdOut, this);
this.mainHd.on("mousemove", this.handleHdMove, this);
this.lockedHd.on("mouseover", this.handleHdOver, this);
this.lockedHd.on("mouseout", this.handleHdOut, this);
this.lockedHd.on("mousemove", this.handleHdMove, this);
this.mainWrap.dom.style.left= this.cm.getTotalLockedWidth() + 'px';
this.scroller.on('scroll', this.syncScroll, this);
if(g.enableColumnResize !== false){
this.splitone = new Ext.grid.GridView.SplitDragZone(g, this.lockedHd.dom);
this.splitone.setOuterHandleElId(Ext.id(this.lockedHd.dom));
this.splitone.setOuterHandleElId(Ext.id(this.mainHd.dom));
}
if(g.enableColumnMove){
this.columnDrag = new Ext.grid.GridView.ColumnDragZone(g, this.innerHd);
this.columnDrop = new Ext.grid.HeaderDropZone(g, this.mainHd.dom);
}
if(g.enableHdMenu !== false){
if(g.enableColumnHide !== false){
this.colMenu = new Ext.menu.Menu({id:g.id + "-hcols-menu"});
this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
this.colMenu.on("itemclick", this.handleHdMenuClick, this);
}
this.hmenu = new Ext.menu.Menu({id: g.id + "-hctx"});
this.hmenu.add(
{id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},

{id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
);
if(this.grid.enableColLock !== false){
this.hmenu.add('-',
{id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},

{id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
);
}
if(g.enableColumnHide !== false){
this.hmenu.add('-',
{id:"columns", text: this.columnsText, menu: this.colMenu, iconCls: 'x-cols-icon'}
);
}
this.hmenu.on("itemclick", this.handleHdMenuClick, this);
}
if(g.enableDragDrop || g.enableDrag){
var dd = new Ext.grid.GridDragZone(g, {
ddGroup : g.ddGroup || 'GridDD'
});
}
this.updateHeaderSortState();
},

afterRender : function(){
var bd = this.renderRows();
if (bd === '') {
bd = ['', ''];
}
this.mainBody.dom.innerHTML = bd[0];
this.lockedBody.dom.innerHTML = bd[1];
this.processRows(0, true);
if(this.deferEmptyText !== true){
this.applyEmptyText();
}

},

updateAllColumnWidths : function(){
var tw = this.cm.getTotalWidth();
var lw = this.cm.getTotalLockedWidth();
var clen = this.cm.getColumnCount();
var lclen = this.cm.getLockedCount();
var ws = [];
var i;
for(i = 0; i < clen; i++){
ws[i] = this.getColumnWidth(i);
}
this.innerHd.firstChild.firstChild.style.width = (tw - lw) + 'px';
this.mainWrap.dom.style.left = lw + 'px';
this.lockedInnerHd.firstChild.firstChild.style.width = lw + 'px';
for(i = 0; i < clen; i++){
var hd = this.getHeaderCell(i);
hd.style.width = ws[i] + 'px';
}
var ns = this.getRows();
var lns = this.getLockedRows();
for(i = 0, len = ns.length; i < len; i++){
ns[i].style.width =(tw - lw) + 'px';
ns[i].firstChild.style.width = (tw-lw) + 'px';
lns[i].style.width = lw + 'px';
lns[i].firstChild.style.width = lw + 'px';
var j, row;
for(j = 0; j < lclen; j++){
row = lns[i].firstChild.rows[0];
row.childNodes[j].style.width = ws[j] + 'px';
}
for(j = lclen; j < clen; j++){
row = ns[i].firstChild.rows[0];
row.childNodes[j].style.width = ws[j] + 'px';
}
}
this.onAllColumnWidthsUpdated(ws, tw);
},

updateColumnWidth : function(col, width){
var w = this.getColumnWidth(col);
var tw = this.cm.getTotalWidth();
var lclen = this.cm.getLockedCount();
var lw = this.cm.getTotalLockedWidth();
var hd = this.getHeaderCell(col);
hd.style.width = w;
var ns, gw;
var ncol = col;
if(col < lclen) {
ns = this.getLockedRows();
gw = lw;
this.lockedInnerHd.firstChild.firstChild.style.width = gw + 'px';
this.mainWrap.dom.style.left= this.cm.getTotalLockedWidth() + 'px';
this.mainWrap.dom.style.display='none';
this.mainWrap.dom.style.display='';
}else {
ns = this.getRows();
gw = tw - lw;
ncol -= lclen;
this.innerHd.firstChild.firstChild.style.width = gw + 'px';
}
for(var i = 0, len = ns.length; i < len; i++){
ns[i].style.width = gw + 'px';
ns[i].firstChild.style.width = gw + 'px';
ns[i].firstChild.rows[0].childNodes[ncol].style.width = w;
}
this.onColumnWidthUpdated(col, w, tw);
this.layout();
},

getEditorParent : function(ed){
return this.el.dom;
},

refreshRow : function(record){
Ext.grid.LockingGridView.superclass.refreshRow.call(this, record);
var index = this.ds.indexOf(record);
this.getLockedRow(index).rowIndex = index;
}
});

Ext.grid.LockingColumnModel = Ext.extend(Ext.grid.ColumnModel,{
getTotalLockedWidth : function(){
var totalWidth = 0;
for(var i = 0; i < this.config.length; i++){
if(this.isLocked(i) && !this.isHidden(i)){
totalWidth += this.getColumnWidth(i);
}
}
return totalWidth;
}
});



Ext.override(Ext.grid.LockingGridView, {
renderUI : function(){
var header = this.renderHeaders();
var body = this.templates.body.apply({rows:''});
var html = this.templates.master.apply({
body: body,
header: header[0],
lockedBody: body,
lockedHeader: header[1]
});
var g = this.grid;
g.getGridEl().dom.innerHTML = html;
this.initElements();
Ext.fly(this.innerHd).on("click", this.handleHdDown, this);
Ext.fly(this.lockedInnerHd).on("click", this.handleHdDown, this);
this.mainHd.on("mouseover", this.handleHdOver, this);
this.mainHd.on("mouseout", this.handleHdOut, this);
this.mainHd.on("mousemove", this.handleHdMove, this);
this.lockedHd.on("mouseover", this.handleHdOver, this);
this.lockedHd.on("mouseout", this.handleHdOut, this);
this.lockedHd.on("mousemove", this.handleHdMove, this);
this.mainWrap.dom.style.left= this.cm.getTotalLockedWidth() + 'px';
this.scroller.on('scroll', this.syncScroll, this);
if(g.enableColumnResize !== false){
this.splitone = new Ext.grid.GridView.SplitDragZone(g, this.lockedHd.dom);
this.splitone.setOuterHandleElId(Ext.id(this.lockedHd.dom));
this.splitone.setOuterHandleElId(Ext.id(this.mainHd.dom));
}
if(g.enableColumnMove){
this.columnDrag = new Ext.grid.GridView.ColumnDragZone(g, this.innerHd);
this.columnDrop = new Ext.grid.HeaderDropZone(g, this.mainHd.dom);
}
if(g.enableHdMenu !== false){
if(g.enableColumnHide !== false){
this.colMenu = new Ext.menu.Menu({id:g.id + "-hcols-menu"});
this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
this.colMenu.on("itemclick", this.handleHdMenuClick, this);
}
this.hmenu = new Ext.menu.Menu({id: g.id + "-hctx"});
this.hmenu.add(
{id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
{id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
);
if(this.grid.enableColLock !== false){
this.hmenu.add('-',
{id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
{id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
);
}
if(g.enableColumnHide !== false){
this.hmenu.add('-',
{id:"columns", text: this.columnsText, menu: this.colMenu, iconCls: 'x-cols-icon'}
);
}
this.hmenu.on("itemclick", this.handleHdMenuClick, this);
}
if(g.enableDragDrop || g.enableDrag){
var dd = new Ext.grid.GridDragZone(g, {
ddGroup : g.ddGroup || 'GridDD'
});
}
this.updateHeaderSortState();
},
afterRender : function(){
var bd = this.renderRows();
if (bd == '') bd = ['', ''];
this.mainBody.dom.innerHTML = bd[0];
this.lockedBody.dom.innerHTML = bd[1];
this.processRows(0, true);
if(this.deferEmptyText !== true){
this.applyEmptyText();
}
},
updateAllColumnWidths : function(){
var tw = this.cm.getTotalWidth();
var lw = this.cm.getTotalLockedWidth();
var clen = this.cm.getColumnCount();
var lclen = this.cm.getLockedCount();
var ws = [];
for(var i = 0; i < clen; i++){
ws[i] = this.getColumnWidth(i);
}
this.innerHd.firstChild.firstChild.style.width = (tw - lw) + 'px';
this.mainWrap.dom.style.left = lw + 'px';
this.lockedInnerHd.firstChild.firstChild.style.width = lw + 'px';
for(var i = 0; i < clen; i++){
var hd = this.getHeaderCell(i);
hd.style.width = ws[i] + 'px';
}
var ns = this.getRows();
var lns = this.getLockedRows();
for(var i = 0, len = ns.length; i < len; i++){
ns[i].style.width =(tw - lw) + 'px';
ns[i].firstChild.style.width = (tw-lw) + 'px';
lns[i].style.width = lw + 'px';
lns[i].firstChild.style.width = lw + 'px';
for(var j = 0; j < lclen; j++){
var row = lns[i].firstChild.rows[0];
row.childNodes[j].style.width = ws[j] + 'px';
}
for(var j = lclen; j < clen; j++){
var row = ns[i].firstChild.rows[0];
row.childNodes[j].style.width = ws[j] + 'px';
}
}
this.onAllColumnWidthsUpdated(ws, tw);
},
updateColumnWidth : function(col, width){
var w = this.getColumnWidth(col);
var tw = this.cm.getTotalWidth();
var lclen = this.cm.getLockedCount();
var lw = this.cm.getTotalLockedWidth();
var hd = this.getHeaderCell(col);
hd.style.width = w;
var ns, gw;
var ncol = col;
if(col < lclen) {
ns = this.getLockedRows();
gw = lw;
this.lockedInnerHd.firstChild.firstChild.style.width = gw + 'px';
this.mainWrap.dom.style.left= this.cm.getTotalLockedWidth() + 'px';
this.mainWrap.dom.style.display='none';
this.mainWrap.dom.style.display='';
}else {
ns = this.getRows();
gw = tw - lw;
ncol -= lclen;
this.innerHd.firstChild.firstChild.style.width = gw + 'px';
}
for(var i = 0, len = ns.length; i < len; i++){
ns[i].style.width = gw + 'px';
ns[i].firstChild.style.width = gw + 'px';
ns[i].firstChild.rows[0].childNodes[ncol].style.width = w;
}
this.onColumnWidthUpdated(col, w, tw);
this.layout();
}


,getEditorParent : function(ed){
return this.el.dom;
}
,refreshRow : function(record){
Ext.grid.LockingGridView.superclass.refreshRow.call(this, record);
var index = this.ds.indexOf(record);
this.getLockedRow(index).rowIndex = index;
}
,getResolvedXY : function(resolved){
if(!resolved){
return null;
}
var lw = this.cm.getTotalLockedWidth();
var s = this.scroller.dom, c = resolved.cell, r = resolved.row;
return c ? Ext.fly(c).getXY() : [this.el.getX()+lw, Ext.fly(r).getY()];
}

});

Attached is a screenshot of the problem. Thank you in advance to anyone who can help me find a solution.

roderick.wu
6 Aug 2009, 11:08 PM
Hi, all,

I almost setup the work around for LockingEditorGridPanel except one issue:

Environment: Ext 2.1 with LockingEditorGridPanel update 4.
Description: after edit the unlocked colums, the corresponding locked cell will be copied one more automatically. the bad result is the locked row and unlocked row will mismatch once you modify any unclocked cell, once you edit one cell, the count of locked rows will add 1.

Thouhg Condor finished excellent version 6 on Ext3.0, while our framework is based on ext 2.1, so I have to try more ....struggling.....


I've created a new version of the LockingGridPanel extension for Ext 3.0.0 (here (http://www.extjs.com/forum/showthread.php?t=76324)).

This new version also fixes the horizontal scroll when clicking on a locked cell (but I don't think I will be backporting this fix to this Ext 2.x extension).

Xander75
8 Aug 2009, 2:16 AM
Hi,

Myself and a work colleague created a locked editor grid and had the same issues as everyone has been reporting regarding headers and body being misaligned.

It's a Saturday so I am not in work and don't have the code but we added code to resolve this by retrieving the id's of the header and body and forcing them to be the same width.

We also had the issue that when you clicked in the grid it would scroll back to the left, this was resolved by setting an override on the grid focus to return false.

NicoP
10 Aug 2009, 4:18 AM
Hi,

Does someone has tried to merge successfully the "locking grid column plugin" with the "livegrid plugin"?

Thanks.

Condor
10 Aug 2009, 5:07 AM
Does someone has try to merge successfully the "locking grid column plugin" with the "livegrid plugin"?

I don't think so. Merging these two is going to be a huge task, because both modify GridView extensively.

hhanna
13 Aug 2009, 1:18 PM
I noticed the stripeRows property isn't working on the locking grid (even in the example file) for update6.

I tried using getRowClass to do it but to no avail. Any ideas on how to resolve this?

BTW: Thanks for the 3.0 version. It is a real life-saver.

LoekieBoy
25 Aug 2009, 1:28 AM
Please do this for fixing the problem of checkbox not getting selected once locked by setting the property "locked = true";


Ext.override(Ext.grid.ColumnModel{
isLocked :function(colIndex){
if(this.config[colIndex] instanceof Ext.grid.CheckboxSelectionModel){return true;}
return this.config[colIndex].locked === true;
}
});

I have implemented this solution with CheckboxSelectionModel in place as the first column, however the checkbox selection is only allowing me to select one record at a time.

I have checked firebug and it is saying the singleSelect value is correctly set to be false.

How can I make it so that it selects multiple records or "select all" with the top check box?

I'm also having issues with this. I've noticed that in the code the deprecated "locked" property is used. However this property isn't deprecated in the CheckboxSelectionModel class, blocking multiple selections.


selectRow : function(index, keepExisting, preventViewNotify){
if(this.isLocked() || (index < 0 || index >= this.grid.store.getCount()) || (keepExisting && this.isSelected(index))){
return;
}
var r = this.grid.store.getAt(index);
if(r && this.fireEvent("beforerowselect", this, index, keepExisting, r) !== false){
if(!keepExisting || this.singleSelect){
this.clearSelections();
}
this.selections.add(r);
this.last = this.lastActive = index;
if(!preventViewNotify){
this.grid.getView().onRowSelect(index);
}
this.fireEvent("rowselect", this, index, r);
this.fireEvent("selectionchange", this);
}
}

Condor
25 Aug 2009, 1:49 AM
I'm also having issues with this. I've noticed that in the code the deprecated "locked" property is used. However this property isn't deprecated in the CheckboxSelectionModel class, blocking multiple selections.

These issues have nothing to do with each other. Locking in the columnmodel has been depricated since Ext 2.0 (that's what this extension is for), but you are talking about a locked selectionmodel.

MeDavid
25 Aug 2009, 3:05 AM
Hi,
Does someone has tried to merge successfully the "locking grid column plugin" with the "livegrid plugin"?


Yes. I'm trying to make the lockingColumn ux more like a plugin in such a way that you can sync multiple grids (one 'locking' grid and a non locking grid for example). This makes it also compatible with for example a grouping gridview. The bad news is: it's not finished yet

LoekieBoy
25 Aug 2009, 5:19 AM
These issues have nothing to do with each other. Locking in the columnmodel has been depricated since Ext 2.0 (that's what this extension is for), but you are talking about a locked selectionmodel.

then what could be causing the defect in the selectionmodel?
I have an example live here (http://stud.hro.nl/0784118/ext-2.3.0/examples/lockinggrid/columnLock.html)

Condor
25 Aug 2009, 5:38 AM
Now I see! It's a conflict between the CheckboxSelectionModel locked property and the column locked property (because you are using the CheckboxSelectionModel as a column).

Since you are not using the locking feature of a CheckboxSelectionModel you could use:

var sm = new Ext.grid.CheckboxSelectionModel({
locked: true,
isLocked: Ext.emptyFn
});

LoekieBoy
25 Aug 2009, 6:59 AM
Now I see! It's a conflict between the CheckboxSelectionModel locked property and the column locked property (because you are using the CheckboxSelectionModel as a column).

Since you are not using the locking feature of a CheckboxSelectionModel you could use:

var sm = new Ext.grid.CheckboxSelectionModel({
locked: true,
isLocked: Ext.emptyFn
});

That resolved the conflict of the locked property I think, but there is something else in the way the mouse click is handled. Ext calls "onMouseDown" of the GridPanel while it should call "onMouseDown" from the CheckboxSelectionModel. Stacks from firebug below:

Now:
selectRow() <<< selectRow is called with keepExisting false
handleMouseDown()
fire()
fireEvent()
processEvent()
onMouseDown() <<< of GridPanel
h()
wrappedFn()


Should be:
selectRow() <<< selectRow is called with keepExisting true
onMouseDown() <<< of CheckboxSelectionmodel
h()
wrappedFn()

Condor
25 Aug 2009, 7:30 AM
Yet another complicating factor.

Try this:

var sm = new Ext.grid.CheckboxSelectionModel({
locked: true,
isLocked: Ext.emptyFn,
initEvents : function(){
Ext.grid.CheckboxSelectionModel.superclass.initEvents.call(this);
this.grid.on('render', function(){
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
Ext.fly(view.lockedInnerHd).on('mousedown', this.onHdMouseDown, this);
}, this);
}
});

jchau
27 Aug 2009, 10:17 AM
There's a bug with clicking on a row. It resets the horizontal scroll to the beginning. This makes it very hard to scroll to a column to the right and try to click on a few rows. Will this be fixed?

Using Update5 with Ext 2.2. Tested in IE7, IE8, and Chrome.

Condor
27 Aug 2009, 10:24 AM
There's a bug with clicking on a row. It resets the horizontal scroll to the beginning. This makes it very hard to scroll to a column to the right and try to click on a few rows. Will this be fixed?

Using Update5 with Ext 2.2. Tested in IE7, IE8, and Chrome.

I know about this already. I fixed it in update 6 (for Ext 3.0), but I don't have the time to backport this to a Ext 2.1, 2.2 and 2.3 version (yes, these would all be different!).

jchau
27 Aug 2009, 10:45 AM
I know about this already. I fixed it in update 6 (for Ext 3.0), but I don't have the time to backport this to a Ext 2.1, 2.2 and 2.3 version (yes, these would all be different!).

I will try and do a diff between the two versions and see if I can fix it. This is possible to fix in Ext 2.2, right? Dont want to spend too much time on it if you already know it's not possible. Thanks!

(your extension is a life saver...)

jchau
27 Aug 2009, 11:00 AM
I will try and do a diff between the two versions and see if I can fix it. This is possible to fix in Ext 2.2, right? Dont want to spend too much time on it if you already know it's not possible. Thanks!

(your extension is a life saver...)

Oops. The fix was already on page 20. I added the following to LockingGridView



getResolvedXY: function(resolved) {
if (!resolved) {
return null;
}
var c = resolved.cell, r = resolved.row;
return c ? Ext.fly(c).getXY() : [this.scroller.getX(), Ext.fly(r).getY()];
},

jchau
14 Sep 2009, 1:45 PM
There is another scrolling bug in IE6. The headers do not scroll with the rest of the grid during horizontal scrolling. I found a few old posts that describe the same issue but no fix has been posted.

imran
24 Sep 2009, 7:54 AM
I'm seeing the same issue when using this extension with 2.3.1.

Basically, the unlocked column headers do not scroll with the body. The reason I'm not upping to 3.0 is because I have the LockingGroupHeader plugin already being used in prod.

When debugging the issue in firebug, I'm able to trace it to the syncHeaderScroll function in GridView:


syncHeaderScroll : function(){
var mb = this.scroller.dom;
this.innerHd.scrollLeft = mb.scrollLeft;
this.innerHd.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore)
}


Although mb.scrollLeft has a value for some reason it does not get stored in innerHd.scrollLeft. I also tried to forcibly set it from Firebug's js console but to no avail:


Ext.getCmp("mygrid").view.innerHd.scrollLeft=25;


The above line correctly scrolls the header in 2.2.1, but does nothing in 2.3.1

Condor, any pointers would be greatly appreciated

Thanks

Condor
24 Sep 2009, 9:26 PM
Ext.grid.GridView changes significantly between Ext 2.2.1 and Ext 2.3, which can cause several display issues in LockingGridView.

I should probably create a LockingGridView for Ext 2.3 (based on the current Ext 3.0 code)...

jchau
7 Oct 2009, 5:01 AM
A lockinggridpanel for Ext 2.3 would be super awesome. I am sure there are quite a few of us who is holding off the Ext 3.0 upgrade due to breaking changes.

ancorgs
27 Oct 2009, 12:02 AM
I'm quite new in ExtJS. In fact, I'm using it through Lipsiadmin (http://github.com/Lipsiasoft/lipsiadmin). I'm trying to integrate LockedGroupHeaderGrid with Lipsiadmin, but I'm not able to make a simple example work.

I'm using Ext 2.2.1, which is the one included in the stable version of Lipsiadmin (yes, in the homepage it's said that is based en ExtJS 3, but it only applies to the development versions). I've tried this simple example (directly grabbed from GroupHeaderPlugin-widthfix.zip):



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http: //www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http: //www.w3.org/1999/xhtml" xml: lang="en" lang="en">
<head>
<link rel="stylesheet" type="text/css" href="../ext.css" />
<link rel="stylesheet" type="text/css" href="GroupHeaderPlugin.css" />
<link rel="stylesheet" type="text/css" href="columnLock.css" />
<script type="text/javascript" src="../prototype.js"></script>
<script type="text/javascript" src="../effects.js"></script>
<script type="text/javascript" src="../dragdrop.js"></script>
<script type="text/javascript" src="../controls.js"></script>
<script type="text/javascript" src="../ext.js"></script>
<script type="text/javascript" src="../locale.js"></script>
<script type="text/javascript" src="../backend.js"></script>
<script type="text/javascript" src="LockedGroupHeaderPlugin.js"></script>
<script type="text/javascript">
Ext.BLANK_IMAGE_URL = '../resources/images/default/s.gif';
Ext.onReady(function() {
new Ext.Viewport({
layout: 'fit',
items: [{
xtype: 'grid',
title: 'LockedGroupHeaderPlugin Example',
store: new Ext.data.SimpleStore({
fields: ['id', 'nr1', 'text1', 'info1', 'special1', 'nr2', 'text2', 'info2', 'special2', 'special3', 'changed'],
data: [
['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11']
]
}),
colModel: new Ext.grid.ColumnModel({
columns: [
{header: 'Id', width: 25, dataIndex: 'id', locked: true},
{header: 'Nr', width: 25, dataIndex: 'nr1'},
{header: 'Text', width: 50, dataIndex: 'text1'},
{header: 'Info', width: 50, dataIndex: 'info1'},
{header: 'Special', width: 60, dataIndex: 'special1'},
{header: 'Nr', width: 25, dataIndex: 'nr2'},
{header: 'Text', width: 50, dataIndex: 'text2'},
{header: 'Info', width: 50, dataIndex: 'info2'},
{header: 'Special', width: 60, dataIndex: 'special2'},
{header: 'Special', width: 60, dataIndex: 'special3'},
{header: 'Changed', width: 50, dataIndex: 'changed'}
],
defaultSortable: true,
rows: [
[
{locked:true},
{header: 'Before', colspan: 4, align: 'center'},
{header: 'After', colspan: 4, align: 'center'},
{colspan: 2}
], [
{locked:true},
{},
{header: 'Merchandise', colspan: 3, align: 'center'},
{},
{header: 'Merchandise', colspan: 3, align: 'center'},
{header: 'Sum', colspan: 2, align: 'center'}
]
]
}),
enableColumnMove: false,
viewConfig: {
forceFit: false
},
plugins: [new Ext.ux.plugins.LockedGroupHeaderGrid()]
}]
});
});
</script>
</head>
<body>
</body>
</html>
Where LockedGroupHeaderPlugin.js contains the code Condor posted in this thread. I get the result showed in the attached screenshot. Sure I'm missing something very obvious for most of you, but I'm a newbie.

Thanks in advance.

Condor
27 Oct 2009, 12:44 AM
For Ext 2.2.1 you need to use the update5 version of the GroupHeaderGrid plugin.

ps. This plugin does NOT support column locking. I have created a LockedGroupHeaderGrid plugin for Ext 2.3 and 3.0.x (other versions on demand), but it's not freeware.

ancorgs
27 Oct 2009, 1:25 AM
Well, we are more interested in the locking feature than in the group header one, so I suppose we'll use columnLock instead.

Would the 2.3 version of LockedGroupHeader work with 2.2.1? We can pay, that's not such a big problem. In case not, how much would cost to have a 2.2.1 version?

Condor
27 Oct 2009, 1:59 AM
I'm asking €150 for existing LockingGroupHeaderGrid plugin versions (currently only Ext 3.0.0) and €600 for the first one to request the plugin for a different version (to cover developement time).

setzor
4 Nov 2009, 5:42 PM
Got it installed and "working" for the most part, still needing to tweak some stuff here and there.

The easiest way to word my problem is that when I click on an editable cell, the editor for the cell I clicked on appears in the cell to the right.

I only have 1 column locked, so I'm guessing that the counter for which column it is that's being detected for the edit is off, like it's accessing the wrong index.

Using ExtJS 2.2.1 and the update5 plugin from the first post.

If any more clarification is needed please let me know, I'm soooo close :s

SMIRZA
19 Nov 2009, 1:11 PM
Hi this is a gr8 plugin! i was wondering if you cane tell me whether it works with GroupingVIew?

Condor
20 Nov 2009, 1:34 AM
Hi this is a gr8 plugin! i was wondering if you cane tell me whether it works with GroupingVIew?

No it doesn't.

You would have to create a LockingGroupingView (lot of work!).

DirkWei
23 Nov 2009, 6:40 PM
I want to know if it is possible to lock the first row of grid and change it's backcolor?

Condor
23 Nov 2009, 11:34 PM
I want to know if it is possible to lock the first row of grid and change it's backcolor?

You mean something like a GridSummary (http://www.extjs.com/forum/showthread.php?t=20802), but at the top instead of the bottom?

Or more something like a HeaderGroup (http://www.extjs.com/forum/showthread.php?t=76322) (multiple header rows)?

abotero
17 Dec 2009, 9:02 AM
Got it installed and "working" for the most part, still needing to tweak some stuff here and there.

The easiest way to word my problem is that when I click on an editable cell, the editor for the cell I clicked on appears in the cell to the right.

I only have 1 column locked, so I'm guessing that the counter for which column it is that's being detected for the edit is off, like it's accessing the wrong index.

Using ExtJS 2.2.1 and the update5 plugin from the first post.

If any more clarification is needed please let me know, I'm soooo close :s


There are a problem with the Ext.ux.grid.CheckColumn. If this is in the first column the editor is displayed in the next column. I used the example from Ext 3.1.

For now I solved it leaving the CheckColumn in the last column.

fangzhouxing
1 Jan 2010, 5:53 AM
I found that the Ext 3.0 version of this extension can be used with Ext 2.3 with small modifications:


/*
* ColumnLock v1.7.1 for Ext 3 (changed for 2.3)
*/
Ext.ns('Ext.ux.grid');

Templates = {
columnLockTpl : new Ext.Template(
'<div class="x-grid3" hidefocus="true">',
'<div class="x-grid3-locked">',
'<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset" style="{lstyle}">{lockedHeader}</div></div><div class="x-clear"></div></div>',
'<div class="x-grid3-scroller"><div class="x-grid3-body" style="{lstyle}">{lockedBody}</div><div class="x-grid3-scroll-spacer"></div></div>',
'</div>',
'<div class="x-grid3-viewport x-grid3-unlocked">',
'<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset" style="{ostyle}">{header}</div></div><div class="x-clear"></div></div>',
'<div class="x-grid3-scroller"><div class="x-grid3-body" style="{bstyle}">{body}</div><a href="#" class="x-grid3-focus" tabIndex="-1"></a></div>',
'</div>',
'<div class="x-grid3-resize-marker">&#160;</div>',
'<div class="x-grid3-resize-proxy">&#160;</div>',
'</div>')

};

Ext.ux.grid.LockingGridPanel = Ext.extend(Ext.grid.GridPanel, {
initComponent : function(){
if(!this.cm && !this.colModel && Ext.isArray(this.columns)){
this.colModel = new Ext.ux.grid.LockingColumnModel(this.columns);
delete this.columns;
}
Ext.ux.grid.LockingGridPanel.superclass.initComponent.call(this);
},
getView : function(){
if(!this.view){
this.view = new Ext.ux.grid.LockingGridView(this.viewConfig);
}
return this.view;
}
});

Ext.ux.grid.LockingEditorGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {
initComponent : function(){
if(!this.cm && !this.colModel && Ext.isArray(this.columns)){
this.colModel = new Ext.ux.grid.LockingColumnModel(this.columns);
delete this.columns;
}
Ext.ux.grid.LockingEditorGridPanel.superclass.initComponent.call(this);
},
getView : function(){
if(!this.view){
this.view = new Ext.ux.grid.LockingGridView(this.viewConfig);
}
return this.view;
}
});

// Added after Ext 3.0.0
Ext.applyIf(Ext.grid.GridView.prototype, {
getScrollOffset: function(){
return this.scrollOffset!=undefined ? this.scrollOffset : Ext.getScrollBarWidth();
}
});

Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, {
lockText : 'Lock',
unlockText : 'Unlock',
rowBorderWidth : 1,
lockedBorderWidth : 1,
initTemplates : function(){
var ts = this.templates || {};
if(!ts.master){
ts.master = Templates.columnLockTpl
}
this.templates = ts;
Ext.ux.grid.LockingGridView.superclass.initTemplates.call(this);
},
getEditorParent : function(ed){
return this.el.dom;
},
initElements : function(){
var E = Ext.Element;
var el = this.grid.getGridEl().dom.firstChild;
var cs = el.childNodes;
this.el = new E(el);
this.lockedWrap = new E(cs[0]);
this.lockedHd = new E(this.lockedWrap.dom.firstChild);
this.lockedInnerHd = this.lockedHd.dom.firstChild;
this.lockedScroller = new E(this.lockedWrap.dom.childNodes[1]);
this.lockedBody = new E(this.lockedScroller.dom.firstChild);
this.mainWrap = new E(cs[1]);
this.mainHd = new E(this.mainWrap.dom.firstChild);
if(this.grid.hideHeaders){
this.lockedHd.setDisplayed(false);
this.mainHd.setDisplayed(false);
}
this.innerHd = this.mainHd.dom.firstChild;
this.scroller = new E(this.mainWrap.dom.childNodes[1]);
if(this.forceFit){
this.scroller.setStyle('overflow-x', 'hidden');
}
this.mainBody = new E(this.scroller.dom.firstChild);
this.focusEl = new E(this.scroller.dom.childNodes[1]);
this.focusEl.swallowEvent('click', true);
this.resizeMarker = new E(cs[2]);
this.resizeProxy = new E(cs[3]);
},
getLockedRows : function(){
return this.hasRows() ? this.lockedBody.dom.childNodes : [];
},
getLockedRow : function(row){
return this.getLockedRows()[row];
},
getCell : function(row, col){
var llen = this.cm.getLockedCount();
if(col < llen){
return this.getLockedRow(row).getElementsByTagName('td')[col];
}
return Ext.ux.grid.LockingGridView.superclass.getCell.call(this, row, col - llen);
},
getHeaderCell : function(index){
var llen = this.cm.getLockedCount();
if(index < llen){
return this.lockedHd.dom.getElementsByTagName('td')[index];
}
return Ext.ux.grid.LockingGridView.superclass.getHeaderCell.call(this, index - llen);
},
addRowClass : function(row, cls){
var r = this.getLockedRow(row);
if(r){
this.fly(r).addClass(cls);
}
Ext.ux.grid.LockingGridView.superclass.addRowClass.call(this, row, cls);
},
removeRowClass : function(row, cls){
var r = this.getLockedRow(row);
if(r){
this.fly(r).removeClass(cls);
}
Ext.ux.grid.LockingGridView.superclass.removeRowClass.call(this, row, cls);
},
removeRow : function(row) {
Ext.removeNode(this.getLockedRow(row));
Ext.ux.grid.LockingGridView.superclass.removeRow.call(this, row);
},
removeRows : function(firstRow, lastRow){
var bd = this.lockedBody.dom;
for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
Ext.removeNode(bd.childNodes[firstRow]);
}
Ext.ux.grid.LockingGridView.superclass.removeRows.call(this, firstRow, lastRow);
},
syncScroll : function(e){
var mb = this.scroller.dom;
this.lockedScroller.dom.scrollTop = mb.scrollTop;
Ext.ux.grid.LockingGridView.superclass.syncScroll.call(this, e);
},
updateSortIcon : function(col, dir){
var sc = this.sortClasses,
lhds = this.lockedHd.select('td').removeClass(sc),
hds = this.mainHd.select('td').removeClass(sc),
llen = this.cm.getLockedCount();
if(col < llen){
lhds.item(col).addClass(sc[dir == 'DESC' ? 1 : 0]);
}else{
hds.item(col - llen).addClass(sc[dir == 'DESC' ? 1 : 0]);
}
},
updateAllColumnWidths : function(){
var tw = this.getTotalWidth(),
clen = this.cm.getColumnCount(),
lw = this.getLockedWidth(),
llen = this.cm.getLockedCount(),
ws = [], len, i;
this.updateLockedWidth();
for(i = 0; i < clen; i++){
ws[i] = this.getColumnWidth(i);
var hd = this.getHeaderCell(i);
hd.style.width = ws[i];
}
var lns = this.getLockedRows(), ns = this.getRows(), row, trow, j;
for(i = 0, len = ns.length; i < len; i++){
row = lns[i];
row.style.width = lw;
if(row.firstChild){
row.firstChild.style.width = lw;
trow = row.firstChild.rows[0];
for (j = 0; j < llen; j++) {
trow.childNodes[j].style.width = ws[j];
}
}
row = ns[i];
row.style.width = tw;
if(row.firstChild){
row.firstChild.style.width = tw;
trow = row.firstChild.rows[0];
for (j = llen; j < clen; j++) {
trow.childNodes[j - llen].style.width = ws[j];
}
}
}
this.onAllColumnWidthsUpdated(ws, tw);
//this.syncHeaderHeight();
},
updateColumnWidth : function(col, width){
var w = this.getColumnWidth(col),
llen = this.cm.getLockedCount(),
ns, rw, c, row;
this.updateLockedWidth();
if(col < llen){
ns = this.getLockedRows();
rw = this.getLockedWidth();
c = col;
}else{
ns = this.getRows();
rw = this.getTotalWidth();
c = col - llen;
}
var hd = this.getHeaderCell(col);
hd.style.width = w;
for(var i = 0, len = ns.length; i < len; i++){
row = ns[i];
row.style.width = rw;
if(row.firstChild){
row.firstChild.style.width = rw;
row.firstChild.rows[0].childNodes[c].style.width = w;
}
}
this.onColumnWidthUpdated(col, w, this.getTotalWidth());
//this.syncHeaderHeight();
},
updateColumnHidden : function(col, hidden){
var llen = this.cm.getLockedCount(),
ns, rw, c, row,
display = hidden ? 'none' : '';
this.updateLockedWidth();
if(col < llen){
ns = this.getLockedRows();
rw = this.getLockedWidth();
c = col;
}else{
ns = this.getRows();
rw = this.getTotalWidth();
c = col - llen;
}
var hd = this.getHeaderCell(col);
hd.style.display = display;
for(var i = 0, len = ns.length; i < len; i++){
row = ns[i];
row.style.width = rw;
if(row.firstChild){
row.firstChild.style.width = rw;
row.firstChild.rows[0].childNodes[c].style.display = display;
}
}
this.onColumnHiddenUpdated(col, hidden, this.getTotalWidth());
delete this.lastViewWidth;
this.layout();
},
doRender : function(cs, rs, ds, startRow, colCount, stripe){
var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount-1,
tstyle = 'width:'+this.getTotalWidth()+';',
lstyle = 'width:'+this.getLockedWidth()+';',
buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r;
for(var j = 0, len = rs.length; j < len; j++){
r = rs[j]; cb = []; lcb = [];
var rowIndex = (j+startRow);
for(var i = 0; i < colCount; i++){
c = cs[i];
p.id = c.id;
p.css = (i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '')) +
(this.cm.config[i].cellCls ? ' ' + this.cm.config[i].cellCls : '');
p.attr = p.cellAttr = '';
p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
p.style = c.style;
if(Ext.isEmpty(p.value)){
p.value = '&#160;';
}
if(this.markDirty && r.dirty && r.modified[c.name]!=undefined){
p.css += ' x-grid3-dirty-cell';
}
if(c.locked){
lcb[lcb.length] = ct.apply(p);
}else{
cb[cb.length] = ct.apply(p);
}
}
var alt = [];
if(stripe && ((rowIndex+1) % 2 === 0)){
alt[0] = 'x-grid3-row-alt';
}
if(r.dirty){
alt[1] = ' x-grid3-dirty-row';
}
rp.cols = colCount;
if(this.getRowClass){
alt[2] = this.getRowClass(r, rowIndex, rp, ds);
}
rp.alt = alt.join(' ');
rp.cells = cb.join('');
rp.tstyle = tstyle;
buf[buf.length] = rt.apply(rp);
rp.cells = lcb.join('');
rp.tstyle = lstyle;
lbuf[lbuf.length] = rt.apply(rp);
}
return [buf.join(''), lbuf.join('')];
},
processRows : function(startRow, skipStripe){
if(!this.ds || this.ds.getCount() < 1){
return;
}
var rows = this.getRows(),
lrows = this.getLockedRows();
skipStripe = skipStripe || !this.grid.stripeRows;
startRow = startRow || 0;
Ext.each(rows, function(row, idx){
var lrow = lrows[idx];
row.rowIndex = idx;
lrow.rowIndex = idx;
if (!skipStripe && (idx + 1) % 2 === 0) {
row.className = row.className.replace(this.rowClsRe, ' ');
lrow.className = lrow.className.replace(this.rowClsRe, ' ');
row.className += ' x-grid3-row-alt';
lrow.className += ' x-grid3-row-alt';
}
}, this);
if(startRow === 0){
Ext.fly(rows[0]).addClass(this.firstRowCls);
Ext.fly(lrows[0]).addClass(this.firstRowCls);
}
Ext.fly(rows[rows.length - 1]).addClass(this.lastRowCls);
Ext.fly(lrows[lrows.length - 1]).addClass(this.lastRowCls);
},
afterRender : function(){
if(!this.ds || !this.cm){
return;
}
var bd = this.renderRows() || ['&#160;', '&#160;'];
this.mainBody.dom.innerHTML = bd[0];
this.lockedBody.dom.innerHTML = bd[1];
this.processRows(0, true);
if(this.deferEmptyText !== true){
this.applyEmptyText();
}
},
renderUI : function(){
var header = this.renderHeaders();
var body = this.templates.body.apply({rows:'&#160;'});
var html = this.templates.master.apply({
body: body,
header: header[0],
ostyle: 'width:'+this.getOffsetWidth()+';',
bstyle: 'width:'+this.getTotalWidth()+';',
lockedBody: body,
lockedHeader: header[1],
lstyle: 'width:'+this.getLockedWidth()+';'
});
var g = this.grid;
g.getGridEl().dom.innerHTML = html;
this.initElements();
Ext.fly(this.innerHd).on('click', this.handleHdDown, this);
Ext.fly(this.lockedInnerHd).on('click', this.handleHdDown, this);
this.mainHd.on({
scope: this,
mouseover: this.handleHdOver,
mouseout: this.handleHdOut,
mousemove: this.handleHdMove
});
this.lockedHd.on({
scope: this,
mouseover: this.handleHdOver,
mouseout: this.handleHdOut,
mousemove: this.handleHdMove
});
this.scroller.on('scroll', this.syncScroll, this);
if(g.enableColumnResize !== false){
this.splitZone = new Ext.grid.GridView.SplitDragZone(g, this.mainHd.dom);
this.splitZone.setOuterHandleElId(Ext.id(this.lockedHd.dom));
this.splitZone.setOuterHandleElId(Ext.id(this.mainHd.dom));
}
if(g.enableColumnMove){
this.columnDrag = new Ext.grid.GridView.ColumnDragZone(g, this.innerHd);
this.columnDrag.setOuterHandleElId(Ext.id(this.lockedInnerHd));
this.columnDrag.setOuterHandleElId(Ext.id(this.innerHd));
this.columnDrop = new Ext.grid.HeaderDropZone(g, this.mainHd.dom);
}
if(g.enableHdMenu !== false){
this.hmenu = new Ext.menu.Menu({id: g.id + '-hctx'});
this.hmenu.add(
{itemId: 'asc', text: this.sortAscText, cls: 'xg-hmenu-sort-asc'},
{itemId: 'desc', text: this.sortDescText, cls: 'xg-hmenu-sort-desc'}
);
if(this.grid.enableColLock !== false){
this.hmenu.add('-',
{itemId: 'lock', text: this.lockText, cls: 'xg-hmenu-lock'},
{itemId: 'unlock', text: this.unlockText, cls: 'xg-hmenu-unlock'}
);
}
if(g.enableColumnHide !== false){
this.colMenu = new Ext.menu.Menu({id:g.id + '-hcols-menu'});
this.colMenu.on({
scope: this,
beforeshow: this.beforeColMenuShow,
itemclick: this.handleHdMenuClick
});
this.hmenu.add('-', {
itemId:'columns',
hideOnClick: false,
text: this.columnsText,
menu: this.colMenu,
iconCls: 'x-cols-icon'
});
}
this.hmenu.on('itemclick', this.handleHdMenuClick, this);
}
if(g.trackMouseOver){
this.mainBody.on({
scope: this,
mouseover: this.onRowOver,
mouseout: this.onRowOut
});
this.lockedBody.on({
scope: this,
mouseover: this.onRowOver,
mouseout: this.onRowOut
});
}
if(g.enableDragDrop || g.enableDrag){
this.dragZone = new Ext.grid.GridDragZone(g, {
ddGroup : g.ddGroup || 'GridDD'
});
}
this.updateHeaderSortState();
},
layout : function(){
if(!this.mainBody){
return;
}
var g = this.grid;
var c = g.getGridEl();
var csize = c.getSize(true);
var vw = csize.width;
if(!g.hideHeaders && (vw < 20 || csize.height < 20)){
return;
}
//this.syncHeaderHeight();
if(g.autoHeight){
this.scroller.dom.style.overflow = 'visible';
this.lockedScroller.dom.style.overflow = 'visible';
if(Ext.isWebKit){
this.scroller.dom.style.position = 'static';
this.lockedScroller.dom.style.position = 'static';
}
}else{
this.el.setSize(csize.width, csize.height);
var hdHeight = this.mainHd.getHeight();
var vh = csize.height - (hdHeight);
}
this.updateLockedWidth();
if(this.forceFit){
if(this.lastViewWidth != vw){
this.fitColumns(false, false);
this.lastViewWidth = vw;
}
}else {
this.autoExpand();
this.syncHeaderScroll();
}
this.onLayout(vw, vh);
},
getOffsetWidth : function() {
return (this.cm.getTotalWidth() - this.cm.getTotalLockedWidth() + this.getScrollOffset()) + 'px';
},
renderHeaders : function(){
var cm = this.cm,
ts = this.templates,
ct = ts.hcell,
cb = [], lcb = [],
p = {},
len = cm.getColumnCount(),
last = len - 1;
for(var i = 0; i < len; i++){
p.id = cm.getColumnId(i);
p.value = cm.getColumnHeader(i) || '';
p.style = this.getColumnStyle(i, true);
p.tooltip = this.getColumnTooltip(i);
p.css = (i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '')) +
(cm.config[i].headerCls ? ' ' + cm.config[i].headerCls : '');
if(cm.config[i].align == 'right'){
p.istyle = 'padding-right:16px';
} else {
delete p.istyle;
}
if(cm.isLocked(i)){
lcb[lcb.length] = ct.apply(p);
}else{
cb[cb.length] = ct.apply(p);
}
}
return [ts.header.apply({cells: cb.join(''), tstyle:'width:'+this.getTotalWidth()+';'}),
ts.header.apply({cells: lcb.join(''), tstyle:'width:'+this.getLockedWidth()+';'})];
},
updateHeaders : function(){
var hd = this.renderHeaders();
this.innerHd.firstChild.innerHTML = hd[0];
this.innerHd.firstChild.style.width = this.getOffsetWidth();
this.innerHd.firstChild.firstChild.style.width = this.getTotalWidth();
this.lockedInnerHd.firstChild.innerHTML = hd[1];
var lw = this.getLockedWidth();
this.lockedInnerHd.firstChild.style.width = lw;
this.lockedInnerHd.firstChild.firstChild.style.width = lw;
},
getResolvedXY : function(resolved){
if(!resolved){
return null;
}
var c = resolved.cell, r = resolved.row;
return c ? Ext.fly(c).getXY() : [this.scroller.getX(), Ext.fly(r).getY()];
},
syncFocusEl : function(row, col, hscroll){
Ext.ux.grid.LockingGridView.superclass.syncFocusEl.call(this, row, col, col < this.cm.getLockedCount() ? false : hscroll);
},
ensureVisible : function(row, col, hscroll){
return Ext.ux.grid.LockingGridView.superclass.ensureVisible.call(this, row, col, col < this.cm.getLockedCount() ? false : hscroll);
},
insertRows : function(dm, firstRow, lastRow, isUpdate){
var last = dm.getCount() - 1;
if(!isUpdate && firstRow === 0 && lastRow >= last){
this.refresh();
}else{
if(!isUpdate){
this.fireEvent('beforerowsinserted', this, firstRow, lastRow);
}
var html = this.renderRows(firstRow, lastRow),
before = this.getRow(firstRow);
if(before){
if(firstRow === 0){
this.removeRowClass(0, this.firstRowCls);
}
Ext.DomHelper.insertHtml('beforeBegin', before, html[0]);
before = this.getLockedRow(firstRow);
Ext.DomHelper.insertHtml('beforeBegin', before, html[1]);
}else{
this.removeRowClass(last - 1, this.lastRowCls);
Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html[0]);
Ext.DomHelper.insertHtml('beforeEnd', this.lockedBody.dom, html[1]);
}
if(!isUpdate){
this.fireEvent('rowsinserted', this, firstRow, lastRow);
this.processRows(firstRow);
}else if(firstRow === 0 || firstRow >= last){
this.addRowClass(firstRow, firstRow === 0 ? this.firstRowCls : this.lastRowCls);
}
}
this.syncFocusEl(firstRow);
},
getColumnStyle : function(col, isHeader){
var style = !isHeader ? this.cm.config[col].cellStyle || this.cm.config[col].css || '' : this.cm.config[col].headerStyle || '';
style += 'width:'+this.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;
},
getLockedWidth : function() {
return this.cm.getTotalLockedWidth() + 'px';
},
getTotalWidth : function() {
return (this.cm.getTotalWidth() - this.cm.getTotalLockedWidth()) + 'px';
},
getColumnData : function(){
var cs = [], cm = this.cm, colCount = cm.getColumnCount();
for(var i = 0; i < colCount; i++){
var name = cm.getDataIndex(i);
cs[i] = {
name : (name==undefined ? this.ds.fields.get(i).name : name),
renderer : cm.getRenderer(i),
id : cm.getColumnId(i),
style : this.getColumnStyle(i),
locked : cm.isLocked(i)
};
}
return cs;
},
renderBody : function(){
var markup = this.renderRows() || ['&#160;', '&#160;'];
return [this.templates.body.apply({rows: markup[0]}), this.templates.body.apply({rows: markup[1]})];
},
refreshRow : function(record){
Ext.ux.grid.LockingGridView.superclass.refreshRow.call(this, record);
var index = Ext.isNumber(record) ? record : this.ds.indexOf(record);
this.getLockedRow(index).rowIndex = index;
},
refresh : function(headersToo){
this.fireEvent('beforerefresh', this);
this.grid.stopEditing(true);
var result = this.renderBody();
this.mainBody.update(result[0]).setWidth(this.getTotalWidth());
this.lockedBody.update(result[1]).setWidth(this.getLockedWidth());
if(headersToo === true){
this.updateHeaders();
this.updateHeaderSortState();
}
this.processRows(0, true);
this.layout();
this.applyEmptyText();
this.fireEvent('refresh', this);
},
onDenyColumnLock : function(){

},
initData : function(ds, cm){
if(this.cm){
this.cm.un('columnlockchange', this.onColumnLock, this);
}
Ext.ux.grid.LockingGridView.superclass.initData.call(this, ds, cm);
if(this.cm){
this.cm.on('columnlockchange', this.onColumnLock, this);
}
},
onColumnLock : function(){
this.refresh(true);
},
handleHdMenuClick : function(item){
var index = this.hdCtxIndex,
cm = this.cm,
id = item.getItemId(),
llen = cm.getLockedCount();
switch(id){
case 'lock':
if(cm.getColumnCount(true) <= llen + 1){
this.onDenyColumnLock();
return;
}
if(llen != index){
cm.setLocked(index, true, true);
cm.moveColumn(index, llen);
this.grid.fireEvent('columnmove', index, llen);
}else{
cm.setLocked(index, true);
}
break;
case 'unlock':
if(llen - 1 != index){
cm.setLocked(index, false, true);
cm.moveColumn(index, llen - 1);
this.grid.fireEvent('columnmove', index, llen - 1);
}else{
cm.setLocked(index, false);
}
break;
default:
return Ext.ux.grid.LockingGridView.superclass.handleHdMenuClick.call(this, item);
}
return true;
},
handleHdDown : function(e, t){
Ext.ux.grid.LockingGridView.superclass.handleHdDown.call(this, e, t);
if(this.grid.enableColLock !== false){
if(Ext.fly(t).hasClass('x-grid3-hd-btn')){
var hd = this.findHeaderCell(t),
index = this.getCellIndex(hd),
ms = this.hmenu.items, cm = this.cm;
ms.get('lock').setDisabled(cm.isLocked(index));
ms.get('unlock').setDisabled(!cm.isLocked(index));
}
}
},
syncHeaderHeight: function(){
this.innerHd.firstChild.firstChild.style.height = 'auto';
this.lockedInnerHd.firstChild.firstChild.style.height = 'auto';
var hd = this.innerHd.firstChild.firstChild.offsetHeight,
lhd = this.lockedInnerHd.firstChild.firstChild.offsetHeight,
height = (lhd > hd ? lhd : hd) + 'px';
this.innerHd.firstChild.firstChild.style.height = height;
this.lockedInnerHd.firstChild.firstChild.style.height = height;
},
updateLockedWidth: function(){
var lw = this.cm.getTotalLockedWidth(),
tw = this.cm.getTotalWidth() - lw,
csize = this.grid.getGridEl().getSize(true),
lp = Ext.isBorderBox ? 0 : this.lockedBorderWidth,
rp = Ext.isBorderBox ? 0 : this.rowBorderWidth,
vw = (csize.width - lw - lp - rp) + 'px',
so = this.getScrollOffset();
if(!this.grid.autoHeight){
var vh = (csize.height - this.mainHd.getHeight()) + 'px';
this.lockedScroller.dom.style.height = vh;
this.scroller.dom.style.height = vh;
}
this.lockedWrap.dom.style.width = (lw + rp) + 'px';
this.scroller.dom.style.width = vw;
this.mainWrap.dom.style.left = (lw + lp + rp) + 'px';
if(this.innerHd){
this.lockedInnerHd.firstChild.style.width = lw + 'px';
//this.lockedInnerHd.firstChild.firstChild.style.width = lw + 'px';
this.innerHd.style.width = vw;
this.innerHd.firstChild.style.width = (tw + rp + so) + 'px';
//this.innerHd.firstChild.firstChild.style.width = tw + 'px';
}
if(this.mainBody){
this.lockedBody.dom.style.width = (lw + rp) + 'px';
this.mainBody.dom.style.width = (tw + rp) + 'px';
}
}
});

Ext.ux.grid.LockingColumnModel = Ext.extend(Ext.grid.ColumnModel, {
isLocked : function(colIndex){
return this.config[colIndex].locked === true;
},
setLocked : function(colIndex, value, suppressEvent){
if(this.isLocked(colIndex) == value){
return;
}
this.config[colIndex].locked = value;
if(!suppressEvent){
this.fireEvent('columnlockchange', this, colIndex, value);
}
},
getTotalLockedWidth : function(){
var totalWidth = 0;
for(var i = 0, len = this.config.length; i < len; i++){
if(this.isLocked(i) && !this.isHidden(i)){
totalWidth += this.getColumnWidth(i);
}
}
return totalWidth;
},
getLockedCount : function(){
for(var i = 0, len = this.config.length; i < len; i++){
if(!this.isLocked(i)){
return i;
}
}
},
moveColumn : function(oldIndex, newIndex){
if(oldIndex < newIndex && this.isLocked(oldIndex) && !this.isLocked(newIndex)){
this.setLocked(oldIndex, false, true);
}else if(oldIndex > newIndex && !this.isLocked(oldIndex) && this.isLocked(newIndex)){
this.setLocked(oldIndex, true, true);
}
Ext.ux.grid.LockingColumnModel.superclass.moveColumn.apply(this, arguments);
}
});

mystix
2 Jan 2010, 8:45 PM
@fangzhouxing -- friendly tip: you might want to highlight your changes in red for readability.

Sergii
15 Jan 2010, 10:05 AM
Hi!
I use last version ColumnLock v1.7.1 for Ext 3 (changed for 2.3) but
Firebug tell me error:
Ext.grid.LockingEditorGridPanel is not a constructor
My code:



<script type="text/javascript" src="js/ColumnLock.js"></script>



Ext.grid.DynamicColumnModel = function(store){
var cols = [];
var recordType = store.recordType;
var fields = recordType.prototype.fields;

// first column set size = 50
var fieldName = fields.keys[0];
var field = recordType.getField(fieldName);
cols[0] = {id: 0, header: field.name, dataIndex: field.name, width: 50, locked:true};

// second column set size = 400
fieldName = fields.keys[1];
field = recordType.getField(fieldName);
cols[1] = {id: 1, header: field.name, dataIndex: field.name, width: 400, locked:true};

for (var i = 2; i < fields.keys.length; i++){
var fieldName = fields.keys[i];
var field = recordType.getField(fieldName);
cols[i] = {id: i, header: field.name, dataIndex: field.name, width: 80};
}
Ext.grid.DynamicColumnModel.superclass.constructor.call(this, cols);
};


var grid = new Ext.grid.LockingEditorGridPanel({
ds: ds,
cm: new Ext.grid.DynamicColumnModel(ds),
selModel: new Ext.grid.RowSelectionModel({singleSelect:true}),
enableColLock: true,
stripeRows: true
});
Wherein problem?

Thanks!

durlabh
22 Feb 2010, 7:46 AM
There are a problem with the Ext.ux.grid.CheckColumn. If this is in the first column the editor is displayed in the next column. I used the example from Ext 3.1.

For now I solved it leaving the CheckColumn in the last column.

IMO, getLockedCount method needs to be overridden in ColumnModel:



getLockedCount: function() {
var count = 0;
for (var i = 0, len = this.config.length; i < len; i++) {
if (this.isLocked(i)) {
count++;
}
}
return count;
}

dewoob
6 Apr 2010, 1:54 AM
Hi everybody,

some months ago, I reported a problem when hiding non-locked columns in a LockedGroupHeaderGrid. Cells of additional header rows didn't get hidden (see this post (http://www.extjs.com/forum/showthread.php?p=344293#post344293)). Unfortunately, nobody could help me ...

Meanwhile, I think I've found the reason and a solution for this issue:



(Un)hiding columns of additional header rows is handled by updateGroupStyles() in LockedGroupHeaderGrid.js. The updateGroupStyles() method is registered to be called in sequence after the onColumnHiddenUpdated() method. The updateGroupStyles() method needs the index of the (un)hidden column as its first parameter.




Bug: the updateGroupStyles() method is called with a wrong column index when hiding a non-locked column. E.g., when there are 5 locked columns (index 0-4), the index value of the first unlocked column should be 5. But when you hide the first unlocked column, 0 instead of 5 is passed to the updateGroupStyles() method. When hiding the 2nd unlocked column, the value is 1 instead of 6. Accordingly, it is 2 instead of 7 for the 3rd unlocked column, and so on.




I assume that the updateGroupStyles() method cannot "know" or guess whether its argument, col, is meant to be a column index of either the locked or the unlocked part of the GridView. My guess it that col would need to be an absolute index, that means, it must be relative to the GridView as a whole.




Now I've tried to trace back the call chain and have a look which param values would show up there. updateGroupStyles() is called in sequence after onColumnHiddenUpdated(), which is called by the LockingGridView's custom implementation of updateColumnHidden().




The first argument passed to updateColumnHidden() is the "absolute" index of the column that has just been (un)hidden - so this would be just what we need for the chained call of onColumnHiddenUpdated() and updateGroupStyles(). Unfortunately, the chain is not called with this correct value.




Within the LockingGridView's custom updateColumnHidden() method, the column index is modified in case the column isn't locked. The resulting index is then zero-based in relation to either the locked or the unlocked part of the GridView. This modified index is used for setting display styles within either the locked or the unlocked rows.




Just like in the GridView's original implementation of updateColumnHidden(), the onColumnHiddenUpdated() method is called afterwards, using column index as the first argument. But now, the modified column index is used - and I think that's what's wrong here.




Solution: save the original column index that was passed to updateColumnHidden() in a new variable and pass this value when calling onColumnHiddenUpdated().


That's what I did in this fix; you may replace the updateColumnHidden() method in columnLock.js with this implementation:



updateColumnHidden : function(col, hidden){
var originalCol = col; // save index of updated column
var tw = this.cm.getTotalWidth();
var lw = this.cm.getTotalLockedWidth();
var lclen = this.cm.getLockedCount();
this.innerHd.firstChild.firstChild.style.width = tw + 'px';
var display = hidden ? 'none' : '';
var hd = this.getHeaderCell(col);
hd.style.display = display;
var ns, gw;
if(col < lclen) {
ns = this.getLockedRows();
gw = lw;
this.lockedHd.dom.firstChild.firstChild.style.width = gw + 'px';
this.mainWrap.dom.style.left= this.cm.getTotalLockedWidth() + 'px';
} else {
ns = this.getRows();
gw = tw - lw;
col -= lclen;
this.innerHd.firstChild.firstChild.style.width = gw + 'px';
}
for(var i = 0, len = ns.length; i < len; i++){
ns[i].style.width = gw + 'px';
ns[i].firstChild.style.width = gw + 'px';
ns[i].firstChild.rows[0].childNodes[col].style.display = display;
}

// call onColumnHiddenUpdated using original index of updated column
// this.onColumnHiddenUpdated(col, hidden, tw);
this.onColumnHiddenUpdated(originalCol, hidden, tw);

delete this.lastViewWidth;
this.layout();
},

Kranthi1981
9 Apr 2010, 11:23 PM
Hi Mankz,

I am developing an extjs application and I have similar kind of requirements. Could u please send me the plug-ins code and an example.

Thanking you in anticipation.

arifali
19 Jan 2011, 2:56 PM
We are using Ext 2.2. After I got the update5.zip file and followed the examples in the thread and in 'columnLockExample.js', I am getting only the locked columns shown in my grid and no unlocked columns. I even appended to the 'columnLockExample.js' the code from Condor (Ext.override(Ext.grid.LockingGridView, { ....) from some page 15/16 of thread too, but no luck.
To give some idea, I replaced by EditorGridPanel with the LockingEditiorGridPanel and am using the Ext.grid.LockingColumnModel. Another difference is that my un-locked columns are composed of editor textfields and comboxes. Could this be the reason that my unlocked columns are actually textfields and comboxes as grid columns? Here is a snippet of my code:


cm = new Ext.grid.LockingColumnModel([
{header: "LSSI 1st",tooltip:"LSSI First character",dataIndex: "lssiFirstChar",hidden:false, width:50, sortable: true, locked: true},
{header: "LSSI 2nd",tooltip:"LSSI Second character",dataIndex: "lssiSecondChar",hidden:false, width:50, sortable: true, locked: true},
{header: "LSSI",tooltip:"LSSI",dataIndex: "lssi",hidden:false, width:40, sortable: true, locked: true},
{header: "LSSI Suffix",tooltip:"LSSI Suffix",dataIndex: "lssiSuffix",hidden:false, width:65, sortable: true,locked: true},
{header: "SL$ Target&nbsp;<img src='images/edit.gif'/>", tooltip:"Safety Budget $ Target", width:78,dataIndex: "safetyLevelBudget", align:"right", editor: new Ext.form.TextField({allowBlank: false}),hidden:false, sortable: true},
{header: "FR Target % &nbsp;<img src='images/edit.gif'/>", tooltip: "FR Target",width:85,dataIndex: "fillRateTarget", align:"right", editor: new Ext.form.TextField({allowBlank: false, msgDisplay:'qtip', regex: frtargetre, regexText:'FR Target value must be < 1'}),hidden:false,renderer:fillRateTargetPercent, sortable: true},
{header: "Min. Risk<img src='images/edit.gif'/>", tooltip: "Minimum Risk", width:70,dataIndex: "minRisk", align:"right", editor: new Ext.form.TextField({allowBlank: false}),hidden:false, sortable: true},
{header: "Max. Risk<img src='images/edit.gif'/>", tooltip: "Maximum Risk", width:70,dataIndex: "maxRisk", align:"right", editor: new Ext.form.TextField({allowBlank: false}),hidden:false, sortable: true},
{header: "Avg. Req. Size&nbsp;<img src='images/edit.gif'/>",tooltip:"Avg. Req. Size ",dataIndex: "averageRequisitionSize", align:"right", editor: new Ext.form.ComboBox({triggerAction: 'all',transform:'arsc',lazyRender:true,listClass: 'x-combo-list-small', forceSelection:true}),hidden:false, sortable: true},
{header: "Crit. Spread&nbsp;<img src='images/edit.gif'/>",tooltip:"Crit. Spread",dataIndex: "critSpread", align:"right", editor: new Ext.form.TextField({allowBlank: false,regex: csharsre, msgTarget:'title', invalidText:'Valid values >= 0'}),hidden:false, sortable: true}
]);

My GridPanel is:
var grid = new Ext.grid.LockingEditorGridPanel({
el:gridCt,
id:'LSSIGridId',
height:400,
width:800,
clicksToEdit: 1,
store: store,
cm: cm,
loadMask: true,
viewConfig: {emptyText: '<div align="center"><font size="2"><b><%=noDataFound %></b></font></div>',
deferEmptyText: false},
tbar: toolbar,
stripeRows: true
//view: new Ext.ux.grid.LockingGridView()
});

Please find attached screenshot showing the behavior (not-showing unlocked columns)

Condor
20 Jan 2011, 12:32 AM
Did you include the css that comes with the extension?

tomlobato
20 Jan 2011, 2:08 PM
Hello! Congratulations, it is a excellent port!
I`m using this by some time, but now I noted that running on chrome there is a little problem.
The locked columns gets a margin on top. Look the attached image.

Below the relevant code..



columns[0] = {header: '<b>Nome</b>', width: 100, editable: false, menuDisabled: true,
sortable: false, resizable: false, dataIndex: 'name',
renderer: function(value){return '<b>'+value+'</b>'}, locked: true}
columns[1] = {menuDisabled: true, width: 35, editable: false, renderer: removeUser,
sortable: false, resizable: false, dataIndex: 'id', align: 'center', locked: true}
columns[2] = {menuDisabled: true, width: 35, editable: false, renderer: altPass,
sortable: false, resizable: false, dataIndex: 'id', align: 'center', locked: true}

for (var i=0; i<col_list.length; i++) {
var header = '<font size=1>'+col_list[i][0]+'</font>'
var dataIndex = col_list[i][1]
columns[columns.length] = {
header: header,
width: colWidth,
height: 30,
editable: true,
renderer: renderPer,
menuDisabled: true,
sortable: false,
resizable: false,
dataIndex: dataIndex
}
}

var userGrid = new Ext.grid.LockingGridPanel({
store: userStore,
columns: columns,
stripeRows: false,
region: 'center',
buttonAlign: 'center',
cls: 'vline-on',
viewConfig: {
getRowClass: function(record, idx){
if (idx == 0)
return 'fix-top-border'
}
},
border: false,
enableHDMenu: false,
enableColumnHide: false,
enableColumnMove: false
});
userGrid.getSelectionModel().lock()

Condor
21 Jan 2011, 12:22 AM
This is a known issue that has been fixed in the Ext 3.x version.

But this fix was never backported to the Ext 2.x and 3.0 versions (I'm no longer using these Ext versions, so it's not very high on my todo list).

tomlobato
21 Jan 2011, 4:23 AM
Hi Condor, I understand.
A workaround for me would be to have specific columns (the locked) with header of height=0.
Is it possible?


This is a known issue that has been fixed in the Ext 3.x version.

But this fix was never backported to the Ext 2.x and 3.0 versions (I'm no longer using these Ext versions, so it's not very high on my todo list).

Condor
21 Jan 2011, 4:49 AM
You're better off trying to backport the fix.

The syncHeaderHeight method updates the height of <table> element, but it needs to update the <tr> element.

Patrick86
12 Oct 2011, 6:04 AM
Hi guys,
I have this problem in the locked and unlocked columns heigth
the rows in the Locked column remain the same height as default, which makes a bad effect - rows in the Locked column do not match the rows in the other (not locked) columns. the heigth is not equal (see joined picture)
. I applicate all the propositions given in this thread but no effect.still the same problem
I wait for u answer
ty28635

chpsrinu
12 Dec 2011, 1:52 AM
Hir,

I tried locking first two columns in my application using LockingGridPanel but no luck. Can i include this .css and .js files with ext 2.0.2 version? i did not see any error but locked columns come in one row and unlocked columns are coming in other row. i am not able to show the pic. Please throw some pointers. Appreciated your help.


Regards,
Srini