Merge pull request #418 from esteemapp/bugfix/markdownPreview

[definitely need test!] fixed #409 #410 #411
This commit is contained in:
uğur erdal 2019-01-15 19:17:07 +03:00 committed by GitHub
commit e93849309c
6 changed files with 97 additions and 96 deletions

View File

@ -9,14 +9,17 @@ export default EStyleSheet.create({
},
textWrapper: {
flex: 1,
flexDirection: 'column',
fontSize: 12,
marginVertical: 16,
paddingVertical: 16,
paddingHorizontal: 16,
color: '$primaryBlack',
fontFamily: '$editorFont',
textAlignVertical: 'top',
},
previewContainer: {
flex: 1,
marginHorizontal: 16,
},
inlinePadding: {
padding: 8,
},

View File

@ -1,20 +1,22 @@
import React, { Component } from 'react';
import {
View, KeyboardAvoidingView, ScrollView, FlatList, Text, Platform,
View, KeyboardAvoidingView, FlatList, Text, Platform,
} from 'react-native';
import Markdown, { getUniqueID } from 'react-native-markdown-renderer';
import ActionSheet from 'react-native-actionsheet';
// Components
import { IconButton } from '../../iconButton';
import { StickyBar } from '../../basicUIElements';
import { TextInput } from '../../textInput';
// Utils
import { markDown2Html } from '../../../utils/markdownToHtml';
import applyImageLink from './formats/applyWebLinkFormat';
import Formats from './formats/formats';
// Components
import { IconButton } from '../../iconButton';
import { PostBody } from '../../postElements';
import { StickyBar } from '../../basicUIElements';
import { TextInput } from '../../textInput';
// Styles
import styles from './markdownEditorStyles';
import markdownStyle from './markdownPreviewStyles';
export default class MarkdownEditorView extends Component {
constructor(props) {
@ -39,7 +41,11 @@ export default class MarkdownEditorView extends Component {
});
}
if (nextProps.uploadedImage && nextProps.uploadedImage.url && nextProps.uploadedImage !== uploadedImage) {
if (
nextProps.uploadedImage
&& nextProps.uploadedImage.url
&& nextProps.uploadedImage !== uploadedImage
) {
applyImageLink({
getState: this._getState,
setState: (state, callback) => {
@ -90,26 +96,10 @@ export default class MarkdownEditorView extends Component {
_renderPreview = () => {
const { text } = this.state;
const rules = {
heading1: (node, children, parent, styles) => (
<Text key={getUniqueID()} style={styles.heading1}>
{children}
</Text>
),
heading2: (node, children, parent, styles) => (
<Text key={getUniqueID()} style={styles.heading2}>
{children}
</Text>
),
};
return (
<View style={styles.textWrapper}>
<ScrollView removeClippedSubviews>
<Markdown rules={rules} style={markdownStyle}>
{text === '' ? '...' : text}
</Markdown>
</ScrollView>
<View style={styles.previewContainer}>
{text ? <PostBody body={markDown2Html(text)} /> : <Text>...</Text>}
</View>
);
};
@ -133,9 +123,7 @@ export default class MarkdownEditorView extends Component {
<FlatList
data={Formats}
keyboardShouldPersistTaps="always"
renderItem={
({ item, index }) => index !== 9
&& this._renderMarkupButton({ item, getState, setState })
renderItem={({ item, index }) => index !== 9 && this._renderMarkupButton({ item, getState, setState })
}
horizontal
/>
@ -176,7 +164,11 @@ export default class MarkdownEditorView extends Component {
const { text, selection } = this.state;
return (
<KeyboardAvoidingView style={styles.container} keyboardVerticalOffset={Platform.select({ ios: 0, android: 25 })} behavior="padding">
<KeyboardAvoidingView
style={styles.container}
keyboardVerticalOffset={Platform.select({ ios: 0, android: 25 })}
behavior="padding"
>
{!isPreviewActive ? (
<TextInput
multiline

View File

@ -1,10 +1,11 @@
import React, { PureComponent, Fragment } from 'react';
import { Dimensions, Linking, Alert } from 'react-native';
import {
Dimensions, Linking, Alert,
} from 'react-native';
import { withNavigation } from 'react-navigation';
import { injectIntl } from 'react-intl';
import HTML from 'react-native-html-renderer';
// Styles
import styles from './postBodyStyles';
@ -13,6 +14,14 @@ import { default as ROUTES } from '../../../../constants/routeNames';
// Components
const WIDTH = Dimensions.get('window').width;
const CUSTOM_RENDERERS = {
// example
//center: () => <Text style={{ backgroundColor: 'blue', textAlign: 'center'}}>ugur</Text>,
};
const DEFAULT_PROPS = {
renderers: CUSTOM_RENDERERS,
debug: true,
};
class PostBody extends PureComponent {
constructor(props) {
@ -102,6 +111,7 @@ class PostBody extends PureComponent {
return (
<Fragment>
<HTML
{...DEFAULT_PROPS}
html={body}
onLinkPress={(evt, href, hrefatr) => this._handleOnLinkPress(evt, href, hrefatr)}
containerStyle={isComment ? styles.commentContainer : styles.container}

View File

@ -308,7 +308,7 @@ class EditorContainer extends Component {
options,
0,
)
.then((result) => {
.then(() => {
Alert.alert(
intl.formatMessage({
id: 'alert.success',

View File

@ -5,8 +5,6 @@ import { injectIntl } from 'react-intl';
// Utils
import { getWordsCount } from '../../../utils/editor';
// Constants
// Components
import { BasicHeader } from '../../../components/basicHeader';
import {

View File

@ -2,11 +2,12 @@ import Remarkable from 'remarkable';
// TODO: Refactoring need!
const md = new Remarkable({ html: true, breaks: true, linkify: true });
const imgCenterRegex = /([<center>]http(s?):)([/|.|\w|\s|-])*\.(?:jpg|gif|png|PNG|GIF|JPG)[</center>]/g;
const onlyImageLinkRegex = /([\n]http(s?):)([/|.|\w|\s|-])*\.(?:jpg|gif|png|PNG|GIF|JPG)/g;
const onlyImageDoubleLinkRegex = /(\nhttps)(.*)(?=jpg|gif|png|PNG|GIF|JPG|)/g;
//const imgCenterRegex = /([<center>]http(s?):)([/|.|\w|\s|-])*\.(?:jpg|gif|png|PNG|GIF|JPG)[</center>]/g;
//const onlyImageLinkRegex = /([\n]http(s?):)([/|.|\w|\s|-])*\.(?:jpg|gif|png|PNG|GIF|JPG)/g;
//const onlyImageDoubleLinkRegex = /(\nhttps)(.*)(?=jpg|gif|png|PNG|GIF|JPG|)/g;
//const pullRightLeftRegex = /(<div class="[^"]*?pull-[^"]*?">(.*?)(<[/]div>))/g;
//const copiedPostRegex = /\/(.*)\/(@[\w.\d-]+)\/(.*)/i;
const postRegex = /^https?:\/\/(.*)\/(.*)\/(@[\w.\d-]+)\/(.*)/i;
const copiedPostRegex = /\/(.*)\/(@[\w.\d-]+)\/(.*)/i;
const youTubeRegex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^& \n<]+)(?:[^ \n<]+)?/g;
const vimeoRegex = /(https?:\/\/)?(www\.)?(?:vimeo)\.com.*(?:videos|video|channels|)\/([\d]+)/i;
const dTubeRegex = /(https?:\/\/d.tube.#!\/v\/)(\w+)\/(\w+)/g;
@ -14,14 +15,12 @@ const authorNameRegex = /(^|[^a-zA-Z0-9_!#$%&*@\/]|(^|[^a-zA-Z0-9_+~.-\/]))[@
const tagsRegex = /(^|\s|>)(#[-a-z\d]+)/gi;
const centerRegex = /(<center>)/g;
const imgRegex = /(https?:\/\/.*\.(?:tiff?|jpe?g|gif|png|svg|ico|PNG|GIF|JPG))/g;
const pullRightLeftRegex = /(<div class="[^"]*?pull-[^"]*?">(.*?)(<[/]div>))/g;
const linkRegex = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi;
const markdownImageRegex = /!\[[^\]]*\]\((.*?)\s*("(?:.*[^"])")?\s*\)/g;
const urlRegex = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?/gm;
const aTagRegex = /(<\s*a[^>]*>(.*?)<\s*[/]\s*a>)/g;
const imgTagRegex = /(<img[^>]*>)/g;
const iframeRegex = /(?:<iframe[^>]*)(?:(?:\/>)|(?:>.*?<\/iframe>))/g;
//const codeTagRegex= /(?:<code[^>]*)(?:(?:\/>)|(?:>.*?<\/code>))/g;
export const markDown2Html = (input) => {
if (!input) {
@ -69,10 +68,6 @@ export const markDown2Html = (input) => {
output = handleIframe(output);
}
// if (codeTagRegex.test(output)) {
// output = handleCodeTag(output);
// }
if (linkRegex.test(output)) {
output = handleLinks(output);
}
@ -157,33 +152,7 @@ const changeMarkdownImage = input => input.replace(markdownImageRegex, (link) =>
return link;
});
const centerStyling = input => input.replace(centerRegex, () => '<center style="text-align:center;">');
// const handleCodeTag = input => input.replace(codeTagRegex, (tag) => {
// const stringsRegex = /(?<=>)(.*)(?=<)/g;
// const match = tag.match(stringsRegex);
// if (match && match[0]) {
// return `<p class="code" >${match[0]}</p>`;
// }
// return iframeBody(match[0]);
// });
const createCenterImage = input => input.replace(imgCenterRegex, (link) => {
let _link = link;
_link = _link.split('>')[1];
_link = _link.split('<')[0];
return `><img data-href="${`https://steemitimages.com/600x0/${_link}`}" src="${`https://steemitimages.com/600x0/${_link}`}"><`;
});
const changePullRightLeft = input => input.replace(pullRightLeftRegex, (item) => {
const imageLink = item.match(linkRegex)[0];
return `<center style="text-align:center;"><img src="${`https://steemitimages.com/600x0/${imageLink}`}"/></center><br>`;
});
const centerStyling = input => input.replace(centerRegex, () => '<center style="text-align: center; align-items: center; justify-content: center;">');
const steemitUrlHandle = input => input.replace(postRegex, (link) => {
const postMatch = link.match(postRegex);
@ -194,7 +163,6 @@ const steemitUrlHandle = input => input.replace(postRegex, (link) => {
return `<a class="markdown-post-link" href="${permlink}" data_tag={${tag}} data_author="${author}">/${permlink}</a>`;
});
const createImage = input => input.replace(onlyImageLinkRegex, link => imageBody(link));
const handleImageTag = input => input.replace(imgTagRegex, (imgTag) => {
const _imgTag = imgTag.trim();
@ -207,12 +175,6 @@ const handleImageTag = input => input.replace(imgTagRegex, (imgTag) => {
return imgTag;
});
const createFromDoubleImageLink = input => input.replace(onlyImageDoubleLinkRegex, (link) => {
const _link = link.trim();
return imageBody(_link);
});
const createYoutubeIframe = input => input.replace(youTubeRegex, (link) => {
const execVideo = youTubeRegex.exec(link);
const match = link.match(youTubeRegex);
@ -237,21 +199,6 @@ const handleIframe = input => input.replace(iframeRegex, (link) => {
return link;
});
const createDtubeIframe = input => input.replace(dTubeRegex, (link) => {
const execLink = dTubeRegex.exec(link);
const dTubeMatch = link.match(dTubeRegex)[0];
if (execLink[2] && execLink[3]) {
const embedLink = `https://emb.d.tube/#!/${execLink[2]}/${execLink[3]}`;
return iframeBody(embedLink);
}
if (dTubeMatch) {
return iframeBody(dTubeMatch);
}
return link;
});
const createVimeoIframe = input => input.replace(vimeoRegex, (link) => {
const execLink = vimeoRegex.exec(link);
@ -262,3 +209,54 @@ const createVimeoIframe = input => input.replace(vimeoRegex, (link) => {
const iframeBody = link => `<iframe frameborder='0' allowfullscreen src='${link}'></iframe>`;
const imageBody = link => `<img src="${`https://steemitimages.com/600x0/${link}`}">`;
// const handleCodeTag = input => input.replace(codeTagRegex, (tag) => {
// const stringsRegex = /(?<=>)(.*)(?=<)/g;
// const match = tag.match(stringsRegex);
// if (match && match[0]) {
// return `<p class="code" >${match[0]}</p>`;
// }
// return iframeBody(match[0]);
// });
// const createCenterImage = input => input.replace(imgCenterRegex, (link) => {
// let _link = link;
// _link = _link.split('>')[1];
// _link = _link.split('<')[0];
// return `><img data-href="${`https://steemitimages.com/600x0/${_link}`}" src="${`https://steemitimages.com/600x0/${_link}`}"><`;
// });
// const changePullRightLeft = input => input.replace(pullRightLeftRegex, (item) => {
// const imageLink = item.match(linkRegex)[0];
// return `<center style="text-align:center;"><img src="${`https://steemitimages.com/600x0/${imageLink}`}"/></center><br>`;
// });
//const createImage = input => input.replace(onlyImageLinkRegex, link => imageBody(link));
// const createFromDoubleImageLink = input => input.replace(onlyImageDoubleLinkRegex, (link) => {
// const _link = link.trim();
// return imageBody(_link);
// });
// const createDtubeIframe = input => input.replace(dTubeRegex, (link) => {
// const execLink = dTubeRegex.exec(link);
// const dTubeMatch = link.match(dTubeRegex)[0];
// if (execLink[2] && execLink[3]) {
// const embedLink = `https://emb.d.tube/#!/${execLink[2]}/${execLink[3]}`;
// return iframeBody(embedLink);
// }
// if (dTubeMatch) {
// return iframeBody(dTubeMatch);
// }
// return link;
// });