@a3s-lab/office 0.19.0 → 0.20.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/README.md +9 -3
- package/dist/0~3635.js +23 -2
- package/dist/0~spreadsheet-editor.js +30 -14
- package/dist/4104.js +678 -273
- package/dist/6164.js +58 -58
- package/dist/internal/features/work/editors/office-color-picker.d.ts +6 -1
- package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +9 -9
- package/dist/internal/features/work/work-xlsx-cell-style-origin.d.ts +44 -0
- package/dist/internal/features/work/work-xlsx-cell-style-values.d.ts +26 -0
- package/dist/internal/features/work/work-xlsx-cell-style-writer.d.ts +4 -1
- package/dist/internal/features/work/work-xlsx-cell-styles.d.ts +2 -0
- package/dist/office-kernel.wasm +0 -0
- package/dist/styles.css +55 -0
- package/package.json +4 -1
package/dist/4104.js
CHANGED
|
@@ -3410,265 +3410,6 @@ function insertXlsxOrderedChild(parent, child, order) {
|
|
|
3410
3410
|
const anchor = directChildren(parent).find((candidate)=>order.indexOf(candidate.localName) > requested);
|
|
3411
3411
|
parent.insertBefore(child, anchor ?? null);
|
|
3412
3412
|
}
|
|
3413
|
-
const fontChildOrder = [
|
|
3414
|
-
'name',
|
|
3415
|
-
'charset',
|
|
3416
|
-
'family',
|
|
3417
|
-
'b',
|
|
3418
|
-
'i',
|
|
3419
|
-
'strike',
|
|
3420
|
-
'outline',
|
|
3421
|
-
'shadow',
|
|
3422
|
-
'condense',
|
|
3423
|
-
'extend',
|
|
3424
|
-
'color',
|
|
3425
|
-
'sz',
|
|
3426
|
-
'u',
|
|
3427
|
-
'vertAlign',
|
|
3428
|
-
'scheme'
|
|
3429
|
-
];
|
|
3430
|
-
class XlsxDirectCellStyleWriter {
|
|
3431
|
-
styles;
|
|
3432
|
-
fonts;
|
|
3433
|
-
fills;
|
|
3434
|
-
borders;
|
|
3435
|
-
cellXfs;
|
|
3436
|
-
generatedFonts = new Map();
|
|
3437
|
-
generatedFills = new Map();
|
|
3438
|
-
generatedBorders = new Map();
|
|
3439
|
-
generatedStyles = new Map();
|
|
3440
|
-
changed = false;
|
|
3441
|
-
constructor(styles){
|
|
3442
|
-
this.styles = styles;
|
|
3443
|
-
const root = styles.documentElement;
|
|
3444
|
-
this.fonts = ensureXlsxStyleCollection(styles, 'fonts', [
|
|
3445
|
-
'fills',
|
|
3446
|
-
'borders',
|
|
3447
|
-
'cellStyleXfs',
|
|
3448
|
-
'cellXfs',
|
|
3449
|
-
'cellStyles',
|
|
3450
|
-
'dxfs',
|
|
3451
|
-
'tableStyles',
|
|
3452
|
-
'colors',
|
|
3453
|
-
'extLst'
|
|
3454
|
-
]);
|
|
3455
|
-
if (!directChildren(this.fonts, 'font').length) {
|
|
3456
|
-
this.fonts.append(styles.createElementNS(root.namespaceURI, 'font'));
|
|
3457
|
-
this.changed = true;
|
|
3458
|
-
}
|
|
3459
|
-
this.fills = ensureXlsxStyleCollection(styles, 'fills', [
|
|
3460
|
-
'borders',
|
|
3461
|
-
'cellStyleXfs',
|
|
3462
|
-
'cellXfs',
|
|
3463
|
-
'cellStyles',
|
|
3464
|
-
'dxfs',
|
|
3465
|
-
'tableStyles',
|
|
3466
|
-
'colors',
|
|
3467
|
-
'extLst'
|
|
3468
|
-
]);
|
|
3469
|
-
if (!directChildren(this.fills, 'fill').length) {
|
|
3470
|
-
this.fills.append(defaultXlsxFill(styles, 'none'));
|
|
3471
|
-
this.fills.append(defaultXlsxFill(styles, 'gray125'));
|
|
3472
|
-
this.changed = true;
|
|
3473
|
-
}
|
|
3474
|
-
this.borders = ensureXlsxStyleCollection(styles, 'borders', [
|
|
3475
|
-
'cellStyleXfs',
|
|
3476
|
-
'cellXfs',
|
|
3477
|
-
'cellStyles',
|
|
3478
|
-
'dxfs',
|
|
3479
|
-
'tableStyles',
|
|
3480
|
-
'colors',
|
|
3481
|
-
'extLst'
|
|
3482
|
-
]);
|
|
3483
|
-
if (!directChildren(this.borders, 'border').length) {
|
|
3484
|
-
this.borders.append(defaultXlsxBorder(styles));
|
|
3485
|
-
this.changed = true;
|
|
3486
|
-
}
|
|
3487
|
-
this.cellXfs = ensureXlsxStyleCollection(styles, 'cellXfs', [
|
|
3488
|
-
'cellStyles',
|
|
3489
|
-
'dxfs',
|
|
3490
|
-
'tableStyles',
|
|
3491
|
-
'colors',
|
|
3492
|
-
'extLst'
|
|
3493
|
-
]);
|
|
3494
|
-
if (!directChildren(this.cellXfs, 'xf').length) {
|
|
3495
|
-
const base = styles.createElementNS(root.namespaceURI, 'xf');
|
|
3496
|
-
base.setAttribute('numFmtId', '0');
|
|
3497
|
-
base.setAttribute('fontId', '0');
|
|
3498
|
-
base.setAttribute('fillId', '0');
|
|
3499
|
-
base.setAttribute('borderId', '0');
|
|
3500
|
-
base.setAttribute('xfId', '0');
|
|
3501
|
-
this.cellXfs.append(base);
|
|
3502
|
-
this.changed = true;
|
|
3503
|
-
}
|
|
3504
|
-
this.updateCounts();
|
|
3505
|
-
}
|
|
3506
|
-
styleId(baseStyleId, cell, border) {
|
|
3507
|
-
const styles = directChildren(this.cellXfs, 'xf');
|
|
3508
|
-
const baseIndex = Number.isInteger(baseStyleId) && styles[baseStyleId] ? baseStyleId : 0;
|
|
3509
|
-
const base = styles[baseIndex];
|
|
3510
|
-
const fontId = this.fontId(work_xlsx_cell_style_writer_nonNegativeInteger(work_ooxml_package_attribute(base, 'fontId')) ?? 0, cell);
|
|
3511
|
-
const fillId = this.fillId(work_xlsx_cell_style_writer_nonNegativeInteger(work_ooxml_package_attribute(base, 'fillId')) ?? 0, cell);
|
|
3512
|
-
const borderId = this.borderId(work_xlsx_cell_style_writer_nonNegativeInteger(work_ooxml_package_attribute(base, 'borderId')) ?? 0, border);
|
|
3513
|
-
const alignment = directAlignment(cell);
|
|
3514
|
-
const key = `${baseIndex}:${fontId}:${fillId}:${borderId}:${JSON.stringify(alignment)}`;
|
|
3515
|
-
const cached = this.generatedStyles.get(key);
|
|
3516
|
-
if (void 0 !== cached) return cached;
|
|
3517
|
-
const clone = base.cloneNode(true);
|
|
3518
|
-
clone.setAttribute('fontId', String(fontId));
|
|
3519
|
-
clone.setAttribute('fillId', String(fillId));
|
|
3520
|
-
clone.setAttribute('borderId', String(borderId));
|
|
3521
|
-
if (hasXlsxDirectFontStyle(cell)) clone.setAttribute('applyFont', '1');
|
|
3522
|
-
if (void 0 !== cell.bg) clone.setAttribute('applyFill', '1');
|
|
3523
|
-
if (border) clone.setAttribute('applyBorder', '1');
|
|
3524
|
-
if (alignment) {
|
|
3525
|
-
writeXlsxAlignment(this.styles, clone, alignment);
|
|
3526
|
-
clone.setAttribute('applyAlignment', '1');
|
|
3527
|
-
}
|
|
3528
|
-
const index = styles.length;
|
|
3529
|
-
this.cellXfs.append(clone);
|
|
3530
|
-
this.generatedStyles.set(key, index);
|
|
3531
|
-
this.changed = true;
|
|
3532
|
-
this.updateCounts();
|
|
3533
|
-
return index;
|
|
3534
|
-
}
|
|
3535
|
-
fontId(baseFontId, cell) {
|
|
3536
|
-
if (!hasXlsxDirectFontStyle(cell)) return baseFontId;
|
|
3537
|
-
const fonts = directChildren(this.fonts, 'font');
|
|
3538
|
-
const baseIndex = fonts[baseFontId] ? baseFontId : 0;
|
|
3539
|
-
const style = directFontStyle(cell);
|
|
3540
|
-
const key = `${baseIndex}:${JSON.stringify(style)}`;
|
|
3541
|
-
const cached = this.generatedFonts.get(key);
|
|
3542
|
-
if (void 0 !== cached) return cached;
|
|
3543
|
-
const font = fonts[baseIndex].cloneNode(true);
|
|
3544
|
-
if (void 0 !== style.name) setXlsxValueChild(this.styles, font, 'name', style.name, fontChildOrder);
|
|
3545
|
-
if (void 0 !== style.size) setXlsxValueChild(this.styles, font, 'sz', String(style.size), fontChildOrder);
|
|
3546
|
-
if (void 0 !== style.color) setXlsxColorChild(this.styles, font, style.color, fontChildOrder);
|
|
3547
|
-
if (void 0 !== style.bold) setXlsxToggleChild(this.styles, font, 'b', style.bold, fontChildOrder);
|
|
3548
|
-
if (void 0 !== style.italic) setXlsxToggleChild(this.styles, font, 'i', style.italic, fontChildOrder);
|
|
3549
|
-
if (void 0 !== style.strike) setXlsxToggleChild(this.styles, font, 'strike', style.strike, fontChildOrder);
|
|
3550
|
-
if (void 0 !== style.underline) setXlsxUnderlineChild(this.styles, font, style.underline, fontChildOrder);
|
|
3551
|
-
const index = fonts.length;
|
|
3552
|
-
this.fonts.append(font);
|
|
3553
|
-
this.generatedFonts.set(key, index);
|
|
3554
|
-
this.changed = true;
|
|
3555
|
-
this.updateCounts();
|
|
3556
|
-
return index;
|
|
3557
|
-
}
|
|
3558
|
-
fillId(baseFillId, cell) {
|
|
3559
|
-
if (void 0 === cell.bg) return baseFillId;
|
|
3560
|
-
const color = xlsxRgbColor(cell.bg);
|
|
3561
|
-
if (!color) return baseFillId;
|
|
3562
|
-
const cached = this.generatedFills.get(color);
|
|
3563
|
-
if (void 0 !== cached) return cached;
|
|
3564
|
-
const fill = this.styles.createElementNS(this.styles.documentElement.namespaceURI, 'fill');
|
|
3565
|
-
const pattern = this.styles.createElementNS(this.styles.documentElement.namespaceURI, 'patternFill');
|
|
3566
|
-
pattern.setAttribute('patternType', 'solid');
|
|
3567
|
-
const foreground = this.styles.createElementNS(this.styles.documentElement.namespaceURI, 'fgColor');
|
|
3568
|
-
foreground.setAttribute('rgb', color);
|
|
3569
|
-
const background = this.styles.createElementNS(this.styles.documentElement.namespaceURI, 'bgColor');
|
|
3570
|
-
background.setAttribute('indexed', '64');
|
|
3571
|
-
pattern.append(foreground, background);
|
|
3572
|
-
fill.append(pattern);
|
|
3573
|
-
const index = directChildren(this.fills, 'fill').length;
|
|
3574
|
-
this.fills.append(fill);
|
|
3575
|
-
this.generatedFills.set(color, index);
|
|
3576
|
-
this.changed = true;
|
|
3577
|
-
this.updateCounts();
|
|
3578
|
-
return index;
|
|
3579
|
-
}
|
|
3580
|
-
borderId(baseBorderId, update) {
|
|
3581
|
-
if (!update) return baseBorderId;
|
|
3582
|
-
const borders = directChildren(this.borders, 'border');
|
|
3583
|
-
const baseIndex = borders[baseBorderId] ? baseBorderId : 0;
|
|
3584
|
-
const key = `${baseIndex}:${JSON.stringify(update)}`;
|
|
3585
|
-
const cached = this.generatedBorders.get(key);
|
|
3586
|
-
if (void 0 !== cached) return cached;
|
|
3587
|
-
const border = borders[baseIndex].cloneNode(true);
|
|
3588
|
-
for (const [name, line] of [
|
|
3589
|
-
[
|
|
3590
|
-
'left',
|
|
3591
|
-
update.left
|
|
3592
|
-
],
|
|
3593
|
-
[
|
|
3594
|
-
'right',
|
|
3595
|
-
update.right
|
|
3596
|
-
],
|
|
3597
|
-
[
|
|
3598
|
-
'top',
|
|
3599
|
-
update.top
|
|
3600
|
-
],
|
|
3601
|
-
[
|
|
3602
|
-
'bottom',
|
|
3603
|
-
update.bottom
|
|
3604
|
-
],
|
|
3605
|
-
[
|
|
3606
|
-
'diagonal',
|
|
3607
|
-
update.diagonal
|
|
3608
|
-
]
|
|
3609
|
-
])if (void 0 !== line) setXlsxBorderLine(this.styles, border, name, line);
|
|
3610
|
-
if (void 0 !== update.diagonalUp) border.setAttribute('diagonalUp', update.diagonalUp ? '1' : '0');
|
|
3611
|
-
if (void 0 !== update.diagonalDown) border.setAttribute('diagonalDown', update.diagonalDown ? '1' : '0');
|
|
3612
|
-
const index = borders.length;
|
|
3613
|
-
this.borders.append(border);
|
|
3614
|
-
this.generatedBorders.set(key, index);
|
|
3615
|
-
this.changed = true;
|
|
3616
|
-
this.updateCounts();
|
|
3617
|
-
return index;
|
|
3618
|
-
}
|
|
3619
|
-
updateCounts() {
|
|
3620
|
-
this.fonts.setAttribute('count', String(directChildren(this.fonts, 'font').length));
|
|
3621
|
-
this.fills.setAttribute('count', String(directChildren(this.fills, 'fill').length));
|
|
3622
|
-
this.borders.setAttribute('count', String(directChildren(this.borders, 'border').length));
|
|
3623
|
-
this.cellXfs.setAttribute('count', String(directChildren(this.cellXfs, 'xf').length));
|
|
3624
|
-
}
|
|
3625
|
-
}
|
|
3626
|
-
function hasXlsxDirectCellStyle(cell) {
|
|
3627
|
-
return Boolean(hasXlsxDirectFontStyle(cell) || void 0 !== cell.bg || void 0 !== cell.ht || void 0 !== cell.vt || void 0 !== cell.tb || void 0 !== cell.rt || void 0 !== cell.tr);
|
|
3628
|
-
}
|
|
3629
|
-
function hasXlsxDirectFontStyle(cell) {
|
|
3630
|
-
return Boolean(void 0 !== cell.bl || void 0 !== cell.it || void 0 !== cell.un || void 0 !== cell.cl || void 0 !== cell.ff || void 0 !== cell.fs || void 0 !== cell.fc);
|
|
3631
|
-
}
|
|
3632
|
-
function directFontStyle(cell) {
|
|
3633
|
-
const color = void 0 !== cell.fc ? xlsxRgbColor(cell.fc) : null;
|
|
3634
|
-
return {
|
|
3635
|
-
...void 0 !== cell.bl ? {
|
|
3636
|
-
bold: 1 === Number(cell.bl)
|
|
3637
|
-
} : {},
|
|
3638
|
-
...color ? {
|
|
3639
|
-
color
|
|
3640
|
-
} : {},
|
|
3641
|
-
...void 0 !== cell.it ? {
|
|
3642
|
-
italic: 1 === Number(cell.it)
|
|
3643
|
-
} : {},
|
|
3644
|
-
...'string' == typeof cell.ff && cell.ff.trim() ? {
|
|
3645
|
-
name: cell.ff.trim()
|
|
3646
|
-
} : {},
|
|
3647
|
-
...'number' == typeof cell.fs && Number.isFinite(cell.fs) && cell.fs > 0 ? {
|
|
3648
|
-
size: cell.fs
|
|
3649
|
-
} : {},
|
|
3650
|
-
...void 0 !== cell.cl ? {
|
|
3651
|
-
strike: 1 === Number(cell.cl)
|
|
3652
|
-
} : {},
|
|
3653
|
-
...void 0 !== cell.un ? {
|
|
3654
|
-
underline: spreadsheetUnderlineStyle(cell.un)
|
|
3655
|
-
} : {}
|
|
3656
|
-
};
|
|
3657
|
-
}
|
|
3658
|
-
function directAlignment(cell) {
|
|
3659
|
-
const alignment = {};
|
|
3660
|
-
if (void 0 !== cell.ht) alignment.horizontal = 0 === Number(cell.ht) ? 'center' : 2 === Number(cell.ht) ? 'right' : 'left';
|
|
3661
|
-
if (void 0 !== cell.vt) alignment.vertical = 0 === Number(cell.vt) ? 'center' : 1 === Number(cell.vt) ? 'top' : 'bottom';
|
|
3662
|
-
if (void 0 !== cell.tb) alignment.wrapText = '2' === cell.tb;
|
|
3663
|
-
const rotation = spreadsheetTextOrientationXlsxValueFromCell(cell);
|
|
3664
|
-
if (null !== rotation) alignment.textRotation = rotation;
|
|
3665
|
-
return Object.keys(alignment).length ? alignment : null;
|
|
3666
|
-
}
|
|
3667
|
-
function work_xlsx_cell_style_writer_nonNegativeInteger(value) {
|
|
3668
|
-
if (null === value || !/^\d+$/.test(value)) return null;
|
|
3669
|
-
const parsed = Number(value);
|
|
3670
|
-
return Number.isSafeInteger(parsed) ? parsed : null;
|
|
3671
|
-
}
|
|
3672
3413
|
const defaultThemeColors = [
|
|
3673
3414
|
'ffffff',
|
|
3674
3415
|
'000000',
|
|
@@ -3870,19 +3611,633 @@ function hslToRgb(hue, saturation, lightness) {
|
|
|
3870
3611
|
}
|
|
3871
3612
|
return channels;
|
|
3872
3613
|
}
|
|
3873
|
-
function normalizedHexColor(value) {
|
|
3874
|
-
if (!value || !/^[0-9a-f]{6,8}$/i.test(value)) return;
|
|
3875
|
-
return value.slice(-6).toLowerCase();
|
|
3614
|
+
function normalizedHexColor(value) {
|
|
3615
|
+
if (!value || !/^[0-9a-f]{6,8}$/i.test(value)) return;
|
|
3616
|
+
return value.slice(-6).toLowerCase();
|
|
3617
|
+
}
|
|
3618
|
+
function boundedInteger(value, maximum) {
|
|
3619
|
+
if (null === value || !/^\d+$/.test(value)) return null;
|
|
3620
|
+
const parsed = Number(value);
|
|
3621
|
+
return Number.isSafeInteger(parsed) && parsed <= maximum ? parsed : null;
|
|
3622
|
+
}
|
|
3623
|
+
function work_xlsx_colors_booleanAttribute(element, name) {
|
|
3624
|
+
const value = work_ooxml_package_attribute(element, name)?.trim().toLowerCase();
|
|
3625
|
+
return '1' === value || 'true' === value || 'on' === value;
|
|
3626
|
+
}
|
|
3627
|
+
const THEME_COLOR_NAMES = [
|
|
3628
|
+
'lt1',
|
|
3629
|
+
'dk1',
|
|
3630
|
+
'lt2',
|
|
3631
|
+
'dk2',
|
|
3632
|
+
'accent1',
|
|
3633
|
+
'accent2',
|
|
3634
|
+
'accent3',
|
|
3635
|
+
'accent4',
|
|
3636
|
+
'accent5',
|
|
3637
|
+
'accent6',
|
|
3638
|
+
'hlink',
|
|
3639
|
+
'folHlink'
|
|
3640
|
+
];
|
|
3641
|
+
const MAX_INDEXED_COLOR = 255;
|
|
3642
|
+
function readXlsxSemanticColorOrigin(element, colors) {
|
|
3643
|
+
if (!element || work_ooxml_package_attribute(element, 'rgb')) return;
|
|
3644
|
+
const renderedColor = resolveXlsxColor(element, colors);
|
|
3645
|
+
if (!renderedColor) return;
|
|
3646
|
+
const tint = boundedTint(work_ooxml_package_attribute(element, 'tint'));
|
|
3647
|
+
const theme = work_xlsx_cell_style_origin_boundedInteger(work_ooxml_package_attribute(element, 'theme'), THEME_COLOR_NAMES.length - 1);
|
|
3648
|
+
if (null !== theme && colors.theme[theme]) return {
|
|
3649
|
+
kind: 'theme',
|
|
3650
|
+
baseColor: `#${colors.theme[theme]}`,
|
|
3651
|
+
index: theme,
|
|
3652
|
+
renderedColor,
|
|
3653
|
+
...null === tint ? {} : {
|
|
3654
|
+
tint
|
|
3655
|
+
}
|
|
3656
|
+
};
|
|
3657
|
+
const indexed = work_xlsx_cell_style_origin_boundedInteger(work_ooxml_package_attribute(element, 'indexed'), MAX_INDEXED_COLOR);
|
|
3658
|
+
if (null !== indexed && colors.indexed[indexed]) return {
|
|
3659
|
+
kind: 'indexed',
|
|
3660
|
+
baseColor: `#${colors.indexed[indexed]}`,
|
|
3661
|
+
index: indexed,
|
|
3662
|
+
renderedColor,
|
|
3663
|
+
...null === tint ? {} : {
|
|
3664
|
+
tint
|
|
3665
|
+
}
|
|
3666
|
+
};
|
|
3667
|
+
if (xlsxBooleanAttribute(element, 'auto')) return {
|
|
3668
|
+
kind: 'automatic',
|
|
3669
|
+
baseColor: '#000000',
|
|
3670
|
+
renderedColor,
|
|
3671
|
+
...null === tint ? {} : {
|
|
3672
|
+
tint
|
|
3673
|
+
}
|
|
3674
|
+
};
|
|
3675
|
+
}
|
|
3676
|
+
function withXlsxCellStyleOrigin(cell, origin) {
|
|
3677
|
+
return origin && xlsxCellStyleOriginHasValues(origin) ? {
|
|
3678
|
+
...cell,
|
|
3679
|
+
a3sXlsxStyleOrigin: origin
|
|
3680
|
+
} : cell;
|
|
3681
|
+
}
|
|
3682
|
+
function xlsxCellStyleOrigin(cell) {
|
|
3683
|
+
const candidate = cell?.a3sXlsxStyleOrigin;
|
|
3684
|
+
if (!work_xlsx_cell_style_origin_isRecord(candidate)) return;
|
|
3685
|
+
const fontColor = normalizedXlsxSemanticColor(candidate.fontColor);
|
|
3686
|
+
const fillColor = normalizedXlsxSemanticColor(candidate.fillColor);
|
|
3687
|
+
const borderColors = normalizedBorderColors(candidate.borderColors);
|
|
3688
|
+
const origin = {
|
|
3689
|
+
...fontColor ? {
|
|
3690
|
+
fontColor
|
|
3691
|
+
} : {},
|
|
3692
|
+
...fillColor ? {
|
|
3693
|
+
fillColor
|
|
3694
|
+
} : {},
|
|
3695
|
+
...borderColors ? {
|
|
3696
|
+
borderColors
|
|
3697
|
+
} : {}
|
|
3698
|
+
};
|
|
3699
|
+
return xlsxCellStyleOriginHasValues(origin) ? origin : void 0;
|
|
3700
|
+
}
|
|
3701
|
+
function xlsxSemanticColorMatchesValue(origin, value) {
|
|
3702
|
+
return normalizedColor(value) === origin.renderedColor.toLowerCase();
|
|
3703
|
+
}
|
|
3704
|
+
function xlsxColorElementMatchesOrigin(element, origin) {
|
|
3705
|
+
if (!element || work_ooxml_package_attribute(element, 'rgb')) return false;
|
|
3706
|
+
if ('theme' === origin.kind) {
|
|
3707
|
+
if (work_ooxml_package_attribute(element, 'theme') !== String(origin.index)) return false;
|
|
3708
|
+
} else if ('indexed' === origin.kind) {
|
|
3709
|
+
if (work_ooxml_package_attribute(element, 'indexed') !== String(origin.index)) return false;
|
|
3710
|
+
} else if (!xlsxBooleanAttribute(element, 'auto')) return false;
|
|
3711
|
+
const tint = boundedTint(work_ooxml_package_attribute(element, 'tint'));
|
|
3712
|
+
return tint === (origin.tint ?? null);
|
|
3713
|
+
}
|
|
3714
|
+
function applyXlsxSemanticColorOrigin(element, origin) {
|
|
3715
|
+
for (const name of [
|
|
3716
|
+
'rgb',
|
|
3717
|
+
'theme',
|
|
3718
|
+
'indexed',
|
|
3719
|
+
'auto',
|
|
3720
|
+
'tint'
|
|
3721
|
+
])element.removeAttribute(name);
|
|
3722
|
+
if ('theme' === origin.kind) element.setAttribute('theme', String(origin.index));
|
|
3723
|
+
else if ('indexed' === origin.kind) element.setAttribute('indexed', String(origin.index));
|
|
3724
|
+
else element.setAttribute('auto', '1');
|
|
3725
|
+
if (void 0 !== origin.tint) element.setAttribute('tint', String(origin.tint));
|
|
3726
|
+
}
|
|
3727
|
+
function xlsxSemanticColorOriginKey(origin) {
|
|
3728
|
+
return origin ? `${origin.kind}:${'index' in origin ? origin.index : ''}:${origin.baseColor}:${origin.renderedColor}:${origin.tint ?? ''}` : '';
|
|
3729
|
+
}
|
|
3730
|
+
function xlsxSemanticColorOriginSupported(origin, palette) {
|
|
3731
|
+
if ('automatic' === origin.kind) return true;
|
|
3732
|
+
return palette?.[origin.kind].get(origin.index)?.toLowerCase() === origin.baseColor.toLowerCase();
|
|
3733
|
+
}
|
|
3734
|
+
function prepareXlsxSemanticPalette(styles, theme, origins) {
|
|
3735
|
+
const candidates = semanticPaletteCandidates(origins);
|
|
3736
|
+
const supportedTheme = new Map();
|
|
3737
|
+
let themeChanged = false;
|
|
3738
|
+
const scheme = theme ? firstDescendant(theme, 'clrScheme') : void 0;
|
|
3739
|
+
for (const [index, color] of candidates.theme){
|
|
3740
|
+
const name = THEME_COLOR_NAMES[index];
|
|
3741
|
+
const entry = name && scheme ? directChild(scheme, name) : void 0;
|
|
3742
|
+
if (entry) {
|
|
3743
|
+
themeChanged = writeThemeColor(entry, color) || themeChanged;
|
|
3744
|
+
supportedTheme.set(index, color);
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
const supportedIndexed = new Map();
|
|
3748
|
+
let stylesChanged = false;
|
|
3749
|
+
if (candidates.indexed.size) {
|
|
3750
|
+
const colors = ensureXlsxStyleCollection(styles, 'colors', [
|
|
3751
|
+
'extLst'
|
|
3752
|
+
]);
|
|
3753
|
+
let indexedColors = directChild(colors, 'indexedColors');
|
|
3754
|
+
if (!indexedColors) {
|
|
3755
|
+
indexedColors = styles.createElementNS(styles.documentElement.namespaceURI, 'indexedColors');
|
|
3756
|
+
colors.prepend(indexedColors);
|
|
3757
|
+
stylesChanged = true;
|
|
3758
|
+
}
|
|
3759
|
+
const resolver = createXlsxColorResolver(styles, theme);
|
|
3760
|
+
const highestIndex = Math.max(...candidates.indexed.keys());
|
|
3761
|
+
while(directChildren(indexedColors, 'rgbColor').length <= highestIndex){
|
|
3762
|
+
const index = directChildren(indexedColors, 'rgbColor').length;
|
|
3763
|
+
const element = styles.createElementNS(styles.documentElement.namespaceURI, 'rgbColor');
|
|
3764
|
+
element.setAttribute('rgb', `FF${(resolver.indexed[index] ?? '000000').toUpperCase()}`);
|
|
3765
|
+
indexedColors.append(element);
|
|
3766
|
+
stylesChanged = true;
|
|
3767
|
+
}
|
|
3768
|
+
const entries = directChildren(indexedColors, 'rgbColor');
|
|
3769
|
+
for (const [index, color] of candidates.indexed){
|
|
3770
|
+
const expected = `FF${color.slice(1).toUpperCase()}`;
|
|
3771
|
+
const entry = entries[index];
|
|
3772
|
+
if (entry) {
|
|
3773
|
+
if (work_ooxml_package_attribute(entry, 'rgb')?.toUpperCase() !== expected) {
|
|
3774
|
+
entry.setAttribute('rgb', expected);
|
|
3775
|
+
stylesChanged = true;
|
|
3776
|
+
}
|
|
3777
|
+
supportedIndexed.set(index, color);
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
return {
|
|
3782
|
+
palette: {
|
|
3783
|
+
indexed: supportedIndexed,
|
|
3784
|
+
theme: supportedTheme
|
|
3785
|
+
},
|
|
3786
|
+
stylesChanged,
|
|
3787
|
+
themeChanged
|
|
3788
|
+
};
|
|
3789
|
+
}
|
|
3790
|
+
function semanticPaletteCandidates(origins) {
|
|
3791
|
+
const theme = new Map();
|
|
3792
|
+
const indexed = new Map();
|
|
3793
|
+
const themeConflicts = new Set();
|
|
3794
|
+
const indexedConflicts = new Set();
|
|
3795
|
+
for (const origin of origins)for (const color of xlsxCellStyleOriginColors(origin)){
|
|
3796
|
+
if ('automatic' === color.kind) continue;
|
|
3797
|
+
const target = 'theme' === color.kind ? theme : indexed;
|
|
3798
|
+
const conflicts = 'theme' === color.kind ? themeConflicts : indexedConflicts;
|
|
3799
|
+
const current = target.get(color.index);
|
|
3800
|
+
if (current && current.toLowerCase() !== color.baseColor.toLowerCase()) conflicts.add(color.index);
|
|
3801
|
+
else if (!current) target.set(color.index, color.baseColor);
|
|
3802
|
+
}
|
|
3803
|
+
for (const index of themeConflicts)theme.delete(index);
|
|
3804
|
+
for (const index of indexedConflicts)indexed.delete(index);
|
|
3805
|
+
return {
|
|
3806
|
+
indexed,
|
|
3807
|
+
theme
|
|
3808
|
+
};
|
|
3809
|
+
}
|
|
3810
|
+
function xlsxCellStyleOriginColors(origin) {
|
|
3811
|
+
return [
|
|
3812
|
+
origin.fontColor,
|
|
3813
|
+
origin.fillColor,
|
|
3814
|
+
...Object.values(origin.borderColors ?? {})
|
|
3815
|
+
].filter((value)=>Boolean(value));
|
|
3816
|
+
}
|
|
3817
|
+
function writeThemeColor(entry, color) {
|
|
3818
|
+
const current = directChildren(entry)[0];
|
|
3819
|
+
if (current?.localName === 'srgbClr' && work_ooxml_package_attribute(current, 'val')?.toLowerCase() === color.slice(1).toLowerCase()) return false;
|
|
3820
|
+
for (const child of directChildren(entry))child.remove();
|
|
3821
|
+
const qualifiedName = entry.prefix ? `${entry.prefix}:srgbClr` : 'srgbClr';
|
|
3822
|
+
const replacement = entry.ownerDocument.createElementNS(entry.namespaceURI, qualifiedName);
|
|
3823
|
+
replacement.setAttribute('val', color.slice(1).toUpperCase());
|
|
3824
|
+
entry.append(replacement);
|
|
3825
|
+
return true;
|
|
3826
|
+
}
|
|
3827
|
+
function normalizedBorderColors(value) {
|
|
3828
|
+
if (!work_xlsx_cell_style_origin_isRecord(value)) return;
|
|
3829
|
+
const result = {};
|
|
3830
|
+
for (const side of [
|
|
3831
|
+
'bottom',
|
|
3832
|
+
'diagonal',
|
|
3833
|
+
'left',
|
|
3834
|
+
'right',
|
|
3835
|
+
'top'
|
|
3836
|
+
]){
|
|
3837
|
+
const color = normalizedXlsxSemanticColor(value[side]);
|
|
3838
|
+
if (color) result[side] = color;
|
|
3839
|
+
}
|
|
3840
|
+
return Object.keys(result).length ? result : void 0;
|
|
3841
|
+
}
|
|
3842
|
+
function normalizedXlsxSemanticColor(value) {
|
|
3843
|
+
if (!work_xlsx_cell_style_origin_isRecord(value)) return;
|
|
3844
|
+
const baseColor = normalizedColor(value.baseColor);
|
|
3845
|
+
const renderedColor = normalizedColor(value.renderedColor);
|
|
3846
|
+
const tint = normalizedTint(value.tint);
|
|
3847
|
+
if (!baseColor || !renderedColor || void 0 === tint) return;
|
|
3848
|
+
if ('automatic' === value.kind) return {
|
|
3849
|
+
kind: 'automatic',
|
|
3850
|
+
baseColor,
|
|
3851
|
+
renderedColor,
|
|
3852
|
+
...null === tint ? {} : {
|
|
3853
|
+
tint
|
|
3854
|
+
}
|
|
3855
|
+
};
|
|
3856
|
+
const maximum = 'theme' === value.kind ? THEME_COLOR_NAMES.length - 1 : MAX_INDEXED_COLOR;
|
|
3857
|
+
const index = boundedNumber(value.index, maximum);
|
|
3858
|
+
if ('theme' !== value.kind && 'indexed' !== value.kind || null === index) return;
|
|
3859
|
+
return {
|
|
3860
|
+
kind: value.kind,
|
|
3861
|
+
baseColor,
|
|
3862
|
+
index,
|
|
3863
|
+
renderedColor,
|
|
3864
|
+
...null === tint ? {} : {
|
|
3865
|
+
tint
|
|
3866
|
+
}
|
|
3867
|
+
};
|
|
3868
|
+
}
|
|
3869
|
+
function xlsxCellStyleOriginHasValues(origin) {
|
|
3870
|
+
return Boolean(origin.fontColor || origin.fillColor || Object.keys(origin.borderColors ?? {}).length);
|
|
3871
|
+
}
|
|
3872
|
+
function normalizedColor(value) {
|
|
3873
|
+
const rgb = xlsxRgbColor(value);
|
|
3874
|
+
return rgb ? `#${rgb.slice(-6).toLowerCase()}` : null;
|
|
3875
|
+
}
|
|
3876
|
+
function normalizedTint(value) {
|
|
3877
|
+
if (void 0 === value) return null;
|
|
3878
|
+
return 'number' == typeof value && Number.isFinite(value) && value >= -1 && value <= 1 ? value : void 0;
|
|
3879
|
+
}
|
|
3880
|
+
function boundedTint(value) {
|
|
3881
|
+
if (null === value) return null;
|
|
3882
|
+
const tint = Number(value);
|
|
3883
|
+
return Number.isFinite(tint) && tint >= -1 && tint <= 1 ? tint : null;
|
|
3884
|
+
}
|
|
3885
|
+
function work_xlsx_cell_style_origin_boundedInteger(value, maximum) {
|
|
3886
|
+
if (null === value || !/^\d+$/.test(value)) return null;
|
|
3887
|
+
return boundedNumber(Number(value), maximum);
|
|
3888
|
+
}
|
|
3889
|
+
function boundedNumber(value, maximum) {
|
|
3890
|
+
return 'number' == typeof value && Number.isSafeInteger(value) && value >= 0 && value <= maximum ? value : null;
|
|
3891
|
+
}
|
|
3892
|
+
function xlsxBooleanAttribute(element, name) {
|
|
3893
|
+
const value = work_ooxml_package_attribute(element, name)?.trim().toLowerCase();
|
|
3894
|
+
return '1' === value || 'true' === value || 'on' === value;
|
|
3895
|
+
}
|
|
3896
|
+
function work_xlsx_cell_style_origin_isRecord(value) {
|
|
3897
|
+
return 'object' == typeof value && null !== value && !Array.isArray(value);
|
|
3898
|
+
}
|
|
3899
|
+
function hasXlsxDirectFontStyle(cell) {
|
|
3900
|
+
return Boolean(void 0 !== cell.bl || void 0 !== cell.it || void 0 !== cell.un || void 0 !== cell.cl || void 0 !== cell.ff || void 0 !== cell.fs || void 0 !== cell.fc);
|
|
3901
|
+
}
|
|
3902
|
+
function directXlsxFontStyle(cell) {
|
|
3903
|
+
const color = void 0 !== cell.fc ? xlsxRgbColor(cell.fc) : null;
|
|
3904
|
+
return {
|
|
3905
|
+
...void 0 !== cell.bl ? {
|
|
3906
|
+
bold: 1 === Number(cell.bl)
|
|
3907
|
+
} : {},
|
|
3908
|
+
...color ? {
|
|
3909
|
+
color
|
|
3910
|
+
} : {},
|
|
3911
|
+
...void 0 !== cell.it ? {
|
|
3912
|
+
italic: 1 === Number(cell.it)
|
|
3913
|
+
} : {},
|
|
3914
|
+
...'string' == typeof cell.ff && cell.ff.trim() ? {
|
|
3915
|
+
name: cell.ff.trim()
|
|
3916
|
+
} : {},
|
|
3917
|
+
...'number' == typeof cell.fs && Number.isFinite(cell.fs) && cell.fs > 0 ? {
|
|
3918
|
+
size: cell.fs
|
|
3919
|
+
} : {},
|
|
3920
|
+
...void 0 !== cell.cl ? {
|
|
3921
|
+
strike: 1 === Number(cell.cl)
|
|
3922
|
+
} : {},
|
|
3923
|
+
...void 0 !== cell.un ? {
|
|
3924
|
+
underline: spreadsheetUnderlineStyle(cell.un)
|
|
3925
|
+
} : {}
|
|
3926
|
+
};
|
|
3927
|
+
}
|
|
3928
|
+
function directXlsxAlignment(cell) {
|
|
3929
|
+
const alignment = {};
|
|
3930
|
+
if (void 0 !== cell.ht) alignment.horizontal = 0 === Number(cell.ht) ? 'center' : 2 === Number(cell.ht) ? 'right' : 'left';
|
|
3931
|
+
if (void 0 !== cell.vt) alignment.vertical = 0 === Number(cell.vt) ? 'center' : 1 === Number(cell.vt) ? 'top' : 'bottom';
|
|
3932
|
+
if (void 0 !== cell.tb) alignment.wrapText = '2' === cell.tb;
|
|
3933
|
+
const rotation = spreadsheetTextOrientationXlsxValueFromCell(cell);
|
|
3934
|
+
if (null !== rotation) alignment.textRotation = rotation;
|
|
3935
|
+
return Object.keys(alignment).length ? alignment : null;
|
|
3876
3936
|
}
|
|
3877
|
-
function
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
return Number.isSafeInteger(parsed) && parsed <= maximum ? parsed : null;
|
|
3937
|
+
function xlsxStyleCollectionIndex(collection, childName, value) {
|
|
3938
|
+
const index = work_xlsx_cell_style_values_nonNegativeInteger(value) ?? 0;
|
|
3939
|
+
return directChildren(collection, childName)[index] ? index : 0;
|
|
3881
3940
|
}
|
|
3882
|
-
function
|
|
3941
|
+
function xlsxColorMatches(element, value, colors, fallback) {
|
|
3942
|
+
const rgb = xlsxRgbColor(value);
|
|
3943
|
+
const resolved = resolveXlsxColor(element, colors) ?? fallback;
|
|
3944
|
+
return Boolean(rgb && resolved && `#${rgb.slice(-6).toLowerCase()}` === resolved.toLowerCase());
|
|
3945
|
+
}
|
|
3946
|
+
function xlsxToggleEnabled(element) {
|
|
3947
|
+
if (!element) return false;
|
|
3948
|
+
const value = work_ooxml_package_attribute(element, 'val')?.trim().toLowerCase();
|
|
3949
|
+
return '0' !== value && 'false' !== value && 'off' !== value;
|
|
3950
|
+
}
|
|
3951
|
+
function xlsxUnderlineStyle(element) {
|
|
3952
|
+
return element ? spreadsheetUnderlineStyle(spreadsheetUnderlineCellValueFromXlsx(work_ooxml_package_attribute(element, 'val'))) : 'none';
|
|
3953
|
+
}
|
|
3954
|
+
function xlsxBorderLineMatches(element, line, colors, semanticColor) {
|
|
3955
|
+
const style = element ? work_ooxml_package_attribute(element, 'style') : null;
|
|
3956
|
+
if (!line) return !style;
|
|
3957
|
+
return style === line.style && (semanticColor ? xlsxColorElementMatchesOrigin(element ? directChild(element, 'color') : void 0, semanticColor) : xlsxColorMatches(element ? directChild(element, 'color') : void 0, line.color, colors, '#000000'));
|
|
3958
|
+
}
|
|
3959
|
+
function activeXlsxSemanticColorOrigin(origin, value, palette) {
|
|
3960
|
+
return origin && xlsxSemanticColorMatchesValue(origin, value) && xlsxSemanticColorOriginSupported(origin, palette) ? origin : void 0;
|
|
3961
|
+
}
|
|
3962
|
+
function work_xlsx_cell_style_values_xlsxBooleanAttribute(element, name) {
|
|
3963
|
+
if (!element) return false;
|
|
3883
3964
|
const value = work_ooxml_package_attribute(element, name)?.trim().toLowerCase();
|
|
3884
3965
|
return '1' === value || 'true' === value || 'on' === value;
|
|
3885
3966
|
}
|
|
3967
|
+
function xlsxAlignmentMatches(xf, style) {
|
|
3968
|
+
const alignment = directChild(xf, 'alignment');
|
|
3969
|
+
if (void 0 !== style.horizontal && work_ooxml_package_attribute(alignment ?? xf, 'horizontal') !== style.horizontal) return false;
|
|
3970
|
+
if (void 0 !== style.vertical && work_ooxml_package_attribute(alignment ?? xf, 'vertical') !== style.vertical) return false;
|
|
3971
|
+
if (void 0 !== style.wrapText && (!alignment || null === work_ooxml_package_attribute(alignment, 'wrapText') || work_xlsx_cell_style_values_xlsxBooleanAttribute(alignment, 'wrapText') !== style.wrapText)) return false;
|
|
3972
|
+
if (void 0 !== style.textRotation) {
|
|
3973
|
+
const rotation = work_xlsx_cell_style_values_nonNegativeInteger(alignment ? work_ooxml_package_attribute(alignment, 'textRotation') : null);
|
|
3974
|
+
if (rotation !== style.textRotation) return false;
|
|
3975
|
+
}
|
|
3976
|
+
return true;
|
|
3977
|
+
}
|
|
3978
|
+
function work_xlsx_cell_style_values_nonNegativeInteger(value) {
|
|
3979
|
+
if (null === value || !/^\d+$/.test(value)) return null;
|
|
3980
|
+
const parsed = Number(value);
|
|
3981
|
+
return Number.isSafeInteger(parsed) ? parsed : null;
|
|
3982
|
+
}
|
|
3983
|
+
const fontChildOrder = [
|
|
3984
|
+
'name',
|
|
3985
|
+
'charset',
|
|
3986
|
+
'family',
|
|
3987
|
+
'b',
|
|
3988
|
+
'i',
|
|
3989
|
+
'strike',
|
|
3990
|
+
'outline',
|
|
3991
|
+
'shadow',
|
|
3992
|
+
'condense',
|
|
3993
|
+
'extend',
|
|
3994
|
+
'color',
|
|
3995
|
+
'sz',
|
|
3996
|
+
'u',
|
|
3997
|
+
'vertAlign',
|
|
3998
|
+
'scheme'
|
|
3999
|
+
];
|
|
4000
|
+
class XlsxDirectCellStyleWriter {
|
|
4001
|
+
styles;
|
|
4002
|
+
semanticPalette;
|
|
4003
|
+
fonts;
|
|
4004
|
+
fills;
|
|
4005
|
+
borders;
|
|
4006
|
+
cellXfs;
|
|
4007
|
+
generatedFonts = new Map();
|
|
4008
|
+
generatedFills = new Map();
|
|
4009
|
+
generatedBorders = new Map();
|
|
4010
|
+
generatedStyles = new Map();
|
|
4011
|
+
colors;
|
|
4012
|
+
changed = false;
|
|
4013
|
+
constructor(styles, theme = null, semanticPalette){
|
|
4014
|
+
this.styles = styles;
|
|
4015
|
+
this.semanticPalette = semanticPalette;
|
|
4016
|
+
this.colors = createXlsxColorResolver(styles, theme);
|
|
4017
|
+
const root = styles.documentElement;
|
|
4018
|
+
this.fonts = ensureXlsxStyleCollection(styles, 'fonts', [
|
|
4019
|
+
'fills',
|
|
4020
|
+
'borders',
|
|
4021
|
+
'cellStyleXfs',
|
|
4022
|
+
'cellXfs',
|
|
4023
|
+
'cellStyles',
|
|
4024
|
+
'dxfs',
|
|
4025
|
+
'tableStyles',
|
|
4026
|
+
'colors',
|
|
4027
|
+
'extLst'
|
|
4028
|
+
]);
|
|
4029
|
+
if (!directChildren(this.fonts, 'font').length) {
|
|
4030
|
+
this.fonts.append(styles.createElementNS(root.namespaceURI, 'font'));
|
|
4031
|
+
this.changed = true;
|
|
4032
|
+
}
|
|
4033
|
+
this.fills = ensureXlsxStyleCollection(styles, 'fills', [
|
|
4034
|
+
'borders',
|
|
4035
|
+
'cellStyleXfs',
|
|
4036
|
+
'cellXfs',
|
|
4037
|
+
'cellStyles',
|
|
4038
|
+
'dxfs',
|
|
4039
|
+
'tableStyles',
|
|
4040
|
+
'colors',
|
|
4041
|
+
'extLst'
|
|
4042
|
+
]);
|
|
4043
|
+
if (!directChildren(this.fills, 'fill').length) {
|
|
4044
|
+
this.fills.append(defaultXlsxFill(styles, 'none'));
|
|
4045
|
+
this.fills.append(defaultXlsxFill(styles, 'gray125'));
|
|
4046
|
+
this.changed = true;
|
|
4047
|
+
}
|
|
4048
|
+
this.borders = ensureXlsxStyleCollection(styles, 'borders', [
|
|
4049
|
+
'cellStyleXfs',
|
|
4050
|
+
'cellXfs',
|
|
4051
|
+
'cellStyles',
|
|
4052
|
+
'dxfs',
|
|
4053
|
+
'tableStyles',
|
|
4054
|
+
'colors',
|
|
4055
|
+
'extLst'
|
|
4056
|
+
]);
|
|
4057
|
+
if (!directChildren(this.borders, 'border').length) {
|
|
4058
|
+
this.borders.append(defaultXlsxBorder(styles));
|
|
4059
|
+
this.changed = true;
|
|
4060
|
+
}
|
|
4061
|
+
this.cellXfs = ensureXlsxStyleCollection(styles, 'cellXfs', [
|
|
4062
|
+
'cellStyles',
|
|
4063
|
+
'dxfs',
|
|
4064
|
+
'tableStyles',
|
|
4065
|
+
'colors',
|
|
4066
|
+
'extLst'
|
|
4067
|
+
]);
|
|
4068
|
+
if (!directChildren(this.cellXfs, 'xf').length) {
|
|
4069
|
+
const base = styles.createElementNS(root.namespaceURI, 'xf');
|
|
4070
|
+
base.setAttribute('numFmtId', '0');
|
|
4071
|
+
base.setAttribute('fontId', '0');
|
|
4072
|
+
base.setAttribute('fillId', '0');
|
|
4073
|
+
base.setAttribute('borderId', '0');
|
|
4074
|
+
base.setAttribute('xfId', '0');
|
|
4075
|
+
this.cellXfs.append(base);
|
|
4076
|
+
this.changed = true;
|
|
4077
|
+
}
|
|
4078
|
+
this.updateCounts();
|
|
4079
|
+
}
|
|
4080
|
+
styleId(baseStyleId, cell, border) {
|
|
4081
|
+
const styles = directChildren(this.cellXfs, 'xf');
|
|
4082
|
+
const baseIndex = Number.isInteger(baseStyleId) && styles[baseStyleId] ? baseStyleId : 0;
|
|
4083
|
+
const base = styles[baseIndex];
|
|
4084
|
+
const baseFontId = xlsxStyleCollectionIndex(this.fonts, 'font', work_ooxml_package_attribute(base, 'fontId'));
|
|
4085
|
+
const baseFillId = xlsxStyleCollectionIndex(this.fills, 'fill', work_ooxml_package_attribute(base, 'fillId'));
|
|
4086
|
+
const baseBorderId = xlsxStyleCollectionIndex(this.borders, 'border', work_ooxml_package_attribute(base, 'borderId'));
|
|
4087
|
+
const origin = xlsxCellStyleOrigin(cell);
|
|
4088
|
+
const fontId = this.fontId(baseFontId, cell, origin?.fontColor);
|
|
4089
|
+
const fillId = this.fillId(baseFillId, cell, origin?.fillColor);
|
|
4090
|
+
const borderId = this.borderId(baseBorderId, border, origin?.borderColors);
|
|
4091
|
+
const alignment = directXlsxAlignment(cell);
|
|
4092
|
+
const alignmentChanged = Boolean(alignment && !xlsxAlignmentMatches(base, alignment));
|
|
4093
|
+
if (fontId === baseFontId && fillId === baseFillId && borderId === baseBorderId && !alignmentChanged) return baseIndex;
|
|
4094
|
+
const key = `${baseIndex}:${fontId}:${fillId}:${borderId}:${alignmentChanged ? JSON.stringify(alignment) : ''}`;
|
|
4095
|
+
const cached = this.generatedStyles.get(key);
|
|
4096
|
+
if (void 0 !== cached) return cached;
|
|
4097
|
+
const clone = base.cloneNode(true);
|
|
4098
|
+
clone.setAttribute('fontId', String(fontId));
|
|
4099
|
+
clone.setAttribute('fillId', String(fillId));
|
|
4100
|
+
clone.setAttribute('borderId', String(borderId));
|
|
4101
|
+
if (fontId !== baseFontId) clone.setAttribute('applyFont', '1');
|
|
4102
|
+
if (fillId !== baseFillId) clone.setAttribute('applyFill', '1');
|
|
4103
|
+
if (borderId !== baseBorderId) clone.setAttribute('applyBorder', '1');
|
|
4104
|
+
if (alignment && alignmentChanged) {
|
|
4105
|
+
writeXlsxAlignment(this.styles, clone, alignment);
|
|
4106
|
+
clone.setAttribute('applyAlignment', '1');
|
|
4107
|
+
}
|
|
4108
|
+
const index = styles.length;
|
|
4109
|
+
this.cellXfs.append(clone);
|
|
4110
|
+
this.generatedStyles.set(key, index);
|
|
4111
|
+
this.changed = true;
|
|
4112
|
+
this.updateCounts();
|
|
4113
|
+
return index;
|
|
4114
|
+
}
|
|
4115
|
+
fontId(baseFontId, cell, colorOrigin) {
|
|
4116
|
+
if (!hasXlsxDirectFontStyle(cell)) return baseFontId;
|
|
4117
|
+
const fonts = directChildren(this.fonts, 'font');
|
|
4118
|
+
const baseIndex = fonts[baseFontId] ? baseFontId : 0;
|
|
4119
|
+
const style = directXlsxFontStyle(cell);
|
|
4120
|
+
const base = fonts[baseIndex];
|
|
4121
|
+
const semanticColor = activeXlsxSemanticColorOrigin(colorOrigin, style.color, this.semanticPalette);
|
|
4122
|
+
const nameChanged = void 0 !== style.name && work_ooxml_package_attribute(directChild(base, 'name') ?? base, 'val')?.trim() !== style.name;
|
|
4123
|
+
const sizeChanged = void 0 !== style.size && Number(work_ooxml_package_attribute(directChild(base, 'sz') ?? base, 'val')) !== style.size;
|
|
4124
|
+
const colorChanged = void 0 !== style.color && (semanticColor ? !xlsxColorElementMatchesOrigin(directChild(base, 'color'), semanticColor) : !xlsxColorMatches(directChild(base, 'color'), style.color, this.colors, '#000000'));
|
|
4125
|
+
const boldChanged = void 0 !== style.bold && xlsxToggleEnabled(directChild(base, 'b')) !== style.bold;
|
|
4126
|
+
const italicChanged = void 0 !== style.italic && xlsxToggleEnabled(directChild(base, 'i')) !== style.italic;
|
|
4127
|
+
const strikeChanged = void 0 !== style.strike && xlsxToggleEnabled(directChild(base, 'strike')) !== style.strike;
|
|
4128
|
+
const underlineChanged = void 0 !== style.underline && xlsxUnderlineStyle(directChild(base, 'u')) !== style.underline;
|
|
4129
|
+
if (!nameChanged && !sizeChanged && !colorChanged && !boldChanged && !italicChanged && !strikeChanged && !underlineChanged) return baseIndex;
|
|
4130
|
+
const key = `${baseIndex}:${JSON.stringify(style)}:${xlsxSemanticColorOriginKey(semanticColor)}`;
|
|
4131
|
+
const cached = this.generatedFonts.get(key);
|
|
4132
|
+
if (void 0 !== cached) return cached;
|
|
4133
|
+
const font = base.cloneNode(true);
|
|
4134
|
+
if (nameChanged && void 0 !== style.name) setXlsxValueChild(this.styles, font, 'name', style.name, fontChildOrder);
|
|
4135
|
+
if (sizeChanged && void 0 !== style.size) setXlsxValueChild(this.styles, font, 'sz', String(style.size), fontChildOrder);
|
|
4136
|
+
if (colorChanged && void 0 !== style.color) {
|
|
4137
|
+
setXlsxColorChild(this.styles, font, style.color, fontChildOrder);
|
|
4138
|
+
const color = directChild(font, 'color');
|
|
4139
|
+
if (color && semanticColor) applyXlsxSemanticColorOrigin(color, semanticColor);
|
|
4140
|
+
}
|
|
4141
|
+
if (boldChanged && void 0 !== style.bold) setXlsxToggleChild(this.styles, font, 'b', style.bold, fontChildOrder);
|
|
4142
|
+
if (italicChanged && void 0 !== style.italic) setXlsxToggleChild(this.styles, font, 'i', style.italic, fontChildOrder);
|
|
4143
|
+
if (strikeChanged && void 0 !== style.strike) setXlsxToggleChild(this.styles, font, 'strike', style.strike, fontChildOrder);
|
|
4144
|
+
if (underlineChanged && void 0 !== style.underline) setXlsxUnderlineChild(this.styles, font, style.underline, fontChildOrder);
|
|
4145
|
+
const index = fonts.length;
|
|
4146
|
+
this.fonts.append(font);
|
|
4147
|
+
this.generatedFonts.set(key, index);
|
|
4148
|
+
this.changed = true;
|
|
4149
|
+
this.updateCounts();
|
|
4150
|
+
return index;
|
|
4151
|
+
}
|
|
4152
|
+
fillId(baseFillId, cell, colorOrigin) {
|
|
4153
|
+
if (void 0 === cell.bg) return baseFillId;
|
|
4154
|
+
const color = xlsxRgbColor(cell.bg);
|
|
4155
|
+
if (!color) return baseFillId;
|
|
4156
|
+
const fills = directChildren(this.fills, 'fill');
|
|
4157
|
+
const baseIndex = fills[baseFillId] ? baseFillId : 0;
|
|
4158
|
+
const basePattern = directChild(fills[baseIndex], 'patternFill');
|
|
4159
|
+
const semanticColor = activeXlsxSemanticColorOrigin(colorOrigin, color, this.semanticPalette);
|
|
4160
|
+
if ('solid' === work_ooxml_package_attribute(basePattern ?? fills[baseIndex], 'patternType') && (semanticColor ? xlsxColorElementMatchesOrigin(directChild(basePattern ?? fills[baseIndex], 'fgColor'), semanticColor) : xlsxColorMatches(directChild(basePattern ?? fills[baseIndex], 'fgColor'), color, this.colors))) return baseIndex;
|
|
4161
|
+
const key = `${color}:${xlsxSemanticColorOriginKey(semanticColor)}`;
|
|
4162
|
+
const cached = this.generatedFills.get(key);
|
|
4163
|
+
if (void 0 !== cached) return cached;
|
|
4164
|
+
const fill = this.styles.createElementNS(this.styles.documentElement.namespaceURI, 'fill');
|
|
4165
|
+
const pattern = this.styles.createElementNS(this.styles.documentElement.namespaceURI, 'patternFill');
|
|
4166
|
+
pattern.setAttribute('patternType', 'solid');
|
|
4167
|
+
const foreground = this.styles.createElementNS(this.styles.documentElement.namespaceURI, 'fgColor');
|
|
4168
|
+
foreground.setAttribute('rgb', color);
|
|
4169
|
+
if (semanticColor) applyXlsxSemanticColorOrigin(foreground, semanticColor);
|
|
4170
|
+
const background = this.styles.createElementNS(this.styles.documentElement.namespaceURI, 'bgColor');
|
|
4171
|
+
background.setAttribute('indexed', '64');
|
|
4172
|
+
pattern.append(foreground, background);
|
|
4173
|
+
fill.append(pattern);
|
|
4174
|
+
const index = directChildren(this.fills, 'fill').length;
|
|
4175
|
+
this.fills.append(fill);
|
|
4176
|
+
this.generatedFills.set(key, index);
|
|
4177
|
+
this.changed = true;
|
|
4178
|
+
this.updateCounts();
|
|
4179
|
+
return index;
|
|
4180
|
+
}
|
|
4181
|
+
borderId(baseBorderId, update, colorOrigins) {
|
|
4182
|
+
if (!update) return baseBorderId;
|
|
4183
|
+
const borders = directChildren(this.borders, 'border');
|
|
4184
|
+
const baseIndex = borders[baseBorderId] ? baseBorderId : 0;
|
|
4185
|
+
const base = borders[baseIndex];
|
|
4186
|
+
const lineUpdates = [
|
|
4187
|
+
[
|
|
4188
|
+
'left',
|
|
4189
|
+
update.left
|
|
4190
|
+
],
|
|
4191
|
+
[
|
|
4192
|
+
'right',
|
|
4193
|
+
update.right
|
|
4194
|
+
],
|
|
4195
|
+
[
|
|
4196
|
+
'top',
|
|
4197
|
+
update.top
|
|
4198
|
+
],
|
|
4199
|
+
[
|
|
4200
|
+
'bottom',
|
|
4201
|
+
update.bottom
|
|
4202
|
+
],
|
|
4203
|
+
[
|
|
4204
|
+
'diagonal',
|
|
4205
|
+
update.diagonal
|
|
4206
|
+
]
|
|
4207
|
+
];
|
|
4208
|
+
const lineChanged = lineUpdates.some(([name, line])=>void 0 !== line && !xlsxBorderLineMatches(directChild(base, name), line, this.colors, line ? activeXlsxSemanticColorOrigin(colorOrigins?.[name], line.color, this.semanticPalette) : void 0));
|
|
4209
|
+
const diagonalUpChanged = void 0 !== update.diagonalUp && work_xlsx_cell_style_values_xlsxBooleanAttribute(base, 'diagonalUp') !== update.diagonalUp;
|
|
4210
|
+
const diagonalDownChanged = void 0 !== update.diagonalDown && work_xlsx_cell_style_values_xlsxBooleanAttribute(base, 'diagonalDown') !== update.diagonalDown;
|
|
4211
|
+
if (!lineChanged && !diagonalUpChanged && !diagonalDownChanged) return baseIndex;
|
|
4212
|
+
const key = `${baseIndex}:${JSON.stringify(update)}:${JSON.stringify(colorOrigins ?? {})}`;
|
|
4213
|
+
const cached = this.generatedBorders.get(key);
|
|
4214
|
+
if (void 0 !== cached) return cached;
|
|
4215
|
+
const border = base.cloneNode(true);
|
|
4216
|
+
for (const [name, line] of lineUpdates)if (void 0 !== line && !xlsxBorderLineMatches(directChild(base, name), line, this.colors, line ? activeXlsxSemanticColorOrigin(colorOrigins?.[name], line.color, this.semanticPalette) : void 0)) {
|
|
4217
|
+
setXlsxBorderLine(this.styles, border, name, line);
|
|
4218
|
+
const semanticColor = line ? activeXlsxSemanticColorOrigin(colorOrigins?.[name], line.color, this.semanticPalette) : void 0;
|
|
4219
|
+
const color = directChild(directChild(border, name) ?? border, 'color');
|
|
4220
|
+
if (color && semanticColor) applyXlsxSemanticColorOrigin(color, semanticColor);
|
|
4221
|
+
}
|
|
4222
|
+
if (diagonalUpChanged && void 0 !== update.diagonalUp) border.setAttribute('diagonalUp', update.diagonalUp ? '1' : '0');
|
|
4223
|
+
if (diagonalDownChanged && void 0 !== update.diagonalDown) border.setAttribute('diagonalDown', update.diagonalDown ? '1' : '0');
|
|
4224
|
+
const index = borders.length;
|
|
4225
|
+
this.borders.append(border);
|
|
4226
|
+
this.generatedBorders.set(key, index);
|
|
4227
|
+
this.changed = true;
|
|
4228
|
+
this.updateCounts();
|
|
4229
|
+
return index;
|
|
4230
|
+
}
|
|
4231
|
+
updateCounts() {
|
|
4232
|
+
this.fonts.setAttribute('count', String(directChildren(this.fonts, 'font').length));
|
|
4233
|
+
this.fills.setAttribute('count', String(directChildren(this.fills, 'fill').length));
|
|
4234
|
+
this.borders.setAttribute('count', String(directChildren(this.borders, 'border').length));
|
|
4235
|
+
this.cellXfs.setAttribute('count', String(directChildren(this.cellXfs, 'xf').length));
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
function hasXlsxDirectCellStyle(cell) {
|
|
4239
|
+
return Boolean(hasXlsxDirectFontStyle(cell) || void 0 !== cell.bg || void 0 !== cell.ht || void 0 !== cell.vt || void 0 !== cell.tb || void 0 !== cell.rt || void 0 !== cell.tr);
|
|
4240
|
+
}
|
|
3886
4241
|
const xlsxCellBorderStyles = new Set([
|
|
3887
4242
|
'dashDot',
|
|
3888
4243
|
'dashDotDot',
|
|
@@ -3913,10 +4268,12 @@ function readXlsxDirectCellStyles(worksheet, styles, theme = null) {
|
|
|
3913
4268
|
if (!coordinate || !xf) return [];
|
|
3914
4269
|
const style = readDirectCellStyle(xf, fonts, fills, colors);
|
|
3915
4270
|
const border = readDirectCellBorder(xf, borders, colors);
|
|
4271
|
+
const origin = readDirectCellStyleOrigin(xf, fonts, fills, borders, colors);
|
|
3916
4272
|
return Object.keys(style).length || border ? [
|
|
3917
4273
|
{
|
|
3918
4274
|
...coordinate,
|
|
3919
4275
|
border,
|
|
4276
|
+
origin,
|
|
3920
4277
|
style
|
|
3921
4278
|
}
|
|
3922
4279
|
] : [];
|
|
@@ -3961,6 +4318,43 @@ function readDirectCellStyle(xf, fonts, fills, colors) {
|
|
|
3961
4318
|
if (alignment) readDirectAlignmentStyle(style, alignment);
|
|
3962
4319
|
return style;
|
|
3963
4320
|
}
|
|
4321
|
+
function readDirectCellStyleOrigin(xf, fonts, fills, borders, colors) {
|
|
4322
|
+
const fontId = work_xlsx_cell_styles_nonNegativeInteger(work_ooxml_package_attribute(xf, 'fontId')) ?? 0;
|
|
4323
|
+
const font = fonts[fontId];
|
|
4324
|
+
const fontColor = font && (0 !== fontId || work_xlsx_cell_styles_booleanAttribute(xf, 'applyFont')) ? readXlsxSemanticColorOrigin(directChild(font, 'color'), colors) : void 0;
|
|
4325
|
+
const fillId = work_xlsx_cell_styles_nonNegativeInteger(work_ooxml_package_attribute(xf, 'fillId')) ?? 0;
|
|
4326
|
+
const fill = fills[fillId];
|
|
4327
|
+
const pattern = fill ? directChild(fill, 'patternFill') : void 0;
|
|
4328
|
+
const fillColor = pattern && 'solid' === work_ooxml_package_attribute(pattern, 'patternType') && (0 !== fillId || work_xlsx_cell_styles_booleanAttribute(xf, 'applyFill')) ? readXlsxSemanticColorOrigin(directChild(pattern, 'fgColor'), colors) : void 0;
|
|
4329
|
+
const borderId = work_xlsx_cell_styles_nonNegativeInteger(work_ooxml_package_attribute(xf, 'borderId')) ?? 0;
|
|
4330
|
+
const border = borders[borderId];
|
|
4331
|
+
const borderColors = {};
|
|
4332
|
+
if (border && (0 !== borderId || work_xlsx_cell_styles_booleanAttribute(xf, 'applyBorder'))) for (const side of [
|
|
4333
|
+
'bottom',
|
|
4334
|
+
'diagonal',
|
|
4335
|
+
'left',
|
|
4336
|
+
'right',
|
|
4337
|
+
'top'
|
|
4338
|
+
]){
|
|
4339
|
+
const line = directChild(border, side);
|
|
4340
|
+
const lineStyle = line ? work_ooxml_package_attribute(line, 'style') : null;
|
|
4341
|
+
if (!line || !lineStyle || !xlsxCellBorderStyles.has(lineStyle)) continue;
|
|
4342
|
+
const color = readXlsxSemanticColorOrigin(directChild(line, 'color'), colors);
|
|
4343
|
+
if (color) borderColors[side] = color;
|
|
4344
|
+
}
|
|
4345
|
+
if (!fontColor && !fillColor && !Object.keys(borderColors).length) return;
|
|
4346
|
+
return {
|
|
4347
|
+
...fontColor ? {
|
|
4348
|
+
fontColor
|
|
4349
|
+
} : {},
|
|
4350
|
+
...fillColor ? {
|
|
4351
|
+
fillColor
|
|
4352
|
+
} : {},
|
|
4353
|
+
...Object.keys(borderColors).length ? {
|
|
4354
|
+
borderColors
|
|
4355
|
+
} : {}
|
|
4356
|
+
};
|
|
4357
|
+
}
|
|
3964
4358
|
function readDirectFontStyle(style, font, colors) {
|
|
3965
4359
|
const bold = directChild(font, 'b');
|
|
3966
4360
|
if (bold && toggleEnabled(bold)) style.bl = 1;
|
|
@@ -6381,8 +6775,10 @@ async function patchXlsxSheetFeatures(buffer, content) {
|
|
|
6381
6775
|
const worksheetParts = await work_xlsx_interop_readWorksheetParts(archive);
|
|
6382
6776
|
const zip = await jszip.loadAsync(buffer);
|
|
6383
6777
|
const styles = archive.has('xl/styles.xml') ? await archive.xml('xl/styles.xml') : null;
|
|
6778
|
+
const theme = archive.has('xl/theme/theme1.xml') ? await archive.xml('xl/theme/theme1.xml') : null;
|
|
6779
|
+
const semanticPalette = styles ? prepareXlsxSemanticPalette(styles, theme, spreadsheetXlsxStyleOrigins(content)) : void 0;
|
|
6384
6780
|
const differentialFormats = styles ? new XlsxDifferentialFormatWriter(styles) : void 0;
|
|
6385
|
-
const directCellStyles = styles ? new XlsxDirectCellStyleWriter(styles) : void 0;
|
|
6781
|
+
const directCellStyles = styles ? new XlsxDirectCellStyleWriter(styles, theme, semanticPalette?.palette) : void 0;
|
|
6386
6782
|
const cellProtection = styles ? new XlsxCellProtectionWriter(styles) : void 0;
|
|
6387
6783
|
for (const sheet of sheets){
|
|
6388
6784
|
const pageBreaks = sheet.id ? pageBreaksBySheetId.get(sheet.id) : void 0;
|
|
@@ -6402,12 +6798,21 @@ async function patchXlsxSheetFeatures(buffer, content) {
|
|
|
6402
6798
|
writeXlsxManualPageBreaks(document1, pageBreaks);
|
|
6403
6799
|
zip.file(partPath, new XMLSerializer().serializeToString(document1));
|
|
6404
6800
|
}
|
|
6405
|
-
if (styles && (differentialFormats?.changed || directCellStyles?.changed || cellProtection?.changed)) zip.file('xl/styles.xml', new XMLSerializer().serializeToString(styles));
|
|
6801
|
+
if (styles && (differentialFormats?.changed || directCellStyles?.changed || cellProtection?.changed || semanticPalette?.stylesChanged)) zip.file('xl/styles.xml', new XMLSerializer().serializeToString(styles));
|
|
6802
|
+
if (theme && semanticPalette?.themeChanged) zip.file('xl/theme/theme1.xml', new XMLSerializer().serializeToString(theme));
|
|
6406
6803
|
return zip.generateAsync({
|
|
6407
6804
|
type: 'arraybuffer',
|
|
6408
6805
|
compression: 'DEFLATE'
|
|
6409
6806
|
});
|
|
6410
6807
|
}
|
|
6808
|
+
function spreadsheetXlsxStyleOrigins(content) {
|
|
6809
|
+
const origins = [];
|
|
6810
|
+
for (const sheet of content.sheets)for (const [, row] of sparseArrayEntries(sheet.data))for (const [, cell] of sparseArrayEntries(row)){
|
|
6811
|
+
const origin = xlsxCellStyleOrigin(cell);
|
|
6812
|
+
if (origin) origins.push(origin);
|
|
6813
|
+
}
|
|
6814
|
+
return origins;
|
|
6815
|
+
}
|
|
6411
6816
|
async function work_xlsx_interop_readWorksheetParts(archive, workbookDocument) {
|
|
6412
6817
|
if (!archive.has('xl/workbook.xml')) return new Map();
|
|
6413
6818
|
const workbook = workbookDocument ?? await archive.xml('xl/workbook.xml');
|
|
@@ -8320,7 +8725,7 @@ async function importWorkSpreadsheetFile(file, extension, context) {
|
|
|
8320
8725
|
const directCellStyle = directCellStyles.get(spreadsheetCellKey(row, column));
|
|
8321
8726
|
directCellStyles.delete(spreadsheetCellKey(row, column));
|
|
8322
8727
|
data[row] ??= [];
|
|
8323
|
-
data[row][column] = freezeImportedSpreadsheetCell(fortuneCellFromXlsx(source, row, column, id, hyperlink, comment, XLSX, directCellStyle?.style));
|
|
8728
|
+
data[row][column] = freezeImportedSpreadsheetCell(withXlsxCellStyleOrigin(fortuneCellFromXlsx(source, row, column, id, hyperlink, comment, XLSX, directCellStyle?.style), directCellStyle?.origin));
|
|
8324
8729
|
if (source.f) formulaCells.push({
|
|
8325
8730
|
column,
|
|
8326
8731
|
row
|
|
@@ -8333,15 +8738,15 @@ async function importWorkSpreadsheetFile(file, extension, context) {
|
|
|
8333
8738
|
}
|
|
8334
8739
|
releaseImportedWorksheetCells(worksheet);
|
|
8335
8740
|
}
|
|
8336
|
-
for (const { column, row, style } of directCellStyles.values()){
|
|
8741
|
+
for (const { column, origin, row, style } of directCellStyles.values()){
|
|
8337
8742
|
rowCount = Math.max(rowCount, row + 1);
|
|
8338
8743
|
columnCount = Math.max(columnCount, column + 1);
|
|
8339
8744
|
data[row] ??= [];
|
|
8340
8745
|
const existing = data[row][column];
|
|
8341
|
-
data[row][column] = freezeImportedSpreadsheetCell({
|
|
8746
|
+
data[row][column] = freezeImportedSpreadsheetCell(withXlsxCellStyleOrigin({
|
|
8342
8747
|
...existing ?? {},
|
|
8343
8748
|
...style
|
|
8344
|
-
});
|
|
8749
|
+
}, origin));
|
|
8345
8750
|
if (!existing) entryIndex += 1;
|
|
8346
8751
|
}
|
|
8347
8752
|
populatedCellCount += entryIndex;
|