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