/** * This plugin allows grid data export using various exporters. Each exporter should extend * the {@link Ext.exporter.Base} class. * * Two new methods are created on the grid panel by this plugin: * * - saveDocumentAs(config): saves the document * - getDocumentData(config): returns the document content * * The grid data is exported for all grid columns that have the flag * {@link Ext.grid.column.Column#ignoreExport ignoreExport} as false. * * A grid column may have an {@link Ext.grid.column.Column#exportStyle exportStyle} defined which is used during * data export. If no `exportStyle` is defined for a column then column formatter is used if * defined. * * Example usage: * * { * xtype: 'grid', * plugins: [{ * ptype: 'gridexporter' * }], * columns: [{ * dataIndex: 'value', * text: 'Total', * exportStyle: { * format: 'Currency', * alignment: { * horizontal: 'Right' * } * } * }] * } * * grid.saveDocumentAs({ * type: 'xlsx', * title: 'My export', * fileName: 'myExport.xlsx' * }); * */Ext.define('Ext.grid.plugin.Exporter', { alias: [ 'plugin.gridexporter' ], extend: 'Ext.exporter.Plugin', /** * @event beforedocumentsave * Fires on the grid panel before a document is exported and saved. * @param {Ext.grid.Panel} grid Reference to the grid panel */ /** * @event documentsave * Fires on the grid panel whenever a document is exported and saved. * @param {Ext.grid.Panel} grid Reference to the grid panel */ /** * @event dataready * Fires on the grid panel when the {Ext.exporter.data.Table data object} is ready. * You could adjust styles or data before the document is generated and saved. * @param {Ext.grid.Panel} grid Reference to the grid panel */ /** * `"both"` (the default) - The plugin is added to both grids * `"top"` - The plugin is added to the containing Panel * `"locked"` - The plugin is added to the locked (left) grid * `"normal"` - The plugin is added to the normal (right) grid * * @private */ lockableScope: 'top', /** * Save the export file. This method is added to the grid panel as "saveDocumentAs". * * Pass in exporter specific configs to the config parameter. * * @method saveDocumentAs * @param {Ext.exporter.Base} config Config object used to initialize the proper exporter * @param {String} config.type Type of the exporter as defined in the exporter alias. Default is `excel`. * @param {String} [config.title] Title added to the export document * @param {String} [config.author] Who exported the document? * @param {String} [config.fileName] Name of the exported file, including the extension * @param {String} [config.charset] Exported file's charset * */ /** * Fetch the export data. This method is added to the grid panel as "getDocumentData". * * Pass in exporter specific configs to the config parameter. * * @method getDocumentData * @param {Ext.exporter.Base} config Config object used to initialize the proper exporter * @param {String} [config.type] Type of the exporter as defined in the exporter alias. Default is `excel`. * @param {String} [config.title] Title added to the export document * @param {String} [config.author] Who exported the document? * @return {String} * */ /** * @inheritdoc */ prepareData: function(config){ var me = this, grid = me.cmp, table = new Ext.exporter.data.Table(), columns = [], store = grid.getStore(), result, group; if(grid.lockedGrid){ Ext.Array.insert(columns, columns.length, grid.lockedGrid.headerCt.items.items); Ext.Array.insert(columns, columns.length, grid.normalGrid.headerCt.items.items); }else{ Ext.Array.insert(columns, columns.length, grid.headerCt.items.items); } result = me.getColumnHeaders(columns, config); table.setColumns(result.headers); if (!store || (store && store.isDestroyed)) { return table; } // <debug> if (store && store.isBufferedStore) { Ext.raise('BufferedStore can\'t be exported because it doesn\'t have all data available'); } // </debug> group = { text: '' }; me.extractGroups(group, result.dataIndexes); table.addGroup(group); return table; }, /** * Fetch all columns that will be exported. Columns that are hidden or have ignoreExport = true are ignored. * * Returns an object that has 2 keys: * - headers * - dataIndexes * * @param {Array} columns * @param {Object} config * @return {Object} * * @private */ getColumnHeaders: function(columns, config){ var cols = [], dataIndexes = [], i, obj, col, ret; for(i = 0; i < columns.length; i++){ col = columns[i]; // each column has a config 'ignoreExport' that can tell us to ignore the column on export if(!col.hidden && !col.ignoreExport) { obj = { text: col.text, width: col.getWidth(), style: this.getExportStyle(col.exportStyle, config) }; if (col.isGroupHeader) { ret = this.getColumnHeaders(col.items.items, config); obj.columns = ret.headers; if(obj.columns.length === 0){ // all children columns are ignored for export so there's no need to export this grouped header obj = null; }else{ Ext.Array.insert(dataIndexes, dataIndexes.length, ret.dataIndexes); } }else{ dataIndexes.push(col); } if(obj) { cols.push(obj); } } } return { headers: cols, dataIndexes: dataIndexes }; }, /** * Generate the data that the exporter can consume * * @param {Ext.exporter.data.Group} group * @param {Array} columns * @return {Ext.exporter.data.Group} * * @private */ extractGroups: function(group, columns){ var store = this.cmp.getStore(), len = store.getCount(), lenCols = columns.length, i, j, record, row, col, useRenderer, v; // we could also export grouped stores group.rows = []; for(i = 0; i < len; i++){ record = store.getAt(i); row = { cells: [] }; for(j = 0; j < lenCols; j++){ col = columns[j]; // if there is no `exportStyle` format for the column then we use the existing formatter useRenderer = !Ext.isEmpty(col.initialConfig.formatter) && Ext.isEmpty(col.formatter) && !col.exportStyle && !(col.exportStyle && col.exportStyle.format); v = record.get(col.dataIndex); row.cells.push({ value: useRenderer ? col.renderer(v) : v }); } group.rows.push(row); } return group; } });