Skip to content
Open
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
19 changes: 14 additions & 5 deletions cypress/e2e/nodes/Table.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import { initUserAndFiles, randUser } from '../../utils/index.js'
import { findChildren } from './../../../src/helpers/prosemirrorUtils.js'
import { createCustomEditor } from './../../support/components.js'

import { CodeBlock } from '@tiptap/extension-code-block'
import { ListItem } from '@tiptap/extension-list-item'
import Markdown, {
createMarkdownSerializer,
} from './../../../src/extensions/Markdown.js'
import markdownit from './../../../src/markdownit/index.js'
import BulletList from './../../../src/nodes/BulletList.js'
import EditableTable from './../../../src/nodes/EditableTable.js'
import Image from './../../../src/nodes/Image.js'

// https://github.com/import-js/eslint-plugin-import/issues/1739
/* eslint-disable-next-line import/no-unresolved */
Expand Down Expand Up @@ -121,20 +125,18 @@ describe('table plugin', () => {
})

it('Creates table and add multilines', function () {
const multilinesContent = 'Line 1\nLine 2\nLine 3'

cy.getActionEntry('table').click()
cy.getContent()
.find('table:nth-of-type(1) tr:nth-child(2) td:nth-child(1)')
.click()

cy.getContent().type(multilinesContent)
cy.getContent().type('Line 1\nLine 2\nLine 3')

cy.getContent()
.find('table:nth-of-type(1) tr:nth-child(2) td:nth-child(1) .content')
.then(($el) => {
expect($el.get(0).innerHTML).to.equal(
multilinesContent.replace(/\n/g, '<br>'),
'<p dir="ltr">Line 1</p><p dir="ltr">Line 2</p><p dir="ltr">Line 3</p>',
)
})
})
Expand Down Expand Up @@ -169,7 +171,14 @@ describe('table plugin', () => {
describe('Table extension integrated in the editor', () => {
const editor = createCustomEditor({
content: '',
extensions: [Markdown, EditableTable],
extensions: [
BulletList,
CodeBlock,
EditableTable,
Image,
ListItem,
Markdown,
],
})

for (const spec of testData.split(/#+\s+/)) {
Expand Down
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"markdown-it-container": "^4.0.0",
"markdown-it-front-matter": "^0.2.4",
"markdown-it-image-figures": "^2.1.1",
"markdown-it-multimd-table": "^4.2.3",
"mermaid": "^11.9.0",
"mitt": "^3.0.1",
"path-normalize": "^6.0.13",
Expand Down
7 changes: 7 additions & 0 deletions src/markdownit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import markdownitMentions from '@quartzy/markdown-it-mentions'
import MarkdownIt from 'markdown-it'
import frontMatter from 'markdown-it-front-matter'
import implicitFigures from 'markdown-it-image-figures'
import multimdTable from 'markdown-it-multimd-table'
import { escapeHtml } from 'markdown-it/lib/common/utils.mjs'
import callouts from './callouts.js'
import details from './details.ts'
Expand All @@ -31,6 +32,12 @@ const markdownit = MarkdownIt('commonmark', { html: false, breaks: false })
.use(keepSyntax)
.use(markdownitMentions)
.use(implicitFigures)
.use(multimdTable, {
multiline: true,
rowspan: false,
headerless: true,
multibody: false,
})

// Render front matter tokens
markdownit.renderer.rules.front_matter = (tokens, idx, options) =>
Expand Down
2 changes: 1 addition & 1 deletion src/nodes/ImageInline.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ImageView from './ImageView.vue'
// Inline image extension. Needed if markdown contains inline images.
// Not supported to be created from our UI (we default to block images).
const ImageInline = TiptapImage.extend({
name: 'image-inline',
name: 'imageInline',

// Lower priority than (block) Image extension
priority: 99,
Expand Down
53 changes: 3 additions & 50 deletions src/nodes/Table/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { mergeAttributes } from '@tiptap/core'
import { Table } from '@tiptap/extension-table'
import { Node } from '@tiptap/pm/model'
// import { Node } from '@tiptap/pm/model'
import { TextSelection } from '@tiptap/pm/state'
import {
addRowAfter,
Expand All @@ -15,6 +15,7 @@ import {
selectedRect,
selectionCell,
} from '@tiptap/pm/tables'
import { tableToMarkdown } from './markdown.ts'
import TableCaption from './TableCaption.js'
import TableCell from './TableCell.js'
import TableHeader from './TableHeader.js'
Expand Down Expand Up @@ -72,50 +73,6 @@ function findSameCellInNextRow($cell) {
}
}

/**
*
* @param {Node} node - Table node
*/
function getColumns(node) {
const columns = []

node.content.forEach((row) => {
row.content.forEach((cell, offset, columnIndex) => {
if (!columns[columnIndex]) {
columns[columnIndex] = []
}
columns[columnIndex].push(cell)
})
})

return columns
}

/**
*
* @param {Array} columns - Columns of table
*/
function calculateColumnWidths(columns) {
const widths = []

columns.forEach((column) => {
let maxWidth = 0

column.forEach((cell) => {
let cellWidth = 0
cell.content.forEach((node) => {
cellWidth += node.text?.length || 6
if (node.text?.includes('|')) cellWidth += 1
})
maxWidth = Math.max(maxWidth, cellWidth)
})

widths.push(maxWidth)
})

return widths
}

export default Table.extend({
content: 'tableCaption? tableHeadRow tableRow*',

Expand Down Expand Up @@ -243,11 +200,7 @@ export default Table.extend({
},

toMarkdown(state, node) {
const columns = getColumns(node)
state.options.columnWidths = calculateColumnWidths(columns)
state.options.currentHeaderIndex = 0
state.renderContent(node)
state.closeBlock(node)
tableToMarkdown(state, node)
},

addKeyboardShortcuts() {
Expand Down
2 changes: 1 addition & 1 deletion src/nodes/Table/TableCaption.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default Node.create({
return ['caption']
},

toMarkdown(state, node) {},
toMarkdown() {},

parseHTML() {
return [{ tag: 'table caption', priority: 90 }]
Expand Down
35 changes: 5 additions & 30 deletions src/nodes/Table/TableCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,12 @@ import { Fragment } from '@tiptap/pm/model'
import { Plugin } from '@tiptap/pm/state'

export default TableCell.extend({
content: 'inline*',
// content: 'block+',
// All block elements except blockquote as that one causes issues for now.
// Blockquote as nested child (e.g. inside a list) is no problem.
content: '(paragraph|list|codeBlock|image|callout|details|horizontalRule)+',

toMarkdown(state, node) {
state.write(' ')
const backup = state.options?.escapeExtraCharacters
const columnIndex = state.options.currentColumnIndex
state.options.escapeExtraCharacters = /\|/

let cellRenderedContentLength = 0
node.content.forEach((childNode, offset, index) => {
cellRenderedContentLength += childNode.text?.length || 6
if (childNode.text?.includes('|')) cellRenderedContentLength += 1
if (childNode.attrs.syntax === ' ')
node.child(index).attrs.syntax = 'html'
})
const columnWidth = state.options.columnWidths[columnIndex]
const align = node.attrs?.textAlign || 'left'
const space = columnWidth - cellRenderedContentLength
const leftPadding = Math.floor(space / 2)
const rightPadding = Math.ceil(space / 2)

if (align === 'center') state.write(' '.repeat(leftPadding))
if (align === 'right') state.write(' '.repeat(space))
state.renderInline(node)
if (align === 'center') state.write(' '.repeat(rightPadding))
if (align === 'left') state.write(' '.repeat(space))

state.options.escapeExtraCharacters = backup
state.write(' |')
state.options.currentColumnIndex++
},
toMarkdown() {},

parseHTML() {
return [
Expand Down
16 changes: 1 addition & 15 deletions src/nodes/Table/TableHeadRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,7 @@ export default TableRow.extend({
content: 'tableHeader+',
allowGapCursor: false,

toMarkdown(state, node) {
state.write('|')
state.renderInline(node)
state.ensureNewLine()
state.write('|')
node.forEach((cell, offset, index) => {
let row = state.repeat('-', state.options.columnWidths[index] + 2)
const align = cell.attrs?.textAlign
if (align === 'center' || align === 'left') row = ':' + row.slice(1)
if (align === 'center' || align === 'right') row = row.slice(0, -1) + ':'
state.write(row)
state.write('|')
})
state.ensureNewLine()
},
toMarkdown() {},

parseHTML() {
return [{ tag: 'tr:first-of-type', priority: 80 }]
Expand Down
18 changes: 1 addition & 17 deletions src/nodes/Table/TableHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,7 @@ import { TableHeader } from '@tiptap/extension-table-header'
export default TableHeader.extend({
content: 'inline*',

toMarkdown(state, node) {
const headerIndex = state.options.currentHeaderIndex
const columnWidth = state.options.columnWidths[headerIndex]
const align = node.attrs?.textAlign || 'left'
const space = columnWidth - node.content.size
const leftPadding = Math.floor(space / 2)
const rightPadding = Math.ceil(space / 2)

state.write(' ')
if (align === 'center') state.write(' '.repeat(leftPadding))
if (align === 'right') state.write(' '.repeat(space))
state.renderInline(node)
if (align === 'center') state.write(' '.repeat(rightPadding))
if (align === 'left') state.write(' '.repeat(space))
state.write(' |')
state.options.currentHeaderIndex++
},
toMarkdown() {},

parseHTML() {
return [
Expand Down
7 changes: 1 addition & 6 deletions src/nodes/Table/TableRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ export default TableRow.extend({
content: 'tableCell*',
allowGapCursor: false,

toMarkdown(state, node) {
state.write('|')
state.options.currentColumnIndex = 0
state.renderInline(node)
state.ensureNewLine()
},
toMarkdown() {},

parseHTML() {
return [{ tag: 'tr', priority: 70 }]
Expand Down
Loading
Loading