fix: Fixed issue where empty new line in Super would create extra new lines when converting to Markdown

This commit is contained in:
Aman Harwara 2023-05-22 19:28:19 +05:30
parent 7a24b205a7
commit 799945b167
No known key found for this signature in database
GPG Key ID: DD433BD9F21FEDD7
6 changed files with 34 additions and 25 deletions

View File

@ -1,4 +1,4 @@
import { InvisibleSuperConverter } from '@/Components/SuperEditor/Tools/InvisibleMarkdownConverter' import { HeadlessSuperConverter } from '@/Components/SuperEditor/Tools/HeadlessSuperConverter'
import { import {
SNComponent, SNComponent,
ComponentMutator, ComponentMutator,
@ -40,7 +40,7 @@ export class DesktopManager
) { ) {
super(application, new InternalEventBus()) super(application, new InternalEventBus())
const markdownConverter = new InvisibleSuperConverter() const markdownConverter = new HeadlessSuperConverter()
backups.setSuperConverter(markdownConverter) backups.setSuperConverter(markdownConverter)
} }

View File

@ -9,17 +9,17 @@ import {
SUPER_EXPORT_JSON, SUPER_EXPORT_JSON,
SUPER_EXPORT_MARKDOWN, SUPER_EXPORT_MARKDOWN,
} from '@standardnotes/ui-services' } from '@standardnotes/ui-services'
import { useCallback, useEffect } from 'react' import { useCallback, useEffect, useRef } from 'react'
import { $convertToMarkdownString } from '@lexical/markdown'
import { MarkdownTransformers } from '../../MarkdownTransformers'
import { $generateHtmlFromNodes } from '@lexical/html'
import { useCommandService } from '@/Components/CommandProvider' import { useCommandService } from '@/Components/CommandProvider'
import { HeadlessSuperConverter } from '../../Tools/HeadlessSuperConverter'
export const ExportPlugin = () => { export const ExportPlugin = () => {
const application = useApplication() const application = useApplication()
const [editor] = useLexicalComposerContext() const [editor] = useLexicalComposerContext()
const commandService = useCommandService() const commandService = useCommandService()
const converter = useRef(new HeadlessSuperConverter())
const downloadData = useCallback( const downloadData = useCallback(
(data: Blob, fileName: string) => { (data: Blob, fileName: string) => {
if (!application.isNativeMobileWeb()) { if (!application.isNativeMobileWeb()) {
@ -38,7 +38,7 @@ export const ExportPlugin = () => {
const exportJson = useCallback( const exportJson = useCallback(
(title: string) => { (title: string) => {
const content = JSON.stringify(editor.toJSON()) const content = converter.current.convertString(JSON.stringify(editor.getEditorState()), 'json')
const blob = new Blob([content], { type: 'application/json' }) const blob = new Blob([content], { type: 'application/json' })
downloadData(blob, `${sanitizeFileName(title)}.json`) downloadData(blob, `${sanitizeFileName(title)}.json`)
}, },
@ -47,22 +47,18 @@ export const ExportPlugin = () => {
const exportMarkdown = useCallback( const exportMarkdown = useCallback(
(title: string) => { (title: string) => {
editor.getEditorState().read(() => { const content = converter.current.convertString(JSON.stringify(editor.getEditorState()), 'md')
const content = $convertToMarkdownString(MarkdownTransformers) const blob = new Blob([content], { type: 'text/markdown' })
const blob = new Blob([content], { type: 'text/markdown' }) downloadData(blob, `${sanitizeFileName(title)}.md`)
downloadData(blob, `${sanitizeFileName(title)}.md`)
})
}, },
[downloadData, editor], [downloadData, editor],
) )
const exportHtml = useCallback( const exportHtml = useCallback(
(title: string) => { (title: string) => {
editor.getEditorState().read(() => { const content = converter.current.convertString(JSON.stringify(editor.getEditorState()), 'html')
const content = $generateHtmlFromNodes(editor) const blob = new Blob([content], { type: 'text/html' })
const blob = new Blob([content], { type: 'text/html' }) downloadData(blob, `${sanitizeFileName(title)}.html`)
downloadData(blob, `${sanitizeFileName(title)}.html`)
})
}, },
[downloadData, editor], [downloadData, editor],
) )

View File

@ -1,7 +1,7 @@
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { useEffect } from 'react' import { useEffect } from 'react'
import { $createCodeNode } from '@lexical/code' import { $createCodeNode } from '@lexical/code'
import { $createTextNode, $getRoot } from 'lexical' import { $createTextNode, $getRoot, $nodesOfType, ParagraphNode } from 'lexical'
import { $convertToMarkdownString } from '@lexical/markdown' import { $convertToMarkdownString } from '@lexical/markdown'
import { MarkdownTransformers } from '../../MarkdownTransformers' import { MarkdownTransformers } from '../../MarkdownTransformers'
@ -15,6 +15,12 @@ export default function MarkdownPreviewPlugin({ onMarkdown }: Props): JSX.Elemen
useEffect(() => { useEffect(() => {
editor.update(() => { editor.update(() => {
const root = $getRoot() const root = $getRoot()
const paragraphs = $nodesOfType(ParagraphNode)
for (const paragraph of paragraphs) {
if (paragraph.isEmpty()) {
paragraph.remove()
}
}
const markdown = $convertToMarkdownString(MarkdownTransformers) const markdown = $convertToMarkdownString(MarkdownTransformers)
root.clear().append($createCodeNode('markdown').append($createTextNode(markdown))) root.clear().append($createCodeNode('markdown').append($createTextNode(markdown)))
root.selectEnd() root.selectEnd()

View File

@ -6,7 +6,7 @@ import Icon from '../Icon/Icon'
import Modal, { ModalAction } from '../Modal/Modal' import Modal, { ModalAction } from '../Modal/Modal'
import { EditorMenuItem } from '../NotesOptions/EditorMenuItem' import { EditorMenuItem } from '../NotesOptions/EditorMenuItem'
import { NoteViewController } from '../NoteView/Controller/NoteViewController' import { NoteViewController } from '../NoteView/Controller/NoteViewController'
import { InvisibleSuperConverter } from './Tools/InvisibleMarkdownConverter' import { HeadlessSuperConverter } from './Tools/HeadlessSuperConverter'
const SuperNoteConverter = ({ const SuperNoteConverter = ({
note, note,
@ -47,7 +47,7 @@ const SuperNoteConverter = ({
return note.text return note.text
} }
return new InvisibleSuperConverter().convertString(note.text, format) return new HeadlessSuperConverter().convertString(note.text, format)
}, [format, note]) }, [format, note])
const componentViewer = useMemo(() => { const componentViewer = useMemo(() => {

View File

@ -1,13 +1,13 @@
import { createHeadlessEditor } from '@lexical/headless' import { createHeadlessEditor } from '@lexical/headless'
import { $convertToMarkdownString } from '@lexical/markdown' import { $convertToMarkdownString } from '@lexical/markdown'
import { SuperConverterServiceInterface } from '@standardnotes/snjs' import { SuperConverterServiceInterface } from '@standardnotes/snjs'
import { LexicalEditor } from 'lexical' import { $nodesOfType, LexicalEditor, ParagraphNode } from 'lexical'
import BlocksEditorTheme from '../Lexical/Theme/Theme' import BlocksEditorTheme from '../Lexical/Theme/Theme'
import { BlockEditorNodes } from '../Lexical/Nodes/AllNodes' import { BlockEditorNodes } from '../Lexical/Nodes/AllNodes'
import { MarkdownTransformers } from '../MarkdownTransformers' import { MarkdownTransformers } from '../MarkdownTransformers'
import { $generateHtmlFromNodes } from '@lexical/html' import { $generateHtmlFromNodes } from '@lexical/html'
export class InvisibleSuperConverter implements SuperConverterServiceInterface { export class HeadlessSuperConverter implements SuperConverterServiceInterface {
private editor: LexicalEditor private editor: LexicalEditor
constructor() { constructor() {
@ -33,9 +33,16 @@ export class InvisibleSuperConverter implements SuperConverterServiceInterface {
() => { () => {
switch (format) { switch (format) {
case 'txt': case 'txt':
case 'md': case 'md': {
const paragraphs = $nodesOfType(ParagraphNode)
for (const paragraph of paragraphs) {
if (paragraph.isEmpty()) {
paragraph.remove()
}
}
content = $convertToMarkdownString(MarkdownTransformers) content = $convertToMarkdownString(MarkdownTransformers)
break break
}
case 'html': case 'html':
content = $generateHtmlFromNodes(this.editor) content = $generateHtmlFromNodes(this.editor)
break break

View File

@ -1,5 +1,5 @@
import { WebApplication } from '@/Application/WebApplication' import { WebApplication } from '@/Application/WebApplication'
import { InvisibleSuperConverter } from '@/Components/SuperEditor/Tools/InvisibleMarkdownConverter' import { HeadlessSuperConverter } from '@/Components/SuperEditor/Tools/HeadlessSuperConverter'
import { PrefDefaults } from '@/Constants/PrefDefaults' import { PrefDefaults } from '@/Constants/PrefDefaults'
import { NoteType, PrefKey, SNNote } from '@standardnotes/snjs' import { NoteType, PrefKey, SNNote } from '@standardnotes/snjs'
@ -43,7 +43,7 @@ export const getNoteBlob = (application: WebApplication, note: SNNote) => {
break break
} }
const content = const content =
note.noteType === NoteType.Super ? new InvisibleSuperConverter().convertString(note.text, format) : note.text note.noteType === NoteType.Super ? new HeadlessSuperConverter().convertString(note.text, format) : note.text
const blob = new Blob([content], { const blob = new Blob([content], {
type, type,
}) })