@a3s-lab/office 0.15.0 → 0.17.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/COLLABORATION_ROADMAP.md +15 -5
- package/README.md +28 -2
- package/dist/0~6090.js +7 -8
- package/dist/0~spreadsheet-editor.js +2347 -406
- package/dist/2180.js +370 -34
- package/dist/4104.js +657 -22
- package/dist/5184.js +1 -1
- package/dist/8715.js +156 -156
- package/dist/internal/collaboration/office-spreadsheet-collaboration-records.d.ts +2 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration-validation-support.d.ts +6 -0
- package/dist/internal/features/work/editors/spreadsheet-auto-filter.d.ts +1 -0
- package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +59 -1
- package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +12 -0
- package/dist/internal/features/work/editors/spreadsheet-editor-ribbon.d.ts +4 -2
- package/dist/internal/features/work/editors/spreadsheet-font-size-command.d.ts +18 -0
- package/dist/internal/features/work/editors/spreadsheet-font-size.d.ts +4 -0
- package/dist/internal/features/work/editors/spreadsheet-table-command.d.ts +3 -0
- package/dist/internal/features/work/editors/spreadsheet-table-conversion.d.ts +7 -0
- package/dist/internal/features/work/editors/spreadsheet-table-dialog.d.ts +8 -0
- package/dist/internal/features/work/editors/spreadsheet-table-limits.d.ts +1 -0
- package/dist/internal/features/work/editors/spreadsheet-table-reconciliation.d.ts +21 -0
- package/dist/internal/features/work/editors/spreadsheet-table-render.d.ts +16 -0
- package/dist/internal/features/work/editors/spreadsheet-table-ribbon.d.ts +8 -0
- package/dist/internal/features/work/editors/spreadsheet-table-style.d.ts +31 -0
- package/dist/internal/features/work/editors/spreadsheet-table.d.ts +55 -0
- package/dist/internal/features/work/editors/use-spreadsheet-table.d.ts +23 -0
- package/dist/internal/features/work/work-types.d.ts +100 -0
- package/dist/internal/features/work/work-xlsx-interop.d.ts +2 -0
- package/dist/internal/features/work/work-xlsx-table-filters.d.ts +3 -0
- package/dist/internal/features/work/work-xlsx-tables.d.ts +4 -0
- package/dist/office-kernel.wasm +0 -0
- package/dist/styles.css +204 -3
- package/dist/work-spreadsheet-package-scan.worker.js +3 -2
- package/docs/latest/en/browser-editor-architecture.md +43 -0
- package/package.json +6 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __webpack_require__ } from "./0~rslib-runtime.js";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Workbook } from "@fortune-sheet/react";
|
|
4
|
-
import { AlignCenter, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowDownToLine, ArrowLeft, ArrowLeftToLine, ArrowRight, ArrowRightToLine, ArrowUp, ArrowUpToLine, BadgeJapaneseYen, BarChart3, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, Bookmark, Calculator, Check, ChevronDown, ChevronLeft, ChevronRight, ClipboardPaste, Cloud, Columns3, Copy, CopyPlus, DecimalsArrowLeft, DecimalsArrowRight, Eraser, Eye, EyeOff, FileX2, Globe2, Grid2X2, Grid3X3, Hash, Italic, KeyRound, Layers2, Link2, Link2Off, ListChecks, ListFilter, LocateFixed, Merge, MessageSquareX, MoveHorizontal, MoveVertical, Paintbrush, Palette, PanelLeft, PanelTop, PanelsTopLeft, Pencil, Percent, Plus, Printer, Redo2, RefreshCw, Rows3, Save, Scissors, Search, Settings2, ShieldCheck, Sigma, SortAsc, SortDesc, Strikethrough, SwatchBook, Table2, TableProperties, Trash2, Underline, Undo2, WrapText, X } from "lucide-react";
|
|
4
|
+
import { AArrowDown, AArrowUp, AlignCenter, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowDownToLine, ArrowLeft, ArrowLeftToLine, ArrowRight, ArrowRightToLine, ArrowUp, ArrowUpToLine, BadgeJapaneseYen, BarChart3, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, Bookmark, Calculator, Check, ChevronDown, ChevronLeft, ChevronRight, ClipboardPaste, Cloud, Columns3, Copy, CopyPlus, DecimalsArrowLeft, DecimalsArrowRight, Eraser, Eye, EyeOff, FileX2, Globe2, Grid2X2, Grid3X3, Hash, Italic, KeyRound, Layers2, Link2, Link2Off, ListChecks, ListFilter, LocateFixed, Merge, MessageSquareX, MoveHorizontal, MoveVertical, Paintbrush, Palette, PanelLeft, PanelTop, PanelsTopLeft, Pencil, Percent, Plus, Printer, Redo2, RefreshCw, Rows3, Save, Scissors, Search, Settings2, ShieldCheck, Sigma, SortAsc, SortDesc, Strikethrough, SwatchBook, Table2, TableProperties, Trash2, Underline, Undo2, WrapText, X } from "lucide-react";
|
|
5
5
|
import { Fragment as external_react_Fragment, cloneElement, memo, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { genarate, indexToColumnChar, update as core_update } from "@fortune-sheet/core";
|
|
7
7
|
import { freezeImportedSpreadsheetCell, withoutEditableRange, spreadsheetMatrixProfile, normalizeSpreadsheetConditionalVisualOptions, effectiveSpreadsheetPageSetup, attachSpreadsheetShownCommentCells, withEditableRange, sameSpreadsheetHistoryValue, createOfficeSpreadsheetCollaborationBinding as createWorkOfficeSpreadsheetCollaborationBinding, isSpreadsheetConditionalComparisonOperator, spreadsheetConditionalIconForValue, defaultSpreadsheetConditionalIconThresholds, normalizeSpreadsheetDateValidationBoundary, sheetProtectionAuthority, editableRangeCellCount, unlockedCellCount, registerDerivedSpreadsheetMatrix, editableRangeRequiresCredentials, SPREADSHEET_CONDITIONAL_COMPARISON_OPERATORS, normalizeSpreadsheetConditionalIconSetFormat, defaultSpreadsheetDataBarOptions, spreadsheetConditionalThresholdValue, normalizeSheetProtectionAuthority, withSheetProtection, spreadsheetProtectionKey, defaultSpreadsheetColorScaleThresholds, protectedSheetCount, SPREADSHEET_CONDITIONAL_ICON_SETS, withSheetSelectionPermissions, spreadsheetConditionalComparisonNeedsUpperValue, drawSpreadsheetConditionalIcon, replaceOfficeSpreadsheetCollaboration as replaceWorkOfficeSpreadsheetCollaboration, readOfficeSpreadsheetCollaboration as readWorkOfficeSpreadsheetCollaboration, spreadsheetConditionalThresholdsEqual } from "./2180.js";
|
|
@@ -10,13 +10,13 @@ import { moveOfficeMenuFocus, stepOfficeZoom, useOfficeRemoteParticipants, Popov
|
|
|
10
10
|
import { useOfficeTaskPaneEscape, OfficeCheckbox, CommittedOfficeNumberField, useOfficeDialog, useOfficeTaskPaneModal, createOfficeKernelClient, officeFontFamilies, CollectionState, OfficeNumberField, handleOfficeTaskPaneKeyDown } from "./0~7048.js";
|
|
11
11
|
import { isOfficeShortcutBlocked, OfficeColorPicker } from "./0~3635.js";
|
|
12
12
|
import { createOfficeEditorExtension, useOfficeEditorRuntime, useOfficeEditorKeyboardShortcuts } from "./0~3557.js";
|
|
13
|
+
import { OFFICE_KERNEL_SPREADSHEET_MAX_ROWS, createOfficeId as createWorkId, isOfficeKernelSpreadsheetError } from "./5184.js";
|
|
13
14
|
import { showToast } from "./6489.js";
|
|
14
15
|
import { unsupportedSpreadsheetFormulaFunctions } from "./0~work-spreadsheet-formula-support.js";
|
|
15
16
|
import { WorkspaceContextMenu, isWorkspaceContextMenuKeyboardEvent, WorkOfficeZoomControls, Tabs, WorkOfficeStatusBar, Dialog, WorkOfficeRibbon, workspaceContextMenuPosition, OfficeSelect, WorkOfficeRibbonGroup, WorkOfficeRibbonButton, WorkOfficePreviewBar } from "./0~4595.js";
|
|
16
17
|
import { useOfficeDraft, InlineNotice } from "./0~345.js";
|
|
17
18
|
import { spreadsheetAgentMenuItems, SpreadsheetChartSeriesStyleEditor, normalizeOptionalOfficeNumber, normalizeRequiredOfficeNumber, SpreadsheetErrorBarEditor, useOfficeHistory, spreadsheetAgentSelection, SpreadsheetTrendlineEditor, applySpreadsheetAgentProposalChanges } from "./0~3539.js";
|
|
18
19
|
import { useOfficeEditorFocusOrigin, useOfficeCollaborationLocationNavigator, StateView } from "./432.js";
|
|
19
|
-
import { OFFICE_KERNEL_SPREADSHEET_MAX_ROWS, createOfficeId as createWorkId, isOfficeKernelSpreadsheetError } from "./5184.js";
|
|
20
20
|
var spreadsheet_editor_namespaceObject = {};
|
|
21
21
|
__webpack_require__.r(spreadsheet_editor_namespaceObject);
|
|
22
22
|
__webpack_require__.d(spreadsheet_editor_namespaceObject, {
|
|
@@ -1373,6 +1373,355 @@ const spreadsheetFontSizes = [
|
|
|
1373
1373
|
48,
|
|
1374
1374
|
72
|
|
1375
1375
|
];
|
|
1376
|
+
function nextSpreadsheetFontSize(current, direction) {
|
|
1377
|
+
if (!Number.isFinite(current) || current < 1 || current > 409) return null;
|
|
1378
|
+
return 'grow' === direction ? spreadsheetFontSizes.find((size)=>size > current) ?? null : [
|
|
1379
|
+
...spreadsheetFontSizes
|
|
1380
|
+
].reverse().find((size)=>size < current) ?? null;
|
|
1381
|
+
}
|
|
1382
|
+
function canApplySpreadsheetTableStructureChange(sheet, change) {
|
|
1383
|
+
if (!sheet || !validSpreadsheetTableStructureChange(change)) return false;
|
|
1384
|
+
for (const table of sheet.tables ?? []){
|
|
1385
|
+
if ('delete' === change.kind && 'row' === change.axis && spreadsheetTableDeleteRemovesSemanticRow(table, change.start, change.end)) return false;
|
|
1386
|
+
if (!transformSpreadsheetTableStructure(table, change)) return false;
|
|
1387
|
+
}
|
|
1388
|
+
return true;
|
|
1389
|
+
}
|
|
1390
|
+
function reconcileSpreadsheetTablesAfterFortune(sheets, sourceSheets, operations = []) {
|
|
1391
|
+
return sheets.map((sheet, index)=>{
|
|
1392
|
+
const source = sourceSheetForReconciliation(sheet, sourceSheets, index);
|
|
1393
|
+
if (!source?.tables?.length) return sheet;
|
|
1394
|
+
const sheetOperations = operations.filter((operation)=>operation.id === source.id);
|
|
1395
|
+
let tables = source.tables;
|
|
1396
|
+
const reconcileColumns = new Set();
|
|
1397
|
+
if (!operations.length) for (const table of tables)reconcileColumns.add(table.id);
|
|
1398
|
+
for (const operation of sheetOperations){
|
|
1399
|
+
const structure = spreadsheetTableStructureChangeFromOperation(operation);
|
|
1400
|
+
if (structure) {
|
|
1401
|
+
const transformed = [];
|
|
1402
|
+
for (const table of tables){
|
|
1403
|
+
const next = transformSpreadsheetTableStructure(table, structure);
|
|
1404
|
+
if (next) {
|
|
1405
|
+
transformed.push(next);
|
|
1406
|
+
if (next !== table) reconcileColumns.add(table.id);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
tables = transformed;
|
|
1410
|
+
continue;
|
|
1411
|
+
}
|
|
1412
|
+
const coordinate = spreadsheetCellCoordinateFromOperation(operation);
|
|
1413
|
+
if (!coordinate) continue;
|
|
1414
|
+
const table = tables.find((candidate)=>candidate.headerRow && candidate.range.row[0] === coordinate.row && coordinate.column >= candidate.range.column[0] && coordinate.column <= candidate.range.column[1]);
|
|
1415
|
+
if (table) reconcileColumns.add(table.id);
|
|
1416
|
+
}
|
|
1417
|
+
const updates = [];
|
|
1418
|
+
const readCell = spreadsheetSheetCellReader(sheet);
|
|
1419
|
+
tables = tables.map((table)=>{
|
|
1420
|
+
if (!reconcileColumns.has(table.id)) return table;
|
|
1421
|
+
const columns = canonicalSpreadsheetTableColumns(table, readCell);
|
|
1422
|
+
if (table.headerRow) for (const [offset, column] of columns.entries()){
|
|
1423
|
+
const cellColumn = table.range.column[0] + offset;
|
|
1424
|
+
if (spreadsheetCellText(readCell(table.range.row[0], cellColumn)) !== column.name) updates.push({
|
|
1425
|
+
column: cellColumn,
|
|
1426
|
+
name: column.name,
|
|
1427
|
+
row: table.range.row[0]
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
return sameSpreadsheetTableColumns(table.columns, columns) ? table : {
|
|
1431
|
+
...table,
|
|
1432
|
+
columns
|
|
1433
|
+
};
|
|
1434
|
+
});
|
|
1435
|
+
const withHeaders = stampSpreadsheetTableHeaderCells(sheet, updates);
|
|
1436
|
+
return {
|
|
1437
|
+
...withHeaders,
|
|
1438
|
+
tables: tables.length ? tables : void 0
|
|
1439
|
+
};
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
function transformSpreadsheetTableStructure(table, change) {
|
|
1443
|
+
if (!validSpreadsheetTableStructureChange(change)) return null;
|
|
1444
|
+
const axis = 'row' === change.axis ? table.range.row : table.range.column;
|
|
1445
|
+
const transformed = 'insert' === change.kind ? transformSpreadsheetTableAxisForInsertion(axis, change) : transformSpreadsheetTableAxisForDeletion(axis, change);
|
|
1446
|
+
if (!transformed) return null;
|
|
1447
|
+
const range = {
|
|
1448
|
+
row: 'row' === change.axis ? transformed.axis : [
|
|
1449
|
+
...table.range.row
|
|
1450
|
+
],
|
|
1451
|
+
column: 'column' === change.axis ? transformed.axis : [
|
|
1452
|
+
...table.range.column
|
|
1453
|
+
]
|
|
1454
|
+
};
|
|
1455
|
+
const height = range.row[1] - range.row[0] + 1;
|
|
1456
|
+
if (height <= Number(table.headerRow) + Number(table.totalsRow)) return null;
|
|
1457
|
+
if ('column' !== change.axis || !transformed.inside) {
|
|
1458
|
+
if (range.row[0] === table.range.row[0] && range.row[1] === table.range.row[1] && range.column[0] === table.range.column[0] && range.column[1] === table.range.column[1]) return table;
|
|
1459
|
+
return {
|
|
1460
|
+
...table,
|
|
1461
|
+
range
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
if ('insert' === change.kind) {
|
|
1465
|
+
const columns = [
|
|
1466
|
+
...table.columns
|
|
1467
|
+
];
|
|
1468
|
+
columns.splice(transformed.offset, 0, ...Array.from({
|
|
1469
|
+
length: change.count
|
|
1470
|
+
}, ()=>({
|
|
1471
|
+
name: ''
|
|
1472
|
+
})));
|
|
1473
|
+
return {
|
|
1474
|
+
...table,
|
|
1475
|
+
range,
|
|
1476
|
+
columns,
|
|
1477
|
+
filters: table.filters.map((filter)=>filter.column >= transformed.offset ? {
|
|
1478
|
+
...filter,
|
|
1479
|
+
column: filter.column + change.count
|
|
1480
|
+
} : filter)
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
if (!('removed' in transformed)) return null;
|
|
1484
|
+
const removed = transformed.removed;
|
|
1485
|
+
if ('number' != typeof removed) return null;
|
|
1486
|
+
const columns = [
|
|
1487
|
+
...table.columns
|
|
1488
|
+
];
|
|
1489
|
+
columns.splice(transformed.offset, removed);
|
|
1490
|
+
if (!columns.length) return null;
|
|
1491
|
+
return {
|
|
1492
|
+
...table,
|
|
1493
|
+
range,
|
|
1494
|
+
columns,
|
|
1495
|
+
filters: filtersAfterSpreadsheetTableColumnDeletion(table.filters, transformed.offset, removed)
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
function transformSpreadsheetTableAxisForInsertion(axis, change) {
|
|
1499
|
+
const start = axis[0] ?? 0;
|
|
1500
|
+
const end = axis[1] ?? start;
|
|
1501
|
+
const insertion = change.index + ('rightbottom' === change.direction ? 1 : 0);
|
|
1502
|
+
if (insertion <= start) return {
|
|
1503
|
+
axis: [
|
|
1504
|
+
start + change.count,
|
|
1505
|
+
end + change.count
|
|
1506
|
+
],
|
|
1507
|
+
inside: false,
|
|
1508
|
+
offset: 0
|
|
1509
|
+
};
|
|
1510
|
+
if (insertion <= end) return {
|
|
1511
|
+
axis: [
|
|
1512
|
+
start,
|
|
1513
|
+
end + change.count
|
|
1514
|
+
],
|
|
1515
|
+
inside: true,
|
|
1516
|
+
offset: insertion - start
|
|
1517
|
+
};
|
|
1518
|
+
return {
|
|
1519
|
+
axis: [
|
|
1520
|
+
start,
|
|
1521
|
+
end
|
|
1522
|
+
],
|
|
1523
|
+
inside: false,
|
|
1524
|
+
offset: 0
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
function transformSpreadsheetTableAxisForDeletion(axis, change) {
|
|
1528
|
+
const start = axis[0] ?? 0;
|
|
1529
|
+
const end = axis[1] ?? start;
|
|
1530
|
+
const count = change.end - change.start + 1;
|
|
1531
|
+
if (change.end < start) return {
|
|
1532
|
+
axis: [
|
|
1533
|
+
start - count,
|
|
1534
|
+
end - count
|
|
1535
|
+
],
|
|
1536
|
+
inside: false,
|
|
1537
|
+
offset: 0,
|
|
1538
|
+
removed: 0
|
|
1539
|
+
};
|
|
1540
|
+
if (change.start > end) return {
|
|
1541
|
+
axis: [
|
|
1542
|
+
start,
|
|
1543
|
+
end
|
|
1544
|
+
],
|
|
1545
|
+
inside: false,
|
|
1546
|
+
offset: 0,
|
|
1547
|
+
removed: 0
|
|
1548
|
+
};
|
|
1549
|
+
const overlapStart = Math.max(start, change.start);
|
|
1550
|
+
const overlapEnd = Math.min(end, change.end);
|
|
1551
|
+
const removed = overlapEnd - overlapStart + 1;
|
|
1552
|
+
const remaining = end - start + 1 - removed;
|
|
1553
|
+
if (remaining <= 0) return null;
|
|
1554
|
+
const deletedBeforeStart = Math.max(0, Math.min(change.end, start - 1) - change.start + 1);
|
|
1555
|
+
const nextStart = start - deletedBeforeStart;
|
|
1556
|
+
return {
|
|
1557
|
+
axis: [
|
|
1558
|
+
nextStart,
|
|
1559
|
+
nextStart + remaining - 1
|
|
1560
|
+
],
|
|
1561
|
+
inside: true,
|
|
1562
|
+
offset: overlapStart - start,
|
|
1563
|
+
removed
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
function filtersAfterSpreadsheetTableColumnDeletion(filters, offset, removed) {
|
|
1567
|
+
const end = offset + removed - 1;
|
|
1568
|
+
return filters.flatMap((filter)=>{
|
|
1569
|
+
if (filter.column >= offset && filter.column <= end) return [];
|
|
1570
|
+
return [
|
|
1571
|
+
filter.column > end ? {
|
|
1572
|
+
...filter,
|
|
1573
|
+
column: filter.column - removed
|
|
1574
|
+
} : filter
|
|
1575
|
+
];
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
function canonicalSpreadsheetTableColumns(table, readCell) {
|
|
1579
|
+
const width = table.range.column[1] - table.range.column[0] + 1;
|
|
1580
|
+
const observed = new Set();
|
|
1581
|
+
return Array.from({
|
|
1582
|
+
length: width
|
|
1583
|
+
}, (_, offset)=>{
|
|
1584
|
+
const raw = table.headerRow ? spreadsheetCellText(readCell(table.range.row[0], table.range.column[0] + offset)).trim() : table.columns[offset]?.name.trim() ?? '';
|
|
1585
|
+
const base = validSpreadsheetTableColumnName(raw) ? raw : `Column${offset + 1}`;
|
|
1586
|
+
let candidate = base;
|
|
1587
|
+
let suffix = 2;
|
|
1588
|
+
while(observed.has(candidate.toLocaleLowerCase())){
|
|
1589
|
+
const suffixText = String(suffix);
|
|
1590
|
+
candidate = `${truncateSpreadsheetTableColumnName(base, 255 - suffixText.length)}${suffixText}`;
|
|
1591
|
+
suffix += 1;
|
|
1592
|
+
}
|
|
1593
|
+
observed.add(candidate.toLocaleLowerCase());
|
|
1594
|
+
return {
|
|
1595
|
+
name: candidate
|
|
1596
|
+
};
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
function spreadsheetTableDeleteRemovesSemanticRow(table, start, end) {
|
|
1600
|
+
return Boolean(table.headerRow && start <= table.range.row[0] && end >= table.range.row[0] || table.totalsRow && start <= table.range.row[1] && end >= table.range.row[1]);
|
|
1601
|
+
}
|
|
1602
|
+
function spreadsheetTableStructureChangeFromOperation(operation) {
|
|
1603
|
+
if (!spreadsheet_table_reconciliation_isRecord(operation.value)) return null;
|
|
1604
|
+
if ('insertRowCol' === operation.op) {
|
|
1605
|
+
const { count, direction, index, type } = operation.value;
|
|
1606
|
+
const change = {
|
|
1607
|
+
axis: 'column' === type ? 'column' : 'row',
|
|
1608
|
+
count: Number(count),
|
|
1609
|
+
direction: 'rightbottom' === direction ? 'rightbottom' : 'lefttop',
|
|
1610
|
+
index: Number(index),
|
|
1611
|
+
kind: 'insert'
|
|
1612
|
+
};
|
|
1613
|
+
return ('column' === type || 'row' === type) && ('lefttop' === direction || 'rightbottom' === direction) && validSpreadsheetTableStructureChange(change) ? change : null;
|
|
1614
|
+
}
|
|
1615
|
+
if ('deleteRowCol' === operation.op) {
|
|
1616
|
+
const { end, start, type } = operation.value;
|
|
1617
|
+
const change = {
|
|
1618
|
+
axis: 'column' === type ? 'column' : 'row',
|
|
1619
|
+
end: Number(end),
|
|
1620
|
+
kind: 'delete',
|
|
1621
|
+
start: Number(start)
|
|
1622
|
+
};
|
|
1623
|
+
return ('column' === type || 'row' === type) && validSpreadsheetTableStructureChange(change) ? change : null;
|
|
1624
|
+
}
|
|
1625
|
+
return null;
|
|
1626
|
+
}
|
|
1627
|
+
function spreadsheetCellCoordinateFromOperation(operation) {
|
|
1628
|
+
if ('data' !== operation.path[0] || operation.path.length < 3) return null;
|
|
1629
|
+
const row = operation.path[1];
|
|
1630
|
+
const column = operation.path[2];
|
|
1631
|
+
return Number.isSafeInteger(row) && Number(row) >= 0 && Number.isSafeInteger(column) && Number(column) >= 0 ? {
|
|
1632
|
+
column: Number(column),
|
|
1633
|
+
row: Number(row)
|
|
1634
|
+
} : null;
|
|
1635
|
+
}
|
|
1636
|
+
function validSpreadsheetTableStructureChange(change) {
|
|
1637
|
+
if ('insert' === change.kind) return Number.isSafeInteger(change.index) && change.index >= 0 && Number.isSafeInteger(change.count) && change.count > 0;
|
|
1638
|
+
return Number.isSafeInteger(change.start) && change.start >= 0 && Number.isSafeInteger(change.end) && change.end >= change.start;
|
|
1639
|
+
}
|
|
1640
|
+
function sourceSheetForReconciliation(sheet, sourceSheets, index) {
|
|
1641
|
+
return (sheet.id ? sourceSheets.find((candidate)=>candidate.id === sheet.id) : void 0) ?? sourceSheets[index];
|
|
1642
|
+
}
|
|
1643
|
+
function spreadsheetSheetCellReader(sheet) {
|
|
1644
|
+
if (void 0 !== sheet.data) return (row, column)=>sheet.data?.[row]?.[column] ?? null;
|
|
1645
|
+
const cells = new Map((sheet.celldata ?? []).map((entry)=>[
|
|
1646
|
+
`${entry.r}:${entry.c}`,
|
|
1647
|
+
entry.v
|
|
1648
|
+
]));
|
|
1649
|
+
return (row, column)=>cells.get(`${row}:${column}`) ?? null;
|
|
1650
|
+
}
|
|
1651
|
+
function stampSpreadsheetTableHeaderCells(sheet, updates) {
|
|
1652
|
+
if (!updates.length) return sheet;
|
|
1653
|
+
if (void 0 !== sheet.data) {
|
|
1654
|
+
const data = [];
|
|
1655
|
+
data.length = sheet.data.length;
|
|
1656
|
+
for (const [row, value] of sparseArrayEntries(sheet.data))data[row] = value;
|
|
1657
|
+
const mutableRows = new Map();
|
|
1658
|
+
for (const update of updates){
|
|
1659
|
+
let row = mutableRows.get(update.row);
|
|
1660
|
+
if (!row) {
|
|
1661
|
+
const source = data[update.row];
|
|
1662
|
+
row = [];
|
|
1663
|
+
row.length = source?.length ?? 0;
|
|
1664
|
+
for (const column of sparseArrayIndexes(source))row[column] = source?.[column];
|
|
1665
|
+
mutableRows.set(update.row, row);
|
|
1666
|
+
data[update.row] = row;
|
|
1667
|
+
}
|
|
1668
|
+
row[update.column] = stampSpreadsheetTableHeaderCell(row[update.column], update.name);
|
|
1669
|
+
}
|
|
1670
|
+
return {
|
|
1671
|
+
...sheet,
|
|
1672
|
+
data
|
|
1673
|
+
};
|
|
1674
|
+
}
|
|
1675
|
+
const celldata = [
|
|
1676
|
+
...sheet.celldata ?? []
|
|
1677
|
+
];
|
|
1678
|
+
const indexes = new Map(celldata.map((entry, index)=>[
|
|
1679
|
+
`${entry.r}:${entry.c}`,
|
|
1680
|
+
index
|
|
1681
|
+
]));
|
|
1682
|
+
for (const update of updates){
|
|
1683
|
+
const key = `${update.row}:${update.column}`;
|
|
1684
|
+
const index = indexes.get(key);
|
|
1685
|
+
const source = void 0 === index ? void 0 : celldata[index];
|
|
1686
|
+
const entry = {
|
|
1687
|
+
r: update.row,
|
|
1688
|
+
c: update.column,
|
|
1689
|
+
v: stampSpreadsheetTableHeaderCell(source?.v, update.name)
|
|
1690
|
+
};
|
|
1691
|
+
if (void 0 === index) {
|
|
1692
|
+
indexes.set(key, celldata.length);
|
|
1693
|
+
celldata.push(entry);
|
|
1694
|
+
} else celldata[index] = entry;
|
|
1695
|
+
}
|
|
1696
|
+
return {
|
|
1697
|
+
...sheet,
|
|
1698
|
+
celldata
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
function stampSpreadsheetTableHeaderCell(cell, name) {
|
|
1702
|
+
return {
|
|
1703
|
+
...cell ?? {},
|
|
1704
|
+
m: name,
|
|
1705
|
+
v: name
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1708
|
+
function spreadsheetCellText(cell) {
|
|
1709
|
+
const value = cell?.m ?? cell?.v;
|
|
1710
|
+
return null == value ? '' : String(value);
|
|
1711
|
+
}
|
|
1712
|
+
function validSpreadsheetTableColumnName(name) {
|
|
1713
|
+
const characters = Array.from(name);
|
|
1714
|
+
return name.trim() === name && characters.length >= 1 && characters.length <= 255 && !characters.some((character)=>/\p{Cc}/u.test(character) || '\uFFFE' === character || '\uFFFF' === character);
|
|
1715
|
+
}
|
|
1716
|
+
function truncateSpreadsheetTableColumnName(value, maximum) {
|
|
1717
|
+
return Array.from(value).slice(0, maximum).join('');
|
|
1718
|
+
}
|
|
1719
|
+
function sameSpreadsheetTableColumns(left, right) {
|
|
1720
|
+
return left.length === right.length && left.every((column, index)=>column.name === right[index]?.name);
|
|
1721
|
+
}
|
|
1722
|
+
function spreadsheet_table_reconciliation_isRecord(value) {
|
|
1723
|
+
return Boolean(value && 'object' == typeof value && !Array.isArray(value));
|
|
1724
|
+
}
|
|
1376
1725
|
function spreadsheetSelectionReference(selection) {
|
|
1377
1726
|
const rowStart = Math.min(selection.row[0] ?? 0, selection.row[1] ?? selection.row[0] ?? 0);
|
|
1378
1727
|
const rowEnd = Math.max(selection.row[0] ?? 0, selection.row[1] ?? selection.row[0] ?? 0);
|
|
@@ -1622,7 +1971,7 @@ function spreadsheetSheetsFromFortune(sheets, sourceSheets, operations = []) {
|
|
|
1622
1971
|
incremental: true,
|
|
1623
1972
|
operationCount: operations.length
|
|
1624
1973
|
});
|
|
1625
|
-
return incremental.sheets;
|
|
1974
|
+
return reconcileSpreadsheetTablesAfterFortune(incremental.sheets, sourceSheets, operations);
|
|
1626
1975
|
}
|
|
1627
1976
|
const projected = sheets.map((sheet, index)=>{
|
|
1628
1977
|
const source = (sheet.id ? sourceSheets.find((candidate)=>candidate.id === sheet.id) : void 0) ?? sourceSheets[index];
|
|
@@ -1651,7 +2000,7 @@ function spreadsheetSheetsFromFortune(sheets, sourceSheets, operations = []) {
|
|
|
1651
2000
|
incremental: false,
|
|
1652
2001
|
operationCount: operations.length
|
|
1653
2002
|
});
|
|
1654
|
-
return projected;
|
|
2003
|
+
return reconcileSpreadsheetTablesAfterFortune(projected, sourceSheets, operations);
|
|
1655
2004
|
}
|
|
1656
2005
|
function recordSpreadsheetControlledProjectionMeasure(start, end, detail) {
|
|
1657
2006
|
try {
|
|
@@ -2289,6 +2638,12 @@ const spreadsheetRibbonTabs = [
|
|
|
2289
2638
|
label: '视图'
|
|
2290
2639
|
}
|
|
2291
2640
|
];
|
|
2641
|
+
const spreadsheetTableDesignRibbonTab = {
|
|
2642
|
+
id: 'tableDesign',
|
|
2643
|
+
label: '表格设计',
|
|
2644
|
+
compactLabel: '设计',
|
|
2645
|
+
contextual: true
|
|
2646
|
+
};
|
|
2292
2647
|
const spreadsheetCommandCatalog = {
|
|
2293
2648
|
undo: {
|
|
2294
2649
|
id: 'history.undo',
|
|
@@ -2456,6 +2811,40 @@ const spreadsheetCommandCatalog = {
|
|
|
2456
2811
|
]
|
|
2457
2812
|
}
|
|
2458
2813
|
},
|
|
2814
|
+
growFont: {
|
|
2815
|
+
id: 'font.grow',
|
|
2816
|
+
label: '增大字号',
|
|
2817
|
+
location: {
|
|
2818
|
+
area: 'ribbon',
|
|
2819
|
+
tab: 'home',
|
|
2820
|
+
group: 'font'
|
|
2821
|
+
},
|
|
2822
|
+
shortcut: {
|
|
2823
|
+
label: 'Cmd/Ctrl+Shift+. 或 Cmd/Ctrl+]',
|
|
2824
|
+
aria: 'Control+Shift+. Meta+Shift+. Control+] Meta+]',
|
|
2825
|
+
editor: [
|
|
2826
|
+
'Mod-Shift-.',
|
|
2827
|
+
'Mod-]'
|
|
2828
|
+
]
|
|
2829
|
+
}
|
|
2830
|
+
},
|
|
2831
|
+
shrinkFont: {
|
|
2832
|
+
id: 'font.shrink',
|
|
2833
|
+
label: '减小字号',
|
|
2834
|
+
location: {
|
|
2835
|
+
area: 'ribbon',
|
|
2836
|
+
tab: 'home',
|
|
2837
|
+
group: 'font'
|
|
2838
|
+
},
|
|
2839
|
+
shortcut: {
|
|
2840
|
+
label: 'Cmd/Ctrl+Shift+, 或 Cmd/Ctrl+[',
|
|
2841
|
+
aria: 'Control+Shift+, Meta+Shift+, Control+[ Meta+[',
|
|
2842
|
+
editor: [
|
|
2843
|
+
'Mod-Shift-,',
|
|
2844
|
+
'Mod-['
|
|
2845
|
+
]
|
|
2846
|
+
}
|
|
2847
|
+
},
|
|
2459
2848
|
numberFormatGeneral: {
|
|
2460
2849
|
id: 'number.general',
|
|
2461
2850
|
label: spreadsheetNumberFormatPresetLabels.general,
|
|
@@ -2672,6 +3061,14 @@ const spreadsheetCommandCatalog = {
|
|
|
2672
3061
|
area: 'ribbon',
|
|
2673
3062
|
tab: 'home',
|
|
2674
3063
|
group: 'font'
|
|
3064
|
+
},
|
|
3065
|
+
shortcut: {
|
|
3066
|
+
label: 'Cmd/Ctrl+Shift+_',
|
|
3067
|
+
aria: 'Control+Shift+_ Meta+Shift+_',
|
|
3068
|
+
editor: [
|
|
3069
|
+
'Mod-Shift-_',
|
|
3070
|
+
'Mod-Shift-Minus'
|
|
3071
|
+
]
|
|
2675
3072
|
}
|
|
2676
3073
|
},
|
|
2677
3074
|
borderAll: {
|
|
@@ -2690,6 +3087,14 @@ const spreadsheetCommandCatalog = {
|
|
|
2690
3087
|
area: 'ribbon',
|
|
2691
3088
|
tab: 'home',
|
|
2692
3089
|
group: 'font'
|
|
3090
|
+
},
|
|
3091
|
+
shortcut: {
|
|
3092
|
+
label: 'Cmd/Ctrl+Shift+&',
|
|
3093
|
+
aria: 'Control+Shift+& Meta+Shift+&',
|
|
3094
|
+
editor: [
|
|
3095
|
+
'Mod-Shift-&',
|
|
3096
|
+
'Mod-Shift-7'
|
|
3097
|
+
]
|
|
2693
3098
|
}
|
|
2694
3099
|
},
|
|
2695
3100
|
borderInside: {
|
|
@@ -3058,6 +3463,22 @@ const spreadsheetCommandCatalog = {
|
|
|
3058
3463
|
group: 'charts'
|
|
3059
3464
|
}
|
|
3060
3465
|
},
|
|
3466
|
+
table: {
|
|
3467
|
+
id: 'insert.table',
|
|
3468
|
+
label: '表格',
|
|
3469
|
+
location: {
|
|
3470
|
+
area: 'ribbon',
|
|
3471
|
+
tab: 'insert',
|
|
3472
|
+
group: 'tables'
|
|
3473
|
+
},
|
|
3474
|
+
shortcut: {
|
|
3475
|
+
label: 'Cmd/Ctrl+T',
|
|
3476
|
+
aria: 'Control+T Meta+T',
|
|
3477
|
+
editor: [
|
|
3478
|
+
'Mod-t'
|
|
3479
|
+
]
|
|
3480
|
+
}
|
|
3481
|
+
},
|
|
3061
3482
|
hyperlink: {
|
|
3062
3483
|
id: 'insert.hyperlink',
|
|
3063
3484
|
label: '超链接',
|
|
@@ -3477,6 +3898,8 @@ function spreadsheet_cell_clear_isRecord(value) {
|
|
|
3477
3898
|
return Boolean(value && 'object' == typeof value && !Array.isArray(value));
|
|
3478
3899
|
}
|
|
3479
3900
|
function createSpreadsheetCellBorderExtension() {
|
|
3901
|
+
const outsideShortcuts = spreadsheetCommandCatalog.borderOutside.shortcut.editor;
|
|
3902
|
+
const noneShortcuts = spreadsheetCommandCatalog.borderNone.shortcut.editor;
|
|
3480
3903
|
return createOfficeEditorExtension({
|
|
3481
3904
|
name: 'spreadsheetCellBorders',
|
|
3482
3905
|
addCommands: ()=>({
|
|
@@ -3484,6 +3907,28 @@ function createSpreadsheetCellBorderExtension() {
|
|
|
3484
3907
|
canExecute: canSetSelectedCellBorders,
|
|
3485
3908
|
execute: setSelectedCellBorders
|
|
3486
3909
|
}
|
|
3910
|
+
}),
|
|
3911
|
+
addKeyboardShortcuts: ()=>({
|
|
3912
|
+
[outsideShortcuts[0]]: ({ can, commands }, event)=>runSpreadsheetBorderShortcut(event, can.setSelectedCellBorders, commands.setSelectedCellBorders, {
|
|
3913
|
+
target: 'outside',
|
|
3914
|
+
color: '#000000',
|
|
3915
|
+
style: 'thin'
|
|
3916
|
+
}),
|
|
3917
|
+
[outsideShortcuts[1]]: ({ can, commands }, event)=>runSpreadsheetBorderShortcut(event, can.setSelectedCellBorders, commands.setSelectedCellBorders, {
|
|
3918
|
+
target: 'outside',
|
|
3919
|
+
color: '#000000',
|
|
3920
|
+
style: 'thin'
|
|
3921
|
+
}),
|
|
3922
|
+
[noneShortcuts[0]]: ({ can, commands }, event)=>runSpreadsheetBorderShortcut(event, can.setSelectedCellBorders, commands.setSelectedCellBorders, {
|
|
3923
|
+
target: 'none',
|
|
3924
|
+
color: '#000000',
|
|
3925
|
+
style: 'thin'
|
|
3926
|
+
}),
|
|
3927
|
+
[noneShortcuts[1]]: ({ can, commands }, event)=>runSpreadsheetBorderShortcut(event, can.setSelectedCellBorders, commands.setSelectedCellBorders, {
|
|
3928
|
+
target: 'none',
|
|
3929
|
+
color: '#000000',
|
|
3930
|
+
style: 'thin'
|
|
3931
|
+
})
|
|
3487
3932
|
})
|
|
3488
3933
|
});
|
|
3489
3934
|
}
|
|
@@ -3491,15 +3936,22 @@ function canSetSelectedCellBorders(context, format) {
|
|
|
3491
3936
|
return Boolean(context.editable && context.workbook && context.targetSheetId && canSetSpreadsheetCellBorders(context.content, context.targetSheetId, liveSpreadsheetBorderRange(context), format));
|
|
3492
3937
|
}
|
|
3493
3938
|
function setSelectedCellBorders(context, format) {
|
|
3494
|
-
if (!
|
|
3495
|
-
const
|
|
3939
|
+
if (!context.editable || !context.workbook || !context.targetSheetId) return false;
|
|
3940
|
+
const selection = context.workbook.getSelection()?.at(-1) ?? context.fallbackRange;
|
|
3941
|
+
const range = spreadsheetSingleRange(selection);
|
|
3942
|
+
if (!canSetSpreadsheetCellBorders(context.content, context.targetSheetId, range, format)) return false;
|
|
3943
|
+
const next = setSpreadsheetCellBorders(context.content, context.targetSheetId, range, format);
|
|
3496
3944
|
if (!next) return false;
|
|
3497
|
-
context.onChange(next);
|
|
3945
|
+
context.onChange(spreadsheetContentWithSelection(next, context.targetSheetId, selection));
|
|
3498
3946
|
return true;
|
|
3499
3947
|
}
|
|
3500
3948
|
function liveSpreadsheetBorderRange(context) {
|
|
3501
3949
|
return spreadsheetSingleRange(context.workbook?.getSelection()?.at(-1) ?? context.fallbackRange);
|
|
3502
3950
|
}
|
|
3951
|
+
function runSpreadsheetBorderShortcut(event, canExecute, execute, format) {
|
|
3952
|
+
if (event.repeat || isOfficeShortcutBlocked(event.target) || isSpreadsheetNativeTextUndoTarget(event.target) || !canExecute(format)) return false;
|
|
3953
|
+
return execute(format);
|
|
3954
|
+
}
|
|
3503
3955
|
const MAX_SPREADSHEET_PER_CELL_BORDER_CELLS = 10000;
|
|
3504
3956
|
function setSpreadsheetCellBordersPerCell(content, sheetId, range, formats) {
|
|
3505
3957
|
const normalizedRange = spreadsheet_cell_range_normalizeSpreadsheetCellRange(range);
|
|
@@ -4354,76 +4806,227 @@ function spreadsheetSelectedCellFillPlan(context, direction) {
|
|
|
4354
4806
|
const sheet = context.content.sheets.find((candidate)=>candidate.id === context.targetSheetId);
|
|
4355
4807
|
return canApplySpreadsheetCellFill(sheet, plan) ? plan : null;
|
|
4356
4808
|
}
|
|
4357
|
-
const
|
|
4358
|
-
|
|
4359
|
-
const
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
if (!named.value) return spreadsheetGoToError('invalid-reference');
|
|
4377
|
-
const fallbackSheet = named.value.scopeSheetId ? content.sheets.find((sheet)=>sheet.id === named.value?.scopeSheetId) : requestedSheet ?? activeSheet;
|
|
4378
|
-
if (!fallbackSheet) return spreadsheetGoToError('sheet-not-found');
|
|
4379
|
-
if (1 === fallbackSheet.hide) return spreadsheetGoToError('hidden-sheet');
|
|
4380
|
-
const namedReference = splitSpreadsheetQualifiedReference(named.value.reference.trim().replace(/^=/, '').trim());
|
|
4381
|
-
if (!namedReference) return spreadsheetGoToError('unsupported-name');
|
|
4382
|
-
const resolved = resolveSpreadsheetDirectRange(content, fallbackSheet, namedReference);
|
|
4383
|
-
if ('error' === resolved.kind) return spreadsheetGoToError(resolved.code);
|
|
4384
|
-
if ('match' !== resolved.kind) return spreadsheetGoToError('unsupported-name');
|
|
4385
|
-
return spreadsheetGoToSuccess(resolved.value, 'named-range', named.value.name);
|
|
4386
|
-
}
|
|
4387
|
-
function spreadsheetGoToValidationMessage(content, activeSheetId, input) {
|
|
4388
|
-
const resolution = resolveSpreadsheetGoToTarget(content, activeSheetId, input);
|
|
4389
|
-
return resolution.ok ? null : resolution.message;
|
|
4809
|
+
const MAX_SPREADSHEET_FONT_SIZE_CELLS = 10000;
|
|
4810
|
+
function createSpreadsheetFontSizeExtension() {
|
|
4811
|
+
const growShortcuts = spreadsheetCommandCatalog.growFont.shortcut.editor;
|
|
4812
|
+
const shrinkShortcuts = spreadsheetCommandCatalog.shrinkFont.shortcut.editor;
|
|
4813
|
+
return createOfficeEditorExtension({
|
|
4814
|
+
name: 'spreadsheetFontSize',
|
|
4815
|
+
addCommands: ()=>({
|
|
4816
|
+
adjustFontSize: {
|
|
4817
|
+
canExecute: canAdjustSelectedFontSize,
|
|
4818
|
+
execute: adjustSelectedFontSize
|
|
4819
|
+
}
|
|
4820
|
+
}),
|
|
4821
|
+
addKeyboardShortcuts: ()=>({
|
|
4822
|
+
[growShortcuts[0]]: ({ can, commands }, event)=>runSpreadsheetFontSizeShortcut(event, can.adjustFontSize, commands.adjustFontSize, 'grow'),
|
|
4823
|
+
[growShortcuts[1]]: ({ can, commands }, event)=>runSpreadsheetFontSizeShortcut(event, can.adjustFontSize, commands.adjustFontSize, 'grow'),
|
|
4824
|
+
[shrinkShortcuts[0]]: ({ can, commands }, event)=>runSpreadsheetFontSizeShortcut(event, can.adjustFontSize, commands.adjustFontSize, 'shrink'),
|
|
4825
|
+
[shrinkShortcuts[1]]: ({ can, commands }, event)=>runSpreadsheetFontSizeShortcut(event, can.adjustFontSize, commands.adjustFontSize, 'shrink')
|
|
4826
|
+
})
|
|
4827
|
+
});
|
|
4390
4828
|
}
|
|
4391
|
-
function
|
|
4392
|
-
const
|
|
4393
|
-
if (!
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
const range = ranges[0];
|
|
4410
|
-
if (!range || !spreadsheetGoToRangeIsBounded(sheet, range)) return {
|
|
4411
|
-
kind: 'error',
|
|
4412
|
-
code: 'out-of-bounds'
|
|
4413
|
-
};
|
|
4414
|
-
return {
|
|
4415
|
-
kind: 'match',
|
|
4416
|
-
value: {
|
|
4417
|
-
range,
|
|
4418
|
-
sheet
|
|
4829
|
+
function spreadsheetFontSizeApiCalls(cells, range, sheetId, direction) {
|
|
4830
|
+
const normalizedRange = spreadsheet_cell_range_normalizeSpreadsheetCellRange(range);
|
|
4831
|
+
if (!normalizedRange || !sheetId || !isSpreadsheetFontSizeDirection(direction) || spreadsheet_cell_range_spreadsheetCellRangeArea(normalizedRange) > MAX_SPREADSHEET_FONT_SIZE_CELLS) return [];
|
|
4832
|
+
const rectangles = [];
|
|
4833
|
+
let active = new Map();
|
|
4834
|
+
const rowCount = normalizedRange.row[1] - normalizedRange.row[0] + 1;
|
|
4835
|
+
const columnCount = normalizedRange.column[1] - normalizedRange.column[0] + 1;
|
|
4836
|
+
for(let rowOffset = 0; rowOffset < rowCount; rowOffset += 1){
|
|
4837
|
+
const row = normalizedRange.row[0] + rowOffset;
|
|
4838
|
+
const runs = spreadsheetFontSizeRowRuns(cells[rowOffset], row, normalizedRange.column[0], columnCount, direction);
|
|
4839
|
+
const nextActive = new Map();
|
|
4840
|
+
for (const run of runs){
|
|
4841
|
+
const signature = `${run.key}:${run.range.column[0]}:${run.range.column[1]}`;
|
|
4842
|
+
const previous = active.get(signature);
|
|
4843
|
+
if (previous && previous.range.row[1] === row - 1) {
|
|
4844
|
+
previous.range.row[1] = row;
|
|
4845
|
+
nextActive.set(signature, previous);
|
|
4846
|
+
} else nextActive.set(signature, run);
|
|
4419
4847
|
}
|
|
4420
|
-
|
|
4848
|
+
for (const [signature, run] of active)if (!nextActive.has(signature)) rectangles.push(run);
|
|
4849
|
+
active = nextActive;
|
|
4850
|
+
}
|
|
4851
|
+
rectangles.push(...active.values());
|
|
4852
|
+
rectangles.sort((left, right)=>left.range.row[0] - right.range.row[0] || left.range.column[0] - right.range.column[0] || left.range.row[1] - right.range.row[1] || left.range.column[1] - right.range.column[1]);
|
|
4853
|
+
return rectangles.map(({ range: targetRange, size })=>({
|
|
4854
|
+
name: 'setCellFormatByRange',
|
|
4855
|
+
args: [
|
|
4856
|
+
'fs',
|
|
4857
|
+
size,
|
|
4858
|
+
targetRange,
|
|
4859
|
+
{
|
|
4860
|
+
id: sheetId
|
|
4861
|
+
}
|
|
4862
|
+
]
|
|
4863
|
+
}));
|
|
4421
4864
|
}
|
|
4422
|
-
function
|
|
4423
|
-
const
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4865
|
+
function spreadsheetFontSizeRowRuns(cells, row, firstColumn, columnCount, direction) {
|
|
4866
|
+
const runs = [];
|
|
4867
|
+
let current = null;
|
|
4868
|
+
for(let columnOffset = 0; columnOffset < columnCount; columnOffset += 1){
|
|
4869
|
+
const column = firstColumn + columnOffset;
|
|
4870
|
+
const size = adjustedSpreadsheetFontSize(cells?.[columnOffset], direction);
|
|
4871
|
+
if (null === size) {
|
|
4872
|
+
if (current) runs.push(current);
|
|
4873
|
+
current = null;
|
|
4874
|
+
continue;
|
|
4875
|
+
}
|
|
4876
|
+
const key = String(size);
|
|
4877
|
+
if (current && current.key === key) {
|
|
4878
|
+
current.range.column[1] = column;
|
|
4879
|
+
continue;
|
|
4880
|
+
}
|
|
4881
|
+
if (current) runs.push(current);
|
|
4882
|
+
current = {
|
|
4883
|
+
key,
|
|
4884
|
+
range: {
|
|
4885
|
+
row: [
|
|
4886
|
+
row,
|
|
4887
|
+
row
|
|
4888
|
+
],
|
|
4889
|
+
column: [
|
|
4890
|
+
column,
|
|
4891
|
+
column
|
|
4892
|
+
]
|
|
4893
|
+
},
|
|
4894
|
+
size
|
|
4895
|
+
};
|
|
4896
|
+
}
|
|
4897
|
+
if (current) runs.push(current);
|
|
4898
|
+
return runs;
|
|
4899
|
+
}
|
|
4900
|
+
function adjustedSpreadsheetFontSize(cell, direction) {
|
|
4901
|
+
const size = cell?.fs === void 0 ? 10 : Number(cell.fs);
|
|
4902
|
+
return nextSpreadsheetFontSize(size, direction);
|
|
4903
|
+
}
|
|
4904
|
+
function canAdjustSelectedFontSize(context, direction) {
|
|
4905
|
+
const workbook = context.workbook;
|
|
4906
|
+
const sheetId = context.targetSheetId;
|
|
4907
|
+
if (!context.editable || !workbook || !sheetId || sheetId !== context.activeSheetId || !isSpreadsheetFontSizeDirection(direction)) return false;
|
|
4908
|
+
const range = liveSpreadsheetFontSizeRange(context);
|
|
4909
|
+
if (spreadsheet_cell_range_spreadsheetCellRangeArea(range) > MAX_SPREADSHEET_FONT_SIZE_CELLS) return false;
|
|
4910
|
+
try {
|
|
4911
|
+
const cells = workbook.getCellsByRange(range, {
|
|
4912
|
+
id: sheetId
|
|
4913
|
+
});
|
|
4914
|
+
return canAdjustSpreadsheetFontSizeCells(range.row[1] - range.row[0] + 1, range.column[1] - range.column[0] + 1, (rowOffset, columnOffset)=>cells[rowOffset]?.[columnOffset] ?? null, direction);
|
|
4915
|
+
} catch {
|
|
4916
|
+
return false;
|
|
4917
|
+
}
|
|
4918
|
+
}
|
|
4919
|
+
function adjustSelectedFontSize(context, direction) {
|
|
4920
|
+
const workbook = context.workbook;
|
|
4921
|
+
const sheetId = context.targetSheetId;
|
|
4922
|
+
if (!context.editable || !workbook || !sheetId || sheetId !== context.activeSheetId || !isSpreadsheetFontSizeDirection(direction)) return false;
|
|
4923
|
+
const range = liveSpreadsheetFontSizeRange(context);
|
|
4924
|
+
if (spreadsheet_cell_range_spreadsheetCellRangeArea(range) > MAX_SPREADSHEET_FONT_SIZE_CELLS) return false;
|
|
4925
|
+
try {
|
|
4926
|
+
const cells = workbook.getCellsByRange(range, {
|
|
4927
|
+
id: sheetId
|
|
4928
|
+
});
|
|
4929
|
+
const calls = spreadsheetFontSizeApiCalls(cells, range, sheetId, direction);
|
|
4930
|
+
if (!calls.length) return false;
|
|
4931
|
+
workbook.batchCallApis(calls);
|
|
4932
|
+
return true;
|
|
4933
|
+
} catch {
|
|
4934
|
+
return false;
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4937
|
+
function canAdjustSpreadsheetFontSizeCells(rowCount, columnCount, cellAt, direction) {
|
|
4938
|
+
for(let rowOffset = 0; rowOffset < rowCount; rowOffset += 1)for(let columnOffset = 0; columnOffset < columnCount; columnOffset += 1)if (null !== adjustedSpreadsheetFontSize(cellAt(rowOffset, columnOffset), direction)) return true;
|
|
4939
|
+
return false;
|
|
4940
|
+
}
|
|
4941
|
+
function liveSpreadsheetFontSizeRange(context) {
|
|
4942
|
+
return spreadsheet_cell_range_normalizeSpreadsheetCellRange(spreadsheetSingleRange(context.workbook?.getSelection()?.at(-1) ?? context.fallbackRange)) ?? {
|
|
4943
|
+
row: [
|
|
4944
|
+
0,
|
|
4945
|
+
0
|
|
4946
|
+
],
|
|
4947
|
+
column: [
|
|
4948
|
+
0,
|
|
4949
|
+
0
|
|
4950
|
+
]
|
|
4951
|
+
};
|
|
4952
|
+
}
|
|
4953
|
+
function isSpreadsheetFontSizeDirection(value) {
|
|
4954
|
+
return 'grow' === value || 'shrink' === value;
|
|
4955
|
+
}
|
|
4956
|
+
function runSpreadsheetFontSizeShortcut(event, canExecute, execute, direction) {
|
|
4957
|
+
if (event.repeat || isOfficeShortcutBlocked(event.target) || isSpreadsheetNativeTextUndoTarget(event.target) || !canExecute(direction)) return false;
|
|
4958
|
+
return execute(direction);
|
|
4959
|
+
}
|
|
4960
|
+
const spreadsheet_go_to_spreadsheetMaximumRows = 1048576;
|
|
4961
|
+
const spreadsheet_go_to_spreadsheetMaximumColumns = 16384;
|
|
4962
|
+
const spreadsheetGoToMaximumInputLength = 512;
|
|
4963
|
+
function resolveSpreadsheetGoToTarget(content, activeSheetId, input) {
|
|
4964
|
+
const value = input.trim().replace(/^=/, '').trim();
|
|
4965
|
+
if (!value) return spreadsheetGoToError('empty');
|
|
4966
|
+
if (value.length > spreadsheetGoToMaximumInputLength) return spreadsheetGoToError('invalid-reference');
|
|
4967
|
+
const activeSheet = content.sheets.find((sheet)=>sheet.id === activeSheetId);
|
|
4968
|
+
if (!activeSheet) return spreadsheetGoToError('sheet-not-found');
|
|
4969
|
+
const qualified = splitSpreadsheetQualifiedReference(value);
|
|
4970
|
+
if (!qualified) return spreadsheetGoToError('invalid-reference');
|
|
4971
|
+
const requestedSheet = qualified.qualifier ? spreadsheetSheetByName(content, qualified.qualifier) : activeSheet;
|
|
4972
|
+
if (qualified.qualifier && !requestedSheet) return spreadsheetGoToError('sheet-not-found');
|
|
4973
|
+
if (requestedSheet?.hide === 1) return spreadsheetGoToError('hidden-sheet');
|
|
4974
|
+
const direct = resolveSpreadsheetDirectRange(content, requestedSheet ?? activeSheet, qualified);
|
|
4975
|
+
if ('error' === direct.kind) return spreadsheetGoToError(direct.code);
|
|
4976
|
+
if ('match' === direct.kind) return spreadsheetGoToSuccess(direct.value, 'reference');
|
|
4977
|
+
const named = findSpreadsheetGoToName(content, qualified.reference, requestedSheet ?? activeSheet, Boolean(qualified.qualifier));
|
|
4978
|
+
if ('error' === named.kind) return spreadsheetGoToError(named.code);
|
|
4979
|
+
if (!named.value) return spreadsheetGoToError('invalid-reference');
|
|
4980
|
+
const fallbackSheet = named.value.scopeSheetId ? content.sheets.find((sheet)=>sheet.id === named.value?.scopeSheetId) : requestedSheet ?? activeSheet;
|
|
4981
|
+
if (!fallbackSheet) return spreadsheetGoToError('sheet-not-found');
|
|
4982
|
+
if (1 === fallbackSheet.hide) return spreadsheetGoToError('hidden-sheet');
|
|
4983
|
+
const namedReference = splitSpreadsheetQualifiedReference(named.value.reference.trim().replace(/^=/, '').trim());
|
|
4984
|
+
if (!namedReference) return spreadsheetGoToError('unsupported-name');
|
|
4985
|
+
const resolved = resolveSpreadsheetDirectRange(content, fallbackSheet, namedReference);
|
|
4986
|
+
if ('error' === resolved.kind) return spreadsheetGoToError(resolved.code);
|
|
4987
|
+
if ('match' !== resolved.kind) return spreadsheetGoToError('unsupported-name');
|
|
4988
|
+
return spreadsheetGoToSuccess(resolved.value, 'named-range', named.value.name);
|
|
4989
|
+
}
|
|
4990
|
+
function spreadsheetGoToValidationMessage(content, activeSheetId, input) {
|
|
4991
|
+
const resolution = resolveSpreadsheetGoToTarget(content, activeSheetId, input);
|
|
4992
|
+
return resolution.ok ? null : resolution.message;
|
|
4993
|
+
}
|
|
4994
|
+
function resolveSpreadsheetDirectRange(content, fallbackSheet, qualified) {
|
|
4995
|
+
const sheet = qualified.qualifier ? spreadsheetSheetByName(content, qualified.qualifier) : fallbackSheet;
|
|
4996
|
+
if (!sheet) return {
|
|
4997
|
+
kind: 'error',
|
|
4998
|
+
code: 'sheet-not-found'
|
|
4999
|
+
};
|
|
5000
|
+
if (1 === sheet.hide) return {
|
|
5001
|
+
kind: 'error',
|
|
5002
|
+
code: 'hidden-sheet'
|
|
5003
|
+
};
|
|
5004
|
+
const ranges = parseSpreadsheetCellRanges(qualified.reference);
|
|
5005
|
+
if (!ranges) return {
|
|
5006
|
+
kind: 'miss'
|
|
5007
|
+
};
|
|
5008
|
+
if (1 !== ranges.length) return {
|
|
5009
|
+
kind: 'error',
|
|
5010
|
+
code: 'multiple-ranges'
|
|
5011
|
+
};
|
|
5012
|
+
const range = ranges[0];
|
|
5013
|
+
if (!range || !spreadsheetGoToRangeIsBounded(sheet, range)) return {
|
|
5014
|
+
kind: 'error',
|
|
5015
|
+
code: 'out-of-bounds'
|
|
5016
|
+
};
|
|
5017
|
+
return {
|
|
5018
|
+
kind: 'match',
|
|
5019
|
+
value: {
|
|
5020
|
+
range,
|
|
5021
|
+
sheet
|
|
5022
|
+
}
|
|
5023
|
+
};
|
|
5024
|
+
}
|
|
5025
|
+
function findSpreadsheetGoToName(content, input, scopeSheet, qualified) {
|
|
5026
|
+
const normalized = input.trim().toLocaleLowerCase();
|
|
5027
|
+
const matching = (content.namedRanges ?? []).filter((range)=>range.name.trim().toLocaleLowerCase() === normalized);
|
|
5028
|
+
const scoped = matching.filter((range)=>range.scopeSheetId === scopeSheet.id);
|
|
5029
|
+
const workbook = matching.filter((range)=>!range.scopeSheetId);
|
|
4427
5030
|
const preferred = scoped.length ? scoped : workbook;
|
|
4428
5031
|
if (preferred.length > 1) return {
|
|
4429
5032
|
kind: 'error',
|
|
@@ -5048,11 +5651,15 @@ function canApplySpreadsheetCellMerge(sheet, range, command) {
|
|
|
5048
5651
|
const merged = spreadsheetMergesIntersectingRange(sheet, normalized);
|
|
5049
5652
|
if ('unmerge-cells' === command || 'unmerge-and-fill' === command) return merged.length > 0;
|
|
5050
5653
|
if (merged.length > 0) return false;
|
|
5654
|
+
if (spreadsheetMergeIntersectsTable(sheet, normalized)) return false;
|
|
5051
5655
|
const rowCount = normalized.row[1] - normalized.row[0] + 1;
|
|
5052
5656
|
const columnCount = normalized.column[1] - normalized.column[0] + 1;
|
|
5053
5657
|
if ('merge-across' === command) return columnCount > 1;
|
|
5054
5658
|
return rowCount * columnCount > 1;
|
|
5055
5659
|
}
|
|
5660
|
+
function spreadsheetMergeIntersectsTable(sheet, range) {
|
|
5661
|
+
return (sheet.tables ?? []).some((table)=>table.range.row[0] <= range.row[1] && table.range.row[1] >= range.row[0] && table.range.column[0] <= range.column[1] && table.range.column[1] >= range.column[0]);
|
|
5662
|
+
}
|
|
5056
5663
|
function spreadsheetCellMergeApiCalls(sheet, sheetId, range, command) {
|
|
5057
5664
|
if (!canApplySpreadsheetCellMerge(sheet, range, command) || !sheet) return [];
|
|
5058
5665
|
const normalized = normalizeSpreadsheetCellMergeRange(range);
|
|
@@ -5943,54 +6550,946 @@ function orderedSpreadsheetSheets(sheets) {
|
|
|
5943
6550
|
index
|
|
5944
6551
|
})).sort((left, right)=>(left.sheet.order ?? left.index) - (right.sheet.order ?? right.index) || left.index - right.index).map(({ sheet })=>sheet);
|
|
5945
6552
|
}
|
|
5946
|
-
function nextSpreadsheetSheetIdentity(sheets) {
|
|
5947
|
-
const ids = new Set(sheets.map((sheet)=>sheet.id));
|
|
5948
|
-
const names = new Set(sheets.map((sheet)=>sheet.name));
|
|
5949
|
-
let ordinal = sheets.length + 1;
|
|
5950
|
-
while(ids.has(`sheet-${ordinal}`) || names.has(`工作表 ${ordinal}`))ordinal += 1;
|
|
6553
|
+
function nextSpreadsheetSheetIdentity(sheets) {
|
|
6554
|
+
const ids = new Set(sheets.map((sheet)=>sheet.id));
|
|
6555
|
+
const names = new Set(sheets.map((sheet)=>sheet.name));
|
|
6556
|
+
let ordinal = sheets.length + 1;
|
|
6557
|
+
while(ids.has(`sheet-${ordinal}`) || names.has(`工作表 ${ordinal}`))ordinal += 1;
|
|
6558
|
+
return {
|
|
6559
|
+
id: `sheet-${ordinal}`,
|
|
6560
|
+
name: `工作表 ${ordinal}`
|
|
6561
|
+
};
|
|
6562
|
+
}
|
|
6563
|
+
function uniqueSpreadsheetSheetName(sheets, preferred) {
|
|
6564
|
+
const names = new Set(sheets.map((sheet)=>sheet.name));
|
|
6565
|
+
if (!names.has(preferred)) return preferred;
|
|
6566
|
+
let suffix = 2;
|
|
6567
|
+
while(names.has(`${preferred} ${suffix}`))suffix += 1;
|
|
6568
|
+
return `${preferred} ${suffix}`;
|
|
6569
|
+
}
|
|
6570
|
+
function spreadsheetSelectionAfterStructureDeletion(selection, axis, extent, start, end) {
|
|
6571
|
+
const deletedCount = Math.max(1, end - start + 1);
|
|
6572
|
+
const remainingExtent = Math.max(1, extent - deletedCount);
|
|
6573
|
+
const focus = Math.min(Math.max(0, start), remainingExtent - 1);
|
|
6574
|
+
if ('row' === axis) return {
|
|
6575
|
+
...selection,
|
|
6576
|
+
row: [
|
|
6577
|
+
focus,
|
|
6578
|
+
focus
|
|
6579
|
+
],
|
|
6580
|
+
column: [
|
|
6581
|
+
...selection.column
|
|
6582
|
+
],
|
|
6583
|
+
...void 0 === selection.row_focus ? {} : {
|
|
6584
|
+
row_focus: focus
|
|
6585
|
+
}
|
|
6586
|
+
};
|
|
6587
|
+
return {
|
|
6588
|
+
...selection,
|
|
6589
|
+
row: [
|
|
6590
|
+
...selection.row
|
|
6591
|
+
],
|
|
6592
|
+
column: [
|
|
6593
|
+
focus,
|
|
6594
|
+
focus
|
|
6595
|
+
],
|
|
6596
|
+
...void 0 === selection.column_focus ? {} : {
|
|
6597
|
+
column_focus: focus
|
|
6598
|
+
}
|
|
6599
|
+
};
|
|
6600
|
+
}
|
|
6601
|
+
function spreadsheetAutoFilterRange(sheet, selection) {
|
|
6602
|
+
const range = spreadsheetSelectionOrCurrentRegion(sheet, selection);
|
|
6603
|
+
if (!range || !validSpreadsheetAutoFilterRange(sheet, range)) return null;
|
|
6604
|
+
return range;
|
|
6605
|
+
}
|
|
6606
|
+
function spreadsheetSelectionOrCurrentRegion(sheet, selection) {
|
|
6607
|
+
if (sheet.isPivotTable || sheet.pivotTables?.length) return null;
|
|
6608
|
+
const normalized = normalizeAutoFilterSelection(selection);
|
|
6609
|
+
return normalized.row[0] !== normalized.row[1] ? normalized : spreadsheetCurrentRegion(sheet, normalized);
|
|
6610
|
+
}
|
|
6611
|
+
function spreadsheetAutoFilterHeaderColumn(sheet, selection) {
|
|
6612
|
+
const range = normalizedFilterSelection(sheet?.filter_select);
|
|
6613
|
+
if (!sheet || !range) return null;
|
|
6614
|
+
const row = spreadsheet_auto_filter_finiteIndex(selection.row_focus, selection.row[0]);
|
|
6615
|
+
const column = spreadsheet_auto_filter_finiteIndex(selection.column_focus, selection.column[0]);
|
|
6616
|
+
if (row !== range.row[0] || column < range.column[0] || column > range.column[1]) return null;
|
|
6617
|
+
return column;
|
|
6618
|
+
}
|
|
6619
|
+
function toggleSpreadsheetAutoFilter(content, sheetId, selection) {
|
|
6620
|
+
const sheetIndex = content.sheets.findIndex((sheet)=>sheet.id === sheetId);
|
|
6621
|
+
const sheet = content.sheets[sheetIndex];
|
|
6622
|
+
if (!sheet) return null;
|
|
6623
|
+
const nextSheet = sheet.filter_select ? spreadsheetSheetWithoutAutoFilter(sheet) : spreadsheetSheetWithAutoFilter(sheet, selection);
|
|
6624
|
+
if (!nextSheet) return null;
|
|
6625
|
+
const sheets = [
|
|
6626
|
+
...content.sheets
|
|
6627
|
+
];
|
|
6628
|
+
sheets[sheetIndex] = {
|
|
6629
|
+
...nextSheet,
|
|
6630
|
+
luckysheet_select_save: [
|
|
6631
|
+
finiteSpreadsheetSelection(selection)
|
|
6632
|
+
]
|
|
6633
|
+
};
|
|
6634
|
+
return {
|
|
6635
|
+
...content,
|
|
6636
|
+
sheets
|
|
6637
|
+
};
|
|
6638
|
+
}
|
|
6639
|
+
function spreadsheetSheetWithAutoFilter(sheet, selection) {
|
|
6640
|
+
const range = spreadsheetAutoFilterRange(sheet, selection);
|
|
6641
|
+
if (!range) return null;
|
|
6642
|
+
return {
|
|
6643
|
+
...sheet,
|
|
6644
|
+
filter: {},
|
|
6645
|
+
filter_select: {
|
|
6646
|
+
row: [
|
|
6647
|
+
...range.row
|
|
6648
|
+
],
|
|
6649
|
+
column: [
|
|
6650
|
+
...range.column
|
|
6651
|
+
]
|
|
6652
|
+
}
|
|
6653
|
+
};
|
|
6654
|
+
}
|
|
6655
|
+
function spreadsheetSheetWithoutAutoFilter(sheet) {
|
|
6656
|
+
const hiddenByFilter = spreadsheetFilterHiddenRows(sheet.filter);
|
|
6657
|
+
const rowhidden = {
|
|
6658
|
+
...sheet.config?.rowhidden
|
|
6659
|
+
};
|
|
6660
|
+
for (const row of hiddenByFilter)delete rowhidden[row];
|
|
6661
|
+
const config = sheet.config ? {
|
|
6662
|
+
...sheet.config,
|
|
6663
|
+
rowhidden
|
|
6664
|
+
} : void 0;
|
|
6665
|
+
const { filter: _filter, filter_select: _selection, ...remaining } = sheet;
|
|
6666
|
+
return {
|
|
6667
|
+
...remaining,
|
|
6668
|
+
config
|
|
6669
|
+
};
|
|
6670
|
+
}
|
|
6671
|
+
function spreadsheetFilterHiddenRows(filter) {
|
|
6672
|
+
const rows = new Set();
|
|
6673
|
+
for (const value of Object.values(filter ?? {})){
|
|
6674
|
+
if (!value || 'object' != typeof value) continue;
|
|
6675
|
+
const rowhidden = value.rowhidden;
|
|
6676
|
+
if (rowhidden && 'object' == typeof rowhidden) for (const row of Object.keys(rowhidden))rows.add(row);
|
|
6677
|
+
}
|
|
6678
|
+
return rows;
|
|
6679
|
+
}
|
|
6680
|
+
function spreadsheetCurrentRegion(sheet, selection) {
|
|
6681
|
+
const cells = spreadsheetCellReader(sheet);
|
|
6682
|
+
const bounds = spreadsheetUsedBounds(sheet);
|
|
6683
|
+
let startRow = selection.row[0];
|
|
6684
|
+
let endRow = selection.row[1];
|
|
6685
|
+
let startColumn = selection.column[0];
|
|
6686
|
+
let endColumn = selection.column[1];
|
|
6687
|
+
if (startRow > bounds.lastRow || startColumn > bounds.lastColumn || !spreadsheet_auto_filter_spreadsheetCellHasContent(cells(startRow, startColumn))) return null;
|
|
6688
|
+
let changed = true;
|
|
6689
|
+
while(changed){
|
|
6690
|
+
changed = false;
|
|
6691
|
+
while(startColumn > 0 && spreadsheetColumnHasContent(cells, startColumn - 1, startRow, endRow)){
|
|
6692
|
+
startColumn -= 1;
|
|
6693
|
+
changed = true;
|
|
6694
|
+
}
|
|
6695
|
+
while(endColumn < bounds.lastColumn && spreadsheetColumnHasContent(cells, endColumn + 1, startRow, endRow)){
|
|
6696
|
+
endColumn += 1;
|
|
6697
|
+
changed = true;
|
|
6698
|
+
}
|
|
6699
|
+
while(startRow > 0 && spreadsheetRowHasContent(cells, startRow - 1, startColumn, endColumn)){
|
|
6700
|
+
startRow -= 1;
|
|
6701
|
+
changed = true;
|
|
6702
|
+
}
|
|
6703
|
+
while(endRow < bounds.lastRow && spreadsheetRowHasContent(cells, endRow + 1, startColumn, endColumn)){
|
|
6704
|
+
endRow += 1;
|
|
6705
|
+
changed = true;
|
|
6706
|
+
}
|
|
6707
|
+
}
|
|
6708
|
+
return {
|
|
6709
|
+
row: [
|
|
6710
|
+
startRow,
|
|
6711
|
+
endRow
|
|
6712
|
+
],
|
|
6713
|
+
column: [
|
|
6714
|
+
startColumn,
|
|
6715
|
+
endColumn
|
|
6716
|
+
]
|
|
6717
|
+
};
|
|
6718
|
+
}
|
|
6719
|
+
function validSpreadsheetAutoFilterRange(sheet, range) {
|
|
6720
|
+
if (range.row[1] <= range.row[0]) return false;
|
|
6721
|
+
if (spreadsheetAutoFilterIntersectsTable(sheet, range)) return false;
|
|
6722
|
+
const cells = spreadsheetCellReader(sheet);
|
|
6723
|
+
if (!spreadsheetRowHasContent(cells, range.row[0], range.column[0], range.column[1])) return false;
|
|
6724
|
+
let dataFound = false;
|
|
6725
|
+
for(let row = range.row[0] + 1; row <= range.row[1]; row += 1)if (spreadsheetRowHasContent(cells, row, range.column[0], range.column[1])) {
|
|
6726
|
+
dataFound = true;
|
|
6727
|
+
break;
|
|
6728
|
+
}
|
|
6729
|
+
return dataFound && !spreadsheetRangeIntersectsMerge(sheet, range);
|
|
6730
|
+
}
|
|
6731
|
+
function spreadsheetAutoFilterIntersectsTable(sheet, range) {
|
|
6732
|
+
return (sheet.tables ?? []).some((table)=>table.range.row[0] <= range.row[1] && table.range.row[1] >= range.row[0] && table.range.column[0] <= range.column[1] && table.range.column[1] >= range.column[0]);
|
|
6733
|
+
}
|
|
6734
|
+
function spreadsheetRangeIntersectsMerge(sheet, range) {
|
|
6735
|
+
return Object.values(sheet.config?.merge ?? {}).some((merge)=>{
|
|
6736
|
+
const endRow = merge.r + Math.max(merge.rs, 1) - 1;
|
|
6737
|
+
const endColumn = merge.c + Math.max(merge.cs, 1) - 1;
|
|
6738
|
+
return merge.r <= range.row[1] && endRow >= range.row[0] && merge.c <= range.column[1] && endColumn >= range.column[0];
|
|
6739
|
+
});
|
|
6740
|
+
}
|
|
6741
|
+
function spreadsheetRowHasContent(cellAt, row, startColumn, endColumn) {
|
|
6742
|
+
for(let column = startColumn; column <= endColumn; column += 1)if (spreadsheet_auto_filter_spreadsheetCellHasContent(cellAt(row, column))) return true;
|
|
6743
|
+
return false;
|
|
6744
|
+
}
|
|
6745
|
+
function spreadsheetColumnHasContent(cellAt, column, startRow, endRow) {
|
|
6746
|
+
for(let row = startRow; row <= endRow; row += 1)if (spreadsheet_auto_filter_spreadsheetCellHasContent(cellAt(row, column))) return true;
|
|
6747
|
+
return false;
|
|
6748
|
+
}
|
|
6749
|
+
function spreadsheet_auto_filter_spreadsheetCellHasContent(cell) {
|
|
6750
|
+
if (!cell) return false;
|
|
6751
|
+
return [
|
|
6752
|
+
cell.v,
|
|
6753
|
+
cell.m,
|
|
6754
|
+
cell.f
|
|
6755
|
+
].some((value)=>null != value && '' !== value);
|
|
6756
|
+
}
|
|
6757
|
+
function spreadsheetCellReader(sheet) {
|
|
6758
|
+
if (sheet.data) return (row, column)=>sheet.data?.[row]?.[column] ?? null;
|
|
6759
|
+
const cells = new Map((sheet.celldata ?? []).map((cell)=>[
|
|
6760
|
+
`${cell.r}:${cell.c}`,
|
|
6761
|
+
cell.v
|
|
6762
|
+
]));
|
|
6763
|
+
return (row, column)=>cells.get(`${row}:${column}`) ?? null;
|
|
6764
|
+
}
|
|
6765
|
+
function spreadsheetUsedBounds(sheet) {
|
|
6766
|
+
let lastRow = Math.max((sheet.data?.length ?? 1) - 1, 0);
|
|
6767
|
+
let lastColumn = Math.max(sparseMatrixColumnCount(sheet.data) - 1, 0);
|
|
6768
|
+
for (const cell of sheet.celldata ?? []){
|
|
6769
|
+
lastRow = Math.max(lastRow, cell.r);
|
|
6770
|
+
lastColumn = Math.max(lastColumn, cell.c);
|
|
6771
|
+
}
|
|
6772
|
+
return {
|
|
6773
|
+
lastColumn,
|
|
6774
|
+
lastRow
|
|
6775
|
+
};
|
|
6776
|
+
}
|
|
6777
|
+
function normalizeAutoFilterSelection(selection) {
|
|
6778
|
+
const startRow = spreadsheet_auto_filter_finiteIndex(selection.row[0], 0);
|
|
6779
|
+
const endRow = spreadsheet_auto_filter_finiteIndex(selection.row[1], startRow);
|
|
6780
|
+
const startColumn = spreadsheet_auto_filter_finiteIndex(selection.column[0], 0);
|
|
6781
|
+
const endColumn = spreadsheet_auto_filter_finiteIndex(selection.column[1], startColumn);
|
|
6782
|
+
return {
|
|
6783
|
+
row: [
|
|
6784
|
+
Math.min(startRow, endRow),
|
|
6785
|
+
Math.max(startRow, endRow)
|
|
6786
|
+
],
|
|
6787
|
+
column: [
|
|
6788
|
+
Math.min(startColumn, endColumn),
|
|
6789
|
+
Math.max(startColumn, endColumn)
|
|
6790
|
+
]
|
|
6791
|
+
};
|
|
6792
|
+
}
|
|
6793
|
+
function normalizedFilterSelection(selection) {
|
|
6794
|
+
if (!selection?.row?.length || !selection.column?.length) return null;
|
|
6795
|
+
return normalizeAutoFilterSelection(selection);
|
|
6796
|
+
}
|
|
6797
|
+
function spreadsheet_auto_filter_finiteIndex(value, fallback) {
|
|
6798
|
+
return 'number' == typeof value && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : fallback;
|
|
6799
|
+
}
|
|
6800
|
+
const ACCENTS = [
|
|
6801
|
+
'#64748b',
|
|
6802
|
+
'#2563eb',
|
|
6803
|
+
'#0f766e',
|
|
6804
|
+
'#7c3aed',
|
|
6805
|
+
'#c2410c',
|
|
6806
|
+
'#be123c',
|
|
6807
|
+
'#15803d'
|
|
6808
|
+
];
|
|
6809
|
+
const DARK_ACCENTS = [
|
|
6810
|
+
'#1e293b',
|
|
6811
|
+
'#1e3a8a',
|
|
6812
|
+
'#134e4a',
|
|
6813
|
+
'#4c1d95',
|
|
6814
|
+
'#7c2d12',
|
|
6815
|
+
'#881337',
|
|
6816
|
+
'#14532d',
|
|
6817
|
+
'#0f172a',
|
|
6818
|
+
'#312e81',
|
|
6819
|
+
'#3f3f46',
|
|
6820
|
+
'#422006'
|
|
6821
|
+
];
|
|
6822
|
+
let cachedChoices = null;
|
|
6823
|
+
function spreadsheetTableStyleChoices() {
|
|
6824
|
+
cachedChoices ??= Object.freeze([
|
|
6825
|
+
...tableStyleFamilyChoices('light', 21),
|
|
6826
|
+
...tableStyleFamilyChoices('medium', 28),
|
|
6827
|
+
...tableStyleFamilyChoices('dark', 11)
|
|
6828
|
+
]);
|
|
6829
|
+
return cachedChoices;
|
|
6830
|
+
}
|
|
6831
|
+
function spreadsheetTableStylePalette(style) {
|
|
6832
|
+
if ('none' === style.family) return null;
|
|
6833
|
+
const maximum = 'light' === style.family ? 21 : 'medium' === style.family ? 28 : 11;
|
|
6834
|
+
if (!Number.isInteger(style.number) || style.number < 1 || style.number > maximum) return null;
|
|
6835
|
+
if ('light' === style.family) return lightPalette(style.number);
|
|
6836
|
+
if ('medium' === style.family) return mediumPalette(style.number);
|
|
6837
|
+
return darkPalette(style.number);
|
|
6838
|
+
}
|
|
6839
|
+
function createSpreadsheetTableRenderResolver(tables) {
|
|
6840
|
+
const renderable = tables.filter((table)=>spreadsheetTableStylePalette(table.style)).slice().sort((left, right)=>left.range.row[0] - right.range.row[0] || left.range.column[0] - right.range.column[0]);
|
|
6841
|
+
let cachedRow = -1;
|
|
6842
|
+
let rowTables = [];
|
|
6843
|
+
return (row, column)=>{
|
|
6844
|
+
if (row !== cachedRow) {
|
|
6845
|
+
cachedRow = row;
|
|
6846
|
+
rowTables = renderable.filter((table)=>row >= table.range.row[0] && row <= table.range.row[1]);
|
|
6847
|
+
}
|
|
6848
|
+
const table = rowTables.find((candidate)=>column >= candidate.range.column[0] && column <= candidate.range.column[1]);
|
|
6849
|
+
return table ? spreadsheetTableCellRenderStyle(table, row, column) : null;
|
|
6850
|
+
};
|
|
6851
|
+
}
|
|
6852
|
+
function spreadsheetTableCellRenderStyle(table, row, column) {
|
|
6853
|
+
const palette = spreadsheetTableStylePalette(table.style);
|
|
6854
|
+
if (!palette) return null;
|
|
6855
|
+
const header = table.headerRow && row === table.range.row[0];
|
|
6856
|
+
const totals = table.totalsRow && row === table.range.row[1];
|
|
6857
|
+
const dataStart = table.range.row[0] + Number(table.headerRow);
|
|
6858
|
+
const dataIndex = Math.max(0, row - dataStart);
|
|
6859
|
+
const secondary = table.showRowStripes && dataIndex % 2 === 1;
|
|
6860
|
+
let background = header ? palette.header : totals ? palette.total : secondary ? palette.secondaryRow : palette.primaryRow;
|
|
6861
|
+
if (!header && !totals && table.showColumnStripes && (column - table.range.column[0]) % 2 === 1) background = mixHex(background, palette.stripeColumn, 0.42);
|
|
6862
|
+
const firstColumn = column === table.range.column[0];
|
|
6863
|
+
const lastColumn = column === table.range.column[1];
|
|
6864
|
+
return {
|
|
6865
|
+
background,
|
|
6866
|
+
bold: header || totals || table.showFirstColumn && firstColumn || table.showLastColumn && lastColumn,
|
|
6867
|
+
borderColor: palette.border,
|
|
6868
|
+
role: header ? 'header' : totals ? 'totals' : 'body',
|
|
6869
|
+
tableId: table.id,
|
|
6870
|
+
textColor: header ? palette.headerText : totals ? palette.totalText : palette.text
|
|
6871
|
+
};
|
|
6872
|
+
}
|
|
6873
|
+
function tableStyleFamilyChoices(family, count) {
|
|
6874
|
+
return Array.from({
|
|
6875
|
+
length: count
|
|
6876
|
+
}, (_, index)=>{
|
|
6877
|
+
const number = index + 1;
|
|
6878
|
+
const style = {
|
|
6879
|
+
family,
|
|
6880
|
+
number
|
|
6881
|
+
};
|
|
6882
|
+
return {
|
|
6883
|
+
label: `${familyLabel(family)} ${number}`,
|
|
6884
|
+
ooxmlName: `TableStyle${capitalize(family)}${number}`,
|
|
6885
|
+
palette: spreadsheetTableStylePalette(style),
|
|
6886
|
+
style
|
|
6887
|
+
};
|
|
6888
|
+
});
|
|
6889
|
+
}
|
|
6890
|
+
function lightPalette(number) {
|
|
6891
|
+
const accent = ACCENTS[(number - 1) % ACCENTS.length] ?? ACCENTS[0];
|
|
6892
|
+
const variant = Math.floor((number - 1) / ACCENTS.length);
|
|
6893
|
+
const headerWeight = [
|
|
6894
|
+
0.84,
|
|
6895
|
+
0.73,
|
|
6896
|
+
0.62
|
|
6897
|
+
][variant] ?? 0.72;
|
|
6898
|
+
return {
|
|
6899
|
+
border: mixHex(accent, '#ffffff', 0.5),
|
|
6900
|
+
header: mixHex(accent, '#ffffff', headerWeight),
|
|
6901
|
+
headerText: mixHex(accent, '#0f172a', 0.38),
|
|
6902
|
+
primaryRow: '#ffffff',
|
|
6903
|
+
secondaryRow: mixHex(accent, '#ffffff', 0.9 - 0.025 * variant),
|
|
6904
|
+
stripeColumn: mixHex(accent, '#ffffff', 0.82),
|
|
6905
|
+
text: '#1f2937',
|
|
6906
|
+
total: mixHex(accent, '#ffffff', 0.78),
|
|
6907
|
+
totalText: '#172033'
|
|
6908
|
+
};
|
|
6909
|
+
}
|
|
6910
|
+
function mediumPalette(number) {
|
|
6911
|
+
const accent = ACCENTS[(number - 1) % ACCENTS.length] ?? ACCENTS[0];
|
|
6912
|
+
const variant = Math.floor((number - 1) / ACCENTS.length);
|
|
6913
|
+
const header = mixHex(accent, '#111827', 0.08 * variant);
|
|
6914
|
+
return {
|
|
6915
|
+
border: mixHex(accent, '#ffffff', 0.34),
|
|
6916
|
+
header,
|
|
6917
|
+
headerText: '#ffffff',
|
|
6918
|
+
primaryRow: '#ffffff',
|
|
6919
|
+
secondaryRow: mixHex(accent, '#ffffff', 0.86 - 0.02 * variant),
|
|
6920
|
+
stripeColumn: mixHex(accent, '#ffffff', 0.76),
|
|
6921
|
+
text: '#172033',
|
|
6922
|
+
total: mixHex(accent, '#ffffff', 0.72),
|
|
6923
|
+
totalText: mixHex(accent, '#111827', 0.48)
|
|
6924
|
+
};
|
|
6925
|
+
}
|
|
6926
|
+
function darkPalette(number) {
|
|
6927
|
+
const accent = DARK_ACCENTS[number - 1] ?? DARK_ACCENTS[0];
|
|
6928
|
+
return {
|
|
6929
|
+
border: mixHex(accent, '#ffffff', 0.32),
|
|
6930
|
+
header: accent,
|
|
6931
|
+
headerText: '#ffffff',
|
|
6932
|
+
primaryRow: mixHex(accent, '#ffffff', 0.9),
|
|
6933
|
+
secondaryRow: mixHex(accent, '#ffffff', 0.78),
|
|
6934
|
+
stripeColumn: mixHex(accent, '#ffffff', 0.68),
|
|
6935
|
+
text: '#172033',
|
|
6936
|
+
total: mixHex(accent, '#ffffff', 0.62),
|
|
6937
|
+
totalText: mixHex(accent, '#111827', 0.34)
|
|
6938
|
+
};
|
|
6939
|
+
}
|
|
6940
|
+
function mixHex(left, right, rightWeight) {
|
|
6941
|
+
const weight = Math.min(1, Math.max(0, rightWeight));
|
|
6942
|
+
const leftRgb = parseHex(left);
|
|
6943
|
+
const rightRgb = parseHex(right);
|
|
6944
|
+
return `#${leftRgb.map((value, index)=>Math.round(value * (1 - weight) + (rightRgb[index] ?? value) * weight).toString(16).padStart(2, '0')).join('')}`;
|
|
6945
|
+
}
|
|
6946
|
+
function parseHex(value) {
|
|
6947
|
+
const hex = value.replace(/^#/, '');
|
|
6948
|
+
return [
|
|
6949
|
+
0,
|
|
6950
|
+
2,
|
|
6951
|
+
4
|
|
6952
|
+
].map((offset)=>Number.parseInt(hex.slice(offset, offset + 2), 16));
|
|
6953
|
+
}
|
|
6954
|
+
function familyLabel(family) {
|
|
6955
|
+
if ('light' === family) return '浅色';
|
|
6956
|
+
if ('medium' === family) return '中等';
|
|
6957
|
+
return '深色';
|
|
6958
|
+
}
|
|
6959
|
+
function capitalize(value) {
|
|
6960
|
+
return `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
|
|
6961
|
+
}
|
|
6962
|
+
const MAX_TABLE_CONVERSION_DENSE_FOOTPRINT = 1000000;
|
|
6963
|
+
function canMaterializeSpreadsheetTableAppearance(table) {
|
|
6964
|
+
return 'none' === table.style.family || spreadsheet_cell_range_spreadsheetCellRangeArea(table.range) <= 100000;
|
|
6965
|
+
}
|
|
6966
|
+
function materializeSpreadsheetTableAppearance(content, sheetId, table) {
|
|
6967
|
+
if (!canMaterializeSpreadsheetTableAppearance(table)) return null;
|
|
6968
|
+
if ('none' === table.style.family) return content;
|
|
6969
|
+
const sheetIndex = content.sheets.findIndex((sheet)=>sheet.id === sheetId);
|
|
6970
|
+
const sheet = content.sheets[sheetIndex];
|
|
6971
|
+
const palette = spreadsheetTableStylePalette(table.style);
|
|
6972
|
+
if (!sheet || !palette) return null;
|
|
6973
|
+
const resolve = createSpreadsheetTableRenderResolver([
|
|
6974
|
+
table
|
|
6975
|
+
]);
|
|
6976
|
+
const styledSheet = shouldMaterializeSpreadsheetTableAsSparseCells(sheet, table) ? materializeSpreadsheetTableSparseCells(sheet, table, resolve) : materializeSpreadsheetTableMatrix(sheet, table, resolve);
|
|
6977
|
+
const sheets = [
|
|
6978
|
+
...content.sheets
|
|
6979
|
+
];
|
|
6980
|
+
sheets[sheetIndex] = styledSheet;
|
|
6981
|
+
return setSpreadsheetCellBorders({
|
|
6982
|
+
...content,
|
|
6983
|
+
sheets
|
|
6984
|
+
}, sheetId, table.range, {
|
|
6985
|
+
target: 'all',
|
|
6986
|
+
color: palette.border,
|
|
6987
|
+
style: 'thin'
|
|
6988
|
+
});
|
|
6989
|
+
}
|
|
6990
|
+
function shouldMaterializeSpreadsheetTableAsSparseCells(sheet, table) {
|
|
6991
|
+
if (void 0 === sheet.data) return true;
|
|
6992
|
+
const [startRow, endRow] = table.range.row;
|
|
6993
|
+
const requiredRowLength = table.range.column[1] + 1;
|
|
6994
|
+
let footprint = 0;
|
|
6995
|
+
let presentTableRows = 0;
|
|
6996
|
+
for (const [rowIndex, row] of sparseArrayEntries(sheet.data)){
|
|
6997
|
+
if (rowIndex >= startRow && rowIndex <= endRow) {
|
|
6998
|
+
presentTableRows += 1;
|
|
6999
|
+
footprint += Math.max(row.length, requiredRowLength);
|
|
7000
|
+
} else footprint += row.length;
|
|
7001
|
+
if (footprint > MAX_TABLE_CONVERSION_DENSE_FOOTPRINT) return true;
|
|
7002
|
+
}
|
|
7003
|
+
footprint += (endRow - startRow + 1 - presentTableRows) * requiredRowLength;
|
|
7004
|
+
return footprint > MAX_TABLE_CONVERSION_DENSE_FOOTPRINT;
|
|
7005
|
+
}
|
|
7006
|
+
function materializeSpreadsheetTableMatrix(sheet, table, resolve) {
|
|
7007
|
+
const source = sheet.data ?? [];
|
|
7008
|
+
const data = [];
|
|
7009
|
+
data.length = Math.max(source.length, table.range.row[1] + 1);
|
|
7010
|
+
for (const [row, value] of sparseArrayEntries(source))data[row] = value;
|
|
7011
|
+
for(let row = table.range.row[0]; row <= table.range.row[1]; row += 1){
|
|
7012
|
+
const sourceRow = source[row];
|
|
7013
|
+
const values = [];
|
|
7014
|
+
values.length = Math.max(sourceRow?.length ?? 0, table.range.column[1] + 1);
|
|
7015
|
+
for (const column of sparseArrayIndexes(sourceRow))values[column] = sourceRow?.[column];
|
|
7016
|
+
for(let column = table.range.column[0]; column <= table.range.column[1]; column += 1){
|
|
7017
|
+
const style = resolve(row, column);
|
|
7018
|
+
if (style) values[column] = spreadsheetCellWithTableAppearance(values[column], style);
|
|
7019
|
+
}
|
|
7020
|
+
data[row] = values;
|
|
7021
|
+
}
|
|
7022
|
+
return {
|
|
7023
|
+
...sheet,
|
|
7024
|
+
data
|
|
7025
|
+
};
|
|
7026
|
+
}
|
|
7027
|
+
function materializeSpreadsheetTableSparseCells(sheet, table, resolve) {
|
|
7028
|
+
const celldata = [];
|
|
7029
|
+
if (void 0 !== sheet.data) for (const [row, values] of sparseArrayEntries(sheet.data))for (const column of sparseArrayIndexes(values)){
|
|
7030
|
+
const cell = values[column];
|
|
7031
|
+
if (null != cell) celldata.push({
|
|
7032
|
+
c: column,
|
|
7033
|
+
r: row,
|
|
7034
|
+
v: cell
|
|
7035
|
+
});
|
|
7036
|
+
}
|
|
7037
|
+
else celldata.push(...sheet.celldata ?? []);
|
|
7038
|
+
const indexes = new Map(celldata.map((entry, index)=>[
|
|
7039
|
+
`${entry.r}:${entry.c}`,
|
|
7040
|
+
index
|
|
7041
|
+
]));
|
|
7042
|
+
for(let row = table.range.row[0]; row <= table.range.row[1]; row += 1)for(let column = table.range.column[0]; column <= table.range.column[1]; column += 1){
|
|
7043
|
+
const style = resolve(row, column);
|
|
7044
|
+
if (!style) continue;
|
|
7045
|
+
const key = `${row}:${column}`;
|
|
7046
|
+
const index = indexes.get(key);
|
|
7047
|
+
const cell = spreadsheetCellWithTableAppearance(void 0 === index ? void 0 : celldata[index]?.v, style);
|
|
7048
|
+
if (void 0 === index) {
|
|
7049
|
+
indexes.set(key, celldata.length);
|
|
7050
|
+
celldata.push({
|
|
7051
|
+
c: column,
|
|
7052
|
+
r: row,
|
|
7053
|
+
v: cell
|
|
7054
|
+
});
|
|
7055
|
+
} else celldata[index] = {
|
|
7056
|
+
c: column,
|
|
7057
|
+
r: row,
|
|
7058
|
+
v: cell
|
|
7059
|
+
};
|
|
7060
|
+
}
|
|
7061
|
+
celldata.sort((left, right)=>left.r - right.r || left.c - right.c);
|
|
7062
|
+
const { data: _data, ...metadata } = sheet;
|
|
7063
|
+
return {
|
|
7064
|
+
...metadata,
|
|
7065
|
+
celldata
|
|
7066
|
+
};
|
|
7067
|
+
}
|
|
7068
|
+
function spreadsheetCellWithTableAppearance(cell, style) {
|
|
7069
|
+
return {
|
|
7070
|
+
...cell ?? {},
|
|
7071
|
+
bg: style.background,
|
|
7072
|
+
fc: style.textColor,
|
|
7073
|
+
...style.bold ? {
|
|
7074
|
+
bl: 1
|
|
7075
|
+
} : {}
|
|
7076
|
+
};
|
|
7077
|
+
}
|
|
7078
|
+
function createSpreadsheetTableDialogSource(content, target) {
|
|
7079
|
+
const sheet = content.sheets.find((candidate)=>candidate.id === target.sheetId);
|
|
7080
|
+
if (!sheet) return null;
|
|
7081
|
+
const range = spreadsheetSelectionOrCurrentRegion(sheet, target.selection);
|
|
7082
|
+
if (!range) return null;
|
|
7083
|
+
let request = {
|
|
7084
|
+
headerRow: true,
|
|
7085
|
+
name: nextSpreadsheetTableName(content),
|
|
7086
|
+
range,
|
|
7087
|
+
sheetId: target.sheetId
|
|
7088
|
+
};
|
|
7089
|
+
if (!validateSpreadsheetTableRequest(content, request).ok) {
|
|
7090
|
+
request = {
|
|
7091
|
+
...request,
|
|
7092
|
+
headerRow: false
|
|
7093
|
+
};
|
|
7094
|
+
if (!validateSpreadsheetTableRequest(content, request).ok) return null;
|
|
7095
|
+
}
|
|
7096
|
+
const rangeReference = formatSpreadsheetCellRanges([
|
|
7097
|
+
range
|
|
7098
|
+
]);
|
|
7099
|
+
return {
|
|
7100
|
+
name: request.name,
|
|
7101
|
+
range,
|
|
7102
|
+
rangeReference,
|
|
7103
|
+
sheetId: target.sheetId,
|
|
7104
|
+
sheetName: sheet.name,
|
|
7105
|
+
value: {
|
|
7106
|
+
headerRow: request.headerRow,
|
|
7107
|
+
rangeReference
|
|
7108
|
+
}
|
|
7109
|
+
};
|
|
7110
|
+
}
|
|
7111
|
+
function spreadsheetTableRangeFromText(value) {
|
|
7112
|
+
const ranges = parseSpreadsheetCellRanges(value);
|
|
7113
|
+
return ranges?.length === 1 ? ranges[0] ?? null : null;
|
|
7114
|
+
}
|
|
7115
|
+
function validateSpreadsheetTableRequest(content, request) {
|
|
7116
|
+
const sheet = content.sheets.find((candidate)=>candidate.id === request.sheetId);
|
|
7117
|
+
if (!sheet) return tableError('sheet-not-found');
|
|
7118
|
+
if (sheet.isPivotTable || sheet.pivotTables?.length) return tableError('pivot-table');
|
|
7119
|
+
const range = spreadsheet_cell_range_normalizeSpreadsheetCellRange(request.range);
|
|
7120
|
+
if (!range) return tableError('invalid-range');
|
|
7121
|
+
const name = request.name.trim();
|
|
7122
|
+
if (!validSpreadsheetTableName(name)) return tableError('invalid-name');
|
|
7123
|
+
if (spreadsheetTableNameExists(content, name)) return tableError('name-conflict');
|
|
7124
|
+
const bounds = spreadsheetSheetBounds(sheet);
|
|
7125
|
+
if (range.row[1] > bounds.lastRow || range.column[1] > bounds.lastColumn) return tableError('out-of-bounds');
|
|
7126
|
+
const height = range.row[1] - range.row[0] + 1;
|
|
7127
|
+
if (height <= Number(request.headerRow)) return tableError('invalid-range');
|
|
7128
|
+
if (spreadsheet_cell_range_spreadsheetCellRangeArea(range) > 100000) return tableError('range-too-large');
|
|
7129
|
+
if (spreadsheetTableIntersectsMerge(sheet, range)) return tableError('merged-range');
|
|
7130
|
+
if ((sheet.tables ?? []).some((table)=>spreadsheetCellRangesIntersect(table.range, range))) return tableError('table-overlap');
|
|
7131
|
+
const autoFilter = spreadsheet_cell_range_normalizeSpreadsheetCellRange(sheet.filter_select ?? {
|
|
7132
|
+
row: [],
|
|
7133
|
+
column: []
|
|
7134
|
+
});
|
|
7135
|
+
if (autoFilter && spreadsheetCellRangesIntersect(autoFilter, range)) return tableError('auto-filter-overlap');
|
|
7136
|
+
if (!canMutateSpreadsheetCellRanges(sheet, [
|
|
7137
|
+
range
|
|
7138
|
+
])) return tableError('protected-range');
|
|
7139
|
+
const style = request.style ?? {
|
|
7140
|
+
family: 'medium',
|
|
7141
|
+
number: 2
|
|
7142
|
+
};
|
|
7143
|
+
if (!validSpreadsheetTableStyle(style)) return tableError('invalid-style');
|
|
7144
|
+
const columns = spreadsheetTableColumnNames(sheet, range, request.headerRow);
|
|
7145
|
+
if (!columns.length || columns.some((column)=>!validTableColumnName(column))) return tableError('invalid-column-name');
|
|
7146
|
+
return {
|
|
7147
|
+
columns,
|
|
7148
|
+
name,
|
|
7149
|
+
ok: true,
|
|
7150
|
+
range,
|
|
7151
|
+
sheet
|
|
7152
|
+
};
|
|
7153
|
+
}
|
|
7154
|
+
function applySpreadsheetTable(content, request) {
|
|
7155
|
+
const validation = validateSpreadsheetTableRequest(content, request);
|
|
7156
|
+
if (!validation.ok) return null;
|
|
7157
|
+
const style = request.style ?? {
|
|
7158
|
+
family: 'medium',
|
|
7159
|
+
number: 2
|
|
7160
|
+
};
|
|
7161
|
+
const table = {
|
|
7162
|
+
id: createWorkId('spreadsheet-table'),
|
|
7163
|
+
name: validation.name,
|
|
7164
|
+
range: cloneRange(validation.range),
|
|
7165
|
+
columns: validation.columns.map((name)=>({
|
|
7166
|
+
name
|
|
7167
|
+
})),
|
|
7168
|
+
filters: [],
|
|
7169
|
+
headerRow: request.headerRow,
|
|
7170
|
+
totalsRow: false,
|
|
7171
|
+
style,
|
|
7172
|
+
showFirstColumn: false,
|
|
7173
|
+
showLastColumn: false,
|
|
7174
|
+
showRowStripes: 'none' !== style.family,
|
|
7175
|
+
showColumnStripes: false
|
|
7176
|
+
};
|
|
7177
|
+
const nextSheet = request.headerRow ? stampSpreadsheetTableHeaders(validation.sheet, validation.range, validation.columns) : validation.sheet;
|
|
7178
|
+
return replaceSpreadsheetTableSheet(content, {
|
|
7179
|
+
...nextSheet,
|
|
7180
|
+
tables: [
|
|
7181
|
+
...nextSheet.tables ?? [],
|
|
7182
|
+
table
|
|
7183
|
+
]
|
|
7184
|
+
});
|
|
7185
|
+
}
|
|
7186
|
+
function updateSpreadsheetTable(content, sheetId, tableId, patch) {
|
|
7187
|
+
const sheet = content.sheets.find((candidate)=>candidate.id === sheetId);
|
|
7188
|
+
const table = sheet?.tables?.find((candidate)=>candidate.id === tableId);
|
|
7189
|
+
if (!sheet || !table) return null;
|
|
7190
|
+
const name = patch.name?.trim() ?? table.name;
|
|
7191
|
+
if (!validSpreadsheetTableName(name) || spreadsheetTableNameExists(content, name, tableId)) return null;
|
|
7192
|
+
const style = patch.style ?? table.style;
|
|
7193
|
+
if (!validSpreadsheetTableStyle(style)) return null;
|
|
7194
|
+
const showFirstColumn = patch.showFirstColumn ?? table.showFirstColumn;
|
|
7195
|
+
const showLastColumn = patch.showLastColumn ?? table.showLastColumn;
|
|
7196
|
+
const showRowStripes = patch.showRowStripes ?? table.showRowStripes;
|
|
7197
|
+
const showColumnStripes = patch.showColumnStripes ?? table.showColumnStripes;
|
|
7198
|
+
if ('none' === style.family && (showFirstColumn || showLastColumn || showRowStripes || showColumnStripes)) return null;
|
|
7199
|
+
const tables = sheet.tables?.map((candidate)=>candidate.id === tableId ? {
|
|
7200
|
+
...candidate,
|
|
7201
|
+
name,
|
|
7202
|
+
...void 0 === patch.name ? {} : {
|
|
7203
|
+
displayName: void 0
|
|
7204
|
+
},
|
|
7205
|
+
style,
|
|
7206
|
+
showFirstColumn,
|
|
7207
|
+
showLastColumn,
|
|
7208
|
+
showRowStripes,
|
|
7209
|
+
showColumnStripes
|
|
7210
|
+
} : candidate);
|
|
7211
|
+
return replaceSpreadsheetTableSheet(content, {
|
|
7212
|
+
...sheet,
|
|
7213
|
+
tables
|
|
7214
|
+
});
|
|
7215
|
+
}
|
|
7216
|
+
function convertSpreadsheetTableToRange(content, sheetId, tableId) {
|
|
7217
|
+
const sheet = content.sheets.find((candidate)=>candidate.id === sheetId);
|
|
7218
|
+
const table = sheet?.tables?.find((candidate)=>candidate.id === tableId);
|
|
7219
|
+
if (!sheet || !table || spreadsheetTableHasStructuredReferences(content, table)) return null;
|
|
7220
|
+
const remaining = sheet.tables?.filter((candidate)=>candidate.id !== tableId);
|
|
7221
|
+
const withoutTable = replaceSpreadsheetTableSheet(content, {
|
|
7222
|
+
...sheet,
|
|
7223
|
+
tables: remaining?.length ? remaining : void 0
|
|
7224
|
+
});
|
|
7225
|
+
return materializeSpreadsheetTableAppearance(withoutTable, sheetId, table);
|
|
7226
|
+
}
|
|
7227
|
+
function spreadsheetTableAtCell(sheet, row, column) {
|
|
7228
|
+
if (!sheet) return null;
|
|
7229
|
+
return (sheet.tables ?? []).find((table)=>spreadsheetCellRangeContains(table.range, row, column)) ?? null;
|
|
7230
|
+
}
|
|
7231
|
+
function spreadsheetTableFailureMessage(content, request) {
|
|
7232
|
+
const validation = validateSpreadsheetTableRequest(content, request);
|
|
7233
|
+
return validation.ok ? null : validation.message;
|
|
7234
|
+
}
|
|
7235
|
+
function nextSpreadsheetTableName(content) {
|
|
7236
|
+
for(let index = 1; index <= 65536; index += 1){
|
|
7237
|
+
const candidate = `Table${index}`;
|
|
7238
|
+
if (!spreadsheetTableNameExists(content, candidate)) return candidate;
|
|
7239
|
+
}
|
|
7240
|
+
return 'Table65536';
|
|
7241
|
+
}
|
|
7242
|
+
function spreadsheetTableNameExists(content, name, exceptTableId) {
|
|
7243
|
+
const normalized = name.toLocaleLowerCase();
|
|
7244
|
+
return content.sheets.some((sheet)=>(sheet.tables ?? []).some((table)=>table.id !== exceptTableId && [
|
|
7245
|
+
table.name,
|
|
7246
|
+
table.displayName
|
|
7247
|
+
].some((candidate)=>candidate?.toLocaleLowerCase() === normalized))) || (content.namedRanges ?? []).some((range)=>range.name.trim().toLocaleLowerCase() === normalized);
|
|
7248
|
+
}
|
|
7249
|
+
function validSpreadsheetTableName(name) {
|
|
7250
|
+
return isValidSpreadsheetDefinedName(name) && !name.startsWith('_xlnm.') && ![
|
|
7251
|
+
'r',
|
|
7252
|
+
'c'
|
|
7253
|
+
].includes(name.toLocaleLowerCase());
|
|
7254
|
+
}
|
|
7255
|
+
function validSpreadsheetTableStyle(style) {
|
|
7256
|
+
if ('none' === style.family) return true;
|
|
7257
|
+
if (!Number.isInteger(style.number)) return false;
|
|
7258
|
+
if ('light' === style.family) return style.number >= 1 && style.number <= 21;
|
|
7259
|
+
if ('medium' === style.family) return style.number >= 1 && style.number <= 28;
|
|
7260
|
+
return style.number >= 1 && style.number <= 11;
|
|
7261
|
+
}
|
|
7262
|
+
function spreadsheetTableColumnNames(sheet, range, headerRow) {
|
|
7263
|
+
const observed = new Set();
|
|
7264
|
+
const names = [];
|
|
7265
|
+
for(let column = range.column[0]; column <= range.column[1]; column += 1){
|
|
7266
|
+
const raw = headerRow ? spreadsheet_table_spreadsheetCellText(sheet, range.row[0], column).trim() : '';
|
|
7267
|
+
const base = validTableColumnName(raw) ? raw : `Column${column - range.column[0] + 1}`;
|
|
7268
|
+
let candidate = base;
|
|
7269
|
+
let suffix = 2;
|
|
7270
|
+
while(observed.has(candidate.toLocaleLowerCase())){
|
|
7271
|
+
const suffixText = String(suffix);
|
|
7272
|
+
candidate = `${truncateTableColumnName(base, 255 - suffixText.length)}${suffixText}`;
|
|
7273
|
+
suffix += 1;
|
|
7274
|
+
}
|
|
7275
|
+
observed.add(candidate.toLocaleLowerCase());
|
|
7276
|
+
names.push(candidate);
|
|
7277
|
+
}
|
|
7278
|
+
return names;
|
|
7279
|
+
}
|
|
7280
|
+
function validTableColumnName(name) {
|
|
7281
|
+
const characters = Array.from(name);
|
|
7282
|
+
return name.trim() === name && characters.length >= 1 && characters.length <= 255 && !characters.some((character)=>/\p{Cc}/u.test(character) || '\uFFFE' === character || '\uFFFF' === character);
|
|
7283
|
+
}
|
|
7284
|
+
function truncateTableColumnName(value, maximum) {
|
|
7285
|
+
return Array.from(value).slice(0, maximum).join('');
|
|
7286
|
+
}
|
|
7287
|
+
function spreadsheet_table_spreadsheetCellText(sheet, row, column) {
|
|
7288
|
+
const cell = sheet.data?.[row]?.[column] ?? sheet.celldata?.find((candidate)=>candidate.r === row && candidate.c === column)?.v;
|
|
7289
|
+
const value = cell?.m ?? cell?.v;
|
|
7290
|
+
return null == value ? '' : String(value);
|
|
7291
|
+
}
|
|
7292
|
+
function stampSpreadsheetTableHeaders(sheet, range, names) {
|
|
7293
|
+
if (void 0 !== sheet.data) {
|
|
7294
|
+
const data = cloneSparseMatrixShell(sheet.data);
|
|
7295
|
+
const sourceRow = sheet.data[range.row[0]];
|
|
7296
|
+
const row = cloneSparseRow(sourceRow);
|
|
7297
|
+
for (const [offset, name] of names.entries()){
|
|
7298
|
+
const column = range.column[0] + offset;
|
|
7299
|
+
row[column] = stampHeaderCell(sourceRow?.[column], name);
|
|
7300
|
+
}
|
|
7301
|
+
data[range.row[0]] = row;
|
|
7302
|
+
return {
|
|
7303
|
+
...sheet,
|
|
7304
|
+
data
|
|
7305
|
+
};
|
|
7306
|
+
}
|
|
7307
|
+
const byCoordinate = new Map((sheet.celldata ?? []).map((entry)=>[
|
|
7308
|
+
`${entry.r}_${entry.c}`,
|
|
7309
|
+
entry
|
|
7310
|
+
]));
|
|
7311
|
+
for (const [offset, name] of names.entries()){
|
|
7312
|
+
const column = range.column[0] + offset;
|
|
7313
|
+
const key = `${range.row[0]}_${column}`;
|
|
7314
|
+
const source = byCoordinate.get(key);
|
|
7315
|
+
byCoordinate.set(key, {
|
|
7316
|
+
r: range.row[0],
|
|
7317
|
+
c: column,
|
|
7318
|
+
v: stampHeaderCell(source?.v, name)
|
|
7319
|
+
});
|
|
7320
|
+
}
|
|
7321
|
+
return {
|
|
7322
|
+
...sheet,
|
|
7323
|
+
celldata: [
|
|
7324
|
+
...byCoordinate.values()
|
|
7325
|
+
]
|
|
7326
|
+
};
|
|
7327
|
+
}
|
|
7328
|
+
function cloneSparseMatrixShell(source) {
|
|
7329
|
+
const data = [];
|
|
7330
|
+
data.length = source.length;
|
|
7331
|
+
for (const [row, value] of sparseArrayEntries(source))data[row] = value;
|
|
7332
|
+
return data;
|
|
7333
|
+
}
|
|
7334
|
+
function cloneSparseRow(source) {
|
|
7335
|
+
const row = [];
|
|
7336
|
+
if (!source) return row;
|
|
7337
|
+
row.length = source.length;
|
|
7338
|
+
for (const column of sparseArrayIndexes(source))row[column] = source[column];
|
|
7339
|
+
return row;
|
|
7340
|
+
}
|
|
7341
|
+
function stampHeaderCell(source, name) {
|
|
7342
|
+
return {
|
|
7343
|
+
...source ?? {},
|
|
7344
|
+
m: name,
|
|
7345
|
+
v: name
|
|
7346
|
+
};
|
|
7347
|
+
}
|
|
7348
|
+
function spreadsheetTableIntersectsMerge(sheet, range) {
|
|
7349
|
+
return Object.values(sheet.config?.merge ?? {}).some((merge)=>spreadsheetCellRangesIntersect(range, {
|
|
7350
|
+
row: [
|
|
7351
|
+
merge.r,
|
|
7352
|
+
merge.r + Math.max(1, merge.rs) - 1
|
|
7353
|
+
],
|
|
7354
|
+
column: [
|
|
7355
|
+
merge.c,
|
|
7356
|
+
merge.c + Math.max(1, merge.cs) - 1
|
|
7357
|
+
]
|
|
7358
|
+
}));
|
|
7359
|
+
}
|
|
7360
|
+
function replaceSpreadsheetTableSheet(content, nextSheet) {
|
|
5951
7361
|
return {
|
|
5952
|
-
|
|
5953
|
-
|
|
7362
|
+
...content,
|
|
7363
|
+
sheets: content.sheets.map((sheet)=>sheet.id === nextSheet.id ? nextSheet : sheet)
|
|
5954
7364
|
};
|
|
5955
7365
|
}
|
|
5956
|
-
function
|
|
5957
|
-
const
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
7366
|
+
function spreadsheetTableHasStructuredReferences(content, table) {
|
|
7367
|
+
const aliases = [
|
|
7368
|
+
table.name,
|
|
7369
|
+
table.displayName
|
|
7370
|
+
].filter((value)=>Boolean(value));
|
|
7371
|
+
const patterns = aliases.map((alias)=>new RegExp(`${escapeRegExp(alias)}\\s*\\[`, 'i'));
|
|
7372
|
+
const matches = (value)=>'string' == typeof value && patterns.some((pattern)=>pattern.test(value));
|
|
7373
|
+
for (const sheet of content.sheets){
|
|
7374
|
+
for (const [, row] of sparseArrayEntries(sheet.data))for (const [, cell] of sparseArrayEntries(row))if (matches(cell?.f)) return true;
|
|
7375
|
+
for (const entry of sheet.celldata ?? [])if (matches(entry.v?.f)) return true;
|
|
7376
|
+
if (Object.values(sheet.formulaMetadata?.sourceFormulas ?? {}).some(matches) || matches(JSON.stringify(sheet.dataValidationRanges ?? [])) || matches(JSON.stringify(sheet.luckysheet_conditionformat_save ?? [])) || matches(JSON.stringify(sheet.charts ?? []))) return true;
|
|
7377
|
+
}
|
|
7378
|
+
return (content.namedRanges ?? []).some((range)=>matches(range.reference));
|
|
5962
7379
|
}
|
|
5963
|
-
function
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
...selection,
|
|
7380
|
+
function escapeRegExp(value) {
|
|
7381
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
7382
|
+
}
|
|
7383
|
+
function cloneRange(range) {
|
|
7384
|
+
return {
|
|
5969
7385
|
row: [
|
|
5970
|
-
|
|
5971
|
-
focus
|
|
7386
|
+
...range.row
|
|
5972
7387
|
],
|
|
5973
7388
|
column: [
|
|
5974
|
-
...
|
|
5975
|
-
]
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
7389
|
+
...range.column
|
|
7390
|
+
]
|
|
7391
|
+
};
|
|
7392
|
+
}
|
|
7393
|
+
function tableError(code) {
|
|
7394
|
+
const messages = {
|
|
7395
|
+
'auto-filter-overlap': '表格区域不能与工作表自动筛选区域重叠。',
|
|
7396
|
+
'invalid-column-name': '表格列名必须唯一且不超过 255 个字符。',
|
|
7397
|
+
'invalid-name': '表格名称必须是有效且不类似单元格引用的标识符。',
|
|
7398
|
+
'invalid-range': '表格至少需要一行数据。',
|
|
7399
|
+
'invalid-style': '表格样式身份无效。',
|
|
7400
|
+
'merged-range': '请先取消表格区域内的合并单元格。',
|
|
7401
|
+
'name-conflict': '表格名称已被其他表格或名称使用。',
|
|
7402
|
+
'out-of-bounds': '表格区域超出当前工作表边界。',
|
|
7403
|
+
'pivot-table': '数据透视表工作表不能创建普通表格。',
|
|
7404
|
+
'protected-range': '受保护或只读区域不能创建表格。',
|
|
7405
|
+
'range-too-large': `一次最多可创建 ${100000..toLocaleString()} 个单元格的表格。`,
|
|
7406
|
+
'sheet-not-found': '找不到目标工作表。',
|
|
7407
|
+
'table-overlap': '表格区域不能与其他表格重叠。'
|
|
5979
7408
|
};
|
|
5980
7409
|
return {
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
7410
|
+
code,
|
|
7411
|
+
message: messages[code],
|
|
7412
|
+
ok: false
|
|
7413
|
+
};
|
|
7414
|
+
}
|
|
7415
|
+
function createSpreadsheetTableExtension() {
|
|
7416
|
+
return createOfficeEditorExtension({
|
|
7417
|
+
name: 'spreadsheetTables',
|
|
7418
|
+
addCommands: ()=>({
|
|
7419
|
+
openTable: {
|
|
7420
|
+
canExecute: canOpenSpreadsheetTable,
|
|
7421
|
+
execute: openSpreadsheetTable
|
|
7422
|
+
},
|
|
7423
|
+
applyTable: {
|
|
7424
|
+
canExecute: (context, request)=>context.editable && validateSpreadsheetTableRequest(context.content, request).ok,
|
|
7425
|
+
execute: applySpreadsheetTableCommand
|
|
7426
|
+
},
|
|
7427
|
+
updateTable: {
|
|
7428
|
+
canExecute: canUpdateSpreadsheetTable,
|
|
7429
|
+
execute: updateSpreadsheetTableCommand
|
|
7430
|
+
},
|
|
7431
|
+
convertTableToRange: {
|
|
7432
|
+
canExecute: canConvertSpreadsheetTableToRange,
|
|
7433
|
+
execute: convertSpreadsheetTableToRangeCommand
|
|
7434
|
+
}
|
|
7435
|
+
}),
|
|
7436
|
+
addKeyboardShortcuts: ()=>({
|
|
7437
|
+
[spreadsheetCommandCatalog.table.shortcut.editor["0"]]: ({ can, commands }, event)=>runSpreadsheetTableShortcut(event, can.openTable, commands.openTable)
|
|
7438
|
+
})
|
|
7439
|
+
});
|
|
7440
|
+
}
|
|
7441
|
+
function canOpenSpreadsheetTable(context) {
|
|
7442
|
+
const target = liveSpreadsheetTableTarget(context);
|
|
7443
|
+
const sheet = context.content.sheets.find((candidate)=>candidate.id === target?.sheetId);
|
|
7444
|
+
const focus = target?.selection;
|
|
7445
|
+
const row = focus?.row_focus ?? focus?.row[0] ?? 0;
|
|
7446
|
+
const column = focus?.column_focus ?? focus?.column[0] ?? 0;
|
|
7447
|
+
return Boolean(context.editable && context.table.canOpen && context.workbook && target && target.sheetId === context.activeSheetId && sheet && !sheet.isPivotTable && !sheet.pivotTables?.length && !spreadsheetTableAtCell(sheet, row, column));
|
|
7448
|
+
}
|
|
7449
|
+
function openSpreadsheetTable(context) {
|
|
7450
|
+
const target = liveSpreadsheetTableTarget(context);
|
|
7451
|
+
return Boolean(target && canOpenSpreadsheetTable(context) && context.table.open(target));
|
|
7452
|
+
}
|
|
7453
|
+
function applySpreadsheetTableCommand(context, request) {
|
|
7454
|
+
if (!context.editable) return false;
|
|
7455
|
+
const next = applySpreadsheetTable(context.content, request);
|
|
7456
|
+
if (!next) return false;
|
|
7457
|
+
context.onChange(next);
|
|
7458
|
+
return true;
|
|
7459
|
+
}
|
|
7460
|
+
function canUpdateSpreadsheetTable(context, sheetId, tableId, patch) {
|
|
7461
|
+
return Boolean(context.editable && updateSpreadsheetTable(context.content, sheetId, tableId, patch));
|
|
7462
|
+
}
|
|
7463
|
+
function updateSpreadsheetTableCommand(context, sheetId, tableId, patch) {
|
|
7464
|
+
if (!context.editable) return false;
|
|
7465
|
+
const next = updateSpreadsheetTable(context.content, sheetId, tableId, patch);
|
|
7466
|
+
if (!next) return false;
|
|
7467
|
+
context.onChange(next);
|
|
7468
|
+
return true;
|
|
7469
|
+
}
|
|
7470
|
+
function canConvertSpreadsheetTableToRange(context, sheetId, tableId) {
|
|
7471
|
+
return Boolean(context.editable && context.content.sheets.find((sheet)=>sheet.id === sheetId)?.tables?.some((table)=>table.id === tableId && canMaterializeSpreadsheetTableAppearance(table)));
|
|
7472
|
+
}
|
|
7473
|
+
function convertSpreadsheetTableToRangeCommand(context, sheetId, tableId) {
|
|
7474
|
+
if (!context.editable) return false;
|
|
7475
|
+
const next = convertSpreadsheetTableToRange(context.content, sheetId, tableId);
|
|
7476
|
+
if (!next) return false;
|
|
7477
|
+
context.onChange(next);
|
|
7478
|
+
return true;
|
|
7479
|
+
}
|
|
7480
|
+
function liveSpreadsheetTableTarget(context) {
|
|
7481
|
+
if (!context.workbook || !context.targetSheetId) return null;
|
|
7482
|
+
const selection = context.workbook.getSelection()?.at(-1) ?? context.fallbackRange;
|
|
7483
|
+
return {
|
|
7484
|
+
sheetId: context.targetSheetId,
|
|
7485
|
+
selection: finiteSpreadsheetSelection(selection)
|
|
5992
7486
|
};
|
|
5993
7487
|
}
|
|
7488
|
+
function runSpreadsheetTableShortcut(event, canExecute, execute) {
|
|
7489
|
+
if (event.repeat || event.isComposing || isOfficeShortcutBlocked(event.target) || isSpreadsheetNativeTextUndoTarget(event.target) || !isSpreadsheetGridKeyboardTarget(event.target)) return false;
|
|
7490
|
+
if (!event.repeat && canExecute()) execute();
|
|
7491
|
+
return true;
|
|
7492
|
+
}
|
|
5994
7493
|
function createSpreadsheetEditorExtensions() {
|
|
5995
7494
|
return [
|
|
5996
7495
|
createOfficeEditorExtension({
|
|
@@ -6007,12 +7506,14 @@ function createSpreadsheetEditorExtensions() {
|
|
|
6007
7506
|
})
|
|
6008
7507
|
}),
|
|
6009
7508
|
createSpreadsheetCellFormatExtension(),
|
|
7509
|
+
createSpreadsheetFontSizeExtension(),
|
|
6010
7510
|
createSpreadsheetCellBorderExtension(),
|
|
6011
7511
|
createSpreadsheetCellStyleExtension(),
|
|
6012
7512
|
createSpreadsheetNumberFormatExtension(),
|
|
6013
7513
|
createSpreadsheetNavigationExtension(),
|
|
6014
7514
|
createSpreadsheetDataValidationExtension(),
|
|
6015
7515
|
createSpreadsheetHyperlinkExtension(),
|
|
7516
|
+
createSpreadsheetTableExtension(),
|
|
6016
7517
|
createSpreadsheetAutoSumExtension(),
|
|
6017
7518
|
createSpreadsheetCellFillExtension(),
|
|
6018
7519
|
createOfficeEditorExtension({
|
|
@@ -6283,9 +7784,16 @@ function canInsertSelectedStructure(context, axis, _position) {
|
|
|
6283
7784
|
const [start, end] = spreadsheetStructureRange(range, axis);
|
|
6284
7785
|
const count = end - start + 1;
|
|
6285
7786
|
const maximum = 'row' === axis ? 10000 : 1000;
|
|
6286
|
-
return spreadsheetStructureExtent(context, axis) + count < maximum
|
|
7787
|
+
return spreadsheetStructureExtent(context, axis) + count < maximum && canApplySpreadsheetTableStructureChange(context.content.sheets.find((sheet)=>sheet.id === context.targetSheetId), {
|
|
7788
|
+
axis,
|
|
7789
|
+
count,
|
|
7790
|
+
direction: 'before' === _position ? 'lefttop' : 'rightbottom',
|
|
7791
|
+
index: 'before' === _position ? start : end,
|
|
7792
|
+
kind: 'insert'
|
|
7793
|
+
});
|
|
6287
7794
|
}
|
|
6288
7795
|
function insertSelectedStructure(context, axis, position) {
|
|
7796
|
+
if (!canInsertSelectedStructure(context, axis, position)) return false;
|
|
6289
7797
|
if (!context.workbook || !context.targetSheetId) return false;
|
|
6290
7798
|
const [start, end] = spreadsheetStructureRange(liveRange(context), axis);
|
|
6291
7799
|
const before = 'before' === position;
|
|
@@ -6301,9 +7809,15 @@ function insertSelectedStructure(context, axis, position) {
|
|
|
6301
7809
|
function canDeleteSelectedStructure(context, axis) {
|
|
6302
7810
|
if (!canEditSelectedCells(context)) return false;
|
|
6303
7811
|
const [start, end] = spreadsheetStructureRange(liveRange(context), axis);
|
|
6304
|
-
return end - start + 1 < spreadsheetStructureExtent(context, axis)
|
|
7812
|
+
return end - start + 1 < spreadsheetStructureExtent(context, axis) && canApplySpreadsheetTableStructureChange(context.content.sheets.find((sheet)=>sheet.id === context.targetSheetId), {
|
|
7813
|
+
axis,
|
|
7814
|
+
end,
|
|
7815
|
+
kind: 'delete',
|
|
7816
|
+
start
|
|
7817
|
+
});
|
|
6305
7818
|
}
|
|
6306
7819
|
function deleteSelectedStructure(context, axis) {
|
|
7820
|
+
if (!canDeleteSelectedStructure(context, axis)) return false;
|
|
6307
7821
|
if (!context.workbook || !context.targetSheetId) return false;
|
|
6308
7822
|
const range = liveRange(context);
|
|
6309
7823
|
const [start, end] = spreadsheetStructureRange(range, axis);
|
|
@@ -7571,6 +9085,7 @@ function SpreadsheetBorderRibbon({ can, commands }) {
|
|
|
7571
9085
|
color
|
|
7572
9086
|
};
|
|
7573
9087
|
const currentDefinition = spreadsheetBorderTargetOptions.find((option)=>option.target === target)?.definition;
|
|
9088
|
+
const currentShortcut = currentDefinition && 'shortcut' in currentDefinition ? currentDefinition.shortcut : void 0;
|
|
7574
9089
|
const currentLabel = currentDefinition?.label ?? '所有框线';
|
|
7575
9090
|
const styleLabel = spreadsheetBorderStyleOptions.find((option)=>option.value === style)?.label;
|
|
7576
9091
|
const menuDisabled = spreadsheetBorderTargetOptions.every((option)=>!can.setSelectedCellBorders({
|
|
@@ -7593,7 +9108,8 @@ function SpreadsheetBorderRibbon({ can, commands }) {
|
|
|
7593
9108
|
type: "button",
|
|
7594
9109
|
className: "work-spreadsheet-border-primary",
|
|
7595
9110
|
"aria-label": currentLabel,
|
|
7596
|
-
|
|
9111
|
+
"aria-keyshortcuts": currentShortcut?.aria,
|
|
9112
|
+
title: `${currentLabel}(${styleLabel},${color.toUpperCase()}${currentShortcut ? `;${currentShortcut.label}` : ''})`,
|
|
7597
9113
|
disabled: !can.setSelectedCellBorders(format),
|
|
7598
9114
|
onClick: ()=>commands.setSelectedCellBorders(format),
|
|
7599
9115
|
children: /*#__PURE__*/ jsx(SpreadsheetBorderGlyph, {
|
|
@@ -7627,11 +9143,14 @@ function SpreadsheetBorderRibbon({ can, commands }) {
|
|
|
7627
9143
|
...format,
|
|
7628
9144
|
target: option
|
|
7629
9145
|
};
|
|
9146
|
+
const shortcut = 'shortcut' in definition ? definition.shortcut : void 0;
|
|
7630
9147
|
return /*#__PURE__*/ jsxs("button", {
|
|
7631
9148
|
type: "button",
|
|
7632
9149
|
role: "menuitemradio",
|
|
7633
9150
|
tabIndex: 0 === index ? 0 : -1,
|
|
7634
9151
|
"aria-checked": option === target,
|
|
9152
|
+
"aria-label": definition.label,
|
|
9153
|
+
"aria-keyshortcuts": shortcut?.aria,
|
|
7635
9154
|
disabled: !can.setSelectedCellBorders(next),
|
|
7636
9155
|
onClick: ()=>{
|
|
7637
9156
|
setTarget(option);
|
|
@@ -7643,7 +9162,11 @@ function SpreadsheetBorderRibbon({ can, commands }) {
|
|
|
7643
9162
|
target: option
|
|
7644
9163
|
}),
|
|
7645
9164
|
/*#__PURE__*/ jsx("span", {
|
|
9165
|
+
className: "work-spreadsheet-border-target-label",
|
|
7646
9166
|
children: definition.label
|
|
9167
|
+
}),
|
|
9168
|
+
shortcut && /*#__PURE__*/ jsx("kbd", {
|
|
9169
|
+
children: shortcut.label
|
|
7647
9170
|
})
|
|
7648
9171
|
]
|
|
7649
9172
|
}, definition.id);
|
|
@@ -7783,6 +9306,8 @@ function SpreadsheetFontRibbonGroup({ can, commands, toolbarCell }) {
|
|
|
7783
9306
|
const strike = 1 === Number(toolbarCell?.cl);
|
|
7784
9307
|
const textColor = 'string' == typeof toolbarCell?.fc ? toolbarCell.fc : '#172033';
|
|
7785
9308
|
const fillColor = 'string' == typeof toolbarCell?.bg ? toolbarCell.bg : '#ffffff';
|
|
9309
|
+
const growFont = spreadsheetCommandCatalog.growFont;
|
|
9310
|
+
const shrinkFont = spreadsheetCommandCatalog.shrinkFont;
|
|
7786
9311
|
return /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
|
|
7787
9312
|
label: "字体",
|
|
7788
9313
|
priority: "high",
|
|
@@ -7802,6 +9327,28 @@ function SpreadsheetFontRibbonGroup({ can, commands, toolbarCell }) {
|
|
|
7802
9327
|
options: spreadsheetFontSizeOptions(toolbarCell?.fs),
|
|
7803
9328
|
onValueChange: (value)=>commands.setCellFormat('fs', Number(value))
|
|
7804
9329
|
}),
|
|
9330
|
+
/*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
|
|
9331
|
+
label: growFont.label,
|
|
9332
|
+
title: `${growFont.label}(${growFont.shortcut.label})`,
|
|
9333
|
+
"aria-keyshortcuts": growFont.shortcut.aria,
|
|
9334
|
+
displayLabel: false,
|
|
9335
|
+
disabled: !can.adjustFontSize('grow'),
|
|
9336
|
+
onClick: ()=>commands.adjustFontSize('grow'),
|
|
9337
|
+
children: /*#__PURE__*/ jsx(AArrowUp, {
|
|
9338
|
+
size: 15
|
|
9339
|
+
})
|
|
9340
|
+
}),
|
|
9341
|
+
/*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
|
|
9342
|
+
label: shrinkFont.label,
|
|
9343
|
+
title: `${shrinkFont.label}(${shrinkFont.shortcut.label})`,
|
|
9344
|
+
"aria-keyshortcuts": shrinkFont.shortcut.aria,
|
|
9345
|
+
displayLabel: false,
|
|
9346
|
+
disabled: !can.adjustFontSize('shrink'),
|
|
9347
|
+
onClick: ()=>commands.adjustFontSize('shrink'),
|
|
9348
|
+
children: /*#__PURE__*/ jsx(AArrowDown, {
|
|
9349
|
+
size: 15
|
|
9350
|
+
})
|
|
9351
|
+
}),
|
|
7805
9352
|
/*#__PURE__*/ jsx(SpreadsheetFontToggle, {
|
|
7806
9353
|
active: bold,
|
|
7807
9354
|
attribute: "bl",
|
|
@@ -8654,89 +10201,350 @@ function SpreadsheetPrintSettingsPanel({ content, onChange }) {
|
|
|
8654
10201
|
/*#__PURE__*/ jsxs("div", {
|
|
8655
10202
|
className: "actions",
|
|
8656
10203
|
children: [
|
|
8657
|
-
error && /*#__PURE__*/ jsx(InlineNotice, {
|
|
8658
|
-
className: "work-office-form-error",
|
|
8659
|
-
tone: "danger",
|
|
8660
|
-
role: "alert",
|
|
8661
|
-
children: error
|
|
8662
|
-
}),
|
|
8663
|
-
/*#__PURE__*/ jsx(button_Button, {
|
|
8664
|
-
tone: "secondary",
|
|
8665
|
-
disabled: dirty || !savedArea && !savedTitles && !savedPageBreaks && !savedPageSetup,
|
|
8666
|
-
onClick: clearSettings,
|
|
8667
|
-
children: "清除"
|
|
8668
|
-
}),
|
|
8669
|
-
/*#__PURE__*/ jsx(button_Button, {
|
|
8670
|
-
tone: "secondary",
|
|
8671
|
-
disabled: !dirty,
|
|
8672
|
-
onClick: cancelDraft,
|
|
8673
|
-
children: "取消更改"
|
|
10204
|
+
error && /*#__PURE__*/ jsx(InlineNotice, {
|
|
10205
|
+
className: "work-office-form-error",
|
|
10206
|
+
tone: "danger",
|
|
10207
|
+
role: "alert",
|
|
10208
|
+
children: error
|
|
10209
|
+
}),
|
|
10210
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
10211
|
+
tone: "secondary",
|
|
10212
|
+
disabled: dirty || !savedArea && !savedTitles && !savedPageBreaks && !savedPageSetup,
|
|
10213
|
+
onClick: clearSettings,
|
|
10214
|
+
children: "清除"
|
|
10215
|
+
}),
|
|
10216
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
10217
|
+
tone: "secondary",
|
|
10218
|
+
disabled: !dirty,
|
|
10219
|
+
onClick: cancelDraft,
|
|
10220
|
+
children: "取消更改"
|
|
10221
|
+
}),
|
|
10222
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
10223
|
+
type: "submit",
|
|
10224
|
+
tone: "primary",
|
|
10225
|
+
disabled: !sheetId || !dirty,
|
|
10226
|
+
children: "保存打印设置"
|
|
10227
|
+
})
|
|
10228
|
+
]
|
|
10229
|
+
})
|
|
10230
|
+
]
|
|
10231
|
+
});
|
|
10232
|
+
}
|
|
10233
|
+
function spreadsheetPrintSettingsDraft(content, sheetId, empty = false) {
|
|
10234
|
+
const area = empty ? void 0 : content.printAreas?.find((item)=>item.sheetId === sheetId);
|
|
10235
|
+
const titles = empty ? void 0 : content.printTitles?.find((item)=>item.sheetId === sheetId);
|
|
10236
|
+
const pageBreaks = empty ? void 0 : content.pageBreaks?.find((item)=>item.sheetId === sheetId);
|
|
10237
|
+
const pageSetup = empty ? void 0 : content.pageSetups?.find((item)=>item.sheetId === sheetId);
|
|
10238
|
+
return {
|
|
10239
|
+
reference: area?.reference ?? '',
|
|
10240
|
+
titleRows: titles?.rows ?? '',
|
|
10241
|
+
titleColumns: titles?.columns ?? '',
|
|
10242
|
+
rowPageBreaks: formatSpreadsheetRowPageBreaks(pageBreaks?.rows),
|
|
10243
|
+
columnPageBreaks: formatSpreadsheetColumnPageBreaks(pageBreaks?.columns),
|
|
10244
|
+
pageSetup: effectiveSpreadsheetPageSetup(pageSetup)
|
|
10245
|
+
};
|
|
10246
|
+
}
|
|
10247
|
+
function spreadsheetMaximumRow(sheet) {
|
|
10248
|
+
return Math.max(0, (sheet?.row ?? 1) - 1, (sheet?.data?.length ?? 1) - 1);
|
|
10249
|
+
}
|
|
10250
|
+
function spreadsheetMaximumColumn(sheet) {
|
|
10251
|
+
let maximum = Math.max(0, (sheet?.column ?? 1) - 1);
|
|
10252
|
+
for (const row of sheet?.data ?? [])maximum = Math.max(maximum, row.length - 1);
|
|
10253
|
+
return maximum;
|
|
10254
|
+
}
|
|
10255
|
+
function PageMarginField({ label, value, onChange }) {
|
|
10256
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
10257
|
+
className: "work-office-field",
|
|
10258
|
+
children: [
|
|
10259
|
+
/*#__PURE__*/ jsx("span", {
|
|
10260
|
+
children: label
|
|
10261
|
+
}),
|
|
10262
|
+
/*#__PURE__*/ jsx(CommittedOfficeNumberField, {
|
|
10263
|
+
ariaLabel: label,
|
|
10264
|
+
min: 0,
|
|
10265
|
+
max: 100,
|
|
10266
|
+
step: 0.01,
|
|
10267
|
+
value: value,
|
|
10268
|
+
normalizeValue: (nextValue)=>normalizePrintDecimal(nextValue, 0, 100),
|
|
10269
|
+
onValueCommit: onChange
|
|
10270
|
+
})
|
|
10271
|
+
]
|
|
10272
|
+
});
|
|
10273
|
+
}
|
|
10274
|
+
function normalizePrintInteger(value, minimum, maximum) {
|
|
10275
|
+
if (!value.trim()) return null;
|
|
10276
|
+
const number = Number(value);
|
|
10277
|
+
return Number.isFinite(number) ? Math.min(maximum, Math.max(minimum, Math.round(number))) : null;
|
|
10278
|
+
}
|
|
10279
|
+
function normalizePrintDecimal(value, minimum, maximum) {
|
|
10280
|
+
if (!value.trim()) return null;
|
|
10281
|
+
const number = Number(value);
|
|
10282
|
+
return Number.isFinite(number) ? Math.min(maximum, Math.max(minimum, Math.round(100 * number) / 100)) : null;
|
|
10283
|
+
}
|
|
10284
|
+
function validPageSetup(pageSetup) {
|
|
10285
|
+
const validInteger = (value, minimum, maximum)=>Number.isInteger(value) && value >= minimum && value <= maximum;
|
|
10286
|
+
return validInteger(pageSetup.scale, 10, 400) && validInteger(pageSetup.fitToWidth, 0, 32767) && validInteger(pageSetup.fitToHeight, 0, 32767) && validInteger(pageSetup.pageNumberStart, 1, 32767) && Object.values(pageSetup.margins).every((margin)=>Number.isFinite(margin) && margin >= 0 && margin <= 100);
|
|
10287
|
+
}
|
|
10288
|
+
function SpreadsheetTableDesignRibbon({ can, commands, sheetId, table }) {
|
|
10289
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
10290
|
+
children: [
|
|
10291
|
+
/*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
|
|
10292
|
+
label: "属性",
|
|
10293
|
+
priority: "high",
|
|
10294
|
+
children: [
|
|
10295
|
+
/*#__PURE__*/ jsx(SpreadsheetTableNameControl, {
|
|
10296
|
+
can: can,
|
|
10297
|
+
commands: commands,
|
|
10298
|
+
sheetId: sheetId,
|
|
10299
|
+
table: table
|
|
10300
|
+
}),
|
|
10301
|
+
/*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
|
|
10302
|
+
label: "转换为区域",
|
|
10303
|
+
disabled: !can.convertTableToRange(sheetId, table.id),
|
|
10304
|
+
onClick: ()=>{
|
|
10305
|
+
if (!commands.convertTableToRange(sheetId, table.id)) showToast('无法转换为区域。请先移除引用此表格的结构化引用。', 'error');
|
|
10306
|
+
},
|
|
10307
|
+
children: /*#__PURE__*/ jsx(TableProperties, {
|
|
10308
|
+
size: 19
|
|
10309
|
+
})
|
|
10310
|
+
})
|
|
10311
|
+
]
|
|
10312
|
+
}),
|
|
10313
|
+
/*#__PURE__*/ jsx(WorkOfficeRibbonGroup, {
|
|
10314
|
+
label: "表格样式",
|
|
10315
|
+
priority: "high",
|
|
10316
|
+
children: /*#__PURE__*/ jsx(SpreadsheetTableStyleGallery, {
|
|
10317
|
+
commands: commands,
|
|
10318
|
+
sheetId: sheetId,
|
|
10319
|
+
table: table
|
|
10320
|
+
})
|
|
10321
|
+
}),
|
|
10322
|
+
/*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
|
|
10323
|
+
label: "表格样式选项",
|
|
10324
|
+
children: [
|
|
10325
|
+
/*#__PURE__*/ jsx(SpreadsheetTableOption, {
|
|
10326
|
+
label: "首列",
|
|
10327
|
+
active: table.showFirstColumn,
|
|
10328
|
+
icon: /*#__PURE__*/ jsx(Columns3, {
|
|
10329
|
+
size: 17
|
|
10330
|
+
}),
|
|
10331
|
+
disabled: !can.updateTable(sheetId, table.id, {
|
|
10332
|
+
showFirstColumn: !table.showFirstColumn
|
|
10333
|
+
}),
|
|
10334
|
+
onToggle: ()=>commands.updateTable(sheetId, table.id, {
|
|
10335
|
+
showFirstColumn: !table.showFirstColumn
|
|
10336
|
+
})
|
|
10337
|
+
}),
|
|
10338
|
+
/*#__PURE__*/ jsx(SpreadsheetTableOption, {
|
|
10339
|
+
label: "末列",
|
|
10340
|
+
active: table.showLastColumn,
|
|
10341
|
+
icon: /*#__PURE__*/ jsx(Columns3, {
|
|
10342
|
+
size: 17
|
|
10343
|
+
}),
|
|
10344
|
+
disabled: !can.updateTable(sheetId, table.id, {
|
|
10345
|
+
showLastColumn: !table.showLastColumn
|
|
10346
|
+
}),
|
|
10347
|
+
onToggle: ()=>commands.updateTable(sheetId, table.id, {
|
|
10348
|
+
showLastColumn: !table.showLastColumn
|
|
10349
|
+
})
|
|
10350
|
+
}),
|
|
10351
|
+
/*#__PURE__*/ jsx(SpreadsheetTableOption, {
|
|
10352
|
+
label: "行条纹",
|
|
10353
|
+
active: table.showRowStripes,
|
|
10354
|
+
icon: /*#__PURE__*/ jsx(Rows3, {
|
|
10355
|
+
size: 17
|
|
10356
|
+
}),
|
|
10357
|
+
disabled: !can.updateTable(sheetId, table.id, {
|
|
10358
|
+
showRowStripes: !table.showRowStripes
|
|
10359
|
+
}),
|
|
10360
|
+
onToggle: ()=>commands.updateTable(sheetId, table.id, {
|
|
10361
|
+
showRowStripes: !table.showRowStripes
|
|
10362
|
+
})
|
|
10363
|
+
}),
|
|
10364
|
+
/*#__PURE__*/ jsx(SpreadsheetTableOption, {
|
|
10365
|
+
label: "列条纹",
|
|
10366
|
+
active: table.showColumnStripes,
|
|
10367
|
+
icon: /*#__PURE__*/ jsx(Columns3, {
|
|
10368
|
+
size: 17
|
|
10369
|
+
}),
|
|
10370
|
+
disabled: !can.updateTable(sheetId, table.id, {
|
|
10371
|
+
showColumnStripes: !table.showColumnStripes
|
|
10372
|
+
}),
|
|
10373
|
+
onToggle: ()=>commands.updateTable(sheetId, table.id, {
|
|
10374
|
+
showColumnStripes: !table.showColumnStripes
|
|
10375
|
+
})
|
|
10376
|
+
})
|
|
10377
|
+
]
|
|
10378
|
+
})
|
|
10379
|
+
]
|
|
10380
|
+
});
|
|
10381
|
+
}
|
|
10382
|
+
function SpreadsheetTableNameControl({ can, commands, sheetId, table }) {
|
|
10383
|
+
const [name, setName] = useState(table.name);
|
|
10384
|
+
useEffect(()=>setName(table.name), [
|
|
10385
|
+
table.id,
|
|
10386
|
+
table.name
|
|
10387
|
+
]);
|
|
10388
|
+
const commit = ()=>{
|
|
10389
|
+
const candidate = name.trim();
|
|
10390
|
+
if (!candidate || candidate === table.name) return void setName(table.name);
|
|
10391
|
+
const patch = {
|
|
10392
|
+
name: candidate
|
|
10393
|
+
};
|
|
10394
|
+
if (!can.updateTable(sheetId, table.id, patch) || !commands.updateTable(sheetId, table.id, patch)) {
|
|
10395
|
+
setName(table.name);
|
|
10396
|
+
showToast('表格名称无效或已被使用。', 'error');
|
|
10397
|
+
}
|
|
10398
|
+
};
|
|
10399
|
+
return /*#__PURE__*/ jsxs("label", {
|
|
10400
|
+
className: "work-spreadsheet-table-name",
|
|
10401
|
+
children: [
|
|
10402
|
+
/*#__PURE__*/ jsx("span", {
|
|
10403
|
+
children: "表格名称"
|
|
10404
|
+
}),
|
|
10405
|
+
/*#__PURE__*/ jsx("input", {
|
|
10406
|
+
type: "text",
|
|
10407
|
+
"aria-label": "表格名称",
|
|
10408
|
+
autoCapitalize: "none",
|
|
10409
|
+
spellCheck: false,
|
|
10410
|
+
value: name,
|
|
10411
|
+
onBlur: commit,
|
|
10412
|
+
onChange: (event)=>setName(event.currentTarget.value),
|
|
10413
|
+
onKeyDown: (event)=>{
|
|
10414
|
+
if ('Enter' === event.key) {
|
|
10415
|
+
event.preventDefault();
|
|
10416
|
+
commit();
|
|
10417
|
+
} else if ('Escape' === event.key) {
|
|
10418
|
+
event.preventDefault();
|
|
10419
|
+
setName(table.name);
|
|
10420
|
+
}
|
|
10421
|
+
}
|
|
10422
|
+
})
|
|
10423
|
+
]
|
|
10424
|
+
});
|
|
10425
|
+
}
|
|
10426
|
+
function SpreadsheetTableStyleGallery({ commands, sheetId, table }) {
|
|
10427
|
+
const choices = spreadsheetTableStyleChoices();
|
|
10428
|
+
const selected = choices.find((choice)=>spreadsheetTableUsesStyle(table.style, choice.style));
|
|
10429
|
+
const families = [
|
|
10430
|
+
{
|
|
10431
|
+
id: 'light',
|
|
10432
|
+
label: '浅色'
|
|
10433
|
+
},
|
|
10434
|
+
{
|
|
10435
|
+
id: 'medium',
|
|
10436
|
+
label: '中等'
|
|
10437
|
+
},
|
|
10438
|
+
{
|
|
10439
|
+
id: 'dark',
|
|
10440
|
+
label: '深色'
|
|
10441
|
+
}
|
|
10442
|
+
];
|
|
10443
|
+
return /*#__PURE__*/ jsx(Popover, {
|
|
10444
|
+
label: "表格样式",
|
|
10445
|
+
panelLabel: "表格样式库",
|
|
10446
|
+
panelRole: "menu",
|
|
10447
|
+
portal: true,
|
|
10448
|
+
className: "work-spreadsheet-table-style-root",
|
|
10449
|
+
panelClassName: "work-spreadsheet-table-style-menu",
|
|
10450
|
+
focusFirstOnOpen: true,
|
|
10451
|
+
onPanelKeyDown: moveSpreadsheetTableStyleFocus,
|
|
10452
|
+
trigger: (triggerProps, { open })=>/*#__PURE__*/ jsxs("button", {
|
|
10453
|
+
...triggerProps,
|
|
10454
|
+
type: "button",
|
|
10455
|
+
className: `with-label work-spreadsheet-table-style-trigger${open ? ' active' : ''}`,
|
|
10456
|
+
title: `表格样式(当前:${selected?.label ?? '无'})`,
|
|
10457
|
+
children: [
|
|
10458
|
+
/*#__PURE__*/ jsx(SpreadsheetTableStylePreview, {
|
|
10459
|
+
choice: selected ?? choices[0]
|
|
8674
10460
|
}),
|
|
8675
|
-
/*#__PURE__*/ jsx(
|
|
8676
|
-
|
|
8677
|
-
tone: "primary",
|
|
8678
|
-
disabled: !sheetId || !dirty,
|
|
8679
|
-
children: "保存打印设置"
|
|
10461
|
+
/*#__PURE__*/ jsx("span", {
|
|
10462
|
+
children: "表格样式"
|
|
8680
10463
|
})
|
|
8681
10464
|
]
|
|
10465
|
+
}),
|
|
10466
|
+
children: (close)=>/*#__PURE__*/ jsx(Fragment, {
|
|
10467
|
+
children: families.map((family)=>/*#__PURE__*/ jsxs("fieldset", {
|
|
10468
|
+
className: "work-spreadsheet-table-style-family",
|
|
10469
|
+
"data-office-menu-grid": true,
|
|
10470
|
+
"aria-label": family.label,
|
|
10471
|
+
children: [
|
|
10472
|
+
/*#__PURE__*/ jsx("span", {
|
|
10473
|
+
children: family.label
|
|
10474
|
+
}),
|
|
10475
|
+
/*#__PURE__*/ jsx("div", {
|
|
10476
|
+
children: choices.filter((choice)=>choice.style.family === family.id).map((choice)=>{
|
|
10477
|
+
const checked = spreadsheetTableUsesStyle(table.style, choice.style);
|
|
10478
|
+
return /*#__PURE__*/ jsx("button", {
|
|
10479
|
+
type: "button",
|
|
10480
|
+
role: "menuitemradio",
|
|
10481
|
+
tabIndex: -1,
|
|
10482
|
+
"aria-label": `应用表格样式:${choice.label}`,
|
|
10483
|
+
"aria-checked": checked,
|
|
10484
|
+
title: choice.label,
|
|
10485
|
+
onClick: ()=>{
|
|
10486
|
+
close();
|
|
10487
|
+
commands.updateTable(sheetId, table.id, {
|
|
10488
|
+
style: choice.style
|
|
10489
|
+
});
|
|
10490
|
+
},
|
|
10491
|
+
children: /*#__PURE__*/ jsx(SpreadsheetTableStylePreview, {
|
|
10492
|
+
choice: choice
|
|
10493
|
+
})
|
|
10494
|
+
}, choice.ooxmlName);
|
|
10495
|
+
})
|
|
10496
|
+
})
|
|
10497
|
+
]
|
|
10498
|
+
}, family.id))
|
|
8682
10499
|
})
|
|
8683
|
-
]
|
|
8684
10500
|
});
|
|
8685
10501
|
}
|
|
8686
|
-
function
|
|
8687
|
-
const
|
|
8688
|
-
const
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
for (const row of sheet?.data ?? [])maximum = Math.max(maximum, row.length - 1);
|
|
8706
|
-
return maximum;
|
|
8707
|
-
}
|
|
8708
|
-
function PageMarginField({ label, value, onChange }) {
|
|
8709
|
-
return /*#__PURE__*/ jsxs("div", {
|
|
8710
|
-
className: "work-office-field",
|
|
10502
|
+
function moveSpreadsheetTableStyleFocus(event) {
|
|
10503
|
+
const active = document.activeElement;
|
|
10504
|
+
const group = [
|
|
10505
|
+
...event.currentTarget.querySelectorAll('[data-office-menu-grid]')
|
|
10506
|
+
].find((candidate)=>candidate.contains(active));
|
|
10507
|
+
const grid = group?.querySelector(':scope > div');
|
|
10508
|
+
const template = grid ? getComputedStyle(grid).gridTemplateColumns : '';
|
|
10509
|
+
const repeated = template.match(/^repeat\(\s*(\d+)/)?.[1];
|
|
10510
|
+
const resolved = template.split(/\s+/).filter((value)=>value && 'none' !== value).length;
|
|
10511
|
+
const columns = repeated ? Number(repeated) : resolved || 7;
|
|
10512
|
+
return moveOfficeGridMenuFocus(event, Math.max(1, columns));
|
|
10513
|
+
}
|
|
10514
|
+
function spreadsheetTableUsesStyle(tableStyle, choice) {
|
|
10515
|
+
return 'none' !== tableStyle.family && tableStyle.family === choice.family && tableStyle.number === choice.number;
|
|
10516
|
+
}
|
|
10517
|
+
function SpreadsheetTableStylePreview({ choice }) {
|
|
10518
|
+
return /*#__PURE__*/ jsxs("span", {
|
|
10519
|
+
className: "work-spreadsheet-table-style-preview",
|
|
10520
|
+
"aria-hidden": "true",
|
|
8711
10521
|
children: [
|
|
8712
|
-
/*#__PURE__*/ jsx("
|
|
8713
|
-
|
|
10522
|
+
/*#__PURE__*/ jsx("i", {
|
|
10523
|
+
style: {
|
|
10524
|
+
backgroundColor: choice.palette.header
|
|
10525
|
+
}
|
|
8714
10526
|
}),
|
|
8715
|
-
/*#__PURE__*/ jsx(
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
10527
|
+
/*#__PURE__*/ jsx("i", {
|
|
10528
|
+
style: {
|
|
10529
|
+
backgroundColor: choice.palette.primaryRow
|
|
10530
|
+
}
|
|
10531
|
+
}),
|
|
10532
|
+
/*#__PURE__*/ jsx("i", {
|
|
10533
|
+
style: {
|
|
10534
|
+
backgroundColor: choice.palette.secondaryRow
|
|
10535
|
+
}
|
|
8723
10536
|
})
|
|
8724
10537
|
]
|
|
8725
10538
|
});
|
|
8726
10539
|
}
|
|
8727
|
-
function
|
|
8728
|
-
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
return Number.isFinite(number) ? Math.min(maximum, Math.max(minimum, Math.round(100 * number) / 100)) : null;
|
|
8736
|
-
}
|
|
8737
|
-
function validPageSetup(pageSetup) {
|
|
8738
|
-
const validInteger = (value, minimum, maximum)=>Number.isInteger(value) && value >= minimum && value <= maximum;
|
|
8739
|
-
return validInteger(pageSetup.scale, 10, 400) && validInteger(pageSetup.fitToWidth, 0, 32767) && validInteger(pageSetup.fitToHeight, 0, 32767) && validInteger(pageSetup.pageNumberStart, 1, 32767) && Object.values(pageSetup.margins).every((margin)=>Number.isFinite(margin) && margin >= 0 && margin <= 100);
|
|
10540
|
+
function SpreadsheetTableOption({ active, disabled, icon, label, onToggle }) {
|
|
10541
|
+
return /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
|
|
10542
|
+
label: label,
|
|
10543
|
+
active: active,
|
|
10544
|
+
disabled: disabled,
|
|
10545
|
+
onClick: onToggle,
|
|
10546
|
+
children: icon
|
|
10547
|
+
});
|
|
8740
10548
|
}
|
|
8741
10549
|
const defaultSpreadsheetFreezePanesSelection = {
|
|
8742
10550
|
row: [
|
|
@@ -8750,7 +10558,11 @@ const defaultSpreadsheetFreezePanesSelection = {
|
|
|
8750
10558
|
row_focus: 0,
|
|
8751
10559
|
column_focus: 0
|
|
8752
10560
|
};
|
|
8753
|
-
function SpreadsheetEditorRibbon({ activeTab, autoFilterActive = false, can, commands, content, fileActions, findOpen, formatPainterMode = null, freezePanesActive = false, freezePanesSelection = defaultSpreadsheetFreezePanesSelection, gridLinesVisible, panelId, onTabChange, onTogglePanel, panel, toolbarCell, toolbarCellBorders }) {
|
|
10561
|
+
function SpreadsheetEditorRibbon({ activeTab, activeTable = null, activeTableSheetId, autoFilterActive = false, can, commands, content, fileActions, findOpen, formatPainterMode = null, freezePanesActive = false, freezePanesSelection = defaultSpreadsheetFreezePanesSelection, gridLinesVisible, panelId, onTabChange, onTogglePanel, panel, toolbarCell, toolbarCellBorders }) {
|
|
10562
|
+
const ribbonTabs = activeTable ? [
|
|
10563
|
+
...spreadsheetRibbonTabs,
|
|
10564
|
+
spreadsheetTableDesignRibbonTab
|
|
10565
|
+
] : spreadsheetRibbonTabs;
|
|
8754
10566
|
const formulaCount = useMemo(()=>spreadsheetFormulaCount(content), [
|
|
8755
10567
|
content
|
|
8756
10568
|
]);
|
|
@@ -8759,7 +10571,7 @@ function SpreadsheetEditorRibbon({ activeTab, autoFilterActive = false, can, com
|
|
|
8759
10571
|
]);
|
|
8760
10572
|
return /*#__PURE__*/ jsx(WorkOfficeRibbon, {
|
|
8761
10573
|
ariaLabel: "表格功能区",
|
|
8762
|
-
tabs:
|
|
10574
|
+
tabs: ribbonTabs,
|
|
8763
10575
|
defaultTab: "home",
|
|
8764
10576
|
activeTab: activeTab,
|
|
8765
10577
|
onTabChange: onTabChange,
|
|
@@ -8991,6 +10803,20 @@ function SpreadsheetEditorRibbon({ activeTab, autoFilterActive = false, can, com
|
|
|
8991
10803
|
}),
|
|
8992
10804
|
insert: /*#__PURE__*/ jsxs(Fragment, {
|
|
8993
10805
|
children: [
|
|
10806
|
+
/*#__PURE__*/ jsx(WorkOfficeRibbonGroup, {
|
|
10807
|
+
label: "表格",
|
|
10808
|
+
priority: "high",
|
|
10809
|
+
children: /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
|
|
10810
|
+
label: spreadsheetCommandCatalog.table.label,
|
|
10811
|
+
title: `${spreadsheetCommandCatalog.table.label}(${spreadsheetCommandCatalog.table.shortcut.label})`,
|
|
10812
|
+
"aria-keyshortcuts": spreadsheetCommandCatalog.table.shortcut.aria,
|
|
10813
|
+
disabled: !can.openTable(),
|
|
10814
|
+
onClick: commands.openTable,
|
|
10815
|
+
children: /*#__PURE__*/ jsx(Table2, {
|
|
10816
|
+
size: 19
|
|
10817
|
+
})
|
|
10818
|
+
})
|
|
10819
|
+
}),
|
|
8994
10820
|
/*#__PURE__*/ jsx(WorkOfficeRibbonGroup, {
|
|
8995
10821
|
label: "链接",
|
|
8996
10822
|
priority: "high",
|
|
@@ -9188,7 +11014,13 @@ function SpreadsheetEditorRibbon({ activeTab, autoFilterActive = false, can, com
|
|
|
9188
11014
|
})
|
|
9189
11015
|
})
|
|
9190
11016
|
]
|
|
9191
|
-
})
|
|
11017
|
+
}),
|
|
11018
|
+
tableDesign: activeTable && activeTableSheetId ? /*#__PURE__*/ jsx(SpreadsheetTableDesignRibbon, {
|
|
11019
|
+
can: can,
|
|
11020
|
+
commands: commands,
|
|
11021
|
+
sheetId: activeTableSheetId,
|
|
11022
|
+
table: activeTable
|
|
11023
|
+
}) : null
|
|
9192
11024
|
}
|
|
9193
11025
|
});
|
|
9194
11026
|
}
|
|
@@ -12086,6 +13918,59 @@ function SheetMenuButton({ icon, label, danger = false, disabled = false, onClic
|
|
|
12086
13918
|
]
|
|
12087
13919
|
});
|
|
12088
13920
|
}
|
|
13921
|
+
const pendingContextRestores = new WeakMap();
|
|
13922
|
+
function beginSpreadsheetTableCellRender(_cell, tableStyle, conditionalStyle, context) {
|
|
13923
|
+
if (tableStyle) context.fillStyle = tableStyle.background;
|
|
13924
|
+
if (conditionalStyle?.cellColor) context.fillStyle = conditionalStyle.cellColor;
|
|
13925
|
+
if (!tableStyle || pendingContextRestores.has(context) || 'function' != typeof context.fillText) return;
|
|
13926
|
+
const fillText = context.fillText;
|
|
13927
|
+
pendingContextRestores.set(context, {
|
|
13928
|
+
fillText,
|
|
13929
|
+
fillTextOwned: Object.hasOwn(context, 'fillText')
|
|
13930
|
+
});
|
|
13931
|
+
const textColor = conditionalStyle?.textColor ?? tableStyle.textColor;
|
|
13932
|
+
context.fillText = (text, x, y, maxWidth)=>{
|
|
13933
|
+
const previousFillStyle = context.fillStyle;
|
|
13934
|
+
const previousFont = context.font;
|
|
13935
|
+
context.fillStyle = textColor;
|
|
13936
|
+
if (tableStyle.bold) context.font = boldSpreadsheetTableCanvasFont(context.font);
|
|
13937
|
+
try {
|
|
13938
|
+
if (void 0 === maxWidth) fillText.call(context, text, x, y);
|
|
13939
|
+
else fillText.call(context, text, x, y, maxWidth);
|
|
13940
|
+
} finally{
|
|
13941
|
+
context.fillStyle = previousFillStyle;
|
|
13942
|
+
context.font = previousFont;
|
|
13943
|
+
}
|
|
13944
|
+
};
|
|
13945
|
+
}
|
|
13946
|
+
function finishSpreadsheetTableCellRender(_cell, cellInfo, tableStyle, context) {
|
|
13947
|
+
if (tableStyle) drawSpreadsheetTableCellBorder(cellInfo, tableStyle, context);
|
|
13948
|
+
const restore = pendingContextRestores.get(context);
|
|
13949
|
+
if (!restore) return;
|
|
13950
|
+
if (restore.fillTextOwned) context.fillText = restore.fillText;
|
|
13951
|
+
else delete context.fillText;
|
|
13952
|
+
pendingContextRestores.delete(context);
|
|
13953
|
+
}
|
|
13954
|
+
function boldSpreadsheetTableCanvasFont(font) {
|
|
13955
|
+
return /(?:^|\s)(?:bold|[6-9]00)(?:\s|$)/i.test(font) ? font : `bold ${font}`;
|
|
13956
|
+
}
|
|
13957
|
+
function drawSpreadsheetTableCellBorder(cellInfo, tableStyle, context) {
|
|
13958
|
+
const left = Math.round(cellInfo.startX) + 0.5;
|
|
13959
|
+
const top = Math.round(cellInfo.startY) + 0.5;
|
|
13960
|
+
const right = Math.round(cellInfo.endX) - 0.5;
|
|
13961
|
+
const bottom = Math.round(cellInfo.endY) - 0.5;
|
|
13962
|
+
context.save();
|
|
13963
|
+
context.beginPath();
|
|
13964
|
+
context.strokeStyle = tableStyle.borderColor;
|
|
13965
|
+
context.lineWidth = 'header' === tableStyle.role ? 1 : 0.75;
|
|
13966
|
+
context.moveTo(left, top);
|
|
13967
|
+
context.lineTo(right, top);
|
|
13968
|
+
context.lineTo(right, bottom);
|
|
13969
|
+
context.lineTo(left, bottom);
|
|
13970
|
+
context.closePath();
|
|
13971
|
+
context.stroke();
|
|
13972
|
+
context.restore();
|
|
13973
|
+
}
|
|
12089
13974
|
function validateSpreadsheetChartSeriesTrendlines(series, seriesIndex) {
|
|
12090
13975
|
for (const [trendlineIndex, trendline] of (series.trendlines ?? []).entries()){
|
|
12091
13976
|
const prefix = `系列 ${seriesIndex + 1} 的趋势线 ${trendlineIndex + 1}`;
|
|
@@ -16195,220 +18080,28 @@ function NamedRangeManager({ content, onChange }) {
|
|
|
16195
18080
|
onClick: cancelDraft,
|
|
16196
18081
|
children: "取消更改"
|
|
16197
18082
|
}),
|
|
16198
|
-
/*#__PURE__*/ jsx(button_Button, {
|
|
16199
|
-
type: "submit",
|
|
16200
|
-
tone: "primary",
|
|
16201
|
-
disabled: Boolean(draft.id) && !dirty,
|
|
16202
|
-
children: "保存名称"
|
|
16203
|
-
})
|
|
16204
|
-
]
|
|
16205
|
-
})
|
|
16206
|
-
]
|
|
16207
|
-
})
|
|
16208
|
-
]
|
|
16209
|
-
});
|
|
16210
|
-
}
|
|
16211
|
-
function rangeDraft(range) {
|
|
16212
|
-
return {
|
|
16213
|
-
id: range?.id,
|
|
16214
|
-
name: range?.name ?? '',
|
|
16215
|
-
reference: range?.reference ?? '',
|
|
16216
|
-
scopeSheetId: range?.scopeSheetId ?? '',
|
|
16217
|
-
comment: range?.comment ?? ''
|
|
16218
|
-
};
|
|
16219
|
-
}
|
|
16220
|
-
function spreadsheetAutoFilterRange(sheet, selection) {
|
|
16221
|
-
if (sheet.isPivotTable || sheet.pivotTables?.length) return null;
|
|
16222
|
-
const normalized = normalizeAutoFilterSelection(selection);
|
|
16223
|
-
const range = normalized.row[0] !== normalized.row[1] ? normalized : spreadsheetCurrentRegion(sheet, normalized);
|
|
16224
|
-
if (!range || !validSpreadsheetAutoFilterRange(sheet, range)) return null;
|
|
16225
|
-
return range;
|
|
16226
|
-
}
|
|
16227
|
-
function spreadsheetAutoFilterHeaderColumn(sheet, selection) {
|
|
16228
|
-
const range = normalizedFilterSelection(sheet?.filter_select);
|
|
16229
|
-
if (!sheet || !range) return null;
|
|
16230
|
-
const row = spreadsheet_auto_filter_finiteIndex(selection.row_focus, selection.row[0]);
|
|
16231
|
-
const column = spreadsheet_auto_filter_finiteIndex(selection.column_focus, selection.column[0]);
|
|
16232
|
-
if (row !== range.row[0] || column < range.column[0] || column > range.column[1]) return null;
|
|
16233
|
-
return column;
|
|
16234
|
-
}
|
|
16235
|
-
function toggleSpreadsheetAutoFilter(content, sheetId, selection) {
|
|
16236
|
-
const sheetIndex = content.sheets.findIndex((sheet)=>sheet.id === sheetId);
|
|
16237
|
-
const sheet = content.sheets[sheetIndex];
|
|
16238
|
-
if (!sheet) return null;
|
|
16239
|
-
const nextSheet = sheet.filter_select ? spreadsheetSheetWithoutAutoFilter(sheet) : spreadsheetSheetWithAutoFilter(sheet, selection);
|
|
16240
|
-
if (!nextSheet) return null;
|
|
16241
|
-
const sheets = [
|
|
16242
|
-
...content.sheets
|
|
16243
|
-
];
|
|
16244
|
-
sheets[sheetIndex] = {
|
|
16245
|
-
...nextSheet,
|
|
16246
|
-
luckysheet_select_save: [
|
|
16247
|
-
finiteSpreadsheetSelection(selection)
|
|
16248
|
-
]
|
|
16249
|
-
};
|
|
16250
|
-
return {
|
|
16251
|
-
...content,
|
|
16252
|
-
sheets
|
|
16253
|
-
};
|
|
16254
|
-
}
|
|
16255
|
-
function spreadsheetSheetWithAutoFilter(sheet, selection) {
|
|
16256
|
-
const range = spreadsheetAutoFilterRange(sheet, selection);
|
|
16257
|
-
if (!range) return null;
|
|
16258
|
-
return {
|
|
16259
|
-
...sheet,
|
|
16260
|
-
filter: {},
|
|
16261
|
-
filter_select: {
|
|
16262
|
-
row: [
|
|
16263
|
-
...range.row
|
|
16264
|
-
],
|
|
16265
|
-
column: [
|
|
16266
|
-
...range.column
|
|
16267
|
-
]
|
|
16268
|
-
}
|
|
16269
|
-
};
|
|
16270
|
-
}
|
|
16271
|
-
function spreadsheetSheetWithoutAutoFilter(sheet) {
|
|
16272
|
-
const hiddenByFilter = spreadsheetFilterHiddenRows(sheet.filter);
|
|
16273
|
-
const rowhidden = {
|
|
16274
|
-
...sheet.config?.rowhidden
|
|
16275
|
-
};
|
|
16276
|
-
for (const row of hiddenByFilter)delete rowhidden[row];
|
|
16277
|
-
const config = sheet.config ? {
|
|
16278
|
-
...sheet.config,
|
|
16279
|
-
rowhidden
|
|
16280
|
-
} : void 0;
|
|
16281
|
-
const { filter: _filter, filter_select: _selection, ...remaining } = sheet;
|
|
16282
|
-
return {
|
|
16283
|
-
...remaining,
|
|
16284
|
-
config
|
|
16285
|
-
};
|
|
16286
|
-
}
|
|
16287
|
-
function spreadsheetFilterHiddenRows(filter) {
|
|
16288
|
-
const rows = new Set();
|
|
16289
|
-
for (const value of Object.values(filter ?? {})){
|
|
16290
|
-
if (!value || 'object' != typeof value) continue;
|
|
16291
|
-
const rowhidden = value.rowhidden;
|
|
16292
|
-
if (rowhidden && 'object' == typeof rowhidden) for (const row of Object.keys(rowhidden))rows.add(row);
|
|
16293
|
-
}
|
|
16294
|
-
return rows;
|
|
16295
|
-
}
|
|
16296
|
-
function spreadsheetCurrentRegion(sheet, selection) {
|
|
16297
|
-
const cells = spreadsheetCellReader(sheet);
|
|
16298
|
-
const bounds = spreadsheetUsedBounds(sheet);
|
|
16299
|
-
let startRow = selection.row[0];
|
|
16300
|
-
let endRow = selection.row[1];
|
|
16301
|
-
let startColumn = selection.column[0];
|
|
16302
|
-
let endColumn = selection.column[1];
|
|
16303
|
-
if (startRow > bounds.lastRow || startColumn > bounds.lastColumn || !spreadsheet_auto_filter_spreadsheetCellHasContent(cells(startRow, startColumn))) return null;
|
|
16304
|
-
let changed = true;
|
|
16305
|
-
while(changed){
|
|
16306
|
-
changed = false;
|
|
16307
|
-
while(startColumn > 0 && spreadsheetColumnHasContent(cells, startColumn - 1, startRow, endRow)){
|
|
16308
|
-
startColumn -= 1;
|
|
16309
|
-
changed = true;
|
|
16310
|
-
}
|
|
16311
|
-
while(endColumn < bounds.lastColumn && spreadsheetColumnHasContent(cells, endColumn + 1, startRow, endRow)){
|
|
16312
|
-
endColumn += 1;
|
|
16313
|
-
changed = true;
|
|
16314
|
-
}
|
|
16315
|
-
while(startRow > 0 && spreadsheetRowHasContent(cells, startRow - 1, startColumn, endColumn)){
|
|
16316
|
-
startRow -= 1;
|
|
16317
|
-
changed = true;
|
|
16318
|
-
}
|
|
16319
|
-
while(endRow < bounds.lastRow && spreadsheetRowHasContent(cells, endRow + 1, startColumn, endColumn)){
|
|
16320
|
-
endRow += 1;
|
|
16321
|
-
changed = true;
|
|
16322
|
-
}
|
|
16323
|
-
}
|
|
16324
|
-
return {
|
|
16325
|
-
row: [
|
|
16326
|
-
startRow,
|
|
16327
|
-
endRow
|
|
16328
|
-
],
|
|
16329
|
-
column: [
|
|
16330
|
-
startColumn,
|
|
16331
|
-
endColumn
|
|
18083
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
18084
|
+
type: "submit",
|
|
18085
|
+
tone: "primary",
|
|
18086
|
+
disabled: Boolean(draft.id) && !dirty,
|
|
18087
|
+
children: "保存名称"
|
|
18088
|
+
})
|
|
18089
|
+
]
|
|
18090
|
+
})
|
|
18091
|
+
]
|
|
18092
|
+
})
|
|
16332
18093
|
]
|
|
16333
|
-
};
|
|
16334
|
-
}
|
|
16335
|
-
function validSpreadsheetAutoFilterRange(sheet, range) {
|
|
16336
|
-
if (range.row[1] <= range.row[0]) return false;
|
|
16337
|
-
const cells = spreadsheetCellReader(sheet);
|
|
16338
|
-
if (!spreadsheetRowHasContent(cells, range.row[0], range.column[0], range.column[1])) return false;
|
|
16339
|
-
let dataFound = false;
|
|
16340
|
-
for(let row = range.row[0] + 1; row <= range.row[1]; row += 1)if (spreadsheetRowHasContent(cells, row, range.column[0], range.column[1])) {
|
|
16341
|
-
dataFound = true;
|
|
16342
|
-
break;
|
|
16343
|
-
}
|
|
16344
|
-
return dataFound && !spreadsheetRangeIntersectsMerge(sheet, range);
|
|
16345
|
-
}
|
|
16346
|
-
function spreadsheetRangeIntersectsMerge(sheet, range) {
|
|
16347
|
-
return Object.values(sheet.config?.merge ?? {}).some((merge)=>{
|
|
16348
|
-
const endRow = merge.r + Math.max(merge.rs, 1) - 1;
|
|
16349
|
-
const endColumn = merge.c + Math.max(merge.cs, 1) - 1;
|
|
16350
|
-
return merge.r <= range.row[1] && endRow >= range.row[0] && merge.c <= range.column[1] && endColumn >= range.column[0];
|
|
16351
18094
|
});
|
|
16352
18095
|
}
|
|
16353
|
-
function
|
|
16354
|
-
for(let column = startColumn; column <= endColumn; column += 1)if (spreadsheet_auto_filter_spreadsheetCellHasContent(cellAt(row, column))) return true;
|
|
16355
|
-
return false;
|
|
16356
|
-
}
|
|
16357
|
-
function spreadsheetColumnHasContent(cellAt, column, startRow, endRow) {
|
|
16358
|
-
for(let row = startRow; row <= endRow; row += 1)if (spreadsheet_auto_filter_spreadsheetCellHasContent(cellAt(row, column))) return true;
|
|
16359
|
-
return false;
|
|
16360
|
-
}
|
|
16361
|
-
function spreadsheet_auto_filter_spreadsheetCellHasContent(cell) {
|
|
16362
|
-
if (!cell) return false;
|
|
16363
|
-
return [
|
|
16364
|
-
cell.v,
|
|
16365
|
-
cell.m,
|
|
16366
|
-
cell.f
|
|
16367
|
-
].some((value)=>null != value && '' !== value);
|
|
16368
|
-
}
|
|
16369
|
-
function spreadsheetCellReader(sheet) {
|
|
16370
|
-
if (sheet.data) return (row, column)=>sheet.data?.[row]?.[column] ?? null;
|
|
16371
|
-
const cells = new Map((sheet.celldata ?? []).map((cell)=>[
|
|
16372
|
-
`${cell.r}:${cell.c}`,
|
|
16373
|
-
cell.v
|
|
16374
|
-
]));
|
|
16375
|
-
return (row, column)=>cells.get(`${row}:${column}`) ?? null;
|
|
16376
|
-
}
|
|
16377
|
-
function spreadsheetUsedBounds(sheet) {
|
|
16378
|
-
let lastRow = Math.max((sheet.data?.length ?? 1) - 1, 0);
|
|
16379
|
-
let lastColumn = Math.max(sparseMatrixColumnCount(sheet.data) - 1, 0);
|
|
16380
|
-
for (const cell of sheet.celldata ?? []){
|
|
16381
|
-
lastRow = Math.max(lastRow, cell.r);
|
|
16382
|
-
lastColumn = Math.max(lastColumn, cell.c);
|
|
16383
|
-
}
|
|
16384
|
-
return {
|
|
16385
|
-
lastColumn,
|
|
16386
|
-
lastRow
|
|
16387
|
-
};
|
|
16388
|
-
}
|
|
16389
|
-
function normalizeAutoFilterSelection(selection) {
|
|
16390
|
-
const startRow = spreadsheet_auto_filter_finiteIndex(selection.row[0], 0);
|
|
16391
|
-
const endRow = spreadsheet_auto_filter_finiteIndex(selection.row[1], startRow);
|
|
16392
|
-
const startColumn = spreadsheet_auto_filter_finiteIndex(selection.column[0], 0);
|
|
16393
|
-
const endColumn = spreadsheet_auto_filter_finiteIndex(selection.column[1], startColumn);
|
|
18096
|
+
function rangeDraft(range) {
|
|
16394
18097
|
return {
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16400
|
-
Math.min(startColumn, endColumn),
|
|
16401
|
-
Math.max(startColumn, endColumn)
|
|
16402
|
-
]
|
|
18098
|
+
id: range?.id,
|
|
18099
|
+
name: range?.name ?? '',
|
|
18100
|
+
reference: range?.reference ?? '',
|
|
18101
|
+
scopeSheetId: range?.scopeSheetId ?? '',
|
|
18102
|
+
comment: range?.comment ?? ''
|
|
16403
18103
|
};
|
|
16404
18104
|
}
|
|
16405
|
-
function normalizedFilterSelection(selection) {
|
|
16406
|
-
if (!selection?.row?.length || !selection.column?.length) return null;
|
|
16407
|
-
return normalizeAutoFilterSelection(selection);
|
|
16408
|
-
}
|
|
16409
|
-
function spreadsheet_auto_filter_finiteIndex(value, fallback) {
|
|
16410
|
-
return 'number' == typeof value && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : fallback;
|
|
16411
|
-
}
|
|
16412
18105
|
function useSpreadsheetAutoFilter({ canvasRef, content, editable, mountRevision, onChange, selection, sheetId, workbook = null }) {
|
|
16413
18106
|
const contentRef = useRef(content);
|
|
16414
18107
|
const editableRef = useRef(editable);
|
|
@@ -19984,6 +21677,206 @@ function spreadsheetHyperlinkValidationMessage(content, source, value) {
|
|
|
19984
21677
|
function spreadsheetHyperlinkFailureMessage(content, source, value, fallback) {
|
|
19985
21678
|
return spreadsheetHyperlinkValidationMessage(content, source, value) ?? fallback;
|
|
19986
21679
|
}
|
|
21680
|
+
function SpreadsheetTableDialog({ source, restoreFocusTarget, onApply, onClose, onValidate }) {
|
|
21681
|
+
const [value, setValue] = useState(source.value);
|
|
21682
|
+
const [touched, setTouched] = useState(false);
|
|
21683
|
+
const formId = useId();
|
|
21684
|
+
const validationError = onValidate(value);
|
|
21685
|
+
const visibleError = touched ? validationError : null;
|
|
21686
|
+
const submit = (event)=>{
|
|
21687
|
+
event.preventDefault();
|
|
21688
|
+
setTouched(true);
|
|
21689
|
+
if (validationError) return;
|
|
21690
|
+
if (onApply(value)) onClose();
|
|
21691
|
+
};
|
|
21692
|
+
return /*#__PURE__*/ jsx(Dialog, {
|
|
21693
|
+
title: "创建表格",
|
|
21694
|
+
description: source.sheetName,
|
|
21695
|
+
className: "work-spreadsheet-table-dialog",
|
|
21696
|
+
restoreFocusTarget: restoreFocusTarget,
|
|
21697
|
+
onClose: onClose,
|
|
21698
|
+
footer: /*#__PURE__*/ jsxs(Fragment, {
|
|
21699
|
+
children: [
|
|
21700
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
21701
|
+
tone: "quiet",
|
|
21702
|
+
onClick: onClose,
|
|
21703
|
+
children: "取消"
|
|
21704
|
+
}),
|
|
21705
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
21706
|
+
tone: "primary",
|
|
21707
|
+
type: "submit",
|
|
21708
|
+
form: formId,
|
|
21709
|
+
disabled: Boolean(validationError),
|
|
21710
|
+
children: "确定"
|
|
21711
|
+
})
|
|
21712
|
+
]
|
|
21713
|
+
}),
|
|
21714
|
+
children: /*#__PURE__*/ jsxs("form", {
|
|
21715
|
+
id: formId,
|
|
21716
|
+
onSubmit: submit,
|
|
21717
|
+
children: [
|
|
21718
|
+
/*#__PURE__*/ jsxs("div", {
|
|
21719
|
+
className: "work-spreadsheet-table-scope",
|
|
21720
|
+
children: [
|
|
21721
|
+
/*#__PURE__*/ jsx("span", {
|
|
21722
|
+
"aria-hidden": "true",
|
|
21723
|
+
children: /*#__PURE__*/ jsx(Table2, {
|
|
21724
|
+
size: 18
|
|
21725
|
+
})
|
|
21726
|
+
}),
|
|
21727
|
+
/*#__PURE__*/ jsxs("div", {
|
|
21728
|
+
children: [
|
|
21729
|
+
/*#__PURE__*/ jsx("strong", {
|
|
21730
|
+
children: source.name
|
|
21731
|
+
}),
|
|
21732
|
+
/*#__PURE__*/ jsx("small", {
|
|
21733
|
+
children: "将连续数据区域转换为原生工作表表格"
|
|
21734
|
+
})
|
|
21735
|
+
]
|
|
21736
|
+
})
|
|
21737
|
+
]
|
|
21738
|
+
}),
|
|
21739
|
+
/*#__PURE__*/ jsx(field_Field, {
|
|
21740
|
+
label: "表格区域",
|
|
21741
|
+
required: true,
|
|
21742
|
+
error: visibleError ?? void 0,
|
|
21743
|
+
description: "输入一个连续区域,例如 A1:C20。",
|
|
21744
|
+
children: /*#__PURE__*/ jsx("input", {
|
|
21745
|
+
type: "text",
|
|
21746
|
+
autoCapitalize: "none",
|
|
21747
|
+
autoFocus: true,
|
|
21748
|
+
spellCheck: false,
|
|
21749
|
+
value: value.rangeReference,
|
|
21750
|
+
onBlur: ()=>setTouched(true),
|
|
21751
|
+
onChange: (event)=>{
|
|
21752
|
+
const rangeReference = event.currentTarget.value;
|
|
21753
|
+
setValue((current)=>({
|
|
21754
|
+
...current,
|
|
21755
|
+
rangeReference
|
|
21756
|
+
}));
|
|
21757
|
+
setTouched(true);
|
|
21758
|
+
}
|
|
21759
|
+
})
|
|
21760
|
+
}),
|
|
21761
|
+
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
21762
|
+
ariaLabel: "表包含标题",
|
|
21763
|
+
checked: value.headerRow,
|
|
21764
|
+
onCheckedChange: (headerRow)=>setValue((current)=>({
|
|
21765
|
+
...current,
|
|
21766
|
+
headerRow
|
|
21767
|
+
})),
|
|
21768
|
+
children: "表包含标题"
|
|
21769
|
+
})
|
|
21770
|
+
]
|
|
21771
|
+
})
|
|
21772
|
+
});
|
|
21773
|
+
}
|
|
21774
|
+
function useSpreadsheetTable({ commandsRef, contentRef, focusGrid, getGridFocusTarget, getLiveSelection, preview }) {
|
|
21775
|
+
const [source, setSource] = useState(null);
|
|
21776
|
+
const invokerRef = useRef(null);
|
|
21777
|
+
const selectionRef = useRef(null);
|
|
21778
|
+
const applyingRef = useRef(false);
|
|
21779
|
+
const appliedRef = useRef(false);
|
|
21780
|
+
useEffect(()=>{
|
|
21781
|
+
if (!preview) return;
|
|
21782
|
+
setSource(null);
|
|
21783
|
+
invokerRef.current = null;
|
|
21784
|
+
selectionRef.current = null;
|
|
21785
|
+
applyingRef.current = false;
|
|
21786
|
+
appliedRef.current = false;
|
|
21787
|
+
}, [
|
|
21788
|
+
preview
|
|
21789
|
+
]);
|
|
21790
|
+
const open = useCallback((target)=>{
|
|
21791
|
+
if (preview || source) return false;
|
|
21792
|
+
const nextSource = createSpreadsheetTableDialogSource(contentRef.current, target);
|
|
21793
|
+
if (!nextSource) {
|
|
21794
|
+
showToast('请选择包含标题和至少一行数据的连续、未合并区域。', 'error');
|
|
21795
|
+
return false;
|
|
21796
|
+
}
|
|
21797
|
+
const grid = getGridFocusTarget();
|
|
21798
|
+
invokerRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : grid;
|
|
21799
|
+
selectionRef.current = {
|
|
21800
|
+
sheetId: target.sheetId,
|
|
21801
|
+
selection: finiteSpreadsheetSelection(getLiveSelection() ?? target.selection)
|
|
21802
|
+
};
|
|
21803
|
+
appliedRef.current = false;
|
|
21804
|
+
setSource(nextSource);
|
|
21805
|
+
return true;
|
|
21806
|
+
}, [
|
|
21807
|
+
contentRef,
|
|
21808
|
+
getGridFocusTarget,
|
|
21809
|
+
getLiveSelection,
|
|
21810
|
+
preview,
|
|
21811
|
+
source
|
|
21812
|
+
]);
|
|
21813
|
+
const close = useCallback(()=>{
|
|
21814
|
+
const invoker = invokerRef.current;
|
|
21815
|
+
const grid = getGridFocusTarget();
|
|
21816
|
+
const restoreGrid = appliedRef.current || invoker === grid;
|
|
21817
|
+
setSource(null);
|
|
21818
|
+
requestAnimationFrame(()=>{
|
|
21819
|
+
if (restoreGrid || !invoker?.isConnected) focusGrid(invoker);
|
|
21820
|
+
else invoker.focus({
|
|
21821
|
+
preventScroll: true
|
|
21822
|
+
});
|
|
21823
|
+
if (invokerRef.current === invoker) invokerRef.current = null;
|
|
21824
|
+
selectionRef.current = null;
|
|
21825
|
+
appliedRef.current = false;
|
|
21826
|
+
});
|
|
21827
|
+
}, [
|
|
21828
|
+
focusGrid,
|
|
21829
|
+
getGridFocusTarget
|
|
21830
|
+
]);
|
|
21831
|
+
const commandPort = useMemo(()=>({
|
|
21832
|
+
canOpen: !preview && null === source,
|
|
21833
|
+
open
|
|
21834
|
+
}), [
|
|
21835
|
+
open,
|
|
21836
|
+
preview,
|
|
21837
|
+
source
|
|
21838
|
+
]);
|
|
21839
|
+
const selectionForChange = useCallback(()=>applyingRef.current ? selectionRef.current : null, []);
|
|
21840
|
+
return {
|
|
21841
|
+
commandPort,
|
|
21842
|
+
selectionForChange,
|
|
21843
|
+
dialog: source ? /*#__PURE__*/ jsx(SpreadsheetTableDialog, {
|
|
21844
|
+
source: source,
|
|
21845
|
+
restoreFocusTarget: ()=>appliedRef.current ? getGridFocusTarget() : invokerRef.current?.isConnected ? invokerRef.current : getGridFocusTarget(),
|
|
21846
|
+
onApply: (value)=>{
|
|
21847
|
+
const range = spreadsheetTableRangeFromText(value.rangeReference);
|
|
21848
|
+
if (!range) return false;
|
|
21849
|
+
applyingRef.current = true;
|
|
21850
|
+
let handled = false;
|
|
21851
|
+
try {
|
|
21852
|
+
handled = commandsRef.current?.applyTable({
|
|
21853
|
+
headerRow: value.headerRow,
|
|
21854
|
+
name: source.name,
|
|
21855
|
+
range,
|
|
21856
|
+
sheetId: source.sheetId
|
|
21857
|
+
}) ?? false;
|
|
21858
|
+
appliedRef.current = handled;
|
|
21859
|
+
} finally{
|
|
21860
|
+
applyingRef.current = false;
|
|
21861
|
+
}
|
|
21862
|
+
if (!handled) showToast(spreadsheetTableValidationMessage(contentRef.current, source, value) ?? '无法创建表格。', 'error');
|
|
21863
|
+
return handled;
|
|
21864
|
+
},
|
|
21865
|
+
onClose: close,
|
|
21866
|
+
onValidate: (value)=>spreadsheetTableValidationMessage(contentRef.current, source, value)
|
|
21867
|
+
}) : null
|
|
21868
|
+
};
|
|
21869
|
+
}
|
|
21870
|
+
function spreadsheetTableValidationMessage(content, source, value) {
|
|
21871
|
+
const range = spreadsheetTableRangeFromText(value.rangeReference);
|
|
21872
|
+
if (!range) return '请输入一个连续区域。';
|
|
21873
|
+
return spreadsheetTableFailureMessage(content, {
|
|
21874
|
+
headerRow: value.headerRow,
|
|
21875
|
+
name: source.name,
|
|
21876
|
+
range,
|
|
21877
|
+
sheetId: source.sheetId
|
|
21878
|
+
});
|
|
21879
|
+
}
|
|
19987
21880
|
const MAXIMUM_BUFFERED_SPREADSHEET_OPERATIONS = 10001;
|
|
19988
21881
|
function useSpreadsheetWorkbookSync(content, synchronizeExternalWorkbook) {
|
|
19989
21882
|
const mountedContentRef = useRef(content);
|
|
@@ -20117,6 +22010,14 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
20117
22010
|
getLiveSelections: getSpreadsheetDataValidationLiveSelections,
|
|
20118
22011
|
preview
|
|
20119
22012
|
});
|
|
22013
|
+
const spreadsheetTable = useSpreadsheetTable({
|
|
22014
|
+
commandsRef: spreadsheetCommandsRef,
|
|
22015
|
+
contentRef,
|
|
22016
|
+
focusGrid: focusSpreadsheetDialogGrid,
|
|
22017
|
+
getGridFocusTarget: getSpreadsheetDialogGridFocusTarget,
|
|
22018
|
+
getLiveSelection: getSpreadsheetHyperlinkLiveSelection,
|
|
22019
|
+
preview
|
|
22020
|
+
});
|
|
20120
22021
|
const officeDialog = useOfficeDialog();
|
|
20121
22022
|
const [findOpen, setFindOpen] = useState(false);
|
|
20122
22023
|
const [findFocusRequest, setFindFocusRequest] = useState(0);
|
|
@@ -20149,6 +22050,16 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
20149
22050
|
]);
|
|
20150
22051
|
const conditionalStylesBySheetRef = useRef(conditionalStylesBySheet);
|
|
20151
22052
|
conditionalStylesBySheetRef.current = conditionalStylesBySheet;
|
|
22053
|
+
const tableStylesBySheet = useMemo(()=>new Map(materializedContent.sheets.flatMap((sheet)=>sheet.id ? [
|
|
22054
|
+
[
|
|
22055
|
+
sheet.id,
|
|
22056
|
+
createSpreadsheetTableRenderResolver(sheet.tables ?? [])
|
|
22057
|
+
]
|
|
22058
|
+
] : [])), [
|
|
22059
|
+
materializedContent.sheets
|
|
22060
|
+
]);
|
|
22061
|
+
const tableStylesBySheetRef = useRef(tableStylesBySheet);
|
|
22062
|
+
tableStylesBySheetRef.current = tableStylesBySheet;
|
|
20152
22063
|
useEffect(()=>{
|
|
20153
22064
|
setPreviewActiveSheetId(preview ? contentActiveSheetId : null);
|
|
20154
22065
|
}, [
|
|
@@ -20259,21 +22170,28 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
20259
22170
|
endColumn: Math.max(selection.column[0], selection.column[1])
|
|
20260
22171
|
}).length);
|
|
20261
22172
|
},
|
|
20262
|
-
beforeRenderCell: (
|
|
22173
|
+
beforeRenderCell: (cell, cellInfo, context)=>{
|
|
22174
|
+
const tableStyle = tableStylesBySheetRef.current.get(activeSheetIdRef.current)?.(cellInfo.row, cellInfo.column) ?? null;
|
|
20263
22175
|
const style = conditionalStylesBySheetRef.current.get(activeSheetIdRef.current)?.get(`${cellInfo.row}_${cellInfo.column}`);
|
|
20264
|
-
|
|
22176
|
+
beginSpreadsheetTableCellRender(cell, tableStyle, style, context);
|
|
20265
22177
|
return true;
|
|
20266
22178
|
},
|
|
20267
22179
|
afterRenderCell: (cell, cellInfo, context)=>{
|
|
22180
|
+
const tableStyle = tableStylesBySheetRef.current.get(activeSheetIdRef.current)?.(cellInfo.row, cellInfo.column) ?? null;
|
|
20268
22181
|
const style = conditionalStylesBySheetRef.current.get(activeSheetIdRef.current)?.get(`${cellInfo.row}_${cellInfo.column}`);
|
|
20269
|
-
|
|
20270
|
-
|
|
20271
|
-
|
|
20272
|
-
|
|
20273
|
-
|
|
20274
|
-
|
|
20275
|
-
|
|
20276
|
-
|
|
22182
|
+
try {
|
|
22183
|
+
if (style?.icon || style?.dataBar) {
|
|
22184
|
+
const background = style.cellColor ?? tableStyle?.background ?? ('string' == typeof cell?.bg ? cell.bg : '#ffffff');
|
|
22185
|
+
if (style.dataBar) drawSpreadsheetConditionalDataBar(context, cellInfo, {
|
|
22186
|
+
...style.dataBar,
|
|
22187
|
+
showValue: style.dataBar.showValue && (style.icon?.showValue ?? true)
|
|
22188
|
+
}, cell, background, style.textColor);
|
|
22189
|
+
if (style.icon) drawSpreadsheetConditionalIcon(context, cellInfo, style.icon, background, style.dataBar ? false : !style.icon.showValue);
|
|
22190
|
+
if (cell?.ps) drawSpreadsheetCommentMarker(context, cellInfo);
|
|
22191
|
+
}
|
|
22192
|
+
} finally{
|
|
22193
|
+
finishSpreadsheetTableCellRender(cell, cellInfo, tableStyle, context);
|
|
22194
|
+
}
|
|
20277
22195
|
}
|
|
20278
22196
|
}), [
|
|
20279
22197
|
collaborationView
|
|
@@ -20393,6 +22311,17 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
20393
22311
|
const toolbarColumn = toolbarSelection.column_focus ?? toolbarSelection.column[0];
|
|
20394
22312
|
const toolbarCell = spreadsheetCellAt(toolbarSheet, toolbarRow, toolbarColumn);
|
|
20395
22313
|
const toolbarCellBorders = spreadsheetCellBordersAt(toolbarSheet, toolbarRow, toolbarColumn);
|
|
22314
|
+
const toolbarContentSheet = materializedContent.sheets.find((sheet)=>sheet.id === toolbarSheetId);
|
|
22315
|
+
const activeTable = spreadsheetTableAtCell(toolbarContentSheet, toolbarRow, toolbarColumn);
|
|
22316
|
+
const activeTableId = activeTable?.id ?? null;
|
|
22317
|
+
useEffect(()=>{
|
|
22318
|
+
setRibbonTab((current)=>{
|
|
22319
|
+
if (activeTableId) return 'tableDesign' === current ? current : 'tableDesign';
|
|
22320
|
+
return 'tableDesign' === current ? 'home' : current;
|
|
22321
|
+
});
|
|
22322
|
+
}, [
|
|
22323
|
+
activeTableId
|
|
22324
|
+
]);
|
|
20396
22325
|
const selectedRange = spreadsheetSingleRange(toolbarSelection);
|
|
20397
22326
|
const multipleCellsSelected = selectedRange.row[0] !== selectedRange.row[1] || selectedRange.column[0] !== selectedRange.column[1];
|
|
20398
22327
|
const selectionSummary = multipleCellsSelected ? spreadsheetSelectionSummary(toolbarSheet, toolbarSelection) : null;
|
|
@@ -20633,12 +22562,18 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
20633
22562
|
onChange: (next)=>{
|
|
20634
22563
|
const formatCellsSelection = formatCellsApplyingRef.current ? formatCellsSelectionRef.current : null;
|
|
20635
22564
|
const dataValidationSelection = spreadsheetDataValidation.selectionForChange();
|
|
22565
|
+
const tableSelection = spreadsheetTable.selectionForChange();
|
|
20636
22566
|
const hyperlinkSelection = spreadsheetHyperlink.selectionForChange();
|
|
20637
22567
|
const preservedSelection = formatCellsSelection ? {
|
|
20638
22568
|
sheetId: formatCellsSelection.sheetId,
|
|
20639
22569
|
selections: [
|
|
20640
22570
|
formatCellsSelection.selection
|
|
20641
22571
|
]
|
|
22572
|
+
} : tableSelection ? {
|
|
22573
|
+
sheetId: tableSelection.sheetId,
|
|
22574
|
+
selections: [
|
|
22575
|
+
tableSelection.selection
|
|
22576
|
+
]
|
|
20642
22577
|
} : dataValidationSelection ?? (hyperlinkSelection ? {
|
|
20643
22578
|
sheetId: hyperlinkSelection.sheetId,
|
|
20644
22579
|
selections: [
|
|
@@ -20650,6 +22585,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
20650
22585
|
onChange(controlled);
|
|
20651
22586
|
},
|
|
20652
22587
|
selection: selectionState,
|
|
22588
|
+
table: spreadsheetTable.commandPort,
|
|
20653
22589
|
targetSheetGridSize,
|
|
20654
22590
|
targetSheetId: toolbarSheetId,
|
|
20655
22591
|
toolbarCell,
|
|
@@ -20853,6 +22789,8 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
20853
22789
|
}),
|
|
20854
22790
|
!preview && /*#__PURE__*/ jsx(SpreadsheetEditorRibbon, {
|
|
20855
22791
|
activeTab: ribbonTab,
|
|
22792
|
+
activeTable: activeTable,
|
|
22793
|
+
activeTableSheetId: activeTable ? toolbarSheetId : void 0,
|
|
20856
22794
|
autoFilterActive: autoFilterActive,
|
|
20857
22795
|
can: spreadsheetCan,
|
|
20858
22796
|
commands: spreadsheetRibbonCommands,
|
|
@@ -21075,6 +23013,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
21075
23013
|
}),
|
|
21076
23014
|
spreadsheetDataValidation.dialog,
|
|
21077
23015
|
spreadsheetHyperlink.dialog,
|
|
23016
|
+
spreadsheetTable.dialog,
|
|
21078
23017
|
spreadsheetClipboard.dialogSource && /*#__PURE__*/ jsx(SpreadsheetPasteSpecialDialog, {
|
|
21079
23018
|
source: spreadsheetClipboard.dialogSource,
|
|
21080
23019
|
restoreFocusTarget: spreadsheetClipboard.restoreDialogFocusTarget,
|
|
@@ -21182,11 +23121,13 @@ function spreadsheetCommandsWithGridFocus(commands, restoreFocus) {
|
|
|
21182
23121
|
return {
|
|
21183
23122
|
...commands,
|
|
21184
23123
|
adjustDecimalPlaces: afterSuccessfulCommand(commands.adjustDecimalPlaces),
|
|
23124
|
+
adjustFontSize: afterSuccessfulCommand(commands.adjustFontSize),
|
|
21185
23125
|
applyAutoSum: afterSuccessfulCommand(commands.applyAutoSum),
|
|
21186
23126
|
activateFormatPainter: afterSuccessfulCommand(commands.activateFormatPainter),
|
|
21187
23127
|
cancelFormatPainter: afterSuccessfulCommand(commands.cancelFormatPainter),
|
|
21188
23128
|
clearSelectedCells: afterSuccessfulCommand(commands.clearSelectedCells),
|
|
21189
23129
|
copySelection: afterSuccessfulCommand(commands.copySelection),
|
|
23130
|
+
convertTableToRange: afterSuccessfulCommand(commands.convertTableToRange),
|
|
21190
23131
|
cutSelection: afterSuccessfulCommand(commands.cutSelection),
|
|
21191
23132
|
deleteSelectedStructure: afterSuccessfulCommand(commands.deleteSelectedStructure),
|
|
21192
23133
|
fillSelectedCells: afterSuccessfulCommand(commands.fillSelectedCells),
|