Move responsibility for parsing and validating table data out of the tabular widget (#15152)

GitOrigin-RevId: bba823ca036501a527f08746cffb155641d3becf
This commit is contained in:
Alf Eaton 2024-01-03 12:43:49 +00:00 committed by Copybot
parent 621bae03ca
commit 4f5ca6624e
3 changed files with 72 additions and 81 deletions

View file

@ -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 },

View file

@ -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)
)

View file

@ -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(
<Tabular
view={view}
tabularNode={this.tabularNode}
parsedTableData={this.parseResult}
tableNode={this.tableNode}
directTableChild={this.isDirectChildOfTableEnvironment}
/>,
this.element
)
}
return this.element
ReactDOM.render(
<Tabular
view={view}
tabularNode={this.tabularNode}
parsedTableData={this.parsedTableData}
tableNode={this.tableNode}
directTableChild={this.isDirectChildOfTableEnvironment}
/>,
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(
<Tabular
view={view}
tabularNode={this.tabularNode}
parsedTableData={this.parseResult}
parsedTableData={this.parsedTableData}
tableNode={this.tableNode}
directTableChild={this.isDirectChildOfTableEnvironment}
/>,
this.element
element
)
return true
}
destroy() {
if (this.element) {
ReactDOM.unmountComponentAtNode(this.element)
}
destroy(element: HTMLElement) {
ReactDOM.unmountComponentAtNode(element)
}
}