@atlaskit/renderer
Version:
Renderer component
405 lines (396 loc) • 14.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _adfSchema = require("@atlaskit/adf-schema");
var _utils = require("@atlaskit/editor-common/utils");
var _editorJsonTransformer = require("@atlaskit/editor-json-transformer");
var _state = require("@atlaskit/editor-prosemirror/state");
var _analytics = require("@atlaskit/editor-common/analytics");
var _transform = require("@atlaskit/editor-prosemirror/transform");
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
var _steps = require("../steps");
var _getRendererRangeInlineNodeNames = require("./get-renderer-range-inline-node-names");
var _matchesUtils = require("./matches-utils");
var _selection = require("./selection");
var RendererActions = exports.default = /*#__PURE__*/function () {
// Any kind of refence is allowed
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function RendererActions() {
var initFromContext = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
(0, _classCallCheck2.default)(this, RendererActions);
// This is our psuedo feature flag for now
// This module can only be used when wrapped with
// the <RendererContext> component for now.
(0, _defineProperty2.default)(this, "initFromContext", false);
this.initFromContext = initFromContext;
this.transformer = new _editorJsonTransformer.JSONTransformer();
}
//#region private
return (0, _createClass2.default)(RendererActions, [{
key: "_privateRegisterRenderer",
value: function _privateRegisterRenderer(ref, doc, schema, onAnalyticsEvent) {
if (!this.initFromContext) {
return;
} else if (!this.ref) {
this.ref = ref;
} else if (this.ref !== ref) {
throw new Error("Renderer has already been registered! It's not allowed to re-register with another new Renderer instance.");
}
this.doc = doc;
this.schema = schema;
this.onAnalyticsEvent = onAnalyticsEvent;
}
}, {
key: "_privateUnregisterRenderer",
value: function _privateUnregisterRenderer() {
this.doc = undefined;
this.ref = undefined;
this.schema = undefined;
}
/**
* Validate whether we can create an annotation between two positions
*/
}, {
key: "_privateValidatePositionsForAnnotation",
value: function _privateValidatePositionsForAnnotation(from, to) {
if (!this.doc || !this.schema) {
return false;
}
var currentSelection = _state.TextSelection.create(this.doc, from, to);
if ((0, _utils.isEmptyTextSelectionRenderer)(currentSelection, this.schema)) {
return false;
}
var result = (0, _utils.canApplyAnnotationOnRange)({
from: from,
to: to
}, this.doc, this.schema);
return result;
}
//#endregion
}, {
key: "deleteAnnotation",
value: function deleteAnnotation(annotationId, annotationType) {
if (!this.doc || !this.schema || !this.schema.marks.annotation) {
return false;
}
var mark = this.schema.marks.annotation.create({
id: annotationId,
annotationType: annotationType
});
var from;
var to;
var nodePos;
var step;
this.doc.descendants(function (node, pos) {
var found = mark.isInSet(node.marks);
if (found && node.type.name === 'media') {
nodePos = pos;
}
if (found && !from) {
// Set both here incase it only spans one node.
from = pos;
to = pos + node.nodeSize;
} else if (found && from) {
// If the mark spans multiple nodes,
// we'll keep setting the end until no longer found.
to = pos + node.nodeSize;
}
return true;
});
if (nodePos !== undefined) {
step = new _transform.RemoveNodeMarkStep(nodePos, mark);
} else {
if (from === undefined || to === undefined) {
return false;
}
step = new _transform.RemoveMarkStep(from, to, mark);
}
var _step$apply = step.apply(this.doc),
doc = _step$apply.doc,
failed = _step$apply.failed;
if (this.onAnalyticsEvent) {
var payload = {
action: _analytics.ACTION.DELETED,
actionSubject: _analytics.ACTION_SUBJECT.ANNOTATION,
actionSubjectId: _analytics.ACTION_SUBJECT_ID.INLINE_COMMENT,
eventType: _analytics.EVENT_TYPE.TRACK,
attributes: {
inlineNodeNames: step instanceof _transform.RemoveMarkStep ? (0, _getRendererRangeInlineNodeNames.getRendererRangeInlineNodeNames)({
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
pos: {
from: from,
to: to
},
actions: this
}) : undefined
}
};
this.onAnalyticsEvent(payload);
}
if (!failed && doc) {
return {
step: step,
doc: this.transformer.encode(doc)
};
}
return false;
}
}, {
key: "annotate",
value: function annotate(range, annotationId, _annotationType) {
if (!this.doc || !this.schema || !this.schema.marks.annotation) {
return false;
}
var pos = (0, _steps.getPosFromRange)(range);
if (!pos) {
return false;
}
var from = pos.from,
to = pos.to;
var validPositions = this._privateValidatePositionsForAnnotation(from, to);
if (!validPositions) {
return false;
}
return this.applyAnnotation(pos, {
annotationId: annotationId,
annotationType: _adfSchema.AnnotationTypes.INLINE_COMMENT
});
}
}, {
key: "isValidAnnotationRange",
value: function isValidAnnotationRange(range) {
if (!range) {
return false;
}
if ((0, _platformFeatureFlags.fg)('editor_inline_comments_on_inline_nodes')) {
if (this.isRendererWithinRange(range)) {
return false;
}
}
var pos = (0, _steps.getPosFromRange)(range);
if (!pos || !this.doc) {
return false;
}
return this._privateValidatePositionsForAnnotation(pos.from, pos.to);
}
}, {
key: "isRangeAnnotatable",
value: function isRangeAnnotatable(range) {
try {
var _startContainer$paren, _endContainer$parentE;
if (!range) {
return false;
}
var startContainer = range.startContainer,
endContainer = range.endContainer;
if ((_startContainer$paren = startContainer.parentElement) !== null && _startContainer$paren !== void 0 && _startContainer$paren.closest('.ak-renderer-extension') || (_endContainer$parentE = endContainer.parentElement) !== null && _endContainer$parentE !== void 0 && _endContainer$parentE.closest('.ak-renderer-extension')) {
return false;
}
return this.isValidAnnotationRange(range);
} catch (_unused) {
// isValidAnnotationRange can fail when called inside nested renderers.
// while isRendererWithinRange guards against this to some degree -- the classnames
// are controlled by product -- and we don't have platform guarantees on them.
//
// Currently there is a mix of logic across the platform and confluence on determining
// positions that are annotatable. This is a defensive check to ensure we don't throw an error
// in cases where the range is not valid.
return false;
}
}
// eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- Ignored via go/ED-25883
/**
* This is replaced by `isRangeAnnotatable`.
*
* @deprecated
**/
}, {
key: "isRendererWithinRange",
value: function isRendererWithinRange(range) {
var startContainer = range.startContainer,
endContainer = range.endContainer;
if (startContainer.parentElement && startContainer.parentElement.closest('.ak-renderer-extension') || endContainer.parentElement && endContainer.parentElement.closest('.ak-renderer-extension')) {
return true;
}
return false;
}
}, {
key: "isValidAnnotationPosition",
value: function isValidAnnotationPosition(pos) {
if (!pos || !this.doc) {
return false;
}
return this._privateValidatePositionsForAnnotation(pos.from, pos.to);
}
/**
* Note: False indicates that the selection not able to be calculated.
*/
}, {
key: "getPositionFromRange",
value: function getPositionFromRange(range) {
if (!this.doc || !this.schema || !range) {
return false;
}
return (0, _steps.getPosFromRange)(range);
}
}, {
key: "getSelectionContext",
value: function getSelectionContext() {
return (0, _selection.getSelectionContext)({
doc: this.doc,
schema: this.schema
});
}
}, {
key: "getAnnotationMarks",
value: function getAnnotationMarks() {
var schema = this.schema,
doc = this.doc;
if (!schema || !doc) {
return [];
}
var annotationMarkType = schema.marks.annotation;
if (!annotationMarkType) {
return [];
}
var marks = [];
doc.descendants(function (node) {
var annotationsMark = node.marks.filter(function (m) {
return m.type === annotationMarkType;
});
if (!annotationsMark || !annotationsMark.length) {
return true;
}
marks.push.apply(marks, (0, _toConsumableArray2.default)(annotationsMark));
return false;
});
var uniqueMarks = new Map();
marks.forEach(function (m) {
uniqueMarks.set(m.attrs.id, m);
});
return Array.from(uniqueMarks.values());
}
}, {
key: "getAnnotationsByPosition",
value: function getAnnotationsByPosition(range) {
if (!this.doc || !this.schema) {
return [];
}
var pos = (0, _steps.getPosFromRange)(range);
if (!pos || !this.doc) {
return [];
}
return (0, _utils.getAnnotationIdsFromRange)(pos, this.doc, this.schema);
}
}, {
key: "applyAnnotation",
value: function applyAnnotation(pos, annotation) {
if (!this.doc || !pos || !this.schema) {
return false;
}
var from = pos.from,
to = pos.to;
var annotationId = annotation.annotationId,
annotationType = annotation.annotationType;
var step;
var targetNodeType;
// As part of fix for RAP, `from` points to the position right before media node
// hence, -1 is not needed
var beforeNodePos = from;
var possibleNode = this.doc.nodeAt(beforeNodePos);
if ((possibleNode === null || possibleNode === void 0 ? void 0 : possibleNode.type.name) === 'media') {
targetNodeType = 'media';
step = new _transform.AddNodeMarkStep(beforeNodePos, this.schema.marks.annotation.create({
id: annotationId,
type: annotationType
}));
} else {
var resolvedNode = this.doc.resolve(from).node();
// annotation is technically on text, but the context is caption
targetNodeType = resolvedNode.type.name === 'caption' ? 'caption' : 'text';
step = (0, _steps.createAnnotationStep)(from, to, {
annotationId: annotationId,
annotationType: annotationType,
schema: this.schema
});
}
var _step$apply2 = step.apply(this.doc),
doc = _step$apply2.doc,
failed = _step$apply2.failed;
if (failed || !doc) {
return false;
}
var originalSelection = doc.textBetween(from, to);
var _getIndexMatch = (0, _matchesUtils.getIndexMatch)(this.doc, this.schema, originalSelection, from),
numMatches = _getIndexMatch.numMatches,
matchIndex = _getIndexMatch.matchIndex,
blockNodePos = _getIndexMatch.blockNodePos;
return {
step: step,
doc: this.transformer.encode(doc),
inlineNodeTypes: (0, _getRendererRangeInlineNodeNames.getRendererRangeInlineNodeNames)({
actions: this,
pos: {
from: from,
to: to
}
}),
ancestorNodeTypes: (0, _getRendererRangeInlineNodeNames.getRendererRangeAncestorNodeNames)({
actions: this,
pos: {
from: from,
to: to
}
}),
originalSelection: originalSelection,
numMatches: numMatches,
matchIndex: matchIndex,
pos: blockNodePos,
targetNodeType: targetNodeType
};
}
}, {
key: "generateAnnotationIndexMatch",
value: function generateAnnotationIndexMatch(pos) {
if (!this.doc || !pos || !this.schema) {
return false;
}
var from = pos.from,
to = pos.to;
var originalSelection = this.doc.textBetween(from, to);
var _getIndexMatch2 = (0, _matchesUtils.getIndexMatch)(this.doc, this.schema, originalSelection, from),
numMatches = _getIndexMatch2.numMatches,
matchIndex = _getIndexMatch2.matchIndex,
blockNodePos = _getIndexMatch2.blockNodePos;
return {
originalSelection: originalSelection,
numMatches: numMatches,
matchIndex: matchIndex,
pos: blockNodePos
};
}
// Ignored via go/ees007
// eslint-disable-next-line @atlaskit/editor/enforce-todo-comment-format
// TODO: Do not forget to remove `undefined` when the `editor_inline_comments_on_inline_nodes` is removed.
}, {
key: "getInlineNodeTypes",
value: function getInlineNodeTypes(annotationId) {
if (!this.doc || !this.schema) {
return [];
}
return (0, _utils.getAnnotationInlineNodeTypes)({
doc: this.doc,
schema: this.schema
}, annotationId);
}
}]);
}();