@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
510 lines (509 loc) • 17.3 kB
JavaScript
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)));