UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

510 lines (509 loc) 17.3 kB
import { tableBackgroundColorPalette } from '@atlaskit/adf-schema'; import { ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD, TABLE_ACTION, TABLE_DISPLAY_MODE } from '@atlaskit/editor-common/analytics'; import { editorCommandToPMCommand } from '@atlaskit/editor-common/preset'; import { CellSelection } from '@atlaskit/editor-tables/cell-selection'; import { TableMap } from '@atlaskit/editor-tables/table-map'; import { findCellClosestToPos, findCellRectClosestToPos, getSelectionRect } from '@atlaskit/editor-tables/utils'; import { getPluginState } from '../plugin-factory'; import { distributeColumnsWidths } from '../table-resizing/commands'; import { deleteRows } from '../transforms/delete-rows'; import { mergeCells } from '../transforms/merge'; import { withEditorAnalyticsAPI, getSelectedCellInfo, getSelectedTableInfo } from '../utils/analytics'; import { checkIfNumberColumnEnabled } from '../utils/nodes'; import { clearMultipleCells } from './clear'; import { wrapTableInExpand } from './collapse'; import { changeColumnWidthByStep } from './column-resize'; import { deleteColumnsCommand } from './delete'; import { setTableDisplayMode } from './display-mode'; import { insertColumn, insertRow } from './insert'; import { deleteTable, deleteTableIfSelected, getTableSelectionType, setMultipleCellAttrs, setTableAlignment, setTableAlignmentWithTableContentWithPos } from './misc'; import { sortByColumn } from './sort'; import { splitCell } from './split-cell'; import { toggleHeaderColumn, toggleHeaderRow, toggleNumberColumn } from './toggle'; // #region Analytics wrappers export const emptyMultipleCellsWithAnalytics = editorAnalyticsAPI => (inputMethod, targetCellPosition) => withEditorAnalyticsAPI(({ selection }) => { const { horizontalCells, verticalCells, totalRowCount, totalColumnCount } = getSelectedCellInfo(selection); return { action: TABLE_ACTION.CLEARED, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { inputMethod, horizontalCells, verticalCells, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(clearMultipleCells(targetCellPosition)); export const mergeCellsWithAnalytics = editorAnalyticsAPI => inputMethod => withEditorAnalyticsAPI(({ selection }) => { const { horizontalCells, verticalCells, totalCells, totalRowCount, totalColumnCount } = getSelectedCellInfo(selection); return { action: TABLE_ACTION.MERGED, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { inputMethod, horizontalCells, verticalCells, totalCells, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)((state, dispatch) => { if (dispatch) { dispatch(mergeCells(state.tr)); } return true; }); export const splitCellWithAnalytics = editorAnalyticsAPI => inputMethod => withEditorAnalyticsAPI(({ selection }) => { const { totalRowCount, totalColumnCount } = getSelectedCellInfo(selection); const cell = findCellClosestToPos(selection.$anchor); if (cell) { const { rowspan: verticalCells, colspan: horizontalCells } = cell.node.attrs; return { action: TABLE_ACTION.SPLIT, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { inputMethod, horizontalCells, verticalCells, totalCells: horizontalCells * verticalCells, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; } return; })(editorAnalyticsAPI)(splitCell); export const setColorWithAnalytics = editorAnalyticsAPI => (inputMethod, cellColor, editorView) => withEditorAnalyticsAPI(({ selection }) => { const { horizontalCells, verticalCells, totalCells, totalRowCount, totalColumnCount } = getSelectedCellInfo(selection); return { action: TABLE_ACTION.COLORED, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { inputMethod, cellColor: (tableBackgroundColorPalette.get(cellColor.toLowerCase()) || cellColor).toLowerCase(), horizontalCells, verticalCells, totalCells, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(setMultipleCellAttrs({ background: cellColor }, editorView)); export const addRowAroundSelection = editorAnalyticsAPI => side => (state, dispatch) => { const { selection } = state; const isCellSelection = selection instanceof CellSelection; const rect = isCellSelection ? getSelectionRect(selection) : findCellRectClosestToPos(selection.$from); if (!rect) { return false; } const position = isCellSelection && side === 'TOP' ? rect.top : rect.bottom - 1; const offset = side === 'BOTTOM' ? 1 : 0; return insertRowWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.SHORTCUT, { index: position + offset, moveCursorToInsertedRow: false })(state, dispatch); }; export const insertRowWithAnalytics = editorAnalyticsAPI => (inputMethod, options) => withEditorAnalyticsAPI(state => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); return { action: TABLE_ACTION.ADDED_ROW, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { inputMethod, position: options.index, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(insertRow(options.index, options.moveCursorToInsertedRow)); export const changeColumnWidthByStepWithAnalytics = (editorAnalyticsAPI, api) => (stepSize, getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, isCommentEditor, inputMethod, ariaNotify, getIntl) => withEditorAnalyticsAPI(state => { const { table, totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); const { hoveredCell: { colIndex } } = getPluginState(state); return { action: TABLE_ACTION.COLUMN_RESIZED, actionSubject: ACTION_SUBJECT.TABLE, eventType: EVENT_TYPE.TRACK, attributes: { colIndex, resizedDelta: stepSize, isLastColumn: colIndex === totalColumnCount - 1, tableWidth: table === null || table === void 0 ? void 0 : table.node.attrs.width, inputMethod, totalRowCount, totalColumnCount } }; })(editorAnalyticsAPI)(changeColumnWidthByStep({ stepSize: stepSize, getEditorContainerWidth: getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, isCommentEditor, ariaNotify: ariaNotify, getIntl: getIntl, api })); export const insertColumnWithAnalytics = (api, editorAnalyticsAPI, isTableScalingEnabled = false, isTableFixedColumnWidthsOptionEnabled = false, shouldUseIncreasedScalingPercent = false, isCommentEditor = false) => (inputMethod, position) => withEditorAnalyticsAPI(state => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); return { action: TABLE_ACTION.ADDED_COLUMN, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { inputMethod, position, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(insertColumn(api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor)(position)); export const deleteRowsWithAnalytics = editorAnalyticsAPI => (inputMethod, rect, isHeaderRowRequired) => withEditorAnalyticsAPI(({ selection }) => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(selection); return { action: TABLE_ACTION.DELETED_ROW, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { inputMethod, position: rect.top, count: rect.bottom - rect.top, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)((state, dispatch) => { if (dispatch) { dispatch(deleteRows(rect, isHeaderRowRequired)(state.tr)); } return true; }); export const deleteColumnsWithAnalytics = (editorAnalyticsAPI, api, isTableScalingEnabled = false, isTableFixedColumnWidthsOptionEnabled = false, shouldUseIncreasedScalingPercent = false, isCommentEditor = false) => (inputMethod, rect) => withEditorAnalyticsAPI(({ selection }) => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(selection); return { action: TABLE_ACTION.DELETED_COLUMN, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { inputMethod, position: rect.left, count: rect.right - rect.left, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(deleteColumnsCommand(rect, api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor)); export const deleteSelectedRowsOrColumnsWithAnalyticsViaShortcut = (editorAnalyticsAPI, api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent) => (state, dispatch) => { const { selection } = state; const isCellSelection = selection instanceof CellSelection; if (!isCellSelection) { return false; } const rect = getSelectionRect(selection); if (!rect) { return false; } const selectionType = getTableSelectionType(selection); if (selectionType === 'row') { const { pluginConfig } = getPluginState(state); const isHeaderRowRequired = pluginConfig.isHeaderRowRequired || false; return deleteRowsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.SHORTCUT, rect, isHeaderRowRequired)(state, dispatch); } else if (selectionType === 'column') { return deleteColumnsWithAnalytics(editorAnalyticsAPI, api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent)(INPUT_METHOD.SHORTCUT, rect)(state, dispatch); } else { return false; } }; const getTableDeletedAnalytics = (selection, inputMethod) => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(selection); return { action: TABLE_ACTION.DELETED, actionSubject: ACTION_SUBJECT.TABLE, attributes: { inputMethod, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; }; export const deleteTableWithAnalytics = editorAnalyticsAPI => withEditorAnalyticsAPI(({ selection }) => getTableDeletedAnalytics(selection, INPUT_METHOD.FLOATING_TB))(editorAnalyticsAPI)(deleteTable); export const deleteTableIfSelectedWithAnalytics = editorAnalyticsAPI => inputMethod => withEditorAnalyticsAPI(({ selection }) => getTableDeletedAnalytics(selection, inputMethod))(editorAnalyticsAPI)(deleteTableIfSelected); export const toggleHeaderRowWithAnalytics = editorAnalyticsAPI => withEditorAnalyticsAPI(state => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); const { isHeaderRowEnabled } = getPluginState(state); return { action: TABLE_ACTION.TOGGLED_HEADER_ROW, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { newState: !isHeaderRowEnabled, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(toggleHeaderRow); export const toggleHeaderColumnWithAnalytics = editorAnalyticsAPI => withEditorAnalyticsAPI(state => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); const { isHeaderColumnEnabled } = getPluginState(state); return { action: TABLE_ACTION.TOGGLED_HEADER_COLUMN, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { newState: !isHeaderColumnEnabled, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(toggleHeaderColumn); export const toggleNumberColumnWithAnalytics = editorAnalyticsAPI => withEditorAnalyticsAPI(state => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); return { action: TABLE_ACTION.TOGGLED_NUMBER_COLUMN, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { newState: !checkIfNumberColumnEnabled(state.selection), totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(toggleNumberColumn); export const sortColumnWithAnalytics = editorAnalyticsAPI => (inputMethod, columnIndex, sortOrder) => withEditorAnalyticsAPI(state => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); return { action: TABLE_ACTION.SORTED_COLUMN, actionSubject: ACTION_SUBJECT.TABLE, attributes: { inputMethod, totalRowCount, totalColumnCount, position: columnIndex, sortOrder, mode: 'editor' }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(sortByColumn(columnIndex, sortOrder)); export const distributeColumnsWidthsWithAnalytics = (editorAnalyticsAPI, api) => (inputMethod, { resizeState, table, attributes }) => { return withEditorAnalyticsAPI(() => { return { action: TABLE_ACTION.DISTRIBUTED_COLUMNS_WIDTHS, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { inputMethod, ...attributes }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)((state, dispatch) => { if (dispatch) { distributeColumnsWidths(resizeState, table, api)(state, dispatch); } return true; }); }; export const wrapTableInExpandWithAnalytics = editorAnalyticsAPI => withEditorAnalyticsAPI(state => { const { totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); return { action: TABLE_ACTION.COLLAPSED, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(wrapTableInExpand); export const toggleFixedColumnWidthsOptionAnalytics = (editorAnalyticsAPI, inputMethod) => withEditorAnalyticsAPI(state => { const { table, totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); let previousDisplayMode; let newDisplayMode; switch (table === null || table === void 0 ? void 0 : table.node.attrs.displayMode) { case 'fixed': previousDisplayMode = TABLE_DISPLAY_MODE.FIXED; newDisplayMode = TABLE_DISPLAY_MODE.DEFAULT; break; case 'default': previousDisplayMode = TABLE_DISPLAY_MODE.DEFAULT; newDisplayMode = TABLE_DISPLAY_MODE.FIXED; break; case null: default: previousDisplayMode = TABLE_DISPLAY_MODE.INITIAL; newDisplayMode = TABLE_DISPLAY_MODE.FIXED; } return { action: TABLE_ACTION.CHANGED_DISPLAY_MODE, actionSubject: ACTION_SUBJECT.TABLE, attributes: { inputMethod, previousDisplayMode, newDisplayMode, tableWidth: table === null || table === void 0 ? void 0 : table.node.attrs.width, totalRowCount, totalColumnCount }, eventType: EVENT_TYPE.TRACK }; })(editorAnalyticsAPI)(editorCommandToPMCommand(setTableDisplayMode)); export const setTableAlignmentWithAnalytics = (editorAnalyticsAPI, isCommentEditor) => (newAlignment, previousAlignment, inputMethod, reason) => withEditorAnalyticsAPI(state => { const { table, totalRowCount, totalColumnCount } = getSelectedTableInfo(state.selection); return { action: TABLE_ACTION.CHANGED_ALIGNMENT, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, eventType: EVENT_TYPE.TRACK, attributes: { tableWidth: table === null || table === void 0 ? void 0 : table.node.attrs.width, newAlignment, previousAlignment: previousAlignment === 'center' || previousAlignment === 'align-start' ? previousAlignment : null, totalRowCount, totalColumnCount, inputMethod, reason } }; })(editorAnalyticsAPI)(editorCommandToPMCommand(setTableAlignment(newAlignment, isCommentEditor))); export const setTableAlignmentWithTableContentWithPosWithAnalytics = editorAnalyticsAPI => (newAlignment, previousAlignment, tableNodeWithPos, inputMethod, reason) => withEditorAnalyticsAPI(() => { const map = TableMap.get(tableNodeWithPos.node); const totalRowCount = map.height; const totalColumnCount = map.width; const attributes = { tableWidth: tableNodeWithPos.node.attrs.width, newAlignment: newAlignment, previousAlignment: previousAlignment, totalRowCount: totalRowCount, totalColumnCount: totalColumnCount, inputMethod: inputMethod, reason: reason }; return { action: TABLE_ACTION.CHANGED_ALIGNMENT, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, eventType: EVENT_TYPE.TRACK, attributes: attributes }; })(editorAnalyticsAPI)(editorCommandToPMCommand(setTableAlignmentWithTableContentWithPos(newAlignment, tableNodeWithPos)));