@file-viewer/doc 2.1.27 → 2.1.29

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.
@@ -1,5 +1,6 @@
1
- import type { MsDocParseOptions, MsDocParseResult, TableRowBlock } from '../types.js';
1
+ import type { MsDocParseOptions, MsDocParseResult, ParagraphModel, TableRowBlock } from '../types.js';
2
2
  export declare function finalizeTableGrid(rows: TableRowBlock[]): void;
3
+ export declare function normalizeRowEndOnlyTables(paragraphs: ParagraphModel[]): void;
3
4
  /**
4
5
  * Main MS-DOC entry point.
5
6
  * It parses the OLE container, restores text through the piece table, resolves
@@ -360,6 +360,30 @@ export function finalizeTableGrid(rows) {
360
360
  }
361
361
  }
362
362
  }
363
+ // HTML tables need one shared column grid even when Word stores a different
364
+ // TDefTable boundary list per row (usually because cells are merged). Map
365
+ // every visible cell back onto the union of physical boundaries so colspan
366
+ // preserves the original geometry instead of squeezing later row cells.
367
+ const boundaries = Array.from(new Set(rows.flatMap((row) => row.cells.flatMap((cell) => {
368
+ const left = cell.meta?.leftBoundary;
369
+ const right = cell.meta?.rightBoundary;
370
+ return [left, right].filter((value) => value != null);
371
+ })))).sort((left, right) => left - right);
372
+ if (boundaries.length > 1) {
373
+ for (const row of rows) {
374
+ for (const cell of row.cells) {
375
+ if (!cell.meta)
376
+ continue;
377
+ const leftIndex = boundaries.indexOf(cell.meta.leftBoundary ?? Number.NaN);
378
+ const rightIndex = boundaries.indexOf(cell.meta.rightBoundary ?? Number.NaN);
379
+ if (leftIndex >= 0)
380
+ cell.colIndex = leftIndex;
381
+ if (!cell.hidden && leftIndex >= 0 && rightIndex > leftIndex) {
382
+ cell.colspan = rightIndex - leftIndex;
383
+ }
384
+ }
385
+ }
386
+ }
363
387
  }
364
388
  function resolveTableGridBorders(rows) {
365
389
  const hasOwnBorder = (borders, side) => (Object.prototype.hasOwnProperty.call(borders, side) && (() => {
@@ -400,7 +424,37 @@ function paragraphToBlock(paragraph) {
400
424
  text: paragraph.text,
401
425
  };
402
426
  }
403
- function normalizeRowEndOnlyTables(paragraphs) {
427
+ function tableGridSignature(paragraph) {
428
+ const cells = applyTableStateToCells(paragraph.tableState);
429
+ if (!cells.length)
430
+ return '';
431
+ const state = paragraph.tableState;
432
+ const border = (side) => {
433
+ const value = state.borders?.[side];
434
+ return `${value?.borderType ?? ''}:${value?.lineWidth ?? ''}:${value?.nil ? 1 : 0}`;
435
+ };
436
+ return [
437
+ cells[0]?.leftBoundary ?? '',
438
+ cells[cells.length - 1]?.rightBoundary ?? '',
439
+ state.alignment ?? '',
440
+ state.leftIndent ?? '',
441
+ state.gapHalf ?? '',
442
+ state.rtl ? 1 : 0,
443
+ border('top'),
444
+ border('left'),
445
+ border('bottom'),
446
+ border('right'),
447
+ border('horizontalInside'),
448
+ border('verticalInside'),
449
+ ].join('|');
450
+ }
451
+ function inheritRowEndTableState(paragraph, rowEnd) {
452
+ paragraph.paraState.inTable = true;
453
+ paragraph.paraState.itap = Math.max(rowEnd.paraState.itap || 1, paragraph.paraState.itap || 0);
454
+ paragraph.tableState = rowEnd.tableState;
455
+ paragraph.tableProps = rowEnd.tableProps;
456
+ }
457
+ export function normalizeRowEndOnlyTables(paragraphs) {
404
458
  for (let index = 0; index < paragraphs.length; index += 1) {
405
459
  const rowEnd = paragraphs[index];
406
460
  const cellCount = applyTableStateToCells(rowEnd.tableState).length;
@@ -409,18 +463,40 @@ function normalizeRowEndOnlyTables(paragraphs) {
409
463
  rowEnd.paraState.inTable = true;
410
464
  rowEnd.paraState.itap = Math.max(1, rowEnd.paraState.itap || 0);
411
465
  let remainingCells = cellCount;
412
- for (let cursor = index - 1; cursor >= 0 && remainingCells > 0; cursor -= 1) {
466
+ let cursor = index - 1;
467
+ const rowParagraphs = [];
468
+ for (; cursor >= 0 && remainingCells > 0; cursor -= 1) {
413
469
  const paragraph = paragraphs[cursor];
414
470
  if (paragraph.paraState.tableRowEnd || paragraph.paraState.innerTableRowEnd)
415
471
  break;
416
- if (paragraph.terminator !== DOC_CONTROL.cellMark)
417
- break;
418
- paragraph.paraState.inTable = true;
419
- paragraph.paraState.itap = Math.max(rowEnd.paraState.itap || 1, paragraph.paraState.itap || 0);
420
- paragraph.tableState = rowEnd.tableState;
421
- paragraph.tableProps = rowEnd.tableProps;
422
- remainingCells -= 1;
472
+ rowParagraphs.push(paragraph);
473
+ if (paragraph.terminator === DOC_CONTROL.cellMark)
474
+ remainingCells -= 1;
475
+ }
476
+ if (remainingCells > 0)
477
+ continue;
478
+ // Some Word/WPS producers store all table properties only on the row-end
479
+ // PAPX. Paragraph marks inside a cell then look like ordinary paragraphs.
480
+ // When the immediately preceding row has the same outer grid and table
481
+ // border identity, everything between the two row terminators belongs to
482
+ // the current row, including leading paragraphs in its first cell.
483
+ let previousRowEndIndex = cursor;
484
+ while (previousRowEndIndex >= 0
485
+ && !paragraphs[previousRowEndIndex].paraState.tableRowEnd
486
+ && !paragraphs[previousRowEndIndex].paraState.innerTableRowEnd
487
+ && paragraphs[previousRowEndIndex].terminator !== DOC_CONTROL.cellMark) {
488
+ previousRowEndIndex -= 1;
489
+ }
490
+ const previousRowEnd = paragraphs[previousRowEndIndex];
491
+ if (previousRowEnd?.paraState.tableRowEnd
492
+ && tableGridSignature(previousRowEnd) === tableGridSignature(rowEnd)) {
493
+ for (let leading = previousRowEndIndex + 1; leading < index; leading += 1) {
494
+ const paragraph = paragraphs[leading];
495
+ if (!rowParagraphs.includes(paragraph))
496
+ rowParagraphs.push(paragraph);
497
+ }
423
498
  }
499
+ rowParagraphs.forEach((paragraph) => inheritRowEndTableState(paragraph, rowEnd));
424
500
  }
425
501
  }
426
502
  function buildTableBlock(tableParagraphs) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/doc",
3
- "version": "2.1.27",
3
+ "version": "2.1.29",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Browser-native legacy MS-DOC (.doc) parser and HTML renderer extracted from the public msdoc-viewer 0.2.0 line.",