mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Lexical: Linked up table resize handler (unfinished)
This commit is contained in:
parent
59936631ec
commit
b1130cb1c3
@ -1,5 +1,5 @@
|
||||
import {SerializedTableNode, TableNode, TableRowNode} from "@lexical/table";
|
||||
import {DOMConversion, DOMConversionMap, DOMConversionOutput, LexicalNode, Spread} from "lexical";
|
||||
import {DOMConversion, DOMConversionMap, DOMConversionOutput, LexicalEditor, LexicalNode, Spread} from "lexical";
|
||||
import {EditorConfig} from "lexical/LexicalEditor";
|
||||
import {el} from "../helpers";
|
||||
|
||||
@ -111,6 +111,21 @@ export class CustomTableNode extends TableNode {
|
||||
}
|
||||
|
||||
function getTableColumnWidths(table: HTMLTableElement): string[] {
|
||||
const maxColRow = getMaxColRowFromTable(table);
|
||||
|
||||
const colGroup = table.querySelector('colgroup');
|
||||
let widths: string[] = [];
|
||||
if (colGroup && (colGroup.childElementCount === maxColRow?.childElementCount || !maxColRow)) {
|
||||
widths = extractWidthsFromRow(colGroup);
|
||||
}
|
||||
if (widths.filter(Boolean).length === 0 && maxColRow) {
|
||||
widths = extractWidthsFromRow(maxColRow);
|
||||
}
|
||||
|
||||
return widths;
|
||||
}
|
||||
|
||||
function getMaxColRowFromTable(table: HTMLTableElement): HTMLTableRowElement|null {
|
||||
const rows = table.querySelectorAll('tr');
|
||||
let maxColCount: number = 0;
|
||||
let maxColRow: HTMLTableRowElement|null = null;
|
||||
@ -122,16 +137,7 @@ function getTableColumnWidths(table: HTMLTableElement): string[] {
|
||||
}
|
||||
}
|
||||
|
||||
const colGroup = table.querySelector('colgroup');
|
||||
let widths: string[] = [];
|
||||
if (colGroup && colGroup.childElementCount === maxColCount) {
|
||||
widths = extractWidthsFromRow(colGroup);
|
||||
}
|
||||
if (widths.filter(Boolean).length === 0 && maxColRow) {
|
||||
widths = extractWidthsFromRow(maxColRow);
|
||||
}
|
||||
|
||||
return widths;
|
||||
return maxColRow;
|
||||
}
|
||||
|
||||
function extractWidthsFromRow(row: HTMLTableRowElement|HTMLTableColElement) {
|
||||
@ -140,7 +146,7 @@ function extractWidthsFromRow(row: HTMLTableRowElement|HTMLTableColElement) {
|
||||
|
||||
function extractWidthFromElement(element: HTMLElement): string {
|
||||
let width = element.style.width || element.getAttribute('width');
|
||||
if (!Number.isNaN(Number(width))) {
|
||||
if (width && !Number.isNaN(Number(width))) {
|
||||
width = width + 'px';
|
||||
}
|
||||
|
||||
@ -176,5 +182,23 @@ export function $setTableColumnWidth(node: CustomTableNode, columnIndex: number,
|
||||
|
||||
colWidths[columnIndex] = width + 'px';
|
||||
node.setColWidths(colWidths);
|
||||
console.log('setting col widths', node, colWidths);
|
||||
}
|
||||
|
||||
export function $getTableColumnWidth(editor: LexicalEditor, node: CustomTableNode, columnIndex: number): number {
|
||||
const colWidths = node.getColWidths();
|
||||
if (colWidths.length > columnIndex && colWidths[columnIndex].endsWith('px')) {
|
||||
return Number(colWidths[columnIndex].replace('px', ''));
|
||||
}
|
||||
|
||||
// Otherwise, get from table element
|
||||
const table = editor.getElementByKey(node.__key) as HTMLTableElement|null;
|
||||
if (table) {
|
||||
const maxColRow = getMaxColRowFromTable(table);
|
||||
if (maxColRow && maxColRow.children.length > columnIndex) {
|
||||
const cell = maxColRow.children[columnIndex];
|
||||
return cell.clientWidth;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import {LexicalEditor} from "lexical";
|
||||
import {$getNearestNodeFromDOMNode, LexicalEditor} from "lexical";
|
||||
import {el} from "../../../helpers";
|
||||
import {MouseDragTracker, MouseDragTrackerDistance} from "./mouse-drag-tracker";
|
||||
import {$getTableColumnWidth, $setTableColumnWidth, CustomTableNode} from "../../../nodes/custom-table";
|
||||
|
||||
type MarkerDomRecord = {x: HTMLElement, y: HTMLElement};
|
||||
|
||||
@ -9,6 +10,10 @@ class TableResizer {
|
||||
protected editArea: HTMLElement;
|
||||
protected markerDom: MarkerDomRecord|null = null;
|
||||
protected mouseTracker: MouseDragTracker|null = null;
|
||||
protected dragging: boolean = false;
|
||||
protected targetCell: HTMLElement|null = null;
|
||||
protected xMarkerAtStart : boolean = false;
|
||||
protected yMarkerAtStart : boolean = false;
|
||||
|
||||
constructor(editor: LexicalEditor, editArea: HTMLElement) {
|
||||
this.editor = editor;
|
||||
@ -19,7 +24,7 @@ class TableResizer {
|
||||
setupListeners() {
|
||||
this.editArea.addEventListener('mousemove', event => {
|
||||
const cell = (event.target as HTMLElement).closest('td,th');
|
||||
if (cell) {
|
||||
if (cell && !this.dragging) {
|
||||
this.onCellMouseMove(cell as HTMLElement, event);
|
||||
}
|
||||
});
|
||||
@ -29,8 +34,13 @@ class TableResizer {
|
||||
const rect = cell.getBoundingClientRect();
|
||||
const midX = rect.left + (rect.width / 2);
|
||||
const midY = rect.top + (rect.height / 2);
|
||||
const xMarkerPos = event.clientX <= midX ? rect.left : rect.right;
|
||||
const yMarkerPos = event.clientY <= midY ? rect.top : rect.bottom;
|
||||
|
||||
this.targetCell = cell;
|
||||
this.xMarkerAtStart = event.clientX <= midX;
|
||||
this.yMarkerAtStart = event.clientY <= midY;
|
||||
|
||||
const xMarkerPos = this.xMarkerAtStart ? rect.left : rect.right;
|
||||
const yMarkerPos = this.yMarkerAtStart ? rect.top : rect.bottom;
|
||||
this.updateMarkersTo(cell, xMarkerPos, yMarkerPos);
|
||||
}
|
||||
|
||||
@ -65,13 +75,68 @@ class TableResizer {
|
||||
}
|
||||
|
||||
watchMarkerMouseDrags(wrapper: HTMLElement) {
|
||||
const _this = this;
|
||||
let markerStart: number = 0;
|
||||
let markerProp: 'left' | 'top' = 'left';
|
||||
|
||||
this.mouseTracker = new MouseDragTracker(wrapper, '.editor-table-marker', {
|
||||
down(event: MouseEvent, marker: HTMLElement) {
|
||||
marker.classList.add('active');
|
||||
_this.dragging = true;
|
||||
|
||||
markerProp = marker.classList.contains('editor-table-marker-column') ? 'left' : 'top';
|
||||
markerStart = Number(marker.style[markerProp].replace('px', ''));
|
||||
},
|
||||
move(event: MouseEvent, marker: HTMLElement, distance: MouseDragTrackerDistance) {
|
||||
marker.style[markerProp] = (markerStart + distance[markerProp === 'left' ? 'x' : 'y']) + 'px';
|
||||
},
|
||||
up(event: MouseEvent, marker: HTMLElement, distance: MouseDragTrackerDistance) {
|
||||
console.log('up', distance, marker);
|
||||
// TODO - Update row/column for distance
|
||||
marker.classList.remove('active');
|
||||
marker.style.left = '0';
|
||||
marker.style.top = '0';
|
||||
|
||||
_this.dragging = false;
|
||||
console.log('up', distance, marker, markerProp, _this.targetCell);
|
||||
const parentTable = _this.targetCell?.closest('table');
|
||||
|
||||
if (markerProp === 'left' && _this.targetCell && parentTable) {
|
||||
const cellIndex = _this.getTargetCellColumnIndex();
|
||||
_this.editor.update(() => {
|
||||
const table = $getNearestNodeFromDOMNode(parentTable);
|
||||
if (table instanceof CustomTableNode) {
|
||||
const originalWidth = $getTableColumnWidth(_this.editor, table, cellIndex);
|
||||
const newWidth = Math.max(originalWidth + distance.x, 10);
|
||||
$setTableColumnWidth(table, cellIndex, newWidth);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getTargetCellColumnIndex(): number {
|
||||
const cell = this.targetCell;
|
||||
if (cell === null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let index = 0;
|
||||
const row = cell.parentElement;
|
||||
for (const rowCell of row?.children || []) {
|
||||
let size = Number(rowCell.getAttribute('colspan'));
|
||||
if (Number.isNaN(size) || size < 1) {
|
||||
size = 1;
|
||||
}
|
||||
|
||||
index += size;
|
||||
|
||||
if (rowCell === cell) {
|
||||
return index - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -169,14 +169,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.editor-table-marker-row,
|
||||
.editor-table-marker-column {
|
||||
.editor-table-marker {
|
||||
position: fixed;
|
||||
background-color: var(--editor-color-primary);
|
||||
z-index: 99;
|
||||
user-select: none;
|
||||
opacity: 0;
|
||||
&:hover {
|
||||
&:hover, &.active {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user