]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/framework/blocks/table-creator.ts
30ff3abc56caa1df99535934fdbcad0e341dbc25
[bookstack] / resources / js / wysiwyg / ui / framework / blocks / table-creator.ts
1 import {EditorUiElement} from "../core";
2 import {$createTableNodeWithDimensions} from "@lexical/table";
3 import {CustomTableNode} from "../../../nodes/custom-table";
4 import {$insertNewBlockNodeAtSelection} from "../../../utils/selection";
5 import {el} from "../../../utils/dom";
6
7
8 export class EditorTableCreator extends EditorUiElement {
9
10     buildDOM(): HTMLElement {
11         const size = 10;
12         const rows: HTMLElement[] = [];
13         const cells: HTMLElement[] = [];
14
15         for (let row = 1; row < size + 1; row++) {
16             const rowCells = [];
17             for (let column = 1; column < size + 1; column++) {
18                 const cell = el('div', {
19                     class: 'editor-table-creator-cell',
20                     'data-rows': String(row),
21                     'data-columns': String(column),
22                 });
23                 rowCells.push(cell);
24                 cells.push(cell);
25             }
26             rows.push(el('div', {
27                 class: 'editor-table-creator-row'
28             }, rowCells));
29         }
30
31         const display = el('div', {class: 'editor-table-creator-display'}, ['0 x 0']);
32         const grid = el('div', {class: 'editor-table-creator-grid'}, rows);
33         grid.addEventListener('mousemove', event => {
34             const cell = (event.target as HTMLElement).closest('.editor-table-creator-cell') as HTMLElement|null;
35             if (cell) {
36                 const row = Number(cell.dataset.rows || 0);
37                 const column = Number(cell.dataset.columns || 0);
38                 this.updateGridSelection(row, column, cells, display)
39             }
40         });
41
42         grid.addEventListener('click', event => {
43             const cell = (event.target as HTMLElement).closest('.editor-table-creator-cell');
44             if (cell) {
45                 this.onCellClick(cell as HTMLElement);
46             }
47         });
48
49         grid.addEventListener('mouseleave', event => {
50              this.updateGridSelection(0, 0, cells, display);
51         });
52
53         return el('div', {
54             class: 'editor-table-creator',
55         }, [
56             grid,
57             display,
58         ]);
59     }
60
61     updateGridSelection(rows: number, columns: number, cells: HTMLElement[], display: HTMLElement) {
62         for (const cell of cells) {
63             const active = Number(cell.dataset.rows) <= rows && Number(cell.dataset.columns) <= columns;
64             cell.classList.toggle('active', active);
65         }
66
67         display.textContent = `${rows} x ${columns}`;
68     }
69
70     onCellClick(cell: HTMLElement) {
71         const rows = Number(cell.dataset.rows || 0);
72         const columns = Number(cell.dataset.columns || 0);
73         if (rows < 1 || columns < 1) {
74             return;
75         }
76
77         const targetColWidth = Math.min(Math.round(840 / columns), 240);
78         const colWidths = Array(columns).fill(targetColWidth + 'px');
79
80         this.getContext().editor.update(() => {
81             const table = $createTableNodeWithDimensions(rows, columns, false) as CustomTableNode;
82             table.setColWidths(colWidths);
83             $insertNewBlockNodeAtSelection(table);
84         });
85     }
86 }