make HTML pasting work

pull/21833/head
Matthew Hodgson 2018-05-19 23:33:07 +01:00
parent 1536ab433a
commit 1f05aea884
1 changed files with 53 additions and 25 deletions

View File

@ -82,6 +82,32 @@ const ENTITY_TYPES = {
// (we use 'line' for oneliners however) // (we use 'line' for oneliners however)
const DEFAULT_NODE = 'paragraph'; const DEFAULT_NODE = 'paragraph';
// map HTML elements through to our Slate schema node types
// used for the HTML deserializer.
// (We don't use the same names so that they are closer to the MD serializer's schema)
const BLOCK_TAGS = {
p: 'paragraph',
blockquote: 'block-quote',
ul: 'bulleted-list',
h1: 'heading-one',
h2: 'heading-two',
h3: 'heading-three',
li: 'list-item',
ol: 'numbered-list',
pre: 'code-block',
};
const MARK_TAGS = {
strong: 'bold',
b: 'bold', // deprecated
em: 'italic',
i: 'italic', // deprecated
code: 'code',
u: 'underline',
del: 'strikethrough',
strike: 'strikethrough', // deprecated
s: 'strikethrough', // deprecated
};
function onSendMessageFailed(err, room) { function onSendMessageFailed(err, room) {
// XXX: temporary logging to try to diagnose // XXX: temporary logging to try to diagnose
@ -153,6 +179,25 @@ export default class MessageComposerInput extends React.Component {
this.html = new Html({ this.html = new Html({
rules: [ rules: [
{ {
deserialize: (el, next) => {
const tag = el.tagName.toLowerCase();
let type = BLOCK_TAGS[tag];
if (type) {
return {
object: 'block',
type: type,
nodes: next(el.childNodes),
}
}
type = MARK_TAGS[tag];
if (type) {
return {
object: 'mark',
type: type,
nodes: next(el.childNodes),
}
}
},
serialize: (obj, children) => { serialize: (obj, children) => {
if (obj.object === 'block' || obj.object === 'inline') { if (obj.object === 'block' || obj.object === 'inline') {
return this.renderNode({ return this.renderNode({
@ -763,34 +808,17 @@ export default class MessageComposerInput extends React.Component {
if (transfer.type === "files") { if (transfer.type === "files") {
return this.props.onFilesPasted(transfer.files); return this.props.onFilesPasted(transfer.files);
} }
if (transfer.type === "html") { else if (transfer.type === "html") {
const fragment = this.html.deserialize(transfer.html);
if (this.state.isRichtextEnabled) {
return change.insertFragment(fragment.document);
}
else {
return change.insertText(this.md.serialize(fragment));
}
} }
}; };
/*
onTextPasted = (text: string, html?: string) => {
const currentSelection = this.state.editorState.getSelection();
const currentContent = this.state.editorState.getCurrentContent();
let contentState = null;
if (html && this.state.isRichtextEnabled) {
contentState = Modifier.replaceWithFragment(
currentContent,
currentSelection,
RichText.htmlToContentState(html).getBlockMap(),
);
} else {
contentState = Modifier.replaceText(currentContent, currentSelection, text);
}
let newEditorState = EditorState.push(this.state.editorState, contentState, 'insert-characters');
newEditorState = EditorState.forceSelection(newEditorState, contentState.getSelectionAfter());
this.onEditorContentChanged(newEditorState);
return true;
};
*/
handleReturn = (ev, change) => { handleReturn = (ev, change) => {
if (ev.shiftKey) { if (ev.shiftKey) {