diff --git a/services/web/frontend/js/features/source-editor/components/table-generator/utils.ts b/services/web/frontend/js/features/source-editor/components/table-generator/utils.ts index 86872c987e..7842a80586 100644 --- a/services/web/frontend/js/features/source-editor/components/table-generator/utils.ts +++ b/services/web/frontend/js/features/source-editor/components/table-generator/utils.ts @@ -451,6 +451,27 @@ export function generateTable( } } +export const validateParsedTable = (parseResult: ParsedTableData) => { + for (const row of parseResult.table.rows) { + const rowLength = row.cells.reduce( + (acc, cell) => acc + (cell.multiColumn?.columnSpan ?? 1), + 0 + ) + for (const cell of row.cells) { + if ( + cell.multiColumn?.columns.specification && + cell.multiColumn.columns.specification.length !== 1 + ) { + return false + } + } + if (rowLength !== parseResult.table.columns.length) { + return false + } + } + return true +} + export function parseTableEnvironment(tableNode: SyntaxNode) { const tableEnvironment: TableEnvironmentData = { table: { from: tableNode.from, to: tableNode.to }, diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts b/services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts index 9e520394f1..5bd75cf5f2 100644 --- a/services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts +++ b/services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts @@ -67,6 +67,12 @@ import { TableRenderingErrorWidget } from './visual-widgets/table-rendering-erro import { GraphicsWidget } from './visual-widgets/graphics' import { InlineGraphicsWidget } from './visual-widgets/inline-graphics' import { PreviewPath } from '../../../../../../types/preview-path' +import { + generateTable, + ParsedTableData, + validateParsedTable, +} from '../../components/table-generator/utils' +import { debugConsole } from '@/utils/debugging' type Options = { previewByPath: (path: string) => PreviewPath | null @@ -324,21 +330,29 @@ export const atomicDecorations = (options: Options) => { tabularNode.parent, tableNode ) - const tabularWidget = new TabularWidget( - tabularNode, - state.doc.sliceString( - (tableNode ?? tabularNode).from, - (tableNode ?? tabularNode).to - ), - tableNode, - directChild, - state - ) - if (tabularWidget.isValid()) { + let parsedTableData: ParsedTableData | null = null + let validTable = false + try { + parsedTableData = generateTable(tabularNode, state) + validTable = validateParsedTable(parsedTableData) + } catch (e) { + debugConsole.error(e) + } + + if (parsedTableData && validTable) { decorations.push( Decoration.replace({ - widget: tabularWidget, + widget: new TabularWidget( + parsedTableData, + tabularNode, + state.doc.sliceString( + (tableNode ?? tabularNode).from, + (tableNode ?? tabularNode).to + ), + tableNode, + directChild + ), block: true, }).range(nodeRef.from, nodeRef.to) ) diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/tabular.tsx b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/tabular.tsx index 7ec606570b..ae286cf025 100644 --- a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/tabular.tsx +++ b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/tabular.tsx @@ -1,77 +1,37 @@ import { EditorView, WidgetType } from '@codemirror/view' -import { EditorState } from '@codemirror/state' import { SyntaxNode } from '@lezer/common' import * as ReactDOM from 'react-dom' import { Tabular } from '../../../components/table-generator/tabular' -import { - ParsedTableData, - generateTable, -} from '../../../components/table-generator/utils' -import { debugConsole } from '@/utils/debugging' +import { ParsedTableData } from '../../../components/table-generator/utils' export class TabularWidget extends WidgetType { - private element: HTMLElement | undefined - private readonly parseResult: ParsedTableData | null = null - constructor( + private parsedTableData: ParsedTableData, private tabularNode: SyntaxNode, private content: string, private tableNode: SyntaxNode | null, - private isDirectChildOfTableEnvironment: boolean, - state: EditorState + private isDirectChildOfTableEnvironment: boolean ) { super() - try { - this.parseResult = generateTable(tabularNode, state) - } catch (e) { - debugConsole.error(e) - this.parseResult = null - } - } - - isValid() { - if (!this.parseResult) { - return false - } - for (const row of this.parseResult.table.rows) { - const rowLength = row.cells.reduce( - (acc, cell) => acc + (cell.multiColumn?.columnSpan ?? 1), - 0 - ) - for (const cell of row.cells) { - if ( - cell.multiColumn?.columns.specification && - cell.multiColumn.columns.specification.length !== 1 - ) { - return false - } - } - if (rowLength !== this.parseResult.table.columns.length) { - return false - } - } - return true } toDOM(view: EditorView) { - this.element = document.createElement('div') - this.element.classList.add('ol-cm-tabular') + const element = document.createElement('div') + element.classList.add('ol-cm-tabular') if (this.tableNode) { - this.element.classList.add('ol-cm-environment-table') + element.classList.add('ol-cm-environment-table') } - if (this.parseResult) { - ReactDOM.render( - , - this.element - ) - } - return this.element + ReactDOM.render( + , + element + ) + return element } eq(widget: TabularWidget): boolean { @@ -79,31 +39,27 @@ export class TabularWidget extends WidgetType { this.tabularNode.from === widget.tabularNode.from && this.tableNode?.from === widget.tableNode?.from && this.tableNode?.to === widget.tableNode?.to && - this.content === widget.content + this.content === widget.content && + this.isDirectChildOfTableEnvironment === + widget.isDirectChildOfTableEnvironment ) } - updateDOM(dom: HTMLElement, view: EditorView): boolean { - if (!this.parseResult) { - return false - } - this.element = dom + updateDOM(element: HTMLElement, view: EditorView): boolean { ReactDOM.render( , - this.element + element ) return true } - destroy() { - if (this.element) { - ReactDOM.unmountComponentAtNode(this.element) - } + destroy(element: HTMLElement) { + ReactDOM.unmountComponentAtNode(element) } }