[IMPROVEMENT] Markdown perf (#1796)
This commit is contained in:
parent
64002ba149
commit
39d9a00933
File diff suppressed because it is too large
Load Diff
|
@ -7,7 +7,7 @@ import { themes } from '../../constants/colors';
|
|||
import styles from './styles';
|
||||
|
||||
const AtMention = React.memo(({
|
||||
mention, mentions, username, navToRoomInfo, preview, style = [], useRealName, theme
|
||||
mention, mentions, username, navToRoomInfo, style = [], useRealName, theme
|
||||
}) => {
|
||||
let mentionStyle = { ...styles.mention, color: themes[theme].buttonText };
|
||||
if (mention === 'all' || mention === 'here') {
|
||||
|
@ -40,8 +40,8 @@ const AtMention = React.memo(({
|
|||
if (user) {
|
||||
return (
|
||||
<Text
|
||||
style={[preview ? { ...styles.text, color: themes[theme].bodyText } : mentionStyle, ...style]}
|
||||
onPress={preview ? undefined : handlePress}
|
||||
style={[mentionStyle, ...style]}
|
||||
onPress={handlePress}
|
||||
>
|
||||
{useRealName ? user.name : user.username}
|
||||
</Text>
|
||||
|
@ -60,7 +60,6 @@ AtMention.propTypes = {
|
|||
username: PropTypes.string,
|
||||
navToRoomInfo: PropTypes.func,
|
||||
style: PropTypes.array,
|
||||
preview: PropTypes.bool,
|
||||
useRealName: PropTypes.bool,
|
||||
theme: PropTypes.string,
|
||||
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
|
||||
|
|
|
@ -7,7 +7,7 @@ import { themes } from '../../constants/colors';
|
|||
import styles from './styles';
|
||||
|
||||
const Hashtag = React.memo(({
|
||||
hashtag, channels, navToRoomInfo, preview, style = [], theme
|
||||
hashtag, channels, navToRoomInfo, style = [], theme
|
||||
}) => {
|
||||
const handlePress = () => {
|
||||
const index = channels.findIndex(channel => channel.name === hashtag);
|
||||
|
@ -21,8 +21,8 @@ const Hashtag = React.memo(({
|
|||
if (channels && channels.length && channels.findIndex(channel => channel.name === hashtag) !== -1) {
|
||||
return (
|
||||
<Text
|
||||
style={[preview ? { ...styles.text, color: themes[theme].bodyText } : styles.mention, ...style]}
|
||||
onPress={preview ? undefined : handlePress}
|
||||
style={[styles.mention, ...style]}
|
||||
onPress={handlePress}
|
||||
>
|
||||
{hashtag}
|
||||
</Text>
|
||||
|
@ -39,7 +39,6 @@ Hashtag.propTypes = {
|
|||
hashtag: PropTypes.string,
|
||||
navToRoomInfo: PropTypes.func,
|
||||
style: PropTypes.array,
|
||||
preview: PropTypes.bool,
|
||||
theme: PropTypes.string,
|
||||
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import EventEmitter from '../../utils/events';
|
|||
import I18n from '../../i18n';
|
||||
|
||||
const Link = React.memo(({
|
||||
children, link, preview, theme
|
||||
children, link, theme
|
||||
}) => {
|
||||
const handlePress = () => {
|
||||
if (!link) {
|
||||
|
@ -28,13 +28,9 @@ const Link = React.memo(({
|
|||
// if you have a [](https://rocket.chat) render https://rocket.chat
|
||||
return (
|
||||
<Text
|
||||
onPress={preview ? undefined : handlePress}
|
||||
onLongPress={preview ? undefined : onLongPress}
|
||||
style={
|
||||
!preview
|
||||
? { ...styles.link, color: themes[theme].actionTintColor }
|
||||
: { color: themes[theme].bodyText }
|
||||
}
|
||||
onPress={handlePress}
|
||||
onLongPress={onLongPress}
|
||||
style={{ ...styles.link, color: themes[theme].actionTintColor }}
|
||||
>
|
||||
{ childLength !== 0 ? children : link }
|
||||
</Text>
|
||||
|
@ -44,8 +40,7 @@ const Link = React.memo(({
|
|||
Link.propTypes = {
|
||||
children: PropTypes.node,
|
||||
link: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
preview: PropTypes.bool
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
||||
export default Link;
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Text, Image } from 'react-native';
|
|||
import { Parser, Node } from 'commonmark';
|
||||
import Renderer from 'commonmark-react-renderer';
|
||||
import PropTypes from 'prop-types';
|
||||
import removeMarkdown from 'remove-markdown';
|
||||
|
||||
import shortnameToUnicode from '../../utils/shortnameToUnicode';
|
||||
import I18n from '../../i18n';
|
||||
|
@ -18,6 +19,7 @@ import MarkdownEmoji from './Emoji';
|
|||
import MarkdownTable from './Table';
|
||||
import MarkdownTableRow from './TableRow';
|
||||
import MarkdownTableCell from './TableCell';
|
||||
import mergeTextNodes from './mergeTextNodes';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
@ -83,10 +85,10 @@ class Markdown extends PureComponent {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.renderer = this.createRenderer(props.preview);
|
||||
this.renderer = this.createRenderer();
|
||||
}
|
||||
|
||||
createRenderer = (preview = false) => new Renderer({
|
||||
createRenderer = () => new Renderer({
|
||||
renderers: {
|
||||
text: this.renderText,
|
||||
|
||||
|
@ -119,7 +121,7 @@ class Markdown extends PureComponent {
|
|||
table_row: this.renderTableRow,
|
||||
table_cell: this.renderTableCell,
|
||||
|
||||
editedIndicator: preview ? () => null : this.renderEditedIndicator
|
||||
editedIndicator: this.renderEditedIndicator
|
||||
},
|
||||
renderParagraphsInLists: true
|
||||
});
|
||||
|
@ -141,19 +143,15 @@ class Markdown extends PureComponent {
|
|||
|
||||
renderText = ({ context, literal }) => {
|
||||
const {
|
||||
numberOfLines, preview, style = []
|
||||
numberOfLines, style = []
|
||||
} = this.props;
|
||||
const defaultStyle = [
|
||||
this.isMessageContainsOnlyEmoji && !preview ? styles.textBig : {},
|
||||
this.isMessageContainsOnlyEmoji ? styles.textBig : {},
|
||||
...context.map(type => styles[type])
|
||||
];
|
||||
return (
|
||||
<Text
|
||||
style={[
|
||||
styles.text,
|
||||
!preview ? defaultStyle : {},
|
||||
...style
|
||||
]}
|
||||
style={[styles.text, defaultStyle, ...style]}
|
||||
numberOfLines={numberOfLines}
|
||||
>
|
||||
{literal}
|
||||
|
@ -162,18 +160,16 @@ class Markdown extends PureComponent {
|
|||
}
|
||||
|
||||
renderCodeInline = ({ literal }) => {
|
||||
const { preview, theme, style = [] } = this.props;
|
||||
const { theme, style = [] } = this.props;
|
||||
return (
|
||||
<Text
|
||||
style={[
|
||||
!preview
|
||||
? {
|
||||
...styles.codeInline,
|
||||
color: themes[theme].bodyText,
|
||||
backgroundColor: themes[theme].bannerBackground,
|
||||
borderColor: themes[theme].bannerBackground
|
||||
}
|
||||
: { ...styles.text, color: themes[theme].bodyText },
|
||||
{
|
||||
...styles.codeInline,
|
||||
color: themes[theme].bodyText,
|
||||
backgroundColor: themes[theme].bannerBackground,
|
||||
borderColor: themes[theme].bannerBackground
|
||||
},
|
||||
...style
|
||||
]}
|
||||
>
|
||||
|
@ -183,18 +179,16 @@ class Markdown extends PureComponent {
|
|||
};
|
||||
|
||||
renderCodeBlock = ({ literal }) => {
|
||||
const { preview, theme, style = [] } = this.props;
|
||||
const { theme, style = [] } = this.props;
|
||||
return (
|
||||
<Text
|
||||
style={[
|
||||
!preview
|
||||
? {
|
||||
...styles.codeBlock,
|
||||
color: themes[theme].bodyText,
|
||||
backgroundColor: themes[theme].bannerBackground,
|
||||
borderColor: themes[theme].bannerBackground
|
||||
}
|
||||
: { ...styles.text, color: themes[theme].bodyText },
|
||||
{
|
||||
...styles.codeBlock,
|
||||
color: themes[theme].bodyText,
|
||||
backgroundColor: themes[theme].bannerBackground,
|
||||
borderColor: themes[theme].bannerBackground
|
||||
},
|
||||
...style
|
||||
]}
|
||||
>
|
||||
|
@ -221,11 +215,10 @@ class Markdown extends PureComponent {
|
|||
};
|
||||
|
||||
renderLink = ({ children, href }) => {
|
||||
const { preview, theme } = this.props;
|
||||
const { theme } = this.props;
|
||||
return (
|
||||
<MarkdownLink
|
||||
link={href}
|
||||
preview={preview}
|
||||
theme={theme}
|
||||
>
|
||||
{children}
|
||||
|
@ -235,14 +228,13 @@ class Markdown extends PureComponent {
|
|||
|
||||
renderHashtag = ({ hashtag }) => {
|
||||
const {
|
||||
channels, navToRoomInfo, style, preview, theme
|
||||
channels, navToRoomInfo, style, theme
|
||||
} = this.props;
|
||||
return (
|
||||
<MarkdownHashtag
|
||||
hashtag={hashtag}
|
||||
channels={channels}
|
||||
navToRoomInfo={navToRoomInfo}
|
||||
preview={preview}
|
||||
theme={theme}
|
||||
style={style}
|
||||
/>
|
||||
|
@ -251,7 +243,7 @@ class Markdown extends PureComponent {
|
|||
|
||||
renderAtMention = ({ mentionName }) => {
|
||||
const {
|
||||
username, mentions, navToRoomInfo, useRealName, preview, style, theme
|
||||
username, mentions, navToRoomInfo, useRealName, style, theme
|
||||
} = this.props;
|
||||
return (
|
||||
<MarkdownAtMention
|
||||
|
@ -260,7 +252,6 @@ class Markdown extends PureComponent {
|
|||
useRealName={useRealName}
|
||||
username={username}
|
||||
navToRoomInfo={navToRoomInfo}
|
||||
preview={preview}
|
||||
theme={theme}
|
||||
style={style}
|
||||
/>
|
||||
|
@ -269,13 +260,13 @@ class Markdown extends PureComponent {
|
|||
|
||||
renderEmoji = ({ emojiName, literal }) => {
|
||||
const {
|
||||
getCustomEmoji, baseUrl, customEmojis = true, preview, style, theme
|
||||
getCustomEmoji, baseUrl, customEmojis = true, style, theme
|
||||
} = this.props;
|
||||
return (
|
||||
<MarkdownEmoji
|
||||
emojiName={emojiName}
|
||||
literal={literal}
|
||||
isMessageContainsOnlyEmoji={this.isMessageContainsOnlyEmoji && !preview}
|
||||
isMessageContainsOnlyEmoji={this.isMessageContainsOnlyEmoji}
|
||||
getCustomEmoji={getCustomEmoji}
|
||||
baseUrl={baseUrl}
|
||||
customEmojis={customEmojis}
|
||||
|
@ -336,10 +327,7 @@ class Markdown extends PureComponent {
|
|||
};
|
||||
|
||||
renderBlockQuote = ({ children }) => {
|
||||
const { preview, theme } = this.props;
|
||||
if (preview) {
|
||||
return children;
|
||||
}
|
||||
const { theme } = this.props;
|
||||
return (
|
||||
<MarkdownBlockQuote theme={theme}>
|
||||
{children}
|
||||
|
@ -367,7 +355,9 @@ class Markdown extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { msg, preview = false } = this.props;
|
||||
const {
|
||||
msg, numberOfLines, preview = false, theme, style = []
|
||||
} = this.props;
|
||||
|
||||
if (!msg) {
|
||||
return null;
|
||||
|
@ -378,19 +368,22 @@ class Markdown extends PureComponent {
|
|||
// Ex: '[ ](https://open.rocket.chat/group/test?msg=abcdef) Test'
|
||||
// Return: 'Test'
|
||||
m = m.replace(/^\[([\s]]*)\]\(([^)]*)\)\s/, '').trim();
|
||||
m = shortnameToUnicode(m);
|
||||
|
||||
if (preview) {
|
||||
m = m.split('\n').reduce((lines, line) => `${ lines } ${ line }`, '');
|
||||
const ast = parser.parse(m);
|
||||
return this.renderer.render(ast);
|
||||
m = m.replace(/\n+/g, ' ');
|
||||
m = shortnameToUnicode(m);
|
||||
m = removeMarkdown(m);
|
||||
return (
|
||||
<Text style={[styles.text, { color: themes[theme].bodyText }, ...style]} numberOfLines={numberOfLines}>
|
||||
{m}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
const ast = parser.parse(m);
|
||||
let ast = parser.parse(m);
|
||||
ast = mergeTextNodes(ast);
|
||||
this.isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3;
|
||||
|
||||
this.editedMessage(ast);
|
||||
|
||||
return this.renderer.render(ast);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// TODO: should we add this to our commonmark fork instead?
|
||||
// we loop through nodes and try to merge all texts
|
||||
export default function mergeTextNodes(ast) {
|
||||
// https://github.com/commonmark/commonmark.js/blob/master/lib/node.js#L268
|
||||
const walker = ast.walker();
|
||||
let event;
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while (event = walker.next()) {
|
||||
const { entering, node } = event;
|
||||
const { type } = node;
|
||||
if (entering && type === 'text') {
|
||||
while (node._next && node._next.type === 'text') {
|
||||
const next = node._next;
|
||||
node.literal += next.literal;
|
||||
node._next = next._next;
|
||||
if (node._next) {
|
||||
node._next._prev = node;
|
||||
}
|
||||
if (node._parent._lastChild === next) {
|
||||
node._parent._lastChild = node;
|
||||
}
|
||||
}
|
||||
walker.resumeAt(node, false);
|
||||
}
|
||||
}
|
||||
return ast;
|
||||
}
|
|
@ -6,7 +6,6 @@ import I18n from '../../i18n';
|
|||
import styles from './styles';
|
||||
import Markdown from '../../containers/markdown';
|
||||
import { themes } from '../../constants/colors';
|
||||
import shortnameToUnicode from '../../utils/shortnameToUnicode';
|
||||
|
||||
const formatMsg = ({
|
||||
lastMessage, type, showLastMessage, username, useRealName
|
||||
|
@ -37,11 +36,7 @@ const formatMsg = ({
|
|||
prefix = `${ useRealName ? name : lastMessage.u.username }: `;
|
||||
}
|
||||
|
||||
let msg = `${ prefix }${ lastMessage.msg.replace(/[\n\t\r]/igm, '') }`;
|
||||
if (msg) {
|
||||
msg = shortnameToUnicode(msg);
|
||||
}
|
||||
return msg;
|
||||
return `${ prefix }${ lastMessage.msg }`;
|
||||
};
|
||||
|
||||
const arePropsEqual = (oldProps, newProps) => _.isEqual(oldProps, newProps);
|
||||
|
|
Loading…
Reference in New Issue