Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/extensions/yfm/YfmTable/YfmTable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {BlockquoteSpecs, blockquoteNodeName} from '../../markdown/Blockquote/Blo

import {YfmTableNode, YfmTableSpecs} from './YfmTableSpecs';
import {YfmTableAttr} from './const';
import {fixPastedTableBodies} from './paste';
import {fixPastedTableBodies, unpackSingleCellTable} from './paste';

const {
schema,
Expand Down Expand Up @@ -154,6 +154,20 @@ nested table
transformPasted: (slice) => fixPastedTableBodies(slice, schema),
});
dispatchPasteEvent(view, {'text/html': html, 'text/plain': text});
expect(view.state.doc).toMatchNode(
doc(table(tbody(tr(td(p('content in thead'))), tr(td(p('content in tbody')))))),
);
});

it('should transform pasted table into slice with content from single cell', () => {
const text = 'content from cell';
const html = '<table><tbody><tr><td>content from cell</td></tr></tbody></table>';
const view = new EditorView(null, {
state: EditorState.create({schema}),
transformPasted: (slice) => unpackSingleCellTable(slice),
});
dispatchPasteEvent(view, {'text/html': html, 'text/plain': text});
expect(view.state.doc).toMatchNode(doc(p('content from cell')));
});

it('should parse table with rowspan and colspan', () => {
Expand Down
38 changes: 36 additions & 2 deletions src/extensions/yfm/YfmTable/paste.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {Fragment, type Node, type Schema, Slice} from 'prosemirror-model';

import {getChildrenOfNode} from '../../../utils/nodes';
import {TableRole} from 'src/table-utils/const';
import {getChildrenOfNode} from 'src/utils/nodes';

import {yfmTableBodyType, yfmTableType} from './utils';
import {yfmTableBodyType, yfmTableCellType, yfmTableRowType, yfmTableType} from './utils';

export function fixPastedTableBodies(slice: Slice, schema: Schema): Slice {
if (slice.content.firstChild?.type === yfmTableBodyType(schema)) {
Expand All @@ -21,3 +22,36 @@ export function fixPastedTableBodies(slice: Slice, schema: Schema): Slice {
}
return slice;
}

export function unpackSingleCellTable(slice: Slice): Slice {
if (slice.content.childCount !== 1) return slice;
if (!isSingeCellTable(slice.content.child(0))) return slice;

let node: Node | null = slice.content.child(0);
while (node && node.type.spec.tableRole !== TableRole.Cell) {
node = node.lastChild;
}

// get content from tableCell
const newFragment = Fragment.from(node?.content);
const newSlice = new Slice(newFragment, 0, 0);

return newSlice;
}

function isSingeCellTable(node: Node): boolean {
const {schema} = node.type;

if (node.type === yfmTableCellType(schema)) return true;

if (node.type === yfmTableRowType(schema) && node.childCount === 1)
return isSingeCellTable(node.child(0));

if (node.type === yfmTableBodyType(schema) && node.childCount === 1)
return isSingeCellTable(node.child(0));

if (node.type === yfmTableType(schema) && node.lastChild?.type === yfmTableBodyType(schema))
return isSingeCellTable(node.lastChild);

return false;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type {Schema} from 'prosemirror-model';
import {Plugin} from 'prosemirror-state';

import {fixPastedTableBodies} from '../paste';
import {fixPastedTableBodies, unpackSingleCellTable} from '../paste';

interface Args {
schema: Schema;
Expand All @@ -10,7 +10,9 @@ export const yfmTableTransformPastedPlugin = ({schema}: Args) =>
new Plugin({
props: {
transformPasted(slice) {
return fixPastedTableBodies(slice, schema);
slice = unpackSingleCellTable(slice);
slice = fixPastedTableBodies(slice, schema);
return slice;
},
},
});
Loading