Skip to content

Instantly share code, notes, and snippets.

@zGrav
Last active January 7, 2018 06:13
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zGrav/440fdbe83d7eca8455362ccfd2e58662 to your computer and use it in GitHub Desktop.
Save zGrav/440fdbe83d7eca8455362ccfd2e58662 to your computer and use it in GitHub Desktop.
import Html from 'slate-html-serializer';
// import React from 'react';
// import { FunctionTypes } from 'constants/editor/ViewModel';
// import { Nodes } from 'components/editor';
import { getEventTransfer } from 'slate-react';
import { BlockTypes } from 'constants/editor';
import { Block } from 'slate';
const MARK_TAGS = {
strong: 'bold',
em: 'italic',
u: 'underline',
s: 'strikethrough',
code: 'code',
};
const BLOCK_TAGS = {
blockquote: {
type: BlockTypes.PARAGRAPH,
data: {
depth: 1,
readOnly: false,
},
},
pre: {
type: BlockTypes.PARAGRAPH,
data: {
depth: 1,
readOnly: false,
},
},
p: {
type: BlockTypes.PARAGRAPH,
data: {
depth: 1,
readOnly: false,
},
},
li: {
type: BlockTypes.LIST_ITEM,
data: {
depth: 1,
readOnly: false,
},
},
h1: {
type: BlockTypes.HEADLINE,
data: {
depth: 1,
readOnly: false,
},
},
h2: {
type: BlockTypes.HEADLINE,
data: {
depth: 2,
readOnly: false,
},
},
h3: {
type: BlockTypes.HEADLINE,
data: {
depth: 3,
readOnly: false,
},
},
h4: {
type: BlockTypes.HEADLINE,
data: {
depth: 4,
readOnly: false,
},
},
h5: {
type: BlockTypes.HEADLINE,
data: {
depth: 5,
readOnly: false,
},
},
h6: {
type: BlockTypes.HEADLINE,
data: {
depth: 6,
readOnly: false,
},
},
table: {
type: BlockTypes.TABLE,
data: {
depth: 1,
readOnly: false,
},
},
th: {
type: BlockTypes.TABLE_HEADER_CELL,
data: {
depth: 1,
readOnly: false,
},
},
tr: {
type: BlockTypes.TABLE_ROW,
data: {
depth: 1,
readOnly: false,
},
},
td: {
type: BlockTypes.TABLE_CELL,
data: {
depth: 1,
readOnly: false,
},
},
};
const RULES = [
{
deserialize(el, next) {
let attr = null;
if (el && el.getAttribute) {
attr = el.getAttribute('parent');
if (attr) {
attr = attr.replace(/Block /g, '');
attr = attr.replace(/Map /g, '');
attr = attr.replace(/Character /g, '');
attr = attr.replace(/Set /g, '');
attr = attr.replace(/Mark {/g, '');
attr = attr.replace(/List /g, '');
attr = attr.replace(/Text /g, '');
attr = attr.replace(/} },/g, '},');
attr = attr.replace('[object Object]', '[]');
attr = JSON.parse(attr);
}
}
const block = BLOCK_TAGS[el.tagName.toLowerCase()];
if (!block) return;
const build = {
kind: 'block',
...block,
nodes: next(el.childNodes),
};
if (attr && attr.type && attr.key) {
build.data.parentKey = attr.key;
build.data.parentType = attr.type;
}
return build;
},
},
{
deserialize(el, next) {
const mark = MARK_TAGS[el.tagName.toLowerCase()];
if (!mark) return;
return {
kind: 'mark',
type: mark,
nodes: next(el.childNodes),
};
},
},
{
// Special case for code blocks, which need to grab the nested childNodes.
deserialize(el, next) {
if (el.tagName.toLowerCase() !== 'pre') return;
const code = el.childNodes[0];
const childNodes = code && code.tagName.toLowerCase() === 'code'
? code.childNodes
: el.childNodes;
return {
kind: 'block',
type: 'code',
nodes: next(childNodes),
};
},
},
{
// Special case for images, to grab their src.
deserialize(el, next) {
if (el.tagName.toLowerCase() !== 'img') return;
return {
kind: 'block',
type: BlockTypes.IMAGE,
isVoid: true,
nodes: next(el.childNodes),
data: {
width: el.getAttribute('width'),
height: el.getAttribute('height'),
uri: el.getAttribute('src').substring(el.getAttribute('src').indexOf('api/') + 3),
},
};
},
},
{
// Special case for links, to grab their href.
deserialize(el, next) {
if (el.tagName.toLowerCase() !== 'a') return;
return {
kind: 'inline',
type: 'link',
nodes: next(el.childNodes),
data: {
href: el.getAttribute('href'),
},
};
},
},
];
/**
* Create a new HTML serializer with `RULES`.
*
* @type {Html}
*/
const serializer = new Html({ rules: RULES });
let nodes = [];
let lists = [];
let listBlock = null;
const pasteHandler = (event, change) => {
// console.log('onPaste', event, change.value.toJS());
const transfer = getEventTransfer(event);
// console.log('!! ', transfer);
if (!transfer.html) return;
const { document } = serializer.deserialize(transfer.html);
document.nodes.forEach((n, idx, arr) => {
// console.log('??? ', n);
if (n.data.get('parentType') === BlockTypes.UNORDERED_LIST || n.data.get('parentType') === BlockTypes.ORDERED_LIST) {
lists.push({
key: n.data.get('parentKey'),
type: n.data.get('parentType'),
});
} else {
if (lists.length > 0) {
lists.forEach((l, listindex) => {
if (!listBlock) {
listBlock = {
kind: 'block',
type: l.type,
nodes: [],
};
listBlock.nodes.push(arr.toJS()[listindex]);
} else {
listBlock.nodes.push(arr.toJS()[listindex]);
}
});
nodes.push(listBlock);
listBlock = null;
lists = [];
}
nodes.push(n.toJS());
}
});
if (nodes.length === 0 && lists.length > 0) {
lists.forEach((l, listindex) => {
if (!listBlock) {
listBlock = {
kind: 'block',
type: l.type,
nodes: [],
};
listBlock.nodes.push(document.nodes.toJS()[listindex]);
} else {
listBlock.nodes.push(document.nodes.toJS()[listindex]);
}
});
nodes.push(listBlock);
listBlock = null;
lists = [];
}
nodes.forEach(n => change.insertBlock(Block.create(n)));
// change.insertFragment(document);
// console.log('>?>>>>> ', document.toJS());
nodes = [];
return true;
};
export default {
onPaste: pasteHandler,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment