|
|
@@ -0,0 +1,333 @@
|
|
|
+function colIdxToLetter(n) {
|
|
|
+ let s = "";
|
|
|
+ n = n + 1;
|
|
|
+ while (n > 0) {
|
|
|
+ const m = (n - 1) % 26;
|
|
|
+ s = String.fromCharCode(65 + m) + s;
|
|
|
+ n = Math.floor((n - m) / 26);
|
|
|
+ }
|
|
|
+ return s;
|
|
|
+}
|
|
|
+
|
|
|
+function escapeXmlText(txt) {
|
|
|
+ return String(txt ?? "")
|
|
|
+ .replace(/&/g, "&")
|
|
|
+ .replace(/</g, "<")
|
|
|
+ .replace(/>/g, ">");
|
|
|
+}
|
|
|
+
|
|
|
+function readCellText($cell, sheet, xlsx) {
|
|
|
+ const t = $cell.attr("t");
|
|
|
+ if (t === "inlineStr") {
|
|
|
+ const tNode = $cell.find("is t");
|
|
|
+ return tNode.length ? tNode.text() : "";
|
|
|
+ }
|
|
|
+ if (t === "s") {
|
|
|
+ const v = $cell.find("v").text();
|
|
|
+ const idx = parseInt(v, 10);
|
|
|
+ const sst = xlsx.xl["sharedStrings.xml"];
|
|
|
+ if (!sst) return "";
|
|
|
+ const si = $("sst si", sst).eq(idx);
|
|
|
+ if (!si.length) return "";
|
|
|
+
|
|
|
+ let out = "";
|
|
|
+ si.find("t").each(function () {
|
|
|
+ out += $(this).text();
|
|
|
+ });
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+
|
|
|
+ const vNode = $cell.find("v");
|
|
|
+ return vNode.length ? vNode.text() : "";
|
|
|
+}
|
|
|
+
|
|
|
+function newexportaction(e, dt, button, config, cb) {
|
|
|
+ const self = this;
|
|
|
+ const settings = dt.settings()[0];
|
|
|
+ const isServerSide = settings.oFeatures && settings.oFeatures.bServerSide;
|
|
|
+ const hasAjax = !!settings.ajax;
|
|
|
+
|
|
|
+ const customizeHeaderExcel = function (xlsx) {
|
|
|
+ const sheet = xlsx.xl.worksheets["sheet1.xml"];
|
|
|
+ const styles = xlsx.xl["styles.xml"];
|
|
|
+
|
|
|
+ // --- crea background azzurro ---
|
|
|
+ const fills = $("fills", styles);
|
|
|
+ fills.append(
|
|
|
+ '<fill><patternFill patternType="solid">' +
|
|
|
+ '<fgColor rgb="FFDDEBF7"/><bgColor indexed="64"/>' +
|
|
|
+ "</patternFill></fill>"
|
|
|
+ );
|
|
|
+ const fillId = $("fill", styles).length - 1;
|
|
|
+ fills.attr("count", $("fill", styles).length); // aggiorna count
|
|
|
+
|
|
|
+ // --- crea FONT bold nero ---
|
|
|
+ const fonts = $("fonts", styles);
|
|
|
+ fonts.append(
|
|
|
+ '<font><b/><sz val="11"/><color rgb="FF000000"/><name val="Calibri"/></font>'
|
|
|
+ );
|
|
|
+ const fontId = $("font", styles).length - 1;
|
|
|
+ fonts.attr("count", $("font", styles).length); // aggiorna count
|
|
|
+
|
|
|
+ // --- crea XF senza bordi, bold + fill azzurro ---
|
|
|
+ const cellXfs = $("cellXfs", styles);
|
|
|
+ cellXfs.append(
|
|
|
+ `<xf xfId="0" applyFont="1" applyFill="1" borderId="0" fontId="${fontId}" fillId="${fillId}">
|
|
|
+ <alignment vertical="center"/>
|
|
|
+ </xf>`
|
|
|
+ );
|
|
|
+ const xfId = $("cellXfs xf", styles).length - 1;
|
|
|
+ cellXfs.attr("count", $("cellXfs xf", styles).length); // aggiorna count
|
|
|
+
|
|
|
+ // --- applica lo stile alla PRIMA riga (header) ---
|
|
|
+ $("row:first c", sheet).attr("s", xfId);
|
|
|
+ };
|
|
|
+
|
|
|
+ const alignLeftCells = function (xlsx, config) {
|
|
|
+ let leftCols = Array.isArray(config.exportLeftCols)
|
|
|
+ ? [...config.exportLeftCols]
|
|
|
+ : [];
|
|
|
+ if (leftCols.length === 0 && dt && dt.columns) {
|
|
|
+ const headerIdxs = [];
|
|
|
+ $(dt.columns().header()).each(function (i, th) {
|
|
|
+ if ($(th).hasClass("export-left")) headerIdxs.push(i);
|
|
|
+ });
|
|
|
+ leftCols = headerIdxs;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (leftCols.length) {
|
|
|
+ const sheet = xlsx.xl.worksheets["sheet1.xml"];
|
|
|
+ const styles = xlsx.xl["styles.xml"];
|
|
|
+
|
|
|
+ const cellXfs = $("cellXfs", styles);
|
|
|
+ cellXfs.append(
|
|
|
+ `<xf xfId="0" applyAlignment="1">
|
|
|
+ <alignment horizontal="left" vertical="center"/>
|
|
|
+ </xf>`
|
|
|
+ );
|
|
|
+ const leftXfId = $("cellXfs xf", styles).length - 1;
|
|
|
+ cellXfs.attr("count", $("cellXfs xf", styles).length);
|
|
|
+
|
|
|
+ leftCols.forEach(function (colIdx) {
|
|
|
+ const colLetter = colIdxToLetter(colIdx);
|
|
|
+
|
|
|
+ $('row:not(:first) c[r^="' + colLetter + '"]', sheet).each(
|
|
|
+ function () {
|
|
|
+ const cell = $(this);
|
|
|
+ const sAttr = cell.attr("s");
|
|
|
+ if (sAttr === undefined) {
|
|
|
+ cell.attr("s", leftXfId);
|
|
|
+ } else {
|
|
|
+ const xfs = $("cellXfs xf", styles);
|
|
|
+ const baseXf = xfs.eq(parseInt(sAttr, 10)).clone();
|
|
|
+ if (baseXf.find("alignment").length === 0) {
|
|
|
+ baseXf.append(
|
|
|
+ '<alignment horizontal="left" vertical="center"/>'
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ baseXf
|
|
|
+ .find("alignment")
|
|
|
+ .attr("horizontal", "left")
|
|
|
+ .attr("vertical", "center");
|
|
|
+ }
|
|
|
+ cellXfs.append(baseXf);
|
|
|
+
|
|
|
+ const newId = $("cellXfs xf", styles).length - 1;
|
|
|
+ cellXfs.attr(
|
|
|
+ "count",
|
|
|
+ $("cellXfs xf", styles).length
|
|
|
+ );
|
|
|
+ cell.attr("s", newId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const forceAllCellsAsText = function (xlsx) {
|
|
|
+ const sheet = xlsx.xl.worksheets["sheet1.xml"];
|
|
|
+ if (!sheet) return;
|
|
|
+
|
|
|
+ $("worksheet sheetData row c", sheet).each(function () {
|
|
|
+ const $cell = $(this);
|
|
|
+ const text = readCellText($cell, sheet, xlsx);
|
|
|
+ // sostituisco contenuto con inline string
|
|
|
+ $cell.attr("t", "inlineStr");
|
|
|
+ $cell.find("v").remove();
|
|
|
+ $cell.find("is").remove();
|
|
|
+ const safe = escapeXmlText(text);
|
|
|
+ $cell.append(`<is><t>${safe}</t></is>`);
|
|
|
+ // NON tocco l’attributo 's' (stile) se già esiste
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ // --- CLIENT-SIDE ---
|
|
|
+ if (!isServerSide || !hasAjax) {
|
|
|
+ // Esporta tutte le righe lato client
|
|
|
+ const origExportOptions = config.exportOptions
|
|
|
+ ? { ...config.exportOptions }
|
|
|
+ : {};
|
|
|
+ config.exportOptions = config.exportOptions || {};
|
|
|
+ config.exportOptions.modifier = {
|
|
|
+ ...(config.exportOptions.modifier || {}),
|
|
|
+ page: "all",
|
|
|
+ };
|
|
|
+
|
|
|
+ // PDF: tabella full-width
|
|
|
+ // const isPdf = button[0].className.indexOf('buttons-pdf') >= 0;
|
|
|
+ // const origCustomize = config.customize;
|
|
|
+ // if (isPdf) {
|
|
|
+ // config.customize = function(doc) {
|
|
|
+ // const table = doc.content[1] && doc.content[1].table ? doc.content[1].table : null;
|
|
|
+ // if (table && table.body && table.body[0]) {
|
|
|
+ // table.widths = Array(table.body[0].length).fill('*');
|
|
|
+ // }
|
|
|
+ // if (typeof origCustomize === 'function') origCustomize(doc);
|
|
|
+ // };
|
|
|
+ // }
|
|
|
+
|
|
|
+ const cls = button[0].className;
|
|
|
+
|
|
|
+ if (cls.includes("buttons-copy")) {
|
|
|
+ $.fn.dataTable.ext.buttons.copyHtml5.action.call(
|
|
|
+ self,
|
|
|
+ e,
|
|
|
+ dt,
|
|
|
+ button,
|
|
|
+ config,
|
|
|
+ cb
|
|
|
+ );
|
|
|
+ } else if (cls.includes("buttons-excel")) {
|
|
|
+ const origCustomize = config.customize;
|
|
|
+ config.filename = config.title;
|
|
|
+ config.title = null;
|
|
|
+ config.customize = function (xlsx) {
|
|
|
+ if (typeof origCustomize === "function") origCustomize(xlsx);
|
|
|
+ customizeHeaderExcel(xlsx);
|
|
|
+ alignLeftCells(xlsx, config);
|
|
|
+ forceAllCellsAsText(xlsx);
|
|
|
+ };
|
|
|
+
|
|
|
+ ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config)
|
|
|
+ ? $.fn.dataTable.ext.buttons.excelHtml5
|
|
|
+ : $.fn.dataTable.ext.buttons.excelFlash
|
|
|
+ ).action.call(self, e, dt, button, config, cb);
|
|
|
+
|
|
|
+ config.customize = origCustomize; // ripristina
|
|
|
+ } else if (cls.includes("buttons-csv")) {
|
|
|
+ ($.fn.dataTable.ext.buttons.csvHtml5.available(dt, config)
|
|
|
+ ? $.fn.dataTable.ext.buttons.csvHtml5
|
|
|
+ : $.fn.dataTable.ext.buttons.csvFlash
|
|
|
+ ).action.call(self, e, dt, button, config, cb);
|
|
|
+ } else if (cls.includes("buttons-pdf")) {
|
|
|
+ ($.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config)
|
|
|
+ ? $.fn.dataTable.ext.buttons.pdfHtml5
|
|
|
+ : $.fn.dataTable.ext.buttons.pdfFlash
|
|
|
+ ).action.call(self, e, dt, button, config, cb);
|
|
|
+ } else if (cls.includes("buttons-print")) {
|
|
|
+ $.fn.dataTable.ext.buttons.print.action.call(
|
|
|
+ self,
|
|
|
+ e,
|
|
|
+ dt,
|
|
|
+ button,
|
|
|
+ config,
|
|
|
+ cb
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Ripristina config
|
|
|
+ config.exportOptions = origExportOptions;
|
|
|
+ // if (isPdf) config.customize = origCustomize;
|
|
|
+
|
|
|
+ if (typeof cb === "function") cb();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- SERVER-SIDE + AJAX: fetch completo poi export ---
|
|
|
+ const info = dt.page.info();
|
|
|
+ const oldStart = info.start;
|
|
|
+ const oldLength = info.length;
|
|
|
+ const targetLength = info.recordsTotal > 0 ? info.recordsTotal : 2147483647;
|
|
|
+
|
|
|
+ dt.one("preXhr", function (e2, s, data) {
|
|
|
+ data.start = 0;
|
|
|
+ data.length = targetLength;
|
|
|
+
|
|
|
+ dt.one("preDraw", function (e3, stg) {
|
|
|
+ const cls = button[0].className;
|
|
|
+
|
|
|
+ if (cls.includes("buttons-copy")) {
|
|
|
+ $.fn.dataTable.ext.buttons.copyHtml5.action.call(
|
|
|
+ self,
|
|
|
+ e,
|
|
|
+ dt,
|
|
|
+ button,
|
|
|
+ config,
|
|
|
+ cb
|
|
|
+ );
|
|
|
+ } else if (cls.includes("buttons-excel")) {
|
|
|
+ const origCustomize = config.customize;
|
|
|
+ config.filename = config.title;
|
|
|
+ config.title = null;
|
|
|
+ config.customize = function (xlsx) {
|
|
|
+ if (typeof origCustomize === "function")
|
|
|
+ origCustomize(xlsx);
|
|
|
+ customizeHeaderExcel(xlsx);
|
|
|
+ alignLeftCells(xlsx, config);
|
|
|
+ forceAllCellsAsText(xlsx);
|
|
|
+ };
|
|
|
+
|
|
|
+ ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config)
|
|
|
+ ? $.fn.dataTable.ext.buttons.excelHtml5
|
|
|
+ : $.fn.dataTable.ext.buttons.excelFlash
|
|
|
+ ).action.call(self, e, dt, button, config, cb);
|
|
|
+
|
|
|
+ config.customize = origCustomize;
|
|
|
+ } else if (cls.includes("buttons-csv")) {
|
|
|
+ ($.fn.dataTable.ext.buttons.csvHtml5.available(dt, config)
|
|
|
+ ? $.fn.dataTable.ext.buttons.csvHtml5
|
|
|
+ : $.fn.dataTable.ext.buttons.csvFlash
|
|
|
+ ).action.call(self, e, dt, button, config, cb);
|
|
|
+ } else if (cls.includes("buttons-pdf")) {
|
|
|
+ // Full-width PDF
|
|
|
+ // const origCustomize = config.customize;
|
|
|
+ // config.customize = function(doc) {
|
|
|
+ // const t = doc.content[1] && doc.content[1].table ? doc.content[1].table : null;
|
|
|
+ // if (t && t.body && t.body[0]) t.widths = Array(t.body[0].length).fill('*');
|
|
|
+ // if (typeof origCustomize === 'function') origCustomize(doc);
|
|
|
+ // };
|
|
|
+ ($.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config)
|
|
|
+ ? $.fn.dataTable.ext.buttons.pdfHtml5
|
|
|
+ : $.fn.dataTable.ext.buttons.pdfFlash
|
|
|
+ ).action.call(self, e, dt, button, config, cb);
|
|
|
+ // config.customize = origCustomize;
|
|
|
+ } else if (cls.includes("buttons-print")) {
|
|
|
+ $.fn.dataTable.ext.buttons.print.action.call(
|
|
|
+ self,
|
|
|
+ e,
|
|
|
+ dt,
|
|
|
+ button,
|
|
|
+ config,
|
|
|
+ cb
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ dt.one("preXhr", function (e4, s2, data2) {
|
|
|
+ data2.start = oldStart;
|
|
|
+ data2.length = oldLength;
|
|
|
+ stg._iDisplayStart = oldStart;
|
|
|
+ });
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ dt.ajax.reload(() => {
|
|
|
+ if (typeof cb === "function") cb();
|
|
|
+ }, false);
|
|
|
+ }, 0);
|
|
|
+
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ dt.ajax.reload();
|
|
|
+}
|