officeparser 7.1.0 → 7.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -56
- package/dist/OfficeGenerator.d.ts +6 -2
- package/dist/OfficeGenerator.js +30 -9
- package/dist/OfficeParser.d.ts +1 -1
- package/dist/OfficeParser.js +1 -1
- package/dist/cli.d.ts +18 -12
- package/dist/cli.js +255 -81
- package/dist/defaults.js +12 -1
- package/dist/generators/BaseGenerator.d.ts +4 -3
- package/dist/generators/BaseGenerator.js +13 -1
- package/dist/generators/ChunkingGenerator.js +32 -5
- package/dist/generators/CsvGenerator.d.ts +1 -1
- package/dist/generators/HtmlGenerator.d.ts +2 -1
- package/dist/generators/HtmlGenerator.js +481 -42
- package/dist/generators/MarkdownGenerator.d.ts +1 -1
- package/dist/generators/MarkdownGenerator.js +35 -2
- package/dist/generators/PdfGenerator.d.ts +1 -1
- package/dist/generators/PdfGenerator.js +0 -6
- package/dist/generators/RtfGenerator.d.ts +2 -1
- package/dist/generators/RtfGenerator.js +49 -6
- package/dist/generators/TextGenerator.d.ts +1 -1
- package/dist/generators/TextGenerator.js +6 -0
- package/dist/officeparser.browser.d.ts +267 -54
- package/dist/officeparser.browser.iife.js +599 -187
- package/dist/officeparser.browser.mjs +599 -187
- package/dist/parsers/CsvParser.js +1 -1
- package/dist/parsers/ExcelParser.js +63 -19
- package/dist/parsers/HtmlParser.js +10 -1
- package/dist/parsers/MarkdownParser.js +13 -10
- package/dist/parsers/OpenOfficeParser.js +57 -34
- package/dist/parsers/PdfParser.js +28 -3
- package/dist/parsers/PowerPointParser.js +164 -40
- package/dist/parsers/RtfParser.js +28 -24
- package/dist/parsers/WordParser.js +154 -11
- package/dist/sbom.cdx.json +100 -100
- package/dist/types.d.ts +268 -53
- package/dist/types.js +4 -0
- package/dist/utils/astUtils.d.ts +2 -2
- package/dist/utils/astUtils.js +2 -1
- package/dist/utils/configUtils.d.ts +5 -0
- package/dist/utils/configUtils.js +55 -1
- package/dist/utils/errorUtils.js +3 -1
- package/dist/utils/moduleLoader.js +55 -11
- package/dist/utils/xmlUtils.d.ts +9 -0
- package/dist/utils/xmlUtils.js +53 -1
- package/package.json +6 -3
|
@@ -27,7 +27,14 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
27
27
|
containerClass = 'presentation-container';
|
|
28
28
|
else if (isPdf)
|
|
29
29
|
containerClass = 'pdf-container';
|
|
30
|
-
|
|
30
|
+
let bodyContent = await this.processNodeArray(this.ast.content);
|
|
31
|
+
if (this.collectedNotes.length > 0) {
|
|
32
|
+
let notesHtml = '';
|
|
33
|
+
for (const note of this.collectedNotes) {
|
|
34
|
+
notesHtml += await this.processNodeRecursive(note, this.nodeProcessor.bind(this));
|
|
35
|
+
}
|
|
36
|
+
bodyContent += `\n<div class="document-notes-section">\n<hr class="page-break">\n${notesHtml}\n</div>\n`;
|
|
37
|
+
}
|
|
31
38
|
const metadataBlock = this.config.renderMetadata ? this.renderMetadataSummary() : '';
|
|
32
39
|
let title = 'Document';
|
|
33
40
|
let metaTags = '';
|
|
@@ -50,6 +57,120 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
50
57
|
spreadsheetTabs = `<div class="spreadsheet-tabs">${tabs}</div>`;
|
|
51
58
|
spreadsheetScript = `
|
|
52
59
|
<script>
|
|
60
|
+
function initSpreadsheetResizing() {
|
|
61
|
+
document.querySelectorAll('.excel-grid').forEach(table => {
|
|
62
|
+
if (table.dataset.resizingInitialized) return;
|
|
63
|
+
if (table.offsetWidth === 0) return; // skip hidden tables
|
|
64
|
+
table.dataset.resizingInitialized = 'true';
|
|
65
|
+
|
|
66
|
+
const sheetId = table.parentElement.id || 'sheet';
|
|
67
|
+
const docId = window.location.pathname;
|
|
68
|
+
|
|
69
|
+
// Freeze initial auto-layout widths of columns and set table layout to fixed
|
|
70
|
+
const colHeaders = table.querySelectorAll('.excel-col-header');
|
|
71
|
+
colHeaders.forEach((header, index) => {
|
|
72
|
+
let currentWidth = header.offsetWidth;
|
|
73
|
+
const savedWidth = localStorage.getItem(docId + '_' + sheetId + '_col_' + index);
|
|
74
|
+
if (savedWidth) {
|
|
75
|
+
currentWidth = parseInt(savedWidth, 10);
|
|
76
|
+
}
|
|
77
|
+
header.style.width = currentWidth + 'px';
|
|
78
|
+
header.style.minWidth = currentWidth + 'px';
|
|
79
|
+
});
|
|
80
|
+
table.style.width = table.offsetWidth + 'px';
|
|
81
|
+
table.style.tableLayout = 'fixed';
|
|
82
|
+
|
|
83
|
+
// Freeze initial auto-layout heights of rows
|
|
84
|
+
table.querySelectorAll('tr').forEach((row, index) => {
|
|
85
|
+
let currentHeight = row.offsetHeight;
|
|
86
|
+
const savedHeight = localStorage.getItem(docId + '_' + sheetId + '_row_' + index);
|
|
87
|
+
if (savedHeight) {
|
|
88
|
+
currentHeight = parseInt(savedHeight, 10);
|
|
89
|
+
}
|
|
90
|
+
row.style.height = currentHeight + 'px';
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
colHeaders.forEach((header, index) => {
|
|
94
|
+
if (header.querySelector('.col-resizer')) return;
|
|
95
|
+
const resizer = document.createElement('div');
|
|
96
|
+
resizer.className = 'col-resizer';
|
|
97
|
+
header.appendChild(resizer);
|
|
98
|
+
|
|
99
|
+
let startX = 0;
|
|
100
|
+
let startWidth = 0;
|
|
101
|
+
let startTableWidth = 0;
|
|
102
|
+
|
|
103
|
+
const onMouseMove = (e) => {
|
|
104
|
+
const width = startWidth + (e.clientX - startX);
|
|
105
|
+
if (width > 40) {
|
|
106
|
+
header.style.width = width + 'px';
|
|
107
|
+
header.style.minWidth = width + 'px';
|
|
108
|
+
table.style.width = (startTableWidth + (width - startWidth)) + 'px';
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const onMouseUp = (e) => {
|
|
113
|
+
resizer.classList.remove('resizing');
|
|
114
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
115
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
116
|
+
const finalWidth = startWidth + (e.clientX - startX);
|
|
117
|
+
if (finalWidth > 40) {
|
|
118
|
+
localStorage.setItem(docId + '_' + sheetId + '_col_' + index, finalWidth);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
resizer.addEventListener('mousedown', (e) => {
|
|
123
|
+
e.preventDefault();
|
|
124
|
+
e.stopPropagation();
|
|
125
|
+
startX = e.clientX;
|
|
126
|
+
startWidth = header.offsetWidth;
|
|
127
|
+
startTableWidth = table.offsetWidth;
|
|
128
|
+
resizer.classList.add('resizing');
|
|
129
|
+
document.addEventListener('mousemove', onMouseMove);
|
|
130
|
+
document.addEventListener('mouseup', onMouseUp);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
table.querySelectorAll('.excel-row-num').forEach((rowHeader, index) => {
|
|
135
|
+
if (rowHeader.querySelector('.row-resizer')) return;
|
|
136
|
+
const resizer = document.createElement('div');
|
|
137
|
+
resizer.className = 'row-resizer';
|
|
138
|
+
rowHeader.appendChild(resizer);
|
|
139
|
+
|
|
140
|
+
const row = rowHeader.parentElement;
|
|
141
|
+
let startY = 0;
|
|
142
|
+
let startHeight = 0;
|
|
143
|
+
|
|
144
|
+
const onMouseMove = (e) => {
|
|
145
|
+
const height = startHeight + (e.clientY - startY);
|
|
146
|
+
if (height > 20) {
|
|
147
|
+
row.style.height = height + 'px';
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const onMouseUp = (e) => {
|
|
152
|
+
resizer.classList.remove('resizing');
|
|
153
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
154
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
155
|
+
const finalHeight = startHeight + (e.clientY - startY);
|
|
156
|
+
if (finalHeight > 20) {
|
|
157
|
+
localStorage.setItem(docId + '_' + sheetId + '_row_' + index, finalHeight);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
resizer.addEventListener('mousedown', (e) => {
|
|
162
|
+
e.preventDefault();
|
|
163
|
+
e.stopPropagation();
|
|
164
|
+
startY = e.clientY;
|
|
165
|
+
startHeight = row.offsetHeight;
|
|
166
|
+
resizer.classList.add('resizing');
|
|
167
|
+
document.addEventListener('mousemove', onMouseMove);
|
|
168
|
+
document.addEventListener('mouseup', onMouseUp);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
53
174
|
function switchSheet() {
|
|
54
175
|
try {
|
|
55
176
|
let hash = window.location.hash;
|
|
@@ -79,6 +200,8 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
79
200
|
}
|
|
80
201
|
});
|
|
81
202
|
}
|
|
203
|
+
|
|
204
|
+
initSpreadsheetResizing();
|
|
82
205
|
} catch (e) {
|
|
83
206
|
console.error('Sheet switch failed:', e);
|
|
84
207
|
const firstSheet = document.querySelector('.spreadsheet-sheet');
|
|
@@ -96,9 +219,11 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
96
219
|
metaTags = this.renderMetaTags();
|
|
97
220
|
}
|
|
98
221
|
const styles = this.config.htmlConfig.standalone ? '' : `<style>${this.getPremiumStyles(this.isSpreadsheetMode, isPresentation, isPdf)}</style>`;
|
|
222
|
+
const inj = this.config.htmlConfig.injections;
|
|
99
223
|
const value = this.config.htmlConfig.standalone ? `<!DOCTYPE html>
|
|
100
224
|
<html lang="en">
|
|
101
225
|
<head>
|
|
226
|
+
${inj.headStart}
|
|
102
227
|
<meta charset="UTF-8">
|
|
103
228
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
104
229
|
<title>${this.escape(title)}</title>
|
|
@@ -107,8 +232,10 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
107
232
|
<style>
|
|
108
233
|
${this.getPremiumStyles(this.isSpreadsheetMode, isPresentation, isPdf)}
|
|
109
234
|
</style>
|
|
235
|
+
${inj.headEnd}
|
|
110
236
|
</head>
|
|
111
237
|
<body>
|
|
238
|
+
${inj.bodyStart}
|
|
112
239
|
<div class="${containerClass}">
|
|
113
240
|
<article>
|
|
114
241
|
${metadataBlock}
|
|
@@ -117,6 +244,7 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
117
244
|
${spreadsheetTabs}
|
|
118
245
|
</div>
|
|
119
246
|
${spreadsheetScript}
|
|
247
|
+
${inj.bodyEnd}
|
|
120
248
|
</body>
|
|
121
249
|
</html>` : `${styles}<div class="${containerClass}">${metadataBlock}${bodyContent}${spreadsheetTabs}</div>${spreadsheetScript}`;
|
|
122
250
|
return {
|
|
@@ -264,9 +392,19 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
264
392
|
// Fallback for nodes that have text property but no children (e.g. simple paragraphs)
|
|
265
393
|
childrenOutput = this.escape(node.text);
|
|
266
394
|
}
|
|
267
|
-
|
|
395
|
+
if (node.notes && node.notes.length > 0) {
|
|
396
|
+
if (node.type !== 'slide') {
|
|
397
|
+
this.collectedNotes.push(...node.notes);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
let result = await processor(node, childrenOutput);
|
|
268
401
|
if (isTable)
|
|
269
402
|
this.tableNestingLevel--;
|
|
403
|
+
if (node.type === 'slide' && node.notes && node.notes.length > 0) {
|
|
404
|
+
for (const note of node.notes) {
|
|
405
|
+
result += await this.processNodeRecursive(note, processor);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
270
408
|
return result;
|
|
271
409
|
}
|
|
272
410
|
/**
|
|
@@ -490,23 +628,127 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
490
628
|
return `<td${rowSpan}${colSpan}${idAttr}${className}${mappedAttrs}${styleAttr}>${childrenOutput}</td>`;
|
|
491
629
|
}
|
|
492
630
|
case 'sheet': {
|
|
493
|
-
// For sheet-based files, wrap rows in a table
|
|
494
|
-
let finalChildren = childrenOutput;
|
|
495
631
|
const rows = node.children || [];
|
|
496
|
-
//
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
632
|
+
// Find grid bounds
|
|
633
|
+
let maxRow = -1;
|
|
634
|
+
let maxCol = -1;
|
|
635
|
+
for (const child of rows) {
|
|
636
|
+
if (child.type === 'row') {
|
|
637
|
+
for (const cell of child.children || []) {
|
|
638
|
+
if (cell.type === 'cell') {
|
|
639
|
+
const meta = cell.metadata;
|
|
640
|
+
if (meta) {
|
|
641
|
+
const r = meta.row;
|
|
642
|
+
const c = meta.col;
|
|
643
|
+
const rSpan = meta.rowSpan || 1;
|
|
644
|
+
const cSpan = meta.colSpan || 1;
|
|
645
|
+
if (r + rSpan - 1 > maxRow)
|
|
646
|
+
maxRow = r + rSpan - 1;
|
|
647
|
+
if (c + cSpan - 1 > maxCol)
|
|
648
|
+
maxCol = c + cSpan - 1;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
let tableHtml = '';
|
|
655
|
+
if (maxRow >= 0 && maxCol >= 0) {
|
|
656
|
+
// Populate cell grid and track merged cells
|
|
657
|
+
const grid = Array.from({ length: maxRow + 1 }, () => Array(maxCol + 1).fill(null));
|
|
658
|
+
const mergedCovered = Array.from({ length: maxRow + 1 }, () => Array(maxCol + 1).fill(false));
|
|
659
|
+
const rowNodeMap = new Map();
|
|
660
|
+
for (const child of rows) {
|
|
661
|
+
if (child.type === 'row') {
|
|
662
|
+
const cellsInRow = child.children?.filter(c => c.type === 'cell') || [];
|
|
663
|
+
if (cellsInRow.length > 0) {
|
|
664
|
+
const r = cellsInRow[0].metadata.row;
|
|
665
|
+
rowNodeMap.set(r, child);
|
|
666
|
+
for (const cell of cellsInRow) {
|
|
667
|
+
const meta = cell.metadata;
|
|
668
|
+
if (meta) {
|
|
669
|
+
const c = meta.col;
|
|
670
|
+
if (r >= 0 && r <= maxRow && c >= 0 && c <= maxCol) {
|
|
671
|
+
grid[r][c] = cell;
|
|
672
|
+
const rSpan = meta.rowSpan || 1;
|
|
673
|
+
const cSpan = meta.colSpan || 1;
|
|
674
|
+
if (rSpan > 1 || cSpan > 1) {
|
|
675
|
+
for (let rOffset = 0; rOffset < rSpan; rOffset++) {
|
|
676
|
+
for (let cOffset = 0; cOffset < cSpan; cOffset++) {
|
|
677
|
+
if (rOffset === 0 && cOffset === 0)
|
|
678
|
+
continue;
|
|
679
|
+
const targetR = r + rOffset;
|
|
680
|
+
const targetC = c + cOffset;
|
|
681
|
+
if (targetR <= maxRow && targetC <= maxCol) {
|
|
682
|
+
mergedCovered[targetR][targetC] = true;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
// Build column headers (A, B, C...)
|
|
694
|
+
let ths = '<th class="excel-row-num-header"></th>';
|
|
695
|
+
for (let c = 0; c <= maxCol; c++) {
|
|
696
|
+
ths += `<th class="excel-col-header">${this.getColumnLetter(c)}</th>`;
|
|
697
|
+
}
|
|
698
|
+
const thead = `<thead><tr>${ths}</tr></thead>`;
|
|
699
|
+
// Build rows
|
|
700
|
+
let tbodyRows = '';
|
|
701
|
+
for (let r = 0; r <= maxRow; r++) {
|
|
702
|
+
const rowNode = rowNodeMap.get(r);
|
|
703
|
+
let trAttrs = '';
|
|
704
|
+
if (rowNode) {
|
|
705
|
+
const mapping = this.getSemanticMapping(rowNode);
|
|
706
|
+
const rClasses = ['excel-row'];
|
|
707
|
+
if (mapping?.classes)
|
|
708
|
+
rClasses.push(...mapping.classes);
|
|
709
|
+
trAttrs += ` class="${rClasses.join(' ')}"`;
|
|
710
|
+
if (mapping?.attributes) {
|
|
711
|
+
for (const [key, val] of Object.entries(mapping.attributes)) {
|
|
712
|
+
trAttrs += ` ${key}="${this.escape(val)}"`;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
const rAnchorIds = this.config.ignoreInternalLinks ? [] : [...(rowNode.metadata?.anchorIds || [])];
|
|
716
|
+
if (rAnchorIds.length > 0) {
|
|
717
|
+
trAttrs += ` id="${rAnchorIds[0]}"`;
|
|
718
|
+
}
|
|
719
|
+
if (this.config.includeFormatting) {
|
|
720
|
+
const styles = this.getInlineStyles(rowNode);
|
|
721
|
+
if (styles)
|
|
722
|
+
trAttrs += ` style="${styles}"`;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
trAttrs = ' class="excel-row"';
|
|
727
|
+
}
|
|
728
|
+
let rowCellsHtml = `<td class="excel-row-num">${r + 1}</td>`;
|
|
729
|
+
for (let c = 0; c <= maxCol; c++) {
|
|
730
|
+
if (mergedCovered[r][c]) {
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
const cell = grid[r][c];
|
|
734
|
+
if (cell) {
|
|
735
|
+
const cellHtml = await this.processNodeRecursive(cell, this.nodeProcessor.bind(this));
|
|
736
|
+
rowCellsHtml += cellHtml;
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
rowCellsHtml += '<td class="excel-cell-empty"></td>';
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
tbodyRows += `<tr${trAttrs}>${rowCellsHtml}</tr>\n`;
|
|
509
743
|
}
|
|
744
|
+
const tbody = `<tbody>${tbodyRows}</tbody>`;
|
|
745
|
+
tableHtml = `<table class="spreadsheet-table excel-grid">${thead}${tbody}</table>`;
|
|
746
|
+
}
|
|
747
|
+
// Process non-row elements (images, charts, etc.)
|
|
748
|
+
const nonRowNodes = rows.filter(c => c.type !== 'row');
|
|
749
|
+
let nonRowHtml = '';
|
|
750
|
+
if (nonRowNodes.length > 0) {
|
|
751
|
+
nonRowHtml = await this.processNodeArray(nonRowNodes);
|
|
510
752
|
}
|
|
511
753
|
const isFirstSheet = this.ast.content.filter(n => n.type === 'sheet')[0] === node;
|
|
512
754
|
const isActive = isFirstSheet;
|
|
@@ -521,11 +763,18 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
521
763
|
const classAttr = ` class="${mergedClasses.join(' ')}"`;
|
|
522
764
|
// Ensure we don't have duplicate IDs
|
|
523
765
|
const finalIdAttr = ` id="${sheetId}"`;
|
|
524
|
-
return `${extraAnchors}<div${finalIdAttr}${classAttr}${mappedAttrs}${styleAttr}
|
|
766
|
+
return `${extraAnchors}<div${finalIdAttr}${classAttr}${mappedAttrs}${styleAttr}>${tableHtml}${nonRowHtml}</div>`;
|
|
525
767
|
}
|
|
526
768
|
case 'paragraph':
|
|
527
769
|
case 'heading': {
|
|
528
770
|
const tag = node.type === 'heading' ? `h${node.metadata?.level || 1}` : 'p';
|
|
771
|
+
// Normalize empty paragraphs so DOCX and PPTX empty cells render with consistent height
|
|
772
|
+
// Strip tags to check if it's purely empty or just contains non-breaking spaces (like PPTX)
|
|
773
|
+
const textOnly = childrenOutput.replace(/<[^>]+>/g, '').trim();
|
|
774
|
+
if (!textOnly && !node.children?.some(c => c.type === 'image' || c.type === 'chart')) {
|
|
775
|
+
const extraClass = className ? ` class="${className.replace('class="', '').replace('"', '')} empty-paragraph"` : ' class="empty-paragraph"';
|
|
776
|
+
return `${extraAnchors}<${tag}${idAttr}${extraClass}${mappedAttrs}${styleAttr}><br></${tag}>`;
|
|
777
|
+
}
|
|
529
778
|
return `${extraAnchors}<${tag}${idAttr}${className}${mappedAttrs}${styleAttr}>${childrenOutput}</${tag}>`;
|
|
530
779
|
}
|
|
531
780
|
case 'slide': {
|
|
@@ -622,6 +871,21 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
622
871
|
return styles.join('; ');
|
|
623
872
|
}
|
|
624
873
|
getPremiumStyles(isSpreadsheet = false, isPresentation = false, isPdf = false) {
|
|
874
|
+
let resolvedWidth = this.config.htmlConfig.containerWidth;
|
|
875
|
+
if (!resolvedWidth || resolvedWidth === 'auto') {
|
|
876
|
+
if (isSpreadsheet) {
|
|
877
|
+
resolvedWidth = '100%';
|
|
878
|
+
}
|
|
879
|
+
else if (isPresentation) {
|
|
880
|
+
resolvedWidth = '297mm';
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
resolvedWidth = '900px';
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
else if (typeof resolvedWidth === 'number') {
|
|
887
|
+
resolvedWidth = `${resolvedWidth}px`;
|
|
888
|
+
}
|
|
625
889
|
return `
|
|
626
890
|
:root {
|
|
627
891
|
--primary-color: #2c3e50;
|
|
@@ -631,6 +895,7 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
631
895
|
--border-color: #e9ecef;
|
|
632
896
|
--accent-color: #3498db;
|
|
633
897
|
--shadow: 0 10px 25px rgba(0,0,0,0.05);
|
|
898
|
+
--container-width: ${resolvedWidth};
|
|
634
899
|
}
|
|
635
900
|
* {
|
|
636
901
|
box-sizing: border-box;
|
|
@@ -644,7 +909,7 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
644
909
|
padding: ${isSpreadsheet ? '0' : '50px 20px'};
|
|
645
910
|
}
|
|
646
911
|
.container {
|
|
647
|
-
max-width:
|
|
912
|
+
max-width: var(--container-width);
|
|
648
913
|
margin: 0 auto;
|
|
649
914
|
background: var(--container-bg);
|
|
650
915
|
padding: 60px 80px;
|
|
@@ -652,7 +917,7 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
652
917
|
box-shadow: var(--shadow);
|
|
653
918
|
}
|
|
654
919
|
.presentation-container, .pdf-container {
|
|
655
|
-
max-width:
|
|
920
|
+
max-width: var(--container-width);
|
|
656
921
|
margin: 0 auto;
|
|
657
922
|
}
|
|
658
923
|
.presentation-container .metadata-summary, .pdf-container .metadata-summary {
|
|
@@ -700,34 +965,51 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
700
965
|
h3 { font-size: 1.5em; }
|
|
701
966
|
|
|
702
967
|
p { margin-bottom: 1.3em; }
|
|
968
|
+
p.empty-paragraph { margin: 0; min-height: 1em; }
|
|
703
969
|
|
|
704
|
-
ul, ol { margin:
|
|
705
|
-
li { margin-bottom: 0.
|
|
970
|
+
ul, ol { margin: 1em 0; padding-left: 2em; }
|
|
971
|
+
li { margin-bottom: 0.25em; }
|
|
972
|
+
li > p { margin-bottom: 0.25em; }
|
|
706
973
|
|
|
707
974
|
.table-container {
|
|
708
|
-
width:
|
|
975
|
+
width: fit-content;
|
|
976
|
+
max-width: 100%;
|
|
709
977
|
overflow-x: auto;
|
|
710
978
|
-webkit-overflow-scrolling: touch;
|
|
711
|
-
margin: 25px
|
|
979
|
+
margin: 25px auto;
|
|
980
|
+
border: 1px solid var(--border-color);
|
|
981
|
+
border-radius: 8px;
|
|
982
|
+
background: white;
|
|
712
983
|
}
|
|
713
984
|
table {
|
|
714
985
|
width: auto;
|
|
715
986
|
max-width: 100%;
|
|
716
987
|
min-width: ${isSpreadsheet ? '100%' : '300px'};
|
|
717
|
-
border-collapse:
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
border
|
|
721
|
-
overflow: hidden;
|
|
988
|
+
border-collapse: separate;
|
|
989
|
+
border-spacing: 0;
|
|
990
|
+
margin: 0;
|
|
991
|
+
border: none;
|
|
722
992
|
}
|
|
723
993
|
th, td {
|
|
724
|
-
padding: 12px
|
|
994
|
+
padding: 8px 12px;
|
|
725
995
|
border-bottom: 1px solid var(--border-color);
|
|
726
996
|
border-right: 1px solid var(--border-color);
|
|
727
997
|
text-align: left;
|
|
728
998
|
vertical-align: top;
|
|
729
999
|
overflow-wrap: break-word;
|
|
730
1000
|
}
|
|
1001
|
+
th:last-child, td:last-child {
|
|
1002
|
+
border-right: none;
|
|
1003
|
+
}
|
|
1004
|
+
tr:last-child th, tr:last-child td {
|
|
1005
|
+
border-bottom: none;
|
|
1006
|
+
}
|
|
1007
|
+
th, td > p {
|
|
1008
|
+
margin: 0;
|
|
1009
|
+
}
|
|
1010
|
+
td > *:last-child, th > *:last-child {
|
|
1011
|
+
margin-bottom: 0;
|
|
1012
|
+
}
|
|
731
1013
|
th {
|
|
732
1014
|
background-color: #f8f9fa;
|
|
733
1015
|
color: var(--primary-color);
|
|
@@ -739,7 +1021,6 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
739
1021
|
top: 0;
|
|
740
1022
|
z-index: 10;
|
|
741
1023
|
}
|
|
742
|
-
tr:last-child td { border-bottom: none; }
|
|
743
1024
|
tr:nth-child(even) { background-color: #fdfdfd; }
|
|
744
1025
|
tr:hover { background-color: #f1f4f9; }
|
|
745
1026
|
|
|
@@ -757,8 +1038,99 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
757
1038
|
padding: 8px 12px;
|
|
758
1039
|
font-size: 13px;
|
|
759
1040
|
white-space: nowrap;
|
|
1041
|
+
}
|
|
1042
|
+
/* Spreadsheet Grid styling */
|
|
1043
|
+
.excel-grid {
|
|
1044
|
+
border-collapse: collapse;
|
|
1045
|
+
border-spacing: 0;
|
|
1046
|
+
background: var(--container-bg);
|
|
1047
|
+
border: 1px solid var(--border-color);
|
|
1048
|
+
width: max-content;
|
|
1049
|
+
max-width: none;
|
|
1050
|
+
min-width: 0;
|
|
1051
|
+
}
|
|
1052
|
+
.excel-grid th, .excel-grid td {
|
|
1053
|
+
border: 1px solid var(--border-color);
|
|
1054
|
+
padding: 4px 8px;
|
|
1055
|
+
font-size: 13px;
|
|
1056
|
+
line-height: 1.2;
|
|
1057
|
+
overflow: hidden;
|
|
1058
|
+
text-overflow: ellipsis;
|
|
1059
|
+
white-space: nowrap;
|
|
1060
|
+
}
|
|
1061
|
+
.excel-col-header {
|
|
1062
|
+
background: #f8f9fa;
|
|
1063
|
+
color: #5f6368;
|
|
1064
|
+
font-weight: 500;
|
|
1065
|
+
text-align: center;
|
|
1066
|
+
user-select: none;
|
|
1067
|
+
border-bottom: 2px solid var(--border-color);
|
|
1068
|
+
position: sticky;
|
|
1069
|
+
top: 0;
|
|
1070
|
+
z-index: 10;
|
|
760
1071
|
min-width: 100px;
|
|
761
1072
|
}
|
|
1073
|
+
.col-resizer {
|
|
1074
|
+
position: absolute;
|
|
1075
|
+
top: 0;
|
|
1076
|
+
right: 0;
|
|
1077
|
+
width: 4px;
|
|
1078
|
+
height: 100%;
|
|
1079
|
+
cursor: col-resize;
|
|
1080
|
+
user-select: none;
|
|
1081
|
+
z-index: 20;
|
|
1082
|
+
}
|
|
1083
|
+
.col-resizer:hover, .col-resizer.resizing {
|
|
1084
|
+
background: var(--accent-color, #3498db);
|
|
1085
|
+
}
|
|
1086
|
+
.excel-row-num {
|
|
1087
|
+
background: #f8f9fa;
|
|
1088
|
+
color: #5f6368;
|
|
1089
|
+
text-align: center;
|
|
1090
|
+
font-weight: 500;
|
|
1091
|
+
width: 45px;
|
|
1092
|
+
min-width: 45px !important;
|
|
1093
|
+
max-width: 45px;
|
|
1094
|
+
user-select: none;
|
|
1095
|
+
border-right: 2px solid var(--border-color);
|
|
1096
|
+
position: sticky;
|
|
1097
|
+
left: 0;
|
|
1098
|
+
z-index: 5;
|
|
1099
|
+
}
|
|
1100
|
+
.row-resizer {
|
|
1101
|
+
position: absolute;
|
|
1102
|
+
bottom: 0;
|
|
1103
|
+
left: 0;
|
|
1104
|
+
width: 100%;
|
|
1105
|
+
height: 4px;
|
|
1106
|
+
cursor: row-resize;
|
|
1107
|
+
user-select: none;
|
|
1108
|
+
z-index: 20;
|
|
1109
|
+
}
|
|
1110
|
+
.row-resizer:hover, .row-resizer.resizing {
|
|
1111
|
+
background: var(--accent-color, #3498db);
|
|
1112
|
+
}
|
|
1113
|
+
.excel-row-num-header {
|
|
1114
|
+
background: #f1f3f4;
|
|
1115
|
+
width: 45px;
|
|
1116
|
+
min-width: 45px !important;
|
|
1117
|
+
max-width: 45px;
|
|
1118
|
+
position: sticky;
|
|
1119
|
+
top: 0;
|
|
1120
|
+
left: 0;
|
|
1121
|
+
z-index: 15;
|
|
1122
|
+
border-right: 2px solid var(--border-color);
|
|
1123
|
+
border-bottom: 2px solid var(--border-color);
|
|
1124
|
+
}
|
|
1125
|
+
.excel-cell-empty {
|
|
1126
|
+
background: var(--container-bg);
|
|
1127
|
+
}
|
|
1128
|
+
.excel-grid tr:hover td {
|
|
1129
|
+
background-color: #f1f4f9;
|
|
1130
|
+
}
|
|
1131
|
+
.excel-grid tr:hover td.excel-row-num {
|
|
1132
|
+
background-color: #f8f9fa; /* Keep header color */
|
|
1133
|
+
}
|
|
762
1134
|
|
|
763
1135
|
/* Tab Bar */
|
|
764
1136
|
.spreadsheet-tabs {
|
|
@@ -792,9 +1164,9 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
792
1164
|
/* Slide & Page Separation */
|
|
793
1165
|
.slide {
|
|
794
1166
|
background: white;
|
|
795
|
-
|
|
1167
|
+
aspect-ratio: 297 / 210;
|
|
796
1168
|
margin: 0 auto 40px auto;
|
|
797
|
-
padding:
|
|
1169
|
+
padding: 4% 6%;
|
|
798
1170
|
border-radius: 12px;
|
|
799
1171
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
|
800
1172
|
position: relative;
|
|
@@ -804,21 +1176,74 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
804
1176
|
border: 1px solid var(--border-color);
|
|
805
1177
|
box-sizing: border-box;
|
|
806
1178
|
width: 100%;
|
|
1179
|
+
overflow: hidden;
|
|
1180
|
+
overflow-y: auto;
|
|
807
1181
|
overflow-wrap: break-word;
|
|
808
1182
|
page-break-after: always;
|
|
809
1183
|
}
|
|
1184
|
+
.slide:has(+ .slide-note) {
|
|
1185
|
+
margin-bottom: 0;
|
|
1186
|
+
border-bottom-left-radius: 0;
|
|
1187
|
+
border-bottom-right-radius: 0;
|
|
1188
|
+
border-bottom: none;
|
|
1189
|
+
}
|
|
1190
|
+
.slide table {
|
|
1191
|
+
width: auto;
|
|
1192
|
+
max-width: 100%;
|
|
1193
|
+
font-size: 0.85em;
|
|
1194
|
+
margin: 10px 0;
|
|
1195
|
+
}
|
|
1196
|
+
.slide th, .slide td {
|
|
1197
|
+
padding: 6px 10px;
|
|
1198
|
+
}
|
|
1199
|
+
.slide > * {
|
|
1200
|
+
flex-shrink: 0;
|
|
1201
|
+
}
|
|
1202
|
+
.slide > .table-container {
|
|
1203
|
+
flex-shrink: 1;
|
|
1204
|
+
min-height: 0;
|
|
1205
|
+
}
|
|
1206
|
+
.slide .table-container {
|
|
1207
|
+
margin: 10px auto;
|
|
1208
|
+
overflow-y: auto;
|
|
1209
|
+
}
|
|
1210
|
+
.slide .chart-container {
|
|
1211
|
+
margin: 15px auto;
|
|
1212
|
+
max-width: 100%;
|
|
1213
|
+
padding: 10px;
|
|
1214
|
+
height: 240px;
|
|
1215
|
+
box-shadow: none;
|
|
1216
|
+
border-radius: 8px;
|
|
1217
|
+
}
|
|
1218
|
+
.slide img {
|
|
1219
|
+
max-height: 200px;
|
|
1220
|
+
width: auto;
|
|
1221
|
+
margin: 10px auto;
|
|
1222
|
+
box-shadow: none;
|
|
1223
|
+
}
|
|
1224
|
+
.slide .image-container {
|
|
1225
|
+
margin: 15px 0;
|
|
1226
|
+
}
|
|
1227
|
+
.slide h1 { font-size: 1.8em; margin-top: 0.4em; margin-bottom: 0.3em; padding-bottom: 5px; }
|
|
1228
|
+
.slide h2 { font-size: 1.4em; margin-top: 0.4em; }
|
|
1229
|
+
.slide h3 { font-size: 1.25em; }
|
|
1230
|
+
.slide p { margin-bottom: 0.6em; font-size: 0.95em; }
|
|
1231
|
+
.slide li > p { margin-bottom: 0.25em; }
|
|
1232
|
+
.slide ul, .slide ol { margin: 0.6em 0; }
|
|
1233
|
+
.slide li { margin-bottom: 0.25em; }
|
|
810
1234
|
.slide-note {
|
|
811
1235
|
background: #fdfdfd;
|
|
812
1236
|
border: 1px solid var(--border-color);
|
|
813
|
-
border-
|
|
814
|
-
border-radius: 12px;
|
|
1237
|
+
border-top: 1px dashed var(--border-color);
|
|
1238
|
+
border-radius: 0 0 12px 12px;
|
|
815
1239
|
padding: 30px 50px;
|
|
816
|
-
margin:
|
|
817
|
-
|
|
1240
|
+
margin: 0 auto 40px auto;
|
|
1241
|
+
width: 100%;
|
|
1242
|
+
box-sizing: border-box;
|
|
818
1243
|
font-size: 0.95em;
|
|
819
1244
|
color: var(--text-color);
|
|
820
1245
|
position: relative;
|
|
821
|
-
box-shadow: 0
|
|
1246
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
|
822
1247
|
}
|
|
823
1248
|
.note-footnote, .note-endnote {
|
|
824
1249
|
margin: 30px auto;
|
|
@@ -848,9 +1273,9 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
848
1273
|
}
|
|
849
1274
|
.page {
|
|
850
1275
|
background: white;
|
|
851
|
-
|
|
1276
|
+
aspect-ratio: 1 / 1.4142;
|
|
852
1277
|
margin: 0 auto 40px auto;
|
|
853
|
-
padding:
|
|
1278
|
+
padding: 8% 10%;
|
|
854
1279
|
box-shadow: 0 5px 20px rgba(0,0,0,0.08);
|
|
855
1280
|
position: relative;
|
|
856
1281
|
border: 1px solid var(--border-color);
|
|
@@ -870,8 +1295,8 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
870
1295
|
|
|
871
1296
|
/* High Fidelity Presentation Mode */
|
|
872
1297
|
@media screen and (max-width: 800px) {
|
|
873
|
-
.slide { min-height: auto; padding: 40px 30px; }
|
|
874
|
-
.page { padding: 40px; }
|
|
1298
|
+
.slide { min-height: auto; aspect-ratio: auto; padding: 40px 30px; }
|
|
1299
|
+
.page { aspect-ratio: auto; padding: 40px; }
|
|
875
1300
|
}
|
|
876
1301
|
|
|
877
1302
|
/* Nested Table Styles */
|
|
@@ -880,6 +1305,8 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
880
1305
|
border-radius: 6px;
|
|
881
1306
|
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
|
|
882
1307
|
background-color: #ffffff;
|
|
1308
|
+
border: 1px solid var(--border-color);
|
|
1309
|
+
overflow: hidden;
|
|
883
1310
|
}
|
|
884
1311
|
td td {
|
|
885
1312
|
padding: 10px 14px;
|
|
@@ -999,11 +1426,23 @@ class HtmlGenerator extends BaseGenerator_js_1.BaseGenerator {
|
|
|
999
1426
|
height: auto !important;
|
|
1000
1427
|
}
|
|
1001
1428
|
}
|
|
1429
|
+
|
|
1430
|
+
/* --- Custom User CSS --- */
|
|
1431
|
+
${this.config.htmlConfig.customCss}
|
|
1002
1432
|
`;
|
|
1003
1433
|
}
|
|
1004
1434
|
slugify(text) {
|
|
1005
1435
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
1006
1436
|
}
|
|
1437
|
+
getColumnLetter(colIndex) {
|
|
1438
|
+
let temp = colIndex;
|
|
1439
|
+
let letter = '';
|
|
1440
|
+
while (temp >= 0) {
|
|
1441
|
+
letter = String.fromCharCode((temp % 26) + 65) + letter;
|
|
1442
|
+
temp = Math.floor(temp / 26) - 1;
|
|
1443
|
+
}
|
|
1444
|
+
return letter;
|
|
1445
|
+
}
|
|
1007
1446
|
escape(text) {
|
|
1008
1447
|
if (typeof text !== 'string')
|
|
1009
1448
|
return text;
|