Skip to content

Commit

Permalink
fix(markdown): copying html into markdown (#7290)
Browse files Browse the repository at this point in the history
* fix(markdown): copying html into markdown //issues/7233

* refactor: sync markdown html parsing script with original

* fix: lint

---------

Co-authored-by: Anze Demsar <anze.demsar@p-m.si>
  • Loading branch information
hip3r and demshy authored Nov 12, 2024
1 parent d9655ea commit f6959e2
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { markdownToSlate, slateToMarkdown } from '../serializers';
import withShortcodes from './plugins/shortcodes/withShortcodes';
import insertShortcode from './plugins/shortcodes/insertShortcode';
import defaultEmptyBlock from './plugins/blocks/defaultEmptyBlock';
import withHtml from './plugins/html/withHtml';

function visualEditorStyles({ minimal }) {
return `
Expand Down Expand Up @@ -97,7 +98,9 @@ function Editor(props) {

const editor = useMemo(
() =>
withReact(withHistory(withShortcodes(withBlocks(withLists(withInlines(createEditor())))))),
withHtml(
withReact(withHistory(withShortcodes(withBlocks(withLists(withInlines(createEditor())))))),
),
[],
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// source: https://github.com/ianstormtaylor/slate/blob/main/site/examples/ts/paste-html.tsx
import { jsx } from 'slate-hyperscript';
import { Transforms } from 'slate';

const ELEMENT_TAGS = {
A: el => ({ type: 'link', url: el.getAttribute('href') }),
BLOCKQUOTE: () => ({ type: 'quote' }),
H1: () => ({ type: 'heading-one' }),
H2: () => ({ type: 'heading-two' }),
H3: () => ({ type: 'heading-three' }),
H4: () => ({ type: 'heading-four' }),
H5: () => ({ type: 'heading-five' }),
H6: () => ({ type: 'heading-six' }),
IMG: el => ({ type: 'image', url: el.getAttribute('src') }),
LI: () => ({ type: 'list-item' }),
OL: () => ({ type: 'numbered-list' }),
P: () => ({ type: 'paragraph' }),
PRE: () => ({ type: 'code' }),
UL: () => ({ type: 'bulleted-list' }),
};

// COMPAT: `B` is omitted here because Google Docs uses `<b>` in weird ways.
const TEXT_TAGS = {
CODE: () => ({ code: true }),
DEL: () => ({ strikethrough: true }),
EM: () => ({ italic: true }),
I: () => ({ italic: true }),
S: () => ({ strikethrough: true }),
STRONG: () => ({ bold: true }),
U: () => ({ underline: true }),
};

function deserialize(el) {
if (el.nodeType === 3) {
return el.textContent;
} else if (el.nodeType !== 1) {
return null;
} else if (el.nodeName === 'BR') {
return '\n';
}

const { nodeName } = el;
let parent = el;

if (nodeName === 'PRE' && el.childNodes[0] && el.childNodes[0].nodeName === 'CODE') {
parent = el.childNodes[0];
}
let children = Array.from(parent.childNodes).map(deserialize).flat();

if (children.length === 0) {
children = [{ text: '' }];
}

if (el.nodeName === 'BODY') {
return jsx('fragment', {}, children);
}

if (ELEMENT_TAGS[nodeName]) {
const attrs = ELEMENT_TAGS[nodeName](el);
return jsx('element', attrs, children);
}

if (TEXT_TAGS[nodeName]) {
const attrs = TEXT_TAGS[nodeName](el);
return children.map(child => jsx('text', attrs, child));
}

return children;
}

function withHtml(editor) {
const { insertData, isInline, isVoid } = editor;

editor.isInline = element => {
return element.type === 'link' ? true : isInline(element);
};

editor.isVoid = element => {
return element.type === 'image' ? true : isVoid(element);
};

editor.insertData = data => {
const html = data.getData('text/html');

if (html) {
const parsed = new DOMParser().parseFromString(html, 'text/html');
const fragment = deserialize(parsed.body);
Transforms.insertFragment(editor, fragment);
return;
}

insertData(data);
};

return editor;
}

export default withHtml;
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,8 @@ function NumberedList(props) {
}

function Link(props) {
const url = props.url;
const title = props.title || url;
const url = props.element.url;
const title = props.element.title || url;

return (
<StyledA href={url} title={title} {...props.attributes}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ export default function slateToRemark(value, { voidCodeBlock }) {
*/
case 'link': {
const { title, data } = node;
return u(typeMap[node.type], { url: data?.url, title, ...data }, children);
return u(typeMap[node.type], { url: node.url, title, ...data }, children);
}

/**
Expand Down

0 comments on commit f6959e2

Please sign in to comment.