diff --git a/src/ComposerHistoryManager.js b/src/ComposerHistoryManager.js index 938be9eee4..e52a8a677f 100644 --- a/src/ComposerHistoryManager.js +++ b/src/ComposerHistoryManager.js @@ -34,17 +34,15 @@ class HistoryItem { format: MessageFormat = 'rich'; constructor(value: ?Value, format: ?MessageFormat) { - this.rawContentState = contentState ? convertToRaw(contentState) : null; + this.value = value; this.format = format; - } toValue(outputFormat: MessageFormat): Value { if (outputFormat === 'markdown') { if (this.format === 'rich') { // convert a rich formatted history entry to its MD equivalent - const markdown = new Markdown({}); - return new Value({ data: markdown.serialize(value) }); + return Plain.deserialize(Md.serialize(value)); // return ContentState.createFromText(RichText.stateToMarkdown(contentState)); } else if (this.format === 'markdown') { @@ -53,9 +51,7 @@ class HistoryItem { } else if (outputFormat === 'rich') { if (this.format === 'markdown') { // convert MD formatted string to its rich equivalent. - const plain = new Plain({}); - const md = new Md({}); - return md.deserialize(plain.serialize(value)); + return Md.deserialize(Plain.serialize(value)); // return RichText.htmlToContentState(new Markdown(contentState.getPlainText()).toHTML()); } else if (this.format === 'rich') { diff --git a/src/RichText.js b/src/RichText.js index 12274ee9f3..7ffb4dd785 100644 --- a/src/RichText.js +++ b/src/RichText.js @@ -1,4 +1,24 @@ +/* +Copyright 2015 - 2017 OpenMarket Ltd +Copyright 2017 Vector Creations Ltd +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + import React from 'react'; + +/* import { Editor, EditorState, @@ -12,11 +32,15 @@ import { SelectionState, Entity, } from 'draft-js'; +import { stateToMarkdown as __stateToMarkdown } from 'draft-js-export-markdown'; +*/ + +import Html from 'slate-html-serializer'; + import * as sdk from './index'; import * as emojione from 'emojione'; -import {stateToHTML} from 'draft-js-export-html'; -import {SelectionRange} from "./autocomplete/Autocompleter"; -import {stateToMarkdown as __stateToMarkdown} from 'draft-js-export-markdown'; + +import { SelectionRange } from "./autocomplete/Autocompleter"; const MARKDOWN_REGEX = { LINK: /(?:\[([^\]]+)\]\(([^\)]+)\))|\<(\w+:\/\/[^\>]+)\>/g, @@ -33,6 +57,7 @@ const EMOJI_REGEX = new RegExp(emojione.unicodeRegexp, 'g'); const ZWS_CODE = 8203; const ZWS = String.fromCharCode(ZWS_CODE); // zero width space + export function stateToMarkdown(state) { return __stateToMarkdown(state) .replace( @@ -40,19 +65,12 @@ export function stateToMarkdown(state) { ''); // this is *not* a zero width space, trust me :) } -export const contentStateToHTML = (contentState: ContentState) => { - return stateToHTML(contentState, { - inlineStyles: { - UNDERLINE: { - element: 'u', - }, - }, - }); -}; +export const editorStateToHTML = (editorState: Value) => { + return Html.deserialize(editorState); +} -export function htmlToContentState(html: string): ContentState { - const blockArray = convertFromHTML(html).contentBlocks; - return ContentState.createFromBlockArray(blockArray); +export function htmlToEditorState(html: string): Value { + return Html.serialize(html); } function unicodeToEmojiUri(str) { diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 9a0863810e..53f7a6d474 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -19,7 +19,7 @@ import PropTypes from 'prop-types'; import type SyntheticKeyboardEvent from 'react/lib/SyntheticKeyboardEvent'; import { Editor } from 'slate-react'; -import { Value, Document } from 'slate'; +import { Value, Document, Event } from 'slate'; import Html from 'slate-html-serializer'; import { Markdown as Md } from 'slate-md-serializer'; @@ -539,15 +539,12 @@ export default class MessageComposerInput extends React.Component { // const md = new Markdown(this.state.editorState.getCurrentContent().getPlainText()); // contentState = RichText.htmlToContentState(md.toHTML()); - const plain = new Plain({}); - const md = new Md({}); - value = md.deserialize(plain.serialize(this.state.editorState)); + value = Md.deserialize(Plain.serialize(this.state.editorState)); } else { // let markdown = RichText.stateToMarkdown(this.state.editorState.getCurrentContent()); // value = ContentState.createFromText(markdown); - const markdown = new Markdown({}); - value = Value({ data: markdown.serialize(value) }); + value = Plain.deserialize(Md.serialize(this.state.editorState)); } Analytics.setRichtextMode(enabled); @@ -559,6 +556,12 @@ export default class MessageComposerInput extends React.Component { SettingsStore.setValue("MessageComposerInput.isRichTextEnabled", null, SettingLevel.ACCOUNT, enabled); } + onKeyDown = (ev: Event, change: Change, editor: Editor) => { + if (ev.keyCode === KeyCode.ENTER) { + return this.handleReturn(ev); + } + } + handleKeyCommand = (command: string): boolean => { /* if (command === 'toggle-mode') { @@ -721,10 +724,7 @@ export default class MessageComposerInput extends React.Component { } */ - const plain = new Plain({}); - value = md.deserialize(); - - let contentText = plain.serialize(contentState); + let contentText = Plain.serialize(contentState); let contentHTML; /* @@ -808,10 +808,10 @@ export default class MessageComposerInput extends React.Component { shouldSendHTML = hasLink; } */ - let shouldSendHTML = true; + let shouldSendHTML = true; if (shouldSendHTML) { contentHTML = HtmlUtils.processHtmlForSending( - RichText.contentStateToHTML(contentState), + RichText.editorStateToHTML(contentState), ); } } else { @@ -840,11 +840,12 @@ export default class MessageComposerInput extends React.Component { return blockText; }).join('\n'); */ - const md = new Markdown(pt); + const md = new Markdown(contentText); // if contains no HTML and we're not quoting (needing HTML) if (md.isPlainText() && !mustSendHTML) { contentText = md.toPlaintext(); } else { + contentText = md.toPlaintext(); contentHTML = md.toHTML(); } } @@ -898,7 +899,6 @@ export default class MessageComposerInput extends React.Component { }); } - this.client.sendMessage(this.props.room.roomId, content).then((res) => { dis.dispatch({ action: 'message_sent', @@ -909,7 +909,7 @@ export default class MessageComposerInput extends React.Component { this.setState({ editorState: this.createEditorState(), - }); + }, ()=>{ this.refs.editor.focus() }); return true; }; @@ -1237,6 +1237,7 @@ export default class MessageComposerInput extends React.Component { placeholder={this.props.placeholder} value={this.state.editorState} onChange={this.onEditorContentChanged} + onKeyDown={this.onKeyDown} /* blockStyleFn={MessageComposerInput.getBlockStyle} keyBindingFn={MessageComposerInput.getKeyBinding}