ooxml-ui 1.6.2 → 1.7.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 +1 -1
- package/custom-elements.json +53 -1
- package/dist/chrome/ruler.d.ts.map +1 -1
- package/dist/chrome/status-bar.d.ts.map +1 -1
- package/dist/chrome/tab-strip.d.ts +3 -1
- package/dist/chrome/tab-strip.d.ts.map +1 -1
- package/dist/chrome/task-pane.d.ts +27 -0
- package/dist/chrome/task-pane.d.ts.map +1 -0
- package/dist/chrome/title-bar.d.ts.map +1 -1
- package/dist/{chunk-QAIVGTQZ.js → chunk-6UPGM3X2.js} +1 -1
- package/dist/{chunk-QHAE6Y5B.js → chunk-SCWCZSTE.js} +71 -32
- package/dist/{chunk-Z7CS3UUK.js → chunk-VAR6O7II.js} +3 -2
- package/dist/controls.d.ts +3 -2
- package/dist/controls.d.ts.map +1 -1
- package/dist/controls.js +1 -1
- package/dist/docx.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/pptx/{chunk-E55NU4BF.mjs → chunk-RCTRRS6E.mjs} +28 -49
- package/dist/pptx/{chunk-BLAJIEXA.cjs → chunk-XGPLA2OY.cjs} +30 -48
- package/dist/pptx/dom/index.cjs +199 -199
- package/dist/pptx/dom/index.mjs +2 -2
- package/dist/pptx/index.cjs +2708 -2708
- package/dist/pptx/index.mjs +1 -1
- package/dist/pptx/render/editor-keymap-arrows.d.ts +0 -7
- package/dist/pptx/render/editor-keymap-arrows.d.ts.map +1 -1
- package/dist/pptx/render/element-interaction.d.ts +2 -6
- package/dist/pptx/render/element-interaction.d.ts.map +1 -1
- package/dist/teams.js +2 -2
- package/dist/visio/ribbon-action.d.ts +3 -1
- package/dist/visio/ribbon-router.d.ts +1 -1
- package/dist/visio/ribbon.d.ts +2 -2
- package/dist/visio/shapes-window.d.ts +2 -2
- package/dist/visio/status-bar.d.ts +7 -4
- package/dist/visio/styles/theme.d.ts +1 -1
- package/dist/visio/styles.d.ts +1 -1
- package/dist/visio/title-bar.d.ts +9 -0
- package/dist/visio/viewer-backstage.d.ts +2 -1
- package/dist/visio/viewer-canvas.d.ts +1 -1
- package/dist/visio/viewer-chrome.d.ts +12 -5
- package/dist/visio/viewer-commands.d.ts +3 -1
- package/dist/visio/viewer-element.d.ts +8 -0
- package/dist/visio/viewer-guides.d.ts +5 -2
- package/dist/visio/viewer-inline-text.d.ts +31 -0
- package/dist/visio/viewer-input.d.ts +5 -1
- package/dist/visio/viewer-layer-properties.d.ts +18 -0
- package/dist/visio/viewer-layout-commands.d.ts +3 -1
- package/dist/visio/viewer-options.d.ts +18 -4
- package/dist/visio.js +974 -708
- package/dist/xlsx.js +4 -4
- package/package.json +2 -2
- package/dist/visio/viewer-edit-controls.d.ts +0 -12
- package/dist/visio/viewer-geometry-controls.d.ts +0 -14
- package/dist/visio/viewer-layer-controls.d.ts +0 -5
package/dist/visio.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { themeBridge, installOfficeUiTheme } from './chunk-BCH2ZLWI.js';
|
|
2
|
-
import { attachKeyTips, registerControls, readOfficeProfile, sanitizeOfficeProfile, writeOfficeProfile, OFFICE_COLOR_SWATCHES, commentInitials } from './chunk-
|
|
2
|
+
import { attachKeyTips, registerControls, readOfficeProfile, sanitizeOfficeProfile, writeOfficeProfile, OFFICE_COLOR_SWATCHES, commentInitials } from './chunk-SCWCZSTE.js';
|
|
3
3
|
import { getIcon, registerIcon } from './chunk-M6GF5ED2.js';
|
|
4
4
|
import { definePresence } from './chunk-L7JV5FVE.js';
|
|
5
5
|
import './chunk-OGNNNTKI.js';
|
|
6
6
|
import './chunk-SPNWHKSR.js';
|
|
7
|
-
import { VISIO_TEXT_LANGUAGES, VISIO_BULLET_STYLES, FOREIGN_VECTOR_SCENE_LIMITS, EMPTY_TEXT_SEARCH, EMPTY_SELECTION, EMPTY_EDIT_STATE, assertViewableDocument, snapshotSelection, selectionKey, indexDocumentText, searchDocumentText, sameSelection, validateSearchQuery, MAX_INPUT_BYTES, DocumentHistory, snapshotEdits, visioWithContainerMembers, visioSelectionIsOnPage, visioDuplicateCommand, visioGroupCommand, visioUngroupCommand, visioContainerCommand, visioCalloutCommand, visioPasteCommand, visioTextOccurrenceSelection, ForeignVectorBudget, VISIO_IDENTITY_TRANSFORM, hasVisibleShapeContent, composeVisioTransform, compatibilityNotes, compatibilityText, visioGradientInstances, visioRenderedGradientStopCount, inspectForeignVectorResource, copySnapshotScene, editErrorMessage, eventKeys, propertyKeys, VISIO_TEXT_REPLACE_LIMITS, visioTextReplaceOccurrences, visioTextReplacePlan, visioTextReplaceCommands, TEXT_SEARCH_LIMITS, visioTextShape, visioTextDraftEdit, isEditCancellation, visioSizePositionCommand, visioSizePositionState, visioWithCalloutLeaders, visioPageInsertCommand, visioQuarterTurnCommand, visioLocalRotationShape, visioMovementShape, visioMoveCommands, visioMoveTargets, visioMarqueeBox, visioPageDragDelta, visioMarqueeSelection, visioConnectorRouteOf, visioPageEditToDrawing, visioResizeShape, visioResizeDrag, textSearchStatus, visioSvgStrokeStyle, visioLineDashLengths, VISIO_DIAGRAM_RULE_SETS, visioClipboardShape, visioArrangeCommands, visioChangeShapeRefusal, visioChangeShapeCommand, visioChangeCaseShape, visioChangeCaseCommand, visioOrderingShape, visioStyleFormattingShape, visioFormattingShape, visioTextFormattingState, visioTextIndentCommand, visioTextFontStepCommand, visioFontFamilies, visioPictureInsertCommand, normalizeVisioHyperlinkAddress, visioFitToDrawingEdits, VISIO_PAPER_SIZES, visioPageSizePresetEdits, visioOrientationEdits, visioPageDecorationState, visioNewPageId, visioMatchingPaperSize, visioPageBreaks, visioRemoveDataGraphicEdits, visioDataGraphicFields, visioDataGraphicEdits, visioShapeDataRow, VISIO_DATA_GRAPHIC_FILL_ROW, visioColorRules, visioLegendEdits, visioTextDialogValues, visioTextDialogPatch, visioShapeFormattingState, visioFormatPainterSnapshot, visioFormatPainterEdits, VISIO_FORMAT_PAINTER_LIMITS, isVisioPathTool, visioPathDrawPlan, visioDrawPlan, visioDrawIsLargeEnough, visioConnectorCreationCommand, visioConnectableShape, visioAddConnectionPointCommand, visioDrawBounds, visioDrawingPoint, visioMovePreviewTransform, visioStraightLineHandles, visioConnectorEndHandles, visioNearestConnectionPoint, visioRotationPreviewTransform, VISIO_RESIZE_HANDLES, visioFillPatternTransform, visioRenderedGradientStops, visioStrokeGradient, VISIO_LAYOUT_STYLES, visioGlowKey, visioShapeEffectValues, visioReflectionKey, visioFollowTarget, visioPaperSize, visioKeepAutoSize, checkVisioDiagram, visioShapeReport, visioShapeReportTable, visioShapeReportCsv, visioShapeReportText, visioSubprocessCommand, visioShapeDataText, VISIO_LAYOUT_LABELS, visioAutoAlignCommands, visioReLayoutCommands, visioLayerAssignState, visioNewLayerNames, visioLayerAssignCommands, VISIO_SELECT_TYPES, VISIO_SELECT_TYPE_LABELS, visioPageMasters, visioSelectByType, visioPasteTextCommand, visioSnapMoveDelta, visioPageGuides, VISIO_FIELD_CATEGORIES, visioTextAppendEdit, visioTextSource, visioTextBlockShape, visioTextBlockFrame, visioTextBlockMatrix, VISIO_TEXT_BLOCK_HANDLES, visioShapeLocalPoint, visioTextBlockDrag, visioTextBlockEdit, visioPathPreview, visioConnectorMovePreviews, visioConnectorPreviewPath, visioShapePageBox, visioDataGraphicMarker, visioParseRange, visioDataTable, visioWorkbookGrid, visioGuideCreateCommand, visioGuideMoveCommand, visioBoxCreationCommand } from 'ooxml-core/visio/ui';
|
|
7
|
+
import { VISIO_TEXT_LANGUAGES, VISIO_BULLET_STYLES, FOREIGN_VECTOR_SCENE_LIMITS, EMPTY_TEXT_SEARCH, EMPTY_SELECTION, EMPTY_EDIT_STATE, assertViewableDocument, snapshotSelection, selectionKey, indexDocumentText, searchDocumentText, sameSelection, validateSearchQuery, MAX_INPUT_BYTES, DocumentHistory, snapshotEdits, visioWithContainerMembers, visioSelectionIsOnPage, visioDuplicateCommand, visioGroupCommand, visioUngroupCommand, visioContainerCommand, visioCalloutCommand, visioPasteCommand, visioTextOccurrenceSelection, ForeignVectorBudget, VISIO_IDENTITY_TRANSFORM, hasVisibleShapeContent, composeVisioTransform, compatibilityNotes, compatibilityText, visioGradientInstances, visioRenderedGradientStopCount, inspectForeignVectorResource, copySnapshotScene, editErrorMessage, eventKeys, propertyKeys, VISIO_TEXT_REPLACE_LIMITS, visioTextReplaceOccurrences, visioTextReplacePlan, visioTextReplaceCommands, TEXT_SEARCH_LIMITS, visioTextShape, visioTextDraftEdit, isEditCancellation, visioSizePositionCommand, visioSizePositionState, visioWithCalloutLeaders, visioPageInsertCommand, visioQuarterTurnCommand, visioLocalRotationShape, visioMovementShape, visioMoveCommands, visioMoveTargets, visioMarqueeBox, visioPageDragDelta, visioMarqueeSelection, visioConnectorRouteOf, visioPageEditToDrawing, visioResizeShape, visioResizeDrag, textSearchStatus, visioSvgStrokeStyle, visioLineDashLengths, VISIO_DIAGRAM_RULE_SETS, visioClipboardShape, visioArrangeCommands, visioChangeShapeRefusal, visioChangeShapeCommand, visioChangeCaseShape, visioChangeCaseCommand, visioOrderingShape, visioStyleFormattingShape, visioFormattingShape, visioTextFormattingState, visioTextIndentCommand, visioTextFontStepCommand, visioFontFamilies, visioPictureInsertCommand, normalizeVisioHyperlinkAddress, visioFitToDrawingEdits, VISIO_PAPER_SIZES, visioPageSizePresetEdits, visioOrientationEdits, visioPageDecorationState, visioNewPageId, visioMatchingPaperSize, visioPageBreaks, visioRemoveDataGraphicEdits, visioDataGraphicFields, visioDataGraphicEdits, visioShapeDataRow, VISIO_DATA_GRAPHIC_FILL_ROW, visioColorRules, visioLegendEdits, visioTextDialogValues, visioTextDialogPatch, visioShapeFormattingState, visioFormatPainterSnapshot, visioFormatPainterEdits, VISIO_FORMAT_PAINTER_LIMITS, isVisioPathTool, visioPathDrawPlan, visioDrawPlan, visioDrawIsLargeEnough, visioConnectorCreationCommand, visioConnectableShape, visioAddConnectionPointCommand, visioDrawBounds, visioDrawingPoint, visioMovePreviewTransform, visioStraightLineHandles, visioConnectorEndHandles, visioNearestConnectionPoint, visioRotationPreviewTransform, VISIO_RESIZE_HANDLES, visioNudgeCommands, visioFillPatternTransform, visioRenderedGradientStops, visioStrokeGradient, VISIO_LAYOUT_STYLES, visioGlowKey, visioShapeEffectValues, visioReflectionKey, visioFollowTarget, visioPaperSize, visioKeepAutoSize, checkVisioDiagram, visioShapeReport, visioShapeReportTable, visioShapeReportCsv, visioShapeReportText, visioSubprocessCommand, visioShapeDataText, VISIO_LAYOUT_LABELS, visioAutoAlignCommands, visioReLayoutCommands, visioLayerAssignState, visioNewLayerNames, visioLayerAssignCommands, VISIO_SELECT_TYPES, VISIO_SELECT_TYPE_LABELS, visioPageMasters, visioSelectByType, visioPasteTextCommand, visioSnapMoveDelta, visioPageGuides, VISIO_FIELD_CATEGORIES, visioTextAppendEdit, visioTextSource, visioTextBlockShape, visioTextBlockFrame, visioTextBlockMatrix, VISIO_TEXT_BLOCK_HANDLES, visioShapeLocalPoint, visioTextBlockDrag, visioTextBlockEdit, visioPathPreview, visioConnectorMovePreviews, visioConnectorPreviewPath, visioShapePageBox, visioDataGraphicMarker, visioParseRange, visioDataTable, visioWorkbookGrid, visioGuideCreateCommand, visioGuideMoveCommand, visioBoxCreationCommand } from 'ooxml-core/visio/ui';
|
|
8
8
|
export { TEXT_SEARCH_LIMITS, compatibilityNotes, compatibilityText, demoDocument, eventKeys, propertyKeys } from 'ooxml-core/visio/ui';
|
|
9
9
|
import { VISIO_VISIBILITY_LIMITS, VISIO_STENCILS, visioOutlineShape, loadVisio, createVsdx, deserializeVisioClipboard, getVisioPageLayers, resolveVisioPageVisibility, VISIO_CLIPBOARD_MAX_CHARS, VISIO_GLOW_TRANSPARENCY, VISIO_METADATA_TEXT_LIMIT, VISIO_PICTURE_MAX_BYTES, inspectVisioRasterImage, VISIO_BUILT_IN_THEMES, VISIO_CONNECTOR_ROUTES, visioFilledArrow, layoutVisioFilledArrowLine, visioOpenArrowPath, VISIO_SHADOW_PRESETS, isVisioChangeShapeTarget, VISIO_CONTAINER_STYLES, VISIO_CALLOUT_STYLES, visioFallbackQuickStyle, VISIO_GLOW_SIZES, VISIO_SOFT_EDGE_SIZES, VISIO_REFLECTION_PRESETS, VISIO_BACKGROUND_STYLES, visioBackgroundShapes, VISIO_BORDER_STYLES, visioBorderShapes, VISIO_SHAPE_DATA_TYPES, visioShapeDataRowName, VISIO_CLIPBOARD_MAGIC, visioThemeVariantColors, isVisioBuiltInThemeId, VISIO_SCALE_UNITS, VISIO_QUICK_STYLE_COLORS } from 'ooxml-core/visio';
|
|
10
|
-
import { resolveRotateHandlePlacement, createRotationDrag } from 'ooxml-core/geometry';
|
|
10
|
+
import { resolveRotateHandlePlacement, createRotationDrag, snapAngle } from 'ooxml-core/geometry';
|
|
11
11
|
|
|
12
12
|
function createWorkerEditor(factory, timeoutMs = 2e4) {
|
|
13
13
|
const create = (() => {
|
|
@@ -190,7 +190,7 @@ var ViewerClipboardCapture = class {
|
|
|
190
190
|
token() {
|
|
191
191
|
const context = this.context();
|
|
192
192
|
if (this.#destroyed || !context)
|
|
193
|
-
throw new Error("
|
|
193
|
+
throw new Error("Open a .vsdx file before using the clipboard.");
|
|
194
194
|
const token = Object.freeze({ [tokenBrand]: true });
|
|
195
195
|
this.#tokens.set(token, context);
|
|
196
196
|
return token;
|
|
@@ -400,9 +400,9 @@ var ViewerTextReplacement = class {
|
|
|
400
400
|
return this.#issue(context, Object.freeze({ scope, pageId: context.pageId, selection: owned }));
|
|
401
401
|
}
|
|
402
402
|
current(token) {
|
|
403
|
-
const
|
|
404
|
-
const context =
|
|
405
|
-
return !!
|
|
403
|
+
const saved2 = this.#tokens.get(token);
|
|
404
|
+
const context = saved2 && this.bridge.context();
|
|
405
|
+
return !!saved2 && !!context && sameReplacementContext(saved2.context, context);
|
|
406
406
|
}
|
|
407
407
|
/** Cancellation is bound to this token's application, even after scope intent changes. */
|
|
408
408
|
cancel(token) {
|
|
@@ -474,9 +474,9 @@ var ViewerTextReplacement = class {
|
|
|
474
474
|
this.#tokens.set(token, { context, scope });
|
|
475
475
|
return token;
|
|
476
476
|
}
|
|
477
|
-
#requireContext(
|
|
477
|
+
#requireContext(saved2) {
|
|
478
478
|
const current = this.bridge.context();
|
|
479
|
-
if (!current || !sameReplacementContext(
|
|
479
|
+
if (!current || !sameReplacementContext(saved2, current)) throw replacementCancelled();
|
|
480
480
|
}
|
|
481
481
|
#require(token) {
|
|
482
482
|
const record = this.#tokens.get(token);
|
|
@@ -1105,7 +1105,7 @@ var ViewerController = class {
|
|
|
1105
1105
|
exportVsdx() {
|
|
1106
1106
|
this.#assertAlive();
|
|
1107
1107
|
if (!this.#history || this.#sourceFormat !== "vsdx" || this.#state.document?.format !== "vsdx")
|
|
1108
|
-
throw new Error("
|
|
1108
|
+
throw new Error("Open a .vsdx file before downloading a copy.");
|
|
1109
1109
|
if (this.#state.edit.busy || this.#state.loading)
|
|
1110
1110
|
throw new Error("Wait for the current document operation before downloading.");
|
|
1111
1111
|
return this.#history.export();
|
|
@@ -1220,7 +1220,7 @@ var ViewerController = class {
|
|
|
1220
1220
|
this.#assertAlive();
|
|
1221
1221
|
const history = this.#history;
|
|
1222
1222
|
if (!history || this.#sourceFormat !== "vsdx" || this.#state.document?.format !== "vsdx")
|
|
1223
|
-
throw new Error("
|
|
1223
|
+
throw new Error("Open a .vsdx file before editing.");
|
|
1224
1224
|
if (this.#state.loading || this.#state.edit.busy)
|
|
1225
1225
|
throw new Error("Another document operation is in progress.");
|
|
1226
1226
|
const target = kind === "undo" ? history.undoTarget : kind === "redo" ? history.redoTarget : void 0;
|
|
@@ -1574,7 +1574,7 @@ function shapeDetails(shape) {
|
|
|
1574
1574
|
fragment.append(list);
|
|
1575
1575
|
} else {
|
|
1576
1576
|
const empty = document.createElement("p");
|
|
1577
|
-
empty.textContent = "No
|
|
1577
|
+
empty.textContent = "No Shape Data";
|
|
1578
1578
|
fragment.append(empty);
|
|
1579
1579
|
}
|
|
1580
1580
|
const define = document.createElement("button");
|
|
@@ -1642,7 +1642,31 @@ function selection(target) {
|
|
|
1642
1642
|
...target.dataset.pageId ? { pageId: target.dataset.pageId } : {}
|
|
1643
1643
|
} : null;
|
|
1644
1644
|
}
|
|
1645
|
-
|
|
1645
|
+
var NUDGE_STEP = 1 / 16;
|
|
1646
|
+
var editableTarget = (event) => event.target?.closest?.("input, textarea, select, [contenteditable]");
|
|
1647
|
+
function nudge(event, controller, announce) {
|
|
1648
|
+
const state = controller.state;
|
|
1649
|
+
const page3 = state.document?.pages[state.pageIndex];
|
|
1650
|
+
if (!page3 || !state.selectedShapes.length || !state.edit.sourceAvailable || state.loading || event.ctrlKey || event.metaKey || event.altKey || editableTarget(event))
|
|
1651
|
+
return false;
|
|
1652
|
+
const step = event.shiftKey ? 1 / (96 * (state.zoom || 1)) : NUDGE_STEP;
|
|
1653
|
+
const ids = state.selectedShapes.map((shape) => shape.id);
|
|
1654
|
+
const edits = visioNudgeCommands(page3, ids, event.key, step);
|
|
1655
|
+
if (edits === null) return false;
|
|
1656
|
+
event.preventDefault();
|
|
1657
|
+
if (state.edit.busy) return true;
|
|
1658
|
+
if (!edits) {
|
|
1659
|
+
announce("The selection cannot be nudged.");
|
|
1660
|
+
return true;
|
|
1661
|
+
}
|
|
1662
|
+
if (edits.length)
|
|
1663
|
+
controller.applySelectionEdits(edits).catch((error) => {
|
|
1664
|
+
if (!isEditCancellation(error)) announce(editErrorMessage(error));
|
|
1665
|
+
});
|
|
1666
|
+
return true;
|
|
1667
|
+
}
|
|
1668
|
+
function wireViewerInputs(controls, controller, fit, announce = () => {
|
|
1669
|
+
}, typeText = () => false) {
|
|
1646
1670
|
const { viewport, zoomSlider } = controls;
|
|
1647
1671
|
const Abort = viewport.ownerDocument.defaultView?.AbortController ?? AbortController, events = new Abort();
|
|
1648
1672
|
const options2 = { signal: events.signal };
|
|
@@ -1666,6 +1690,12 @@ function wireViewerInputs(controls, controller, fit) {
|
|
|
1666
1690
|
viewport.addEventListener(
|
|
1667
1691
|
"keydown",
|
|
1668
1692
|
(event) => {
|
|
1693
|
+
if (nudge(event, controller, announce)) return;
|
|
1694
|
+
if (event.key.length === 1 && event.key !== " " && !event.ctrlKey && !event.metaKey && !event.altKey && !event.isComposing && !editableTarget(event) && controller.state.selectedShapes.length === 1 && controller.state.edit.sourceAvailable && typeText(event.key)) {
|
|
1695
|
+
event.preventDefault();
|
|
1696
|
+
event.stopPropagation();
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1669
1699
|
const target = targetShape(event);
|
|
1670
1700
|
if (target && ["ArrowDown", "ArrowRight", "ArrowUp", "ArrowLeft", "Home", "End"].includes(event.key)) {
|
|
1671
1701
|
event.preventDefault();
|
|
@@ -1699,98 +1729,6 @@ function wireViewerInputs(controls, controller, fit) {
|
|
|
1699
1729
|
);
|
|
1700
1730
|
return () => events.abort();
|
|
1701
1731
|
}
|
|
1702
|
-
var layerControlsTemplate = `<details class="layer-controls" hidden><summary>Layers</summary><p>Display changes only. SVG and print snapshots use saved visibility. Guides, NoShow and unknown hidden reasons remain hidden.</p><div data-layer-list></div><p data-layer-status role="status"></p><button type="button" data-layer-reset="all">Reset all layers</button></details>`;
|
|
1703
|
-
function renderLayerControls(panel, state) {
|
|
1704
|
-
const model = state.document, page3 = model?.pages[state.pageIndex];
|
|
1705
|
-
const list = panel.querySelector("[data-layer-list]");
|
|
1706
|
-
const active = panel.getRootNode();
|
|
1707
|
-
const focused = active.activeElement;
|
|
1708
|
-
const focus = focused && panel.contains(focused) ? { ...focused.dataset } : void 0;
|
|
1709
|
-
const fragment = panel.ownerDocument.createDocumentFragment();
|
|
1710
|
-
const overrides = layerOverrideMaps(model, state.layerVisibilityOverrides);
|
|
1711
|
-
let total = 0, shown = 0;
|
|
1712
|
-
for (const source of model && page3 ? getVisioPageLayers(model, page3.id) : []) {
|
|
1713
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1714
|
-
const fieldset2 = panel.ownerDocument.createElement("fieldset");
|
|
1715
|
-
const legend = panel.ownerDocument.createElement("legend");
|
|
1716
|
-
const pageLabel = `${source.name.slice(0, 256)} (page ${source.id})`;
|
|
1717
|
-
legend.textContent = `${pageLabel}${source.id === page3.id ? "" : " (background)"}`;
|
|
1718
|
-
fieldset2.append(legend);
|
|
1719
|
-
let rows = 0;
|
|
1720
|
-
for (const layer of source.layers ?? []) {
|
|
1721
|
-
if (ids.has(layer.id)) continue;
|
|
1722
|
-
ids.add(layer.id);
|
|
1723
|
-
++total;
|
|
1724
|
-
if (shown >= VIEWER_LAYER_LIMITS.controls) continue;
|
|
1725
|
-
++shown;
|
|
1726
|
-
++rows;
|
|
1727
|
-
const row = panel.ownerDocument.createElement("div");
|
|
1728
|
-
const label = panel.ownerDocument.createElement("label");
|
|
1729
|
-
const input = panel.ownerDocument.createElement("input");
|
|
1730
|
-
const override = overrides.get(source.id)?.get(layer.id);
|
|
1731
|
-
input.type = "checkbox";
|
|
1732
|
-
input.dataset.layerId = layer.id;
|
|
1733
|
-
input.dataset.pageId = source.id;
|
|
1734
|
-
input.checked = override ?? layer.visible;
|
|
1735
|
-
const name = `${layer.name.slice(0, 256) || "Layer"} (ID ${layer.id})`;
|
|
1736
|
-
input.setAttribute("aria-label", `${pageLabel}: ${name}`);
|
|
1737
|
-
const description = `${name} \xB7 saved ${layer.visible ? "visible" : "hidden"}${override === void 0 ? "" : ` \xB7 override ${override ? "visible" : "hidden"}`}`;
|
|
1738
|
-
label.append(input, description);
|
|
1739
|
-
row.append(label);
|
|
1740
|
-
if (override !== void 0) {
|
|
1741
|
-
const reset = panel.ownerDocument.createElement("button");
|
|
1742
|
-
reset.type = "button";
|
|
1743
|
-
reset.textContent = "Reset";
|
|
1744
|
-
reset.dataset.layerReset = "one";
|
|
1745
|
-
reset.dataset.layerId = layer.id;
|
|
1746
|
-
reset.dataset.pageId = source.id;
|
|
1747
|
-
reset.setAttribute("aria-label", `Reset ${pageLabel}: ${name}`);
|
|
1748
|
-
row.append(reset);
|
|
1749
|
-
}
|
|
1750
|
-
fieldset2.append(row);
|
|
1751
|
-
}
|
|
1752
|
-
if (rows) fragment.append(fieldset2);
|
|
1753
|
-
}
|
|
1754
|
-
list.replaceChildren(fragment);
|
|
1755
|
-
panel.hidden = total === 0 && state.layerVisibilityOverrides.length === 0;
|
|
1756
|
-
panel.querySelector("[data-layer-status]").textContent = total > shown ? `Showing ${shown} of ${total} layers. Other layers are available through the viewer API.` : `${total} layers in this drawing \xB7 ${state.layerVisibilityOverrides.length} document display overrides`;
|
|
1757
|
-
panel.querySelector('[data-layer-reset="all"]').disabled = state.layerVisibilityOverrides.length === 0;
|
|
1758
|
-
if (focus) {
|
|
1759
|
-
const controls = [...panel.querySelectorAll("input,button")];
|
|
1760
|
-
const match = (control) => control.dataset.layerId === focus.layerId && control.dataset.pageId === focus.pageId;
|
|
1761
|
-
const target = controls.find(
|
|
1762
|
-
(control) => match(control) && control.dataset.layerReset === focus.layerReset
|
|
1763
|
-
) ?? controls.find(match);
|
|
1764
|
-
target?.focus();
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
function wireLayerControls(panel, controller) {
|
|
1768
|
-
const Abort = panel.ownerDocument.defaultView?.AbortController ?? AbortController;
|
|
1769
|
-
const events = new Abort(), options2 = { signal: events.signal };
|
|
1770
|
-
panel.addEventListener(
|
|
1771
|
-
"change",
|
|
1772
|
-
(event) => {
|
|
1773
|
-
const input = event.target;
|
|
1774
|
-
if (input.matches('input[type="checkbox"]') && input.dataset.pageId !== void 0 && input.dataset.layerId !== void 0)
|
|
1775
|
-
controller.setLayerVisibility(input.dataset.pageId, input.dataset.layerId, input.checked);
|
|
1776
|
-
},
|
|
1777
|
-
options2
|
|
1778
|
-
);
|
|
1779
|
-
panel.addEventListener(
|
|
1780
|
-
"click",
|
|
1781
|
-
(event) => {
|
|
1782
|
-
const button = event.target.closest(
|
|
1783
|
-
"button[data-layer-reset]"
|
|
1784
|
-
);
|
|
1785
|
-
if (!button || !panel.contains(button)) return;
|
|
1786
|
-
if (button.dataset.layerReset === "all") controller.resetLayerVisibility();
|
|
1787
|
-
else if (button.dataset.pageId !== void 0 && button.dataset.layerId !== void 0)
|
|
1788
|
-
controller.setLayerVisibility(button.dataset.pageId, button.dataset.layerId, null);
|
|
1789
|
-
},
|
|
1790
|
-
options2
|
|
1791
|
-
);
|
|
1792
|
-
return () => events.abort();
|
|
1793
|
-
}
|
|
1794
1732
|
|
|
1795
1733
|
// src/visio/styles.ts
|
|
1796
1734
|
var viewerStyles = `
|
|
@@ -1816,21 +1754,10 @@ button[aria-pressed="true"] { color:var(--_vv-accent); background:var(--_vv-acce
|
|
|
1816
1754
|
.ribbon-hint { align-self:center; flex:none; margin:0; padding:0 16px; font-size:11px; line-height:18px; color:var(--_vv-muted); }
|
|
1817
1755
|
.workspace { position:relative; display:flex; flex:1; min-width:0; min-height:0; overflow:hidden; }
|
|
1818
1756
|
.pane-heading { height:37px; display:flex; align-items:center; justify-content:space-between; gap:8px; padding:8px 10px; border-bottom:1px solid var(--_vv-border); font-size:11px; font-weight:600; }
|
|
1819
|
-
.inspector-kind { color:var(--_vv-muted); font-size:10px; font-weight:400; }
|
|
1820
1757
|
.viewport { position:relative; display:flex; flex-direction:column; flex:1; overflow:auto; min-width:0; min-height:0; padding:16px 4px; background:var(--_vv-bg); }
|
|
1821
1758
|
.paper { display:block; flex:none; background:white; box-shadow:var(--_vv-shadow); margin:auto; }
|
|
1822
1759
|
.paper [data-shape-id] { cursor:pointer; }
|
|
1823
|
-
.paper [data-selected="true"] > [data-geometry] { stroke:var(--_vv-accent) !important; stroke-width:.025 !important; }
|
|
1824
|
-
.paper [role="group"][data-selected="true"] [data-geometry] { stroke:var(--_vv-accent) !important; stroke-dasharray:.06 .04; }
|
|
1825
1760
|
.inspector-pane { flex:0 0 288px; width:288px; min-width:0; overflow:auto; border-left:1px solid var(--_vv-border); background:var(--_vv-secondary); }
|
|
1826
|
-
.inspector-body { display:flex; flex-direction:column; gap:12px; padding:12px 10px; }
|
|
1827
|
-
.inspector-card,.edit-controls,.layer-controls { min-width:0; padding:8px; margin:0; border:1px solid var(--_vv-border); border-radius:4px; background:var(--_vv-surface); font-size:11px; line-height:17px; }
|
|
1828
|
-
.document-card h2 { margin:0 0 8px; font-size:10px; font-weight:500; letter-spacing:.5px; text-transform:uppercase; color:var(--_vv-muted); }
|
|
1829
|
-
.current-page-name { margin:0 0 8px; font-size:12px; font-weight:500; overflow-wrap:anywhere; }
|
|
1830
|
-
.document-card dl { display:grid; grid-template-columns:1fr auto; gap:4px 10px; margin:0; font-size:11px; }
|
|
1831
|
-
.document-card dt { color:var(--_vv-muted); }
|
|
1832
|
-
.document-card dd { margin:0; text-align:right; overflow-wrap:anywhere; }
|
|
1833
|
-
.selection-hint { margin:0; padding:0 2px; color:var(--_vv-muted); font-size:11px; }
|
|
1834
1761
|
summary { cursor:pointer; min-height:22px; line-height:22px; font-weight:500; }
|
|
1835
1762
|
summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
1836
1763
|
.shape-inspector div { max-height:260px; overflow:auto; }
|
|
@@ -1840,35 +1767,12 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1840
1767
|
.shape-inspector dd { margin:0; overflow-wrap:anywhere; white-space:pre-wrap; }
|
|
1841
1768
|
.shape-inspector h3 { margin:12px 0 5px; font-size:11px; }
|
|
1842
1769
|
.shape-inspector a { color:var(--_vv-accent); overflow-wrap:anywhere; }
|
|
1843
|
-
.edit-controls p,.layer-controls p { margin:6px 0; color:var(--_vv-muted); overflow-wrap:anywhere; }
|
|
1844
|
-
.edit-controls textarea { display:block; width:100%; resize:vertical; max-height:180px; margin-top:4px; background:var(--_vv-secondary); }
|
|
1845
|
-
.edit-controls label { display:block; margin-top:8px; }
|
|
1846
|
-
.edit-actions { display:flex; flex-wrap:wrap; gap:4px; margin-top:8px; }
|
|
1847
|
-
.edit-actions button { font-size:11px; padding:3px 7px; }
|
|
1848
|
-
.edit-actions [data-edit="apply"]:enabled { background:var(--_vv-accent); border-color:var(--_vv-accent); color:var(--_vv-accent-ink); }
|
|
1849
|
-
.edit-controls [data-geometry] { min-width:0; margin:8px 0 0; padding:6px; border:1px solid var(--_vv-border); }
|
|
1850
|
-
.edit-controls [data-geometry-field] { display:block; width:100%; min-width:0; margin-top:4px; }
|
|
1851
|
-
.edit-controls [data-geometry-error] { color:var(--_vv-danger); }
|
|
1852
|
-
.edit-controls [data-edit-error] { color:var(--_vv-danger); }
|
|
1853
|
-
.edit-controls [data-edit-diagnostics] { max-height:100px; overflow:auto; padding-left:16px; }
|
|
1854
|
-
.layer-controls [data-layer-list] { max-height:240px; overflow:auto; }
|
|
1855
|
-
.layer-controls fieldset { border:1px solid var(--_vv-border); margin:6px 0; padding:6px; min-width:0; }
|
|
1856
|
-
.layer-controls legend { max-width:100%; overflow-wrap:anywhere; }
|
|
1857
|
-
.layer-controls fieldset div { display:flex; align-items:center; gap:6px; margin:3px 0; }
|
|
1858
|
-
.layer-controls label { display:flex; align-items:center; gap:6px; overflow-wrap:anywhere; }
|
|
1859
|
-
.layer-controls input { flex-shrink:0; width:16px; height:16px; min-height:16px; padding:0; accent-color:var(--_vv-accent); }
|
|
1860
|
-
.notes ul { max-height:220px; overflow:auto; padding-left:17px; margin:6px 0 0; color:var(--_vv-muted); }
|
|
1861
|
-
.notes li { margin:5px 0; overflow-wrap:anywhere; }
|
|
1862
|
-
.notes-strip { flex:none; display:flex; align-items:center; justify-content:space-between; min-height:25.5px; padding:0 12px; border-top:1px solid var(--_vv-border); background:var(--_vv-bg); color:var(--_vv-muted); font-size:10px; }
|
|
1863
|
-
.notes-strip button { min-height:24.5px; padding:2px 0; border:0; background:transparent; color:var(--_vv-muted); font-size:11px; }
|
|
1864
|
-
.notes-strip button::before { content:"\u25B8"; margin-right:6px; }
|
|
1865
|
-
.notes-strip button[aria-expanded="true"]::before { content:"\u25BE"; }
|
|
1866
1770
|
.status { flex:none; display:flex; align-items:center; justify-content:space-between; gap:12px; min-width:0; min-height:29px; padding:0 8px 0 12px; border-top:1px solid var(--_vv-border); color:var(--_vv-muted); background:var(--_vv-surface); font-size:10px; }
|
|
1867
1771
|
.status-message { display:flex; gap:16px; min-width:0; }
|
|
1868
1772
|
.status-message span { overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
|
|
1869
1773
|
.empty { max-width:360px; margin:60px auto; padding:16px; text-align:center; color:var(--_vv-muted); font-size:12px; }
|
|
1870
1774
|
.empty strong { display:block; color:var(--_vv-ink); font-size:18px; font-weight:500; margin-bottom:8px; }
|
|
1871
|
-
@media(max-width:1100px) { .ribbon-hint { display:none; }
|
|
1775
|
+
@media(max-width:1100px) { .ribbon-hint { display:none; } }
|
|
1872
1776
|
@media(max-width:760px) {
|
|
1873
1777
|
button,select,input,textarea { min-height:44px; }
|
|
1874
1778
|
button { min-width:44px; }
|
|
@@ -1880,22 +1784,14 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1880
1784
|
.workspace { display:block; overflow:auto; }
|
|
1881
1785
|
.viewport { height:340px; min-height:260px; padding:16px 4px; }
|
|
1882
1786
|
.inspector-pane { width:100%; overflow:visible; border-left:0; border-top:1px solid var(--_vv-border); }
|
|
1883
|
-
.inspector-body { gap:8px; padding:10px; }
|
|
1884
|
-
.inspector-card,.edit-controls,.layer-controls { font-size:12px; }
|
|
1885
|
-
.layer-controls label { min-height:44px; }
|
|
1886
|
-
.layer-controls input { min-width:20px; width:20px; height:20px; min-height:20px; }
|
|
1887
|
-
.notes-strip { min-height:44px; padding:0 10px; }
|
|
1888
|
-
.notes-strip button { min-height:44px; }
|
|
1889
1787
|
.status { flex-wrap:wrap; gap:0; padding:4px 8px; }
|
|
1890
1788
|
.status-message { width:100%; min-height:18px; }
|
|
1891
1789
|
}
|
|
1892
1790
|
@media(pointer:coarse) {
|
|
1893
1791
|
button,select,input,textarea { min-height:44px; }
|
|
1894
1792
|
button { min-width:44px; }
|
|
1895
|
-
summary
|
|
1793
|
+
summary { min-height:44px; line-height:44px; }
|
|
1896
1794
|
.ribbon-content { min-height:96px; }
|
|
1897
|
-
.notes-strip button { min-height:44px; height:44px; }
|
|
1898
|
-
.layer-controls input { min-height:20px; }
|
|
1899
1795
|
}
|
|
1900
1796
|
/* Suite ribbon: tabs lead directly into Visio command groups. */
|
|
1901
1797
|
.ribbon-content { min-height:104px; padding:4px 4px; }
|
|
@@ -1910,8 +1806,6 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1910
1806
|
.viewport { flex:1; width:100%; height:100%; min-height:0; padding:16px 4px; }
|
|
1911
1807
|
.inspector-pane { position:absolute; inset:0 0 0 auto; width:min(320px,100%); z-index:4; overflow:auto; border-left:1px solid var(--_vv-border); box-shadow:-8px 0 24px #0002; }
|
|
1912
1808
|
.pane-close { display:block; width:44px; height:44px; padding:0; font-size:22px; background:transparent; border:0; }
|
|
1913
|
-
.inspector-kind { margin-left:auto; }
|
|
1914
|
-
.notes-strip { display:none; }
|
|
1915
1809
|
.status { min-height:48px; padding:2px 8px; }
|
|
1916
1810
|
.status-message { display:none; }
|
|
1917
1811
|
}
|
|
@@ -1922,12 +1816,7 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1922
1816
|
.ribbon-command { font-size:12px; min-width:88px; }
|
|
1923
1817
|
.ribbon-hint { font-size:12px; line-height:20px; flex:1; }
|
|
1924
1818
|
.group-label { font-size:11px; line-height:14px; }
|
|
1925
|
-
.inspector-card,.edit-controls,.layer-controls { font-size:12px; line-height:18px; }
|
|
1926
|
-
.selection-hint,.document-card dl { font-size:12px; }
|
|
1927
1819
|
.pane-heading { font-size:12px; }
|
|
1928
|
-
.inspector-pane .pane-heading { position:sticky; top:0; z-index:1; background:var(--_vv-secondary); flex:none; }
|
|
1929
|
-
.status .notes-strip { border:0; padding:0 8px; background:transparent; min-height:28px; }
|
|
1930
|
-
.status .notes-strip>span { display:none; }
|
|
1931
1820
|
.status-message { flex:1; }
|
|
1932
1821
|
@media(max-width:760px) {
|
|
1933
1822
|
#home-panel { overflow:visible; min-height:54px; padding:4px; }
|
|
@@ -1941,7 +1830,6 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1941
1830
|
.ribbon-tools .ribbon-command { min-width:88px; font-size:12px; }
|
|
1942
1831
|
.ribbon-tools .search-feedback { display:block; }
|
|
1943
1832
|
.status { flex-wrap:nowrap; gap:4px; min-height:48px; }
|
|
1944
|
-
.status .notes-strip { display:none; }
|
|
1945
1833
|
}
|
|
1946
1834
|
@media(prefers-reduced-motion:reduce) { * { scroll-behavior:auto !important; } }
|
|
1947
1835
|
`;
|
|
@@ -1950,16 +1838,16 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1950
1838
|
var backstage_default = "/* Visio's File tab and backstage. */\n:host {\n position: relative;\n}\n/* The shared office-ui-backstage draws the File column; these style Visio's page content. */\n.backstage-page h1 {\n margin: 0 0 24px;\n font-size: 34px;\n font-weight: 300;\n}\n.backstage-page h2 {\n margin: 20px 0 8px;\n font-size: 16px;\n font-weight: 600;\n}\n.backstage-file {\n margin-top: 0 !important;\n font-size: 20px !important;\n font-weight: 400 !important;\n overflow-wrap: anywhere;\n}\n.backstage-facts {\n display: grid;\n grid-template-columns: max-content 1fr;\n gap: 8px 24px;\n max-width: 520px;\n margin: 0;\n font-size: 13px;\n}\n.backstage-facts dt {\n color: var(--_vv-muted);\n}\n.backstage-facts dd {\n margin: 0;\n overflow-wrap: anywhere;\n}\n.backstage-action {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n width: min(420px, 100%);\n min-height: 64px;\n margin: 0 0 10px;\n padding: 10px 16px;\n text-align: left;\n background: var(--_vv-surface);\n}\n.backstage-action strong {\n font-size: 14px;\n font-weight: 600;\n}\n.backstage-action span,\n.backstage-muted,\n.backstage-note-count {\n color: var(--_vv-muted);\n font-size: 12px;\n}\n.backstage-templates {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n}\n.backstage-templates .backstage-action,\n.backstage-templates ::slotted(*) {\n width: 200px;\n min-height: 120px;\n}\n/* Account: the shared profile editor, then Visio's product information. */\n.backstage-page office-ui-account {\n max-width: 560px;\n}\n.backstage-product {\n margin-top: 24px;\n}\n/* Share with people: a live session between windows of this browser. */\n.share-panel {\n max-width: 560px;\n margin-bottom: 16px;\n}\n.share-panel h2 {\n margin-top: 0 !important;\n}\n.share-field {\n display: grid;\n gap: 4px;\n max-width: 320px;\n margin: 12px 0;\n font-size: 13px;\n}\n.share-room {\n min-height: 30px;\n padding: 2px 8px;\n border: 1px solid var(--_vv-border);\n border-radius: 3px;\n background: var(--_vv-surface);\n color: inherit;\n font: inherit;\n}\n.share-buttons button {\n min-height: 32px;\n padding: 0 16px;\n}\n.share-buttons button[hidden] {\n display: none;\n}\n.share-status {\n min-height: 20px;\n font-size: 13px;\n}\n";
|
|
1951
1839
|
|
|
1952
1840
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/canvas.css?raw
|
|
1953
|
-
var canvas_default = "/*\n * Drawing canvas focus. SVG outlines are drawn in drawing units (inches here), so a browser\n * focus ring on a shape becomes a page-sized blob. Shapes show focus with a dashed accent\n * stroke instead, only for keyboard focus; selection keeps its solid accent stroke.\n */\n.paper [data-shape-id]:focus,\n.paper [data-shape-id]:focus-visible {\n outline: none;\n}\n.paper [data-shape-id]:focus-visible > [data-geometry] {\n stroke: var(--_vv-focus) !important;\n stroke-width: 0.04 !important;\n stroke-dasharray: 0.08 0.05;\n}\n\n.paper [data-line-endpoint],\n.paper [data-resize-handle],\n.rotation-overlay [data-rotation-handle] {\n fill: var(--_vv-accent);\n stroke:
|
|
1841
|
+
var canvas_default = "/*\n * Drawing canvas focus. SVG outlines are drawn in drawing units (inches here), so a browser\n * focus ring on a shape becomes a page-sized blob. Shapes show focus with a dashed accent\n * stroke instead, only for keyboard focus; selection keeps its solid accent stroke.\n */\n.paper [data-shape-id]:focus,\n.paper [data-shape-id]:focus-visible {\n outline: none;\n}\n.paper [data-shape-id]:focus-visible > [data-geometry] {\n stroke: var(--_vv-focus) !important;\n stroke-width: 0.04 !important;\n stroke-dasharray: 0.08 0.05;\n}\n\n/* Visio's selection: white handles with a grey outline on a thin grey frame. */\n.paper [data-line-endpoint],\n.paper [data-resize-handle],\n.rotation-overlay [data-rotation-handle] {\n fill: #fff;\n stroke: var(--_vv-handle, #7a7a7a);\n stroke-width: 1.25px;\n cursor: crosshair;\n touch-action: none;\n pointer-events: all;\n}\n.paper [data-resize-handle]:hover,\n.paper [data-line-endpoint]:hover,\n.rotation-overlay [data-rotation-handle]:hover {\n fill: var(--_vv-accent-soft, #dfe5f6);\n}\n.paper [data-resize-handle='n'],\n.paper [data-resize-handle='s'] {\n cursor: ns-resize;\n}\n.paper [data-resize-handle='e'],\n.paper [data-resize-handle='w'] {\n cursor: ew-resize;\n}\n.paper [data-resize-handle='ne'],\n.paper [data-resize-handle='sw'] {\n cursor: nesw-resize;\n}\n.paper [data-resize-handle='nw'],\n.paper [data-resize-handle='se'] {\n cursor: nwse-resize;\n}\n.rotation-overlay [data-rotation-handle] {\n stroke: transparent;\n cursor: grab;\n}\n.rotation-overlay .rotation-glyph {\n fill: none;\n stroke: var(--_vv-handle, #7a7a7a);\n stroke-width: 1.5px;\n stroke-linecap: round;\n stroke-linejoin: round;\n pointer-events: none;\n}\n.rotation-overlay [data-rotation-handle]:hover + .rotation-glyph {\n stroke: var(--_vv-accent);\n}\n.paper [data-resize-frame] {\n fill: none;\n stroke: var(--_vv-handle, #7a7a7a);\n stroke-width: 1px;\n pointer-events: none;\n}\n/*\n * A selection with no frame or endpoint handles (several shapes, a group, a glued connector) is\n * marked on the shapes themselves; a framed shape keeps its own outline, as in Visio.\n */\n.viewport:not([data-selection-frame]) .paper [data-selected='true'] > [data-geometry] {\n stroke: var(--_vv-accent) !important;\n stroke-width: 0.025 !important;\n}\n.viewport:not([data-selection-frame]) .paper [role='group'][data-selected='true'] [data-geometry] {\n stroke: var(--_vv-accent) !important;\n stroke-dasharray: 0.06 0.04;\n}\n/* Handles step aside while a shape's text is edited in place. */\n.viewport[data-text-editing] [data-resize-overlay],\n.viewport[data-text-editing] .rotation-overlay,\n.viewport[data-text-editing] [data-line-endpoint] {\n display: none;\n}\n.paper [data-resize-frame-preview] {\n stroke-dasharray: 5 3;\n}\n.paper .endpoint-preview,\n.paper .rotation-preview {\n stroke: var(--_vv-accent);\n stroke-width: 1.5px;\n stroke-dasharray: 5 3;\n pointer-events: none;\n}\n/* Visio shows no line from the pin to the rotation handle. */\n.rotation-overlay .rotation-stem {\n display: none;\n}\n\n.rotation-overlay {\n position: absolute;\n z-index: 1;\n pointer-events: none;\n}\n/* View > Visual Aids > Connection Points: blue x markers (presentation only, never exported). */\n.paper [data-connection-points] path {\n fill: none;\n stroke: #1f6fd1;\n stroke-width: 1.25px;\n pointer-events: none;\n}\n.paper [data-connection-points] path[data-inherited='true'] {\n stroke-opacity: 0.55;\n}\n.paper [data-connection-points] path[data-selected='true'] {\n stroke: var(--_vv-accent);\n stroke-width: 2.5px;\n}\n/* A connector end over a connection point glues to that point. */\n.paper .connect-point-target {\n fill: none;\n stroke: #2e9d43;\n stroke-width: 2px;\n pointer-events: none;\n}\n/* Connectors glued to dragged shapes, re-routed live until the move is committed. */\n.paper .connector-preview {\n fill: none;\n stroke: var(--_vv-accent);\n stroke-width: 1.5px;\n stroke-dasharray: 4 3;\n pointer-events: none;\n}\n";
|
|
1954
1842
|
|
|
1955
1843
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/ribbon.css?raw
|
|
1956
|
-
var ribbon_default = "/*\n * Microsoft Visio ribbon layout on the shared ooxml-ui controls. The shared --office-* tokens come\n * from the bridge in styles/theme.ts. Loaded after the legacy styles.ts.\n */\n\n/* Tab row: Quick Access Toolbar, then Visio's tabs. */\n.ribbon-head {\n display: flex;\n align-items: stretch;\n min-width: 0;\n border-bottom: 1px solid var(--_vv-border);\n}\n.
|
|
1844
|
+
var ribbon_default = "/*\n * Microsoft Visio ribbon layout on the shared ooxml-ui controls. The shared --office-* tokens come\n * from the bridge in styles/theme.ts. Loaded after the legacy styles.ts.\n */\n\n/* Tab row: Quick Access Toolbar, then Visio's tabs. */\n.ribbon-head {\n display: flex;\n align-items: stretch;\n min-width: 0;\n border-bottom: 1px solid var(--_vv-border);\n}\n.ribbon-head .ribbon-tabs {\n flex: 0 1 auto;\n min-width: 0;\n height: 36px;\n border-bottom: 0;\n overflow-x: auto;\n scrollbar-width: none;\n}\n.ribbon-head .ribbon-tabs button {\n flex: none;\n min-height: 35px;\n padding: 6px 12px;\n font-size: 13px;\n}\n\n/* Panels: groups of large commands and three-row stacks, as dense as Visio's. */\n.ribbon-content {\n min-height: 96px;\n padding: 2px 2px 0;\n}\n.ribbon-row {\n display: flex;\n flex-wrap: nowrap;\n align-items: stretch;\n gap: 0;\n padding: 0;\n border: 0;\n background: transparent;\n}\n.ribbon-row office-ui-ribbon-group,\n.tools-content office-ui-ribbon-group {\n min-width: 0;\n}\noffice-ui-ribbon-group office-ui-button,\noffice-ui-ribbon-group office-ui-menu-button {\n --office-target-size: 24px;\n}\noffice-ui-ribbon-group [data-size='large'] {\n --office-target-size: 30px;\n}\noffice-ui-button[variant='stacked']::part(button) {\n min-width: 48px;\n min-height: 66px;\n padding: 2px 6px;\n font-size: 12px;\n}\noffice-ui-menu-button[variant='stacked']::part(button) {\n min-width: 48px;\n min-height: 50px;\n font-size: 12px;\n}\noffice-ui-ribbon-group [data-size='small']::part(button) {\n justify-content: flex-start;\n font-size: 12px;\n}\noffice-ui-ribbon-stack:not([orientation]) {\n justify-content: flex-start;\n padding-top: 2px;\n}\noffice-ui-ribbon-stack:not([orientation]) > * {\n min-height: 24px;\n}\noffice-ui-ribbon-group > office-ui-ribbon-stack > office-ui-ribbon-stack[orientation] {\n min-height: 32px;\n}\noffice-ui-select[data-combo] {\n --office-target-size: 24px;\n}\noffice-ui-menu-button[data-active]::part(button) {\n background: var(--_vv-accent-soft);\n box-shadow: inset 0 0 0 1px var(--_vv-accent);\n}\n[data-unsupported] {\n cursor: not-allowed;\n}\n.ribbon-check {\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: 24px;\n padding: 0 6px;\n font-size: 12px;\n white-space: nowrap;\n cursor: pointer;\n}\n.ribbon-check[data-unsupported] {\n color: var(--_vv-muted);\n opacity: 0.6;\n}\n.ribbon-hint {\n display: none;\n}\n\n/* Drawing window with optional rulers. */\n.canvas-area {\n display: grid;\n flex: 1;\n min-width: 0;\n min-height: 0;\n grid-template-columns: 0 1fr;\n grid-template-rows: 0 1fr;\n}\n.canvas-area[data-ruler='true'] {\n grid-template-columns: 18px 1fr;\n grid-template-rows: 18px 1fr;\n}\n.canvas-area > .viewport {\n grid-column: 2;\n grid-row: 2;\n}\n.ruler,\n.ruler-corner {\n display: none;\n background: var(--_vv-surface);\n}\n.canvas-area[data-ruler='true'] > .ruler,\n.canvas-area[data-ruler='true'] > .ruler-corner {\n display: block;\n}\n.ruler-corner {\n grid-column: 1;\n grid-row: 1;\n border-right: 1px solid var(--_vv-border);\n border-bottom: 1px solid var(--_vv-border);\n}\n/* The shared office-ui-ruler draws ticks, labels and its own edge. */\n.ruler-h {\n grid-column: 2;\n grid-row: 1;\n}\n.ruler-v {\n grid-column: 1;\n grid-row: 2;\n}\n\n.page-bar {\n display: flex;\n flex: none;\n align-items: stretch;\n min-width: 0;\n border-top: 1px solid var(--_vv-border);\n background: var(--_vv-secondary);\n}\n.page-bar office-ui-menu-button {\n --office-target-size: 28px;\n flex: none;\n padding: 0 2px;\n}\n.page-tabs {\n flex: 1;\n min-width: 0;\n border-top: 0;\n}\noffice-ui-status-bar.status {\n gap: 16px;\n min-height: 29px;\n padding: 0 8px 0 12px;\n font-size: 11px;\n background: var(--_vv-surface);\n color: var(--_vv-ink);\n}\noffice-ui-status-item[value=''] {\n display: none;\n}\n.viewport[data-tool='ellipse'],\n.viewport[data-tool='ellipse'] .paper [data-shape-id],\n.viewport[data-tool='rectangle'],\n.viewport[data-tool='rectangle'] .paper [data-shape-id],\n.viewport[data-tool='line'],\n.viewport[data-tool='line'] .paper [data-shape-id],\n.viewport[data-tool='freeform'],\n.viewport[data-tool='freeform'] .paper [data-shape-id],\n.viewport[data-tool='arc'],\n.viewport[data-tool='arc'] .paper [data-shape-id],\n.viewport[data-tool='pencil'],\n.viewport[data-tool='pencil'] .paper [data-shape-id],\n.viewport[data-tool='connector'],\n.viewport[data-tool='connector'] .paper [data-shape-id],\n.viewport[data-tool='connection-point'],\n.viewport[data-tool='connection-point'] .paper [data-shape-id] {\n cursor: crosshair;\n}\n.viewport[data-tool='ellipse'],\n.viewport[data-tool='rectangle'],\n.viewport[data-tool='line'],\n.viewport[data-tool='freeform'],\n.viewport[data-tool='arc'],\n.viewport[data-tool='pencil'],\n.viewport[data-tool='connector'] {\n touch-action: none;\n}\n/* Connector tool: the shape under the pointer is the glue target (Visio's green glue box). */\n.viewport .paper [data-connect-target='true'] > path[data-geometry] {\n /* Drawing units (inches), like the canvas focus stroke; wins over a focused shape's dashes. */\n stroke: var(--_vv-accent) !important;\n stroke-width: 0.05 !important;\n stroke-opacity: 1 !important;\n stroke-dasharray: none !important;\n}\npath.draw-preview {\n fill: none;\n}\n.draw-preview {\n fill: var(--_vv-accent-soft);\n stroke: var(--_vv-accent);\n stroke-width: 1.5px;\n stroke-dasharray: 4 3;\n pointer-events: none;\n}\n.viewport[data-grid='true'] .paper {\n --_vv-grid-minor: rgb(0 0 0 / 7%);\n --_vv-grid-major: rgb(0 0 0 / 16%);\n background-image:\n linear-gradient(to right, var(--_vv-grid-major) 1px, transparent 1px),\n linear-gradient(to top, var(--_vv-grid-major) 1px, transparent 1px),\n linear-gradient(to right, var(--_vv-grid-minor) 1px, transparent 1px),\n linear-gradient(to top, var(--_vv-grid-minor) 1px, transparent 1px);\n background-size:\n var(--vv-inch, 96px) var(--vv-inch, 96px),\n var(--vv-inch, 96px) var(--vv-inch, 96px),\n calc(var(--vv-inch, 96px) / 4) calc(var(--vv-inch, 96px) / 4),\n calc(var(--vv-inch, 96px) / 4) calc(var(--vv-inch, 96px) / 4);\n background-position: left bottom;\n}\n:host(:fullscreen) {\n width: 100vw;\n height: 100vh;\n}\n\n@media (max-width: 760px) {\n .ribbon-row {\n flex: 1;\n min-width: 0;\n }\n .ribbon-tools .tools-content office-ui-ribbon-group {\n width: 100%;\n }\n office-ui-status-bar.status {\n gap: 4px;\n min-height: 48px;\n }\n office-ui-status-item:not([data-page-status]) {\n display: none;\n }\n .zoom-controls {\n flex: 1;\n min-width: 0;\n --office-zoom-slider-width: 0;\n }\n}\n\n/* Visio's Tell me box sits right after the tabs. */\n.tell-me {\n flex: 0 1 280px;\n min-width: 140px;\n margin: 0 8px;\n --office-target-size: 28px;\n}\n.presentation-mode {\n --office-target-size: 24px;\n}\n@media (max-width: 760px) {\n .tell-me {\n display: none;\n }\n}\n";
|
|
1957
1845
|
|
|
1958
1846
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/shapes.css?raw
|
|
1959
|
-
var shapes_default = "/* Visio's Shapes window:
|
|
1847
|
+
var shapes_default = "/* Visio's Shapes window: Search shapes, More/Quick Shapes rows and a two-column master grid. */\n.shapes-pane {\n display: flex;\n flex: 0 0 232px;\n flex-direction: column;\n width: 232px;\n min-width: 0;\n overflow: hidden;\n border-right: 1px solid var(--_vv-border);\n background: var(--_vv-surface);\n}\n.shapes-pane .pane-heading {\n height: 46px;\n padding: 10px 8px 4px 12px;\n border-bottom: 0;\n font-size: 21px;\n font-weight: 300;\n color: var(--_vv-accent);\n}\n.pane-collapse {\n min-height: 28px;\n width: 28px;\n padding: 0;\n border-color: transparent;\n background: transparent;\n font-size: 18px;\n line-height: 1;\n}\n.shapes-search-box {\n position: relative;\n margin: 6px 12px 10px;\n}\n.shapes-search-box office-ui-icon {\n position: absolute;\n top: 50%;\n right: 8px;\n translate: 0 -50%;\n color: var(--_vv-accent);\n font-size: 15px;\n pointer-events: none;\n}\n#shapes-stencils,\n#shapes-search {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 4px 0 8px;\n}\n.shapes-row {\n display: flex;\n align-items: center;\n width: 100%;\n min-height: 30px;\n padding: 0 12px;\n border: 0;\n border-radius: 0;\n background: transparent;\n font-size: 12px;\n text-align: left;\n}\n/* More Shapes opens a menu, so it alone carries Visio's small arrow, right after its label. */\n.shapes-row[aria-haspopup]::after {\n content: '';\n margin-left: 12px;\n border: 4px solid transparent;\n border-left-color: currentColor;\n}\n.shapes-row:hover,\n.stencil-header:hover {\n background: var(--_vv-secondary);\n}\n.stencil-header {\n display: flex;\n align-items: stretch;\n margin: 1px 6px;\n}\n/* The open stencil is Visio's filled, bold title bar. */\n.stencil-header:has(.stencil-title[aria-expanded='true']),\n.stencil-header:has(.stencil-title[aria-expanded='true']):hover {\n background: color-mix(in srgb, var(--_vv-accent) 28%, var(--_vv-surface));\n}\n.stencil-title {\n flex: 1;\n min-width: 0;\n padding: 5px 6px;\n border: 0;\n border-radius: 0;\n background: transparent;\n font-size: 12px;\n font-weight: 400;\n text-align: left;\n}\n.stencil-title[aria-expanded='true'] {\n font-weight: 600;\n}\n.stencil-close {\n min-height: 0;\n width: 26px;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: var(--_vv-muted);\n font-size: 14px;\n}\n#shapes-quick {\n border-bottom: 1px solid var(--_vv-border);\n}\n.stencil-header + .masters {\n margin-top: 6px;\n border-top: 1px solid var(--_vv-border);\n}\n#shapes-quick[hidden],\n.masters[hidden] {\n display: none;\n}\n.masters {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 2px;\n margin: 0;\n padding: 4px 6px;\n list-style: none;\n}\n.masters li[hidden] {\n display: none;\n}\n.master {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-height: 40px;\n padding: 4px 6px;\n border-color: transparent;\n background: transparent;\n font-size: 12px;\n line-height: 1.2;\n text-align: left;\n cursor: grab;\n}\n.master svg {\n flex: none;\n width: 28px;\n height: 28px;\n fill: var(--_vv-surface);\n stroke: var(--_vv-ink);\n stroke-width: 1;\n stroke-linejoin: round;\n}\n.master[data-unsupported] {\n cursor: not-allowed;\n opacity: 0.45;\n}\n.master[data-unsupported]:hover {\n border-color: transparent;\n background: transparent;\n}\n.shapes-search-field {\n display: block;\n width: 100%;\n padding-right: 28px;\n border-radius: 0;\n}\n.shapes-empty {\n margin: 8px 12px;\n color: var(--_vv-muted);\n font-size: 12px;\n}\n@media (max-width: 760px) {\n .shapes-pane {\n position: absolute;\n inset: 0 auto 0 0;\n z-index: 3;\n width: min(260px, 100%);\n box-shadow: 8px 0 24px #0002;\n }\n .master {\n min-height: 44px;\n }\n}\n.shapes-strip {\n display: flex;\n flex: 0 0 28px;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n width: 28px;\n min-width: 28px;\n padding: 8px 0;\n border: 0;\n border-right: 1px solid var(--_vv-border);\n border-radius: 0;\n background: var(--_vv-secondary);\n color: var(--_vv-accent);\n font-size: 16px;\n}\n.shapes-strip[hidden] {\n display: none;\n}\n.shapes-strip-label {\n writing-mode: vertical-rl;\n color: var(--_vv-ink);\n font-size: 12px;\n}\n/* Visio's floating Pan & Zoom window. */\n.pan-zoom {\n position: absolute;\n right: 16px;\n bottom: 16px;\n z-index: 5;\n width: 240px;\n border: 1px solid var(--_vv-border);\n background: var(--_vv-surface);\n box-shadow: 0 6px 20px rgb(0 0 0 / 18%);\n}\n.pan-zoom[hidden] {\n display: none;\n}\n.pan-zoom-heading {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2px 4px 2px 10px;\n border-bottom: 1px solid var(--_vv-border);\n font-size: 12px;\n font-weight: 600;\n}\n.pan-zoom-close {\n min-height: 24px;\n width: 24px;\n padding: 0;\n border-color: transparent;\n background: transparent;\n}\n.pan-zoom-view {\n display: grid;\n place-items: center;\n height: 180px;\n padding: 8px;\n background: var(--_vv-bg);\n cursor: crosshair;\n touch-action: none;\n}\n.pan-zoom-view svg {\n max-width: 100%;\n max-height: 100%;\n background: #fff;\n box-shadow: 0 1px 3px rgb(0 0 0 / 20%);\n}\n.pan-zoom-frame {\n fill: rgb(220 38 38 / 8%);\n stroke: #dc2626;\n stroke-width: 2px;\n}\n";
|
|
1960
1848
|
|
|
1961
1849
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/size-position.css?raw
|
|
1962
|
-
var size_position_default = ".size-position {\n position: absolute;\n
|
|
1850
|
+
var size_position_default = "/* Visio's Size & Position window: anchored at the bottom left of the drawing, a vertical caption\n strip and rows of label, value and unit. */\n.size-position {\n position: absolute;\n left: 16px;\n bottom: 16px;\n z-index: 8;\n display: flex;\n width: 236px;\n max-width: calc(100% - 32px);\n max-height: calc(100% - 32px);\n overflow: auto;\n background: var(--_vv-surface);\n color: var(--_vv-ink);\n border: 1px solid var(--_vv-border);\n box-shadow: 0 2px 8px #0002;\n font-size: 12px;\n}\n.size-position[hidden] {\n display: none;\n}\n/* Anchored to the drawing window, so it clears the Shapes window or its minimised strip. */\n.shapes-pane:not([hidden]) ~ .size-position {\n left: 248px;\n}\n.shapes-strip:not([hidden]) ~ .size-position {\n left: 44px;\n}\n@media (max-width: 760px) {\n .shapes-pane:not([hidden]) ~ .size-position {\n left: 16px;\n }\n}\n.size-caption {\n display: flex;\n flex: none;\n flex-direction: column;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n width: 24px;\n padding: 8px 0 4px;\n}\n.size-caption strong {\n writing-mode: vertical-rl;\n color: var(--_vv-accent);\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n white-space: nowrap;\n}\n.size-caption button {\n width: 22px;\n min-width: 0;\n min-height: 22px;\n padding: 0;\n border: 0;\n background: transparent;\n color: var(--_vv-muted);\n font-size: 15px;\n line-height: 1;\n}\n.size-body {\n flex: 1;\n min-width: 0;\n padding: 4px 6px 4px 0;\n}\n.size-position label {\n display: grid;\n grid-template-columns: 58px 1fr auto;\n align-items: center;\n gap: 4px;\n border-bottom: 1px solid var(--_vv-border);\n}\n.size-position label > span:first-child {\n padding: 4px 6px;\n border-right: 1px solid var(--_vv-border);\n color: var(--_vv-muted);\n}\n.size-position input {\n min-width: 0;\n width: 100%;\n min-height: 0;\n box-sizing: border-box;\n padding: 3px 4px;\n font: inherit;\n color: inherit;\n background: transparent;\n border: 0;\n border-radius: 0;\n}\n.size-position input:focus-visible {\n outline: 1px solid var(--_vv-focus);\n outline-offset: -1px;\n}\n.size-unit {\n padding-right: 4px;\n color: var(--_vv-muted);\n}\n.size-position p {\n margin: 6px 6px 2px;\n color: var(--_vv-muted);\n}\n.size-position p:empty {\n display: none;\n}\n.size-position [role='alert'] {\n color: var(--_vv-danger);\n}\n";
|
|
1963
1851
|
|
|
1964
1852
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/text-tool.css?raw
|
|
1965
1853
|
var text_tool_default = ".viewport[data-tool='text'] {\n cursor: text;\n touch-action: none;\n}\n.text-box-draft {\n box-sizing: border-box;\n overflow: auto;\n position: absolute;\n z-index: 3;\n width: 300px;\n max-width: calc(100% - 16px);\n padding: 12px;\n background: var(--_vv-surface);\n color: var(--_vv-ink);\n border: 1px solid var(--_vv-accent);\n border-radius: 4px;\n box-shadow: 0 2px 12px #0003;\n}\n.text-box-draft label {\n display: grid;\n gap: 6px;\n font-weight: 600;\n}\n.text-box-draft textarea {\n box-sizing: border-box;\n width: 100%;\n resize: vertical;\n font: inherit;\n}\n.text-box-draft p {\n margin: 8px 0;\n font-size: 12px;\n}\n.text-box-draft > div {\n display: flex;\n gap: 8px;\n}\n.text-box-draft-frame {\n pointer-events: none;\n}\n.paper [data-shape-id][data-selected='true'] > [data-text-hit],\n.paper [data-shape-id]:focus-visible > [data-text-hit] {\n stroke: var(--_vv-accent);\n stroke-width: 1px;\n}\n";
|
|
@@ -1988,6 +1876,194 @@ var layout_default = "/* Layout, Assign to Layer, Select by Type, Paste Special
|
|
|
1988
1876
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/text-features.css?raw
|
|
1989
1877
|
var text_features_default = "/* Text dialog, Symbol, Field and Language dialogs, and the Text Block tool overlay. */\n.text-dialog-tabs {\n display: flex;\n flex-wrap: wrap;\n gap: 2px;\n margin: 0 0 12px;\n border-bottom: 1px solid var(--_vv-border);\n}\n.text-dialog-tabs [role='tab'] {\n padding: 6px 10px;\n color: inherit;\n background: transparent;\n border: 1px solid transparent;\n border-bottom: 2px solid transparent;\n cursor: pointer;\n font: inherit;\n}\n.text-dialog-tabs [role='tab'][aria-selected='true'] {\n border-bottom-color: var(--_vv-accent);\n font-weight: 600;\n}\n.text-dialog-panel {\n display: grid;\n gap: 10px;\n min-width: min(420px, 80vw);\n}\n.field-dialog label,\n.language-dialog label {\n min-width: min(420px, 80vw);\n margin: 0 0 10px;\n}\n.text-dialog-panel label,\n.field-dialog label,\n.language-dialog label {\n display: grid;\n grid-template-columns: minmax(150px, 1fr) minmax(140px, 1fr);\n align-items: center;\n gap: 12px;\n}\n.text-dialog-panel label.text-dialog-check {\n display: flex;\n gap: 8px;\n}\n.text-dialog-panel input:not([type='checkbox']),\n.text-dialog-panel select,\n.field-dialog input,\n.field-dialog select,\n.language-dialog select {\n box-sizing: border-box;\n width: 100%;\n min-height: 28px;\n padding: 4px 6px;\n color: inherit;\n background: var(--_vv-surface);\n border: 1px solid var(--_vv-border);\n border-radius: 3px;\n}\n.text-dialog .text-dialog-note,\n.field-dialog .text-dialog-note,\n.symbol-dialog .text-dialog-note {\n max-width: 440px;\n margin: 8px 0 0;\n font-size: 12px;\n}\n.text-dialog [role='alert'],\n.field-dialog [role='alert'],\n.symbol-dialog [role='alert'],\n.language-dialog [role='alert'] {\n margin: 6px 0 0;\n color: var(--office-error, #b00020);\n}\n.symbol-dialog office-ui-symbol-picker {\n min-width: min(360px, 80vw);\n}\n@media (max-width: 480px) {\n .text-dialog-panel label,\n .field-dialog label,\n .language-dialog label {\n grid-template-columns: 1fr;\n gap: 5px;\n }\n}\n\n/* Text Block tool: the text block frame replaces the shape's resize and rotation handles. */\n.viewport[data-text-block='true'] [data-resize-overlay],\n.viewport[data-text-block='true'] .rotation-overlay {\n display: none;\n}\n.paper [data-text-block-frame] {\n fill: transparent;\n stroke: var(--_vv-accent);\n stroke-width: 1px;\n stroke-dasharray: 4 3;\n cursor: move;\n pointer-events: all;\n touch-action: none;\n}\n.paper circle[data-text-block-handle] {\n fill: white;\n stroke: var(--_vv-accent);\n stroke-width: 1.5px;\n cursor: crosshair;\n pointer-events: all;\n touch-action: none;\n}\n.paper circle[data-text-block-handle='rotate'] {\n fill: var(--_vv-accent);\n cursor: grab;\n}\n.paper [data-text-block-preview] [data-text-block-frame] {\n stroke-dasharray: 2 2;\n}\n.text-dialog-panel[hidden],\n.field-dialog label[hidden] {\n display: none;\n}\n";
|
|
1990
1878
|
|
|
1879
|
+
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/task-pane.css?raw
|
|
1880
|
+
var task_pane_default = `/* The right task pane (Shape Data, Layers): the shared office-ui-task-pane, one view at a time. */
|
|
1881
|
+
.inspector-pane {
|
|
1882
|
+
flex: 0 0 288px;
|
|
1883
|
+
width: 288px;
|
|
1884
|
+
overflow: hidden;
|
|
1885
|
+
border-left: 1px solid var(--_vv-border);
|
|
1886
|
+
background: var(--_vv-surface);
|
|
1887
|
+
--office-background: var(--_vv-surface);
|
|
1888
|
+
--office-surface: var(--_vv-secondary);
|
|
1889
|
+
--office-foreground: var(--_vv-ink);
|
|
1890
|
+
}
|
|
1891
|
+
.inspector-pane [data-pane-view]:not([data-active]) {
|
|
1892
|
+
display: none;
|
|
1893
|
+
}
|
|
1894
|
+
.selection-hint {
|
|
1895
|
+
margin: 24px 0;
|
|
1896
|
+
text-align: center;
|
|
1897
|
+
color: var(--_vv-muted);
|
|
1898
|
+
font-size: 12px;
|
|
1899
|
+
}
|
|
1900
|
+
/* Shape Data reads as Visio's two-column window: a label column and a value column in rows. */
|
|
1901
|
+
.shape-inspector {
|
|
1902
|
+
font-size: 12px;
|
|
1903
|
+
line-height: 18px;
|
|
1904
|
+
}
|
|
1905
|
+
.shape-inspector div {
|
|
1906
|
+
max-height: none;
|
|
1907
|
+
overflow: visible;
|
|
1908
|
+
}
|
|
1909
|
+
.shape-inspector dl {
|
|
1910
|
+
gap: 0;
|
|
1911
|
+
margin: 6px 0;
|
|
1912
|
+
border-top: 1px solid var(--_vv-border);
|
|
1913
|
+
}
|
|
1914
|
+
.shape-inspector dt,
|
|
1915
|
+
.shape-inspector dd {
|
|
1916
|
+
padding: 4px 6px;
|
|
1917
|
+
border-bottom: 1px solid var(--_vv-border);
|
|
1918
|
+
}
|
|
1919
|
+
.shape-inspector dt {
|
|
1920
|
+
font-weight: 400;
|
|
1921
|
+
color: var(--_vv-muted);
|
|
1922
|
+
border-right: 1px solid var(--_vv-border);
|
|
1923
|
+
}
|
|
1924
|
+
.shape-inspector h3 {
|
|
1925
|
+
font-size: 12px;
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
/* Status bar: Visio's Page, Width, Height, Angle and language; messages are for screen readers. */
|
|
1929
|
+
office-ui-status-bar.status {
|
|
1930
|
+
gap: 18px;
|
|
1931
|
+
/* A host may recolour the bar: see the status aliases in theme.ts. */
|
|
1932
|
+
background: var(--_vv-status-bg);
|
|
1933
|
+
color: var(--_vv-status-ink);
|
|
1934
|
+
}
|
|
1935
|
+
/*
|
|
1936
|
+
* Office Theme "Colorful" (File > Options, or the status-bar attribute): the bar takes the product
|
|
1937
|
+
* colour, as desktop Visio's does, and its controls draw in the bar's own ink.
|
|
1938
|
+
*/
|
|
1939
|
+
:host([status-bar='colorful']) office-ui-status-bar.status {
|
|
1940
|
+
border-top-color: transparent;
|
|
1941
|
+
accent-color: var(--_vv-status-ink);
|
|
1942
|
+
--office-foreground: currentColor;
|
|
1943
|
+
--office-muted-foreground: currentColor;
|
|
1944
|
+
--office-accent: currentColor;
|
|
1945
|
+
--office-ring: currentColor;
|
|
1946
|
+
--office-border: color-mix(in srgb, currentColor 45%, transparent);
|
|
1947
|
+
--office-surface: color-mix(in srgb, currentColor 18%, transparent);
|
|
1948
|
+
--office-background: color-mix(in srgb, currentColor 18%, transparent);
|
|
1949
|
+
}
|
|
1950
|
+
:host([status-bar='colorful']) .status-message[data-error] {
|
|
1951
|
+
color: inherit;
|
|
1952
|
+
font-weight: 600;
|
|
1953
|
+
}
|
|
1954
|
+
/* Presentation Mode sits beside the zoom, at the trailing edge. */
|
|
1955
|
+
office-ui-status-bar.status .zoom-controls {
|
|
1956
|
+
margin-inline-start: 0;
|
|
1957
|
+
}
|
|
1958
|
+
.status-message:not([data-error]) {
|
|
1959
|
+
position: absolute;
|
|
1960
|
+
width: 1px;
|
|
1961
|
+
height: 1px;
|
|
1962
|
+
margin: -1px;
|
|
1963
|
+
overflow: hidden;
|
|
1964
|
+
clip-path: inset(50%);
|
|
1965
|
+
white-space: nowrap;
|
|
1966
|
+
}
|
|
1967
|
+
.status-message[data-error] {
|
|
1968
|
+
flex: 1;
|
|
1969
|
+
min-width: 0;
|
|
1970
|
+
color: var(--_vv-danger);
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
/* In-place text editing: the editor sits on the shape and replaces its drawn text. */
|
|
1974
|
+
.inline-text {
|
|
1975
|
+
position: absolute;
|
|
1976
|
+
z-index: 3;
|
|
1977
|
+
box-sizing: border-box;
|
|
1978
|
+
margin: 0;
|
|
1979
|
+
padding: 0 4px;
|
|
1980
|
+
overflow: hidden;
|
|
1981
|
+
resize: none;
|
|
1982
|
+
border: 0;
|
|
1983
|
+
border-radius: 0;
|
|
1984
|
+
outline: 1px dashed var(--_vv-accent);
|
|
1985
|
+
outline-offset: 2px;
|
|
1986
|
+
background: transparent;
|
|
1987
|
+
line-height: 1.2;
|
|
1988
|
+
min-height: 0;
|
|
1989
|
+
}
|
|
1990
|
+
.paper [data-editing-text] text {
|
|
1991
|
+
visibility: hidden;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
/* File > Info lists what the drawing shows approximately. */
|
|
1995
|
+
.backstage-notes-list {
|
|
1996
|
+
max-height: 240px;
|
|
1997
|
+
margin: 6px 0 0;
|
|
1998
|
+
padding-left: 18px;
|
|
1999
|
+
overflow: auto;
|
|
2000
|
+
color: var(--_vv-muted);
|
|
2001
|
+
}
|
|
2002
|
+
.backstage-notes-list li {
|
|
2003
|
+
margin: 5px 0;
|
|
2004
|
+
overflow-wrap: anywhere;
|
|
2005
|
+
}
|
|
2006
|
+
@media (max-width: 760px) {
|
|
2007
|
+
.inspector-pane {
|
|
2008
|
+
position: absolute;
|
|
2009
|
+
inset: 0 0 0 auto;
|
|
2010
|
+
z-index: 4;
|
|
2011
|
+
width: min(320px, 100%);
|
|
2012
|
+
box-shadow: -8px 0 24px #0002;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
/* Layer Properties: Visio's table of layers with their flags. */
|
|
2017
|
+
.layer-table {
|
|
2018
|
+
width: 100%;
|
|
2019
|
+
border-collapse: collapse;
|
|
2020
|
+
font-size: 12px;
|
|
2021
|
+
}
|
|
2022
|
+
.layer-table th,
|
|
2023
|
+
.layer-table td {
|
|
2024
|
+
padding: 4px 8px;
|
|
2025
|
+
border: 1px solid var(--_vv-border);
|
|
2026
|
+
text-align: center;
|
|
2027
|
+
}
|
|
2028
|
+
.layer-table thead th {
|
|
2029
|
+
background: var(--_vv-secondary);
|
|
2030
|
+
font-weight: 600;
|
|
2031
|
+
}
|
|
2032
|
+
.layer-table tbody th {
|
|
2033
|
+
text-align: left;
|
|
2034
|
+
font-weight: 400;
|
|
2035
|
+
overflow-wrap: anywhere;
|
|
2036
|
+
}
|
|
2037
|
+
.layer-table .layer-page th {
|
|
2038
|
+
background: var(--_vv-secondary);
|
|
2039
|
+
color: var(--_vv-muted);
|
|
2040
|
+
font-size: 11px;
|
|
2041
|
+
}
|
|
2042
|
+
.layer-table input {
|
|
2043
|
+
width: 16px;
|
|
2044
|
+
height: 16px;
|
|
2045
|
+
min-height: 16px;
|
|
2046
|
+
padding: 0;
|
|
2047
|
+
accent-color: var(--_vv-accent);
|
|
2048
|
+
}
|
|
2049
|
+
.layer-colour {
|
|
2050
|
+
display: inline-block;
|
|
2051
|
+
width: 28px;
|
|
2052
|
+
height: 12px;
|
|
2053
|
+
border: 1px solid var(--_vv-border);
|
|
2054
|
+
}
|
|
2055
|
+
.layer-note:empty {
|
|
2056
|
+
display: none;
|
|
2057
|
+
}
|
|
2058
|
+
.layer-note {
|
|
2059
|
+
color: var(--_vv-muted);
|
|
2060
|
+
font-size: 12px;
|
|
2061
|
+
}
|
|
2062
|
+
`;
|
|
2063
|
+
|
|
2064
|
+
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/title-bar.css?raw
|
|
2065
|
+
var title_bar_default = "/* Visio's title bar: the shared office-ui-title-bar, with the signed-in name at its right end. */\n.title-bar {\n flex: none;\n}\n.title-bar[hidden] {\n display: none;\n}\n.title-account {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--_vv-ink);\n}\n.title-account[hidden] {\n display: none;\n}\n.title-account-avatar {\n display: inline-grid;\n place-items: center;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n color: #fff;\n font-size: 10px;\n font-weight: 600;\n}\n@media (max-width: 760px) {\n .title-account-name {\n display: none;\n }\n}\n";
|
|
2066
|
+
|
|
1991
2067
|
// src/visio/styles/theme.ts
|
|
1992
2068
|
var visioThemeAliases = `:host {
|
|
1993
2069
|
--_vv-bg:var(--vv-background,var(--office-surface,#eceae8));
|
|
@@ -2002,6 +2078,12 @@ var visioThemeAliases = `:host {
|
|
|
2002
2078
|
--_vv-focus:var(--vv-focus,var(--office-ring,var(--_vv-accent)));
|
|
2003
2079
|
--_vv-danger:var(--vv-danger,var(--office-danger,#b42318));
|
|
2004
2080
|
--_vv-shadow:var(--vv-shadow,var(--office-shadow,0 2px 8px rgb(0 0 0 / 14%)));
|
|
2081
|
+
--_vv-status-bg:var(--vv-status-background,var(--_vv-surface));
|
|
2082
|
+
--_vv-status-ink:var(--vv-status-ink,var(--_vv-ink));
|
|
2083
|
+
}
|
|
2084
|
+
:host([status-bar='colorful']) {
|
|
2085
|
+
--_vv-status-bg:var(--vv-status-background,var(--_vv-accent));
|
|
2086
|
+
--_vv-status-ink:var(--vv-status-ink,var(--_vv-accent-ink));
|
|
2005
2087
|
}
|
|
2006
2088
|
`;
|
|
2007
2089
|
var visioThemeBridge = themeBridge(":host > *", {
|
|
@@ -2032,6 +2114,8 @@ var canvasAndRibbonStyles = [
|
|
|
2032
2114
|
data_default,
|
|
2033
2115
|
layout_default,
|
|
2034
2116
|
text_features_default,
|
|
2117
|
+
task_pane_default,
|
|
2118
|
+
title_bar_default,
|
|
2035
2119
|
visioThemeBridge
|
|
2036
2120
|
].join("\n");
|
|
2037
2121
|
|
|
@@ -2858,27 +2942,27 @@ function storage(doc) {
|
|
|
2858
2942
|
}
|
|
2859
2943
|
}
|
|
2860
2944
|
function load(doc) {
|
|
2861
|
-
const
|
|
2945
|
+
const saved2 = { open: [], quick: {} };
|
|
2862
2946
|
try {
|
|
2863
2947
|
const raw = storage(doc)?.getItem(SHAPES_STORAGE_KEY);
|
|
2864
2948
|
const value = raw ? JSON.parse(raw) : {};
|
|
2865
2949
|
const known = new Set(STENCILS.map((stencil) => stencil.id));
|
|
2866
2950
|
if (Array.isArray(value.open))
|
|
2867
|
-
|
|
2951
|
+
saved2.open = value.open.filter(
|
|
2868
2952
|
(id) => typeof id === "string" && known.has(id) && id !== BASIC_STENCIL_ID
|
|
2869
2953
|
);
|
|
2870
2954
|
for (const [stencil, ids] of Object.entries(value.quick ?? {}))
|
|
2871
2955
|
if (known.has(stencil) && Array.isArray(ids))
|
|
2872
|
-
|
|
2956
|
+
saved2.quick[stencil] = ids.filter(
|
|
2873
2957
|
(id) => typeof id === "string" && findMaster(id)?.stencil.id === stencil
|
|
2874
2958
|
);
|
|
2875
2959
|
} catch {
|
|
2876
2960
|
}
|
|
2877
|
-
return
|
|
2961
|
+
return saved2;
|
|
2878
2962
|
}
|
|
2879
|
-
function save(doc,
|
|
2963
|
+
function save(doc, saved2) {
|
|
2880
2964
|
try {
|
|
2881
|
-
storage(doc)?.setItem(SHAPES_STORAGE_KEY, JSON.stringify(
|
|
2965
|
+
storage(doc)?.setItem(SHAPES_STORAGE_KEY, JSON.stringify(saved2));
|
|
2882
2966
|
} catch {
|
|
2883
2967
|
}
|
|
2884
2968
|
}
|
|
@@ -2923,7 +3007,7 @@ function unsupportedItem(item, reason) {
|
|
|
2923
3007
|
return item;
|
|
2924
3008
|
}
|
|
2925
3009
|
function buildStencilsView(doc, panel, pane) {
|
|
2926
|
-
const
|
|
3010
|
+
const saved2 = load(doc);
|
|
2927
3011
|
const row = (id, label) => {
|
|
2928
3012
|
const button = doc.createElement("button");
|
|
2929
3013
|
button.type = "button";
|
|
@@ -2934,7 +3018,7 @@ function buildStencilsView(doc, panel, pane) {
|
|
|
2934
3018
|
};
|
|
2935
3019
|
const more = row("shapes-more", "More Shapes");
|
|
2936
3020
|
more.setAttribute("aria-haspopup", "menu");
|
|
2937
|
-
more.title = "More Shapes: open
|
|
3021
|
+
more.title = "More Shapes: open another stencil.";
|
|
2938
3022
|
const quickToggle = row("shapes-quick-toggle", "Quick Shapes");
|
|
2939
3023
|
quickToggle.setAttribute("aria-expanded", "false");
|
|
2940
3024
|
quickToggle.setAttribute("aria-controls", "shapes-quick");
|
|
@@ -2951,8 +3035,8 @@ function buildStencilsView(doc, panel, pane) {
|
|
|
2951
3035
|
masterMenu.dataset.shapesMenu = "master";
|
|
2952
3036
|
masterMenu.setAttribute("label", "Master");
|
|
2953
3037
|
let menuMaster;
|
|
2954
|
-
const openIds = () => [BASIC_STENCIL_ID, ...
|
|
2955
|
-
const quickIds = (stencil) =>
|
|
3038
|
+
const openIds = () => [BASIC_STENCIL_ID, ...saved2.open];
|
|
3039
|
+
const quickIds = (stencil) => saved2.quick[stencil.id] ?? stencil.masters.slice(0, DEFAULT_QUICK).map((master) => master.id);
|
|
2956
3040
|
const renderQuick = () => {
|
|
2957
3041
|
if (quick.hidden) return quick.replaceChildren();
|
|
2958
3042
|
const masters = openIds().map((id) => STENCILS.find((stencil) => stencil.id === id)).flatMap((stencil) => quickIds(stencil).map((id) => findMaster(id).master));
|
|
@@ -3004,7 +3088,7 @@ function buildStencilsView(doc, panel, pane) {
|
|
|
3004
3088
|
};
|
|
3005
3089
|
const renderMenu = () => moreMenu.replaceChildren(
|
|
3006
3090
|
...STENCILS.filter((stencil) => stencil.id !== BASIC_STENCIL_ID).map(
|
|
3007
|
-
(stencil) => menuItem(doc, `stencil:${stencil.id}`, stencil.name,
|
|
3091
|
+
(stencil) => menuItem(doc, `stencil:${stencil.id}`, stencil.name, saved2.open.includes(stencil.id))
|
|
3008
3092
|
),
|
|
3009
3093
|
doc.createElement("office-ui-menu-separator"),
|
|
3010
3094
|
unsupportedItem(
|
|
@@ -3018,8 +3102,8 @@ function buildStencilsView(doc, panel, pane) {
|
|
|
3018
3102
|
renderQuick();
|
|
3019
3103
|
};
|
|
3020
3104
|
const toggleStencil = (id) => {
|
|
3021
|
-
|
|
3022
|
-
save(doc,
|
|
3105
|
+
saved2.open = saved2.open.includes(id) ? saved2.open.filter((candidate) => candidate !== id) : [...saved2.open, id];
|
|
3106
|
+
save(doc, saved2);
|
|
3023
3107
|
render();
|
|
3024
3108
|
};
|
|
3025
3109
|
more.addEventListener("click", () => {
|
|
@@ -3065,8 +3149,8 @@ function buildStencilsView(doc, panel, pane) {
|
|
|
3065
3149
|
const found = menuMaster && findMaster(menuMaster);
|
|
3066
3150
|
if (!found) return;
|
|
3067
3151
|
const ids = quickIds(found.stencil);
|
|
3068
|
-
|
|
3069
|
-
save(doc,
|
|
3152
|
+
saved2.quick[found.stencil.id] = ids.includes(found.master.id) ? ids.filter((id) => id !== found.master.id) : [...ids, found.master.id];
|
|
3153
|
+
save(doc, saved2);
|
|
3070
3154
|
renderQuick();
|
|
3071
3155
|
});
|
|
3072
3156
|
render();
|
|
@@ -3093,70 +3177,48 @@ function createShapesWindow(doc) {
|
|
|
3093
3177
|
collapse.title = "Close Shapes";
|
|
3094
3178
|
collapse.textContent = "\u2039";
|
|
3095
3179
|
heading.append(title2, collapse);
|
|
3096
|
-
const
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
tab.tabIndex = selected ? 0 : -1;
|
|
3110
|
-
return tab;
|
|
3111
|
-
};
|
|
3112
|
-
views.append(view("stencils", "Stencils", true), view("search", "Search", false));
|
|
3180
|
+
const box2 = doc.createElement("div");
|
|
3181
|
+
box2.className = "shapes-search-box";
|
|
3182
|
+
const field = doc.createElement("input");
|
|
3183
|
+
field.type = "search";
|
|
3184
|
+
field.className = "shapes-search-field";
|
|
3185
|
+
field.placeholder = "Search shapes";
|
|
3186
|
+
field.setAttribute("aria-label", "Search shapes");
|
|
3187
|
+
field.setAttribute("aria-controls", "shapes-search");
|
|
3188
|
+
field.autocomplete = "off";
|
|
3189
|
+
const glass = doc.createElement("office-ui-icon");
|
|
3190
|
+
glass.setAttribute("name", "search");
|
|
3191
|
+
glass.setAttribute("aria-hidden", "true");
|
|
3192
|
+
box2.append(field, glass);
|
|
3113
3193
|
const stencils = doc.createElement("div");
|
|
3114
3194
|
stencils.id = "shapes-stencils";
|
|
3115
|
-
stencils.setAttribute("role", "tabpanel");
|
|
3116
|
-
stencils.setAttribute("aria-labelledby", "shapes-stencils-tab");
|
|
3117
3195
|
const menus = buildStencilsView(doc, stencils, pane);
|
|
3118
3196
|
const search = doc.createElement("div");
|
|
3119
3197
|
search.id = "shapes-search";
|
|
3120
3198
|
search.hidden = true;
|
|
3121
|
-
search.setAttribute("role", "
|
|
3122
|
-
search.setAttribute("aria-
|
|
3123
|
-
const field = doc.createElement("input");
|
|
3124
|
-
field.type = "search";
|
|
3125
|
-
field.className = "shapes-search-field";
|
|
3126
|
-
field.placeholder = "Search for shapes";
|
|
3127
|
-
field.setAttribute("aria-label", "Search for shapes");
|
|
3128
|
-
field.autocomplete = "off";
|
|
3199
|
+
search.setAttribute("role", "region");
|
|
3200
|
+
search.setAttribute("aria-label", "Search results");
|
|
3129
3201
|
const results = masterList(
|
|
3130
3202
|
doc,
|
|
3131
3203
|
STENCILS.flatMap((stencil) => stencil.masters)
|
|
3132
3204
|
);
|
|
3133
3205
|
const empty = doc.createElement("p");
|
|
3134
3206
|
empty.className = "shapes-empty";
|
|
3135
|
-
empty.textContent = "No
|
|
3207
|
+
empty.textContent = "No shapes match your search.";
|
|
3136
3208
|
empty.hidden = true;
|
|
3137
3209
|
field.addEventListener("input", () => {
|
|
3138
3210
|
const query = field.value.trim().toLowerCase();
|
|
3139
3211
|
let shown = 0;
|
|
3140
3212
|
for (const item of results.querySelectorAll("li")) {
|
|
3141
|
-
item.hidden =
|
|
3213
|
+
item.hidden = !item.dataset.name.toLowerCase().includes(query);
|
|
3142
3214
|
if (!item.hidden) shown++;
|
|
3143
3215
|
}
|
|
3144
3216
|
empty.hidden = shown > 0;
|
|
3217
|
+
search.hidden = !query;
|
|
3218
|
+
stencils.hidden = !!query;
|
|
3145
3219
|
});
|
|
3146
|
-
search.append(
|
|
3147
|
-
|
|
3148
|
-
const tab = event.target.closest("[data-shapes-view]");
|
|
3149
|
-
if (!tab) return;
|
|
3150
|
-
for (const candidate of views.querySelectorAll("[data-shapes-view]")) {
|
|
3151
|
-
const selected = candidate === tab;
|
|
3152
|
-
candidate.setAttribute("aria-selected", String(selected));
|
|
3153
|
-
candidate.tabIndex = selected ? 0 : -1;
|
|
3154
|
-
}
|
|
3155
|
-
stencils.hidden = tab.dataset.shapesView !== "stencils";
|
|
3156
|
-
search.hidden = !stencils.hidden;
|
|
3157
|
-
if (!search.hidden) field.focus();
|
|
3158
|
-
});
|
|
3159
|
-
pane.append(heading, views, stencils, search, ...menus);
|
|
3220
|
+
search.append(results, empty);
|
|
3221
|
+
pane.append(heading, box2, stencils, search, ...menus);
|
|
3160
3222
|
return pane;
|
|
3161
3223
|
}
|
|
3162
3224
|
function createShapesStrip(doc) {
|
|
@@ -3519,7 +3581,7 @@ function buildHomePanel(doc, panel) {
|
|
|
3519
3581
|
{
|
|
3520
3582
|
id: "layer-properties",
|
|
3521
3583
|
label: "Layer Properties...",
|
|
3522
|
-
action: { type: "
|
|
3584
|
+
action: { type: "layer-properties" }
|
|
3523
3585
|
},
|
|
3524
3586
|
{
|
|
3525
3587
|
id: "assign-layer",
|
|
@@ -4408,22 +4470,11 @@ function buildViewPanel(doc, panel) {
|
|
|
4408
4470
|
action: { type: "pane", pane: "shapes" },
|
|
4409
4471
|
checked: true
|
|
4410
4472
|
},
|
|
4411
|
-
{
|
|
4412
|
-
id: "inspector",
|
|
4413
|
-
label: "Inspector",
|
|
4414
|
-
action: { type: "pane", pane: "inspector" },
|
|
4415
|
-
checked: true
|
|
4416
|
-
},
|
|
4417
4473
|
{
|
|
4418
4474
|
id: "shape-data",
|
|
4419
4475
|
label: "Shape Data",
|
|
4420
|
-
action: { type: "reveal", panel: "selection" }
|
|
4421
|
-
|
|
4422
|
-
{ id: "layers-pane", label: "Layers", action: { type: "reveal", panel: "layers" } },
|
|
4423
|
-
{
|
|
4424
|
-
id: "notes",
|
|
4425
|
-
label: "Compatibility Notes",
|
|
4426
|
-
action: { type: "reveal", panel: "notes" }
|
|
4476
|
+
action: { type: "reveal", panel: "selection" },
|
|
4477
|
+
checked: false
|
|
4427
4478
|
},
|
|
4428
4479
|
{ id: "pan-zoom", label: "Pan & Zoom", action: { type: "panZoom" }, checked: false },
|
|
4429
4480
|
{
|
|
@@ -4615,31 +4666,6 @@ var RIBBON_TABS = [
|
|
|
4615
4666
|
["view", "View", buildViewPanel],
|
|
4616
4667
|
["help", "Help", buildHelpPanel]
|
|
4617
4668
|
];
|
|
4618
|
-
function quickAccess(doc) {
|
|
4619
|
-
const qat = doc.createElement("div");
|
|
4620
|
-
qat.className = "qat";
|
|
4621
|
-
qat.setAttribute("role", "toolbar");
|
|
4622
|
-
qat.setAttribute("aria-label", "Quick Access Toolbar");
|
|
4623
|
-
qat.append(
|
|
4624
|
-
command(doc, {
|
|
4625
|
-
id: "undo",
|
|
4626
|
-
label: "Undo",
|
|
4627
|
-
icon: "undo",
|
|
4628
|
-
size: "icon",
|
|
4629
|
-
action: { type: "history", key: "undo" },
|
|
4630
|
-
keys: ["Control+Z", "Ctrl+Z"]
|
|
4631
|
-
}),
|
|
4632
|
-
command(doc, {
|
|
4633
|
-
id: "redo",
|
|
4634
|
-
label: "Redo",
|
|
4635
|
-
icon: "redo",
|
|
4636
|
-
size: "icon",
|
|
4637
|
-
action: { type: "history", key: "redo" },
|
|
4638
|
-
keys: ["Control+Y", "Ctrl+Y"]
|
|
4639
|
-
})
|
|
4640
|
-
);
|
|
4641
|
-
return qat;
|
|
4642
|
-
}
|
|
4643
4669
|
function createRibbon(doc) {
|
|
4644
4670
|
const ribbon = doc.createElement("office-ui-ribbon");
|
|
4645
4671
|
ribbon.className = "toolbar";
|
|
@@ -4647,11 +4673,9 @@ function createRibbon(doc) {
|
|
|
4647
4673
|
ribbon.setAttribute("aria-label", "Diagram controls");
|
|
4648
4674
|
ribbon.setAttribute("label", "Ribbon");
|
|
4649
4675
|
ribbon.setAttribute("selected", "home");
|
|
4650
|
-
const qat = quickAccess(doc);
|
|
4651
|
-
qat.slot = "quick-access";
|
|
4652
4676
|
const tellMe = createTellMe(doc);
|
|
4653
4677
|
tellMe.slot = "search";
|
|
4654
|
-
ribbon.append(
|
|
4678
|
+
ribbon.append(tellMe);
|
|
4655
4679
|
for (const [key, name, build] of RIBBON_TABS) {
|
|
4656
4680
|
const panel = doc.createElement("div");
|
|
4657
4681
|
panel.className = "ribbon-content";
|
|
@@ -4763,8 +4787,6 @@ function generated(label, used, singles) {
|
|
|
4763
4787
|
function applyKeyTips(toolbar) {
|
|
4764
4788
|
toolbar.setAttribute("file-keytip", "F");
|
|
4765
4789
|
toolbar.querySelector(".tell-me").dataset.keytip = "Q";
|
|
4766
|
-
toolbar.querySelector('.qat [command="undo"]').dataset.keytip = "1";
|
|
4767
|
-
toolbar.querySelector('.qat [command="redo"]').dataset.keytip = "2";
|
|
4768
4790
|
for (const panel of toolbar.querySelectorAll("[data-ribbon-tab]")) {
|
|
4769
4791
|
const tab = panel.dataset.ribbonTab;
|
|
4770
4792
|
panel.dataset.tabKeytip = TABS[tab] ?? tab.slice(0, 1).toUpperCase();
|
|
@@ -4814,23 +4836,7 @@ function createStatusBar(doc) {
|
|
|
4814
4836
|
message.setAttribute("role", "status");
|
|
4815
4837
|
const text = doc.createElement("span");
|
|
4816
4838
|
text.dataset.status = "";
|
|
4817
|
-
|
|
4818
|
-
diagnostics.dataset.diagnostics = "";
|
|
4819
|
-
message.append(text, diagnostics);
|
|
4820
|
-
const notes = doc.createElement("div");
|
|
4821
|
-
notes.className = "notes-strip";
|
|
4822
|
-
const notesButton = doc.createElement("button");
|
|
4823
|
-
notesButton.type = "button";
|
|
4824
|
-
notesButton.dataset.chrome = "notes";
|
|
4825
|
-
notesButton.setAttribute("aria-controls", "inspector-pane");
|
|
4826
|
-
notesButton.setAttribute("aria-expanded", "false");
|
|
4827
|
-
const count = doc.createElement("span");
|
|
4828
|
-
count.className = "notes-count";
|
|
4829
|
-
count.dataset.noteCount = "";
|
|
4830
|
-
notesButton.append("Notes", count);
|
|
4831
|
-
const local = doc.createElement("span");
|
|
4832
|
-
local.textContent = "Files stay in your browser";
|
|
4833
|
-
notes.append(notesButton, local);
|
|
4839
|
+
message.append(text);
|
|
4834
4840
|
const footer2 = doc.createElement("slot");
|
|
4835
4841
|
footer2.name = "workspace-footer";
|
|
4836
4842
|
const zoom = doc.createElement("office-ui-zoom-slider");
|
|
@@ -4849,15 +4855,28 @@ function createStatusBar(doc) {
|
|
|
4849
4855
|
presentation.setAttribute("title", "Presentation Mode: open a drawing with a foreground page.");
|
|
4850
4856
|
bar.append(
|
|
4851
4857
|
item("data-page-status"),
|
|
4852
|
-
item("data-
|
|
4858
|
+
item("data-width-status"),
|
|
4859
|
+
item("data-height-status"),
|
|
4860
|
+
item("data-angle-status"),
|
|
4861
|
+
item("data-language-status"),
|
|
4853
4862
|
message,
|
|
4854
|
-
notes,
|
|
4855
4863
|
footer2,
|
|
4856
4864
|
presentation,
|
|
4857
4865
|
zoom
|
|
4858
4866
|
);
|
|
4859
4867
|
return bar;
|
|
4860
4868
|
}
|
|
4869
|
+
function statusLanguage(tag) {
|
|
4870
|
+
try {
|
|
4871
|
+
const locale = new Intl.Locale(tag || "en-US").maximize();
|
|
4872
|
+
const names = new Intl.DisplayNames(["en"], { type: "language" });
|
|
4873
|
+
const language = names.of(locale.language) ?? "";
|
|
4874
|
+
const region = locale.region ? new Intl.DisplayNames(["en"], { type: "region" }).of(locale.region) : "";
|
|
4875
|
+
return region ? `${language} (${region})` : language;
|
|
4876
|
+
} catch {
|
|
4877
|
+
return "";
|
|
4878
|
+
}
|
|
4879
|
+
}
|
|
4861
4880
|
function createPageTabs(doc) {
|
|
4862
4881
|
const bar = doc.createElement("div");
|
|
4863
4882
|
bar.className = "page-bar";
|
|
@@ -4874,9 +4893,82 @@ function createPageTabs(doc) {
|
|
|
4874
4893
|
strip.setAttribute("add-label", "Insert Page");
|
|
4875
4894
|
strip.setAttribute("add-disabled", "");
|
|
4876
4895
|
strip.setAttribute("add-title", "Insert Page: open a .vsdx file to edit pages.");
|
|
4877
|
-
|
|
4896
|
+
strip.toggleAttribute("plain", true);
|
|
4897
|
+
all.slot = "after-tabs";
|
|
4898
|
+
strip.append(all);
|
|
4899
|
+
bar.append(strip);
|
|
4900
|
+
return bar;
|
|
4901
|
+
}
|
|
4902
|
+
|
|
4903
|
+
// src/visio/title-bar.ts
|
|
4904
|
+
function createTitleBar(doc) {
|
|
4905
|
+
const bar = doc.createElement("office-ui-title-bar");
|
|
4906
|
+
bar.className = "title-bar";
|
|
4907
|
+
const account2 = doc.createElement("span");
|
|
4908
|
+
account2.slot = "account";
|
|
4909
|
+
account2.className = "title-account";
|
|
4910
|
+
const name = doc.createElement("span");
|
|
4911
|
+
name.className = "title-account-name";
|
|
4912
|
+
const avatar = doc.createElement("span");
|
|
4913
|
+
avatar.className = "title-account-avatar";
|
|
4914
|
+
avatar.setAttribute("aria-hidden", "true");
|
|
4915
|
+
account2.append(name, avatar);
|
|
4916
|
+
bar.append(account2);
|
|
4917
|
+
bar.state = { appMark: "V", fileName: "Visio" };
|
|
4878
4918
|
return bar;
|
|
4879
4919
|
}
|
|
4920
|
+
function initials(profile) {
|
|
4921
|
+
if (profile.initial) return profile.initial.slice(0, 2).toUpperCase();
|
|
4922
|
+
const words = profile.displayName.trim().split(/\s+/).filter(Boolean);
|
|
4923
|
+
return ((words[0]?.[0] ?? "") + (words.length > 1 ? words.at(-1)?.[0] ?? "" : "")).toUpperCase();
|
|
4924
|
+
}
|
|
4925
|
+
function status(state) {
|
|
4926
|
+
if (!state.document) return "";
|
|
4927
|
+
if (state.loading) return "Opening...";
|
|
4928
|
+
if (state.document.format === "vsd" || !state.edit.sourceAvailable) return "Read-only";
|
|
4929
|
+
return state.edit.dirty ? "Unsaved changes" : "";
|
|
4930
|
+
}
|
|
4931
|
+
function renderTitleBar(bar, state, fileName, profile) {
|
|
4932
|
+
const busy = state.loading || state.edit.busy;
|
|
4933
|
+
bar.state = {
|
|
4934
|
+
appMark: "V",
|
|
4935
|
+
fileName: fileName || (state.document ? "Drawing1" : "Visio"),
|
|
4936
|
+
status: status(state),
|
|
4937
|
+
tone: state.loading ? "saving" : "idle",
|
|
4938
|
+
quickAccess: {
|
|
4939
|
+
label: "Quick Access Toolbar",
|
|
4940
|
+
items: [
|
|
4941
|
+
{
|
|
4942
|
+
id: "save",
|
|
4943
|
+
icon: "save",
|
|
4944
|
+
label: "Save",
|
|
4945
|
+
title: state.edit.sourceAvailable ? "Save (Ctrl+S): download a copy" : "Save: open a .vsdx file to save a copy",
|
|
4946
|
+
disabled: !state.edit.sourceAvailable || busy
|
|
4947
|
+
},
|
|
4948
|
+
{
|
|
4949
|
+
id: "undo",
|
|
4950
|
+
icon: "undo",
|
|
4951
|
+
label: "Undo",
|
|
4952
|
+
title: "Undo (Ctrl+Z)",
|
|
4953
|
+
disabled: !state.edit.canUndo || busy
|
|
4954
|
+
},
|
|
4955
|
+
{
|
|
4956
|
+
id: "redo",
|
|
4957
|
+
icon: "redo",
|
|
4958
|
+
label: "Redo",
|
|
4959
|
+
title: "Redo (Ctrl+Y)",
|
|
4960
|
+
disabled: !state.edit.canRedo || busy
|
|
4961
|
+
}
|
|
4962
|
+
]
|
|
4963
|
+
}
|
|
4964
|
+
};
|
|
4965
|
+
const account2 = bar.querySelector(".title-account");
|
|
4966
|
+
account2.hidden = !profile.displayName;
|
|
4967
|
+
account2.querySelector(".title-account-name").textContent = profile.displayName;
|
|
4968
|
+
const avatar = account2.querySelector(".title-account-avatar");
|
|
4969
|
+
avatar.textContent = initials(profile);
|
|
4970
|
+
avatar.style.background = profile.avatarColor;
|
|
4971
|
+
}
|
|
4880
4972
|
function createFindBar(doc) {
|
|
4881
4973
|
const bar = doc.createElement("office-ui-find-bar");
|
|
4882
4974
|
bar.className = "find-bar";
|
|
@@ -5267,8 +5359,8 @@ function share(doc) {
|
|
|
5267
5359
|
stop.dataset.share = "stop";
|
|
5268
5360
|
stop.hidden = true;
|
|
5269
5361
|
buttons.append(start, stop);
|
|
5270
|
-
const
|
|
5271
|
-
|
|
5362
|
+
const status2 = el(doc, "p", "share-status");
|
|
5363
|
+
status2.setAttribute("role", "status");
|
|
5272
5364
|
const people = doc.createElement("office-ui-presence");
|
|
5273
5365
|
people.className = "share-people";
|
|
5274
5366
|
people.setAttribute("label", "People in this session");
|
|
@@ -5282,7 +5374,7 @@ function share(doc) {
|
|
|
5282
5374
|
),
|
|
5283
5375
|
field,
|
|
5284
5376
|
buttons,
|
|
5285
|
-
|
|
5377
|
+
status2,
|
|
5286
5378
|
people,
|
|
5287
5379
|
el(
|
|
5288
5380
|
doc,
|
|
@@ -5322,10 +5414,11 @@ function createBackstage(doc) {
|
|
|
5322
5414
|
facts.append(el(doc, "dt", "", label), value);
|
|
5323
5415
|
}
|
|
5324
5416
|
const notes = el(doc, "div", "backstage-notes");
|
|
5417
|
+
notes.hidden = true;
|
|
5325
5418
|
notes.append(
|
|
5326
5419
|
el(doc, "h2", "", "Compatibility"),
|
|
5327
5420
|
el(doc, "p", "backstage-note-count"),
|
|
5328
|
-
|
|
5421
|
+
el(doc, "ul", "backstage-notes-list")
|
|
5329
5422
|
);
|
|
5330
5423
|
const file = el(doc, "h2", "backstage-file");
|
|
5331
5424
|
file.dataset.info = "name";
|
|
@@ -5584,9 +5677,6 @@ var ViewerBackstage = class {
|
|
|
5584
5677
|
else if (action2 === "page-setup") {
|
|
5585
5678
|
this.hide();
|
|
5586
5679
|
this.host.pageSetup?.();
|
|
5587
|
-
} else if (action2 === "notes") {
|
|
5588
|
-
this.hide();
|
|
5589
|
-
this.host.revealNotes();
|
|
5590
5680
|
}
|
|
5591
5681
|
}
|
|
5592
5682
|
#save(blob2, name) {
|
|
@@ -5607,6 +5697,10 @@ var ViewerBackstage = class {
|
|
|
5607
5697
|
#base() {
|
|
5608
5698
|
return this.host.fileName().replace(/\.vsdx?$/i, "") || "Drawing";
|
|
5609
5699
|
}
|
|
5700
|
+
/** Save: download the edited drawing as a copy (File > Save and the Quick Access Toolbar). */
|
|
5701
|
+
download() {
|
|
5702
|
+
this.#download();
|
|
5703
|
+
}
|
|
5610
5704
|
#download() {
|
|
5611
5705
|
if (!this.#state?.edit.sourceAvailable) return;
|
|
5612
5706
|
try {
|
|
@@ -5616,9 +5710,7 @@ var ViewerBackstage = class {
|
|
|
5616
5710
|
`${this.#base()}-${result.dirty ? "edited" : "original"}-copy.vsdx`
|
|
5617
5711
|
);
|
|
5618
5712
|
this.hide();
|
|
5619
|
-
this.host.announce(
|
|
5620
|
-
"VSDX copy download requested. Native Visio compatibility is not verified."
|
|
5621
|
-
);
|
|
5713
|
+
this.host.announce("Downloaded a copy of the drawing.");
|
|
5622
5714
|
} catch (error) {
|
|
5623
5715
|
this.host.announce(error instanceof Error ? error.message : String(error));
|
|
5624
5716
|
}
|
|
@@ -5697,10 +5789,10 @@ var ViewerBackstage = class {
|
|
|
5697
5789
|
set("shapes", page3 ? `${page3.shapes.length} top-level` : "None");
|
|
5698
5790
|
set(
|
|
5699
5791
|
"state",
|
|
5700
|
-
state.document?.format === "vsd" ? "Legacy VSD preview (read only)" : !state.edit.sourceAvailable ? state.document ? "
|
|
5792
|
+
state.document?.format === "vsd" ? "Legacy VSD preview (read only)" : !state.edit.sourceAvailable ? state.document ? "Preview (read-only)" : "None" : state.edit.dirty ? "Edited copy (not saved)" : "Original"
|
|
5701
5793
|
);
|
|
5702
5794
|
const notes = this.host.noteCount();
|
|
5703
|
-
this.#root.querySelector(".backstage-note-count").textContent = notes ? `${notes
|
|
5795
|
+
this.#root.querySelector(".backstage-note-count").textContent = notes ? `${notes === 1 ? "One part" : `${notes} parts`} of this drawing ${notes === 1 ? "is" : "are"} shown approximately or not at all:` : "No compatibility notes.";
|
|
5704
5796
|
const busy = state.loading || state.edit.busy;
|
|
5705
5797
|
const blank = this.#root.querySelector(
|
|
5706
5798
|
'[data-backstage-action="new-blank"]'
|
|
@@ -5735,7 +5827,6 @@ var ViewerBackstage = class {
|
|
|
5735
5827
|
'[data-backstage-action^="export-"], [data-backstage-action="print"]'
|
|
5736
5828
|
))
|
|
5737
5829
|
node.disabled = !page3 || busy;
|
|
5738
|
-
this.#root.querySelector('[data-backstage-action="notes"]').disabled = notes === 0;
|
|
5739
5830
|
}
|
|
5740
5831
|
};
|
|
5741
5832
|
function pagePoint(svg2, page3, event, options2 = {}) {
|
|
@@ -7564,45 +7655,53 @@ var labels = {
|
|
|
7564
7655
|
height: "Height (in)",
|
|
7565
7656
|
angle: "Angle (\xB0)"
|
|
7566
7657
|
};
|
|
7658
|
+
var captions = { x: "X", y: "Y", width: "Width", height: "Height", angle: "Angle" };
|
|
7567
7659
|
function createSizePosition(doc) {
|
|
7568
7660
|
const pane = doc.createElement("section");
|
|
7569
7661
|
pane.className = "size-position";
|
|
7570
7662
|
pane.hidden = true;
|
|
7571
7663
|
pane.setAttribute("aria-label", "Size & Position");
|
|
7572
7664
|
const heading = doc.createElement("div");
|
|
7573
|
-
heading.className = "
|
|
7665
|
+
heading.className = "size-caption";
|
|
7574
7666
|
const title2 = doc.createElement("strong");
|
|
7575
7667
|
title2.textContent = "Size & Position";
|
|
7576
7668
|
const close = doc.createElement("button");
|
|
7577
7669
|
close.type = "button";
|
|
7578
7670
|
close.setAttribute("aria-label", "Close Size & Position");
|
|
7671
|
+
close.title = "Close";
|
|
7579
7672
|
close.textContent = "\xD7";
|
|
7580
7673
|
heading.append(title2, close);
|
|
7674
|
+
const body = doc.createElement("div");
|
|
7675
|
+
body.className = "size-body";
|
|
7581
7676
|
const target = doc.createElement("p");
|
|
7582
7677
|
target.dataset.sizeTarget = "";
|
|
7583
|
-
const hint = doc.createElement("p");
|
|
7584
|
-
hint.textContent = "Drawing inches. X/Y locate the rotation pin; Y increases upward.";
|
|
7585
7678
|
const controls = doc.createElement("div");
|
|
7586
7679
|
controls.dataset.sizeFields = "";
|
|
7587
|
-
const
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7680
|
+
const status2 = doc.createElement("p");
|
|
7681
|
+
status2.dataset.sizeStatus = "";
|
|
7682
|
+
status2.setAttribute("role", "status");
|
|
7683
|
+
status2.setAttribute("aria-live", "polite");
|
|
7591
7684
|
const error = doc.createElement("p");
|
|
7592
7685
|
error.dataset.sizeError = "";
|
|
7593
7686
|
error.setAttribute("role", "alert");
|
|
7594
7687
|
error.hidden = true;
|
|
7595
|
-
|
|
7688
|
+
body.append(controls, target, status2, error);
|
|
7689
|
+
pane.append(heading, body);
|
|
7596
7690
|
for (const field of fields) {
|
|
7597
7691
|
const label = doc.createElement("label");
|
|
7598
|
-
|
|
7692
|
+
const caption = doc.createElement("span");
|
|
7693
|
+
caption.textContent = captions[field];
|
|
7694
|
+
const unit2 = doc.createElement("span");
|
|
7695
|
+
unit2.className = "size-unit";
|
|
7696
|
+
unit2.setAttribute("aria-hidden", "true");
|
|
7697
|
+
unit2.textContent = field === "angle" ? "deg." : "in.";
|
|
7599
7698
|
const input = doc.createElement("input");
|
|
7600
7699
|
input.type = "number";
|
|
7601
7700
|
input.step = "any";
|
|
7602
7701
|
input.dataset.sizeField = field;
|
|
7603
7702
|
input.setAttribute("aria-label", labels[field]);
|
|
7604
7703
|
if (field === "width" || field === "height") input.min = "0";
|
|
7605
|
-
label.append(input);
|
|
7704
|
+
label.append(caption, input, unit2);
|
|
7606
7705
|
controls.append(label);
|
|
7607
7706
|
}
|
|
7608
7707
|
return pane;
|
|
@@ -7757,7 +7856,7 @@ var ViewerSizePosition = class {
|
|
|
7757
7856
|
input.disabled = !values || !state.edit.sourceAvailable || state.loading || state.edit.busy || this.#pending;
|
|
7758
7857
|
}
|
|
7759
7858
|
this.#pane.setAttribute("aria-busy", String(state.loading || state.edit.busy || this.#pending));
|
|
7760
|
-
this.#pane.querySelector("[data-size-target]").textContent = values ?
|
|
7859
|
+
this.#pane.querySelector("[data-size-target]").textContent = values ? "" : "Select a shape to see its size and position.";
|
|
7761
7860
|
}
|
|
7762
7861
|
};
|
|
7763
7862
|
function createContextMenus(doc) {
|
|
@@ -8179,7 +8278,18 @@ var VISIO_OPTION_CATEGORIES = [
|
|
|
8179
8278
|
description: "Stored on this device only. Shared sessions show this name to others.",
|
|
8180
8279
|
controls: [
|
|
8181
8280
|
{ kind: "text", key: "userName", label: "User name", maxLength: 64 },
|
|
8182
|
-
{ kind: "text", key: "userInitials", label: "Initials", maxLength: 2 }
|
|
8281
|
+
{ kind: "text", key: "userInitials", label: "Initials", maxLength: 2 },
|
|
8282
|
+
{
|
|
8283
|
+
kind: "select",
|
|
8284
|
+
key: "officeTheme",
|
|
8285
|
+
label: "Office Theme",
|
|
8286
|
+
info: "Colorful gives the status bar the Visio colour, White keeps it neutral and Black is the dark theme.",
|
|
8287
|
+
choices: [
|
|
8288
|
+
{ value: "colorful", label: "Colorful" },
|
|
8289
|
+
{ value: "neutral", label: "White" },
|
|
8290
|
+
{ value: "dark", label: "Black" }
|
|
8291
|
+
]
|
|
8292
|
+
}
|
|
8183
8293
|
]
|
|
8184
8294
|
}
|
|
8185
8295
|
]
|
|
@@ -8261,8 +8371,26 @@ var VISIO_OPTION_CATEGORIES = [
|
|
|
8261
8371
|
sections: []
|
|
8262
8372
|
}
|
|
8263
8373
|
];
|
|
8264
|
-
|
|
8374
|
+
var THEME_KEY = "ooxml-visio-office-theme";
|
|
8375
|
+
var isStatusBarTheme = (value) => value === "colorful" || value === "neutral";
|
|
8376
|
+
function readStatusBarTheme() {
|
|
8377
|
+
try {
|
|
8378
|
+
const stored = globalThis.localStorage?.getItem(THEME_KEY);
|
|
8379
|
+
return isStatusBarTheme(stored) ? stored : void 0;
|
|
8380
|
+
} catch {
|
|
8381
|
+
return void 0;
|
|
8382
|
+
}
|
|
8383
|
+
}
|
|
8384
|
+
function writeStatusBarTheme(theme) {
|
|
8385
|
+
try {
|
|
8386
|
+
globalThis.localStorage?.setItem(THEME_KEY, theme);
|
|
8387
|
+
} catch {
|
|
8388
|
+
}
|
|
8389
|
+
}
|
|
8390
|
+
var isOfficeThemeChoice = (value) => value === "dark" || isStatusBarTheme(value);
|
|
8391
|
+
function profileValues(profile, officeTheme) {
|
|
8265
8392
|
return {
|
|
8393
|
+
officeTheme,
|
|
8266
8394
|
miniToolbar: false,
|
|
8267
8395
|
livePreview: false,
|
|
8268
8396
|
screenTips: "descriptions",
|
|
@@ -8280,13 +8408,19 @@ function createOptionsDialog(doc) {
|
|
|
8280
8408
|
}
|
|
8281
8409
|
var ViewerProfile = class {
|
|
8282
8410
|
constructor(root, onProfile = () => {
|
|
8411
|
+
}, theme = {
|
|
8412
|
+
get: () => "neutral",
|
|
8413
|
+
set: () => {
|
|
8414
|
+
}
|
|
8283
8415
|
}) {
|
|
8284
8416
|
this.onProfile = onProfile;
|
|
8417
|
+
this.theme = theme;
|
|
8285
8418
|
this.#dialog = root.querySelector("office-ui-options-dialog");
|
|
8286
8419
|
this.#account = root.querySelector("office-ui-account");
|
|
8287
8420
|
this.#sync();
|
|
8288
8421
|
}
|
|
8289
8422
|
onProfile;
|
|
8423
|
+
theme;
|
|
8290
8424
|
#profile = readOfficeProfile();
|
|
8291
8425
|
#dialog;
|
|
8292
8426
|
#account;
|
|
@@ -8295,7 +8429,7 @@ var ViewerProfile = class {
|
|
|
8295
8429
|
}
|
|
8296
8430
|
/** Open Visio Options, on General as Visio does. */
|
|
8297
8431
|
showOptions(category = "general") {
|
|
8298
|
-
this.#dialog.values = profileValues(this.#profile);
|
|
8432
|
+
this.#dialog.values = profileValues(this.#profile, this.theme.get());
|
|
8299
8433
|
this.#dialog.category = category;
|
|
8300
8434
|
this.#dialog.show();
|
|
8301
8435
|
}
|
|
@@ -8307,6 +8441,10 @@ var ViewerProfile = class {
|
|
|
8307
8441
|
"office-options-change",
|
|
8308
8442
|
(event) => {
|
|
8309
8443
|
const { values } = event.detail;
|
|
8444
|
+
if (isOfficeThemeChoice(values.officeTheme) && values.officeTheme !== this.theme.get()) {
|
|
8445
|
+
this.theme.set(values.officeTheme);
|
|
8446
|
+
if (values.officeTheme !== "dark") writeStatusBarTheme(values.officeTheme);
|
|
8447
|
+
}
|
|
8310
8448
|
const initial = String(values.userInitials ?? "").trim();
|
|
8311
8449
|
this.#update({
|
|
8312
8450
|
displayName: String(values.userName ?? "").trim(),
|
|
@@ -8331,7 +8469,7 @@ var ViewerProfile = class {
|
|
|
8331
8469
|
}
|
|
8332
8470
|
#sync() {
|
|
8333
8471
|
if (this.#account) this.#account.profile = this.#profile;
|
|
8334
|
-
this.#dialog.values = profileValues(this.#profile);
|
|
8472
|
+
this.#dialog.values = profileValues(this.#profile, this.theme.get());
|
|
8335
8473
|
}
|
|
8336
8474
|
};
|
|
8337
8475
|
|
|
@@ -8566,7 +8704,7 @@ function wireStencil(pane, viewport, controller, announce) {
|
|
|
8566
8704
|
const page3 = state.document?.pages[state.pageIndex];
|
|
8567
8705
|
if (!master || !page3) return queue;
|
|
8568
8706
|
if (!editable3()) {
|
|
8569
|
-
announce("Open a .vsdx file to add shapes.
|
|
8707
|
+
announce("Open a .vsdx file to add shapes.");
|
|
8570
8708
|
return queue;
|
|
8571
8709
|
}
|
|
8572
8710
|
const { size } = master;
|
|
@@ -8697,336 +8835,215 @@ function createRulers(viewport) {
|
|
|
8697
8835
|
}
|
|
8698
8836
|
};
|
|
8699
8837
|
}
|
|
8700
|
-
var
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
}) {
|
|
8704
|
-
this.panel = panel;
|
|
8838
|
+
var ViewerInlineText = class {
|
|
8839
|
+
constructor(viewport, controller, announce) {
|
|
8840
|
+
this.viewport = viewport;
|
|
8705
8841
|
this.controller = controller;
|
|
8706
|
-
this.
|
|
8707
|
-
const
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
angle.dataset.geometryField = "angle";
|
|
8715
|
-
label.append(angle);
|
|
8716
|
-
const actions = panel.querySelector("[data-geometry] .edit-actions");
|
|
8717
|
-
actions.before(label);
|
|
8718
|
-
const rotate = doc.createElement("button");
|
|
8719
|
-
rotate.type = "button";
|
|
8720
|
-
rotate.dataset.geometryAction = "rotate-shape";
|
|
8721
|
-
rotate.textContent = "Rotate selected";
|
|
8722
|
-
actions.append(rotate);
|
|
8723
|
-
this.#fields = {
|
|
8724
|
-
id: field("id"),
|
|
8725
|
-
text: field("text"),
|
|
8726
|
-
x: field("x"),
|
|
8727
|
-
y: field("y"),
|
|
8728
|
-
width: field("width"),
|
|
8729
|
-
height: field("height"),
|
|
8730
|
-
angle
|
|
8731
|
-
};
|
|
8732
|
-
this.#buttons = [...panel.querySelectorAll("[data-geometry-action]")];
|
|
8733
|
-
this.#error = panel.querySelector("[data-geometry-error]");
|
|
8842
|
+
this.announce = announce;
|
|
8843
|
+
const doc = viewport.ownerDocument;
|
|
8844
|
+
this.input = doc.createElement("textarea");
|
|
8845
|
+
this.input.id = "edit-text";
|
|
8846
|
+
this.input.className = "inline-text";
|
|
8847
|
+
this.input.spellcheck = true;
|
|
8848
|
+
this.input.hidden = true;
|
|
8849
|
+
this.input.setAttribute("aria-label", "Shape text");
|
|
8734
8850
|
}
|
|
8735
|
-
|
|
8851
|
+
viewport;
|
|
8736
8852
|
controller;
|
|
8737
|
-
|
|
8738
|
-
#fields;
|
|
8739
|
-
#buttons;
|
|
8740
|
-
#error;
|
|
8741
|
-
#identity = "";
|
|
8742
|
-
#request = 0;
|
|
8743
|
-
wire() {
|
|
8744
|
-
const Abort = this.panel.ownerDocument.defaultView?.AbortController ?? AbortController;
|
|
8745
|
-
const events = new Abort();
|
|
8746
|
-
for (const field of Object.values(this.#fields))
|
|
8747
|
-
field.addEventListener(
|
|
8748
|
-
"input",
|
|
8749
|
-
() => {
|
|
8750
|
-
this.render(this.controller.state);
|
|
8751
|
-
this.draftChanged();
|
|
8752
|
-
},
|
|
8753
|
-
{
|
|
8754
|
-
signal: events.signal
|
|
8755
|
-
}
|
|
8756
|
-
);
|
|
8757
|
-
for (const button of this.#buttons)
|
|
8758
|
-
button.addEventListener(
|
|
8759
|
-
"click",
|
|
8760
|
-
() => {
|
|
8761
|
-
void this.#run(button);
|
|
8762
|
-
},
|
|
8763
|
-
{ signal: events.signal }
|
|
8764
|
-
);
|
|
8765
|
-
return () => {
|
|
8766
|
-
++this.#request;
|
|
8767
|
-
events.abort();
|
|
8768
|
-
};
|
|
8769
|
-
}
|
|
8770
|
-
async #run(button) {
|
|
8771
|
-
if (button.disabled) return;
|
|
8772
|
-
const state = this.controller.state;
|
|
8773
|
-
const pageId = state.selectedShape?.pageId ?? state.document?.pages[state.pageIndex]?.id;
|
|
8774
|
-
if (pageId === void 0) return;
|
|
8775
|
-
const type = button.dataset.geometryAction;
|
|
8776
|
-
if (type !== "create-rectangle" && state.selectedShapes.length !== 1) return;
|
|
8777
|
-
const shapeId = type === "create-rectangle" ? this.#fields.id.value : state.selectedShape?.id;
|
|
8778
|
-
if (!shapeId) return;
|
|
8779
|
-
const x = this.#fields.x.valueAsNumber, y = this.#fields.y.valueAsNumber;
|
|
8780
|
-
const width = this.#fields.width.valueAsNumber, height = this.#fields.height.valueAsNumber;
|
|
8781
|
-
const target = { pageId, shapeId };
|
|
8782
|
-
const command2 = type === "create-rectangle" ? {
|
|
8783
|
-
type,
|
|
8784
|
-
...target,
|
|
8785
|
-
x,
|
|
8786
|
-
y,
|
|
8787
|
-
width,
|
|
8788
|
-
height,
|
|
8789
|
-
...this.#fields.text.value ? { text: this.#fields.text.value } : {}
|
|
8790
|
-
} : type === "move-shape" ? { type, ...target, x, y } : type === "resize-shape" ? { type, ...target, width, height } : type === "rotate-shape" ? { type, ...target, angle: this.#fields.angle.valueAsNumber * Math.PI / 180 } : { type: "delete-shape", ...target };
|
|
8791
|
-
const request = ++this.#request;
|
|
8792
|
-
this.#error.hidden = true;
|
|
8793
|
-
try {
|
|
8794
|
-
await this.controller.applyEdits([command2]);
|
|
8795
|
-
if (request === this.#request) {
|
|
8796
|
-
this.reset();
|
|
8797
|
-
this.render(this.controller.state);
|
|
8798
|
-
this.draftChanged();
|
|
8799
|
-
}
|
|
8800
|
-
} catch (error) {
|
|
8801
|
-
if (request === this.#request && !isEditCancellation(error)) {
|
|
8802
|
-
this.#error.textContent = editErrorMessage(error);
|
|
8803
|
-
this.#error.hidden = false;
|
|
8804
|
-
}
|
|
8805
|
-
}
|
|
8806
|
-
}
|
|
8807
|
-
get hasDraft() {
|
|
8808
|
-
return Object.values(this.#fields).some((field) => field.value !== "");
|
|
8809
|
-
}
|
|
8810
|
-
reset() {
|
|
8811
|
-
++this.#request;
|
|
8812
|
-
this.#error.hidden = true;
|
|
8813
|
-
for (const field of Object.values(this.#fields)) field.value = "";
|
|
8814
|
-
}
|
|
8815
|
-
render(state) {
|
|
8816
|
-
const pageId = state.selectedShape?.pageId ?? state.document?.pages[state.pageIndex]?.id;
|
|
8817
|
-
const identity = JSON.stringify([
|
|
8818
|
-
this.controller.sourceGeneration,
|
|
8819
|
-
state.pageIndex,
|
|
8820
|
-
pageId,
|
|
8821
|
-
state.selectedShape?.id,
|
|
8822
|
-
state.selectedShapes.length
|
|
8823
|
-
]);
|
|
8824
|
-
if (identity !== this.#identity) {
|
|
8825
|
-
this.#identity = identity;
|
|
8826
|
-
++this.#request;
|
|
8827
|
-
this.#error.hidden = true;
|
|
8828
|
-
for (const field of Object.values(this.#fields)) field.value = "";
|
|
8829
|
-
}
|
|
8830
|
-
const available = state.edit.sourceAvailable && pageId !== void 0 && !state.loading && !state.edit.busy;
|
|
8831
|
-
for (const field of Object.values(this.#fields)) field.disabled = !available;
|
|
8832
|
-
const position = [this.#fields.x, this.#fields.y].every(
|
|
8833
|
-
(field) => Number.isFinite(field.valueAsNumber)
|
|
8834
|
-
);
|
|
8835
|
-
const size = [this.#fields.width, this.#fields.height].every(
|
|
8836
|
-
(field) => Number.isFinite(field.valueAsNumber) && field.valueAsNumber > 0
|
|
8837
|
-
);
|
|
8838
|
-
const selected = selectedShape(state.document, state.selectedShape, state.pageIndex);
|
|
8839
|
-
const lineSize = selected?.kind === "connector" && selected.height === 0 && Number.isFinite(this.#fields.width.valueAsNumber) && this.#fields.width.valueAsNumber > 0 && this.#fields.height.valueAsNumber === 0;
|
|
8840
|
-
for (const button of this.#buttons) {
|
|
8841
|
-
const action2 = button.dataset.geometryAction;
|
|
8842
|
-
button.disabled = !available || (action2 === "create-rectangle" ? !this.#fields.id.value || !position || !size : !state.selectedShape || state.selectedShapes.length !== 1 || action2 === "move-shape" && !position || action2 === "resize-shape" && !size && !lineSize || action2 === "rotate-shape" && (!Number.isFinite(this.#fields.angle.valueAsNumber) || selected?.kind === "connector"));
|
|
8843
|
-
}
|
|
8844
|
-
}
|
|
8845
|
-
};
|
|
8846
|
-
|
|
8847
|
-
// src/visio/viewer-edit-controls.ts
|
|
8848
|
-
var editControlsTemplate = `<details class="edit-controls"><summary>Edit diagram (experimental)</summary><p id="edit-warning">Experimental source-backed editing. Unsupported targets are rejected. Native Visio compatibility is not verified. Keep your original file.</p><p data-edit-target></p><label for="edit-text">Selected shape text</label><textarea id="edit-text" rows="3" spellcheck="true" aria-describedby="edit-warning edit-target edit-status"></textarea><div class="edit-actions"><button type="button" data-edit="apply">Apply text</button><button type="button" data-edit="cancel">Cancel</button><button type="button" data-edit="undo">Undo</button><button type="button" data-edit="redo">Redo</button></div><p id="edit-status" role="status" aria-live="polite"></p><p data-edit-error role="alert" hidden></p><ul data-edit-diagnostics></ul>${geometryControlsTemplate}</details>`;
|
|
8849
|
-
var ViewerEditControls = class {
|
|
8850
|
-
panel;
|
|
8853
|
+
announce;
|
|
8851
8854
|
input;
|
|
8852
|
-
#
|
|
8853
|
-
#status;
|
|
8854
|
-
#error;
|
|
8855
|
-
#diagnostics;
|
|
8856
|
-
#buttons;
|
|
8857
|
-
#identity = "";
|
|
8858
|
-
#initial = "";
|
|
8859
|
-
#pageId;
|
|
8860
|
-
#shapeId;
|
|
8855
|
+
#session;
|
|
8861
8856
|
#request = 0;
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
#controller;
|
|
8865
|
-
#geometry;
|
|
8866
|
-
constructor(root, controller) {
|
|
8867
|
-
this.#controller = controller;
|
|
8868
|
-
this.panel = root.querySelector(".edit-controls");
|
|
8869
|
-
this.#geometry = new ViewerGeometryControls(
|
|
8870
|
-
this.panel,
|
|
8871
|
-
controller,
|
|
8872
|
-
() => this.render(controller.state)
|
|
8873
|
-
);
|
|
8874
|
-
this.input = this.panel.querySelector("textarea");
|
|
8875
|
-
this.#target = this.panel.querySelector("[data-edit-target]");
|
|
8876
|
-
this.#target.id = "edit-target";
|
|
8877
|
-
this.#status = this.panel.querySelector("#edit-status");
|
|
8878
|
-
this.#error = this.panel.querySelector("[data-edit-error]");
|
|
8879
|
-
this.#diagnostics = this.panel.querySelector("[data-edit-diagnostics]");
|
|
8880
|
-
const button = (name) => this.panel.querySelector(`[data-edit="${name}"]`);
|
|
8881
|
-
this.#buttons = {
|
|
8882
|
-
apply: button("apply"),
|
|
8883
|
-
cancel: button("cancel"),
|
|
8884
|
-
undo: button("undo"),
|
|
8885
|
-
redo: button("redo")
|
|
8886
|
-
};
|
|
8857
|
+
get editing() {
|
|
8858
|
+
return !!this.#session;
|
|
8887
8859
|
}
|
|
8888
8860
|
wire() {
|
|
8889
|
-
const
|
|
8890
|
-
const Abort = this.panel.ownerDocument.defaultView?.AbortController ?? AbortController;
|
|
8861
|
+
const Abort = this.viewport.ownerDocument.defaultView?.AbortController ?? AbortController;
|
|
8891
8862
|
const events = new Abort();
|
|
8892
8863
|
const options2 = { signal: events.signal };
|
|
8893
|
-
|
|
8894
|
-
|
|
8864
|
+
const input = this.input;
|
|
8865
|
+
input.addEventListener("input", () => this.#layout(), options2);
|
|
8866
|
+
input.addEventListener(
|
|
8895
8867
|
"keydown",
|
|
8896
8868
|
(event) => {
|
|
8869
|
+
event.stopPropagation();
|
|
8897
8870
|
if (event.isComposing) return;
|
|
8898
|
-
if (event.key === "Escape") {
|
|
8871
|
+
if (event.key === "Escape" || event.key === "Enter" && (event.ctrlKey || event.metaKey)) {
|
|
8899
8872
|
event.preventDefault();
|
|
8900
|
-
this.
|
|
8901
|
-
}
|
|
8902
|
-
if (event.key === "Enter" && (event.ctrlKey || event.metaKey)) {
|
|
8903
|
-
event.preventDefault();
|
|
8904
|
-
this.#buttons.apply.click();
|
|
8873
|
+
void this.commit(true);
|
|
8905
8874
|
}
|
|
8906
8875
|
},
|
|
8907
8876
|
options2
|
|
8908
8877
|
);
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
|
|
8917
|
-
|
|
8878
|
+
for (const name of ["pointerdown", "click", "dblclick", "contextmenu"])
|
|
8879
|
+
input.addEventListener(name, (event) => event.stopPropagation(), options2);
|
|
8880
|
+
this.viewport.addEventListener(
|
|
8881
|
+
"pointerdown",
|
|
8882
|
+
(event) => {
|
|
8883
|
+
if (this.#session && event.target !== input) void this.commit(false);
|
|
8884
|
+
},
|
|
8885
|
+
{ ...options2, capture: true }
|
|
8886
|
+
);
|
|
8918
8887
|
return () => {
|
|
8919
|
-
disposeGeometry();
|
|
8920
8888
|
events.abort();
|
|
8921
8889
|
++this.#request;
|
|
8922
|
-
this.#
|
|
8923
|
-
|
|
8924
|
-
this.#identity = "";
|
|
8925
|
-
this.input.value = this.#initial;
|
|
8890
|
+
this.#close();
|
|
8891
|
+
input.remove();
|
|
8926
8892
|
};
|
|
8927
8893
|
}
|
|
8928
|
-
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
8933
|
-
this
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
if (
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
if (
|
|
8894
|
+
/**
|
|
8895
|
+
* Start editing the one selected shape's text. `typed` replaces the text with a typed character,
|
|
8896
|
+
* as typing on a selected shape does in Visio. False when the selection has no editable text.
|
|
8897
|
+
*/
|
|
8898
|
+
start(typed) {
|
|
8899
|
+
const state = this.controller.state;
|
|
8900
|
+
const page3 = state.document?.pages[state.pageIndex];
|
|
8901
|
+
const selected = state.selectedShape;
|
|
8902
|
+
if (this.#session) {
|
|
8903
|
+
this.input.focus();
|
|
8904
|
+
return true;
|
|
8905
|
+
}
|
|
8906
|
+
if (!page3 || !selected || state.selectedShapes.length !== 1) {
|
|
8907
|
+
this.announce("Select one shape to edit its text.");
|
|
8908
|
+
return false;
|
|
8909
|
+
}
|
|
8910
|
+
if (!state.edit.sourceAvailable || state.edit.busy || state.loading) {
|
|
8911
|
+
this.announce("This drawing cannot be edited.");
|
|
8912
|
+
return false;
|
|
8913
|
+
}
|
|
8914
|
+
const shape = visioTextShape(page3, selected.id);
|
|
8915
|
+
if (!shape) return false;
|
|
8916
|
+
const group2 = this.viewport.querySelector(
|
|
8917
|
+
`svg.paper [data-shape-id="${CSS.escape(shape.id)}"]`
|
|
8918
|
+
);
|
|
8919
|
+
const initial = shape.text?.plainText ?? "";
|
|
8920
|
+
this.#session = {
|
|
8921
|
+
pageId: page3.id,
|
|
8922
|
+
shapeId: shape.id,
|
|
8923
|
+
initial,
|
|
8924
|
+
generation: this.controller.sourceGeneration,
|
|
8925
|
+
document: state.document,
|
|
8926
|
+
group: group2
|
|
8927
|
+
};
|
|
8928
|
+
group2?.setAttribute("data-editing-text", "");
|
|
8929
|
+
this.viewport.dataset.textEditing = "";
|
|
8930
|
+
this.#style(shape, state.zoom || 1);
|
|
8931
|
+
this.input.value = typed ?? initial;
|
|
8932
|
+
this.input.hidden = false;
|
|
8933
|
+
this.viewport.append(this.input);
|
|
8934
|
+
this.#layout();
|
|
8935
|
+
this.input.focus({ preventScroll: true });
|
|
8936
|
+
const end = this.input.value.length;
|
|
8937
|
+
this.input.setSelectionRange(end, end);
|
|
8938
|
+
return true;
|
|
8939
|
+
}
|
|
8940
|
+
/** Save the draft as one edit; `focusCanvas` returns keyboard focus to the drawing. */
|
|
8941
|
+
async commit(focusCanvas) {
|
|
8942
|
+
const session = this.#session;
|
|
8943
|
+
if (!session) return;
|
|
8944
|
+
const draft = this.input.value;
|
|
8945
|
+
this.#close();
|
|
8946
|
+
if (focusCanvas) this.viewport.focus({ preventScroll: true });
|
|
8947
|
+
const state = this.controller.state;
|
|
8948
|
+
const page3 = state.document?.pages.find((item) => item.id === session.pageId);
|
|
8949
|
+
if (!page3 || this.controller.sourceGeneration !== session.generation || draft === session.initial)
|
|
8950
|
+
return;
|
|
8941
8951
|
const request = ++this.#request;
|
|
8942
|
-
this.#pending = true;
|
|
8943
|
-
this.#localError = void 0;
|
|
8944
|
-
this.render(this.#controller.state);
|
|
8945
8952
|
try {
|
|
8946
|
-
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
);
|
|
8951
|
-
if (page3 && visioTextShape(page3, this.#shapeId)?.text.fields?.length) {
|
|
8952
|
-
const edit = visioTextDraftEdit(page3, this.#shapeId, this.input.value);
|
|
8953
|
-
if (edit) await this.#controller.applyEdits([edit]);
|
|
8954
|
-
} else
|
|
8955
|
-
await this.#controller.replacePlainText(this.#pageId, this.#shapeId, this.input.value);
|
|
8956
|
-
} else await this.#controller[action2]();
|
|
8953
|
+
const shape = visioTextShape(page3, session.shapeId);
|
|
8954
|
+
const rich = !!shape && shape.masterId === void 0 && shape.text.runs.length > 1;
|
|
8955
|
+
const edit = visioTextDraftEdit(page3, session.shapeId, draft, rich ? { ranges: true } : {});
|
|
8956
|
+
if (edit) await this.controller.applyEdits([edit]);
|
|
8957
8957
|
} catch (error) {
|
|
8958
8958
|
if (request === this.#request && !isEditCancellation(error))
|
|
8959
|
-
this
|
|
8960
|
-
} finally {
|
|
8961
|
-
if (request === this.#request) {
|
|
8962
|
-
this.#pending = false;
|
|
8963
|
-
this.render(this.#controller.state);
|
|
8964
|
-
}
|
|
8959
|
+
this.announce(editErrorMessage(error));
|
|
8965
8960
|
}
|
|
8966
8961
|
}
|
|
8962
|
+
/**
|
|
8963
|
+
* Selecting something else or changing page saves; another edit to the same drawing (formatting,
|
|
8964
|
+
* a move, undo) keeps the draft on the redrawn shape; a different file discards it.
|
|
8965
|
+
*/
|
|
8967
8966
|
render(state) {
|
|
8968
|
-
this.#
|
|
8969
|
-
|
|
8970
|
-
const
|
|
8971
|
-
const shape =
|
|
8972
|
-
|
|
8973
|
-
this.#
|
|
8974
|
-
|
|
8975
|
-
|
|
8976
|
-
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
this
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
this.#
|
|
8999
|
-
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
this.#
|
|
9003
|
-
|
|
9004
|
-
this
|
|
9005
|
-
this
|
|
9006
|
-
this
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
);
|
|
8967
|
+
const session = this.#session;
|
|
8968
|
+
if (!session) return;
|
|
8969
|
+
const page3 = state.document?.pages[state.pageIndex];
|
|
8970
|
+
const shape = page3?.id === session.pageId ? visioTextShape(page3, session.shapeId) : void 0;
|
|
8971
|
+
if (this.controller.sourceGeneration !== session.generation || !state.document) {
|
|
8972
|
+
this.#close();
|
|
8973
|
+
return;
|
|
8974
|
+
}
|
|
8975
|
+
if (!shape || state.selectedShapes.length !== 1 || state.selectedShape?.id !== session.shapeId) {
|
|
8976
|
+
void this.commit(false);
|
|
8977
|
+
return;
|
|
8978
|
+
}
|
|
8979
|
+
if (state.document !== session.document) {
|
|
8980
|
+
const dirty = this.input.value !== session.initial;
|
|
8981
|
+
session.document = state.document;
|
|
8982
|
+
session.initial = shape.text?.plainText ?? "";
|
|
8983
|
+
if (!dirty) this.input.value = session.initial;
|
|
8984
|
+
session.group = this.viewport.querySelector(
|
|
8985
|
+
`svg.paper [data-shape-id="${CSS.escape(shape.id)}"]`
|
|
8986
|
+
);
|
|
8987
|
+
session.group?.setAttribute("data-editing-text", "");
|
|
8988
|
+
this.#style(shape, state.zoom || 1);
|
|
8989
|
+
}
|
|
8990
|
+
if (!this.input.isConnected) {
|
|
8991
|
+
const { selectionStart, selectionEnd } = this.input;
|
|
8992
|
+
this.viewport.append(this.input);
|
|
8993
|
+
this.viewport.dataset.textEditing = "";
|
|
8994
|
+
this.input.focus({ preventScroll: true });
|
|
8995
|
+
this.input.setSelectionRange(selectionStart, selectionEnd);
|
|
8996
|
+
}
|
|
8997
|
+
this.#layout();
|
|
8998
|
+
}
|
|
8999
|
+
#close() {
|
|
9000
|
+
const session = this.#session;
|
|
9001
|
+
this.#session = void 0;
|
|
9002
|
+
session?.group?.removeAttribute("data-editing-text");
|
|
9003
|
+
delete this.viewport.dataset.textEditing;
|
|
9004
|
+
this.input.hidden = true;
|
|
9005
|
+
this.input.remove();
|
|
9006
|
+
}
|
|
9007
|
+
/** Match the shape's text: family, size at this zoom, colour and alignment. */
|
|
9008
|
+
#style(shape, zoom) {
|
|
9009
|
+
const text = shape.text;
|
|
9010
|
+
const style = this.input.style;
|
|
9011
|
+
style.fontFamily = text?.fontFamily ? `"${text.fontFamily}", var(--office-font)` : "";
|
|
9012
|
+
style.fontSize = `${Math.max(8, (text?.fontSize ?? 12 / 72) * 96 * zoom)}px`;
|
|
9013
|
+
style.color = text?.color ?? "";
|
|
9014
|
+
style.textAlign = text?.horizontalAlign === "justify" ? "justify" : text?.horizontalAlign ?? "center";
|
|
9015
|
+
this.input.dataset.verticalAlign = text?.verticalAlign ?? "middle";
|
|
9016
|
+
}
|
|
9017
|
+
/** Cover the shape's drawn box and keep the text vertically placed as the shape aligns it. */
|
|
9018
|
+
#layout() {
|
|
9019
|
+
const session = this.#session;
|
|
9020
|
+
if (!session) return;
|
|
9021
|
+
const box2 = this.viewport.getBoundingClientRect();
|
|
9022
|
+
const rect = session.group?.getBoundingClientRect();
|
|
9023
|
+
const width = Math.max(48, rect?.width ?? 160);
|
|
9024
|
+
const height = Math.max(24, rect?.height ?? 48);
|
|
9025
|
+
const style = this.input.style;
|
|
9026
|
+
style.left = `${(rect ? rect.left - box2.left : 16) + this.viewport.scrollLeft}px`;
|
|
9027
|
+
style.top = `${(rect ? rect.top - box2.top : 16) + this.viewport.scrollTop}px`;
|
|
9028
|
+
style.width = `${width}px`;
|
|
9029
|
+
style.paddingTop = "0px";
|
|
9030
|
+
style.height = "0px";
|
|
9031
|
+
const content = this.input.scrollHeight;
|
|
9032
|
+
const free = Math.max(0, height - content);
|
|
9033
|
+
style.height = `${Math.max(height, content)}px`;
|
|
9034
|
+
const align = this.input.dataset.verticalAlign;
|
|
9035
|
+
style.paddingTop = `${align === "top" ? 0 : align === "bottom" ? free : free / 2}px`;
|
|
9013
9036
|
}
|
|
9014
9037
|
};
|
|
9015
9038
|
|
|
9016
9039
|
// src/visio/viewer-chrome.ts
|
|
9017
9040
|
var viewerChromeTemplate = `<div class="workspace">
|
|
9018
9041
|
<div class="viewport" tabindex="0" role="region" aria-label="Diagram canvas"></div>
|
|
9019
|
-
<
|
|
9020
|
-
<
|
|
9021
|
-
|
|
9022
|
-
<section class="inspector-card document-card" aria-label="Current page"><h2>Current page</h2><p class="current-page-name" data-page-name>No diagram open</p><dl><dt>Size</dt><dd data-page-size>No page</dd><dt>Shapes</dt><dd data-page-shapes>No shapes</dd></dl></section>
|
|
9023
|
-
<p class="selection-hint">Select a shape on the canvas to see its data and links.</p>
|
|
9024
|
-
<details class="shape-inspector inspector-card" hidden><summary>Selected shape</summary><div></div></details>
|
|
9025
|
-
${editControlsTemplate}${layerControlsTemplate}
|
|
9026
|
-
<details class="notes inspector-card"><summary>Compatibility notes</summary><ul></ul></details>
|
|
9027
|
-
</div>
|
|
9028
|
-
</aside>
|
|
9042
|
+
<office-ui-task-pane id="inspector-pane" class="inspector-pane" label="Shape Data" hidden>
|
|
9043
|
+
<section class="shape-inspector" data-pane-view="selection"><p class="selection-hint">No Shape Data</p><div></div></section>
|
|
9044
|
+
</office-ui-task-pane>
|
|
9029
9045
|
</div>`;
|
|
9046
|
+
var PANE_TITLES = { selection: "Shape Data" };
|
|
9030
9047
|
var ViewerChrome = class {
|
|
9031
9048
|
#root;
|
|
9032
9049
|
#controller;
|
|
@@ -9036,7 +9053,7 @@ var ViewerChrome = class {
|
|
|
9036
9053
|
#tools;
|
|
9037
9054
|
#inspector;
|
|
9038
9055
|
#panes;
|
|
9039
|
-
#
|
|
9056
|
+
#view = "selection";
|
|
9040
9057
|
#responsive;
|
|
9041
9058
|
#compact;
|
|
9042
9059
|
/** Panes the user showed or hid; responsive defaults leave them alone afterwards. */
|
|
@@ -9049,7 +9066,6 @@ var ViewerChrome = class {
|
|
|
9049
9066
|
this.#tools = root.querySelector(".ribbon-tools");
|
|
9050
9067
|
this.#inspector = root.querySelector(".inspector-pane");
|
|
9051
9068
|
this.#panes = { shapes: root.querySelector(".shapes-pane"), inspector: this.#inspector };
|
|
9052
|
-
this.#notes = root.querySelector(".notes");
|
|
9053
9069
|
}
|
|
9054
9070
|
wire() {
|
|
9055
9071
|
const view = this.#root.ownerDocument.defaultView;
|
|
@@ -9078,7 +9094,7 @@ var ViewerChrome = class {
|
|
|
9078
9094
|
);
|
|
9079
9095
|
const responsive = () => {
|
|
9080
9096
|
if (!this.#manual.has("shapes")) this.#setPane("shapes", !this.#responsive?.matches);
|
|
9081
|
-
if (!this.#manual.has("inspector")) this.#setPane("inspector",
|
|
9097
|
+
if (!this.#manual.has("inspector")) this.#setPane("inspector", false);
|
|
9082
9098
|
};
|
|
9083
9099
|
responsive();
|
|
9084
9100
|
this.#responsive?.addEventListener("change", responsive, options2);
|
|
@@ -9090,7 +9106,15 @@ var ViewerChrome = class {
|
|
|
9090
9106
|
if (!button || button.disabled) return;
|
|
9091
9107
|
const action2 = button.dataset.chrome;
|
|
9092
9108
|
if (action2 === "inspector" || action2 === "shapes") this.togglePane(action2);
|
|
9093
|
-
|
|
9109
|
+
},
|
|
9110
|
+
options2
|
|
9111
|
+
);
|
|
9112
|
+
this.#inspector.addEventListener(
|
|
9113
|
+
"office-pane-close",
|
|
9114
|
+
() => {
|
|
9115
|
+
this.#manual.add("inspector");
|
|
9116
|
+
this.#setPane("inspector", false);
|
|
9117
|
+
this.#root.querySelector(".viewport")?.focus({ preventScroll: true });
|
|
9094
9118
|
},
|
|
9095
9119
|
options2
|
|
9096
9120
|
);
|
|
@@ -9114,7 +9138,6 @@ var ViewerChrome = class {
|
|
|
9114
9138
|
options2
|
|
9115
9139
|
);
|
|
9116
9140
|
this.#root.addEventListener("office-ribbon-select", () => this.closeCompactTools(), options2);
|
|
9117
|
-
this.#notes.addEventListener("toggle", () => this.#syncNotes(), options2);
|
|
9118
9141
|
return () => events.abort();
|
|
9119
9142
|
}
|
|
9120
9143
|
showTab(tab) {
|
|
@@ -9140,36 +9163,33 @@ var ViewerChrome = class {
|
|
|
9140
9163
|
for (const other of Object.keys(this.#panes))
|
|
9141
9164
|
if (other !== pane) {
|
|
9142
9165
|
this.#panes[other].hidden = true;
|
|
9143
|
-
this.#command(other)
|
|
9166
|
+
this.#command(other)?.setAttribute("checked", "false");
|
|
9144
9167
|
}
|
|
9145
9168
|
}
|
|
9146
9169
|
this.#panes[pane].hidden = !visible;
|
|
9147
|
-
this.#command(pane)
|
|
9170
|
+
this.#command(pane)?.setAttribute("checked", String(visible));
|
|
9171
|
+
this.#command("shape-data")?.setAttribute(
|
|
9172
|
+
"checked",
|
|
9173
|
+
String(!this.#inspector.hidden && this.#view === "selection")
|
|
9174
|
+
);
|
|
9148
9175
|
if (pane === "shapes") {
|
|
9149
9176
|
const strip = this.#root.querySelector(".shapes-strip");
|
|
9150
9177
|
if (strip) strip.hidden = visible || !!this.#compact?.matches;
|
|
9151
9178
|
}
|
|
9152
|
-
this.#syncNotes();
|
|
9153
|
-
}
|
|
9154
|
-
#syncNotes() {
|
|
9155
|
-
this.#root.querySelector(".notes-strip button").setAttribute("aria-expanded", String(!this.#inspector.hidden && this.#notes.open));
|
|
9156
9179
|
}
|
|
9157
|
-
/**
|
|
9158
|
-
reveal(kind
|
|
9180
|
+
/** Show a task pane view (Shape Data) and move focus into it. */
|
|
9181
|
+
reveal(kind) {
|
|
9159
9182
|
if (this.#compact?.matches) this.#tools.open = false;
|
|
9183
|
+
this.#view = kind;
|
|
9184
|
+
for (const view of this.#inspector.querySelectorAll("[data-pane-view]"))
|
|
9185
|
+
view.toggleAttribute("data-active", view.dataset.paneView === kind);
|
|
9186
|
+
this.#inspector.setAttribute("label", PANE_TITLES[kind]);
|
|
9160
9187
|
this.#manual.add("inspector");
|
|
9161
9188
|
this.#setPane("inspector", true);
|
|
9162
|
-
const
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
const text = panel.querySelector("textarea");
|
|
9167
|
-
if (focusText && text && !text.disabled) text.focus();
|
|
9168
|
-
else panel.querySelector("summary").focus();
|
|
9169
|
-
panel.scrollIntoView?.({ block: "nearest", inline: "nearest" });
|
|
9170
|
-
this.#syncNotes();
|
|
9171
|
-
}
|
|
9172
|
-
render(state, noteCount) {
|
|
9189
|
+
const panel = this.#inspector.querySelector(`[data-pane-view="${kind}"]`);
|
|
9190
|
+
(panel.querySelector("input, button, a[href]") ?? this.#inspector).focus();
|
|
9191
|
+
}
|
|
9192
|
+
render(state) {
|
|
9173
9193
|
const page3 = state.document?.pages[state.pageIndex];
|
|
9174
9194
|
const doc = this.#root.ownerDocument;
|
|
9175
9195
|
if (state.document !== this.#document) {
|
|
@@ -9235,18 +9255,7 @@ var ViewerChrome = class {
|
|
|
9235
9255
|
"value",
|
|
9236
9256
|
page3 ? `Page ${state.pageIndex + 1} of ${state.document.pages.length}` : ""
|
|
9237
9257
|
);
|
|
9238
|
-
this.#root.querySelector("[data-page-name]").textContent = page3?.name ?? "No diagram open";
|
|
9239
|
-
this.#root.querySelector("[data-page-size]").textContent = page3 ? `${page3.width} \xD7 ${page3.height} in` : "No page";
|
|
9240
|
-
this.#root.querySelector("[data-page-shapes]").textContent = page3 ? `${page3.shapes.length} top-level` : "No shapes";
|
|
9241
9258
|
this.#root.querySelector(".selection-hint").hidden = !!state.selectedShape;
|
|
9242
|
-
const layers = Boolean(this.#root.querySelector(".layer-controls").hidden);
|
|
9243
|
-
this.#command("shape-data").disabled = !state.selectedShape;
|
|
9244
|
-
this.#command("layer-properties").disabled = layers;
|
|
9245
|
-
this.#command("layers-pane").disabled = layers;
|
|
9246
|
-
this.#command("notes").disabled = noteCount === 0;
|
|
9247
|
-
this.#root.querySelector(".notes-strip button").disabled = noteCount === 0;
|
|
9248
|
-
this.#root.querySelector("[data-note-count]").textContent = noteCount ? ` \xB7 ${noteCount}` : "";
|
|
9249
|
-
this.#syncNotes();
|
|
9250
9259
|
}
|
|
9251
9260
|
};
|
|
9252
9261
|
var ViewerCanvas = class {
|
|
@@ -9366,8 +9375,6 @@ var ViewerCanvas = class {
|
|
|
9366
9375
|
const inspected = selectedShape(state.document, selection2, state.pageIndex);
|
|
9367
9376
|
if (inspected !== this.#inspected) {
|
|
9368
9377
|
this.#inspected = inspected;
|
|
9369
|
-
this.inspector.hidden = !inspected;
|
|
9370
|
-
if (inspected) this.inspector.open = true;
|
|
9371
9378
|
this.inspector.querySelector("div").replaceChildren(...inspected ? [shapeDetails(inspected)] : []);
|
|
9372
9379
|
}
|
|
9373
9380
|
this.#selection = selection2 ? { ...selection2 } : null;
|
|
@@ -9388,6 +9395,7 @@ function routeRibbonAction(targets, action2) {
|
|
|
9388
9395
|
case "re-layout":
|
|
9389
9396
|
case "layout-options":
|
|
9390
9397
|
case "assign-layers":
|
|
9398
|
+
case "layer-properties":
|
|
9391
9399
|
case "select-by-type":
|
|
9392
9400
|
case "paste-special":
|
|
9393
9401
|
case "guides":
|
|
@@ -11064,8 +11072,7 @@ var ViewerDuplication = class {
|
|
|
11064
11072
|
controller;
|
|
11065
11073
|
edit;
|
|
11066
11074
|
reason(state) {
|
|
11067
|
-
if (!state.edit.sourceAvailable)
|
|
11068
|
-
return "Open a .vsdx file to duplicate shapes. Model-only documents are read only.";
|
|
11075
|
+
if (!state.edit.sourceAvailable) return "Open a .vsdx file to duplicate shapes.";
|
|
11069
11076
|
if (state.loading || state.edit.busy) return "Wait for the current operation to finish.";
|
|
11070
11077
|
if (!state.selectedShapes.length) return "Select shapes to duplicate.";
|
|
11071
11078
|
const page3 = state.document?.pages[state.pageIndex];
|
|
@@ -11106,8 +11113,7 @@ var ViewerGrouping = class {
|
|
|
11106
11113
|
controller;
|
|
11107
11114
|
edit;
|
|
11108
11115
|
reason(state, operation) {
|
|
11109
|
-
if (!state.edit.sourceAvailable)
|
|
11110
|
-
return "Open a .vsdx file to group shapes. Model-only documents are read only.";
|
|
11116
|
+
if (!state.edit.sourceAvailable) return "Open a .vsdx file to group shapes.";
|
|
11111
11117
|
if (state.loading || state.edit.busy) return "Wait for the current operation to finish.";
|
|
11112
11118
|
const page3 = state.document?.pages[state.pageIndex];
|
|
11113
11119
|
if (!page3 || state.selectedShapes.some((shape) => !visioSelectionIsOnPage(shape, page3.id)))
|
|
@@ -11170,8 +11176,7 @@ var ViewerClipboard = class {
|
|
|
11170
11176
|
return operation === "paste" ? typeof this.clipboard?.readText === "function" : this.hasPromiseWrite() || typeof this.clipboard?.writeText === "function";
|
|
11171
11177
|
}
|
|
11172
11178
|
baseReason(state) {
|
|
11173
|
-
if (!state.edit.sourceAvailable)
|
|
11174
|
-
return "Open a .vsdx file. Model-only documents are read only.";
|
|
11179
|
+
if (!state.edit.sourceAvailable) return "Open a .vsdx file.";
|
|
11175
11180
|
if (state.loading || state.edit.busy || this.#pending)
|
|
11176
11181
|
return "Wait for the current operation to finish.";
|
|
11177
11182
|
if (!state.document?.pages[state.pageIndex]) return "Open a page before using the clipboard.";
|
|
@@ -11978,8 +11983,8 @@ var ViewerPageSetupDialog = class {
|
|
|
11978
11983
|
const paper = f("paper");
|
|
11979
11984
|
if (paper && Number(paper) !== setup?.paperKind) print.paperKind = Number(paper);
|
|
11980
11985
|
const orientation = f("print-orientation");
|
|
11981
|
-
const
|
|
11982
|
-
if ((orientation === "portrait" || orientation === "landscape") && orientation !==
|
|
11986
|
+
const saved2 = setup?.printPageOrientation === 1 ? "portrait" : setup?.printPageOrientation === 2 ? "landscape" : "";
|
|
11987
|
+
if ((orientation === "portrait" || orientation === "landscape") && orientation !== saved2)
|
|
11983
11988
|
print.printOrientation = orientation;
|
|
11984
11989
|
if (Object.keys(print).length > 2) edits.push(print);
|
|
11985
11990
|
return visioKeepAutoSize(page3, edits);
|
|
@@ -12844,7 +12849,7 @@ var ViewerComments = class {
|
|
|
12844
12849
|
if (this.pane.labels.newComment !== newComment)
|
|
12845
12850
|
this.pane.labels = { empty: "No comments on this page.", newComment };
|
|
12846
12851
|
const button = (name) => this.root.querySelector(`[command="${name}"]`);
|
|
12847
|
-
const reason = !page3 ? "Open a drawing first." : !state.edit.sourceAvailable ? "Open a .vsdx file to add comments.
|
|
12852
|
+
const reason = !page3 ? "Open a drawing first." : !state.edit.sourceAvailable ? "Open a .vsdx file to add comments." : !editable3 ? "Wait for the current operation to finish." : "";
|
|
12848
12853
|
for (const name of ["new-comment", "ctx-comment", "ctx-page-comment"]) {
|
|
12849
12854
|
const control = button(name);
|
|
12850
12855
|
if (!control) continue;
|
|
@@ -13235,8 +13240,7 @@ var ViewerSubprocess = class {
|
|
|
13235
13240
|
return state.selectedShapes.map((shape) => shape.id);
|
|
13236
13241
|
}
|
|
13237
13242
|
reason(state, mode) {
|
|
13238
|
-
if (!state.edit.sourceAvailable)
|
|
13239
|
-
return "Open a .vsdx file to create subprocesses. Model-only documents are read only.";
|
|
13243
|
+
if (!state.edit.sourceAvailable) return "Open a .vsdx file to create subprocesses.";
|
|
13240
13244
|
if (state.loading || state.edit.busy) return "Wait for the current operation to finish.";
|
|
13241
13245
|
const page3 = this.#page(state);
|
|
13242
13246
|
if (!page3 || page3.isBackground) return "Open a foreground page.";
|
|
@@ -13427,8 +13431,7 @@ var ViewerDiagramParts = class {
|
|
|
13427
13431
|
edit;
|
|
13428
13432
|
revealText;
|
|
13429
13433
|
reason(state, part) {
|
|
13430
|
-
if (!state.edit.sourceAvailable)
|
|
13431
|
-
return "Open a .vsdx file to insert diagram parts. Model-only documents are read only.";
|
|
13434
|
+
if (!state.edit.sourceAvailable) return "Open a .vsdx file to insert diagram parts.";
|
|
13432
13435
|
if (state.loading || state.edit.busy) return "Wait for the current operation to finish.";
|
|
13433
13436
|
const page3 = state.document?.pages[state.pageIndex];
|
|
13434
13437
|
if (!page3 || state.selectedShapes.some((shape) => !visioSelectionIsOnPage(shape, page3.id)))
|
|
@@ -14711,7 +14714,8 @@ var ViewerGuides = class {
|
|
|
14711
14714
|
controller;
|
|
14712
14715
|
announce;
|
|
14713
14716
|
#shown = false;
|
|
14714
|
-
|
|
14717
|
+
/** On by default, as in Visio: moving shapes snap to other shapes' edges and centres. */
|
|
14718
|
+
#dynamic = true;
|
|
14715
14719
|
#selected;
|
|
14716
14720
|
#drag;
|
|
14717
14721
|
get shown() {
|
|
@@ -14736,16 +14740,20 @@ var ViewerGuides = class {
|
|
|
14736
14740
|
#editable(state) {
|
|
14737
14741
|
return state.edit.sourceAvailable && !state.loading && !state.edit.busy;
|
|
14738
14742
|
}
|
|
14739
|
-
/**
|
|
14740
|
-
|
|
14743
|
+
/**
|
|
14744
|
+
* Snap a shape drag; draws alignment hints. `grid` is the Snap to Grid step in page inches (0
|
|
14745
|
+
* while the grid is hidden). Unchanged when no snapping is active.
|
|
14746
|
+
*/
|
|
14747
|
+
snap(page3, ids, delta, grid = 0) {
|
|
14741
14748
|
const svg2 = this.#svg();
|
|
14742
14749
|
this.clearHints();
|
|
14743
|
-
if (!this.#shown && !this.#dynamic) return delta;
|
|
14750
|
+
if (!this.#shown && !this.#dynamic && !grid) return delta;
|
|
14744
14751
|
const zoom = this.controller.state.zoom || 1;
|
|
14745
14752
|
const result = visioSnapMoveDelta(page3, ids, delta, {
|
|
14746
14753
|
shapes: this.#dynamic,
|
|
14747
14754
|
guides: this.#shown,
|
|
14748
|
-
threshold: SNAP_PIXELS / (96 * zoom)
|
|
14755
|
+
threshold: SNAP_PIXELS / (96 * zoom),
|
|
14756
|
+
grid
|
|
14749
14757
|
});
|
|
14750
14758
|
if (!svg2 || !result.lines.length) return result.delta;
|
|
14751
14759
|
const hints = svg2.ownerDocument.createElementNS(SVG3, "g");
|
|
@@ -15101,6 +15109,180 @@ var ViewerLayerAssign = class {
|
|
|
15101
15109
|
this.dialog.close();
|
|
15102
15110
|
}
|
|
15103
15111
|
};
|
|
15112
|
+
var LABEL4 = "Layer Properties";
|
|
15113
|
+
var FLAGS = [
|
|
15114
|
+
["visible", "Visible"],
|
|
15115
|
+
["print", "Print"],
|
|
15116
|
+
["lock", "Lock"]
|
|
15117
|
+
];
|
|
15118
|
+
var saved = (layer, flag) => flag === "visible" ? layer.visible : flag === "print" ? layer.printable : layer.locked;
|
|
15119
|
+
var ViewerLayerProperties = class {
|
|
15120
|
+
constructor(root, controller, announce) {
|
|
15121
|
+
this.root = root;
|
|
15122
|
+
this.controller = controller;
|
|
15123
|
+
this.announce = announce;
|
|
15124
|
+
const doc = root.ownerDocument;
|
|
15125
|
+
this.dialog = new ViewerDialog(
|
|
15126
|
+
root,
|
|
15127
|
+
"layer-properties-dialog",
|
|
15128
|
+
LABEL4,
|
|
15129
|
+
["OK", "Cancel"],
|
|
15130
|
+
(b) => b === "OK" ? void this.#apply() : this.dialog.close()
|
|
15131
|
+
);
|
|
15132
|
+
this.#table = doc.createElement("table");
|
|
15133
|
+
this.#table.className = "layer-table";
|
|
15134
|
+
this.#note = doc.createElement("p");
|
|
15135
|
+
this.#note.className = "layer-note";
|
|
15136
|
+
this.dialog.body.append(this.#table, this.#note);
|
|
15137
|
+
}
|
|
15138
|
+
root;
|
|
15139
|
+
controller;
|
|
15140
|
+
announce;
|
|
15141
|
+
dialog;
|
|
15142
|
+
#table;
|
|
15143
|
+
#note;
|
|
15144
|
+
#generation;
|
|
15145
|
+
#sources(state) {
|
|
15146
|
+
const model = state.document;
|
|
15147
|
+
const page3 = model?.pages[state.pageIndex];
|
|
15148
|
+
return model && page3 ? getVisioPageLayers(model, page3.id) : [];
|
|
15149
|
+
}
|
|
15150
|
+
open() {
|
|
15151
|
+
const state = this.controller.state;
|
|
15152
|
+
const model = state.document;
|
|
15153
|
+
const sources = this.#sources(state);
|
|
15154
|
+
if (!model || !sources.some((source) => source.layers?.length)) {
|
|
15155
|
+
this.announce(`${LABEL4}: this page has no layers. Use Assign to Layer to add one.`);
|
|
15156
|
+
return;
|
|
15157
|
+
}
|
|
15158
|
+
const doc = this.root.ownerDocument;
|
|
15159
|
+
const editable3 = state.edit.sourceAvailable;
|
|
15160
|
+
const overrides = layerOverrideMaps(model, state.layerVisibilityOverrides);
|
|
15161
|
+
const cell = (tag, text = "") => Object.assign(doc.createElement(tag), { textContent: text });
|
|
15162
|
+
const head = doc.createElement("thead");
|
|
15163
|
+
const titles = doc.createElement("tr");
|
|
15164
|
+
for (const title2 of ["Name", "#", "Visible", "Print", "Lock", "Color"])
|
|
15165
|
+
titles.append(Object.assign(cell("th", title2), { scope: "col" }));
|
|
15166
|
+
head.append(titles);
|
|
15167
|
+
const body = doc.createElement("tbody");
|
|
15168
|
+
let shown = 0;
|
|
15169
|
+
for (const source of sources) {
|
|
15170
|
+
const page3 = model.pages.find((candidate) => candidate.id === source.id);
|
|
15171
|
+
const layers = source.layers ?? [];
|
|
15172
|
+
if (!layers.length) continue;
|
|
15173
|
+
if (sources.length > 1) {
|
|
15174
|
+
const caption = doc.createElement("tr");
|
|
15175
|
+
const label = cell(
|
|
15176
|
+
"th",
|
|
15177
|
+
source.id === sources[0].id ? source.name : `${source.name} (background)`
|
|
15178
|
+
);
|
|
15179
|
+
label.colSpan = 6;
|
|
15180
|
+
label.scope = "rowgroup";
|
|
15181
|
+
caption.className = "layer-page";
|
|
15182
|
+
caption.append(label);
|
|
15183
|
+
body.append(caption);
|
|
15184
|
+
}
|
|
15185
|
+
for (const layer of layers) {
|
|
15186
|
+
if (shown >= VIEWER_LAYER_LIMITS.controls) break;
|
|
15187
|
+
++shown;
|
|
15188
|
+
const name = layer.name.slice(0, 256) || "Layer";
|
|
15189
|
+
const row = doc.createElement("tr");
|
|
15190
|
+
row.dataset.pageId = source.id;
|
|
15191
|
+
row.dataset.layerId = layer.id;
|
|
15192
|
+
const count = (page3?.shapes ?? []).filter(
|
|
15193
|
+
(shape) => shape.layerIds?.includes(layer.id)
|
|
15194
|
+
).length;
|
|
15195
|
+
row.append(Object.assign(cell("th", name), { scope: "row" }), cell("td", String(count)));
|
|
15196
|
+
for (const [flag, title2] of FLAGS) {
|
|
15197
|
+
const box2 = doc.createElement("input");
|
|
15198
|
+
box2.type = "checkbox";
|
|
15199
|
+
box2.dataset.flag = flag;
|
|
15200
|
+
box2.setAttribute("aria-label", `${name}: ${title2}`);
|
|
15201
|
+
const override = flag === "visible" ? overrides.get(source.id)?.get(layer.id) : void 0;
|
|
15202
|
+
box2.checked = override ?? saved(layer, flag);
|
|
15203
|
+
box2.disabled = !editable3 && flag !== "visible";
|
|
15204
|
+
const holder = cell("td");
|
|
15205
|
+
holder.append(box2);
|
|
15206
|
+
row.append(holder);
|
|
15207
|
+
}
|
|
15208
|
+
const colour = cell("td");
|
|
15209
|
+
if (layer.color) {
|
|
15210
|
+
const swatch = doc.createElement("span");
|
|
15211
|
+
swatch.className = "layer-colour";
|
|
15212
|
+
swatch.style.background = layer.color;
|
|
15213
|
+
swatch.title = layer.color;
|
|
15214
|
+
colour.append(swatch);
|
|
15215
|
+
}
|
|
15216
|
+
row.append(colour);
|
|
15217
|
+
body.append(row);
|
|
15218
|
+
}
|
|
15219
|
+
}
|
|
15220
|
+
this.#table.replaceChildren(head, body);
|
|
15221
|
+
this.#note.textContent = editable3 ? "" : "This drawing is read-only: Visible changes how it is shown here and is not saved.";
|
|
15222
|
+
this.#generation = this.controller.documentGeneration;
|
|
15223
|
+
this.dialog.show();
|
|
15224
|
+
this.#table.querySelector("input:not([disabled])")?.focus();
|
|
15225
|
+
}
|
|
15226
|
+
async #apply() {
|
|
15227
|
+
const state = this.controller.state;
|
|
15228
|
+
const model = state.document;
|
|
15229
|
+
if (!model || this.controller.documentGeneration !== this.#generation) {
|
|
15230
|
+
this.dialog.close();
|
|
15231
|
+
return;
|
|
15232
|
+
}
|
|
15233
|
+
const editable3 = state.edit.sourceAvailable;
|
|
15234
|
+
const sources = new Map(this.#sources(state).map((source) => [source.id, source]));
|
|
15235
|
+
const edits = [];
|
|
15236
|
+
const shown = [];
|
|
15237
|
+
for (const row of this.#table.querySelectorAll("tr[data-layer-id]")) {
|
|
15238
|
+
const pageId = row.dataset.pageId, layerId = row.dataset.layerId;
|
|
15239
|
+
const layer = sources.get(pageId)?.layers?.find((candidate) => candidate.id === layerId);
|
|
15240
|
+
if (!layer) continue;
|
|
15241
|
+
const value = (flag) => row.querySelector(`input[data-flag="${flag}"]`).checked;
|
|
15242
|
+
if (!editable3) {
|
|
15243
|
+
shown.push({
|
|
15244
|
+
pageId,
|
|
15245
|
+
layerId,
|
|
15246
|
+
visible: value("visible") === layer.visible ? null : value("visible")
|
|
15247
|
+
});
|
|
15248
|
+
continue;
|
|
15249
|
+
}
|
|
15250
|
+
const changed = FLAGS.filter(([flag]) => value(flag) !== saved(layer, flag));
|
|
15251
|
+
if (changed.length)
|
|
15252
|
+
edits.push({
|
|
15253
|
+
type: "set-layer-properties",
|
|
15254
|
+
pageId,
|
|
15255
|
+
layerId,
|
|
15256
|
+
...Object.fromEntries(changed.map(([flag]) => [flag, value(flag)]))
|
|
15257
|
+
});
|
|
15258
|
+
shown.push({ pageId, layerId, visible: null });
|
|
15259
|
+
}
|
|
15260
|
+
this.dialog.busy(true);
|
|
15261
|
+
try {
|
|
15262
|
+
if (edits.length) await this.controller.applyEdits(edits);
|
|
15263
|
+
for (const item of shown)
|
|
15264
|
+
this.controller.setLayerVisibility(item.pageId, item.layerId, item.visible);
|
|
15265
|
+
this.dialog.close();
|
|
15266
|
+
if (edits.length)
|
|
15267
|
+
this.announce(`Updated ${edits.length} layer${edits.length === 1 ? "" : "s"}.`);
|
|
15268
|
+
} catch (error) {
|
|
15269
|
+
if (this.dialog.open && !isEditCancellation(error))
|
|
15270
|
+
this.dialog.error.textContent = editErrorMessage(error);
|
|
15271
|
+
} finally {
|
|
15272
|
+
this.dialog.busy(false);
|
|
15273
|
+
}
|
|
15274
|
+
}
|
|
15275
|
+
render(state) {
|
|
15276
|
+
const none = !this.#sources(state).some((source) => source.layers?.length);
|
|
15277
|
+
const command2 = this.root.querySelector('[command="layer-properties"]');
|
|
15278
|
+
if (command2) {
|
|
15279
|
+
command2.disabled = none;
|
|
15280
|
+
command2.title = none ? `${LABEL4}: this page has no layers.` : `${LABEL4}...`;
|
|
15281
|
+
}
|
|
15282
|
+
if (this.dialog.open && (state.loading || this.controller.documentGeneration !== this.#generation))
|
|
15283
|
+
this.dialog.close();
|
|
15284
|
+
}
|
|
15285
|
+
};
|
|
15104
15286
|
var AUTO_ALIGN = "Auto Align & Space";
|
|
15105
15287
|
var ViewerLayout = class {
|
|
15106
15288
|
constructor(root, controller, run) {
|
|
@@ -15513,6 +15695,7 @@ var ViewerLayoutCommands = class {
|
|
|
15513
15695
|
const { root, controller, announce } = host;
|
|
15514
15696
|
this.layout = new ViewerLayout(root, controller, host.edit);
|
|
15515
15697
|
this.layers = new ViewerLayerAssign(root, controller, announce);
|
|
15698
|
+
this.layerProperties = new ViewerLayerProperties(root, controller, announce);
|
|
15516
15699
|
this.select = new ViewerSelectType(root, controller, announce);
|
|
15517
15700
|
this.paste = new ViewerPasteSpecial(root, controller, announce, host.pasteShapes);
|
|
15518
15701
|
this.guides = new ViewerGuides(root, host.viewport, host.rulers, controller, announce);
|
|
@@ -15521,6 +15704,7 @@ var ViewerLayoutCommands = class {
|
|
|
15521
15704
|
host;
|
|
15522
15705
|
layout;
|
|
15523
15706
|
layers;
|
|
15707
|
+
layerProperties;
|
|
15524
15708
|
select;
|
|
15525
15709
|
paste;
|
|
15526
15710
|
guides;
|
|
@@ -15535,6 +15719,8 @@ var ViewerLayoutCommands = class {
|
|
|
15535
15719
|
return this.layout.showOptions();
|
|
15536
15720
|
case "assign-layers":
|
|
15537
15721
|
return this.layers.open();
|
|
15722
|
+
case "layer-properties":
|
|
15723
|
+
return this.layerProperties.open();
|
|
15538
15724
|
case "select-by-type":
|
|
15539
15725
|
return this.select.open();
|
|
15540
15726
|
case "paste-special":
|
|
@@ -15571,6 +15757,7 @@ var ViewerLayoutCommands = class {
|
|
|
15571
15757
|
render(state) {
|
|
15572
15758
|
this.layout.render(state);
|
|
15573
15759
|
this.layers.render(state);
|
|
15760
|
+
this.layerProperties.render(state);
|
|
15574
15761
|
this.select.render(state);
|
|
15575
15762
|
this.paste.render(state);
|
|
15576
15763
|
this.guides.render(state);
|
|
@@ -16371,7 +16558,7 @@ var ViewerTextFeatures = class {
|
|
|
16371
16558
|
/** The shape text editor, when it holds the caret for the selected shape. */
|
|
16372
16559
|
#activeEditor() {
|
|
16373
16560
|
const editor = this.#editor;
|
|
16374
|
-
return editor?.isConnected && !editor.disabled && editor.
|
|
16561
|
+
return editor?.isConnected && !editor.disabled && !editor.hidden ? editor : void 0;
|
|
16375
16562
|
}
|
|
16376
16563
|
run(feature) {
|
|
16377
16564
|
const { state, page: page3, editing, shapes, formattable, single } = this.#state();
|
|
@@ -16477,7 +16664,6 @@ var ViewerTextFeatures = class {
|
|
|
16477
16664
|
this.#language.dialog.close();
|
|
16478
16665
|
}
|
|
16479
16666
|
#spelling(page3) {
|
|
16480
|
-
const editor = this.root.querySelector(EDITOR);
|
|
16481
16667
|
const state = this.controller.state;
|
|
16482
16668
|
const selected = state.selectedShape;
|
|
16483
16669
|
const texts = [];
|
|
@@ -16489,17 +16675,15 @@ var ViewerTextFeatures = class {
|
|
|
16489
16675
|
};
|
|
16490
16676
|
visit(page3.shapes);
|
|
16491
16677
|
const shape = texts.find((item) => item.id === selected?.id) ?? texts[0];
|
|
16492
|
-
if (!
|
|
16493
|
-
this.announce(
|
|
16494
|
-
editor ? "This page has no shape text to check." : "Spelling needs the shape text editor."
|
|
16495
|
-
);
|
|
16678
|
+
if (!shape) {
|
|
16679
|
+
this.announce("This page has no shape text to check.");
|
|
16496
16680
|
return;
|
|
16497
16681
|
}
|
|
16498
16682
|
if (shape.id !== selected?.id || state.selectedShapes.length !== 1)
|
|
16499
16683
|
this.controller.selectShape({ id: shape.id, name: shape.name, pageId: page3.id });
|
|
16500
16684
|
this.reveal("edit", true);
|
|
16501
16685
|
this.announce(
|
|
16502
|
-
`Spelling uses your browser's spell checker: misspelled words in "${shape.name || `Shape ${shape.id}`}" are underlined in the shape
|
|
16686
|
+
`Spelling uses your browser's spell checker: misspelled words in "${shape.name || `Shape ${shape.id}`}" are underlined in the shape. Right-click a word for suggestions, then press Esc to keep the change. ${texts.length > 1 ? `${texts.length - 1} more shapes on this page have text.` : ""}`.trim()
|
|
16503
16687
|
);
|
|
16504
16688
|
}
|
|
16505
16689
|
wire() {
|
|
@@ -16507,8 +16691,8 @@ var ViewerTextFeatures = class {
|
|
|
16507
16691
|
const target = event.composedPath()[0];
|
|
16508
16692
|
if (target instanceof HTMLTextAreaElement && target.matches(EDITOR)) this.#editor = target;
|
|
16509
16693
|
};
|
|
16510
|
-
const pointer = () => {
|
|
16511
|
-
this.#editor = void 0;
|
|
16694
|
+
const pointer = (event) => {
|
|
16695
|
+
if (event.target !== this.#editor) this.#editor = void 0;
|
|
16512
16696
|
};
|
|
16513
16697
|
this.root.addEventListener("focusin", focus);
|
|
16514
16698
|
this.viewport.addEventListener("pointerdown", pointer, true);
|
|
@@ -16573,6 +16757,7 @@ var ViewerTextFeatures = class {
|
|
|
16573
16757
|
var editable2 = (target) => target instanceof Element && !!target.closest(
|
|
16574
16758
|
'input, textarea, select, office-ui-select, [contenteditable]:not([contenteditable="false"])'
|
|
16575
16759
|
);
|
|
16760
|
+
var GRID_STEP = 1 / 4;
|
|
16576
16761
|
var ViewerCommands = class {
|
|
16577
16762
|
constructor(host) {
|
|
16578
16763
|
this.host = host;
|
|
@@ -16767,6 +16952,10 @@ var ViewerCommands = class {
|
|
|
16767
16952
|
layoutCommands;
|
|
16768
16953
|
#textFeatures;
|
|
16769
16954
|
#targets;
|
|
16955
|
+
/** Page inches between minor grid lines while View > Grid is on (Snap to Grid), else 0. */
|
|
16956
|
+
get gridStep() {
|
|
16957
|
+
return this.#grid ? GRID_STEP : 0;
|
|
16958
|
+
}
|
|
16770
16959
|
get tool() {
|
|
16771
16960
|
return this.#tool;
|
|
16772
16961
|
}
|
|
@@ -17090,8 +17279,6 @@ var ViewerCommands = class {
|
|
|
17090
17279
|
root.querySelector('[data-menu="position"]').disabled = !rotating && !distributing && !this.layoutCommands.layout.available(state);
|
|
17091
17280
|
button("select-all").disabled = !page3 || state.loading;
|
|
17092
17281
|
button("clear-selection").disabled = !state.selectedShapes.length;
|
|
17093
|
-
button("undo").disabled = !state.edit.canUndo || state.edit.busy || state.loading;
|
|
17094
|
-
button("redo").disabled = !state.edit.canRedo || state.edit.busy || state.loading;
|
|
17095
17282
|
button("pointer").setAttribute("pressed", String(this.#tool === "pointer"));
|
|
17096
17283
|
button("connector").setAttribute("pressed", String(this.#tool === "connector"));
|
|
17097
17284
|
button("connector").disabled = !editing || !page3;
|
|
@@ -17119,7 +17306,7 @@ var ViewerCommands = class {
|
|
|
17119
17306
|
button("replace").title = editing ? "Replace literal, case-sensitive text occurrences (Ctrl+H)." : "Open a .vsdx file to replace text.";
|
|
17120
17307
|
for (const name of ["text-tool", "text-box"])
|
|
17121
17308
|
button(name).title = editing ? "Drag a fixed-size text box, or click a shape to edit plain text." : "Open a .vsdx file to add text boxes.";
|
|
17122
|
-
rectangle.title = state.edit.sourceAvailable ? "Rectangle (Ctrl+8)" : "Rectangle (Ctrl+8): open a .vsdx file to draw.
|
|
17309
|
+
rectangle.title = state.edit.sourceAvailable ? "Rectangle (Ctrl+8)" : "Rectangle (Ctrl+8): open a .vsdx file to draw.";
|
|
17123
17310
|
box2("grid").checked = this.#grid;
|
|
17124
17311
|
box2("grid").disabled = !page3;
|
|
17125
17312
|
box2("ruler").checked = this.#ruler;
|
|
@@ -17674,6 +17861,7 @@ function createRotationPreview(model, page3, shape, source) {
|
|
|
17674
17861
|
// src/visio/viewer-rotation-handle.ts
|
|
17675
17862
|
var SVG6 = "http://www.w3.org/2000/svg";
|
|
17676
17863
|
var pointOptions3 = { snap: false, bounded: false };
|
|
17864
|
+
var radians = (degrees, snap) => -(snap ? snapAngle(degrees) : degrees) * Math.PI / 180;
|
|
17677
17865
|
var ViewerRotationHandle = class {
|
|
17678
17866
|
constructor(viewport, controller, options2) {
|
|
17679
17867
|
this.viewport = viewport;
|
|
@@ -17738,10 +17926,14 @@ var ViewerRotationHandle = class {
|
|
|
17738
17926
|
handle.dataset.rotationHandle = shape.id;
|
|
17739
17927
|
handle.setAttribute("cx", String(point.x));
|
|
17740
17928
|
handle.setAttribute("cy", String(point.y));
|
|
17741
|
-
handle.setAttribute("r", "
|
|
17929
|
+
handle.setAttribute("r", "8");
|
|
17742
17930
|
handle.setAttribute("vector-effect", "non-scaling-stroke");
|
|
17743
17931
|
handle.setAttribute("aria-label", "Drag rotation handle");
|
|
17744
|
-
|
|
17932
|
+
const glyph = this.viewport.ownerDocument.createElementNS(SVG6, "path");
|
|
17933
|
+
glyph.classList.add("rotation-glyph");
|
|
17934
|
+
glyph.setAttribute("transform", `translate(${point.x} ${point.y})`);
|
|
17935
|
+
glyph.setAttribute("d", "M4.6 -2.9A5.4 5.4 0 1 0 5.4 .6M5.6 -5.9V-2.4H2.1");
|
|
17936
|
+
overlay.append(stem, handle, glyph);
|
|
17745
17937
|
this.viewport.append(overlay);
|
|
17746
17938
|
this.#overlay = overlay;
|
|
17747
17939
|
}
|
|
@@ -17829,7 +18021,7 @@ var ViewerRotationHandle = class {
|
|
|
17829
18021
|
}
|
|
17830
18022
|
const point = pagePoint(drag.svg, drag.page, event, pointOptions3);
|
|
17831
18023
|
if (point) {
|
|
17832
|
-
const angle =
|
|
18024
|
+
const angle = radians(drag.rotate(point), event.shiftKey);
|
|
17833
18025
|
try {
|
|
17834
18026
|
drag.shapePreview.update(angle);
|
|
17835
18027
|
} catch (error) {
|
|
@@ -17861,7 +18053,7 @@ var ViewerRotationHandle = class {
|
|
|
17861
18053
|
event.preventDefault();
|
|
17862
18054
|
event.stopImmediatePropagation();
|
|
17863
18055
|
const point = pagePoint(drag.svg, drag.page, event, pointOptions3);
|
|
17864
|
-
const angle = point ?
|
|
18056
|
+
const angle = point ? radians(drag.rotate(point), event.shiftKey) : void 0;
|
|
17865
18057
|
this.#cancel();
|
|
17866
18058
|
if (angle === void 0 || Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY) < 0.5 || this.controller.state.document !== drag.document)
|
|
17867
18059
|
return;
|
|
@@ -18679,7 +18871,6 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
18679
18871
|
#disposeInputs;
|
|
18680
18872
|
#viewport;
|
|
18681
18873
|
#zoomSlider;
|
|
18682
|
-
#shapeStatus;
|
|
18683
18874
|
#announcement;
|
|
18684
18875
|
#commands;
|
|
18685
18876
|
#presentation;
|
|
@@ -18700,11 +18891,10 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
18700
18891
|
#findBar;
|
|
18701
18892
|
#replace;
|
|
18702
18893
|
#status;
|
|
18703
|
-
#
|
|
18894
|
+
#titleBar;
|
|
18704
18895
|
#toolbar;
|
|
18705
18896
|
#chrome;
|
|
18706
18897
|
#edit;
|
|
18707
|
-
#layers;
|
|
18708
18898
|
#notes;
|
|
18709
18899
|
#unsubscribe;
|
|
18710
18900
|
#eventUnsubscribe;
|
|
@@ -18726,7 +18916,8 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
18726
18916
|
this.#findBar = createFindBar(document);
|
|
18727
18917
|
const ribbon = createRibbon(document);
|
|
18728
18918
|
applyKeyTips(ribbon);
|
|
18729
|
-
|
|
18919
|
+
this.#titleBar = createTitleBar(document);
|
|
18920
|
+
workspace.before(this.#titleBar, ribbon, this.#findBar);
|
|
18730
18921
|
workspace.prepend(createShapesStrip(document), createShapesWindow(document));
|
|
18731
18922
|
workspace.append(createPanZoom(document), createSizePosition(document));
|
|
18732
18923
|
this.#root.append(
|
|
@@ -18738,17 +18929,17 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
18738
18929
|
this.#viewport = this.#root.querySelector(".viewport");
|
|
18739
18930
|
this.#rulers = createRulers(this.#viewport);
|
|
18740
18931
|
this.#zoomSlider = this.#root.querySelector("office-ui-zoom-slider");
|
|
18741
|
-
this.#shapeStatus = this.#root.querySelector("[data-shape-status]");
|
|
18742
18932
|
this.#status = this.#root.querySelector("[data-status]");
|
|
18743
|
-
this.#diagnostics = this.#root.querySelector("[data-diagnostics]");
|
|
18744
18933
|
this.#toolbar = this.#root.querySelector(".toolbar");
|
|
18745
|
-
this.#edit = new
|
|
18746
|
-
|
|
18747
|
-
|
|
18934
|
+
this.#edit = new ViewerInlineText(this.#viewport, this.controller, (message) => {
|
|
18935
|
+
this.#announcement = message;
|
|
18936
|
+
this.#status.textContent = message;
|
|
18937
|
+
});
|
|
18938
|
+
this.#notes = this.#root.querySelector(".backstage-notes ul");
|
|
18748
18939
|
this.#canvas = new ViewerCanvas(
|
|
18749
18940
|
this.#viewport,
|
|
18750
18941
|
this.#notes,
|
|
18751
|
-
this.#root.querySelector(".notes"),
|
|
18942
|
+
this.#root.querySelector(".backstage-notes"),
|
|
18752
18943
|
this.#root.querySelector(".shape-inspector")
|
|
18753
18944
|
);
|
|
18754
18945
|
this.#chrome = new ViewerChrome(this.#root, this.controller);
|
|
@@ -18780,7 +18971,7 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
18780
18971
|
},
|
|
18781
18972
|
fit: (mode) => this.#fit(mode),
|
|
18782
18973
|
togglePane: (pane) => this.#chrome.togglePane(pane),
|
|
18783
|
-
reveal: (panel
|
|
18974
|
+
reveal: (panel) => this.#reveal(panel),
|
|
18784
18975
|
rulers: this.#rulers,
|
|
18785
18976
|
togglePanZoom: () => this.#panZoom.toggle(),
|
|
18786
18977
|
present: () => this.#presentation.start(),
|
|
@@ -18799,14 +18990,22 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
18799
18990
|
this.#status.textContent = message;
|
|
18800
18991
|
}
|
|
18801
18992
|
});
|
|
18802
|
-
|
|
18993
|
+
const profileChanged = () => renderTitleBar(this.#titleBar, this.controller.state, this.#fileName, this.#profile.profile);
|
|
18994
|
+
this.#profile = new ViewerProfile(this.#root, profileChanged, {
|
|
18995
|
+
get: () => this.#dark() ? "dark" : this.statusBar,
|
|
18996
|
+
set: (theme) => {
|
|
18997
|
+
if (theme !== "dark") this.statusBar = theme;
|
|
18998
|
+
if (theme === "dark" !== this.#dark())
|
|
18999
|
+
this.#requestScheme(theme === "dark" ? "dark" : "light");
|
|
19000
|
+
}
|
|
19001
|
+
});
|
|
18803
19002
|
this.#pointer = new ViewerPointerGestures(this.#viewport, this.controller, {
|
|
18804
19003
|
active: () => this.#commands.tool === "pointer",
|
|
18805
19004
|
announce: (message) => {
|
|
18806
19005
|
this.#announcement = message;
|
|
18807
19006
|
this.#status.textContent = message;
|
|
18808
19007
|
},
|
|
18809
|
-
snap: (page3, ids, delta) => this.#commands.layoutCommands.guides.snap(page3, ids, delta),
|
|
19008
|
+
snap: (page3, ids, delta) => this.#commands.layoutCommands.guides.snap(page3, ids, delta, this.#commands.gridStep),
|
|
18810
19009
|
clearSnap: () => this.#commands.layoutCommands.guides.clearHints()
|
|
18811
19010
|
});
|
|
18812
19011
|
this.#lineEndpoints = new ViewerLineEndpoints(this.#viewport, this.controller, {
|
|
@@ -18852,7 +19051,6 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
18852
19051
|
this.#fileName = "";
|
|
18853
19052
|
this.controller.setDocument(null);
|
|
18854
19053
|
},
|
|
18855
|
-
revealNotes: () => this.#chrome.reveal("notes"),
|
|
18856
19054
|
showOptions: () => this.#profile.showOptions(),
|
|
18857
19055
|
announce: (message) => {
|
|
18858
19056
|
this.#announcement = message;
|
|
@@ -18887,12 +19085,43 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
18887
19085
|
set zoom(value) {
|
|
18888
19086
|
this.controller.setZoom(value);
|
|
18889
19087
|
}
|
|
19088
|
+
/**
|
|
19089
|
+
* The status bar's look: `'neutral'` (the suite's bar, the default) or `'colorful'` (Visio's
|
|
19090
|
+
* product colour). Reflects the `status-bar` attribute; `--vv-status-background` and
|
|
19091
|
+
* `--vv-status-ink` recolour either.
|
|
19092
|
+
*/
|
|
19093
|
+
get statusBar() {
|
|
19094
|
+
return this.getAttribute("status-bar") === "colorful" ? "colorful" : "neutral";
|
|
19095
|
+
}
|
|
19096
|
+
set statusBar(value) {
|
|
19097
|
+
this.setAttribute("status-bar", value === "colorful" ? "colorful" : "neutral");
|
|
19098
|
+
}
|
|
19099
|
+
/** Whether the page the viewer sits in is using the dark theme. */
|
|
19100
|
+
#dark() {
|
|
19101
|
+
const root = this.ownerDocument.documentElement;
|
|
19102
|
+
return (root.dataset.officeTheme ?? root.dataset.theme) === "dark";
|
|
19103
|
+
}
|
|
19104
|
+
/**
|
|
19105
|
+
* Light or dark belongs to the page, which every editor on it shares. Ask the host with a
|
|
19106
|
+
* cancelable `office-theme-request` (`{ scheme }`); when no host takes it, set the shared
|
|
19107
|
+
* theme's `data-office-theme` on the document.
|
|
19108
|
+
*/
|
|
19109
|
+
#requestScheme(scheme) {
|
|
19110
|
+
const event = new CustomEvent("office-theme-request", {
|
|
19111
|
+
detail: { scheme },
|
|
19112
|
+
bubbles: true,
|
|
19113
|
+
composed: true,
|
|
19114
|
+
cancelable: true
|
|
19115
|
+
});
|
|
19116
|
+
if (this.dispatchEvent(event)) this.ownerDocument.documentElement.dataset.officeTheme = scheme;
|
|
19117
|
+
}
|
|
18890
19118
|
get showToolbar() {
|
|
18891
19119
|
return !this.#toolbar.hidden;
|
|
18892
19120
|
}
|
|
18893
19121
|
set showToolbar(value) {
|
|
18894
19122
|
this.#assertAlive();
|
|
18895
19123
|
this.#toolbar.hidden = !value;
|
|
19124
|
+
this.#titleBar.hidden = !value;
|
|
18896
19125
|
this.#root.querySelector(".zoom-controls").hidden = !value;
|
|
18897
19126
|
}
|
|
18898
19127
|
get renderWarnings() {
|
|
@@ -18984,7 +19213,32 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
18984
19213
|
}
|
|
18985
19214
|
cancelEdit() {
|
|
18986
19215
|
this.#assertAlive();
|
|
18987
|
-
this
|
|
19216
|
+
this.controller.cancelEdit();
|
|
19217
|
+
}
|
|
19218
|
+
/** Visio's status bar: Page n of m, then the selection's Width, Height and Angle, and language. */
|
|
19219
|
+
#renderStatus(state) {
|
|
19220
|
+
const set = (name, value) => this.#root.querySelector(`[data-${name}-status]`).setAttribute("value", value);
|
|
19221
|
+
const shape = selectedShape(state.document, state.selectedShape, state.pageIndex);
|
|
19222
|
+
const inches2 = (value) => `${+value.toFixed(3)} in.`;
|
|
19223
|
+
const many = state.selectedShapes.length > 1;
|
|
19224
|
+
set(
|
|
19225
|
+
"width",
|
|
19226
|
+
many ? `${state.selectedShapes.length} shapes selected` : shape ? `Width: ${inches2(shape.width)}` : ""
|
|
19227
|
+
);
|
|
19228
|
+
set("height", !many && shape ? `Height: ${inches2(shape.height)}` : "");
|
|
19229
|
+
const turn = shape?.rotation ? (shape.rotation.angle * 180 / Math.PI % 360 + 360) % 360 : 0;
|
|
19230
|
+
const angle = turn > 180 ? turn - 360 : turn;
|
|
19231
|
+
set("angle", !many && shape ? `Angle: ${+angle.toFixed(2)}\xB0` : "");
|
|
19232
|
+
set(
|
|
19233
|
+
"language",
|
|
19234
|
+
state.document ? statusLanguage(this.lang || this.ownerDocument.documentElement.lang || navigator.language) : ""
|
|
19235
|
+
);
|
|
19236
|
+
}
|
|
19237
|
+
/** Shape text edits in place on the canvas; compatibility notes live in File > Info. */
|
|
19238
|
+
#reveal(panel) {
|
|
19239
|
+
if (panel === "edit") this.#edit.start();
|
|
19240
|
+
else if (panel === "notes") this.#backstage.show("info");
|
|
19241
|
+
else this.#chrome.reveal(panel);
|
|
18988
19242
|
}
|
|
18989
19243
|
exportVsdx() {
|
|
18990
19244
|
this.#assertAlive();
|
|
@@ -19056,6 +19310,8 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
19056
19310
|
}
|
|
19057
19311
|
connectedCallback() {
|
|
19058
19312
|
if (this.#disposed) return;
|
|
19313
|
+
const savedTheme = readStatusBarTheme();
|
|
19314
|
+
if (!this.hasAttribute("status-bar") && savedTheme) this.statusBar = savedTheme;
|
|
19059
19315
|
if (this.#suspended) this.#disposeInputs = this.#wireInputs();
|
|
19060
19316
|
this.#suspended = false;
|
|
19061
19317
|
this.#fontEvents = this.ownerDocument.fonts;
|
|
@@ -19089,6 +19345,13 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
19089
19345
|
const disposePanZoom = this.#panZoom.wire();
|
|
19090
19346
|
const disposeSizePosition = this.#sizePosition.wire();
|
|
19091
19347
|
const disposeProfile = this.#profile.wire();
|
|
19348
|
+
const quickAccess = (event) => {
|
|
19349
|
+
const id = event.detail.command;
|
|
19350
|
+
event.stopPropagation();
|
|
19351
|
+
if (id === "save") this.#backstage.download();
|
|
19352
|
+
else if (id === "undo" || id === "redo") this.#commands.run({ type: "history", key: id });
|
|
19353
|
+
};
|
|
19354
|
+
this.#titleBar.addEventListener("office-command", quickAccess);
|
|
19092
19355
|
const disposeShare = this.#share.wire();
|
|
19093
19356
|
const disposeRulers = this.#rulers.wire();
|
|
19094
19357
|
const disposeStencil = wireStencil(
|
|
@@ -19107,14 +19370,18 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
19107
19370
|
);
|
|
19108
19371
|
const disposeReplace = this.#replace.wire();
|
|
19109
19372
|
const disposeEdit = this.#edit.wire();
|
|
19110
|
-
const disposeLayers = wireLayerControls(this.#layers, this.controller);
|
|
19111
19373
|
const disposeInputs = wireViewerInputs(
|
|
19112
19374
|
{
|
|
19113
19375
|
viewport: this.#viewport,
|
|
19114
19376
|
zoomSlider: this.#zoomSlider
|
|
19115
19377
|
},
|
|
19116
19378
|
this.controller,
|
|
19117
|
-
(mode) => this.#fit(mode)
|
|
19379
|
+
(mode) => this.#fit(mode),
|
|
19380
|
+
(message) => {
|
|
19381
|
+
this.#announcement = message;
|
|
19382
|
+
this.#status.textContent = message;
|
|
19383
|
+
},
|
|
19384
|
+
(character) => this.#commands.tool === "pointer" && this.#edit.start(character)
|
|
19118
19385
|
);
|
|
19119
19386
|
return () => {
|
|
19120
19387
|
disposeChrome();
|
|
@@ -19131,13 +19398,13 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
19131
19398
|
disposePanZoom();
|
|
19132
19399
|
disposeSizePosition();
|
|
19133
19400
|
disposeProfile();
|
|
19401
|
+
this.#titleBar.removeEventListener("office-command", quickAccess);
|
|
19134
19402
|
disposeShare();
|
|
19135
19403
|
disposeRulers();
|
|
19136
19404
|
disposeStencil();
|
|
19137
19405
|
disposeFind();
|
|
19138
19406
|
disposeReplace();
|
|
19139
19407
|
disposeInputs();
|
|
19140
|
-
disposeLayers();
|
|
19141
19408
|
disposeEdit();
|
|
19142
19409
|
};
|
|
19143
19410
|
}
|
|
@@ -19154,25 +19421,22 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
19154
19421
|
this.#lineEndpoints.render(state);
|
|
19155
19422
|
this.#rotationHandle.render(state);
|
|
19156
19423
|
this.#resizeHandles.render(state);
|
|
19424
|
+
this.#viewport.toggleAttribute(
|
|
19425
|
+
"data-selection-frame",
|
|
19426
|
+
!!this.#viewport.querySelector("[data-resize-overlay], [data-line-endpoint]")
|
|
19427
|
+
);
|
|
19157
19428
|
}
|
|
19158
19429
|
if (changed) this.#announcement = void 0;
|
|
19159
19430
|
this.#zoomSlider.value = Math.round(state.zoom * 100);
|
|
19160
19431
|
this.#zoomSlider.disabled = !page3;
|
|
19161
|
-
|
|
19162
|
-
|
|
19163
|
-
this.#shapeStatus.setAttribute(
|
|
19164
|
-
"value",
|
|
19165
|
-
state.selectedShapes.length > 1 ? `${state.selectedShapes.length} shapes selected` : inspected ? `Width: ${inches2(inspected.width)} Height: ${inches2(inspected.height)}` : ""
|
|
19166
|
-
);
|
|
19432
|
+
this.#renderStatus(state);
|
|
19433
|
+
renderTitleBar(this.#titleBar, state, this.#fileName, this.#profile.profile);
|
|
19167
19434
|
for (const button of this.#root.querySelectorAll("[data-action]"))
|
|
19168
19435
|
button.disabled = !page3;
|
|
19169
19436
|
renderFindBar(this.#findBar, state);
|
|
19170
19437
|
this.#replace.render(state);
|
|
19171
19438
|
this.#edit.render(state);
|
|
19172
|
-
|
|
19173
|
-
else
|
|
19174
|
-
this.#layers.querySelector('[data-layer-reset="all"]').disabled = state.layerVisibilityOverrides.length === 0;
|
|
19175
|
-
this.#chrome.render(state, this.#notes.children.length);
|
|
19439
|
+
this.#chrome.render(state);
|
|
19176
19440
|
this.#commands.render(state);
|
|
19177
19441
|
this.#presentation.render(state);
|
|
19178
19442
|
this.#backstage.render(state);
|
|
@@ -19180,9 +19444,11 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
19180
19444
|
this.#panZoom.render();
|
|
19181
19445
|
this.#sizePosition.render(state);
|
|
19182
19446
|
this.#viewport.setAttribute("aria-busy", String(state.loading || state.edit.busy));
|
|
19183
|
-
this.#status.textContent = state.loading ? "Opening diagram\u2026" : state.edit.busy ? "Updating diagram\u2026" : state.error?.message ?? (state.edit.error ? `Edit rejected: ${editErrorMessage(state.edit.error)}` : void 0) ?? this.#announcement ??
|
|
19184
|
-
|
|
19185
|
-
|
|
19447
|
+
this.#status.textContent = state.loading ? "Opening diagram\u2026" : state.edit.busy ? "Updating diagram\u2026" : state.error?.message ?? (state.edit.error ? `Edit rejected: ${editErrorMessage(state.edit.error)}` : void 0) ?? this.#announcement ?? "";
|
|
19448
|
+
this.#status.parentElement.toggleAttribute(
|
|
19449
|
+
"data-error",
|
|
19450
|
+
!state.loading && !state.edit.busy && !!(state.error ?? state.edit.error)
|
|
19451
|
+
);
|
|
19186
19452
|
}
|
|
19187
19453
|
};
|
|
19188
19454
|
function registerVisioViewer() {
|