mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-11-29 22:07:46 +03:00
Merge pull request #418 from esteemapp/bugfix/markdownPreview
[definitely need test!] fixed #409 #410 #411
This commit is contained in:
commit
ea54cd478b
@ -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,
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -308,7 +308,7 @@ class EditorContainer extends Component {
|
||||
options,
|
||||
0,
|
||||
)
|
||||
.then((result) => {
|
||||
.then(() => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'alert.success',
|
||||
|
@ -5,8 +5,6 @@ import { injectIntl } from 'react-intl';
|
||||
// Utils
|
||||
import { getWordsCount } from '../../../utils/editor';
|
||||
|
||||
// Constants
|
||||
|
||||
// Components
|
||||
import { BasicHeader } from '../../../components/basicHeader';
|
||||
import {
|
||||
|
@ -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;
|
||||
// });
|
Loading…
Reference in New Issue
Block a user