y-mxgraph 0.3.1 → 0.4.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/y-mxgraph.iife.js DELETED
@@ -1,1758 +0,0 @@
1
- var YMXGraph = function(exports, xmlJs, Y2, lodashEs, colord2, iframeBridge) {
2
- "use strict";
3
- function _interopNamespaceDefault(e) {
4
- const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
5
- if (e) {
6
- for (const k in e) {
7
- if (k !== "default") {
8
- const d = Object.getOwnPropertyDescriptor(e, k);
9
- Object.defineProperty(n, k, d.get ? d : {
10
- enumerable: true,
11
- get: () => e[k]
12
- });
13
- }
14
- }
15
- }
16
- n.default = e;
17
- return Object.freeze(n);
18
- }
19
- const Y__namespace = /* @__PURE__ */ _interopNamespaceDefault(Y2);
20
- function deepProcess(node) {
21
- if (node == null)
22
- return;
23
- if (Array.isArray(node)) {
24
- for (const item of node) {
25
- deepProcess(item);
26
- }
27
- return;
28
- }
29
- if (typeof node !== "object")
30
- return;
31
- const obj = node;
32
- const keys = Object.keys(obj);
33
- for (const key2 of keys) {
34
- if (key2 === "_attributes")
35
- continue;
36
- let value = obj[key2];
37
- const keyLower = key2.toLowerCase();
38
- if ((keyLower === "diagram" || keyLower === "mxcell") && value !== void 0 && !Array.isArray(value)) {
39
- obj[key2] = [value];
40
- value = obj[key2];
41
- }
42
- if (Array.isArray(value)) {
43
- for (const v of value)
44
- deepProcess(v);
45
- } else if (value && typeof value === "object") {
46
- deepProcess(value);
47
- }
48
- }
49
- }
50
- function parse$4(xml) {
51
- const result = xmlJs.xml2js(xml, { compact: true });
52
- deepProcess(result);
53
- return result;
54
- }
55
- function serializer$1(obj, spaces = 2) {
56
- return xmlJs.js2xml(obj, {
57
- compact: true,
58
- spaces
59
- });
60
- }
61
- const key$3 = "mxCell";
62
- const mxGeometryKey = "mxGeometry";
63
- const mxGeometryAttributeKey = "geometry";
64
- function parse$3(object) {
65
- var _a;
66
- const xmlElement = new Y__namespace.XmlElement("mxCell");
67
- for (const attribute of Object.keys(object._attributes || {})) {
68
- xmlElement.setAttribute(
69
- attribute,
70
- `${((_a = object._attributes) == null ? void 0 : _a[attribute]) || ""}`
71
- );
72
- }
73
- if (object[mxGeometryKey]) {
74
- const geometry = object[mxGeometryKey];
75
- const geometryString = xmlJs.js2xml(geometry, {
76
- compact: true
77
- });
78
- xmlElement.setAttribute(mxGeometryAttributeKey, geometryString);
79
- delete object[mxGeometryKey];
80
- }
81
- return xmlElement;
82
- }
83
- function serialize$2(xmlElement) {
84
- const rawAttributes = {
85
- ...xmlElement.getAttributes()
86
- };
87
- let mxGeometry = null;
88
- let mxGeometryString;
89
- if (mxGeometryAttributeKey in rawAttributes) {
90
- mxGeometryString = rawAttributes[mxGeometryAttributeKey];
91
- delete rawAttributes[mxGeometryAttributeKey];
92
- }
93
- const attributes = {};
94
- for (const [key2, value] of Object.entries(rawAttributes)) {
95
- if (typeof value === "string") {
96
- attributes[key2] = value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
97
- } else if (value != null) {
98
- attributes[key2] = String(value);
99
- }
100
- }
101
- if (mxGeometryString) {
102
- try {
103
- const parsed = xmlJs.xml2js(mxGeometryString, { compact: true });
104
- mxGeometry = parsed[mxGeometryKey] ?? null;
105
- if (mxGeometry && mxGeometry._attributes) {
106
- mxGeometry._attributes["as"] = "geometry";
107
- }
108
- } catch (e) {
109
- console.warn("[y-mxgraph] Failed to parse mxGeometry:", e);
110
- }
111
- }
112
- const obj = {
113
- _attributes: attributes
114
- };
115
- if (mxGeometry) {
116
- obj[mxGeometryKey] = mxGeometry;
117
- }
118
- return obj;
119
- }
120
- const key$2 = "mxGraphModel";
121
- const mxCellOrderKey = key$3 + "Order";
122
- function parse$2(object, doc) {
123
- const mxCells = (object.root[key$3] || []).map((cell) => {
124
- var _a;
125
- return {
126
- value: parse$3(cell),
127
- id: ((_a = cell._attributes) == null ? void 0 : _a.id) || ""
128
- };
129
- });
130
- const mxGraphElement = (doc == null ? void 0 : doc.getMap(key$2)) || new Y__namespace.Map();
131
- const cells = new Y__namespace.Map();
132
- const cellsOrder = new Y__namespace.Array();
133
- mxCells.forEach((cell) => {
134
- cells.set(cell.id, cell.value);
135
- });
136
- cellsOrder.push(mxCells.map((cell) => cell.id));
137
- mxGraphElement.set(key$3, cells);
138
- mxGraphElement.set(mxCellOrderKey, cellsOrder);
139
- return mxGraphElement;
140
- }
141
- function serialize$1(map) {
142
- const cells = map.get(key$3);
143
- const cellsOrder = map.get(mxCellOrderKey);
144
- return {
145
- _attributes: {},
146
- root: {
147
- [key$3]: cellsOrder.toArray().map((id) => serialize$2(cells.get(id)))
148
- }
149
- };
150
- }
151
- const key$1 = "diagram";
152
- function parse$1(object) {
153
- var _a, _b;
154
- const yDiagramElement = new Y__namespace.Map();
155
- yDiagramElement.set("name", `${((_a = object._attributes) == null ? void 0 : _a.name) || ""}`);
156
- yDiagramElement.set("id", `${((_b = object._attributes) == null ? void 0 : _b.id) || ""}`);
157
- const mxGraphModel = parse$2(object[key$2]);
158
- yDiagramElement.set(key$2, mxGraphModel);
159
- return yDiagramElement;
160
- }
161
- function serialize(yDiagram) {
162
- const mxGraphModel = yDiagram.get(key$2);
163
- return {
164
- _attributes: {
165
- name: yDiagram.get("name"),
166
- id: yDiagram.get("id")
167
- },
168
- [key$2]: mxGraphModel ? serialize$1(mxGraphModel) : void 0
169
- };
170
- }
171
- const key = "mxfile";
172
- const diagramOrderKey = key$1 + "Order";
173
- function parse(object, doc) {
174
- var _a;
175
- const mxfile = doc.getMap(key);
176
- mxfile.set("pages", (((_a = object._attributes) == null ? void 0 : _a.pages) || "1") + "");
177
- const diagramList = object.diagram.map((diagram) => {
178
- var _a2;
179
- return {
180
- value: parse$1(diagram),
181
- id: ((_a2 = diagram._attributes) == null ? void 0 : _a2.id) || ""
182
- };
183
- });
184
- const diagramMap = new Y__namespace.Map();
185
- const diagramOrder = new Y__namespace.Array();
186
- diagramList.forEach((diagram) => {
187
- diagramMap.set(diagram.id, diagram.value);
188
- });
189
- diagramOrder.push(diagramList.map((diagram) => diagram.id));
190
- mxfile.set(key$1, diagramMap);
191
- mxfile.set(diagramOrderKey, diagramOrder);
192
- return mxfile;
193
- }
194
- function serializer(yMxFile) {
195
- const diagrams = yMxFile.get(key$1);
196
- const diagramOrder = yMxFile.get(
197
- diagramOrderKey
198
- );
199
- const orderIds = diagramOrder ? diagramOrder.toArray() : [];
200
- const ids = orderIds.length > 0 ? orderIds : diagrams ? Array.from(diagrams.keys()) : [];
201
- const obj = {
202
- _attributes: {
203
- pages: yMxFile.get("pages") || "1"
204
- },
205
- [key$1]: ids.map((id) => diagrams.get(id)).filter((d) => !!d).map((diagramElement) => serialize(diagramElement))
206
- };
207
- return obj;
208
- }
209
- const DIFF_INSERT = "i";
210
- const DIFF_REMOVE = "r";
211
- const DIFF_UPDATE = "u";
212
- const docSnapshots = /* @__PURE__ */ new WeakMap();
213
- function insertAfterUnique(orderArr, id, previous, fallbackToEnd = false) {
214
- const currentIds = orderArr.toArray();
215
- let anchorPos = previous ? currentIds.indexOf(previous) : -1;
216
- if (anchorPos === -1 && fallbackToEnd)
217
- anchorPos = currentIds.length - 1;
218
- let targetIndex = anchorPos + 1;
219
- const existingIndex = currentIds.indexOf(id);
220
- if (existingIndex === -1) {
221
- orderArr.insert(targetIndex, [id]);
222
- return;
223
- }
224
- if (existingIndex === targetIndex)
225
- return;
226
- if (existingIndex < targetIndex)
227
- targetIndex -= 1;
228
- orderArr.delete(existingIndex, 1);
229
- orderArr.insert(targetIndex, [id]);
230
- }
231
- function ensureUniqueOrder(orderArr) {
232
- const arr = orderArr.toArray();
233
- const seen = /* @__PURE__ */ new Set();
234
- const dupIdx = [];
235
- for (let i = 0; i < arr.length; i++) {
236
- const id = arr[i];
237
- if (!id)
238
- continue;
239
- if (seen.has(id))
240
- dupIdx.push(i);
241
- else
242
- seen.add(id);
243
- }
244
- if (dupIdx.length) {
245
- dupIdx.sort((a, b) => b - a).forEach((idx) => orderArr.delete(idx, 1));
246
- }
247
- }
248
- function applyFilePatch(doc, patch, options) {
249
- doc.transact(() => {
250
- const mxfile = doc.getMap(key);
251
- if (patch[DIFF_REMOVE]) {
252
- const diagramsMap = mxfile.get(key$1);
253
- const orderArr = mxfile.get(
254
- diagramOrderKey
255
- );
256
- ensureUniqueOrder(orderArr);
257
- const orderList = orderArr.toArray();
258
- const removeIds = patch[DIFF_REMOVE];
259
- if (removeIds && removeIds.length) {
260
- const indexList = removeIds.map((id) => orderList.indexOf(id)).filter((i) => i !== -1).sort((a, b) => b - a);
261
- indexList.forEach((idx) => orderArr.delete(idx, 1));
262
- removeIds.forEach((id) => diagramsMap.delete(id));
263
- }
264
- }
265
- if (patch[DIFF_INSERT]) {
266
- const diagramsMap = mxfile.get(key$1);
267
- const orderArr = mxfile.get(
268
- diagramOrderKey
269
- );
270
- ensureUniqueOrder(orderArr);
271
- const currentOrder = orderArr.toArray();
272
- if (currentOrder.length === 0 && diagramsMap && diagramsMap.size > 0) {
273
- const allIds = Array.from(diagramsMap.keys());
274
- orderArr.push(allIds);
275
- }
276
- ensureUniqueOrder(orderArr);
277
- const existingIds = orderArr.toArray();
278
- const existingIndex = /* @__PURE__ */ new Map();
279
- existingIds.forEach((id, idx) => existingIndex.set(id, idx));
280
- const inserts = patch[DIFF_INSERT].map((item, order) => {
281
- const object = parse$4(item.data);
282
- const diagramObj = Array.isArray(object == null ? void 0 : object.diagram) ? object.diagram[0] : object == null ? void 0 : object.diagram;
283
- const diagramElement = parse$1(
284
- diagramObj
285
- );
286
- return {
287
- id: item.id,
288
- previous: item.previous || "",
289
- diagramElement,
290
- order
291
- };
292
- });
293
- const byId = new Map(inserts.map((i) => [i.id, i]));
294
- const computeAnchor = (node) => {
295
- let depth = 1;
296
- let anchorId = "";
297
- let prevId = node.previous;
298
- const seen = /* @__PURE__ */ new Set([node.id]);
299
- while (prevId) {
300
- if (seen.has(prevId)) {
301
- depth = 1;
302
- anchorId = "";
303
- break;
304
- }
305
- seen.add(prevId);
306
- const prevNode = byId.get(prevId);
307
- if (prevNode) {
308
- depth += 1;
309
- prevId = prevNode.previous;
310
- continue;
311
- }
312
- if (existingIndex.has(prevId)) {
313
- anchorId = prevId;
314
- } else {
315
- anchorId = "";
316
- }
317
- break;
318
- }
319
- return { anchorId, depth };
320
- };
321
- const enriched = inserts.map((i) => ({ ...i, ...computeAnchor(i) }));
322
- enriched.sort((a, b) => {
323
- const aIdx = a.anchorId ? existingIndex.get(a.anchorId) : -1;
324
- const bIdx = b.anchorId ? existingIndex.get(b.anchorId) : -1;
325
- if (aIdx !== bIdx)
326
- return aIdx - bIdx;
327
- if (a.depth !== b.depth)
328
- return b.depth - a.depth;
329
- return b.order - a.order;
330
- });
331
- for (const item of enriched) {
332
- diagramsMap.set(item.id, item.diagramElement);
333
- insertAfterUnique(orderArr, item.id, item.anchorId || null);
334
- }
335
- }
336
- if (patch[DIFF_UPDATE]) {
337
- Object.keys(patch[DIFF_UPDATE]).forEach((id) => {
338
- const diagramsMap = mxfile.get(
339
- key$1
340
- );
341
- const diagram = diagramsMap.get(id);
342
- if (diagram) {
343
- const update = patch[DIFF_UPDATE][id];
344
- if ("name" in update) {
345
- diagram.set(
346
- "name",
347
- update.name || ""
348
- );
349
- }
350
- if (update.cells) {
351
- const yMxGraphModel = diagram.get(key$2);
352
- if (!yMxGraphModel)
353
- return;
354
- const cellsMap = yMxGraphModel.get(key$3);
355
- const orderArr = yMxGraphModel.get(mxCellOrderKey);
356
- if (!cellsMap || !orderArr)
357
- return;
358
- ensureUniqueOrder(orderArr);
359
- if (update.cells[DIFF_REMOVE] && update.cells[DIFF_REMOVE].length) {
360
- const orderIds = orderArr.toArray();
361
- const removeIndexList = update.cells[DIFF_REMOVE].map(
362
- (cid) => orderIds.indexOf(cid)
363
- ).filter((i) => i !== -1).sort((a, b) => b - a);
364
- removeIndexList.forEach((idx) => orderArr.delete(idx, 1));
365
- update.cells[DIFF_REMOVE].forEach((cid) => cellsMap.delete(cid));
366
- }
367
- if (update.cells[DIFF_INSERT] && update.cells[DIFF_INSERT].length) {
368
- for (const item of update.cells[DIFF_INSERT]) {
369
- const id2 = item["id"];
370
- if (!id2)
371
- continue;
372
- const xmlElement = new Y__namespace.XmlElement("mxCell");
373
- Object.keys(item).forEach((key2) => {
374
- if (key2 === "previous")
375
- return;
376
- xmlElement.setAttribute(key2, item[key2]);
377
- });
378
- cellsMap.set(id2, xmlElement);
379
- const previous = item["previous"];
380
- const parent = item["parent"];
381
- let anchorId = null;
382
- let fallbackToEnd = true;
383
- if (typeof previous !== "undefined") {
384
- if (previous === "") {
385
- if (parent) {
386
- anchorId = parent;
387
- fallbackToEnd = true;
388
- } else {
389
- anchorId = null;
390
- fallbackToEnd = false;
391
- }
392
- } else {
393
- anchorId = previous;
394
- fallbackToEnd = true;
395
- }
396
- } else if (parent) {
397
- anchorId = parent;
398
- fallbackToEnd = true;
399
- }
400
- insertAfterUnique(
401
- orderArr,
402
- id2,
403
- anchorId,
404
- fallbackToEnd
405
- );
406
- }
407
- }
408
- if (update.cells[DIFF_UPDATE]) {
409
- Object.keys(update.cells[DIFF_UPDATE]).forEach((cid) => {
410
- const updateObj = update.cells[DIFF_UPDATE][cid];
411
- const cell = cellsMap.get(cid);
412
- if (cell) {
413
- Object.keys(updateObj).forEach((k) => {
414
- if (k === "previous")
415
- return;
416
- cell.setAttribute(k, updateObj[k]);
417
- });
418
- }
419
- });
420
- Object.keys(update.cells[DIFF_UPDATE]).forEach((cellId) => {
421
- const updateObj = update.cells[DIFF_UPDATE][cellId];
422
- const hasPrev = "previous" in updateObj;
423
- const hasParent = "parent" in updateObj;
424
- if (!hasPrev && !hasParent)
425
- return;
426
- const prevVal = hasPrev ? updateObj.previous : void 0;
427
- const parentVal = hasParent ? updateObj.parent : void 0;
428
- let anchorId = null;
429
- let fallbackToEnd = true;
430
- if (hasPrev) {
431
- if (prevVal === "") {
432
- if (parentVal) {
433
- anchorId = parentVal;
434
- fallbackToEnd = true;
435
- } else {
436
- anchorId = null;
437
- fallbackToEnd = false;
438
- }
439
- } else {
440
- anchorId = prevVal;
441
- fallbackToEnd = true;
442
- }
443
- } else if (parentVal) {
444
- anchorId = parentVal;
445
- fallbackToEnd = true;
446
- }
447
- const currentIds = orderArr.toArray();
448
- const currentIndex = currentIds.indexOf(cellId);
449
- if (currentIndex === -1) {
450
- let newCell = cellsMap.get(cellId);
451
- if (!newCell) {
452
- newCell = new Y__namespace.XmlElement("mxCell");
453
- newCell.setAttribute("id", cellId);
454
- Object.keys(updateObj).forEach((k) => {
455
- if (k === "previous")
456
- return;
457
- newCell.setAttribute(k, updateObj[k]);
458
- });
459
- cellsMap.set(cellId, newCell);
460
- }
461
- insertAfterUnique(
462
- orderArr,
463
- cellId,
464
- anchorId,
465
- fallbackToEnd
466
- );
467
- return;
468
- }
469
- insertAfterUnique(
470
- orderArr,
471
- cellId,
472
- anchorId,
473
- fallbackToEnd
474
- );
475
- });
476
- }
477
- }
478
- if ("previous" in update) {
479
- const previous = update.previous || null;
480
- const orderArr = mxfile.get(
481
- diagramOrderKey
482
- );
483
- ensureUniqueOrder(orderArr);
484
- insertAfterUnique(orderArr, id, previous, false);
485
- }
486
- }
487
- });
488
- }
489
- }, options == null ? void 0 : options.origin);
490
- }
491
- function initDocSnapshot(doc, resetSnapshot = false) {
492
- try {
493
- const mxfile = doc.getMap(key);
494
- const diagramsMap = mxfile.get(key$1);
495
- const orderArr = mxfile.get(diagramOrderKey);
496
- const orderIds = orderArr ? orderArr.toArray() : [];
497
- const allDiagramIds = orderIds.length > 0 ? orderIds : diagramsMap ? Array.from(diagramsMap.keys()) : [];
498
- const diagramOrder = resetSnapshot ? [] : allDiagramIds.slice();
499
- const snap = {
500
- diagramOrder,
501
- cellsOrder: /* @__PURE__ */ new Map(),
502
- cellAttrs: /* @__PURE__ */ new Map()
503
- };
504
- const diagrams = diagramOrder.map((id) => diagramsMap.get(id)).filter((d) => !!d);
505
- for (const d of diagrams) {
506
- const did = d.get("id") || "";
507
- if (!did)
508
- continue;
509
- const gm = d.get(key$2);
510
- if (gm) {
511
- const order = gm.get(mxCellOrderKey);
512
- const ids = order ? order.toArray().slice() : [];
513
- snap.cellsOrder.set(did, ids);
514
- const cellsMap = gm.get(key$3);
515
- const attrMap = /* @__PURE__ */ new Map();
516
- if (cellsMap) {
517
- for (const cid of ids) {
518
- const el = cellsMap.get(cid);
519
- if (el) {
520
- attrMap.set(
521
- cid,
522
- el.getAttributes() || {}
523
- );
524
- }
525
- }
526
- }
527
- snap.cellAttrs.set(did, attrMap);
528
- } else {
529
- snap.cellsOrder.set(did, []);
530
- snap.cellAttrs.set(did, /* @__PURE__ */ new Map());
531
- }
532
- }
533
- docSnapshots.set(doc, snap);
534
- } catch (e) {
535
- console.warn("[y-mxgraph] initDocSnapshot failed:", e);
536
- }
537
- }
538
- function generatePatch(events, explicitDoc) {
539
- var _a, _b;
540
- const patch = {};
541
- const doc = explicitDoc ?? ((_b = (_a = events[0]) == null ? void 0 : _a.transaction) == null ? void 0 : _b.doc);
542
- if (!doc)
543
- return patch;
544
- if (!explicitDoc && (!events || events.length === 0))
545
- return patch;
546
- const mxfile = doc.getMap(key);
547
- const diagramsMap = mxfile.get(key$1);
548
- const orderArr = mxfile.get(diagramOrderKey);
549
- let snap = docSnapshots.get(doc);
550
- if (!snap) {
551
- snap = {
552
- diagramOrder: null,
553
- cellsOrder: /* @__PURE__ */ new Map(),
554
- cellAttrs: /* @__PURE__ */ new Map()
555
- };
556
- docSnapshots.set(doc, snap);
557
- }
558
- const prevDiagramOrder = snap.diagramOrder;
559
- const prevCellsOrder = snap.cellsOrder;
560
- const prevCellsAttrs = snap.cellAttrs;
561
- const ensureUpdate = (diagramId) => {
562
- patch[DIFF_UPDATE] = patch[DIFF_UPDATE] || {};
563
- patch[DIFF_UPDATE][diagramId] = patch[DIFF_UPDATE][diagramId] || {};
564
- return patch[DIFF_UPDATE][diagramId];
565
- };
566
- const ensureCellSection = (diagramId) => {
567
- const u = ensureUpdate(diagramId);
568
- u.cells = u.cells || {};
569
- return u.cells;
570
- };
571
- const orderIds = orderArr.toArray();
572
- const currDiagramOrder = orderIds.length > 0 ? orderIds : diagramsMap ? Array.from(diagramsMap.keys()) : [];
573
- const diagramsList = currDiagramOrder.map((id) => diagramsMap.get(id)).filter((d) => !!d);
574
- const currCellsOrder = /* @__PURE__ */ new Map();
575
- const cellAttrMap = /* @__PURE__ */ new Map();
576
- for (const d of diagramsList) {
577
- const did = d.get("id") || "";
578
- const attrs = /* @__PURE__ */ new Map();
579
- const gm = d.get(key$2);
580
- if (gm) {
581
- const cellsMap = gm.get(key$3);
582
- const orderArr2 = gm.get(mxCellOrderKey);
583
- if (cellsMap && orderArr2) {
584
- const ids = orderArr2.toArray();
585
- currCellsOrder.set(did, ids);
586
- for (const cid of ids) {
587
- const c = cellsMap.get(cid);
588
- if (c)
589
- attrs.set(cid, c.getAttributes() || {});
590
- }
591
- } else {
592
- currCellsOrder.set(did, []);
593
- }
594
- } else {
595
- currCellsOrder.set(did, []);
596
- }
597
- cellAttrMap.set(did, attrs);
598
- }
599
- const insertedDiagramIdGlobal = /* @__PURE__ */ new Set();
600
- const insertedCellIdGlobal = /* @__PURE__ */ new Set();
601
- if (prevDiagramOrder) {
602
- const prevSet = new Set(prevDiagramOrder);
603
- const currSet = new Set(currDiagramOrder);
604
- const removed = prevDiagramOrder.filter(
605
- (id) => !currSet.has(id) && id
606
- );
607
- if (removed.length)
608
- patch[DIFF_REMOVE] = removed;
609
- const removedDiagramSet = new Set(removed);
610
- const inserted = currDiagramOrder.filter(
611
- (id) => !prevSet.has(id) && id
612
- );
613
- if (inserted.length) {
614
- patch[DIFF_INSERT] = patch[DIFF_INSERT] || [];
615
- for (const id of inserted) {
616
- const index = currDiagramOrder.indexOf(id);
617
- const previous = index <= 0 ? "" : currDiagramOrder[index - 1];
618
- const yDiagram = diagramsMap.get(id);
619
- if (!yDiagram)
620
- continue;
621
- const data = serializer$1({ diagram: serialize(yDiagram) });
622
- patch[DIFF_INSERT].push({ id, previous, data });
623
- insertedDiagramIdGlobal.add(id);
624
- }
625
- }
626
- const prevNeighbor = (order, id) => {
627
- const i = order.indexOf(id);
628
- return i <= 0 ? "" : order[i - 1];
629
- };
630
- const common = currDiagramOrder.filter((id) => prevSet.has(id) && id);
631
- for (const id of common) {
632
- const prevP = prevNeighbor(prevDiagramOrder, id);
633
- const currP = prevNeighbor(currDiagramOrder, id);
634
- if (prevP !== currP) {
635
- if (prevP && removedDiagramSet.has(prevP))
636
- continue;
637
- const u = ensureUpdate(id);
638
- u.previous = currP;
639
- }
640
- }
641
- }
642
- const allDiagramIds = /* @__PURE__ */ new Set([
643
- ...prevDiagramOrder || [],
644
- ...currDiagramOrder
645
- ]);
646
- for (const did of allDiagramIds) {
647
- if (!did)
648
- continue;
649
- const prevCells = prevCellsOrder.get(did) || [];
650
- const currCells = currCellsOrder.get(did) || [];
651
- if (!prevCells.length && !currCells.length)
652
- continue;
653
- const prevSet = new Set(prevCells);
654
- const currSet = new Set(currCells);
655
- const removed = prevCells.filter((cid) => !currSet.has(cid) && cid);
656
- if (removed.length) {
657
- const cells = ensureCellSection(did);
658
- cells[DIFF_REMOVE] = (cells[DIFF_REMOVE] || []).concat(removed);
659
- }
660
- const removedCellSet = new Set(removed);
661
- const inserted = currCells.filter(
662
- (cid) => !prevSet.has(cid) && cid
663
- );
664
- if (inserted.length) {
665
- const cells = ensureCellSection(did);
666
- cells[DIFF_INSERT] = cells[DIFF_INSERT] || [];
667
- const attrsMap = cellAttrMap.get(did) || /* @__PURE__ */ new Map();
668
- for (const cid of inserted) {
669
- const attrs = attrsMap.get(cid) || {};
670
- const index = currCells.indexOf(cid);
671
- const previous = index <= 0 ? "" : currCells[index - 1];
672
- cells[DIFF_INSERT].push({
673
- ...attrs,
674
- previous
675
- });
676
- insertedCellIdGlobal.add(cid);
677
- }
678
- }
679
- const prevNeighbor = (order, id) => {
680
- const i = order.indexOf(id);
681
- return i <= 0 ? "" : order[i - 1];
682
- };
683
- const commonCells = currCells.filter((cid) => prevSet.has(cid) && cid);
684
- for (const cid of commonCells) {
685
- const prevP = prevNeighbor(prevCells, cid);
686
- const currP = prevNeighbor(currCells, cid);
687
- if (prevP !== currP) {
688
- if (prevP && removedCellSet.has(prevP))
689
- continue;
690
- const cells = ensureCellSection(did);
691
- cells[DIFF_UPDATE] = cells[DIFF_UPDATE] || {};
692
- const cellUpdate = cells[DIFF_UPDATE][cid] = cells[DIFF_UPDATE][cid] || {};
693
- cellUpdate.previous = currP;
694
- }
695
- }
696
- }
697
- {
698
- const diagramSet = new Set(
699
- diagramsList
700
- );
701
- for (const ev of events) {
702
- const target = ev.target;
703
- if (!(target instanceof Y__namespace.Map))
704
- continue;
705
- if (!diagramSet.has(target))
706
- continue;
707
- const changed = ev.keysChanged || /* @__PURE__ */ new Set();
708
- if (!changed || !changed.has("name"))
709
- continue;
710
- const did = target.get("id") || "";
711
- if (!did || insertedDiagramIdGlobal.has(did))
712
- continue;
713
- const u = ensureUpdate(did);
714
- u.name = target.get("name") || "";
715
- }
716
- }
717
- if (!prevDiagramOrder) {
718
- for (const d of diagramsList) {
719
- const did = d.get("id") || "";
720
- if (!did)
721
- continue;
722
- const u = ensureUpdate(did);
723
- u.name = d.get("name") || "";
724
- }
725
- }
726
- for (const ev of events) {
727
- const target = ev.target;
728
- if (!(target instanceof Y__namespace.XmlElement))
729
- continue;
730
- const el = target;
731
- if (el.nodeName !== "mxCell")
732
- continue;
733
- const changed = ev.attributesChanged || ev.keysChanged || /* @__PURE__ */ new Set();
734
- if (!changed || changed.size === 0)
735
- continue;
736
- const cellId = el.getAttribute("id");
737
- if (!cellId || insertedCellIdGlobal.has(cellId))
738
- continue;
739
- const idsEntries = Array.from(currCellsOrder.entries());
740
- let diagramId = "";
741
- for (const [did, ids] of idsEntries) {
742
- if (ids.includes(cellId)) {
743
- diagramId = did;
744
- break;
745
- }
746
- }
747
- if (!diagramId)
748
- continue;
749
- const cellsPatch = ensureCellSection(diagramId);
750
- cellsPatch[DIFF_UPDATE] = cellsPatch[DIFF_UPDATE] || {};
751
- const cellUpdate = cellsPatch[DIFF_UPDATE][cellId] = cellsPatch[DIFF_UPDATE][cellId] || {};
752
- for (const key2 of Array.from(changed)) {
753
- cellUpdate[key2] = el.getAttribute(key2) || "";
754
- }
755
- }
756
- if (prevDiagramOrder) {
757
- for (const [did, currAttrsMap] of cellAttrMap.entries()) {
758
- const prevAttrsMap = prevCellsAttrs.get(did) || /* @__PURE__ */ new Map();
759
- const cellsPatch = ensureCellSection(did);
760
- cellsPatch[DIFF_UPDATE] = cellsPatch[DIFF_UPDATE] || {};
761
- const updateBucket = cellsPatch[DIFF_UPDATE];
762
- const currCells = currAttrsMap.keys();
763
- for (const cid of currCells) {
764
- if (insertedCellIdGlobal.has(cid))
765
- continue;
766
- const prevAttrs = prevAttrsMap.get(cid) || {};
767
- const currAttrs = currAttrsMap.get(cid) || {};
768
- const keys = /* @__PURE__ */ new Set([
769
- ...Object.keys(prevAttrs),
770
- ...Object.keys(currAttrs)
771
- ]);
772
- const cellUpdate = updateBucket[cid] = updateBucket[cid] || {};
773
- let changed = false;
774
- for (const k of keys) {
775
- const pv = prevAttrs[k] ?? "";
776
- const cv = currAttrs[k] ?? "";
777
- if (pv !== cv) {
778
- cellUpdate[k] = cv;
779
- changed = true;
780
- }
781
- }
782
- if (!changed) {
783
- if (Object.keys(cellUpdate).length === 0) {
784
- delete updateBucket[cid];
785
- }
786
- }
787
- }
788
- }
789
- }
790
- snap.diagramOrder = currDiagramOrder.slice();
791
- const newCellsOrder = /* @__PURE__ */ new Map();
792
- const newCellsAttrs = /* @__PURE__ */ new Map();
793
- for (const [did, arr] of currCellsOrder.entries()) {
794
- newCellsOrder.set(did, arr.slice());
795
- }
796
- for (const [did, attrsMap] of cellAttrMap.entries()) {
797
- const copy = /* @__PURE__ */ new Map();
798
- for (const [cid, attrs] of attrsMap.entries()) {
799
- copy.set(cid, { ...attrs });
800
- }
801
- newCellsAttrs.set(did, copy);
802
- }
803
- snap.cellsOrder = newCellsOrder;
804
- snap.cellAttrs = newCellsAttrs;
805
- docSnapshots.set(doc, snap);
806
- return patch;
807
- }
808
- function xml2doc(xml, doc) {
809
- const object = parse$4(xml);
810
- const mxfile = object.mxfile;
811
- const mxGraphModel = object.mxGraphModel;
812
- if (mxfile) {
813
- doc.transact(() => {
814
- parse(mxfile, doc);
815
- });
816
- } else if (mxGraphModel) {
817
- doc.transact(() => {
818
- parse$2(mxGraphModel, doc);
819
- });
820
- } else {
821
- throw new Error("不支持的文件格式");
822
- }
823
- return doc;
824
- }
825
- function doc2xml(doc, spaces = 0) {
826
- if (doc.share.has(key)) {
827
- return serializer$1(
828
- {
829
- [key]: serializer(
830
- doc.share.get(key)
831
- )
832
- },
833
- spaces
834
- );
835
- } else if (doc.share.has(key$2)) {
836
- return serializer$1(
837
- {
838
- [key$2]: serialize$1(
839
- doc.share.get(key$2)
840
- )
841
- },
842
- spaces
843
- );
844
- }
845
- return "";
846
- }
847
- const LOCAL_ORIGIN = {};
848
- function createMxEventObject(name, props) {
849
- const _props = props || {};
850
- return {
851
- name,
852
- getName: () => name,
853
- getProperty: (k) => _props[k]
854
- };
855
- }
856
- function bindUndoManager(doc, file, yUndo) {
857
- const editor = file.getUi().editor;
858
- const originUndoManager = editor.undoManager;
859
- let lastTxnLocalOrigin = false;
860
- const beforeTxnHandler = (t) => {
861
- lastTxnLocalOrigin = !!(t.local || t.origin === LOCAL_ORIGIN);
862
- };
863
- const afterTxnHandler = (t) => {
864
- lastTxnLocalOrigin = !!(t.local || t.origin === LOCAL_ORIGIN);
865
- };
866
- doc.on("beforeTransaction", beforeTxnHandler);
867
- doc.on("afterTransaction", afterTxnHandler);
868
- const pairs = [];
869
- const raw = Array.isArray(originUndoManager == null ? void 0 : originUndoManager.eventListeners) ? originUndoManager.eventListeners : [];
870
- for (let i = 0; i + 1 < raw.length; i += 2) {
871
- const key2 = String(raw[i]);
872
- const fn = raw[i + 1];
873
- pairs.push([key2, fn]);
874
- }
875
- const mxLike = {
876
- eventListeners: [],
877
- history: [],
878
- indexOfNextAdd: 0,
879
- _y: yUndo,
880
- addListener(name, fn) {
881
- this.eventListeners.push(name, fn);
882
- },
883
- fireEvent(evt) {
884
- var _a;
885
- const eventName = (evt == null ? void 0 : evt.name) || (((_a = evt == null ? void 0 : evt.getName) == null ? void 0 : _a.call(evt)) ?? "");
886
- for (let i = 0; i + 1 < this.eventListeners.length; i += 2) {
887
- const key2 = this.eventListeners[i];
888
- const listener = this.eventListeners[i + 1];
889
- if (key2 === eventName) {
890
- try {
891
- listener(this, evt);
892
- } catch (e) {
893
- console.warn("[y-mxgraph] undoManager event listener error:", e);
894
- }
895
- }
896
- }
897
- },
898
- clear() {
899
- if (typeof this._y.clear === "function") {
900
- this._y.clear();
901
- } else {
902
- while (this._y.canUndo && this._y.canUndo())
903
- this._y.undo();
904
- while (this._y.canRedo && this._y.canRedo())
905
- this._y.redo();
906
- }
907
- this.history = [];
908
- this.indexOfNextAdd = 0;
909
- this.fireEvent(createMxEventObject("clear"));
910
- },
911
- canUndo() {
912
- return typeof this._y.canUndo === "function" && this._y.canUndo();
913
- },
914
- canRedo() {
915
- return typeof this._y.canRedo === "function" && this._y.canRedo();
916
- },
917
- undo() {
918
- this._y.undo();
919
- },
920
- redo() {
921
- this._y.redo();
922
- },
923
- undoableEditHappened() {
924
- }
925
- };
926
- const bridgeHandlers = [];
927
- const bridge = (mxEventName, yEventName) => {
928
- const handler = () => {
929
- if (mxEventName !== "clear" && !lastTxnLocalOrigin) {
930
- return;
931
- }
932
- switch (mxEventName) {
933
- case "add": {
934
- if (mxLike.indexOfNextAdd < mxLike.history.length) {
935
- mxLike.history.splice(
936
- mxLike.indexOfNextAdd,
937
- mxLike.history.length - mxLike.indexOfNextAdd
938
- );
939
- }
940
- mxLike.history.push({});
941
- mxLike.indexOfNextAdd = mxLike.history.length;
942
- break;
943
- }
944
- case "clear": {
945
- mxLike.history = [];
946
- mxLike.indexOfNextAdd = 0;
947
- break;
948
- }
949
- }
950
- const evt = createMxEventObject(mxEventName, { edit: { changes: [] } });
951
- mxLike.fireEvent(evt);
952
- };
953
- yUndo.on(yEventName, handler);
954
- bridgeHandlers.push([yEventName, handler]);
955
- };
956
- bridge("add", "stack-item-added");
957
- bridge("clear", "stack-cleared");
958
- const poppedHandler = (e) => {
959
- const t = e && (e.type || e.reason || e.kind);
960
- if (t === "undo") {
961
- if (mxLike.indexOfNextAdd > 0)
962
- mxLike.indexOfNextAdd--;
963
- const evt = createMxEventObject("undo", { edit: { changes: [] } });
964
- mxLike.fireEvent(evt);
965
- } else if (t === "redo") {
966
- if (mxLike.indexOfNextAdd < mxLike.history.length)
967
- mxLike.indexOfNextAdd++;
968
- const evt = createMxEventObject("redo", { edit: { changes: [] } });
969
- mxLike.fireEvent(evt);
970
- }
971
- };
972
- yUndo.on("stack-item-popped", poppedHandler);
973
- const updatedHandler = () => {
974
- const evt = createMxEventObject("redo", { edit: { changes: [] } });
975
- mxLike.fireEvent(evt);
976
- };
977
- yUndo.on("stack-item-updated", updatedHandler);
978
- pairs.forEach(([key2, fn]) => {
979
- const k = key2.toLowerCase();
980
- if (k === "add" || k === "clear" || k === "undo" || k === "redo") {
981
- mxLike.addListener(k, fn);
982
- }
983
- });
984
- editor.undoManager = mxLike;
985
- editor.undoListener = function() {
986
- };
987
- const destroy = () => {
988
- doc.off("beforeTransaction", beforeTxnHandler);
989
- doc.off("afterTransaction", afterTxnHandler);
990
- bridgeHandlers.forEach(([event, handler]) => {
991
- yUndo.off(event, handler);
992
- });
993
- yUndo.off("stack-item-popped", poppedHandler);
994
- yUndo.off("stack-item-updated", updatedHandler);
995
- editor.undoManager = originUndoManager;
996
- editor.undoListener = originUndoManager == null ? void 0 : originUndoManager.undoListener;
997
- };
998
- return destroy;
999
- }
1000
- function getAwarenessStateValue(awareness, key2, clientId) {
1001
- const states = awareness.getStates();
1002
- const id = clientId != null ? Number(clientId) : awareness.clientID;
1003
- const clientState = states.get(id);
1004
- if (!clientState)
1005
- return null;
1006
- if (!key2)
1007
- return clientState;
1008
- return getByPath(clientState, key2);
1009
- }
1010
- function getByPath(obj, path) {
1011
- const parts = path.split(".");
1012
- let cur = obj;
1013
- for (const part of parts) {
1014
- if (cur == null)
1015
- return null;
1016
- const key2 = Array.isArray(cur) && /^\d+$/.test(part) ? Number(part) : part;
1017
- cur = cur == null ? void 0 : cur[key2];
1018
- }
1019
- return cur;
1020
- }
1021
- function setAwarenessStateValue(awareness, key2, value, clientId) {
1022
- const id = clientId != null ? Number(clientId) : awareness.clientID;
1023
- if (id !== awareness.clientID)
1024
- return false;
1025
- if (!key2) {
1026
- awareness.setLocalState(value);
1027
- return true;
1028
- }
1029
- const current = awareness.getLocalState() || {};
1030
- const next = setByPath(current, key2, value);
1031
- awareness.setLocalState(next);
1032
- return true;
1033
- }
1034
- function setByPath(obj, path, value) {
1035
- const parts = path.split(".");
1036
- const root = Array.isArray(obj) ? obj.slice() : { ...obj };
1037
- let cur = root;
1038
- for (let i = 0; i < parts.length; i++) {
1039
- const part = parts[i];
1040
- const isIndex = /^\d+$/.test(part);
1041
- const key2 = isIndex ? Number(part) : part;
1042
- const isLast = i === parts.length - 1;
1043
- if (isLast) {
1044
- cur[key2] = value;
1045
- } else {
1046
- let next = cur[key2];
1047
- const nextIsIndex = /^\d+$/.test(parts[i + 1]);
1048
- if (next == null) {
1049
- next = nextIsIndex ? [] : {};
1050
- } else {
1051
- next = Array.isArray(next) ? next.slice() : { ...next };
1052
- }
1053
- cur[key2] = next;
1054
- cur = next;
1055
- }
1056
- }
1057
- return root;
1058
- }
1059
- function generateColor(seed) {
1060
- const hash = hashString(String(seed || Math.random()));
1061
- const h = hash % 360;
1062
- const s = 65 + (hash >>> 8) % 20;
1063
- const l = 55 + (hash >>> 16) % 10;
1064
- return hslToHex(h, s, l);
1065
- }
1066
- function generateRandomName() {
1067
- const len = 6;
1068
- const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
1069
- let id = "";
1070
- if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
1071
- const bytes = new Uint8Array(len);
1072
- crypto.getRandomValues(bytes);
1073
- for (let i = 0; i < len; i++) {
1074
- id += alphabet[bytes[i] % alphabet.length];
1075
- }
1076
- } else {
1077
- for (let i = 0; i < len; i++) {
1078
- id += alphabet[Math.floor(Math.random() * alphabet.length)];
1079
- }
1080
- }
1081
- return id;
1082
- }
1083
- function hashString(str) {
1084
- let hash = 5381;
1085
- for (let i = 0; i < str.length; i++) {
1086
- hash = (hash << 5) + hash ^ str.charCodeAt(i);
1087
- }
1088
- return hash >>> 0;
1089
- }
1090
- function hslToHex(h, s, l) {
1091
- s /= 100;
1092
- l /= 100;
1093
- const c = (1 - Math.abs(2 * l - 1)) * s;
1094
- const hp = h / 60;
1095
- const x = c * (1 - Math.abs(hp % 2 - 1));
1096
- let r1 = 0, g1 = 0, b1 = 0;
1097
- if (hp >= 0 && hp < 1)
1098
- [r1, g1, b1] = [c, x, 0];
1099
- else if (hp >= 1 && hp < 2)
1100
- [r1, g1, b1] = [x, c, 0];
1101
- else if (hp >= 2 && hp < 3)
1102
- [r1, g1, b1] = [0, c, x];
1103
- else if (hp >= 3 && hp < 4)
1104
- [r1, g1, b1] = [0, x, c];
1105
- else if (hp >= 4 && hp < 5)
1106
- [r1, g1, b1] = [x, 0, c];
1107
- else
1108
- [r1, g1, b1] = [c, 0, x];
1109
- const m = l - c / 2;
1110
- const r = Math.round((r1 + m) * 255);
1111
- const g = Math.round((g1 + m) * 255);
1112
- const b = Math.round((b1 + m) * 255);
1113
- return "#" + [r, g, b].map((v) => v.toString(16).padStart(2, "0")).join("");
1114
- }
1115
- function createCursorImage(color) {
1116
- const w = 8;
1117
- const h = 12;
1118
- const path = '<path d="M 4 0 L 8 12 L 4 10 L 0 12 Z" stroke="' + color + '" fill="' + color + '"/>';
1119
- const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="' + w + 'px" height="' + h + 'px" viewBox="0 0 ' + w + " " + h + '" version="1.1">' + path + "</svg>";
1120
- const bytes = new Uint8Array(svg.length);
1121
- for (let i = 0; i < svg.length; i++) {
1122
- bytes[i] = svg.charCodeAt(i);
1123
- }
1124
- const encoded = btoa(String.fromCharCode.apply(null, bytes));
1125
- return "data:image/svg+xml;base64," + encoded;
1126
- }
1127
- const CacheKey$1 = "__remoteCursor__";
1128
- function createCursorEl(color, username) {
1129
- const cursor = document.createElement("div");
1130
- cursor.style.position = "absolute";
1131
- cursor.style.opacity = "0.9";
1132
- cursor.style.transition = "all 0.3s ease-in-out";
1133
- const img = document.createElement("img");
1134
- img.style.transform = "rotate(-45deg) translateX(-14px)";
1135
- img.setAttribute("src", createCursorImage(color));
1136
- img.style.width = "10px";
1137
- img.style.transition = "all 0.3s ease-in-out";
1138
- cursor.appendChild(img);
1139
- const name = document.createElement("div");
1140
- name.style.backgroundColor = color;
1141
- name.style.color = colord2.colord(color).isDark() ? "#fff" : "#000";
1142
- name.style.fontSize = "9pt";
1143
- name.style.padding = "3px 7px";
1144
- name.style.marginTop = "8px";
1145
- name.style.borderRadius = "10px";
1146
- name.style.maxWidth = "100px";
1147
- name.style.overflow = "hidden";
1148
- name.style.textOverflow = "ellipsis";
1149
- name.style.whiteSpace = "nowrap";
1150
- name.innerText = username;
1151
- cursor.appendChild(name);
1152
- return cursor;
1153
- }
1154
- function bindCursor(file, options) {
1155
- const graph = options.graph || file.getUi().editor.graph;
1156
- const awareness = options.awareness;
1157
- const mouseMoveThrottle = options.mouseMoveThrottle ?? 100;
1158
- const listener = {
1159
- startX: 0,
1160
- startY: 0,
1161
- scrollLeft: 0,
1162
- scrollTop: 0,
1163
- mouseDown: function() {
1164
- },
1165
- mouseUp: function() {
1166
- },
1167
- mouseMove: lodashEs.throttle(function(_sender, event) {
1168
- var _a;
1169
- const containerRect = graph.container.getBoundingClientRect();
1170
- const { translate, scale } = graph.view;
1171
- const x = Math.round(
1172
- (event.evt.clientX - containerRect.x + graph.container.scrollLeft) / scale - translate.x
1173
- );
1174
- const y = Math.round(
1175
- (event.evt.clientY - containerRect.y + graph.container.scrollTop) / scale - translate.y
1176
- );
1177
- awareness.setLocalStateField("cursor", {
1178
- x,
1179
- y,
1180
- pageId: (_a = file.getUi().currentPage) == null ? void 0 : _a.getId()
1181
- });
1182
- }, mouseMoveThrottle)
1183
- };
1184
- graph.addMouseListener(listener);
1185
- const handleMouseLeave = () => {
1186
- var _a;
1187
- awareness.setLocalStateField("cursor", {
1188
- x: 0,
1189
- y: 0,
1190
- pageId: (_a = file.getUi().currentPage) == null ? void 0 : _a.getId(),
1191
- hide: true
1192
- });
1193
- };
1194
- graph.container.addEventListener("mouseleave", handleMouseLeave);
1195
- return () => {
1196
- graph.removeMouseListener(listener);
1197
- graph.container.removeEventListener("mouseleave", handleMouseLeave);
1198
- };
1199
- }
1200
- function renderRemoteCursors(ui, remotes) {
1201
- var _a;
1202
- if (!(CacheKey$1 in ui)) {
1203
- ui[CacheKey$1] = /* @__PURE__ */ new Map();
1204
- }
1205
- const cache = ui[CacheKey$1];
1206
- const currentPageId = (_a = ui.currentPage) == null ? void 0 : _a.getId();
1207
- if (!currentPageId) {
1208
- Array.from(cache.values()).forEach((el) => el.remove());
1209
- cache.clear();
1210
- return;
1211
- }
1212
- const currentPageRemotes = [];
1213
- const otherPageRemotes = [];
1214
- const leaveRemotesIds = /* @__PURE__ */ new Set();
1215
- Array.from(cache.keys()).forEach((clientId) => {
1216
- if (!remotes.has(clientId))
1217
- leaveRemotesIds.add(clientId);
1218
- });
1219
- Array.from(remotes.values()).forEach((remote) => {
1220
- var _a2;
1221
- if (((_a2 = remote.cursorState) == null ? void 0 : _a2.pageId) === currentPageId) {
1222
- currentPageRemotes.push(remote);
1223
- } else {
1224
- otherPageRemotes.push(remote);
1225
- }
1226
- });
1227
- leaveRemotesIds.forEach((clientId) => {
1228
- const el = cache.get(clientId);
1229
- cache.delete(clientId);
1230
- if (!el)
1231
- return;
1232
- el.remove();
1233
- });
1234
- otherPageRemotes.forEach(({ clientId }) => {
1235
- const el = cache.get(clientId);
1236
- if (!el)
1237
- return;
1238
- el.remove();
1239
- });
1240
- if (!currentPageRemotes.length)
1241
- return;
1242
- const graph = ui.editor.graph;
1243
- const { translate, scale } = graph.view;
1244
- currentPageRemotes.forEach(
1245
- ({ clientId, cursorState, userColor, userName }) => {
1246
- if (!cursorState)
1247
- return;
1248
- let el = cache.get(clientId);
1249
- if (cursorState.hide) {
1250
- if (el) {
1251
- el.remove();
1252
- cache.delete(clientId);
1253
- }
1254
- return;
1255
- }
1256
- if (!el) {
1257
- el = createCursorEl(userColor, userName);
1258
- ui.diagramContainer.appendChild(el);
1259
- cache.set(clientId, el);
1260
- }
1261
- const x = (translate.x + cursorState.x) * scale + 8;
1262
- const y = (translate.y + cursorState.y) * scale - 12;
1263
- const cx = Math.max(
1264
- graph.container.scrollLeft,
1265
- Math.min(
1266
- graph.container.scrollLeft + graph.container.clientWidth - el.clientWidth,
1267
- x
1268
- )
1269
- );
1270
- const cy = Math.max(
1271
- graph.container.scrollTop - 22,
1272
- Math.min(
1273
- graph.container.scrollTop + graph.container.clientHeight - el.clientHeight,
1274
- y
1275
- )
1276
- );
1277
- el.style.left = cx + "px";
1278
- el.style.top = cy + "px";
1279
- el.style.display = "";
1280
- }
1281
- );
1282
- }
1283
- function getId(item) {
1284
- if (item.id)
1285
- return item.id;
1286
- return null;
1287
- }
1288
- const SELECTION_OPACITY = 70;
1289
- const CacheKey = "__remoteSelection__";
1290
- function bindSelection(file, options) {
1291
- const graph = options.graph || file.getUi().editor.graph;
1292
- const awareness = options.awareness;
1293
- const handler = function() {
1294
- var _a;
1295
- const pageId = (_a = file.getUi().currentPage) == null ? void 0 : _a.getId();
1296
- const cells = graph.getSelectionModel().cells;
1297
- const ids = Object.keys(cells || {}).map(
1298
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1299
- (key2) => getId(cells[key2])
1300
- ).filter(Boolean);
1301
- awareness.setLocalStateField("selection", { ids, pageId });
1302
- };
1303
- const selectionModel = graph.getSelectionModel();
1304
- selectionModel.addListener("change", handler);
1305
- return () => {
1306
- selectionModel.removeListener("change", handler);
1307
- };
1308
- }
1309
- function renderRemoteSelections(ui, remotes) {
1310
- var _a;
1311
- if (!(CacheKey in ui)) {
1312
- ui[CacheKey] = /* @__PURE__ */ new Map();
1313
- }
1314
- const cache = ui[CacheKey];
1315
- const currentPageId = (_a = ui.currentPage) == null ? void 0 : _a.getId();
1316
- if (!currentPageId) {
1317
- cache.clear();
1318
- return;
1319
- }
1320
- const currentPageRemotes = [];
1321
- const otherPageRemotes = [];
1322
- const leaveRemotesIds = /* @__PURE__ */ new Set();
1323
- Array.from(cache.keys()).forEach((clientId) => {
1324
- if (!remotes.has(clientId))
1325
- leaveRemotesIds.add(clientId);
1326
- });
1327
- Array.from(remotes.values()).forEach((remote) => {
1328
- var _a2;
1329
- if (((_a2 = remote.selectionState) == null ? void 0 : _a2.pageId) === currentPageId) {
1330
- currentPageRemotes.push(remote);
1331
- } else {
1332
- otherPageRemotes.push(remote);
1333
- }
1334
- });
1335
- leaveRemotesIds.forEach((clientId) => {
1336
- const highlightCellMap = cache.get(clientId);
1337
- cache.delete(clientId);
1338
- if (!highlightCellMap)
1339
- return;
1340
- Array.from(highlightCellMap.values()).forEach((h) => h.destroy());
1341
- highlightCellMap.clear();
1342
- });
1343
- otherPageRemotes.forEach(({ clientId }) => {
1344
- const highlightCellMap = cache.get(clientId);
1345
- if (!highlightCellMap)
1346
- return;
1347
- Array.from(highlightCellMap.values()).forEach((h) => h.destroy());
1348
- highlightCellMap.clear();
1349
- });
1350
- if (!currentPageRemotes.length)
1351
- return;
1352
- const graph = ui.editor.graph;
1353
- currentPageRemotes.forEach(({ clientId, selectionState, userColor }) => {
1354
- let highlightCellMap = cache.get(clientId);
1355
- if (!highlightCellMap) {
1356
- highlightCellMap = /* @__PURE__ */ new Map();
1357
- cache.set(clientId, highlightCellMap);
1358
- }
1359
- const currentIds = new Set((selectionState == null ? void 0 : selectionState.ids) ?? []);
1360
- Array.from(highlightCellMap.keys()).forEach((id) => {
1361
- var _a2;
1362
- if (!currentIds.has(id)) {
1363
- (_a2 = highlightCellMap.get(id)) == null ? void 0 : _a2.destroy();
1364
- highlightCellMap.delete(id);
1365
- }
1366
- });
1367
- currentIds.forEach((id) => {
1368
- if (highlightCellMap.has(id))
1369
- return;
1370
- const cell = graph.model.getCell(id);
1371
- if (cell) {
1372
- const highlightCell = graph.highlightCell(
1373
- cell,
1374
- userColor,
1375
- 6e4,
1376
- SELECTION_OPACITY,
1377
- 3
1378
- );
1379
- highlightCellMap.set(id, highlightCell);
1380
- }
1381
- });
1382
- });
1383
- }
1384
- const DEFAULT_USER_NAME_KEY = "user.name";
1385
- const DEFAULT_USER_COLOR_KEY = "user.color";
1386
- function bindCollaborator(file, options) {
1387
- const graph = options.graph || file.getUi().editor.graph;
1388
- const awareness = options.awareness;
1389
- const mouseMoveThrottle = options.mouseMoveThrottle ?? 100;
1390
- const cursorOption = options.cursor;
1391
- const userNameKey = typeof cursorOption === "object" && (cursorOption == null ? void 0 : cursorOption.userNameKey) ? cursorOption.userNameKey : DEFAULT_USER_NAME_KEY;
1392
- const userColorKey = typeof cursorOption === "object" && (cursorOption == null ? void 0 : cursorOption.userColorKey) ? cursorOption.userColorKey : DEFAULT_USER_COLOR_KEY;
1393
- let userName = getAwarenessStateValue(awareness, userNameKey);
1394
- if (!userName) {
1395
- userName = generateRandomName();
1396
- setAwarenessStateValue(awareness, userNameKey, userName);
1397
- }
1398
- let userColor = getAwarenessStateValue(awareness, userColorKey);
1399
- if (!userColor) {
1400
- userColor = generateColor(userName);
1401
- setAwarenessStateValue(awareness, userColorKey, userColor);
1402
- }
1403
- const cleanupCursor = bindCursor(file, {
1404
- awareness,
1405
- graph,
1406
- mouseMoveThrottle
1407
- });
1408
- const cleanupSelection = bindSelection(file, {
1409
- awareness,
1410
- graph
1411
- });
1412
- const showCursor = options.cursor ?? true;
1413
- let cleanupAwareness;
1414
- if (typeof showCursor === "boolean" && showCursor) {
1415
- const awarenessHandler = (update) => {
1416
- const states = awareness.getStates();
1417
- const remotes = /* @__PURE__ */ new Map();
1418
- const changedClientIds = /* @__PURE__ */ new Set([...update.added, ...update.updated]);
1419
- for (const [clientId] of states.entries()) {
1420
- if (clientId === awareness.clientID)
1421
- continue;
1422
- if (!changedClientIds.has(clientId))
1423
- continue;
1424
- const name = getAwarenessStateValue(awareness, userNameKey, clientId) || clientId + "";
1425
- const color = getAwarenessStateValue(awareness, userColorKey, clientId) || "#000000";
1426
- remotes.set(clientId, {
1427
- clientId,
1428
- cursorState: getAwarenessStateValue(
1429
- awareness,
1430
- "cursor",
1431
- clientId
1432
- ),
1433
- selectionState: getAwarenessStateValue(
1434
- awareness,
1435
- "selection",
1436
- clientId
1437
- ),
1438
- userColor: color,
1439
- userName: name
1440
- });
1441
- }
1442
- renderRemoteCursors(file.getUi(), remotes);
1443
- renderRemoteSelections(file.getUi(), remotes);
1444
- };
1445
- awareness.on("update", awarenessHandler);
1446
- cleanupAwareness = () => awareness.off("update", awarenessHandler);
1447
- }
1448
- return () => {
1449
- cleanupCursor == null ? void 0 : cleanupCursor();
1450
- cleanupSelection == null ? void 0 : cleanupSelection();
1451
- cleanupAwareness == null ? void 0 : cleanupAwareness();
1452
- };
1453
- }
1454
- const defaultApplyFileData = (file, xml) => {
1455
- file.ui.setFileData(xml);
1456
- };
1457
- function mergeFileIntoDoc(doc, fileXml, strategy) {
1458
- let parsed;
1459
- try {
1460
- parsed = parse$4(fileXml);
1461
- } catch (err) {
1462
- console.warn(
1463
- "[y-mxgraph] 合并失败,file XML 解析异常,回退到 replace:",
1464
- err
1465
- );
1466
- return false;
1467
- }
1468
- const mxfileObj = parsed == null ? void 0 : parsed.mxfile;
1469
- if (!mxfileObj || !Array.isArray(mxfileObj.diagram)) {
1470
- console.warn(
1471
- "[y-mxgraph] 合并失败,file XML 不是合法 mxfile,回退到 replace"
1472
- );
1473
- return false;
1474
- }
1475
- const mxfileMap = doc.getMap(key);
1476
- const diagramMap = mxfileMap.get(key$1);
1477
- const diagramOrder = mxfileMap.get(diagramOrderKey);
1478
- if (!diagramMap || !diagramOrder) {
1479
- console.warn("[y-mxgraph] 合并失败,doc 结构不完整,回退到 replace");
1480
- return false;
1481
- }
1482
- doc.transact(() => {
1483
- var _a;
1484
- for (const diagram of mxfileObj.diagram) {
1485
- const id = ((_a = diagram._attributes) == null ? void 0 : _a.id) || "";
1486
- if (!id)
1487
- continue;
1488
- const docHas = diagramMap.has(id);
1489
- if (docHas && strategy === "merge-remote") {
1490
- continue;
1491
- }
1492
- const yDiagram = parse$1(
1493
- diagram
1494
- );
1495
- diagramMap.set(id, yDiagram);
1496
- if (!docHas) {
1497
- diagramOrder.push([id]);
1498
- }
1499
- }
1500
- });
1501
- return true;
1502
- }
1503
- function reconcileInitialContent(doc, file, strategy, applyFileData) {
1504
- const mxfileMap = doc.getMap(key);
1505
- const docHasData = mxfileMap.size > 0;
1506
- const fileHasAnyData = !!file.data;
1507
- const fileHasDiagrams = fileHasAnyData && file.data.includes("<diagram");
1508
- if (strategy === "replace") {
1509
- if (docHasData) {
1510
- const xml2 = doc2xml(doc);
1511
- if (xml2 && xml2.includes("<diagram")) {
1512
- applyFileData(file, xml2);
1513
- } else if (!fileHasAnyData) {
1514
- applyFileData(file, Binding.generateFileTemplate("diagram-0"));
1515
- }
1516
- } else if (!fileHasAnyData) {
1517
- applyFileData(file, Binding.generateFileTemplate("diagram-0"));
1518
- }
1519
- return mxfileMap.size > 0;
1520
- }
1521
- if (!docHasData && !fileHasDiagrams) {
1522
- if (!fileHasAnyData) {
1523
- applyFileData(file, Binding.generateFileTemplate("diagram-0"));
1524
- }
1525
- return false;
1526
- }
1527
- if (!docHasData && fileHasDiagrams) {
1528
- try {
1529
- doc.transact(() => {
1530
- xml2doc(file.data, doc);
1531
- });
1532
- return true;
1533
- } catch (err) {
1534
- console.warn(
1535
- "[y-mxgraph] merge 模式下 xml2doc 失败,回退 replace:",
1536
- err
1537
- );
1538
- applyFileData(file, Binding.generateFileTemplate("diagram-0"));
1539
- return false;
1540
- }
1541
- }
1542
- if (docHasData && !fileHasDiagrams) {
1543
- const xml2 = doc2xml(doc);
1544
- if (xml2 && xml2.includes("<diagram")) {
1545
- applyFileData(file, xml2);
1546
- } else if (!fileHasAnyData) {
1547
- applyFileData(file, Binding.generateFileTemplate("diagram-0"));
1548
- }
1549
- return mxfileMap.size > 0;
1550
- }
1551
- const ok = mergeFileIntoDoc(doc, file.data, strategy);
1552
- if (!ok) {
1553
- const xml2 = doc2xml(doc);
1554
- if (xml2 && xml2.includes("<diagram"))
1555
- applyFileData(file, xml2);
1556
- return mxfileMap.size > 0;
1557
- }
1558
- const xml = doc2xml(doc);
1559
- if (xml && xml.includes("<diagram"))
1560
- applyFileData(file, xml);
1561
- return true;
1562
- }
1563
- class Binding {
1564
- constructor(file, options) {
1565
- this.suppressLocalApply = false;
1566
- this.docInitialized = false;
1567
- this.ui = null;
1568
- const {
1569
- doc,
1570
- awareness,
1571
- undoManager,
1572
- mouseMoveThrottle,
1573
- cursor,
1574
- initialContent = "replace",
1575
- applyFileData = defaultApplyFileData,
1576
- disableBeforeUnload = true
1577
- } = options;
1578
- this.doc = doc;
1579
- this.initialContentStrategy = initialContent;
1580
- const ui = file.getUi();
1581
- const graph = ui.editor.graph;
1582
- this.mxGraphModel = graph.model;
1583
- this.ui = ui;
1584
- if (disableBeforeUnload) {
1585
- ui.onBeforeUnload = () => null;
1586
- }
1587
- this.suppressLocalApply = true;
1588
- try {
1589
- this.docInitialized = reconcileInitialContent(
1590
- doc,
1591
- file,
1592
- initialContent,
1593
- applyFileData
1594
- );
1595
- if (this.docInitialized) {
1596
- initDocSnapshot(doc, false);
1597
- }
1598
- } finally {
1599
- this.suppressLocalApply = false;
1600
- }
1601
- file.setShadowPages(file.ui.clonePages(file.ui.pages));
1602
- this.mxListener = () => {
1603
- if (this.suppressLocalApply)
1604
- return;
1605
- const patch = file.ui.diffPages(
1606
- file.shadowPages,
1607
- file.ui.pages
1608
- );
1609
- const patchKeys = Object.keys(patch);
1610
- if (patchKeys.length === 0)
1611
- return;
1612
- if (!this.docInitialized) {
1613
- doc.transact(() => {
1614
- xml2doc(file.data, doc);
1615
- initDocSnapshot(doc, false);
1616
- });
1617
- this.docInitialized = true;
1618
- }
1619
- file.setShadowPages(file.ui.clonePages(file.ui.pages));
1620
- applyFilePatch(doc, patch, { origin: LOCAL_ORIGIN });
1621
- this.resetEditorStatus();
1622
- };
1623
- this.mxGraphModel.addListener("change", this.mxListener);
1624
- this.docObserver = (events, transaction) => {
1625
- if (transaction.local && transaction.origin === LOCAL_ORIGIN) {
1626
- generatePatch(events);
1627
- return;
1628
- }
1629
- if (this.shouldReplaceWhenDocHasData && !transaction.local) {
1630
- const mxfileMap = doc.getMap(key);
1631
- const diagramMap = mxfileMap.get(key$1);
1632
- if (diagramMap && diagramMap.size > 0) {
1633
- const xml = doc2xml(doc);
1634
- if (xml && xml.includes("<diagram")) {
1635
- this.suppressLocalApply = true;
1636
- try {
1637
- applyFileData(file, xml);
1638
- file.setShadowPages(file.ui.clonePages(file.ui.pages));
1639
- initDocSnapshot(doc, false);
1640
- this.resetEditorStatus();
1641
- } finally {
1642
- this.suppressLocalApply = false;
1643
- }
1644
- this.docInitialized = true;
1645
- return;
1646
- }
1647
- }
1648
- }
1649
- if (!this.docInitialized) {
1650
- this.docInitialized = true;
1651
- }
1652
- const patch = generatePatch(events);
1653
- if (Object.keys(patch).length === 0)
1654
- return;
1655
- this.suppressLocalApply = true;
1656
- try {
1657
- file.patch([patch]);
1658
- file.setShadowPages(file.ui.clonePages(file.ui.pages));
1659
- this.resetEditorStatus();
1660
- } finally {
1661
- this.suppressLocalApply = false;
1662
- }
1663
- };
1664
- doc.getMap(key).observeDeep(this.docObserver);
1665
- if (awareness) {
1666
- this.cleanupCollaborator = bindCollaborator(file, {
1667
- awareness,
1668
- graph,
1669
- cursor: cursor ?? true,
1670
- mouseMoveThrottle
1671
- });
1672
- }
1673
- if (undoManager) {
1674
- this.cleanupUndoManager = bindUndoManager(doc, file, undoManager);
1675
- }
1676
- }
1677
- /** replace 策略下,构造时 doc 为空,现在 doc 有数据时需要强制替换 */
1678
- get shouldReplaceWhenDocHasData() {
1679
- return this.initialContentStrategy === "replace" && !this.docInitialized;
1680
- }
1681
- /**
1682
- * 重置 editor 和 file 的 modified 状态及状态栏。
1683
- * Yjs 接管持久化后,draw.io 的原生保存状态不再有意义。
1684
- */
1685
- resetEditorStatus() {
1686
- var _a;
1687
- if (!this.ui)
1688
- return;
1689
- this.ui.editor.setModified(false);
1690
- this.ui.editor.setStatus("");
1691
- (_a = this.ui.currentFile) == null ? void 0 : _a.setModified(false);
1692
- }
1693
- /**
1694
- * 销毁绑定,解除所有监听器
1695
- * @param deep - 是否深度清理(包括 awareness/undoManager),默认 false
1696
- */
1697
- destroy(deep = false) {
1698
- var _a, _b;
1699
- this.mxGraphModel.removeListener("change", this.mxListener);
1700
- this.doc.getMap(key).unobserveDeep(this.docObserver);
1701
- if (deep) {
1702
- (_a = this.cleanupCollaborator) == null ? void 0 : _a.call(this);
1703
- (_b = this.cleanupUndoManager) == null ? void 0 : _b.call(this);
1704
- }
1705
- }
1706
- /**
1707
- * 生成标准化的 mxfile XML 模板,用于确保多端协同的数据起点一致。
1708
- *
1709
- * draw.io 每次新建 diagram 时默认生成随机 id(如 `DEMOabHTdChjKBf1yHdD`)。
1710
- * 如果各客户端初始化时的 diagram id 不同,Y.Doc 中的数据与本地 file.data 无法对齐,
1711
- * 会导致:
1712
- * - 后进房间的客户端出现「孤立 page」(来自本地 XML,未写入 Y.Doc)
1713
- * - patch 的 diff 无法正确匹配 diagram/cell id,协同失效
1714
- *
1715
- * 因此业务方应在初始化 draw.io 文件时,先用此方法生成统一起点的 XML,
1716
- * 再注入到 draw.io 的 currentFile 中(详见文档「接入注意事项」)。
1717
- *
1718
- * @param diagramId - diagram 的固定 id,默认 `diagram-0`
1719
- * @returns 最小化的 mxfile XML 字符串
1720
- */
1721
- static generateFileTemplate(diagramId = "diagram-0") {
1722
- return `<mxfile pages="1">
1723
- <diagram id="${diagramId}">
1724
- <mxGraphModel>
1725
- <root>
1726
- <mxCell id="0" />
1727
- <mxCell id="1" parent="0" />
1728
- </root>
1729
- </mxGraphModel>
1730
- </diagram>
1731
- </mxfile>`;
1732
- }
1733
- /**
1734
- * 静态工厂方法,创建 Binding 实例
1735
- * 与 `new Binding()` 等价
1736
- */
1737
- static create(file, options) {
1738
- return new Binding(file, options);
1739
- }
1740
- }
1741
- Object.defineProperty(exports, "createIframeBridgeProvider", {
1742
- enumerable: true,
1743
- get: () => iframeBridge.createIframeBridgeProvider
1744
- });
1745
- Object.defineProperty(exports, "createIframeBridgeServer", {
1746
- enumerable: true,
1747
- get: () => iframeBridge.createIframeBridgeServer
1748
- });
1749
- exports.Binding = Binding;
1750
- exports.DEFAULT_USER_COLOR_KEY = DEFAULT_USER_COLOR_KEY;
1751
- exports.DEFAULT_USER_NAME_KEY = DEFAULT_USER_NAME_KEY;
1752
- exports.LOCAL_ORIGIN = LOCAL_ORIGIN;
1753
- exports.doc2xml = doc2xml;
1754
- exports.xml2doc = xml2doc;
1755
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
1756
- return exports;
1757
- }({}, xmljs, Y, _, colord, YMxGraphIframeBridge);
1758
- //# sourceMappingURL=y-mxgraph.iife.js.map