@atlaskit/editor-plugin-editor-viewmode-effects
Version:
Editor-Viewmode effects plugin for @atlaskit/editor-core
126 lines (125 loc) • 5.67 kB
JavaScript
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
import { AddMarkStep, AddNodeMarkStep, ReplaceAroundStep, ReplaceStep, RemoveMarkStep, RemoveNodeMarkStep } from '@atlaskit/editor-prosemirror/transform';
import { fg } from '@atlaskit/platform-feature-flags';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { ViewModeNodeStep, ViewModeStep } from './pm-plugins/viewModeStep';
const createFilterStepsPlugin = api => () => new SafePlugin({
filterTransaction: tr => {
var _api$editorViewMode, _api$editorViewMode$s;
const mode = api === null || api === void 0 ? void 0 : (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : (_api$editorViewMode$s = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode$s === void 0 ? void 0 : _api$editorViewMode$s.mode;
if (mode !== 'view') {
return true;
}
if (expValEquals('platform_editor_are_nodes_equal_ignore_mark_order', 'isEnabled', true)) {
if (tr.getMeta('isRemote') || tr.getMeta('replaceDocument') || tr.getMeta('allowViewModeTransaction') && fg('platform_editor_allow_viewmode_transaction')) {
return true;
}
} else {
if (tr.getMeta('isRemote') || tr.getMeta('allowViewModeTransaction') && fg('platform_editor_allow_viewmode_transaction')) {
return true;
}
}
const viewModeSteps = tr.steps.reduce((acc, s) => {
if (s instanceof ViewModeNodeStep || s instanceof ViewModeStep) {
acc.push(s);
}
return acc;
}, []);
if (viewModeSteps.length === 0 || !api) {
if (tr.docChanged &&
// Check if the transaction contains any steps that modify the document (view mode steps do not)
tr.steps.filter(s => s instanceof ReplaceAroundStep || s instanceof ReplaceStep || s instanceof AddMarkStep || s instanceof AddNodeMarkStep || s instanceof RemoveMarkStep || s instanceof RemoveNodeMarkStep).length) {
return false;
}
return true;
return true;
}
viewModeSteps.forEach(step => {
if (step.inverted || !step.mark) {
return;
}
if (step.mark.type.name === 'annotation') {
if (step instanceof ViewModeNodeStep) {
var _api$collabEdit;
(_api$collabEdit = api.collabEdit) === null || _api$collabEdit === void 0 ? void 0 : _api$collabEdit.actions.addInlineCommentNodeMark({
mark: step.mark,
pos: step.pos
});
} else if (step instanceof ViewModeStep) {
var _api$collabEdit2;
(_api$collabEdit2 = api.collabEdit) === null || _api$collabEdit2 === void 0 ? void 0 : _api$collabEdit2.actions.addInlineCommentMark({
mark: step.mark,
from: step.from,
to: step.to
});
}
}
});
// Ignored via go/ees007
// eslint-disable-next-line @atlaskit/editor/enforce-todo-comment-format
// TODO: Follow-up and improve annotation logic so we can filter out transactions here
return true;
}
});
const createReplaceDocumentTransactionPlugin = api => () => new SafePlugin({
// Shouldn't need explicit types but sometimes TS can't infer them so 🤷
appendTransaction: (transactions, _oldState, newState) => {
var _api$editorViewMode2, _api$editorViewMode2$;
if (!api) {
return;
}
const isViewMode = (api === null || api === void 0 ? void 0 : (_api$editorViewMode2 = api.editorViewMode) === null || _api$editorViewMode2 === void 0 ? void 0 : (_api$editorViewMode2$ = _api$editorViewMode2.sharedState.currentState()) === null || _api$editorViewMode2$ === void 0 ? void 0 : _api$editorViewMode2$.mode) === 'view';
if (!isViewMode) {
return;
}
const remoteReplaceDocumentTransaction = transactions.find(tr => {
var _api$collabEdit3, _api$collabEdit3$acti;
return (_api$collabEdit3 = api.collabEdit) === null || _api$collabEdit3 === void 0 ? void 0 : (_api$collabEdit3$acti = _api$collabEdit3.actions) === null || _api$collabEdit3$acti === void 0 ? void 0 : _api$collabEdit3$acti.isRemoteReplaceDocumentTransaction(tr);
});
if (!remoteReplaceDocumentTransaction || !remoteReplaceDocumentTransaction.selectionSet) {
return;
}
const doc = newState.doc;
const nextTr = newState.tr;
const emptySelection = new TextSelection(doc.resolve(0));
nextTr.setSelection(emptySelection);
return nextTr;
}
});
export const editorViewModeEffectsPlugin = ({
api
}) => ({
name: 'editorViewModeEffects',
actions: {
allowViewModeTransaction: tr => {
tr.setMeta('allowViewModeTransaction', true);
return tr;
},
applyViewModeStepAt: tr => {
const marksSteps = tr.steps.reduce((acc, s) => {
// Ignored via go/ees007
// eslint-disable-next-line @atlaskit/editor/enforce-todo-comment-format
// TODO: We probably want to check the RemoveMarkStep flow too.
if (s instanceof AddMarkStep || s instanceof AddNodeMarkStep) {
acc.push(s);
}
return acc;
}, []);
if (marksSteps.length === 0) {
return false;
}
marksSteps.reverse().map(s => s instanceof AddNodeMarkStep ? tr.step(ViewModeNodeStep.from(s)) : tr.step(ViewModeStep.from(s)));
return true;
}
},
pmPlugins() {
return [{
name: 'editorViewModeEffectsFilterSteps',
plugin: createFilterStepsPlugin(api)
}, {
name: 'editorViewModeEffectsReplaceDocumentTransaction',
plugin: createReplaceDocumentTransactionPlugin(api)
}];
}
});