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/README.zh-CN.md +2 -2
- package/binding/index.d.ts +9 -1
- package/binding/index.d.ts.map +1 -1
- package/iframe-bridge/index.d.ts +2 -0
- package/iframe-bridge/index.d.ts.map +1 -0
- package/iframe-bridge/provider.cjs.js +246 -0
- package/iframe-bridge/provider.cjs.js.map +1 -0
- package/iframe-bridge/provider.es.js +229 -0
- package/iframe-bridge/provider.es.js.map +1 -0
- package/iframe-bridge/server.cjs.js +139 -0
- package/iframe-bridge/server.cjs.js.map +1 -0
- package/iframe-bridge/server.es.js +122 -0
- package/iframe-bridge/server.es.js.map +1 -0
- package/index.d.ts +1 -3
- package/index.d.ts.map +1 -1
- package/package.json +11 -3
- package/transformer/index.d.ts +2 -2
- package/transformer/index.d.ts.map +1 -1
- package/y-mxgraph.cjs.js +88 -168
- package/y-mxgraph.cjs.js.map +1 -1
- package/y-mxgraph.es.js +88 -162
- package/y-mxgraph.es.js.map +1 -1
- package/y-mxgraph.iife.js +0 -1758
- package/y-mxgraph.iife.js.map +0 -1
- package/y-mxgraph.umd.js +0 -1759
- package/y-mxgraph.umd.js.map +0 -1
package/README.zh-CN.md
CHANGED
|
@@ -82,7 +82,7 @@ App.main((app) => {
|
|
|
82
82
|
|
|
83
83
|
```ts
|
|
84
84
|
// Server(父页面)
|
|
85
|
-
import { createIframeBridgeServer } from '
|
|
85
|
+
import { createIframeBridgeServer } from 'y-mxgraph/iframe-bridge/server';
|
|
86
86
|
|
|
87
87
|
const doc = new Y.Doc();
|
|
88
88
|
const provider = new WebrtcProvider(roomName, doc, { signaling });
|
|
@@ -90,7 +90,7 @@ const bridge = createIframeBridgeServer(doc, provider.awareness);
|
|
|
90
90
|
bridge.addIframe(iframeElement, 'child-1');
|
|
91
91
|
|
|
92
92
|
// Provider(iframe 子页面)
|
|
93
|
-
import { createIframeBridgeProvider } from '
|
|
93
|
+
import { createIframeBridgeProvider } from 'y-mxgraph/iframe-bridge/provider';
|
|
94
94
|
|
|
95
95
|
const doc = new Y.Doc();
|
|
96
96
|
const awareness = new Awareness(doc);
|
package/binding/index.d.ts
CHANGED
|
@@ -11,7 +11,13 @@ export type InitialContentStrategy = "replace" | "merge-remote" | "merge-client"
|
|
|
11
11
|
export interface BindDrawioFileOptions {
|
|
12
12
|
doc: Y.Doc;
|
|
13
13
|
awareness?: Awareness;
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* UndoManager 实例,用于支持 undo/redo。
|
|
16
|
+
* - 传入 Y.UndoManager 实例:绑定到 draw.io 的 undoManager
|
|
17
|
+
* - 传入 false:跳过绑定(用于 iframe-bridge 等外部接管场景)
|
|
18
|
+
* - 不传或 undefined:不绑定 undoManager
|
|
19
|
+
*/
|
|
20
|
+
undoManager?: Y.UndoManager | false;
|
|
15
21
|
mouseMoveThrottle?: number;
|
|
16
22
|
cursor?: boolean | {
|
|
17
23
|
userNameKey?: string;
|
|
@@ -55,6 +61,8 @@ export interface BindDrawioFileOptions {
|
|
|
55
61
|
export declare class Binding {
|
|
56
62
|
/** Y.Doc 实例,用于协同数据存储 */
|
|
57
63
|
readonly doc: Y.Doc;
|
|
64
|
+
/** draw.io file 实例 */
|
|
65
|
+
readonly file: DrawioFile;
|
|
58
66
|
/** mxGraph 的数据模型,用于监听本地变更 */
|
|
59
67
|
private mxGraphModel;
|
|
60
68
|
/** 本地变更抑制标志,防止循环同步 */
|
package/binding/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/binding/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAiBvD,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,iBAAiB,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAC9B,SAAS,GACT,cAAc,GACd,cAAc,CAAC;AAEnB,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACX,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/binding/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAiBvD,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,iBAAiB,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAC9B,SAAS,GACT,cAAc,GACd,cAAc,CAAC;AAEnB,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACX,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC;IACpC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EACH,OAAO,GACP;QACE,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACN;;OAEG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AA0KD;;;;;;;GAOG;AACH,qBAAa,OAAO;IAClB,wBAAwB;IACxB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACpB,sBAAsB;IACtB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,6BAA6B;IAC7B,OAAO,CAAC,YAAY,CAAe;IACnC,sBAAsB;IACtB,OAAO,CAAC,kBAAkB,CAAS;IACnC,4BAA4B;IAC5B,OAAO,CAAC,cAAc,CAAS;IAC/B,2BAA2B;IAC3B,OAAO,CAAC,UAAU,CAAa;IAC/B,oBAAoB;IACpB,OAAO,CAAC,WAAW,CAKT;IACV,gCAAgC;IAChC,OAAO,CAAC,mBAAmB,CAAC,CAAa;IACzC,yBAAyB;IACzB,OAAO,CAAC,kBAAkB,CAAC,CAAa;IACxC,aAAa;IACb,OAAO,CAAC,sBAAsB,CAAyB;IACvD,0CAA0C;IAC1C,OAAO,CAAC,EAAE,CAAyB;IAEnC,+CAA+C;IAC/C,OAAO,KAAK,2BAA2B,GAEtC;gBAEW,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,qBAAqB;IAqJ5D;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;OAGG;IACH,OAAO,CAAC,IAAI,UAAQ,GAAG,IAAI;IAS3B;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,oBAAoB,CAAC,SAAS,SAAc,GAAG,MAAM;IAa5D;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO;CAGzE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/iframe-bridge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const Y = require("yjs");
|
|
4
|
+
const awareness = require("y-protocols/awareness");
|
|
5
|
+
function _interopNamespaceDefault(e) {
|
|
6
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
7
|
+
if (e) {
|
|
8
|
+
for (const k in e) {
|
|
9
|
+
if (k !== "default") {
|
|
10
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
11
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: () => e[k]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
n.default = e;
|
|
19
|
+
return Object.freeze(n);
|
|
20
|
+
}
|
|
21
|
+
const Y__namespace = /* @__PURE__ */ _interopNamespaceDefault(Y);
|
|
22
|
+
function createMxEventObject(name, props) {
|
|
23
|
+
const _props = props || {};
|
|
24
|
+
return {
|
|
25
|
+
name,
|
|
26
|
+
getName: () => name,
|
|
27
|
+
getProperty: (k) => _props[k]
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function readVarUint(data, pos) {
|
|
31
|
+
let result = 0;
|
|
32
|
+
let shift = 0;
|
|
33
|
+
let byte;
|
|
34
|
+
do {
|
|
35
|
+
byte = data[pos++];
|
|
36
|
+
result |= (byte & 127) << shift;
|
|
37
|
+
shift += 7;
|
|
38
|
+
} while (byte >= 128);
|
|
39
|
+
return [result >>> 0, pos];
|
|
40
|
+
}
|
|
41
|
+
function writeVarUint(value) {
|
|
42
|
+
const bytes = [];
|
|
43
|
+
while (value > 127) {
|
|
44
|
+
bytes.push(value & 127 | 128);
|
|
45
|
+
value >>>= 7;
|
|
46
|
+
}
|
|
47
|
+
bytes.push(value);
|
|
48
|
+
return bytes;
|
|
49
|
+
}
|
|
50
|
+
function readVarString(data, pos) {
|
|
51
|
+
const [len, pos2] = readVarUint(data, pos);
|
|
52
|
+
const str = new TextDecoder().decode(data.subarray(pos2, pos2 + len));
|
|
53
|
+
return [str, pos2 + len];
|
|
54
|
+
}
|
|
55
|
+
function writeVarString(str) {
|
|
56
|
+
const encoded = new TextEncoder().encode(str);
|
|
57
|
+
return [...writeVarUint(encoded.length), ...encoded];
|
|
58
|
+
}
|
|
59
|
+
function remapClientIdInUpdate(update, fromId, toId) {
|
|
60
|
+
const result = [];
|
|
61
|
+
let pos = 0;
|
|
62
|
+
const [count, pos2] = readVarUint(update, pos);
|
|
63
|
+
pos = pos2;
|
|
64
|
+
result.push(...writeVarUint(count));
|
|
65
|
+
for (let i = 0; i < count; i++) {
|
|
66
|
+
const [clientID, pos3] = readVarUint(update, pos);
|
|
67
|
+
pos = pos3;
|
|
68
|
+
const [clock, pos4] = readVarUint(update, pos);
|
|
69
|
+
pos = pos4;
|
|
70
|
+
const [state, pos5] = readVarString(update, pos);
|
|
71
|
+
pos = pos5;
|
|
72
|
+
const mappedId = clientID === fromId ? toId : clientID;
|
|
73
|
+
result.push(...writeVarUint(mappedId));
|
|
74
|
+
result.push(...writeVarUint(clock));
|
|
75
|
+
result.push(...writeVarString(state));
|
|
76
|
+
}
|
|
77
|
+
return new Uint8Array(result);
|
|
78
|
+
}
|
|
79
|
+
function createIframeBridgeProvider(ydoc, awareness$1) {
|
|
80
|
+
let applyingParentUpdate = false;
|
|
81
|
+
let serverClientId = null;
|
|
82
|
+
let currentCleanup = null;
|
|
83
|
+
let currentMxLike = null;
|
|
84
|
+
const onYdocUpdate = (update) => {
|
|
85
|
+
if (applyingParentUpdate) return;
|
|
86
|
+
if (currentMxLike) {
|
|
87
|
+
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) {
|
|
88
|
+
currentMxLike.history.splice(
|
|
89
|
+
currentMxLike.indexOfNextAdd,
|
|
90
|
+
currentMxLike.history.length - currentMxLike.indexOfNextAdd
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
currentMxLike.history.push({});
|
|
94
|
+
currentMxLike.indexOfNextAdd = currentMxLike.history.length;
|
|
95
|
+
currentMxLike.fireEvent(createMxEventObject("add", { edit: { changes: [] } }));
|
|
96
|
+
}
|
|
97
|
+
window.parent.postMessage(
|
|
98
|
+
{ type: "ydoc-update", payload: Array.from(update) },
|
|
99
|
+
"*"
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
const onAwarenessUpdate = ({
|
|
103
|
+
added,
|
|
104
|
+
updated,
|
|
105
|
+
removed
|
|
106
|
+
}) => {
|
|
107
|
+
if (applyingParentUpdate) return;
|
|
108
|
+
const changes = [...added, ...updated, ...removed];
|
|
109
|
+
if (changes.length === 0) return;
|
|
110
|
+
const update = awareness.encodeAwarenessUpdate(awareness$1, changes);
|
|
111
|
+
const remapped = serverClientId != null ? remapClientIdInUpdate(update, awareness$1.clientID, serverClientId) : update;
|
|
112
|
+
window.parent.postMessage(
|
|
113
|
+
{ type: "awareness-update", payload: Array.from(remapped) },
|
|
114
|
+
"*"
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
const onMessage = (event) => {
|
|
118
|
+
if (event.source !== window.parent) return;
|
|
119
|
+
const { type, payload, serverClientId: receivedServerId } = event.data;
|
|
120
|
+
if (type === "pong" && receivedServerId != null) {
|
|
121
|
+
serverClientId = receivedServerId;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (type === "ydoc-sync" || type === "ydoc-update") {
|
|
125
|
+
applyingParentUpdate = true;
|
|
126
|
+
Y__namespace.applyUpdate(ydoc, new Uint8Array(payload));
|
|
127
|
+
applyingParentUpdate = false;
|
|
128
|
+
} else if (type === "awareness-sync" || type === "awareness-update") {
|
|
129
|
+
if (receivedServerId != null) {
|
|
130
|
+
serverClientId = receivedServerId;
|
|
131
|
+
}
|
|
132
|
+
const raw = new Uint8Array(payload);
|
|
133
|
+
const remapped = serverClientId != null ? remapClientIdInUpdate(raw, serverClientId, awareness$1.clientID) : raw;
|
|
134
|
+
applyingParentUpdate = true;
|
|
135
|
+
awareness.applyAwarenessUpdate(awareness$1, remapped, null);
|
|
136
|
+
applyingParentUpdate = false;
|
|
137
|
+
} else if (type === "undo" && currentMxLike) {
|
|
138
|
+
applyingParentUpdate = true;
|
|
139
|
+
if (currentMxLike.indexOfNextAdd > 0) currentMxLike.indexOfNextAdd--;
|
|
140
|
+
currentMxLike.fireEvent(createMxEventObject("undo", { edit: { changes: [] } }));
|
|
141
|
+
applyingParentUpdate = false;
|
|
142
|
+
} else if (type === "redo" && currentMxLike) {
|
|
143
|
+
applyingParentUpdate = true;
|
|
144
|
+
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) currentMxLike.indexOfNextAdd++;
|
|
145
|
+
currentMxLike.fireEvent(createMxEventObject("redo", { edit: { changes: [] } }));
|
|
146
|
+
applyingParentUpdate = false;
|
|
147
|
+
} else if (type === "clear" && currentMxLike) {
|
|
148
|
+
applyingParentUpdate = true;
|
|
149
|
+
currentMxLike.history = [];
|
|
150
|
+
currentMxLike.indexOfNextAdd = 0;
|
|
151
|
+
currentMxLike.fireEvent(createMxEventObject("clear"));
|
|
152
|
+
applyingParentUpdate = false;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
ydoc.on("update", onYdocUpdate);
|
|
156
|
+
awareness$1.on("update", onAwarenessUpdate);
|
|
157
|
+
window.addEventListener("message", onMessage);
|
|
158
|
+
window.parent.postMessage({ type: "init" }, "*");
|
|
159
|
+
return {
|
|
160
|
+
get serverClientId() {
|
|
161
|
+
return serverClientId;
|
|
162
|
+
},
|
|
163
|
+
takeoverUndoManager(file) {
|
|
164
|
+
if (currentCleanup) {
|
|
165
|
+
currentCleanup();
|
|
166
|
+
}
|
|
167
|
+
const editor = file.getUi().editor;
|
|
168
|
+
const originUndoManager = editor.undoManager;
|
|
169
|
+
const pairs = [];
|
|
170
|
+
const raw = Array.isArray(originUndoManager == null ? void 0 : originUndoManager.eventListeners) ? originUndoManager.eventListeners : [];
|
|
171
|
+
for (let i = 0; i + 1 < raw.length; i += 2) {
|
|
172
|
+
const key = String(raw[i]);
|
|
173
|
+
const fn = raw[i + 1];
|
|
174
|
+
pairs.push([key, fn]);
|
|
175
|
+
}
|
|
176
|
+
const mxLike = {
|
|
177
|
+
eventListeners: [],
|
|
178
|
+
history: [],
|
|
179
|
+
indexOfNextAdd: 0,
|
|
180
|
+
addListener(name, fn) {
|
|
181
|
+
this.eventListeners.push(name, fn);
|
|
182
|
+
},
|
|
183
|
+
fireEvent(evt) {
|
|
184
|
+
var _a;
|
|
185
|
+
const eventName = (evt == null ? void 0 : evt.name) || (((_a = evt == null ? void 0 : evt.getName) == null ? void 0 : _a.call(evt)) ?? "");
|
|
186
|
+
for (let i = 0; i + 1 < this.eventListeners.length; i += 2) {
|
|
187
|
+
const key = this.eventListeners[i];
|
|
188
|
+
const listener = this.eventListeners[i + 1];
|
|
189
|
+
if (key === eventName) {
|
|
190
|
+
try {
|
|
191
|
+
listener(this, evt);
|
|
192
|
+
} catch (e) {
|
|
193
|
+
console.warn("[iframe-bridge] undoManager event listener error:", e);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
canUndo() {
|
|
199
|
+
return this.indexOfNextAdd > 0;
|
|
200
|
+
},
|
|
201
|
+
canRedo() {
|
|
202
|
+
return this.indexOfNextAdd < this.history.length;
|
|
203
|
+
},
|
|
204
|
+
undo() {
|
|
205
|
+
if (!applyingParentUpdate) {
|
|
206
|
+
window.parent.postMessage({ type: "undo" }, "*");
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
redo() {
|
|
210
|
+
if (!applyingParentUpdate) {
|
|
211
|
+
window.parent.postMessage({ type: "redo" }, "*");
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
undoableEditHappened() {
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
pairs.forEach(([key, fn]) => {
|
|
218
|
+
const k = key.toLowerCase();
|
|
219
|
+
if (k === "add" || k === "clear" || k === "undo" || k === "redo") {
|
|
220
|
+
mxLike.addListener(k, fn);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
currentMxLike = mxLike;
|
|
224
|
+
editor.undoManager = mxLike;
|
|
225
|
+
editor.undoListener = function() {
|
|
226
|
+
};
|
|
227
|
+
const cleanup = () => {
|
|
228
|
+
editor.undoManager = originUndoManager;
|
|
229
|
+
editor.undoListener = originUndoManager == null ? void 0 : originUndoManager.undoListener;
|
|
230
|
+
currentMxLike = null;
|
|
231
|
+
};
|
|
232
|
+
currentCleanup = cleanup;
|
|
233
|
+
return cleanup;
|
|
234
|
+
},
|
|
235
|
+
destroy: () => {
|
|
236
|
+
ydoc.off("update", onYdocUpdate);
|
|
237
|
+
awareness$1.off("update", onAwarenessUpdate);
|
|
238
|
+
window.removeEventListener("message", onMessage);
|
|
239
|
+
if (currentCleanup) {
|
|
240
|
+
currentCleanup();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
exports.createIframeBridgeProvider = createIframeBridgeProvider;
|
|
246
|
+
//# sourceMappingURL=provider.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.cjs.js","sources":["../../../iframe-bridge/src/provider.ts"],"sourcesContent":["import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\n\ntype ListenerFn = (sender: unknown, evt?: unknown) => void;\n\nfunction createMxEventObject(name: string, props?: Record<string, unknown>) {\n const _props = props || {};\n return {\n name,\n getName: () => name,\n getProperty: (k: string) => _props[k],\n };\n}\n\ntype MxLike = Record<string, unknown> & {\n eventListeners: Array<string | ListenerFn>;\n history: unknown[];\n indexOfNextAdd: number;\n addListener(name: string, fn: ListenerFn): void;\n fireEvent(evt: unknown): void;\n canUndo(): boolean;\n canRedo(): boolean;\n undo(): void;\n redo(): void;\n undoableEditHappened(_edit: unknown): void;\n};\n\nexport interface DrawioEditor {\n undoManager?: {\n eventListeners?: unknown[];\n [key: string]: unknown;\n };\n undoListener?: (...args: unknown[]) => void;\n}\n\nexport interface DrawioFile {\n getUi(): { editor: DrawioEditor };\n}\n\nexport interface IframeBridgeProvider {\n serverClientId: number | null;\n takeoverUndoManager: (file: DrawioFile) => () => void;\n destroy: () => void;\n}\n\nfunction readVarUint(data: Uint8Array, pos: number): [number, number] {\n let result = 0;\n let shift = 0;\n let byte: number;\n do {\n byte = data[pos++];\n result |= (byte & 0x7f) << shift;\n shift += 7;\n } while (byte >= 0x80);\n return [result >>> 0, pos];\n}\n\nfunction writeVarUint(value: number): number[] {\n const bytes: number[] = [];\n while (value > 0x7f) {\n bytes.push((value & 0x7f) | 0x80);\n value >>>= 7;\n }\n bytes.push(value);\n return bytes;\n}\n\nfunction readVarString(data: Uint8Array, pos: number): [string, number] {\n const [len, pos2] = readVarUint(data, pos);\n const str = new TextDecoder().decode(data.subarray(pos2, pos2 + len));\n return [str, pos2 + len];\n}\n\nfunction writeVarString(str: string): number[] {\n const encoded = new TextEncoder().encode(str);\n return [...writeVarUint(encoded.length), ...encoded];\n}\n\nfunction remapClientIdInUpdate(\n update: Uint8Array,\n fromId: number,\n toId: number,\n): Uint8Array {\n const result: number[] = [];\n let pos = 0;\n\n const [count, pos2] = readVarUint(update, pos);\n pos = pos2;\n result.push(...writeVarUint(count));\n\n for (let i = 0; i < count; i++) {\n const [clientID, pos3] = readVarUint(update, pos);\n pos = pos3;\n const [clock, pos4] = readVarUint(update, pos);\n pos = pos4;\n const [state, pos5] = readVarString(update, pos);\n pos = pos5;\n\n const mappedId = clientID === fromId ? toId : clientID;\n result.push(...writeVarUint(mappedId));\n result.push(...writeVarUint(clock));\n result.push(...writeVarString(state));\n }\n\n return new Uint8Array(result);\n}\n\nexport function createIframeBridgeProvider(\n ydoc: Y.Doc,\n awareness: Awareness,\n): IframeBridgeProvider {\n let applyingParentUpdate = false;\n let serverClientId: number | null = null;\n let currentCleanup: (() => void) | null = null;\n let currentMxLike: MxLike | null = null;\n\n const onYdocUpdate = (update: Uint8Array) => {\n if (applyingParentUpdate) return;\n // 本地编辑,添加 history 条目\n if (currentMxLike) {\n if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) {\n currentMxLike.history.splice(\n currentMxLike.indexOfNextAdd,\n currentMxLike.history.length - currentMxLike.indexOfNextAdd,\n );\n }\n currentMxLike.history.push({});\n currentMxLike.indexOfNextAdd = currentMxLike.history.length;\n currentMxLike.fireEvent(createMxEventObject(\"add\", { edit: { changes: [] } }));\n }\n window.parent.postMessage(\n { type: \"ydoc-update\", payload: Array.from(update) },\n \"*\",\n );\n };\n\n const onAwarenessUpdate = ({\n added,\n updated,\n removed,\n }: {\n added: number[];\n updated: number[];\n removed: number[];\n }) => {\n if (applyingParentUpdate) return;\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n\n const update = encodeAwarenessUpdate(awareness, changes);\n const remapped =\n serverClientId != null\n ? remapClientIdInUpdate(update, awareness.clientID, serverClientId)\n : update;\n\n window.parent.postMessage(\n { type: \"awareness-update\", payload: Array.from(remapped) },\n \"*\",\n );\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== window.parent) return;\n const { type, payload, serverClientId: receivedServerId } = event.data;\n\n if (type === \"pong\" && receivedServerId != null) {\n serverClientId = receivedServerId;\n return;\n }\n\n if (type === \"ydoc-sync\" || type === \"ydoc-update\") {\n applyingParentUpdate = true;\n Y.applyUpdate(ydoc, new Uint8Array(payload));\n applyingParentUpdate = false;\n } else if (type === \"awareness-sync\" || type === \"awareness-update\") {\n if (receivedServerId != null) {\n serverClientId = receivedServerId;\n }\n\n const raw = new Uint8Array(payload);\n const remapped =\n serverClientId != null\n ? remapClientIdInUpdate(raw, serverClientId, awareness.clientID)\n : raw;\n\n applyingParentUpdate = true;\n applyAwarenessUpdate(awareness, remapped, null);\n applyingParentUpdate = false;\n } else if (type === \"undo\" && currentMxLike) {\n applyingParentUpdate = true;\n if (currentMxLike.indexOfNextAdd > 0) currentMxLike.indexOfNextAdd--;\n currentMxLike.fireEvent(createMxEventObject(\"undo\", { edit: { changes: [] } }));\n applyingParentUpdate = false;\n } else if (type === \"redo\" && currentMxLike) {\n applyingParentUpdate = true;\n if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) currentMxLike.indexOfNextAdd++;\n currentMxLike.fireEvent(createMxEventObject(\"redo\", { edit: { changes: [] } }));\n applyingParentUpdate = false;\n } else if (type === \"clear\" && currentMxLike) {\n applyingParentUpdate = true;\n currentMxLike.history = [];\n currentMxLike.indexOfNextAdd = 0;\n currentMxLike.fireEvent(createMxEventObject(\"clear\"));\n applyingParentUpdate = false;\n }\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n awareness.on(\"update\", onAwarenessUpdate);\n window.addEventListener(\"message\", onMessage);\n\n window.parent.postMessage({ type: \"init\" }, \"*\");\n\n return {\n get serverClientId() {\n return serverClientId;\n },\n takeoverUndoManager(file: DrawioFile) {\n if (currentCleanup) {\n currentCleanup();\n }\n\n const editor = file.getUi().editor;\n const originUndoManager = editor.undoManager;\n\n const pairs: Array<[string, ListenerFn]> = [];\n const raw = Array.isArray(originUndoManager?.eventListeners)\n ? (originUndoManager.eventListeners as unknown[])\n : [];\n for (let i = 0; i + 1 < raw.length; i += 2) {\n const key = String(raw[i]);\n const fn = raw[i + 1] as ListenerFn;\n pairs.push([key, fn]);\n }\n\n const mxLike: MxLike = {\n eventListeners: [] as Array<string | ListenerFn>,\n history: [] as unknown[],\n indexOfNextAdd: 0,\n\n addListener(name: string, fn: ListenerFn) {\n this.eventListeners.push(name, fn);\n },\n\n fireEvent(evt: unknown) {\n const eventName: string =\n (evt as { name?: string } | undefined)?.name ||\n ((evt as { getName?: () => string } | undefined)?.getName?.() ?? \"\");\n for (let i = 0; i + 1 < this.eventListeners.length; i += 2) {\n const key = this.eventListeners[i];\n const listener = this.eventListeners[i + 1] as ListenerFn;\n if (key === eventName) {\n try {\n listener(this, evt);\n } catch (e) {\n console.warn(\"[iframe-bridge] undoManager event listener error:\", e);\n }\n }\n }\n },\n\n canUndo(): boolean {\n return this.indexOfNextAdd > 0;\n },\n\n canRedo(): boolean {\n return this.indexOfNextAdd < this.history.length;\n },\n\n undo() {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"undo\" }, \"*\");\n }\n },\n\n redo() {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"redo\" }, \"*\");\n }\n },\n\n undoableEditHappened() {\n // no-op\n },\n };\n\n pairs.forEach(([key, fn]) => {\n const k = key.toLowerCase();\n if (k === \"add\" || k === \"clear\" || k === \"undo\" || k === \"redo\") {\n mxLike.addListener(k, fn);\n }\n });\n\n currentMxLike = mxLike;\n editor.undoManager = mxLike as any;\n editor.undoListener = function () {};\n\n const cleanup = () => {\n editor.undoManager = originUndoManager;\n editor.undoListener = originUndoManager?.undoListener as ((...args: unknown[]) => void) | undefined;\n currentMxLike = null;\n };\n\n currentCleanup = cleanup;\n return cleanup;\n },\n destroy: () => {\n ydoc.off(\"update\", onYdocUpdate);\n awareness.off(\"update\", onAwarenessUpdate);\n window.removeEventListener(\"message\", onMessage);\n if (currentCleanup) {\n currentCleanup();\n }\n },\n };\n}\n"],"names":["awareness","encodeAwarenessUpdate","Y","applyAwarenessUpdate"],"mappings":"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"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import * as Y from "yjs";
|
|
2
|
+
import { encodeAwarenessUpdate, applyAwarenessUpdate } from "y-protocols/awareness";
|
|
3
|
+
function createMxEventObject(name, props) {
|
|
4
|
+
const _props = props || {};
|
|
5
|
+
return {
|
|
6
|
+
name,
|
|
7
|
+
getName: () => name,
|
|
8
|
+
getProperty: (k) => _props[k]
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function readVarUint(data, pos) {
|
|
12
|
+
let result = 0;
|
|
13
|
+
let shift = 0;
|
|
14
|
+
let byte;
|
|
15
|
+
do {
|
|
16
|
+
byte = data[pos++];
|
|
17
|
+
result |= (byte & 127) << shift;
|
|
18
|
+
shift += 7;
|
|
19
|
+
} while (byte >= 128);
|
|
20
|
+
return [result >>> 0, pos];
|
|
21
|
+
}
|
|
22
|
+
function writeVarUint(value) {
|
|
23
|
+
const bytes = [];
|
|
24
|
+
while (value > 127) {
|
|
25
|
+
bytes.push(value & 127 | 128);
|
|
26
|
+
value >>>= 7;
|
|
27
|
+
}
|
|
28
|
+
bytes.push(value);
|
|
29
|
+
return bytes;
|
|
30
|
+
}
|
|
31
|
+
function readVarString(data, pos) {
|
|
32
|
+
const [len, pos2] = readVarUint(data, pos);
|
|
33
|
+
const str = new TextDecoder().decode(data.subarray(pos2, pos2 + len));
|
|
34
|
+
return [str, pos2 + len];
|
|
35
|
+
}
|
|
36
|
+
function writeVarString(str) {
|
|
37
|
+
const encoded = new TextEncoder().encode(str);
|
|
38
|
+
return [...writeVarUint(encoded.length), ...encoded];
|
|
39
|
+
}
|
|
40
|
+
function remapClientIdInUpdate(update, fromId, toId) {
|
|
41
|
+
const result = [];
|
|
42
|
+
let pos = 0;
|
|
43
|
+
const [count, pos2] = readVarUint(update, pos);
|
|
44
|
+
pos = pos2;
|
|
45
|
+
result.push(...writeVarUint(count));
|
|
46
|
+
for (let i = 0; i < count; i++) {
|
|
47
|
+
const [clientID, pos3] = readVarUint(update, pos);
|
|
48
|
+
pos = pos3;
|
|
49
|
+
const [clock, pos4] = readVarUint(update, pos);
|
|
50
|
+
pos = pos4;
|
|
51
|
+
const [state, pos5] = readVarString(update, pos);
|
|
52
|
+
pos = pos5;
|
|
53
|
+
const mappedId = clientID === fromId ? toId : clientID;
|
|
54
|
+
result.push(...writeVarUint(mappedId));
|
|
55
|
+
result.push(...writeVarUint(clock));
|
|
56
|
+
result.push(...writeVarString(state));
|
|
57
|
+
}
|
|
58
|
+
return new Uint8Array(result);
|
|
59
|
+
}
|
|
60
|
+
function createIframeBridgeProvider(ydoc, awareness) {
|
|
61
|
+
let applyingParentUpdate = false;
|
|
62
|
+
let serverClientId = null;
|
|
63
|
+
let currentCleanup = null;
|
|
64
|
+
let currentMxLike = null;
|
|
65
|
+
const onYdocUpdate = (update) => {
|
|
66
|
+
if (applyingParentUpdate) return;
|
|
67
|
+
if (currentMxLike) {
|
|
68
|
+
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) {
|
|
69
|
+
currentMxLike.history.splice(
|
|
70
|
+
currentMxLike.indexOfNextAdd,
|
|
71
|
+
currentMxLike.history.length - currentMxLike.indexOfNextAdd
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
currentMxLike.history.push({});
|
|
75
|
+
currentMxLike.indexOfNextAdd = currentMxLike.history.length;
|
|
76
|
+
currentMxLike.fireEvent(createMxEventObject("add", { edit: { changes: [] } }));
|
|
77
|
+
}
|
|
78
|
+
window.parent.postMessage(
|
|
79
|
+
{ type: "ydoc-update", payload: Array.from(update) },
|
|
80
|
+
"*"
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
const onAwarenessUpdate = ({
|
|
84
|
+
added,
|
|
85
|
+
updated,
|
|
86
|
+
removed
|
|
87
|
+
}) => {
|
|
88
|
+
if (applyingParentUpdate) return;
|
|
89
|
+
const changes = [...added, ...updated, ...removed];
|
|
90
|
+
if (changes.length === 0) return;
|
|
91
|
+
const update = encodeAwarenessUpdate(awareness, changes);
|
|
92
|
+
const remapped = serverClientId != null ? remapClientIdInUpdate(update, awareness.clientID, serverClientId) : update;
|
|
93
|
+
window.parent.postMessage(
|
|
94
|
+
{ type: "awareness-update", payload: Array.from(remapped) },
|
|
95
|
+
"*"
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
const onMessage = (event) => {
|
|
99
|
+
if (event.source !== window.parent) return;
|
|
100
|
+
const { type, payload, serverClientId: receivedServerId } = event.data;
|
|
101
|
+
if (type === "pong" && receivedServerId != null) {
|
|
102
|
+
serverClientId = receivedServerId;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (type === "ydoc-sync" || type === "ydoc-update") {
|
|
106
|
+
applyingParentUpdate = true;
|
|
107
|
+
Y.applyUpdate(ydoc, new Uint8Array(payload));
|
|
108
|
+
applyingParentUpdate = false;
|
|
109
|
+
} else if (type === "awareness-sync" || type === "awareness-update") {
|
|
110
|
+
if (receivedServerId != null) {
|
|
111
|
+
serverClientId = receivedServerId;
|
|
112
|
+
}
|
|
113
|
+
const raw = new Uint8Array(payload);
|
|
114
|
+
const remapped = serverClientId != null ? remapClientIdInUpdate(raw, serverClientId, awareness.clientID) : raw;
|
|
115
|
+
applyingParentUpdate = true;
|
|
116
|
+
applyAwarenessUpdate(awareness, remapped, null);
|
|
117
|
+
applyingParentUpdate = false;
|
|
118
|
+
} else if (type === "undo" && currentMxLike) {
|
|
119
|
+
applyingParentUpdate = true;
|
|
120
|
+
if (currentMxLike.indexOfNextAdd > 0) currentMxLike.indexOfNextAdd--;
|
|
121
|
+
currentMxLike.fireEvent(createMxEventObject("undo", { edit: { changes: [] } }));
|
|
122
|
+
applyingParentUpdate = false;
|
|
123
|
+
} else if (type === "redo" && currentMxLike) {
|
|
124
|
+
applyingParentUpdate = true;
|
|
125
|
+
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) currentMxLike.indexOfNextAdd++;
|
|
126
|
+
currentMxLike.fireEvent(createMxEventObject("redo", { edit: { changes: [] } }));
|
|
127
|
+
applyingParentUpdate = false;
|
|
128
|
+
} else if (type === "clear" && currentMxLike) {
|
|
129
|
+
applyingParentUpdate = true;
|
|
130
|
+
currentMxLike.history = [];
|
|
131
|
+
currentMxLike.indexOfNextAdd = 0;
|
|
132
|
+
currentMxLike.fireEvent(createMxEventObject("clear"));
|
|
133
|
+
applyingParentUpdate = false;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
ydoc.on("update", onYdocUpdate);
|
|
137
|
+
awareness.on("update", onAwarenessUpdate);
|
|
138
|
+
window.addEventListener("message", onMessage);
|
|
139
|
+
window.parent.postMessage({ type: "init" }, "*");
|
|
140
|
+
return {
|
|
141
|
+
get serverClientId() {
|
|
142
|
+
return serverClientId;
|
|
143
|
+
},
|
|
144
|
+
takeoverUndoManager(file) {
|
|
145
|
+
if (currentCleanup) {
|
|
146
|
+
currentCleanup();
|
|
147
|
+
}
|
|
148
|
+
const editor = file.getUi().editor;
|
|
149
|
+
const originUndoManager = editor.undoManager;
|
|
150
|
+
const pairs = [];
|
|
151
|
+
const raw = Array.isArray(originUndoManager == null ? void 0 : originUndoManager.eventListeners) ? originUndoManager.eventListeners : [];
|
|
152
|
+
for (let i = 0; i + 1 < raw.length; i += 2) {
|
|
153
|
+
const key = String(raw[i]);
|
|
154
|
+
const fn = raw[i + 1];
|
|
155
|
+
pairs.push([key, fn]);
|
|
156
|
+
}
|
|
157
|
+
const mxLike = {
|
|
158
|
+
eventListeners: [],
|
|
159
|
+
history: [],
|
|
160
|
+
indexOfNextAdd: 0,
|
|
161
|
+
addListener(name, fn) {
|
|
162
|
+
this.eventListeners.push(name, fn);
|
|
163
|
+
},
|
|
164
|
+
fireEvent(evt) {
|
|
165
|
+
var _a;
|
|
166
|
+
const eventName = (evt == null ? void 0 : evt.name) || (((_a = evt == null ? void 0 : evt.getName) == null ? void 0 : _a.call(evt)) ?? "");
|
|
167
|
+
for (let i = 0; i + 1 < this.eventListeners.length; i += 2) {
|
|
168
|
+
const key = this.eventListeners[i];
|
|
169
|
+
const listener = this.eventListeners[i + 1];
|
|
170
|
+
if (key === eventName) {
|
|
171
|
+
try {
|
|
172
|
+
listener(this, evt);
|
|
173
|
+
} catch (e) {
|
|
174
|
+
console.warn("[iframe-bridge] undoManager event listener error:", e);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
canUndo() {
|
|
180
|
+
return this.indexOfNextAdd > 0;
|
|
181
|
+
},
|
|
182
|
+
canRedo() {
|
|
183
|
+
return this.indexOfNextAdd < this.history.length;
|
|
184
|
+
},
|
|
185
|
+
undo() {
|
|
186
|
+
if (!applyingParentUpdate) {
|
|
187
|
+
window.parent.postMessage({ type: "undo" }, "*");
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
redo() {
|
|
191
|
+
if (!applyingParentUpdate) {
|
|
192
|
+
window.parent.postMessage({ type: "redo" }, "*");
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
undoableEditHappened() {
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
pairs.forEach(([key, fn]) => {
|
|
199
|
+
const k = key.toLowerCase();
|
|
200
|
+
if (k === "add" || k === "clear" || k === "undo" || k === "redo") {
|
|
201
|
+
mxLike.addListener(k, fn);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
currentMxLike = mxLike;
|
|
205
|
+
editor.undoManager = mxLike;
|
|
206
|
+
editor.undoListener = function() {
|
|
207
|
+
};
|
|
208
|
+
const cleanup = () => {
|
|
209
|
+
editor.undoManager = originUndoManager;
|
|
210
|
+
editor.undoListener = originUndoManager == null ? void 0 : originUndoManager.undoListener;
|
|
211
|
+
currentMxLike = null;
|
|
212
|
+
};
|
|
213
|
+
currentCleanup = cleanup;
|
|
214
|
+
return cleanup;
|
|
215
|
+
},
|
|
216
|
+
destroy: () => {
|
|
217
|
+
ydoc.off("update", onYdocUpdate);
|
|
218
|
+
awareness.off("update", onAwarenessUpdate);
|
|
219
|
+
window.removeEventListener("message", onMessage);
|
|
220
|
+
if (currentCleanup) {
|
|
221
|
+
currentCleanup();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
export {
|
|
227
|
+
createIframeBridgeProvider
|
|
228
|
+
};
|
|
229
|
+
//# sourceMappingURL=provider.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.es.js","sources":["../../../iframe-bridge/src/provider.ts"],"sourcesContent":["import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\n\ntype ListenerFn = (sender: unknown, evt?: unknown) => void;\n\nfunction createMxEventObject(name: string, props?: Record<string, unknown>) {\n const _props = props || {};\n return {\n name,\n getName: () => name,\n getProperty: (k: string) => _props[k],\n };\n}\n\ntype MxLike = Record<string, unknown> & {\n eventListeners: Array<string | ListenerFn>;\n history: unknown[];\n indexOfNextAdd: number;\n addListener(name: string, fn: ListenerFn): void;\n fireEvent(evt: unknown): void;\n canUndo(): boolean;\n canRedo(): boolean;\n undo(): void;\n redo(): void;\n undoableEditHappened(_edit: unknown): void;\n};\n\nexport interface DrawioEditor {\n undoManager?: {\n eventListeners?: unknown[];\n [key: string]: unknown;\n };\n undoListener?: (...args: unknown[]) => void;\n}\n\nexport interface DrawioFile {\n getUi(): { editor: DrawioEditor };\n}\n\nexport interface IframeBridgeProvider {\n serverClientId: number | null;\n takeoverUndoManager: (file: DrawioFile) => () => void;\n destroy: () => void;\n}\n\nfunction readVarUint(data: Uint8Array, pos: number): [number, number] {\n let result = 0;\n let shift = 0;\n let byte: number;\n do {\n byte = data[pos++];\n result |= (byte & 0x7f) << shift;\n shift += 7;\n } while (byte >= 0x80);\n return [result >>> 0, pos];\n}\n\nfunction writeVarUint(value: number): number[] {\n const bytes: number[] = [];\n while (value > 0x7f) {\n bytes.push((value & 0x7f) | 0x80);\n value >>>= 7;\n }\n bytes.push(value);\n return bytes;\n}\n\nfunction readVarString(data: Uint8Array, pos: number): [string, number] {\n const [len, pos2] = readVarUint(data, pos);\n const str = new TextDecoder().decode(data.subarray(pos2, pos2 + len));\n return [str, pos2 + len];\n}\n\nfunction writeVarString(str: string): number[] {\n const encoded = new TextEncoder().encode(str);\n return [...writeVarUint(encoded.length), ...encoded];\n}\n\nfunction remapClientIdInUpdate(\n update: Uint8Array,\n fromId: number,\n toId: number,\n): Uint8Array {\n const result: number[] = [];\n let pos = 0;\n\n const [count, pos2] = readVarUint(update, pos);\n pos = pos2;\n result.push(...writeVarUint(count));\n\n for (let i = 0; i < count; i++) {\n const [clientID, pos3] = readVarUint(update, pos);\n pos = pos3;\n const [clock, pos4] = readVarUint(update, pos);\n pos = pos4;\n const [state, pos5] = readVarString(update, pos);\n pos = pos5;\n\n const mappedId = clientID === fromId ? toId : clientID;\n result.push(...writeVarUint(mappedId));\n result.push(...writeVarUint(clock));\n result.push(...writeVarString(state));\n }\n\n return new Uint8Array(result);\n}\n\nexport function createIframeBridgeProvider(\n ydoc: Y.Doc,\n awareness: Awareness,\n): IframeBridgeProvider {\n let applyingParentUpdate = false;\n let serverClientId: number | null = null;\n let currentCleanup: (() => void) | null = null;\n let currentMxLike: MxLike | null = null;\n\n const onYdocUpdate = (update: Uint8Array) => {\n if (applyingParentUpdate) return;\n // 本地编辑,添加 history 条目\n if (currentMxLike) {\n if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) {\n currentMxLike.history.splice(\n currentMxLike.indexOfNextAdd,\n currentMxLike.history.length - currentMxLike.indexOfNextAdd,\n );\n }\n currentMxLike.history.push({});\n currentMxLike.indexOfNextAdd = currentMxLike.history.length;\n currentMxLike.fireEvent(createMxEventObject(\"add\", { edit: { changes: [] } }));\n }\n window.parent.postMessage(\n { type: \"ydoc-update\", payload: Array.from(update) },\n \"*\",\n );\n };\n\n const onAwarenessUpdate = ({\n added,\n updated,\n removed,\n }: {\n added: number[];\n updated: number[];\n removed: number[];\n }) => {\n if (applyingParentUpdate) return;\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n\n const update = encodeAwarenessUpdate(awareness, changes);\n const remapped =\n serverClientId != null\n ? remapClientIdInUpdate(update, awareness.clientID, serverClientId)\n : update;\n\n window.parent.postMessage(\n { type: \"awareness-update\", payload: Array.from(remapped) },\n \"*\",\n );\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== window.parent) return;\n const { type, payload, serverClientId: receivedServerId } = event.data;\n\n if (type === \"pong\" && receivedServerId != null) {\n serverClientId = receivedServerId;\n return;\n }\n\n if (type === \"ydoc-sync\" || type === \"ydoc-update\") {\n applyingParentUpdate = true;\n Y.applyUpdate(ydoc, new Uint8Array(payload));\n applyingParentUpdate = false;\n } else if (type === \"awareness-sync\" || type === \"awareness-update\") {\n if (receivedServerId != null) {\n serverClientId = receivedServerId;\n }\n\n const raw = new Uint8Array(payload);\n const remapped =\n serverClientId != null\n ? remapClientIdInUpdate(raw, serverClientId, awareness.clientID)\n : raw;\n\n applyingParentUpdate = true;\n applyAwarenessUpdate(awareness, remapped, null);\n applyingParentUpdate = false;\n } else if (type === \"undo\" && currentMxLike) {\n applyingParentUpdate = true;\n if (currentMxLike.indexOfNextAdd > 0) currentMxLike.indexOfNextAdd--;\n currentMxLike.fireEvent(createMxEventObject(\"undo\", { edit: { changes: [] } }));\n applyingParentUpdate = false;\n } else if (type === \"redo\" && currentMxLike) {\n applyingParentUpdate = true;\n if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) currentMxLike.indexOfNextAdd++;\n currentMxLike.fireEvent(createMxEventObject(\"redo\", { edit: { changes: [] } }));\n applyingParentUpdate = false;\n } else if (type === \"clear\" && currentMxLike) {\n applyingParentUpdate = true;\n currentMxLike.history = [];\n currentMxLike.indexOfNextAdd = 0;\n currentMxLike.fireEvent(createMxEventObject(\"clear\"));\n applyingParentUpdate = false;\n }\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n awareness.on(\"update\", onAwarenessUpdate);\n window.addEventListener(\"message\", onMessage);\n\n window.parent.postMessage({ type: \"init\" }, \"*\");\n\n return {\n get serverClientId() {\n return serverClientId;\n },\n takeoverUndoManager(file: DrawioFile) {\n if (currentCleanup) {\n currentCleanup();\n }\n\n const editor = file.getUi().editor;\n const originUndoManager = editor.undoManager;\n\n const pairs: Array<[string, ListenerFn]> = [];\n const raw = Array.isArray(originUndoManager?.eventListeners)\n ? (originUndoManager.eventListeners as unknown[])\n : [];\n for (let i = 0; i + 1 < raw.length; i += 2) {\n const key = String(raw[i]);\n const fn = raw[i + 1] as ListenerFn;\n pairs.push([key, fn]);\n }\n\n const mxLike: MxLike = {\n eventListeners: [] as Array<string | ListenerFn>,\n history: [] as unknown[],\n indexOfNextAdd: 0,\n\n addListener(name: string, fn: ListenerFn) {\n this.eventListeners.push(name, fn);\n },\n\n fireEvent(evt: unknown) {\n const eventName: string =\n (evt as { name?: string } | undefined)?.name ||\n ((evt as { getName?: () => string } | undefined)?.getName?.() ?? \"\");\n for (let i = 0; i + 1 < this.eventListeners.length; i += 2) {\n const key = this.eventListeners[i];\n const listener = this.eventListeners[i + 1] as ListenerFn;\n if (key === eventName) {\n try {\n listener(this, evt);\n } catch (e) {\n console.warn(\"[iframe-bridge] undoManager event listener error:\", e);\n }\n }\n }\n },\n\n canUndo(): boolean {\n return this.indexOfNextAdd > 0;\n },\n\n canRedo(): boolean {\n return this.indexOfNextAdd < this.history.length;\n },\n\n undo() {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"undo\" }, \"*\");\n }\n },\n\n redo() {\n if (!applyingParentUpdate) {\n window.parent.postMessage({ type: \"redo\" }, \"*\");\n }\n },\n\n undoableEditHappened() {\n // no-op\n },\n };\n\n pairs.forEach(([key, fn]) => {\n const k = key.toLowerCase();\n if (k === \"add\" || k === \"clear\" || k === \"undo\" || k === \"redo\") {\n mxLike.addListener(k, fn);\n }\n });\n\n currentMxLike = mxLike;\n editor.undoManager = mxLike as any;\n editor.undoListener = function () {};\n\n const cleanup = () => {\n editor.undoManager = originUndoManager;\n editor.undoListener = originUndoManager?.undoListener as ((...args: unknown[]) => void) | undefined;\n currentMxLike = null;\n };\n\n currentCleanup = cleanup;\n return cleanup;\n },\n destroy: () => {\n ydoc.off(\"update\", onYdocUpdate);\n awareness.off(\"update\", onAwarenessUpdate);\n window.removeEventListener(\"message\", onMessage);\n if (currentCleanup) {\n currentCleanup();\n }\n },\n };\n}\n"],"names":[],"mappings":"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"}
|