Allow changing of table class and attributes
This commit is contained in:
@@ -61,67 +61,158 @@ const MenuBar = ({ editor }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button onClick={() => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()}>
|
<button
|
||||||
|
onClick={() => editor
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.insertTable({ rows: 3, cols: 3, withHeaderRow: true })
|
||||||
|
.run()
|
||||||
|
}
|
||||||
|
>
|
||||||
insertTable
|
insertTable
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().insertContent(tableHTML, {
|
<button
|
||||||
parseOptions: {
|
onClick={() => editor
|
||||||
preserveWhitespace: false,
|
.chain()
|
||||||
},
|
.focus()
|
||||||
}).run()}>
|
.insertContent(tableHTML, {
|
||||||
|
parseOptions: {
|
||||||
|
preserveWhitespace: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.run()
|
||||||
|
}
|
||||||
|
>
|
||||||
insertHTMLTable
|
insertHTMLTable
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().addColumnBefore().run()} disabled={!editor.can().addColumnBefore()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().addColumnBefore().run()}
|
||||||
|
disabled={!editor.can().addColumnBefore()}
|
||||||
|
>
|
||||||
addColumnBefore
|
addColumnBefore
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().addColumnAfter().run()} disabled={!editor.can().addColumnAfter()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().addColumnAfter().run()}
|
||||||
|
disabled={!editor.can().addColumnAfter()}
|
||||||
|
>
|
||||||
addColumnAfter
|
addColumnAfter
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().deleteColumn().run()} disabled={!editor.can().deleteColumn()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().deleteColumn().run()}
|
||||||
|
disabled={!editor.can().deleteColumn()}
|
||||||
|
>
|
||||||
deleteColumn
|
deleteColumn
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().addRowBefore().run()} disabled={!editor.can().addRowBefore()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().addRowBefore().run()}
|
||||||
|
disabled={!editor.can().addRowBefore()}
|
||||||
|
>
|
||||||
addRowBefore
|
addRowBefore
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().addRowAfter().run()} disabled={!editor.can().addRowAfter()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().addRowAfter().run()}
|
||||||
|
disabled={!editor.can().addRowAfter()}
|
||||||
|
>
|
||||||
addRowAfter
|
addRowAfter
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().deleteRow().run()} disabled={!editor.can().deleteRow()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().deleteRow().run()}
|
||||||
|
disabled={!editor.can().deleteRow()}
|
||||||
|
>
|
||||||
deleteRow
|
deleteRow
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().deleteTable().run()} disabled={!editor.can().deleteTable()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().deleteTable().run()}
|
||||||
|
disabled={!editor.can().deleteTable()}
|
||||||
|
>
|
||||||
deleteTable
|
deleteTable
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().mergeCells().run()} disabled={!editor.can().mergeCells()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().mergeCells().run()}
|
||||||
|
disabled={!editor.can().mergeCells()}
|
||||||
|
>
|
||||||
mergeCells
|
mergeCells
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().splitCell().run()} disabled={!editor.can().splitCell()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().splitCell().run()}
|
||||||
|
disabled={!editor.can().splitCell()}
|
||||||
|
>
|
||||||
splitCell
|
splitCell
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().toggleHeaderColumn().run()} disabled={!editor.can().toggleHeaderColumn()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().toggleHeaderColumn().run()}
|
||||||
|
disabled={!editor.can().toggleHeaderColumn()}
|
||||||
|
>
|
||||||
toggleHeaderColumn
|
toggleHeaderColumn
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().toggleHeaderRow().run()} disabled={!editor.can().toggleHeaderRow()}>
|
<button
|
||||||
toggleHeaderRow
|
onClick={() => editor.chain().focus().toggleHeaderRow().run()}
|
||||||
|
disabled={!editor.can().toggleHeaderRow()}
|
||||||
|
>
|
||||||
|
{editor.can().tableHasHeader() && <>* toggleHeaderRow</>}
|
||||||
|
{!editor.can().tableHasHeader() && <>toggleHeaderRow</>}
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().toggleHeaderCell().run()} disabled={!editor.can().toggleHeaderCell()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().toggleHeaderCell().run()}
|
||||||
|
disabled={!editor.can().toggleHeaderCell()}
|
||||||
|
>
|
||||||
toggleHeaderCell
|
toggleHeaderCell
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().mergeOrSplit().run()} disabled={!editor.can().mergeOrSplit()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().mergeOrSplit().run()}
|
||||||
|
disabled={!editor.can().mergeOrSplit()}
|
||||||
|
>
|
||||||
mergeOrSplit
|
mergeOrSplit
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().setCellAttribute('backgroundColor', '#FAF594').run()} disabled={!editor.can().setCellAttribute('backgroundColor', '#FAF594')}>
|
<button
|
||||||
|
onClick={() => editor
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.setCellAttribute('backgroundColor', '#FAF594')
|
||||||
|
.run()
|
||||||
|
}
|
||||||
|
disabled={!editor.can().setCellAttribute('backgroundColor', '#FAF594')}
|
||||||
|
>
|
||||||
setCellAttribute
|
setCellAttribute
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().fixTables().run()} disabled={!editor.can().fixTables()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().fixTables().run()}
|
||||||
|
disabled={!editor.can().fixTables()}
|
||||||
|
>
|
||||||
fixTables
|
fixTables
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().goToNextCell().run()} disabled={!editor.can().goToNextCell()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().goToNextCell().run()}
|
||||||
|
disabled={!editor.can().goToNextCell()}
|
||||||
|
>
|
||||||
goToNextCell
|
goToNextCell
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => editor.chain().focus().goToPreviousCell().run()} disabled={!editor.can().goToPreviousCell()}>
|
<button
|
||||||
|
onClick={() => editor.chain().focus().goToPreviousCell().run()}
|
||||||
|
disabled={!editor.can().goToPreviousCell()}
|
||||||
|
>
|
||||||
goToPreviousCell
|
goToPreviousCell
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => editor.chain().focus().toggleTableClass('table-fullwidth').run()
|
||||||
|
}
|
||||||
|
>
|
||||||
|
toggleTableClass(fullwidth)
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => editor.chain().focus().toggleTableClass('table-centred').run()
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{editor.can().tableHasClass('table-centred') && (
|
||||||
|
<>* toggleTableClass(centred)</>
|
||||||
|
)}
|
||||||
|
{!editor.can().tableHasClass('table-centred') && (
|
||||||
|
<>toggleTableClass(centred)</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
<button onClick={() => console.log(editor.getHTML())}>Get HTML</button>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -152,10 +243,10 @@ export default () => {
|
|||||||
<p>
|
<p>
|
||||||
Here is an example:
|
Here is an example:
|
||||||
</p>
|
</p>
|
||||||
<table>
|
<table class="tablestyle tablestyle2" data-foo="bar">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name!</th>
|
||||||
<th colspan="3">Description</th>
|
<th colspan="3">Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -2,7 +2,14 @@
|
|||||||
import { Node as ProseMirrorNode } from 'prosemirror-model'
|
import { Node as ProseMirrorNode } from 'prosemirror-model'
|
||||||
import { NodeView } from 'prosemirror-view'
|
import { NodeView } from 'prosemirror-view'
|
||||||
|
|
||||||
export function updateColumns(node: ProseMirrorNode, colgroup: Element, table: Element, cellMinWidth: number, overrideCol?: number, overrideValue?: any) {
|
export function updateColumns(
|
||||||
|
node: ProseMirrorNode,
|
||||||
|
colgroup: Element,
|
||||||
|
table: Element,
|
||||||
|
cellMinWidth: number,
|
||||||
|
overrideCol?: number,
|
||||||
|
overrideValue?: any,
|
||||||
|
) {
|
||||||
let totalWidth = 0
|
let totalWidth = 0
|
||||||
let fixedWidth = true
|
let fixedWidth = true
|
||||||
let nextDOM = colgroup.firstChild
|
let nextDOM = colgroup.firstChild
|
||||||
@@ -50,7 +57,6 @@ export function updateColumns(node: ProseMirrorNode, colgroup: Element, table: E
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class TableView implements NodeView {
|
export class TableView implements NodeView {
|
||||||
|
|
||||||
node: ProseMirrorNode
|
node: ProseMirrorNode
|
||||||
|
|
||||||
cellMinWidth: number
|
cellMinWidth: number
|
||||||
@@ -69,6 +75,8 @@ export class TableView implements NodeView {
|
|||||||
this.dom = document.createElement('div')
|
this.dom = document.createElement('div')
|
||||||
this.dom.className = 'tableWrapper'
|
this.dom.className = 'tableWrapper'
|
||||||
this.table = this.dom.appendChild(document.createElement('table'))
|
this.table = this.dom.appendChild(document.createElement('table'))
|
||||||
|
this.table.className = node.attrs?.class
|
||||||
|
this.table.setAttribute('data-ref', node.attrs?.ref)
|
||||||
this.colgroup = this.table.appendChild(document.createElement('colgroup'))
|
this.colgroup = this.table.appendChild(document.createElement('colgroup'))
|
||||||
updateColumns(node, this.colgroup, this.table, cellMinWidth)
|
updateColumns(node, this.colgroup, this.table, cellMinWidth)
|
||||||
this.contentDOM = this.table.appendChild(document.createElement('tbody'))
|
this.contentDOM = this.table.appendChild(document.createElement('tbody'))
|
||||||
@@ -85,7 +93,13 @@ export class TableView implements NodeView {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
ignoreMutation(mutation: MutationRecord | { type: 'selection'; target: Element }) {
|
ignoreMutation(
|
||||||
return mutation.type === 'attributes' && (mutation.target === this.table || this.colgroup.contains(mutation.target))
|
mutation: MutationRecord | { type: 'selection'; target: Element },
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
mutation.type === 'attributes'
|
||||||
|
&& (mutation.target === this.table
|
||||||
|
|| this.colgroup.contains(mutation.target))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,50 +32,62 @@ import { createTable } from './utilities/createTable'
|
|||||||
import { deleteTableWhenAllCellsSelected } from './utilities/deleteTableWhenAllCellsSelected'
|
import { deleteTableWhenAllCellsSelected } from './utilities/deleteTableWhenAllCellsSelected'
|
||||||
|
|
||||||
export interface TableOptions {
|
export interface TableOptions {
|
||||||
HTMLAttributes: Record<string, any>,
|
HTMLAttributes: Record<string, any>;
|
||||||
resizable: boolean,
|
resizable: boolean;
|
||||||
handleWidth: number,
|
handleWidth: number;
|
||||||
cellMinWidth: number,
|
cellMinWidth: number;
|
||||||
View: NodeView,
|
View: NodeView;
|
||||||
lastColumnResizable: boolean,
|
lastColumnResizable: boolean;
|
||||||
allowTableNodeSelection: boolean,
|
allowTableNodeSelection: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@tiptap/core' {
|
declare module '@tiptap/core' {
|
||||||
interface Commands<ReturnType> {
|
interface Commands<ReturnType> {
|
||||||
table: {
|
table: {
|
||||||
insertTable: (options?: { rows?: number, cols?: number, withHeaderRow?: boolean }) => ReturnType,
|
insertTable: (options?: {
|
||||||
addColumnBefore: () => ReturnType,
|
rows?: number;
|
||||||
addColumnAfter: () => ReturnType,
|
cols?: number;
|
||||||
deleteColumn: () => ReturnType,
|
withHeaderRow?: boolean;
|
||||||
addRowBefore: () => ReturnType,
|
}) => ReturnType;
|
||||||
addRowAfter: () => ReturnType,
|
addColumnBefore: () => ReturnType;
|
||||||
deleteRow: () => ReturnType,
|
addColumnAfter: () => ReturnType;
|
||||||
deleteTable: () => ReturnType,
|
deleteColumn: () => ReturnType;
|
||||||
mergeCells: () => ReturnType,
|
addRowBefore: () => ReturnType;
|
||||||
splitCell: () => ReturnType,
|
addRowAfter: () => ReturnType;
|
||||||
toggleHeaderColumn: () => ReturnType,
|
deleteRow: () => ReturnType;
|
||||||
toggleHeaderRow: () => ReturnType,
|
deleteTable: () => ReturnType;
|
||||||
toggleHeaderCell: () => ReturnType,
|
mergeCells: () => ReturnType;
|
||||||
mergeOrSplit: () => ReturnType,
|
splitCell: () => ReturnType;
|
||||||
setCellAttribute: (name: string, value: any) => ReturnType,
|
toggleHeaderColumn: () => ReturnType;
|
||||||
goToNextCell: () => ReturnType,
|
toggleHeaderRow: () => ReturnType;
|
||||||
goToPreviousCell: () => ReturnType,
|
toggleHeaderCell: () => ReturnType;
|
||||||
fixTables: () => ReturnType,
|
mergeOrSplit: () => ReturnType;
|
||||||
setCellSelection: (position: { anchorCell: number, headCell?: number }) => ReturnType,
|
setCellAttribute: (name: string, value: any) => ReturnType;
|
||||||
}
|
goToNextCell: () => ReturnType;
|
||||||
|
goToPreviousCell: () => ReturnType;
|
||||||
|
fixTables: () => ReturnType;
|
||||||
|
setCellSelection: (position: {
|
||||||
|
anchorCell: number;
|
||||||
|
headCell?: number;
|
||||||
|
}) => ReturnType;
|
||||||
|
toggleTableClass: (className: string) => ReturnType;
|
||||||
|
tableHasClass: (className: string) => ReturnType;
|
||||||
|
tableHasHeader: () => ReturnType;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NodeConfig<Options, Storage> {
|
interface NodeConfig<Options, Storage> {
|
||||||
/**
|
/**
|
||||||
* Table Role
|
* Table Role
|
||||||
*/
|
*/
|
||||||
tableRole?: string | ((this: {
|
tableRole?:
|
||||||
name: string,
|
| string
|
||||||
options: Options,
|
| ((this: {
|
||||||
storage: Storage,
|
name: string;
|
||||||
parent: ParentConfig<NodeConfig<Options>>['tableRole'],
|
options: Options;
|
||||||
}) => string),
|
storage: Storage;
|
||||||
|
parent: ParentConfig<NodeConfig<Options>>['tableRole'];
|
||||||
|
}) => string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,99 +117,209 @@ export const Table = Node.create<TableOptions>({
|
|||||||
group: 'block',
|
group: 'block',
|
||||||
|
|
||||||
parseHTML() {
|
parseHTML() {
|
||||||
return [
|
return [{ tag: 'table' }]
|
||||||
{ tag: 'table' },
|
},
|
||||||
]
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
|
...this.parent?.(),
|
||||||
|
class: {
|
||||||
|
default: null,
|
||||||
|
parseHTML: element => element.getAttribute('class'),
|
||||||
|
},
|
||||||
|
ref: {
|
||||||
|
default: `table${Math.random().toString().substring(2)}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
renderHTML({ HTMLAttributes }) {
|
renderHTML({ HTMLAttributes }) {
|
||||||
return ['table', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), ['tbody', 0]]
|
return [
|
||||||
|
'table',
|
||||||
|
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
||||||
|
['tbody', 0],
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
addCommands() {
|
addCommands() {
|
||||||
return {
|
return {
|
||||||
insertTable: ({ rows = 3, cols = 3, withHeaderRow = true } = {}) => ({ tr, dispatch, editor }) => {
|
insertTable:
|
||||||
const node = createTable(editor.schema, rows, cols, withHeaderRow)
|
({ rows = 3, cols = 3, withHeaderRow = true } = {}) => ({ tr, dispatch, editor }) => {
|
||||||
|
const node = createTable(editor.schema, rows, cols, withHeaderRow)
|
||||||
|
|
||||||
if (dispatch) {
|
if (dispatch) {
|
||||||
const offset = tr.selection.anchor + 1
|
const offset = tr.selection.anchor + 1
|
||||||
|
|
||||||
tr.replaceSelectionWith(node)
|
tr.replaceSelectionWith(node)
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.setSelection(TextSelection.near(tr.doc.resolve(offset)))
|
.setSelection(TextSelection.near(tr.doc.resolve(offset)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
addColumnBefore: () => ({ state, dispatch }) => {
|
|
||||||
return addColumnBefore(state, dispatch)
|
|
||||||
},
|
|
||||||
addColumnAfter: () => ({ state, dispatch }) => {
|
|
||||||
return addColumnAfter(state, dispatch)
|
|
||||||
},
|
|
||||||
deleteColumn: () => ({ state, dispatch }) => {
|
|
||||||
return deleteColumn(state, dispatch)
|
|
||||||
},
|
|
||||||
addRowBefore: () => ({ state, dispatch }) => {
|
|
||||||
return addRowBefore(state, dispatch)
|
|
||||||
},
|
|
||||||
addRowAfter: () => ({ state, dispatch }) => {
|
|
||||||
return addRowAfter(state, dispatch)
|
|
||||||
},
|
|
||||||
deleteRow: () => ({ state, dispatch }) => {
|
|
||||||
return deleteRow(state, dispatch)
|
|
||||||
},
|
|
||||||
deleteTable: () => ({ state, dispatch }) => {
|
|
||||||
return deleteTable(state, dispatch)
|
|
||||||
},
|
|
||||||
mergeCells: () => ({ state, dispatch }) => {
|
|
||||||
return mergeCells(state, dispatch)
|
|
||||||
},
|
|
||||||
splitCell: () => ({ state, dispatch }) => {
|
|
||||||
return splitCell(state, dispatch)
|
|
||||||
},
|
|
||||||
toggleHeaderColumn: () => ({ state, dispatch }) => {
|
|
||||||
return toggleHeader('column')(state, dispatch)
|
|
||||||
},
|
|
||||||
toggleHeaderRow: () => ({ state, dispatch }) => {
|
|
||||||
return toggleHeader('row')(state, dispatch)
|
|
||||||
},
|
|
||||||
toggleHeaderCell: () => ({ state, dispatch }) => {
|
|
||||||
return toggleHeaderCell(state, dispatch)
|
|
||||||
},
|
|
||||||
mergeOrSplit: () => ({ state, dispatch }) => {
|
|
||||||
if (mergeCells(state, dispatch)) {
|
|
||||||
return true
|
return true
|
||||||
}
|
},
|
||||||
|
addColumnBefore:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return addColumnBefore(state, dispatch)
|
||||||
|
},
|
||||||
|
addColumnAfter:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return addColumnAfter(state, dispatch)
|
||||||
|
},
|
||||||
|
deleteColumn:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return deleteColumn(state, dispatch)
|
||||||
|
},
|
||||||
|
addRowBefore:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return addRowBefore(state, dispatch)
|
||||||
|
},
|
||||||
|
addRowAfter:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return addRowAfter(state, dispatch)
|
||||||
|
},
|
||||||
|
deleteRow:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return deleteRow(state, dispatch)
|
||||||
|
},
|
||||||
|
deleteTable:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return deleteTable(state, dispatch)
|
||||||
|
},
|
||||||
|
mergeCells:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return mergeCells(state, dispatch)
|
||||||
|
},
|
||||||
|
splitCell:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return splitCell(state, dispatch)
|
||||||
|
},
|
||||||
|
toggleHeaderColumn:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return toggleHeader('column')(state, dispatch)
|
||||||
|
},
|
||||||
|
toggleHeaderRow:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return toggleHeader('row')(state, dispatch)
|
||||||
|
},
|
||||||
|
toggleHeaderCell:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
return toggleHeaderCell(state, dispatch)
|
||||||
|
},
|
||||||
|
mergeOrSplit:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
if (mergeCells(state, dispatch)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
return splitCell(state, dispatch)
|
return splitCell(state, dispatch)
|
||||||
},
|
},
|
||||||
setCellAttribute: (name, value) => ({ state, dispatch }) => {
|
setCellAttribute:
|
||||||
return setCellAttr(name, value)(state, dispatch)
|
(name, value) => ({ state, dispatch }) => {
|
||||||
},
|
return setCellAttr(name, value)(state, dispatch)
|
||||||
goToNextCell: () => ({ state, dispatch }) => {
|
},
|
||||||
return goToNextCell(1)(state, dispatch)
|
goToNextCell:
|
||||||
},
|
() => ({ state, dispatch }) => {
|
||||||
goToPreviousCell: () => ({ state, dispatch }) => {
|
return goToNextCell(1)(state, dispatch)
|
||||||
return goToNextCell(-1)(state, dispatch)
|
},
|
||||||
},
|
goToPreviousCell:
|
||||||
fixTables: () => ({ state, dispatch }) => {
|
() => ({ state, dispatch }) => {
|
||||||
if (dispatch) {
|
return goToNextCell(-1)(state, dispatch)
|
||||||
fixTables(state)
|
},
|
||||||
}
|
fixTables:
|
||||||
|
() => ({ state, dispatch }) => {
|
||||||
|
if (dispatch) {
|
||||||
|
fixTables(state)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
setCellSelection: position => ({ tr, dispatch }) => {
|
setCellSelection:
|
||||||
if (dispatch) {
|
position => ({ tr, dispatch }) => {
|
||||||
const selection = CellSelection.create(tr.doc, position.anchorCell, position.headCell)
|
if (dispatch) {
|
||||||
|
const selection = CellSelection.create(
|
||||||
|
tr.doc,
|
||||||
|
position.anchorCell,
|
||||||
|
position.headCell,
|
||||||
|
)
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
tr.setSelection(selection)
|
tr.setSelection(selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
tableHasHeader:
|
||||||
|
() => ({ state }) => {
|
||||||
|
const $pos = state.selection.$anchor
|
||||||
|
|
||||||
|
for (let d = $pos.depth; d > 0; d -= 1) {
|
||||||
|
const node = $pos.node(d)
|
||||||
|
|
||||||
|
if (node.type.spec.tableRole === 'table') {
|
||||||
|
const ref = node.attrs?.ref
|
||||||
|
|
||||||
|
if (!ref) { return false }
|
||||||
|
const tableThDom = document.querySelector(
|
||||||
|
`div.ProseMirror table[data-ref=${node.attrs.ref}] > tbody > tr > th, div.ProseMirror table[data-ref=${node.attrs.ref}] > thead > tr > th`,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (tableThDom) { return true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
tableHasClass:
|
||||||
|
className => ({ state }) => {
|
||||||
|
const $pos = state.selection.$anchor
|
||||||
|
|
||||||
|
for (let d = $pos.depth; d > 0; d -= 1) {
|
||||||
|
const node = $pos.node(d)
|
||||||
|
|
||||||
|
if (node.type.spec.tableRole === 'table') {
|
||||||
|
const classStr = node.attrs?.class || ''
|
||||||
|
const classList = classStr?.split(' ') || []
|
||||||
|
const classIndex = classList.indexOf(className)
|
||||||
|
|
||||||
|
if (classIndex >= 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleTableClass:
|
||||||
|
className => ({ state }) => {
|
||||||
|
const $pos = state.selection.$anchor
|
||||||
|
|
||||||
|
for (let d = $pos.depth; d > 0; d -= 1) {
|
||||||
|
const node = $pos.node(d)
|
||||||
|
|
||||||
|
if (node.type.spec.tableRole === 'table') {
|
||||||
|
const classStr = node.attrs?.class || ''
|
||||||
|
const classList = classStr?.split(' ') || []
|
||||||
|
const classIndex = classList.indexOf(className)
|
||||||
|
|
||||||
|
if (classIndex >= 0) {
|
||||||
|
classList.splice(classIndex, 1)
|
||||||
|
} else {
|
||||||
|
classList.push(className)
|
||||||
|
}
|
||||||
|
const newClassStr = classList.join(' ')
|
||||||
|
|
||||||
|
state.tr.setNodeAttribute($pos.before(d), 'class', newClassStr)
|
||||||
|
const tableDom = document.querySelector(
|
||||||
|
`div.ProseMirror table[data-ref=${node.attrs.ref}]`,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (tableDom) { tableDom.className = newClassStr }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -212,11 +334,7 @@ export const Table = Node.create<TableOptions>({
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.editor
|
return this.editor.chain().addRowAfter().goToNextCell().run()
|
||||||
.chain()
|
|
||||||
.addRowAfter()
|
|
||||||
.goToNextCell()
|
|
||||||
.run()
|
|
||||||
},
|
},
|
||||||
'Shift-Tab': () => this.editor.commands.goToPreviousCell(),
|
'Shift-Tab': () => this.editor.commands.goToPreviousCell(),
|
||||||
Backspace: deleteTableWhenAllCellsSelected,
|
Backspace: deleteTableWhenAllCellsSelected,
|
||||||
@@ -230,14 +348,18 @@ export const Table = Node.create<TableOptions>({
|
|||||||
const isResizable = this.options.resizable && this.editor.isEditable
|
const isResizable = this.options.resizable && this.editor.isEditable
|
||||||
|
|
||||||
return [
|
return [
|
||||||
...(isResizable ? [columnResizing({
|
...(isResizable
|
||||||
handleWidth: this.options.handleWidth,
|
? [
|
||||||
cellMinWidth: this.options.cellMinWidth,
|
columnResizing({
|
||||||
View: this.options.View,
|
handleWidth: this.options.handleWidth,
|
||||||
// TODO: PR for @types/prosemirror-tables
|
cellMinWidth: this.options.cellMinWidth,
|
||||||
// @ts-ignore (incorrect type)
|
View: this.options.View,
|
||||||
lastColumnResizable: this.options.lastColumnResizable,
|
// TODO: PR for @types/prosemirror-tables
|
||||||
})] : []),
|
// @ts-ignore (incorrect type)
|
||||||
|
lastColumnResizable: this.options.lastColumnResizable,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
: []),
|
||||||
tableEditing({
|
tableEditing({
|
||||||
allowTableNodeSelection: this.options.allowTableNodeSelection,
|
allowTableNodeSelection: this.options.allowTableNodeSelection,
|
||||||
}),
|
}),
|
||||||
@@ -252,7 +374,9 @@ export const Table = Node.create<TableOptions>({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tableRole: callOrReturn(getExtensionField(extension, 'tableRole', context)),
|
tableRole: callOrReturn(
|
||||||
|
getExtensionField(extension, 'tableRole', context),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user