UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

212 lines (207 loc) • 10.6 kB
import { Node } from '@atlaskit/editor-prosemirror/model'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { getNodeIdProvider } from '../../node-anchor/node-anchor-provider'; import { processRawFragmentValue, processRawValue, processRawValueWithoutValidation } from '../../utils/processRawValue'; import { editorCommandToPMCommand } from '../editor-commands'; import { appearancePluginKey, createAppearancePlugin } from './pm-plugins/appearance-plugin'; import { createThrottleSchedule, returnDocumentRequest, returnDocumentRequestNoThrowError } from './requestDocument'; /** * Core plugin that is always included in the preset. * Allows for executing `EditorCommand` and other core functionality. */ export var corePlugin = function corePlugin(_ref) { var config = _ref.config; // Create the document request throttler per editor (rather than at a module level) var scheduleDocumentRequest = createThrottleSchedule(returnDocumentRequest); var scheduleDocumentRequestNoThrowError = createThrottleSchedule(returnDocumentRequestNoThrowError); return { name: 'core', getSharedState: function getSharedState(state) { var pluginState = state && appearancePluginKey.getState(state); return { schema: state === null || state === void 0 ? void 0 : state.schema, appearance: expValEquals('platform_editor_appearance_shared_state', 'isEnabled', true) ? pluginState === null || pluginState === void 0 ? void 0 : pluginState.appearance : undefined }; }, pmPlugins: function pmPlugins() { if (expValEquals('platform_editor_appearance_shared_state', 'isEnabled', true)) { return [{ name: 'appearancePlugin', plugin: function plugin() { return createAppearancePlugin(config === null || config === void 0 ? void 0 : config.appearance); } }]; } return []; }, actions: { execute: function execute(command) { var editorView = config === null || config === void 0 ? void 0 : config.getEditorView(); if (!editorView || !command) { return false; } var state = editorView.state, dispatch = editorView.dispatch; return editorCommandToPMCommand(command)(state, dispatch); }, // Code copied from `EditorActions.focus()` focus: function focus(options) { var _options$scrollIntoVi; var editorView = config === null || config === void 0 ? void 0 : config.getEditorView(); if (!editorView || editorView.hasFocus()) { return false; } editorView.focus(); if ((_options$scrollIntoVi = options === null || options === void 0 ? void 0 : options.scrollIntoView) !== null && _options$scrollIntoVi !== void 0 ? _options$scrollIntoVi : true) { editorView.dispatch(editorView.state.tr.scrollIntoView()); } return true; }, // Code copied from `EditorActions.blur()` blur: function blur() { var editorView = config === null || config === void 0 ? void 0 : config.getEditorView(); if (!editorView || !editorView.hasFocus()) { return false; } // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting editorView.dom.blur(); return true; }, scrollToPos: function scrollToPos(pos, scrollOptions) { var editorView = config === null || config === void 0 ? void 0 : config.getEditorView(); if (!editorView) { return false; } var tr = editorView.state.tr; var isValidPos = typeof pos === 'number' && pos >= 0 && pos <= tr.doc.content.size; if (!isValidPos) { return false; } var dom = editorView.domAtPos(pos).node; if (!(dom instanceof Element)) { // If it's not an element (e.g. #text node), we'll try the parent. // This is expected to cover most of the scenarios, if not, window.scrollTo is an alternative if (dom.parentNode instanceof Element) { dom.parentNode.scrollIntoView(scrollOptions); return true; } return false; } dom.scrollIntoView(scrollOptions); return true; }, updateAppearance: function updateAppearance(newAppearance) { var _appearancePluginKey$; if (!expValEquals('platform_editor_appearance_shared_state', 'isEnabled', true)) { return false; } var editorView = config === null || config === void 0 ? void 0 : config.getEditorView(); if (!editorView) { return false; } // Avoid dispatching a redundant transaction if appearance hasn't changed var currentAppearance = (_appearancePluginKey$ = appearancePluginKey.getState(editorView.state)) === null || _appearancePluginKey$ === void 0 ? void 0 : _appearancePluginKey$.appearance; if (currentAppearance === newAppearance) { return false; } var tr = editorView.state.tr.setMeta(appearancePluginKey, { appearance: newAppearance }); tr.setMeta('addToHistory', false); editorView.dispatch(tr); return true; }, replaceDocument: function replaceDocument(replaceValue, options) { var editorView = config === null || config === void 0 ? void 0 : config.getEditorView(); if (!editorView || replaceValue === undefined || replaceValue === null) { return false; } var state = editorView.state; var schema = state.schema; var content = options !== null && options !== void 0 && options.skipValidation ? processRawValueWithoutValidation(schema, replaceValue) : Array.isArray(replaceValue) ? processRawFragmentValue(schema, replaceValue, undefined, undefined, options === null || options === void 0 ? void 0 : options.transformer) : processRawValue(schema, replaceValue, undefined, undefined, options === null || options === void 0 ? void 0 : options.transformer); // Don't replace the document if it's the same document, as full size // replace transactions cause issues for collaborative editing and // content reconciliation (eg. inline comments getting dropped) if (content instanceof Node && state.doc.eq(content)) { return false; } if (content) { var _options$scrollIntoVi2; var tr = state.tr.replaceWith(0, state.doc.nodeSize - 2, content); if (expValEquals('platform_editor_are_nodes_equal_ignore_mark_order', 'isEnabled', true)) { tr.setMeta('replaceDocument', true); } if ((options === null || options === void 0 ? void 0 : options.addToHistory) === false) { tr.setMeta('addToHistory', false); } if ((_options$scrollIntoVi2 = options === null || options === void 0 ? void 0 : options.scrollIntoView) !== null && _options$scrollIntoVi2 !== void 0 ? _options$scrollIntoVi2 : true) { editorView.dispatch(tr.scrollIntoView()); } else { editorView.dispatch(tr.setMeta('scrollIntoView', false)); } return true; } return false; }, // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any requestDocument: function requestDocument(onReceive, options) { var _config$getEditorView; var view = (_config$getEditorView = config === null || config === void 0 ? void 0 : config.getEditorView()) !== null && _config$getEditorView !== void 0 ? _config$getEditorView : null; scheduleDocumentRequest(view, onReceive, options === null || options === void 0 ? void 0 : options.transformer, config === null || config === void 0 ? void 0 : config.fireAnalyticsEvent, options === null || options === void 0 ? void 0 : options.alwaysFire); }, requestDocumentAsync: function requestDocumentAsync(options) { return new Promise(function (resolve) { var _config$getEditorView2; var view = (_config$getEditorView2 = config === null || config === void 0 ? void 0 : config.getEditorView()) !== null && _config$getEditorView2 !== void 0 ? _config$getEditorView2 : null; scheduleDocumentRequestNoThrowError(view, function (doc) { resolve(doc); }, options === null || options === void 0 ? void 0 : options.transformer, config === null || config === void 0 ? void 0 : config.fireAnalyticsEvent, true); }); }, createTransformer: function createTransformer(cb) { var _config$getEditorView3; var view = (_config$getEditorView3 = config === null || config === void 0 ? void 0 : config.getEditorView()) !== null && _config$getEditorView3 !== void 0 ? _config$getEditorView3 : null; if (!(view !== null && view !== void 0 && view.state.schema)) { return undefined; } return cb(view === null || view === void 0 ? void 0 : view.state.schema); }, getAnchorIdForNode: function getAnchorIdForNode(node, pos) { var _config$getEditorView4; var view = (_config$getEditorView4 = config === null || config === void 0 ? void 0 : config.getEditorView()) !== null && _config$getEditorView4 !== void 0 ? _config$getEditorView4 : null; if (!view) { return undefined; } var nodeIdProvider = getNodeIdProvider(view); var cachedId = nodeIdProvider.getIdForNode(node); if (cachedId) { return cachedId; } if (pos < 0) { return undefined; } // Check DOM first to avoid generating a new ID with a collision suffix // when the DOM already has a valid anchor. This prevents misalignment // of drag handles on first focus after clicking from the title. var nodeDOM = view.nodeDOM(pos); if (nodeDOM instanceof HTMLElement) { var domAnchor = nodeDOM.getAttribute('data-node-anchor'); if (domAnchor) { // Cache the DOM anchor for this node to maintain consistency // This ensures subsequent calls return the same anchor nodeIdProvider.setIdForNode(node, domAnchor); return domAnchor; } } // Only generate a new ID if DOM doesn't have one var generatedId = nodeIdProvider.getOrGenerateId(node, pos); if (generatedId) { return generatedId; } return undefined; } } }; };