UNPKG

@atlaskit/editor-plugin-undo-redo

Version:

Undo redo plugin for @atlaskit/editor-core

91 lines (90 loc) 2.76 kB
import { ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics'; import { withAnalytics } from '@atlaskit/editor-common/editor-analytics'; import { areNodesEqualIgnoreAttrs } from '@atlaskit/editor-common/utils/document'; import { InputSource } from './enums'; import { pluginKey as undoPluginKey } from './plugin-key'; export const attachInputMeta = inputSource => command => (state, dispatch) => { let customTr = state.tr; const fakeDispatch = tr => { customTr = tr; }; command(state, fakeDispatch); if (!customTr || !customTr.docChanged) { return false; } customTr.setMeta(undoPluginKey, inputSource); if (dispatch) { dispatch(customTr); } return true; }; const inputSourceToInputMethod = inputSource => { switch (inputSource) { case InputSource.EXTERNAL: return INPUT_METHOD.EXTERNAL; case InputSource.KEYBOARD: return INPUT_METHOD.KEYBOARD; case InputSource.TOOLBAR: return INPUT_METHOD.TOOLBAR; default: return INPUT_METHOD.EXTERNAL; } }; function getNodesWithDifferingAttributes({ before, after }) { const allAttributeKeys = Object.keys({ ...before.attrs, ...after.attrs }); const differingAttributes = allAttributeKeys.filter(key => before.attrs[key] !== after.attrs[key]); const affectedNodes = differingAttributes.length ? [{ type: before.type.name, attributes: differingAttributes }] : []; return before.children.reduce((acc, beforeChild, index) => [...acc, ...getNodesWithDifferingAttributes({ before: beforeChild, after: after.child(index) })], affectedNodes); } /** * Analyzes changes between two ProseMirror document nodes. * * @param params - Object containing before and after node states * @param params.before - The document node before changes * @param params.after - The document node after changes * @returns Object containing change analysis results with hasChanged boolean and affectedNodes array */ export function getChanges({ before, after }) { const hasChanged = !areNodesEqualIgnoreAttrs(after, before); const affectedNodes = hasChanged ? undefined : getNodesWithDifferingAttributes({ before, after }) // Limit to 25 nodes to avoid oversize payloads .slice(0, 25); return { hasChanged, affectedNodes }; } export const attachInputMetaWithAnalytics = editorAnalyticsAPI => (inputSource, action) => command => attachInputMeta(inputSource)(withAnalytics(editorAnalyticsAPI, ({ doc: before }, { currentDoc: after }) => ({ eventType: EVENT_TYPE.TRACK, action, actionSubject: ACTION_SUBJECT.EDITOR, attributes: { inputMethod: inputSourceToInputMethod(inputSource), ...getChanges({ before, after }) } }))(command));