visio-solid-viewer 0.4.0 → 0.5.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/dist/index.js +593 -351
- package/dist/index.server.js +593 -351
- package/dist/types/src/backstage.d.ts +7 -1
- package/dist/types/src/contract.d.ts +1 -1
- package/dist/types/src/controller.d.ts +5 -0
- package/dist/types/src/ribbon.d.ts +3 -2
- package/dist/types/src/styles.d.ts +1 -1
- package/dist/types/src/viewer-backstage.d.ts +2 -5
- package/dist/types/src/viewer-input.d.ts +0 -2
- package/dist/types/src/viewer-options.d.ts +22 -0
- package/dist/types/src/viewer-ruler.d.ts +6 -0
- package/dist/types/src/viewer-search.d.ts +16 -16
- package/dist/types/src/viewer-share.d.ts +20 -0
- package/package.json +4 -4
package/dist/index.server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { VISIO_RASTER_IMAGE_LIMITS, VISIO_VISIBILITY_LIMITS, getVisioPageLayers, inspectVisioRasterImage, loadVisio, resolveVisioPageVisibility, validateVisioForeignVector } from "ooxml-core/visio";
|
|
2
|
-
import { attachKeyTips, registerControls } from "ooxml-ui/controls";
|
|
2
|
+
import { attachKeyTips, readOfficeProfile, registerControls, sanitizeOfficeProfile, writeOfficeProfile } from "ooxml-ui/controls";
|
|
3
3
|
import { getIcon, registerIcon } from "ooxml-ui/icons";
|
|
4
|
+
import { definePresence } from "ooxml-ui/presence";
|
|
4
5
|
import { escape, ssr, ssrAttribute, ssrHydrationKey, ssrStyle } from "solid-js/web";
|
|
5
6
|
import { createEffect, createSignal, onCleanup, onMount } from "solid-js";
|
|
6
7
|
export * from "visio-core";
|
|
@@ -1069,6 +1070,13 @@ var ViewerController = class {
|
|
|
1069
1070
|
async undo() {
|
|
1070
1071
|
return this.#mutate("undo");
|
|
1071
1072
|
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Adopt a package from a shared session as one undoable history step. Emits `document-change`
|
|
1075
|
+
* with kind `remote`, which a session must not publish back.
|
|
1076
|
+
*/
|
|
1077
|
+
async applyRemoteSource(bytes) {
|
|
1078
|
+
return this.#mutate("remote", void 0, bytes);
|
|
1079
|
+
}
|
|
1072
1080
|
async redo() {
|
|
1073
1081
|
return this.#mutate("redo");
|
|
1074
1082
|
}
|
|
@@ -1092,13 +1100,13 @@ var ViewerController = class {
|
|
|
1092
1100
|
#sourceEditState() {
|
|
1093
1101
|
return this.#sourceFormat === "vsdx" && this.#state.document?.format === "vsdx" ? this.#history?.state ?? EMPTY_EDIT_STATE : EMPTY_EDIT_STATE;
|
|
1094
1102
|
}
|
|
1095
|
-
async #mutate(kind, commands) {
|
|
1103
|
+
async #mutate(kind, commands, remote) {
|
|
1096
1104
|
this.#assertAlive();
|
|
1097
1105
|
const history = this.#history;
|
|
1098
1106
|
if (!history || this.#sourceFormat !== "vsdx" || this.#state.document?.format !== "vsdx") throw new Error("Load a VSDX file before editing. Model-only documents are read only.");
|
|
1099
1107
|
if (this.#state.loading || this.#state.edit.busy) throw new Error("Another document operation is in progress.");
|
|
1100
1108
|
const target = kind === "undo" ? history.undoTarget : kind === "redo" ? history.redoTarget : void 0;
|
|
1101
|
-
if (kind
|
|
1109
|
+
if ((kind === "undo" || kind === "redo") && !target) return;
|
|
1102
1110
|
const id = ++this.#editId;
|
|
1103
1111
|
const loadId = this.#loadId;
|
|
1104
1112
|
const current = () => !this.#destroyed && id === this.#editId && loadId === this.#loadId && history === this.#history;
|
|
@@ -1118,6 +1126,9 @@ var ViewerController = class {
|
|
|
1118
1126
|
assertCurrent();
|
|
1119
1127
|
if (edited.bytes.byteLength > 33554432) throw new Error("The modified VSDX exceeds 32 MiB.");
|
|
1120
1128
|
document = edited.document;
|
|
1129
|
+
} else if (kind === "remote") {
|
|
1130
|
+
if (remote.byteLength > 33554432) throw new Error("The shared VSDX exceeds 32 MiB.");
|
|
1131
|
+
document = await this.parser(Uint8Array.from(remote));
|
|
1121
1132
|
} else document = await this.parser(Uint8Array.from(target.bytes));
|
|
1122
1133
|
assertCurrent();
|
|
1123
1134
|
assertViewableDocument(document);
|
|
@@ -1132,6 +1143,7 @@ var ViewerController = class {
|
|
|
1132
1143
|
const selection = this.#state.selectedShape;
|
|
1133
1144
|
const selectedShape = selection && visibleSelection(document, this.#state.pageIndex, selection, visible) ? selection : null;
|
|
1134
1145
|
if (edited) history.append(edited.bytes, edited.diagnostics);
|
|
1146
|
+
else if (kind === "remote") history.append(Uint8Array.from(remote), []);
|
|
1135
1147
|
else history.move(target);
|
|
1136
1148
|
this.#visible = visible;
|
|
1137
1149
|
this.#searchIndex = searchIndex;
|
|
@@ -1366,28 +1378,10 @@ function selection(target) {
|
|
|
1366
1378
|
}
|
|
1367
1379
|
/** Own every DOM listener and abort them together when the surface is disposed. */
|
|
1368
1380
|
function wireViewerInputs(controls, controller, fit) {
|
|
1369
|
-
const { viewport,
|
|
1381
|
+
const { viewport, zoomSlider } = controls;
|
|
1370
1382
|
const events = new ((viewport.ownerDocument.defaultView?.AbortController) ?? AbortController)();
|
|
1371
1383
|
const options = { signal: events.signal };
|
|
1372
|
-
searchInput.addEventListener("input", () => controller.setSearchQuery(searchInput.value), options);
|
|
1373
|
-
searchInput.addEventListener("keydown", (event) => {
|
|
1374
|
-
if (event.isComposing) return;
|
|
1375
|
-
if (event.key === "Enter") {
|
|
1376
|
-
event.preventDefault();
|
|
1377
|
-
if (event.shiftKey) controller.previousSearchResult();
|
|
1378
|
-
else controller.nextSearchResult();
|
|
1379
|
-
}
|
|
1380
|
-
if (event.key === "Escape") {
|
|
1381
|
-
event.preventDefault();
|
|
1382
|
-
controller.setSearchQuery("");
|
|
1383
|
-
}
|
|
1384
|
-
}, options);
|
|
1385
1384
|
zoomSlider.addEventListener("input", () => controller.setZoom(zoomSlider.value / 100), options);
|
|
1386
|
-
commandRoot.addEventListener("click", (event) => {
|
|
1387
|
-
const action = event.target?.closest?.("button")?.dataset.action;
|
|
1388
|
-
if (action === "search-next") controller.nextSearchResult();
|
|
1389
|
-
if (action === "search-previous") controller.previousSearchResult();
|
|
1390
|
-
}, options);
|
|
1391
1385
|
viewport.addEventListener("click", (event) => controller.selectShape(selection(targetShape$1(event))), options);
|
|
1392
1386
|
viewport.addEventListener("keydown", (event) => {
|
|
1393
1387
|
const target = targetShape$1(event);
|
|
@@ -1528,22 +1522,12 @@ button:focus-visible,select:focus-visible,input:focus-visible,textarea:focus-vis
|
|
|
1528
1522
|
button[aria-pressed="true"] { color:var(--_vv-accent); background:var(--_vv-accent-soft); }
|
|
1529
1523
|
.toolbar { flex:none; min-width:0; border-bottom:1px solid var(--_vv-border); background:var(--_vv-surface); }
|
|
1530
1524
|
.spacer { flex:1; }
|
|
1531
|
-
.ribbon-tabs { height:35px; display:flex; align-items:stretch; padding:0 4px; border-bottom:1px solid var(--_vv-border); }
|
|
1532
|
-
.ribbon-tabs button { position:relative; min-height:34px; padding:7px 14px; border:0; border-radius:0; background:transparent; color:var(--_vv-muted); font-size:12px; font-weight:500; }
|
|
1533
|
-
.ribbon-tabs button[aria-selected="true"] { color:var(--_vv-accent); }
|
|
1534
|
-
.ribbon-tabs button[aria-selected="true"]::after { content:""; position:absolute; inset:auto 0 -1px; height:2.5px; background:var(--_vv-accent); }
|
|
1535
1525
|
.ribbon-content { min-height:82px; display:flex; align-items:stretch; gap:0; padding:2px 4px; overflow-x:auto; }
|
|
1536
1526
|
.ribbon-group { display:flex; flex-direction:column; justify-content:space-between; flex:none; gap:2px; padding:3px 10px 4px; border-right:1px solid var(--_vv-border); }
|
|
1537
1527
|
.group-label { font-size:10px; line-height:12px; color:var(--_vv-muted); text-align:center; }
|
|
1538
1528
|
.ribbon-actions { display:flex; align-items:stretch; gap:2px; flex:1; }
|
|
1539
1529
|
.ribbon-command { display:flex; flex-direction:column; justify-content:center; align-items:center; gap:2px; min-width:70px; padding:2px 6px; border-color:transparent; background:transparent; font-size:11px; white-space:nowrap; }
|
|
1540
1530
|
.ribbon-hint { align-self:center; flex:none; margin:0; padding:0 16px; font-size:11px; line-height:18px; color:var(--_vv-muted); }
|
|
1541
|
-
.search-group { width:330px; }
|
|
1542
|
-
.search-controls { display:flex; align-items:center; gap:4px; flex-wrap:wrap; }
|
|
1543
|
-
.search-controls label { display:flex; align-items:center; min-width:0; gap:6px; flex:1; font-size:11px; }
|
|
1544
|
-
.search-controls input { width:100%; min-width:0; padding:3px 6px; font-size:11px; }
|
|
1545
|
-
.search-controls button { padding:3px 6px; font-size:10px; background:var(--_vv-secondary); }
|
|
1546
|
-
.search-controls [role="status"] { display:block; width:100%; min-height:15px; font-size:10px; line-height:15px; color:var(--_vv-muted); overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
|
|
1547
1531
|
.workspace { position:relative; display:flex; flex:1; min-width:0; min-height:0; overflow:hidden; }
|
|
1548
1532
|
.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; }
|
|
1549
1533
|
.inspector-kind { color:var(--_vv-muted); font-size:10px; font-weight:400; }
|
|
@@ -1602,17 +1586,8 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1602
1586
|
button,select,input,textarea { min-height:44px; }
|
|
1603
1587
|
button { min-width:44px; }
|
|
1604
1588
|
summary { min-height:44px; line-height:44px; }
|
|
1605
|
-
.ribbon-tabs { height:44px; }
|
|
1606
|
-
.ribbon-tabs button { min-height:44px; padding:8px 16px; }
|
|
1607
1589
|
.ribbon-content { min-height:86px; }
|
|
1608
1590
|
.ribbon-group { padding:4px 8px; }
|
|
1609
|
-
.search-group { width:100%; border-right:0; }
|
|
1610
|
-
.search-controls { gap:4px; }
|
|
1611
|
-
.search-controls label { font-size:12px; }
|
|
1612
|
-
.search-controls input { font-size:12px; }
|
|
1613
|
-
.search-controls button { min-width:44px; font-size:0; padding:3px; }
|
|
1614
|
-
.search-controls [data-action="search-previous"]::before { content:"‹"; font-size:22px; }
|
|
1615
|
-
.search-controls [data-action="search-next"]::before { content:"›"; font-size:22px; }
|
|
1616
1591
|
#home-panel>.ribbon-group:not(.search-group):not(.undo-group) { display:none; }
|
|
1617
1592
|
.ribbon-command { min-width:90px; }
|
|
1618
1593
|
.workspace { display:block; overflow:auto; }
|
|
@@ -1631,26 +1606,17 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1631
1606
|
button,select,input,textarea { min-height:44px; }
|
|
1632
1607
|
button { min-width:44px; }
|
|
1633
1608
|
summary,.layer-controls label { min-height:44px; line-height:44px; }
|
|
1634
|
-
.ribbon-tabs { min-height:44px; height:44px; }
|
|
1635
|
-
.ribbon-tabs button { min-height:44px; }
|
|
1636
1609
|
.ribbon-content { min-height:96px; }
|
|
1637
|
-
.search-group { width:380px; max-width:100%; }
|
|
1638
1610
|
.notes-strip button { min-height:44px; height:44px; }
|
|
1639
1611
|
.layer-controls input { min-height:20px; }
|
|
1640
1612
|
}
|
|
1641
1613
|
/* Suite ribbon: tabs lead directly into Visio command groups. */
|
|
1642
|
-
.ribbon-tabs { height:40px; }
|
|
1643
|
-
.ribbon-tabs button { min-height:39px; padding:8px 16px; }
|
|
1644
1614
|
.ribbon-content { min-height:104px; padding:4px 4px; }
|
|
1645
|
-
.search-group { order:2; width:320px; }
|
|
1646
1615
|
.ribbon-hint { order:3; padding:10px 18px; }
|
|
1647
1616
|
.ribbon-command { min-width:82px; }
|
|
1648
1617
|
.pane-close { display:none; }
|
|
1649
1618
|
@media(max-width:760px) {
|
|
1650
|
-
.ribbon-tabs { height:44px; }
|
|
1651
|
-
.ribbon-tabs button { min-height:44px; }
|
|
1652
1619
|
.ribbon-content { min-height:54px; padding:4px 0; }
|
|
1653
|
-
.search-group { flex:0 0 100%; width:100%; min-height:54px; }
|
|
1654
1620
|
.search-feedback,.group-label { display:none; }
|
|
1655
1621
|
.ribbon-content { overflow-x:auto; scroll-snap-type:x mandatory; }
|
|
1656
1622
|
.workspace { display:flex; position:relative; overflow:hidden; }
|
|
@@ -1686,12 +1652,10 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1686
1652
|
.ribbon-tools .ribbon-group { display:flex; width:100%; min-height:64px; border:0; padding:0; }
|
|
1687
1653
|
.ribbon-tools .ribbon-actions { justify-content:space-between; }
|
|
1688
1654
|
.ribbon-tools .ribbon-command { min-width:88px; font-size:12px; }
|
|
1689
|
-
.ribbon-tools .search-group { order:1; flex:auto; }
|
|
1690
1655
|
.ribbon-tools .search-feedback { display:block; }
|
|
1691
1656
|
.status { flex-wrap:nowrap; gap:4px; min-height:48px; }
|
|
1692
1657
|
.status .notes-strip { display:none; }
|
|
1693
1658
|
}
|
|
1694
|
-
@media(pointer:coarse) { .ribbon-tabs {height:45px;min-height:45px;} .ribbon-tabs button {min-height:44px;height:44px;} }
|
|
1695
1659
|
@media(prefers-reduced-motion:reduce) { * { scroll-behavior:auto !important; } }
|
|
1696
1660
|
`;
|
|
1697
1661
|
//#endregion
|
|
@@ -1701,9 +1665,9 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
|
|
|
1701
1665
|
* `styles.ts` string moves into this directory when it is next changed.
|
|
1702
1666
|
*/
|
|
1703
1667
|
var canvasAndRibbonStyles = [
|
|
1704
|
-
":host{--office-foreground:var(--_vv-ink);--office-muted-foreground:var(--_vv-muted);--office-background:var(--_vv-surface);--office-surface:var(--_vv-accent-soft);--office-border:var(--_vv-border);--office-accent:var(--_vv-accent);--office-accent-foreground:var(--vv-accent-ink,#fff);--office-ring:var(--vv-focus,var(--_vv-accent));--office-font:\"Segoe UI\", Arial, sans-serif}.ribbon-head{border-bottom:1px solid var(--_vv-border);align-items:stretch;min-width:0;display:flex}.qat{border-right:1px solid var(--_vv-border);align-items:center;gap:0;padding:0 6px;display:flex}.qat office-ui-button{--office-target-size:30px}.ribbon-head .ribbon-tabs{scrollbar-width:none;border-bottom:0;flex:0 auto;min-width:0;height:36px;overflow-x:auto}.ribbon-head .ribbon-tabs button{flex:none;min-height:35px;padding:6px 12px;font-size:13px}.ribbon-content{min-height:96px;padding:2px 2px 0}.ribbon-row{background:0 0;border:0;flex-wrap:nowrap;align-items:stretch;gap:0;padding:0;display:flex}.ribbon-row office-ui-ribbon-group,.tools-content office-ui-ribbon-group{min-width:0}office-ui-ribbon-group office-ui-button,office-ui-ribbon-group office-ui-menu-button{--office-target-size:24px}office-ui-ribbon-group [data-size=large]{--office-target-size:30px}office-ui-button[variant=stacked]::part(button){min-width:48px;min-height:66px;padding:2px 6px;font-size:12px}office-ui-menu-button[variant=stacked]::part(button){min-width:48px;min-height:50px;font-size:12px}office-ui-ribbon-group [data-size=small]::part(button){justify-content:flex-start;font-size:12px}office-ui-ribbon-stack:not([orientation]){justify-content:flex-start;padding-top:2px}office-ui-ribbon-stack:not([orientation])>*{min-height:24px}office-ui-ribbon-group>office-ui-ribbon-stack>office-ui-ribbon-stack[orientation]{min-height:32px}office-ui-select[data-combo]{--office-target-size:24px}office-ui-menu-button[data-active]::part(button){background:var(--_vv-accent-soft);box-shadow:inset 0 0 0 1px var(--_vv-accent)}[data-unsupported]{cursor:not-allowed}.ribbon-check{white-space:nowrap;cursor:pointer;align-items:center;gap:6px;min-height:24px;padding:0 6px;font-size:12px;display:flex}.ribbon-check[data-unsupported]{color:var(--_vv-muted);opacity:.6}.ribbon-hint{display:none}.
|
|
1668
|
+
":host{--office-foreground:var(--_vv-ink);--office-muted-foreground:var(--_vv-muted);--office-background:var(--_vv-surface);--office-surface:var(--_vv-accent-soft);--office-border:var(--_vv-border);--office-accent:var(--_vv-accent);--office-accent-foreground:var(--vv-accent-ink,#fff);--office-ring:var(--vv-focus,var(--_vv-accent));--office-font:\"Segoe UI\", Arial, sans-serif}.ribbon-head{border-bottom:1px solid var(--_vv-border);align-items:stretch;min-width:0;display:flex}.qat{border-right:1px solid var(--_vv-border);align-items:center;gap:0;padding:0 6px;display:flex}.qat office-ui-button{--office-target-size:30px}.ribbon-head .ribbon-tabs{scrollbar-width:none;border-bottom:0;flex:0 auto;min-width:0;height:36px;overflow-x:auto}.ribbon-head .ribbon-tabs button{flex:none;min-height:35px;padding:6px 12px;font-size:13px}.ribbon-content{min-height:96px;padding:2px 2px 0}.ribbon-row{background:0 0;border:0;flex-wrap:nowrap;align-items:stretch;gap:0;padding:0;display:flex}.ribbon-row office-ui-ribbon-group,.tools-content office-ui-ribbon-group{min-width:0}office-ui-ribbon-group office-ui-button,office-ui-ribbon-group office-ui-menu-button{--office-target-size:24px}office-ui-ribbon-group [data-size=large]{--office-target-size:30px}office-ui-button[variant=stacked]::part(button){min-width:48px;min-height:66px;padding:2px 6px;font-size:12px}office-ui-menu-button[variant=stacked]::part(button){min-width:48px;min-height:50px;font-size:12px}office-ui-ribbon-group [data-size=small]::part(button){justify-content:flex-start;font-size:12px}office-ui-ribbon-stack:not([orientation]){justify-content:flex-start;padding-top:2px}office-ui-ribbon-stack:not([orientation])>*{min-height:24px}office-ui-ribbon-group>office-ui-ribbon-stack>office-ui-ribbon-stack[orientation]{min-height:32px}office-ui-select[data-combo]{--office-target-size:24px}office-ui-menu-button[data-active]::part(button){background:var(--_vv-accent-soft);box-shadow:inset 0 0 0 1px var(--_vv-accent)}[data-unsupported]{cursor:not-allowed}.ribbon-check{white-space:nowrap;cursor:pointer;align-items:center;gap:6px;min-height:24px;padding:0 6px;font-size:12px;display:flex}.ribbon-check[data-unsupported]{color:var(--_vv-muted);opacity:.6}.ribbon-hint{display:none}.canvas-area{flex:1;grid-template-rows:0 1fr;grid-template-columns:0 1fr;min-width:0;min-height:0;display:grid}.canvas-area[data-ruler=true]{grid-template-rows:18px 1fr;grid-template-columns:18px 1fr}.canvas-area>.viewport{grid-area:2/2}.ruler,.ruler-corner{background:var(--_vv-surface);display:none}.canvas-area[data-ruler=true]>.ruler,.canvas-area[data-ruler=true]>.ruler-corner{display:block}.ruler-corner{border-right:1px solid var(--_vv-border);border-bottom:1px solid var(--_vv-border);grid-area:1/1}.ruler-h{grid-area:1/2}.ruler-v{grid-area:2/1}.page-bar{border-top:1px solid var(--_vv-border);background:var(--_vv-secondary);flex:none;align-items:stretch;min-width:0;display:flex}.page-bar office-ui-menu-button{--office-target-size:28px;flex:none;padding:0 2px}.page-tabs{border-top:0;flex:1;min-width:0}office-ui-status-bar.status{background:var(--_vv-surface);min-height:29px;color:var(--_vv-muted);gap:16px;padding:0 8px 0 12px;font-size:11px}office-ui-status-item[value=\"\"]{display:none}office-ui-status-item[data-page-status]{color:var(--_vv-ink)}.status-message{flex:1;min-width:0}.viewport[data-tool=rectangle],.viewport[data-tool=rectangle] .paper [data-shape-id]{cursor:crosshair}.viewport[data-tool=rectangle]{touch-action:none}.draw-preview{fill:var(--_vv-accent-soft);stroke:var(--_vv-accent);stroke-width:1.5px;stroke-dasharray:4 3;pointer-events:none}.viewport[data-grid=true] .paper{--_vv-grid-minor:#00000012;--_vv-grid-major:#00000029;background-image:linear-gradient(to right, var(--_vv-grid-major) 1px, transparent 1px), linear-gradient(to top, var(--_vv-grid-major) 1px, transparent 1px), linear-gradient(to right, var(--_vv-grid-minor) 1px, transparent 1px), linear-gradient(to top, var(--_vv-grid-minor) 1px, transparent 1px);background-size:var(--vv-inch,96px) var(--vv-inch,96px), var(--vv-inch,96px) var(--vv-inch,96px), calc(var(--vv-inch,96px) / 4) calc(var(--vv-inch,96px) / 4), calc(var(--vv-inch,96px) / 4) calc(var(--vv-inch,96px) / 4);background-position:0 100%}:host(:fullscreen){width:100vw;height:100vh}@media (width<=760px){.ribbon-row{flex:1;min-width:0}.qat office-ui-button{--office-target-size:44px}.ribbon-tools .tools-content office-ui-ribbon-group{width:100%}office-ui-status-bar.status{gap:4px;min-height:48px}office-ui-status-bar .notes-strip,office-ui-status-bar .status-message,office-ui-status-item[data-shape-status],office-ui-status-item[data-page-status]{display:none}.zoom-controls{--office-zoom-slider-width:0;flex:1;min-width:0}}.tell-me{--office-target-size:28px;flex:0 280px;min-width:140px;margin:0 8px}.presentation-mode{--office-target-size:24px}@media (width<=760px){.tell-me{display:none}}",
|
|
1705
1669
|
".shapes-pane{border-right:1px solid var(--_vv-border);background:var(--_vv-secondary);flex-direction:column;flex:0 0 232px;width:232px;min-width:0;display:flex;overflow:hidden}.shapes-pane .pane-heading{height:42px;color:var(--_vv-accent);font-size:18px;font-weight:400}.pane-collapse{background:0 0;border-color:#0000;width:28px;min-height:28px;padding:0;font-size:18px;line-height:1}.shapes-views{border-bottom:1px solid var(--_vv-border);gap:14px;padding:4px 12px 0;display:flex}.shapes-views button{min-height:28px;color:var(--_vv-muted);letter-spacing:.06em;text-transform:uppercase;background:0 0;border:0;border-radius:0;padding:2px 0 6px;font-size:11px;font-weight:600;position:relative}.shapes-views button[aria-selected=true]{color:var(--_vv-ink)}.shapes-views button[aria-selected=true]:after{content:\"\";background:var(--_vv-accent);height:2px;position:absolute;inset:auto 0 -1px}#shapes-stencils,#shapes-search{flex:1;min-height:0;padding:4px 0 8px;overflow:auto}.shapes-row{text-align:left;background:0 0;border:0;border-radius:0;align-items:center;width:100%;min-height:30px;padding:0 12px;font-size:12px;display:flex}.shapes-row:after{content:\"›\";margin-left:auto;font-size:15px}.stencil-title{border-left:3px solid var(--_vv-accent);background:var(--_vv-accent-soft);margin:2px 0;padding:6px 12px;font-size:12px;font-weight:600}.masters{grid-template-columns:1fr 1fr;gap:2px;margin:0;padding:4px 6px;list-style:none;display:grid}.masters li[hidden]{display:none}.master{text-align:left;cursor:grab;background:0 0;border-color:#0000;align-items:center;gap:6px;width:100%;min-height:40px;padding:4px 6px;font-size:11px;line-height:1.2;display:flex}.master svg{width:28px;height:28px;fill:var(--_vv-surface);stroke:var(--_vv-accent);stroke-width:1.2px;stroke-linejoin:round;flex:none}.master[data-unsupported]{cursor:not-allowed;opacity:.45}.master[data-unsupported]:hover{background:0 0;border-color:#0000}.shapes-search-field{width:calc(100% - 24px);margin:6px 12px;display:block}.shapes-empty{color:var(--_vv-muted);margin:8px 12px;font-size:12px}@media (width<=760px){.shapes-pane{z-index:3;width:min(260px,100%);position:absolute;inset:0 auto 0 0;box-shadow:8px 0 24px #0002}.master{min-height:44px}}.shapes-strip{border:0;border-right:1px solid var(--_vv-border);background:var(--_vv-secondary);width:28px;min-width:28px;color:var(--_vv-accent);border-radius:0;flex-direction:column;flex:0 0 28px;align-items:center;gap:10px;padding:8px 0;font-size:16px;display:flex}.shapes-strip[hidden]{display:none}.shapes-strip-label{writing-mode:vertical-rl;color:var(--_vv-ink);font-size:12px}.pan-zoom{z-index:5;border:1px solid var(--_vv-border);background:var(--_vv-surface);width:240px;position:absolute;bottom:16px;right:16px;box-shadow:0 6px 20px #0000002e}.pan-zoom[hidden]{display:none}.pan-zoom-heading{border-bottom:1px solid var(--_vv-border);justify-content:space-between;align-items:center;padding:2px 4px 2px 10px;font-size:12px;font-weight:600;display:flex}.pan-zoom-close{background:0 0;border-color:#0000;width:24px;min-height:24px;padding:0}.pan-zoom-view{background:var(--_vv-bg);cursor:crosshair;touch-action:none;place-items:center;height:180px;padding:8px;display:grid}.pan-zoom-view svg{background:#fff;max-width:100%;max-height:100%;box-shadow:0 1px 3px #0003}.pan-zoom-frame{fill:#dc262614;stroke:#dc2626;stroke-width:2px}",
|
|
1706
|
-
":host{position:relative}.
|
|
1670
|
+
":host{position:relative}.backstage{--office-accent:var(--_vv-accent);--office-accent-foreground:var(--vv-accent-ink,#fff)}.backstage-page h1{margin:0 0 24px;font-size:34px;font-weight:300}.backstage-page h2{margin:20px 0 8px;font-size:16px;font-weight:600}.backstage-file{overflow-wrap:anywhere;margin-top:0!important;font-size:20px!important;font-weight:400!important}.backstage-facts{grid-template-columns:max-content 1fr;gap:8px 24px;max-width:520px;margin:0;font-size:13px;display:grid}.backstage-facts dt{color:var(--_vv-muted)}.backstage-facts dd{overflow-wrap:anywhere;margin:0}.backstage-action{text-align:left;background:var(--_vv-surface);flex-direction:column;align-items:flex-start;gap:2px;width:min(420px,100%);min-height:64px;margin:0 0 10px;padding:10px 16px;display:flex}.backstage-action strong{font-size:14px;font-weight:600}.backstage-action span,.backstage-muted,.backstage-note-count{color:var(--_vv-muted);font-size:12px}.backstage-templates{flex-wrap:wrap;gap:12px;display:flex}.backstage-templates .backstage-action,.backstage-templates ::slotted(*){width:200px;min-height:120px}.backstage-page office-ui-account{max-width:560px}.backstage-product{margin-top:24px}.share-panel{max-width:560px;margin-bottom:16px}.share-panel h2{margin-top:0!important}.share-field{gap:4px;max-width:320px;margin:12px 0;font-size:13px;display:grid}.share-room{border:1px solid var(--_vv-border);background:var(--_vv-surface);min-height:30px;color:inherit;font:inherit;border-radius:3px;padding:2px 8px}.share-buttons button{min-height:32px;padding:0 16px}.share-buttons button[hidden]{display:none}.share-status{min-height:20px;font-size:13px}",
|
|
1707
1671
|
".paper [data-shape-id]:focus,.paper [data-shape-id]:focus-visible{outline:none}.paper [data-shape-id]:focus-visible>[data-geometry]{stroke-dasharray:.08 .05;stroke:var(--vv-focus,var(--_vv-accent))!important;stroke-width:.04px!important}"
|
|
1708
1672
|
].join("\n");
|
|
1709
1673
|
//#endregion
|
|
@@ -2820,8 +2784,7 @@ function ribbonCommands(root) {
|
|
|
2820
2784
|
const commands = [];
|
|
2821
2785
|
const context = (node) => {
|
|
2822
2786
|
const group = node.closest("office-ui-ribbon-group")?.getAttribute("label") ?? "";
|
|
2823
|
-
|
|
2824
|
-
return [panel ? root.querySelector(`[aria-controls="${panel.id}"]`)?.textContent ?? "" : "", group].filter(Boolean).join(" › ");
|
|
2787
|
+
return [node.closest("[data-ribbon-tab]")?.dataset.label ?? "", group].filter(Boolean).join(" › ");
|
|
2825
2788
|
};
|
|
2826
2789
|
for (const node of root.querySelectorAll(".toolbar [command]")) {
|
|
2827
2790
|
const id = node.getAttribute("command");
|
|
@@ -2953,50 +2916,32 @@ function quickAccess(doc) {
|
|
|
2953
2916
|
return qat;
|
|
2954
2917
|
}
|
|
2955
2918
|
/**
|
|
2956
|
-
* The Visio ribbon
|
|
2957
|
-
*
|
|
2919
|
+
* The Visio ribbon on the shared `office-ui-ribbon`: Quick Access Toolbar, File, one panel per
|
|
2920
|
+
* tab and Tell me. The shared element owns the tab row, selection and arrow-key movement;
|
|
2921
|
+
* commands emit `ribbon-action` events for the router.
|
|
2958
2922
|
*/
|
|
2959
2923
|
function createRibbon(doc) {
|
|
2960
|
-
const
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
const
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
file.type = "button";
|
|
2972
|
-
file.className = "file-tab";
|
|
2973
|
-
file.textContent = "File";
|
|
2974
|
-
file.setAttribute("aria-haspopup", "dialog");
|
|
2975
|
-
file.setAttribute("aria-expanded", "false");
|
|
2976
|
-
head.append(quickAccess(doc), file, tabs, createTellMe(doc));
|
|
2977
|
-
toolbar.append(head);
|
|
2924
|
+
const ribbon = doc.createElement("office-ui-ribbon");
|
|
2925
|
+
ribbon.className = "toolbar";
|
|
2926
|
+
ribbon.setAttribute("role", "group");
|
|
2927
|
+
ribbon.setAttribute("aria-label", "Diagram controls");
|
|
2928
|
+
ribbon.setAttribute("label", "Ribbon");
|
|
2929
|
+
ribbon.setAttribute("selected", "home");
|
|
2930
|
+
const qat = quickAccess(doc);
|
|
2931
|
+
qat.slot = "quick-access";
|
|
2932
|
+
const tellMe = createTellMe(doc);
|
|
2933
|
+
tellMe.slot = "search";
|
|
2934
|
+
ribbon.append(qat, tellMe);
|
|
2978
2935
|
for (const [key, name, build] of RIBBON_TABS) {
|
|
2979
|
-
const selected = key === "home";
|
|
2980
|
-
const tab = doc.createElement("button");
|
|
2981
|
-
tab.type = "button";
|
|
2982
|
-
tab.id = `${key}-tab`;
|
|
2983
|
-
tab.dataset.tab = key;
|
|
2984
|
-
tab.textContent = name;
|
|
2985
|
-
tab.setAttribute("role", "tab");
|
|
2986
|
-
tab.setAttribute("aria-selected", String(selected));
|
|
2987
|
-
tab.setAttribute("aria-controls", `${key}-panel`);
|
|
2988
|
-
if (!selected) tab.tabIndex = -1;
|
|
2989
2936
|
const panel = doc.createElement("div");
|
|
2990
2937
|
panel.className = "ribbon-content";
|
|
2991
2938
|
panel.id = `${key}-panel`;
|
|
2992
|
-
panel.
|
|
2993
|
-
panel.
|
|
2994
|
-
panel.hidden = !selected;
|
|
2939
|
+
panel.dataset.ribbonTab = key;
|
|
2940
|
+
panel.dataset.label = name;
|
|
2995
2941
|
build(doc, panel);
|
|
2996
|
-
|
|
2997
|
-
toolbar.append(panel);
|
|
2942
|
+
ribbon.append(panel);
|
|
2998
2943
|
}
|
|
2999
|
-
return
|
|
2944
|
+
return ribbon;
|
|
3000
2945
|
}
|
|
3001
2946
|
//#endregion
|
|
3002
2947
|
//#region src/ribbon-keytips.ts
|
|
@@ -3102,13 +3047,13 @@ function generated(label, used, singles) {
|
|
|
3102
3047
|
}
|
|
3103
3048
|
/** Annotate the ribbon for KeyTips. Labels and ids are static application strings. */
|
|
3104
3049
|
function applyKeyTips(toolbar) {
|
|
3105
|
-
toolbar.
|
|
3050
|
+
toolbar.setAttribute("file-keytip", "F");
|
|
3106
3051
|
toolbar.querySelector(".tell-me").dataset.keytip = "Q";
|
|
3107
3052
|
toolbar.querySelector(".qat [command=\"undo\"]").dataset.keytip = "1";
|
|
3108
3053
|
toolbar.querySelector(".qat [command=\"redo\"]").dataset.keytip = "2";
|
|
3109
|
-
for (const
|
|
3110
|
-
tab
|
|
3111
|
-
|
|
3054
|
+
for (const panel of toolbar.querySelectorAll("[data-ribbon-tab]")) {
|
|
3055
|
+
const tab = panel.dataset.ribbonTab;
|
|
3056
|
+
panel.dataset.tabKeytip = TABS[tab] ?? tab.slice(0, 1).toUpperCase();
|
|
3112
3057
|
}
|
|
3113
3058
|
for (const panel of toolbar.querySelectorAll(".ribbon-content")) {
|
|
3114
3059
|
panel.dataset.keytipLevel = "";
|
|
@@ -3213,98 +3158,42 @@ function createPageTabs(doc) {
|
|
|
3213
3158
|
}
|
|
3214
3159
|
//#endregion
|
|
3215
3160
|
//#region src/viewer-search.ts
|
|
3216
|
-
/** Builds the Find group: a search field, previous/next result buttons and a live status. */
|
|
3217
|
-
function createSearchGroup(doc) {
|
|
3218
|
-
const group = doc.createElement("div");
|
|
3219
|
-
group.className = "ribbon-group search-group";
|
|
3220
|
-
group.setAttribute("role", "group");
|
|
3221
|
-
group.setAttribute("aria-label", "Find");
|
|
3222
|
-
const controls = doc.createElement("div");
|
|
3223
|
-
controls.className = "search-controls";
|
|
3224
|
-
controls.setAttribute("role", "search");
|
|
3225
|
-
controls.setAttribute("aria-label", "Diagram text search");
|
|
3226
|
-
const label = doc.createElement("label");
|
|
3227
|
-
label.append("Find ");
|
|
3228
|
-
const input = doc.createElement("input");
|
|
3229
|
-
input.type = "search";
|
|
3230
|
-
input.setAttribute("aria-label", "Search diagram text");
|
|
3231
|
-
input.placeholder = "Text across pages";
|
|
3232
|
-
input.maxLength = TEXT_SEARCH_LIMITS.queryCharacters;
|
|
3233
|
-
input.autocomplete = "off";
|
|
3234
|
-
input.spellcheck = false;
|
|
3235
|
-
input.setAttribute("aria-describedby", "search-status");
|
|
3236
|
-
label.append(input);
|
|
3237
|
-
const step = (action, name, text) => {
|
|
3238
|
-
const button = doc.createElement("button");
|
|
3239
|
-
button.type = "button";
|
|
3240
|
-
button.dataset.action = action;
|
|
3241
|
-
button.setAttribute("aria-label", name);
|
|
3242
|
-
button.textContent = text;
|
|
3243
|
-
return button;
|
|
3244
|
-
};
|
|
3245
|
-
const status = doc.createElement("span");
|
|
3246
|
-
status.id = "search-status";
|
|
3247
|
-
status.setAttribute("role", "status");
|
|
3248
|
-
status.setAttribute("aria-live", "polite");
|
|
3249
|
-
status.setAttribute("aria-atomic", "true");
|
|
3250
|
-
controls.append(label, step("search-previous", "Previous matching shape", "Previous"), step("search-next", "Next matching shape", "Next"), status);
|
|
3251
|
-
const caption = doc.createElement("span");
|
|
3252
|
-
caption.className = "group-label";
|
|
3253
|
-
caption.textContent = "Find in drawing";
|
|
3254
|
-
group.append(controls, caption);
|
|
3255
|
-
return group;
|
|
3256
|
-
}
|
|
3257
3161
|
/**
|
|
3258
|
-
* Visio opens Find from Home > Editing rather than keeping a box in the ribbon. The
|
|
3259
|
-
* sits under the ribbon, hidden until Find... or Ctrl+F
|
|
3162
|
+
* Visio opens Find from Home > Editing rather than keeping a box in the ribbon. The shared
|
|
3163
|
+
* `office-ui-find-bar` sits under the ribbon, hidden until Find... or Ctrl+F; Enter and
|
|
3164
|
+
* Shift+Enter step through matching shapes and Escape clears, then closes.
|
|
3260
3165
|
*/
|
|
3261
3166
|
function createFindBar(doc) {
|
|
3262
|
-
const bar = doc.createElement("
|
|
3167
|
+
const bar = doc.createElement("office-ui-find-bar");
|
|
3263
3168
|
bar.className = "find-bar";
|
|
3264
|
-
bar.
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
close.title = "Close Find (Esc)";
|
|
3271
|
-
close.textContent = "×";
|
|
3272
|
-
bar.append(createSearchGroup(doc), close);
|
|
3169
|
+
bar.setAttribute("label", "Diagram text search");
|
|
3170
|
+
bar.setAttribute("input-label", "Search diagram text");
|
|
3171
|
+
bar.setAttribute("placeholder", "Text across pages");
|
|
3172
|
+
bar.setAttribute("maxlength", String(TEXT_SEARCH_LIMITS.queryCharacters));
|
|
3173
|
+
bar.setAttribute("previous-label", "Previous matching shape");
|
|
3174
|
+
bar.setAttribute("next-label", "Next matching shape");
|
|
3273
3175
|
return bar;
|
|
3274
3176
|
}
|
|
3275
|
-
/**
|
|
3276
|
-
function wireFindBar(bar,
|
|
3177
|
+
/** Route the find bar's queries and steps to the controller; `closed` restores focus. */
|
|
3178
|
+
function wireFindBar(bar, controller, closed) {
|
|
3277
3179
|
const events = new ((bar.ownerDocument.defaultView?.AbortController) ?? AbortController)();
|
|
3278
|
-
const
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
},
|
|
3285
|
-
bar.addEventListener("
|
|
3286
|
-
if (event.key === "Escape" && input.value === "") close();
|
|
3287
|
-
}, {
|
|
3288
|
-
signal: events.signal,
|
|
3289
|
-
capture: true
|
|
3290
|
-
});
|
|
3180
|
+
const options = { signal: events.signal };
|
|
3181
|
+
bar.addEventListener("office-find-input", (event) => controller.setSearchQuery(event.detail.query), options);
|
|
3182
|
+
bar.addEventListener("office-find-step", (event) => {
|
|
3183
|
+
const { direction } = event.detail;
|
|
3184
|
+
if (direction === "next") controller.nextSearchResult();
|
|
3185
|
+
else controller.previousSearchResult();
|
|
3186
|
+
}, options);
|
|
3187
|
+
bar.addEventListener("office-find-close", closed, options);
|
|
3291
3188
|
return () => events.abort();
|
|
3292
3189
|
}
|
|
3293
|
-
function
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
next: root.querySelector("[data-action=\"search-next\"]")
|
|
3299
|
-
};
|
|
3300
|
-
}
|
|
3301
|
-
function renderSearchControls(controls, state) {
|
|
3302
|
-
if (controls.input.value !== state.search.query) controls.input.value = state.search.query;
|
|
3303
|
-
controls.input.disabled = !state.document?.pages.length;
|
|
3304
|
-
controls.previous.disabled = controls.next.disabled = !state.search.results.length;
|
|
3305
|
-
controls.status.textContent = state.document ? textSearchStatus(state.search) : "Open a diagram to search";
|
|
3190
|
+
function renderFindBar(bar, state) {
|
|
3191
|
+
bar.value = state.search.query;
|
|
3192
|
+
bar.toggleAttribute("disabled", !state.document?.pages.length);
|
|
3193
|
+
bar.toggleAttribute("navigation-disabled", !state.search.results.length);
|
|
3194
|
+
bar.status = state.document ? textSearchStatus(state.search) : "Open a diagram to search";
|
|
3306
3195
|
const result = state.search.results[state.search.activeIndex];
|
|
3307
|
-
|
|
3196
|
+
bar.statusTitle = result ? `${result.pageName} · ${result.shapeName}: ${result.preview}` : "";
|
|
3308
3197
|
}
|
|
3309
3198
|
//#endregion
|
|
3310
3199
|
//#region src/viewer-fit.ts
|
|
@@ -3598,6 +3487,17 @@ var BACKSTAGE_FOOTER = [
|
|
|
3598
3487
|
["feedback", "Feedback"],
|
|
3599
3488
|
["options", "Options"]
|
|
3600
3489
|
];
|
|
3490
|
+
/** The navigation items, with optional disabled states (Save and Close follow the drawing). */
|
|
3491
|
+
function backstageItems(state = {}) {
|
|
3492
|
+
const item = (id, label, group) => ({
|
|
3493
|
+
id,
|
|
3494
|
+
label,
|
|
3495
|
+
...group ? { group } : {},
|
|
3496
|
+
...state[id]?.disabled ? { disabled: true } : {},
|
|
3497
|
+
...state[id]?.title ? { title: state[id].title } : {}
|
|
3498
|
+
});
|
|
3499
|
+
return [...BACKSTAGE_ITEMS.map(([id, label]) => item(id, label)), ...BACKSTAGE_FOOTER.map(([id, label]) => item(id, label, "footer"))];
|
|
3500
|
+
}
|
|
3601
3501
|
var LOCAL = "Documents stay in this browser; nothing is uploaded.";
|
|
3602
3502
|
function el(doc, tag, className, text) {
|
|
3603
3503
|
const node = doc.createElement(tag);
|
|
@@ -3621,7 +3521,6 @@ function action(doc, id, label, description, unsupported) {
|
|
|
3621
3521
|
function page(doc, id, title, ...content) {
|
|
3622
3522
|
const section = el(doc, "section", "backstage-page");
|
|
3623
3523
|
section.dataset.backstagePage = id;
|
|
3624
|
-
section.hidden = true;
|
|
3625
3524
|
section.setAttribute("aria-labelledby", `backstage-${id}-title`);
|
|
3626
3525
|
const heading = el(doc, "h1", "", title);
|
|
3627
3526
|
heading.id = `backstage-${id}-title`;
|
|
@@ -3629,31 +3528,55 @@ function page(doc, id, title, ...content) {
|
|
|
3629
3528
|
return section;
|
|
3630
3529
|
}
|
|
3631
3530
|
/**
|
|
3531
|
+
* Share with people: a live session (Yjs) between tabs and windows of this browser. The room name
|
|
3532
|
+
* is all a second window needs; nothing is uploaded.
|
|
3533
|
+
*/
|
|
3534
|
+
function share(doc) {
|
|
3535
|
+
const panel = el(doc, "section", "share-panel");
|
|
3536
|
+
panel.setAttribute("aria-labelledby", "share-title");
|
|
3537
|
+
const title = el(doc, "h2", "", "Share with people");
|
|
3538
|
+
title.id = "share-title";
|
|
3539
|
+
const field = el(doc, "label", "share-field");
|
|
3540
|
+
const room = el(doc, "input", "share-room");
|
|
3541
|
+
room.type = "text";
|
|
3542
|
+
room.maxLength = 64;
|
|
3543
|
+
room.autocomplete = "off";
|
|
3544
|
+
room.spellcheck = false;
|
|
3545
|
+
field.append(el(doc, "span", "", "Session name"), room);
|
|
3546
|
+
const buttons = el(doc, "div", "share-buttons");
|
|
3547
|
+
const start = el(doc, "button", "share-start", "Start sharing");
|
|
3548
|
+
start.type = "button";
|
|
3549
|
+
start.dataset.share = "start";
|
|
3550
|
+
const stop = el(doc, "button", "share-stop", "Stop sharing");
|
|
3551
|
+
stop.type = "button";
|
|
3552
|
+
stop.dataset.share = "stop";
|
|
3553
|
+
stop.hidden = true;
|
|
3554
|
+
buttons.append(start, stop);
|
|
3555
|
+
const status = el(doc, "p", "share-status");
|
|
3556
|
+
status.setAttribute("role", "status");
|
|
3557
|
+
const people = doc.createElement("office-ui-presence");
|
|
3558
|
+
people.className = "share-people";
|
|
3559
|
+
people.setAttribute("label", "People in this session");
|
|
3560
|
+
panel.append(title, el(doc, "p", "", "Edit this drawing together with other windows of this browser. Open the same session name in another window to join."), field, buttons, status, people, el(doc, "p", "backstage-muted", "The whole drawing is shared; when two people change it at once, the last change wins. Nothing leaves this device."));
|
|
3561
|
+
return panel;
|
|
3562
|
+
}
|
|
3563
|
+
/** Visio's Account page: the shared Office profile editor and product information. */
|
|
3564
|
+
function account(doc) {
|
|
3565
|
+
const profile = doc.createElement("office-ui-account");
|
|
3566
|
+
const product = el(doc, "section", "backstage-product");
|
|
3567
|
+
product.append(el(doc, "h2", "", "Product Information"), el(doc, "p", "", "Visio viewer (beta). No sign-in or subscription is used."), el(doc, "p", "backstage-muted", LOCAL));
|
|
3568
|
+
profile.append(product);
|
|
3569
|
+
return profile;
|
|
3570
|
+
}
|
|
3571
|
+
/**
|
|
3632
3572
|
* Visio's backstage: a full-window File view with a navigation column and one page per item.
|
|
3633
3573
|
* Static application structure only; document values are filled in later as text.
|
|
3634
3574
|
*/
|
|
3635
3575
|
function createBackstage(doc) {
|
|
3636
|
-
const root =
|
|
3637
|
-
root.
|
|
3638
|
-
root.setAttribute("
|
|
3639
|
-
root.
|
|
3640
|
-
root.setAttribute("aria-label", "File");
|
|
3641
|
-
const nav = el(doc, "nav", "backstage-nav");
|
|
3642
|
-
nav.setAttribute("aria-label", "File");
|
|
3643
|
-
const back = el(doc, "button", "backstage-back", "←");
|
|
3644
|
-
back.type = "button";
|
|
3645
|
-
back.dataset.backstage = "back";
|
|
3646
|
-
back.setAttribute("aria-label", "Back to the drawing");
|
|
3647
|
-
back.title = "Back (Esc)";
|
|
3648
|
-
const item = ([id, label]) => {
|
|
3649
|
-
const button = el(doc, "button", "backstage-item", label);
|
|
3650
|
-
button.type = "button";
|
|
3651
|
-
button.dataset.backstageItem = id;
|
|
3652
|
-
return button;
|
|
3653
|
-
};
|
|
3654
|
-
const footer = el(doc, "div", "backstage-footer");
|
|
3655
|
-
footer.append(...BACKSTAGE_FOOTER.map(item));
|
|
3656
|
-
nav.append(back, ...BACKSTAGE_ITEMS.map(item), footer);
|
|
3576
|
+
const root = doc.createElement("office-ui-backstage");
|
|
3577
|
+
root.className = "backstage";
|
|
3578
|
+
root.setAttribute("back-label", "Back to the drawing");
|
|
3579
|
+
root.items = backstageItems();
|
|
3657
3580
|
const facts = el(doc, "dl", "backstage-facts");
|
|
3658
3581
|
for (const [key, label] of [
|
|
3659
3582
|
["pages", "Pages"],
|
|
@@ -3679,67 +3602,61 @@ function createBackstage(doc) {
|
|
|
3679
3602
|
input.accept = ".vsdx,.vsd";
|
|
3680
3603
|
input.hidden = true;
|
|
3681
3604
|
input.setAttribute("aria-label", "Choose a Visio drawing");
|
|
3682
|
-
const preview =
|
|
3683
|
-
preview.
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
root.append(
|
|
3605
|
+
const preview = doc.createElement("office-ui-print-preview");
|
|
3606
|
+
preview.className = "backstage-print-preview";
|
|
3607
|
+
preview.setAttribute("label", "Print preview of the current page");
|
|
3608
|
+
preview.setAttribute("empty-label", "Open a drawing to print it.");
|
|
3609
|
+
root.append(page(doc, "info", "Info", file, facts, notes), page(doc, "new", "New", templates), page(doc, "open", "Open", action(doc, "open", "Browse", "Open a .vsdx drawing or a legacy .vsd preview from this device."), input, el(doc, "p", "backstage-muted", `Recent drawings are not tracked. ${LOCAL}`)), page(doc, "save-as", "Save As", action(doc, "download", "Download a copy", "Save the drawing, with your edits, as a .vsdx file."), action(doc, "export-svg", "Export the current page as SVG", "An approximate picture with compatibility notes.")), page(doc, "print", "Print", action(doc, "print", "Print", "Print the current page."), preview), page(doc, "share", "Share", share(doc), action(doc, "email", "Email", "Send the drawing as an attachment.", LOCAL)), page(doc, "export", "Export", action(doc, "export-svg", "Export the current page as SVG", "An approximate picture with compatibility notes."), action(doc, "export-pdf", "Create PDF/XPS Document", "A fixed-layout document.", "Needs PDF output."), action(doc, "change-type", "Change File Type", "Save in another Visio format.", "Needs core format conversion.")), page(doc, "account", "Account", account(doc)), page(doc, "feedback", "Feedback", el(doc, "p", "backstage-muted", "Feedback is not collected by this viewer.")));
|
|
3687
3610
|
return root;
|
|
3688
3611
|
}
|
|
3689
3612
|
//#endregion
|
|
3690
3613
|
//#region src/viewer-backstage.ts
|
|
3691
|
-
/**
|
|
3692
|
-
* Visio's File backstage: opened from the File tab, closed with Back or Escape (focus returns to
|
|
3693
|
-
* File). Open, Save, Save As, Export, Print and Close are real; the rest is shown disabled.
|
|
3694
|
-
*/
|
|
3695
3614
|
var ViewerBackstage = class {
|
|
3696
3615
|
host;
|
|
3697
3616
|
#root;
|
|
3698
|
-
#
|
|
3617
|
+
#ribbon;
|
|
3699
3618
|
#input;
|
|
3700
3619
|
#state;
|
|
3620
|
+
#items = "";
|
|
3701
3621
|
#urls = /* @__PURE__ */ new Set();
|
|
3702
3622
|
constructor(host) {
|
|
3703
3623
|
this.host = host;
|
|
3704
|
-
this.#root = host.root.querySelector("
|
|
3705
|
-
this.#
|
|
3624
|
+
this.#root = host.root.querySelector("office-ui-backstage");
|
|
3625
|
+
this.#ribbon = host.root.querySelector("office-ui-ribbon");
|
|
3706
3626
|
this.#input = this.#root.querySelector(".backstage-file-input");
|
|
3707
3627
|
}
|
|
3708
3628
|
get open() {
|
|
3709
|
-
return
|
|
3629
|
+
return this.#root.open;
|
|
3710
3630
|
}
|
|
3711
3631
|
show(page = "info") {
|
|
3712
|
-
this.#
|
|
3713
|
-
this.#
|
|
3714
|
-
this.#
|
|
3715
|
-
this.#root.querySelector(`[data-backstage-item="${page}"]`)?.focus();
|
|
3632
|
+
this.#ribbon.setAttribute("file-expanded", "true");
|
|
3633
|
+
this.#root.show(page);
|
|
3634
|
+
if (page === "print") this.#preview();
|
|
3716
3635
|
}
|
|
3717
3636
|
hide() {
|
|
3718
|
-
|
|
3719
|
-
this.#root.hidden = true;
|
|
3720
|
-
this.#file.setAttribute("aria-expanded", "false");
|
|
3721
|
-
this.#file.focus();
|
|
3637
|
+
this.#root.close();
|
|
3722
3638
|
}
|
|
3723
3639
|
wire() {
|
|
3724
3640
|
const events = new ((this.host.root.ownerDocument.defaultView?.AbortController) ?? AbortController)();
|
|
3725
3641
|
const options = { signal: events.signal };
|
|
3726
|
-
this.#
|
|
3642
|
+
this.#ribbon.addEventListener("office-ribbon-file", () => this.open ? this.hide() : this.show(), options);
|
|
3643
|
+
this.#root.addEventListener("office-backstage-select", (event) => {
|
|
3644
|
+
const id = event.detail.id;
|
|
3645
|
+
if (id === "save") this.#download();
|
|
3646
|
+
else if (id === "close") this.#close();
|
|
3647
|
+
else if (id === "options") {
|
|
3648
|
+
this.hide();
|
|
3649
|
+
this.host.showOptions();
|
|
3650
|
+
} else if (id === "print") this.#preview();
|
|
3651
|
+
}, options);
|
|
3652
|
+
this.#root.addEventListener("office-backstage-close", () => {
|
|
3653
|
+
this.#ribbon.setAttribute("file-expanded", "false");
|
|
3654
|
+
this.#ribbon.focusFile();
|
|
3655
|
+
}, options);
|
|
3727
3656
|
this.#root.addEventListener("click", (event) => {
|
|
3728
|
-
const
|
|
3729
|
-
if (target.closest?.("[data-backstage=\"back\"]")) return this.hide();
|
|
3730
|
-
const item = target.closest?.("[data-backstage-item]")?.dataset.backstageItem;
|
|
3731
|
-
if (item === "save") return this.#download();
|
|
3732
|
-
if (item === "close") return this.#close();
|
|
3733
|
-
if (item) return this.#select(item);
|
|
3734
|
-
const action = target.closest?.("[data-backstage-action]");
|
|
3657
|
+
const action = event.target.closest?.("[data-backstage-action]");
|
|
3735
3658
|
if (action && !action.disabled) this.#run(action.dataset.backstageAction);
|
|
3736
3659
|
}, options);
|
|
3737
|
-
this.#root.addEventListener("keydown", (event) => {
|
|
3738
|
-
if (event.key !== "Escape") return;
|
|
3739
|
-
event.preventDefault();
|
|
3740
|
-
event.stopPropagation();
|
|
3741
|
-
this.hide();
|
|
3742
|
-
}, options);
|
|
3743
3660
|
this.#input.addEventListener("change", () => {
|
|
3744
3661
|
const file = this.#input.files?.[0];
|
|
3745
3662
|
this.#input.value = "";
|
|
@@ -3753,11 +3670,6 @@ var ViewerBackstage = class {
|
|
|
3753
3670
|
this.#urls.clear();
|
|
3754
3671
|
};
|
|
3755
3672
|
}
|
|
3756
|
-
#select(page) {
|
|
3757
|
-
for (const item of this.#root.querySelectorAll("[data-backstage-item]")) item.toggleAttribute("aria-current", item.dataset.backstageItem === page);
|
|
3758
|
-
for (const section of this.#root.querySelectorAll("[data-backstage-page]")) section.hidden = section.dataset.backstagePage !== page;
|
|
3759
|
-
if (page === "print") this.#preview();
|
|
3760
|
-
}
|
|
3761
3673
|
#run(action) {
|
|
3762
3674
|
if (action === "open") this.#input.click();
|
|
3763
3675
|
else if (action === "download") this.#download();
|
|
@@ -3807,14 +3719,11 @@ var ViewerBackstage = class {
|
|
|
3807
3719
|
this.host.announce(error instanceof Error ? error.message : String(error));
|
|
3808
3720
|
}
|
|
3809
3721
|
}
|
|
3810
|
-
/**
|
|
3722
|
+
/** The shared print preview shows an inert clone of the rendered page, never parsed markup. */
|
|
3811
3723
|
#preview() {
|
|
3812
|
-
const
|
|
3724
|
+
const preview = this.#root.querySelector("office-ui-print-preview");
|
|
3813
3725
|
const paper = this.host.viewport.querySelector("svg.paper");
|
|
3814
|
-
|
|
3815
|
-
const clone = target.querySelector("svg");
|
|
3816
|
-
clone?.removeAttribute("style");
|
|
3817
|
-
clone?.querySelectorAll("[tabindex]").forEach((node) => node.removeAttribute("tabindex"));
|
|
3726
|
+
preview.pages = paper ? [paper] : [];
|
|
3818
3727
|
}
|
|
3819
3728
|
#print() {
|
|
3820
3729
|
const doc = this.host.root.ownerDocument;
|
|
@@ -3858,13 +3767,24 @@ var ViewerBackstage = class {
|
|
|
3858
3767
|
this.#root.querySelector(".backstage-note-count").textContent = notes ? `${notes} compatibility notes describe what this viewer approximates or omits.` : "No compatibility notes.";
|
|
3859
3768
|
const busy = state.loading || state.edit.busy;
|
|
3860
3769
|
const saveReason = state.document?.format === "vsd" ? "Legacy VSD drawings are read only here." : "Open a .vsdx file to save a copy.";
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3770
|
+
const saveDisabled = !state.edit.sourceAvailable || busy;
|
|
3771
|
+
const download = this.#root.querySelector("[data-backstage-action=\"download\"]");
|
|
3772
|
+
download.disabled = saveDisabled;
|
|
3773
|
+
download.title = saveDisabled ? saveReason : "";
|
|
3774
|
+
const items = backstageItems({
|
|
3775
|
+
save: {
|
|
3776
|
+
disabled: saveDisabled,
|
|
3777
|
+
...saveDisabled ? { title: saveReason } : {}
|
|
3778
|
+
},
|
|
3779
|
+
close: { disabled: !state.document }
|
|
3780
|
+
});
|
|
3781
|
+
const key = JSON.stringify(items);
|
|
3782
|
+
if (key !== this.#items) {
|
|
3783
|
+
this.#items = key;
|
|
3784
|
+
this.#root.items = items;
|
|
3864
3785
|
}
|
|
3865
3786
|
for (const node of this.#root.querySelectorAll("[data-backstage-action=\"export-svg\"], [data-backstage-action=\"print\"]")) node.disabled = !page || busy;
|
|
3866
3787
|
this.#root.querySelector("[data-backstage-action=\"notes\"]").disabled = notes === 0;
|
|
3867
|
-
this.#root.querySelector("[data-backstage-item=\"close\"]").disabled = !state.document;
|
|
3868
3788
|
}
|
|
3869
3789
|
};
|
|
3870
3790
|
//#endregion
|
|
@@ -4206,6 +4126,396 @@ var ViewerPanZoom = class {
|
|
|
4206
4126
|
}
|
|
4207
4127
|
};
|
|
4208
4128
|
//#endregion
|
|
4129
|
+
//#region src/viewer-options.ts
|
|
4130
|
+
var disabled = (reason) => ({ disabled: `Not available yet. ${reason}` });
|
|
4131
|
+
/**
|
|
4132
|
+
* Visio's File > Options categories, in Visio's order. Only User name and Initials are honoured
|
|
4133
|
+
* today (they are the local profile, also used as the identity in a shared session); every other
|
|
4134
|
+
* setting is shown disabled with the capability it is waiting for.
|
|
4135
|
+
*/
|
|
4136
|
+
var VISIO_OPTION_CATEGORIES = [
|
|
4137
|
+
{
|
|
4138
|
+
id: "general",
|
|
4139
|
+
label: "General",
|
|
4140
|
+
description: "General options for working with Visio.",
|
|
4141
|
+
sections: [{
|
|
4142
|
+
id: "ui",
|
|
4143
|
+
title: "User Interface options",
|
|
4144
|
+
controls: [
|
|
4145
|
+
{
|
|
4146
|
+
kind: "toggle",
|
|
4147
|
+
key: "miniToolbar",
|
|
4148
|
+
label: "Show Mini Toolbar on selection",
|
|
4149
|
+
...disabled("Needs rich text formatting.")
|
|
4150
|
+
},
|
|
4151
|
+
{
|
|
4152
|
+
kind: "toggle",
|
|
4153
|
+
key: "livePreview",
|
|
4154
|
+
label: "Enable Live Preview",
|
|
4155
|
+
...disabled("Needs Quick Styles and themes.")
|
|
4156
|
+
},
|
|
4157
|
+
{
|
|
4158
|
+
kind: "select",
|
|
4159
|
+
key: "screenTips",
|
|
4160
|
+
label: "ScreenTip style",
|
|
4161
|
+
choices: [{
|
|
4162
|
+
value: "descriptions",
|
|
4163
|
+
label: "Show feature descriptions in ScreenTips"
|
|
4164
|
+
}],
|
|
4165
|
+
...disabled("ScreenTips always describe the command.")
|
|
4166
|
+
}
|
|
4167
|
+
]
|
|
4168
|
+
}, {
|
|
4169
|
+
id: "personalize",
|
|
4170
|
+
title: "Personalize your copy of Microsoft Office",
|
|
4171
|
+
description: "Stored on this device only. Shared sessions show this name to others.",
|
|
4172
|
+
controls: [{
|
|
4173
|
+
kind: "text",
|
|
4174
|
+
key: "userName",
|
|
4175
|
+
label: "User name",
|
|
4176
|
+
maxLength: 64
|
|
4177
|
+
}, {
|
|
4178
|
+
kind: "text",
|
|
4179
|
+
key: "userInitials",
|
|
4180
|
+
label: "Initials",
|
|
4181
|
+
maxLength: 2
|
|
4182
|
+
}]
|
|
4183
|
+
}]
|
|
4184
|
+
},
|
|
4185
|
+
{
|
|
4186
|
+
id: "proofing",
|
|
4187
|
+
label: "Proofing",
|
|
4188
|
+
description: "Change how Visio corrects and formats your text.",
|
|
4189
|
+
disabled: "Not available yet. Spelling and AutoCorrect need rich text editing.",
|
|
4190
|
+
sections: []
|
|
4191
|
+
},
|
|
4192
|
+
{
|
|
4193
|
+
id: "save",
|
|
4194
|
+
label: "Save",
|
|
4195
|
+
description: "Customize how drawings are saved.",
|
|
4196
|
+
disabled: "Not available yet. Drawings are saved as downloaded copies; AutoRecover is not kept.",
|
|
4197
|
+
sections: []
|
|
4198
|
+
},
|
|
4199
|
+
{
|
|
4200
|
+
id: "language",
|
|
4201
|
+
label: "Language",
|
|
4202
|
+
description: "Set the Office Language Preferences.",
|
|
4203
|
+
disabled: "Not available yet. The viewer is English only.",
|
|
4204
|
+
sections: []
|
|
4205
|
+
},
|
|
4206
|
+
{
|
|
4207
|
+
id: "advanced",
|
|
4208
|
+
label: "Advanced",
|
|
4209
|
+
description: "Advanced options for working with Visio.",
|
|
4210
|
+
sections: [{
|
|
4211
|
+
id: "editing",
|
|
4212
|
+
title: "Editing options",
|
|
4213
|
+
controls: [{
|
|
4214
|
+
kind: "number",
|
|
4215
|
+
key: "undoLevels",
|
|
4216
|
+
label: "Number of undo levels",
|
|
4217
|
+
min: 1,
|
|
4218
|
+
max: 99,
|
|
4219
|
+
...disabled("The history depth is fixed.")
|
|
4220
|
+
}, {
|
|
4221
|
+
kind: "toggle",
|
|
4222
|
+
key: "autoSizeText",
|
|
4223
|
+
label: "Auto-size text while editing",
|
|
4224
|
+
...disabled("Needs core text layout.")
|
|
4225
|
+
}]
|
|
4226
|
+
}]
|
|
4227
|
+
},
|
|
4228
|
+
{
|
|
4229
|
+
id: "ribbon",
|
|
4230
|
+
label: "Customize Ribbon",
|
|
4231
|
+
description: "Customize the Ribbon and keyboard shortcuts.",
|
|
4232
|
+
disabled: "Not available yet. The ribbon layout is fixed.",
|
|
4233
|
+
sections: []
|
|
4234
|
+
},
|
|
4235
|
+
{
|
|
4236
|
+
id: "qat",
|
|
4237
|
+
label: "Quick Access Toolbar",
|
|
4238
|
+
description: "Customize the Quick Access Toolbar.",
|
|
4239
|
+
disabled: "Not available yet. The Quick Access Toolbar shows Undo and Redo.",
|
|
4240
|
+
sections: []
|
|
4241
|
+
},
|
|
4242
|
+
{
|
|
4243
|
+
id: "add-ins",
|
|
4244
|
+
label: "Add-ins",
|
|
4245
|
+
description: "View and manage Microsoft Office Add-ins.",
|
|
4246
|
+
disabled: "Not available. Add-ins and macros never run in this viewer.",
|
|
4247
|
+
sections: []
|
|
4248
|
+
},
|
|
4249
|
+
{
|
|
4250
|
+
id: "trust",
|
|
4251
|
+
label: "Trust Center",
|
|
4252
|
+
description: "Help keep your documents safe and your computer secure and healthy.",
|
|
4253
|
+
disabled: "Not available. Documents stay local and active content is never run.",
|
|
4254
|
+
sections: []
|
|
4255
|
+
}
|
|
4256
|
+
];
|
|
4257
|
+
function profileValues(profile) {
|
|
4258
|
+
return {
|
|
4259
|
+
miniToolbar: false,
|
|
4260
|
+
livePreview: false,
|
|
4261
|
+
screenTips: "descriptions",
|
|
4262
|
+
undoLevels: 20,
|
|
4263
|
+
autoSizeText: false,
|
|
4264
|
+
userName: profile.displayName,
|
|
4265
|
+
userInitials: profile.initial ?? ""
|
|
4266
|
+
};
|
|
4267
|
+
}
|
|
4268
|
+
/** The Options dialog element. Built once and appended to the viewer's shadow root. */
|
|
4269
|
+
function createOptionsDialog(doc) {
|
|
4270
|
+
const dialog = doc.createElement("office-ui-options-dialog");
|
|
4271
|
+
dialog.setAttribute("heading", "Visio Options");
|
|
4272
|
+
dialog.categories = VISIO_OPTION_CATEGORIES;
|
|
4273
|
+
return dialog;
|
|
4274
|
+
}
|
|
4275
|
+
/**
|
|
4276
|
+
* File > Account and File > Options share one local profile. Edits in either are written to the
|
|
4277
|
+
* suite-wide profile store, mirrored into the other and reported through `onProfile`.
|
|
4278
|
+
*/
|
|
4279
|
+
var ViewerProfile = class {
|
|
4280
|
+
onProfile;
|
|
4281
|
+
#profile = readOfficeProfile();
|
|
4282
|
+
#dialog;
|
|
4283
|
+
#account;
|
|
4284
|
+
constructor(root, onProfile = () => {}) {
|
|
4285
|
+
this.onProfile = onProfile;
|
|
4286
|
+
this.#dialog = root.querySelector("office-ui-options-dialog");
|
|
4287
|
+
this.#account = root.querySelector("office-ui-account");
|
|
4288
|
+
this.#sync();
|
|
4289
|
+
}
|
|
4290
|
+
get profile() {
|
|
4291
|
+
return { ...this.#profile };
|
|
4292
|
+
}
|
|
4293
|
+
/** Open Visio Options, on General as Visio does. */
|
|
4294
|
+
showOptions(category = "general") {
|
|
4295
|
+
this.#dialog.values = profileValues(this.#profile);
|
|
4296
|
+
this.#dialog.category = category;
|
|
4297
|
+
this.#dialog.show();
|
|
4298
|
+
}
|
|
4299
|
+
wire() {
|
|
4300
|
+
const events = new ((this.#dialog.ownerDocument.defaultView?.AbortController) ?? AbortController)();
|
|
4301
|
+
const options = { signal: events.signal };
|
|
4302
|
+
this.#dialog.addEventListener("office-options-change", (event) => {
|
|
4303
|
+
const { values } = event.detail;
|
|
4304
|
+
const initial = String(values.userInitials ?? "").trim();
|
|
4305
|
+
this.#update({
|
|
4306
|
+
displayName: String(values.userName ?? "").trim(),
|
|
4307
|
+
avatarColor: this.#profile.avatarColor,
|
|
4308
|
+
...initial ? { initial } : {}
|
|
4309
|
+
});
|
|
4310
|
+
}, options);
|
|
4311
|
+
this.#account?.addEventListener("office-profile-change", (event) => this.#update(event.detail.profile), options);
|
|
4312
|
+
return () => events.abort();
|
|
4313
|
+
}
|
|
4314
|
+
#update(profile) {
|
|
4315
|
+
this.#profile = sanitizeOfficeProfile(profile);
|
|
4316
|
+
writeOfficeProfile(this.#profile);
|
|
4317
|
+
this.#sync();
|
|
4318
|
+
this.onProfile(this.profile);
|
|
4319
|
+
}
|
|
4320
|
+
#sync() {
|
|
4321
|
+
if (this.#account) this.#account.profile = this.#profile;
|
|
4322
|
+
this.#dialog.values = profileValues(this.#profile);
|
|
4323
|
+
}
|
|
4324
|
+
};
|
|
4325
|
+
//#endregion
|
|
4326
|
+
//#region src/viewer-share.ts
|
|
4327
|
+
/** Room names the core accepts: 1-64 letters, digits, hyphens or underscores. */
|
|
4328
|
+
var ROOM = /^[A-Za-z0-9_-]{1,64}$/;
|
|
4329
|
+
/**
|
|
4330
|
+
* File > Share: a live session over `ooxml-core/collab` (Yjs). Peers in other windows of this
|
|
4331
|
+
* browser share the whole VSDX package through a BroadcastChannel; remote changes arrive as one
|
|
4332
|
+
* undoable history step. The collab runtime loads only when sharing starts.
|
|
4333
|
+
*/
|
|
4334
|
+
var ViewerShare = class {
|
|
4335
|
+
controller;
|
|
4336
|
+
profile;
|
|
4337
|
+
loadCollab;
|
|
4338
|
+
#panel;
|
|
4339
|
+
#room;
|
|
4340
|
+
#start;
|
|
4341
|
+
#stop;
|
|
4342
|
+
#status;
|
|
4343
|
+
#people;
|
|
4344
|
+
#session = null;
|
|
4345
|
+
#teardown = null;
|
|
4346
|
+
#revision = 0;
|
|
4347
|
+
/** The package this window last published or adopted, to skip repeats of it. */
|
|
4348
|
+
#last = null;
|
|
4349
|
+
#adopting = false;
|
|
4350
|
+
#pending = null;
|
|
4351
|
+
#starting = false;
|
|
4352
|
+
constructor(root, controller, profile, loadCollab = () => import("ooxml-core/collab")) {
|
|
4353
|
+
this.controller = controller;
|
|
4354
|
+
this.profile = profile;
|
|
4355
|
+
this.loadCollab = loadCollab;
|
|
4356
|
+
this.#panel = root.querySelector(".share-panel");
|
|
4357
|
+
this.#room = this.#panel.querySelector(".share-room");
|
|
4358
|
+
this.#start = this.#panel.querySelector("[data-share=\"start\"]");
|
|
4359
|
+
this.#stop = this.#panel.querySelector("[data-share=\"stop\"]");
|
|
4360
|
+
this.#status = this.#panel.querySelector(".share-status");
|
|
4361
|
+
this.#people = this.#panel.querySelector("office-ui-presence");
|
|
4362
|
+
this.#room.value = `visio-${Math.random().toString(36).slice(2, 8)}`;
|
|
4363
|
+
}
|
|
4364
|
+
get active() {
|
|
4365
|
+
return this.#session !== null;
|
|
4366
|
+
}
|
|
4367
|
+
wire() {
|
|
4368
|
+
const events = new ((this.#panel.ownerDocument.defaultView?.AbortController) ?? AbortController)();
|
|
4369
|
+
this.#panel.addEventListener("click", (event) => {
|
|
4370
|
+
const action = event.target.closest?.("[data-share]");
|
|
4371
|
+
if (action?.dataset.share === "start") this.start(this.#room.value.trim());
|
|
4372
|
+
if (action?.dataset.share === "stop") this.stop();
|
|
4373
|
+
}, { signal: events.signal });
|
|
4374
|
+
return () => {
|
|
4375
|
+
events.abort();
|
|
4376
|
+
this.stop();
|
|
4377
|
+
};
|
|
4378
|
+
}
|
|
4379
|
+
async start(roomId) {
|
|
4380
|
+
if (this.#session || this.#starting) return;
|
|
4381
|
+
if (!ROOM.test(roomId)) return this.#say("Use 1 to 64 letters, digits, hyphens or underscores for the session name.");
|
|
4382
|
+
this.#starting = true;
|
|
4383
|
+
this.#render();
|
|
4384
|
+
try {
|
|
4385
|
+
const collab = await this.loadCollab();
|
|
4386
|
+
if (!collab.canBroadcast()) return this.#say("Sharing needs BroadcastChannel, which this browser does not provide.");
|
|
4387
|
+
this.#join(collab, roomId);
|
|
4388
|
+
} catch (error) {
|
|
4389
|
+
this.#say(error instanceof Error ? error.message : String(error));
|
|
4390
|
+
} finally {
|
|
4391
|
+
this.#starting = false;
|
|
4392
|
+
this.#render();
|
|
4393
|
+
}
|
|
4394
|
+
}
|
|
4395
|
+
stop() {
|
|
4396
|
+
this.#teardown?.();
|
|
4397
|
+
this.#teardown = null;
|
|
4398
|
+
this.#session?.destroy();
|
|
4399
|
+
this.#session = null;
|
|
4400
|
+
this.#pending = null;
|
|
4401
|
+
this.#revision = 0;
|
|
4402
|
+
this.#last = null;
|
|
4403
|
+
this.#people.participants = [];
|
|
4404
|
+
this.#say("Not sharing.");
|
|
4405
|
+
this.#render();
|
|
4406
|
+
}
|
|
4407
|
+
#join(collab, roomId) {
|
|
4408
|
+
const adapter = collab.packageAdapter();
|
|
4409
|
+
const me = this.profile();
|
|
4410
|
+
const session = collab.createCollabSession({
|
|
4411
|
+
roomId: `visio-${roomId}`,
|
|
4412
|
+
provider: collab.transportProvider({ transport: collab.createBroadcastTransport({ roomId: `visio-${roomId}` }) }),
|
|
4413
|
+
user: {
|
|
4414
|
+
name: me.displayName || "Visio user",
|
|
4415
|
+
color: me.avatarColor
|
|
4416
|
+
},
|
|
4417
|
+
teardown: true
|
|
4418
|
+
});
|
|
4419
|
+
this.#session = session;
|
|
4420
|
+
const publish = () => {
|
|
4421
|
+
const bytes = this.#localBytes();
|
|
4422
|
+
if (!bytes || !session.canWrite()) return;
|
|
4423
|
+
adapter.write(session.doc, {
|
|
4424
|
+
bytes,
|
|
4425
|
+
revision: this.#revision
|
|
4426
|
+
}, collab.LOCAL_ORIGIN);
|
|
4427
|
+
this.#revision = adapter.read(session.doc).revision;
|
|
4428
|
+
this.#last = bytes;
|
|
4429
|
+
};
|
|
4430
|
+
const adopt = () => {
|
|
4431
|
+
if (adapter.isEmpty(session.doc)) return;
|
|
4432
|
+
const model = adapter.read(session.doc);
|
|
4433
|
+
if (model.revision < this.#revision) return;
|
|
4434
|
+
if (model.revision === this.#revision && same(model.bytes, this.#last)) return;
|
|
4435
|
+
this.#revision = model.revision;
|
|
4436
|
+
this.#last = model.bytes;
|
|
4437
|
+
this.#apply(model.bytes);
|
|
4438
|
+
};
|
|
4439
|
+
const map = session.doc.getMap("package");
|
|
4440
|
+
const observer = (_event, transaction) => {
|
|
4441
|
+
if (transaction.origin !== collab.LOCAL_ORIGIN) adopt();
|
|
4442
|
+
};
|
|
4443
|
+
map.observe(observer);
|
|
4444
|
+
const settle = () => adapter.isEmpty(session.doc) ? publish() : adopt();
|
|
4445
|
+
const stopReady = session.on("ready", settle);
|
|
4446
|
+
const stopPeers = session.on("peers", (peers) => this.#showPeers(peers));
|
|
4447
|
+
const stopEvents = this.controller.onEvent((name, detail) => {
|
|
4448
|
+
if (name === "document-change" && detail.kind !== "remote") publish();
|
|
4449
|
+
if (name === "document-load" && !this.#adopting) publish();
|
|
4450
|
+
});
|
|
4451
|
+
const stopState = this.controller.subscribe((state) => this.#flush(state));
|
|
4452
|
+
this.#teardown = () => {
|
|
4453
|
+
map.unobserve(observer);
|
|
4454
|
+
stopReady();
|
|
4455
|
+
stopPeers();
|
|
4456
|
+
stopEvents();
|
|
4457
|
+
stopState();
|
|
4458
|
+
};
|
|
4459
|
+
if (session.canWrite()) settle();
|
|
4460
|
+
this.#showPeers(session.peers());
|
|
4461
|
+
this.#say(`Sharing as ${me.displayName || "Visio user"} in session ${roomId}.`);
|
|
4462
|
+
}
|
|
4463
|
+
#localBytes() {
|
|
4464
|
+
const { edit, loading } = this.controller.state;
|
|
4465
|
+
if (!edit.sourceAvailable || edit.busy || loading) return null;
|
|
4466
|
+
try {
|
|
4467
|
+
return this.controller.exportVsdx().bytes;
|
|
4468
|
+
} catch {
|
|
4469
|
+
return null;
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
#apply(bytes) {
|
|
4473
|
+
const { edit, loading, document } = this.controller.state;
|
|
4474
|
+
if (edit.busy || loading) {
|
|
4475
|
+
this.#pending = bytes;
|
|
4476
|
+
return;
|
|
4477
|
+
}
|
|
4478
|
+
this.#pending = null;
|
|
4479
|
+
const done = (error) => {
|
|
4480
|
+
this.#adopting = false;
|
|
4481
|
+
if (error) this.#say(error instanceof Error ? error.message : String(error));
|
|
4482
|
+
};
|
|
4483
|
+
this.#adopting = true;
|
|
4484
|
+
(document && edit.sourceAvailable ? this.controller.applyRemoteSource(bytes) : this.controller.load(bytes)).then(() => done(), done);
|
|
4485
|
+
}
|
|
4486
|
+
#flush(state) {
|
|
4487
|
+
if (this.#pending && !state.edit.busy && !state.loading) this.#apply(this.#pending);
|
|
4488
|
+
}
|
|
4489
|
+
#showPeers(peers) {
|
|
4490
|
+
const me = this.profile();
|
|
4491
|
+
this.#people.participants = [{
|
|
4492
|
+
id: "self",
|
|
4493
|
+
name: me.displayName || "Visio user",
|
|
4494
|
+
color: me.avatarColor,
|
|
4495
|
+
self: true
|
|
4496
|
+
}, ...peers.map((peer) => ({
|
|
4497
|
+
id: String(peer.clientId),
|
|
4498
|
+
name: peer.userName,
|
|
4499
|
+
color: peer.userColor
|
|
4500
|
+
}))];
|
|
4501
|
+
}
|
|
4502
|
+
#say(message) {
|
|
4503
|
+
this.#status.textContent = message;
|
|
4504
|
+
}
|
|
4505
|
+
#render() {
|
|
4506
|
+
const active = this.active;
|
|
4507
|
+
this.#start.hidden = active;
|
|
4508
|
+
this.#stop.hidden = !active;
|
|
4509
|
+
this.#start.disabled = this.#starting;
|
|
4510
|
+
this.#room.disabled = active || this.#starting;
|
|
4511
|
+
}
|
|
4512
|
+
};
|
|
4513
|
+
function same(a, b) {
|
|
4514
|
+
if (!b || a.byteLength !== b.byteLength) return false;
|
|
4515
|
+
for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;
|
|
4516
|
+
return true;
|
|
4517
|
+
}
|
|
4518
|
+
//#endregion
|
|
4209
4519
|
//#region src/edit-error.ts
|
|
4210
4520
|
/** Core error codes remain visible for a refused transaction; document content is plain text. */
|
|
4211
4521
|
function editErrorMessage(error) {
|
|
@@ -4436,12 +4746,6 @@ function wireStencil(pane, viewport, controller, announce) {
|
|
|
4436
4746
|
}
|
|
4437
4747
|
//#endregion
|
|
4438
4748
|
//#region src/viewer-ruler.ts
|
|
4439
|
-
/**
|
|
4440
|
-
* Visio's rulers: inch scales along the top and left of the drawing window with 0 at the page's
|
|
4441
|
-
* left and bottom edges (vertical values grow upward, as in Visio). Viewer-only presentation:
|
|
4442
|
-
* nothing is read from or written to the document beyond the rendered page box.
|
|
4443
|
-
*/
|
|
4444
|
-
var SIZE = 18;
|
|
4445
4749
|
/** Wraps the viewport in a grid with a corner, a top ruler and a left ruler. */
|
|
4446
4750
|
function createRulers(viewport) {
|
|
4447
4751
|
const doc = viewport.ownerDocument;
|
|
@@ -4449,79 +4753,35 @@ function createRulers(viewport) {
|
|
|
4449
4753
|
area.className = "canvas-area";
|
|
4450
4754
|
const corner = doc.createElement("div");
|
|
4451
4755
|
corner.className = "ruler-corner";
|
|
4452
|
-
|
|
4756
|
+
corner.setAttribute("aria-hidden", "true");
|
|
4757
|
+
const top = doc.createElement("office-ui-ruler");
|
|
4453
4758
|
top.className = "ruler ruler-h";
|
|
4454
|
-
const left = doc.createElement("
|
|
4759
|
+
const left = doc.createElement("office-ui-ruler");
|
|
4455
4760
|
left.className = "ruler ruler-v";
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
top,
|
|
4459
|
-
left
|
|
4460
|
-
]) ruler.setAttribute("aria-hidden", "true");
|
|
4761
|
+
left.setAttribute("orientation", "vertical");
|
|
4762
|
+
left.setAttribute("direction", "reverse");
|
|
4461
4763
|
viewport.replaceWith(area);
|
|
4462
4764
|
area.append(corner, top, left, viewport);
|
|
4463
4765
|
let visible = false;
|
|
4464
4766
|
let zoom = 1;
|
|
4465
4767
|
let frame = 0;
|
|
4466
|
-
const
|
|
4768
|
+
const place = () => {
|
|
4467
4769
|
frame = 0;
|
|
4468
4770
|
if (!visible) return;
|
|
4469
4771
|
const paper = viewport.querySelector("svg.paper");
|
|
4470
|
-
|
|
4471
|
-
const ink = (doc.defaultView?.getComputedStyle(area))?.getPropertyValue("--_vv-muted").trim() || "#605e5c";
|
|
4772
|
+
if (!paper) return;
|
|
4472
4773
|
const base = viewport.getBoundingClientRect();
|
|
4473
|
-
const page = paper
|
|
4474
|
-
const
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
canvas.height = Math.round(SIZE * ratio);
|
|
4480
|
-
if (!horizontal) [canvas.width, canvas.height] = [canvas.height, canvas.width];
|
|
4481
|
-
const context = canvas.getContext?.("2d");
|
|
4482
|
-
if (!context || !page) return;
|
|
4483
|
-
context.scale(ratio, ratio);
|
|
4484
|
-
context.strokeStyle = ink;
|
|
4485
|
-
context.fillStyle = ink;
|
|
4486
|
-
context.lineWidth = 1;
|
|
4487
|
-
context.font = "9px \"Segoe UI\", Arial, sans-serif";
|
|
4488
|
-
const origin = horizontal ? page.left - base.left : page.bottom - base.top;
|
|
4489
|
-
const step = inch / divisions;
|
|
4490
|
-
const first = Math.floor((horizontal ? -origin : origin - length) / step) - 1;
|
|
4491
|
-
const last = Math.ceil((horizontal ? length - origin : origin) / step) + 1;
|
|
4492
|
-
context.beginPath();
|
|
4493
|
-
for (let index = first; index <= last; index++) {
|
|
4494
|
-
const position = horizontal ? origin + index * step : origin - index * step;
|
|
4495
|
-
const tick = index % divisions === 0 ? SIZE : index % (divisions / 2) === 0 ? SIZE * .5 : SIZE * .3;
|
|
4496
|
-
const at = Math.round(position) + .5;
|
|
4497
|
-
if (horizontal) {
|
|
4498
|
-
context.moveTo(at, SIZE);
|
|
4499
|
-
context.lineTo(at, SIZE - tick);
|
|
4500
|
-
} else {
|
|
4501
|
-
context.moveTo(SIZE, at);
|
|
4502
|
-
context.lineTo(SIZE - tick, at);
|
|
4503
|
-
}
|
|
4504
|
-
if (index % divisions === 0) {
|
|
4505
|
-
const label = String(index / divisions);
|
|
4506
|
-
if (horizontal) context.fillText(label, at + 2, 9);
|
|
4507
|
-
else {
|
|
4508
|
-
context.save();
|
|
4509
|
-
context.translate(9, at - 2);
|
|
4510
|
-
context.rotate(-Math.PI / 2);
|
|
4511
|
-
context.fillText(label, 0, 0);
|
|
4512
|
-
context.restore();
|
|
4513
|
-
}
|
|
4514
|
-
}
|
|
4515
|
-
}
|
|
4516
|
-
context.stroke();
|
|
4517
|
-
};
|
|
4518
|
-
paint(top, true);
|
|
4519
|
-
paint(left, false);
|
|
4774
|
+
const page = paper.getBoundingClientRect();
|
|
4775
|
+
const scale = String(96 * zoom);
|
|
4776
|
+
top.setAttribute("scale", scale);
|
|
4777
|
+
left.setAttribute("scale", scale);
|
|
4778
|
+
top.setAttribute("origin", String(page.left - base.left));
|
|
4779
|
+
left.setAttribute("origin", String(page.bottom - base.top));
|
|
4520
4780
|
};
|
|
4521
4781
|
const schedule = () => {
|
|
4522
4782
|
if (!visible || frame) return;
|
|
4523
|
-
frame = doc.defaultView?.requestAnimationFrame?.(
|
|
4524
|
-
if (!frame)
|
|
4783
|
+
frame = doc.defaultView?.requestAnimationFrame?.(place) ?? 0;
|
|
4784
|
+
if (!frame) place();
|
|
4525
4785
|
};
|
|
4526
4786
|
return {
|
|
4527
4787
|
element: area,
|
|
@@ -4905,8 +5165,6 @@ var ViewerChrome = class {
|
|
|
4905
5165
|
this.#root.addEventListener("click", (event) => {
|
|
4906
5166
|
const button = event.target?.closest?.("button");
|
|
4907
5167
|
if (!button || button.disabled) return;
|
|
4908
|
-
const tab = button.dataset.tab;
|
|
4909
|
-
if (tab) this.showTab(tab);
|
|
4910
5168
|
const action = button.dataset.chrome;
|
|
4911
5169
|
if (action === "inspector" || action === "shapes") this.togglePane(action);
|
|
4912
5170
|
if (action === "notes") this.reveal("notes");
|
|
@@ -4922,33 +5180,13 @@ var ViewerChrome = class {
|
|
|
4922
5180
|
event.stopPropagation();
|
|
4923
5181
|
this.#controller.setPage(Number(index));
|
|
4924
5182
|
}, options);
|
|
4925
|
-
this.#root.addEventListener("
|
|
4926
|
-
const key = event;
|
|
4927
|
-
const button = event.target?.closest?.("button");
|
|
4928
|
-
if (!button?.dataset.tab || ![
|
|
4929
|
-
"ArrowLeft",
|
|
4930
|
-
"ArrowRight",
|
|
4931
|
-
"Home",
|
|
4932
|
-
"End"
|
|
4933
|
-
].includes(key.key)) return;
|
|
4934
|
-
key.preventDefault();
|
|
4935
|
-
const tabs = [...this.#root.querySelectorAll("[data-tab]")];
|
|
4936
|
-
const index = tabs.indexOf(button);
|
|
4937
|
-
const next = key.key === "Home" ? tabs[0] : key.key === "End" ? tabs.at(-1) : tabs[(index + (key.key === "ArrowRight" ? 1 : -1) + tabs.length) % tabs.length];
|
|
4938
|
-
if (!next?.dataset.tab) return;
|
|
4939
|
-
this.showTab(next.dataset.tab);
|
|
4940
|
-
next.focus();
|
|
4941
|
-
}, options);
|
|
5183
|
+
this.#root.addEventListener("office-ribbon-select", () => this.closeCompactTools(), options);
|
|
4942
5184
|
this.#notes.addEventListener("toggle", () => this.#syncNotes(), options);
|
|
4943
5185
|
return () => events.abort();
|
|
4944
5186
|
}
|
|
4945
5187
|
showTab(tab) {
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
button.setAttribute("aria-selected", String(selected));
|
|
4949
|
-
button.tabIndex = selected ? 0 : -1;
|
|
4950
|
-
}
|
|
4951
|
-
for (const panel of this.#root.querySelectorAll(".ribbon-content")) panel.hidden = panel.id !== `${tab}-panel`;
|
|
5188
|
+
const ribbon = this.#root.querySelector("office-ui-ribbon");
|
|
5189
|
+
if (ribbon) ribbon.selected = tab;
|
|
4952
5190
|
}
|
|
4953
5191
|
/** On phones, close the Tools sheet once a command runs. */
|
|
4954
5192
|
closeCompactTools() {
|
|
@@ -6195,6 +6433,7 @@ var VISIO_ICONS = {
|
|
|
6195
6433
|
function registerViewerControls(registry) {
|
|
6196
6434
|
for (const [name, path] of Object.entries(VISIO_ICONS)) if (!getIcon(name)) registerIcon(name, path);
|
|
6197
6435
|
registerControls(registry);
|
|
6436
|
+
definePresence(registry);
|
|
6198
6437
|
}
|
|
6199
6438
|
//#endregion
|
|
6200
6439
|
//#region src/export-svg.ts
|
|
@@ -6814,6 +7053,8 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
6814
7053
|
#rulers;
|
|
6815
7054
|
#canvas;
|
|
6816
7055
|
#panZoom;
|
|
7056
|
+
#profile;
|
|
7057
|
+
#share;
|
|
6817
7058
|
#backstage;
|
|
6818
7059
|
#fileName = "";
|
|
6819
7060
|
#loadToken = 0;
|
|
@@ -6822,7 +7063,6 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
6822
7063
|
#diagnostics;
|
|
6823
7064
|
#toolbar;
|
|
6824
7065
|
#chrome;
|
|
6825
|
-
#search;
|
|
6826
7066
|
#edit;
|
|
6827
7067
|
#layers;
|
|
6828
7068
|
#notes;
|
|
@@ -6848,7 +7088,7 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
6848
7088
|
workspace.before(ribbon, this.#findBar);
|
|
6849
7089
|
workspace.prepend(createShapesStrip(document), createShapesWindow(document));
|
|
6850
7090
|
workspace.append(createPanZoom(document));
|
|
6851
|
-
this.#root.append(createBackstage(document), ...createContextMenus(document));
|
|
7091
|
+
this.#root.append(createBackstage(document), createOptionsDialog(document), ...createContextMenus(document));
|
|
6852
7092
|
workspace.after(createPageTabs(document), createStatusBar(document));
|
|
6853
7093
|
this.#viewport = this.#root.querySelector(".viewport");
|
|
6854
7094
|
this.#rulers = createRulers(this.#viewport);
|
|
@@ -6857,7 +7097,6 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
6857
7097
|
this.#status = this.#root.querySelector("[data-status]");
|
|
6858
7098
|
this.#diagnostics = this.#root.querySelector("[data-diagnostics]");
|
|
6859
7099
|
this.#toolbar = this.#root.querySelector(".toolbar");
|
|
6860
|
-
this.#search = searchControls(this.#root);
|
|
6861
7100
|
this.#edit = new ViewerEditControls(this.#root, this.controller);
|
|
6862
7101
|
this.#layers = this.#root.querySelector(".layer-controls");
|
|
6863
7102
|
this.#notes = this.#root.querySelector(".notes ul");
|
|
@@ -6875,15 +7114,15 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
6875
7114
|
togglePanZoom: () => this.#panZoom.toggle(),
|
|
6876
7115
|
focusSearch: () => {
|
|
6877
7116
|
this.#chrome.closeCompactTools();
|
|
6878
|
-
this.#findBar.
|
|
6879
|
-
this.#search.input.focus();
|
|
6880
|
-
this.#search.input.select();
|
|
7117
|
+
this.#findBar.show();
|
|
6881
7118
|
},
|
|
6882
7119
|
announce: (message) => {
|
|
6883
7120
|
this.#announcement = message;
|
|
6884
7121
|
this.#status.textContent = message;
|
|
6885
7122
|
}
|
|
6886
7123
|
});
|
|
7124
|
+
this.#profile = new ViewerProfile(this.#root);
|
|
7125
|
+
this.#share = new ViewerShare(this.#root, this.controller, () => this.#profile.profile);
|
|
6887
7126
|
this.#backstage = new ViewerBackstage({
|
|
6888
7127
|
root: this.#root,
|
|
6889
7128
|
viewport: this.#viewport,
|
|
@@ -6896,6 +7135,7 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
6896
7135
|
this.controller.setDocument(null);
|
|
6897
7136
|
},
|
|
6898
7137
|
revealNotes: () => this.#chrome.reveal("notes"),
|
|
7138
|
+
showOptions: () => this.#profile.showOptions(),
|
|
6899
7139
|
announce: (message) => {
|
|
6900
7140
|
this.#announcement = message;
|
|
6901
7141
|
this.#status.textContent = message;
|
|
@@ -7073,19 +7313,19 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
7073
7313
|
const disposeTellMe = wireTellMe(this.#root);
|
|
7074
7314
|
const keyTips = attachKeyTips(this.#root);
|
|
7075
7315
|
const disposePanZoom = this.#panZoom.wire();
|
|
7316
|
+
const disposeProfile = this.#profile.wire();
|
|
7317
|
+
const disposeShare = this.#share.wire();
|
|
7076
7318
|
const disposeRulers = this.#rulers.wire();
|
|
7077
7319
|
const disposeStencil = wireStencil(this.#root.querySelector(".shapes-pane"), this.#viewport, this.controller, (message) => {
|
|
7078
7320
|
this.#announcement = message;
|
|
7079
7321
|
this.#status.textContent = message;
|
|
7080
7322
|
});
|
|
7081
|
-
const disposeFind = wireFindBar(this.#findBar, this
|
|
7323
|
+
const disposeFind = wireFindBar(this.#findBar, this.controller, () => this.#viewport.focus({ preventScroll: true }));
|
|
7082
7324
|
const disposeEdit = this.#edit.wire();
|
|
7083
7325
|
const disposeLayers = wireLayerControls(this.#layers, this.controller);
|
|
7084
7326
|
const disposeInputs = wireViewerInputs({
|
|
7085
7327
|
viewport: this.#viewport,
|
|
7086
|
-
|
|
7087
|
-
zoomSlider: this.#zoomSlider,
|
|
7088
|
-
searchInput: this.#search.input
|
|
7328
|
+
zoomSlider: this.#zoomSlider
|
|
7089
7329
|
}, this.controller, (mode) => this.#fit(mode));
|
|
7090
7330
|
return () => {
|
|
7091
7331
|
disposeChrome();
|
|
@@ -7095,6 +7335,8 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
7095
7335
|
disposeTellMe();
|
|
7096
7336
|
keyTips.dispose();
|
|
7097
7337
|
disposePanZoom();
|
|
7338
|
+
disposeProfile();
|
|
7339
|
+
disposeShare();
|
|
7098
7340
|
disposeRulers();
|
|
7099
7341
|
disposeStencil();
|
|
7100
7342
|
disposeFind();
|
|
@@ -7117,7 +7359,7 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
7117
7359
|
const inches = (value) => `${+value.toFixed(3)} in`;
|
|
7118
7360
|
this.#shapeStatus.setAttribute("value", inspected ? `Width: ${inches(inspected.width)} Height: ${inches(inspected.height)}` : "");
|
|
7119
7361
|
for (const button of this.#root.querySelectorAll("[data-action]")) button.disabled = !page;
|
|
7120
|
-
|
|
7362
|
+
renderFindBar(this.#findBar, state);
|
|
7121
7363
|
this.#edit.render(state);
|
|
7122
7364
|
if (changed) renderLayerControls(this.#layers, state);
|
|
7123
7365
|
else this.#layers.querySelector("[data-layer-reset=\"all\"]").disabled = state.layerVisibilityOverrides.length === 0;
|