Ext.grid.RowExpander.prototype.initOrig = Ext.grid.RowExpander.prototype.init; /** * extended version of Ext.ux.grid.RowExpander. This version looks for changes in the grid and saves the html of the expanded rows, it then restores the html back into the grid when the view refreshes. * Note: For this plug in to work properly you need to encapsulate the elements in each expanded row into 1 parent element. Multiple elements at the top of the expanded rows dom element will result in just the first one being captured and preserved. */ Ext.override(Ext.grid.RowExpander, { /** * @cfg {String|Null} storeHtmlBy * This is the attribute of the store record that is used to save and restore the html in the grid. If left null then the id of the store record will be used, if you are going to be using remote sorting you may need to change this value. The property of the record you use will need to be a unique identifier. Defaults to null */ storeHtmlBy: null, /** * @private internal config {Object} storedHtml * Used to store the html that will be restored to the grid. * */ storedHtml: {}, //Maintains the associations of Record Keys to the Record's view index before a refresh/update action occurs. recordKeyAtRow: {}, //Maintains the expanded & rendered statuses for each Record. recordStatus: {}, //@private init: function(grid) { this.initOrig(grid); if (this.preserveRowsOnRefresh) { this.grid.on('viewready', this.markRows, this); this.grid.on('rowsinserted', this.markRows, this); var view = this.grid.view; if (typeof Ext.net == undefined && typeof Coolite == undefined && typeof Ext.net.CommandColumn == undefined) { //Coolite/Ext.net's CommandColumn also adds this event. So, dont add it again, if the CommandColumn is present. view.addEvents("beforerowupdate"); view.refreshRow = view.refreshRow.createInterceptor(function(record) { view.fireEvent("beforerowupdate", view, view.grid.store.indexOf(record), record); }); } view.on('beforerefresh', this.onBeforeRefresh, this); view.on('refresh', this.onRefresh, this); view.on('beforerowupdate', this.saveRowHtml, this); view.on('rowupdated', this.restoreRowHtml, this); this.on('expand', this.rowExpanded); this.on('collapse', this.rowCollapsed); } }, getRecordKey: function(record) { if (!Ext.isEmpty(this.storeHtmlBy)) { return (record.get(this.storeHtmlBy)); } else { return (record.id); } }, rowExpanded: function(expander, record, body, rowIndex) { var key = this.getRecordKey(record); var status = { rendered: true, expanded: true }; this.recordStatus[key] = status; }, rowCollapsed: function(expander, record, body, rowIndex) { var key = this.getRecordKey(record); var status = { rendered: true, expanded: false }; this.recordStatus[key] = status; }, //@private onBeforeRefresh: function(view) { var store = this.grid.getStore(), n, record; this.storedHtml = {}; for (n = 0; n < store.data.items.length; n++) { record = store.getAt(n); this.saveRowHtml(view, n, record); } }, saveRowHtml: function(view, index, record) { var key = this.getRecordKey(record); var rowIndex = null, found = false; //Find the view's rowIndex for this record before the refresh action happened. //While saving the Row Html for a Record, we have to find the previous position of the record in the view before //the refresh action happened. for (rowIndex in this.recordKeyAtRow) { if (this.recordKeyAtRow[rowIndex] == key) { found = true; break; } } if (found) { var row = view.getRow(rowIndex); var body = Ext.DomQuery.selectNode('div.x-grid3-row-body', row); this.storedHtml[key] = body.innerHTML; } }, //@private onRefresh: function(view) { var store = this.grid.getStore(), n, row, record; for (n = 0; n < store.data.items.length; n++) { row = view.getRow(n); if (row) { record = store.getAt(n); this.restoreRowHtml(view, n, record); } } }, restoreRowHtml: function(view, index, record) { var key = this.getRecordKey(record); //When restoring the Row Html for a Record, the restore has to happen at the current position of the Record after //the refresh action happened. var storedBody = this.storedHtml[key]; if (!Ext.isEmpty(storedBody)) { var row = view.getRow(index); var body = Ext.DomQuery.selectNode('div.x-grid3-row-body', row); while (body.hasChildNodes()) { body.removeChild(body.lastChild); } var status = this.recordStatus[key]; if (!status) { //the row has not been touched. body.innerHTML = this.tpl.html; this.collapseRow(row); } else { body.innerHTML = storedBody; if (status.expanded) this.expandRow(row); else this.collapseRow(row); } } this.markRow(view, index, record); }, //@private markRow: function(view, index, record) { var key; var row = view.getRow(index); if (row) { key = this.getRecordKey(record); this.recordKeyAtRow[index] = key; } }, markRows: function() { var view = this.grid.getView(), store = this.grid.getStore(), record, n; this.recordKeyAtRow = {}; for (n = 0; n < store.data.items.length; n++) { record = store.getAt(n); this.markRow(view, n, record); } } });