/* This file is part of Ext JS 3.4 Copyright (c) 2011-2013 Sencha Inc Contact: http://www.sencha.com/contact GNU General Public License Usage This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact. Build date: 2013-04-03 15:07:25 */ Ext.ns('Ext.ux.grid'); /** * @class Ext.ux.grid.BufferView * @extends Ext.grid.GridView * A custom GridView which renders rows on an as-needed basis. */ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, { /** * @cfg {Number} rowHeight * The height of a row in the grid. */ rowHeight: 19, /** * @cfg {Number} borderHeight * The combined height of border-top and border-bottom of a row. */ borderHeight: 2, /** * @cfg {Boolean/Number} scrollDelay * The number of milliseconds before rendering rows out of the visible * viewing area. Defaults to 100. Rows will render immediately with a config * of false. */ scrollDelay: 100, /** * @cfg {Number} cacheSize * The number of rows to look forward and backwards from the currently viewable * area. The cache applies only to rows that have been rendered already. */ cacheSize: 20, /** * @cfg {Number} cleanDelay * The number of milliseconds to buffer cleaning of extra rows not in the * cache. */ cleanDelay: 500, initTemplates : function(){ Ext.ux.grid.BufferView.superclass.initTemplates.call(this); var ts = this.templates; // empty div to act as a place holder for a row ts.rowHolder = new Ext.Template( '
' ); ts.rowHolder.disableFormats = true; ts.rowHolder.compile(); ts.rowBody = new Ext.Template( '', '{cells}', (this.enableRowBody ? '' : ''), '
{body}
' ); ts.rowBody.disableFormats = true; ts.rowBody.compile(); }, getStyleRowHeight : function(){ return Ext.isBorderBox ? (this.rowHeight + this.borderHeight) : this.rowHeight; }, getCalculatedRowHeight : function(){ return this.rowHeight + this.borderHeight; }, getVisibleRowCount : function(){ var rh = this.getCalculatedRowHeight(), visibleHeight = this.scroller.dom.clientHeight; return (visibleHeight < 1) ? 0 : Math.ceil(visibleHeight / rh); }, getVisibleRows: function(){ var count = this.getVisibleRowCount(), sc = this.scroller.dom.scrollTop, start = (sc === 0 ? 0 : Math.floor(sc/this.getCalculatedRowHeight())-1); return { first: Math.max(start, 0), last: Math.min(start + count + 2, this.ds.getCount()-1) }; }, doRender : function(cs, rs, ds, startRow, colCount, stripe, onlyBody){ var ts = this.templates, ct = ts.cell, rt = ts.row, rb = ts.rowBody, last = colCount-1, rh = this.getStyleRowHeight(), vr = this.getVisibleRows(), tstyle = 'width:'+this.getTotalWidth()+';height:'+rh+'px;', // buffers buf = [], cb, c, p = {}, rp = {tstyle: tstyle}, r; for (var j = 0, len = rs.length; j < len; j++) { r = rs[j]; cb = []; var rowIndex = (j+startRow), visible = rowIndex >= vr.first && rowIndex <= vr.last; if (visible) { 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'; } 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(""); buf[buf.length] = !visible ? ts.rowHolder.apply(rp) : (onlyBody ? rb.apply(rp) : rt.apply(rp)); } return buf.join(""); }, isRowRendered: function(index){ var row = this.getRow(index); return row && row.childNodes.length > 0; }, syncScroll: function(){ Ext.ux.grid.BufferView.superclass.syncScroll.apply(this, arguments); this.update(); }, // a (optionally) buffered method to update contents of gridview update: function(){ if (this.scrollDelay) { if (!this.renderTask) { this.renderTask = new Ext.util.DelayedTask(this.doUpdate, this); } this.renderTask.delay(this.scrollDelay); }else{ this.doUpdate(); } }, onRemove : function(ds, record, index, isUpdate){ Ext.ux.grid.BufferView.superclass.onRemove.apply(this, arguments); if(isUpdate !== true){ this.update(); } }, doUpdate: function(){ if (this.getVisibleRowCount() > 0) { var g = this.grid, cm = g.colModel, ds = g.store, cs = this.getColumnData(), vr = this.getVisibleRows(), row; for (var i = vr.first; i <= vr.last; i++) { // if row is NOT rendered and is visible, render it if(!this.isRowRendered(i) && (row = this.getRow(i))){ var html = this.doRender(cs, [ds.getAt(i)], ds, i, cm.getColumnCount(), g.stripeRows, true); row.innerHTML = html; } } this.clean(); } }, // a buffered method to clean rows clean : function(){ if(!this.cleanTask){ this.cleanTask = new Ext.util.DelayedTask(this.doClean, this); } this.cleanTask.delay(this.cleanDelay); }, doClean: function(){ if (this.getVisibleRowCount() > 0) { var vr = this.getVisibleRows(); vr.first -= this.cacheSize; vr.last += this.cacheSize; var i = 0, rows = this.getRows(); // if first is less than 0, all rows have been rendered // so lets clean the end... if(vr.first <= 0){ i = vr.last + 1; } for(var len = this.ds.getCount(); i < len; i++){ // if current row is outside of first and last and // has content, update the innerHTML to nothing if ((i < vr.first || i > vr.last) && rows[i].innerHTML) { rows[i].innerHTML = ''; } } } }, removeTask: function(name){ var task = this[name]; if(task && task.cancel){ task.cancel(); this[name] = null; } }, destroy : function(){ this.removeTask('cleanTask'); this.removeTask('renderTask'); Ext.ux.grid.BufferView.superclass.destroy.call(this); }, layout: function(){ Ext.ux.grid.BufferView.superclass.layout.call(this); this.update(); } });