@atlaskit/editor-plugin-extension
Version:
editor-plugin-extension plugin for @atlaskit/editor-core
289 lines (285 loc) • 13.6 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.onCopyFailed = exports.getSelectedExtension = exports.getSelectedDomElement = exports.getNodeTypesReferenced = exports.getDataConsumerMark = exports.findNodePosWithLocalId = exports.findExtensionWithLocalId = exports.copyUnsupportedContentToClipboard = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _analytics = require("@atlaskit/editor-common/analytics");
var _clipboard = require("@atlaskit/editor-common/clipboard");
var _utils = require("@atlaskit/editor-common/utils");
var _editorJsonTransformer = require("@atlaskit/editor-json-transformer");
var _utils2 = require("@atlaskit/editor-prosemirror/utils");
var _resource = require("@atlaskit/mention/resource");
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
var getSelectedExtension = exports.getSelectedExtension = function getSelectedExtension(state) {
var searchParent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var _state$schema$nodes = state.schema.nodes,
inlineExtension = _state$schema$nodes.inlineExtension,
extension = _state$schema$nodes.extension,
bodiedExtension = _state$schema$nodes.bodiedExtension,
multiBodiedExtension = _state$schema$nodes.multiBodiedExtension;
var nodeTypes = [extension, bodiedExtension, inlineExtension, multiBodiedExtension];
return (0, _utils2.findSelectedNodeOfType)(nodeTypes)(state.selection) || searchParent && (0, _utils2.findParentNodeOfType)(nodeTypes)(state.selection) || undefined;
};
var findExtensionWithLocalId = exports.findExtensionWithLocalId = function findExtensionWithLocalId(state, localId) {
var selectedExtension = getSelectedExtension(state, true);
if (!localId) {
return selectedExtension;
}
if (selectedExtension && selectedExtension.node.attrs.localId === localId) {
return selectedExtension;
}
var _state$schema$nodes2 = state.schema.nodes,
inlineExtension = _state$schema$nodes2.inlineExtension,
extension = _state$schema$nodes2.extension,
bodiedExtension = _state$schema$nodes2.bodiedExtension,
multiBodiedExtension = _state$schema$nodes2.multiBodiedExtension;
var nodeTypes = [extension, bodiedExtension, inlineExtension, multiBodiedExtension];
var matched;
state.doc.descendants(function (node, pos) {
if (nodeTypes.includes(node.type) && node.attrs.localId === localId) {
matched = {
node: node,
pos: pos
};
}
});
return matched;
};
var getSelectedDomElement = exports.getSelectedDomElement = function getSelectedDomElement(schema, domAtPos, selectedExtensionNode) {
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
var selectedExtensionDomNode = (0, _utils2.findDomRefAtPos)(selectedExtensionNode.pos, domAtPos);
var isContentExtension = selectedExtensionNode.node.type !== schema.nodes.bodiedExtension;
return (
// Content extension can be nested in bodied-extension, the following check is necessary for that case
(isContentExtension // Search down
? selectedExtensionDomNode.querySelector('.extension-container') // Try searching up and then down
: (0, _utils.closestElement)(selectedExtensionDomNode, '.extension-container') || selectedExtensionDomNode.querySelector('.extension-container')) || selectedExtensionDomNode
);
};
var getDataConsumerMark = exports.getDataConsumerMark = function getDataConsumerMark(newNode) {
var _newNode$marks;
return (_newNode$marks = newNode.marks) === null || _newNode$marks === void 0 ? void 0 : _newNode$marks.find(function (mark) {
return mark.type.name === 'dataConsumer';
});
};
var getNodeTypesReferenced = exports.getNodeTypesReferenced = function getNodeTypesReferenced(ids, state) {
return (0, _utils.findNodePosByLocalIds)(state, ids, {
includeDocNode: true
}).map(function (_ref) {
var node = _ref.node;
return node.type.name;
});
};
var findNodePosWithLocalId = exports.findNodePosWithLocalId = function findNodePosWithLocalId(state, localId) {
var nodes = (0, _utils.findNodePosByLocalIds)(state, [localId]);
return nodes.length >= 1 ? nodes[0] : undefined;
};
/**
* Converts a ProseMirror node to its text representation.
* Handles text nodes with marks (links) and inline nodes (status, mention, emoji).
* Returns the content for this node, with a trailing separator for text blocks.
*/
var convertNodeToText = function convertNodeToText(node, mentionSet, parent, locale) {
if (node.isInline) {
var schema = node.type.schema;
var finalText = '';
if (node.isText) {
finalText = node.text || '';
if (node.marks.length > 0) {
var _iterator = _createForOfIteratorHelper(node.marks),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var mark = _step.value;
// if it's link, include the href in the text
if (mark.type === schema.marks.link) {
var href = mark.attrs.href;
var text = node.text || '';
// If the text differs from the href, include both
if (text && text !== href) {
finalText = "".concat(text, " ").concat(href);
} else {
finalText = href;
}
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
} else {
switch (node.type) {
case schema.nodes.status:
finalText = node.attrs.text || '';
break;
case schema.nodes.mention:
mentionSet.add(node.attrs.id);
finalText = "@".concat(node.attrs.id);
break;
case schema.nodes.emoji:
finalText = node.attrs.shortName || '';
break;
case schema.nodes.date:
var timestamp = new Date(Number(node.attrs.timestamp));
finalText = !isNaN(timestamp.getTime()) ? timestamp.toLocaleDateString(locale !== null && locale !== void 0 ? locale : 'en-US') : String(node.attrs.timestamp);
break;
default:
finalText = node.textContent;
break;
}
}
if (parent && parent.isTextblock && node === parent.lastChild && parent.childCount > 0) {
finalText += '\n\n';
}
return finalText;
}
return '';
};
/**
* Resolves mention IDs to their display names and replaces them in the text.
* Returns the text with resolved mentions, or the original text if the provider is unavailable.
*/
var resolveMentionsInText = /*#__PURE__*/function () {
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(text, mentionSet, api) {
var _api$mention;
var mentionProvider, resolvedText, _iterator2, _step2, id, mention;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
mentionProvider = api === null || api === void 0 || (_api$mention = api.mention) === null || _api$mention === void 0 || (_api$mention = _api$mention.sharedState) === null || _api$mention === void 0 || (_api$mention = _api$mention.currentState()) === null || _api$mention === void 0 ? void 0 : _api$mention.mentionProvider;
if (!(!mentionProvider || !(0, _resource.isResolvingMentionProvider)(mentionProvider))) {
_context.next = 3;
break;
}
return _context.abrupt("return", text);
case 3:
resolvedText = text;
_iterator2 = _createForOfIteratorHelper(mentionSet);
_context.prev = 5;
_iterator2.s();
case 7:
if ((_step2 = _iterator2.n()).done) {
_context.next = 15;
break;
}
id = _step2.value;
_context.next = 11;
return mentionProvider.resolveMentionName(id);
case 11:
mention = _context.sent;
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace -- Ignored via go/ees017 (to be fixed)
resolvedText = resolvedText.replace("@".concat(id), "@".concat(mention.name) || '@…');
case 13:
_context.next = 7;
break;
case 15:
_context.next = 20;
break;
case 17:
_context.prev = 17;
_context.t0 = _context["catch"](5);
_iterator2.e(_context.t0);
case 20:
_context.prev = 20;
_iterator2.f();
return _context.finish(20);
case 23:
return _context.abrupt("return", resolvedText);
case 24:
case "end":
return _context.stop();
}
}, _callee, null, [[5, 17, 20, 23]]);
}));
return function resolveMentionsInText(_x, _x2, _x3) {
return _ref2.apply(this, arguments);
};
}();
/**
* copying ADF from the unsupported content extension as text to clipboard
*/
var copyUnsupportedContentToClipboard = exports.copyUnsupportedContentToClipboard = /*#__PURE__*/function () {
var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(_ref3) {
var locale, schema, unsupportedContent, api, transformer, pmNode, text, mentionSet;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
locale = _ref3.locale, schema = _ref3.schema, unsupportedContent = _ref3.unsupportedContent, api = _ref3.api;
_context2.prev = 1;
if (unsupportedContent) {
_context2.next = 4;
break;
}
throw new Error('No nested content found');
case 4:
if (unsupportedContent.type !== 'doc') {
unsupportedContent = {
version: 1,
type: 'doc',
content: [unsupportedContent]
};
}
transformer = new _editorJsonTransformer.JSONTransformer(schema);
pmNode = transformer.parse(unsupportedContent);
text = '';
mentionSet = new Set();
pmNode.nodesBetween(0, pmNode.content.size, function (node, _pos, parent) {
text += convertNodeToText(node, mentionSet, parent, locale);
});
// Trim leading/trailing whitespace from the collected text
text = text.trim();
_context2.next = 13;
return resolveMentionsInText(text, mentionSet, api);
case 13:
text = _context2.sent;
(0, _clipboard.copyToClipboard)(text);
_context2.next = 20;
break;
case 17:
_context2.prev = 17;
_context2.t0 = _context2["catch"](1);
throw _context2.t0 instanceof Error ? _context2.t0 : new Error('Failed to copy content');
case 20:
case "end":
return _context2.stop();
}
}, _callee2, null, [[1, 17]]);
}));
return function copyUnsupportedContentToClipboard(_x4) {
return _ref4.apply(this, arguments);
};
}();
var onCopyFailed = exports.onCopyFailed = function onCopyFailed(_ref5) {
var _extensionApi$analyti;
var error = _ref5.error,
extensionApi = _ref5.extensionApi,
state = _ref5.state;
var nodeWithPos = getSelectedExtension(state, true);
if (!nodeWithPos) {
return;
}
var node = nodeWithPos.node;
var _node$attrs = node.attrs,
extensionType = _node$attrs.extensionType,
extensionKey = _node$attrs.extensionKey;
extensionApi === null || extensionApi === void 0 || (_extensionApi$analyti = extensionApi.analytics) === null || _extensionApi$analyti === void 0 || _extensionApi$analyti.actions.fireAnalyticsEvent({
eventType: _analytics.EVENT_TYPE.OPERATIONAL,
action: _analytics.ACTION.COPY_FAILED,
actionSubject: _analytics.ACTION_SUBJECT.EXTENSION,
actionSubjectId: node.type.name,
attributes: {
extensionKey: extensionKey,
extensionType: extensionType,
errorMessage: error.message,
errorStack: error.stack
}
});
};