adds a method to deserialize pasted HTML into RichText

This commit is contained in:
James
2020-10-03 15:55:38 -04:00
parent e00a2eeef7
commit 31487fb022

View File

@@ -0,0 +1,96 @@
import { Transforms } from 'slate';
import { jsx } from 'slate-hyperscript';
const ELEMENT_TAGS = {
A: (el) => ({ type: 'link', newTab: el.getAttribute('target') === '_blank', url: el.getAttribute('href') }),
BLOCKQUOTE: () => ({ type: 'blockquote' }),
H1: () => ({ type: 'h1' }),
H2: () => ({ type: 'h2' }),
H3: () => ({ type: 'h3' }),
H4: () => ({ type: 'h4' }),
H5: () => ({ type: 'h5' }),
H6: () => ({ type: 'h6' }),
IMG: (el) => ({ type: 'image', url: el.getAttribute('src') }),
LI: () => ({ type: 'li' }),
OL: () => ({ type: 'ol' }),
P: () => ({ type: 'paragraph' }),
PRE: () => ({ type: 'code' }),
UL: () => ({ type: 'ul' }),
};
const TEXT_TAGS = {
CODE: () => ({ code: true }),
DEL: () => ({ strikethrough: true }),
EM: () => ({ italic: true }),
I: () => ({ italic: true }),
S: () => ({ strikethrough: true }),
STRONG: () => ({ bold: true }),
U: () => ({ underline: true }),
};
const deserialize = (el) => {
if (el.nodeType === 3) {
return el.textContent;
} if (el.nodeType !== 1) {
return null;
} 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;
}
const children = Array.from(parent.childNodes)
.map(deserialize)
.flat();
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;
};
const withHTML = (incomingEditor) => {
const { insertData, isInline, isVoid } = incomingEditor;
const editor = incomingEditor;
editor.isInline = (element) => (element.type === 'link' ? true : isInline(element));
editor.isVoid = (element) => (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;