ooxml-ui 1.0.0 → 1.2.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 +40 -36
- package/custom-elements.json +211 -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-T3HB5LMH.js → chunk-7FNDOWTX.js} +393 -15
- package/dist/{chunk-FLHM5Q4O.js → chunk-AYXFLBSV.js} +92 -13
- package/dist/{chunk-X7RINDJQ.js → chunk-JAJFLFAV.js} +1 -1
- package/dist/{chunk-OXKWNNNJ.js → chunk-VUB44CAJ.js} +1 -1
- package/dist/{chunk-JFJXBYRD.js → chunk-XNCWB2X6.js} +5 -0
- package/dist/{chunk-XDUYS4KK.js → chunk-Y2E22JVO.js} +1 -1
- package/dist/{chunk-ZV2Z4IWH.js → chunk-YK2DPYMU.js} +5 -2
- package/dist/{chunk-4QQASR5A.js → chunk-YP5S7DTT.js} +6 -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 +4 -2
- package/dist/controls.d.ts.map +1 -1
- package/dist/controls.js +4 -4
- package/dist/docx/comments-panel.d.ts +8 -1
- package/dist/docx/image-media.d.ts +1 -1
- package/dist/docx/locales/en-ribbon.d.ts +1 -0
- package/dist/docx/locales/en.d.ts +1 -0
- package/dist/docx/localization-strings.d.ts +2 -1
- package/dist/docx/localization.d.ts +7 -1
- 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/ruler.d.ts +7 -10
- package/dist/docx.js +289 -339
- package/dist/form/gradient-preset-gallery.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -8
- package/dist/pptx/{chart-3d-view-scene-2KRQ5667.mjs → chart-3d-view-scene-6B5TOWB6.mjs} +3 -3
- package/dist/pptx/{chart-3d-view-scene-36DMZWZ3.cjs → chart-3d-view-scene-MJ6YNT56.cjs} +37 -37
- package/dist/pptx/{chunk-YOGDIDPB.mjs → chunk-AWKKC3VW.mjs} +8 -2
- package/dist/pptx/{chunk-XQZWZMGZ.cjs → chunk-SM3CWDIQ.cjs} +7 -17
- package/dist/pptx/{chunk-CJU4P5FT.cjs → chunk-STKGUT5S.cjs} +18 -12
- package/dist/pptx/{chunk-JSBGBVBH.mjs → chunk-VRFNAF3Q.mjs} +7 -17
- package/dist/pptx/{chunk-YHA6XAB3.cjs → chunk-XIQMFSNG.cjs} +1 -1
- package/dist/pptx/{chunk-YARCML7O.mjs → chunk-XQVKQD5Z.mjs} +294 -265
- package/dist/pptx/{chunk-XWE5GSE7.mjs → chunk-YI5LH5NN.mjs} +533 -428
- package/dist/pptx/{chunk-ADOC5JLI.mjs → chunk-YMTQLZ2I.mjs} +1 -1
- package/dist/pptx/{chunk-AIL3BNZS.cjs → chunk-YRHK45AB.cjs} +301 -265
- package/dist/pptx/{chunk-FEFQTZDM.cjs → chunk-ZK344LOB.cjs} +689 -574
- 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/table.d.ts.map +1 -1
- package/dist/pptx/dom/index.cjs +257 -246
- package/dist/pptx/dom/index.mjs +28 -17
- package/dist/pptx/export/html2canvas-clone.cjs +2 -2
- package/dist/pptx/export/html2canvas-clone.mjs +1 -1
- package/dist/pptx/i18n/index.cjs +6 -6
- package/dist/pptx/i18n/index.mjs +1 -1
- package/dist/pptx/i18n/translator.d.ts.map +1 -1
- package/dist/pptx/index.cjs +3035 -2991
- package/dist/pptx/index.mjs +5 -5
- 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-cartesian-axes.d.ts.map +1 -1
- package/dist/pptx/render/chart-cartesian-bars.d.ts +3 -3
- package/dist/pptx/render/chart-cartesian-bars.d.ts.map +1 -1
- package/dist/pptx/render/chart-cartesian-percent-stacked.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-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-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-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 +31 -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/connector-elbow-geometry.d.ts +7 -43
- package/dist/pptx/render/connector-elbow-geometry.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 +2 -0
- package/dist/pptx/render/index.d.ts.map +1 -1
- 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.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 +54 -0
- package/dist/pptx/render/viewer-root-options.d.ts.map +1 -0
- package/dist/pptx/web-components/office-token-bridge.d.ts.map +1 -1
- package/dist/pptx/web-components/registration-contract.d.ts.map +1 -1
- package/dist/presence.js +3 -3
- package/dist/registry.d.ts +2 -0
- package/dist/registry.d.ts.map +1 -1
- 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 +6 -6
- package/dist/theme.js +2 -2
- package/dist/tokens.d.ts +5 -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 +76 -25
- 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/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 +3 -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 +21 -0
- package/dist/xlsx/shell-commands.d.ts +1 -1
- package/dist/xlsx/title-bar.d.ts +4 -2
- package/dist/xlsx.js +712 -90
- package/package.json +3 -3
- 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-YP5S7DTT.js';
|
|
2
|
+
import { defineSmartArt } from './chunk-Y2E22JVO.js';
|
|
3
|
+
import { withExtension, saveExtension, downloadBytes, emit, emitEvent, blobFor, announceFileCommand, pickFile } from './chunk-AYXFLBSV.js';
|
|
4
|
+
export { XLSX_EDITOR_EVENTS } from './chunk-AYXFLBSV.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-
|
|
6
|
+
import { shadcnBridge } from './chunk-JAJFLFAV.js';
|
|
7
|
+
import { range_control_default, createRibbonOverflow, defineBackstage, defineRibbon, defineTitleBar, defineStatusBar, defineZoomSlider, rangeControl, defineDialog, runKeyTips, assignKeyTips, defineCheckbox, defineGallery, defineContextMenu, defineCommentsPane, parseSvgPreview } from './chunk-7FNDOWTX.js';
|
|
8
8
|
import { getIcon, registerIcon } from './chunk-BOX43CZD.js';
|
|
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';
|
|
9
|
+
import { definePresence } from './chunk-VUB44CAJ.js';
|
|
10
|
+
import { withTokens } from './chunk-YK2DPYMU.js';
|
|
11
|
+
import './chunk-XNCWB2X6.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, 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.xve-
|
|
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/* Ribbon tab row, right end (the shared ribbon's actions slot): Editing / Viewing, Comments and\n Share, as Excel 365 places them. */\n.xve-ribbon-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n padding-inline-start: 8px;\n}\n.xve-mode {\n position: relative;\n display: inline-flex;\n align-items: center;\n height: 28px;\n border-radius: 4px;\n color: var(--ink);\n}\n.xve-mode > .ribbon-icon {\n position: absolute;\n inset-inline-start: 8px;\n pointer-events: none;\n}\n.xve-mode-select {\n height: 28px;\n padding: 0 6px 0 30px;\n border: 1px solid var(--line);\n border-radius: 4px;\n background: var(--surface);\n color: var(--ink);\n font: inherit;\n cursor: pointer;\n}\n.xve-comments-button {\n gap: 6px;\n border: 1px solid var(--line);\n}\n.xve-share-button {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 28px;\n padding: 0 12px;\n border: 1px solid var(--xl);\n border-radius: 4px;\n background: var(--xl);\n color: var(--xve-primary-foreground);\n font: inherit;\n cursor: pointer;\n}\n.xve-share-button:hover,\n.xve-share-button[aria-pressed='true'] {\n border-color: var(--xl-strong);\n background: var(--xl-strong);\n}\n.xve-mode-select:focus-visible,\n.xve-comments-button:focus-visible,\n.xve-share-button:focus-visible {\n outline: 2px solid var(--xl);\n outline-offset: 1px;\n}\n/* Narrow windows keep the icons and drop the labels, as Office's simplified layout does. */\n@media (max-width: 900px) {\n .xve-action-label {\n display: none;\n }\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,58 @@ 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
|
+
const element = el2(doc, "div", "xve-ribbon-actions");
|
|
14609
|
+
element.slot = "actions";
|
|
14610
|
+
const modeBox = el2(doc, "label", "xve-mode");
|
|
14611
|
+
const mode = el2(doc, "select", "xve-mode-select");
|
|
14612
|
+
mode.append(new Option("", "editing"), new Option("", "viewing"));
|
|
14613
|
+
mode.addEventListener("change", () => handlers.setReadOnly(mode.value === "viewing"));
|
|
14614
|
+
modeBox.append(ribbonIcon(doc, "pencil", 16), mode);
|
|
14615
|
+
const labelled2 = (className, icon7) => {
|
|
14616
|
+
const button2 = el2(doc, "button", className);
|
|
14617
|
+
button2.type = "button";
|
|
14618
|
+
const text3 = el2(doc, "span", "xve-action-label");
|
|
14619
|
+
button2.append(ribbonIcon(doc, icon7, 16), text3);
|
|
14620
|
+
return { button: button2, text: text3 };
|
|
14621
|
+
};
|
|
14622
|
+
const comments = labelled2("xve-icon-button xve-comments-button", "comments");
|
|
14623
|
+
comments.button.addEventListener("click", () => void ctx.commands.run("review.show-comments"));
|
|
14624
|
+
const share = labelled2("xve-share-button", "share");
|
|
14625
|
+
share.button.addEventListener("click", () => void ctx.commands.run("file.share"));
|
|
14626
|
+
element.append(modeBox, comments.button, share.button);
|
|
14627
|
+
const relocalize = () => {
|
|
14628
|
+
mode.setAttribute("aria-label", ctx.t("Editing mode"));
|
|
14629
|
+
mode.title = ctx.t("Editing mode");
|
|
14630
|
+
mode.options[0].textContent = ctx.t("Editing");
|
|
14631
|
+
mode.options[1].textContent = ctx.t("Viewing");
|
|
14632
|
+
comments.text.textContent = ctx.t("Comments");
|
|
14633
|
+
comments.button.title = ctx.t("Show comments");
|
|
14634
|
+
share.text.textContent = ctx.t("Share");
|
|
14635
|
+
share.button.title = ctx.t("Share");
|
|
14636
|
+
refresh();
|
|
14637
|
+
};
|
|
14638
|
+
const refresh = () => {
|
|
14639
|
+
mode.value = ctx.readOnly() ? "viewing" : "editing";
|
|
14640
|
+
share.button.hidden = !ctx.commands.get("file.share") || handlers.isHidden("file.share");
|
|
14641
|
+
share.button.setAttribute("aria-pressed", String(Boolean(handlers.collaboration?.().active)));
|
|
14642
|
+
const showComments = ctx.commands.get("review.show-comments");
|
|
14643
|
+
comments.button.hidden = !showComments;
|
|
14644
|
+
if (!showComments) return;
|
|
14645
|
+
let pressed = false;
|
|
14646
|
+
try {
|
|
14647
|
+
pressed = showComments.checked?.(ctx) ?? false;
|
|
14648
|
+
} catch {
|
|
14649
|
+
pressed = false;
|
|
14650
|
+
}
|
|
14651
|
+
comments.button.setAttribute("aria-pressed", String(pressed));
|
|
14652
|
+
};
|
|
14653
|
+
relocalize();
|
|
14654
|
+
return { element, refresh, relocalize };
|
|
14655
|
+
}
|
|
14344
14656
|
var hasWorkbook = (ctx) => Boolean(ctx.workbook());
|
|
14345
14657
|
function adjacentSheet(ctx, step2) {
|
|
14346
14658
|
const sheets = ctx.workbook()?.sheets ?? [];
|
|
@@ -14372,6 +14684,12 @@ function shellCommands(handlers) {
|
|
|
14372
14684
|
run: () => handlers.openBackstage("saveAs")
|
|
14373
14685
|
},
|
|
14374
14686
|
{ id: "file.info", label: "Info", icon: "info", run: () => handlers.openBackstage("info") },
|
|
14687
|
+
{
|
|
14688
|
+
id: "file.share",
|
|
14689
|
+
label: "Share",
|
|
14690
|
+
icon: "share",
|
|
14691
|
+
run: () => handlers.openBackstage("share")
|
|
14692
|
+
},
|
|
14375
14693
|
{
|
|
14376
14694
|
id: "file.options",
|
|
14377
14695
|
label: "Options",
|
|
@@ -14384,8 +14702,8 @@ function shellCommands(handlers) {
|
|
|
14384
14702
|
icon: "undo",
|
|
14385
14703
|
shortcut: "Ctrl+Z",
|
|
14386
14704
|
editing: true,
|
|
14387
|
-
enabled: (ctx) => ctx
|
|
14388
|
-
run: (ctx) => void ctx
|
|
14705
|
+
enabled: (ctx) => historyOf(ctx)?.canUndo() ?? false,
|
|
14706
|
+
run: (ctx) => void historyOf(ctx)?.undo()
|
|
14389
14707
|
},
|
|
14390
14708
|
{
|
|
14391
14709
|
id: "edit.redo",
|
|
@@ -14393,8 +14711,8 @@ function shellCommands(handlers) {
|
|
|
14393
14711
|
icon: "redo",
|
|
14394
14712
|
shortcut: "Ctrl+Y",
|
|
14395
14713
|
editing: true,
|
|
14396
|
-
enabled: (ctx) => ctx
|
|
14397
|
-
run: (ctx) => void ctx
|
|
14714
|
+
enabled: (ctx) => historyOf(ctx)?.canRedo() ?? false,
|
|
14715
|
+
run: (ctx) => void historyOf(ctx)?.redo()
|
|
14398
14716
|
},
|
|
14399
14717
|
{
|
|
14400
14718
|
id: "sheet.next",
|
|
@@ -14517,7 +14835,7 @@ function createStatusBar(ctx, handlers) {
|
|
|
14517
14835
|
element.setAttribute("part", "status-bar");
|
|
14518
14836
|
element.setAttribute("role", "status");
|
|
14519
14837
|
const stats = el2(doc, "span", "xve-status-stats");
|
|
14520
|
-
stats.slot = "
|
|
14838
|
+
stats.slot = "summary";
|
|
14521
14839
|
const shown2 = /* @__PURE__ */ new Set(["average", "count", "sum"]);
|
|
14522
14840
|
stats.addEventListener("contextmenu", (event) => {
|
|
14523
14841
|
event.preventDefault();
|
|
@@ -14603,22 +14921,17 @@ function createTitleBar(ctx, handlers) {
|
|
|
14603
14921
|
const element = doc.createElement("office-ui-title-bar");
|
|
14604
14922
|
element.className = "xve-titlebar";
|
|
14605
14923
|
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);
|
|
14924
|
+
definePresence();
|
|
14925
|
+
const people = doc.createElement("office-ui-presence");
|
|
14926
|
+
people.className = "xve-title-people";
|
|
14927
|
+
people.slot = "collaboration";
|
|
14928
|
+
people.setAttribute("max", "3");
|
|
14929
|
+
people.hidden = true;
|
|
14930
|
+
element.append(people);
|
|
14617
14931
|
let fileName = "";
|
|
14618
14932
|
let saveState = "saved";
|
|
14619
14933
|
const render3 = () => {
|
|
14620
|
-
const
|
|
14621
|
-
const undoLabel = session?.undoLabel();
|
|
14934
|
+
const undoLabel = historyOf(ctx)?.undoLabel();
|
|
14622
14935
|
const entries = [
|
|
14623
14936
|
{ id: "save", icon: "save", label: ctx.t("Save"), title: `${ctx.t("Save")} (Ctrl+S)` },
|
|
14624
14937
|
{
|
|
@@ -14669,31 +14982,15 @@ function createTitleBar(ctx, handlers) {
|
|
|
14669
14982
|
ctx.grid()?.focus();
|
|
14670
14983
|
void ctx.commands.run(command.id);
|
|
14671
14984
|
});
|
|
14672
|
-
const label = (control, text3) => {
|
|
14673
|
-
const translated = ctx.t(text3);
|
|
14674
|
-
control.setAttribute("aria-label", translated);
|
|
14675
|
-
control.title = translated;
|
|
14676
|
-
};
|
|
14677
14985
|
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");
|
|
14986
|
+
people.setAttribute("label", ctx.t("People in this session"));
|
|
14682
14987
|
render3();
|
|
14683
14988
|
};
|
|
14684
14989
|
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
|
-
}
|
|
14990
|
+
const sharing = handlers.collaboration?.();
|
|
14991
|
+
people.hidden = !sharing?.active;
|
|
14992
|
+
const next = sharing?.active ? participants(sharing) : [];
|
|
14993
|
+
if (JSON.stringify(next) !== JSON.stringify(people.participants)) people.participants = next;
|
|
14697
14994
|
render3();
|
|
14698
14995
|
};
|
|
14699
14996
|
relocalize();
|
|
@@ -14822,6 +15119,11 @@ function buildShell(core) {
|
|
|
14822
15119
|
core.dirty.set(true);
|
|
14823
15120
|
backstage.relocalize();
|
|
14824
15121
|
},
|
|
15122
|
+
share: {
|
|
15123
|
+
state: () => core.collab.state(),
|
|
15124
|
+
start: (roomId) => core.collab.start({ roomId }),
|
|
15125
|
+
stop: () => core.collab.stop()
|
|
15126
|
+
},
|
|
14825
15127
|
hiddenActions: () => core.hiddenActions,
|
|
14826
15128
|
setHiddenActions(ids) {
|
|
14827
15129
|
element.hiddenActions = ids;
|
|
@@ -14841,10 +15143,16 @@ function buildShell(core) {
|
|
|
14841
15143
|
);
|
|
14842
15144
|
safeMount("commands", () => installCommands(ctx));
|
|
14843
15145
|
const ribbon = createRibbon(ctx, { openBackstage: () => backstage.open("info"), isHidden });
|
|
15146
|
+
const ribbonActions = createRibbonActions(ctx, {
|
|
15147
|
+
isHidden,
|
|
15148
|
+
setReadOnly: (readOnly) => element.readOnly = readOnly,
|
|
15149
|
+
collaboration: () => core.collab.state()
|
|
15150
|
+
});
|
|
15151
|
+
ribbon.element.append(ribbonActions.element);
|
|
14844
15152
|
const titleBar = createTitleBar(ctx, {
|
|
14845
15153
|
isHidden,
|
|
14846
15154
|
save: () => void fileCommand("save"),
|
|
14847
|
-
|
|
15155
|
+
collaboration: () => core.collab.state(),
|
|
14848
15156
|
revealControl(id) {
|
|
14849
15157
|
const control = ribbon.element.querySelector(
|
|
14850
15158
|
`.ribbon-panel [data-command="${id.replace(/["\\]/g, "")}"]`
|
|
@@ -14935,10 +15243,12 @@ function buildShell(core) {
|
|
|
14935
15243
|
focusRegion(next);
|
|
14936
15244
|
};
|
|
14937
15245
|
installKeyboard(ctx, actions);
|
|
15246
|
+
element.addEventListener("collaboration-change", () => backstage.refresh("share"));
|
|
14938
15247
|
core.shell = {
|
|
14939
15248
|
render() {
|
|
14940
15249
|
ribbon.refresh();
|
|
14941
15250
|
titleBar.refresh();
|
|
15251
|
+
ribbonActions.refresh();
|
|
14942
15252
|
statusBar.refresh();
|
|
14943
15253
|
chartSeriesPane.refresh();
|
|
14944
15254
|
chartAreaPane.refresh();
|
|
@@ -14954,6 +15264,7 @@ function buildShell(core) {
|
|
|
14954
15264
|
emptyText.textContent = ctx.t("Open a workbook or create a new one from the File tab.");
|
|
14955
15265
|
ribbon.rebuild();
|
|
14956
15266
|
titleBar.relocalize();
|
|
15267
|
+
ribbonActions.relocalize();
|
|
14957
15268
|
statusBar.relocalize();
|
|
14958
15269
|
backstage.relocalize();
|
|
14959
15270
|
chartSeriesPane.relocalize();
|
|
@@ -14972,6 +15283,269 @@ function buildShell(core) {
|
|
|
14972
15283
|
fileCommand
|
|
14973
15284
|
};
|
|
14974
15285
|
}
|
|
15286
|
+
|
|
15287
|
+
// src/xlsx/collaboration-session.ts
|
|
15288
|
+
function createRoomSession(collab, xlsx, options, defaultName) {
|
|
15289
|
+
const roomId = options.roomId ?? "";
|
|
15290
|
+
if (!collab.isValidRoomId(roomId))
|
|
15291
|
+
throw new Error("Use 1 to 128 letters, digits, hyphens or underscores for the room name.");
|
|
15292
|
+
let provider = options.provider;
|
|
15293
|
+
if (!provider && options.serverUrl)
|
|
15294
|
+
provider = collab.transportProvider({
|
|
15295
|
+
transport: collab.createWebSocketTransport({
|
|
15296
|
+
url: collab.roomUrl(options.serverUrl, roomId)
|
|
15297
|
+
})
|
|
15298
|
+
});
|
|
15299
|
+
if (!provider) {
|
|
15300
|
+
if (!collab.canBroadcast())
|
|
15301
|
+
throw new Error("This browser cannot share between windows; pass a server URL.");
|
|
15302
|
+
provider = collab.transportProvider({
|
|
15303
|
+
transport: collab.createBroadcastTransport({ roomId, prefix: "ooxml-xlsx:" })
|
|
15304
|
+
});
|
|
15305
|
+
}
|
|
15306
|
+
const user = options.user ?? {};
|
|
15307
|
+
return collab.createCollabSession({
|
|
15308
|
+
roomId,
|
|
15309
|
+
provider,
|
|
15310
|
+
user: {
|
|
15311
|
+
name: user.name || defaultName,
|
|
15312
|
+
...user.color ? { color: user.color } : {},
|
|
15313
|
+
...user.role ? { role: user.role } : {}
|
|
15314
|
+
},
|
|
15315
|
+
initialPresence: {},
|
|
15316
|
+
sanitizePayload: xlsx.sanitizeXlsxPresence,
|
|
15317
|
+
teardown: true
|
|
15318
|
+
});
|
|
15319
|
+
}
|
|
15320
|
+
|
|
15321
|
+
// src/xlsx/collaboration-types.ts
|
|
15322
|
+
var OFF_STATE = Object.freeze({
|
|
15323
|
+
active: false,
|
|
15324
|
+
roomId: void 0,
|
|
15325
|
+
status: "off",
|
|
15326
|
+
synced: false,
|
|
15327
|
+
people: []
|
|
15328
|
+
});
|
|
15329
|
+
|
|
15330
|
+
// src/xlsx/collaboration.ts
|
|
15331
|
+
var loadRuntime = () => Promise.all([import('ooxml-core/collab'), import('ooxml-core/xlsx/collab')]);
|
|
15332
|
+
function presenceRange(selection) {
|
|
15333
|
+
const { row: row2, col } = selection.active;
|
|
15334
|
+
const holding = selection.ranges.find(
|
|
15335
|
+
(r) => row2 >= r.start.row && row2 <= r.end.row && col >= r.start.col && col <= r.end.col
|
|
15336
|
+
);
|
|
15337
|
+
return holding ?? selection.ranges[selection.ranges.length - 1] ?? {
|
|
15338
|
+
start: selection.active,
|
|
15339
|
+
end: selection.active
|
|
15340
|
+
};
|
|
15341
|
+
}
|
|
15342
|
+
var XlsxCollaboration = class {
|
|
15343
|
+
constructor(host, load = loadRuntime) {
|
|
15344
|
+
this.host = host;
|
|
15345
|
+
this.load = load;
|
|
15346
|
+
}
|
|
15347
|
+
host;
|
|
15348
|
+
load;
|
|
15349
|
+
#active;
|
|
15350
|
+
#starting;
|
|
15351
|
+
/** Bumped by every stop, so a join still loading the runtime is abandoned. */
|
|
15352
|
+
#epoch = 0;
|
|
15353
|
+
#wanted;
|
|
15354
|
+
#lost = false;
|
|
15355
|
+
#connected = false;
|
|
15356
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
15357
|
+
get active() {
|
|
15358
|
+
return this.#active !== void 0;
|
|
15359
|
+
}
|
|
15360
|
+
/** Joined or joining. */
|
|
15361
|
+
get busy() {
|
|
15362
|
+
return this.#active !== void 0 || this.#starting !== void 0;
|
|
15363
|
+
}
|
|
15364
|
+
/** The options of the declarative `collaboration` property, if set. */
|
|
15365
|
+
get wanted() {
|
|
15366
|
+
return this.#wanted;
|
|
15367
|
+
}
|
|
15368
|
+
/**
|
|
15369
|
+
* Declarative sharing: while set, the open workbook is shared in that room, and a workbook
|
|
15370
|
+
* opened later joins it too (the room's content wins when it already has one). Undefined stops.
|
|
15371
|
+
*/
|
|
15372
|
+
want(options) {
|
|
15373
|
+
if (options === this.#wanted) return;
|
|
15374
|
+
this.#wanted = options;
|
|
15375
|
+
this.#leave();
|
|
15376
|
+
this.resume();
|
|
15377
|
+
}
|
|
15378
|
+
/** Leaves the room before the workbook is replaced; true when it was shared. */
|
|
15379
|
+
suspend() {
|
|
15380
|
+
const was = this.busy;
|
|
15381
|
+
this.#leave();
|
|
15382
|
+
return was;
|
|
15383
|
+
}
|
|
15384
|
+
/** Joins the wanted room with the workbook now open. */
|
|
15385
|
+
resume() {
|
|
15386
|
+
const wanted = this.#wanted;
|
|
15387
|
+
if (!wanted || this.busy || !this.host.edit()) return;
|
|
15388
|
+
this.start(wanted).catch((error) => {
|
|
15389
|
+
const failure = asError(error);
|
|
15390
|
+
this.host.toast(this.host.t(failure.message), "error");
|
|
15391
|
+
this.host.error(failure);
|
|
15392
|
+
});
|
|
15393
|
+
}
|
|
15394
|
+
/** Joins a room. Rejects when one is active, no workbook is open or the room is invalid. */
|
|
15395
|
+
start(options) {
|
|
15396
|
+
if (this.#active || this.#starting)
|
|
15397
|
+
return Promise.reject(new Error("Stop the current collaboration session first."));
|
|
15398
|
+
const starting = this.#start(options).finally(() => {
|
|
15399
|
+
if (this.#starting === starting) this.#starting = void 0;
|
|
15400
|
+
});
|
|
15401
|
+
this.#starting = starting;
|
|
15402
|
+
return starting;
|
|
15403
|
+
}
|
|
15404
|
+
async #start(options) {
|
|
15405
|
+
if (!this.host.edit()) throw new Error("Open or create a workbook before sharing it.");
|
|
15406
|
+
const epoch = this.#epoch;
|
|
15407
|
+
const [collab, xlsx] = await this.load();
|
|
15408
|
+
if (epoch !== this.#epoch) return;
|
|
15409
|
+
const edit = this.host.edit();
|
|
15410
|
+
if (!edit) throw new Error("Open or create a workbook before sharing it.");
|
|
15411
|
+
const session = options.session ?? createRoomSession(collab, xlsx, options, this.host.userName());
|
|
15412
|
+
const binding = xlsx.bindWorkbookSession(session, edit, {
|
|
15413
|
+
onError: (error) => this.host.error(asError(error))
|
|
15414
|
+
});
|
|
15415
|
+
const active2 = { session, binding, owned: !options.session, stop: [] };
|
|
15416
|
+
this.#active = active2;
|
|
15417
|
+
this.#lost = false;
|
|
15418
|
+
this.#connected = session.status === "connected";
|
|
15419
|
+
const publish = (selection) => binding.setSelection(selection.sheet, presenceRange(selection));
|
|
15420
|
+
active2.stop.push(
|
|
15421
|
+
this.host.selection.onChange(publish),
|
|
15422
|
+
session.on("peers", () => this.#changed()),
|
|
15423
|
+
session.on("synced", () => this.#changed()),
|
|
15424
|
+
session.on("status", (status) => this.#status(status)),
|
|
15425
|
+
session.on("error", (error) => this.host.error(error)),
|
|
15426
|
+
edit.onChange((change) => {
|
|
15427
|
+
if (change.external) this.#notify();
|
|
15428
|
+
})
|
|
15429
|
+
);
|
|
15430
|
+
if (session.role === "viewer") this.host.setReadOnly(true);
|
|
15431
|
+
publish(this.host.selection.get());
|
|
15432
|
+
this.#changed();
|
|
15433
|
+
}
|
|
15434
|
+
/**
|
|
15435
|
+
* Leaves the room and forgets the `collaboration` property. A session the host passed in stays
|
|
15436
|
+
* alive; one the editor made is destroyed.
|
|
15437
|
+
*/
|
|
15438
|
+
stop() {
|
|
15439
|
+
this.#wanted = void 0;
|
|
15440
|
+
this.#leave();
|
|
15441
|
+
}
|
|
15442
|
+
#leave() {
|
|
15443
|
+
this.#epoch++;
|
|
15444
|
+
this.#starting = void 0;
|
|
15445
|
+
const active2 = this.#active;
|
|
15446
|
+
if (!active2) return;
|
|
15447
|
+
this.#active = void 0;
|
|
15448
|
+
for (const stop of active2.stop) stop();
|
|
15449
|
+
active2.binding.dispose();
|
|
15450
|
+
if (active2.owned) active2.session.destroy();
|
|
15451
|
+
this.#changed();
|
|
15452
|
+
}
|
|
15453
|
+
/** Restarts the connection, keeping the shared workbook and queued changes. */
|
|
15454
|
+
reconnect() {
|
|
15455
|
+
this.#active?.session.reconnect();
|
|
15456
|
+
}
|
|
15457
|
+
/** The binding's history while shared (only this window's edits), else undefined. */
|
|
15458
|
+
history() {
|
|
15459
|
+
const binding = this.#active?.binding;
|
|
15460
|
+
if (!binding) return void 0;
|
|
15461
|
+
return {
|
|
15462
|
+
undo: () => binding.undo(),
|
|
15463
|
+
redo: () => binding.redo(),
|
|
15464
|
+
canUndo: () => binding.canUndo(),
|
|
15465
|
+
canRedo: () => binding.canRedo(),
|
|
15466
|
+
undoLabel: () => void 0,
|
|
15467
|
+
redoLabel: () => void 0
|
|
15468
|
+
};
|
|
15469
|
+
}
|
|
15470
|
+
remoteSelections() {
|
|
15471
|
+
return this.#active?.binding.remoteSelections() ?? [];
|
|
15472
|
+
}
|
|
15473
|
+
onRemoteChange(listener) {
|
|
15474
|
+
this.#listeners.add(listener);
|
|
15475
|
+
return () => {
|
|
15476
|
+
this.#listeners.delete(listener);
|
|
15477
|
+
};
|
|
15478
|
+
}
|
|
15479
|
+
state() {
|
|
15480
|
+
const active2 = this.#active;
|
|
15481
|
+
if (!active2) return OFF_STATE;
|
|
15482
|
+
const { session } = active2;
|
|
15483
|
+
return {
|
|
15484
|
+
active: true,
|
|
15485
|
+
roomId: session.roomId,
|
|
15486
|
+
status: session.status,
|
|
15487
|
+
synced: session.synced,
|
|
15488
|
+
people: [
|
|
15489
|
+
{
|
|
15490
|
+
clientId: session.clientId,
|
|
15491
|
+
name: session.identity.userName,
|
|
15492
|
+
color: session.identity.userColor,
|
|
15493
|
+
self: true
|
|
15494
|
+
},
|
|
15495
|
+
...session.peers().map((peer) => ({
|
|
15496
|
+
clientId: peer.clientId,
|
|
15497
|
+
name: peer.userName,
|
|
15498
|
+
color: peer.userColor,
|
|
15499
|
+
self: false
|
|
15500
|
+
}))
|
|
15501
|
+
]
|
|
15502
|
+
};
|
|
15503
|
+
}
|
|
15504
|
+
#status(status) {
|
|
15505
|
+
const { t } = this.host;
|
|
15506
|
+
if (status === "connected") {
|
|
15507
|
+
if (this.#lost)
|
|
15508
|
+
this.host.toast(t("Reconnected. Changes made while offline were sent."), "info");
|
|
15509
|
+
this.#lost = false;
|
|
15510
|
+
this.#connected = true;
|
|
15511
|
+
} else if ((status === "disconnected" || status === "error") && this.#connected && !this.#lost) {
|
|
15512
|
+
this.#lost = true;
|
|
15513
|
+
this.host.toast(
|
|
15514
|
+
t("Connection lost. Keep working; your changes are sent when it returns."),
|
|
15515
|
+
"warning"
|
|
15516
|
+
);
|
|
15517
|
+
}
|
|
15518
|
+
this.#changed();
|
|
15519
|
+
}
|
|
15520
|
+
#notify() {
|
|
15521
|
+
for (const listener of [...this.#listeners]) listener();
|
|
15522
|
+
}
|
|
15523
|
+
#changed() {
|
|
15524
|
+
this.#notify();
|
|
15525
|
+
this.host.changed(this.state());
|
|
15526
|
+
}
|
|
15527
|
+
};
|
|
15528
|
+
function collaborationFor(core) {
|
|
15529
|
+
const { host } = core;
|
|
15530
|
+
return new XlsxCollaboration({
|
|
15531
|
+
edit: () => core.session,
|
|
15532
|
+
selection: core.selection,
|
|
15533
|
+
userName: () => core.authorName,
|
|
15534
|
+
t: core.ctx.t,
|
|
15535
|
+
toast: (message, kind) => core.shell?.toast(message, kind),
|
|
15536
|
+
error: (error) => emit(host, "workbook-error", { error, message: error.message }),
|
|
15537
|
+
changed: (state) => {
|
|
15538
|
+
emit(host, "collaboration-change", state);
|
|
15539
|
+
core.requestRender();
|
|
15540
|
+
},
|
|
15541
|
+
setReadOnly: (readOnly) => core.setReadOnly(readOnly)
|
|
15542
|
+
});
|
|
15543
|
+
}
|
|
15544
|
+
function asError(error) {
|
|
15545
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
15546
|
+
}
|
|
15547
|
+
|
|
15548
|
+
// src/xlsx/editor-core.ts
|
|
14975
15549
|
var EditorCore = class {
|
|
14976
15550
|
constructor(host) {
|
|
14977
15551
|
this.host = host;
|
|
@@ -15008,6 +15582,7 @@ var EditorCore = class {
|
|
|
15008
15582
|
this.requestRender();
|
|
15009
15583
|
});
|
|
15010
15584
|
this.ctx = this.createContext();
|
|
15585
|
+
this.collab = collaborationFor(this);
|
|
15011
15586
|
}
|
|
15012
15587
|
host;
|
|
15013
15588
|
workbook;
|
|
@@ -15031,6 +15606,8 @@ var EditorCore = class {
|
|
|
15031
15606
|
dialogs;
|
|
15032
15607
|
dirty;
|
|
15033
15608
|
ctx;
|
|
15609
|
+
/** Co-editing over `ooxml-core/collab`; undo and redo go through it while shared. */
|
|
15610
|
+
collab;
|
|
15034
15611
|
gridController;
|
|
15035
15612
|
modelListeners = /* @__PURE__ */ new Set();
|
|
15036
15613
|
stopSession;
|
|
@@ -15081,7 +15658,10 @@ var EditorCore = class {
|
|
|
15081
15658
|
return emitEvent(core.host, type, detail);
|
|
15082
15659
|
},
|
|
15083
15660
|
authorName: () => core.authorName,
|
|
15084
|
-
locale: () => core.locale
|
|
15661
|
+
locale: () => core.locale,
|
|
15662
|
+
history: () => core.collab.history() ?? core.session,
|
|
15663
|
+
remoteSelections: () => core.collab.remoteSelections(),
|
|
15664
|
+
onRemoteSelectionsChange: (listener) => core.collab.onRemoteChange(listener)
|
|
15085
15665
|
};
|
|
15086
15666
|
}
|
|
15087
15667
|
/** Debounced refresh of the ribbon, title bar and status bar. */
|
|
@@ -15109,6 +15689,8 @@ var EditorCore = class {
|
|
|
15109
15689
|
}
|
|
15110
15690
|
/** Replaces the workbook (load, new, template, property), with a fresh edit session. */
|
|
15111
15691
|
setWorkbook(workbook) {
|
|
15692
|
+
if (this.collab.suspend() && !this.collab.wanted)
|
|
15693
|
+
this.shell?.toast(this.ctx.t("Sharing stopped because another workbook was opened."));
|
|
15112
15694
|
this.savePassword = void 0;
|
|
15113
15695
|
this.stopSession?.();
|
|
15114
15696
|
this.stopSession = void 0;
|
|
@@ -15134,6 +15716,7 @@ var EditorCore = class {
|
|
|
15134
15716
|
this.selection.set(initialSelection(this.activeSheet, workbook));
|
|
15135
15717
|
this.dirty.set(false);
|
|
15136
15718
|
this.notifyModel({ kind: "load" });
|
|
15719
|
+
this.collab.resume();
|
|
15137
15720
|
}
|
|
15138
15721
|
createSession(workbook) {
|
|
15139
15722
|
try {
|
|
@@ -15247,6 +15830,8 @@ var XlsxEditorApi = class extends HTMLElementBase {
|
|
|
15247
15830
|
core = new EditorCore(this);
|
|
15248
15831
|
/** Set by the shell once connected. */
|
|
15249
15832
|
chrome;
|
|
15833
|
+
/** Set by the shell once connected: opens File > Share. */
|
|
15834
|
+
openShare;
|
|
15250
15835
|
/** Opens .xlsx, .xlsm, .xltx, .xls or .csv bytes; `fileName` helps detection and names the file. */
|
|
15251
15836
|
async load(bytes, fileName) {
|
|
15252
15837
|
await loadInto(this.core, bytes, fileName, this.chrome);
|
|
@@ -15300,6 +15885,31 @@ var XlsxEditorApi = class extends HTMLElementBase {
|
|
|
15300
15885
|
setActiveSheet(index) {
|
|
15301
15886
|
this.core.setActiveSheet(index);
|
|
15302
15887
|
}
|
|
15888
|
+
/**
|
|
15889
|
+
* Shares the open workbook in a room (see `XlsxCollaborationOptions`). Resolves once joined;
|
|
15890
|
+
* the room's workbook replaces this one when the room already has one. Rejects when sharing is
|
|
15891
|
+
* already active or no workbook is open.
|
|
15892
|
+
*/
|
|
15893
|
+
startCollaboration(options) {
|
|
15894
|
+
return this.core.collab.start(options);
|
|
15895
|
+
}
|
|
15896
|
+
/** Leaves the room (and clears `collaboration`). The workbook stays as it is. */
|
|
15897
|
+
stopCollaboration() {
|
|
15898
|
+
this.core.collab.stop();
|
|
15899
|
+
}
|
|
15900
|
+
/** Restarts the connection, keeping the shared workbook and changes made offline. */
|
|
15901
|
+
reconnectCollaboration() {
|
|
15902
|
+
this.core.collab.reconnect();
|
|
15903
|
+
}
|
|
15904
|
+
/** Who is in the room and how the connection is. */
|
|
15905
|
+
get collaborationState() {
|
|
15906
|
+
return this.core.collab.state();
|
|
15907
|
+
}
|
|
15908
|
+
/** Opens File > Share, where the user starts or stops sharing and sees who is in the room. */
|
|
15909
|
+
share() {
|
|
15910
|
+
this.openShare?.();
|
|
15911
|
+
}
|
|
15912
|
+
/** Undo the last edit; while shared, only this window's edits are undone. */
|
|
15303
15913
|
undo() {
|
|
15304
15914
|
void this.core.commands.run("edit.undo");
|
|
15305
15915
|
}
|
|
@@ -15323,6 +15933,7 @@ var XlsxEditorElement = class extends XlsxEditorApi {
|
|
|
15323
15933
|
if (this.shell) return;
|
|
15324
15934
|
this.shell = buildShell(this.core);
|
|
15325
15935
|
this.chrome = this.shell.chrome;
|
|
15936
|
+
this.openShare = () => this.shell?.backstage.open("share");
|
|
15326
15937
|
this.core.requestRender();
|
|
15327
15938
|
}
|
|
15328
15939
|
attributeChangedCallback(name, _old, value) {
|
|
@@ -15417,6 +16028,17 @@ var XlsxEditorElement = class extends XlsxEditorApi {
|
|
|
15417
16028
|
get dirty() {
|
|
15418
16029
|
return this.core.dirty.dirty;
|
|
15419
16030
|
}
|
|
16031
|
+
/**
|
|
16032
|
+
* Shares the open workbook in a room while set: a workbook opened later joins the same room
|
|
16033
|
+
* (the room's content wins when it already has a workbook); `null` leaves it. A window joining
|
|
16034
|
+
* an existing room still needs a workbook open (`newWorkbook()` is enough).
|
|
16035
|
+
*/
|
|
16036
|
+
get collaboration() {
|
|
16037
|
+
return this.core.collab.wanted ?? null;
|
|
16038
|
+
}
|
|
16039
|
+
set collaboration(value) {
|
|
16040
|
+
this.core.collab.want(value ?? void 0);
|
|
16041
|
+
}
|
|
15420
16042
|
get activeSheet() {
|
|
15421
16043
|
return this.core.activeSheet;
|
|
15422
16044
|
}
|