Skip to content

Commit 4a84011

Browse files
committed
Remove the aem2prose handling
Also cleans up old websockets on navigation
1 parent 3076750 commit 4a84011

File tree

5 files changed

+46
-151
lines changed

5 files changed

+46
-151
lines changed

blocks/edit/da-editor/da-editor.js

+13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ export default class DaEditor extends LitElement {
2222
initIms().then(() => { this._imsLoaded = true; });
2323
}
2424

25+
disconnectWebsocket() {
26+
if (this.wsProvider) {
27+
this.wsProvider.disconnect({ data: 'Client navigation' });
28+
this.wsProvider = undefined;
29+
}
30+
}
31+
32+
disconnectedCallback() {
33+
super.disconnectedCallback();
34+
this.disconnectWebsocket();
35+
}
36+
2537
async fetchVersion() {
2638
const resp = await daFetch(this.version);
2739
if (!resp.ok) return;
@@ -72,6 +84,7 @@ export default class DaEditor extends LitElement {
7284

7385
updated(props) {
7486
if (!this._imsLoaded) return;
87+
this.disconnectWebsocket();
7588
if (!(props.has('version') || props.has('_versionDom'))) {
7689
const prose = this.shadowRoot.querySelector('.da-prose-mirror');
7790
prose.innerHTML = '';

blocks/edit/prose/index.js

+10-58
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import {
33
EditorState,
44
EditorView,
5-
DOMParser,
65
Schema,
76
baseSchema,
87
history,
@@ -25,15 +24,13 @@ import {
2524
yUndoPlugin,
2625
yUndo,
2726
yRedo,
28-
prosemirrorToYXmlFragment,
2927
} from 'da-y-wrapper';
3028

3129
// DA
3230
import prose2aem from '../../shared/prose2aem.js';
3331
import menu from './plugins/menu.js';
3432
import imageDrop from './plugins/imageDrop.js';
3533
import linkConverter from './plugins/linkConverter.js';
36-
import { aem2prose, parse } from '../utils/helpers.js';
3734
import { COLLAB_ORIGIN, getDaAdmin } from '../../shared/constants.js';
3835
import { addLocNodes, getLocClass } from './loc-utils.js';
3936

@@ -84,18 +81,6 @@ function pollForUpdates() {
8481
}, 500);
8582
}
8683

87-
// Apply the document in AEM doc format to the editor.
88-
// For this it's converted to Prose and then applied to the current ydoc as an XML fragment
89-
function setAEMDocInEditor(aemDoc, yXmlFragment, schema) {
90-
const doc = parse(aemDoc);
91-
const pdoc = aem2prose(doc);
92-
const docc = document.createElement('div');
93-
docc.append(...pdoc);
94-
const parser = DOMParser.fromSchema(schema);
95-
const fin = parser.parse(docc);
96-
prosemirrorToYXmlFragment(fin, yXmlFragment);
97-
}
98-
9984
function handleAwarenessUpdates(wsProvider, daTitle, win) {
10085
const users = new Set();
10186

@@ -131,45 +116,12 @@ export function createAwarenessStatusWidget(wsProvider, win) {
131116
return daTitle;
132117
}
133118

134-
export function handleYDocUpdates({
135-
daTitle, editor, ydoc, path, schema, wsProvider, yXmlFragment, fnInitProse,
136-
}, win = window, fnSetAEMDocInEditor = setAEMDocInEditor) {
137-
let firstUpdate = true;
138-
ydoc.on('update', (_, originWS) => {
139-
if (firstUpdate) {
140-
firstUpdate = false;
141-
142-
// Do the following async to allow the ydoc to init itself with any
143-
// changes coming from other editors
144-
setTimeout(() => {
145-
const aemMap = ydoc.getMap('aem');
146-
const current = aemMap.get('content');
147-
const inital = aemMap.get('initial');
148-
if (!current && inital) {
149-
fnSetAEMDocInEditor(inital, yXmlFragment, schema);
150-
}
151-
}, 1);
152-
}
153-
154-
const serverInvKey = 'svrinv';
155-
const svrUpdate = ydoc.getMap('aem').get(serverInvKey);
156-
if (svrUpdate) {
157-
// push update from the server: re-init document
158-
delete daTitle.collabStatus;
159-
delete daTitle.collabUsers;
160-
ydoc.destroy();
161-
wsProvider.destroy();
162-
editor.innerHTML = '';
163-
fnInitProse({ editor, path });
164-
return;
165-
}
166-
167-
if (originWS && originWS !== wsProvider) {
168-
const proseEl = win.view.root.querySelector('.ProseMirror');
169-
const clone = proseEl.cloneNode(true);
170-
const aem = prose2aem(clone);
171-
const aemMap = ydoc.getMap('aem');
172-
aemMap.set('content', aem);
119+
function registerErrorHandler(ydoc) {
120+
ydoc.on('update', () => {
121+
const errorMap = ydoc.getMap('error');
122+
if (errorMap && errorMap.size > 0) {
123+
// eslint-disable-next-line no-console
124+
console.log('Error from server', JSON.stringify(errorMap));
173125
}
174126
});
175127
}
@@ -209,12 +161,10 @@ export default function initProse({ editor, path }) {
209161
}
210162

211163
const wsProvider = new WebsocketProvider(server, roomName, ydoc, opts);
212-
const daTitle = createAwarenessStatusWidget(wsProvider, window);
164+
createAwarenessStatusWidget(wsProvider, window);
165+
registerErrorHandler(ydoc);
213166

214167
const yXmlFragment = ydoc.getXmlFragment('prosemirror');
215-
handleYDocUpdates({
216-
daTitle, editor, ydoc, path, schema, wsProvider, yXmlFragment, fnInitProse: initProse,
217-
});
218168

219169
if (window.adobeIMS?.isSignedInUser()) {
220170
window.adobeIMS.getProfile().then(
@@ -293,4 +243,6 @@ export default function initProse({ editor, path }) {
293243

294244
document.execCommand('enableObjectResizing', false, 'false');
295245
document.execCommand('enableInlineTableEditing', false, 'false');
246+
247+
return wsProvider;
296248
}

blocks/shared/constants.js

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const DA_ADMIN_ENVS = {
2121

2222
const DA_COLLAB_ENVS = {
2323
local: 'ws://localhost:4711',
24+
stage: 'wss://stage-collab.da.live',
2425
prod: 'wss://collab.da.live',
2526
};
2627

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { expect } from '@esm-bundle/chai';
2+
3+
// This is needed to make a dynamic import work that is indirectly referenced
4+
// from da-editor.js
5+
const { setNx } = await import('../../../../../scripts/utils.js');
6+
setNx('/bheuaark/', { hostname: 'localhost' });
7+
8+
const { default: DaEditor } = await import('../../../../../blocks/edit/da-editor/da-editor.js');
9+
10+
describe('da-editor', () => {
11+
it('Test wsprovider disconnectedcallback', async () => {
12+
const ed = new DaEditor();
13+
14+
const called = [];
15+
const mockWSProvider = { disconnect: () => called.push('disconnect') };
16+
17+
ed.wsProvider = mockWSProvider;
18+
ed.disconnectWebsocket();
19+
expect(ed.wsProvider).to.be.undefined;
20+
expect(called).to.deep.equal(['disconnect']);
21+
});
22+
});

test/unit/blocks/edit/proseCollab.test.js

-93
Original file line numberDiff line numberDiff line change
@@ -73,97 +73,4 @@ describe('Prose collab', () => {
7373
awarenessOnCalled[0].f(delta2); // Call the callback function
7474
expect(daTitle.collabUsers).to.deep.equal(['Anonymous', 'Anonymous', 'Joe Bloggs']);
7575
});
76-
77-
it('Test YDoc firstUpdate callback', (done) => {
78-
const ydocMap = new Map();
79-
ydocMap.set('initial', 'Some intial text');
80-
81-
const ydocOnCalls = [];
82-
const ydoc = {
83-
getMap: (n) => (n === 'aem' ? ydocMap : null),
84-
on: (n, f) => ydocOnCalls.push({ n, f }),
85-
};
86-
87-
const setAEMDocCalls = [];
88-
const fnSetAEMDoc = () => setAEMDocCalls.push('called');
89-
90-
pi.handleYDocUpdates({
91-
daTitle: {},
92-
editor: {},
93-
ydoc,
94-
path: {},
95-
schema: {},
96-
wsProvider: {},
97-
yXmlFragment: {},
98-
fnInitProse: () => {},
99-
}, {}, fnSetAEMDoc);
100-
expect(ydocOnCalls.length).to.equal(1);
101-
expect(ydocOnCalls[0].n).to.equal('update');
102-
103-
ydocOnCalls[0].f();
104-
setTimeout(() => {
105-
expect(setAEMDocCalls).to.deep.equal(['called']);
106-
107-
// the function call again, it should not perform any action this time
108-
ydocOnCalls[0].f();
109-
setTimeout(() => {
110-
expect(setAEMDocCalls).to.deep.equal(
111-
['called'],
112-
'First update code should only be called once',
113-
);
114-
done();
115-
}, 200);
116-
}, 200);
117-
});
118-
119-
it('Test YDoc server update callback', () => {
120-
const daTitle = {
121-
collabStatus: 'yeah',
122-
collabUsers: 'some',
123-
};
124-
const editor = {};
125-
126-
const ydocMap = new Map();
127-
ydocMap.set('svrinv', 'Some svrinv text');
128-
129-
const ydocCalls = [];
130-
const ydocOnCalls = [];
131-
const ydoc = {
132-
getMap: (n) => (n === 'aem' ? ydocMap : null),
133-
destroy: () => ydocCalls.push('destroy'),
134-
on: (n, f) => ydocOnCalls.push({ n, f }),
135-
};
136-
137-
const wspCalls = [];
138-
const wsp = { destroy: () => wspCalls.push('destroy') };
139-
140-
const initProseCalls = [];
141-
const mockInitProse = () => initProseCalls.push('init');
142-
143-
pi.handleYDocUpdates({
144-
daTitle,
145-
editor,
146-
ydoc,
147-
path: {},
148-
schema: {},
149-
wsProvider: wsp,
150-
yXmlFragment: {},
151-
fnInitProse: mockInitProse,
152-
}, {}, () => {});
153-
expect(ydocOnCalls.length).to.equal(1);
154-
expect(ydocOnCalls[0].n).to.equal('update');
155-
156-
expect(daTitle.collabStatus).to.equal('yeah', 'Precondition');
157-
expect(daTitle.collabUsers).to.equal('some', 'Precondition');
158-
159-
// Calls server invalidation
160-
ydocOnCalls[0].f();
161-
162-
expect(daTitle.collabStatus).to.be.undefined;
163-
expect(daTitle.collabUsers).to.be.undefined;
164-
expect(ydocCalls).to.deep.equal(['destroy']);
165-
expect(wspCalls).to.deep.equal(['destroy']);
166-
expect(initProseCalls).to.deep.equal(['init']);
167-
expect(editor.innerHTML).to.equal('');
168-
});
16976
});

0 commit comments

Comments
 (0)