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