Merge pull request #497 from matrix-org/dbkr/richtext_use_markdown_wrapper
Make RTE mode use the new Markdown wrapper class
This commit is contained in:
commit
60ce49910a
3 changed files with 36 additions and 36 deletions
|
@ -15,17 +15,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type SyntheticKeyboardEvent from 'react/lib/SyntheticKeyboardEvent';
|
import type SyntheticKeyboardEvent from 'react/lib/SyntheticKeyboardEvent';
|
||||||
import marked from 'marked';
|
|
||||||
marked.setOptions({
|
|
||||||
renderer: new marked.Renderer(),
|
|
||||||
gfm: true,
|
|
||||||
tables: true,
|
|
||||||
breaks: false,
|
|
||||||
pedantic: false,
|
|
||||||
sanitize: true,
|
|
||||||
smartLists: true,
|
|
||||||
smartypants: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
import {Editor, EditorState, RichUtils, CompositeDecorator,
|
import {Editor, EditorState, RichUtils, CompositeDecorator,
|
||||||
convertFromRaw, convertToRaw, Modifier, EditorChangeType,
|
convertFromRaw, convertToRaw, Modifier, EditorChangeType,
|
||||||
|
@ -50,6 +39,7 @@ import * as RichText from '../../../RichText';
|
||||||
import * as HtmlUtils from '../../../HtmlUtils';
|
import * as HtmlUtils from '../../../HtmlUtils';
|
||||||
import Autocomplete from './Autocomplete';
|
import Autocomplete from './Autocomplete';
|
||||||
import {Completion} from "../../../autocomplete/Autocompleter";
|
import {Completion} from "../../../autocomplete/Autocompleter";
|
||||||
|
import Markdown from '../../../Markdown';
|
||||||
|
|
||||||
const TYPING_USER_TIMEOUT = 10000, TYPING_SERVER_TIMEOUT = 30000;
|
const TYPING_USER_TIMEOUT = 10000, TYPING_SERVER_TIMEOUT = 30000;
|
||||||
|
|
||||||
|
@ -64,12 +54,6 @@ function stateToMarkdown(state) {
|
||||||
''); // this is *not* a zero width space, trust me :)
|
''); // this is *not* a zero width space, trust me :)
|
||||||
}
|
}
|
||||||
|
|
||||||
function mdownToHtml(mdown: string): string {
|
|
||||||
let html = marked(mdown) || "";
|
|
||||||
html = html.trim();
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The textInput part of the MessageComposer
|
* The textInput part of the MessageComposer
|
||||||
*/
|
*/
|
||||||
|
@ -416,8 +400,8 @@ export default class MessageComposerInput extends React.Component {
|
||||||
enableRichtext(enabled: boolean) {
|
enableRichtext(enabled: boolean) {
|
||||||
let contentState = null;
|
let contentState = null;
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
const html = mdownToHtml(this.state.editorState.getCurrentContent().getPlainText());
|
const md = new Markdown(this.state.editorState.getCurrentContent().getPlainText());
|
||||||
contentState = RichText.HTMLtoContentState(html);
|
contentState = RichText.HTMLtoContentState(md.toHTML());
|
||||||
} else {
|
} else {
|
||||||
let markdown = stateToMarkdown(this.state.editorState.getCurrentContent());
|
let markdown = stateToMarkdown(this.state.editorState.getCurrentContent());
|
||||||
if (markdown[markdown.length - 1] === '\n') {
|
if (markdown[markdown.length - 1] === '\n') {
|
||||||
|
@ -499,7 +483,7 @@ export default class MessageComposerInput extends React.Component {
|
||||||
if (!contentState.hasText()) {
|
if (!contentState.hasText()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let contentText = contentState.getPlainText(), contentHTML;
|
let contentText = contentState.getPlainText(), contentHTML;
|
||||||
|
|
||||||
|
@ -534,24 +518,37 @@ export default class MessageComposerInput extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.isRichtextEnabled) {
|
if (this.state.isRichtextEnabled) {
|
||||||
contentHTML = RichText.contentStateToHTML(contentState);
|
contentHTML = HtmlUtils.stripParagraphs(
|
||||||
|
RichText.contentStateToHTML(contentState)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
contentHTML = mdownToHtml(contentText);
|
const md = new Markdown(contentText);
|
||||||
|
if (!md.isPlainText()) {
|
||||||
|
contentHTML = md.toHTML();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contentHTML = HtmlUtils.stripParagraphs(contentHTML);
|
let sendHtmlFn = this.client.sendHtmlMessage;
|
||||||
|
let sendTextFn = this.client.sendTextMessage;
|
||||||
let sendFn = this.client.sendHtmlMessage;
|
|
||||||
|
|
||||||
if (contentText.startsWith('/me')) {
|
if (contentText.startsWith('/me')) {
|
||||||
contentText = contentText.replace('/me', '');
|
contentText = contentText.replace('/me', '');
|
||||||
// bit of a hack, but the alternative would be quite complicated
|
// bit of a hack, but the alternative would be quite complicated
|
||||||
contentHTML = contentHTML.replace('/me', '');
|
if (contentHTML) contentHTML = contentHTML.replace('/me', '');
|
||||||
sendFn = this.client.sendHtmlEmote;
|
sendHtmlFn = this.client.sendHtmlEmote;
|
||||||
|
sendTextFn = this.client.sendEmoteMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sentHistory.push(contentHTML);
|
// XXX: We don't actually seem to use this history?
|
||||||
let sendMessagePromise = sendFn.call(this.client, this.props.room.roomId, contentText, contentHTML);
|
this.sentHistory.push(contentHTML || contentText);
|
||||||
|
let sendMessagePromise;
|
||||||
|
if (contentHTML) {
|
||||||
|
sendMessagePromise = sendHtmlFn.call(
|
||||||
|
this.client, this.props.room.roomId, contentText, contentHTML
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
sendMessagePromise = sendTextFn.call(this.client, this.props.room.roomId, contentText);
|
||||||
|
}
|
||||||
|
|
||||||
sendMessagePromise.then(() => {
|
sendMessagePromise.then(() => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
|
|
|
@ -68,15 +68,17 @@ describe('MessageComposerInput', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not send messages when composer is empty', () => {
|
it('should not send messages when composer is empty', () => {
|
||||||
const spy = sinon.spy(client, 'sendHtmlMessage');
|
const textSpy = sinon.spy(client, 'sendTextMessage');
|
||||||
|
const htmlSpy = sinon.spy(client, 'sendHtmlMessage');
|
||||||
mci.enableRichtext(true);
|
mci.enableRichtext(true);
|
||||||
mci.handleReturn(sinon.stub());
|
mci.handleReturn(sinon.stub());
|
||||||
|
|
||||||
expect(spy.calledOnce).toEqual(false, 'should not send message');
|
expect(textSpy.calledOnce).toEqual(false, 'should not send text message');
|
||||||
|
expect(htmlSpy.calledOnce).toEqual(false, 'should not send html message');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not change content unnecessarily on RTE -> Markdown conversion', () => {
|
it('should not change content unnecessarily on RTE -> Markdown conversion', () => {
|
||||||
const spy = sinon.spy(client, 'sendHtmlMessage');
|
const spy = sinon.spy(client, 'sendTextMessage');
|
||||||
mci.enableRichtext(true);
|
mci.enableRichtext(true);
|
||||||
addTextToDraft('a');
|
addTextToDraft('a');
|
||||||
mci.handleKeyCommand('toggle-mode');
|
mci.handleKeyCommand('toggle-mode');
|
||||||
|
@ -87,7 +89,7 @@ describe('MessageComposerInput', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not change content unnecessarily on Markdown -> RTE conversion', () => {
|
it('should not change content unnecessarily on Markdown -> RTE conversion', () => {
|
||||||
const spy = sinon.spy(client, 'sendHtmlMessage');
|
const spy = sinon.spy(client, 'sendTextMessage');
|
||||||
mci.enableRichtext(false);
|
mci.enableRichtext(false);
|
||||||
addTextToDraft('a');
|
addTextToDraft('a');
|
||||||
mci.handleKeyCommand('toggle-mode');
|
mci.handleKeyCommand('toggle-mode');
|
||||||
|
@ -97,7 +99,7 @@ describe('MessageComposerInput', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send emoji messages in rich text', () => {
|
it('should send emoji messages in rich text', () => {
|
||||||
const spy = sinon.spy(client, 'sendHtmlMessage');
|
const spy = sinon.spy(client, 'sendTextMessage');
|
||||||
mci.enableRichtext(true);
|
mci.enableRichtext(true);
|
||||||
addTextToDraft('☹');
|
addTextToDraft('☹');
|
||||||
mci.handleReturn(sinon.stub());
|
mci.handleReturn(sinon.stub());
|
||||||
|
@ -106,7 +108,7 @@ describe('MessageComposerInput', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send emoji messages in Markdown', () => {
|
it('should send emoji messages in Markdown', () => {
|
||||||
const spy = sinon.spy(client, 'sendHtmlMessage');
|
const spy = sinon.spy(client, 'sendTextMessage');
|
||||||
mci.enableRichtext(false);
|
mci.enableRichtext(false);
|
||||||
addTextToDraft('☹');
|
addTextToDraft('☹');
|
||||||
mci.handleReturn(sinon.stub());
|
mci.handleReturn(sinon.stub());
|
||||||
|
@ -139,7 +141,7 @@ describe('MessageComposerInput', () => {
|
||||||
// });
|
// });
|
||||||
|
|
||||||
it('should insert formatting characters in Markdown mode', () => {
|
it('should insert formatting characters in Markdown mode', () => {
|
||||||
const spy = sinon.spy(client, 'sendHtmlMessage');
|
const spy = sinon.spy(client, 'sendTextMessage');
|
||||||
mci.enableRichtext(false);
|
mci.enableRichtext(false);
|
||||||
mci.handleKeyCommand('italic');
|
mci.handleKeyCommand('italic');
|
||||||
mci.handleReturn(sinon.stub());
|
mci.handleReturn(sinon.stub());
|
||||||
|
|
|
@ -54,6 +54,7 @@ export function stubClient() {
|
||||||
},
|
},
|
||||||
setAccountData: sinon.stub(),
|
setAccountData: sinon.stub(),
|
||||||
sendTyping: sinon.stub().returns(q({})),
|
sendTyping: sinon.stub().returns(q({})),
|
||||||
|
sendTextMessage: () => q({}),
|
||||||
sendHtmlMessage: () => q({}),
|
sendHtmlMessage: () => q({}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue