y-mxgraph 0.4.1 → 0.5.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/iframe-bridge/provider.cjs.js +26 -15
- package/iframe-bridge/provider.cjs.js.map +1 -1
- package/iframe-bridge/provider.es.js +26 -15
- package/iframe-bridge/provider.es.js.map +1 -1
- package/iframe-bridge/server.cjs.js +29 -54
- package/iframe-bridge/server.cjs.js.map +1 -1
- package/iframe-bridge/server.es.js +29 -54
- package/iframe-bridge/server.es.js.map +1 -1
- package/package.json +1 -1
|
@@ -83,17 +83,6 @@ function createIframeBridgeProvider(ydoc, awareness$1) {
|
|
|
83
83
|
let currentMxLike = null;
|
|
84
84
|
const onYdocUpdate = (update) => {
|
|
85
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
86
|
window.parent.postMessage(
|
|
98
87
|
{ type: "ydoc-update", payload: Array.from(update) },
|
|
99
88
|
"*"
|
|
@@ -134,15 +123,34 @@ function createIframeBridgeProvider(ydoc, awareness$1) {
|
|
|
134
123
|
applyingParentUpdate = true;
|
|
135
124
|
awareness.applyAwarenessUpdate(awareness$1, remapped, null);
|
|
136
125
|
applyingParentUpdate = false;
|
|
126
|
+
} else if (type === "add" && currentMxLike) {
|
|
127
|
+
applyingParentUpdate = true;
|
|
128
|
+
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) {
|
|
129
|
+
currentMxLike.history.splice(
|
|
130
|
+
currentMxLike.indexOfNextAdd,
|
|
131
|
+
currentMxLike.history.length - currentMxLike.indexOfNextAdd
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
currentMxLike.history.push({});
|
|
135
|
+
currentMxLike.indexOfNextAdd = currentMxLike.history.length;
|
|
136
|
+
currentMxLike.fireEvent(
|
|
137
|
+
createMxEventObject("add", { edit: { changes: [] } })
|
|
138
|
+
);
|
|
139
|
+
applyingParentUpdate = false;
|
|
137
140
|
} else if (type === "undo" && currentMxLike) {
|
|
138
141
|
applyingParentUpdate = true;
|
|
139
142
|
if (currentMxLike.indexOfNextAdd > 0) currentMxLike.indexOfNextAdd--;
|
|
140
|
-
currentMxLike.fireEvent(
|
|
143
|
+
currentMxLike.fireEvent(
|
|
144
|
+
createMxEventObject("undo", { edit: { changes: [] } })
|
|
145
|
+
);
|
|
141
146
|
applyingParentUpdate = false;
|
|
142
147
|
} else if (type === "redo" && currentMxLike) {
|
|
143
148
|
applyingParentUpdate = true;
|
|
144
|
-
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length)
|
|
145
|
-
|
|
149
|
+
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length)
|
|
150
|
+
currentMxLike.indexOfNextAdd++;
|
|
151
|
+
currentMxLike.fireEvent(
|
|
152
|
+
createMxEventObject("redo", { edit: { changes: [] } })
|
|
153
|
+
);
|
|
146
154
|
applyingParentUpdate = false;
|
|
147
155
|
} else if (type === "clear" && currentMxLike) {
|
|
148
156
|
applyingParentUpdate = true;
|
|
@@ -190,7 +198,10 @@ function createIframeBridgeProvider(ydoc, awareness$1) {
|
|
|
190
198
|
try {
|
|
191
199
|
listener(this, evt);
|
|
192
200
|
} catch (e) {
|
|
193
|
-
console.warn(
|
|
201
|
+
console.warn(
|
|
202
|
+
"[iframe-bridge] undoManager event listener error:",
|
|
203
|
+
e
|
|
204
|
+
);
|
|
194
205
|
}
|
|
195
206
|
}
|
|
196
207
|
}
|
|
@@ -1 +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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"}
|
|
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 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 === \"add\" && currentMxLike) {\n applyingParentUpdate = true;\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(\n createMxEventObject(\"add\", { edit: { changes: [] } }),\n );\n applyingParentUpdate = false;\n } else if (type === \"undo\" && currentMxLike) {\n applyingParentUpdate = true;\n if (currentMxLike.indexOfNextAdd > 0) currentMxLike.indexOfNextAdd--;\n currentMxLike.fireEvent(\n createMxEventObject(\"undo\", { edit: { changes: [] } }),\n );\n applyingParentUpdate = false;\n } else if (type === \"redo\" && currentMxLike) {\n applyingParentUpdate = true;\n if (currentMxLike.indexOfNextAdd < currentMxLike.history.length)\n currentMxLike.indexOfNextAdd++;\n currentMxLike.fireEvent(\n createMxEventObject(\"redo\", { edit: { changes: [] } }),\n );\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 \"\");\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(\n \"[iframe-bridge] undoManager event listener error:\",\n e,\n );\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\n | ((...args: unknown[]) => void)\n | 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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"}
|
|
@@ -64,17 +64,6 @@ function createIframeBridgeProvider(ydoc, awareness) {
|
|
|
64
64
|
let currentMxLike = null;
|
|
65
65
|
const onYdocUpdate = (update) => {
|
|
66
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
67
|
window.parent.postMessage(
|
|
79
68
|
{ type: "ydoc-update", payload: Array.from(update) },
|
|
80
69
|
"*"
|
|
@@ -115,15 +104,34 @@ function createIframeBridgeProvider(ydoc, awareness) {
|
|
|
115
104
|
applyingParentUpdate = true;
|
|
116
105
|
applyAwarenessUpdate(awareness, remapped, null);
|
|
117
106
|
applyingParentUpdate = false;
|
|
107
|
+
} else if (type === "add" && currentMxLike) {
|
|
108
|
+
applyingParentUpdate = true;
|
|
109
|
+
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length) {
|
|
110
|
+
currentMxLike.history.splice(
|
|
111
|
+
currentMxLike.indexOfNextAdd,
|
|
112
|
+
currentMxLike.history.length - currentMxLike.indexOfNextAdd
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
currentMxLike.history.push({});
|
|
116
|
+
currentMxLike.indexOfNextAdd = currentMxLike.history.length;
|
|
117
|
+
currentMxLike.fireEvent(
|
|
118
|
+
createMxEventObject("add", { edit: { changes: [] } })
|
|
119
|
+
);
|
|
120
|
+
applyingParentUpdate = false;
|
|
118
121
|
} else if (type === "undo" && currentMxLike) {
|
|
119
122
|
applyingParentUpdate = true;
|
|
120
123
|
if (currentMxLike.indexOfNextAdd > 0) currentMxLike.indexOfNextAdd--;
|
|
121
|
-
currentMxLike.fireEvent(
|
|
124
|
+
currentMxLike.fireEvent(
|
|
125
|
+
createMxEventObject("undo", { edit: { changes: [] } })
|
|
126
|
+
);
|
|
122
127
|
applyingParentUpdate = false;
|
|
123
128
|
} else if (type === "redo" && currentMxLike) {
|
|
124
129
|
applyingParentUpdate = true;
|
|
125
|
-
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length)
|
|
126
|
-
|
|
130
|
+
if (currentMxLike.indexOfNextAdd < currentMxLike.history.length)
|
|
131
|
+
currentMxLike.indexOfNextAdd++;
|
|
132
|
+
currentMxLike.fireEvent(
|
|
133
|
+
createMxEventObject("redo", { edit: { changes: [] } })
|
|
134
|
+
);
|
|
127
135
|
applyingParentUpdate = false;
|
|
128
136
|
} else if (type === "clear" && currentMxLike) {
|
|
129
137
|
applyingParentUpdate = true;
|
|
@@ -171,7 +179,10 @@ function createIframeBridgeProvider(ydoc, awareness) {
|
|
|
171
179
|
try {
|
|
172
180
|
listener(this, evt);
|
|
173
181
|
} catch (e) {
|
|
174
|
-
console.warn(
|
|
182
|
+
console.warn(
|
|
183
|
+
"[iframe-bridge] undoManager event listener error:",
|
|
184
|
+
e
|
|
185
|
+
);
|
|
175
186
|
}
|
|
176
187
|
}
|
|
177
188
|
}
|
|
@@ -1 +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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"}
|
|
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 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 === \"add\" && currentMxLike) {\n applyingParentUpdate = true;\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(\n createMxEventObject(\"add\", { edit: { changes: [] } }),\n );\n applyingParentUpdate = false;\n } else if (type === \"undo\" && currentMxLike) {\n applyingParentUpdate = true;\n if (currentMxLike.indexOfNextAdd > 0) currentMxLike.indexOfNextAdd--;\n currentMxLike.fireEvent(\n createMxEventObject(\"undo\", { edit: { changes: [] } }),\n );\n applyingParentUpdate = false;\n } else if (type === \"redo\" && currentMxLike) {\n applyingParentUpdate = true;\n if (currentMxLike.indexOfNextAdd < currentMxLike.history.length)\n currentMxLike.indexOfNextAdd++;\n currentMxLike.fireEvent(\n createMxEventObject(\"redo\", { edit: { changes: [] } }),\n );\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 \"\");\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(\n \"[iframe-bridge] undoManager event listener error:\",\n e,\n );\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\n | ((...args: unknown[]) => void)\n | 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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"}
|
|
@@ -20,13 +20,17 @@ function _interopNamespaceDefault(e) {
|
|
|
20
20
|
}
|
|
21
21
|
const Y__namespace = /* @__PURE__ */ _interopNamespaceDefault(Y);
|
|
22
22
|
const IFRAME_ORIGIN = {};
|
|
23
|
-
function createIframeBridgeServer(ydoc, awareness$1, options) {
|
|
23
|
+
function createIframeBridgeServer(iframe, ydoc, awareness$1, options) {
|
|
24
24
|
const { undoManager } = options ?? {};
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
function postToIframe(type, payload) {
|
|
26
|
+
const cw = iframe.contentWindow;
|
|
27
|
+
if (cw) {
|
|
28
|
+
cw.postMessage({ type, payload }, "*");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
27
31
|
const onYdocUpdate = (update, origin) => {
|
|
28
32
|
if (origin === IFRAME_ORIGIN) return;
|
|
29
|
-
|
|
33
|
+
postToIframe("ydoc-update", update);
|
|
30
34
|
};
|
|
31
35
|
const onAwarenessUpdate = ({
|
|
32
36
|
added,
|
|
@@ -36,56 +40,33 @@ function createIframeBridgeServer(ydoc, awareness$1, options) {
|
|
|
36
40
|
const changes = [...added, ...updated, ...removed];
|
|
37
41
|
if (changes.length === 0) return;
|
|
38
42
|
const update = awareness.encodeAwarenessUpdate(awareness$1, changes);
|
|
39
|
-
|
|
43
|
+
postToIframe("awareness-update", update);
|
|
40
44
|
};
|
|
41
|
-
function broadcastToAll(type, payload, excludeSource) {
|
|
42
|
-
for (const iframe of iframes.values()) {
|
|
43
|
-
if (iframe.contentWindow && iframe.contentWindow !== excludeSource) {
|
|
44
|
-
iframe.contentWindow.postMessage({ type, payload }, "*");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
45
|
const onMessage = (event) => {
|
|
49
|
-
|
|
50
|
-
for (const [id, iframe] of iframes) {
|
|
51
|
-
if (event.source === iframe.contentWindow) {
|
|
52
|
-
iframeId = id;
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (!iframeId) return;
|
|
46
|
+
if (event.source !== iframe.contentWindow) return;
|
|
57
47
|
const { type: msgType, payload } = event.data;
|
|
58
|
-
const sourceWindow = event.source;
|
|
59
48
|
if (msgType === "init") {
|
|
60
|
-
if (!iframeReady.has(iframeId)) {
|
|
61
|
-
iframeReady.add(iframeId);
|
|
62
|
-
}
|
|
63
49
|
const docState = Y__namespace.encodeStateAsUpdate(ydoc);
|
|
64
50
|
const awarenessState = awareness.encodeAwarenessUpdate(
|
|
65
51
|
awareness$1,
|
|
66
52
|
Array.from(awareness$1.getStates().keys())
|
|
67
53
|
);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
sourceWindow.postMessage(
|
|
73
|
-
{
|
|
74
|
-
type: "awareness-sync",
|
|
75
|
-
payload: Array.from(awarenessState),
|
|
76
|
-
serverClientId: awareness$1.clientID
|
|
77
|
-
},
|
|
78
|
-
"*"
|
|
54
|
+
postToIframe("ydoc-sync", new Uint8Array(Array.from(docState)));
|
|
55
|
+
postToIframe(
|
|
56
|
+
"awareness-sync",
|
|
57
|
+
new Uint8Array(Array.from(awarenessState))
|
|
79
58
|
);
|
|
80
59
|
} else if (msgType === "ping") {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
60
|
+
const cw = iframe.contentWindow;
|
|
61
|
+
if (cw) {
|
|
62
|
+
cw.postMessage(
|
|
63
|
+
{ type: "pong", serverClientId: awareness$1.clientID },
|
|
64
|
+
"*"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
85
67
|
} else if (msgType === "ydoc-update") {
|
|
86
68
|
const update = new Uint8Array(payload);
|
|
87
69
|
Y__namespace.applyUpdate(ydoc, update, IFRAME_ORIGIN);
|
|
88
|
-
broadcastToAll("ydoc-update", update, sourceWindow);
|
|
89
70
|
} else if (msgType === "awareness-update") {
|
|
90
71
|
awareness.applyAwarenessUpdate(awareness$1, new Uint8Array(payload), null);
|
|
91
72
|
} else if (msgType === "undo" && undoManager) {
|
|
@@ -94,23 +75,19 @@ function createIframeBridgeServer(ydoc, awareness$1, options) {
|
|
|
94
75
|
undoManager.redo();
|
|
95
76
|
}
|
|
96
77
|
};
|
|
97
|
-
function addIframe(iframe, iframeId) {
|
|
98
|
-
iframes.set(iframeId, iframe);
|
|
99
|
-
}
|
|
100
|
-
function removeIframe(iframeId) {
|
|
101
|
-
iframes.delete(iframeId);
|
|
102
|
-
iframeReady.delete(iframeId);
|
|
103
|
-
}
|
|
104
78
|
const onUndoPopped = (e) => {
|
|
105
79
|
const t = e && (e.type || e.reason || e.kind);
|
|
106
80
|
if (t === "undo") {
|
|
107
|
-
|
|
81
|
+
postToIframe("undo", new Uint8Array());
|
|
108
82
|
} else if (t === "redo") {
|
|
109
|
-
|
|
83
|
+
postToIframe("redo", new Uint8Array());
|
|
110
84
|
}
|
|
111
85
|
};
|
|
112
86
|
const onStackCleared = () => {
|
|
113
|
-
|
|
87
|
+
postToIframe("clear", new Uint8Array());
|
|
88
|
+
};
|
|
89
|
+
const onStackItemAdded = () => {
|
|
90
|
+
postToIframe("add", new Uint8Array());
|
|
114
91
|
};
|
|
115
92
|
ydoc.on("update", onYdocUpdate);
|
|
116
93
|
awareness$1.on("update", onAwarenessUpdate);
|
|
@@ -118,10 +95,9 @@ function createIframeBridgeServer(ydoc, awareness$1, options) {
|
|
|
118
95
|
if (undoManager) {
|
|
119
96
|
undoManager.on("stack-item-popped", onUndoPopped);
|
|
120
97
|
undoManager.on("stack-cleared", onStackCleared);
|
|
98
|
+
undoManager.on("stack-item-added", onStackItemAdded);
|
|
121
99
|
}
|
|
122
100
|
return {
|
|
123
|
-
addIframe,
|
|
124
|
-
removeIframe,
|
|
125
101
|
destroy: () => {
|
|
126
102
|
ydoc.off("update", onYdocUpdate);
|
|
127
103
|
awareness$1.off("update", onAwarenessUpdate);
|
|
@@ -129,9 +105,8 @@ function createIframeBridgeServer(ydoc, awareness$1, options) {
|
|
|
129
105
|
if (undoManager) {
|
|
130
106
|
undoManager.off("stack-item-popped", onUndoPopped);
|
|
131
107
|
undoManager.off("stack-cleared", onStackCleared);
|
|
108
|
+
undoManager.off("stack-item-added", onStackItemAdded);
|
|
132
109
|
}
|
|
133
|
-
iframes.clear();
|
|
134
|
-
iframeReady.clear();
|
|
135
110
|
}
|
|
136
111
|
};
|
|
137
112
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.cjs.js","sources":["../../../iframe-bridge/src/origin.ts","../../../iframe-bridge/src/server.ts"],"sourcesContent":["/**\n * iframe bridge 内部变更的 origin 标识。\n * 当 provider 端产生 ydoc-update 时,使用此 origin 标记,\n * 以便 server 端的 UndoManager 能正确追踪来自 iframe 的变更。\n */\nexport const IFRAME_ORIGIN: object = {};\n","import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\nimport { IFRAME_ORIGIN } from \"./origin.js\";\n\nexport interface IframeBridgeServerOptions {\n undoManager?: Y.UndoManager;\n}\n\nexport interface IframeBridgeServer {\n
|
|
1
|
+
{"version":3,"file":"server.cjs.js","sources":["../../../iframe-bridge/src/origin.ts","../../../iframe-bridge/src/server.ts"],"sourcesContent":["/**\n * iframe bridge 内部变更的 origin 标识。\n * 当 provider 端产生 ydoc-update 时,使用此 origin 标记,\n * 以便 server 端的 UndoManager 能正确追踪来自 iframe 的变更。\n */\nexport const IFRAME_ORIGIN: object = {};\n","import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\nimport { IFRAME_ORIGIN } from \"./origin.js\";\n\nexport interface IframeBridgeServerOptions {\n undoManager?: Y.UndoManager;\n}\n\nexport interface IframeBridgeServer {\n destroy: () => void;\n}\n\nexport function createIframeBridgeServer(\n iframe: HTMLIFrameElement,\n ydoc: Y.Doc,\n awareness: Awareness,\n options?: IframeBridgeServerOptions,\n): IframeBridgeServer {\n const { undoManager } = options ?? {};\n let iframeReady = false;\n\n function postToIframe(type: string, payload: Uint8Array) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type, payload }, \"*\");\n }\n }\n\n const onYdocUpdate = (update: Uint8Array, origin: unknown) => {\n if (origin === IFRAME_ORIGIN) return;\n postToIframe(\"ydoc-update\", update);\n };\n\n const onAwarenessUpdate = ({\n added,\n updated,\n removed,\n }: {\n added: number[];\n updated: number[];\n removed: number[];\n }) => {\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n const update = encodeAwarenessUpdate(awareness, changes);\n postToIframe(\"awareness-update\", update);\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return;\n\n const { type: msgType, payload } = event.data;\n\n if (msgType === \"init\") {\n if (!iframeReady) {\n iframeReady = true;\n }\n const docState = Y.encodeStateAsUpdate(ydoc);\n const awarenessState = encodeAwarenessUpdate(\n awareness,\n Array.from(awareness.getStates().keys()),\n );\n postToIframe(\"ydoc-sync\", new Uint8Array(Array.from(docState)));\n postToIframe(\n \"awareness-sync\",\n new Uint8Array(Array.from(awarenessState)),\n );\n } else if (msgType === \"ping\") {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage(\n { type: \"pong\", serverClientId: awareness.clientID },\n \"*\",\n );\n }\n } else if (msgType === \"ydoc-update\") {\n const update = new Uint8Array(payload);\n Y.applyUpdate(ydoc, update, IFRAME_ORIGIN);\n // 源 iframe 已经持有此 update,无需回传\n } else if (msgType === \"awareness-update\") {\n applyAwarenessUpdate(awareness, new Uint8Array(payload), null);\n } else if (msgType === \"undo\" && undoManager) {\n undoManager.undo();\n } else if (msgType === \"redo\" && undoManager) {\n undoManager.redo();\n }\n };\n\n const onUndoPopped = (e: {\n type?: string;\n reason?: string;\n kind?: string;\n }) => {\n const t = e && (e.type || e.reason || e.kind);\n if (t === \"undo\") {\n postToIframe(\"undo\", new Uint8Array());\n } else if (t === \"redo\") {\n postToIframe(\"redo\", new Uint8Array());\n }\n };\n\n const onStackCleared = () => {\n postToIframe(\"clear\", new Uint8Array());\n };\n\n const onStackItemAdded = () => {\n postToIframe(\"add\", new Uint8Array());\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n awareness.on(\"update\", onAwarenessUpdate);\n window.addEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.on(\"stack-item-popped\", onUndoPopped);\n undoManager.on(\"stack-cleared\", onStackCleared);\n undoManager.on(\"stack-item-added\", onStackItemAdded);\n }\n\n return {\n destroy: () => {\n ydoc.off(\"update\", onYdocUpdate);\n awareness.off(\"update\", onAwarenessUpdate);\n window.removeEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.off(\"stack-item-popped\", onUndoPopped);\n undoManager.off(\"stack-cleared\", onStackCleared);\n undoManager.off(\"stack-item-added\", onStackItemAdded);\n }\n iframeReady = false;\n },\n };\n}\n"],"names":["awareness","encodeAwarenessUpdate","Y","applyAwarenessUpdate"],"mappings":"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"}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import * as Y from "yjs";
|
|
2
2
|
import { encodeAwarenessUpdate, applyAwarenessUpdate } from "y-protocols/awareness";
|
|
3
3
|
const IFRAME_ORIGIN = {};
|
|
4
|
-
function createIframeBridgeServer(ydoc, awareness, options) {
|
|
4
|
+
function createIframeBridgeServer(iframe, ydoc, awareness, options) {
|
|
5
5
|
const { undoManager } = options ?? {};
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
function postToIframe(type, payload) {
|
|
7
|
+
const cw = iframe.contentWindow;
|
|
8
|
+
if (cw) {
|
|
9
|
+
cw.postMessage({ type, payload }, "*");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
8
12
|
const onYdocUpdate = (update, origin) => {
|
|
9
13
|
if (origin === IFRAME_ORIGIN) return;
|
|
10
|
-
|
|
14
|
+
postToIframe("ydoc-update", update);
|
|
11
15
|
};
|
|
12
16
|
const onAwarenessUpdate = ({
|
|
13
17
|
added,
|
|
@@ -17,56 +21,33 @@ function createIframeBridgeServer(ydoc, awareness, options) {
|
|
|
17
21
|
const changes = [...added, ...updated, ...removed];
|
|
18
22
|
if (changes.length === 0) return;
|
|
19
23
|
const update = encodeAwarenessUpdate(awareness, changes);
|
|
20
|
-
|
|
24
|
+
postToIframe("awareness-update", update);
|
|
21
25
|
};
|
|
22
|
-
function broadcastToAll(type, payload, excludeSource) {
|
|
23
|
-
for (const iframe of iframes.values()) {
|
|
24
|
-
if (iframe.contentWindow && iframe.contentWindow !== excludeSource) {
|
|
25
|
-
iframe.contentWindow.postMessage({ type, payload }, "*");
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
26
|
const onMessage = (event) => {
|
|
30
|
-
|
|
31
|
-
for (const [id, iframe] of iframes) {
|
|
32
|
-
if (event.source === iframe.contentWindow) {
|
|
33
|
-
iframeId = id;
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (!iframeId) return;
|
|
27
|
+
if (event.source !== iframe.contentWindow) return;
|
|
38
28
|
const { type: msgType, payload } = event.data;
|
|
39
|
-
const sourceWindow = event.source;
|
|
40
29
|
if (msgType === "init") {
|
|
41
|
-
if (!iframeReady.has(iframeId)) {
|
|
42
|
-
iframeReady.add(iframeId);
|
|
43
|
-
}
|
|
44
30
|
const docState = Y.encodeStateAsUpdate(ydoc);
|
|
45
31
|
const awarenessState = encodeAwarenessUpdate(
|
|
46
32
|
awareness,
|
|
47
33
|
Array.from(awareness.getStates().keys())
|
|
48
34
|
);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
sourceWindow.postMessage(
|
|
54
|
-
{
|
|
55
|
-
type: "awareness-sync",
|
|
56
|
-
payload: Array.from(awarenessState),
|
|
57
|
-
serverClientId: awareness.clientID
|
|
58
|
-
},
|
|
59
|
-
"*"
|
|
35
|
+
postToIframe("ydoc-sync", new Uint8Array(Array.from(docState)));
|
|
36
|
+
postToIframe(
|
|
37
|
+
"awareness-sync",
|
|
38
|
+
new Uint8Array(Array.from(awarenessState))
|
|
60
39
|
);
|
|
61
40
|
} else if (msgType === "ping") {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
41
|
+
const cw = iframe.contentWindow;
|
|
42
|
+
if (cw) {
|
|
43
|
+
cw.postMessage(
|
|
44
|
+
{ type: "pong", serverClientId: awareness.clientID },
|
|
45
|
+
"*"
|
|
46
|
+
);
|
|
47
|
+
}
|
|
66
48
|
} else if (msgType === "ydoc-update") {
|
|
67
49
|
const update = new Uint8Array(payload);
|
|
68
50
|
Y.applyUpdate(ydoc, update, IFRAME_ORIGIN);
|
|
69
|
-
broadcastToAll("ydoc-update", update, sourceWindow);
|
|
70
51
|
} else if (msgType === "awareness-update") {
|
|
71
52
|
applyAwarenessUpdate(awareness, new Uint8Array(payload), null);
|
|
72
53
|
} else if (msgType === "undo" && undoManager) {
|
|
@@ -75,23 +56,19 @@ function createIframeBridgeServer(ydoc, awareness, options) {
|
|
|
75
56
|
undoManager.redo();
|
|
76
57
|
}
|
|
77
58
|
};
|
|
78
|
-
function addIframe(iframe, iframeId) {
|
|
79
|
-
iframes.set(iframeId, iframe);
|
|
80
|
-
}
|
|
81
|
-
function removeIframe(iframeId) {
|
|
82
|
-
iframes.delete(iframeId);
|
|
83
|
-
iframeReady.delete(iframeId);
|
|
84
|
-
}
|
|
85
59
|
const onUndoPopped = (e) => {
|
|
86
60
|
const t = e && (e.type || e.reason || e.kind);
|
|
87
61
|
if (t === "undo") {
|
|
88
|
-
|
|
62
|
+
postToIframe("undo", new Uint8Array());
|
|
89
63
|
} else if (t === "redo") {
|
|
90
|
-
|
|
64
|
+
postToIframe("redo", new Uint8Array());
|
|
91
65
|
}
|
|
92
66
|
};
|
|
93
67
|
const onStackCleared = () => {
|
|
94
|
-
|
|
68
|
+
postToIframe("clear", new Uint8Array());
|
|
69
|
+
};
|
|
70
|
+
const onStackItemAdded = () => {
|
|
71
|
+
postToIframe("add", new Uint8Array());
|
|
95
72
|
};
|
|
96
73
|
ydoc.on("update", onYdocUpdate);
|
|
97
74
|
awareness.on("update", onAwarenessUpdate);
|
|
@@ -99,10 +76,9 @@ function createIframeBridgeServer(ydoc, awareness, options) {
|
|
|
99
76
|
if (undoManager) {
|
|
100
77
|
undoManager.on("stack-item-popped", onUndoPopped);
|
|
101
78
|
undoManager.on("stack-cleared", onStackCleared);
|
|
79
|
+
undoManager.on("stack-item-added", onStackItemAdded);
|
|
102
80
|
}
|
|
103
81
|
return {
|
|
104
|
-
addIframe,
|
|
105
|
-
removeIframe,
|
|
106
82
|
destroy: () => {
|
|
107
83
|
ydoc.off("update", onYdocUpdate);
|
|
108
84
|
awareness.off("update", onAwarenessUpdate);
|
|
@@ -110,9 +86,8 @@ function createIframeBridgeServer(ydoc, awareness, options) {
|
|
|
110
86
|
if (undoManager) {
|
|
111
87
|
undoManager.off("stack-item-popped", onUndoPopped);
|
|
112
88
|
undoManager.off("stack-cleared", onStackCleared);
|
|
89
|
+
undoManager.off("stack-item-added", onStackItemAdded);
|
|
113
90
|
}
|
|
114
|
-
iframes.clear();
|
|
115
|
-
iframeReady.clear();
|
|
116
91
|
}
|
|
117
92
|
};
|
|
118
93
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.es.js","sources":["../../../iframe-bridge/src/origin.ts","../../../iframe-bridge/src/server.ts"],"sourcesContent":["/**\n * iframe bridge 内部变更的 origin 标识。\n * 当 provider 端产生 ydoc-update 时,使用此 origin 标记,\n * 以便 server 端的 UndoManager 能正确追踪来自 iframe 的变更。\n */\nexport const IFRAME_ORIGIN: object = {};\n","import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\nimport { IFRAME_ORIGIN } from \"./origin.js\";\n\nexport interface IframeBridgeServerOptions {\n undoManager?: Y.UndoManager;\n}\n\nexport interface IframeBridgeServer {\n
|
|
1
|
+
{"version":3,"file":"server.es.js","sources":["../../../iframe-bridge/src/origin.ts","../../../iframe-bridge/src/server.ts"],"sourcesContent":["/**\n * iframe bridge 内部变更的 origin 标识。\n * 当 provider 端产生 ydoc-update 时,使用此 origin 标记,\n * 以便 server 端的 UndoManager 能正确追踪来自 iframe 的变更。\n */\nexport const IFRAME_ORIGIN: object = {};\n","import * as Y from \"yjs\";\nimport {\n Awareness,\n applyAwarenessUpdate,\n encodeAwarenessUpdate,\n} from \"y-protocols/awareness\";\nimport { IFRAME_ORIGIN } from \"./origin.js\";\n\nexport interface IframeBridgeServerOptions {\n undoManager?: Y.UndoManager;\n}\n\nexport interface IframeBridgeServer {\n destroy: () => void;\n}\n\nexport function createIframeBridgeServer(\n iframe: HTMLIFrameElement,\n ydoc: Y.Doc,\n awareness: Awareness,\n options?: IframeBridgeServerOptions,\n): IframeBridgeServer {\n const { undoManager } = options ?? {};\n let iframeReady = false;\n\n function postToIframe(type: string, payload: Uint8Array) {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage({ type, payload }, \"*\");\n }\n }\n\n const onYdocUpdate = (update: Uint8Array, origin: unknown) => {\n if (origin === IFRAME_ORIGIN) return;\n postToIframe(\"ydoc-update\", update);\n };\n\n const onAwarenessUpdate = ({\n added,\n updated,\n removed,\n }: {\n added: number[];\n updated: number[];\n removed: number[];\n }) => {\n const changes = [...added, ...updated, ...removed];\n if (changes.length === 0) return;\n const update = encodeAwarenessUpdate(awareness, changes);\n postToIframe(\"awareness-update\", update);\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return;\n\n const { type: msgType, payload } = event.data;\n\n if (msgType === \"init\") {\n if (!iframeReady) {\n iframeReady = true;\n }\n const docState = Y.encodeStateAsUpdate(ydoc);\n const awarenessState = encodeAwarenessUpdate(\n awareness,\n Array.from(awareness.getStates().keys()),\n );\n postToIframe(\"ydoc-sync\", new Uint8Array(Array.from(docState)));\n postToIframe(\n \"awareness-sync\",\n new Uint8Array(Array.from(awarenessState)),\n );\n } else if (msgType === \"ping\") {\n const cw = iframe.contentWindow;\n if (cw) {\n cw.postMessage(\n { type: \"pong\", serverClientId: awareness.clientID },\n \"*\",\n );\n }\n } else if (msgType === \"ydoc-update\") {\n const update = new Uint8Array(payload);\n Y.applyUpdate(ydoc, update, IFRAME_ORIGIN);\n // 源 iframe 已经持有此 update,无需回传\n } else if (msgType === \"awareness-update\") {\n applyAwarenessUpdate(awareness, new Uint8Array(payload), null);\n } else if (msgType === \"undo\" && undoManager) {\n undoManager.undo();\n } else if (msgType === \"redo\" && undoManager) {\n undoManager.redo();\n }\n };\n\n const onUndoPopped = (e: {\n type?: string;\n reason?: string;\n kind?: string;\n }) => {\n const t = e && (e.type || e.reason || e.kind);\n if (t === \"undo\") {\n postToIframe(\"undo\", new Uint8Array());\n } else if (t === \"redo\") {\n postToIframe(\"redo\", new Uint8Array());\n }\n };\n\n const onStackCleared = () => {\n postToIframe(\"clear\", new Uint8Array());\n };\n\n const onStackItemAdded = () => {\n postToIframe(\"add\", new Uint8Array());\n };\n\n ydoc.on(\"update\", onYdocUpdate);\n awareness.on(\"update\", onAwarenessUpdate);\n window.addEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.on(\"stack-item-popped\", onUndoPopped);\n undoManager.on(\"stack-cleared\", onStackCleared);\n undoManager.on(\"stack-item-added\", onStackItemAdded);\n }\n\n return {\n destroy: () => {\n ydoc.off(\"update\", onYdocUpdate);\n awareness.off(\"update\", onAwarenessUpdate);\n window.removeEventListener(\"message\", onMessage);\n if (undoManager) {\n undoManager.off(\"stack-item-popped\", onUndoPopped);\n undoManager.off(\"stack-cleared\", onStackCleared);\n undoManager.off(\"stack-item-added\", onStackItemAdded);\n }\n iframeReady = false;\n },\n };\n}\n"],"names":[],"mappings":"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"}
|