Fanu2 commited on
Commit
26da80c
·
1 Parent(s): 8fcb3b7

Updated design and layout

Browse files
Files changed (1) hide show
  1. index.html +262 -287
index.html CHANGED
@@ -2,147 +2,147 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>HTML Table Extractor to DOC</title>
 
7
  <style>
8
  :root {
9
  --primary: #6366f1;
10
  --primary-dark: #4f46e5;
11
- --bg: #f8fafc;
12
  --surface: #ffffff;
13
- --text: #1e293b;
14
- --text-muted: #64748b;
15
- --border: #e2e8f0;
16
- --success: #10b981;
17
  --error: #ef4444;
18
- --radius: 0.75rem;
19
- --shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
20
- --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
21
  }
22
 
23
  * {
24
  box-sizing: border-box;
25
- margin: 0;
26
- padding: 0;
27
  }
28
 
29
  body {
30
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
 
31
  background: var(--bg);
32
  color: var(--text);
33
  line-height: 1.6;
34
- min-height: 100vh;
35
- display: grid;
36
- place-items: center;
37
- padding: 2rem;
38
  }
39
 
40
- .app-container {
41
  width: 100%;
42
- max-width: 900px;
43
- margin: 0 auto;
44
  }
45
 
46
- .header {
47
  text-align: center;
48
- margin-bottom: 3rem;
49
- }
50
-
51
- .header h1 {
52
- font-size: 2.5rem;
53
- font-weight: 700;
54
- background: linear-gradient(135deg, var(--primary), var(--primary-dark));
55
- -webkit-background-clip: text;
56
- -webkit-text-fill-color: transparent;
57
- background-clip: text;
58
- margin-bottom: 0.5rem;
59
  }
60
 
61
- .header p {
62
- color: var(--text-muted);
63
- font-size: 1.125rem;
 
64
  }
65
 
66
  .card {
67
  background: var(--surface);
68
- border: 1px solid var(--border);
69
  border-radius: var(--radius);
70
  box-shadow: var(--shadow);
71
  padding: 2rem;
72
- transition: box-shadow 0.3s ease;
73
  }
74
 
75
- .card:hover {
76
- box-shadow: var(--shadow-lg);
77
- }
78
-
79
- .upload-area {
80
  border: 2px dashed var(--border);
81
  border-radius: var(--radius);
82
- padding: 3rem;
83
  text-align: center;
84
- transition: all 0.3s ease;
85
  cursor: pointer;
86
- position: relative;
87
  }
88
 
89
- .upload-area:hover,
90
- .upload-area.dragover {
 
 
 
 
91
  border-color: var(--primary);
92
- background: linear-gradient(135deg, transparent 0%, rgba(99, 102, 241, 0.05) 100%);
93
  }
94
 
95
  .upload-icon {
96
- width: 64px;
97
- height: 64px;
98
- margin: 0 auto 1rem;
99
- fill: var(--primary);
100
  }
101
 
102
  .upload-text {
103
  font-size: 1.125rem;
104
  font-weight: 600;
105
- margin-bottom: 0.5rem;
106
  }
107
 
108
  .upload-hint {
109
- color: var(--text-muted);
110
- font-size: 0.875rem;
111
  }
112
 
113
  .file-input {
114
- position: absolute;
115
- inset: 0;
116
- opacity: 0;
117
- cursor: pointer;
 
 
118
  }
119
 
120
- .preview-section {
 
 
 
 
 
 
 
 
 
 
121
  margin-top: 2rem;
122
- display: none;
 
 
123
  }
124
 
125
- .preview-section.show {
 
 
126
  display: block;
127
- animation: fadeIn 0.3s ease;
128
  }
129
 
130
- @keyframes fadeIn {
131
- from {
132
- opacity: 0;
133
- transform: translateY(-10px);
134
- }
135
- to {
136
- opacity: 1;
137
- transform: translateY(0);
138
- }
139
  }
