## Introduction

My requirement is to implement an online paper typesetting editor and export the pdf generated by LaTeX.

-- Updated --

https://github.com/facebook/draft-js/pull/2590

-- Orignial --

Project link：Eorg

Relative projects are Overleaf and Resumake.

I prefer to React.js, so I chose Draft.js, a rich text editor that was also developed for Facebook. Paper writing can't hide from table insertion, but Draft.js does not have a ready-made table plug-in. There are also a few tools for generating tables. Totally unnecessary to write another table support by my own, but it is convenient for users, and the table does not need to be too complicated. You can export a `booktabs`

-like table, so I plan to try to implement table support by myself

## Content

Idea：

A robust table is to use `new ContentBlock`

to write metadata into `block`

，which is an approach closed to Draft.js !

Relatively speaking, my implementation is more trick, which borrow from offical TeX example ，using `AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, ' ')`

API to add metadata to React.js props：

- rows and columns

```
const contentStateWithEntity = contentState.createEntity(
'TABLE',
'IMMUTABLE',
{
row, column, caption, // data
},
)
// ...
const { row, column, caption } = props // Table Component
```

- table cell

```
// createTable.js
/**
* cell = {
* 0: ["cell-0,0", "cell-0,1", ..., "cell-0,m"],
* 1: ["cell-1,0", "cell-1,1", ..., "cell-1,m"],
* ...,
* n: ["cell-n,0", "cell-n,1", ..., "cell-n,m"],
* }
*/
const cell = Object.fromEntries(Array.from(
{ length: row },
(_, i) => [
i,
Array.from({ length: column }, (_, j) => `cell-${i},${j}`)
])
)
const contentStateWithEntity = contentState.createEntity(
'TABLE',
'IMMUTABLE',
{
..., cell, // data
},
)
// ...
const { ..., cell } = props // Table Component
```

and initialize a table：

```
// TableBlock.js
// tbody -- version 1
const coordinate = []
if (row > 1) {
for (let i = 1; i < row; i += 1) {
const cols = []
for (let j = 0; j < column; j += 1) {
cols.push(
<td key={i + j} >
{cell[i][j]}
</td>,
)
}
rows.push(<tr key={i}>{cols}</tr>)
}
}
```

store

`row`

,`column`

,`caption`

,`cell`

to React.js`props`

- obtain cell coordinate：

The first idea is to calculate the Dom Node location，which means find the index of `<tr>`

at `closest('td')`

at `closest('table')`

Later, more better approach is retrive the `key`

value in `<tr>`

and `<td>`

, and its coordinate is (x1, y1):

```
// TableBlock.js
// tbody -- version 2
const coordinate = []
if (row > 1) { // thead need to calculate separately
for (let i = 1; i < row; i += 1) {
const cols = []
for (let j = 0; j < column; j += 1) {
cols.push(
<td
key={i + j} // TODO key-1
onDoubleClick={() => coordinate.push([i, j])}
>
{cell[i][j]}
</td>,
)
}
rows.push(<tr key={i}>{cols}</tr>)
}
}
```

Above key-1 is not stable，we can work with nanoid library:

```
key = {`i+j+${nanoid()}`}
```

Now it's stable and we can store cell values:

```
// find the coordinate of the node clicked
const x1 = coordinate[coordinate.length - 1][0]
const y1 = coordinate[coordinate.length - 1][1]
// update cell[i][j]
cell[x1][y1] = evt.target.innerHTML
```

cell-2,1 can be stored to props

## Summary

The table is not yet complete, for example:

- how to process cursor
- it's mutable

## Next

To support adding and deleting cell.

## Top comments (0)