Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol diffdown.com

fix(frontend): use dispatchTransaction hook to detect local PM steps, eliminating echo feedback loop

+24 -8
+24 -8
templates/document_edit.html
··· 325 325 ...plugins, 326 326 collab({ version: collabClient.version }), 327 327 ]); 328 + // Override dispatchTransaction to detect local edits at the PM level. 329 + // After every transaction, sendableSteps is non-null only for local 330 + // (unconfirmed) edits — remote receiveTransaction steps are confirmed 331 + // immediately and never appear in sendableSteps. 332 + ctx.update(editorViewOptionsCtx, (prev) => ({ 333 + ...prev, 334 + dispatchTransaction: function(tr) { 335 + const newState = this.state.apply(tr); 336 + this.updateState(newState); 337 + if (!applyingRemote) { 338 + const sendable = sendableSteps(newState); 339 + if (sendable) { 340 + const stepsJSON = sendable.steps.map(s => JSON.stringify(s.toJSON())); 341 + collabClient.sendSteps(stepsJSON.map(j => ({type: 'pm-step', json: j}))); 342 + try { 343 + const serializer = milkdownEditor.action(c => c.get(serializerCtx)); 344 + scheduleAutoSave(serializer(newState.doc)); 345 + } catch(_) {} 346 + } 347 + } 348 + }, 349 + })); 328 350 }) 329 351 .use(commonmark) 330 352 .use(history) 331 353 .use(listener) 332 354 .config((ctx) => { 333 355 ctx.get(listenerCtx).markdownUpdated((_ctx, markdown, prevMarkdown) => { 334 - if (markdown === prevMarkdown || applyingRemote) return; 356 + // Solo-mode auto-save fallback (no collab session). 357 + if (markdown === prevMarkdown || applyingRemote || accessToken) return; 335 358 scheduleAutoSave(markdown); 336 - // Use prosemirror-collab to extract pending steps from the PM state. 337 - const pmView = milkdownEditor.action(c => c.get(editorViewCtx)); 338 - const sendable = sendableSteps(pmView.state); 339 - if (sendable) { 340 - const stepsJSON = sendable.steps.map(s => JSON.stringify(s.toJSON())); 341 - collabClient.sendSteps(stepsJSON.map(j => ({type: 'pm-step', json: j}))); 342 - } 343 359 }); 344 360 }) 345 361 .create();