UNPKG

@atlaskit/editor-plugin-annotation

Version:

Annotation plugin for @atlaskit/editor-core

201 lines (199 loc) 9.93 kB
import React from 'react'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD, MODE } from '@atlaskit/editor-common/analytics'; import { ToolTipContent, addInlineComment } from '@atlaskit/editor-common/keymaps'; import { currentMediaNodeWithPos } from '@atlaskit/editor-common/media-single'; import { annotationMessages } from '@atlaskit/editor-common/messages'; import { calculateToolbarPositionAboveSelection, calculateToolbarPositionTrackHead, getRangeInlineNodeNames } from '@atlaskit/editor-common/utils'; import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity'; import CommentIcon from '@atlaskit/icon/core/comment'; import { fg } from '@atlaskit/platform-feature-flags'; import { setInlineCommentDraftState } from '../editor-commands'; import { AnnotationSelectionType, AnnotationTestIds } from '../types'; import { getPluginState, isSelectionValid, resolveDraftBookmark } from './utils'; var getValidNodes = function getValidNodes(state) { var schema = state.schema; var annotation = schema.marks.annotation; return Object.keys(schema.nodes).reduce(function (acc, current) { var type = schema.nodes[current]; if (type.allowsMarkType(annotation)) { acc.push(type); } return acc; }, []); }; /** * Should suppress toolbars when the user is creating an inline comment * This only applies when the selection range exactly matches the bookmark range * which should be the case immediately after the comment button is clicked * if the user creates a different selection range, the floating toolbar should still be shown * @param root0 * @param root0.state * @param root0.bookmark * @example */ export var shouldSuppressFloatingToolbar = function shouldSuppressFloatingToolbar(_ref) { var state = _ref.state, bookmark = _ref.bookmark; if (!bookmark) { return false; } var tr = state.tr; var resolvedBookmark = bookmark.resolve(tr.doc); var isSelectionMatchingBookmark = resolvedBookmark.to === tr.selection.to && resolvedBookmark.from === tr.selection.from; return isSelectionMatchingBookmark; }; export var buildSuppressedToolbar = function buildSuppressedToolbar(state) { return { items: [], nodeType: getValidNodes(state), title: 'Annotation suppressed toolbar' }; }; export var buildToolbar = function buildToolbar(editorAnalyticsAPI) { return function (_ref2) { var _api$connectivity; var state = _ref2.state, intl = _ref2.intl, _ref2$isToolbarAbove = _ref2.isToolbarAbove, isToolbarAbove = _ref2$isToolbarAbove === void 0 ? false : _ref2$isToolbarAbove, _ref2$_supportedNodes = _ref2._supportedNodes, _supportedNodes = _ref2$_supportedNodes === void 0 ? [] : _ref2$_supportedNodes, api = _ref2.api, createCommentExperience = _ref2.createCommentExperience, annotationManager = _ref2.annotationManager, onCommentButtonMount = _ref2.onCommentButtonMount, _ref2$getCanAddCommen = _ref2.getCanAddComments, getCanAddComments = _ref2$getCanAddCommen === void 0 ? function () { return true; } : _ref2$getCanAddCommen, contentType = _ref2.contentType; var selectionValid = isSelectionValid(state); var isMediaSelected = currentMediaNodeWithPos(state); // comments on media can only be added via media floating toolbar if (isMediaSelected || selectionValid === AnnotationSelectionType.INVALID) { return undefined; } var createCommentMessage = intl.formatMessage(annotationMessages.createComment); var commentDisabledMessage = intl.formatMessage(fg('editor_inline_comments_on_inline_nodes') ? annotationMessages.createCommentDisabled : annotationMessages.createCommentInvalid); var canAddComments = getCanAddComments(); var isCommentButtonDisabled = !canAddComments || selectionValid === AnnotationSelectionType.DISABLED; var disabledTooltipContent = !canAddComments ? intl.formatMessage(annotationMessages.noPermissionToAddComment, { contentType: contentType }) : commentDisabledMessage; var createComment = { type: 'button', showTitle: true, disabled: isCommentButtonDisabled || isOfflineMode(api === null || api === void 0 || (_api$connectivity = api.connectivity) === null || _api$connectivity === void 0 || (_api$connectivity = _api$connectivity.sharedState) === null || _api$connectivity === void 0 || (_api$connectivity = _api$connectivity.currentState()) === null || _api$connectivity === void 0 ? void 0 : _api$connectivity.mode), testId: AnnotationTestIds.floatingToolbarCreateButton, interactionName: 'start-inline-comment-action', icon: CommentIcon, iconFallback: CommentIcon, tooltipContent: isCommentButtonDisabled ? disabledTooltipContent : /*#__PURE__*/React.createElement(ToolTipContent, { description: createCommentMessage, keymap: addInlineComment }), title: createCommentMessage, onMount: function onMount() { var _getRangeInlineNodeNa; if (fg('confluence_frontend_preload_inline_comment_editor')) { onCommentButtonMount && onCommentButtonMount(); } // Check if the selection includes an non-text inline node var inlineCommentPluginState = getPluginState(state); var inlineNodeNames = (_getRangeInlineNodeNa = getRangeInlineNodeNames({ doc: state.doc, pos: resolveDraftBookmark(state, inlineCommentPluginState === null || inlineCommentPluginState === void 0 ? void 0 : inlineCommentPluginState.bookmark) })) !== null && _getRangeInlineNodeNa !== void 0 ? _getRangeInlineNodeNa : []; var isNonTextInlineNodeInludedInComment = inlineNodeNames.filter(function (nodeName) { return nodeName !== 'text'; }).length > 0; if (editorAnalyticsAPI) { editorAnalyticsAPI.fireAnalyticsEvent({ action: ACTION.VIEWED, actionSubject: ACTION_SUBJECT.BUTTON, actionSubjectId: ACTION_SUBJECT_ID.INLINE_COMMENT, eventType: EVENT_TYPE.UI, attributes: { isNonTextInlineNodeInludedInComment: isNonTextInlineNodeInludedInComment, isDisabled: selectionValid === AnnotationSelectionType.DISABLED, inputMethod: INPUT_METHOD.FLOATING_TB, mode: MODE.EDITOR } }); } }, onClick: function onClick(state, dispatch) { editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.fireAnalyticsEvent({ action: ACTION.CLICKED, actionSubject: ACTION_SUBJECT.BUTTON, actionSubjectId: ACTION_SUBJECT_ID.CREATE_INLINE_COMMENT_FROM_HIGHLIGHT_ACTIONS_MENU, eventType: EVENT_TYPE.UI, attributes: { source: 'highlightActionsMenu', pageMode: 'edit' } }); if (annotationManager) { annotationManager.checkPreemptiveGate().then(function (canStartDraft) { if (canStartDraft) { createCommentExperience === null || createCommentExperience === void 0 || createCommentExperience.start({ attributes: { pageClass: 'editor', commentType: 'inline', entryPoint: 'highlightActions' } }); createCommentExperience === null || createCommentExperience === void 0 || createCommentExperience.initExperience.start(); var result = annotationManager.startDraft(); if (!result.success) { // Fire an analytics event to indicate that the user has clicked the button // but the action was not completed, the result should contain a reason. editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.fireAnalyticsEvent({ action: ACTION.ERROR, actionSubject: ACTION_SUBJECT.ANNOTATION, actionSubjectId: ACTION_SUBJECT_ID.INLINE_COMMENT, eventType: EVENT_TYPE.OPERATIONAL, attributes: { errorReason: "toolbar-start-draft-failed/".concat(result.reason) } }); } } }).catch(function () { editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.fireAnalyticsEvent({ action: ACTION.ERROR, actionSubject: ACTION_SUBJECT.ANNOTATION, actionSubjectId: ACTION_SUBJECT_ID.INLINE_COMMENT, eventType: EVENT_TYPE.OPERATIONAL, attributes: { errorReason: "toolbar-start-draft-preemptive-gate-error" } }); }); return true; } else { createCommentExperience === null || createCommentExperience === void 0 || createCommentExperience.start({ attributes: { pageClass: 'editor', commentType: 'inline', entryPoint: 'highlightActions' } }); createCommentExperience === null || createCommentExperience === void 0 || createCommentExperience.initExperience.start(); return setInlineCommentDraftState(editorAnalyticsAPI)(true)(state, dispatch); } }, supportsViewMode: true // TODO: MODES-3950 - Clean up this floating toolbar view mode logic, }; var toolbarTitle = intl.formatMessage(annotationMessages.toolbar); var calcToolbarPosition = isToolbarAbove ? calculateToolbarPositionAboveSelection : calculateToolbarPositionTrackHead; var onPositionCalculated = calcToolbarPosition(toolbarTitle); return { title: toolbarTitle, nodeType: getValidNodes(state), items: [createComment], onPositionCalculated: onPositionCalculated, pluginName: 'annotation' }; }; };