140
 
141
- .table-container {
 
 
 
 
 
 
142
  overflow-x: auto;
143
- margin: 2rem 0;
144
- border: 1px solid var(--border);
145
- border-radius: var(--radius);
146
  }
147
 
148
  table {
@@ -153,300 +153,275 @@
153
 
154
  th, td {
155
  padding: 0.75rem;
156
- text-align: left;
157
  border-bottom: 1px solid var(--border);
 
158
  }
159
 
160
  th {
161
- background: var(--bg);
162
  font-weight: 600;
163
- color: var(--text);
164
- }
165
-
166
- tr:hover {
167
- background: rgba(99, 102, 241, 0.05);
168
  }
169
 
170
  .btn {
171
- display: inline-flex;
172
- align-items: center;
173
- justify-content: center;
174
- gap: 0.5rem;
175
- padding: 0.75rem 1.5rem;
176
  border: none;
177
- border-radius: var(--radius);
 
178
  font-size: 1rem;
179
- font-weight: 500;
180
  cursor: pointer;
181
- transition: all 0.3s ease;
182
- text-decoration: none;
183
- }
184
-
185
- .btn-primary {
186
- background: var(--primary);
187
- color: white;
188
  }
189
 
190
- .btn-primary:hover {
191
  background: var(--primary-dark);
192
- transform: translateY(-1px);
193
- box-shadow: var(--shadow);
194
- }
195
-
196
- .btn:disabled {
197
- opacity: 0.5;
198
- cursor: not-allowed;
199
- transform: none;
200
  }
201
 
202
- .error {
203
- background: rgba(239, 68, 68, 0.1);
204
- border: 1px solid var(--error);
205
- color: var(--error);
206
- padding: 1rem;
207
- border-radius: var(--radius);
208
  margin-top: 1rem;
209
- display: none;
210
- }
211
-
212
- .success {
213
- background: rgba(16, 185, 129, 0.1);
214
- border: 1px solid var(--success);
215
- color: var(--success);
216
  padding: 1rem;
217
  border-radius: var(--radius);
218
- margin-top: 1rem;
219
- display: none;
220
  }
221
 
222
- .loading {
223
- display: none;
224
- text-align: center;
225
- padding: 2rem;
226
  }
227
 
228
- .spinner {
229
- width: 40px;
230
- height: 40px;
231
- border: 4px solid var(--border);
232
- border-top-color: var(--primary);
233
- border-radius: 50%;
234
- animation: spin 1s linear infinite;
235
- margin: 0 auto;
236
  }
237
 
238
- @keyframes spin {
239
- to { transform: rotate(360deg); }
 
240
  }
241
 
242
- @media (max-width: 640px) {
243
- body {
244
- padding: 1rem;
245
- }
246
-
247
- .header h1 {
248
- font-size: 2rem;
249
  }
250
 
251
  .card {
252
  padding: 1.5rem;
253
  }
254
 
255
- .upload-area {
256
- padding: 2rem;
257
  }
258
  }
259
  </style>
260
  </head>
261
  <body>
262
- <div class="app-container">
263
- <div class="header">
264
- <h1>HTML Table Extractor</h1>
265
- <p>Convert your HTML tables to Word documents easily</p>
266
- </div>
267
 
268
  <div class="card">
269
- <div class="upload-area" id="uploadArea">
270
- <svg class="upload-icon" viewBox="0 0 24 24">
271
- <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20M13,13V7H11V13H8L12,17L16,13H13Z" />
272
- </svg>
273
- <div class="upload-text">Drop HTML file here or click to browse</div>
274
- <div class="upload-hint">Supports .html and .htm files</div>
275
- <input type="file" id="fileInput" class="file-input" accept=".html,.htm">
276
- </div>
277
-
278
- <div class="loading" id="loading">
279
- <div class="spinner"></div>
280
- <p>Processing file...</p>
281
- </div>
282
-
283
- <div class="error" id="error"></div>
284
- <div class="success" id="success"></div>
285
-
286
- <div class="preview-section" id="previewSection">
287
- <h3>Extracted Table (First 7 columns)</h3>
288
- <div class="table-container">
 
 
 
289
  <table id="previewTable"></table>
290
  </div>
291
- <button class="btn btn-primary" id="downloadBtn">
292
- <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
293
- <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20M14,12L10,16H12.5V21H15.5V16H18L14,12Z" />
294
- </svg>
295
- Download as Word (.docx)
296
  </button>
297
- </div>
298
  </div>
299
  </div>
300
 
301
- <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
302
- <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
303
  <script>
304
- const uploadArea = document.getElementById('uploadArea');
305
  const fileInput = document.getElementById('fileInput');
306
- const loading = document.getElementById('loading');
307
- const error = document.getElementById('error');
308
- const success = document.getElementById('success');
309
- const previewSection = document.getElementById('previewSection');
310
  const previewTable = document.getElementById('previewTable');
311
  const downloadBtn = document.getElementById('downloadBtn');
 
 
312
 
313
- let currentDf = null;
314
 
315
- // File upload handlers
316
- uploadArea.addEventListener('click', () => fileInput.click());
317
- uploadArea.addEventListener('dragover', handleDragOver);
318
- uploadArea.addEventListener('drop', handleDrop);
319
- uploadArea.addEventListener('dragleave', handleDragLeave);
320
- fileInput.addEventListener('change', handleFileSelect);
321
 
322
- function handleDragOver(e) {
323
  e.preventDefault();
324
- uploadArea.classList.add('dragover');
325
- }
326
 
327
- function handleDragLeave(e) {
328
- e.preventDefault();
329
- uploadArea.classList.remove('dragover');
330
- }
331
 
332
- function handleDrop(e) {
333
  e.preventDefault();
334
- uploadArea.classList.remove('dragover');
335
- const file = e.dataTransfer.files[0];
336
- if (file) processFile(file);
337
- }
338
-
339
- function handleFileSelect(e) {
340
- const file = e.target.files[0];
341
- if (file) processFile(file);
342
- }
343
-
344
- async function processFile(file) {
345
- if (!file.name.endsWith('.html') && !file.name.endsWith('.htm')) {
346
- showError('Please upload a valid HTML file.');
347
- return;
348
  }
 
349
 
350
- try {
351
- loading.style.display = 'block';
352
- uploadArea.style.display = 'none';
353
-
354
- const content = await file.text();
355
- const df = htmlTableToDf(content);
356
 
357
- if (df === null) {
358
- showError('No table found in the uploaded HTML file.');
359
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
  }
361
-
362
- currentDf = df;
363
- displayTable(df);
364
- showSuccess('File processed successfully!');
365
- } catch (err) {
366
- showError('Error processing file: ' + err.message);
367
- } finally {
368
- loading.style.display = 'none';
369
- }
370
  }
371
 
372
- function htmlTableToDf(htmlContent) {
373
  const parser = new DOMParser();
374
- const doc = parser.parseFromString(htmlContent, 'text/html');
375
- const table = doc.querySelector('table');
376
-
377
- if (!table) return null;
378
-
379
- const rows = Array.from(table.querySelectorAll('tr'));
380
- const data = rows.map(row => {
381
- const cells = Array.from(row.querySelectorAll('td, th'));
382
- return cells.slice(0, 7).map(cell => cell.textContent.trim());
383
  });
384
-
385
- return data;
386
  }
387
 
388
- function displayTable(data) {
 
 
 
 
 
389
  previewTable.innerHTML = '';
390
-
391
- const thead = document.createElement('thead');
392
- const tbody = document.createElement('tbody');
393
-
394
- data.forEach((row, index) => {
395
  const tr = document.createElement('tr');
396
- row.forEach(cell => {
397
- const cellElement = index === 0 ? document.createElement('th') : document.createElement('td');
398
- cellElement.textContent = cell;
399
- tr.appendChild(cellElement);
400
  });
401
-
402
- if (index === 0) {
403
- thead.appendChild(tr);
404
- } else {
 
 
 
 
 
 
 
 
405
  tbody.appendChild(tr);
406
  }
407
- });
408
-
409
- previewTable.appendChild(thead);
410
- previewTable.appendChild(tbody);
411
- previewSection.classList.add('show');
412
  }
413
 
 
 
 
414
  downloadBtn.addEventListener('click', () => {
415
- if (!currentDf) return;
 
 
 
416
 
417
- const doc = createDocx(currentDf);
418
- saveAs(doc, 'extracted_table.docx');
419
  });
420
 
421
- function createDocx(data) {
422
- const doc = new docx.Document();
423
-
424
- const table = doc.addTable({
425
- rows: data.length,
426
- columns: data[0].length,
427
- });
428
-
429
- data.forEach((row, rowIndex) => {
430
- row.forEach((cell, cellIndex) => {
431
- const cellObj = table.getCell(rowIndex, cellIndex);
432
- cellObj.addParagraph(cell);
433
  });
 
434
  });
 
435
 
436
- return docx.Packer.toBlob(doc);
437
- }
438
-
439
- function showError(message) {
440
- error.textContent = message;
441
- error.style.display = 'block';
442
- setTimeout(() => error.style.display = 'none', 5000);
 
 
443
  }
444
 
445
- function showSuccess(message) {
446
- success.textContent = message;
447
- success.style.display = 'block';
448
- setTimeout(() => success.style.display = 'none', 3000);
449
  }
450
  </script>
451
  </body>
452
- </html>
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>HTML Table to Word Converter</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
  <style>
9
  :root {
10
  --primary: #6366f1;
11
  --primary-dark: #4f46e5;
12
+ --bg: #f9fafb;
13
  --surface: #ffffff;
14
+ --text: #111827;
15
+ --muted: #6b7280;
16
+ --border: #e5e7eb;
 
17
  --error: #ef4444;
18
+ --success: #10b981;
19
+ --radius: 12px;
20
+ --shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
21
  }
22
 
23
  * {
24
  box-sizing: border-box;
 
 
25
  }
26
 
27
  body {
28
+ margin: 0;
29
+ font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
30
  background: var(--bg);
31
  color: var(--text);
32
  line-height: 1.6;
33
+ display: flex;
34
+ justify-content: center;
35
+ padding: 2rem 1rem;
 
36
  }
37
 
38
+ .app {
39
  width: 100%;
40
+ max-width: 640px;
 
41
  }
42
 
43
+ header {
44
  text-align: center;
45
+ margin-bottom: 2rem;
 
 
 
 
 
 
 
 
 
 
46
  }
47
 
48
+ h1 {
49
+ font-size: 2.25rem;
50
+ font-weight: 800;
51
+ margin: 0;
52
  }
53
 
54
  .card {
55
  background: var(--surface);
 
56
  border-radius: var(--radius);
57
  box-shadow: var(--shadow);
58
  padding: 2rem;
 
59
  }
60
 
61
+ .upload-zone {
 
 
 
 
62
  border: 2px dashed var(--border);
63
  border-radius: var(--radius);
64
+ padding: 3rem 2rem;
65
  text-align: center;
66
+ transition: border-color 0.3s, background-color 0.3s;
67
  cursor: pointer;
 
68
  }
69
 
70
+ .upload-zone:hover {
71
+ border-color: var(--primary);
72
+ background-color: #f3f4ff;
73
+ }
74
+
75
+ .upload-zone.dragover {
76
  border-color: var(--primary);
77
+ background-color: #e0e7ff;
78
  }
79
 
80
  .upload-icon {
81
+ font-size: 3rem;
82
+ color: var(--muted);
83
+ margin-bottom: 0.5rem;
 
84
  }
85
 
86
  .upload-text {
87
  font-size: 1.125rem;
88
  font-weight: 600;
89
+ margin: 0;
90
  }
91
 
92
  .upload-hint {
93
+ color: var(--muted);
94
+ margin-top: 0.5rem;
95
  }
96
 
97
  .file-input {
98
+ display: none;
99
+ }
100
+
101
+ .success {
102
+ color: var(--success);
103
+ font-weight: 600;
104
  }
105
 
106
+ .error {
107
+ color: var(--error);
108
+ font-weight: 600;
109
+ }
110
+
111
+ .info {
112
+ color: var(--muted);
113
+ margin-top: 0.5rem;
114
+ }
115
+
116
+ .controls {
117
  margin-top: 2rem;
118
+ display: flex;
119
+ flex-direction: column;
120
+ gap: 1rem;
121
  }
122
 
123
+ label {
124
+ font-weight: 600;
125
+ margin-bottom: 0.5rem;
126
  display: block;
 
127
  }
128
 
129
+ input[type="number"] {
130
+ width: 100%;
131
+ padding: 0.75rem;
132
+ border: 1px solid var(--border);
133
+ border-radius: 8px;
134
+ font-size: 1rem;
 
 
 
135
  }
136
 
137
+ input[type="number"]:focus {
138
+ border-color: var(--primary);
139
+ outline: none;
140
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
141
+ }
142
+
143
+ .preview {
144
  overflow-x: auto;
145
+ margin-top: 2rem;
 
 
146
  }
147
 
148
  table {
 
153
 
154
  th, td {
155
  padding: 0.75rem;
 
156
  border-bottom: 1px solid var(--border);
157
+ text-align: left;
158
  }
159
 
160
  th {
161
+ background-color: #f3f4f6;
162
  font-weight: 600;
 
 
 
 
 
163
  }
164
 
165
  .btn {
166
+ background: var(--primary);
167
+ color: #fff;
 
 
 
168
  border: none;
169
+ padding: 0.75rem 1.5rem;
170
+ border-radius: 8px;
171
  font-size: 1rem;
172
+ font-weight: 600;
173
  cursor: pointer;
174
+ transition: background-color 0.3s;
175
+ display: inline-flex;
176
+ align-items: center;
177
+ gap: 0.5rem;
 
 
 
178
  }
179
 
180
+ .btn:hover {
181
  background: var(--primary-dark);
 
 
 
 
 
 
 
 
182
  }
183
 
184
+ .status {
 
 
 
 
 
185
  margin-top: 1rem;
 
 
 
 
 
 
 
186
  padding: 1rem;
187
  border-radius: var(--radius);
 
 
188
  }
189
 
190
+ .status.success {
191
+ background: #ecfdf5;
192
+ color: var(--success);
 
193
  }
194
 
195
+ .status.error {
196
+ background: #fef2f2;
197
+ color: var(--error);
 
 
 
 
 
198
  }
199
 
200
+ .status.info {
201
+ background: #f3f4f6;
202
+ color: var(--muted);
203
  }
204
 
205
+ @media (max-width: 600px) {
206
+ h1 {
207
+ font-size: 1.75rem;
 
 
 
 
208
  }
209
 
210
  .card {
211
  padding: 1.5rem;
212
  }
213
 
214
+ .upload-zone {
215
+ padding: 2rem 1rem;
216
  }
217
  }
218
  </style>
219
  </head>
220
  <body>
221
+ <div class="app">
222
+ <header>
223
+ <h1>HTML Table to Word Converter</h1>
224
+ </header>
 
225
 
226
  <div class="card">
227
+ <form id="uploadForm">
228
+ <div class="upload-zone" id="dropZone">
229
+ <i class="fas fa-cloud-upload-alt upload-icon"></i>
230
+ <p class="upload-text">Upload HTML File</p>
231
+ <p class="upload-hint">Drag & drop or click to select</p>
232
+ <input type="file" id="fileInput" class="file-input" accept=".html,.htm" />
233
+ </div>
234
+
235
+ <div id="status" class="status" style="display: none;"></div>
236
+
237
+ <div id="controls" class="controls" style="display: none;">
238
+ <div>
239
+ <label for="skipRows">Rows to skip (from top)</label>
240
+ <input type="number" id="skipRows" min="0" value="1" />
241
+ </div>
242
+ <div>
243
+ <label for="numColumns">Number of columns to import</label>
244
+ <input type="number" id="numColumns" min="1" max="50" value="8" />
245
+ </div>
246
+ </div>
247
+
248
+ <div id="preview" class="preview" style="display: none;">
249
+ <h2>Extracted Table Preview</h2>
250
  <table id="previewTable"></table>
251
  </div>
252
+
253
+ <button type="button" id="downloadBtn" class="btn" style="display: none;">
254
+ <i class="fas fa-download"></i>Download as Word (.docx)
 
 
255
  </button>
256
+ </form>
257
  </div>
258
  </div>
259
 
 
 
260
  <script>
 
261
  const fileInput = document.getElementById('fileInput');
262
+ const dropZone = document.getElementById('dropZone');
263
+ const statusDiv = document.getElementById('status');
264
+ const controlsDiv = document.getElementById('controls');
265
+ const previewDiv = document.getElementById('preview');
266
  const previewTable = document.getElementById('previewTable');
267
  const downloadBtn = document.getElementById('downloadBtn');
268
+ const skipRowsInput = document.getElementById('skipRows');
269
+ const numColumnsInput = document.getElementById('numColumns');
270
 
271
+ let extractedTable = null;
272
 
273
+ dropZone.addEventListener('click', () => fileInput.click());
 
 
 
 
 
274
 
275
+ dropZone.addEventListener('dragover', (e) => {
276
  e.preventDefault();
277
+ dropZone.classList.add('dragover');
278
+ });
279
 
280
+ dropZone.addEventListener('dragleave', () => {
281
+ dropZone.classList.remove('dragover');
282
+ });
 
283
 
284
+ dropZone.addEventListener('drop', (e) => {
285
  e.preventDefault();
286
+ dropZone.classList.remove('dragover');
287
+ const files = e.dataTransfer.files;
288
+ if (files.length) {
289
+ handleFile(files[0]);
 
 
 
 
 
 
 
 
 
 
290
  }
291
+ });
292
 
293
+ fileInput.addEventListener('change', () => {
294
+ const file = fileInput.files[0];
295
+ if (file) {
296
+ handleFile(file);
297
+ }
298
+ });
299
 
300
+ function handleFile(file) {
301
+ const reader = new FileReader();
302
+ reader.onload = (e) => {
303
+ try {
304
+ const html = e.target.result;
305
+ const tables = extractAllTables(html);
306
+ const validTables = tables.filter(t => t && t.length && t[0].length >= 5);
307
+ if (!validTables.length) {
308
+ showStatus("No valid tables found in the uploaded HTML file.", 'error');
309
+ return;
310
+ }
311
+
312
+ const largest = validTables.reduce((max, cur) => (cur.length > max.length ? cur : max), validTables[0]);
313
+ extractedTable = largest;
314
+
315
+ const maxCols = largest[0].length;
316
+ const maxRows = largest.length;
317
+
318
+ showStatus(`Found ${validTables.length} table(s). Using the largest one with ${maxRows} rows and ${maxCols} columns.`, 'success');
319
+
320
+ skipRowsInput.max = Math.max(maxRows - 1, 0);
321
+ skipRowsInput.value = maxRows <= 1 ? 0 : 1;
322
+
323
+ numColumnsInput.max = maxCols;
324
+ numColumnsInput.value = Math.min(8, maxCols);
325
+
326
+ controlsDiv.style.display = 'block';
327
+ previewTable.innerHTML = '';
328
+ updatePreview();
329
+ } catch (err) {
330
+ showStatus("An error occurred while processing the file.", 'error');
331
+ console.error(err);
332
  }
333
+ };
334
+ reader.readAsText(file);
 
 
 
 
 
 
 
335
  }
336
 
337
+ function extractAllTables(html) {
338
  const parser = new DOMParser();
339
+ const doc = parser.parseFromString(html, 'text/html');
340
+ const tables = doc.querySelectorAll('table');
341
+ return Array.from(tables).map(table => {
342
+ const rows = Array.from(table.querySelectorAll('tr'));
343
+ return rows.map(row => {
344
+ const cells = Array.from(row.querySelectorAll('td, th'));
345
+ return cells.map(cell => cell.textContent.trim());
346
+ });
 
347
  });
 
 
348
  }
349
 
350
+ function updatePreview() {
351
+ if (!extractedTable) return;
352
+ const skip = parseInt(skipRowsInput.value, 10);
353
+ const cols = parseInt(numColumnsInput.value, 10);
354
+ const sliced = extractedTable.slice(skip).map(row => row.slice(0, cols));
355
+
356
  previewTable.innerHTML = '';
357
+ if (sliced.length > 0) {
358
+ const thead = document.createElement('thead');
 
 
 
359
  const tr = document.createElement('tr');
360
+ sliced[0].forEach(cell => {
361
+ const th = document.createElement('th');
362
+ th.textContent = cell;
363
+ tr.appendChild(th);
364
  });
365
+ thead.appendChild(tr);
366
+ previewTable.appendChild(thead);
367
+
368
+ const tbody = document.createElement('tbody');
369
+ for (let i = 1; i < sliced.length; i++) {
370
+ if (sliced[i].every(c => !c)) continue;
371
+ const tr = document.createElement('tr');
372
+ sliced[i].forEach(cell => {
373
+ const td = document.createElement('td');
374
+ td.textContent = cell;
375
+ tr.appendChild(td);
376
+ });
377
  tbody.appendChild(tr);
378
  }
379
+ previewTable.appendChild(tbody);
380
+ }
381
+
382
+ previewDiv.style.display = 'block';
383
+ downloadBtn.style.display = 'inline-flex';
384
  }
385
 
386
+ skipRowsInput.addEventListener('input', updatePreview);
387
+ numColumnsInput.addEventListener('input', updatePreview);
388
+
389
  downloadBtn.addEventListener('click', () => {
390
+ if (!extractedTable) return;
391
+ const skip = parseInt(skipRowsInput.value, 10);
392
+ const cols = parseInt(numColumnsInput.value, 10);
393
+ const sliced = extractedTable.slice(skip).map(row => row.slice(0, cols));
394
 
395
+ downloadTableAsDocx(sliced, 'extracted_table.docx');
 
396
  });
397
 
398
+ function downloadTableAsDocx(table, filename) {
399
+ let html = '<html><head><meta charset="UTF-8"></head><body><table>';
400
+ table.forEach(row => {
401
+ html += '<tr>';
402
+ row.forEach(cell => {
403
+ html += `<td>${cell}</td>`;
 
 
 
 
 
 
404
  });
405
+ html += '</tr>';
406
  });
407
+ html += '</table></body></html>';
408
 
409
+ const blob = new Blob([html], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
410
+ const url = URL.createObjectURL(blob);
411
+ const a = document.createElement('a');
412
+ a.href = url;
413
+ a.download = filename;
414
+ document.body.appendChild(a);
415
+ a.click();
416
+ document.body.removeChild(a);
417
+ URL.revokeObjectURL(url);
418
  }
419
 
420
+ function showStatus(message, type) {
421
+ statusDiv.textContent = message;
422
+ statusDiv.className = `status ${type}`;
423
+ statusDiv.style.display = 'block';
424
  }
425
  </script>
426
  </body>
427
+ </html>