ghostTable.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { fastInnerHTML } from '../../../helpers/dom/element';
  2. import { clone } from '../../../helpers/object';
  3. class GhostTable {
  4. constructor(plugin) {
  5. /**
  6. * Reference to NestedHeaders plugin.
  7. *
  8. * @type {NestedHeaders}
  9. */
  10. this.nestedHeaders = plugin;
  11. /**
  12. * Temporary element created to get minimal headers widths.
  13. *
  14. * @type {*}
  15. */
  16. this.container = void 0;
  17. /**
  18. * Cached the headers widths.
  19. *
  20. * @type {Array}
  21. */
  22. this.widthsCache = [];
  23. }
  24. /**
  25. * Build cache of the headers widths.
  26. *
  27. * @private
  28. */
  29. buildWidthsMapper() {
  30. this.container = document.createElement('div');
  31. this.buildGhostTable(this.container);
  32. this.nestedHeaders.hot.rootElement.appendChild(this.container);
  33. const columns = this.container.querySelectorAll('tr:last-of-type th');
  34. const maxColumns = columns.length;
  35. for (let i = 0; i < maxColumns; i++) {
  36. this.widthsCache.push(columns[i].offsetWidth);
  37. }
  38. this.container.parentNode.removeChild(this.container);
  39. this.container = null;
  40. this.nestedHeaders.hot.render();
  41. }
  42. /**
  43. * Build temporary table for getting minimal columns widths.
  44. *
  45. * @private
  46. * @param {HTMLElement} container
  47. */
  48. buildGhostTable(container) {
  49. const d = document;
  50. const fragment = d.createDocumentFragment();
  51. const table = d.createElement('table');
  52. let lastRowColspan = false;
  53. const isDropdownEnabled = !!this.nestedHeaders.hot.getSettings().dropdownMenu;
  54. const maxRows = this.nestedHeaders.colspanArray.length;
  55. const maxCols = this.nestedHeaders.hot.countCols();
  56. const lastRowIndex = maxRows - 1;
  57. for (let row = 0; row < maxRows; row++) {
  58. const tr = d.createElement('tr');
  59. lastRowColspan = false;
  60. for (let col = 0; col < maxCols; col++) {
  61. const td = d.createElement('th');
  62. const headerObj = clone(this.nestedHeaders.colspanArray[row][col]);
  63. if (headerObj && !headerObj.hidden) {
  64. if (row === lastRowIndex) {
  65. if (headerObj.colspan > 1) {
  66. lastRowColspan = true;
  67. }
  68. if (isDropdownEnabled) {
  69. headerObj.label += '<button class="changeType"></button>';
  70. }
  71. }
  72. fastInnerHTML(td, headerObj.label);
  73. td.colSpan = headerObj.colspan;
  74. tr.appendChild(td);
  75. }
  76. }
  77. table.appendChild(tr);
  78. }
  79. // We have to be sure the last row contains only the single columns.
  80. if (lastRowColspan) {
  81. {
  82. const tr = d.createElement('tr');
  83. for (let col = 0; col < maxCols; col++) {
  84. const td = d.createElement('th');
  85. tr.appendChild(td);
  86. }
  87. table.appendChild(tr);
  88. }
  89. }
  90. fragment.appendChild(table);
  91. container.appendChild(fragment);
  92. }
  93. /**
  94. * Clear the widths cache.
  95. */
  96. clear() {
  97. this.container = null;
  98. this.widthsCache.length = 0;
  99. }
  100. }
  101. export default GhostTable;