UNPKG

@atlaskit/editor-plugin-collab-edit

Version:

Collab Edit plugin for @atlaskit/editor-core

157 lines (153 loc) 7.53 kB
// It is important to get all steps in that package // Ignored via go/ees005 // eslint-disable-next-line import/no-namespace import * as adfCustomSteps from '@atlaskit/adf-schema/steps'; // It is important to get all steps in that package // Ignored via go/ees005 // eslint-disable-next-line import/no-namespace import * as atlaskKitCustomSteps from '@atlaskit/custom-steps'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, fireAnalyticsEvent } from '@atlaskit/editor-common/analytics'; import { SafePlugin } from '@atlaskit/editor-common/safe-plugin'; import { Step } from '@atlaskit/editor-prosemirror/transform'; import { addSynchronyErrorAnalytics } from '../analytics'; import { initialize } from '../events/initialize'; import { pluginKey } from './plugin-key'; import { PluginState } from './plugin-state'; const enforceCustomStepRegisters = () => { const tryToRegisterStep = obj => { for (const customStep of Object.values(obj)) { var _customStep$prototype; // I know this seems awful // But unfortunate ProseMirror does not expose the jsonID property p // @ts-expect-error const id = customStep === null || customStep === void 0 ? void 0 : (_customStep$prototype = customStep.prototype) === null || _customStep$prototype === void 0 ? void 0 : _customStep$prototype.jsonID; if (typeof id === 'string') { try { // We are trying to re-register the steps here // in the normal flow, those custom step should be already registred // So, it should throw an expeception // @ts-expect-error Step.jsonID(id, customStep); } catch (e) { // This mean the step was already registred. // It is ok to ignore this exception. } } } }; // @ts-expect-error tryToRegisterStep(atlaskKitCustomSteps); // @ts-expect-error tryToRegisterStep(adfCustomSteps); }; export const createPlugin = (dispatch, providerFactory, providerResolver, collabProviderCallback, options, featureFlags, pluginInjectionApi) => { enforceCustomStepRegisters(); return new SafePlugin({ key: pluginKey, state: { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any init(config) { return PluginState.init(config); }, apply(transaction, prevPluginState, _oldEditorState, _newEditorState) { const pluginState = prevPluginState.apply(transaction); dispatch(pluginKey, pluginState); return pluginState; } }, props: { decorations(state) { var _pluginKey$getState; return (_pluginKey$getState = pluginKey.getState(state)) === null || _pluginKey$getState === void 0 ? void 0 : _pluginKey$getState.decorations; }, handleDOMEvents: { click(view, event) { var _pluginKey$getState2, _pluginKey$getState2$, _pluginInjectionApi$a, _pluginInjectionApi$a2, _pluginInjectionApi$a3; if (!(event.target instanceof HTMLElement)) { return false; } if (!view.state.selection.empty) { return false; } const { pos } = view.state.tr.selection.$from; if (!pos) { return false; } // check if the pos is the same pos as a telepointer decoration const decorations = (_pluginKey$getState2 = pluginKey.getState(view.state)) === null || _pluginKey$getState2 === void 0 ? void 0 : (_pluginKey$getState2$ = _pluginKey$getState2.decorations) === null || _pluginKey$getState2$ === void 0 ? void 0 : _pluginKey$getState2$.find(pos, pos); if (!(decorations !== null && decorations !== void 0 && decorations.length)) { return false; } // analytics to track telepointer clicks as they sometimes cause broken selections const fireAnalyticsCallback = fireAnalyticsEvent((_pluginInjectionApi$a = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a2 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a2 === void 0 ? void 0 : (_pluginInjectionApi$a3 = _pluginInjectionApi$a2.sharedState.currentState()) === null || _pluginInjectionApi$a3 === void 0 ? void 0 : _pluginInjectionApi$a3.createAnalyticsEvent) !== null && _pluginInjectionApi$a !== void 0 ? _pluginInjectionApi$a : undefined); fireAnalyticsCallback({ payload: { action: ACTION.CLICKED, actionSubject: ACTION_SUBJECT.TELEPOINTER, actionSubjectId: ACTION_SUBJECT_ID.TELEPOINTER, eventType: EVENT_TYPE.TRACK } }); } } }, filterTransaction(tr, state) { const pluginState = pluginKey.getState(state); const collabInitialiseTr = tr.getMeta('collabInitialised'); // Don't allow transactions that modifies the document before // collab-plugin is ready. if (collabInitialiseTr) { return true; } if (!(pluginState !== null && pluginState !== void 0 && pluginState.isReady) && tr.docChanged) { return false; } return true; }, view(view) { var _pluginInjectionApi$a4, _pluginInjectionApi$a8; const addErrorAnalytics = addSynchronyErrorAnalytics(view.state, view.state.tr, featureFlags, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a4 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a4 === void 0 ? void 0 : _pluginInjectionApi$a4.actions); const onSyncUpError = attributes => { var _pluginInjectionApi$a5, _pluginInjectionApi$a6, _pluginInjectionApi$a7; const fireAnalyticsCallback = fireAnalyticsEvent((_pluginInjectionApi$a5 = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a6 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a6 === void 0 ? void 0 : (_pluginInjectionApi$a7 = _pluginInjectionApi$a6.sharedState.currentState()) === null || _pluginInjectionApi$a7 === void 0 ? void 0 : _pluginInjectionApi$a7.createAnalyticsEvent) !== null && _pluginInjectionApi$a5 !== void 0 ? _pluginInjectionApi$a5 : undefined); fireAnalyticsCallback({ payload: { action: ACTION.NEW_COLLAB_SYNC_UP_ERROR_NO_STEPS, actionSubject: ACTION_SUBJECT.EDITOR, eventType: EVENT_TYPE.OPERATIONAL, attributes } }); }; options.onSyncUpError = onSyncUpError; const cleanup = collabProviderCallback(initialize({ view, options, providerFactory, featureFlags, pluginInjectionApi, editorAnalyticsApi: pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a8 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a8 === void 0 ? void 0 : _pluginInjectionApi$a8.actions }), addErrorAnalytics); providerFactory && providerFactory.subscribe('collabEditProvider', (_name, providerPromise) => { if (providerPromise) { providerPromise.then(provider => providerResolver(provider)); } }); return { destroy() { providerFactory.unsubscribeAll('collabEditProvider'); if (cleanup) { cleanup.then(unsubscribe => { if (unsubscribe) { unsubscribe(); } }); } } }; } }); };