UNPKG

@atlaskit/editor-plugin-collab-edit

Version:

Collab Edit plugin for @atlaskit/editor-core

101 lines (99 loc) 4.8 kB
import memoizeOne from 'memoize-one'; import { Step } from '@atlaskit/editor-prosemirror/transform'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { pluginKey } from '../main/plugin-key'; import { trackNCSInitializationPluginKey } from '../track-ncs-initialization'; import { subscribe } from './handlers'; var initCollab = function initCollab(collabEditProvider, view) { if (collabEditProvider.initialize) { collabEditProvider.initialize(function () { return view.state; }, function (json) { return Step.fromJSON(view.state.schema, json); }); } }; var initNewCollab = function initNewCollab(collabEditProvider, view, editorApi, onSyncUpError) { collabEditProvider.setup({ getState: function getState() { return view.state; }, editorApi: editorApi, onSyncUpError: onSyncUpError }); }; var initCollabMemo = memoizeOne(initCollab); export var initialize = function initialize(_ref) { var options = _ref.options, providerFactory = _ref.providerFactory, view = _ref.view, featureFlags = _ref.featureFlags, editorAnalyticsApi = _ref.editorAnalyticsApi, pluginInjectionApi = _ref.pluginInjectionApi; return function (provider) { // eslint-disable-next-line prefer-const var cleanup; var pluginState = pluginKey.getState(view.state); if (pluginState !== null && pluginState !== void 0 && pluginState.isReady && cleanup) { cleanup(); } cleanup = subscribe(view, provider, options, featureFlags, providerFactory, editorAnalyticsApi); // Initialize provider if (options.useNativePlugin) { // ED-13912 For NCS we don't want to use memoizeOne because it causes // infinite text while changing page-width initNewCollab(provider, view, pluginInjectionApi, options.onSyncUpError); } else { /** * We only want to initialise once, if we reload/reconfigure this plugin * We dont want to re-init collab, it would break existing sessions */ initCollabMemo(provider, view); } // Rebind path: if the provider has already initialised (i.e. this view() // is running because the editor preset was reconfigured or the EditorView // was recreated mid-session, e.g. on a rich-text → markdown-mode flip), // the provider's `init` event has already fired and won't fire again. // Without intervention the freshly-attached collab plugin view never sees // `collabInitialised`, so `filterTransaction` silently drops every // doc-changing transaction and the editor appears read-only. // // PM `state.reconfigure` preserves plugin state by key, so in many cases // the plugin state survives and no action is needed; we only seed when // state was actually lost (e.g. EditorView recreated from scratch). // // Gated behind `cc-markdown-mode` (the same experiment that drives the // preset rebuild on convert); when off, behaviour is unchanged. Uses // `expValEquals` (not `*NoExposure`) so the editor's statsig client // enrols the user — otherwise an early rebind can race the FE-side // exposure and read the default (false), defeating the gate. The // experiment check is last so legacy providers (no `getInitPayload`) // short-circuit and don't fire an exposure. if (provider.getInitPayload && expValEquals('cc-markdown-mode', 'isEnabled', true)) { var cachedInit = provider.getInitPayload(); if (cachedInit) { // Defer one microtask so the new pluginView is fully registered // before we dispatch (mirrors the timing of a real `init` event). Promise.resolve().then(function () { if (view.isDestroyed) { return; } var currentCollabState = pluginKey.getState(view.state); var currentTrackState = trackNCSInitializationPluginKey.getState(view.state); // State was preserved across reconfigure → nothing to do. if (currentCollabState !== null && currentCollabState !== void 0 && currentCollabState.isReady && currentTrackState !== null && currentTrackState !== void 0 && currentTrackState.collabInitialisedAt) { return; } // Seed the freshly-attached pluginView so `isReady` flips to true, // `data-has-collab-initialised` becomes "true", and downstream // listeners (analytics, sweet-state, track-ncs) re-receive init. // Note: we intentionally do NOT replay `handleInit` (which would // call `replaceDocument`) — the document is already in the editor // and replacing it would clobber any in-flight local steps. view.dispatch(view.state.tr.setMeta('collabInitialised', true)); }); } } return cleanup; }; };