Exportar Tablas HTML a Excel (con ExcelJS + Observer)

Agrega un botón a cada tabla HTML para exportarla a Excel usando ExcelJS

  1. // ==UserScript==
  2. // @name Exportar Tablas HTML a Excel (con ExcelJS + Observer)
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @description Agrega un botón a cada tabla HTML para exportarla a Excel usando ExcelJS
  6. // @match *://*/*
  7. // @grant none
  8. // @license MIT
  9. // ==/UserScript==
  10.  
  11. (function () {
  12. 'use strict';
  13.  
  14. function injectScript(fn) {
  15. const script = document.createElement('script');
  16. script.textContent = `(${fn})();`;
  17. document.body.appendChild(script);
  18. }
  19.  
  20. function mainScript() {
  21. const exceljsSrc = 'https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.3.0/exceljs.min.js';
  22.  
  23. function loadExcelJS() {
  24. return new Promise((resolve) => {
  25. const script = document.createElement('script');
  26. script.src = exceljsSrc;
  27. script.onload = resolve;
  28. document.head.appendChild(script);
  29. });
  30. }
  31.  
  32. function observeDOMForTables() {
  33. const observer = new MutationObserver(() => {
  34. const tables = document.querySelectorAll('table:not([data-excel-ready])');
  35.  
  36. if (tables.length > 0) {
  37. console.clear();
  38. console.log('tables encontradas:', tables);
  39. }
  40.  
  41. tables.forEach((table, index) => {
  42. table.setAttribute('data-excel-ready', 'true');
  43. addExportButton(table, index + 1);
  44. });
  45. });
  46.  
  47. observer.observe(document.body, { childList: true, subtree: true });
  48. }
  49.  
  50. function addExportButton(table, index) {
  51. const btn = document.createElement('button');
  52. btn.textContent = '📥 Excel';
  53. btn.style.position = 'absolute';
  54. btn.style.fontSize = '12px';
  55. btn.style.padding = '4px';
  56. btn.style.background = '#4CAF50';
  57. btn.style.color = '#fff';
  58. btn.style.border = 'none';
  59. btn.style.cursor = 'pointer';
  60. btn.style.zIndex = 9999;
  61.  
  62. const rect = table.getBoundingClientRect();
  63. btn.style.top = `${window.scrollY + rect.top + 5}px`;
  64. btn.style.left = `${window.scrollX + rect.right - 80}px`;
  65.  
  66. document.body.appendChild(btn);
  67.  
  68. btn.addEventListener('click', () => exportTableToExcel(table, index));
  69. }
  70.  
  71. function exportTableToExcel(table, tableIndex) {
  72. const workbook = new ExcelJS.Workbook();
  73. const sheet = workbook.addWorksheet(`Tabla ${tableIndex}`);
  74. const cellMap = {};
  75.  
  76. const rows = Array.from(table.rows);
  77. for (let rowIndex = 0, excelRowIndex = 1; rowIndex < rows.length; rowIndex++, excelRowIndex++) {
  78. const row = rows[rowIndex];
  79. const cells = Array.from(row.cells);
  80. let colIndex = 1;
  81.  
  82. cells.forEach(cell => {
  83. while (cellMap[`${excelRowIndex}:${colIndex}`]) colIndex++;
  84.  
  85. const excelCell = sheet.getCell(excelRowIndex, colIndex);
  86. excelCell.value = cell.innerText.trim();
  87.  
  88. const colspan = parseInt(cell.getAttribute('colspan') || '1', 10);
  89. const rowspan = parseInt(cell.getAttribute('rowspan') || '1', 10);
  90.  
  91. if (colspan > 1 || rowspan > 1) {
  92. const endCol = colIndex + colspan - 1;
  93. const endRow = excelRowIndex + rowspan - 1;
  94. sheet.mergeCells(excelRowIndex, colIndex, endRow, endCol);
  95.  
  96. for (let r = excelRowIndex; r <= endRow; r++) {
  97. for (let c = colIndex; c <= endCol; c++) {
  98. cellMap[`${r}:${c}`] = true;
  99. }
  100. }
  101. } else {
  102. cellMap[`${excelRowIndex}:${colIndex}`] = true;
  103. }
  104.  
  105. colIndex += colspan;
  106. });
  107. }
  108.  
  109. workbook.xlsx.writeBuffer().then((buffer) => {
  110. const blob = new Blob([buffer], {
  111. type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  112. });
  113. const link = document.createElement('a');
  114. link.href = URL.createObjectURL(blob);
  115. link.download = `tabla_${tableIndex}.xlsx`;
  116. link.click();
  117. });
  118. }
  119.  
  120. window.addEventListener('load', async () => {
  121. await loadExcelJS();
  122. observeDOMForTables();
  123. });
  124. }
  125.  
  126. injectScript(mainScript);
  127. })();