@atlaskit/editor-plugin-annotation
Version:
Annotation plugin for @atlaskit/editor-core
146 lines (143 loc) • 7.04 kB
JavaScript
import { AnnotationTypes } from '@atlaskit/adf-schema';
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
import { applyMarkOnRange } from '@atlaskit/editor-common/mark';
import { getRangeInlineNodeNames } from '@atlaskit/editor-common/utils';
import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
import { AddMarkStep } from '@atlaskit/editor-prosemirror/transform';
import { fg } from '@atlaskit/platform-feature-flags';
import { getDraftCommandAnalyticsPayload, getPluginState, resolveDraftBookmark } from '../pm-plugins/utils';
const isAnnotationStep = step => step instanceof AddMarkStep && step.mark.type.name === 'annotation';
const addAnnotationMark = (id, supportedBlockNodes) => (transaction, state) => {
const inlineCommentState = getPluginState(state);
const {
bookmark
} = inlineCommentState || {};
const annotationMark = state.schema.marks.annotation.create({
id,
type: AnnotationTypes.INLINE_COMMENT
});
const {
from,
to,
head,
isBlockNode
} = resolveDraftBookmark(state, bookmark, supportedBlockNodes);
let tr = transaction;
if (isBlockNode) {
tr = tr.addNodeMark(from, annotationMark);
// Set selection on the node so that we can display view component
tr.setSelection(NodeSelection.create(tr.doc, from));
} else {
// Apply the mark only to text node in the range.
const tr = applyMarkOnRange(from, to, false, annotationMark, transaction);
// The mark may not be applied to the current "head" of the bookmark so determine what was applied
// above and use that instead
const annotationMarkStep = tr.steps.reverse().find(isAnnotationStep);
const headBasedOnMark = from === head ? annotationMarkStep === null || annotationMarkStep === void 0 ? void 0 : annotationMarkStep.from : annotationMarkStep === null || annotationMarkStep === void 0 ? void 0 : annotationMarkStep.to;
tr.setSelection(TextSelection.create(tr.doc, headBasedOnMark !== null && headBasedOnMark !== void 0 ? headBasedOnMark : head));
}
return tr;
};
const addInlineComment = (editorAnalyticsAPI, editorAPI) => (id, supportedBlockNodes) => (transaction, state) => {
var _editorAPI$editorView, _pluginState$featureF;
let tr = addAnnotationMark(id, supportedBlockNodes)(transaction, state);
editorAPI === null || editorAPI === void 0 ? void 0 : (_editorAPI$editorView = editorAPI.editorViewModeEffects) === null || _editorAPI$editorView === void 0 ? void 0 : _editorAPI$editorView.actions.applyViewModeStepAt(tr);
// add insert analytics step to transaction
tr = addInsertAnalytics(editorAnalyticsAPI)(tr, state);
// add close analytics step to transaction
tr = addOpenCloseAnalytics(editorAnalyticsAPI)(false, INPUT_METHOD.TOOLBAR)(tr, state);
const pluginState = getPluginState(state);
const isAutoScrollBugFixEnabled = pluginState === null || pluginState === void 0 ? void 0 : (_pluginState$featureF = pluginState.featureFlagsPluginState) === null || _pluginState$featureF === void 0 ? void 0 : _pluginState$featureF.commentsOnMediaAutoscrollInEditor;
if (isAutoScrollBugFixEnabled) {
// Explicitly disable scrollIntoView as scrolling is handled by CommentSidebar
tr.setMeta('scrollIntoView', false);
}
return tr;
};
const addOpenCloseAnalytics = editorAnalyticsAPI => (drafting, method = INPUT_METHOD.TOOLBAR) => (transaction, state) => {
const draftingPayload = getDraftCommandAnalyticsPayload(drafting, method)(state);
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(draftingPayload)(transaction);
return transaction;
};
const handleDraftState = editorAnalyticsAPI => (drafting, method = INPUT_METHOD.TOOLBAR) => (transaction, state) => {
var _pluginState$featureF2;
const tr = addOpenCloseAnalytics(editorAnalyticsAPI)(drafting, method)(transaction, state);
const pluginState = getPluginState(state);
const isAutoScrollBugFixEnabled = pluginState === null || pluginState === void 0 ? void 0 : (_pluginState$featureF2 = pluginState.featureFlagsPluginState) === null || _pluginState$featureF2 === void 0 ? void 0 : _pluginState$featureF2.commentsOnMediaAutoscrollInEditor;
if (isAutoScrollBugFixEnabled) {
// Explicitly disable scrollIntoView as scrolling is handled by CommentSidebar
tr.setMeta('scrollIntoView', false);
}
return tr;
};
const addInsertAnalytics = editorAnalyticsAPI => (transaction, state) => {
const analyticsEvent = {
action: ACTION.INSERTED,
actionSubject: ACTION_SUBJECT.ANNOTATION,
eventType: EVENT_TYPE.TRACK,
actionSubjectId: ACTION_SUBJECT_ID.INLINE_COMMENT,
attributes: {}
};
if (fg('editor_inline_comments_on_inline_nodes')) {
const {
bookmark
} = getPluginState(state) || {};
// When this FF is removed we can move the analytics event creation inside of the
// attachAnalyticsEvent and get type inference for the attributes.
// @ts-ignore
analyticsEvent.attributes.inlineNodeNames = getRangeInlineNodeNames({
doc: state.doc,
pos: resolveDraftBookmark(state, bookmark)
});
}
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(analyticsEvent)(transaction);
return transaction;
};
const addResolveAnalytics = editorAnalyticsAPI => method => (transaction, state) => {
const resolvedPayload = {
action: ACTION.RESOLVED,
actionSubject: ACTION_SUBJECT.ANNOTATION,
actionSubjectId: ACTION_SUBJECT_ID.INLINE_COMMENT,
eventType: EVENT_TYPE.TRACK,
attributes: {
method
}
};
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(resolvedPayload)(transaction);
return transaction;
};
const addPreemptiveGateErrorAnalytics = editorAnalyticsAPI => errorReason => (transaction, state) => {
const analyticsEvent = {
action: ACTION.ERROR,
actionSubject: ACTION_SUBJECT.ANNOTATION,
actionSubjectId: ACTION_SUBJECT_ID.INLINE_COMMENT,
eventType: EVENT_TYPE.OPERATIONAL,
attributes: {
errorReason
}
};
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(analyticsEvent)(transaction);
return transaction;
};
const addDeleteAnalytics = editorAnalyticsAPI => (transaction, state) => {
const analyticsEvent = {
action: ACTION.DELETED,
actionSubject: ACTION_SUBJECT.ANNOTATION,
actionSubjectId: ACTION_SUBJECT_ID.INLINE_COMMENT,
eventType: EVENT_TYPE.TRACK,
attributes: {}
};
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(analyticsEvent)(transaction);
return transaction;
};
const _default_1 = {
addAnnotationMark,
addInlineComment,
handleDraftState,
addOpenCloseAnalytics,
addInsertAnalytics,
addResolveAnalytics,
addPreemptiveGateErrorAnalytics,
addDeleteAnalytics
};
export default _default_1;