ooxml-core 1.22.0 → 1.23.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 +7 -2
- package/dist/automation/index.cjs +6 -4
- package/dist/automation/index.mjs +6 -4
- package/dist/collab/embedding.d.ts +7 -0
- package/dist/collab/embedding.d.ts.map +1 -1
- package/dist/collab/index.cjs +189 -0
- package/dist/collab/index.d.ts +2 -0
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.mjs +186 -1
- package/dist/collab/write-back-lifecycle.d.ts +33 -0
- package/dist/collab/write-back-lifecycle.d.ts.map +1 -0
- package/dist/collab/write-back.d.ts +75 -0
- package/dist/collab/write-back.d.ts.map +1 -0
- package/dist/visio/collab/baseline.d.ts +36 -0
- package/dist/visio/collab/baseline.d.ts.map +1 -0
- package/dist/visio/collab/bind.d.ts +20 -2
- package/dist/visio/collab/bind.d.ts.map +1 -1
- package/dist/visio/collab/compose-lists.d.ts +27 -0
- package/dist/visio/collab/compose-lists.d.ts.map +1 -0
- package/dist/visio/collab/compose.d.ts +6 -2
- package/dist/visio/collab/compose.d.ts.map +1 -1
- package/dist/visio/collab/fixups.d.ts +5 -0
- package/dist/visio/collab/fixups.d.ts.map +1 -0
- package/dist/visio/collab/index.cjs +1499 -362
- package/dist/visio/collab/index.d.ts +3 -2
- package/dist/visio/collab/index.d.ts.map +1 -1
- package/dist/visio/collab/index.mjs +1492 -363
- package/dist/visio/collab/keys.d.ts +30 -1
- package/dist/visio/collab/keys.d.ts.map +1 -1
- package/dist/visio/collab/package.d.ts +22 -1
- package/dist/visio/collab/package.d.ts.map +1 -1
- package/dist/visio/collab/pieces.d.ts +34 -0
- package/dist/visio/collab/pieces.d.ts.map +1 -0
- package/dist/visio/collab/read-ids.d.ts +29 -0
- package/dist/visio/collab/read-ids.d.ts.map +1 -0
- package/dist/visio/collab/read-parts.d.ts +34 -0
- package/dist/visio/collab/read-parts.d.ts.map +1 -0
- package/dist/visio/collab/read-shapes.d.ts +35 -0
- package/dist/visio/collab/read-shapes.d.ts.map +1 -0
- package/dist/visio/collab/read-util.d.ts +20 -0
- package/dist/visio/collab/read-util.d.ts.map +1 -0
- package/dist/visio/collab/read.d.ts +40 -19
- package/dist/visio/collab/read.d.ts.map +1 -1
- package/dist/visio/collab/schema.d.ts +55 -1
- package/dist/visio/collab/schema.d.ts.map +1 -1
- package/dist/visio/collab/snapshot-contents.d.ts +9 -0
- package/dist/visio/collab/snapshot-contents.d.ts.map +1 -0
- package/dist/visio/collab/snapshot-io.d.ts +26 -0
- package/dist/visio/collab/snapshot-io.d.ts.map +1 -0
- package/dist/visio/collab/snapshot-parts.d.ts +14 -0
- package/dist/visio/collab/snapshot-parts.d.ts.map +1 -0
- package/dist/visio/collab/snapshot.d.ts +31 -24
- package/dist/visio/collab/snapshot.d.ts.map +1 -1
- package/dist/visio/collab/write-parts.d.ts +8 -0
- package/dist/visio/collab/write-parts.d.ts.map +1 -0
- package/dist/visio/collab/write-shapes.d.ts +30 -0
- package/dist/visio/collab/write-shapes.d.ts.map +1 -0
- package/dist/visio/collab/write.d.ts +4 -16
- package/dist/visio/collab/write.d.ts.map +1 -1
- package/dist/visio/index.cjs +57 -4
- package/dist/visio/index.d.ts +1 -0
- package/dist/visio/index.d.ts.map +1 -1
- package/dist/visio/index.mjs +56 -5
- package/dist/visio/parse-incremental.d.ts +16 -0
- package/dist/visio/parse-incremental.d.ts.map +1 -0
- package/dist/visio/parser.d.ts +7 -0
- package/dist/visio/parser.d.ts.map +1 -1
- package/dist/visio/ui/collab-options.d.ts +10 -5
- package/dist/visio/ui/collab-options.d.ts.map +1 -1
- package/dist/visio/ui/index.cjs +6 -4
- package/dist/visio/ui/index.mjs +6 -4
- package/package.json +1 -1
|
@@ -3,6 +3,143 @@ import JSZip from 'jszip';
|
|
|
3
3
|
import { XMLSerializer, DOMParser } from '@xmldom/xmldom';
|
|
4
4
|
|
|
5
5
|
// visio/collab/bind.ts
|
|
6
|
+
|
|
7
|
+
// digest/sha256.ts
|
|
8
|
+
var K = new Uint32Array([
|
|
9
|
+
1116352408,
|
|
10
|
+
1899447441,
|
|
11
|
+
3049323471,
|
|
12
|
+
3921009573,
|
|
13
|
+
961987163,
|
|
14
|
+
1508970993,
|
|
15
|
+
2453635748,
|
|
16
|
+
2870763221,
|
|
17
|
+
3624381080,
|
|
18
|
+
310598401,
|
|
19
|
+
607225278,
|
|
20
|
+
1426881987,
|
|
21
|
+
1925078388,
|
|
22
|
+
2162078206,
|
|
23
|
+
2614888103,
|
|
24
|
+
3248222580,
|
|
25
|
+
3835390401,
|
|
26
|
+
4022224774,
|
|
27
|
+
264347078,
|
|
28
|
+
604807628,
|
|
29
|
+
770255983,
|
|
30
|
+
1249150122,
|
|
31
|
+
1555081692,
|
|
32
|
+
1996064986,
|
|
33
|
+
2554220882,
|
|
34
|
+
2821834349,
|
|
35
|
+
2952996808,
|
|
36
|
+
3210313671,
|
|
37
|
+
3336571891,
|
|
38
|
+
3584528711,
|
|
39
|
+
113926993,
|
|
40
|
+
338241895,
|
|
41
|
+
666307205,
|
|
42
|
+
773529912,
|
|
43
|
+
1294757372,
|
|
44
|
+
1396182291,
|
|
45
|
+
1695183700,
|
|
46
|
+
1986661051,
|
|
47
|
+
2177026350,
|
|
48
|
+
2456956037,
|
|
49
|
+
2730485921,
|
|
50
|
+
2820302411,
|
|
51
|
+
3259730800,
|
|
52
|
+
3345764771,
|
|
53
|
+
3516065817,
|
|
54
|
+
3600352804,
|
|
55
|
+
4094571909,
|
|
56
|
+
275423344,
|
|
57
|
+
430227734,
|
|
58
|
+
506948616,
|
|
59
|
+
659060556,
|
|
60
|
+
883997877,
|
|
61
|
+
958139571,
|
|
62
|
+
1322822218,
|
|
63
|
+
1537002063,
|
|
64
|
+
1747873779,
|
|
65
|
+
1955562222,
|
|
66
|
+
2024104815,
|
|
67
|
+
2227730452,
|
|
68
|
+
2361852424,
|
|
69
|
+
2428436474,
|
|
70
|
+
2756734187,
|
|
71
|
+
3204031479,
|
|
72
|
+
3329325298
|
|
73
|
+
]);
|
|
74
|
+
var IV = [
|
|
75
|
+
1779033703,
|
|
76
|
+
3144134277,
|
|
77
|
+
1013904242,
|
|
78
|
+
2773480762,
|
|
79
|
+
1359893119,
|
|
80
|
+
2600822924,
|
|
81
|
+
528734635,
|
|
82
|
+
1541459225
|
|
83
|
+
];
|
|
84
|
+
var W = new Uint32Array(64);
|
|
85
|
+
var rotr = (x, n) => x >>> n | x << 32 - n;
|
|
86
|
+
function compress(h, view, offset) {
|
|
87
|
+
for (let i = 0; i < 16; i++) W[i] = view.getUint32(offset + i * 4);
|
|
88
|
+
for (let i = 16; i < 64; i++) {
|
|
89
|
+
const a2 = W[i - 15];
|
|
90
|
+
const b2 = W[i - 2];
|
|
91
|
+
const s0 = rotr(a2, 7) ^ rotr(a2, 18) ^ a2 >>> 3;
|
|
92
|
+
const s1 = rotr(b2, 17) ^ rotr(b2, 19) ^ b2 >>> 10;
|
|
93
|
+
W[i] = W[i - 16] + s0 + W[i - 7] + s1 >>> 0;
|
|
94
|
+
}
|
|
95
|
+
let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], k = h[7];
|
|
96
|
+
for (let i = 0; i < 64; i++) {
|
|
97
|
+
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
98
|
+
const ch = e & f ^ ~e & g;
|
|
99
|
+
const t1 = k + S1 + ch + K[i] + W[i] >>> 0;
|
|
100
|
+
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
101
|
+
const maj = a & b ^ a & c ^ b & c;
|
|
102
|
+
const t2 = S0 + maj >>> 0;
|
|
103
|
+
k = g;
|
|
104
|
+
g = f;
|
|
105
|
+
f = e;
|
|
106
|
+
e = d + t1 >>> 0;
|
|
107
|
+
d = c;
|
|
108
|
+
c = b;
|
|
109
|
+
b = a;
|
|
110
|
+
a = t1 + t2 >>> 0;
|
|
111
|
+
}
|
|
112
|
+
h[0] = h[0] + a >>> 0;
|
|
113
|
+
h[1] = h[1] + b >>> 0;
|
|
114
|
+
h[2] = h[2] + c >>> 0;
|
|
115
|
+
h[3] = h[3] + d >>> 0;
|
|
116
|
+
h[4] = h[4] + e >>> 0;
|
|
117
|
+
h[5] = h[5] + f >>> 0;
|
|
118
|
+
h[6] = h[6] + g >>> 0;
|
|
119
|
+
h[7] = h[7] + k >>> 0;
|
|
120
|
+
}
|
|
121
|
+
function pad64(data) {
|
|
122
|
+
const padded = new Uint8Array(Math.ceil((data.length + 9) / 64) * 64);
|
|
123
|
+
padded.set(data);
|
|
124
|
+
padded[data.length] = 128;
|
|
125
|
+
const bits = data.length * 8;
|
|
126
|
+
const view = new DataView(padded.buffer);
|
|
127
|
+
view.setUint32(padded.length - 8, Math.floor(bits / 4294967296));
|
|
128
|
+
view.setUint32(padded.length - 4, bits >>> 0);
|
|
129
|
+
return view;
|
|
130
|
+
}
|
|
131
|
+
function wordsOut(h) {
|
|
132
|
+
const out = new Uint8Array(h.length * 4);
|
|
133
|
+
const view = new DataView(out.buffer);
|
|
134
|
+
for (let i = 0; i < h.length; i++) view.setUint32(i * 4, h[i]);
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
function sha256(data) {
|
|
138
|
+
const h = new Uint32Array(IV);
|
|
139
|
+
const view = pad64(data);
|
|
140
|
+
for (let offset = 0; offset < view.byteLength; offset += 64) compress(h, view, offset);
|
|
141
|
+
return wordsOut(h);
|
|
142
|
+
}
|
|
6
143
|
var DEFAULT_XML_LIMITS = {
|
|
7
144
|
maxDepth: 512,
|
|
8
145
|
maxNodes: 5e6
|
|
@@ -253,11 +390,51 @@ function stripPageOverrides(xml) {
|
|
|
253
390
|
(tag) => attrOf(tag, "ContentType") === PAGE_CONTENT_TYPE ? "" : tag
|
|
254
391
|
);
|
|
255
392
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
393
|
+
var withPageOverrides = (xml, pagePaths) => withOverrides(stripPageOverrides(xml), PAGE_CONTENT_TYPE, pagePaths);
|
|
394
|
+
var MASTER_TYPE = "http://schemas.microsoft.com/visio/2010/relationships/master";
|
|
395
|
+
var MASTER_CONTENT_TYPE = "application/vnd.ms-visio.master+xml";
|
|
396
|
+
function withOverrides(xml, contentType, paths) {
|
|
397
|
+
const add = paths.map((path) => `<Override PartName="/${path}" ContentType="${contentType}"/>`).join("");
|
|
398
|
+
const close = xml.lastIndexOf("</");
|
|
399
|
+
return close < 0 ? xml : xml.slice(0, close) + add + xml.slice(close);
|
|
400
|
+
}
|
|
401
|
+
function stripOverrides(xml, types, parts = /* @__PURE__ */ new Set()) {
|
|
402
|
+
return xml.replace(/<(?:\w+:)?Override\b[^>]*>/g, (tag) => {
|
|
403
|
+
const type = attrOf(tag, "ContentType");
|
|
404
|
+
const name = attrOf(tag, "PartName");
|
|
405
|
+
return type !== void 0 && types.includes(type) || name !== void 0 && parts.has(name.replace(/^\//, "")) ? "" : tag;
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
function declaredType(xml, path) {
|
|
409
|
+
for (const tag of xml.matchAll(/<(?:\w+:)?Override\b[^>]*>/g)) {
|
|
410
|
+
const name = attrOf(tag[0], "PartName");
|
|
411
|
+
const type = attrOf(tag[0], "ContentType");
|
|
412
|
+
if (name === `/${path}` && type !== void 0) return { type, byDefault: false };
|
|
413
|
+
}
|
|
414
|
+
const ext = /\.([^./]+)$/.exec(path)?.[1]?.toLowerCase();
|
|
415
|
+
if (ext === void 0) return void 0;
|
|
416
|
+
for (const tag of xml.matchAll(/<(?:\w+:)?Default\b[^>]*>/g)) {
|
|
417
|
+
const e = attrOf(tag[0], "Extension");
|
|
418
|
+
const type = attrOf(tag[0], "ContentType");
|
|
419
|
+
if (e?.toLowerCase() === ext && type !== void 0) return { type, byDefault: true };
|
|
420
|
+
}
|
|
421
|
+
return void 0;
|
|
422
|
+
}
|
|
423
|
+
function ensureType(xml, path, declared) {
|
|
424
|
+
if (declaredType(xml, path)) return xml;
|
|
425
|
+
const close = xml.lastIndexOf("</");
|
|
426
|
+
if (close < 0) return xml;
|
|
427
|
+
const ext = /\.([^./]+)$/.exec(path)?.[1];
|
|
428
|
+
const tag = declared.byDefault && ext ? `<Default Extension="${ext}" ContentType="${declared.type}"/>` : `<Override PartName="/${path}" ContentType="${declared.type}"/>`;
|
|
429
|
+
return xml.slice(0, close) + tag + xml.slice(close);
|
|
430
|
+
}
|
|
431
|
+
var isMediaPart = (path) => /(^|\/)media\/[^/]+$/i.test(path);
|
|
432
|
+
function relativeTarget(dir, path) {
|
|
433
|
+
const from = dir ? dir.split("/") : [];
|
|
434
|
+
const to = path.split("/");
|
|
435
|
+
let i = 0;
|
|
436
|
+
while (i < from.length && i < to.length - 1 && from[i] === to[i]) i++;
|
|
437
|
+
return [...from.slice(i).map(() => ".."), ...to.slice(i)].join("/");
|
|
261
438
|
}
|
|
262
439
|
function toBase64(bytes) {
|
|
263
440
|
let out = "";
|
|
@@ -291,15 +468,154 @@ function canon(xml) {
|
|
|
291
468
|
canonCache.set(xml, result);
|
|
292
469
|
return result;
|
|
293
470
|
}
|
|
471
|
+
function contentHash(bytes) {
|
|
472
|
+
let out = "";
|
|
473
|
+
for (const byte of sha256(bytes)) out += byte.toString(16).padStart(2, "0");
|
|
474
|
+
return out;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// visio/collab/pieces.ts
|
|
478
|
+
var seg = (value) => value.replace(/[%/]/g, (c) => c === "%" ? "%25" : "%2F");
|
|
479
|
+
var tagName = (open) => /^<([^\s/>]+)/.exec(open)?.[1] ?? "Shape";
|
|
480
|
+
var openTagOf = (text, span) => {
|
|
481
|
+
const tag = text.slice(span.start, span.openEnd);
|
|
482
|
+
return span.selfClosing ? tag.replace(/\s*\/>$/, ">") : tag;
|
|
483
|
+
};
|
|
484
|
+
var closeTagOf = (open) => `</${tagName(open)}>`;
|
|
485
|
+
function splitShape(xml) {
|
|
486
|
+
const box = scanContainer(xml, "Shape");
|
|
487
|
+
if (!box) return void 0;
|
|
488
|
+
const used = /* @__PURE__ */ new Set();
|
|
489
|
+
const unique = (path) => {
|
|
490
|
+
let out = path;
|
|
491
|
+
for (let n = 2; used.has(out); n++) out = `${path}~${n}`;
|
|
492
|
+
used.add(out);
|
|
493
|
+
return out;
|
|
494
|
+
};
|
|
495
|
+
const pieces = [];
|
|
496
|
+
const nested = [];
|
|
497
|
+
const others = /* @__PURE__ */ new Map();
|
|
498
|
+
const other = (parent, name, text) => {
|
|
499
|
+
const k = others.get(parent + name) ?? 0;
|
|
500
|
+
others.set(parent + name, k + 1);
|
|
501
|
+
pieces.push({
|
|
502
|
+
path: unique(`${parent ? `${parent}/` : ""}x/${name}#${k}`),
|
|
503
|
+
parent,
|
|
504
|
+
kind: "leaf",
|
|
505
|
+
text
|
|
506
|
+
});
|
|
507
|
+
};
|
|
508
|
+
const cell = (parent, text) => {
|
|
509
|
+
const n = attrOf(text.slice(0, text.search(/>/) + 1), "N");
|
|
510
|
+
if (n === void 0) return other(parent, "Cell", text);
|
|
511
|
+
pieces.push({
|
|
512
|
+
path: unique(`${parent ? `${parent}/` : ""}c/${seg(n)}`),
|
|
513
|
+
parent,
|
|
514
|
+
kind: "leaf",
|
|
515
|
+
text
|
|
516
|
+
});
|
|
517
|
+
};
|
|
518
|
+
for (const child of box.children) {
|
|
519
|
+
const text = xml.slice(child.start, child.end);
|
|
520
|
+
if (child.name === "Cell") cell("", text);
|
|
521
|
+
else if (child.name === "Shapes") {
|
|
522
|
+
const list = scanContainer(text, "Shapes");
|
|
523
|
+
for (const s of list?.children ?? [])
|
|
524
|
+
if (s.name === "Shape") nested.push(text.slice(s.start, s.end));
|
|
525
|
+
} else if (child.name === "Section") {
|
|
526
|
+
const head = openTagOf(xml, child);
|
|
527
|
+
const n = attrOf(head, "N");
|
|
528
|
+
const ix = attrOf(head, "IX");
|
|
529
|
+
if (n === void 0 && ix === void 0) {
|
|
530
|
+
other("", "Section", text);
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
const sec = unique(`s/${seg(n ?? "")}${ix !== void 0 ? `:${seg(ix)}` : ""}`);
|
|
534
|
+
pieces.push({ path: sec, parent: "", kind: "open", text: head });
|
|
535
|
+
const inner = scanContainer(text, "Section");
|
|
536
|
+
let rowIndex = 0;
|
|
537
|
+
for (const part of inner?.children ?? []) {
|
|
538
|
+
const sub = text.slice(part.start, part.end);
|
|
539
|
+
if (part.name === "Cell") cell(sec, sub);
|
|
540
|
+
else if (part.name === "Row") {
|
|
541
|
+
const rowHead = openTagOf(text, part);
|
|
542
|
+
const id = attrOf(rowHead, "IX") ?? attrOf(rowHead, "N") ?? `#${rowIndex}`;
|
|
543
|
+
rowIndex++;
|
|
544
|
+
const row = unique(`${sec}/r/${seg(id)}`);
|
|
545
|
+
pieces.push({ path: row, parent: sec, kind: "open", text: rowHead });
|
|
546
|
+
for (const rc of scanContainer(sub, "Row")?.children ?? [])
|
|
547
|
+
if (rc.name === "Cell") cell(row, sub.slice(rc.start, rc.end));
|
|
548
|
+
else other(row, rc.name, sub.slice(rc.start, rc.end));
|
|
549
|
+
} else other(sec, part.name, sub);
|
|
550
|
+
}
|
|
551
|
+
} else other("", child.name, text);
|
|
552
|
+
}
|
|
553
|
+
return { open: openTagOf(xml, box), pieces, nested };
|
|
554
|
+
}
|
|
555
|
+
function buildShape(open, entries, tail) {
|
|
556
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
557
|
+
for (const [path, entry] of entries) {
|
|
558
|
+
const parent = parentOf(path);
|
|
559
|
+
const list = byParent.get(parent) ?? [];
|
|
560
|
+
list.push({ path, entry });
|
|
561
|
+
byParent.set(parent, list);
|
|
562
|
+
}
|
|
563
|
+
const render = (parent) => (byParent.get(parent) ?? []).sort((a, b) => a.entry.pos - b.entry.pos || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)).map(
|
|
564
|
+
({ path, entry }) => entry.open !== void 0 ? entry.open + render(path) + closeTagOf(entry.open) : entry.xml ?? ""
|
|
565
|
+
).join("");
|
|
566
|
+
return open + render("") + tail + closeTagOf(open);
|
|
567
|
+
}
|
|
568
|
+
function parentOf(path) {
|
|
569
|
+
const parts = path.split("/");
|
|
570
|
+
return parts.length <= 2 ? "" : parts.slice(0, -2).join("/");
|
|
571
|
+
}
|
|
572
|
+
var SIMPLE = /^<([^\s/>]+)((?:\s+[^\s=/>]+\s*=\s*(?:"[^"]*"|'[^']*'))*)\s*(?:\/>|>([^<]*)<\/\1>)$/;
|
|
573
|
+
var ATTR = /\s([^\s=/>]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
574
|
+
function pieceContent(kind, text) {
|
|
575
|
+
const simple = SIMPLE.exec(kind === "open" ? `${text}</${tagName(text)}>` : text);
|
|
576
|
+
if (!simple) return kind === "open" ? canon(`${text}</${tagName(text)}>`) : canon(text);
|
|
577
|
+
const attrs = [...(simple[2] ?? "").matchAll(ATTR)].map((m) => [m[1], m[2] ?? m[3] ?? ""]).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
578
|
+
return JSON.stringify([simple[1], attrs, simple[3] ?? ""]);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// visio/collab/baseline.ts
|
|
582
|
+
var masterScope = (key) => `m~${key}`;
|
|
583
|
+
var pageId = (key) => `p:${key}`;
|
|
584
|
+
var bodyId = (key) => `b:${key}`;
|
|
585
|
+
var shapeId = (page, key) => `s:${page}/${key}`;
|
|
586
|
+
var cellId = (page, shape, path) => `f:${page}/${shape}/${path}`;
|
|
587
|
+
var connectId = (key) => `c:${key}`;
|
|
588
|
+
var masterId = (key) => `m:${key}`;
|
|
589
|
+
var mediaId = (key) => `i:${key}`;
|
|
590
|
+
var pageContent = (e) => JSON.stringify([e.id, e.back ?? null, canon(e.xml)]);
|
|
591
|
+
var bodyContent = (e) => JSON.stringify([canon(e.shell), e.rels ?? null]);
|
|
592
|
+
var shellContent = (e) => JSON.stringify([e.parent ?? null, pieceContent("open", e.open)]);
|
|
593
|
+
var entryContent = (e) => e.xml !== void 0 ? pieceContent("leaf", e.xml) : pieceContent("open", e.open ?? "");
|
|
594
|
+
var masterContent = (e) => JSON.stringify([e.id, canon(e.xml), e.rels ?? null, e.print]);
|
|
294
595
|
|
|
295
596
|
// visio/collab/schema.ts
|
|
296
|
-
var SCHEMA_VERSION =
|
|
597
|
+
var SCHEMA_VERSION = 3;
|
|
598
|
+
var SchemaVersionError = class extends Error {
|
|
599
|
+
constructor(found) {
|
|
600
|
+
super(
|
|
601
|
+
`The shared drawing uses schema version ${String(found)}; this build reads version ${SCHEMA_VERSION}.`
|
|
602
|
+
);
|
|
603
|
+
this.found = found;
|
|
604
|
+
this.name = "SchemaVersionError";
|
|
605
|
+
}
|
|
606
|
+
found;
|
|
607
|
+
};
|
|
297
608
|
var META = "visio:meta";
|
|
298
609
|
var PAGES = "visio:pages";
|
|
299
610
|
var BODIES = "visio:bodies";
|
|
300
611
|
var SHAPES = "visio:shapes";
|
|
612
|
+
var CELLS = "visio:cells";
|
|
301
613
|
var CONNECTS = "visio:connects";
|
|
302
614
|
var DEAD = "visio:dead";
|
|
615
|
+
var MASTERS = "visio:masters";
|
|
616
|
+
var RENUM = "visio:renum";
|
|
617
|
+
var MEDIA = "visio:media";
|
|
618
|
+
var BLOBS = "visio:blobs";
|
|
303
619
|
var PARTS = "visio:parts";
|
|
304
620
|
var REL_MARK = "<!--@rel-->";
|
|
305
621
|
var SHAPES_MARK = "<!--@shapes-->";
|
|
@@ -310,8 +626,13 @@ function sharedDrawing(doc) {
|
|
|
310
626
|
pages: doc.getMap(PAGES),
|
|
311
627
|
bodies: doc.getMap(BODIES),
|
|
312
628
|
shapes: doc.getMap(SHAPES),
|
|
629
|
+
cells: doc.getMap(CELLS),
|
|
313
630
|
connects: doc.getMap(CONNECTS),
|
|
314
631
|
dead: doc.getMap(DEAD),
|
|
632
|
+
masters: doc.getMap(MASTERS),
|
|
633
|
+
renum: doc.getMap(RENUM),
|
|
634
|
+
media: doc.getMap(MEDIA),
|
|
635
|
+
blobs: doc.getMap(BLOBS),
|
|
315
636
|
parts: doc.getMap(PARTS)
|
|
316
637
|
};
|
|
317
638
|
}
|
|
@@ -320,17 +641,27 @@ var sharedTypes = (shared) => [
|
|
|
320
641
|
shared.pages,
|
|
321
642
|
shared.bodies,
|
|
322
643
|
shared.shapes,
|
|
644
|
+
shared.cells,
|
|
323
645
|
shared.connects,
|
|
324
646
|
shared.dead,
|
|
647
|
+
shared.masters,
|
|
648
|
+
shared.renum,
|
|
649
|
+
shared.media,
|
|
650
|
+
shared.blobs,
|
|
325
651
|
shared.parts
|
|
326
652
|
];
|
|
327
653
|
var isSharedDrawingEmpty = (shared) => shared.pages.size === 0 && shared.meta.get("v") === void 0;
|
|
654
|
+
function assertSchemaVersion(shared) {
|
|
655
|
+
const v = shared.meta.get("v");
|
|
656
|
+
if (v !== void 0 && v !== SCHEMA_VERSION) throw new SchemaVersionError(v);
|
|
657
|
+
}
|
|
328
658
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
329
659
|
function sameRecord(a, b) {
|
|
330
660
|
if (!isRecord(a) || !isRecord(b)) return a === b;
|
|
331
661
|
const ka = Object.keys(a).filter((k) => a[k] !== void 0);
|
|
332
662
|
const kb = Object.keys(b).filter((k) => b[k] !== void 0);
|
|
333
|
-
|
|
663
|
+
const same = (x, y) => x === y || Array.isArray(x) && Array.isArray(y) && JSON.stringify(x) === JSON.stringify(y);
|
|
664
|
+
return ka.length === kb.length && ka.every((k) => same(a[k], b[k]));
|
|
334
665
|
}
|
|
335
666
|
function setIfChanged(map, key, value) {
|
|
336
667
|
if (sameRecord(map.get(key), value)) return false;
|
|
@@ -339,27 +670,53 @@ function setIfChanged(map, key, value) {
|
|
|
339
670
|
}
|
|
340
671
|
var str = (value) => typeof value === "string" ? value : void 0;
|
|
341
672
|
var num = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
673
|
+
var opt = (key, value) => value === void 0 ? {} : { [key]: value };
|
|
342
674
|
function pageEntry(value) {
|
|
343
675
|
if (!isRecord(value)) return void 0;
|
|
344
676
|
const pos = num(value.pos);
|
|
345
677
|
const id = str(value.id);
|
|
346
678
|
const xml = str(value.xml);
|
|
347
679
|
if (pos === void 0 || id === void 0 || xml === void 0) return void 0;
|
|
348
|
-
|
|
349
|
-
return { pos, id, xml, ...back !== void 0 ? { back } : {} };
|
|
680
|
+
return { pos, id, xml, ...opt("back", str(value.back)) };
|
|
350
681
|
}
|
|
351
682
|
function bodyEntry(value) {
|
|
352
683
|
if (!isRecord(value)) return void 0;
|
|
353
684
|
const shell = str(value.shell);
|
|
354
685
|
if (shell === void 0) return void 0;
|
|
355
|
-
|
|
356
|
-
return { shell, ...rels !== void 0 ? { rels } : {} };
|
|
686
|
+
return { shell, ...opt("rels", str(value.rels)), ...opt("b", str(value.b)) };
|
|
357
687
|
}
|
|
358
688
|
function shapeEntry(value) {
|
|
689
|
+
if (!isRecord(value)) return void 0;
|
|
690
|
+
const pos = num(value.pos);
|
|
691
|
+
const open = str(value.open);
|
|
692
|
+
if (pos === void 0 || open === void 0) return void 0;
|
|
693
|
+
return { pos, open, ...opt("parent", str(value.parent)), ...opt("b", str(value.b)) };
|
|
694
|
+
}
|
|
695
|
+
function cellEntry(value) {
|
|
359
696
|
if (!isRecord(value)) return void 0;
|
|
360
697
|
const pos = num(value.pos);
|
|
361
698
|
const xml = str(value.xml);
|
|
362
|
-
|
|
699
|
+
const open = str(value.open);
|
|
700
|
+
if (pos === void 0 || xml === void 0 && open === void 0) return void 0;
|
|
701
|
+
return { pos, ...opt("xml", xml), ...opt("open", xml === void 0 ? open : void 0) };
|
|
702
|
+
}
|
|
703
|
+
function masterEntry(value) {
|
|
704
|
+
if (!isRecord(value)) return void 0;
|
|
705
|
+
const pos = num(value.pos);
|
|
706
|
+
const id = str(value.id);
|
|
707
|
+
const xml = str(value.xml);
|
|
708
|
+
const part = str(value.part);
|
|
709
|
+
if (pos === void 0 || id === void 0 || xml === void 0 || part === void 0)
|
|
710
|
+
return void 0;
|
|
711
|
+
return { pos, id, xml, part, ...opt("rels", str(value.rels)), ...opt("b", str(value.b)) };
|
|
712
|
+
}
|
|
713
|
+
function mediaEntry(value) {
|
|
714
|
+
if (!isRecord(value)) return void 0;
|
|
715
|
+
const path = str(value.path);
|
|
716
|
+
const hash = str(value.hash);
|
|
717
|
+
const ct = str(value.ct);
|
|
718
|
+
if (path === void 0 || hash === void 0 || ct === void 0) return void 0;
|
|
719
|
+
return { path, hash, ct, d: value.d === true, ...opt("b", str(value.b)) };
|
|
363
720
|
}
|
|
364
721
|
function connectEntry(value) {
|
|
365
722
|
if (!isRecord(value)) return void 0;
|
|
@@ -371,11 +728,15 @@ function connectEntry(value) {
|
|
|
371
728
|
}
|
|
372
729
|
return out;
|
|
373
730
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
731
|
+
function renumEntry(value) {
|
|
732
|
+
if (!isRecord(value)) return void 0;
|
|
733
|
+
const pair = (v) => Array.isArray(v) && v.length === 2 && typeof v[0] === "string" && typeof v[1] === "string" ? [v[0], v[1]] : void 0;
|
|
734
|
+
const i = pair(value.i);
|
|
735
|
+
const m = pair(value.m);
|
|
736
|
+
return i || m ? { ...i ? { i } : {}, ...m ? { m } : {} } : void 0;
|
|
378
737
|
}
|
|
738
|
+
|
|
739
|
+
// visio/collab/snapshot-contents.ts
|
|
379
740
|
function splitList(text, name, mark, child) {
|
|
380
741
|
const box = scanContainer(text, name);
|
|
381
742
|
if (!box) return { text, items: [] };
|
|
@@ -391,6 +752,46 @@ function splitList(text, name, mark, child) {
|
|
|
391
752
|
}
|
|
392
753
|
return { text: text.slice(0, box.openEnd) + mark + text.slice(box.closeStart), items };
|
|
393
754
|
}
|
|
755
|
+
function flatten(xml, parent, page, keys, out) {
|
|
756
|
+
const split2 = splitShape(xml);
|
|
757
|
+
const id = split2 ? attrOf(split2.open, "ID") : void 0;
|
|
758
|
+
if (!split2 || id === void 0) return;
|
|
759
|
+
const key = keys.shapeKey(page, id);
|
|
760
|
+
out.push({
|
|
761
|
+
key,
|
|
762
|
+
id,
|
|
763
|
+
...parent !== void 0 ? { parent } : {},
|
|
764
|
+
open: split2.open,
|
|
765
|
+
pieces: split2.pieces
|
|
766
|
+
});
|
|
767
|
+
for (const nested of split2.nested) flatten(nested, key, page, keys, out);
|
|
768
|
+
}
|
|
769
|
+
function splitContents(content, scope, keys) {
|
|
770
|
+
const shapesSplit = splitList(content, "Shapes", SHAPES_MARK, "Shape");
|
|
771
|
+
const connectsSplit = splitList(shapesSplit.text, "Connects", CONNECTS_MARK, "Connect");
|
|
772
|
+
const shapes = [];
|
|
773
|
+
for (const text of shapesSplit.items) flatten(text, void 0, scope, keys, shapes);
|
|
774
|
+
const owner = new Map(shapes.map((s) => [s.id, s.key]));
|
|
775
|
+
const connects = [];
|
|
776
|
+
for (const text of connectsSplit.items) {
|
|
777
|
+
const a = (name) => attrOf(text, name) ?? "";
|
|
778
|
+
const entry = {
|
|
779
|
+
fk: owner.get(a("FromSheet")) ?? "",
|
|
780
|
+
fi: a("FromSheet"),
|
|
781
|
+
tk: owner.get(a("ToSheet")) ?? "",
|
|
782
|
+
ti: a("ToSheet"),
|
|
783
|
+
fc: a("FromCell"),
|
|
784
|
+
tc: a("ToCell"),
|
|
785
|
+
fp: a("FromPart"),
|
|
786
|
+
tp: a("ToPart")
|
|
787
|
+
};
|
|
788
|
+
connects.push({
|
|
789
|
+
key: `${scope}/${entry.fk}.${entry.fi}.${entry.fc}.${entry.fp}>${entry.tk}.${entry.ti}.${entry.tc}.${entry.tp}`,
|
|
790
|
+
entry
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
return { shell: connectsSplit.text, shapes, connects };
|
|
794
|
+
}
|
|
394
795
|
var readZip = (bytes) => JSZip.loadAsync(bytes);
|
|
395
796
|
var zipText = async (zip, path) => zip.file(path)?.async("string");
|
|
396
797
|
async function readLayout(zip) {
|
|
@@ -401,19 +802,25 @@ async function readLayout(zip) {
|
|
|
401
802
|
const documentPath = resolveTarget("", root.target);
|
|
402
803
|
const rels = parseRelationships(await zipText(zip, relsPathOf(documentPath)));
|
|
403
804
|
const pages = rels.find((r) => r.type.endsWith("/pages"));
|
|
404
|
-
|
|
805
|
+
const masters = rels.find((r) => r.type.endsWith("/masters"));
|
|
806
|
+
const dir = dirName(documentPath);
|
|
807
|
+
return pages ? {
|
|
808
|
+
documentPath,
|
|
809
|
+
pagesPath: resolveTarget(dir, pages.target),
|
|
810
|
+
...masters ? { mastersPath: resolveTarget(dir, masters.target) } : {}
|
|
811
|
+
} : void 0;
|
|
405
812
|
}
|
|
406
|
-
async function
|
|
407
|
-
const box = scanContainer(
|
|
813
|
+
async function readLocalItems(zip, listPath, xml, container, child) {
|
|
814
|
+
const box = scanContainer(xml, container);
|
|
408
815
|
if (!box) return void 0;
|
|
409
816
|
const rels = new Map(
|
|
410
|
-
parseRelationships(await zipText(zip, relsPathOf(
|
|
817
|
+
parseRelationships(await zipText(zip, relsPathOf(listPath))).map((r) => [r.id, r])
|
|
411
818
|
);
|
|
412
|
-
const
|
|
819
|
+
const items = [];
|
|
413
820
|
for (const span of box.children) {
|
|
414
|
-
if (span.name !==
|
|
415
|
-
const text =
|
|
416
|
-
const inner = scanContainer(text,
|
|
821
|
+
if (span.name !== child) continue;
|
|
822
|
+
const text = xml.slice(span.start, span.end);
|
|
823
|
+
const inner = scanContainer(text, child);
|
|
417
824
|
const relSpan = inner?.children.find((c) => c.name === "Rel");
|
|
418
825
|
if (!inner || !relSpan) return void 0;
|
|
419
826
|
const relTag = text.slice(relSpan.start, relSpan.openEnd);
|
|
@@ -421,239 +828,194 @@ async function readLocalPages(zip, layout, pagesXml) {
|
|
|
421
828
|
const target = rid ? rels.get(rid)?.target : void 0;
|
|
422
829
|
const id = attrOf(text.slice(0, inner.openEnd), "ID");
|
|
423
830
|
if (target === void 0 || id === void 0) return void 0;
|
|
424
|
-
|
|
831
|
+
items.push({
|
|
425
832
|
id,
|
|
426
833
|
text,
|
|
427
|
-
path: resolveTarget(dirName(
|
|
834
|
+
path: resolveTarget(dirName(listPath), target),
|
|
428
835
|
rel: { start: relSpan.start, end: relSpan.end }
|
|
429
836
|
});
|
|
430
837
|
}
|
|
431
|
-
return { box,
|
|
838
|
+
return { box, items };
|
|
839
|
+
}
|
|
840
|
+
var withMark = (item) => item.text.slice(0, item.rel.start) + REL_MARK + item.text.slice(item.rel.end);
|
|
841
|
+
|
|
842
|
+
// visio/collab/snapshot-parts.ts
|
|
843
|
+
async function snapshotMasters(zip, layout, keys, derived) {
|
|
844
|
+
const masters = [];
|
|
845
|
+
let mastersOpen;
|
|
846
|
+
let mastersClose;
|
|
847
|
+
if (layout.mastersPath) {
|
|
848
|
+
const listXml = await zipText(zip, layout.mastersPath) ?? "";
|
|
849
|
+
const list = await readLocalItems(zip, layout.mastersPath, listXml, "Masters", "Master");
|
|
850
|
+
if (list) {
|
|
851
|
+
derived.add(layout.mastersPath).add(relsPathOf(layout.mastersPath));
|
|
852
|
+
mastersOpen = listXml.slice(0, list.box.openEnd);
|
|
853
|
+
mastersClose = listXml.slice(list.box.closeStart);
|
|
854
|
+
for (const item of list.items) {
|
|
855
|
+
const content = await zipText(zip, item.path);
|
|
856
|
+
if (content === void 0) continue;
|
|
857
|
+
derived.add(item.path).add(relsPathOf(item.path));
|
|
858
|
+
const key = keys.masterKey(item.id);
|
|
859
|
+
keys.masterPaths.set(key, item.path);
|
|
860
|
+
const rels = await zipText(zip, relsPathOf(item.path));
|
|
861
|
+
const { shell, shapes, connects } = splitContents(content, masterScope(key), keys);
|
|
862
|
+
masters.push({
|
|
863
|
+
key,
|
|
864
|
+
id: item.id,
|
|
865
|
+
xml: withMark(item),
|
|
866
|
+
path: item.path,
|
|
867
|
+
part: encoder.encode(shell),
|
|
868
|
+
...rels !== void 0 ? { rels } : {},
|
|
869
|
+
shapes,
|
|
870
|
+
connects
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return { masters, mastersOpen, mastersClose };
|
|
876
|
+
}
|
|
877
|
+
async function snapshotRest(zip, derived, limit) {
|
|
878
|
+
const parts = /* @__PURE__ */ new Map();
|
|
879
|
+
const media = [];
|
|
880
|
+
const typesXml = await zipText(zip, CONTENT_TYPES) ?? "";
|
|
881
|
+
const mediaPaths = /* @__PURE__ */ new Set();
|
|
882
|
+
let total = 0;
|
|
883
|
+
for (const path of Object.keys(zip.files)) {
|
|
884
|
+
const file = zip.files[path];
|
|
885
|
+
if (file.dir || derived.has(path) || isLocalOnlyPart(path)) continue;
|
|
886
|
+
const data = await file.async("uint8array");
|
|
887
|
+
total += data.length;
|
|
888
|
+
if (total > limit) throw new Error("The package parts exceed the shared size limit.");
|
|
889
|
+
const declared = isMediaPart(path) ? declaredType(typesXml, path) : void 0;
|
|
890
|
+
if (declared) {
|
|
891
|
+
mediaPaths.add(path);
|
|
892
|
+
media.push({
|
|
893
|
+
path,
|
|
894
|
+
hash: contentHash(data),
|
|
895
|
+
ct: declared.type,
|
|
896
|
+
d: declared.byDefault,
|
|
897
|
+
data
|
|
898
|
+
});
|
|
899
|
+
} else parts.set(path, data);
|
|
900
|
+
}
|
|
901
|
+
const types = parts.get(CONTENT_TYPES);
|
|
902
|
+
if (types)
|
|
903
|
+
parts.set(
|
|
904
|
+
CONTENT_TYPES,
|
|
905
|
+
encoder.encode(
|
|
906
|
+
stripOverrides(decoder.decode(types), [PAGE_CONTENT_TYPE, MASTER_CONTENT_TYPE], mediaPaths)
|
|
907
|
+
)
|
|
908
|
+
);
|
|
909
|
+
return { parts, media };
|
|
432
910
|
}
|
|
911
|
+
|
|
912
|
+
// visio/collab/snapshot.ts
|
|
913
|
+
var DEFAULT_MAX_PART_BYTES = 48 * 1024 * 1024;
|
|
433
914
|
async function snapshotDrawing(bytes, keys, options = {}) {
|
|
434
915
|
const zip = await readZip(bytes);
|
|
435
916
|
const layout = await readLayout(zip);
|
|
436
917
|
if (!layout) throw new Error("The package has no Visio pages part.");
|
|
437
918
|
const pagesXml = await zipText(zip, layout.pagesPath) ?? "";
|
|
438
|
-
const local = await
|
|
919
|
+
const local = await readLocalItems(zip, layout.pagesPath, pagesXml, "Pages", "Page");
|
|
439
920
|
if (!local) throw new Error("The pages part cannot be split into pages.");
|
|
440
921
|
const derived = /* @__PURE__ */ new Set([layout.pagesPath, relsPathOf(layout.pagesPath)]);
|
|
441
|
-
const idToKey = new Map(local.
|
|
922
|
+
const idToKey = new Map(local.items.map((p) => [p.id, keys.pageKey(p.id)]));
|
|
442
923
|
const pages = [];
|
|
443
|
-
for (const page of local.
|
|
924
|
+
for (const page of local.items) {
|
|
444
925
|
const key = idToKey.get(page.id);
|
|
445
926
|
derived.add(page.path).add(relsPathOf(page.path));
|
|
446
927
|
const head = page.text.slice(0, scanContainer(page.text, "Page").openEnd);
|
|
447
928
|
const backId = attrOf(head, "BackPage");
|
|
448
|
-
const xml = page.text.slice(0, page.rel.start) + REL_MARK + page.text.slice(page.rel.end);
|
|
449
929
|
const content = await zipText(zip, page.path) ?? "";
|
|
450
930
|
const rels = await zipText(zip, relsPathOf(page.path));
|
|
451
|
-
const
|
|
452
|
-
const connectsSplit = splitList(shapesSplit.text, "Connects", CONNECTS_MARK, "Connect");
|
|
453
|
-
const owner = /* @__PURE__ */ new Map();
|
|
454
|
-
const shapes = [];
|
|
455
|
-
for (const text of shapesSplit.items) {
|
|
456
|
-
const ids = shapeIds(text);
|
|
457
|
-
const id = ids[0];
|
|
458
|
-
if (id === void 0) continue;
|
|
459
|
-
const shapeKey = keys.shapeKey(key, id);
|
|
460
|
-
for (const nested of ids) owner.set(nested, shapeKey);
|
|
461
|
-
shapes.push({ key: shapeKey, id, xml: text });
|
|
462
|
-
}
|
|
463
|
-
const connects = [];
|
|
464
|
-
for (const text of connectsSplit.items) {
|
|
465
|
-
const a = (name) => attrOf(text, name) ?? "";
|
|
466
|
-
const entry = {
|
|
467
|
-
fk: owner.get(a("FromSheet")) ?? "",
|
|
468
|
-
fi: a("FromSheet"),
|
|
469
|
-
tk: owner.get(a("ToSheet")) ?? "",
|
|
470
|
-
ti: a("ToSheet"),
|
|
471
|
-
fc: a("FromCell"),
|
|
472
|
-
tc: a("ToCell"),
|
|
473
|
-
fp: a("FromPart"),
|
|
474
|
-
tp: a("ToPart")
|
|
475
|
-
};
|
|
476
|
-
connects.push({
|
|
477
|
-
key: `${key}/${entry.fk}.${entry.fi}.${entry.fc}.${entry.fp}>${entry.tk}.${entry.ti}.${entry.tc}.${entry.tp}`,
|
|
478
|
-
entry
|
|
479
|
-
});
|
|
480
|
-
}
|
|
931
|
+
const { shell, shapes, connects } = splitContents(content, key, keys);
|
|
481
932
|
keys.pagePaths.set(key, page.path);
|
|
482
933
|
pages.push({
|
|
483
934
|
key,
|
|
484
935
|
id: page.id,
|
|
485
936
|
...backId !== void 0 && idToKey.has(backId) ? { back: idToKey.get(backId) } : {},
|
|
486
|
-
xml,
|
|
487
|
-
shell
|
|
937
|
+
xml: withMark(page),
|
|
938
|
+
shell,
|
|
488
939
|
...rels !== void 0 ? { rels } : {},
|
|
489
940
|
path: page.path,
|
|
490
941
|
shapes,
|
|
491
942
|
connects
|
|
492
943
|
});
|
|
493
944
|
}
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
let data = await file.async("uint8array");
|
|
501
|
-
if (path === CONTENT_TYPES) data = encoder.encode(stripPageOverrides(decoder.decode(data)));
|
|
502
|
-
total += data.length;
|
|
503
|
-
if (total > limit) throw new Error("The package parts exceed the shared size limit.");
|
|
504
|
-
parts.set(path, data);
|
|
505
|
-
}
|
|
945
|
+
const { masters, mastersOpen, mastersClose } = await snapshotMasters(zip, layout, keys, derived);
|
|
946
|
+
const { parts, media } = await snapshotRest(
|
|
947
|
+
zip,
|
|
948
|
+
derived,
|
|
949
|
+
options.maxPartBytes ?? DEFAULT_MAX_PART_BYTES
|
|
950
|
+
);
|
|
506
951
|
return {
|
|
507
952
|
pagesPath: layout.pagesPath,
|
|
508
953
|
pagesOpen: pagesXml.slice(0, local.box.openEnd),
|
|
509
954
|
pagesClose: pagesXml.slice(local.box.closeStart),
|
|
510
955
|
pages,
|
|
956
|
+
...mastersOpen !== void 0 && mastersClose !== void 0 && layout.mastersPath ? { mastersPath: layout.mastersPath, mastersOpen, mastersClose } : {},
|
|
957
|
+
masters,
|
|
958
|
+
media,
|
|
511
959
|
parts
|
|
512
960
|
};
|
|
513
961
|
}
|
|
514
962
|
|
|
515
|
-
// visio/collab/
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
let i = 0;
|
|
528
|
-
while (i < order.length) {
|
|
529
|
-
const known = kept[i];
|
|
530
|
-
if (known !== void 0) {
|
|
531
|
-
result.set(order[i], known);
|
|
532
|
-
i++;
|
|
533
|
-
continue;
|
|
534
|
-
}
|
|
535
|
-
let end = i;
|
|
536
|
-
while (end < order.length && kept[end] === void 0) end++;
|
|
537
|
-
const lo = i > 0 ? kept[i - 1] : void 0;
|
|
538
|
-
const hi = end < order.length ? kept[end] : void 0;
|
|
539
|
-
const count = end - i;
|
|
540
|
-
for (let j = 0; j < count; j++) {
|
|
541
|
-
const key = order[i + j];
|
|
542
|
-
if (lo !== void 0 && hi !== void 0)
|
|
543
|
-
result.set(key, lo + (hi - lo) * (j + 1) / (count + 1));
|
|
544
|
-
else if (lo !== void 0) result.set(key, lo + j + 1);
|
|
545
|
-
else if (hi !== void 0) result.set(key, hi - count + j);
|
|
546
|
-
else result.set(key, j + 1);
|
|
547
|
-
}
|
|
548
|
-
i = end;
|
|
549
|
-
}
|
|
550
|
-
return result;
|
|
551
|
-
}
|
|
552
|
-
function byPosition(items) {
|
|
553
|
-
return items.sort((a, b) => a.pos - b.pos || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// visio/collab/write.ts
|
|
557
|
-
var pageId = (key) => `p:${key}`;
|
|
558
|
-
var bodyId = (key) => `b:${key}`;
|
|
559
|
-
var shapeId = (page, key) => `s:${page}/${key}`;
|
|
560
|
-
var connectId = (key) => `c:${key}`;
|
|
561
|
-
var pageContent = (e) => JSON.stringify([e.id, e.back ?? null, canon(e.xml)]);
|
|
562
|
-
var bodyContent = (e) => JSON.stringify([canon(e.shell), e.rels ?? null]);
|
|
563
|
-
function writeSharedDrawing(shared, snapshot, keys) {
|
|
564
|
-
let writes = 0;
|
|
565
|
-
const set = (map, key, value) => {
|
|
566
|
-
if (setIfChanged(map, key, value)) writes++;
|
|
567
|
-
};
|
|
568
|
-
set(shared.meta, "v", SCHEMA_VERSION);
|
|
569
|
-
set(shared.meta, "pagesPath", snapshot.pagesPath);
|
|
570
|
-
set(shared.meta, "pagesOpen", snapshot.pagesOpen);
|
|
571
|
-
set(shared.meta, "pagesClose", snapshot.pagesClose);
|
|
572
|
-
const now = /* @__PURE__ */ new Map();
|
|
573
|
-
const changed = (id, content, room) => {
|
|
574
|
-
const base = keys.known.get(id);
|
|
575
|
-
return base === void 0 ? room !== content : base !== content;
|
|
576
|
-
};
|
|
577
|
-
const pagePos = assignPositions(
|
|
578
|
-
snapshot.pages.map((p) => p.key),
|
|
579
|
-
(key) => pageEntry(shared.pages.get(key))?.pos
|
|
580
|
-
);
|
|
581
|
-
for (const page of snapshot.pages) {
|
|
582
|
-
const room = pageEntry(shared.pages.get(page.key));
|
|
583
|
-
const content = pageContent(page);
|
|
584
|
-
now.set(pageId(page.key), content);
|
|
585
|
-
const own = changed(pageId(page.key), content, room && pageContent(room));
|
|
586
|
-
const source = own || !room ? page : room;
|
|
587
|
-
set(shared.pages, page.key, {
|
|
588
|
-
pos: pagePos.get(page.key),
|
|
589
|
-
id: source.id,
|
|
590
|
-
...source.back !== void 0 ? { back: source.back } : {},
|
|
591
|
-
xml: source.xml
|
|
592
|
-
});
|
|
593
|
-
const roomBody = bodyEntry(shared.bodies.get(page.key));
|
|
594
|
-
const bodyText = bodyContent(page);
|
|
595
|
-
now.set(bodyId(page.key), bodyText);
|
|
596
|
-
const ownBody = changed(bodyId(page.key), bodyText, roomBody && bodyContent(roomBody));
|
|
597
|
-
const body = ownBody || !roomBody ? page : roomBody;
|
|
598
|
-
set(shared.bodies, page.key, {
|
|
599
|
-
shell: body.shell,
|
|
600
|
-
...body.rels !== void 0 ? { rels: body.rels } : {}
|
|
601
|
-
});
|
|
602
|
-
const shapePos = assignPositions(
|
|
603
|
-
page.shapes.map((s) => s.key),
|
|
604
|
-
(key) => shapeEntry(shared.shapes.get(`${page.key}/${key}`))?.pos
|
|
605
|
-
);
|
|
606
|
-
for (const shape of page.shapes) {
|
|
607
|
-
const id = shapeId(page.key, shape.key);
|
|
608
|
-
const roomShape = shapeEntry(shared.shapes.get(`${page.key}/${shape.key}`));
|
|
609
|
-
const text = canon(shape.xml);
|
|
610
|
-
now.set(id, text);
|
|
611
|
-
const xml = changed(id, text, roomShape && canon(roomShape.xml)) || !roomShape ? shape.xml : roomShape.xml;
|
|
612
|
-
set(shared.shapes, `${page.key}/${shape.key}`, { pos: shapePos.get(shape.key), xml });
|
|
613
|
-
}
|
|
614
|
-
for (const connect of page.connects) {
|
|
615
|
-
now.set(connectId(connect.key), "");
|
|
616
|
-
if (!keys.known.has(connectId(connect.key)) || !shared.connects.has(connect.key))
|
|
617
|
-
set(shared.connects, connect.key, connect.entry);
|
|
963
|
+
// visio/collab/compose-lists.ts
|
|
964
|
+
var relTarget = (dir, path) => dir && path.startsWith(`${dir}/`) ? path.slice(dir.length + 1) : `/${path}`;
|
|
965
|
+
async function placeList(options) {
|
|
966
|
+
const { files, taken, localZip, items } = options;
|
|
967
|
+
const dir = dirName(options.listPath);
|
|
968
|
+
taken.add(options.listPath).add(relsPathOf(options.listPath));
|
|
969
|
+
const paths = /* @__PURE__ */ new Map();
|
|
970
|
+
for (const item of items) {
|
|
971
|
+
const known = options.known.get(item.key);
|
|
972
|
+
if (known && !taken.has(known) && localZip?.file(known)) {
|
|
973
|
+
paths.set(item.key, known);
|
|
974
|
+
taken.add(known);
|
|
618
975
|
}
|
|
619
976
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
writes++;
|
|
630
|
-
} else if (id.startsWith("s:")) {
|
|
631
|
-
const slash = name.indexOf("/");
|
|
632
|
-
const page = name.slice(0, slash);
|
|
633
|
-
if (!now.has(pageId(page))) continue;
|
|
634
|
-
shared.dead.set(name, true);
|
|
635
|
-
shared.shapes.delete(name);
|
|
636
|
-
keys.forgetShape(page, name.slice(slash + 1));
|
|
637
|
-
writes++;
|
|
638
|
-
} else if (id.startsWith("c:") && shared.connects.has(name)) {
|
|
639
|
-
shared.connects.delete(name);
|
|
640
|
-
writes++;
|
|
641
|
-
}
|
|
977
|
+
let counter = 0;
|
|
978
|
+
for (const item of items) {
|
|
979
|
+
if (paths.has(item.key)) continue;
|
|
980
|
+
let path;
|
|
981
|
+
do
|
|
982
|
+
path = `${dir ? `${dir}/` : ""}${options.stem}${++counter}.xml`;
|
|
983
|
+
while (taken.has(path) || localZip?.file(path));
|
|
984
|
+
paths.set(item.key, path);
|
|
985
|
+
taken.add(path);
|
|
642
986
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
987
|
+
const others = parseRelationships(
|
|
988
|
+
localZip ? await zipText(localZip, relsPathOf(options.listPath)) : void 0
|
|
989
|
+
).filter((r) => r.type !== options.relType);
|
|
990
|
+
const usedIds = new Set(others.map((r) => r.id));
|
|
991
|
+
let nextRel = 0;
|
|
992
|
+
const rels = [];
|
|
993
|
+
const elements = [];
|
|
994
|
+
for (const item of items) {
|
|
995
|
+
const path = paths.get(item.key);
|
|
996
|
+
let id;
|
|
997
|
+
do
|
|
998
|
+
id = `rId${++nextRel}`;
|
|
999
|
+
while (usedIds.has(id));
|
|
1000
|
+
usedIds.add(id);
|
|
1001
|
+
rels.push(
|
|
1002
|
+
`<Relationship Id="${id}" Type="${options.relType}" Target="${escapeAttr(relTarget(dir, path))}"/>`
|
|
1003
|
+
);
|
|
1004
|
+
const rel = `<Rel xmlns:r="${REL_NS}" r:id="${id}"/>`;
|
|
1005
|
+
elements.push(
|
|
1006
|
+
item.xml.includes(REL_MARK) ? item.xml.replace(REL_MARK, () => rel) : item.xml.slice(0, item.xml.lastIndexOf("</")) + rel + item.xml.slice(item.xml.lastIndexOf("</"))
|
|
1007
|
+
);
|
|
1008
|
+
files.set(path, item.part);
|
|
1009
|
+
if (item.rels !== void 0) files.set(relsPathOf(path), encoder.encode(item.rels));
|
|
649
1010
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
1011
|
+
files.set(options.listPath, encoder.encode(options.open + elements.join("") + options.close));
|
|
1012
|
+
files.set(
|
|
1013
|
+
relsPathOf(options.listPath),
|
|
1014
|
+
encoder.encode(
|
|
1015
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + others.map((r) => r.text).join("") + rels.join("") + "</Relationships>"
|
|
1016
|
+
)
|
|
1017
|
+
);
|
|
1018
|
+
return paths;
|
|
657
1019
|
}
|
|
658
1020
|
|
|
659
1021
|
// visio/collab/compose.ts
|
|
@@ -669,32 +1031,51 @@ function connectXml(item) {
|
|
|
669
1031
|
];
|
|
670
1032
|
return `<Connect ${attrs.filter(([, v]) => v !== "").map(([k, v]) => `${k}="${escapeAttr(v)}"`).join(" ")}/>`;
|
|
671
1033
|
}
|
|
672
|
-
function
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
return shell.replace(SHAPES_MARK, () => page.shapes.map((s) => s.xml).join("")).replace(CONNECTS_MARK, () => page.connects.map(connectXml).join(""));
|
|
681
|
-
}
|
|
682
|
-
function relTarget(pagesDir, path) {
|
|
683
|
-
return pagesDir && path.startsWith(`${pagesDir}/`) ? path.slice(pagesDir.length + 1) : `/${path}`;
|
|
1034
|
+
function contentsXml(shell, root, shapesXml, hasShapes, connects) {
|
|
1035
|
+
const outer = scanContainer(shell, root);
|
|
1036
|
+
if (hasShapes && !shell.includes(SHAPES_MARK) && outer && !outer.selfClosing)
|
|
1037
|
+
shell = shell.slice(0, outer.openEnd) + `<Shapes>${SHAPES_MARK}</Shapes>` + shell.slice(outer.openEnd);
|
|
1038
|
+
const outer2 = scanContainer(shell, root);
|
|
1039
|
+
if (connects.length && !shell.includes(CONNECTS_MARK) && outer2 && !outer2.selfClosing)
|
|
1040
|
+
shell = shell.slice(0, outer2.closeStart) + `<Connects>${CONNECTS_MARK}</Connects>` + shell.slice(outer2.closeStart);
|
|
1041
|
+
return shell.replace(SHAPES_MARK, () => shapesXml).replace(CONNECTS_MARK, () => connects.map(connectXml).join(""));
|
|
684
1042
|
}
|
|
1043
|
+
var pagePartXml = (page) => contentsXml(
|
|
1044
|
+
page.body.shell,
|
|
1045
|
+
"PageContents",
|
|
1046
|
+
page.shapesXml,
|
|
1047
|
+
page.shapes.length > 0,
|
|
1048
|
+
page.connects
|
|
1049
|
+
);
|
|
1050
|
+
var masterPartXml = (master) => contentsXml(
|
|
1051
|
+
decoder.decode(fromBase64(master.part)),
|
|
1052
|
+
"MasterContents",
|
|
1053
|
+
master.shapesXml,
|
|
1054
|
+
master.shapes.length > 0,
|
|
1055
|
+
master.connects
|
|
1056
|
+
);
|
|
685
1057
|
async function composeDrawing(drawing, local, keys, options = {}) {
|
|
686
1058
|
const localZip = local ? await readZip(local) : void 0;
|
|
687
1059
|
const files = /* @__PURE__ */ new Map();
|
|
688
1060
|
const prints = /* @__PURE__ */ new Map();
|
|
689
1061
|
let total = 0;
|
|
690
1062
|
const limit = options.maxPartBytes ?? 48 * 1024 * 1024;
|
|
691
|
-
|
|
692
|
-
|
|
1063
|
+
const cache = keys.cache.parts;
|
|
1064
|
+
const decode = (path, b64) => {
|
|
1065
|
+
const hit = cache.get(path);
|
|
1066
|
+
const data = hit && hit.b64 === b64 ? hit.data : fromBase64(b64);
|
|
1067
|
+
if (!hit || hit.b64 !== b64) cache.set(path, { b64, data });
|
|
693
1068
|
total += data.length;
|
|
694
1069
|
if (total > limit) throw new Error("The shared parts exceed the size limit.");
|
|
1070
|
+
return data;
|
|
1071
|
+
};
|
|
1072
|
+
for (const [path, b64] of drawing.parts) {
|
|
1073
|
+
const data = decode(path, b64);
|
|
695
1074
|
files.set(path, data);
|
|
696
1075
|
prints.set(path, fingerprint(data));
|
|
697
1076
|
}
|
|
1077
|
+
for (const path of [...cache.keys()])
|
|
1078
|
+
if (!drawing.parts.has(path) && !path.startsWith("media:")) cache.delete(path);
|
|
698
1079
|
if (localZip)
|
|
699
1080
|
for (const path of Object.keys(localZip.files)) {
|
|
700
1081
|
const file = localZip.files[path];
|
|
@@ -702,6 +1083,10 @@ async function composeDrawing(drawing, local, keys, options = {}) {
|
|
|
702
1083
|
files.set(path, await file.async("uint8array"));
|
|
703
1084
|
}
|
|
704
1085
|
let contentTypes = files.get(CONTENT_TYPES) !== void 0 ? decoder.decode(files.get(CONTENT_TYPES)) : (localZip && await zipText(localZip, CONTENT_TYPES)) ?? DEFAULT_CONTENT_TYPES;
|
|
1086
|
+
for (const item of drawing.media) {
|
|
1087
|
+
files.set(item.path, decode(`media:${item.path}`, item.data));
|
|
1088
|
+
contentTypes = ensureType(contentTypes, item.path, item.declared);
|
|
1089
|
+
}
|
|
705
1090
|
for (const [path, data] of [...files]) {
|
|
706
1091
|
if (!path.endsWith(".rels") || typeof data === "string") continue;
|
|
707
1092
|
const source = path.replace(/(^|\/)_rels\/([^/]+)\.rels$/, "$1$2");
|
|
@@ -720,65 +1105,56 @@ async function composeDrawing(drawing, local, keys, options = {}) {
|
|
|
720
1105
|
});
|
|
721
1106
|
if (next !== text) files.set(path, encoder.encode(next));
|
|
722
1107
|
}
|
|
723
|
-
const
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
localZip
|
|
749
|
-
)
|
|
750
|
-
|
|
751
|
-
let
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
1108
|
+
const taken = new Set(files.keys());
|
|
1109
|
+
const pageCache = keys.cache.pageParts;
|
|
1110
|
+
const pageItems = drawing.pages.map((page) => {
|
|
1111
|
+
const hit = pageCache.get(page.key);
|
|
1112
|
+
const bytes2 = hit && hit.sig === page.signature ? hit.bytes : encoder.encode(pagePartXml(page));
|
|
1113
|
+
pageCache.set(page.key, { sig: page.signature, bytes: bytes2 });
|
|
1114
|
+
return {
|
|
1115
|
+
key: page.key,
|
|
1116
|
+
xml: page.xml,
|
|
1117
|
+
part: bytes2,
|
|
1118
|
+
...page.body.rels !== void 0 ? { rels: page.body.rels } : {}
|
|
1119
|
+
};
|
|
1120
|
+
});
|
|
1121
|
+
for (const key of [...pageCache.keys()])
|
|
1122
|
+
if (!drawing.pages.some((p) => p.key === key)) pageCache.delete(key);
|
|
1123
|
+
const pagePaths = await placeList({
|
|
1124
|
+
listPath: drawing.pagesPath,
|
|
1125
|
+
open: drawing.pagesOpen,
|
|
1126
|
+
close: drawing.pagesClose,
|
|
1127
|
+
relType: PAGE_TYPE,
|
|
1128
|
+
stem: "page",
|
|
1129
|
+
items: pageItems,
|
|
1130
|
+
known: keys.pagePaths,
|
|
1131
|
+
files,
|
|
1132
|
+
taken,
|
|
1133
|
+
localZip
|
|
1134
|
+
});
|
|
1135
|
+
contentTypes = withPageOverrides(contentTypes, [...pagePaths.values()]);
|
|
1136
|
+
let masterPaths = /* @__PURE__ */ new Map();
|
|
1137
|
+
if (drawing.mastersPath !== void 0) {
|
|
1138
|
+
masterPaths = await placeList({
|
|
1139
|
+
listPath: drawing.mastersPath,
|
|
1140
|
+
open: drawing.mastersOpen ?? "<Masters>",
|
|
1141
|
+
close: drawing.mastersClose ?? "</Masters>",
|
|
1142
|
+
relType: MASTER_TYPE,
|
|
1143
|
+
stem: "master",
|
|
1144
|
+
items: drawing.masters.map((m) => ({
|
|
1145
|
+
key: m.key,
|
|
1146
|
+
xml: m.xml,
|
|
1147
|
+
part: encoder.encode(masterPartXml(m)),
|
|
1148
|
+
...m.rels !== void 0 ? { rels: m.rels } : {}
|
|
1149
|
+
})),
|
|
1150
|
+
known: keys.masterPaths,
|
|
1151
|
+
files,
|
|
1152
|
+
taken,
|
|
1153
|
+
localZip
|
|
1154
|
+
});
|
|
1155
|
+
contentTypes = withOverrides(contentTypes, MASTER_CONTENT_TYPE, [...masterPaths.values()]);
|
|
770
1156
|
}
|
|
771
|
-
files.set(
|
|
772
|
-
drawing.pagesPath,
|
|
773
|
-
encoder.encode(drawing.pagesOpen + pageXml.join("") + drawing.pagesClose)
|
|
774
|
-
);
|
|
775
|
-
files.set(
|
|
776
|
-
relsPathOf(drawing.pagesPath),
|
|
777
|
-
encoder.encode(
|
|
778
|
-
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + others.map((r) => r.text).join("") + pageRels.join("") + "</Relationships>"
|
|
779
|
-
)
|
|
780
|
-
);
|
|
781
|
-
files.set(CONTENT_TYPES, encoder.encode(withPageOverrides(contentTypes, [...paths.values()])));
|
|
1157
|
+
files.set(CONTENT_TYPES, encoder.encode(contentTypes));
|
|
782
1158
|
const zip = new JSZip();
|
|
783
1159
|
const names = [...files.keys()].sort(
|
|
784
1160
|
(a, b) => a === CONTENT_TYPES ? -1 : b === CONTENT_TYPES ? 1 : 0
|
|
@@ -787,24 +1163,58 @@ async function composeDrawing(drawing, local, keys, options = {}) {
|
|
|
787
1163
|
const bytes = await zip.generateAsync({ type: "uint8array", compression: "STORE" });
|
|
788
1164
|
const commit = () => {
|
|
789
1165
|
const pageIds = /* @__PURE__ */ new Map();
|
|
790
|
-
const
|
|
1166
|
+
const shapeIds = /* @__PURE__ */ new Map();
|
|
1167
|
+
const masterIds = /* @__PURE__ */ new Map();
|
|
791
1168
|
const known = /* @__PURE__ */ new Map();
|
|
1169
|
+
const recordShapes = (scope, shapes, connects) => {
|
|
1170
|
+
shapeIds.set(scope, new Map(shapes.map((s) => [s.id, s.key])));
|
|
1171
|
+
for (const shape of shapes) {
|
|
1172
|
+
known.set(shapeId(scope, shape.key), shellContent(shape));
|
|
1173
|
+
for (const [path, entry] of shape.entries)
|
|
1174
|
+
known.set(cellId(scope, shape.key, path), entryContent(entry));
|
|
1175
|
+
}
|
|
1176
|
+
for (const connect of connects) known.set(connectId(connect.key), "");
|
|
1177
|
+
};
|
|
792
1178
|
keys.pagePaths.clear();
|
|
1179
|
+
keys.masterPaths.clear();
|
|
1180
|
+
keys.mediaKeys.clear();
|
|
793
1181
|
for (const page of drawing.pages) {
|
|
794
1182
|
pageIds.set(page.id, page.key);
|
|
795
|
-
keys.pagePaths.set(page.key,
|
|
1183
|
+
keys.pagePaths.set(page.key, pagePaths.get(page.key));
|
|
796
1184
|
known.set(pageId(page.key), pageContent(page));
|
|
797
1185
|
known.set(bodyId(page.key), bodyContent(page.body));
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
1186
|
+
recordShapes(page.key, page.shapes, page.connects);
|
|
1187
|
+
}
|
|
1188
|
+
for (const master of drawing.masters) {
|
|
1189
|
+
masterIds.set(master.id, master.key);
|
|
1190
|
+
recordShapes(masterScope(master.key), master.shapes, master.connects);
|
|
1191
|
+
const path = masterPaths.get(master.key);
|
|
1192
|
+
if (path) keys.masterPaths.set(master.key, path);
|
|
1193
|
+
known.set(
|
|
1194
|
+
masterId(master.key),
|
|
1195
|
+
masterContent({ ...master, print: fingerprint(fromBase64(master.part)) })
|
|
1196
|
+
);
|
|
801
1197
|
}
|
|
802
|
-
|
|
1198
|
+
for (const item of drawing.media) {
|
|
1199
|
+
known.set(mediaId(item.key), "");
|
|
1200
|
+
keys.mediaKeys.set(item.path, item.key);
|
|
1201
|
+
}
|
|
1202
|
+
keys.reset(pageIds, shapeIds, masterIds);
|
|
803
1203
|
keys.known = known;
|
|
804
1204
|
keys.partPrints.clear();
|
|
805
1205
|
for (const [path, print] of prints) keys.partPrints.set(path, print);
|
|
806
1206
|
};
|
|
807
|
-
return { bytes, commit };
|
|
1207
|
+
return { bytes, signature: drawing.signature, commit };
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
// visio/collab/fixups.ts
|
|
1211
|
+
function applyFixups(shared, fixups) {
|
|
1212
|
+
let changed = 0;
|
|
1213
|
+
for (const fixup of fixups) {
|
|
1214
|
+
const map = fixup.map === "renum" ? shared.renum : shared.cells;
|
|
1215
|
+
if (setIfChanged(map, fixup.key, fixup.value)) changed++;
|
|
1216
|
+
}
|
|
1217
|
+
return changed;
|
|
808
1218
|
}
|
|
809
1219
|
|
|
810
1220
|
// visio/collab/keys.ts
|
|
@@ -818,15 +1228,34 @@ var DrawingKeys = class {
|
|
|
818
1228
|
seeding = false;
|
|
819
1229
|
#pages = /* @__PURE__ */ new Map();
|
|
820
1230
|
#shapes = /* @__PURE__ */ new Map();
|
|
1231
|
+
#masters = /* @__PURE__ */ new Map();
|
|
821
1232
|
/** Content of each entry this peer last wrote or applied, to tell a local edit or deletion from a change it has not applied yet. */
|
|
822
1233
|
known = /* @__PURE__ */ new Map();
|
|
823
1234
|
/** Fingerprints of the parts this peer last wrote or applied. */
|
|
824
1235
|
partPrints = /* @__PURE__ */ new Map();
|
|
825
1236
|
/** The part path of each page key in the local package. */
|
|
826
1237
|
pagePaths = /* @__PURE__ */ new Map();
|
|
1238
|
+
/** The part path of each master key in the local package. */
|
|
1239
|
+
masterPaths = /* @__PURE__ */ new Map();
|
|
1240
|
+
/** The room key of each media path in the local package. */
|
|
1241
|
+
mediaKeys = /* @__PURE__ */ new Map();
|
|
1242
|
+
/** Serialised page parts and decoded shared parts of the last rebuild, to skip unchanged work. */
|
|
1243
|
+
cache = {
|
|
1244
|
+
pageParts: /* @__PURE__ */ new Map(),
|
|
1245
|
+
parts: /* @__PURE__ */ new Map()
|
|
1246
|
+
};
|
|
1247
|
+
/**
|
|
1248
|
+
* What was last applied to the editor: the drawing signature, the editor version it produced,
|
|
1249
|
+
* the signature of everything but page content and the content signature of each page.
|
|
1250
|
+
*/
|
|
1251
|
+
applied;
|
|
827
1252
|
mint() {
|
|
828
1253
|
return `${this.tag}.${(++this.#counter).toString(36)}`;
|
|
829
1254
|
}
|
|
1255
|
+
/** A fresh id for one write batch: entries written together share it. */
|
|
1256
|
+
batch() {
|
|
1257
|
+
return this.mint();
|
|
1258
|
+
}
|
|
830
1259
|
pageKey(id) {
|
|
831
1260
|
let key = this.#pages.get(id);
|
|
832
1261
|
if (key === void 0) {
|
|
@@ -845,6 +1274,14 @@ var DrawingKeys = class {
|
|
|
845
1274
|
}
|
|
846
1275
|
return key;
|
|
847
1276
|
}
|
|
1277
|
+
masterKey(id) {
|
|
1278
|
+
let key = this.#masters.get(id);
|
|
1279
|
+
if (key === void 0) {
|
|
1280
|
+
key = this.seeding ? `s${id}` : this.mint();
|
|
1281
|
+
this.#masters.set(id, key);
|
|
1282
|
+
}
|
|
1283
|
+
return key;
|
|
1284
|
+
}
|
|
848
1285
|
findPage(id) {
|
|
849
1286
|
return this.#pages.get(id);
|
|
850
1287
|
}
|
|
@@ -858,38 +1295,355 @@ var DrawingKeys = class {
|
|
|
858
1295
|
for (const [id, k] of map) if (k === key) map.delete(id);
|
|
859
1296
|
}
|
|
860
1297
|
}
|
|
1298
|
+
forgetMaster(key) {
|
|
1299
|
+
for (const [id, k] of this.#masters) if (k === key) this.#masters.delete(id);
|
|
1300
|
+
this.#shapes.delete(masterScope(key));
|
|
1301
|
+
this.masterPaths.delete(key);
|
|
1302
|
+
}
|
|
861
1303
|
/** Replaces the id-to-key tables with those of a freshly composed package. */
|
|
862
|
-
reset(pages, shapes) {
|
|
1304
|
+
reset(pages, shapes, masters = /* @__PURE__ */ new Map()) {
|
|
863
1305
|
this.#pages.clear();
|
|
864
1306
|
this.#shapes.clear();
|
|
1307
|
+
this.#masters.clear();
|
|
865
1308
|
for (const [id, key] of pages) this.#pages.set(id, key);
|
|
866
1309
|
for (const [page, map] of shapes) this.#shapes.set(page, new Map(map));
|
|
1310
|
+
for (const [id, key] of masters) this.#masters.set(id, key);
|
|
867
1311
|
}
|
|
868
1312
|
};
|
|
869
1313
|
|
|
870
|
-
// visio/collab/
|
|
1314
|
+
// visio/collab/order.ts
|
|
1315
|
+
function assignPositions(order, current) {
|
|
1316
|
+
const result = /* @__PURE__ */ new Map();
|
|
1317
|
+
const kept = [];
|
|
1318
|
+
let last = -Infinity;
|
|
1319
|
+
for (const key of order) {
|
|
1320
|
+
const pos = current(key);
|
|
1321
|
+
if (pos !== void 0 && pos > last) {
|
|
1322
|
+
kept.push(pos);
|
|
1323
|
+
last = pos;
|
|
1324
|
+
} else kept.push(void 0);
|
|
1325
|
+
}
|
|
1326
|
+
let i = 0;
|
|
1327
|
+
while (i < order.length) {
|
|
1328
|
+
const known = kept[i];
|
|
1329
|
+
if (known !== void 0) {
|
|
1330
|
+
result.set(order[i], known);
|
|
1331
|
+
i++;
|
|
1332
|
+
continue;
|
|
1333
|
+
}
|
|
1334
|
+
let end = i;
|
|
1335
|
+
while (end < order.length && kept[end] === void 0) end++;
|
|
1336
|
+
const lo = i > 0 ? kept[i - 1] : void 0;
|
|
1337
|
+
const hi = end < order.length ? kept[end] : void 0;
|
|
1338
|
+
const count = end - i;
|
|
1339
|
+
for (let j = 0; j < count; j++) {
|
|
1340
|
+
const key = order[i + j];
|
|
1341
|
+
if (lo !== void 0 && hi !== void 0)
|
|
1342
|
+
result.set(key, lo + (hi - lo) * (j + 1) / (count + 1));
|
|
1343
|
+
else if (lo !== void 0) result.set(key, lo + j + 1);
|
|
1344
|
+
else if (hi !== void 0) result.set(key, hi - count + j);
|
|
1345
|
+
else result.set(key, j + 1);
|
|
1346
|
+
}
|
|
1347
|
+
i = end;
|
|
1348
|
+
}
|
|
1349
|
+
return result;
|
|
1350
|
+
}
|
|
1351
|
+
function byPosition(items) {
|
|
1352
|
+
return items.sort((a, b) => a.pos - b.pos || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// visio/collab/read-ids.ts
|
|
871
1356
|
var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
872
1357
|
var numeric = (id) => /^\d+$/.test(id) ? Number(id) : 0;
|
|
1358
|
+
function assignIds(items) {
|
|
1359
|
+
const effective = (item) => item.fixed ?? item.id;
|
|
1360
|
+
let max = Math.max(0, ...items.map((item) => numeric(effective(item))));
|
|
1361
|
+
const order = [...items].sort(
|
|
1362
|
+
(a, b) => Number(b.fixed !== void 0) - Number(a.fixed !== void 0) || compare(a.key, b.key)
|
|
1363
|
+
);
|
|
1364
|
+
const used = /* @__PURE__ */ new Set();
|
|
1365
|
+
const ids = /* @__PURE__ */ new Map();
|
|
1366
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
1367
|
+
for (const item of order) {
|
|
1368
|
+
let id = effective(item);
|
|
1369
|
+
if (used.has(id)) {
|
|
1370
|
+
id = String(++max);
|
|
1371
|
+
fresh.set(item.key, { from: item.id, to: id });
|
|
1372
|
+
}
|
|
1373
|
+
used.add(id);
|
|
1374
|
+
ids.set(item.key, id);
|
|
1375
|
+
}
|
|
1376
|
+
return { ids, fresh };
|
|
1377
|
+
}
|
|
1378
|
+
var fixedId = (renum, key, id) => {
|
|
1379
|
+
const pair = renum.get(key)?.i;
|
|
1380
|
+
return pair && pair[0] === id ? pair[1] : void 0;
|
|
1381
|
+
};
|
|
1382
|
+
function readRenum(shared) {
|
|
1383
|
+
const out = /* @__PURE__ */ new Map();
|
|
1384
|
+
for (const [key, value] of shared.renum) {
|
|
1385
|
+
const entry = renumEntry(value);
|
|
1386
|
+
if (entry) out.set(key, entry);
|
|
1387
|
+
}
|
|
1388
|
+
return out;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
// visio/collab/read-util.ts
|
|
1392
|
+
function hashTexts(texts) {
|
|
1393
|
+
let a = 2166136261;
|
|
1394
|
+
let b = 16777619 ^ 2654435769;
|
|
1395
|
+
for (const text of texts) {
|
|
1396
|
+
for (let i = 0; i < text.length; i++) {
|
|
1397
|
+
const c = text.charCodeAt(i);
|
|
1398
|
+
a = Math.imul(a ^ c, 16777619);
|
|
1399
|
+
b = Math.imul(b + c, 2246822507) ^ b >>> 13;
|
|
1400
|
+
}
|
|
1401
|
+
a = Math.imul(a ^ 255, 16777619);
|
|
1402
|
+
b = Math.imul(b ^ 255, 3266489909);
|
|
1403
|
+
}
|
|
1404
|
+
return `${(a >>> 0).toString(16)}${(b >>> 0).toString(16)}`;
|
|
1405
|
+
}
|
|
1406
|
+
var split = (key, depth) => {
|
|
1407
|
+
const out = [];
|
|
1408
|
+
let from = 0;
|
|
1409
|
+
for (let i = 0; i < depth; i++) {
|
|
1410
|
+
const slash = key.indexOf("/", from);
|
|
1411
|
+
if (slash < 0) return void 0;
|
|
1412
|
+
out.push(key.slice(from, slash));
|
|
1413
|
+
from = slash + 1;
|
|
1414
|
+
}
|
|
1415
|
+
out.push(key.slice(from));
|
|
1416
|
+
return out;
|
|
1417
|
+
};
|
|
1418
|
+
var connectSignature = (connects) => connects.flatMap((c) => [c.from, c.to, c.entry.fc, c.entry.tc, c.entry.fp, c.entry.tp]);
|
|
1419
|
+
function resolveConnects(list, shapes) {
|
|
1420
|
+
const byKey = new Map(shapes.map((s) => [s.key, s]));
|
|
1421
|
+
const out = [];
|
|
1422
|
+
for (const item of [...list ?? []].sort((a, b) => compare(a.key, b.key))) {
|
|
1423
|
+
const { entry } = item;
|
|
1424
|
+
const from = entry.fk ? byKey.get(entry.fk) : void 0;
|
|
1425
|
+
const to = entry.tk ? byKey.get(entry.tk) : void 0;
|
|
1426
|
+
if (entry.fk && !from || entry.tk && !to) continue;
|
|
1427
|
+
out.push({ key: item.key, entry, from: from?.id ?? entry.fi, to: to?.id ?? entry.ti });
|
|
1428
|
+
}
|
|
1429
|
+
return out;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
// visio/collab/read-shapes.ts
|
|
873
1433
|
function setAttr(open, name, value) {
|
|
874
1434
|
return open.replace(
|
|
875
1435
|
new RegExp(String.raw`(\s${name}\s*=\s*)(?:"[^"]*"|'[^']*')`),
|
|
876
1436
|
(_m, head) => `${head}"${value}"`
|
|
877
1437
|
);
|
|
878
1438
|
}
|
|
879
|
-
function
|
|
880
|
-
if (!remap.size) return xml;
|
|
881
|
-
return xml.replace(
|
|
882
|
-
|
|
883
|
-
(tag) => tag.replace(/(\bID\s*=\s*)(["'])(\d+)\2/, (m, head, q, id) => {
|
|
1439
|
+
function renumberFormulas(xml, remap) {
|
|
1440
|
+
if (!remap.size || !xml.includes("Sheet.")) return xml;
|
|
1441
|
+
return xml.replace(/(\sF\s*=\s*)("[^"]*"|'[^']*')/g, (_m, head, value) => {
|
|
1442
|
+
const body = value.slice(1, -1).replace(/Sheet\.(\d+)(?!\d)/g, (m, id) => {
|
|
884
1443
|
const next = remap.get(id);
|
|
885
|
-
return next === void 0 ? m :
|
|
1444
|
+
return next === void 0 ? m : `Sheet.${next}`;
|
|
1445
|
+
});
|
|
1446
|
+
return `${head}${value[0]}${body}${value[0]}`;
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
function resolveShapes(input) {
|
|
1450
|
+
const raw = /* @__PURE__ */ new Map();
|
|
1451
|
+
for (const [key, entry] of input.shapes) {
|
|
1452
|
+
const id = attrOf(entry.open, "ID");
|
|
1453
|
+
if (id !== void 0) raw.set(key, { entry, id });
|
|
1454
|
+
}
|
|
1455
|
+
const state = /* @__PURE__ */ new Map();
|
|
1456
|
+
const valid = (key, seen = /* @__PURE__ */ new Set()) => {
|
|
1457
|
+
const known = state.get(key);
|
|
1458
|
+
if (known !== void 0) return known;
|
|
1459
|
+
const item = raw.get(key);
|
|
1460
|
+
const parent = item?.entry.parent;
|
|
1461
|
+
let ok = !!item;
|
|
1462
|
+
if (ok && parent !== void 0) ok = !seen.has(key) && valid(parent, seen.add(key));
|
|
1463
|
+
state.set(key, ok);
|
|
1464
|
+
return ok;
|
|
1465
|
+
};
|
|
1466
|
+
const live = [...raw.keys()].filter((k) => valid(k)).sort(compare);
|
|
1467
|
+
const { ids: finalId, fresh: renumbered } = assignIds(
|
|
1468
|
+
live.map((key) => {
|
|
1469
|
+
const { id } = raw.get(key);
|
|
1470
|
+
return { key, id, fixed: fixedId(input.renum, key, id) };
|
|
886
1471
|
})
|
|
887
|
-
)
|
|
888
|
-
|
|
889
|
-
|
|
1472
|
+
);
|
|
1473
|
+
const batchRemap = /* @__PURE__ */ new Map();
|
|
1474
|
+
for (const [key, change] of renumbered) {
|
|
1475
|
+
const b = raw.get(key).entry.b;
|
|
1476
|
+
if (b === void 0) continue;
|
|
1477
|
+
const map = batchRemap.get(b) ?? /* @__PURE__ */ new Map();
|
|
1478
|
+
map.set(change.from, change.to);
|
|
1479
|
+
batchRemap.set(b, map);
|
|
1480
|
+
}
|
|
1481
|
+
const remapFor = (key) => {
|
|
1482
|
+
const out = new Map(batchRemap.get(raw.get(key).entry.b ?? "") ?? []);
|
|
1483
|
+
const chain = [];
|
|
1484
|
+
for (let k = key; k !== void 0; k = raw.get(k)?.entry.parent)
|
|
1485
|
+
chain.unshift(k);
|
|
1486
|
+
for (const k of chain) {
|
|
1487
|
+
const change = renumbered.get(k);
|
|
1488
|
+
if (change) out.set(change.from, change.to);
|
|
1489
|
+
}
|
|
1490
|
+
return out;
|
|
1491
|
+
};
|
|
1492
|
+
const children = /* @__PURE__ */ new Map();
|
|
1493
|
+
for (const key of live) {
|
|
1494
|
+
const parent = raw.get(key).entry.parent ?? "";
|
|
1495
|
+
children.set(parent, [...children.get(parent) ?? [], key]);
|
|
1496
|
+
}
|
|
1497
|
+
const sortSiblings = (keys) => keys.sort((a, b) => raw.get(a).entry.pos - raw.get(b).entry.pos || compare(a, b));
|
|
1498
|
+
const shapes = [];
|
|
1499
|
+
const fixups = [];
|
|
1500
|
+
const render = (key) => {
|
|
1501
|
+
const { entry } = raw.get(key);
|
|
1502
|
+
const id = finalId.get(key);
|
|
1503
|
+
const remap = remapFor(key);
|
|
1504
|
+
let open = setAttr(entry.open, "ID", id);
|
|
1505
|
+
const record = { ...input.renum.get(key) };
|
|
1506
|
+
let dirty = false;
|
|
1507
|
+
const change = renumbered.get(key);
|
|
1508
|
+
if (change) {
|
|
1509
|
+
record.i = [change.from, change.to];
|
|
1510
|
+
dirty = true;
|
|
1511
|
+
}
|
|
1512
|
+
const master = attrOf(open, "Master");
|
|
1513
|
+
const persisted = record.m && record.m[0] === master ? record.m[1] : void 0;
|
|
1514
|
+
const batched = master !== void 0 ? input.masterRemap.get(entry.b ?? "")?.get(master) : void 0;
|
|
1515
|
+
const next = persisted ?? batched;
|
|
1516
|
+
if (next !== void 0) open = setAttr(open, "Master", next);
|
|
1517
|
+
if (persisted === void 0 && batched !== void 0) {
|
|
1518
|
+
record.m = [master, batched];
|
|
1519
|
+
dirty = true;
|
|
1520
|
+
}
|
|
1521
|
+
if (dirty) fixups.push({ map: "renum", key: `${input.scope}/${key}`, value: record });
|
|
1522
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1523
|
+
for (const [path, piece] of input.cells.get(key) ?? []) {
|
|
1524
|
+
const leaf = piece.xml !== void 0 && /(^|\/)c\/[^/]*$/.test(path);
|
|
1525
|
+
const xml2 = leaf ? renumberFormulas(piece.xml, remap) : void 0;
|
|
1526
|
+
if (xml2 !== void 0 && xml2 !== piece.xml) {
|
|
1527
|
+
const value = { ...piece, xml: xml2 };
|
|
1528
|
+
entries.set(path, value);
|
|
1529
|
+
fixups.push({ map: "cells", key: `${input.scope}/${key}/${path}`, value });
|
|
1530
|
+
} else entries.set(path, piece);
|
|
1531
|
+
}
|
|
1532
|
+
shapes.push({
|
|
1533
|
+
key,
|
|
1534
|
+
id,
|
|
1535
|
+
...entry.parent !== void 0 ? { parent: entry.parent } : {},
|
|
1536
|
+
open,
|
|
1537
|
+
entries
|
|
1538
|
+
});
|
|
1539
|
+
const inner = sortSiblings(children.get(key) ?? []).map(render).join("");
|
|
1540
|
+
return buildShape(open, entries, inner ? `<Shapes>${inner}</Shapes>` : "");
|
|
1541
|
+
};
|
|
1542
|
+
const xml = sortSiblings(children.get("") ?? []).map(render).join("");
|
|
1543
|
+
return { shapes, xml, fixups };
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
// visio/collab/read-parts.ts
|
|
1547
|
+
var compare2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
1548
|
+
function resolveMasters(shared, renum) {
|
|
1549
|
+
const alive = [];
|
|
1550
|
+
for (const [key, value] of shared.masters) {
|
|
1551
|
+
const entry = masterEntry(value);
|
|
1552
|
+
if (entry) alive.push({ key, entry });
|
|
1553
|
+
}
|
|
1554
|
+
const { ids, fresh } = assignIds(
|
|
1555
|
+
alive.map(({ key, entry }) => ({
|
|
1556
|
+
key,
|
|
1557
|
+
id: entry.id,
|
|
1558
|
+
fixed: fixedId(renum, masterScope(key), entry.id)
|
|
1559
|
+
}))
|
|
1560
|
+
);
|
|
1561
|
+
const remap = /* @__PURE__ */ new Map();
|
|
1562
|
+
const fixups = [];
|
|
1563
|
+
for (const [key, change] of [...fresh].sort((a, b) => compare2(a[0], b[0]))) {
|
|
1564
|
+
const b = alive.find((m) => m.key === key).entry.b;
|
|
1565
|
+
if (b !== void 0) {
|
|
1566
|
+
const map = remap.get(b) ?? /* @__PURE__ */ new Map();
|
|
1567
|
+
map.set(change.from, change.to);
|
|
1568
|
+
remap.set(b, map);
|
|
1569
|
+
}
|
|
1570
|
+
fixups.push({
|
|
1571
|
+
map: "renum",
|
|
1572
|
+
key: masterScope(key),
|
|
1573
|
+
value: { ...renum.get(masterScope(key)), i: [change.from, change.to] }
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
alive.sort((a, b) => a.entry.pos - b.entry.pos || compare2(a.key, b.key));
|
|
1577
|
+
return {
|
|
1578
|
+
masters: alive.map(({ key, entry }) => {
|
|
1579
|
+
const id = ids.get(key);
|
|
1580
|
+
const open = /^<[^>]*>/.exec(entry.xml)?.[0];
|
|
1581
|
+
return {
|
|
1582
|
+
key,
|
|
1583
|
+
id,
|
|
1584
|
+
xml: open ? setAttr(open, "ID", id) + entry.xml.slice(open.length) : entry.xml,
|
|
1585
|
+
part: entry.part,
|
|
1586
|
+
...entry.rels !== void 0 ? { rels: entry.rels } : {}
|
|
1587
|
+
};
|
|
1588
|
+
}),
|
|
1589
|
+
remap,
|
|
1590
|
+
fixups
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
function resolveMedia(shared) {
|
|
1594
|
+
const items = [...shared.media].flatMap(([key, value]) => {
|
|
1595
|
+
const entry = mediaEntry(value);
|
|
1596
|
+
const data = entry ? str(shared.blobs.get(entry.hash)) : void 0;
|
|
1597
|
+
return entry && data !== void 0 ? [{ key, entry, data }] : [];
|
|
1598
|
+
}).sort((a, b) => compare2(a.key, b.key));
|
|
1599
|
+
const taken = /* @__PURE__ */ new Set();
|
|
1600
|
+
const first = /* @__PURE__ */ new Map();
|
|
1601
|
+
for (const item of items) if (!first.has(item.entry.path)) first.set(item.entry.path, item.key);
|
|
1602
|
+
for (const path of first.keys()) taken.add(path);
|
|
1603
|
+
const renames = /* @__PURE__ */ new Map();
|
|
1604
|
+
const media = [];
|
|
1605
|
+
for (const { key, entry, data } of items) {
|
|
1606
|
+
let path = entry.path;
|
|
1607
|
+
if (first.get(entry.path) !== key) {
|
|
1608
|
+
const dot = path.lastIndexOf(".");
|
|
1609
|
+
const stem = dot > path.lastIndexOf("/") ? path.slice(0, dot) : path;
|
|
1610
|
+
const ext = dot > path.lastIndexOf("/") ? path.slice(dot) : "";
|
|
1611
|
+
path = `${stem}-${entry.hash.slice(0, 8)}${ext}`;
|
|
1612
|
+
for (let n = 2; taken.has(path); n++) path = `${stem}-${entry.hash.slice(0, 8)}-${n}${ext}`;
|
|
1613
|
+
taken.add(path);
|
|
1614
|
+
if (entry.b !== void 0) {
|
|
1615
|
+
const map = renames.get(entry.b) ?? /* @__PURE__ */ new Map();
|
|
1616
|
+
map.set(entry.path, path);
|
|
1617
|
+
renames.set(entry.b, map);
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
media.push({
|
|
1621
|
+
key,
|
|
1622
|
+
path,
|
|
1623
|
+
hash: entry.hash,
|
|
1624
|
+
declared: { type: entry.ct, byDefault: entry.d },
|
|
1625
|
+
data
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
return { media, renames };
|
|
1629
|
+
}
|
|
1630
|
+
function renameTargets(rels, baseDir, renames) {
|
|
1631
|
+
return rels.replace(/<(?:\w+:)?Relationship\b[^>]*>/g, (tag) => {
|
|
1632
|
+
const target = attrOf(tag, "Target");
|
|
1633
|
+
if (target === void 0 || attrOf(tag, "TargetMode") === "External") return tag;
|
|
1634
|
+
const next = renames.get(resolveTarget(baseDir, target));
|
|
1635
|
+
if (next === void 0) return tag;
|
|
1636
|
+
const value = target.startsWith("/") ? `/${next}` : relativeTarget(baseDir, next);
|
|
1637
|
+
return tag.replace(
|
|
1638
|
+
/(\sTarget\s*=\s*)(?:"[^"]*"|'[^']*')/,
|
|
1639
|
+
(_m, head) => `${head}"${value}"`
|
|
1640
|
+
);
|
|
890
1641
|
});
|
|
891
1642
|
}
|
|
1643
|
+
|
|
1644
|
+
// visio/collab/read.ts
|
|
892
1645
|
function readSharedDrawing(shared) {
|
|
1646
|
+
assertSchemaVersion(shared);
|
|
893
1647
|
if (isSharedDrawingEmpty(shared)) return void 0;
|
|
894
1648
|
const pagesPath = str(shared.meta.get("pagesPath"));
|
|
895
1649
|
const pagesOpen = str(shared.meta.get("pagesOpen"));
|
|
@@ -901,25 +1655,50 @@ function readSharedDrawing(shared) {
|
|
|
901
1655
|
const body = bodyEntry(shared.bodies.get(key));
|
|
902
1656
|
return entry && body ? [{ key, pos: entry.pos, entry, body }] : [];
|
|
903
1657
|
});
|
|
904
|
-
const
|
|
905
|
-
const
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1658
|
+
const renum = readRenum(shared);
|
|
1659
|
+
const fixups = [];
|
|
1660
|
+
const { ids: pageIds, fresh: freshPages } = assignIds(
|
|
1661
|
+
alive.map((p) => ({
|
|
1662
|
+
key: p.key,
|
|
1663
|
+
id: p.entry.id,
|
|
1664
|
+
fixed: fixedId(renum, p.key, p.entry.id)
|
|
1665
|
+
}))
|
|
1666
|
+
);
|
|
1667
|
+
for (const [key, change] of [...freshPages].sort((a, b) => compare(a[0], b[0])))
|
|
1668
|
+
fixups.push({
|
|
1669
|
+
map: "renum",
|
|
1670
|
+
key,
|
|
1671
|
+
value: { ...renum.get(key), i: [change.from, change.to] }
|
|
1672
|
+
});
|
|
913
1673
|
const shapesByPage = /* @__PURE__ */ new Map();
|
|
914
1674
|
for (const [full, value] of shared.shapes) {
|
|
915
|
-
const
|
|
916
|
-
if (
|
|
1675
|
+
const parts2 = split(full, 1);
|
|
1676
|
+
if (!parts2 || shared.dead.has(full)) continue;
|
|
917
1677
|
const entry = shapeEntry(value);
|
|
918
1678
|
if (!entry) continue;
|
|
919
|
-
const
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1679
|
+
const map = shapesByPage.get(parts2[0]) ?? /* @__PURE__ */ new Map();
|
|
1680
|
+
map.set(parts2[1], entry);
|
|
1681
|
+
shapesByPage.set(parts2[0], map);
|
|
1682
|
+
}
|
|
1683
|
+
const cellsByPage = /* @__PURE__ */ new Map();
|
|
1684
|
+
for (const [full, value] of shared.cells) {
|
|
1685
|
+
const parts2 = split(full, 2);
|
|
1686
|
+
const entry = parts2 && cellEntry(value);
|
|
1687
|
+
if (!parts2 || !entry) continue;
|
|
1688
|
+
const [page, shape, path] = parts2;
|
|
1689
|
+
const shapes = cellsByPage.get(page) ?? /* @__PURE__ */ new Map();
|
|
1690
|
+
const cells = shapes.get(shape) ?? /* @__PURE__ */ new Map();
|
|
1691
|
+
cells.set(path, entry);
|
|
1692
|
+
shapes.set(shape, cells);
|
|
1693
|
+
cellsByPage.set(page, shapes);
|
|
1694
|
+
}
|
|
1695
|
+
const renumByScope = /* @__PURE__ */ new Map();
|
|
1696
|
+
for (const [full, entry] of renum) {
|
|
1697
|
+
const parts2 = split(full, 1);
|
|
1698
|
+
if (!parts2) continue;
|
|
1699
|
+
const map = renumByScope.get(parts2[0]) ?? /* @__PURE__ */ new Map();
|
|
1700
|
+
map.set(parts2[1], entry);
|
|
1701
|
+
renumByScope.set(parts2[0], map);
|
|
923
1702
|
}
|
|
924
1703
|
const connectsByPage = /* @__PURE__ */ new Map();
|
|
925
1704
|
for (const [full, value] of shared.connects) {
|
|
@@ -930,24 +1709,25 @@ function readSharedDrawing(shared) {
|
|
|
930
1709
|
list.push({ key: full, entry });
|
|
931
1710
|
connectsByPage.set(full.slice(0, slash), list);
|
|
932
1711
|
}
|
|
1712
|
+
const { masters, remap: masterRemap, fixups: masterFixups } = resolveMasters(shared, renum);
|
|
1713
|
+
fixups.push(...masterFixups);
|
|
1714
|
+
const { media, renames } = resolveMedia(shared);
|
|
1715
|
+
const mastersPath = str(shared.meta.get("mastersPath"));
|
|
1716
|
+
const mastersOpen = str(shared.meta.get("mastersOpen"));
|
|
1717
|
+
const mastersClose = str(shared.meta.get("mastersClose"));
|
|
1718
|
+
const pagesDir = dirName(pagesPath);
|
|
933
1719
|
const pages = [];
|
|
934
1720
|
for (const page of byPosition(alive)) {
|
|
935
1721
|
const finalId = pageIds.get(page.key);
|
|
936
|
-
const
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
key: item.key,
|
|
946
|
-
entry,
|
|
947
|
-
from: from?.remap.get(entry.fi) ?? entry.fi,
|
|
948
|
-
to: to?.remap.get(entry.ti) ?? entry.ti
|
|
949
|
-
});
|
|
950
|
-
}
|
|
1722
|
+
const resolved = resolveShapes({
|
|
1723
|
+
scope: page.key,
|
|
1724
|
+
shapes: shapesByPage.get(page.key) ?? /* @__PURE__ */ new Map(),
|
|
1725
|
+
cells: cellsByPage.get(page.key) ?? /* @__PURE__ */ new Map(),
|
|
1726
|
+
renum: renumByScope.get(page.key) ?? /* @__PURE__ */ new Map(),
|
|
1727
|
+
masterRemap
|
|
1728
|
+
});
|
|
1729
|
+
fixups.push(...resolved.fixups);
|
|
1730
|
+
const connects = resolveConnects(connectsByPage.get(page.key), resolved.shapes);
|
|
951
1731
|
let xml = page.entry.xml;
|
|
952
1732
|
const open = /^<[^>]*>/.exec(xml)?.[0];
|
|
953
1733
|
if (open) {
|
|
@@ -956,46 +1736,360 @@ function readSharedDrawing(shared) {
|
|
|
956
1736
|
if (back !== void 0) next = setAttr(next, "BackPage", back);
|
|
957
1737
|
xml = next + xml.slice(open.length);
|
|
958
1738
|
}
|
|
1739
|
+
const rename = page.body.b !== void 0 ? renames.get(page.body.b) : void 0;
|
|
1740
|
+
const body = rename && page.body.rels !== void 0 ? { ...page.body, rels: renameTargets(page.body.rels, pagesDir, rename) } : page.body;
|
|
1741
|
+
const contentSignature = hashTexts([
|
|
1742
|
+
body.shell,
|
|
1743
|
+
body.rels ?? "\0",
|
|
1744
|
+
resolved.xml,
|
|
1745
|
+
...connectSignature(connects)
|
|
1746
|
+
]);
|
|
959
1747
|
pages.push({
|
|
960
1748
|
key: page.key,
|
|
961
1749
|
id: finalId,
|
|
962
1750
|
...page.entry.back !== void 0 ? { back: page.entry.back } : {},
|
|
963
1751
|
xml,
|
|
964
|
-
body
|
|
965
|
-
shapes,
|
|
966
|
-
|
|
1752
|
+
body,
|
|
1753
|
+
shapes: resolved.shapes,
|
|
1754
|
+
shapesXml: resolved.xml,
|
|
1755
|
+
connects,
|
|
1756
|
+
signature: hashTexts([xml, contentSignature]),
|
|
1757
|
+
contentSignature
|
|
967
1758
|
});
|
|
968
1759
|
}
|
|
1760
|
+
const mastersDir = mastersPath !== void 0 ? dirName(mastersPath) : pagesDir;
|
|
1761
|
+
const finalMasters = masters.map((m) => {
|
|
1762
|
+
const batch = shared.masters.get(m.key)?.b;
|
|
1763
|
+
const rename = typeof batch === "string" ? renames.get(batch) : void 0;
|
|
1764
|
+
const scope = masterScope(m.key);
|
|
1765
|
+
const resolved = resolveShapes({
|
|
1766
|
+
scope,
|
|
1767
|
+
shapes: shapesByPage.get(scope) ?? /* @__PURE__ */ new Map(),
|
|
1768
|
+
cells: cellsByPage.get(scope) ?? /* @__PURE__ */ new Map(),
|
|
1769
|
+
renum: renumByScope.get(scope) ?? /* @__PURE__ */ new Map(),
|
|
1770
|
+
masterRemap: /* @__PURE__ */ new Map()
|
|
1771
|
+
});
|
|
1772
|
+
fixups.push(...resolved.fixups);
|
|
1773
|
+
return {
|
|
1774
|
+
...m,
|
|
1775
|
+
...rename && m.rels !== void 0 ? { rels: renameTargets(m.rels, mastersDir, rename) } : {},
|
|
1776
|
+
shapes: resolved.shapes,
|
|
1777
|
+
shapesXml: resolved.xml,
|
|
1778
|
+
connects: resolveConnects(connectsByPage.get(scope), resolved.shapes)
|
|
1779
|
+
};
|
|
1780
|
+
});
|
|
969
1781
|
const parts = /* @__PURE__ */ new Map();
|
|
970
1782
|
for (const [path, value] of shared.parts) if (typeof value === "string") parts.set(path, value);
|
|
971
|
-
|
|
1783
|
+
const baseSignature = hashTexts([
|
|
1784
|
+
pagesPath,
|
|
1785
|
+
pagesOpen,
|
|
1786
|
+
pagesClose,
|
|
1787
|
+
mastersPath ?? "",
|
|
1788
|
+
mastersOpen ?? "",
|
|
1789
|
+
mastersClose ?? "",
|
|
1790
|
+
...pages.map((p) => `${p.key}:${p.id}:${p.xml}`),
|
|
1791
|
+
...finalMasters.flatMap((m) => [
|
|
1792
|
+
m.key,
|
|
1793
|
+
m.id,
|
|
1794
|
+
m.xml,
|
|
1795
|
+
m.part,
|
|
1796
|
+
m.rels ?? "\0",
|
|
1797
|
+
m.shapesXml,
|
|
1798
|
+
...connectSignature(m.connects)
|
|
1799
|
+
]),
|
|
1800
|
+
...media.flatMap((m) => [m.path, m.hash, m.declared.type, String(m.declared.byDefault)]),
|
|
1801
|
+
...[...parts].flatMap(([path, data]) => [path, data])
|
|
1802
|
+
]);
|
|
1803
|
+
const signature = hashTexts([
|
|
1804
|
+
baseSignature,
|
|
1805
|
+
...pages.map((p) => `${p.key}:${p.contentSignature}`)
|
|
1806
|
+
]);
|
|
1807
|
+
return {
|
|
1808
|
+
pagesPath,
|
|
1809
|
+
pagesOpen,
|
|
1810
|
+
pagesClose,
|
|
1811
|
+
pages,
|
|
1812
|
+
...mastersPath !== void 0 && mastersOpen !== void 0 && mastersClose !== void 0 ? { mastersPath, mastersOpen, mastersClose } : {},
|
|
1813
|
+
masters: finalMasters,
|
|
1814
|
+
media,
|
|
1815
|
+
parts,
|
|
1816
|
+
signature,
|
|
1817
|
+
baseSignature,
|
|
1818
|
+
fixups
|
|
1819
|
+
};
|
|
972
1820
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
const
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1821
|
+
|
|
1822
|
+
// visio/collab/write-shapes.ts
|
|
1823
|
+
function syncEntry(ctx, map, mapKey, id, content, room, roomContent, local, stamp = false) {
|
|
1824
|
+
ctx.now.set(id, content);
|
|
1825
|
+
const base = ctx.keys.known.get(id);
|
|
1826
|
+
const own = base === void 0 ? !room || roomContent() !== content : base !== content;
|
|
1827
|
+
if (own || !room) {
|
|
1828
|
+
const value = local();
|
|
1829
|
+
ctx.write(map, mapKey, stamp ? { ...value, b: ctx.batch } : value);
|
|
1830
|
+
} else {
|
|
1831
|
+
const pos = local().pos;
|
|
1832
|
+
ctx.write(map, mapKey, pos === void 0 ? room : { ...room, pos });
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
function groupPositions(items, current) {
|
|
1836
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1837
|
+
for (const item of items) groups.set(item.group, [...groups.get(item.group) ?? [], item.key]);
|
|
1838
|
+
const out = /* @__PURE__ */ new Map();
|
|
1839
|
+
for (const list of groups.values())
|
|
1840
|
+
for (const [key, pos] of assignPositions(list, current)) out.set(key, pos);
|
|
1841
|
+
return out;
|
|
1842
|
+
}
|
|
1843
|
+
function syncConnects(ctx, connects) {
|
|
1844
|
+
for (const connect of connects) {
|
|
1845
|
+
ctx.now.set(connectId(connect.key), "");
|
|
1846
|
+
if (!ctx.keys.known.has(connectId(connect.key)) || !ctx.shared.connects.has(connect.key))
|
|
1847
|
+
ctx.write(ctx.shared.connects, connect.key, connect.entry);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
function syncShapes(ctx, page) {
|
|
1851
|
+
const { shared } = ctx;
|
|
1852
|
+
const shapePos = groupPositions(
|
|
1853
|
+
page.shapes.map((s) => ({ key: s.key, group: s.parent ?? "" })),
|
|
1854
|
+
(key) => shapeEntry(shared.shapes.get(`${page.key}/${key}`))?.pos
|
|
1855
|
+
);
|
|
1856
|
+
for (const shape of page.shapes) {
|
|
1857
|
+
const full = `${page.key}/${shape.key}`;
|
|
1858
|
+
const room = shapeEntry(shared.shapes.get(full));
|
|
1859
|
+
const parent = shape.parent;
|
|
1860
|
+
syncEntry(
|
|
1861
|
+
ctx,
|
|
1862
|
+
shared.shapes,
|
|
1863
|
+
full,
|
|
1864
|
+
shapeId(page.key, shape.key),
|
|
1865
|
+
shellContent({ parent, open: shape.open }),
|
|
1866
|
+
room,
|
|
1867
|
+
() => shellContent(room),
|
|
1868
|
+
() => ({
|
|
1869
|
+
pos: shapePos.get(shape.key),
|
|
1870
|
+
...parent !== void 0 ? { parent } : {},
|
|
1871
|
+
open: shape.open,
|
|
1872
|
+
b: room?.b ?? ctx.batch
|
|
1873
|
+
})
|
|
1874
|
+
);
|
|
1875
|
+
const piecePos = groupPositions(
|
|
1876
|
+
shape.pieces.map((p) => ({ key: p.path, group: p.parent })),
|
|
1877
|
+
(path) => cellEntry(shared.cells.get(`${full}/${path}`))?.pos
|
|
1878
|
+
);
|
|
1879
|
+
for (const piece of shape.pieces) {
|
|
1880
|
+
const cellKey = `${full}/${piece.path}`;
|
|
1881
|
+
const roomCell = cellEntry(shared.cells.get(cellKey));
|
|
1882
|
+
const local = () => ({
|
|
1883
|
+
pos: piecePos.get(piece.path),
|
|
1884
|
+
...piece.kind === "leaf" ? { xml: piece.text } : { open: piece.text }
|
|
1885
|
+
});
|
|
1886
|
+
syncEntry(
|
|
1887
|
+
ctx,
|
|
1888
|
+
shared.cells,
|
|
1889
|
+
cellKey,
|
|
1890
|
+
cellId(page.key, shape.key, piece.path),
|
|
1891
|
+
entryContent(piece.kind === "leaf" ? { xml: piece.text } : { open: piece.text }),
|
|
1892
|
+
roomCell,
|
|
1893
|
+
() => entryContent(roomCell),
|
|
1894
|
+
local
|
|
1895
|
+
);
|
|
982
1896
|
}
|
|
983
|
-
const ids = item.ids.map((id) => remap.get(id) ?? id);
|
|
984
|
-
for (const id of ids) used.add(id);
|
|
985
|
-
done.set(item.key, {
|
|
986
|
-
key: item.key,
|
|
987
|
-
id: ids[0] ?? "",
|
|
988
|
-
xml: renumberShape(item.xml, remap),
|
|
989
|
-
remap,
|
|
990
|
-
ids
|
|
991
|
-
});
|
|
992
1897
|
}
|
|
993
|
-
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
// visio/collab/write-parts.ts
|
|
1901
|
+
var mediaKey = (hash, path) => `${hash}|${path}`;
|
|
1902
|
+
function syncMasters(ctx, snapshot) {
|
|
1903
|
+
const { shared } = ctx;
|
|
1904
|
+
const pos = assignPositions(
|
|
1905
|
+
snapshot.masters.map((m) => m.key),
|
|
1906
|
+
(key) => masterEntry(shared.masters.get(key))?.pos
|
|
1907
|
+
);
|
|
1908
|
+
for (const master of snapshot.masters) {
|
|
1909
|
+
const room = masterEntry(shared.masters.get(master.key));
|
|
1910
|
+
syncEntry(
|
|
1911
|
+
ctx,
|
|
1912
|
+
shared.masters,
|
|
1913
|
+
master.key,
|
|
1914
|
+
masterId(master.key),
|
|
1915
|
+
masterContent({ ...master, print: fingerprint(master.part) }),
|
|
1916
|
+
room,
|
|
1917
|
+
() => masterContent({
|
|
1918
|
+
...room,
|
|
1919
|
+
print: fingerprint(fromBase64(room.part))
|
|
1920
|
+
}),
|
|
1921
|
+
() => ({
|
|
1922
|
+
pos: pos.get(master.key),
|
|
1923
|
+
id: master.id,
|
|
1924
|
+
xml: master.xml,
|
|
1925
|
+
part: toBase64(master.part),
|
|
1926
|
+
...master.rels !== void 0 ? { rels: master.rels } : {}
|
|
1927
|
+
}),
|
|
1928
|
+
true
|
|
1929
|
+
);
|
|
1930
|
+
syncShapes(ctx, { key: masterScope(master.key), shapes: master.shapes });
|
|
1931
|
+
syncConnects(ctx, master.connects);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
function syncMedia(ctx, snapshot) {
|
|
1935
|
+
const { shared } = ctx;
|
|
1936
|
+
for (const item of snapshot.media) {
|
|
1937
|
+
const known = ctx.keys.mediaKeys.get(item.path);
|
|
1938
|
+
const key = known?.startsWith(`${item.hash}|`) ? known : mediaKey(item.hash, item.path);
|
|
1939
|
+
ctx.now.set(mediaId(key), "");
|
|
1940
|
+
if (!mediaEntry(shared.media.get(key))) {
|
|
1941
|
+
ctx.write(shared.media, key, {
|
|
1942
|
+
path: item.path,
|
|
1943
|
+
hash: item.hash,
|
|
1944
|
+
ct: item.ct,
|
|
1945
|
+
d: item.d,
|
|
1946
|
+
b: ctx.batch
|
|
1947
|
+
});
|
|
1948
|
+
shared.blobs.set(item.hash, toBase64(item.data));
|
|
1949
|
+
} else if (!shared.blobs.has(item.hash)) shared.blobs.set(item.hash, toBase64(item.data));
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
function syncParts(ctx, snapshot) {
|
|
1953
|
+
const { shared, keys } = ctx;
|
|
1954
|
+
for (const [path, data] of snapshot.parts) {
|
|
1955
|
+
const print = fingerprint(data);
|
|
1956
|
+
if (keys.partPrints.get(path) === print) continue;
|
|
1957
|
+
ctx.write(shared.parts, path, toBase64(data));
|
|
1958
|
+
keys.partPrints.set(path, print);
|
|
1959
|
+
}
|
|
1960
|
+
let removed = 0;
|
|
1961
|
+
for (const path of [...keys.partPrints.keys()])
|
|
1962
|
+
if (!snapshot.parts.has(path)) {
|
|
1963
|
+
shared.parts.delete(path);
|
|
1964
|
+
keys.partPrints.delete(path);
|
|
1965
|
+
removed++;
|
|
1966
|
+
}
|
|
1967
|
+
return removed;
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
// visio/collab/write.ts
|
|
1971
|
+
function removeScope(shared, name) {
|
|
1972
|
+
shared.renum.delete(name);
|
|
1973
|
+
for (const map of [shared.shapes, shared.cells, shared.connects, shared.renum])
|
|
1974
|
+
for (const key of [...map.keys()]) if (key.startsWith(`${name}/`)) map.delete(key);
|
|
1975
|
+
}
|
|
1976
|
+
function removePage(shared, name) {
|
|
1977
|
+
shared.dead.set(name, true);
|
|
1978
|
+
for (const map of [shared.pages, shared.bodies]) map.delete(name);
|
|
1979
|
+
removeScope(shared, name);
|
|
1980
|
+
}
|
|
1981
|
+
function writeSharedDrawing(shared, snapshot, keys) {
|
|
1982
|
+
assertSchemaVersion(shared);
|
|
1983
|
+
let writes = 0;
|
|
1984
|
+
const write = (map, key, value) => {
|
|
1985
|
+
if (setIfChanged(map, key, value)) writes++;
|
|
1986
|
+
};
|
|
1987
|
+
const now = /* @__PURE__ */ new Map();
|
|
1988
|
+
const ctx = { shared, keys, now, batch: keys.batch(), write };
|
|
1989
|
+
write(shared.meta, "v", SCHEMA_VERSION);
|
|
1990
|
+
write(shared.meta, "pagesPath", snapshot.pagesPath);
|
|
1991
|
+
write(shared.meta, "pagesOpen", snapshot.pagesOpen);
|
|
1992
|
+
write(shared.meta, "pagesClose", snapshot.pagesClose);
|
|
1993
|
+
if (snapshot.mastersPath !== void 0) {
|
|
1994
|
+
write(shared.meta, "mastersPath", snapshot.mastersPath);
|
|
1995
|
+
write(shared.meta, "mastersOpen", snapshot.mastersOpen);
|
|
1996
|
+
write(shared.meta, "mastersClose", snapshot.mastersClose);
|
|
1997
|
+
}
|
|
1998
|
+
const pagePos = assignPositions(
|
|
1999
|
+
snapshot.pages.map((p) => p.key),
|
|
2000
|
+
(key) => pageEntry(shared.pages.get(key))?.pos
|
|
2001
|
+
);
|
|
2002
|
+
for (const page of snapshot.pages) {
|
|
2003
|
+
const room = pageEntry(shared.pages.get(page.key));
|
|
2004
|
+
syncEntry(
|
|
2005
|
+
ctx,
|
|
2006
|
+
shared.pages,
|
|
2007
|
+
page.key,
|
|
2008
|
+
pageId(page.key),
|
|
2009
|
+
pageContent(page),
|
|
2010
|
+
room,
|
|
2011
|
+
() => pageContent(room),
|
|
2012
|
+
() => ({
|
|
2013
|
+
pos: pagePos.get(page.key),
|
|
2014
|
+
id: page.id,
|
|
2015
|
+
...page.back !== void 0 ? { back: page.back } : {},
|
|
2016
|
+
xml: page.xml
|
|
2017
|
+
})
|
|
2018
|
+
);
|
|
2019
|
+
const roomBody = bodyEntry(shared.bodies.get(page.key));
|
|
2020
|
+
syncEntry(
|
|
2021
|
+
ctx,
|
|
2022
|
+
shared.bodies,
|
|
2023
|
+
page.key,
|
|
2024
|
+
bodyId(page.key),
|
|
2025
|
+
bodyContent(page),
|
|
2026
|
+
roomBody,
|
|
2027
|
+
() => bodyContent(roomBody),
|
|
2028
|
+
() => ({ shell: page.shell, ...page.rels !== void 0 ? { rels: page.rels } : {} }),
|
|
2029
|
+
true
|
|
2030
|
+
);
|
|
2031
|
+
syncShapes(ctx, page);
|
|
2032
|
+
syncConnects(ctx, page.connects);
|
|
2033
|
+
}
|
|
2034
|
+
syncMasters(ctx, snapshot);
|
|
2035
|
+
syncMedia(ctx, snapshot);
|
|
2036
|
+
for (const id of keys.known.keys()) {
|
|
2037
|
+
if (now.has(id)) continue;
|
|
2038
|
+
const name = id.slice(2);
|
|
2039
|
+
switch (id.slice(0, 2)) {
|
|
2040
|
+
case "p:":
|
|
2041
|
+
removePage(shared, name);
|
|
2042
|
+
keys.forgetPage(name);
|
|
2043
|
+
writes++;
|
|
2044
|
+
break;
|
|
2045
|
+
case "s:": {
|
|
2046
|
+
const slash = name.indexOf("/");
|
|
2047
|
+
const page = name.slice(0, slash);
|
|
2048
|
+
if (!now.has(page.startsWith(masterScope("")) ? masterId(page.slice(2)) : pageId(page)))
|
|
2049
|
+
break;
|
|
2050
|
+
shared.dead.set(name, true);
|
|
2051
|
+
shared.shapes.delete(name);
|
|
2052
|
+
keys.forgetShape(page, name.slice(slash + 1));
|
|
2053
|
+
writes++;
|
|
2054
|
+
break;
|
|
2055
|
+
}
|
|
2056
|
+
case "f:":
|
|
2057
|
+
if (shared.cells.has(name)) {
|
|
2058
|
+
shared.cells.delete(name);
|
|
2059
|
+
writes++;
|
|
2060
|
+
}
|
|
2061
|
+
break;
|
|
2062
|
+
case "c:":
|
|
2063
|
+
if (shared.connects.has(name)) {
|
|
2064
|
+
shared.connects.delete(name);
|
|
2065
|
+
writes++;
|
|
2066
|
+
}
|
|
2067
|
+
break;
|
|
2068
|
+
case "m:":
|
|
2069
|
+
if (shared.masters.has(name)) {
|
|
2070
|
+
shared.masters.delete(name);
|
|
2071
|
+
removeScope(shared, masterScope(name));
|
|
2072
|
+
writes++;
|
|
2073
|
+
}
|
|
2074
|
+
keys.forgetMaster(name);
|
|
2075
|
+
break;
|
|
2076
|
+
case "i:":
|
|
2077
|
+
if (shared.media.has(name)) {
|
|
2078
|
+
shared.media.delete(name);
|
|
2079
|
+
writes++;
|
|
2080
|
+
}
|
|
2081
|
+
break;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
keys.known = now;
|
|
2085
|
+
writes += syncParts(ctx, snapshot);
|
|
2086
|
+
return writes;
|
|
994
2087
|
}
|
|
995
2088
|
|
|
996
2089
|
// visio/collab/bind.ts
|
|
997
2090
|
var VISIO_EDIT_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:visio:edit");
|
|
998
2091
|
var VISIO_SYNC_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:visio:sync");
|
|
2092
|
+
var VISIO_FIXUP_ORIGIN = /* @__PURE__ */ Symbol("ooxml-core:visio:fixup");
|
|
999
2093
|
function bindDrawingSession(host, editor, options = {}) {
|
|
1000
2094
|
const { doc } = host;
|
|
1001
2095
|
const shared = sharedDrawing(doc);
|
|
@@ -1015,6 +2109,12 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1015
2109
|
let settled = false;
|
|
1016
2110
|
let localDirty = false;
|
|
1017
2111
|
let remoteDirty = false;
|
|
2112
|
+
let incompatible = false;
|
|
2113
|
+
let queued = false;
|
|
2114
|
+
let queuedDone;
|
|
2115
|
+
const schedule = options.schedule ?? ((run) => {
|
|
2116
|
+
setTimeout(run, 0);
|
|
2117
|
+
});
|
|
1018
2118
|
let running;
|
|
1019
2119
|
const report = (error) => options.onError?.(error);
|
|
1020
2120
|
const publish = async () => {
|
|
@@ -1033,7 +2133,14 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1033
2133
|
const rebuild = async () => {
|
|
1034
2134
|
const resolved = readSharedDrawing(shared);
|
|
1035
2135
|
if (!resolved) return;
|
|
2136
|
+
if (resolved.fixups.length && host.canWrite())
|
|
2137
|
+
doc.transact(() => applyFixups(shared, resolved.fixups), VISIO_FIXUP_ORIGIN);
|
|
1036
2138
|
const version = editor.version();
|
|
2139
|
+
if (keys.applied?.signature === resolved.signature && keys.applied.version === version) return;
|
|
2140
|
+
const before = keys.applied;
|
|
2141
|
+
const change = before && before.version === version && before.base === resolved.baseSignature ? {
|
|
2142
|
+
pages: resolved.pages.filter((page) => before.pages.get(page.key) !== page.contentSignature).map((page) => page.id)
|
|
2143
|
+
} : void 0;
|
|
1037
2144
|
const composed = await composeDrawing(resolved, editor.exportBytes(), keys);
|
|
1038
2145
|
if (disposed) return;
|
|
1039
2146
|
if (editor.busy() || editor.version() !== version) {
|
|
@@ -1041,15 +2148,21 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1041
2148
|
return;
|
|
1042
2149
|
}
|
|
1043
2150
|
try {
|
|
1044
|
-
await editor.applyRemote(composed.bytes);
|
|
2151
|
+
await editor.applyRemote(composed.bytes, change);
|
|
1045
2152
|
} catch (error) {
|
|
1046
2153
|
if (editor.busy()) remoteDirty = true;
|
|
1047
2154
|
else report(error);
|
|
1048
2155
|
return;
|
|
1049
2156
|
}
|
|
1050
2157
|
composed.commit();
|
|
2158
|
+
keys.applied = {
|
|
2159
|
+
signature: composed.signature,
|
|
2160
|
+
version: editor.version(),
|
|
2161
|
+
base: resolved.baseSignature,
|
|
2162
|
+
pages: new Map(resolved.pages.map((page) => [page.key, page.contentSignature]))
|
|
2163
|
+
};
|
|
1051
2164
|
};
|
|
1052
|
-
const blocked = () => disposed || !settled || editor.busy();
|
|
2165
|
+
const blocked = () => disposed || incompatible || !settled || editor.busy();
|
|
1053
2166
|
const pending = () => !blocked() && (localDirty && host.canWrite() || remoteDirty && !localDirty);
|
|
1054
2167
|
const loop = async () => {
|
|
1055
2168
|
while (pending()) {
|
|
@@ -1062,6 +2175,7 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1062
2175
|
await rebuild();
|
|
1063
2176
|
}
|
|
1064
2177
|
} catch (error) {
|
|
2178
|
+
if (error instanceof SchemaVersionError) incompatible = true;
|
|
1065
2179
|
report(error);
|
|
1066
2180
|
}
|
|
1067
2181
|
}
|
|
@@ -1088,18 +2202,30 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1088
2202
|
}
|
|
1089
2203
|
pump();
|
|
1090
2204
|
};
|
|
2205
|
+
const queueRemote = () => {
|
|
2206
|
+
if (queued) return;
|
|
2207
|
+
queued = true;
|
|
2208
|
+
queuedDone = new Promise(
|
|
2209
|
+
(resolve) => schedule(() => {
|
|
2210
|
+
queued = false;
|
|
2211
|
+
remoteDirty = true;
|
|
2212
|
+
resolve();
|
|
2213
|
+
pump();
|
|
2214
|
+
})
|
|
2215
|
+
);
|
|
2216
|
+
};
|
|
1091
2217
|
const afterTransaction = (transaction) => {
|
|
1092
2218
|
if (disposed) return;
|
|
1093
2219
|
const origin = transaction.origin;
|
|
1094
|
-
if (origin === VISIO_EDIT_ORIGIN || origin === VISIO_SYNC_ORIGIN)
|
|
2220
|
+
if (origin === VISIO_EDIT_ORIGIN || origin === VISIO_SYNC_ORIGIN || origin === VISIO_FIXUP_ORIGIN)
|
|
2221
|
+
return;
|
|
1095
2222
|
const changed = transaction.changed;
|
|
1096
2223
|
if (!types.some((type) => changed.has(type))) return;
|
|
1097
2224
|
if (!settled) {
|
|
1098
2225
|
if (!isSharedDrawingEmpty(shared)) settle();
|
|
1099
2226
|
return;
|
|
1100
2227
|
}
|
|
1101
|
-
|
|
1102
|
-
pump();
|
|
2228
|
+
queueRemote();
|
|
1103
2229
|
};
|
|
1104
2230
|
doc.on("afterTransaction", afterTransaction);
|
|
1105
2231
|
const stops = [
|
|
@@ -1117,7 +2243,10 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1117
2243
|
];
|
|
1118
2244
|
if (host.synced || host.canWrite()) settle();
|
|
1119
2245
|
const idle = async () => {
|
|
1120
|
-
while (running)
|
|
2246
|
+
while (running || queued) {
|
|
2247
|
+
if (queued) await queuedDone;
|
|
2248
|
+
if (running) await running;
|
|
2249
|
+
}
|
|
1121
2250
|
};
|
|
1122
2251
|
const replay = async (kind) => {
|
|
1123
2252
|
await idle();
|
|
@@ -1149,4 +2278,4 @@ function bindDrawingSession(host, editor, options = {}) {
|
|
|
1149
2278
|
};
|
|
1150
2279
|
}
|
|
1151
2280
|
|
|
1152
|
-
export { BODIES, CONNECTS, DEAD, DrawingKeys, META, PAGES, PARTS, SCHEMA_VERSION, SHAPES, VISIO_EDIT_ORIGIN, VISIO_SYNC_ORIGIN, bindDrawingSession, composeDrawing, isSharedDrawingEmpty, readSharedDrawing, sharedDrawing, snapshotDrawing, writeSharedDrawing };
|
|
2281
|
+
export { BLOBS, BODIES, CELLS, CONNECTS, DEAD, DrawingKeys, MASTERS, MEDIA, META, PAGES, PARTS, RENUM, SCHEMA_VERSION, SHAPES, SchemaVersionError, VISIO_EDIT_ORIGIN, VISIO_FIXUP_ORIGIN, VISIO_SYNC_ORIGIN, applyFixups, bindDrawingSession, composeDrawing, isSharedDrawingEmpty, readSharedDrawing, sharedDrawing, snapshotDrawing, writeSharedDrawing };
|