From 046c803974c5dc3916066d0301007919fc10c484 Mon Sep 17 00:00:00 2001 From: Renaud Le Gac <legac@cppm.in2p3.fr> Date: Tue, 23 Sep 2014 21:19:17 +0200 Subject: [PATCH] Better coding of the CSV / LaTeX export. It also covers the case with grouping summary. --- static/plugin_dbui/src/grid/plugin/Export.js | 298 +++++++++---------- 1 file changed, 144 insertions(+), 154 deletions(-) diff --git a/static/plugin_dbui/src/grid/plugin/Export.js b/static/plugin_dbui/src/grid/plugin/Export.js index 965bb855..60aaae81 100644 --- a/static/plugin_dbui/src/grid/plugin/Export.js +++ b/static/plugin_dbui/src/grid/plugin/Export.js @@ -11,6 +11,7 @@ Ext.define('App.grid.plugin.Export', { extend: 'Ext.AbstractPlugin', alias: 'plugin.pGridExport', + requires: 'Ext.form.action.StandardSubmit', /** * @cfg {String} @@ -111,57 +112,12 @@ Ext.define('App.grid.plugin.Export', { return value; }, - /** - * Get the content of the cells as rendered by the grid. - * The method handle the grouping cell as well. - * - * @param {Ext.dom.Element} - * The DOM element corresponding to the x-grid-row. - * - * @return {Object} - * @return {String} return.groupValue - * @return {String[]} return.values - * - */ - getCells: function (row) { - - "use strict"; - - var cell, - groupValue, - values = []; - - // get the first cell of the HTML row - cell = row.down("td"); - - // the first cell can be a container when grouping is used - // - // a) extract the grouping value in the first children - // b) extract the cells of the first row in the second children - // keep in mind that they can be null is the group is closed. - // - if (cell.dom.className === "x-group-hd-container") { - groupValue = cell.dom.childNodes[0].textContent; - cell = cell.down("td"); - } - - // scan the row - if (cell) { - do { - values.push(cell.dom.textContent); - cell = cell.next(); - } while (cell); - } - - return {groupValue: groupValue, values: values}; - }, - /** * Get the label and the alignment of the visible columns. * * @return {Object} * @return {String[]} return.alignments - * @return {String[]} return.labels + * @return {String[]} return.labels empty for hidden headers * */ getColumnHeader: function () { @@ -190,144 +146,94 @@ Ext.define('App.grid.plugin.Export', { } } + if (container[0].hiddenHeaders) { + labels = []; + } + return {alignments: alignments, labels: labels}; }, /** - * Build the file content under CSV format. + * Show the context menu when right clicking in an empty grid. * - * @return {String[]} One string per line. + * @param {App.grid.Panel} grid + * @param {Ext.EventObject} event + * @param {Object} eOpts * */ - getCSV: function () { + onContainerContextMenu: function (grid, event, eOpts) { "use strict"; - var cells, - data = [], - header = this.getColumnHeader(), - i, - row; - - // the grid header - if (header.labels.length) { - for (i = 0; i < header.labels.length; i += 1) { - header.labels[i] = this.delimit(header.labels[i]); - } - data.push(header.labels.join(this.separator)); - } - - // scan the row of the HTML table - row = this.getCmp().getView().getEl().down("tr"); - do { - // get the cells of the HTML row - cells = this.getCells(row); - - // group cell - if (cells.groupValue) { - data.push(this.delimit(cells.groupValue)); - } - - // standard cells - if (cells.values.length) { - for (i = 0; i < cells.values.length; i += 1) { - cells.values[i] = this.delimit(cells.values[i]); - } - data.push(cells.values.join(this.separator)); - } - - // move to the next HTML row - row = row.next(); - - } while (row); - - return data; + event.stopEvent(); + this.menu.showAt(event.getXY()); }, /** - * Build the file content under CSV format. - * - * @return {String[]} One string per line. + * Export the content of the grid as a CSV file. * */ - getLaTeX: function () { + onCsvExport: function () { "use strict"; - var cells, - cmd, - data = [], + var div, + grid = this.getCmp(), header = this.getColumnHeader(), - nColumns = header.alignments.length, i, - row; + li, + lines = [], + total; - //begin document - data = data.concat(this.preamble); - data.push('\\begin{document}'); - - - //begin table - for (i = 0; i < nColumns; i += 1) { - header.alignments[i] = header.alignments[i][0]; + // convert the header + if (header.labels.length) { + for (i = 0; i < header.labels.length; i += 1) { + header.labels[i] = this.delimit(header.labels[i]); + } + lines.push(header.labels.join(this.separator)); } - cmd = '\\begin{tabular}{' + header.alignments.join('') + '}'; - data.push(cmd); + // + // convert the HTML row associated to the Ext.grid.View + // The structure of the HTML table is complex because it contains + // several types of row depending on the grouping features. + // + grid.getView().getEl().select("table tr").each(function(trEl, cEl, index){ - // table content - row = this.getCmp().getView().getEl().down("tr"); - do { - // get the cells of the HTML row - cells = this.getCells(row); - - // group cell - if (cells.groupValue) { - cmd = '\\multicolumn{' + nColumns + '}{l}{' + cells.groupValue + '} \\\\'; - data.push(cmd); - } + if(trEl.hasCls("x-grid-wrap-row")) { - // standard cells - data.push(cells.values.join(' & ') + ' \\\\'); + div = trEl.down(".x-grid-group-title"); + if (div) { + lines.push(this.delimit(div.dom.textContent)); + } - // move to the next HTML row - row = row.next(); + } else if (trEl.hasCls("x-grid-data-row") || trEl.hasCls("x-grid-row-summary")) { - } while (row); + li = []; - //end table and document - data.push('\\end{tabular}'); - data.push('\\end{document}'); + trEl.select("td").each(function(tdEl){ + li.push(this.delimit(tdEl.dom.textContent)); + }, this); - return data; - }, + li = li.join(this.separator); - /** - * Show the context menu when right clicking in an empty grid. - * - * @param {App.grid.Panel} grid - * @param {Ext.EventObject} event - * @param {Object} eOpts - * - */ - onContainerContextMenu: function (grid, event, eOpts) { - - "use strict"; - - event.stopEvent(); - this.menu.showAt(event.getXY()); - }, + // unfortunately the grand total appear as the first row (Ext JS 4.2) + if (index === 0 && trEl.hasCls("x-grid-row-summary")) { + total = li; + } else { + lines.push(li); + } + } - /** - * Export the content of the grid as a CSV file. - * - */ - onCsvExport: function () { + }, this); - "use strict"; + // push the grand total at the end + if (total) { + lines.push(total); + } - var data = this.getCSV(); - this.save("text/csv", "utf-8", data); + // trigger the transfer using URI technique + this.save("text/csv", "utf-8", lines); }, /** @@ -372,8 +278,8 @@ Ext.define('App.grid.plugin.Export', { "use strict"; - var data = this.getLaTeX(); - this.save("application/x-latex", "utf-8", data); + var lines = this.toLaTeX(); + this.save("application/x-latex", "utf-8", lines); }, /** @@ -389,7 +295,7 @@ Ext.define('App.grid.plugin.Export', { var data, form; - data = this.getLaTeX().join(this.newLine); + data = this.toLaTeX().join(this.newLine); // send the latex data to the server. // the method used standardSubmit using a form. @@ -444,5 +350,89 @@ Ext.define('App.grid.plugin.Export', { window.location.href = uri; }, + /** + * Convert the Ext.grid.View content into a string. + * the information are encoded using LaTeX standard. + * + * @return {String[]} One string per line. + * + */ + toLaTeX: function () { + + "use strict"; + + var cmd, + div, + grid = this.getCmp(), + header = this.getColumnHeader(), + li, + lines = [], + nColumns = header.alignments.length, + total; + + //begin document + lines = lines.concat(this.preamble); + lines.push('\\begin{document}'); + + + //begin table + header.alignments.forEach(function(value, index, array){ + array[index] = value[0]; + }); + + cmd = '\\begin{tabular}{' + header.alignments.join('') + '}'; + lines.push(cmd); + + // table header + if (header.labels.length) { + lines.push(header.labels.join(' & ') + ' \\\\'); + } + + // table content + // + // convert the HTML row associated to the Ext.grid.View. + // The structure of the HTML table is complex because it contains + // several type of row depending on the grouping features. + // + grid.getView().getEl().select("table tr").each(function(trEl, cEl, index){ + + if(trEl.hasCls("x-grid-wrap-row")) { + + div = trEl.down(".x-grid-group-title"); + if (div) { + cmd = '\\multicolumn{' + nColumns + '}{l}{' + div.dom.textContent + '} \\\\'; + lines.push(cmd); + } + + } else if (trEl.hasCls("x-grid-data-row") || trEl.hasCls("x-grid-row-summary")) { + + li = []; + + trEl.select("td").each(function(tdEl){ + li.push(tdEl.dom.textContent); + }, this); + + li = li.join(' & ') + ' \\\\'; + + // unfortunately the grand total appear as the first row (Ext JS 4.2) + if (index === 0 && trEl.hasCls("x-grid-row-summary")) { + total = li; + } else { + lines.push(li); + } + } + + }, this); + + // push the grand total at the end + if (total) { + lines.push(total); + } + + //end table and document + lines.push('\\end{tabular}'); + lines.push('\\end{document}'); + return lines; + } }); \ No newline at end of file -- GitLab