mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-22 21:01:31 +03:00
Merge pull request #1312 from esteemapp/bugfix/post-display
Markdown refactoring
This commit is contained in:
commit
499abb49bd
Binary file not shown.
@ -49,6 +49,7 @@
|
||||
"react-native": "0.61.2",
|
||||
"react-native-actionsheet": "^2.4.2",
|
||||
"react-native-autocomplete-input": "^4.1.0",
|
||||
"react-native-autoheight-webview": "^1.2.2",
|
||||
"react-native-code-push": "esteemapp/react-native-code-push",
|
||||
"react-native-config": "luggit/react-native-config#master",
|
||||
"react-native-dark-mode": "^0.1.2",
|
||||
|
@ -19,10 +19,12 @@ import WalletDetailsPlaceHolder from './view/placeHolder/walletDetailsPlaceHolde
|
||||
import WalletUnclaimedPlaceHolder from './view/placeHolder/walletUnclaimedPlaceHolder';
|
||||
import ListPlaceHolder from './view/placeHolder/listPlaceHolderView';
|
||||
import BoostPlaceHolder from './view/placeHolder/boostPlaceHolderView';
|
||||
import CommentPlaceHolder from './view/placeHolder/commentPlaceHolderView';
|
||||
|
||||
export {
|
||||
Card,
|
||||
Chip,
|
||||
CommentPlaceHolder,
|
||||
GrayWrapper,
|
||||
LineBreak,
|
||||
ListItemPlaceHolder,
|
||||
|
@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import Placeholder from 'rn-placeholder';
|
||||
|
||||
import { ThemeContainer } from '../../../../containers';
|
||||
|
||||
import styles from './listItemPlaceHolderStyles';
|
||||
|
||||
const CommentPlaceHolderView = () => {
|
||||
return (
|
||||
<ThemeContainer>
|
||||
{({ isDarkTheme }) => {
|
||||
const color = isDarkTheme ? '#2e3d51' : '#f5f5f5';
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.paragraphWithoutMargin}>
|
||||
<Placeholder.Paragraph
|
||||
color={color}
|
||||
lineNumber={3}
|
||||
textSize={12}
|
||||
lineSpacing={8}
|
||||
width="100%"
|
||||
lastLineWidth="70%"
|
||||
firstLineWidth="50%"
|
||||
animate="fade"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
</ThemeContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommentPlaceHolderView;
|
@ -16,4 +16,7 @@ export default EStyleSheet.create({
|
||||
marginTop: 3,
|
||||
flex: 1,
|
||||
},
|
||||
paragraphWithoutMargin: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
106
src/components/postElements/body/view/config.js
Normal file
106
src/components/postElements/body/view/config.js
Normal file
@ -0,0 +1,106 @@
|
||||
export default `document.addEventListener('click', function(event) {
|
||||
let el = event.target;
|
||||
// A element can be wrapped with inline element. Look parent elements.
|
||||
while (el.tagName !== 'A') {
|
||||
if (!el.parentNode) {
|
||||
break;
|
||||
}
|
||||
el = el.parentNode;
|
||||
}
|
||||
if (!el || el.tagName !== 'A') {
|
||||
window.ReactNativeWebView.postMessage('4');
|
||||
if (el.tagName) window.ReactNativeWebView.postMessage(el.tagName);
|
||||
return;
|
||||
}
|
||||
if (el.getAttribute('target') === '_external') {
|
||||
const href = el.getAttribute('href');
|
||||
const result = {
|
||||
type: '_external',
|
||||
href
|
||||
}
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(result));
|
||||
|
||||
return true;
|
||||
}
|
||||
if (el.classList.contains('markdown-external-link')) {
|
||||
const href = el.getAttribute('data-href');
|
||||
const result = {
|
||||
type: 'markdown-external-link',
|
||||
href
|
||||
}
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(result));
|
||||
|
||||
return true;
|
||||
}
|
||||
if (el.classList.contains('markdown-author-link')) {
|
||||
const author = el.getAttribute('data-author');
|
||||
const result = {
|
||||
type: 'markdown-author-link',
|
||||
author,
|
||||
}
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (el.classList.contains('markdown-post-link')) {
|
||||
let category = el.getAttribute('data-tag');
|
||||
let author = el.getAttribute('data-author');
|
||||
let permlink = el.getAttribute('data-permlink');
|
||||
const result = {
|
||||
type: 'markdown-post-link',
|
||||
category,
|
||||
author,
|
||||
permlink,
|
||||
}
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(result));
|
||||
return false;
|
||||
}
|
||||
if (el.classList.contains('markdown-tag-link')) {
|
||||
let tag = el.getAttribute('data-tag');
|
||||
const result = {
|
||||
type: 'markdown-tag-link',
|
||||
tag
|
||||
}
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(result));
|
||||
return false;
|
||||
}
|
||||
if (el.classList.contains('markdown-witnesses-link')) {
|
||||
|
||||
const result = {
|
||||
type: 'markdown-witnesses-link'
|
||||
}
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(result));
|
||||
return false;
|
||||
}
|
||||
if (el.classList.contains('markdown-proposal-link')) {
|
||||
|
||||
let proposal = el.getAttribute('data-proposal');
|
||||
const result = {
|
||||
type: 'markdown-proposal-link',
|
||||
proposal
|
||||
}
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(result));
|
||||
return false;
|
||||
}
|
||||
if (el.classList.contains('markdown-video-link')) {
|
||||
const embedSrc = '<iframe frameborder="0" allowfullscreen src="' + el.getAttribute('data-embed-src') + '"></iframe>';
|
||||
if (embedSrc) {
|
||||
el.innerHTML = embedSrc;
|
||||
return;
|
||||
}
|
||||
const videoHref = el.getAttribute('data-video-href');
|
||||
if (videoHref) {
|
||||
const result = {
|
||||
type: 'markdown-video-link',
|
||||
videoHref
|
||||
}
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(result));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
window.ReactNativeWebView.postMessage('4');
|
||||
const author = el.getAttribute('data-author').toString();
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify(author));
|
||||
})
|
||||
true;`;
|
@ -1,16 +1,17 @@
|
||||
import React from 'react';
|
||||
import { Dimensions, Linking, Alert, TouchableOpacity, Text } from 'react-native';
|
||||
import React, { Fragment } from 'react';
|
||||
import { Dimensions, Linking, Alert } from 'react-native';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { useIntl, injectIntl } from 'react-intl';
|
||||
import HTML from 'react-native-render-html';
|
||||
import { getParentsTagsRecursively } from 'react-native-render-html/src/HTMLUtils';
|
||||
import AutoHeightWebView from 'react-native-autoheight-webview';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import get from 'lodash/get';
|
||||
|
||||
import script from './config.js';
|
||||
import { PostPlaceHolder, CommentPlaceHolder } from '../../../basicUIElements';
|
||||
|
||||
// Constants
|
||||
import { default as ROUTES } from '../../../../constants/routeNames';
|
||||
|
||||
// Styles
|
||||
import styles from './postBodyStyles';
|
||||
|
||||
const WIDTH = Dimensions.get('window').width;
|
||||
|
||||
const PostBody = ({
|
||||
@ -23,36 +24,72 @@ const PostBody = ({
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const _handleOnLinkPress = (href, hrefAtr) => {
|
||||
if (hrefAtr.class === 'markdown-author-link') {
|
||||
if (!handleOnUserPress) {
|
||||
_handleOnUserPress(hrefAtr['data-author']);
|
||||
} else {
|
||||
handleOnUserPress(hrefAtr['data-author']);
|
||||
const _handleOnLinkPress = event => {
|
||||
if ((!event && !get(event, 'nativeEvent.data'), false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = JSON.parse(get(event, 'nativeEvent.data'));
|
||||
|
||||
const { type, href, author, category, permlink, tag, proposal, videoHref } = data;
|
||||
|
||||
switch (type) {
|
||||
case '_external':
|
||||
case 'markdown-external-link':
|
||||
_handleBrowserLink(href);
|
||||
break;
|
||||
case 'markdown-author-link':
|
||||
if (!handleOnUserPress) {
|
||||
_handleOnUserPress(author);
|
||||
} else {
|
||||
handleOnUserPress(author);
|
||||
}
|
||||
break;
|
||||
case 'markdown-post-link':
|
||||
if (!handleOnPostPress) {
|
||||
_handleOnPostPress(permlink, author);
|
||||
} else {
|
||||
handleOnPostPress(permlink, author);
|
||||
}
|
||||
break;
|
||||
case 'markdown-tag-link':
|
||||
_handleTagPress(tag);
|
||||
break;
|
||||
case 'markdown-witnesses-link':
|
||||
break;
|
||||
case 'markdown-proposal-link':
|
||||
break;
|
||||
case 'markdown-video-link':
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (hrefAtr.class === 'markdown-post-link') {
|
||||
if (!handleOnPostPress) {
|
||||
_handleOnPostPress(hrefAtr['data-permlink'], hrefAtr['data-author']);
|
||||
} else {
|
||||
handleOnPostPress(hrefAtr['data-permlink']);
|
||||
}
|
||||
} else {
|
||||
_handleBrowserLink(href);
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const _handleTagPress = tag => {
|
||||
if (tag) {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.SEARCH_RESULT,
|
||||
params: {
|
||||
tag,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const _handleBrowserLink = async url => {
|
||||
if (!url) {
|
||||
return;
|
||||
if (url) {
|
||||
Linking.canOpenURL(url).then(supported => {
|
||||
if (supported) {
|
||||
Linking.openURL(url);
|
||||
} else {
|
||||
Alert.alert(intl.formatMessage({ id: 'alert.failed_to_open' }));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Linking.canOpenURL(url).then(supported => {
|
||||
if (supported) {
|
||||
Linking.openURL(url);
|
||||
} else {
|
||||
Alert.alert(intl.formatMessage({ id: 'alert.failed_to_open' }));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _handleOnPostPress = (permlink, author) => {
|
||||
@ -82,117 +119,116 @@ const PostBody = ({
|
||||
}
|
||||
};
|
||||
|
||||
const _hasParentTag = (node, name) => {
|
||||
if (!node.parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.name === name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return _hasParentTag(node.parent, name);
|
||||
};
|
||||
|
||||
const _alterNode = (node, isComment) => {
|
||||
if (isComment) {
|
||||
if (node.name === 'img') {
|
||||
node.attribs.style = `max-width: ${WIDTH - 50}px; height: 100px; width: ${WIDTH -
|
||||
50}px; text-align: center;`;
|
||||
}
|
||||
} else if (node.name === 'a') {
|
||||
node.attribs.style = 'text-decoration: underline';
|
||||
}
|
||||
|
||||
if (node.name === 'img') {
|
||||
node.attribs.style = 'text-align: center;';
|
||||
if (_hasParentTag(node, 'td')) {
|
||||
node.attribs.style = `max-width: ${WIDTH / 2 - 20}px; `;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.name === 'div' && node.attribs && node.attribs.class) {
|
||||
const _className = node.attribs.class;
|
||||
|
||||
if (_className === 'pull-right') {
|
||||
node.attribs.style = 'text-align: right; align-self: flex-end;';
|
||||
}
|
||||
|
||||
if (_className === 'pull-left') {
|
||||
node.attribs.style = 'text-align: left; align-self: flex-start;';
|
||||
}
|
||||
|
||||
if (_className === 'text-justify') {
|
||||
node.attribs.style = 'text-align: justify; text-justify: inter-word; letter-spacing: 0px;';
|
||||
}
|
||||
|
||||
if (_className === 'phishy') {
|
||||
node.attribs.style = 'color: red';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _alterData = node => {
|
||||
if (
|
||||
node.type === 'text' &&
|
||||
node.data.includes('markdown-author-link') &&
|
||||
node.parent &&
|
||||
getParentsTagsRecursively(node.parent).includes('code')
|
||||
) {
|
||||
return node.data.replace(/<[^>]*>/g, '');
|
||||
}
|
||||
};
|
||||
|
||||
const _initialDimensions = isComment
|
||||
? { width: WIDTH - 50, height: 80 }
|
||||
: { width: WIDTH, height: 216 };
|
||||
|
||||
const _customRenderer = {
|
||||
a: (htmlAttribs, children, convertedCSSStyles, passProps) => {
|
||||
if (passProps.parentWrapper === 'Text') {
|
||||
return (
|
||||
<Text
|
||||
key={passProps.key}
|
||||
{...htmlAttribs}
|
||||
onPress={() => _handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={passProps.key}
|
||||
{...htmlAttribs}
|
||||
onPress={() => _handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}
|
||||
>
|
||||
{children}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
},
|
||||
br: (htmlAttribs, children, passProps) => {
|
||||
return <Text {...passProps}>{'\n'}</Text>;
|
||||
},
|
||||
};
|
||||
const test = body.replace(/<a/g, '<a target="_blank"');
|
||||
const customStyle = `
|
||||
* {
|
||||
color: ${EStyleSheet.value('$primaryBlack')};
|
||||
font-family: Roboto, sans-serif;
|
||||
max-width: 100%;
|
||||
}
|
||||
body {
|
||||
color: ${EStyleSheet.value('$primaryBlack')};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
a {
|
||||
color: ${EStyleSheet.value('$primaryBlue')};
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
img {
|
||||
align-self: 'center';
|
||||
max-width: 100%;
|
||||
}
|
||||
center {
|
||||
text-align: 'center';
|
||||
align-items: 'center';
|
||||
justify-content: 'center';
|
||||
}
|
||||
th {
|
||||
flex: 1;
|
||||
justify-content: 'center';
|
||||
font-weight: 'bold';
|
||||
color: ${EStyleSheet.value('$primaryBlack')};
|
||||
font-size: 14;
|
||||
padding: 5;
|
||||
}
|
||||
tr {
|
||||
background-color: ${EStyleSheet.value('$darkIconColor')};
|
||||
flex-direction: 'row';
|
||||
}
|
||||
td: {
|
||||
border-width: 0.5;
|
||||
border-color: ${EStyleSheet.value('$tableBorderColor')};
|
||||
flex: 1;
|
||||
padding: 10;
|
||||
background-color: ${EStyleSheet.value('$tableTrColor')};
|
||||
}
|
||||
blockquote: {
|
||||
border-left-width: 5;
|
||||
border-color: ${EStyleSheet.value('$darkIconColor')};
|
||||
padding-left: 5;
|
||||
}
|
||||
code: {
|
||||
background-color: ${EStyleSheet.value('$darkIconColor')};
|
||||
font-family: ${EStyleSheet.value('$editorFont')};
|
||||
}
|
||||
center: {
|
||||
text-align: 'center';
|
||||
align-items: 'center';
|
||||
justify-content: 'center';
|
||||
}
|
||||
.markdown-video-link {
|
||||
max-width: 100%;
|
||||
}
|
||||
.pull-right {
|
||||
float: right;
|
||||
}
|
||||
.pull-left {
|
||||
float: left;
|
||||
}
|
||||
.pull-left,
|
||||
.pull-right {
|
||||
max-width: calc(50% - 10px);
|
||||
padding-left: 10px;
|
||||
margin-bottom: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.phishy {
|
||||
display: inline;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.text-justify {
|
||||
text-align: justify;
|
||||
text-justify: inter-word;
|
||||
letter-spacing: 0px;
|
||||
}
|
||||
`;
|
||||
return (
|
||||
<HTML
|
||||
html={body}
|
||||
onLinkPress={(evt, href, hrefAtr) => _handleOnLinkPress(evt, href, hrefAtr)}
|
||||
containerStyle={isComment ? styles.commentContainer : styles.container}
|
||||
textSelectable={textSelectable}
|
||||
tagsStyles={isComment ? { img: { height: 120 } } : styles}
|
||||
ignoredTags={['script']}
|
||||
debug={false}
|
||||
staticContentMaxWidth={WIDTH - 33}
|
||||
imagesInitialDimensions={_initialDimensions}
|
||||
baseFontStyle={styles.text}
|
||||
imagesMaxWidth={isComment ? WIDTH - 50 : WIDTH}
|
||||
alterNode={e => _alterNode(e, isComment)}
|
||||
alterData={e => _alterData(e)}
|
||||
renderers={_customRenderer}
|
||||
/>
|
||||
<Fragment>
|
||||
<AutoHeightWebView
|
||||
source={{
|
||||
html: test,
|
||||
}}
|
||||
style={{ width: isComment ? WIDTH - 61 : WIDTH - 32 }}
|
||||
customStyle={customStyle}
|
||||
onMessage={_handleOnLinkPress}
|
||||
customScript={script.toString()}
|
||||
renderLoading={() => (isComment ? <CommentPlaceHolder /> : <PostPlaceHolder />)}
|
||||
startInLoadingState={true}
|
||||
onShouldStartLoadWithRequest={false}
|
||||
scrollEnabled={false}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default injectIntl(withNavigation(PostBody));
|
||||
const areEqual = (prevProps, nextProps) => {
|
||||
if (prevProps.body !== nextProps.body) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export default React.memo(injectIntl(withNavigation(PostBody)), areEqual);
|
||||
|
@ -162,7 +162,9 @@ class PostDisplayView extends PureComponent {
|
||||
const isGetComment = scrollHeight + 300 > postHeight;
|
||||
const formatedTime = post && getTimeFromNow(post.created);
|
||||
|
||||
if (isGetComment && !isLoadedComments) this.setState({ isLoadedComments: true });
|
||||
if (isGetComment && !isLoadedComments) {
|
||||
this.setState({ isLoadedComments: true });
|
||||
}
|
||||
|
||||
if (isPostUnavailable) {
|
||||
return (
|
||||
|
@ -7458,6 +7458,13 @@ react-native-autocomplete-input@^4.1.0:
|
||||
resolved "https://registry.yarnpkg.com/react-native-autocomplete-input/-/react-native-autocomplete-input-4.1.0.tgz#979ece28d891b245ecb967b6d31f1f924445b8ab"
|
||||
integrity sha512-Yn4GulZ9F6tde74UUGZHdVFeYWVuL7+EbUZy6kt+QHrzMc5B4OuRop1FT4RyWLpvbySW/vvqYgj9LAmlzkuEqA==
|
||||
|
||||
react-native-autoheight-webview@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/react-native-autoheight-webview/-/react-native-autoheight-webview-1.2.2.tgz#5b65fdad47f552cd154fc9dd916aebc69492cc24"
|
||||
integrity sha512-Did1IBXxY3fmGyGn7ioT3Osu9Uk7H+4M/rc6bal83cwEjxsX0lUDhzXOMNJh4D6Wh5eRne2r7zPz52tKjeLv8g==
|
||||
dependencies:
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-native-code-push@esteemapp/react-native-code-push:
|
||||
version "1000.0.0-beta"
|
||||
resolved "https://codeload.github.com/esteemapp/react-native-code-push/tar.gz/c07b7023c1212dc5d9231a0526a869d2501cb221"
|
||||
|
Loading…
Reference in New Issue
Block a user