scripts/core/editor3/helpers/table.ts
import {
Modifier,
ContentState,
SelectionState,
ContentBlock,
EditorState,
CompositeDecorator,
convertToRaw,
convertFromRaw,
RawDraftContentState,
} from 'draft-js';
import {OrderedSet, Map} from 'immutable';
import {LinkDecorator} from '../components/links/LinkDecorator';
import {createBlockSelection} from './selection';
/**
* @ngdoc method
* @name getCell
* @param {Array} cells The array of cells in the table
* @param {Number} row The row of the cell in the table
* @param {Number} col The column of the cell in the table
* @description Retrieves the content state of the cell at row/col.
*/
export function getCell(data: IEditor3TableData, row, col, currentStyle, selection): EditorState {
const decorator = new CompositeDecorator([LinkDecorator]);
const {cells} = data;
let cellEditorState;
if (!cells[row] || !cells[row][col]) {
cellEditorState = EditorState.createWithContent(
ContentState.createFromText(''),
decorator,
);
} else {
cellEditorState = EditorState.createWithContent(
convertFromRaw(cells[row][col]),
decorator,
);
}
if (selection != null) {
const {anchorKey, focusKey} = selection;
const cellContentState = cellEditorState.getCurrentContent();
const anchorBlock = cellContentState.getBlockForKey(anchorKey);
const focusBlock = cellContentState.getBlockForKey(focusKey);
if (anchorBlock != null && focusBlock != null) {
const newSelection = cellEditorState
.getSelection()
.merge({...selection});
cellEditorState = EditorState.forceSelection(
cellEditorState,
newSelection,
);
}
}
if (currentStyle != null) {
cellEditorState = EditorState.setInlineStyleOverride(
cellEditorState,
OrderedSet(currentStyle),
);
}
return cellEditorState;
}
/**
* @ngdoc method
* @name TableBlockComponent#setCell
* @param {Number} row The row of the cell in the table
* @param {Number} col The column of the cell in the table
* @param {Object} cellContentState The state of the editor within the cell
* @description Updates data about this cell inside the entity for this atomic
* block.
*/
export function setCell(data: IEditor3TableData, row, col, cellEditorState: EditorState) {
const cellContentState = cellEditorState.getCurrentContent();
let needUpdate = true;
let forceUpdate = true;
if (!data.cells[row]) {
data.cells[row] = [];
}
if (data.cells[row][col]) {
needUpdate =
JSON.stringify(data.cells[row][col]) !==
JSON.stringify(convertToRaw(cellContentState));
forceUpdate =
convertFromRaw(data.cells[row][col]).getPlainText() !==
cellContentState.getPlainText();
}
data.cells[row][col] = convertToRaw(cellContentState);
return {data, needUpdate, forceUpdate};
}
/**
* @ngdoc method
* @name getData
* @param {Object} contentState The editor content state
* @param {String} blockKey The current atomic block key
* @description Returns the data contained in the entity of this atomic block.
* @return {Object}
*/
export function getData(contentState: ContentState, blockKey: string) {
const block = contentState.getBlockForKey(blockKey);
const entityKey = block.getEntityAt(0);
const {data} = contentState.getEntity(entityKey).getData();
const blockData = block.getData().get('data');
if (!blockData && data) {
return data;
}
return JSON.parse(blockData);
}
export interface IEditor3TableData {
cells: Array<Array<RawDraftContentState>>;
numRows: number;
numCols: number;
withHeader: boolean;
currentStyle?: string;
}
/**
* @ngdoc method
* @name setData
* @param {Object} contentState The editor content state
* @param {Object} block The current atomic block
* @description Returns EditorState with the data contained in the entity of this atomic block.
* @return {Object}
*/
export function setData(
editorState: EditorState,
block: ContentBlock,
data: IEditor3TableData,
lastChangeType,
): EditorState {
const contentState = editorState.getCurrentContent();
const selection = createBlockSelection(editorState, block);
const newContentState = setDataForContent(contentState, selection, block, data);
const newEditorState = EditorState.push(
editorState,
newContentState,
lastChangeType,
);
return newEditorState;
}
/**
* @ngdoc method
* @name setDataForContent
* @param {Object} contentState The editor content state
* @param {Object} block The current atomic block
* @description Returns ContentState with the data contained in the entity of this atomic block.
* @return {Object}
*/
export function setDataForContent(
contentState: ContentState,
selection: SelectionState,
block: ContentBlock,
data: IEditor3TableData,
): ContentState {
const entityKey = block.getEntityAt(0);
const newContentState = Modifier.setBlockData(
contentState,
selection,
Map().set('data', JSON.stringify(data)),
);
newContentState.replaceEntityData(entityKey, {data});
return newContentState;
}