y-mxgraph 0.8.6 → 0.9.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/binding/consistency.d.ts +56 -0
- package/binding/consistency.d.ts.map +1 -0
- package/binding/index.d.ts +38 -0
- package/binding/index.d.ts.map +1 -1
- package/binding/patch.d.ts +4 -2
- package/binding/patch.d.ts.map +1 -1
- package/iframe-bridge/provider.cjs +63 -6
- package/iframe-bridge/provider.cjs.map +1 -1
- package/iframe-bridge/provider.js +61 -4
- package/iframe-bridge/provider.js.map +1 -1
- package/iframe-bridge/server.cjs +86 -16
- package/iframe-bridge/server.cjs.map +1 -1
- package/iframe-bridge/server.js +78 -8
- package/iframe-bridge/server.js.map +1 -1
- package/{index-BhW4J2Zt.js → index-CN7tFgEG.js} +26 -4
- package/index-CN7tFgEG.js.map +1 -0
- package/{index-D3Hk2QcW.cjs → index-CqD1uLD3.cjs} +24 -2
- package/index-CqD1uLD3.cjs.map +1 -0
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/models/mxGraphModel.d.ts.map +1 -1
- package/origin-C_FHB48F.cjs +6 -0
- package/origin-C_FHB48F.cjs.map +1 -0
- package/origin-Doo2uLkM.js +7 -0
- package/origin-Doo2uLkM.js.map +1 -0
- package/package.json +1 -1
- package/transform.cjs +1 -1
- package/transform.js +1 -1
- package/y-mxgraph.cjs +366 -143
- package/y-mxgraph.cjs.map +1 -1
- package/y-mxgraph.js +366 -143
- package/y-mxgraph.js.map +1 -1
- package/index-BhW4J2Zt.js.map +0 -1
- package/index-D3Hk2QcW.cjs.map +0 -1
package/y-mxgraph.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const transform = require("./index-
|
|
3
|
+
const transform = require("./index-CqD1uLD3.cjs");
|
|
4
4
|
const Y = require("yjs");
|
|
5
5
|
const colord = require("colord");
|
|
6
6
|
function _interopNamespaceDefault(e) {
|
|
@@ -93,9 +93,15 @@ const DIFF_UPDATE = "u";
|
|
|
93
93
|
const docSnapshots = /* @__PURE__ */ new WeakMap();
|
|
94
94
|
function insertAfterUnique(orderArr, id, previous, fallbackToEnd = false) {
|
|
95
95
|
const currentIds = orderArr.toArray();
|
|
96
|
-
let anchorPos = previous ? currentIds.indexOf(previous) : -1;
|
|
96
|
+
let anchorPos = previous != null ? currentIds.indexOf(previous) : -1;
|
|
97
97
|
if (anchorPos === -1 && fallbackToEnd) anchorPos = currentIds.length - 1;
|
|
98
98
|
let targetIndex = anchorPos + 1;
|
|
99
|
+
if (previous === "" && id !== "0" && id !== "1") {
|
|
100
|
+
const layerIndex = currentIds.indexOf("1");
|
|
101
|
+
if (layerIndex >= 0) {
|
|
102
|
+
targetIndex = layerIndex + 1;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
99
105
|
const existingIndex = currentIds.indexOf(id);
|
|
100
106
|
if (existingIndex === -1) {
|
|
101
107
|
orderArr.insert(targetIndex, [id]);
|
|
@@ -150,34 +156,41 @@ function pruneEmptyPatch(patch) {
|
|
|
150
156
|
}
|
|
151
157
|
function applyFilePatch(doc, patch, options) {
|
|
152
158
|
doc.transact(() => {
|
|
159
|
+
var _a, _b;
|
|
153
160
|
const mxfile = doc.getMap(transform.key$1);
|
|
154
161
|
if (patch[DIFF_REMOVE]) {
|
|
155
162
|
const diagramsMap = mxfile.get(transform.key$2);
|
|
156
|
-
const orderArr = mxfile.get(
|
|
157
|
-
|
|
158
|
-
);
|
|
159
|
-
ensureUniqueOrder(orderArr);
|
|
160
|
-
const orderList = orderArr.toArray();
|
|
163
|
+
const orderArr = mxfile.get(transform.diagramOrderKey);
|
|
164
|
+
if (orderArr) ensureUniqueOrder(orderArr);
|
|
161
165
|
const removeIds = patch[DIFF_REMOVE];
|
|
162
166
|
if (removeIds && removeIds.length) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
167
|
+
if (orderArr) {
|
|
168
|
+
const orderList = orderArr.toArray();
|
|
169
|
+
const indexList = removeIds.map((id) => orderList.indexOf(id)).filter((i) => i !== -1).sort((a, b) => b - a);
|
|
170
|
+
indexList.forEach((idx) => orderArr.delete(idx, 1));
|
|
171
|
+
}
|
|
172
|
+
if (diagramsMap) {
|
|
173
|
+
removeIds.forEach((id) => {
|
|
174
|
+
if (diagramsMap.has(id)) {
|
|
175
|
+
diagramsMap.delete(id);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
166
179
|
}
|
|
167
180
|
}
|
|
168
181
|
if (patch[DIFF_INSERT]) {
|
|
169
182
|
const diagramsMap = mxfile.get(transform.key$2);
|
|
170
|
-
const orderArr = mxfile.get(
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
183
|
+
const orderArr = mxfile.get(transform.diagramOrderKey);
|
|
184
|
+
if (orderArr) {
|
|
185
|
+
ensureUniqueOrder(orderArr);
|
|
186
|
+
const currentOrder = orderArr.toArray();
|
|
187
|
+
if (currentOrder.length === 0 && diagramsMap && diagramsMap.size > 0) {
|
|
188
|
+
const allIds = Array.from(diagramsMap.keys());
|
|
189
|
+
orderArr.push(allIds);
|
|
190
|
+
}
|
|
191
|
+
ensureUniqueOrder(orderArr);
|
|
178
192
|
}
|
|
179
|
-
|
|
180
|
-
const existingIds = orderArr.toArray();
|
|
193
|
+
const existingIds = (_a = orderArr == null ? void 0 : orderArr.toArray()) != null ? _a : [];
|
|
181
194
|
const existingIndex = /* @__PURE__ */ new Map();
|
|
182
195
|
existingIds.forEach((id, idx) => existingIndex.set(id, idx));
|
|
183
196
|
const inserts = patch[DIFF_INSERT].map((item, order) => {
|
|
@@ -188,7 +201,7 @@ function applyFilePatch(doc, patch, options) {
|
|
|
188
201
|
);
|
|
189
202
|
return {
|
|
190
203
|
id: item.id,
|
|
191
|
-
previous: item.previous
|
|
204
|
+
previous: item.previous === void 0 ? null : item.previous,
|
|
192
205
|
diagramElement,
|
|
193
206
|
order
|
|
194
207
|
};
|
|
@@ -230,16 +243,19 @@ function applyFilePatch(doc, patch, options) {
|
|
|
230
243
|
return b.order - a.order;
|
|
231
244
|
});
|
|
232
245
|
for (const item of enriched) {
|
|
233
|
-
diagramsMap
|
|
234
|
-
|
|
246
|
+
if (diagramsMap) {
|
|
247
|
+
diagramsMap.set(item.id, item.diagramElement);
|
|
248
|
+
}
|
|
249
|
+
if (orderArr) {
|
|
250
|
+
const anchorArg = item.anchorId === "" ? "" : (_b = item.anchorId) != null ? _b : null;
|
|
251
|
+
insertAfterUnique(orderArr, item.id, anchorArg);
|
|
252
|
+
}
|
|
235
253
|
}
|
|
236
254
|
}
|
|
237
255
|
if (patch[DIFF_UPDATE]) {
|
|
238
256
|
Object.keys(patch[DIFF_UPDATE]).forEach((id) => {
|
|
239
|
-
const diagramsMap = mxfile.get(
|
|
240
|
-
|
|
241
|
-
);
|
|
242
|
-
const diagram = diagramsMap.get(id);
|
|
257
|
+
const diagramsMap = mxfile.get(transform.key$2);
|
|
258
|
+
const diagram = diagramsMap == null ? void 0 : diagramsMap.get(id);
|
|
243
259
|
if (diagram) {
|
|
244
260
|
const update = patch[DIFF_UPDATE][id];
|
|
245
261
|
if ("name" in update) {
|
|
@@ -253,132 +269,151 @@ function applyFilePatch(doc, patch, options) {
|
|
|
253
269
|
}
|
|
254
270
|
if (update.cells) {
|
|
255
271
|
const yMxGraphModel = diagram.get(transform.key);
|
|
256
|
-
if (!yMxGraphModel)
|
|
272
|
+
if (!yMxGraphModel) {
|
|
273
|
+
console.warn(
|
|
274
|
+
"[y-mxgraph] applyFilePatch: yMxGraphModel not found for diagram, skipping cells update"
|
|
275
|
+
);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
257
278
|
const cellsMap = yMxGraphModel.get(transform.key$3);
|
|
258
279
|
const orderArr = yMxGraphModel.get(transform.mxCellOrderKey);
|
|
259
|
-
if (!cellsMap
|
|
260
|
-
|
|
280
|
+
if (!cellsMap && !orderArr) {
|
|
281
|
+
console.warn(
|
|
282
|
+
"[y-mxgraph] applyFilePatch: both cellsMap and orderArr missing, skipping cells update"
|
|
283
|
+
);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (orderArr) ensureUniqueOrder(orderArr);
|
|
261
287
|
if (update.cells[DIFF_REMOVE] && update.cells[DIFF_REMOVE].length) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
288
|
+
if (orderArr) {
|
|
289
|
+
const orderIds = orderArr.toArray();
|
|
290
|
+
const removeIndexList = update.cells[DIFF_REMOVE].map(
|
|
291
|
+
(cid) => orderIds.indexOf(cid)
|
|
292
|
+
).filter((i) => i !== -1).sort((a, b) => b - a);
|
|
293
|
+
removeIndexList.forEach((idx) => orderArr.delete(idx, 1));
|
|
294
|
+
}
|
|
295
|
+
if (cellsMap) {
|
|
296
|
+
update.cells[DIFF_REMOVE].forEach((cid) => {
|
|
297
|
+
if (cellsMap.has(cid)) {
|
|
298
|
+
cellsMap.delete(cid);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
268
302
|
}
|
|
269
303
|
if (update.cells[DIFF_INSERT] && update.cells[DIFF_INSERT].length) {
|
|
270
304
|
for (const item of update.cells[DIFF_INSERT]) {
|
|
271
305
|
const id2 = item["id"];
|
|
272
306
|
if (!id2) continue;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
anchorId = null;
|
|
307
|
+
if (cellsMap) {
|
|
308
|
+
const xmlElement = new Y__namespace.XmlElement("mxCell");
|
|
309
|
+
Object.keys(item).forEach((key) => {
|
|
310
|
+
if (key === "previous") return;
|
|
311
|
+
xmlElement.setAttribute(key, item[key]);
|
|
312
|
+
});
|
|
313
|
+
cellsMap.set(id2, xmlElement);
|
|
314
|
+
}
|
|
315
|
+
if (orderArr) {
|
|
316
|
+
const previous = item["previous"];
|
|
317
|
+
const parent = item["parent"];
|
|
318
|
+
let anchorId = null;
|
|
319
|
+
let fallbackToEnd = true;
|
|
320
|
+
if (typeof previous !== "undefined") {
|
|
321
|
+
if (previous === "") {
|
|
322
|
+
anchorId = "";
|
|
290
323
|
fallbackToEnd = false;
|
|
324
|
+
} else {
|
|
325
|
+
anchorId = previous;
|
|
326
|
+
fallbackToEnd = true;
|
|
291
327
|
}
|
|
292
|
-
} else {
|
|
293
|
-
anchorId =
|
|
328
|
+
} else if (parent) {
|
|
329
|
+
anchorId = parent;
|
|
294
330
|
fallbackToEnd = true;
|
|
295
331
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
332
|
+
insertAfterUnique(
|
|
333
|
+
orderArr,
|
|
334
|
+
id2,
|
|
335
|
+
anchorId,
|
|
336
|
+
fallbackToEnd
|
|
337
|
+
);
|
|
299
338
|
}
|
|
300
|
-
insertAfterUnique(
|
|
301
|
-
orderArr,
|
|
302
|
-
id2,
|
|
303
|
-
anchorId,
|
|
304
|
-
fallbackToEnd
|
|
305
|
-
);
|
|
306
339
|
}
|
|
307
340
|
}
|
|
308
341
|
if (update.cells[DIFF_UPDATE]) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
342
|
+
if (cellsMap) {
|
|
343
|
+
Object.keys(update.cells[DIFF_UPDATE]).forEach((cid) => {
|
|
344
|
+
const updateObj = update.cells[DIFF_UPDATE][cid];
|
|
345
|
+
const cell = cellsMap.get(cid);
|
|
346
|
+
if (cell) {
|
|
347
|
+
Object.keys(updateObj).forEach((k) => {
|
|
348
|
+
if (k === "previous") return;
|
|
349
|
+
cell.setAttribute(k, updateObj[k]);
|
|
350
|
+
});
|
|
351
|
+
} else {
|
|
352
|
+
console.warn(
|
|
353
|
+
`[y-mxgraph] applyFilePatch: cell ${cid} not found in cellsMap, skipping update`
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
if (cellsMap && orderArr) {
|
|
359
|
+
const reorderEntries = Object.keys(update.cells[DIFF_UPDATE]).map((cellId) => {
|
|
360
|
+
const updateObj = update.cells[DIFF_UPDATE][cellId];
|
|
361
|
+
const hasPrev = "previous" in updateObj;
|
|
362
|
+
const hasParent = "parent" in updateObj;
|
|
363
|
+
if (!hasPrev && !hasParent) return null;
|
|
364
|
+
const prevVal = hasPrev ? updateObj.previous : void 0;
|
|
365
|
+
const parentVal = hasParent ? updateObj.parent : void 0;
|
|
366
|
+
let anchorId = null;
|
|
367
|
+
let fallbackToEnd = true;
|
|
368
|
+
if (hasPrev) {
|
|
369
|
+
if (prevVal === "") {
|
|
370
|
+
anchorId = "";
|
|
371
|
+
fallbackToEnd = false;
|
|
372
|
+
} else if (prevVal === null || typeof prevVal === "undefined") {
|
|
373
|
+
anchorId = null;
|
|
332
374
|
fallbackToEnd = true;
|
|
333
375
|
} else {
|
|
334
|
-
anchorId =
|
|
335
|
-
fallbackToEnd =
|
|
376
|
+
anchorId = prevVal;
|
|
377
|
+
fallbackToEnd = true;
|
|
336
378
|
}
|
|
337
|
-
} else {
|
|
338
|
-
anchorId =
|
|
379
|
+
} else if (parentVal) {
|
|
380
|
+
anchorId = parentVal;
|
|
339
381
|
fallbackToEnd = true;
|
|
340
382
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
383
|
+
return { cellId, anchorId, fallbackToEnd, updateObj };
|
|
384
|
+
}).filter((e) => e !== null);
|
|
385
|
+
const applyReorder = (entry) => {
|
|
386
|
+
const { cellId, anchorId, fallbackToEnd, updateObj } = entry;
|
|
387
|
+
const currentIds = orderArr.toArray();
|
|
388
|
+
const currentIndex = currentIds.indexOf(cellId);
|
|
389
|
+
if (currentIndex === -1) {
|
|
390
|
+
let newCell = cellsMap.get(cellId);
|
|
391
|
+
if (!newCell) {
|
|
392
|
+
newCell = new Y__namespace.XmlElement("mxCell");
|
|
393
|
+
newCell.setAttribute("id", cellId);
|
|
394
|
+
Object.keys(updateObj).forEach((k) => {
|
|
395
|
+
if (k === "previous") return;
|
|
396
|
+
newCell.setAttribute(k, updateObj[k]);
|
|
397
|
+
});
|
|
398
|
+
cellsMap.set(cellId, newCell);
|
|
399
|
+
}
|
|
400
|
+
insertAfterUnique(orderArr, cellId, anchorId, fallbackToEnd);
|
|
401
|
+
return;
|
|
357
402
|
}
|
|
358
|
-
insertAfterUnique(
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
);
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
insertAfterUnique(
|
|
367
|
-
orderArr,
|
|
368
|
-
cellId,
|
|
369
|
-
anchorId,
|
|
370
|
-
fallbackToEnd
|
|
371
|
-
);
|
|
372
|
-
});
|
|
403
|
+
insertAfterUnique(orderArr, cellId, anchorId, fallbackToEnd);
|
|
404
|
+
};
|
|
405
|
+
reorderEntries.filter((e) => e.anchorId === "" || e.anchorId === null).forEach(applyReorder);
|
|
406
|
+
reorderEntries.filter((e) => e.anchorId !== "" && e.anchorId !== null).forEach(applyReorder);
|
|
407
|
+
}
|
|
373
408
|
}
|
|
374
409
|
}
|
|
375
410
|
if ("previous" in update) {
|
|
376
|
-
const previous = update.previous
|
|
377
|
-
const orderArr = mxfile.get(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
411
|
+
const previous = Object.prototype.hasOwnProperty.call(update, "previous") ? update.previous : null;
|
|
412
|
+
const orderArr = mxfile.get(transform.diagramOrderKey);
|
|
413
|
+
if (orderArr) {
|
|
414
|
+
ensureUniqueOrder(orderArr);
|
|
415
|
+
insertAfterUnique(orderArr, id, previous, false);
|
|
416
|
+
}
|
|
382
417
|
}
|
|
383
418
|
}
|
|
384
419
|
});
|
|
@@ -399,7 +434,7 @@ function initDocSnapshot(doc, resetSnapshot = false) {
|
|
|
399
434
|
cellAttrs: /* @__PURE__ */ new Map(),
|
|
400
435
|
diagramBackground: /* @__PURE__ */ new Map()
|
|
401
436
|
};
|
|
402
|
-
const diagrams = diagramOrder.map((id) => diagramsMap.get(id)).filter((d) => !!d);
|
|
437
|
+
const diagrams = diagramOrder.map((id) => diagramsMap == null ? void 0 : diagramsMap.get(id)).filter((d) => !!d);
|
|
403
438
|
for (const d of diagrams) {
|
|
404
439
|
const did = d.get("id") || "";
|
|
405
440
|
if (!did) continue;
|
|
@@ -434,7 +469,7 @@ function initDocSnapshot(doc, resetSnapshot = false) {
|
|
|
434
469
|
}
|
|
435
470
|
}
|
|
436
471
|
function generatePatch(events, explicitDoc) {
|
|
437
|
-
var _a, _b, _c, _d, _e;
|
|
472
|
+
var _a, _b, _c, _d, _e, _f;
|
|
438
473
|
const patch = {};
|
|
439
474
|
const doc = (_b = (_a = events[0]) == null ? void 0 : _a.transaction) == null ? void 0 : _b.doc;
|
|
440
475
|
if (!doc) return patch;
|
|
@@ -468,7 +503,7 @@ function generatePatch(events, explicitDoc) {
|
|
|
468
503
|
};
|
|
469
504
|
const orderIds = (_c = orderArr == null ? void 0 : orderArr.toArray()) != null ? _c : [];
|
|
470
505
|
const currDiagramOrder = orderIds.length > 0 ? orderIds : diagramsMap ? Array.from(diagramsMap.keys()) : [];
|
|
471
|
-
const diagramsList = currDiagramOrder.map((id) => diagramsMap.get(id)).filter((d) => !!d);
|
|
506
|
+
const diagramsList = currDiagramOrder.map((id) => diagramsMap == null ? void 0 : diagramsMap.get(id)).filter((d) => !!d);
|
|
472
507
|
const currCellsOrder = /* @__PURE__ */ new Map();
|
|
473
508
|
const cellAttrMap = /* @__PURE__ */ new Map();
|
|
474
509
|
const currDiagramBackground = /* @__PURE__ */ new Map();
|
|
@@ -514,7 +549,7 @@ function generatePatch(events, explicitDoc) {
|
|
|
514
549
|
for (const id of inserted) {
|
|
515
550
|
const index = currDiagramOrder.indexOf(id);
|
|
516
551
|
const previous = index <= 0 ? "" : currDiagramOrder[index - 1];
|
|
517
|
-
const yDiagram = diagramsMap.get(id);
|
|
552
|
+
const yDiagram = diagramsMap == null ? void 0 : diagramsMap.get(id);
|
|
518
553
|
if (!yDiagram) continue;
|
|
519
554
|
const data = transform.serializer({ diagram: transform.serialize(yDiagram) });
|
|
520
555
|
patch[DIFF_INSERT].push({ id, previous, data });
|
|
@@ -523,7 +558,8 @@ function generatePatch(events, explicitDoc) {
|
|
|
523
558
|
}
|
|
524
559
|
const prevNeighbor = (order, id) => {
|
|
525
560
|
const i = order.indexOf(id);
|
|
526
|
-
|
|
561
|
+
if (i === -1) return null;
|
|
562
|
+
return i === 0 ? "" : order[i - 1];
|
|
527
563
|
};
|
|
528
564
|
const common = currDiagramOrder.filter((id) => prevSet.has(id) && id);
|
|
529
565
|
for (const id of common) {
|
|
@@ -572,7 +608,8 @@ function generatePatch(events, explicitDoc) {
|
|
|
572
608
|
}
|
|
573
609
|
const prevNeighbor = (order, id) => {
|
|
574
610
|
const i = order.indexOf(id);
|
|
575
|
-
|
|
611
|
+
if (i === -1) return null;
|
|
612
|
+
return i === 0 ? "" : order[i - 1];
|
|
576
613
|
};
|
|
577
614
|
const commonCells = currCells.filter((cid) => prevSet.has(cid) && cid);
|
|
578
615
|
for (const cid of commonCells) {
|
|
@@ -649,7 +686,7 @@ function generatePatch(events, explicitDoc) {
|
|
|
649
686
|
cellsPatch[DIFF_UPDATE] = cellsPatch[DIFF_UPDATE] || {};
|
|
650
687
|
const cellUpdate = cellsPatch[DIFF_UPDATE][cellId] = cellsPatch[DIFF_UPDATE][cellId] || {};
|
|
651
688
|
for (const key of Array.from(changed)) {
|
|
652
|
-
cellUpdate[key] = el.getAttribute(key)
|
|
689
|
+
cellUpdate[key] = (_d = el.getAttribute(key)) != null ? _d : "";
|
|
653
690
|
}
|
|
654
691
|
}
|
|
655
692
|
if (prevDiagramOrder) {
|
|
@@ -678,8 +715,8 @@ function generatePatch(events, explicitDoc) {
|
|
|
678
715
|
const cellUpdate = updateBucket[cid] = updateBucket[cid] || {};
|
|
679
716
|
let changed = false;
|
|
680
717
|
for (const k of keys) {
|
|
681
|
-
const pv = (
|
|
682
|
-
const cv = (
|
|
718
|
+
const pv = (_e = prevAttrs[k]) != null ? _e : "";
|
|
719
|
+
const cv = (_f = currAttrs[k]) != null ? _f : "";
|
|
683
720
|
if (pv !== cv) {
|
|
684
721
|
cellUpdate[k] = cv;
|
|
685
722
|
changed = true;
|
|
@@ -1365,6 +1402,91 @@ function bindCollaborator(file, options) {
|
|
|
1365
1402
|
cleanupAwareness == null ? void 0 : cleanupAwareness();
|
|
1366
1403
|
};
|
|
1367
1404
|
}
|
|
1405
|
+
function checkConsistency(doc, fileData) {
|
|
1406
|
+
try {
|
|
1407
|
+
const xmlFromYdoc = transform.ydoc2xml(doc);
|
|
1408
|
+
if (xmlFromYdoc === fileData) return true;
|
|
1409
|
+
const diagramCountFromYdoc = (xmlFromYdoc.match(/<diagram /g) || []).length;
|
|
1410
|
+
const diagramCountFromFile = (fileData.match(/<diagram /g) || []).length;
|
|
1411
|
+
if (diagramCountFromYdoc !== diagramCountFromFile) return false;
|
|
1412
|
+
const cellCountFromYdoc = (xmlFromYdoc.match(/<mxCell /g) || []).length;
|
|
1413
|
+
const cellCountFromFile = (fileData.match(/<mxCell /g) || []).length;
|
|
1414
|
+
if (cellCountFromYdoc !== cellCountFromFile) return false;
|
|
1415
|
+
return true;
|
|
1416
|
+
} catch (e) {
|
|
1417
|
+
return false;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
class ConsistencyChecker {
|
|
1421
|
+
constructor(doc, getFileData, options = {}) {
|
|
1422
|
+
this.doc = doc;
|
|
1423
|
+
this.getFileData = getFileData;
|
|
1424
|
+
this.intervalId = null;
|
|
1425
|
+
this.handlers = /* @__PURE__ */ new Set();
|
|
1426
|
+
this.consecutiveDriftCount = 0;
|
|
1427
|
+
var _a, _b;
|
|
1428
|
+
this.source = (_a = options.source) != null ? _a : "binding";
|
|
1429
|
+
this.maxAutoFixAttempts = (_b = options.maxAutoFixAttempts) != null ? _b : 3;
|
|
1430
|
+
}
|
|
1431
|
+
/** 注册 drift 事件监听 */
|
|
1432
|
+
onDrift(handler) {
|
|
1433
|
+
this.handlers.add(handler);
|
|
1434
|
+
return () => this.handlers.delete(handler);
|
|
1435
|
+
}
|
|
1436
|
+
/** 启动定期检查(毫秒间隔),0 或负数表示禁用 */
|
|
1437
|
+
start(intervalMs) {
|
|
1438
|
+
this.stop();
|
|
1439
|
+
if (intervalMs <= 0) return;
|
|
1440
|
+
this.intervalId = setInterval(() => {
|
|
1441
|
+
this.check();
|
|
1442
|
+
}, intervalMs);
|
|
1443
|
+
}
|
|
1444
|
+
/** 停止定期检查 */
|
|
1445
|
+
stop() {
|
|
1446
|
+
if (this.intervalId != null) {
|
|
1447
|
+
clearInterval(this.intervalId);
|
|
1448
|
+
this.intervalId = null;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* 执行一次一致性检查。
|
|
1453
|
+
* @returns true = 一致,false = 存在 drift
|
|
1454
|
+
*/
|
|
1455
|
+
check() {
|
|
1456
|
+
const consistent = checkConsistency(this.doc, this.getFileData());
|
|
1457
|
+
if (consistent) {
|
|
1458
|
+
this.consecutiveDriftCount = 0;
|
|
1459
|
+
return true;
|
|
1460
|
+
}
|
|
1461
|
+
this.consecutiveDriftCount++;
|
|
1462
|
+
const event = {
|
|
1463
|
+
timestamp: Date.now(),
|
|
1464
|
+
source: this.source,
|
|
1465
|
+
direction: "unknown",
|
|
1466
|
+
details: `drift detected (consecutive #${this.consecutiveDriftCount})`
|
|
1467
|
+
};
|
|
1468
|
+
this.handlers.forEach((handler) => {
|
|
1469
|
+
try {
|
|
1470
|
+
handler(event);
|
|
1471
|
+
} catch (e) {
|
|
1472
|
+
console.warn("[y-mxgraph] drift handler error:", e);
|
|
1473
|
+
}
|
|
1474
|
+
});
|
|
1475
|
+
return false;
|
|
1476
|
+
}
|
|
1477
|
+
/** 重置连续 drift 计数(forceSync 成功后调用) */
|
|
1478
|
+
resetDriftCount() {
|
|
1479
|
+
this.consecutiveDriftCount = 0;
|
|
1480
|
+
}
|
|
1481
|
+
/** 是否已超过最大自动修复次数 */
|
|
1482
|
+
get shouldStopAutoFix() {
|
|
1483
|
+
return this.consecutiveDriftCount >= this.maxAutoFixAttempts;
|
|
1484
|
+
}
|
|
1485
|
+
destroy() {
|
|
1486
|
+
this.stop();
|
|
1487
|
+
this.handlers.clear();
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1368
1490
|
const defaultApplyFileData = (file, xml) => {
|
|
1369
1491
|
file.ui.setFileData(xml);
|
|
1370
1492
|
};
|
|
@@ -1476,6 +1598,7 @@ class Binding {
|
|
|
1476
1598
|
this.suppressLocalApply = false;
|
|
1477
1599
|
this.docInitialized = false;
|
|
1478
1600
|
this.ui = null;
|
|
1601
|
+
this.debouncedForceSync = null;
|
|
1479
1602
|
const {
|
|
1480
1603
|
doc,
|
|
1481
1604
|
awareness,
|
|
@@ -1485,12 +1608,15 @@ class Binding {
|
|
|
1485
1608
|
initialContent = "replace",
|
|
1486
1609
|
applyFileData = defaultApplyFileData,
|
|
1487
1610
|
disableBeforeUnload = true,
|
|
1488
|
-
transformPatch
|
|
1611
|
+
transformPatch,
|
|
1612
|
+
syncOnOrderMismatch = false
|
|
1489
1613
|
} = options;
|
|
1490
1614
|
this.doc = doc;
|
|
1491
1615
|
this.file = file;
|
|
1492
1616
|
this.initialContentStrategy = initialContent;
|
|
1493
1617
|
this.transformPatch = transformPatch;
|
|
1618
|
+
this.applyFileData = applyFileData;
|
|
1619
|
+
this.syncOnOrderMismatch = syncOnOrderMismatch;
|
|
1494
1620
|
const ui = file.getUi();
|
|
1495
1621
|
const graph = ui.editor.graph;
|
|
1496
1622
|
this.mxGraphModel = graph.model;
|
|
@@ -1541,7 +1667,6 @@ class Binding {
|
|
|
1541
1667
|
this.mxGraphModel.addListener("change", this.mxListener);
|
|
1542
1668
|
this.docObserver = (events, transaction) => {
|
|
1543
1669
|
if (transaction.local && transaction.origin === LOCAL_ORIGIN) {
|
|
1544
|
-
generatePatch(events);
|
|
1545
1670
|
return;
|
|
1546
1671
|
}
|
|
1547
1672
|
if (this.shouldReplaceWhenDocHasData && !transaction.local) {
|
|
@@ -1568,7 +1693,8 @@ class Binding {
|
|
|
1568
1693
|
this.docInitialized = true;
|
|
1569
1694
|
}
|
|
1570
1695
|
const patch = generatePatch(events);
|
|
1571
|
-
|
|
1696
|
+
const patchKeys = Object.keys(patch);
|
|
1697
|
+
if (patchKeys.length === 0) return;
|
|
1572
1698
|
this.suppressLocalApply = true;
|
|
1573
1699
|
try {
|
|
1574
1700
|
file.patch([patch]);
|
|
@@ -1577,6 +1703,14 @@ class Binding {
|
|
|
1577
1703
|
} finally {
|
|
1578
1704
|
this.suppressLocalApply = false;
|
|
1579
1705
|
}
|
|
1706
|
+
if (this.syncOnOrderMismatch && patch.u && this.checkOrderMismatch(patch)) {
|
|
1707
|
+
console.warn("[y-mxgraph] order mismatch detected, debounced forceSync (file → ydoc)");
|
|
1708
|
+
if (this.debouncedForceSync) clearTimeout(this.debouncedForceSync);
|
|
1709
|
+
this.debouncedForceSync = setTimeout(() => {
|
|
1710
|
+
this.debouncedForceSync = null;
|
|
1711
|
+
this.forceSync("file-to-ydoc");
|
|
1712
|
+
}, 300);
|
|
1713
|
+
}
|
|
1580
1714
|
};
|
|
1581
1715
|
doc.getMap(transform.key$1).observeDeep(this.docObserver);
|
|
1582
1716
|
if (awareness) {
|
|
@@ -1590,6 +1724,29 @@ class Binding {
|
|
|
1590
1724
|
if (undoManager) {
|
|
1591
1725
|
this.cleanupUndoManager = bindUndoManager(doc, file, undoManager);
|
|
1592
1726
|
}
|
|
1727
|
+
const {
|
|
1728
|
+
consistencyCheckInterval,
|
|
1729
|
+
onDrift
|
|
1730
|
+
} = options;
|
|
1731
|
+
if (consistencyCheckInterval && consistencyCheckInterval > 0) {
|
|
1732
|
+
this.consistencyChecker = new ConsistencyChecker(doc, () => file.data, {
|
|
1733
|
+
source: "binding"
|
|
1734
|
+
});
|
|
1735
|
+
if (onDrift) {
|
|
1736
|
+
this.consistencyChecker.onDrift(onDrift);
|
|
1737
|
+
}
|
|
1738
|
+
this.consistencyChecker.onDrift((event) => {
|
|
1739
|
+
var _a;
|
|
1740
|
+
if ((_a = this.consistencyChecker) == null ? void 0 : _a.shouldStopAutoFix) {
|
|
1741
|
+
console.warn(
|
|
1742
|
+
`[y-mxgraph] 连续 ${event.details} 次 drift,停止自动 forceSync`
|
|
1743
|
+
);
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
this.forceSync("ydoc-to-file");
|
|
1747
|
+
});
|
|
1748
|
+
this.consistencyChecker.start(consistencyCheckInterval);
|
|
1749
|
+
}
|
|
1593
1750
|
}
|
|
1594
1751
|
/** replace 策略下,构造时 doc 为空,现在 doc 有数据时需要强制替换 */
|
|
1595
1752
|
get shouldReplaceWhenDocHasData() {
|
|
@@ -1606,17 +1763,83 @@ class Binding {
|
|
|
1606
1763
|
this.ui.editor.setStatus("");
|
|
1607
1764
|
(_a = this.ui.currentFile) == null ? void 0 : _a.setModified(false);
|
|
1608
1765
|
}
|
|
1766
|
+
/**
|
|
1767
|
+
* 强制同步 ydoc 与 file,修复检测到的不一致。
|
|
1768
|
+
*
|
|
1769
|
+
* @param direction - 同步方向
|
|
1770
|
+
* - `ydoc-to-file`(默认):用 ydoc 数据覆盖 file
|
|
1771
|
+
* - `file-to-ydoc`:用 file 数据覆盖 ydoc
|
|
1772
|
+
*/
|
|
1773
|
+
forceSync(direction = "ydoc-to-file") {
|
|
1774
|
+
var _a;
|
|
1775
|
+
if (direction === "ydoc-to-file") {
|
|
1776
|
+
const xml = transform.ydoc2xml(this.doc);
|
|
1777
|
+
if (!xml || !xml.includes("<diagram")) return;
|
|
1778
|
+
this.suppressLocalApply = true;
|
|
1779
|
+
try {
|
|
1780
|
+
this.applyFileData(this.file, xml);
|
|
1781
|
+
this.file.setShadowPages(this.file.ui.clonePages(this.file.ui.pages));
|
|
1782
|
+
initDocSnapshot(this.doc, false);
|
|
1783
|
+
this.resetEditorStatus();
|
|
1784
|
+
} finally {
|
|
1785
|
+
this.suppressLocalApply = false;
|
|
1786
|
+
}
|
|
1787
|
+
} else {
|
|
1788
|
+
this.doc.transact(() => {
|
|
1789
|
+
transform.xml2ydoc(this.file.data, this.doc);
|
|
1790
|
+
initDocSnapshot(this.doc, false);
|
|
1791
|
+
}, LOCAL_ORIGIN);
|
|
1792
|
+
}
|
|
1793
|
+
(_a = this.consistencyChecker) == null ? void 0 : _a.resetDriftCount();
|
|
1794
|
+
}
|
|
1795
|
+
checkOrderMismatch(patch) {
|
|
1796
|
+
var _a;
|
|
1797
|
+
if (!patch.u) return false;
|
|
1798
|
+
for (const [did, update] of Object.entries(patch.u)) {
|
|
1799
|
+
if (!((_a = update.cells) == null ? void 0 : _a.u)) continue;
|
|
1800
|
+
for (const [cid, cellUpdate] of Object.entries(update.cells.u)) {
|
|
1801
|
+
if (!("previous" in cellUpdate)) continue;
|
|
1802
|
+
const mxfile = this.doc.getMap(transform.key$1);
|
|
1803
|
+
const diagramsMap = mxfile.get(transform.key$2);
|
|
1804
|
+
const diagram = diagramsMap == null ? void 0 : diagramsMap.get(did);
|
|
1805
|
+
if (!diagram) continue;
|
|
1806
|
+
const gm = diagram.get(transform.key);
|
|
1807
|
+
if (!gm) continue;
|
|
1808
|
+
const orderArr = gm.get(transform.mxCellOrderKey);
|
|
1809
|
+
if (!orderArr) continue;
|
|
1810
|
+
const ids = orderArr.toArray();
|
|
1811
|
+
const idx = ids.indexOf(cid);
|
|
1812
|
+
if (idx === -1) continue;
|
|
1813
|
+
const expectedPrev = idx === 0 ? "" : ids[idx - 1];
|
|
1814
|
+
const actualPrev = cellUpdate.previous;
|
|
1815
|
+
if (expectedPrev !== actualPrev) {
|
|
1816
|
+
console.log(`[y-mxgraph] order mismatch: cell=${cid}, ydoc prev=${JSON.stringify(expectedPrev)}, patch prev=${JSON.stringify(actualPrev)}`);
|
|
1817
|
+
return true;
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
return false;
|
|
1822
|
+
}
|
|
1823
|
+
/**
|
|
1824
|
+
* 手动触发一次一致性检查。
|
|
1825
|
+
* @returns true = 一致,false = 存在 drift
|
|
1826
|
+
*/
|
|
1827
|
+
checkConsistency() {
|
|
1828
|
+
if (!this.consistencyChecker) return true;
|
|
1829
|
+
return this.consistencyChecker.check();
|
|
1830
|
+
}
|
|
1609
1831
|
/**
|
|
1610
1832
|
* 销毁绑定,解除所有监听器
|
|
1611
1833
|
* @param deep - 是否深度清理(包括 awareness/undoManager),默认 false
|
|
1612
1834
|
*/
|
|
1613
1835
|
destroy(deep = false) {
|
|
1614
|
-
var _a, _b;
|
|
1836
|
+
var _a, _b, _c;
|
|
1615
1837
|
this.mxGraphModel.removeListener("change", this.mxListener);
|
|
1616
1838
|
this.doc.getMap(transform.key$1).unobserveDeep(this.docObserver);
|
|
1839
|
+
(_a = this.consistencyChecker) == null ? void 0 : _a.destroy();
|
|
1617
1840
|
if (deep) {
|
|
1618
|
-
(
|
|
1619
|
-
(
|
|
1841
|
+
(_b = this.cleanupCollaborator) == null ? void 0 : _b.call(this);
|
|
1842
|
+
(_c = this.cleanupUndoManager) == null ? void 0 : _c.call(this);
|
|
1620
1843
|
}
|
|
1621
1844
|
}
|
|
1622
1845
|
/**
|