UNPKG

@atlaskit/editor-plugin-paste

Version:

Paste plugin for @atlaskit/editor-core

427 lines (423 loc) 23 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.createPasteAnalyticsPayload = createPasteAnalyticsPayload; exports.createPasteMeasurePayload = void 0; exports.getContent = getContent; exports.getContentNodeTypes = void 0; exports.getMediaTraceId = getMediaTraceId; exports.sendPasteAnalyticsEvent = exports.handleSelectedTableWithAnalytics = exports.handleRichTextWithAnalytics = exports.handlePastePreservingMarksWithAnalytics = exports.handlePastePanelOrDecisionIntoListWithAnalytics = exports.handlePasteNonNestableBlockNodesIntoListWithAnalytics = exports.handlePasteLinkOnSelectedTextWithAnalytics = exports.handlePasteIntoTaskAndDecisionWithAnalytics = exports.handlePasteIntoCaptionWithAnalytics = exports.handlePasteAsPlainTextWithAnalytics = exports.handleNestedTablePasteWithAnalytics = exports.handleMediaSingleWithAnalytics = exports.handleMarkdownWithAnalytics = exports.handleExpandWithAnalytics = exports.handleCodeBlockWithAnalytics = void 0; var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _analytics = require("@atlaskit/editor-common/analytics"); var _utils = require("@atlaskit/editor-common/utils"); var _utils2 = require("@atlaskit/editor-prosemirror/utils"); var _util = require("./util"); var _handlers = require("./util/handlers"); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var contentToPasteContent = { url: _analytics.PasteContents.url, paragraph: _analytics.PasteContents.text, bulletList: _analytics.PasteContents.bulletList, orderedList: _analytics.PasteContents.orderedList, heading: _analytics.PasteContents.heading, blockquote: _analytics.PasteContents.blockquote, codeBlock: _analytics.PasteContents.codeBlock, panel: _analytics.PasteContents.panel, rule: _analytics.PasteContents.rule, mediaSingle: _analytics.PasteContents.mediaSingle, mediaCard: _analytics.PasteContents.mediaCard, mediaGroup: _analytics.PasteContents.mediaGroup, table: _analytics.PasteContents.table, tableCells: _analytics.PasteContents.tableCells, tableHeader: _analytics.PasteContents.tableHeader, tableRow: _analytics.PasteContents.tableRow, decisionList: _analytics.PasteContents.decisionList, decisionItem: _analytics.PasteContents.decisionItem, taskList: _analytics.PasteContents.taskItem, extension: _analytics.PasteContents.extension, bodiedExtension: _analytics.PasteContents.bodiedExtension, blockCard: _analytics.PasteContents.blockCard, layoutSection: _analytics.PasteContents.layoutSection }; var nodeToActionSubjectId = { blockquote: _analytics.ACTION_SUBJECT_ID.PASTE_BLOCKQUOTE, blockCard: _analytics.ACTION_SUBJECT_ID.PASTE_BLOCK_CARD, bodiedExtension: _analytics.ACTION_SUBJECT_ID.PASTE_BODIED_EXTENSION, bulletList: _analytics.ACTION_SUBJECT_ID.PASTE_BULLET_LIST, codeBlock: _analytics.ACTION_SUBJECT_ID.PASTE_CODE_BLOCK, decisionList: _analytics.ACTION_SUBJECT_ID.PASTE_DECISION_LIST, extension: _analytics.ACTION_SUBJECT_ID.PASTE_EXTENSION, heading: _analytics.ACTION_SUBJECT_ID.PASTE_HEADING, mediaGroup: _analytics.ACTION_SUBJECT_ID.PASTE_MEDIA_GROUP, mediaSingle: _analytics.ACTION_SUBJECT_ID.PASTE_MEDIA_SINGLE, orderedList: _analytics.ACTION_SUBJECT_ID.PASTE_ORDERED_LIST, panel: _analytics.ACTION_SUBJECT_ID.PASTE_PANEL, rule: _analytics.ACTION_SUBJECT_ID.PASTE_RULE, table: _analytics.ACTION_SUBJECT_ID.PASTE_TABLE, tableCell: _analytics.ACTION_SUBJECT_ID.PASTE_TABLE_CELL, tableHeader: _analytics.ACTION_SUBJECT_ID.PASTE_TABLE_HEADER, tableRow: _analytics.ACTION_SUBJECT_ID.PASTE_TABLE_ROW, taskList: _analytics.ACTION_SUBJECT_ID.PASTE_TASK_LIST }; function getContent(_ref) { var schema = _ref.schema, slice = _ref.slice; var paragraph = schema.nodes.paragraph, link = schema.marks.link; var nodeOrMarkName = new Set(); slice.content.forEach(function (node) { if (node.type === paragraph && node.content.size === 0) { // Skip empty paragraph return; } if (node.type.name === 'text' && link.isInSet(node.marks)) { nodeOrMarkName.add('url'); return; } // Check node contain link if (node.type === paragraph && node.rangeHasMark(0, node.nodeSize - 2, link)) { nodeOrMarkName.add('url'); return; } nodeOrMarkName.add(node.type.name); }); if (nodeOrMarkName.size > 1) { return _analytics.PasteContents.mixed; } if (nodeOrMarkName.size === 0) { return _analytics.PasteContents.uncategorized; } var type = nodeOrMarkName.values().next().value; // @ts-ignore - TS2538 TypeScript 5.9.2 upgrade var pasteContent = contentToPasteContent[type]; return pasteContent ? pasteContent : _analytics.PasteContents.uncategorized; } function getMediaTraceId(slice) { var traceId; (0, _utils.mapSlice)(slice, function (node) { if (node.type.name === 'media' || node.type.name === 'mediaInline') { traceId = node.attrs.__mediaTraceId; } return node; }); return traceId; } function getActionSubjectId(_ref2) { var selection = _ref2.selection, schema = _ref2.schema; var _schema$nodes = schema.nodes, paragraph = _schema$nodes.paragraph, listItem = _schema$nodes.listItem, taskItem = _schema$nodes.taskItem, decisionItem = _schema$nodes.decisionItem; var parent = (0, _utils2.findParentNode)(function (node) { if (node.type !== paragraph && node.type !== listItem && node.type !== taskItem && node.type !== decisionItem) { return true; } return false; })(selection); if (!parent) { return _analytics.ACTION_SUBJECT_ID.PASTE_PARAGRAPH; } var parentType = parent.node.type; var actionSubjectId = nodeToActionSubjectId[parentType.name]; return actionSubjectId ? actionSubjectId : _analytics.ACTION_SUBJECT_ID.PASTE_PARAGRAPH; } function createPasteAsPlainPayload(actionSubjectId, text, linksInPasteCount) { return { action: _analytics.ACTION.PASTED_AS_PLAIN, actionSubject: _analytics.ACTION_SUBJECT.DOCUMENT, actionSubjectId: actionSubjectId, eventType: _analytics.EVENT_TYPE.TRACK, attributes: { inputMethod: _analytics.INPUT_METHOD.KEYBOARD, pasteSize: text.length, linksInPasteCount: linksInPasteCount } }; } function createPastePayload(actionSubjectId, attributes, linkDomain) { return _objectSpread({ action: _analytics.ACTION.PASTED, actionSubject: _analytics.ACTION_SUBJECT.DOCUMENT, actionSubjectId: actionSubjectId, eventType: _analytics.EVENT_TYPE.TRACK, attributes: _objectSpread({ inputMethod: _analytics.INPUT_METHOD.KEYBOARD }, attributes) }, linkDomain && linkDomain.length > 0 ? { nonPrivacySafeAttributes: { linkDomain: linkDomain } } : {}); } function createPasteAnalyticsPayloadBySelection(event, slice, pasteContext, pluginInjectionApi) { return function (selection) { var _pluginInjectionApi$m; var text = event.clipboardData ? event.clipboardData.getData('text/plain') || event.clipboardData.getData('text/uri-list') : ''; var actionSubjectId = getActionSubjectId({ selection: selection, schema: selection.$from.doc.type.schema }); var pasteSize = slice.size; var content = getContent({ schema: selection.$from.doc.type.schema, slice: slice }); var linkUrls = []; var mediaTraceId = getMediaTraceId(slice); // If we have a link among the pasted content, grab the // domain and send it up with the analytics event if (content === _analytics.PasteContents.url || content === _analytics.PasteContents.mixed) { (0, _utils.mapSlice)(slice, function (node) { var linkMark = node.marks.find(function (mark) { return mark.type.name === 'link'; }); if (linkMark) { linkUrls.push(linkMark.attrs.href); } return node; }); } if (pasteContext.asPlain) { return createPasteAsPlainPayload(actionSubjectId, text, linkUrls.length); } var source = (0, _util.getPasteSource)(event); var mentionIds = []; var mentionLocalIds = []; slice.content.descendants(function (node) { if (node.type.name === 'mention') { mentionIds.push(node.attrs.id); mentionLocalIds.push(node.attrs.localId); } }); if (pluginInjectionApi !== null && pluginInjectionApi !== void 0 && (_pluginInjectionApi$m = pluginInjectionApi.mention) !== null && _pluginInjectionApi$m !== void 0 && (_pluginInjectionApi$m = _pluginInjectionApi$m.actions) !== null && _pluginInjectionApi$m !== void 0 && _pluginInjectionApi$m.announceMentionsInsertion) { var _pluginInjectionApi$m2; var mentionsInserted = []; slice.content.descendants(function (node) { if (node.type.name === 'mention') { mentionsInserted.push({ type: 'added', id: node.attrs.id, localId: node.attrs.localId, method: 'pasted' }); } if (node.type.name === 'taskItem') { node.content.forEach(function (nodeContent) { if (nodeContent.type.name === 'mention') { mentionsInserted.push({ type: 'added', localId: nodeContent.attrs.localId, id: nodeContent.attrs.id, taskLocalId: node.attrs.localId, method: 'pasted' }); } }); return false; } }); pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$m2 = pluginInjectionApi.mention) === null || _pluginInjectionApi$m2 === void 0 || (_pluginInjectionApi$m2 = _pluginInjectionApi$m2.actions) === null || _pluginInjectionApi$m2 === void 0 || _pluginInjectionApi$m2.announceMentionsInsertion(mentionsInserted); } if (pasteContext.type === _analytics.PasteTypes.plain) { return createPastePayload(actionSubjectId, { pasteSize: text.length, type: pasteContext.type, content: _analytics.PasteContents.text, source: source, hyperlinkPasteOnText: false, linksInPasteCount: linkUrls.length, mentionIds: mentionIds, mentionLocalIds: mentionLocalIds, pasteSplitList: pasteContext.pasteSplitList }); } var linkDomains = linkUrls.map(_utils.getLinkDomain); return createPastePayload(actionSubjectId, { type: pasteContext.type, pasteSize: pasteSize, content: content, source: source, hyperlinkPasteOnText: !!pasteContext.hyperlinkPasteOnText, linksInPasteCount: linkUrls.length, mediaTraceId: mediaTraceId, mentionIds: mentionIds, mentionLocalIds: mentionLocalIds, pasteSplitList: pasteContext.pasteSplitList }, linkDomains); }; } function createPasteAnalyticsPayload(view, event, slice, pasteContext) { return createPasteAnalyticsPayloadBySelection(event, slice, pasteContext)(view.state.selection); } // TODO: ED-6612 - We should not dispatch only analytics, it's preferred to wrap each command with his own analytics. // However, handlers like handleMacroAutoConvert dispatch multiple time, // so pasteCommandWithAnalytics is useless in this case. var sendPasteAnalyticsEvent = exports.sendPasteAnalyticsEvent = function sendPasteAnalyticsEvent(editorAnalyticsAPI) { return function (view, event, slice, pasteContext) { var tr = view.state.tr; var payload = createPasteAnalyticsPayload(view, event, slice, pasteContext); editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent(payload)(tr); view.dispatch(tr); }; }; var handlePasteAsPlainTextWithAnalytics = exports.handlePasteAsPlainTextWithAnalytics = function handlePasteAsPlainTextWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: _analytics.PasteTypes.plain, asPlain: true }))((0, _handlers.handlePasteAsPlainText)(slice, event, editorAnalyticsAPI)); }; }; var handlePasteIntoTaskAndDecisionWithAnalytics = exports.handlePasteIntoTaskAndDecisionWithAnalytics = function handlePasteIntoTaskAndDecisionWithAnalytics(view, event, slice, type, pluginInjectionApi) { var _pluginInjectionApi$a, _pluginInjectionApi$c; return injectAnalyticsPayloadBeforeCommand(pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions)(createPasteAnalyticsPayloadBySelection(event, slice, { type: type }))((0, _handlers.handlePasteIntoTaskOrDecisionOrPanel)(slice, pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c = pluginInjectionApi.card) === null || _pluginInjectionApi$c === void 0 || (_pluginInjectionApi$c = _pluginInjectionApi$c.actions) === null || _pluginInjectionApi$c === void 0 ? void 0 : _pluginInjectionApi$c.queueCardsFromChangedTr)); }; var handlePasteIntoCaptionWithAnalytics = exports.handlePasteIntoCaptionWithAnalytics = function handlePasteIntoCaptionWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, type) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: type }))((0, _handlers.handlePasteIntoCaption)(slice)); }; }; var handleCodeBlockWithAnalytics = exports.handleCodeBlockWithAnalytics = function handleCodeBlockWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, text) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: _analytics.PasteTypes.plain }))((0, _handlers.handleCodeBlock)(text)); }; }; var handleMediaSingleWithAnalytics = exports.handleMediaSingleWithAnalytics = function handleMediaSingleWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, type, insertMediaAsMediaSingle) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: type }))((0, _handlers.handleMediaSingle)(_analytics.INPUT_METHOD.CLIPBOARD, insertMediaAsMediaSingle)(slice)); }; }; var handlePastePreservingMarksWithAnalytics = exports.handlePastePreservingMarksWithAnalytics = function handlePastePreservingMarksWithAnalytics(view, event, slice, type, pluginInjectionApi) { var _pluginInjectionApi$a2, _pluginInjectionApi$c2; return injectAnalyticsPayloadBeforeCommand(pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a2 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a2 === void 0 ? void 0 : _pluginInjectionApi$a2.actions)(createPasteAnalyticsPayloadBySelection(event, slice, { type: type }))((0, _handlers.handlePastePreservingMarks)(slice, pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c2 = pluginInjectionApi.card) === null || _pluginInjectionApi$c2 === void 0 || (_pluginInjectionApi$c2 = _pluginInjectionApi$c2.actions) === null || _pluginInjectionApi$c2 === void 0 ? void 0 : _pluginInjectionApi$c2.queueCardsFromChangedTr)); }; var handleMarkdownWithAnalytics = exports.handleMarkdownWithAnalytics = function handleMarkdownWithAnalytics(view, event, slice, pluginInjectionApi) { var _pluginInjectionApi$a3, _pluginInjectionApi$c3; return injectAnalyticsPayloadBeforeCommand(pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a3 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a3 === void 0 ? void 0 : _pluginInjectionApi$a3.actions)(createPasteAnalyticsPayloadBySelection(event, slice, { type: _analytics.PasteTypes.markdown }))((0, _handlers.handleMarkdown)(slice, pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c3 = pluginInjectionApi.card) === null || _pluginInjectionApi$c3 === void 0 || (_pluginInjectionApi$c3 = _pluginInjectionApi$c3.actions) === null || _pluginInjectionApi$c3 === void 0 ? void 0 : _pluginInjectionApi$c3.queueCardsFromChangedTr)); }; var handleRichTextWithAnalytics = exports.handleRichTextWithAnalytics = function handleRichTextWithAnalytics(view, event, slice, pluginInjectionApi) { var _pluginInjectionApi$a4, _pluginInjectionApi$c4; return injectAnalyticsPayloadBeforeCommand(pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a4 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a4 === void 0 ? void 0 : _pluginInjectionApi$a4.actions)(createPasteAnalyticsPayloadBySelection(event, slice, { type: _analytics.PasteTypes.richText }, pluginInjectionApi))((0, _handlers.handleRichText)(slice, pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c4 = pluginInjectionApi.card) === null || _pluginInjectionApi$c4 === void 0 || (_pluginInjectionApi$c4 = _pluginInjectionApi$c4.actions) === null || _pluginInjectionApi$c4 === void 0 ? void 0 : _pluginInjectionApi$c4.queueCardsFromChangedTr)); }; var injectAnalyticsPayloadBeforeCommand = function injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI) { return function (createPayloadByTransaction) { return function (mainCommand) { return function (state, dispatch, view) { var originalTransaction = state.tr; var fakeDispatch = function fakeDispatch(tr) { originalTransaction = tr; }; var result = mainCommand(state, fakeDispatch, view); if (!result) { return false; } if (dispatch && originalTransaction.docChanged) { // it needs to know the selection before the changes var payload = createPayloadByTransaction(state.selection); editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent(payload)(originalTransaction); dispatch(originalTransaction); } return true; }; }; }; }; var handlePastePanelOrDecisionIntoListWithAnalytics = exports.handlePastePanelOrDecisionIntoListWithAnalytics = function handlePastePanelOrDecisionIntoListWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, findRootParentListNode) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: _analytics.PasteTypes.richText }))((0, _handlers.handlePastePanelOrDecisionContentIntoList)(slice, findRootParentListNode)); }; }; var handlePasteNonNestableBlockNodesIntoListWithAnalytics = exports.handlePasteNonNestableBlockNodesIntoListWithAnalytics = function handlePasteNonNestableBlockNodesIntoListWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: _analytics.PasteTypes.richText, pasteSplitList: true }))((0, _handlers.handlePasteNonNestableBlockNodesIntoList)(slice)); }; }; var handleExpandWithAnalytics = exports.handleExpandWithAnalytics = function handleExpandWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: _analytics.PasteTypes.richText, pasteSplitList: true }))((0, _handlers.handleExpandPaste)(slice)); }; }; var handleNestedTablePasteWithAnalytics = exports.handleNestedTablePasteWithAnalytics = function handleNestedTablePasteWithAnalytics(editorAnalyticsAPI, isNestingTablesSupported) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: _analytics.PasteTypes.richText, pasteSplitList: true }))((0, _handlers.handleNestedTablePaste)(slice, isNestingTablesSupported)); }; }; var handleSelectedTableWithAnalytics = exports.handleSelectedTableWithAnalytics = function handleSelectedTableWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: _analytics.PasteTypes.richText }))((0, _handlers.handleSelectedTable)(editorAnalyticsAPI)(slice)); }; }; var handlePasteLinkOnSelectedTextWithAnalytics = exports.handlePasteLinkOnSelectedTextWithAnalytics = function handlePasteLinkOnSelectedTextWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, type) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: type, hyperlinkPasteOnText: true }))((0, _handlers.handlePasteLinkOnSelectedText)(slice)); }; }; var createPasteMeasurePayload = exports.createPasteMeasurePayload = function createPasteMeasurePayload(_ref3) { var view = _ref3.view, duration = _ref3.duration, content = _ref3.content, distortedDuration = _ref3.distortedDuration; var pasteIntoNode = getActionSubjectId({ selection: view.state.selection, schema: view.state.schema }); return { action: _analytics.ACTION.PASTED_TIMED, actionSubject: _analytics.ACTION_SUBJECT.EDITOR, eventType: _analytics.EVENT_TYPE.OPERATIONAL, attributes: { pasteIntoNode: pasteIntoNode, content: content, time: duration, distortedDuration: distortedDuration } }; }; var _getContentNodeTypes = exports.getContentNodeTypes = function getContentNodeTypes(content) { var nodeTypes = new Set(); if (content.size) { content.forEach(function (node) { if (node.content && node.content.size) { nodeTypes = new Set([].concat((0, _toConsumableArray2.default)(nodeTypes), (0, _toConsumableArray2.default)(_getContentNodeTypes(node.content)))); } nodeTypes.add(node.type.name); }); } return Array.from(nodeTypes); };