From c549433b7131ceb63158a2f4b298219126fa27a2 Mon Sep 17 00:00:00 2001 From: Muhammed Mustafa Date: Thu, 23 Nov 2023 11:20:36 +0000 Subject: [PATCH] fix: Added checkbox support for md <-> html conversions --- packages/nc-gui/components/cell/RichText.vue | 57 +++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/components/cell/RichText.vue b/packages/nc-gui/components/cell/RichText.vue index b13f391f3a..926ddbf5b8 100644 --- a/packages/nc-gui/components/cell/RichText.vue +++ b/packages/nc-gui/components/cell/RichText.vue @@ -4,7 +4,7 @@ import TaskItem from '@tiptap/extension-task-item' import TaskList from '@tiptap/extension-task-list' import { EditorContent, useEditor } from '@tiptap/vue-3' import TurndownService from 'turndown' -import { parse } from 'marked' +import { marked } from 'marked' import { generateJSON } from '@tiptap/html' import Underline from '@tiptap/extension-underline' import { Link } from '@/helpers/dbTiptapExtensions/links' @@ -21,6 +21,59 @@ const emits = defineEmits(['update:value']) const turndownService = new TurndownService() +turndownService.addRule('taskList', { + filter: (node) => { + return node.nodeName === 'LI' && !!node.getAttribute('data-checked') + }, + replacement: (content) => { + // Remove the first \n\n and last \n\n + const processContent = content.replace(/^\n\n/, '').replace(/\n\n$/, '') + return `[ ] ${processContent}\n\n` + }, +}) + +const checkListItem = { + name: 'checkListItem', + level: 'block', + tokenizer(src: string) { + src = src.split('\n\n')[0] + const isMatched = src.startsWith('[ ]') || src.startsWith('[x]') || src.startsWith('[X]') + + if (isMatched) { + const isNotChecked = src.startsWith('[ ]') + let text = src.slice(3) + if (text[0] === ' ') text = text.slice(1) + + const token = { + // Token to generate + type: 'checkListItem', + raw: src, + text, + tokens: [], + checked: !isNotChecked, + } + + ;(this as any).lexer.inline(token.text, token.tokens) // Queue this data to be processed for inline tokens + return token + } + + return false + }, + renderer(token: any) { + return `` // parseInline to turn child tokens into HTML + }, +} + +marked.use({ extensions: [checkListItem] }) + const editorDom = ref(null) const vModel = useVModel(props, 'value', emits, { defaultValue: '' }) @@ -52,7 +105,7 @@ const setEditorContent = (contentMd: any) => { const selection = editor.value.view.state.selection - const contentHtml = contentMd ? parse(contentMd) : '

' + const contentHtml = contentMd ? marked.parse(contentMd) : '

' const content = generateJSON(contentHtml, tiptapExtensions)