@atlaskit/editor-plugin-annotation
Version:
Annotation plugin for @atlaskit/editor-core
352 lines (341 loc) • 16.1 kB
JavaScript
"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
};
};
};