UNPKG

@atlaskit/editor-plugin-paste

Version:

Paste plugin for @atlaskit/editor-core

416 lines (413 loc) 20.7 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; 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) { _defineProperty(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; } import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD, PasteContents, PasteTypes } from '@atlaskit/editor-common/analytics'; import { getLinkDomain, mapSlice } from '@atlaskit/editor-common/utils'; import { findParentNode } from '@atlaskit/editor-prosemirror/utils'; import { getPasteSource } from './util'; import { handleCodeBlock, handleExpandPaste, handleMarkdown, handleMediaSingle, handlePasteAsPlainText, handlePasteIntoCaption, handlePasteIntoTaskOrDecisionOrPanel, handlePasteLinkOnSelectedText, handlePasteNonNestableBlockNodesIntoList, handlePastePanelOrDecisionContentIntoList, handlePastePreservingMarks, handleRichText, handleSelectedTable, handleNestedTablePaste } from './util/handlers'; var contentToPasteContent = { url: PasteContents.url, paragraph: PasteContents.text, bulletList: PasteContents.bulletList, orderedList: PasteContents.orderedList, heading: PasteContents.heading, blockquote: PasteContents.blockquote, codeBlock: PasteContents.codeBlock, panel: PasteContents.panel, rule: PasteContents.rule, mediaSingle: PasteContents.mediaSingle, mediaCard: PasteContents.mediaCard, mediaGroup: PasteContents.mediaGroup, table: PasteContents.table, tableCells: PasteContents.tableCells, tableHeader: PasteContents.tableHeader, tableRow: PasteContents.tableRow, decisionList: PasteContents.decisionList, decisionItem: PasteContents.decisionItem, taskList: PasteContents.taskItem, extension: PasteContents.extension, bodiedExtension: PasteContents.bodiedExtension, blockCard: PasteContents.blockCard, layoutSection: PasteContents.layoutSection }; var nodeToActionSubjectId = { blockquote: ACTION_SUBJECT_ID.PASTE_BLOCKQUOTE, blockCard: ACTION_SUBJECT_ID.PASTE_BLOCK_CARD, bodiedExtension: ACTION_SUBJECT_ID.PASTE_BODIED_EXTENSION, bulletList: ACTION_SUBJECT_ID.PASTE_BULLET_LIST, codeBlock: ACTION_SUBJECT_ID.PASTE_CODE_BLOCK, decisionList: ACTION_SUBJECT_ID.PASTE_DECISION_LIST, extension: ACTION_SUBJECT_ID.PASTE_EXTENSION, heading: ACTION_SUBJECT_ID.PASTE_HEADING, mediaGroup: ACTION_SUBJECT_ID.PASTE_MEDIA_GROUP, mediaSingle: ACTION_SUBJECT_ID.PASTE_MEDIA_SINGLE, orderedList: ACTION_SUBJECT_ID.PASTE_ORDERED_LIST, panel: ACTION_SUBJECT_ID.PASTE_PANEL, rule: ACTION_SUBJECT_ID.PASTE_RULE, table: ACTION_SUBJECT_ID.PASTE_TABLE, tableCell: ACTION_SUBJECT_ID.PASTE_TABLE_CELL, tableHeader: ACTION_SUBJECT_ID.PASTE_TABLE_HEADER, tableRow: ACTION_SUBJECT_ID.PASTE_TABLE_ROW, taskList: ACTION_SUBJECT_ID.PASTE_TASK_LIST }; export 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 PasteContents.mixed; } if (nodeOrMarkName.size === 0) { return PasteContents.uncategorized; } var type = nodeOrMarkName.values().next().value; // @ts-ignore - TS2538 TypeScript 5.9.2 upgrade var pasteContent = contentToPasteContent[type]; return pasteContent ? pasteContent : PasteContents.uncategorized; } export function getMediaTraceId(slice) { var traceId; 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 = findParentNode(function (node) { if (node.type !== paragraph && node.type !== listItem && node.type !== taskItem && node.type !== decisionItem) { return true; } return false; })(selection); if (!parent) { return ACTION_SUBJECT_ID.PASTE_PARAGRAPH; } var parentType = parent.node.type; var actionSubjectId = nodeToActionSubjectId[parentType.name]; return actionSubjectId ? actionSubjectId : ACTION_SUBJECT_ID.PASTE_PARAGRAPH; } function createPasteAsPlainPayload(actionSubjectId, text, linksInPasteCount) { return { action: ACTION.PASTED_AS_PLAIN, actionSubject: ACTION_SUBJECT.DOCUMENT, actionSubjectId: actionSubjectId, eventType: EVENT_TYPE.TRACK, attributes: { inputMethod: INPUT_METHOD.KEYBOARD, pasteSize: text.length, linksInPasteCount: linksInPasteCount } }; } function createPastePayload(actionSubjectId, attributes, linkDomain) { return _objectSpread({ action: ACTION.PASTED, actionSubject: ACTION_SUBJECT.DOCUMENT, actionSubjectId: actionSubjectId, eventType: EVENT_TYPE.TRACK, attributes: _objectSpread({ inputMethod: 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 === PasteContents.url || content === PasteContents.mixed) { 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 = 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 === PasteTypes.plain) { return createPastePayload(actionSubjectId, { pasteSize: text.length, type: pasteContext.type, content: PasteContents.text, source: source, hyperlinkPasteOnText: false, linksInPasteCount: linkUrls.length, mentionIds: mentionIds, mentionLocalIds: mentionLocalIds, pasteSplitList: pasteContext.pasteSplitList }); } var linkDomains = linkUrls.map(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); }; } export 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. export var 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); }; }; export var handlePasteAsPlainTextWithAnalytics = function handlePasteAsPlainTextWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: PasteTypes.plain, asPlain: true }))(handlePasteAsPlainText(slice, event, editorAnalyticsAPI)); }; }; export var 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 }))(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)); }; export var handlePasteIntoCaptionWithAnalytics = function handlePasteIntoCaptionWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, type) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: type }))(handlePasteIntoCaption(slice)); }; }; export var handleCodeBlockWithAnalytics = function handleCodeBlockWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, text) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: PasteTypes.plain }))(handleCodeBlock(text)); }; }; export var handleMediaSingleWithAnalytics = function handleMediaSingleWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, type, insertMediaAsMediaSingle) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: type }))(handleMediaSingle(INPUT_METHOD.CLIPBOARD, insertMediaAsMediaSingle)(slice)); }; }; export var 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 }))(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)); }; export var 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: PasteTypes.markdown }))(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)); }; export var 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: PasteTypes.richText }, pluginInjectionApi))(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; }; }; }; }; export var handlePastePanelOrDecisionIntoListWithAnalytics = function handlePastePanelOrDecisionIntoListWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, findRootParentListNode) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: PasteTypes.richText }))(handlePastePanelOrDecisionContentIntoList(slice, findRootParentListNode)); }; }; export var handlePasteNonNestableBlockNodesIntoListWithAnalytics = function handlePasteNonNestableBlockNodesIntoListWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: PasteTypes.richText, pasteSplitList: true }))(handlePasteNonNestableBlockNodesIntoList(slice)); }; }; export var handleExpandWithAnalytics = function handleExpandWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: PasteTypes.richText, pasteSplitList: true }))(handleExpandPaste(slice)); }; }; export var handleNestedTablePasteWithAnalytics = function handleNestedTablePasteWithAnalytics(editorAnalyticsAPI, isNestingTablesSupported) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: PasteTypes.richText, pasteSplitList: true }))(handleNestedTablePaste(slice, isNestingTablesSupported)); }; }; export var handleSelectedTableWithAnalytics = function handleSelectedTableWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: PasteTypes.richText }))(handleSelectedTable(editorAnalyticsAPI)(slice)); }; }; export var handlePasteLinkOnSelectedTextWithAnalytics = function handlePasteLinkOnSelectedTextWithAnalytics(editorAnalyticsAPI) { return function (view, event, slice, type) { return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, { type: type, hyperlinkPasteOnText: true }))(handlePasteLinkOnSelectedText(slice)); }; }; export var 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: ACTION.PASTED_TIMED, actionSubject: ACTION_SUBJECT.EDITOR, eventType: EVENT_TYPE.OPERATIONAL, attributes: { pasteIntoNode: pasteIntoNode, content: content, time: duration, distortedDuration: distortedDuration } }; }; var _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(_toConsumableArray(nodeTypes), _toConsumableArray(_getContentNodeTypes(node.content)))); } nodeTypes.add(node.type.name); }); } return Array.from(nodeTypes); }; export { _getContentNodeTypes as getContentNodeTypes };