X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/a27a325af77e31a184cdb33dc05cb658de697e0b..refs/pull/5313/head:/resources/js/wysiwyg/nodes/custom-table.ts diff --git a/resources/js/wysiwyg/nodes/custom-table.ts b/resources/js/wysiwyg/nodes/custom-table.ts index 7dda24a7a..c25c06c65 100644 --- a/resources/js/wysiwyg/nodes/custom-table.ts +++ b/resources/js/wysiwyg/nodes/custom-table.ts @@ -1,16 +1,27 @@ -import {SerializedTableNode, TableNode, TableRowNode} from "@lexical/table"; -import {DOMConversion, DOMConversionMap, DOMConversionOutput, LexicalEditor, LexicalNode, Spread} from "lexical"; +import {SerializedTableNode, TableNode} from "@lexical/table"; +import {DOMConversion, DOMConversionMap, DOMConversionOutput, LexicalNode, Spread} from "lexical"; import {EditorConfig} from "lexical/LexicalEditor"; -import {el} from "../helpers"; -export type SerializedCustomTableNode = Spread<{ - id: string; +import {el, extractStyleMapFromElement, StyleMap} from "../utils/dom"; +import {getTableColumnWidths} from "../utils/tables"; +import { + CommonBlockAlignment, deserializeCommonBlockNode, + SerializedCommonBlockNode, + setCommonBlockPropsFromElement, + updateElementWithCommonBlockProps +} from "./_common"; + +export type SerializedCustomTableNode = Spread + styles: Record, +}, SerializedTableNode>, SerializedCommonBlockNode> export class CustomTableNode extends TableNode { __id: string = ''; __colWidths: string[] = []; + __styles: StyleMap = new Map; + __alignment: CommonBlockAlignment = ''; + __inset: number = 0; static getType() { return 'custom-table'; @@ -26,6 +37,26 @@ export class CustomTableNode extends TableNode { return self.__id; } + setAlignment(alignment: CommonBlockAlignment) { + const self = this.getWritable(); + self.__alignment = alignment; + } + + getAlignment(): CommonBlockAlignment { + const self = this.getLatest(); + return self.__alignment; + } + + setInset(size: number) { + const self = this.getWritable(); + self.__inset = size; + } + + getInset(): number { + const self = this.getLatest(); + return self.__inset; + } + setColWidths(widths: string[]) { const self = this.getWritable(); self.__colWidths = widths; @@ -36,19 +67,29 @@ export class CustomTableNode extends TableNode { return self.__colWidths; } + getStyles(): StyleMap { + const self = this.getLatest(); + return new Map(self.__styles); + } + + setStyles(styles: StyleMap): void { + const self = this.getWritable(); + self.__styles = new Map(styles); + } + static clone(node: CustomTableNode) { const newNode = new CustomTableNode(node.__key); newNode.__id = node.__id; newNode.__colWidths = node.__colWidths; + newNode.__styles = new Map(node.__styles); + newNode.__alignment = node.__alignment; + newNode.__inset = node.__inset; return newNode; } createDOM(config: EditorConfig): HTMLElement { const dom = super.createDOM(config); - const id = this.getId(); - if (id) { - dom.setAttribute('id', id); - } + updateElementWithCommonBlockProps(dom, this); const colWidths = this.getColWidths(); if (colWidths.length > 0) { @@ -63,6 +104,10 @@ export class CustomTableNode extends TableNode { dom.append(colgroup); } + for (const [name, value] of this.__styles.entries()) { + dom.style.setProperty(name, value); + } + return dom; } @@ -77,13 +122,17 @@ export class CustomTableNode extends TableNode { version: 1, id: this.__id, colWidths: this.__colWidths, + styles: Object.fromEntries(this.__styles), + alignment: this.__alignment, + inset: this.__inset, }; } static importJSON(serializedNode: SerializedCustomTableNode): CustomTableNode { const node = $createCustomTableNode(); - node.setId(serializedNode.id); + deserializeCommonBlockNode(serializedNode, node); node.setColWidths(serializedNode.colWidths); + node.setStyles(new Map(Object.entries(serializedNode.styles))); return node; } @@ -93,13 +142,11 @@ export class CustomTableNode extends TableNode { return { conversion: (element: HTMLElement): DOMConversionOutput|null => { const node = $createCustomTableNode(); - - if (element.id) { - node.setId(element.id); - } + setCommonBlockPropsFromElement(element, node); const colWidths = getTableColumnWidths(element as HTMLTableElement); node.setColWidths(colWidths); + node.setStyles(extractStyleMapFromElement(element)); return {node}; }, @@ -110,49 +157,6 @@ 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; - - for (const row of rows) { - if (row.childElementCount > maxColCount) { - maxColRow = row; - maxColCount = row.childElementCount; - } - } - - return maxColRow; -} - -function extractWidthsFromRow(row: HTMLTableRowElement|HTMLTableColElement) { - return [...row.children].map(child => extractWidthFromElement(child as HTMLElement)) -} - -function extractWidthFromElement(element: HTMLElement): string { - let width = element.style.width || element.getAttribute('width'); - if (width && !Number.isNaN(Number(width))) { - width = width + 'px'; - } - - return width || ''; -} - export function $createCustomTableNode(): CustomTableNode { return new CustomTableNode(); } @@ -160,45 +164,3 @@ export function $createCustomTableNode(): CustomTableNode { export function $isCustomTableNode(node: LexicalNode | null | undefined): node is CustomTableNode { return node instanceof CustomTableNode; } - -export function $setTableColumnWidth(node: CustomTableNode, columnIndex: number, width: number): void { - const rows = node.getChildren() as TableRowNode[]; - let maxCols = 0; - for (const row of rows) { - const cellCount = row.getChildren().length; - if (cellCount > maxCols) { - maxCols = cellCount; - } - } - - let colWidths = node.getColWidths(); - if (colWidths.length === 0 || colWidths.length < maxCols) { - colWidths = Array(maxCols).fill(''); - } - - if (columnIndex + 1 > colWidths.length) { - console.error(`Attempted to set table column width for column [${columnIndex}] but only ${colWidths.length} columns found`); - } - - colWidths[columnIndex] = width + 'px'; - node.setColWidths(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; -} \ No newline at end of file