UNPKG

@atlaskit/editor-plugin-text-formatting

Version:

Text-formatting plugin for @atlaskit/editor-core

202 lines (201 loc) 7.74 kB
import { INPUT_METHOD, ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics'; import { liftTarget } from '@atlaskit/editor-prosemirror/transform'; import { CellSelection } from '@atlaskit/editor-tables/cell-selection'; import { cellSelectionNodesBetween } from './utils/cell-selection'; export const FORMATTING_NODE_TYPES = ['heading', 'blockquote']; export const FORMATTING_MARK_TYPES = ['em', 'code', 'strike', 'strong', 'underline', 'textColor', 'subsup', 'backgroundColor']; const formatTypes = { em: ACTION_SUBJECT_ID.FORMAT_ITALIC, code: ACTION_SUBJECT_ID.FORMAT_CODE, strike: ACTION_SUBJECT_ID.FORMAT_STRIKE, strong: ACTION_SUBJECT_ID.FORMAT_STRONG, underline: ACTION_SUBJECT_ID.FORMAT_UNDERLINE, textColor: ACTION_SUBJECT_ID.FORMAT_COLOR, subsup: 'subsup', backgroundColor: ACTION_SUBJECT_ID.FORMAT_BACKGROUND_COLOR }; // eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required /** * Consider removing this function when cleaning up platform_editor–toolbar_aifc * @deprecated use `clearFormattingWithAnalyticsNext` instead, which returns EditorCommand */ export function clearFormattingWithAnalytics(inputMethod, editorAnalyticsAPI) { return clearFormatting(inputMethod, editorAnalyticsAPI); } const clearNodeFormattingOnSelectionNext = (schema, tr, formattedNodeType, nodeName, formattingCleared) => { return function (node, pos) { if (node.type === formattedNodeType) { if (formattedNodeType.isTextblock) { tr.setNodeMarkup(pos, schema.nodes.paragraph); formattingCleared.push(nodeName); return false; } else { // In case of panel or blockquote const fromPos = tr.doc.resolve(pos + 1); const toPos = tr.doc.resolve(pos + node.nodeSize - 1); const nodeRange = fromPos.blockRange(toPos); if (nodeRange) { const targetLiftDepth = liftTarget(nodeRange); if (targetLiftDepth || targetLiftDepth === 0) { formattingCleared.push(nodeName); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion tr.lift(nodeRange, targetLiftDepth); } } } } return true; }; }; function clearNodeFormattingOnSelection(state, tr, formattedNodeType, nodeName, formattingCleared) { return function (node, pos) { if (node.type === formattedNodeType) { if (formattedNodeType.isTextblock) { tr.setNodeMarkup(pos, state.schema.nodes.paragraph); formattingCleared.push(nodeName); return false; } else { // In case of panel or blockquote const fromPos = tr.doc.resolve(pos + 1); const toPos = tr.doc.resolve(pos + node.nodeSize - 1); const nodeRange = fromPos.blockRange(toPos); if (nodeRange) { const targetLiftDepth = liftTarget(nodeRange); if (targetLiftDepth || targetLiftDepth === 0) { formattingCleared.push(nodeName); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion tr.lift(nodeRange, targetLiftDepth); } } } } return true; }; } export function clearFormatting(inputMethod, editorAnalyticsAPI) { return function (state, dispatch) { const { tr } = state; const formattingCleared = []; FORMATTING_MARK_TYPES.forEach(mark => { const { from, to } = tr.selection; const markType = state.schema.marks[mark]; if (!markType) { return; } if (tr.selection instanceof CellSelection) { cellSelectionNodesBetween(tr.selection, tr.doc, (node, pos) => { const isTableCell = node.type === state.schema.nodes.tableCell || node.type === state.schema.nodes.tableHeader; if (!isTableCell) { return true; } if (tr.doc.rangeHasMark(pos, pos + node.nodeSize, markType)) { formattingCleared.push(formatTypes[mark]); tr.removeMark(pos, pos + node.nodeSize, markType); } return false; }); } else if (tr.doc.rangeHasMark(from, to, markType)) { formattingCleared.push(formatTypes[mark]); tr.removeMark(from, to, markType); } }); FORMATTING_NODE_TYPES.forEach(nodeName => { const formattedNodeType = state.schema.nodes[nodeName]; const { $from, $to } = tr.selection; if (tr.selection instanceof CellSelection) { cellSelectionNodesBetween(tr.selection, tr.doc, clearNodeFormattingOnSelection(state, tr, formattedNodeType, nodeName, formattingCleared)); } else { tr.doc.nodesBetween($from.pos, $to.pos, clearNodeFormattingOnSelection(state, tr, formattedNodeType, nodeName, formattingCleared)); } }); tr.setStoredMarks([]); if (formattingCleared.length && inputMethod) { editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({ action: ACTION.FORMATTED, eventType: EVENT_TYPE.TRACK, actionSubject: ACTION_SUBJECT.TEXT, actionSubjectId: ACTION_SUBJECT_ID.FORMAT_CLEAR, attributes: { inputMethod, formattingCleared, dropdownMenu: inputMethod === INPUT_METHOD.TOOLBAR || inputMethod === INPUT_METHOD.FLOATING_TB ? 'textFormatting' : undefined } })(tr); } if (dispatch) { dispatch(tr); } return true; }; } export const clearFormattingWithAnalyticsNext = editorAnalyticsApi => inputMethod => ({ tr }) => { const formattingCleared = []; const { schema } = tr.doc.type; FORMATTING_MARK_TYPES.forEach(mark => { const { from, to } = tr.selection; const markType = schema.marks[mark]; if (!markType) { return; } if (tr.selection instanceof CellSelection) { cellSelectionNodesBetween(tr.selection, tr.doc, (node, pos) => { const isTableCell = node.type === tr.doc.type.schema.nodes.tableCell || node.type === schema.nodes.tableHeader; if (!isTableCell) { return true; } if (tr.doc.rangeHasMark(pos, pos + node.nodeSize, markType)) { formattingCleared.push(formatTypes[mark]); tr.removeMark(pos, pos + node.nodeSize, markType); } return false; }); } else if (tr.doc.rangeHasMark(from, to, markType)) { formattingCleared.push(formatTypes[mark]); tr.removeMark(from, to, markType); } }); FORMATTING_NODE_TYPES.forEach(nodeName => { const formattedNodeType = schema.nodes[nodeName]; const { $from, $to } = tr.selection; if (tr.selection instanceof CellSelection) { cellSelectionNodesBetween(tr.selection, tr.doc, clearNodeFormattingOnSelectionNext(schema, tr, formattedNodeType, nodeName, formattingCleared)); } else { tr.doc.nodesBetween($from.pos, $to.pos, clearNodeFormattingOnSelectionNext(schema, tr, formattedNodeType, nodeName, formattingCleared)); } }); tr.setStoredMarks([]); if (formattingCleared.length && inputMethod) { editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent({ action: ACTION.FORMATTED, eventType: EVENT_TYPE.TRACK, actionSubject: ACTION_SUBJECT.TEXT, actionSubjectId: ACTION_SUBJECT_ID.FORMAT_CLEAR, attributes: { inputMethod, formattingCleared, dropdownMenu: inputMethod === INPUT_METHOD.TOOLBAR || inputMethod === INPUT_METHOD.FLOATING_TB ? 'textFormatting' : undefined } })(tr); } return tr; };