@a3s-lab/office 0.36.0 → 0.37.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 +13 -6
- package/dist/0~7048.js +93 -1
- package/dist/0~spreadsheet-editor.js +388 -35
- package/dist/3266.js +366 -6
- package/dist/4121.js +1942 -1939
- package/dist/core.js +30 -3
- package/dist/internal/features/work/editors/spreadsheet-table-totals.d.ts +39 -0
- package/dist/internal/features/work/editors/spreadsheet-table.d.ts +11 -1
- package/dist/internal/features/work/work-types.d.ts +14 -0
- package/dist/internal/kernel/office-kernel-spreadsheet-fallback-formula.d.ts +11 -0
- package/dist/office-kernel.wasm +0 -0
- package/dist/office-kernel.worker.js +93 -1
- package/dist/styles.css +120 -0
- package/docs/latest/en/browser-editor-architecture.md +8 -2
- package/package.json +4 -1
|
@@ -6,7 +6,7 @@ import { Fragment as external_react_Fragment, cloneElement, memo, useCallback, u
|
|
|
6
6
|
import { convertSpanToShareString, genarate, indexToColumnChar, update as core_update } from "@fortune-sheet/core";
|
|
7
7
|
import { freezeImportedSpreadsheetCell, normalizeXlsxSemanticColorOrigin, spreadsheetMatrixProfile, withXlsxPatternFill, withoutEditableRange, normalizeSpreadsheetConditionalVisualOptions, xlsxSemanticColorMatchesValue, withXlsxGradientFill, effectiveSpreadsheetPageSetup, attachSpreadsheetShownCommentCells, normalizeXlsxPatternFill, withEditableRange, sameSpreadsheetHistoryValue, isSpreadsheetConditionalComparisonOperator, spreadsheetConditionalIconForValue, defaultSpreadsheetConditionalIconThresholds, xlsxPatternFillTypes, sheetProtectionAuthority, normalizeXlsxGradientFill, xlsxGradientFillFallbackColor, editableRangeCellCount, unlockedCellCount, registerDerivedSpreadsheetMatrix, editableRangeRequiresCredentials, SPREADSHEET_CONDITIONAL_COMPARISON_OPERATORS, normalizeSpreadsheetConditionalIconSetFormat, defaultSpreadsheetDataBarOptions, spreadsheetConditionalThresholdValue, normalizeSheetProtectionAuthority, withSheetProtection, spreadsheetProtectionKey, defaultSpreadsheetColorScaleThresholds, protectedSheetCount, SPREADSHEET_CONDITIONAL_ICON_SETS, withSheetSelectionPermissions, spreadsheetConditionalComparisonNeedsUpperValue, drawSpreadsheetConditionalIcon, spreadsheetConditionalThresholdsEqual } from "./9333.js";
|
|
8
8
|
import { workSpreadsheetChartSupportsGrouping, spreadsheetFormulaRangesForSelection, createSpreadsheetChartFromSelection, normalizeWorkSpreadsheetDataLabelPosition, normalizeSpreadsheetPrintTitleColumns, normalizeSpreadsheetPrintTitleRows, formulaHasStructuredReference, normalizeWorkSpreadsheetErrorBars, defaultPivotValueCaption, workSpreadsheetChartSupportsBarSpacing, normalizeWorkSpreadsheetChartGrouping, spreadsheetGridSize, normalizeWorkSpreadsheetChartAxisGroup, normalizeWorkSpreadsheetScatterStyle, cloneSparseMatrix, spreadsheetPivotAggregationLabel, workSpreadsheetChartAxisIsCategoryAxis, reconcileSpreadsheetChartPreviews, normalizeWorkSpreadsheetChartAxes, normalizeWorkSpreadsheetDoughnutHoleSize, normalizeWorkSpreadsheetChartLegendPosition, spreadsheetChartCount, workSpreadsheetChartTypeLabel, sparseArrayEntries, normalizeWorkSpreadsheetTrendline, effectiveSpreadsheetCalculationSettings, spreadsheetPivotIntersects, normalizeWorkSpreadsheetDataLabels, spreadsheetPivotOutputContains, normalizeSpreadsheetPrintArea, spreadsheetCellAddress, formatSpreadsheetCellRanges, normalizeWorkSpreadsheetChartLayout, spreadsheetFormulaRangeForCell, workSpreadsheetChartAxisIsValueAxis, normalizeWorkSpreadsheetChartSmoothLines, spreadsheetPivotFilterValueKey, normalizeWorkSpreadsheetBubbleScale, normalizeWorkSpreadsheetChartSeriesStyle, volatileSpreadsheetFormulaFunctions, sparseArrayIndexes, normalizeWorkSpreadsheetBubbleSizeRepresents, workSpreadsheetChartSupportsTrendlines, normalizeWorkSpreadsheetChartLegendOverlay, parseSpreadsheetChartReference, workSpreadsheetChartGroupingIsStacked, normalizeWorkSpreadsheetChartGapWidth, workSpreadsheetChartSupportsSmoothLines, refreshSpreadsheetPivotTables, createSpreadsheetPivotFromSelection, reconcileSpreadsheetPivots, spreadsheetPivotCount, sparseMatrixColumnCount, workSpreadsheetChartSupportsErrorBars, formulaHasExternalReference, isValidSpreadsheetDefinedName, spreadsheetPivotValidation, deleteSpreadsheetPivotTable, workSpreadsheetChartAxisDefaultLabelPosition, workSpreadsheetChartSupportsSeriesAnalysis, parseSpreadsheetCellRanges, spreadsheetPivotFilterItems, spreadsheetPivotFields, normalizeWorkSpreadsheetChartOverlap, spreadsheetFormulaRangeConflict, spreadsheetSheetsWithChartPreviews, workSpreadsheetChartUsesNumericXAxis, workSpreadsheetChartAxisShowsMajorGridlinesByDefault, workSpreadsheetChartSupportsAxes, normalizeWorkSpreadsheetCombinationSeriesType, normalizeWorkSpreadsheetRadarStyle } from "./8715.js";
|
|
9
|
-
import { reconcileSpreadsheetTableCalculatedColumns, spreadsheetTextOrientationFromChoice, xlsxRichTextCellText,
|
|
9
|
+
import { reconcileSpreadsheetTableCalculatedColumns, isSpreadsheetTextOrientationId, spreadsheetTextOrientationFromChoice, xlsxRichTextCellText, spreadsheetTextOrientationFromAngle, replaceOfficeSpreadsheetCollaboration as replaceWorkOfficeSpreadsheetCollaboration, spreadsheetCellValueWithDiagonalBorder, spreadsheetUnderlineCellValue, normalizeSpreadsheetDataValidationErrorStyle, readOfficeSpreadsheetCollaboration as readWorkOfficeSpreadsheetCollaboration, spreadsheetTableTotalsFunctionLabel, withDefaultSpreadsheetTableTotalsLabel, normalizeXlsxRichTextEditSource, spreadsheetTableTotalsColumnPatch, normalizeXlsxRichTextColor, isHighSurrogate, xlsxNativeFillCellKeys, createOfficeSpreadsheetCollaborationBinding as createWorkOfficeSpreadsheetCollaborationBinding, SPREADSHEET_TABLE_TOTALS_FUNCTIONS, boundedSpreadsheetDataValidationText, normalizeXlsxRichTextCell, activeXlsxNativeFill, spreadsheetUnderlineStyle, normalizeSpreadsheetDateValidationBoundary, deleteXlsxNativeFills, spreadsheetTextOrientationCellStyle, spreadsheetTextOrientationChoiceFromCell, normalizeXlsxRichTextRun, spreadsheetDiagonalBorderFromCellValue, sameXlsxRichTextRunStyle, isLowSurrogate, spreadsheetTableTotalsRowHasContent, reconcileSpreadsheetTableTotalsColumns, spreadsheetTextOrientationFromCell, coalesceXlsxRichTextRuns, fillSpreadsheetTableCalculatedColumns, synchronizeSpreadsheetTableTotalsRow, validXlsxRichText, patchSpreadsheetRichTextFontRuns, isSpreadsheetUnderlineStyle, spreadsheetVisibleTextRotationFromCell } from "./3266.js";
|
|
10
10
|
import { moveOfficeMenuFocus, stepOfficeZoom, useOfficeRemoteParticipants, Popover, Dialog, officePresenceColor, useOfficePublishPresenceLocation, button_Button, icon_button_IconButton, moveOfficeGridMenuFocus, office_text_field_OfficeTextField, useDialogFocusScope, useOfficeEditorWheelZoom } from "./0~8136.js";
|
|
11
11
|
import { isOfficeKernelSpreadsheetError, normalizeCssColor, OFFICE_KERNEL_SPREADSHEET_MAX_ROWS, createOfficeId as createWorkId } from "./4121.js";
|
|
12
12
|
import { useOfficeTaskPaneEscape, OfficeCheckbox, CommittedOfficeNumberField, useOfficeDialog, useOfficeTaskPaneModal, createOfficeKernelClient, officeFontFamilies, CollectionState, OfficeNumberField, handleOfficeTaskPaneKeyDown } from "./0~7048.js";
|
|
@@ -3770,6 +3770,7 @@ function reconcileSpreadsheetTablesAfterFortune(sheets, sourceSheets, operations
|
|
|
3770
3770
|
let tables = source.tables;
|
|
3771
3771
|
const reconcileColumns = new Set();
|
|
3772
3772
|
const calculatedColumnRows = new Map();
|
|
3773
|
+
const editedTotalsColumns = new Map();
|
|
3773
3774
|
if (!operations.length) for (const table of tables)reconcileColumns.add(table.id);
|
|
3774
3775
|
for (const operation of sheetOperations){
|
|
3775
3776
|
const structure = spreadsheetTableStructureChangeFromOperation(operation);
|
|
@@ -3797,7 +3798,17 @@ function reconcileSpreadsheetTablesAfterFortune(sheets, sourceSheets, operations
|
|
|
3797
3798
|
const coordinate = spreadsheetCellCoordinateFromOperation(operation);
|
|
3798
3799
|
if (!coordinate) continue;
|
|
3799
3800
|
const table = tables.find((candidate)=>spreadsheetTableContainsCell(candidate, coordinate.row, coordinate.column));
|
|
3800
|
-
if (table)
|
|
3801
|
+
if (table) {
|
|
3802
|
+
reconcileColumns.add(table.id);
|
|
3803
|
+
if (table.totalsRow && coordinate.row === table.range.row[1]) {
|
|
3804
|
+
const offset = coordinate.column - table.range.column[0];
|
|
3805
|
+
if (offset >= 0 && offset < table.columns.length) {
|
|
3806
|
+
const offsets = editedTotalsColumns.get(table.id) ?? new Set();
|
|
3807
|
+
offsets.add(offset);
|
|
3808
|
+
editedTotalsColumns.set(table.id, offsets);
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3801
3812
|
}
|
|
3802
3813
|
const updates = [];
|
|
3803
3814
|
const readCell = spreadsheetSheetCellReader(sheet);
|
|
@@ -3808,7 +3819,11 @@ function reconcileSpreadsheetTablesAfterFortune(sheets, sourceSheets, operations
|
|
|
3808
3819
|
...table,
|
|
3809
3820
|
columns
|
|
3810
3821
|
});
|
|
3811
|
-
|
|
3822
|
+
const reconciledColumns = reconcileSpreadsheetTableTotalsColumns(sheet, {
|
|
3823
|
+
...table,
|
|
3824
|
+
columns: calculatedColumns
|
|
3825
|
+
}, editedTotalsColumns.get(table.id));
|
|
3826
|
+
if (table.headerRow) for (const [offset, column] of reconciledColumns.entries()){
|
|
3812
3827
|
const cellColumn = table.range.column[0] + offset;
|
|
3813
3828
|
if (spreadsheetCellText(readCell(table.range.row[0], cellColumn)) !== column.name) updates.push({
|
|
3814
3829
|
column: cellColumn,
|
|
@@ -3816,9 +3831,9 @@ function reconcileSpreadsheetTablesAfterFortune(sheets, sourceSheets, operations
|
|
|
3816
3831
|
row: table.range.row[0]
|
|
3817
3832
|
});
|
|
3818
3833
|
}
|
|
3819
|
-
return sameSpreadsheetTableColumns(table.columns,
|
|
3834
|
+
return sameSpreadsheetTableColumns(table.columns, reconciledColumns) ? table : {
|
|
3820
3835
|
...table,
|
|
3821
|
-
columns:
|
|
3836
|
+
columns: reconciledColumns
|
|
3822
3837
|
};
|
|
3823
3838
|
});
|
|
3824
3839
|
let withCalculatedColumns = sheet;
|
|
@@ -3829,8 +3844,13 @@ function reconcileSpreadsheetTablesAfterFortune(sheets, sourceSheets, operations
|
|
|
3829
3844
|
]);
|
|
3830
3845
|
}
|
|
3831
3846
|
const withHeaders = stampSpreadsheetTableHeaderCells(withCalculatedColumns, updates);
|
|
3847
|
+
let withTotals = withHeaders;
|
|
3848
|
+
for (const table of tables){
|
|
3849
|
+
const previous = source.tables.find((candidate)=>candidate.id === table.id);
|
|
3850
|
+
withTotals = synchronizeSpreadsheetTableTotalsRow(withTotals, previous, table);
|
|
3851
|
+
}
|
|
3832
3852
|
return {
|
|
3833
|
-
...
|
|
3853
|
+
...withTotals,
|
|
3834
3854
|
tables: tables.length ? tables : void 0
|
|
3835
3855
|
};
|
|
3836
3856
|
});
|
|
@@ -4021,6 +4041,7 @@ function canonicalSpreadsheetTableColumns(table, readCell) {
|
|
|
4021
4041
|
}
|
|
4022
4042
|
observed.add(candidate.toLocaleLowerCase());
|
|
4023
4043
|
return {
|
|
4044
|
+
...table.columns[offset] ?? {},
|
|
4024
4045
|
name: candidate
|
|
4025
4046
|
};
|
|
4026
4047
|
});
|
|
@@ -4146,7 +4167,7 @@ function truncateSpreadsheetTableColumnName(value, maximum) {
|
|
|
4146
4167
|
return Array.from(value).slice(0, maximum).join('');
|
|
4147
4168
|
}
|
|
4148
4169
|
function sameSpreadsheetTableColumns(left, right) {
|
|
4149
|
-
return left.length === right.length && left.every((column, index)=>column.name === right[index]?.name && column.calculatedFormula === right[index]?.calculatedFormula);
|
|
4170
|
+
return left.length === right.length && left.every((column, index)=>column.name === right[index]?.name && column.calculatedFormula === right[index]?.calculatedFormula && column.totalsFunction === right[index]?.totalsFunction && column.totalsLabel === right[index]?.totalsLabel && column.totalsFormula === right[index]?.totalsFormula);
|
|
4150
4171
|
}
|
|
4151
4172
|
function spreadsheet_table_reconciliation_isRecord(value) {
|
|
4152
4173
|
return Boolean(value && 'object' == typeof value && !Array.isArray(value));
|
|
@@ -9378,7 +9399,8 @@ function createSpreadsheetTableDialogSource(content, target) {
|
|
|
9378
9399
|
sheetName: sheet.name,
|
|
9379
9400
|
value: {
|
|
9380
9401
|
headerRow: request.headerRow,
|
|
9381
|
-
rangeReference
|
|
9402
|
+
rangeReference,
|
|
9403
|
+
totalsRow: false
|
|
9382
9404
|
}
|
|
9383
9405
|
};
|
|
9384
9406
|
}
|
|
@@ -9390,13 +9412,25 @@ function validateSpreadsheetTableRequest(content, request) {
|
|
|
9390
9412
|
const sheet = content.sheets.find((candidate)=>candidate.id === request.sheetId);
|
|
9391
9413
|
if (!sheet) return tableError('sheet-not-found');
|
|
9392
9414
|
if (sheet.isPivotTable || sheet.pivotTables?.length) return tableError('pivot-table');
|
|
9393
|
-
const
|
|
9394
|
-
if (!
|
|
9415
|
+
const bodyRange = spreadsheet_cell_range_normalizeSpreadsheetCellRange(request.range);
|
|
9416
|
+
if (!bodyRange) return tableError('invalid-range');
|
|
9417
|
+
const totalsRow = true === request.totalsRow;
|
|
9418
|
+
const range = totalsRow ? {
|
|
9419
|
+
row: [
|
|
9420
|
+
bodyRange.row[0],
|
|
9421
|
+
bodyRange.row[1] + 1
|
|
9422
|
+
],
|
|
9423
|
+
column: [
|
|
9424
|
+
...bodyRange.column
|
|
9425
|
+
]
|
|
9426
|
+
} : bodyRange;
|
|
9395
9427
|
const name = request.name.trim();
|
|
9396
9428
|
if (!validSpreadsheetTableName(name)) return tableError('invalid-name');
|
|
9397
9429
|
if (spreadsheetTableNameExists(content, name)) return tableError('name-conflict');
|
|
9398
9430
|
const bounds = spreadsheetSheetBounds(sheet);
|
|
9399
|
-
|
|
9431
|
+
const configuredRows = Number(sheet.row);
|
|
9432
|
+
const lastAllowedRow = Number.isFinite(configuredRows) && configuredRows > 0 ? bounds.lastRow : Math.max(bounds.lastRow, range.row[1]);
|
|
9433
|
+
if (bodyRange.row[0] > lastAllowedRow || bodyRange.row[1] > lastAllowedRow || bodyRange.column[0] > bounds.lastColumn || bodyRange.column[1] > bounds.lastColumn || range.row[1] >= OFFICE_KERNEL_SPREADSHEET_MAX_ROWS) return tableError('out-of-bounds');
|
|
9400
9434
|
const height = range.row[1] - range.row[0] + 1;
|
|
9401
9435
|
if (height <= Number(request.headerRow)) return tableError('invalid-range');
|
|
9402
9436
|
if (spreadsheet_cell_range_spreadsheetCellRangeArea(range) > 100000) return tableError('range-too-large');
|
|
@@ -9415,8 +9449,27 @@ function validateSpreadsheetTableRequest(content, request) {
|
|
|
9415
9449
|
number: 2
|
|
9416
9450
|
};
|
|
9417
9451
|
if (!validSpreadsheetTableStyle(style)) return tableError('invalid-style');
|
|
9418
|
-
const columns = spreadsheetTableColumnNames(sheet,
|
|
9452
|
+
const columns = spreadsheetTableColumnNames(sheet, bodyRange, request.headerRow);
|
|
9419
9453
|
if (!columns.length || columns.some((column)=>!validTableColumnName(column))) return tableError('invalid-column-name');
|
|
9454
|
+
const totalsColumns = spreadsheetTableTotalsColumnPatch(columns.map((name)=>({
|
|
9455
|
+
name
|
|
9456
|
+
})), request.totalsColumns);
|
|
9457
|
+
if (!totalsColumns) return tableError('invalid-totals');
|
|
9458
|
+
const candidate = {
|
|
9459
|
+
id: '__validation__',
|
|
9460
|
+
name,
|
|
9461
|
+
range,
|
|
9462
|
+
columns: withDefaultSpreadsheetTableTotalsLabel(totalsColumns, totalsRow),
|
|
9463
|
+
filters: [],
|
|
9464
|
+
headerRow: request.headerRow,
|
|
9465
|
+
totalsRow,
|
|
9466
|
+
style,
|
|
9467
|
+
showFirstColumn: false,
|
|
9468
|
+
showLastColumn: false,
|
|
9469
|
+
showRowStripes: 'none' !== style.family,
|
|
9470
|
+
showColumnStripes: false
|
|
9471
|
+
};
|
|
9472
|
+
if (totalsRow && spreadsheetTableTotalsRowHasContent(sheet, candidate)) return tableError('totals-row-content');
|
|
9420
9473
|
return {
|
|
9421
9474
|
columns,
|
|
9422
9475
|
name,
|
|
@@ -9432,16 +9485,19 @@ function applySpreadsheetTable(content, request) {
|
|
|
9432
9485
|
family: 'medium',
|
|
9433
9486
|
number: 2
|
|
9434
9487
|
};
|
|
9488
|
+
const totalsRow = true === request.totalsRow;
|
|
9489
|
+
const totalsColumns = spreadsheetTableTotalsColumnPatch(validation.columns.map((name)=>({
|
|
9490
|
+
name
|
|
9491
|
+
})), request.totalsColumns);
|
|
9492
|
+
if (!totalsColumns) return null;
|
|
9435
9493
|
const tableWithoutCalculatedColumns = {
|
|
9436
9494
|
id: createWorkId('spreadsheet-table'),
|
|
9437
9495
|
name: validation.name,
|
|
9438
9496
|
range: cloneRange(validation.range),
|
|
9439
|
-
columns:
|
|
9440
|
-
name
|
|
9441
|
-
})),
|
|
9497
|
+
columns: withDefaultSpreadsheetTableTotalsLabel(totalsColumns, totalsRow),
|
|
9442
9498
|
filters: [],
|
|
9443
9499
|
headerRow: request.headerRow,
|
|
9444
|
-
totalsRow
|
|
9500
|
+
totalsRow,
|
|
9445
9501
|
style,
|
|
9446
9502
|
showFirstColumn: false,
|
|
9447
9503
|
showLastColumn: false,
|
|
@@ -9453,10 +9509,14 @@ function applySpreadsheetTable(content, request) {
|
|
|
9453
9509
|
columns: reconcileSpreadsheetTableCalculatedColumns(validation.sheet, tableWithoutCalculatedColumns)
|
|
9454
9510
|
};
|
|
9455
9511
|
const nextSheet = request.headerRow ? stampSpreadsheetTableHeaders(validation.sheet, validation.range, validation.columns) : validation.sheet;
|
|
9512
|
+
const sizedSheet = ensureSpreadsheetTableRowCapacity(nextSheet, rangeEndRow(table));
|
|
9513
|
+
const synchronizedSheet = synchronizeSpreadsheetTableTotalsRow(sizedSheet, void 0, table, {
|
|
9514
|
+
force: totalsRow
|
|
9515
|
+
});
|
|
9456
9516
|
return replaceSpreadsheetTableSheet(content, {
|
|
9457
|
-
...
|
|
9517
|
+
...synchronizedSheet,
|
|
9458
9518
|
tables: [
|
|
9459
|
-
...
|
|
9519
|
+
...synchronizedSheet.tables ?? [],
|
|
9460
9520
|
table
|
|
9461
9521
|
]
|
|
9462
9522
|
});
|
|
@@ -9474,20 +9534,46 @@ function updateSpreadsheetTable(content, sheetId, tableId, patch) {
|
|
|
9474
9534
|
const showRowStripes = patch.showRowStripes ?? table.showRowStripes;
|
|
9475
9535
|
const showColumnStripes = patch.showColumnStripes ?? table.showColumnStripes;
|
|
9476
9536
|
if ('none' === style.family && (showFirstColumn || showLastColumn || showRowStripes || showColumnStripes)) return null;
|
|
9477
|
-
const
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
|
|
9485
|
-
|
|
9486
|
-
|
|
9487
|
-
|
|
9488
|
-
|
|
9537
|
+
const totalsRow = patch.totalsRow ?? table.totalsRow;
|
|
9538
|
+
const range = cloneRange(table.range);
|
|
9539
|
+
if (totalsRow !== table.totalsRow) range.row[1] += totalsRow ? 1 : -1;
|
|
9540
|
+
if (range.row[0] < 0 || range.row[1] < range.row[0] || range.row[1] >= OFFICE_KERNEL_SPREADSHEET_MAX_ROWS || range.row[1] - range.row[0] + 1 <= Number(table.headerRow) + Number(totalsRow)) return null;
|
|
9541
|
+
const totalsColumns = spreadsheetTableTotalsColumnPatch(table.columns, patch.totalsColumns);
|
|
9542
|
+
if (!totalsColumns) return null;
|
|
9543
|
+
const nextColumns = withDefaultSpreadsheetTableTotalsLabel(totalsColumns, totalsRow);
|
|
9544
|
+
const nextTable = {
|
|
9545
|
+
...table,
|
|
9546
|
+
name,
|
|
9547
|
+
...void 0 === patch.name ? {} : {
|
|
9548
|
+
displayName: void 0
|
|
9549
|
+
},
|
|
9550
|
+
range,
|
|
9551
|
+
columns: nextColumns,
|
|
9552
|
+
totalsRow,
|
|
9553
|
+
style,
|
|
9554
|
+
showFirstColumn,
|
|
9555
|
+
showLastColumn,
|
|
9556
|
+
showRowStripes,
|
|
9557
|
+
showColumnStripes
|
|
9558
|
+
};
|
|
9559
|
+
if (totalsRow && !table.totalsRow && spreadsheetTableTotalsRowHasContent(sheet, nextTable)) return null;
|
|
9560
|
+
if (totalsRow && !table.totalsRow) {
|
|
9561
|
+
const totalsGrowthRange = {
|
|
9562
|
+
row: [
|
|
9563
|
+
table.range.row[1] + 1,
|
|
9564
|
+
range.row[1]
|
|
9565
|
+
],
|
|
9566
|
+
column: [
|
|
9567
|
+
...range.column
|
|
9568
|
+
]
|
|
9569
|
+
};
|
|
9570
|
+
if (spreadsheet_cell_range_spreadsheetCellRangeArea(range) > 100000 || spreadsheetTableGrowthConflicts(sheet, tableId, totalsGrowthRange)) return null;
|
|
9571
|
+
}
|
|
9572
|
+
const tables = sheet.tables?.map((candidate)=>candidate.id === tableId ? nextTable : candidate);
|
|
9573
|
+
const sizedSheet = ensureSpreadsheetTableRowCapacity(sheet, rangeEndRow(nextTable));
|
|
9574
|
+
const synchronizedSheet = synchronizeSpreadsheetTableTotalsRow(sizedSheet, table, nextTable);
|
|
9489
9575
|
return replaceSpreadsheetTableSheet(content, {
|
|
9490
|
-
...
|
|
9576
|
+
...synchronizedSheet,
|
|
9491
9577
|
tables
|
|
9492
9578
|
});
|
|
9493
9579
|
}
|
|
@@ -9635,6 +9721,16 @@ function spreadsheetTableIntersectsMerge(sheet, range) {
|
|
|
9635
9721
|
]
|
|
9636
9722
|
}));
|
|
9637
9723
|
}
|
|
9724
|
+
function spreadsheetTableGrowthConflicts(sheet, tableId, growthRange) {
|
|
9725
|
+
if (spreadsheetTableIntersectsMerge(sheet, growthRange) || (sheet.tables ?? []).some((candidate)=>candidate.id !== tableId && spreadsheetCellRangesIntersect(candidate.range, growthRange)) || !canMutateSpreadsheetCellRanges(sheet, [
|
|
9726
|
+
growthRange
|
|
9727
|
+
])) return true;
|
|
9728
|
+
const autoFilter = spreadsheet_cell_range_normalizeSpreadsheetCellRange(sheet.filter_select ?? {
|
|
9729
|
+
row: [],
|
|
9730
|
+
column: []
|
|
9731
|
+
});
|
|
9732
|
+
return Boolean(autoFilter && spreadsheetCellRangesIntersect(autoFilter, growthRange));
|
|
9733
|
+
}
|
|
9638
9734
|
function replaceSpreadsheetTableSheet(content, nextSheet) {
|
|
9639
9735
|
return {
|
|
9640
9736
|
...content,
|
|
@@ -9675,6 +9771,7 @@ function tableError(code) {
|
|
|
9675
9771
|
'invalid-name': '表格名称必须是有效且不类似单元格引用的标识符。',
|
|
9676
9772
|
'invalid-range': '表格至少需要一行数据。',
|
|
9677
9773
|
'invalid-style': '表格样式身份无效。',
|
|
9774
|
+
'invalid-totals': '汇总行函数、标签或公式无效。',
|
|
9678
9775
|
'merged-range': '请先取消表格区域内的合并单元格。',
|
|
9679
9776
|
'name-conflict': '表格名称已被其他表格或名称使用。',
|
|
9680
9777
|
'out-of-bounds': '表格区域超出当前工作表边界。',
|
|
@@ -9682,7 +9779,8 @@ function tableError(code) {
|
|
|
9682
9779
|
'protected-range': '受保护或只读区域不能创建表格。',
|
|
9683
9780
|
'range-too-large': `一次最多可创建 ${100000..toLocaleString()} 个单元格的表格。`,
|
|
9684
9781
|
'sheet-not-found': '找不到目标工作表。',
|
|
9685
|
-
'table-overlap': '表格区域不能与其他表格重叠。'
|
|
9782
|
+
'table-overlap': '表格区域不能与其他表格重叠。',
|
|
9783
|
+
'totals-row-content': '汇总行目标单元格已有内容,请先清空后再启用。'
|
|
9686
9784
|
};
|
|
9687
9785
|
return {
|
|
9688
9786
|
code,
|
|
@@ -9690,6 +9788,20 @@ function tableError(code) {
|
|
|
9690
9788
|
ok: false
|
|
9691
9789
|
};
|
|
9692
9790
|
}
|
|
9791
|
+
function rangeEndRow(table) {
|
|
9792
|
+
return table.range.row[1];
|
|
9793
|
+
}
|
|
9794
|
+
function ensureSpreadsheetTableRowCapacity(sheet, lastRow) {
|
|
9795
|
+
if (!Number.isSafeInteger(lastRow) || lastRow < 0) return sheet;
|
|
9796
|
+
const configured = Number(sheet.row);
|
|
9797
|
+
if (!Number.isFinite(configured) || configured <= 0) return sheet;
|
|
9798
|
+
const required = lastRow + 1;
|
|
9799
|
+
if (required <= configured) return sheet;
|
|
9800
|
+
return {
|
|
9801
|
+
...sheet,
|
|
9802
|
+
row: Math.min(OFFICE_KERNEL_SPREADSHEET_MAX_ROWS, required)
|
|
9803
|
+
};
|
|
9804
|
+
}
|
|
9693
9805
|
function createSpreadsheetTableExtension() {
|
|
9694
9806
|
return createOfficeEditorExtension({
|
|
9695
9807
|
name: 'spreadsheetTables',
|
|
@@ -9742,7 +9854,8 @@ function updateSpreadsheetTableCommand(context, sheetId, tableId, patch) {
|
|
|
9742
9854
|
if (!context.editable) return false;
|
|
9743
9855
|
const next = updateSpreadsheetTable(context.content, sheetId, tableId, patch);
|
|
9744
9856
|
if (!next) return false;
|
|
9745
|
-
context.
|
|
9857
|
+
const selection = context.workbook?.getSelection()?.at(-1) ?? (context.selection?.sheetId === sheetId ? context.selection.selection : void 0);
|
|
9858
|
+
context.onChange(spreadsheetContentWithSelection(next, sheetId, selection));
|
|
9746
9859
|
return true;
|
|
9747
9860
|
}
|
|
9748
9861
|
function canConvertSpreadsheetTableToRange(context, sheetId, tableId) {
|
|
@@ -13606,6 +13719,16 @@ function SpreadsheetTableDesignRibbon({ can, commands, sheetId, table }) {
|
|
|
13606
13719
|
})
|
|
13607
13720
|
]
|
|
13608
13721
|
}),
|
|
13722
|
+
/*#__PURE__*/ jsx(WorkOfficeRibbonGroup, {
|
|
13723
|
+
label: "汇总行",
|
|
13724
|
+
priority: "high",
|
|
13725
|
+
children: /*#__PURE__*/ jsx(SpreadsheetTableTotalsMenu, {
|
|
13726
|
+
can: can,
|
|
13727
|
+
commands: commands,
|
|
13728
|
+
sheetId: sheetId,
|
|
13729
|
+
table: table
|
|
13730
|
+
})
|
|
13731
|
+
}),
|
|
13609
13732
|
/*#__PURE__*/ jsx(WorkOfficeRibbonGroup, {
|
|
13610
13733
|
label: "表格样式",
|
|
13611
13734
|
priority: "high",
|
|
@@ -13675,6 +13798,225 @@ function SpreadsheetTableDesignRibbon({ can, commands, sheetId, table }) {
|
|
|
13675
13798
|
]
|
|
13676
13799
|
});
|
|
13677
13800
|
}
|
|
13801
|
+
const totalsFunctionOptions = [
|
|
13802
|
+
{
|
|
13803
|
+
value: 'none',
|
|
13804
|
+
label: '不汇总'
|
|
13805
|
+
},
|
|
13806
|
+
...SPREADSHEET_TABLE_TOTALS_FUNCTIONS.map((value)=>({
|
|
13807
|
+
value,
|
|
13808
|
+
label: spreadsheetTableTotalsFunctionLabel(value)
|
|
13809
|
+
}))
|
|
13810
|
+
];
|
|
13811
|
+
function SpreadsheetTableTotalsMenu({ can, commands, sheetId, table }) {
|
|
13812
|
+
const [drafts, setDrafts] = useState({});
|
|
13813
|
+
useEffect(()=>{
|
|
13814
|
+
const next = {};
|
|
13815
|
+
table.columns.forEach((column, offset)=>{
|
|
13816
|
+
next[offset] = {
|
|
13817
|
+
formula: column.totalsFormula ?? '',
|
|
13818
|
+
label: column.totalsLabel ?? ''
|
|
13819
|
+
};
|
|
13820
|
+
});
|
|
13821
|
+
setDrafts(next);
|
|
13822
|
+
}, [
|
|
13823
|
+
table.id,
|
|
13824
|
+
table.columns
|
|
13825
|
+
]);
|
|
13826
|
+
const patchColumn = (offset, patch)=>{
|
|
13827
|
+
const designPatch = {
|
|
13828
|
+
totalsColumns: {
|
|
13829
|
+
[offset]: patch
|
|
13830
|
+
}
|
|
13831
|
+
};
|
|
13832
|
+
if (!can.updateTable(sheetId, table.id, designPatch) || !commands.updateTable(sheetId, table.id, designPatch)) showToast('汇总行设置无效,请检查函数、标签或公式。', 'error');
|
|
13833
|
+
};
|
|
13834
|
+
const toggleTotalsRow = ()=>{
|
|
13835
|
+
const patch = {
|
|
13836
|
+
totalsRow: !table.totalsRow
|
|
13837
|
+
};
|
|
13838
|
+
if (!can.updateTable(sheetId, table.id, patch) || !commands.updateTable(sheetId, table.id, patch)) showToast(table.totalsRow ? '无法关闭汇总行。' : '汇总行目标区域已有内容,请先清空该行。', 'error');
|
|
13839
|
+
};
|
|
13840
|
+
return /*#__PURE__*/ jsx(Popover, {
|
|
13841
|
+
label: "汇总行",
|
|
13842
|
+
panelLabel: "表格汇总行设置",
|
|
13843
|
+
panelRole: "dialog",
|
|
13844
|
+
portal: true,
|
|
13845
|
+
className: "work-spreadsheet-table-totals-root",
|
|
13846
|
+
panelClassName: "work-spreadsheet-table-totals-menu",
|
|
13847
|
+
placement: "bottom-end",
|
|
13848
|
+
trigger: (triggerProps, { open })=>/*#__PURE__*/ jsxs("button", {
|
|
13849
|
+
...triggerProps,
|
|
13850
|
+
className: `with-label work-spreadsheet-table-totals-trigger${open || table.totalsRow ? ' active' : ''}`,
|
|
13851
|
+
"aria-pressed": table.totalsRow,
|
|
13852
|
+
title: "设置表格汇总行",
|
|
13853
|
+
children: [
|
|
13854
|
+
/*#__PURE__*/ jsx(Calculator, {
|
|
13855
|
+
size: 19
|
|
13856
|
+
}),
|
|
13857
|
+
/*#__PURE__*/ jsx("span", {
|
|
13858
|
+
children: "汇总行"
|
|
13859
|
+
})
|
|
13860
|
+
]
|
|
13861
|
+
}),
|
|
13862
|
+
children: (close)=>/*#__PURE__*/ jsxs("div", {
|
|
13863
|
+
className: "work-spreadsheet-table-totals-content",
|
|
13864
|
+
children: [
|
|
13865
|
+
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
13866
|
+
ariaLabel: "启用汇总行",
|
|
13867
|
+
checked: table.totalsRow,
|
|
13868
|
+
disabled: !table.totalsRow && !can.updateTable(sheetId, table.id, {
|
|
13869
|
+
totalsRow: true
|
|
13870
|
+
}),
|
|
13871
|
+
onCheckedChange: ()=>{
|
|
13872
|
+
toggleTotalsRow();
|
|
13873
|
+
},
|
|
13874
|
+
children: "启用汇总行"
|
|
13875
|
+
}),
|
|
13876
|
+
/*#__PURE__*/ jsx("p", {
|
|
13877
|
+
className: "work-spreadsheet-table-totals-hint",
|
|
13878
|
+
children: "汇总行位于表格末尾,函数会随筛选结果更新。"
|
|
13879
|
+
}),
|
|
13880
|
+
/*#__PURE__*/ jsx("div", {
|
|
13881
|
+
className: "work-spreadsheet-table-totals-columns",
|
|
13882
|
+
children: table.columns.map((column, offset)=>{
|
|
13883
|
+
const selected = column.totalsFormula ? 'custom' : column.totalsFunction ?? 'none';
|
|
13884
|
+
const draft = drafts[offset] ?? {
|
|
13885
|
+
formula: column.totalsFormula ?? '',
|
|
13886
|
+
label: column.totalsLabel ?? ''
|
|
13887
|
+
};
|
|
13888
|
+
const formulaEnabled = 'custom' === selected;
|
|
13889
|
+
const labelEnabled = 'none' === selected;
|
|
13890
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
13891
|
+
className: "work-spreadsheet-table-totals-column",
|
|
13892
|
+
children: [
|
|
13893
|
+
/*#__PURE__*/ jsx("strong", {
|
|
13894
|
+
children: column.name
|
|
13895
|
+
}),
|
|
13896
|
+
/*#__PURE__*/ jsxs("label", {
|
|
13897
|
+
children: [
|
|
13898
|
+
/*#__PURE__*/ jsx("span", {
|
|
13899
|
+
children: "函数"
|
|
13900
|
+
}),
|
|
13901
|
+
/*#__PURE__*/ jsx("select", {
|
|
13902
|
+
"aria-label": `${column.name} 汇总函数`,
|
|
13903
|
+
"data-selected-value": selected,
|
|
13904
|
+
disabled: !table.totalsRow,
|
|
13905
|
+
value: selected,
|
|
13906
|
+
onChange: (event)=>{
|
|
13907
|
+
const value = event.currentTarget.value;
|
|
13908
|
+
if ('none' === value) patchColumn(offset, {
|
|
13909
|
+
totalsFunction: null,
|
|
13910
|
+
totalsFormula: null
|
|
13911
|
+
});
|
|
13912
|
+
else if ('custom' === value) {
|
|
13913
|
+
const formula = draft.formula || `=SUM(${table.name}[${escapeTotalsColumnName(column.name)}])`;
|
|
13914
|
+
setDrafts((current)=>({
|
|
13915
|
+
...current,
|
|
13916
|
+
[offset]: {
|
|
13917
|
+
...draft,
|
|
13918
|
+
formula
|
|
13919
|
+
}
|
|
13920
|
+
}));
|
|
13921
|
+
patchColumn(offset, {
|
|
13922
|
+
totalsFunction: 'custom',
|
|
13923
|
+
totalsFormula: formula,
|
|
13924
|
+
totalsLabel: null
|
|
13925
|
+
});
|
|
13926
|
+
} else patchColumn(offset, {
|
|
13927
|
+
totalsFunction: value,
|
|
13928
|
+
totalsFormula: null,
|
|
13929
|
+
totalsLabel: null
|
|
13930
|
+
});
|
|
13931
|
+
},
|
|
13932
|
+
children: totalsFunctionOptions.map((option)=>/*#__PURE__*/ jsx("option", {
|
|
13933
|
+
value: option.value,
|
|
13934
|
+
children: option.label
|
|
13935
|
+
}, option.value))
|
|
13936
|
+
})
|
|
13937
|
+
]
|
|
13938
|
+
}),
|
|
13939
|
+
/*#__PURE__*/ jsxs("label", {
|
|
13940
|
+
children: [
|
|
13941
|
+
/*#__PURE__*/ jsx("span", {
|
|
13942
|
+
children: "标签"
|
|
13943
|
+
}),
|
|
13944
|
+
/*#__PURE__*/ jsx("input", {
|
|
13945
|
+
"aria-label": `${column.name} 汇总标签`,
|
|
13946
|
+
disabled: !table.totalsRow || !labelEnabled,
|
|
13947
|
+
value: draft.label,
|
|
13948
|
+
onChange: (event)=>{
|
|
13949
|
+
const value = event.currentTarget.value;
|
|
13950
|
+
setDrafts((current)=>({
|
|
13951
|
+
...current,
|
|
13952
|
+
[offset]: {
|
|
13953
|
+
...draft,
|
|
13954
|
+
label: value
|
|
13955
|
+
}
|
|
13956
|
+
}));
|
|
13957
|
+
},
|
|
13958
|
+
onBlur: ()=>{
|
|
13959
|
+
if (!labelEnabled) return;
|
|
13960
|
+
patchColumn(offset, {
|
|
13961
|
+
totalsLabel: draft.label.trim() || null
|
|
13962
|
+
});
|
|
13963
|
+
},
|
|
13964
|
+
onKeyDown: (event)=>{
|
|
13965
|
+
if ('Enter' === event.key) event.currentTarget.blur();
|
|
13966
|
+
}
|
|
13967
|
+
})
|
|
13968
|
+
]
|
|
13969
|
+
}),
|
|
13970
|
+
/*#__PURE__*/ jsxs("label", {
|
|
13971
|
+
children: [
|
|
13972
|
+
/*#__PURE__*/ jsx("span", {
|
|
13973
|
+
children: "自定义公式"
|
|
13974
|
+
}),
|
|
13975
|
+
/*#__PURE__*/ jsx("input", {
|
|
13976
|
+
"aria-label": `${column.name} 汇总公式`,
|
|
13977
|
+
disabled: !table.totalsRow || !formulaEnabled,
|
|
13978
|
+
placeholder: "=SUM(Table[Column])",
|
|
13979
|
+
value: draft.formula,
|
|
13980
|
+
onChange: (event)=>{
|
|
13981
|
+
const value = event.currentTarget.value;
|
|
13982
|
+
setDrafts((current)=>({
|
|
13983
|
+
...current,
|
|
13984
|
+
[offset]: {
|
|
13985
|
+
...draft,
|
|
13986
|
+
formula: value
|
|
13987
|
+
}
|
|
13988
|
+
}));
|
|
13989
|
+
},
|
|
13990
|
+
onBlur: ()=>{
|
|
13991
|
+
if (!formulaEnabled) return;
|
|
13992
|
+
patchColumn(offset, {
|
|
13993
|
+
totalsFunction: 'custom',
|
|
13994
|
+
totalsFormula: draft.formula.trim() || null
|
|
13995
|
+
});
|
|
13996
|
+
},
|
|
13997
|
+
onKeyDown: (event)=>{
|
|
13998
|
+
if ('Enter' === event.key) event.currentTarget.blur();
|
|
13999
|
+
}
|
|
14000
|
+
})
|
|
14001
|
+
]
|
|
14002
|
+
})
|
|
14003
|
+
]
|
|
14004
|
+
}, `${table.id}-${offset}`);
|
|
14005
|
+
})
|
|
14006
|
+
}),
|
|
14007
|
+
/*#__PURE__*/ jsx("button", {
|
|
14008
|
+
type: "button",
|
|
14009
|
+
className: "work-spreadsheet-table-totals-close",
|
|
14010
|
+
onClick: close,
|
|
14011
|
+
children: "完成"
|
|
14012
|
+
})
|
|
14013
|
+
]
|
|
14014
|
+
})
|
|
14015
|
+
});
|
|
14016
|
+
}
|
|
14017
|
+
function escapeTotalsColumnName(value) {
|
|
14018
|
+
return value.replaceAll(']', ']]');
|
|
14019
|
+
}
|
|
13678
14020
|
function SpreadsheetTableNameControl({ can, commands, sheetId, table }) {
|
|
13679
14021
|
const [name, setName] = useState(table.name);
|
|
13680
14022
|
useEffect(()=>setName(table.name), [
|
|
@@ -25384,6 +25726,15 @@ function SpreadsheetTableDialog({ source, restoreFocusTarget, onApply, onClose,
|
|
|
25384
25726
|
headerRow
|
|
25385
25727
|
})),
|
|
25386
25728
|
children: "表包含标题"
|
|
25729
|
+
}),
|
|
25730
|
+
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
25731
|
+
ariaLabel: "启用汇总行",
|
|
25732
|
+
checked: true === value.totalsRow,
|
|
25733
|
+
onCheckedChange: (totalsRow)=>setValue((current)=>({
|
|
25734
|
+
...current,
|
|
25735
|
+
totalsRow
|
|
25736
|
+
})),
|
|
25737
|
+
children: "启用汇总行"
|
|
25387
25738
|
})
|
|
25388
25739
|
]
|
|
25389
25740
|
})
|
|
@@ -25471,7 +25822,8 @@ function useSpreadsheetTable({ commandsRef, contentRef, focusGrid, getGridFocusT
|
|
|
25471
25822
|
headerRow: value.headerRow,
|
|
25472
25823
|
name: source.name,
|
|
25473
25824
|
range,
|
|
25474
|
-
sheetId: source.sheetId
|
|
25825
|
+
sheetId: source.sheetId,
|
|
25826
|
+
totalsRow: true === value.totalsRow
|
|
25475
25827
|
}) ?? false;
|
|
25476
25828
|
appliedRef.current = handled;
|
|
25477
25829
|
} finally{
|
|
@@ -25492,7 +25844,8 @@ function spreadsheetTableValidationMessage(content, source, value) {
|
|
|
25492
25844
|
headerRow: value.headerRow,
|
|
25493
25845
|
name: source.name,
|
|
25494
25846
|
range,
|
|
25495
|
-
sheetId: source.sheetId
|
|
25847
|
+
sheetId: source.sheetId,
|
|
25848
|
+
totalsRow: true === value.totalsRow
|
|
25496
25849
|
});
|
|
25497
25850
|
}
|
|
25498
25851
|
const MAXIMUM_BUFFERED_SPREADSHEET_OPERATIONS = 10001;
|