ooxml-ui 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -36
- package/custom-elements.json +372 -4
- package/dist/chrome/ruler.d.ts +60 -2
- package/dist/chrome/ruler.d.ts.map +1 -1
- package/dist/chrome/status-bar.d.ts +3 -1
- package/dist/chrome/status-bar.d.ts.map +1 -1
- package/dist/{chunk-JFJXBYRD.js → chunk-2WLRFPMW.js} +9 -0
- package/dist/{chunk-X7RINDJQ.js → chunk-56A2JK63.js} +1 -1
- package/dist/{chunk-KVKKXRL7.js → chunk-5OFAJDMQ.js} +93 -14
- package/dist/{chunk-M5DTJSOV.js → chunk-723JC3OC.js} +461 -16
- package/dist/{chunk-USDLALB5.js → chunk-IY7QJLQG.js} +1 -1
- package/dist/{chunk-BOX43CZD.js → chunk-M6GF5ED2.js} +2 -1
- package/dist/{chunk-BEN3453I.js → chunk-NYRRH2MD.js} +1 -1
- package/dist/{chunk-3FPW7M6U.js → chunk-TWQ45BFL.js} +1 -1
- package/dist/{chunk-ZU7GX4SY.js → chunk-V6P6KZCO.js} +7 -5
- package/dist/comments/comments-pane.d.ts +116 -0
- package/dist/comments/comments-pane.d.ts.map +1 -0
- package/dist/comments/types.d.ts +80 -0
- package/dist/comments/types.d.ts.map +1 -0
- package/dist/controls.d.ts +6 -2
- package/dist/controls.d.ts.map +1 -1
- package/dist/controls.js +5 -5
- package/dist/docx/comments-panel.d.ts +8 -1
- package/dist/docx/editor-chrome.d.ts +8 -1
- package/dist/docx/file-commands.d.ts +1 -1
- package/dist/docx/image-media.d.ts +1 -1
- package/dist/docx/locales/en-app.d.ts +1 -0
- package/dist/docx/locales/en-ribbon.d.ts +1 -0
- package/dist/docx/locales/en.d.ts +2 -0
- package/dist/docx/localization-strings.d.ts +2 -0
- package/dist/docx/localization.d.ts +7 -0
- package/dist/docx/print-layout.d.ts +2 -2
- package/dist/docx/print-picture.d.ts +12 -0
- package/dist/docx/review-controller.d.ts +2 -0
- package/dist/docx/ribbon-actions.d.ts +22 -0
- package/dist/docx/ruler.d.ts +7 -10
- package/dist/docx/title-bar.d.ts +3 -5
- package/dist/docx.js +342 -362
- package/dist/form/gradient-preset-gallery.d.ts +2 -2
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -9
- package/dist/pptx/{chart-3d-view-scene-2KRQ5667.mjs → chart-3d-view-scene-OYJ4CDCO.mjs} +4 -5
- package/dist/pptx/{chart-3d-view-scene-36DMZWZ3.cjs → chart-3d-view-scene-SE2Y6QRE.cjs} +38 -39
- package/dist/pptx/{chunk-YOGDIDPB.mjs → chunk-CIVA3MLN.mjs} +8 -2
- package/dist/pptx/{chunk-KPZWYF44.cjs → chunk-FPE5PZMI.cjs} +789 -491
- package/dist/pptx/{chunk-AIL3BNZS.cjs → chunk-IURZJAWP.cjs} +529 -387
- package/dist/pptx/{chunk-YHA6XAB3.cjs → chunk-KRMMJUCO.cjs} +83 -1
- package/dist/pptx/{chunk-Y2W4SZER.mjs → chunk-MWHGUEIJ.mjs} +637 -348
- package/dist/pptx/{chunk-YARCML7O.mjs → chunk-STLXPKJJ.mjs} +519 -388
- package/dist/pptx/{chunk-ADOC5JLI.mjs → chunk-TC7HCF5M.mjs} +76 -2
- package/dist/pptx/{chunk-CJU4P5FT.cjs → chunk-WKLHJEPD.cjs} +18 -12
- package/dist/pptx/dom/element-styles.d.ts.map +1 -1
- package/dist/pptx/dom/elements/chart.d.ts +2 -3
- package/dist/pptx/dom/elements/chart.d.ts.map +1 -1
- package/dist/pptx/dom/elements/connector.d.ts.map +1 -1
- package/dist/pptx/dom/elements/shape-filter-defs.d.ts.map +1 -1
- package/dist/pptx/dom/elements/table.d.ts.map +1 -1
- package/dist/pptx/dom/index.cjs +272 -261
- package/dist/pptx/dom/index.mjs +46 -35
- package/dist/pptx/dom/slide-stage.d.ts.map +1 -1
- package/dist/pptx/export/html2canvas-clone.cjs +2 -2
- package/dist/pptx/export/html2canvas-clone.mjs +1 -1
- package/dist/pptx/index.cjs +3065 -2993
- package/dist/pptx/index.mjs +4 -4
- package/dist/pptx/render/chart-3d-oblique-layout.d.ts.map +1 -1
- package/dist/pptx/render/chart-3d-persp-bars.d.ts.map +1 -1
- package/dist/pptx/render/chart-3d-persp-layout.d.ts.map +1 -1
- package/dist/pptx/render/chart-axis-range.d.ts +7 -0
- package/dist/pptx/render/chart-axis-range.d.ts.map +1 -1
- package/dist/pptx/render/chart-axis-render.d.ts +3 -1
- package/dist/pptx/render/chart-axis-render.d.ts.map +1 -1
- package/dist/pptx/render/chart-axis-style.d.ts +5 -0
- package/dist/pptx/render/chart-axis-style.d.ts.map +1 -1
- package/dist/pptx/render/chart-axis.d.ts +1 -1
- package/dist/pptx/render/chart-axis.d.ts.map +1 -1
- package/dist/pptx/render/chart-bar-cluster-geometry.d.ts +1 -1
- package/dist/pptx/render/chart-bar-cluster-geometry.d.ts.map +1 -1
- package/dist/pptx/render/chart-cartesian-area.d.ts.map +1 -1
- package/dist/pptx/render/chart-cartesian-axes.d.ts.map +1 -1
- package/dist/pptx/render/chart-cartesian-bars.d.ts +3 -3
- package/dist/pptx/render/chart-cartesian-line-area.d.ts.map +1 -1
- package/dist/pptx/render/chart-cartesian-percent-stacked.d.ts.map +1 -1
- package/dist/pptx/render/chart-cartesian-stacked-labels.d.ts +11 -7
- package/dist/pptx/render/chart-cartesian-stacked-labels.d.ts.map +1 -1
- package/dist/pptx/render/chart-cartesian.d.ts.map +1 -1
- package/dist/pptx/render/chart-combo-stock.cjs +3 -3
- package/dist/pptx/render/chart-combo-stock.mjs +1 -1
- package/dist/pptx/render/chart-combo.d.ts.map +1 -1
- package/dist/pptx/render/chart-data-label-anchor.d.ts +4 -1
- package/dist/pptx/render/chart-data-label-anchor.d.ts.map +1 -1
- package/dist/pptx/render/chart-gridlines-toggle.d.ts +13 -1
- package/dist/pptx/render/chart-gridlines-toggle.d.ts.map +1 -1
- package/dist/pptx/render/chart-helpers.d.ts +13 -13
- package/dist/pptx/render/chart-helpers.d.ts.map +1 -1
- package/dist/pptx/render/chart-horizontal-bars-helpers.d.ts +7 -3
- package/dist/pptx/render/chart-horizontal-bars-helpers.d.ts.map +1 -1
- package/dist/pptx/render/chart-horizontal-bars.d.ts.map +1 -1
- package/dist/pptx/render/chart-interaction-stacked.d.ts.map +1 -1
- package/dist/pptx/render/chart-line-path.d.ts +9 -0
- package/dist/pptx/render/chart-line-path.d.ts.map +1 -1
- package/dist/pptx/render/chart-overlays.cjs +7 -7
- package/dist/pptx/render/chart-overlays.mjs +1 -1
- package/dist/pptx/render/chart-palette.d.ts +5 -14
- package/dist/pptx/render/chart-palette.d.ts.map +1 -1
- package/dist/pptx/render/chart-plot-clip.d.ts +37 -0
- package/dist/pptx/render/chart-plot-clip.d.ts.map +1 -0
- package/dist/pptx/render/chart-quick-action-styles.d.ts +5 -3
- package/dist/pptx/render/chart-quick-action-styles.d.ts.map +1 -1
- package/dist/pptx/render/chart-scatter-x-axis.d.ts.map +1 -1
- package/dist/pptx/render/chart-style-palette.d.ts +52 -0
- package/dist/pptx/render/chart-style-palette.d.ts.map +1 -0
- package/dist/pptx/render/chart-surface-treemap.cjs +4 -4
- package/dist/pptx/render/chart-surface-treemap.mjs +1 -1
- package/dist/pptx/render/chart-view-model-bars.d.ts +32 -1
- package/dist/pptx/render/chart-view-model-bars.d.ts.map +1 -1
- package/dist/pptx/render/chart-view-model-build.d.ts.map +1 -1
- package/dist/pptx/render/chart-view-model.cjs +53 -41
- package/dist/pptx/render/chart-view-model.mjs +1 -1
- package/dist/pptx/render/chart-waterfall-map.cjs +6 -6
- package/dist/pptx/render/chart-waterfall-map.mjs +1 -1
- package/dist/pptx/render/device-pixel-stroke.d.ts +101 -0
- package/dist/pptx/render/device-pixel-stroke.d.ts.map +1 -0
- package/dist/pptx/render/export-clone.d.ts +4 -0
- package/dist/pptx/render/export-clone.d.ts.map +1 -1
- package/dist/pptx/render/foreign-object-svg-document.d.ts +12 -0
- package/dist/pptx/render/foreign-object-svg-document.d.ts.map +1 -1
- package/dist/pptx/render/index.d.ts +3 -0
- package/dist/pptx/render/index.d.ts.map +1 -1
- package/dist/pptx/render/stroke-outline.d.ts +6 -0
- package/dist/pptx/render/stroke-outline.d.ts.map +1 -1
- package/dist/pptx/render/stroke-style.d.ts +8 -2
- package/dist/pptx/render/stroke-style.d.ts.map +1 -1
- package/dist/pptx/render/tab-row-actions.d.ts +40 -0
- package/dist/pptx/render/tab-row-actions.d.ts.map +1 -0
- package/dist/pptx/render/table-cell-css.d.ts +3 -2
- package/dist/pptx/render/table-cell-css.d.ts.map +1 -1
- package/dist/pptx/render/table-cell-edit.d.ts +1 -1
- package/dist/pptx/render/table-cell-edit.d.ts.map +1 -1
- package/dist/pptx/render/table-cell-paragraphs.d.ts +29 -0
- package/dist/pptx/render/table-cell-paragraphs.d.ts.map +1 -0
- package/dist/pptx/render/table-style-borders.d.ts.map +1 -1
- package/dist/pptx/render/table-style.d.ts +2 -0
- package/dist/pptx/render/table-style.d.ts.map +1 -1
- package/dist/pptx/render/title-bar.d.ts +5 -0
- package/dist/pptx/render/title-bar.d.ts.map +1 -1
- package/dist/pptx/render/viewer-root-options.d.ts +11 -3
- package/dist/pptx/render/viewer-root-options.d.ts.map +1 -1
- package/dist/pptx/web-components/index.d.ts.map +1 -1
- package/dist/pptx/web-components/office-token-bridge.d.ts +1 -1
- package/dist/pptx/web-components/office-token-bridge.d.ts.map +1 -1
- package/dist/pptx/web-components/ribbon-actions.d.ts +8 -0
- package/dist/pptx/web-components/ribbon-actions.d.ts.map +1 -0
- package/dist/presence.js +3 -3
- package/dist/ribbon/ribbon-actions.d.ts +119 -0
- package/dist/ribbon/ribbon-actions.d.ts.map +1 -0
- package/dist/ribbon/ribbon-tabs.d.ts +2 -1
- package/dist/ribbon/ribbon-tabs.d.ts.map +1 -1
- package/dist/smartart/smartart-svg.d.ts +3 -2
- package/dist/smartart.js +3 -3
- package/dist/suite/attachment-store.d.ts +13 -0
- package/dist/suite/document-store.d.ts +31 -0
- package/dist/suite/index.d.ts +2 -0
- package/dist/suite.js +132 -1
- package/dist/teams/app/channel-tab.d.ts +5 -0
- package/dist/teams/chat-composer.d.ts +3 -0
- package/dist/teams.js +7 -7
- package/dist/theme.js +2 -2
- package/dist/tokens.d.ts +9 -0
- package/dist/tokens.d.ts.map +1 -1
- package/dist/visio/styles/index.d.ts +2 -0
- package/dist/visio/styles/theme.d.ts +11 -0
- package/dist/visio/styles.d.ts +2 -2
- package/dist/visio.js +66 -21
- package/dist/xlsx/backstage/index.d.ts +4 -1
- package/dist/xlsx/backstage/pages-share.d.ts +19 -0
- package/dist/xlsx/backstage/parts.d.ts +3 -0
- package/dist/xlsx/calc-preparation.d.ts +44 -0
- package/dist/xlsx/chart-fill-binding.d.ts +2 -2
- package/dist/xlsx/chart-series-gradient-type.d.ts +3 -2
- package/dist/xlsx/collaboration-session.d.ts +9 -0
- package/dist/xlsx/collaboration-types.d.ts +41 -0
- package/dist/xlsx/collaboration.d.ts +56 -0
- package/dist/xlsx/component.d.ts +8 -0
- package/dist/xlsx/dialogs/comments-list.d.ts +4 -0
- package/dist/xlsx/dialogs/help-dialogs.d.ts +1 -1
- package/dist/xlsx/editor-core.d.ts +6 -0
- package/dist/xlsx/element-api.d.ts +19 -1
- package/dist/xlsx/events.d.ts +4 -1
- package/dist/xlsx/grid/remote-layer.d.ts +3 -0
- package/dist/xlsx/grid/sparkline.d.ts +3 -0
- package/dist/xlsx/grid/styles.d.ts +1 -1
- package/dist/xlsx/index.d.ts +1 -0
- package/dist/xlsx/ribbon-actions.d.ts +22 -0
- package/dist/xlsx/shell-commands.d.ts +1 -1
- package/dist/xlsx/title-bar.d.ts +4 -2
- package/dist/xlsx.js +801 -92
- package/package.json +2 -2
- package/dist/pptx/web-components/status-bar-styles.d.ts +0 -3
- package/dist/pptx/web-components/status-bar-styles.d.ts.map +0 -1
- package/dist/pptx/web-components/title-bar-styles.d.ts +0 -7
- package/dist/pptx/web-components/title-bar-styles.d.ts.map +0 -1
package/dist/xlsx.js
CHANGED
|
@@ -1,27 +1,24 @@
|
|
|
1
|
-
import './chunk-
|
|
2
|
-
import { defineSmartArt } from './chunk-
|
|
3
|
-
import { withExtension, saveExtension, downloadBytes, emit, emitEvent, blobFor, announceFileCommand, pickFile } from './chunk-
|
|
4
|
-
export { XLSX_EDITOR_EVENTS } from './chunk-
|
|
1
|
+
import './chunk-V6P6KZCO.js';
|
|
2
|
+
import { defineSmartArt } from './chunk-NYRRH2MD.js';
|
|
3
|
+
import { withExtension, saveExtension, downloadBytes, emit, emitEvent, blobFor, announceFileCommand, pickFile } from './chunk-5OFAJDMQ.js';
|
|
4
|
+
export { XLSX_EDITOR_EVENTS } from './chunk-5OFAJDMQ.js';
|
|
5
5
|
import './chunk-SNV6YKPC.js';
|
|
6
|
-
import './chunk-
|
|
7
|
-
import { range_control_default, createRibbonOverflow, defineBackstage, defineRibbon, defineTitleBar, defineStatusBar, defineZoomSlider, rangeControl, defineDialog, runKeyTips, assignKeyTips, defineCheckbox, defineGallery, defineContextMenu, parseSvgPreview } from './chunk-
|
|
8
|
-
import { getIcon, registerIcon } from './chunk-
|
|
9
|
-
import './chunk-
|
|
10
|
-
import { withTokens } from './chunk-
|
|
11
|
-
import './chunk-
|
|
12
|
-
import { SPECIAL_CODES, FRACTION_CODES, AUTOSUM_FUNCTIONS, themeToCssVars, lightTheme, darkTheme, ICON_ACCENTS, ICON_PATHS, normalizeThemeMode, applyThemeColors, parseSelectionRef, selectionRef, normalizeEditorLocale, DirtyState, createCommandRegistry, createDialogRegistry, activeRef, createSelectionModel, SheetSelections, translator, initialSelection, sheetBaseName, onRibbonTabsChange, activeChart, editChart, ribbonTabs, isTabHidden, selectTab, setTabHidden, tabButton, searchCommands, formatNumber, TEMPLATES, createTemplateWorkbook, isMenuSeparator, registerRibbonTabs, installFormatPainter, SHEET_ICONS, clipboardCommands, fontCommands, alignmentCommands, numberCommands, cellCommands, editingCommands, pageLayoutCommands, formulaCommands, dataCommands, contextualCommands, reviewTab, viewTab, helpTab, editBridge, CellViewCache, QUADRANTS, columnHeaderHeight, rowHeaderWidth, GridGeometry, cellRange, scrollToReveal, buildItems, fitNumber, cssFont, clampAddress, selectCell, movingEnd, extendSelection, moveWithinSelection, rowsRange, colsRange, ALL_RANGE, tabMenu, editing, icon, DATA_BAR_COLORS, dataBarRule, COLOR_SCALES, colorScaleRule, iconSetRule, target, tableAt, viewing, activeTable, numberFormatOptions, FONT_NAMES, FONT_SIZES, BORDER_PRESETS, ORIENTATIONS, ACCOUNTING_FORMATS, themePaletteItems, MARGIN_PRESETS, PAPER_SIZES, FUNCTION_MENUS, MORE_FUNCTION_CATEGORIES, functionsIn, isSingleCell, spanRange, selectionCellCount, addRange, activeStyle, selectSpecial, insertFunctionCall, guessHeader, regionOf, HIGHLIGHT_STYLES, ICON_SETS, TABLE_STYLES, tableStylePreview, resolveNameBox, absoluteReference, nameForRange, fillPaint, iconSvg, colSelected, rowSelected, rowHeaderMenu, columnHeaderMenu, cellMenu, recentFunctions, evaluateRef, buildChart, detectCategory, CATEGORIES, TIME_CODES, DATE_CODES, DEFAULT_OPTIONS, cellStyleItems, textDecoration, justify, alignItems, textAlign, hasBorders, edgeCss, diagonalSvg, SYMBOLS, buildCode, UNSET, dxfCss, negativeCodes, iconCount, iconThresholds, rowsOf, colsOf } from 'ooxml-core/xlsx/ui';
|
|
6
|
+
import { shadcnBridge } from './chunk-56A2JK63.js';
|
|
7
|
+
import { range_control_default, createRibbonOverflow, defineBackstage, defineRibbon, defineRibbonActions, defineTitleBar, defineStatusBar, defineZoomSlider, rangeControl, defineDialog, runKeyTips, assignKeyTips, defineCheckbox, defineGallery, defineContextMenu, defineCommentsPane, parseSvgPreview } from './chunk-723JC3OC.js';
|
|
8
|
+
import { getIcon, registerIcon } from './chunk-M6GF5ED2.js';
|
|
9
|
+
import { definePresence } from './chunk-TWQ45BFL.js';
|
|
10
|
+
import { withTokens } from './chunk-IY7QJLQG.js';
|
|
11
|
+
import './chunk-2WLRFPMW.js';
|
|
12
|
+
import { SPECIAL_CODES, FRACTION_CODES, AUTOSUM_FUNCTIONS, themeToCssVars, lightTheme, darkTheme, ICON_ACCENTS, ICON_PATHS, normalizeThemeMode, applyThemeColors, parseSelectionRef, selectionRef, normalizeEditorLocale, DirtyState, createCommandRegistry, createDialogRegistry, activeRef, createSelectionModel, SheetSelections, translator, initialSelection, sheetBaseName, historyOf, onRibbonTabsChange, activeChart, editChart, ribbonTabs, isTabHidden, selectTab, setTabHidden, tabButton, searchCommands, formatNumber, TEMPLATES, createTemplateWorkbook, isMenuSeparator, registerRibbonTabs, installFormatPainter, SHEET_ICONS, clipboardCommands, fontCommands, alignmentCommands, numberCommands, cellCommands, editingCommands, pageLayoutCommands, formulaCommands, dataCommands, contextualCommands, reviewTab, viewTab, helpTab, editBridge, CellViewCache, QUADRANTS, columnHeaderHeight, rowHeaderWidth, GridGeometry, cellRange, scrollToReveal, buildItems, fitNumber, cssFont, clampAddress, selectCell, movingEnd, extendSelection, moveWithinSelection, rowsRange, colsRange, ALL_RANGE, tabMenu, editing, icon, DATA_BAR_COLORS, dataBarRule, COLOR_SCALES, colorScaleRule, iconSetRule, target, tableAt, viewing, activeTable, numberFormatOptions, FONT_NAMES, FONT_SIZES, BORDER_PRESETS, ORIENTATIONS, ACCOUNTING_FORMATS, themePaletteItems, MARGIN_PRESETS, PAPER_SIZES, FUNCTION_MENUS, MORE_FUNCTION_CATEGORIES, functionsIn, isSingleCell, spanRange, selectionCellCount, addRange, activeStyle, selectSpecial, insertFunctionCall, guessHeader, regionOf, HIGHLIGHT_STYLES, ICON_SETS, TABLE_STYLES, tableStylePreview, resolveNameBox, absoluteReference, nameForRange, fillPaint, iconSvg, colSelected, rowSelected, rowHeaderMenu, columnHeaderMenu, cellMenu, recentFunctions, evaluateRef, buildChart, detectCategory, CATEGORIES, TIME_CODES, DATE_CODES, DEFAULT_OPTIONS, cellStyleItems, textDecoration, justify, alignItems, textAlign, hasBorders, edgeCss, diagonalSvg, SYMBOLS, buildCode, UNSET, dxfCss, negativeCodes, iconCount, iconThresholds, rowsOf, colsOf } from 'ooxml-core/xlsx/ui';
|
|
13
13
|
export { EDITOR_LOCALES, THEME_KEYS, normalizeEditorLocale, registerRibbonTabs, themeToCssVars, darkTheme as xlsxDarkTheme, lightTheme as xlsxLightTheme } from 'ooxml-core/xlsx/ui';
|
|
14
|
-
import { createWorksheet, createEditSession, approximateMeasure, createWorkbook, MAX_ROW, MAX_COL, chartView, createRefEvaluator, chartBarSpacing, CHART_FILL_PARTS, selectionStats, formatRange, chartSeriesTransparencyPatch, chartSeriesTransparency, chartSeriesGradientPatch, chartSeriesSolidFillPatch, chartSeriesFillPatch, chartWithElementFills, chartElementTransparencyPatch, chartElementTransparency, chartElementGradientPatch, chartElementSolidFillPatch, chartElementFillPatch, chartElementFill, usedRange, chartGradientStopTransparency, createGridMetrics, mergeView, cellView, DEFAULT_THEME, resolveColor, nextSheetName, FUNCTION_CATALOG, mergeAt, visibleCells, getCell, cellInputText, closeParens, isFormulaText, parseCellInput, referenceTarget, formatAddress, navigate, anchorToPixelBox, renderChartSvg, pixelBoxToAnchor, listValidationOptions, validationAt, getValue, resolvePasteOptions, DEFAULT_COL_WIDTH, nameAtCaret, functionMatches, callAtCaret, splice, acceptsReference, translateFormula, isCellError, parseHtmlTable, toggleAbsolute, rangeContains, formatValue, isDateFormat, pictureAnchorAt, validateDefinedName, parseAddress, styleAt, parseRange, rangesIntersect, chartColorScheme, coloredReferences, syntaxParams, activeParam, columnLabel, THEME_SLOTS, normalizeRange, currentRegion, autoFitColumnWidth, validateSheetName, dateToSerial, IMAGE_EXTENSIONS, verifySheetPassword, verifyWorkbookPassword, sheetByName, quoteSheetName, serialToDate, BUILTIN_NUMBER_FORMATS, pixelsToColumnWidth, validateTableName } from 'ooxml-core/xlsx';
|
|
14
|
+
import { createWorksheet, createEditSession, approximateMeasure, createWorkbook, MAX_ROW, MAX_COL, chartView, createRefEvaluator, chartBarSpacing, CHART_FILL_PARTS, selectionStats, formatSelectionStat, formatRange, chartSeriesTransparencyPatch, chartSeriesTransparency, chartSeriesGradientPatch, chartSeriesSolidFillPatch, chartSeriesFillPatch, chartWithElementFills, chartElementTransparencyPatch, chartElementTransparency, chartElementGradientPatch, chartElementSolidFillPatch, chartElementFillPatch, chartElementFill, usedRange, chartGradientStopTransparency, createGridMetrics, mergeView, cellView, DEFAULT_THEME, resolveColor, nextSheetName, FUNCTION_CATALOG, mergeAt, visibleCells, getCell, cellInputText, closeParens, isFormulaText, parseCellInput, referenceTarget, formatAddress, navigate, anchorToPixelBox, renderChartSvg, pixelBoxToAnchor, listValidationOptions, validationAt, getValue, resolvePasteOptions, DEFAULT_COL_WIDTH, nameAtCaret, functionMatches, callAtCaret, splice, acceptsReference, translateFormula, isCellError, layoutRemoteSelections, parseHtmlTable, toggleAbsolute, rangeContains, formatValue, isDateFormat, pictureAnchorAt, validateDefinedName, parseAddress, styleAt, parseRange, rangesIntersect, chartColorScheme, coloredReferences, syntaxParams, activeParam, columnLabel, THEME_SLOTS, normalizeRange, currentRegion, autoFitColumnWidth, validateSheetName, dateToSerial, IMAGE_EXTENSIONS, verifySheetPassword, verifyWorkbookPassword, sheetByName, quoteSheetName, serialToDate, BUILTIN_NUMBER_FORMATS, pixelsToColumnWidth, validateTableName } from 'ooxml-core/xlsx';
|
|
15
15
|
import { hyperlinkPolicy } from 'ooxml-core/opc';
|
|
16
16
|
import { resolveChartGradient, sortGradientStops, withChartGradientDirection, buildChartGradientDef, chartGradientMarkup, CHART_COLOR_PALETTES, chartPaletteColors } from 'ooxml-core/chart';
|
|
17
17
|
import { render } from 'lit';
|
|
18
18
|
import { RECT_GRADIENT_DIRECTIONS, OFFICE_GRADIENT_PRESETS, officeGradientPresetId, officeGradientPresetFill, resolveDrawingColor, drawingColorBrightness, drawingColorCss, rectGradientDirection } from 'ooxml-core/diagram';
|
|
19
19
|
|
|
20
|
-
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/xlsx/theme/office-bridge.css?raw
|
|
21
|
-
var office_bridge_default = "/*\n * The shared ooxml-ui elements read only --office-* tokens. This feeds them from the editor's\n * --xve-* theme, declared on the host so a theme, a dark scheme or a host override of --xve-*\n * keeps working (the same approach as pptx-viewer's office-token-bridge and docx-viewer's).\n */\n:host {\n --office-font: 'Segoe UI', system-ui, -apple-system, sans-serif;\n --office-foreground: var(--xve-foreground);\n --office-muted-foreground: var(--xve-muted-foreground);\n --office-background: var(--xve-background);\n --office-surface: var(--xve-card);\n --office-selected: var(--xve-accent);\n --office-border: var(--xve-border);\n --office-accent: var(--xve-primary);\n --office-accent-foreground: var(--xve-primary-foreground);\n --office-ring: var(--xve-ring);\n --office-popover: var(--xve-popover);\n --office-popover-foreground: var(--xve-popover-foreground, var(--xve-foreground));\n --office-danger: var(--xve-destructive);\n --office-danger-foreground: var(--xve-destructive-foreground);\n}\n";
|
|
22
|
-
|
|
23
20
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/xlsx/theme/shell.css?raw
|
|
24
|
-
var shell_default = "/* Frame, title bar and status bar. Mirrors docx-viewer's chrome (styles/base.css,\n chrome-titlebar.css, status-dialogs.css) with --xve-* tokens. */\n:host {\n --xl: var(--xve-primary);\n --xl-strong: color-mix(in srgb, var(--xve-primary) 70%, #000);\n --xl-soft: color-mix(in srgb, var(--xve-primary) 12%, transparent);\n --accent-soft: var(--xl-soft);\n --ink: var(--xve-foreground);\n --muted: var(--xve-muted-foreground);\n --line: var(--xve-border);\n --surface: var(--xve-card);\n --chrome: var(--xve-background);\n display: block;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-height: 0;\n color: var(--ink);\n font:\n 13px/1.35 'Segoe UI',\n Arial,\n sans-serif;\n}\n.xve-frame {\n position: relative;\n display: flex;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-height: 0;\n min-width: 0;\n flex-direction: column;\n overflow: hidden;\n background: var(--surface);\n}\n:focus-visible {\n outline: 2px solid var(--xve-ring);\n outline-offset: 1px;\n}\n[hidden],\n[data-xve-hidden] {\n display: none !important;\n}\n.xve-icon {\n flex: none;\n}\n.xve-icon-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 28px;\n height: 28px;\n padding: 0 6px;\n border: 0;\n border-radius: 4px;\n background: none;\n color: inherit;\n font: inherit;\n cursor: pointer;\n}\n.xve-icon-button:hover:not(:disabled),\n.xve-icon-button[aria-pressed='true'] {\n background: var(--xl-soft);\n}\n.xve-icon-button:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* Workspace: formula bar, grid and sheet tabs between the ribbon and the status bar. */\n.xve-workspace {\n position: relative;\n display: flex;\n flex: 1;\n min-height: 0;\n min-width: 0;\n flex-direction: column;\n background: var(--xve-sheet-bg);\n}\n.xve-formula-row {\n flex: none;\n min-width: 0;\n border-bottom: 1px solid var(--line);\n background: var(--surface);\n}\n.xve-grid-host {\n position: relative;\n display: flex;\n flex: 1;\n min-height: 0;\n min-width: 0;\n overflow: hidden;\n background: var(--xve-sheet-bg);\n color-scheme: light;\n}\n.xve-grid-host > * {\n flex: 1;\n min-width: 0;\n}\n.xve-tabs-row {\n flex: none;\n min-width: 0;\n border-top: 1px solid var(--line);\n background: var(--chrome);\n}\n.xve-empty {\n position: absolute;\n z-index: 5;\n inset: 0;\n display: grid;\n place-items: center;\n color: var(--muted);\n background: var(--chrome);\n}\n:host([show-formula-bar='false']) .xve-formula-row,\n:host([show-toolbar='false']) .xve-ribbon {\n display: none;\n}\n\n/* Title bar: drawn by the shared office-ui-title-bar; the mark, background and borders come from its tokens. */\n.xve-titlebar {\n display: block;\n flex: none;\n --office-title-bar-background: var(--chrome);\n --office-title-bar-foreground: var(--ink);\n --office-title-bar-border: var(--line);\n --office-title-bar-mark-background: var(--xl);\n --office-title-bar-mark-foreground: var(--xve-primary-foreground);\n}\n
|
|
21
|
+
var shell_default = "/* Frame, title bar and status bar. Mirrors docx-viewer's chrome (styles/base.css,\n chrome-titlebar.css, status-dialogs.css) with --xve-* tokens. */\n:host {\n --xl: var(--xve-primary);\n --xl-strong: color-mix(in srgb, var(--xve-primary) 70%, #000);\n --xl-soft: color-mix(in srgb, var(--xve-primary) 12%, transparent);\n --accent-soft: var(--xl-soft);\n --ink: var(--xve-foreground);\n --muted: var(--xve-muted-foreground);\n --line: var(--xve-border);\n --surface: var(--xve-card);\n --chrome: var(--xve-background);\n display: block;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-height: 0;\n color: var(--ink);\n font:\n 13px/1.35 'Segoe UI',\n Arial,\n sans-serif;\n}\n.xve-frame {\n position: relative;\n display: flex;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-height: 0;\n min-width: 0;\n flex-direction: column;\n overflow: hidden;\n background: var(--surface);\n}\n:focus-visible {\n outline: 2px solid var(--xve-ring);\n outline-offset: 1px;\n}\n[hidden],\n[data-xve-hidden] {\n display: none !important;\n}\n.xve-icon {\n flex: none;\n}\n.xve-icon-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 28px;\n height: 28px;\n padding: 0 6px;\n border: 0;\n border-radius: 4px;\n background: none;\n color: inherit;\n font: inherit;\n cursor: pointer;\n}\n.xve-icon-button:hover:not(:disabled),\n.xve-icon-button[aria-pressed='true'] {\n background: var(--xl-soft);\n}\n.xve-icon-button:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* Workspace: formula bar, grid and sheet tabs between the ribbon and the status bar. */\n.xve-workspace {\n position: relative;\n display: flex;\n flex: 1;\n min-height: 0;\n min-width: 0;\n flex-direction: column;\n background: var(--xve-sheet-bg);\n}\n.xve-formula-row {\n flex: none;\n min-width: 0;\n border-bottom: 1px solid var(--line);\n background: var(--surface);\n}\n.xve-grid-host {\n position: relative;\n display: flex;\n flex: 1;\n min-height: 0;\n min-width: 0;\n overflow: hidden;\n background: var(--xve-sheet-bg);\n color-scheme: light;\n}\n.xve-grid-host > * {\n flex: 1;\n min-width: 0;\n}\n.xve-tabs-row {\n flex: none;\n min-width: 0;\n border-top: 1px solid var(--line);\n background: var(--chrome);\n}\n.xve-empty {\n position: absolute;\n z-index: 5;\n inset: 0;\n display: grid;\n place-items: center;\n color: var(--muted);\n background: var(--chrome);\n}\n:host([show-formula-bar='false']) .xve-formula-row,\n:host([show-toolbar='false']) .xve-ribbon {\n display: none;\n}\n\n/* Title bar: drawn by the shared office-ui-title-bar; the mark, background and borders come from its tokens. */\n.xve-titlebar {\n display: block;\n flex: none;\n --office-title-bar-background: var(--chrome);\n --office-title-bar-foreground: var(--ink);\n --office-title-bar-border: var(--line);\n --office-title-bar-mark-background: var(--xl);\n --office-title-bar-mark-foreground: var(--xve-primary-foreground);\n}\n\n/* Status bar: drawn by the shared office-ui-status-bar; this places it and styles the slotted stats. */\n.xve-status {\n display: block;\n flex: none;\n min-width: 0;\n border-top: 1px solid var(--line);\n}\n.xve-status-stats {\n margin-inline-end: 10px;\n overflow: hidden;\n color: var(--ink);\n font-size: 11px;\n white-space: nowrap;\n}\n\n@media (max-width: 760px) {\n .xve-status-stats {\n display: none;\n }\n}\n";
|
|
25
22
|
|
|
26
23
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/xlsx/theme/ribbon.css?raw
|
|
27
24
|
var ribbon_default = "/* Ribbon: tabs, panels, groups and controls. Mirrors docx-viewer's styles/ribbon*.css. */\n.xve-ribbon-gallery[data-office-gallery] .trigger {\n flex-direction: column;\n justify-content: center;\n min-width: 56px;\n height: 78px;\n white-space: normal;\n text-align: center;\n}\n.xve-ribbon-gallery[data-office-gallery] .trigger > svg {\n width: 28px;\n height: 28px;\n}\n.xve-ribbon-gallery[data-office-gallery] .trigger > span:not([aria-hidden]) {\n max-width: 56px;\n}\n.xve-ribbon {\n position: relative;\n display: flex;\n flex: none;\n min-width: 0;\n flex-direction: column;\n background: var(--surface);\n border-bottom: 1px solid var(--line);\n}\n/* The tab row, File button and collapse button are the shared office-ui-ribbon; these colour it. */\n.xve-ribbon {\n --office-ribbon-contextual: #0f7b6c;\n}\n.xve-ribbon::part(file) {\n font-weight: 600;\n}\n.ribbon-panel {\n display: flex;\n flex: none;\n box-sizing: border-box;\n height: 104px;\n min-width: 0;\n align-items: stretch;\n gap: 4px;\n padding: 6px 10px 4px;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: thin;\n}\n.ribbon-group {\n position: relative;\n display: flex;\n flex: 0 0 auto;\n align-items: flex-start;\n min-width: 0;\n gap: 2px;\n padding: 2px 10px 18px 2px;\n border-right: 1px solid var(--line);\n}\n.ribbon-group:last-child {\n border: 0;\n}\n.ribbon-group::after {\n position: absolute;\n right: 0;\n bottom: 2px;\n left: 0;\n color: var(--muted);\n font-size: 10px;\n line-height: 1.1;\n text-align: center;\n white-space: nowrap;\n content: attr(data-caption);\n}\n.ribbon-caption-sizer {\n position: absolute;\n visibility: hidden;\n font-size: 10px;\n white-space: nowrap;\n}\n.ribbon-stack {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n}\n.ribbon-stack > .ribbon-stack {\n flex-direction: row;\n align-items: center;\n}\n.ribbon-separator {\n align-self: stretch;\n width: 1px;\n margin: 2px 3px;\n background: var(--line);\n}\n.ribbon-stack > .ribbon-separator {\n width: auto;\n height: 1px;\n}\n.ribbon-stack > .ribbon-stack > .ribbon-separator {\n width: 1px;\n height: 20px;\n}\n\n/* Buttons */\n.ribbon-group button {\n flex: none;\n min-width: 28px;\n height: 28px;\n max-width: 100%;\n padding: 0 4px;\n overflow: hidden;\n border: 1px solid transparent;\n border-radius: 4px;\n background: transparent;\n color: var(--ink);\n font:\n 400 12px 'Segoe UI',\n Arial,\n sans-serif;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: pointer;\n}\n.ribbon-group button:hover:not(:disabled) {\n border-color: var(--line);\n background: var(--accent-soft);\n}\n.ribbon-group button[aria-pressed='true'],\n.ribbon-group button[aria-expanded='true'] {\n border-color: color-mix(in srgb, var(--xl) 45%, transparent);\n background: color-mix(in srgb, var(--xl) 20%, transparent);\n}\n.ribbon-group button:active:not(:disabled) {\n background: color-mix(in srgb, var(--xl) 28%, transparent);\n}\n.ribbon-group button:focus-visible {\n outline: 2px solid var(--xl);\n outline-offset: -2px;\n}\n.ribbon-group button:disabled,\n.ribbon-group input:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.ribbon-group button.ribbon-small {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n height: 24px;\n padding: 0 3px;\n}\n.ribbon-group button.ribbon-small.ribbon-labelled {\n justify-content: flex-start;\n padding: 0 6px 0 4px;\n}\n.ribbon-group button.ribbon-large {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-start;\n gap: 2px;\n width: auto;\n min-width: 48px;\n height: 76px;\n padding: 3px 3px 2px;\n font-size: 11px;\n line-height: 1.15;\n white-space: normal;\n text-align: center;\n}\n.ribbon-large > .ribbon-icon:last-child:not(:first-child) {\n margin-top: auto;\n}\n.ribbon-large > span,\n.ribbon-caption {\n /* Two balanced lines (see ribbon/caption.ts); the button grows to the widest. */\n white-space: pre;\n}\n.ribbon-icon {\n flex: none;\n}\n.ribbon-icon[data-icon$='-caret'],\n.ribbon-icon[data-icon='caret'] {\n opacity: 0.8;\n}\n\n/* Split buttons: a main half and a caret that opens a menu or the colour grid. */\n.ribbon-split {\n display: inline-flex;\n align-items: stretch;\n}\n.ribbon-split.ribbon-split-large {\n flex-direction: column;\n}\n.ribbon-group .ribbon-split > button:first-child {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.ribbon-group .ribbon-split > .ribbon-caret {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n min-width: 14px;\n padding: 0;\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.ribbon-group .ribbon-split-large > button:first-child {\n height: 46px;\n border-radius: 4px 4px 0 0;\n}\n.ribbon-group .ribbon-split-large > .ribbon-caret {\n width: auto;\n height: 26px;\n border-radius: 0 0 4px 4px;\n font-size: 11px;\n flex-direction: column;\n gap: 0;\n}\n.ribbon-color {\n position: relative;\n}\n.ribbon-group button.ribbon-color::after {\n position: absolute;\n right: 4px;\n bottom: 2px;\n left: 4px;\n height: 3px;\n background: var(--bar, transparent);\n outline: 1px solid var(--line);\n content: '';\n}\n\n/* Editable combo boxes (font name and size) and plain selects. */\n.ribbon-combo {\n display: inline-flex;\n align-items: stretch;\n height: 24px;\n border: 1px solid var(--line);\n border-radius: 3px;\n background: var(--surface);\n}\n.ribbon-combo:focus-within {\n border-color: var(--xl);\n outline: 1px solid var(--xl);\n}\n.ribbon-combo input {\n flex: 1;\n min-width: 0;\n padding: 0 6px;\n border: 0;\n background: transparent;\n color: var(--ink);\n font:\n 12px 'Segoe UI',\n Arial,\n sans-serif;\n outline: none;\n}\n.ribbon-group .ribbon-combo .ribbon-caret {\n width: 18px;\n min-width: 18px;\n height: 100%;\n padding: 0;\n border: 0;\n border-radius: 0;\n}\n\n/* Plain drop-downs (Number Format) and gallery previews. */\n.ribbon-group select.ribbon-select {\n height: 24px;\n padding: 0 6px;\n border: 1px solid var(--line);\n border-radius: 3px;\n background: var(--surface);\n color: var(--ink);\n font:\n 12px 'Segoe UI',\n Arial,\n sans-serif;\n text-overflow: ellipsis;\n}\n.ribbon-group select.ribbon-select:focus-visible {\n outline: 2px solid var(--xl);\n outline-offset: -1px;\n}\n.ribbon-gallery-preview {\n display: block;\n height: 36px;\n margin-bottom: 3px;\n border: 1px solid var(--line);\n border-radius: 2px;\n background: #fff;\n color: #1f1f1f;\n font-size: 11px;\n line-height: 36px;\n text-align: center;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.ribbon-gallery-preview > svg {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n/* Dialog launcher: the corner arrow of a group. */\n.ribbon-group button.ribbon-launcher {\n position: absolute;\n right: 2px;\n bottom: 0;\n z-index: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n min-width: 14px;\n height: 14px;\n padding: 0;\n color: var(--muted);\n}\n\n/* Collapsed groups: a narrow ribbon folds its rightmost groups into one dropdown each. */\n.ribbon-group > .ribbon-overflow-button {\n display: none;\n}\n.ribbon-group[data-collapsed] {\n padding-right: 4px;\n}\n.ribbon-group[data-collapsed] > :not(.ribbon-overflow-button) {\n display: none !important;\n}\n.ribbon-group[data-collapsed] > button.ribbon-overflow-button {\n display: flex;\n}\n.ribbon-group[data-collapsed]::after {\n display: none;\n}\n.ribbon-overflow-panel .ribbon-group {\n height: 84px;\n padding-right: 2px;\n border: 0;\n}\n\n/* KeyTips */\n.xve-keytip {\n position: absolute;\n bottom: -2px;\n left: 50%;\n z-index: 70;\n min-width: 16px;\n padding: 1px 4px;\n border: 1px solid var(--line);\n border-radius: 3px;\n background: #1f1f1f;\n color: #fff;\n font:\n 600 11px/14px 'Segoe UI',\n Arial,\n sans-serif;\n text-align: center;\n pointer-events: none;\n transform: translateX(-50%);\n}\n.xve-keytip-command {\n position: fixed;\n bottom: auto;\n}\n\n/* Accent hues on command icons, as in Office. */\n:host {\n --ribbon-accent-blue: #2b7cd3;\n --ribbon-accent-green: #2f9e5f;\n --ribbon-accent-red: #d13438;\n --ribbon-accent-orange: #d9822b;\n}\n@media (prefers-color-scheme: dark) {\n :host(:not([theme='light'])) {\n --ribbon-accent-blue: #5ea5f0;\n --ribbon-accent-green: #5cc98a;\n --ribbon-accent-red: #f07a7d;\n --ribbon-accent-orange: #f0a35e;\n }\n}\n:host([theme='dark']) {\n --ribbon-accent-blue: #5ea5f0;\n --ribbon-accent-green: #5cc98a;\n --ribbon-accent-red: #f07a7d;\n --ribbon-accent-orange: #f0a35e;\n}\n.ribbon-icon[data-accent='blue'] {\n color: var(--ribbon-accent-blue);\n}\n.ribbon-icon[data-accent='green'] {\n color: var(--ribbon-accent-green);\n}\n.ribbon-icon[data-accent='red'] {\n color: var(--ribbon-accent-red);\n}\n.ribbon-icon[data-accent='orange'] {\n color: var(--ribbon-accent-orange);\n}\n";
|
|
@@ -43,7 +40,10 @@ var themeTokenText = `:host{${declarations(lightTheme, "light")}}
|
|
|
43
40
|
:host([theme="light"]){${declarations(lightTheme, "light")}}`;
|
|
44
41
|
var editorStyleText = [
|
|
45
42
|
themeTokenText,
|
|
46
|
-
|
|
43
|
+
// The shared elements read --office-*; feed them from the editor's --xve-* theme.
|
|
44
|
+
shadcnBridge(":host", "--xve-", {
|
|
45
|
+
extra: { "--office-font": "'Segoe UI', system-ui, -apple-system, sans-serif" }
|
|
46
|
+
}),
|
|
47
47
|
shell_default,
|
|
48
48
|
ribbon_default,
|
|
49
49
|
popups_default,
|
|
@@ -363,7 +363,7 @@ function renderInfo(page) {
|
|
|
363
363
|
paragraph(
|
|
364
364
|
page,
|
|
365
365
|
t(
|
|
366
|
-
"Charts are shown but not edited; pivot tables,
|
|
366
|
+
"Charts and sparklines are shown but not edited; pivot tables, macros and other unsupported parts are kept in the file but not shown."
|
|
367
367
|
),
|
|
368
368
|
"xve-backstage-muted"
|
|
369
369
|
)
|
|
@@ -856,12 +856,105 @@ function renderCustomize(page) {
|
|
|
856
856
|
...sections
|
|
857
857
|
);
|
|
858
858
|
}
|
|
859
|
+
|
|
860
|
+
// src/xlsx/backstage/pages-share.ts
|
|
861
|
+
var STATUS = {
|
|
862
|
+
off: "Not sharing.",
|
|
863
|
+
connecting: "Connecting...",
|
|
864
|
+
connected: "Connected.",
|
|
865
|
+
disconnected: "Disconnected. Changes are kept and sent when the connection returns.",
|
|
866
|
+
error: "The connection failed. Changes are kept and sent when the connection returns."
|
|
867
|
+
};
|
|
868
|
+
var suggestRoom = () => `book-${Math.random().toString(36).slice(2, 8)}`;
|
|
869
|
+
function renderShare(page) {
|
|
870
|
+
const { t, doc } = page;
|
|
871
|
+
const share = page.host.share;
|
|
872
|
+
if (!share) {
|
|
873
|
+
page.content.replaceChildren(heading(page, t("Share")));
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
const state = share.state();
|
|
877
|
+
const status = paragraph(page, t(STATUS[state.status]), "xve-share-status");
|
|
878
|
+
status.setAttribute("role", "status");
|
|
879
|
+
const say = (message) => {
|
|
880
|
+
status.textContent = message;
|
|
881
|
+
};
|
|
882
|
+
const children = [
|
|
883
|
+
heading(page, t("Share")),
|
|
884
|
+
paragraph(
|
|
885
|
+
page,
|
|
886
|
+
t(
|
|
887
|
+
"Edit this workbook together with other people. Everyone who joins the same session sees changes as they are made."
|
|
888
|
+
)
|
|
889
|
+
)
|
|
890
|
+
];
|
|
891
|
+
if (state.active) {
|
|
892
|
+
children.push(paragraph(page, t("Session: {room}", { room: state.roomId ?? "" })));
|
|
893
|
+
if (state.status === "connected" && !state.synced) say(t("Joining the session..."));
|
|
894
|
+
} else {
|
|
895
|
+
const room = doc.createElement("input");
|
|
896
|
+
room.type = "text";
|
|
897
|
+
room.className = "xve-share-room";
|
|
898
|
+
room.maxLength = 128;
|
|
899
|
+
room.autocomplete = "off";
|
|
900
|
+
room.spellcheck = false;
|
|
901
|
+
room.value = suggestRoom();
|
|
902
|
+
children.push(labelled(page, t("Session name"), room));
|
|
903
|
+
const start = primary(page, t("Start sharing"), () => {
|
|
904
|
+
start.disabled = true;
|
|
905
|
+
say(t("Connecting..."));
|
|
906
|
+
share.start(room.value.trim()).catch((error) => {
|
|
907
|
+
start.disabled = false;
|
|
908
|
+
say(t(error instanceof Error ? error.message : String(error)));
|
|
909
|
+
});
|
|
910
|
+
});
|
|
911
|
+
start.dataset.share = "start";
|
|
912
|
+
children.push(start);
|
|
913
|
+
}
|
|
914
|
+
children.push(status);
|
|
915
|
+
if (state.active) {
|
|
916
|
+
definePresence();
|
|
917
|
+
const people = doc.createElement("office-ui-presence");
|
|
918
|
+
people.className = "xve-share-people";
|
|
919
|
+
people.setAttribute("label", t("People in this session"));
|
|
920
|
+
people.participants = participants(state);
|
|
921
|
+
const stop = primary(page, t("Stop sharing"), () => share.stop());
|
|
922
|
+
stop.dataset.share = "stop";
|
|
923
|
+
children.push(people, stop);
|
|
924
|
+
}
|
|
925
|
+
children.push(
|
|
926
|
+
paragraph(
|
|
927
|
+
page,
|
|
928
|
+
t(
|
|
929
|
+
"Cell values, formulas, formats, sheets, rows, columns, merges and names are shared. Charts, pictures, comments, conditional formats, data validation, tables and page setup stay in this window."
|
|
930
|
+
),
|
|
931
|
+
"xve-backstage-muted"
|
|
932
|
+
),
|
|
933
|
+
paragraph(
|
|
934
|
+
page,
|
|
935
|
+
t(
|
|
936
|
+
"Without a server set by the page, a session connects only windows and tabs of this browser. Nothing is uploaded."
|
|
937
|
+
),
|
|
938
|
+
"xve-backstage-muted"
|
|
939
|
+
)
|
|
940
|
+
);
|
|
941
|
+
page.content.replaceChildren(...children);
|
|
942
|
+
}
|
|
943
|
+
function participants(state) {
|
|
944
|
+
return state.people.map((person) => ({
|
|
945
|
+
id: String(person.clientId),
|
|
946
|
+
name: person.name,
|
|
947
|
+
color: person.color,
|
|
948
|
+
...person.self ? { self: true } : {}
|
|
949
|
+
}));
|
|
950
|
+
}
|
|
859
951
|
var PAGES = [
|
|
860
952
|
["info", "Info"],
|
|
861
953
|
["new", "New"],
|
|
862
954
|
["open", "Open"],
|
|
863
955
|
["saveAs", "Save As"],
|
|
864
956
|
["print", "Print"],
|
|
957
|
+
["share", "Share"],
|
|
865
958
|
["export", "Export"],
|
|
866
959
|
["options", "Options"],
|
|
867
960
|
["customize", "Customize Ribbon"]
|
|
@@ -872,6 +965,7 @@ var RENDERERS = {
|
|
|
872
965
|
open: renderOpen,
|
|
873
966
|
saveAs: renderSaveAs,
|
|
874
967
|
print: renderPrint,
|
|
968
|
+
share: renderShare,
|
|
875
969
|
export: renderExport,
|
|
876
970
|
options: renderOptions,
|
|
877
971
|
customize: renderCustomize
|
|
@@ -934,6 +1028,7 @@ function createBackstage(host) {
|
|
|
934
1028
|
item("save", "Save"),
|
|
935
1029
|
page("saveAs"),
|
|
936
1030
|
page("print"),
|
|
1031
|
+
page("share"),
|
|
937
1032
|
page("export"),
|
|
938
1033
|
page("options", "footer"),
|
|
939
1034
|
page("customize", "footer")
|
|
@@ -953,7 +1048,10 @@ function createBackstage(host) {
|
|
|
953
1048
|
get isOpen() {
|
|
954
1049
|
return element.open;
|
|
955
1050
|
},
|
|
956
|
-
relocalize
|
|
1051
|
+
relocalize,
|
|
1052
|
+
refresh(page) {
|
|
1053
|
+
if (element.open && current === page) show(page);
|
|
1054
|
+
}
|
|
957
1055
|
};
|
|
958
1056
|
}
|
|
959
1057
|
|
|
@@ -3083,46 +3181,61 @@ function openGoToSpecial(ctx) {
|
|
|
3083
3181
|
}
|
|
3084
3182
|
|
|
3085
3183
|
// src/xlsx/dialogs/comments-list.ts
|
|
3184
|
+
function excelCommentThreads(comments) {
|
|
3185
|
+
return [...comments].sort((a, b) => a.address.row - b.address.row || a.address.col - b.address.col).map((comment) => {
|
|
3186
|
+
const id = formatAddress(comment.address);
|
|
3187
|
+
return {
|
|
3188
|
+
id,
|
|
3189
|
+
anchorLabel: id,
|
|
3190
|
+
resolved: false,
|
|
3191
|
+
comments: [
|
|
3192
|
+
{ id: `${id}:0`, author: comment.author, text: comment.text },
|
|
3193
|
+
...(comment.replies ?? []).map((reply, index) => ({
|
|
3194
|
+
id: `${id}:${index + 1}`,
|
|
3195
|
+
author: reply.author,
|
|
3196
|
+
text: reply.text,
|
|
3197
|
+
...reply.date ? { created: reply.date } : {}
|
|
3198
|
+
}))
|
|
3199
|
+
]
|
|
3200
|
+
};
|
|
3201
|
+
});
|
|
3202
|
+
}
|
|
3086
3203
|
function openCommentsList(ctx) {
|
|
3087
3204
|
const ws = ctx.workbook()?.sheets[ctx.activeSheet()];
|
|
3088
|
-
const comments =
|
|
3089
|
-
|
|
3090
|
-
);
|
|
3205
|
+
const comments = ws?.comments ?? [];
|
|
3206
|
+
const threads = excelCommentThreads(comments);
|
|
3091
3207
|
let close;
|
|
3092
3208
|
let chosen;
|
|
3093
|
-
|
|
3094
|
-
|
|
3209
|
+
defineCommentsPane(ctx.host.ownerDocument.defaultView?.customElements);
|
|
3210
|
+
const pane = ctx.host.ownerDocument.createElement(
|
|
3211
|
+
"office-ui-comments-pane"
|
|
3212
|
+
);
|
|
3213
|
+
pane.className = "xve-comments-list";
|
|
3214
|
+
pane.listOnly = true;
|
|
3215
|
+
pane.labels = {
|
|
3216
|
+
heading: "",
|
|
3217
|
+
list: ctx.t("Comments"),
|
|
3218
|
+
empty: ctx.t("There are no comments on this sheet.")
|
|
3219
|
+
};
|
|
3220
|
+
pane.threads = threads;
|
|
3221
|
+
pane.activeThreadId = threads[0]?.id ?? null;
|
|
3222
|
+
pane.addEventListener("thread-select", (event) => {
|
|
3223
|
+
const id = event.detail.threadId;
|
|
3224
|
+
const comment = comments.find((item) => formatAddress(item.address) === id);
|
|
3095
3225
|
if (!comment) return;
|
|
3096
3226
|
const at = { ...comment.address };
|
|
3097
|
-
chosen =
|
|
3227
|
+
chosen = id;
|
|
3098
3228
|
selectOn(ctx, ctx.activeSheet(), { start: at, end: at });
|
|
3099
3229
|
close?.();
|
|
3100
|
-
};
|
|
3101
|
-
const list = listBox(ctx, "Comments", void 0, activate);
|
|
3102
|
-
list.setItems(
|
|
3103
|
-
comments.map(
|
|
3104
|
-
(c, i) => [
|
|
3105
|
-
String(i),
|
|
3106
|
-
`${formatAddress(c.address)} ${c.author}: ${c.text.replace(/\s+/g, " ")}`
|
|
3107
|
-
]
|
|
3108
|
-
)
|
|
3109
|
-
);
|
|
3110
|
-
for (const option of list.element.querySelectorAll('[role="option"]'))
|
|
3111
|
-
option.addEventListener(
|
|
3112
|
-
"click",
|
|
3113
|
-
() => option.dataset.value !== void 0 && activate(option.dataset.value)
|
|
3114
|
-
);
|
|
3115
|
-
const first = comments.length ? "0" : void 0;
|
|
3116
|
-
if (first) list.select(first);
|
|
3117
|
-
const body = comments.length ? [list.element] : [text(ctx, "There are no comments on this sheet.")];
|
|
3230
|
+
});
|
|
3118
3231
|
return showDialog(
|
|
3119
3232
|
ctx,
|
|
3120
3233
|
{
|
|
3121
3234
|
name: "comments-list",
|
|
3122
3235
|
heading: "Comments",
|
|
3123
3236
|
okLabel: null,
|
|
3124
|
-
body,
|
|
3125
|
-
opened: () =>
|
|
3237
|
+
body: [pane],
|
|
3238
|
+
opened: () => pane.focus()
|
|
3126
3239
|
},
|
|
3127
3240
|
(open) => {
|
|
3128
3241
|
close = open.close;
|
|
@@ -4067,7 +4180,8 @@ var SUPPORTED_FEATURES = [
|
|
|
4067
4180
|
"Freeze panes"
|
|
4068
4181
|
];
|
|
4069
4182
|
var UNSUPPORTED_FEATURES = [
|
|
4070
|
-
"Pivot tables
|
|
4183
|
+
"Pivot tables (kept in the file but not shown)",
|
|
4184
|
+
"Creating or editing sparklines (existing ones are shown)",
|
|
4071
4185
|
"Show Formulas",
|
|
4072
4186
|
"Manual calculation",
|
|
4073
4187
|
"Outline (grouping) for columns",
|
|
@@ -11092,10 +11206,10 @@ function gridCommands(host) {
|
|
|
11092
11206
|
icon: "undo",
|
|
11093
11207
|
shortcut: "Ctrl+Z",
|
|
11094
11208
|
editing: true,
|
|
11095
|
-
enabled: (ctx) => Boolean(ctx
|
|
11209
|
+
enabled: (ctx) => Boolean(historyOf(ctx)?.canUndo()) || host.isEditing(),
|
|
11096
11210
|
run: (ctx) => {
|
|
11097
11211
|
if (host.isEditing()) return host.cancelEdit();
|
|
11098
|
-
ctx
|
|
11212
|
+
historyOf(ctx)?.undo();
|
|
11099
11213
|
}
|
|
11100
11214
|
},
|
|
11101
11215
|
{
|
|
@@ -11104,8 +11218,8 @@ function gridCommands(host) {
|
|
|
11104
11218
|
icon: "redo",
|
|
11105
11219
|
shortcut: "Ctrl+Y",
|
|
11106
11220
|
editing: true,
|
|
11107
|
-
enabled: (ctx) => Boolean(ctx
|
|
11108
|
-
run: (ctx) => void ctx
|
|
11221
|
+
enabled: (ctx) => Boolean(historyOf(ctx)?.canRedo()),
|
|
11222
|
+
run: (ctx) => void historyOf(ctx)?.redo()
|
|
11109
11223
|
},
|
|
11110
11224
|
{
|
|
11111
11225
|
id: "edit.select-all",
|
|
@@ -11880,6 +11994,82 @@ var GridSelection = class {
|
|
|
11880
11994
|
return g.fCols > 0 ? 0 : this.#view.metrics.colAt(g.scrollLeft);
|
|
11881
11995
|
}
|
|
11882
11996
|
};
|
|
11997
|
+
|
|
11998
|
+
// src/xlsx/grid/sparkline.ts
|
|
11999
|
+
var SVG = "http://www.w3.org/2000/svg";
|
|
12000
|
+
var fixed = (n) => String(Math.round(n * 100) / 100);
|
|
12001
|
+
function svgElement(doc, tag, attrs) {
|
|
12002
|
+
const node = doc.createElementNS(SVG, tag);
|
|
12003
|
+
for (const [name, value] of Object.entries(attrs)) node.setAttribute(name, value);
|
|
12004
|
+
return node;
|
|
12005
|
+
}
|
|
12006
|
+
function sparklineSvg(doc, view, w, h2, zoom) {
|
|
12007
|
+
const scale = zoom / 100;
|
|
12008
|
+
const stroke = Math.max(0.5, view.lineWeightPt * (96 / 72) * scale);
|
|
12009
|
+
const radius = view.markers.length ? Math.max(1.5 * scale, stroke * 1.25) : 0;
|
|
12010
|
+
const padX = 2 * scale + (view.type === "line" ? Math.max(radius, stroke / 2) : 0);
|
|
12011
|
+
const padY = 2 * scale + (view.type === "line" ? Math.max(radius, stroke / 2) : 0);
|
|
12012
|
+
const innerW = Math.max(0, w - 2 * padX);
|
|
12013
|
+
const innerH = Math.max(0, h2 - 2 * padY);
|
|
12014
|
+
const px = (x) => padX + x * innerW;
|
|
12015
|
+
const py = (y) => padY + y * innerH;
|
|
12016
|
+
const svg = svgElement(doc, "svg", {
|
|
12017
|
+
class: "xg-spark",
|
|
12018
|
+
width: fixed(w),
|
|
12019
|
+
height: fixed(h2),
|
|
12020
|
+
"aria-hidden": "true"
|
|
12021
|
+
});
|
|
12022
|
+
if (view.axis)
|
|
12023
|
+
svg.append(
|
|
12024
|
+
svgElement(doc, "line", {
|
|
12025
|
+
x1: fixed(padX),
|
|
12026
|
+
x2: fixed(padX + innerW),
|
|
12027
|
+
y1: fixed(py(view.axis.y)),
|
|
12028
|
+
y2: fixed(py(view.axis.y)),
|
|
12029
|
+
stroke: view.axis.color,
|
|
12030
|
+
"stroke-width": fixed(Math.max(1, scale)),
|
|
12031
|
+
"shape-rendering": "crispEdges"
|
|
12032
|
+
})
|
|
12033
|
+
);
|
|
12034
|
+
for (const column of view.columns) {
|
|
12035
|
+
const height = Math.max(1, column.h * innerH);
|
|
12036
|
+
const top = column.h * innerH < 1 && column.y >= 0.5 ? py(column.y) - 1 : py(column.y);
|
|
12037
|
+
svg.append(
|
|
12038
|
+
svgElement(doc, "rect", {
|
|
12039
|
+
x: fixed(px(column.x)),
|
|
12040
|
+
y: fixed(top),
|
|
12041
|
+
width: fixed(Math.max(1, column.w * innerW)),
|
|
12042
|
+
height: fixed(height),
|
|
12043
|
+
fill: column.color
|
|
12044
|
+
})
|
|
12045
|
+
);
|
|
12046
|
+
}
|
|
12047
|
+
for (const line of view.lines) {
|
|
12048
|
+
if (line.length === 1) continue;
|
|
12049
|
+
svg.append(
|
|
12050
|
+
svgElement(doc, "polyline", {
|
|
12051
|
+
points: line.map((p) => `${fixed(px(p.x))},${fixed(py(p.y))}`).join(" "),
|
|
12052
|
+
fill: "none",
|
|
12053
|
+
stroke: view.color,
|
|
12054
|
+
"stroke-width": fixed(stroke),
|
|
12055
|
+
"stroke-linejoin": "round",
|
|
12056
|
+
"stroke-linecap": "round"
|
|
12057
|
+
})
|
|
12058
|
+
);
|
|
12059
|
+
}
|
|
12060
|
+
for (const marker of view.markers)
|
|
12061
|
+
svg.append(
|
|
12062
|
+
svgElement(doc, "circle", {
|
|
12063
|
+
cx: fixed(px(marker.x)),
|
|
12064
|
+
cy: fixed(py(marker.y)),
|
|
12065
|
+
r: fixed(radius),
|
|
12066
|
+
fill: marker.color
|
|
12067
|
+
})
|
|
12068
|
+
);
|
|
12069
|
+
return svg;
|
|
12070
|
+
}
|
|
12071
|
+
|
|
12072
|
+
// src/xlsx/grid/cell-layer.ts
|
|
11883
12073
|
var viewKeys = /* @__PURE__ */ new WeakMap();
|
|
11884
12074
|
var viewKey = (view) => {
|
|
11885
12075
|
let key = viewKeys.get(view);
|
|
@@ -12006,6 +12196,7 @@ function paintCell(doc, node, item, zoom) {
|
|
|
12006
12196
|
style.backgroundImage = fill?.image ?? "";
|
|
12007
12197
|
node.className = `xg-c${item.overflowing ? " xg-c-over" : ""}${view.hasHyperlink ? " xg-link" : ""}${item.merged ? " xg-merged" : ""}`;
|
|
12008
12198
|
node.replaceChildren();
|
|
12199
|
+
if (view.sparkline) node.append(sparklineSvg(doc, view.sparkline, item.w, item.h, zoom));
|
|
12009
12200
|
if (view.dataBar) {
|
|
12010
12201
|
const bar = h(doc, "div", "xg-db");
|
|
12011
12202
|
const width = Math.max(0, Math.min(1, view.dataBar.fraction)) * (item.w - 4);
|
|
@@ -12764,6 +12955,7 @@ var GRID_CSS = `
|
|
|
12764
12955
|
.xg-link{cursor:pointer}
|
|
12765
12956
|
.xg-b{position:absolute;left:-1px;top:-1px;box-sizing:border-box;pointer-events:none}
|
|
12766
12957
|
.xg-diag{position:absolute;left:0;top:0;pointer-events:none}
|
|
12958
|
+
.xg-spark{position:absolute;left:0;top:0;pointer-events:none;overflow:hidden}
|
|
12767
12959
|
.xg-db{position:absolute;left:2px;top:2px;bottom:2px;border:1px solid;box-sizing:border-box}
|
|
12768
12960
|
.xg-ic{position:absolute;left:2px;top:50%;transform:translateY(-50%)}
|
|
12769
12961
|
.xg-cm{position:absolute;right:0;top:0;width:0;height:0;border-left:6px solid transparent;border-top:6px solid #d13438;z-index:2}
|
|
@@ -12781,6 +12973,12 @@ var GRID_CSS = `
|
|
|
12781
12973
|
@media (prefers-reduced-motion:reduce){.xg-ants{animation:none}}
|
|
12782
12974
|
.xg-fill-preview{position:absolute;box-sizing:border-box;border:1px dashed #666}
|
|
12783
12975
|
.xg-refbox{position:absolute;box-sizing:border-box;border:2px solid}
|
|
12976
|
+
.xg-remote-layer{position:absolute;left:0;top:0;pointer-events:none;z-index:3}
|
|
12977
|
+
.xg-remote{position:absolute;box-sizing:border-box;border:2px solid}
|
|
12978
|
+
.xg-remote[hidden]{display:none}
|
|
12979
|
+
.xg-remote-tag{position:absolute;left:-2px;bottom:100%;max-width:160px;padding:0 4px;height:16px;line-height:16px;
|
|
12980
|
+
font:600 11px/16px var(--xve-font,system-ui,sans-serif);color:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border-radius:2px 2px 2px 0}
|
|
12981
|
+
.xg-remote[data-tag="inside"] .xg-remote-tag{bottom:auto;top:0;left:0;border-radius:0 0 2px 0}
|
|
12784
12982
|
.xg-hbox{background:var(--xve-header-bg,#f3f3f3);z-index:4}
|
|
12785
12983
|
.xg-hdr-plane{position:absolute;left:0;top:0;will-change:transform}
|
|
12786
12984
|
.xg-hd{position:absolute;box-sizing:border-box;display:flex;align-items:center;justify-content:center;
|
|
@@ -12986,6 +13184,66 @@ var ValidationList = class {
|
|
|
12986
13184
|
if (refocus) this.#onDone();
|
|
12987
13185
|
}
|
|
12988
13186
|
};
|
|
13187
|
+
var TAG_HEIGHT = 16;
|
|
13188
|
+
var RemoteLayer = class {
|
|
13189
|
+
constructor(doc) {
|
|
13190
|
+
this.doc = doc;
|
|
13191
|
+
this.element = h(doc, "div", "xg-remote-layer");
|
|
13192
|
+
}
|
|
13193
|
+
doc;
|
|
13194
|
+
element;
|
|
13195
|
+
#nodes = [];
|
|
13196
|
+
render(boxes) {
|
|
13197
|
+
boxes.forEach((box, index) => {
|
|
13198
|
+
let node = this.#nodes[index];
|
|
13199
|
+
if (!node) {
|
|
13200
|
+
node = h(this.doc, "div", "xg-remote");
|
|
13201
|
+
node.append(h(this.doc, "span", "xg-remote-tag"));
|
|
13202
|
+
this.#nodes.push(node);
|
|
13203
|
+
this.element.append(node);
|
|
13204
|
+
}
|
|
13205
|
+
node.hidden = false;
|
|
13206
|
+
place(node, box.x - 1, box.y - 1, box.w + 1, box.h + 1);
|
|
13207
|
+
node.style.borderColor = box.color;
|
|
13208
|
+
node.dataset.clientId = String(box.clientId);
|
|
13209
|
+
node.dataset.tag = box.tag;
|
|
13210
|
+
node.title = box.name;
|
|
13211
|
+
const tag = node.firstElementChild;
|
|
13212
|
+
tag.textContent = box.label;
|
|
13213
|
+
tag.style.backgroundColor = box.color;
|
|
13214
|
+
});
|
|
13215
|
+
for (let i = boxes.length; i < this.#nodes.length; i++) {
|
|
13216
|
+
const node = this.#nodes[i];
|
|
13217
|
+
if (node) node.hidden = true;
|
|
13218
|
+
}
|
|
13219
|
+
}
|
|
13220
|
+
};
|
|
13221
|
+
function installRemoteSelections(view) {
|
|
13222
|
+
const ctx = view.ctx;
|
|
13223
|
+
const layers = QUADRANTS.map((q) => {
|
|
13224
|
+
const layer = new RemoteLayer(view.doc);
|
|
13225
|
+
view.quads[q].plane.append(layer.element);
|
|
13226
|
+
return layer;
|
|
13227
|
+
});
|
|
13228
|
+
const hook = () => {
|
|
13229
|
+
const peers = ctx.remoteSelections?.() ?? [];
|
|
13230
|
+
const boxes = peers.length ? layoutRemoteSelections(view.metrics, peers, {
|
|
13231
|
+
sheet: view.sheetIndex(),
|
|
13232
|
+
maxRow: view.extentRow,
|
|
13233
|
+
maxCol: view.extentCol,
|
|
13234
|
+
tagHeight: TAG_HEIGHT
|
|
13235
|
+
}) : [];
|
|
13236
|
+
for (const layer of layers) layer.render(boxes);
|
|
13237
|
+
};
|
|
13238
|
+
view.hooks.add(hook);
|
|
13239
|
+
const stop = ctx.onRemoteSelectionsChange?.(() => view.schedule());
|
|
13240
|
+
hook();
|
|
13241
|
+
return () => {
|
|
13242
|
+
stop?.();
|
|
13243
|
+
view.hooks.delete(hook);
|
|
13244
|
+
for (const layer of layers) layer.element.remove();
|
|
13245
|
+
};
|
|
13246
|
+
}
|
|
12989
13247
|
var structuralKinds = /* @__PURE__ */ new Set(["structure", "sheets", "view", "undo", "redo", "batch"]);
|
|
12990
13248
|
function mountGrid(ctx, container) {
|
|
12991
13249
|
ensureStyle(ctx.root, "xg", GRID_CSS);
|
|
@@ -12998,6 +13256,7 @@ function mountGrid(ctx, container) {
|
|
|
12998
13256
|
const drawings = new DrawingLayer(view);
|
|
12999
13257
|
const list = new ValidationList(view, () => editor.focus());
|
|
13000
13258
|
const a11y = new GridA11y(view, sink);
|
|
13259
|
+
const removeRemote = installRemoteSelections(view);
|
|
13001
13260
|
let marqueeSheet = -1;
|
|
13002
13261
|
const clipboard = createGridClipboard({
|
|
13003
13262
|
ctx,
|
|
@@ -13141,6 +13400,7 @@ function mountGrid(ctx, container) {
|
|
|
13141
13400
|
drawings.destroy();
|
|
13142
13401
|
editor.destroy();
|
|
13143
13402
|
a11y.destroy();
|
|
13403
|
+
removeRemote();
|
|
13144
13404
|
view.destroy();
|
|
13145
13405
|
};
|
|
13146
13406
|
}
|
|
@@ -14341,6 +14601,52 @@ function createRibbon(ctx, handlers) {
|
|
|
14341
14601
|
}
|
|
14342
14602
|
};
|
|
14343
14603
|
}
|
|
14604
|
+
|
|
14605
|
+
// src/xlsx/ribbon-actions.ts
|
|
14606
|
+
function createRibbonActions(ctx, handlers) {
|
|
14607
|
+
const doc = ctx.host.ownerDocument;
|
|
14608
|
+
defineRibbonActions(doc.defaultView?.customElements);
|
|
14609
|
+
const element = doc.createElement("office-ui-ribbon-actions");
|
|
14610
|
+
element.className = "xve-ribbon-actions";
|
|
14611
|
+
element.slot = "actions";
|
|
14612
|
+
element.addEventListener(
|
|
14613
|
+
"office-ribbon-mode",
|
|
14614
|
+
(event) => handlers.setReadOnly(event.detail.mode === "viewing")
|
|
14615
|
+
);
|
|
14616
|
+
element.addEventListener("office-ribbon-comments", () => {
|
|
14617
|
+
void ctx.commands.run("review.show-comments");
|
|
14618
|
+
});
|
|
14619
|
+
element.addEventListener("office-ribbon-share", () => void ctx.commands.run("file.share"));
|
|
14620
|
+
const relocalize = () => {
|
|
14621
|
+
element.modeLabel = ctx.t("Editing mode");
|
|
14622
|
+
element.modes = [
|
|
14623
|
+
{ value: "editing", label: ctx.t("Editing") },
|
|
14624
|
+
{ value: "viewing", label: ctx.t("Viewing") }
|
|
14625
|
+
];
|
|
14626
|
+
element.commentsLabel = ctx.t("Comments");
|
|
14627
|
+
element.commentsTitle = ctx.t("Show comments");
|
|
14628
|
+
element.shareLabel = ctx.t("Share");
|
|
14629
|
+
element.shareTitle = ctx.t("Share");
|
|
14630
|
+
refresh();
|
|
14631
|
+
};
|
|
14632
|
+
const refresh = () => {
|
|
14633
|
+
element.mode = ctx.readOnly() ? "viewing" : "editing";
|
|
14634
|
+
element.noShare = !ctx.commands.get("file.share") || handlers.isHidden("file.share");
|
|
14635
|
+
element.sharePressed = Boolean(handlers.collaboration?.().active);
|
|
14636
|
+
const showComments = ctx.commands.get("review.show-comments");
|
|
14637
|
+
element.noComments = !showComments;
|
|
14638
|
+
if (!showComments) return;
|
|
14639
|
+
let pressed = false;
|
|
14640
|
+
try {
|
|
14641
|
+
pressed = showComments.checked?.(ctx) ?? false;
|
|
14642
|
+
} catch {
|
|
14643
|
+
pressed = false;
|
|
14644
|
+
}
|
|
14645
|
+
element.commentsPressed = pressed;
|
|
14646
|
+
};
|
|
14647
|
+
relocalize();
|
|
14648
|
+
return { element, refresh, relocalize };
|
|
14649
|
+
}
|
|
14344
14650
|
var hasWorkbook = (ctx) => Boolean(ctx.workbook());
|
|
14345
14651
|
function adjacentSheet(ctx, step2) {
|
|
14346
14652
|
const sheets = ctx.workbook()?.sheets ?? [];
|
|
@@ -14372,6 +14678,12 @@ function shellCommands(handlers) {
|
|
|
14372
14678
|
run: () => handlers.openBackstage("saveAs")
|
|
14373
14679
|
},
|
|
14374
14680
|
{ id: "file.info", label: "Info", icon: "info", run: () => handlers.openBackstage("info") },
|
|
14681
|
+
{
|
|
14682
|
+
id: "file.share",
|
|
14683
|
+
label: "Share",
|
|
14684
|
+
icon: "share",
|
|
14685
|
+
run: () => handlers.openBackstage("share")
|
|
14686
|
+
},
|
|
14375
14687
|
{
|
|
14376
14688
|
id: "file.options",
|
|
14377
14689
|
label: "Options",
|
|
@@ -14384,8 +14696,8 @@ function shellCommands(handlers) {
|
|
|
14384
14696
|
icon: "undo",
|
|
14385
14697
|
shortcut: "Ctrl+Z",
|
|
14386
14698
|
editing: true,
|
|
14387
|
-
enabled: (ctx) => ctx
|
|
14388
|
-
run: (ctx) => void ctx
|
|
14699
|
+
enabled: (ctx) => historyOf(ctx)?.canUndo() ?? false,
|
|
14700
|
+
run: (ctx) => void historyOf(ctx)?.undo()
|
|
14389
14701
|
},
|
|
14390
14702
|
{
|
|
14391
14703
|
id: "edit.redo",
|
|
@@ -14393,8 +14705,8 @@ function shellCommands(handlers) {
|
|
|
14393
14705
|
icon: "redo",
|
|
14394
14706
|
shortcut: "Ctrl+Y",
|
|
14395
14707
|
editing: true,
|
|
14396
|
-
enabled: (ctx) => ctx
|
|
14397
|
-
run: (ctx) => void ctx
|
|
14708
|
+
enabled: (ctx) => historyOf(ctx)?.canRedo() ?? false,
|
|
14709
|
+
run: (ctx) => void historyOf(ctx)?.redo()
|
|
14398
14710
|
},
|
|
14399
14711
|
{
|
|
14400
14712
|
id: "sheet.next",
|
|
@@ -14503,7 +14815,8 @@ function statisticsText(ctx, shown2) {
|
|
|
14503
14815
|
if (!shown2.has(key)) continue;
|
|
14504
14816
|
const value = key === "count" ? stats.count : key === "numericCount" ? stats.numericCount : key === "sum" ? stats.numericCount ? stats.sum : void 0 : stats[key];
|
|
14505
14817
|
if (value === void 0) continue;
|
|
14506
|
-
|
|
14818
|
+
const text3 = key === "count" || key === "numericCount" ? formatNumber(locale, value) : formatSelectionStat(workbook, stats, value);
|
|
14819
|
+
parts.push(`${ctx.t(STAT_LABELS[key])}: ${text3}`);
|
|
14507
14820
|
}
|
|
14508
14821
|
return parts.join(" ");
|
|
14509
14822
|
}
|
|
@@ -14517,7 +14830,7 @@ function createStatusBar(ctx, handlers) {
|
|
|
14517
14830
|
element.setAttribute("part", "status-bar");
|
|
14518
14831
|
element.setAttribute("role", "status");
|
|
14519
14832
|
const stats = el2(doc, "span", "xve-status-stats");
|
|
14520
|
-
stats.slot = "
|
|
14833
|
+
stats.slot = "summary";
|
|
14521
14834
|
const shown2 = /* @__PURE__ */ new Set(["average", "count", "sum"]);
|
|
14522
14835
|
stats.addEventListener("contextmenu", (event) => {
|
|
14523
14836
|
event.preventDefault();
|
|
@@ -14603,22 +14916,17 @@ function createTitleBar(ctx, handlers) {
|
|
|
14603
14916
|
const element = doc.createElement("office-ui-title-bar");
|
|
14604
14917
|
element.className = "xve-titlebar";
|
|
14605
14918
|
element.setAttribute("part", "title-bar");
|
|
14606
|
-
|
|
14607
|
-
|
|
14608
|
-
|
|
14609
|
-
|
|
14610
|
-
|
|
14611
|
-
|
|
14612
|
-
|
|
14613
|
-
mode.append(new Option("", "editing"), new Option("", "viewing"));
|
|
14614
|
-
mode.addEventListener("change", () => handlers.setReadOnly(mode.value === "viewing"));
|
|
14615
|
-
actions.append(comments, mode);
|
|
14616
|
-
element.append(actions);
|
|
14919
|
+
definePresence();
|
|
14920
|
+
const people = doc.createElement("office-ui-presence");
|
|
14921
|
+
people.className = "xve-title-people";
|
|
14922
|
+
people.slot = "collaboration";
|
|
14923
|
+
people.setAttribute("max", "3");
|
|
14924
|
+
people.hidden = true;
|
|
14925
|
+
element.append(people);
|
|
14617
14926
|
let fileName = "";
|
|
14618
14927
|
let saveState = "saved";
|
|
14619
14928
|
const render3 = () => {
|
|
14620
|
-
const
|
|
14621
|
-
const undoLabel = session?.undoLabel();
|
|
14929
|
+
const undoLabel = historyOf(ctx)?.undoLabel();
|
|
14622
14930
|
const entries = [
|
|
14623
14931
|
{ id: "save", icon: "save", label: ctx.t("Save"), title: `${ctx.t("Save")} (Ctrl+S)` },
|
|
14624
14932
|
{
|
|
@@ -14669,31 +14977,15 @@ function createTitleBar(ctx, handlers) {
|
|
|
14669
14977
|
ctx.grid()?.focus();
|
|
14670
14978
|
void ctx.commands.run(command.id);
|
|
14671
14979
|
});
|
|
14672
|
-
const label = (control, text3) => {
|
|
14673
|
-
const translated = ctx.t(text3);
|
|
14674
|
-
control.setAttribute("aria-label", translated);
|
|
14675
|
-
control.title = translated;
|
|
14676
|
-
};
|
|
14677
14980
|
const relocalize = () => {
|
|
14678
|
-
label
|
|
14679
|
-
mode.setAttribute("aria-label", ctx.t("Editing mode"));
|
|
14680
|
-
mode.options[0].textContent = ctx.t("Editing");
|
|
14681
|
-
mode.options[1].textContent = ctx.t("Viewing");
|
|
14981
|
+
people.setAttribute("label", ctx.t("People in this session"));
|
|
14682
14982
|
render3();
|
|
14683
14983
|
};
|
|
14684
14984
|
const refresh = () => {
|
|
14685
|
-
|
|
14686
|
-
|
|
14687
|
-
|
|
14688
|
-
if (
|
|
14689
|
-
let pressed = false;
|
|
14690
|
-
try {
|
|
14691
|
-
pressed = showComments.checked?.(ctx) ?? false;
|
|
14692
|
-
} catch {
|
|
14693
|
-
pressed = false;
|
|
14694
|
-
}
|
|
14695
|
-
comments.setAttribute("aria-pressed", String(pressed));
|
|
14696
|
-
}
|
|
14985
|
+
const sharing = handlers.collaboration?.();
|
|
14986
|
+
people.hidden = !sharing?.active;
|
|
14987
|
+
const next = sharing?.active ? participants(sharing) : [];
|
|
14988
|
+
if (JSON.stringify(next) !== JSON.stringify(people.participants)) people.participants = next;
|
|
14697
14989
|
render3();
|
|
14698
14990
|
};
|
|
14699
14991
|
relocalize();
|
|
@@ -14822,6 +15114,11 @@ function buildShell(core) {
|
|
|
14822
15114
|
core.dirty.set(true);
|
|
14823
15115
|
backstage.relocalize();
|
|
14824
15116
|
},
|
|
15117
|
+
share: {
|
|
15118
|
+
state: () => core.collab.state(),
|
|
15119
|
+
start: (roomId) => core.collab.start({ roomId }),
|
|
15120
|
+
stop: () => core.collab.stop()
|
|
15121
|
+
},
|
|
14825
15122
|
hiddenActions: () => core.hiddenActions,
|
|
14826
15123
|
setHiddenActions(ids) {
|
|
14827
15124
|
element.hiddenActions = ids;
|
|
@@ -14841,10 +15138,16 @@ function buildShell(core) {
|
|
|
14841
15138
|
);
|
|
14842
15139
|
safeMount("commands", () => installCommands(ctx));
|
|
14843
15140
|
const ribbon = createRibbon(ctx, { openBackstage: () => backstage.open("info"), isHidden });
|
|
15141
|
+
const ribbonActions = createRibbonActions(ctx, {
|
|
15142
|
+
isHidden,
|
|
15143
|
+
setReadOnly: (readOnly) => element.readOnly = readOnly,
|
|
15144
|
+
collaboration: () => core.collab.state()
|
|
15145
|
+
});
|
|
15146
|
+
ribbon.element.append(ribbonActions.element);
|
|
14844
15147
|
const titleBar = createTitleBar(ctx, {
|
|
14845
15148
|
isHidden,
|
|
14846
15149
|
save: () => void fileCommand("save"),
|
|
14847
|
-
|
|
15150
|
+
collaboration: () => core.collab.state(),
|
|
14848
15151
|
revealControl(id) {
|
|
14849
15152
|
const control = ribbon.element.querySelector(
|
|
14850
15153
|
`.ribbon-panel [data-command="${id.replace(/["\\]/g, "")}"]`
|
|
@@ -14935,10 +15238,12 @@ function buildShell(core) {
|
|
|
14935
15238
|
focusRegion(next);
|
|
14936
15239
|
};
|
|
14937
15240
|
installKeyboard(ctx, actions);
|
|
15241
|
+
element.addEventListener("collaboration-change", () => backstage.refresh("share"));
|
|
14938
15242
|
core.shell = {
|
|
14939
15243
|
render() {
|
|
14940
15244
|
ribbon.refresh();
|
|
14941
15245
|
titleBar.refresh();
|
|
15246
|
+
ribbonActions.refresh();
|
|
14942
15247
|
statusBar.refresh();
|
|
14943
15248
|
chartSeriesPane.refresh();
|
|
14944
15249
|
chartAreaPane.refresh();
|
|
@@ -14954,6 +15259,7 @@ function buildShell(core) {
|
|
|
14954
15259
|
emptyText.textContent = ctx.t("Open a workbook or create a new one from the File tab.");
|
|
14955
15260
|
ribbon.rebuild();
|
|
14956
15261
|
titleBar.relocalize();
|
|
15262
|
+
ribbonActions.relocalize();
|
|
14957
15263
|
statusBar.relocalize();
|
|
14958
15264
|
backstage.relocalize();
|
|
14959
15265
|
chartSeriesPane.relocalize();
|
|
@@ -14972,6 +15278,357 @@ function buildShell(core) {
|
|
|
14972
15278
|
fileCommand
|
|
14973
15279
|
};
|
|
14974
15280
|
}
|
|
15281
|
+
|
|
15282
|
+
// src/xlsx/calc-preparation.ts
|
|
15283
|
+
var SLICE_MS = 8;
|
|
15284
|
+
var QUIET_MS = 250;
|
|
15285
|
+
var ACTIVITY = ["keydown", "wheel", "pointerdown", "touchmove"];
|
|
15286
|
+
function windowScheduler(view) {
|
|
15287
|
+
const clock = () => (view?.performance ?? performance).now();
|
|
15288
|
+
const later = (run, ms) => {
|
|
15289
|
+
const id = setTimeout(run, ms);
|
|
15290
|
+
return () => clearTimeout(id);
|
|
15291
|
+
};
|
|
15292
|
+
return {
|
|
15293
|
+
now: clock,
|
|
15294
|
+
later,
|
|
15295
|
+
afterPaint(run) {
|
|
15296
|
+
if (!view || typeof view.requestAnimationFrame !== "function") return later(run, 0);
|
|
15297
|
+
let cancelTimer;
|
|
15298
|
+
const id = view.requestAnimationFrame(() => {
|
|
15299
|
+
cancelTimer = later(run, 0);
|
|
15300
|
+
});
|
|
15301
|
+
return () => {
|
|
15302
|
+
view.cancelAnimationFrame(id);
|
|
15303
|
+
cancelTimer?.();
|
|
15304
|
+
};
|
|
15305
|
+
},
|
|
15306
|
+
idle(run) {
|
|
15307
|
+
if (view && typeof view.requestIdleCallback === "function") {
|
|
15308
|
+
const id = view.requestIdleCallback(run);
|
|
15309
|
+
return () => view.cancelIdleCallback(id);
|
|
15310
|
+
}
|
|
15311
|
+
const start = clock();
|
|
15312
|
+
return later(() => run({ timeRemaining: () => SLICE_MS - (clock() - start) }), 1);
|
|
15313
|
+
}
|
|
15314
|
+
};
|
|
15315
|
+
}
|
|
15316
|
+
var CalcPreparation = class {
|
|
15317
|
+
constructor(host, busy, scheduler = windowScheduler(host.ownerDocument.defaultView)) {
|
|
15318
|
+
this.busy = busy;
|
|
15319
|
+
this.scheduler = scheduler;
|
|
15320
|
+
const active2 = () => {
|
|
15321
|
+
this.lastActivity = this.scheduler.now();
|
|
15322
|
+
};
|
|
15323
|
+
for (const type of ACTIVITY) host.addEventListener(type, active2, { passive: true });
|
|
15324
|
+
}
|
|
15325
|
+
busy;
|
|
15326
|
+
scheduler;
|
|
15327
|
+
session;
|
|
15328
|
+
cancel;
|
|
15329
|
+
lastActivity = Number.NEGATIVE_INFINITY;
|
|
15330
|
+
/** Prepares `session` (the workbook just opened) after the next paint; stops earlier work. */
|
|
15331
|
+
start(session) {
|
|
15332
|
+
this.stop();
|
|
15333
|
+
if (!session) return;
|
|
15334
|
+
this.session = session;
|
|
15335
|
+
this.cancel = this.scheduler.afterPaint(() => this.next());
|
|
15336
|
+
}
|
|
15337
|
+
stop() {
|
|
15338
|
+
this.cancel?.();
|
|
15339
|
+
this.cancel = void 0;
|
|
15340
|
+
this.session = void 0;
|
|
15341
|
+
}
|
|
15342
|
+
/** Whether work is still waiting (tests and diagnostics). */
|
|
15343
|
+
get pending() {
|
|
15344
|
+
return this.session !== void 0;
|
|
15345
|
+
}
|
|
15346
|
+
next() {
|
|
15347
|
+
this.cancel = this.scheduler.idle((deadline) => this.slice(deadline));
|
|
15348
|
+
}
|
|
15349
|
+
slice(deadline) {
|
|
15350
|
+
this.cancel = void 0;
|
|
15351
|
+
const session = this.session;
|
|
15352
|
+
if (!session) return;
|
|
15353
|
+
const quietFor = this.scheduler.now() - this.lastActivity;
|
|
15354
|
+
if (this.busy() || quietFor < QUIET_MS) {
|
|
15355
|
+
const wait = Math.max(QUIET_MS - quietFor, 50);
|
|
15356
|
+
this.cancel = this.scheduler.later(() => this.next(), wait);
|
|
15357
|
+
return;
|
|
15358
|
+
}
|
|
15359
|
+
const end = this.scheduler.now() + Math.min(SLICE_MS, Math.max(deadline.timeRemaining(), 1));
|
|
15360
|
+
let done = true;
|
|
15361
|
+
try {
|
|
15362
|
+
done = session.prepareCalculation({ timeRemaining: () => end - this.scheduler.now() });
|
|
15363
|
+
} catch {
|
|
15364
|
+
}
|
|
15365
|
+
if (done) this.session = void 0;
|
|
15366
|
+
else this.next();
|
|
15367
|
+
}
|
|
15368
|
+
};
|
|
15369
|
+
|
|
15370
|
+
// src/xlsx/collaboration-session.ts
|
|
15371
|
+
function createRoomSession(collab, xlsx, options, defaultName) {
|
|
15372
|
+
const roomId = options.roomId ?? "";
|
|
15373
|
+
if (!collab.isValidRoomId(roomId))
|
|
15374
|
+
throw new Error("Use 1 to 128 letters, digits, hyphens or underscores for the room name.");
|
|
15375
|
+
let provider = options.provider;
|
|
15376
|
+
if (!provider && options.serverUrl)
|
|
15377
|
+
provider = collab.transportProvider({
|
|
15378
|
+
transport: collab.createWebSocketTransport({
|
|
15379
|
+
url: collab.roomUrl(options.serverUrl, roomId)
|
|
15380
|
+
})
|
|
15381
|
+
});
|
|
15382
|
+
if (!provider) {
|
|
15383
|
+
if (!collab.canBroadcast())
|
|
15384
|
+
throw new Error("This browser cannot share between windows; pass a server URL.");
|
|
15385
|
+
provider = collab.transportProvider({
|
|
15386
|
+
transport: collab.createBroadcastTransport({ roomId, prefix: "ooxml-xlsx:" })
|
|
15387
|
+
});
|
|
15388
|
+
}
|
|
15389
|
+
const user = options.user ?? {};
|
|
15390
|
+
return collab.createCollabSession({
|
|
15391
|
+
roomId,
|
|
15392
|
+
provider,
|
|
15393
|
+
user: {
|
|
15394
|
+
name: user.name || defaultName,
|
|
15395
|
+
...user.color ? { color: user.color } : {},
|
|
15396
|
+
...user.role ? { role: user.role } : {}
|
|
15397
|
+
},
|
|
15398
|
+
initialPresence: {},
|
|
15399
|
+
sanitizePayload: xlsx.sanitizeXlsxPresence,
|
|
15400
|
+
teardown: true
|
|
15401
|
+
});
|
|
15402
|
+
}
|
|
15403
|
+
|
|
15404
|
+
// src/xlsx/collaboration-types.ts
|
|
15405
|
+
var OFF_STATE = Object.freeze({
|
|
15406
|
+
active: false,
|
|
15407
|
+
roomId: void 0,
|
|
15408
|
+
status: "off",
|
|
15409
|
+
synced: false,
|
|
15410
|
+
people: []
|
|
15411
|
+
});
|
|
15412
|
+
|
|
15413
|
+
// src/xlsx/collaboration.ts
|
|
15414
|
+
var loadRuntime = () => Promise.all([import('ooxml-core/collab'), import('ooxml-core/xlsx/collab')]);
|
|
15415
|
+
function presenceRange(selection) {
|
|
15416
|
+
const { row: row2, col } = selection.active;
|
|
15417
|
+
const holding = selection.ranges.find(
|
|
15418
|
+
(r) => row2 >= r.start.row && row2 <= r.end.row && col >= r.start.col && col <= r.end.col
|
|
15419
|
+
);
|
|
15420
|
+
return holding ?? selection.ranges[selection.ranges.length - 1] ?? {
|
|
15421
|
+
start: selection.active,
|
|
15422
|
+
end: selection.active
|
|
15423
|
+
};
|
|
15424
|
+
}
|
|
15425
|
+
var XlsxCollaboration = class {
|
|
15426
|
+
constructor(host, load = loadRuntime) {
|
|
15427
|
+
this.host = host;
|
|
15428
|
+
this.load = load;
|
|
15429
|
+
}
|
|
15430
|
+
host;
|
|
15431
|
+
load;
|
|
15432
|
+
#active;
|
|
15433
|
+
#starting;
|
|
15434
|
+
/** Bumped by every stop, so a join still loading the runtime is abandoned. */
|
|
15435
|
+
#epoch = 0;
|
|
15436
|
+
#wanted;
|
|
15437
|
+
#lost = false;
|
|
15438
|
+
#connected = false;
|
|
15439
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
15440
|
+
get active() {
|
|
15441
|
+
return this.#active !== void 0;
|
|
15442
|
+
}
|
|
15443
|
+
/** Joined or joining. */
|
|
15444
|
+
get busy() {
|
|
15445
|
+
return this.#active !== void 0 || this.#starting !== void 0;
|
|
15446
|
+
}
|
|
15447
|
+
/** The options of the declarative `collaboration` property, if set. */
|
|
15448
|
+
get wanted() {
|
|
15449
|
+
return this.#wanted;
|
|
15450
|
+
}
|
|
15451
|
+
/**
|
|
15452
|
+
* Declarative sharing: while set, the open workbook is shared in that room, and a workbook
|
|
15453
|
+
* opened later joins it too (the room's content wins when it already has one). Undefined stops.
|
|
15454
|
+
*/
|
|
15455
|
+
want(options) {
|
|
15456
|
+
if (options === this.#wanted) return;
|
|
15457
|
+
this.#wanted = options;
|
|
15458
|
+
this.#leave();
|
|
15459
|
+
this.resume();
|
|
15460
|
+
}
|
|
15461
|
+
/** Leaves the room before the workbook is replaced; true when it was shared. */
|
|
15462
|
+
suspend() {
|
|
15463
|
+
const was = this.busy;
|
|
15464
|
+
this.#leave();
|
|
15465
|
+
return was;
|
|
15466
|
+
}
|
|
15467
|
+
/** Joins the wanted room with the workbook now open. */
|
|
15468
|
+
resume() {
|
|
15469
|
+
const wanted = this.#wanted;
|
|
15470
|
+
if (!wanted || this.busy || !this.host.edit()) return;
|
|
15471
|
+
this.start(wanted).catch((error) => {
|
|
15472
|
+
const failure = asError(error);
|
|
15473
|
+
this.host.toast(this.host.t(failure.message), "error");
|
|
15474
|
+
this.host.error(failure);
|
|
15475
|
+
});
|
|
15476
|
+
}
|
|
15477
|
+
/** Joins a room. Rejects when one is active, no workbook is open or the room is invalid. */
|
|
15478
|
+
start(options) {
|
|
15479
|
+
if (this.#active || this.#starting)
|
|
15480
|
+
return Promise.reject(new Error("Stop the current collaboration session first."));
|
|
15481
|
+
const starting = this.#start(options).finally(() => {
|
|
15482
|
+
if (this.#starting === starting) this.#starting = void 0;
|
|
15483
|
+
});
|
|
15484
|
+
this.#starting = starting;
|
|
15485
|
+
return starting;
|
|
15486
|
+
}
|
|
15487
|
+
async #start(options) {
|
|
15488
|
+
if (!this.host.edit()) throw new Error("Open or create a workbook before sharing it.");
|
|
15489
|
+
const epoch = this.#epoch;
|
|
15490
|
+
const [collab, xlsx] = await this.load();
|
|
15491
|
+
if (epoch !== this.#epoch) return;
|
|
15492
|
+
const edit = this.host.edit();
|
|
15493
|
+
if (!edit) throw new Error("Open or create a workbook before sharing it.");
|
|
15494
|
+
const session = options.session ?? createRoomSession(collab, xlsx, options, this.host.userName());
|
|
15495
|
+
const binding = xlsx.bindWorkbookSession(session, edit, {
|
|
15496
|
+
onError: (error) => this.host.error(asError(error))
|
|
15497
|
+
});
|
|
15498
|
+
const active2 = { session, binding, owned: !options.session, stop: [] };
|
|
15499
|
+
this.#active = active2;
|
|
15500
|
+
this.#lost = false;
|
|
15501
|
+
this.#connected = session.status === "connected";
|
|
15502
|
+
const publish = (selection) => binding.setSelection(selection.sheet, presenceRange(selection));
|
|
15503
|
+
active2.stop.push(
|
|
15504
|
+
this.host.selection.onChange(publish),
|
|
15505
|
+
session.on("peers", () => this.#changed()),
|
|
15506
|
+
session.on("synced", () => this.#changed()),
|
|
15507
|
+
session.on("status", (status) => this.#status(status)),
|
|
15508
|
+
session.on("error", (error) => this.host.error(error)),
|
|
15509
|
+
edit.onChange((change) => {
|
|
15510
|
+
if (change.external) this.#notify();
|
|
15511
|
+
})
|
|
15512
|
+
);
|
|
15513
|
+
if (session.role === "viewer") this.host.setReadOnly(true);
|
|
15514
|
+
publish(this.host.selection.get());
|
|
15515
|
+
this.#changed();
|
|
15516
|
+
}
|
|
15517
|
+
/**
|
|
15518
|
+
* Leaves the room and forgets the `collaboration` property. A session the host passed in stays
|
|
15519
|
+
* alive; one the editor made is destroyed.
|
|
15520
|
+
*/
|
|
15521
|
+
stop() {
|
|
15522
|
+
this.#wanted = void 0;
|
|
15523
|
+
this.#leave();
|
|
15524
|
+
}
|
|
15525
|
+
#leave() {
|
|
15526
|
+
this.#epoch++;
|
|
15527
|
+
this.#starting = void 0;
|
|
15528
|
+
const active2 = this.#active;
|
|
15529
|
+
if (!active2) return;
|
|
15530
|
+
this.#active = void 0;
|
|
15531
|
+
for (const stop of active2.stop) stop();
|
|
15532
|
+
active2.binding.dispose();
|
|
15533
|
+
if (active2.owned) active2.session.destroy();
|
|
15534
|
+
this.#changed();
|
|
15535
|
+
}
|
|
15536
|
+
/** Restarts the connection, keeping the shared workbook and queued changes. */
|
|
15537
|
+
reconnect() {
|
|
15538
|
+
this.#active?.session.reconnect();
|
|
15539
|
+
}
|
|
15540
|
+
/** The binding's history while shared (only this window's edits), else undefined. */
|
|
15541
|
+
history() {
|
|
15542
|
+
const binding = this.#active?.binding;
|
|
15543
|
+
if (!binding) return void 0;
|
|
15544
|
+
return {
|
|
15545
|
+
undo: () => binding.undo(),
|
|
15546
|
+
redo: () => binding.redo(),
|
|
15547
|
+
canUndo: () => binding.canUndo(),
|
|
15548
|
+
canRedo: () => binding.canRedo(),
|
|
15549
|
+
undoLabel: () => void 0,
|
|
15550
|
+
redoLabel: () => void 0
|
|
15551
|
+
};
|
|
15552
|
+
}
|
|
15553
|
+
remoteSelections() {
|
|
15554
|
+
return this.#active?.binding.remoteSelections() ?? [];
|
|
15555
|
+
}
|
|
15556
|
+
onRemoteChange(listener) {
|
|
15557
|
+
this.#listeners.add(listener);
|
|
15558
|
+
return () => {
|
|
15559
|
+
this.#listeners.delete(listener);
|
|
15560
|
+
};
|
|
15561
|
+
}
|
|
15562
|
+
state() {
|
|
15563
|
+
const active2 = this.#active;
|
|
15564
|
+
if (!active2) return OFF_STATE;
|
|
15565
|
+
const { session } = active2;
|
|
15566
|
+
return {
|
|
15567
|
+
active: true,
|
|
15568
|
+
roomId: session.roomId,
|
|
15569
|
+
status: session.status,
|
|
15570
|
+
synced: session.synced,
|
|
15571
|
+
people: [
|
|
15572
|
+
{
|
|
15573
|
+
clientId: session.clientId,
|
|
15574
|
+
name: session.identity.userName,
|
|
15575
|
+
color: session.identity.userColor,
|
|
15576
|
+
self: true
|
|
15577
|
+
},
|
|
15578
|
+
...session.peers().map((peer) => ({
|
|
15579
|
+
clientId: peer.clientId,
|
|
15580
|
+
name: peer.userName,
|
|
15581
|
+
color: peer.userColor,
|
|
15582
|
+
self: false
|
|
15583
|
+
}))
|
|
15584
|
+
]
|
|
15585
|
+
};
|
|
15586
|
+
}
|
|
15587
|
+
#status(status) {
|
|
15588
|
+
const { t } = this.host;
|
|
15589
|
+
if (status === "connected") {
|
|
15590
|
+
if (this.#lost)
|
|
15591
|
+
this.host.toast(t("Reconnected. Changes made while offline were sent."), "info");
|
|
15592
|
+
this.#lost = false;
|
|
15593
|
+
this.#connected = true;
|
|
15594
|
+
} else if ((status === "disconnected" || status === "error") && this.#connected && !this.#lost) {
|
|
15595
|
+
this.#lost = true;
|
|
15596
|
+
this.host.toast(
|
|
15597
|
+
t("Connection lost. Keep working; your changes are sent when it returns."),
|
|
15598
|
+
"warning"
|
|
15599
|
+
);
|
|
15600
|
+
}
|
|
15601
|
+
this.#changed();
|
|
15602
|
+
}
|
|
15603
|
+
#notify() {
|
|
15604
|
+
for (const listener of [...this.#listeners]) listener();
|
|
15605
|
+
}
|
|
15606
|
+
#changed() {
|
|
15607
|
+
this.#notify();
|
|
15608
|
+
this.host.changed(this.state());
|
|
15609
|
+
}
|
|
15610
|
+
};
|
|
15611
|
+
function collaborationFor(core) {
|
|
15612
|
+
const { host } = core;
|
|
15613
|
+
return new XlsxCollaboration({
|
|
15614
|
+
edit: () => core.session,
|
|
15615
|
+
selection: core.selection,
|
|
15616
|
+
userName: () => core.authorName,
|
|
15617
|
+
t: core.ctx.t,
|
|
15618
|
+
toast: (message, kind) => core.shell?.toast(message, kind),
|
|
15619
|
+
error: (error) => emit(host, "workbook-error", { error, message: error.message }),
|
|
15620
|
+
changed: (state) => {
|
|
15621
|
+
emit(host, "collaboration-change", state);
|
|
15622
|
+
core.requestRender();
|
|
15623
|
+
},
|
|
15624
|
+
setReadOnly: (readOnly) => core.setReadOnly(readOnly)
|
|
15625
|
+
});
|
|
15626
|
+
}
|
|
15627
|
+
function asError(error) {
|
|
15628
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
15629
|
+
}
|
|
15630
|
+
|
|
15631
|
+
// src/xlsx/editor-core.ts
|
|
14975
15632
|
var EditorCore = class {
|
|
14976
15633
|
constructor(host) {
|
|
14977
15634
|
this.host = host;
|
|
@@ -15008,6 +15665,8 @@ var EditorCore = class {
|
|
|
15008
15665
|
this.requestRender();
|
|
15009
15666
|
});
|
|
15010
15667
|
this.ctx = this.createContext();
|
|
15668
|
+
this.collab = collaborationFor(this);
|
|
15669
|
+
this.calcPreparation = new CalcPreparation(host, () => !!this.gridController?.isEditing());
|
|
15011
15670
|
}
|
|
15012
15671
|
host;
|
|
15013
15672
|
workbook;
|
|
@@ -15031,6 +15690,10 @@ var EditorCore = class {
|
|
|
15031
15690
|
dialogs;
|
|
15032
15691
|
dirty;
|
|
15033
15692
|
ctx;
|
|
15693
|
+
/** Co-editing over `ooxml-core/collab`; undo and redo go through it while shared. */
|
|
15694
|
+
collab;
|
|
15695
|
+
/** Builds the formula graph in idle time after a workbook opens. */
|
|
15696
|
+
calcPreparation;
|
|
15034
15697
|
gridController;
|
|
15035
15698
|
modelListeners = /* @__PURE__ */ new Set();
|
|
15036
15699
|
stopSession;
|
|
@@ -15081,7 +15744,10 @@ var EditorCore = class {
|
|
|
15081
15744
|
return emitEvent(core.host, type, detail);
|
|
15082
15745
|
},
|
|
15083
15746
|
authorName: () => core.authorName,
|
|
15084
|
-
locale: () => core.locale
|
|
15747
|
+
locale: () => core.locale,
|
|
15748
|
+
history: () => core.collab.history() ?? core.session,
|
|
15749
|
+
remoteSelections: () => core.collab.remoteSelections(),
|
|
15750
|
+
onRemoteSelectionsChange: (listener) => core.collab.onRemoteChange(listener)
|
|
15085
15751
|
};
|
|
15086
15752
|
}
|
|
15087
15753
|
/** Debounced refresh of the ribbon, title bar and status bar. */
|
|
@@ -15109,6 +15775,8 @@ var EditorCore = class {
|
|
|
15109
15775
|
}
|
|
15110
15776
|
/** Replaces the workbook (load, new, template, property), with a fresh edit session. */
|
|
15111
15777
|
setWorkbook(workbook) {
|
|
15778
|
+
if (this.collab.suspend() && !this.collab.wanted)
|
|
15779
|
+
this.shell?.toast(this.ctx.t("Sharing stopped because another workbook was opened."));
|
|
15112
15780
|
this.savePassword = void 0;
|
|
15113
15781
|
this.stopSession?.();
|
|
15114
15782
|
this.stopSession = void 0;
|
|
@@ -15122,6 +15790,7 @@ var EditorCore = class {
|
|
|
15122
15790
|
}
|
|
15123
15791
|
}
|
|
15124
15792
|
this.stopSession = this.session?.onChange((change) => this.onSessionChange(change));
|
|
15793
|
+
this.calcPreparation.start(this.session);
|
|
15125
15794
|
const sheets = workbook?.sheets.length ?? 0;
|
|
15126
15795
|
const preferred = workbook?.activeSheet ?? 0;
|
|
15127
15796
|
this.activeSheet = Math.min(Math.max(0, preferred), Math.max(0, sheets - 1));
|
|
@@ -15134,6 +15803,7 @@ var EditorCore = class {
|
|
|
15134
15803
|
this.selection.set(initialSelection(this.activeSheet, workbook));
|
|
15135
15804
|
this.dirty.set(false);
|
|
15136
15805
|
this.notifyModel({ kind: "load" });
|
|
15806
|
+
this.collab.resume();
|
|
15137
15807
|
}
|
|
15138
15808
|
createSession(workbook) {
|
|
15139
15809
|
try {
|
|
@@ -15247,6 +15917,8 @@ var XlsxEditorApi = class extends HTMLElementBase {
|
|
|
15247
15917
|
core = new EditorCore(this);
|
|
15248
15918
|
/** Set by the shell once connected. */
|
|
15249
15919
|
chrome;
|
|
15920
|
+
/** Set by the shell once connected: opens File > Share. */
|
|
15921
|
+
openShare;
|
|
15250
15922
|
/** Opens .xlsx, .xlsm, .xltx, .xls or .csv bytes; `fileName` helps detection and names the file. */
|
|
15251
15923
|
async load(bytes, fileName) {
|
|
15252
15924
|
await loadInto(this.core, bytes, fileName, this.chrome);
|
|
@@ -15300,6 +15972,31 @@ var XlsxEditorApi = class extends HTMLElementBase {
|
|
|
15300
15972
|
setActiveSheet(index) {
|
|
15301
15973
|
this.core.setActiveSheet(index);
|
|
15302
15974
|
}
|
|
15975
|
+
/**
|
|
15976
|
+
* Shares the open workbook in a room (see `XlsxCollaborationOptions`). Resolves once joined;
|
|
15977
|
+
* the room's workbook replaces this one when the room already has one. Rejects when sharing is
|
|
15978
|
+
* already active or no workbook is open.
|
|
15979
|
+
*/
|
|
15980
|
+
startCollaboration(options) {
|
|
15981
|
+
return this.core.collab.start(options);
|
|
15982
|
+
}
|
|
15983
|
+
/** Leaves the room (and clears `collaboration`). The workbook stays as it is. */
|
|
15984
|
+
stopCollaboration() {
|
|
15985
|
+
this.core.collab.stop();
|
|
15986
|
+
}
|
|
15987
|
+
/** Restarts the connection, keeping the shared workbook and changes made offline. */
|
|
15988
|
+
reconnectCollaboration() {
|
|
15989
|
+
this.core.collab.reconnect();
|
|
15990
|
+
}
|
|
15991
|
+
/** Who is in the room and how the connection is. */
|
|
15992
|
+
get collaborationState() {
|
|
15993
|
+
return this.core.collab.state();
|
|
15994
|
+
}
|
|
15995
|
+
/** Opens File > Share, where the user starts or stops sharing and sees who is in the room. */
|
|
15996
|
+
share() {
|
|
15997
|
+
this.openShare?.();
|
|
15998
|
+
}
|
|
15999
|
+
/** Undo the last edit; while shared, only this window's edits are undone. */
|
|
15303
16000
|
undo() {
|
|
15304
16001
|
void this.core.commands.run("edit.undo");
|
|
15305
16002
|
}
|
|
@@ -15323,6 +16020,7 @@ var XlsxEditorElement = class extends XlsxEditorApi {
|
|
|
15323
16020
|
if (this.shell) return;
|
|
15324
16021
|
this.shell = buildShell(this.core);
|
|
15325
16022
|
this.chrome = this.shell.chrome;
|
|
16023
|
+
this.openShare = () => this.shell?.backstage.open("share");
|
|
15326
16024
|
this.core.requestRender();
|
|
15327
16025
|
}
|
|
15328
16026
|
attributeChangedCallback(name, _old, value) {
|
|
@@ -15417,6 +16115,17 @@ var XlsxEditorElement = class extends XlsxEditorApi {
|
|
|
15417
16115
|
get dirty() {
|
|
15418
16116
|
return this.core.dirty.dirty;
|
|
15419
16117
|
}
|
|
16118
|
+
/**
|
|
16119
|
+
* Shares the open workbook in a room while set: a workbook opened later joins the same room
|
|
16120
|
+
* (the room's content wins when it already has a workbook); `null` leaves it. A window joining
|
|
16121
|
+
* an existing room still needs a workbook open (`newWorkbook()` is enough).
|
|
16122
|
+
*/
|
|
16123
|
+
get collaboration() {
|
|
16124
|
+
return this.core.collab.wanted ?? null;
|
|
16125
|
+
}
|
|
16126
|
+
set collaboration(value) {
|
|
16127
|
+
this.core.collab.want(value ?? void 0);
|
|
16128
|
+
}
|
|
15420
16129
|
get activeSheet() {
|
|
15421
16130
|
return this.core.activeSheet;
|
|
15422
16131
|
}
|