svelte-rtf-editor 1.2.0 → 1.3.0
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/dist/rtf-parser.js +54 -10
- package/package.json +1 -1
package/dist/rtf-parser.js
CHANGED
|
@@ -228,14 +228,19 @@ export function rtfToHtml(rtfString) {
|
|
|
228
228
|
let fontTable = new Map();
|
|
229
229
|
let currentParagraph = '';
|
|
230
230
|
let paragraphs = [];
|
|
231
|
+
let paragraphAligns = [];
|
|
231
232
|
let paragraphHasText = false;
|
|
232
233
|
let paragraphHasListMarker = false;
|
|
234
|
+
// Paragraph alignment (reset by \pard, affects cells and paragraphs)
|
|
235
|
+
let currentAlign = 'left';
|
|
233
236
|
// Table state
|
|
234
237
|
let tableRows = [];
|
|
235
238
|
let currentRowCells = [];
|
|
236
239
|
let currentRowIsHeader = false;
|
|
237
240
|
let currentRowCellRights = [];
|
|
241
|
+
let currentRowCellAligns = [];
|
|
238
242
|
let inTableCell = false;
|
|
243
|
+
let pendingBottomBorder = false; // set by \clbrdrb, confirmed by a real border type
|
|
239
244
|
// First pass: extract color table and font table from the root group
|
|
240
245
|
const rootGroup = tree.children[0]?.type === 'group' ? tree.children[0] : tree;
|
|
241
246
|
for (let i = 0; i < rootGroup.children.length; i++) {
|
|
@@ -343,15 +348,18 @@ export function rtfToHtml(rtfString) {
|
|
|
343
348
|
const right = row.cellRights[ci] ?? total;
|
|
344
349
|
const pct = ((right - prevRight) / total * 100).toFixed(1);
|
|
345
350
|
prevRight = right;
|
|
351
|
+
const align = row.cellAligns[ci] ?? 'left';
|
|
352
|
+
const alignStyle = align !== 'left' ? `;text-align:${align}` : '';
|
|
346
353
|
const style = row.isHeader
|
|
347
|
-
? `border-bottom:1px solid;padding:2px 6px;text-align
|
|
348
|
-
: `padding:2px 6px;width:${pct}
|
|
354
|
+
? `border-bottom:1px solid;padding:2px 6px;text-align:${align};width:${pct}%`
|
|
355
|
+
: `padding:2px 6px;width:${pct}%${alignStyle}`;
|
|
349
356
|
html += `<${tag} style="${style}">${row.cells[ci] || ''}</${tag}>`;
|
|
350
357
|
}
|
|
351
358
|
html += '</tr>';
|
|
352
359
|
}
|
|
353
360
|
html += '</table>';
|
|
354
361
|
paragraphs.push(html);
|
|
362
|
+
paragraphAligns.push('left');
|
|
355
363
|
tableRows = [];
|
|
356
364
|
}
|
|
357
365
|
function flushParagraph() {
|
|
@@ -360,14 +368,17 @@ export function rtfToHtml(rtfString) {
|
|
|
360
368
|
if (!trimmed) {
|
|
361
369
|
if (!paragraphHasListMarker) {
|
|
362
370
|
paragraphs.push(currentParagraph);
|
|
371
|
+
paragraphAligns.push(currentAlign);
|
|
363
372
|
}
|
|
364
373
|
}
|
|
365
374
|
else {
|
|
366
375
|
paragraphs.push(currentParagraph);
|
|
376
|
+
paragraphAligns.push(currentAlign);
|
|
367
377
|
}
|
|
368
378
|
currentParagraph = '';
|
|
369
379
|
paragraphHasText = false;
|
|
370
380
|
paragraphHasListMarker = false;
|
|
381
|
+
currentAlign = 'left';
|
|
371
382
|
}
|
|
372
383
|
let pendingUnicodeSkip = 0;
|
|
373
384
|
function walk(nodes) {
|
|
@@ -444,6 +455,18 @@ export function rtfToHtml(rtfString) {
|
|
|
444
455
|
if (p != null)
|
|
445
456
|
state.fontIndex = p;
|
|
446
457
|
break;
|
|
458
|
+
case 'ql':
|
|
459
|
+
currentAlign = 'left';
|
|
460
|
+
break;
|
|
461
|
+
case 'qr':
|
|
462
|
+
currentAlign = 'right';
|
|
463
|
+
break;
|
|
464
|
+
case 'qc':
|
|
465
|
+
currentAlign = 'center';
|
|
466
|
+
break;
|
|
467
|
+
case 'qj':
|
|
468
|
+
currentAlign = 'justify';
|
|
469
|
+
break;
|
|
447
470
|
case 'par':
|
|
448
471
|
if (!inTableCell)
|
|
449
472
|
flushParagraph();
|
|
@@ -452,19 +475,32 @@ export function rtfToHtml(rtfString) {
|
|
|
452
475
|
currentRowCells = [];
|
|
453
476
|
currentRowIsHeader = false;
|
|
454
477
|
currentRowCellRights = [];
|
|
478
|
+
pendingBottomBorder = false;
|
|
455
479
|
break;
|
|
456
480
|
case 'trgaph':
|
|
457
481
|
case 'trkeep':
|
|
458
482
|
case 'trleft':
|
|
459
483
|
case 'trhdr':
|
|
460
|
-
case 'brdrs':
|
|
461
|
-
case 'brdrnil':
|
|
462
484
|
case 'clbrdrr':
|
|
463
485
|
case 'clbrdrl':
|
|
464
486
|
case 'clbrdrt':
|
|
487
|
+
pendingBottomBorder = false;
|
|
465
488
|
break; // table formatting, ignored
|
|
466
489
|
case 'clbrdrb':
|
|
467
|
-
|
|
490
|
+
pendingBottomBorder = true;
|
|
491
|
+
break;
|
|
492
|
+
case 'brdrnone':
|
|
493
|
+
case 'brdrnil':
|
|
494
|
+
pendingBottomBorder = false;
|
|
495
|
+
break;
|
|
496
|
+
case 'brdrs':
|
|
497
|
+
case 'brdrdb':
|
|
498
|
+
case 'brdrth':
|
|
499
|
+
case 'brdrdot':
|
|
500
|
+
case 'brdrdash':
|
|
501
|
+
if (pendingBottomBorder)
|
|
502
|
+
currentRowIsHeader = true;
|
|
503
|
+
pendingBottomBorder = false;
|
|
468
504
|
break;
|
|
469
505
|
case 'cellx':
|
|
470
506
|
if (p != null)
|
|
@@ -475,14 +511,17 @@ export function rtfToHtml(rtfString) {
|
|
|
475
511
|
break;
|
|
476
512
|
case 'cell':
|
|
477
513
|
currentRowCells.push(currentParagraph.trim());
|
|
514
|
+
currentRowCellAligns.push(currentAlign);
|
|
478
515
|
currentParagraph = '';
|
|
479
516
|
paragraphHasText = false;
|
|
517
|
+
currentAlign = 'left';
|
|
480
518
|
break;
|
|
481
519
|
case 'row':
|
|
482
|
-
tableRows.push({ cells: currentRowCells, isHeader: currentRowIsHeader, cellRights: currentRowCellRights });
|
|
520
|
+
tableRows.push({ cells: currentRowCells, isHeader: currentRowIsHeader, cellRights: currentRowCellRights, cellAligns: currentRowCellAligns });
|
|
483
521
|
currentRowCells = [];
|
|
484
522
|
currentRowIsHeader = false;
|
|
485
523
|
currentRowCellRights = [];
|
|
524
|
+
currentRowCellAligns = [];
|
|
486
525
|
inTableCell = false;
|
|
487
526
|
break;
|
|
488
527
|
case 'pard':
|
|
@@ -490,6 +529,7 @@ export function rtfToHtml(rtfString) {
|
|
|
490
529
|
state.italic = false;
|
|
491
530
|
state.underline = false;
|
|
492
531
|
state.strike = false;
|
|
532
|
+
currentAlign = 'left';
|
|
493
533
|
break;
|
|
494
534
|
case 'line':
|
|
495
535
|
currentParagraph += '<br>';
|
|
@@ -535,6 +575,7 @@ export function rtfToHtml(rtfString) {
|
|
|
535
575
|
case 'page':
|
|
536
576
|
flushParagraph();
|
|
537
577
|
paragraphs.push('<hr>');
|
|
578
|
+
paragraphAligns.push('left');
|
|
538
579
|
break;
|
|
539
580
|
case 'emspace':
|
|
540
581
|
case 'enspace':
|
|
@@ -608,6 +649,7 @@ export function rtfToHtml(rtfString) {
|
|
|
608
649
|
const isListLine = (text) => /^[-\u2022]/.test(text.replace(/^ +/g, ''));
|
|
609
650
|
for (let i = 0; i < trimmedParagraphs.length; i++) {
|
|
610
651
|
const trimmed = trimmedParagraphs[i];
|
|
652
|
+
const align = paragraphAligns[i] ?? 'left';
|
|
611
653
|
const prev = i > 0 ? trimmedParagraphs[i - 1] : '';
|
|
612
654
|
const next = i + 1 < trimmedParagraphs.length ? trimmedParagraphs[i + 1] : '';
|
|
613
655
|
if (!trimmed) {
|
|
@@ -632,20 +674,22 @@ export function rtfToHtml(rtfString) {
|
|
|
632
674
|
const sizeMatch = trimmed.match(/font-size:\s*([\d.]+)pt/);
|
|
633
675
|
if (sizeMatch) {
|
|
634
676
|
const pt = parseFloat(sizeMatch[1]);
|
|
677
|
+
const alignAttr = align !== 'left' ? ` style="text-align:${align}"` : '';
|
|
635
678
|
if (pt >= 24) {
|
|
636
|
-
rendered.push(`<h1>${stripSizeSpan(trimmed)}</h1>`);
|
|
679
|
+
rendered.push(`<h1${alignAttr}>${stripSizeSpan(trimmed)}</h1>`);
|
|
637
680
|
continue;
|
|
638
681
|
}
|
|
639
682
|
if (pt >= 18) {
|
|
640
|
-
rendered.push(`<h2>${stripSizeSpan(trimmed)}</h2>`);
|
|
683
|
+
rendered.push(`<h2${alignAttr}>${stripSizeSpan(trimmed)}</h2>`);
|
|
641
684
|
continue;
|
|
642
685
|
}
|
|
643
686
|
if (pt >= 14) {
|
|
644
|
-
rendered.push(`<h3>${stripSizeSpan(trimmed)}</h3>`);
|
|
687
|
+
rendered.push(`<h3${alignAttr}>${stripSizeSpan(trimmed)}</h3>`);
|
|
645
688
|
continue;
|
|
646
689
|
}
|
|
647
690
|
}
|
|
648
|
-
|
|
691
|
+
const pStyle = align !== 'left' ? ` style="text-align:${align}"` : '';
|
|
692
|
+
rendered.push(`<p${pStyle}>${trimmed}</p>`);
|
|
649
693
|
}
|
|
650
694
|
const output = rendered.join('\n');
|
|
651
695
|
// fontTable is parsed (for future font rendering) but not yet used in output
|
package/package.json
CHANGED