UNPKG

@atlaskit/editor-plugin-annotation

Version:

Annotation plugin for @atlaskit/editor-core

352 lines (341 loc) 16.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.startDraft = exports.setIsAnnotationSelected = exports.setIsAnnotationHovered = exports.getDraft = exports.clearDraft = exports.clearAnnotation = exports.applyDraft = exports.allowAnnotation = void 0; var _adfSchema = require("@atlaskit/adf-schema"); var _utils = require("@atlaskit/editor-common/utils"); var _utils2 = require("@atlaskit/editor-prosemirror/utils"); var _editorCommands = require("../editor-commands"); var _types = require("../types"); var _utils3 = require("./utils"); var ERROR_REASON_DRAFT_NOT_STARTED = 'draft-not-started'; var ERROR_REASON_DRAFT_IN_PROGRESS = 'draft-in-progress'; var ERROR_REASON_RANGE_MISSING = 'range-no-longer-exists'; var ERROR_REASON_RANGE_INVALID = 'invalid-range'; var ERROR_REASON_ID_INVALID = 'id-not-valid'; var domRefFromPos = function domRefFromPos(view, position) { var dom; try { // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting dom = (0, _utils2.findDomRefAtPos)(position, view.domAtPos.bind(view)); } catch (error) { // eslint-disable-next-line no-console console.warn(error); return undefined; } return dom; }; var allowAnnotation = exports.allowAnnotation = function allowAnnotation(editorView, _options) { return function () { var _ref = _utils3.inlineCommentPluginKey.getState(editorView.state) || {}, isDrafting = _ref.isDrafting, draftDecorationSet = _ref.draftDecorationSet; if (isDrafting) { return false; } var decoration = draftDecorationSet === null || draftDecorationSet === void 0 ? void 0 : draftDecorationSet.find(); // If a draft decoration exists then we should block the user from creating a new one. if (!!(decoration !== null && decoration !== void 0 && decoration.length)) { return false; } return (0, _utils3.isSelectionValid)(editorView.state) === _types.AnnotationSelectionType.VALID; }; }; var startDraft = exports.startDraft = function startDraft(editorView, options) { return function () { var _getRangeInlineNodeNa, _options$annotationMa2; var _ref2 = _utils3.inlineCommentPluginKey.getState(editorView.state) || {}, isDrafting = _ref2.isDrafting, selectedAnnotations = _ref2.selectedAnnotations; if (isDrafting) { return { success: false, reason: ERROR_REASON_DRAFT_IN_PROGRESS }; } if (!!(selectedAnnotations !== null && selectedAnnotations !== void 0 && selectedAnnotations.length)) { // if there are selected annotations when starting a draft, we need to clear the selected annotations // before we start the draft. (0, _editorCommands.closeComponent)()(editorView.state, editorView.dispatch); // not only that but we need to also deselect any other annotations that are currently selected. selectedAnnotations === null || selectedAnnotations === void 0 || selectedAnnotations.forEach(function (annotation) { var _options$annotationMa, _getAnnotationInlineN; (_options$annotationMa = options.annotationManager) === null || _options$annotationMa === void 0 || _options$annotationMa.emit({ name: 'annotationSelectionChanged', data: { annotationId: annotation.id, isSelected: false, inlineNodeTypes: (_getAnnotationInlineN = (0, _utils.getAnnotationInlineNodeTypes)(editorView.state, annotation.id)) !== null && _getAnnotationInlineN !== void 0 ? _getAnnotationInlineN : [] } }); }); } (0, _editorCommands.setInlineCommentDraftState)(options.editorAnalyticsAPI, undefined, options.api)(true)(editorView.state, editorView.dispatch); var _ref3 = _utils3.inlineCommentPluginKey.getState(editorView.state) || {}, draftDecorationSet = _ref3.draftDecorationSet; var decorations = draftDecorationSet === null || draftDecorationSet === void 0 ? void 0 : draftDecorationSet.find(); // If the matching decorations is not found containing the id, it means something went wrong with the draft. if (!(decorations !== null && decorations !== void 0 && decorations.length)) { return { success: false, reason: ERROR_REASON_RANGE_INVALID }; } var from = decorations[0].from; var targetElement = domRefFromPos(editorView, from); var inlineNodeTypes = (_getRangeInlineNodeNa = (0, _utils.getRangeInlineNodeNames)({ doc: editorView.state.doc, pos: { from: from, to: decorations[decorations.length - 1].to } })) !== null && _getRangeInlineNodeNa !== void 0 ? _getRangeInlineNodeNa : []; (_options$annotationMa2 = options.annotationManager) === null || _options$annotationMa2 === void 0 || _options$annotationMa2.emit({ name: 'draftAnnotationStarted', data: { targetElement: targetElement, actionResult: undefined, inlineNodeTypes: inlineNodeTypes } }); return { success: true, targetElement: targetElement, // In Editor the action result is undefined, because the editor will perform the transaction on the document. actionResult: undefined, inlineNodeTypes: inlineNodeTypes }; }; }; var clearDraft = exports.clearDraft = function clearDraft(editorView, options) { return function () { var _ref4 = _utils3.inlineCommentPluginKey.getState(editorView.state) || {}, isDrafting = _ref4.isDrafting, draftDecorationSet = _ref4.draftDecorationSet; if (!isDrafting) { return { success: false, reason: ERROR_REASON_DRAFT_NOT_STARTED }; } var decorations = draftDecorationSet === null || draftDecorationSet === void 0 ? void 0 : draftDecorationSet.find(); if (!(decorations !== null && decorations !== void 0 && decorations.length)) { return { success: false, reason: ERROR_REASON_DRAFT_NOT_STARTED }; } (0, _editorCommands.setInlineCommentDraftState)(options.editorAnalyticsAPI, undefined, options.api)(false)(editorView.state, editorView.dispatch); !editorView.hasFocus() && editorView.focus(); return { success: true }; }; }; var applyDraft = exports.applyDraft = function applyDraft(editorView, options) { return function (id) { var _options$annotationMa3, _getAnnotationInlineN2; var _ref5 = _utils3.inlineCommentPluginKey.getState(editorView.state) || {}, isDrafting = _ref5.isDrafting, draftDecorationSet = _ref5.draftDecorationSet, bookmark = _ref5.bookmark; if (!isDrafting) { return { success: false, reason: ERROR_REASON_DRAFT_NOT_STARTED }; } var decorations = draftDecorationSet === null || draftDecorationSet === void 0 ? void 0 : draftDecorationSet.find(); if (!(decorations !== null && decorations !== void 0 && decorations.length) || !bookmark) { return { success: false, reason: ERROR_REASON_RANGE_MISSING }; } var from = decorations[0].from; (0, _editorCommands.createAnnotation)(options.editorAnalyticsAPI, options.api)(id, _adfSchema.AnnotationTypes.INLINE_COMMENT, options.provider.supportedBlockNodes)(editorView.state, editorView.dispatch); !editorView.hasFocus() && editorView.focus(); // Using the original decoration from position we should be able to locate the new target element. // This is because the new annotation will be created at the same position as the draft decoration. var targetElement = domRefFromPos(editorView, from); // When a draft is applied it is automatically selected, so we need to set the selected annotation. // emit the event for the selected annotation. (_options$annotationMa3 = options.annotationManager) === null || _options$annotationMa3 === void 0 || _options$annotationMa3.emit({ name: 'annotationSelectionChanged', data: { annotationId: id, isSelected: true, inlineNodeTypes: (_getAnnotationInlineN2 = (0, _utils.getAnnotationInlineNodeTypes)(editorView.state, id)) !== null && _getAnnotationInlineN2 !== void 0 ? _getAnnotationInlineN2 : [] } }); return { success: true, // Get the dom element from the newly created annotation and return it here. targetElement: targetElement, // In Editor this is undefined, because the editor will update the document. actionResult: undefined }; }; }; var getDraft = exports.getDraft = function getDraft(editorView, _options) { return function () { var _getRangeInlineNodeNa2; var _ref6 = _utils3.inlineCommentPluginKey.getState(editorView.state) || {}, isDrafting = _ref6.isDrafting, draftDecorationSet = _ref6.draftDecorationSet; if (!isDrafting) { return { success: false, reason: ERROR_REASON_DRAFT_NOT_STARTED }; } var decorations = draftDecorationSet === null || draftDecorationSet === void 0 ? void 0 : draftDecorationSet.find(); if (!(decorations !== null && decorations !== void 0 && decorations.length)) { return { success: false, reason: ERROR_REASON_DRAFT_NOT_STARTED }; } var from = decorations[0].from; var targetElement = domRefFromPos(editorView, from); var inlineNodeTypes = (_getRangeInlineNodeNa2 = (0, _utils.getRangeInlineNodeNames)({ doc: editorView.state.doc, pos: { from: from, to: decorations[decorations.length - 1].to } })) !== null && _getRangeInlineNodeNa2 !== void 0 ? _getRangeInlineNodeNa2 : []; return { success: true, inlineNodeTypes: inlineNodeTypes, targetElement: targetElement, actionResult: undefined }; }; }; var setIsAnnotationSelected = exports.setIsAnnotationSelected = function setIsAnnotationSelected(editorView, options) { return function (id, isSelected) { var _selectedAnnotations$; var _ref7 = _utils3.inlineCommentPluginKey.getState(editorView.state) || {}, annotations = _ref7.annotations, isDrafting = _ref7.isDrafting, selectedAnnotations = _ref7.selectedAnnotations; if (isDrafting) { return { success: false, reason: ERROR_REASON_DRAFT_IN_PROGRESS }; } // If there is no annotation state with this id then we can assume the annotation is invalid. if (!(annotations !== null && annotations !== void 0 && annotations.hasOwnProperty(id))) { return { success: false, reason: ERROR_REASON_ID_INVALID }; } var isCurrentlySelectedIndex = (_selectedAnnotations$ = selectedAnnotations === null || selectedAnnotations === void 0 ? void 0 : selectedAnnotations.findIndex(function (annotation) { return annotation.id === id; })) !== null && _selectedAnnotations$ !== void 0 ? _selectedAnnotations$ : -1; var isCurrentlySelected = isCurrentlySelectedIndex !== -1; if (isSelected !== isCurrentlySelected) { // the annotation is selection is changing. if (isCurrentlySelected && !isSelected) { var _options$annotationMa4, _getAnnotationInlineN3; // the selected annotaion is being unselected, so we need to close the view. (0, _editorCommands.closeComponent)()(editorView.state, editorView.dispatch); (_options$annotationMa4 = options.annotationManager) === null || _options$annotationMa4 === void 0 || _options$annotationMa4.emit({ name: 'annotationSelectionChanged', data: { annotationId: id, isSelected: false, inlineNodeTypes: (_getAnnotationInlineN3 = (0, _utils.getAnnotationInlineNodeTypes)(editorView.state, id)) !== null && _getAnnotationInlineN3 !== void 0 ? _getAnnotationInlineN3 : [] } }); } else if (!isCurrentlySelected && isSelected) { var _options$annotationMa6, _getAnnotationInlineN5; // the annotation is currently not selected and is being selected, so we need to open the view. (0, _editorCommands.setSelectedAnnotation)(id)(editorView.state, editorView.dispatch); // the current annotations are going to be unselected. So we need to notify listeners of this change also. selectedAnnotations === null || selectedAnnotations === void 0 || selectedAnnotations.forEach(function (annotation) { if (annotation.id !== id) { var _options$annotationMa5, _getAnnotationInlineN4; (_options$annotationMa5 = options.annotationManager) === null || _options$annotationMa5 === void 0 || _options$annotationMa5.emit({ name: 'annotationSelectionChanged', data: { annotationId: annotation.id, isSelected: false, inlineNodeTypes: (_getAnnotationInlineN4 = (0, _utils.getAnnotationInlineNodeTypes)(editorView.state, annotation.id)) !== null && _getAnnotationInlineN4 !== void 0 ? _getAnnotationInlineN4 : [] } }); } }); // Lastly we need to emit the event for the selected annotation. (_options$annotationMa6 = options.annotationManager) === null || _options$annotationMa6 === void 0 || _options$annotationMa6.emit({ name: 'annotationSelectionChanged', data: { annotationId: id, isSelected: true, inlineNodeTypes: (_getAnnotationInlineN5 = (0, _utils.getAnnotationInlineNodeTypes)(editorView.state, id)) !== null && _getAnnotationInlineN5 !== void 0 ? _getAnnotationInlineN5 : [] } }); } } return { success: true, isSelected: isSelected }; }; }; var setIsAnnotationHovered = exports.setIsAnnotationHovered = function setIsAnnotationHovered(editorView, _options) { return function (id, isHovered) { var _hoveredAnnotations$f; var _ref8 = _utils3.inlineCommentPluginKey.getState(editorView.state) || {}, annotations = _ref8.annotations, hoveredAnnotations = _ref8.hoveredAnnotations; // If there is no annotation state with this id then we can assume the annotation is invalid. if (!(annotations !== null && annotations !== void 0 && annotations.hasOwnProperty(id))) { return { success: false, reason: ERROR_REASON_ID_INVALID }; } var isCurrentlyHoveredIndex = (_hoveredAnnotations$f = hoveredAnnotations === null || hoveredAnnotations === void 0 ? void 0 : hoveredAnnotations.findIndex(function (annotation) { return annotation.id === id; })) !== null && _hoveredAnnotations$f !== void 0 ? _hoveredAnnotations$f : -1; var isCurrentlyHovered = isCurrentlyHoveredIndex !== -1; if (isHovered !== isCurrentlyHovered) { // the annotation in hovered is changing. if (isCurrentlyHovered && !isHovered) { // the hovered annotaion is being unhovered, so we should remove the hover state. (0, _editorCommands.setHoveredAnnotation)('')(editorView.state, editorView.dispatch); } else if (!isCurrentlyHovered && isHovered) { // the annotation is currently not hovered and is being hovered. (0, _editorCommands.setHoveredAnnotation)(id)(editorView.state, editorView.dispatch); } } return { success: true, isHovered: isHovered }; }; }; var clearAnnotation = exports.clearAnnotation = function clearAnnotation(editorView, options) { return function (id) { var _ref9 = _utils3.inlineCommentPluginKey.getState(editorView.state) || {}, annotations = _ref9.annotations; // If there is no annotation state with this id then we can assume the annotation is invalid. if (!(annotations !== null && annotations !== void 0 && annotations.hasOwnProperty(id))) { return { success: false, reason: ERROR_REASON_ID_INVALID }; } (0, _editorCommands.removeInlineCommentFromDoc)(options.editorAnalyticsAPI)(id, options.provider.supportedBlockNodes)(editorView.state, editorView.dispatch); return { success: true, actionResult: undefined }; }; };