@atlaskit/editor-plugin-collab-edit
Version:
Collab Edit plugin for @atlaskit/editor-core
85 lines (82 loc) • 3.63 kB
JavaScript
import { applyRemoteData, handleConnection, handleInit, handlePresence, handleTelePointer } from '../actions';
import { addSynchronyEntityAnalytics, addSynchronyErrorAnalytics } from '../analytics';
import { trackLastRemoteConflictPluginKey } from '../track-reconnection-conflict';
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const effect = (fn, eq) => {
let previousDeps;
let cleanup;
return (...currentDeps) => {
if (cleanup && eq(previousDeps, currentDeps)) {
return cleanup;
}
cleanup = fn(...currentDeps);
previousDeps = currentDeps;
return cleanup;
};
};
export const subscribe = effect((view, provider, options, featureFlags, _providerFactory, editorAnalyticsApi) => {
let entityRef;
const entityHandlers = {
disconnectedHandler: () => {
addSynchronyEntityAnalytics(view.state, view.state.tr)('disconnected', editorAnalyticsApi);
},
errorHandler: () => {
addSynchronyEntityAnalytics(view.state, view.state.tr)('error', editorAnalyticsApi);
}
};
const unsubscribeSynchronyEntity = () => {
if (entityRef) {
entityRef.off('disconnected', entityHandlers.disconnectedHandler);
entityRef.off('error', entityHandlers.errorHandler);
}
};
const handlers = {
initHandler: data => {
view.dispatch(view.state.tr.setMeta('collabInitialised', true));
handleInit(data, view, options, editorAnalyticsApi);
},
connectedHandler: data => handleConnection(data, view),
dataHandler: data => applyRemoteData(data, view, options),
presenceHandler: data => handlePresence(data, view),
telepointerHandler: data => handleTelePointer(data, view),
localStepsHandler: data => {
const {
steps
} = data;
const {
state
} = view;
const {
tr
} = state;
steps.forEach(step => tr.step(step));
view.dispatch(tr);
},
errorHandler: error => {
addSynchronyErrorAnalytics(view.state, view.state.tr, featureFlags, editorAnalyticsApi)(error);
},
entityHandler: ({
entity
}) => {
unsubscribeSynchronyEntity();
if (options.EXPERIMENTAL_allowInternalErrorAnalytics) {
entity.on('disconnected', entityHandlers.disconnectedHandler);
entity.on('error', entityHandlers.errorHandler);
entityRef = entity;
}
},
dataConflictHandler: data => {
view.dispatch(view.state.tr.setMeta(trackLastRemoteConflictPluginKey, data));
}
};
provider.on('init', handlers.initHandler).on('connected', handlers.connectedHandler).on('data', handlers.dataHandler).on('presence', handlers.presenceHandler).on('telepointer', handlers.telepointerHandler).on('local-steps', handlers.localStepsHandler).on('error', handlers.errorHandler).on('entity', handlers.entityHandler).on('data:conflict', handlers.dataConflictHandler);
return () => {
unsubscribeSynchronyEntity();
provider.off('init', handlers.initHandler).off('connected', handlers.connectedHandler).off('data', handlers.dataHandler).off('presence', handlers.presenceHandler).off('telepointer', handlers.telepointerHandler).off('local-steps', handlers.localStepsHandler).off('error', handlers.errorHandler).off('entity', handlers.entityHandler).off('data:conflict', handlers.dataConflictHandler);
};
}, (previousDeps, currentDeps) => currentDeps && currentDeps.every((dep, i) => dep === previousDeps[i]));