Merge pull request #897 from esteemapp/markdown-refactoring-2

Markdown refactoring 2
This commit is contained in:
uğur erdal 2019-06-11 22:15:57 +03:00 committed by GitHub
commit 6303ca043b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 162 additions and 619 deletions

View File

@ -45,30 +45,6 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## BugsnagReactNative
Copyright (c) 2016 Bugsnag, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## CodePush
Microsoft CodePush Plugin for React Native
@ -321,6 +297,29 @@ SOFTWARE.
END OF TERMS AND CONDITIONS
## JWT
Copyright (c) 2013 Karma Mobility, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## QBImagePickerController
Copyright (c) 2015 Katsuma Tanaka
@ -384,7 +383,7 @@ THE SOFTWARE.
MIT License
Copyright (c) Facebook, Inc. and its affiliates.
Copyright (c) 2015-present, Facebook, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -429,6 +428,30 @@ THE SOFTWARE.
## SSZipArchive
Copyright (c) 2010-2015, Sam Soffes, http://soff.es
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## boost-for-react-native
Boost Software License - Version 1.0 - August 17th, 2003

View File

@ -68,36 +68,6 @@ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2016 Bugsnag, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>BugsnagReactNative</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Microsoft CodePush Plugin for React Native
@ -374,6 +344,35 @@ SOFTWARE.
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2013 Karma Mobility, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>JWT</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2015 Katsuma Tanaka
@ -455,7 +454,7 @@ THE SOFTWARE.
<key>FooterText</key>
<string>MIT License
Copyright (c) Facebook, Inc. and its affiliates.
Copyright (c) 2015-present, Facebook, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -512,6 +511,36 @@ THE SOFTWARE.
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2010-2015, Sam Soffes, http://soff.es
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>SSZipArchive</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Boost Software License - Version 1.0 - August 17th, 2003

View File

@ -1,10 +1,9 @@
import React, { PureComponent, Fragment } from 'react';
import {
Dimensions, Linking, Alert, TouchableOpacity, Text,
} from 'react-native';
import { Dimensions, Linking, Alert, TouchableOpacity, Text } from 'react-native';
import { withNavigation } from 'react-navigation';
import { injectIntl } from 'react-intl';
import FastImage from 'react-native-fast-image';
import { proxifyImageSrc } from '@esteemapp/esteem-render-helpers';
import HTML from 'react-native-render-html';
import { getParentsTagsRecursively } from 'react-native-render-html/src/HTMLUtils';
@ -48,7 +47,7 @@ class PostBody extends PureComponent {
if (!url) return;
const { intl } = this.props;
Linking.canOpenURL(url).then((supported) => {
Linking.canOpenURL(url).then(supported => {
if (supported) {
Linking.openURL(url);
} else {
@ -158,7 +157,10 @@ class PostBody extends PureComponent {
<FastImage
key={passProps.key}
defaultSource={DEFAULT_IMAGE}
source={{ uri: htmlAttribs.src, priority: FastImage.priority.normal }}
source={{
uri: proxifyImageSrc(htmlAttribs.src, _initialDimensions.width, 0),
priority: FastImage.priority.normal,
}}
style={isComment ? styles.commentImage : styles.postImage}
resizeMode={FastImage.resizeMode.contain}
/>
@ -166,13 +168,21 @@ class PostBody extends PureComponent {
a: (htmlAttribs, children, convertedCSSStyles, passProps) => {
if (passProps.parentWrapper === 'Text') {
return (
<Text key={passProps.key} {...htmlAttribs} onPress={() => this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}>
<Text
key={passProps.key}
{...htmlAttribs}
onPress={() => this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}
>
{children}
</Text>
);
}
return (
<TouchableOpacity key={passProps.key} {...htmlAttribs} onPress={() => this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}>
<TouchableOpacity
key={passProps.key}
{...htmlAttribs}
onPress={() => this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}
>
{children}
</TouchableOpacity>
);

View File

@ -3,9 +3,9 @@ import { injectIntl } from 'react-intl';
import { View, FlatList, Text } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import ActionSheet from 'react-native-actionsheet';
import { postBodySummary } from '@esteemapp/esteem-render-helpers';
// Utils
import { getPostSummary } from '../../../utils/formatter';
import { catchDraftImage } from '../../../utils/image';
import { getFormatedCreatedDate } from '../../../utils/time';
@ -41,7 +41,7 @@ class DraftsScreen extends Component {
const tags = item.tags ? item.tags.split(/[ ,]+/) : [];
const tag = tags[0] || '';
const image = catchDraftImage(item.body);
const summary = getPostSummary(item.body, 100);
const summary = postBodySummary(item, 100);
const isSchedules = type === 'schedules';
return (

View File

@ -1,22 +1,3 @@
export const getPostSummary = (postBody, length, isQuote) => {
if (!postBody) {
return '';
}
postBody = postBody
.replace(/(<([^>]+)>)/gi, '') // Remove html tags
.replace(/\r?\n|\r/g, ' ') // Remove new lines
.replace(/(?:https?|ftp):\/\/[\n\S]+/g, '') // Remove urls
.trim()
.replace(/ +(?= )/g, ''); // Remove all multiple spaces
if (length) {
// Truncate
postBody = postBody.substring(0, length);
}
return isQuote ? `"${postBody}..."` : `${postBody}...`;
};
export const makeCountFriendly = value => {
if (!value) return value;
if (value >= 1000000) return `${intlFormat(value / 1000000)}M`;

View File

@ -1,69 +0,0 @@
// TODO: Refactor
export const sanitizeNode = node => {
const ALLOWED_TAGS = [
'A',
'STRONG',
'B',
'I',
'EM',
'CODE',
'BLOCKQUOTE',
'SUP',
'SUB',
'H2',
'H1',
'H3',
'H4',
'H5',
'H6',
'DIV',
'P',
'IFRAME',
'CENTER',
'UL',
'OL',
'LI',
'TABLE',
'THEAD',
'TBODY',
'TR',
'TD',
'TH',
'HR',
'BR',
'IMG',
];
const ALLOWED_ATTRS = [
'data-permlink',
'data-tag',
'data-author',
'data-href',
'class',
'src',
'alt',
'title',
'width',
'height',
'border',
'frameborder',
'allowfullscreen',
'mozallowfullscreen',
'webkitallowfullscreen',
];
const allElems = node.querySelectorAll('*');
allElems.forEach(el => {
if (ALLOWED_TAGS.indexOf(el.tagName) === -1) {
el.outerHTML = `<span>${el.innerText.replace('>', '&gt;').replace('<', '&lt;')}</span>`;
}
for (const attr of el.attributes) {
if (ALLOWED_ATTRS.indexOf(attr.name) === -1) {
el.removeAttribute(attr.name);
}
}
});
return node;
};

View File

@ -1,33 +1,22 @@
import CryptoJS from 'crypto-js';
import * as dsteem from 'dsteem';
import { Buffer } from 'buffer';
import { proxifyImageSrc } from '@esteemapp/esteem-render-helpers';
export const generateSignature = (media, privateKey) => {
const STRING = 'ImageSigningChallenge';
const prefix = new Buffer(STRING);
const prefix = Buffer.from(STRING);
const commaIdx = media.data.indexOf(',');
const dataBs64 = media.data.substring(commaIdx + 1);
const data = new Buffer(dataBs64, 'base64');
const data = Buffer.from(dataBs64, 'base64');
const hash = CryptoJS.SHA256(prefix, data);
const buffer = Buffer.from(hash.toString(CryptoJS.enc.Hex), 'hex');
const array = new Uint8Array(buffer);
const key = dsteem.PrivateKey.fromString(privateKey);
return key.sign(new Buffer(array)).toString();
};
export const proxifyImageSrc = (url, width = 0, height = 0) => {
if (!url) {
return '';
}
const prefix = `https://steemitimages.com/${width}x${height}/`;
if (url.startsWith(prefix)) return url;
return `${prefix}${url}`;
return key.sign(Buffer.from(array)).toString();
};
export const catchEntryImage = (entry, width = 0, height = 0) => {

View File

@ -1,342 +0,0 @@
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 pullRightLeftRegex = /(<div class="[^"]*?pull-[^"]*?">(.*?)(<[/]div>))/g;
// const markdownLinkRegex = /(?:__|[])|\[(.*?)\]\(.*?\)/g;
const copiedPostRegex = /\/(.*)\/(@[\w.\d-]+)\/(.*)/i;
const postRegex = /^https?:\/\/(.*)\/(.*)\/(@[\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;
const authorNameRegex = /(^|[^a-zA-Z0-9_!#$%&*@\/]|(^|[^a-zA-Z0-9_+~.-\/]))[@]([a-z][-\.a-z\d]+[a-z\d])/gi;
const tagsRegex = /(^|\s|>)(#[-a-z\d]+)/gi;
const centerRegex = /(<center>)/g;
const imgRegex = /(https?:\/\/.*\.(?:tiff?|jpe?g|gif|png|svg|ico|PNG|GIF|JPG|JPEG))/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 hTagRegex = /(<h([1-6])>([^<]*)<\/h([1-6])>)/g;
const emptyLinkRegex = /!\[]\(\)/g;
export const markDown2Html = input => {
if (!input) {
return '';
}
let output = input;
if (authorNameRegex.test(output)) {
output = replaceAuthorNames(output);
}
if (emptyLinkRegex.test(output)) {
output = handleEmptyLink(output);
}
if (tagsRegex.test(output)) {
output = replaceTags(output);
}
if (youTubeRegex.test(output)) {
output = createYoutubeIframe(output);
}
if (imgTagRegex.test(output)) {
output = handleImageTag(output);
}
if (vimeoRegex.test(output)) {
output = createVimeoIframe(output);
}
if (vimeoRegex.test(output)) {
output = createVimeoIframe(output);
}
if (centerRegex.test(output)) {
output = centerStyling(output);
}
if (postRegex.test(output)) {
output = steemitUrlHandle(output);
}
if (markdownImageRegex.test(output)) {
output = changeMarkdownImage(output);
}
if (iframeRegex.test(output)) {
output = handleIframe(output);
}
// if (imgRegex.test(output)) {
// output = handleImageLink(output);
// }
if (linkRegex.test(output)) {
output = handleLinks(output);
}
if (aTagRegex.test(output)) {
output = handleATag(output);
}
if (hTagRegex.test(output)) {
output = handleHTag(output);
}
// if (copiedPostRegex.test(output)) {
// output = handleMarkdownLink(output);
// }
output = md.render(output);
return output;
};
const replaceAuthorNames = input =>
input.replace(authorNameRegex, (match, preceeding1, preceeding2, user) => {
const userLower = user.toLowerCase();
const preceedings = (preceeding1 || '') + (preceeding2 || '');
return `${preceedings}<a class="markdown-author-link" href="${userLower}" data-author="${userLower}">@${user}</a>`;
});
const replaceTags = input =>
input.replace(tagsRegex, tag => {
if (/#[\d]+$/.test(tag)) return tag;
const preceding = /^\s|>/.test(tag) ? tag[0] : '';
tag = tag.replace('>', '');
const tag2 = tag.trim().substring(1);
const tagLower = tag2.toLowerCase();
return `${preceding}<a class="markdown-tag-link" href="${tagLower}" data-tag="${tagLower}">${tag.trim()}</a>`;
});
const handleATag = input =>
input.replace(aTagRegex, link => {
if (dTubeRegex.test(link)) {
const dTubeMatch = link.match(dTubeRegex)[0];
const execLink = dTubeRegex.exec(dTubeMatch);
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;
}
if (imgRegex.test(link)) {
const imgMatch = link.match(imgRegex)[0];
if (imgMatch) return `<a src="${imgMatch}">Image</a>`;
}
return link;
});
const handleHTag = input => input.replace(hTagRegex, tag => `<div>${tag}</div>`);
const handleMarkdownLink = input =>
input.replace(copiedPostRegex, link => {
const postMatch = link.match(copiedPostRegex);
if (postMatch) {
let tag = postMatch[1];
if (tag === '/busy.org') {
tag = 'busy';
}
const _permlink =
postMatch[3].indexOf(')') > 0 ? postMatch[3].replace(')', '') : postMatch[3];
return `<a class="markdown-post-link" href="${_permlink}" data_tag={${tag.trim()}} data_author="${postMatch[2].replace(
'@',
'',
)}">/${_permlink}</a>`;
}
});
const handleLinks = input =>
input.replace(linkRegex, link => {
if (link) {
if (
link
.toLowerCase()
.trim()
.indexOf('https://steemitimages.com/0x0/') === 0 ||
imgRegex.test(link)
) {
const imageMatch = link.match(imgRegex);
if (imageMatch) {
if (imageMatch[0].indexOf('.gif') > 0) {
return gifBody(imageMatch[0]);
}
if (imageMatch[0]) {
return imageBody(imageMatch[0]);
}
} else if (link.trim().indexOf('ipfs.busy.org') > 0) {
return imageBody(link);
}
return link;
}
if (link.trim().indexOf('ipfs.busy.org') > 0) {
return imageBody(link);
}
if (imgRegex.test(link)) {
return imageBody(link);
}
}
return link;
});
const changeMarkdownImage = input =>
input.replace(markdownImageRegex, link => {
const markdownMatch = link.match(markdownImageRegex);
if (markdownMatch[0]) {
const firstMarkdownMatch = markdownMatch[0];
const _link = firstMarkdownMatch.match(urlRegex) && firstMarkdownMatch.match(urlRegex)[0];
if (_link) return _link;
return link;
}
return link;
});
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);
const tag = postMatch[2];
const author = postMatch[3].replace('@', '');
const permlink = postMatch[4];
return `<a class="markdown-post-link" href="${permlink}" data_tag={${tag}} data_author="${author}">/${permlink}</a>`;
});
const handleImageTag = input =>
input.replace(imgTagRegex, imgTag => {
const _imgTag = imgTag.trim();
const match = _imgTag.match(imgRegex);
if (match && match[0]) {
return match[0];
}
return imgTag;
});
const createYoutubeIframe = input =>
input.replace(youTubeRegex, link => {
if (link.indexOf(')') || link.indexOf('(')) {
return link;
}
const execVideo = youTubeRegex.exec(link);
const match = link.match(youTubeRegex);
if (execVideo[1] && match) {
const videoLink = execVideo[1];
const embedLink = `https://www.youtube.com/embed/${videoLink}`;
return iframeBody(embedLink);
}
return link;
});
const handleIframe = input =>
input.replace(iframeRegex, link => {
const match = link.match(linkRegex);
if (match && match[0]) {
return iframeBody(match[0]);
}
return link;
});
const handleEmptyLink = input => input.replace(handleEmptyLink, () => '');
const createVimeoIframe = input =>
input.replace(vimeoRegex, link => {
const execLink = vimeoRegex.exec(link);
const embedLink = `https://player.vimeo.com/video/${execLink[3]}`;
return iframeBody(embedLink);
});
const iframeBody = link => `<iframe frameborder='0' allowfullscreen src='${link}'></iframe>`;
const imageBody = link =>
`<center style="text-align: center; align-items: center; justify-content: center;"><img src="${`https://steemitimages.com/600x0/${link}`}" /></center>`;
const gifBody = link => `<img src="${`https://steemitimages.com/0x0/${link}`}" />`;
// const handleImageLink = input => input.replace(imgRegex, link => imageBody(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;
// });

View File

@ -1,18 +1,3 @@
import parseToken from './parseToken';
import { isEmptyContentDate } from './time';
export const postSumTotal = content => {
if (content.pending_payout_value && isEmptyContentDate(content.last_payout)) {
return content.total_payout_value
? parseToken(content.total_payout_value) + parseToken(content.pending_payout_value)
: 0;
}
return content.total_payout_value
? parseToken(content.total_payout_value) + parseToken(content.curator_payout_value)
: 0;
};
export const getPostUrl = url => {
const BASE_URL = 'https://steemit.com';

View File

@ -1,7 +1,7 @@
import isEmpty from 'lodash/isEmpty';
import forEach from 'lodash/forEach';
import { postBodySummary, renderPostBody } from '@esteemapp/esteem-render-helpers';
// Utils
import { markDown2Html } from './markdownToHtml';
import { getPostSummary } from './formatter';
import { getReputation } from './reputation';
export const parsePosts = (posts, currentUserName) =>
@ -43,18 +43,15 @@ export const parsePost = (post, currentUserName) => {
const voteRshares = post.active_votes.reduce((a, b) => a + parseFloat(b.rshares), 0);
const ratio = totalPayout / voteRshares;
if (post.active_votes && post.active_votes.length > 0) {
for (const i in post.active_votes) {
post.vote_perecent =
post.active_votes[i].voter === currentUserName ? post.active_votes[i].percent : null;
post.active_votes[i].value = (post.active_votes[i].rshares * ratio).toFixed(3);
post.active_votes[i].reputation = getReputation(post.active_votes[i].reputation);
post.active_votes[i].percent = post.active_votes[i].percent / 100;
post.active_votes[i].is_down_vote = Math.sign(post.active_votes[i].percent) < 0;
post.active_votes[i].avatar = `https://steemitimages.com/u/${
post.active_votes[i].voter
}/avatar/small`;
}
if (!isEmpty(post.active_votes)) {
forEach(post.active_votes, value => {
post.vote_perecent = value.voter === currentUserName ? value.percent : null;
value.value = (value.rshares * ratio).toFixed(3);
value.reputation = getReputation(value.reputation);
value.percent /= 100;
value.is_down_vote = Math.sign(value.percent) < 0;
value.avatar = `https://steemitimages.com/u/${value.voter}/avatar/small`;
});
}
return post;
@ -66,23 +63,24 @@ const isVoted = (activeVotes, currentUserName) =>
const postImage = (metaData, body) => {
const imgTagRegex = /(<img[^>]*>)/g;
const markdownImageRegex = /!\[[^\]]*\]\((.*?)\s*("(?:.*[^"])")?\s*\)/g;
// eslint-disable-next-line max-len
const urlRegex = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?/gm;
const imageRegex = /(http(s?):)([/|.|\w|\s|-])*\.(?:jpg|gif|png)/g;
let imageLink;
if (metaData && metaData.image && metaData.image[0]) {
imageLink = metaData.image[0];
[imageLink] = metaData.image;
} else if (body && markdownImageRegex.test(body)) {
const markdownMatch = body.match(markdownImageRegex);
if (markdownMatch[0]) {
const firstMarkdownMatch = markdownMatch[0];
imageLink = firstMarkdownMatch.match(urlRegex)[0];
[imageLink] = firstMarkdownMatch.match(urlRegex);
}
}
if (!imageLink && imageRegex.test(body)) {
const imageMatch = body.match(imageRegex);
imageLink = imageMatch[0];
[imageLink] = imageMatch;
}
if (!imageLink && imgTagRegex.test(body)) {
@ -90,7 +88,7 @@ const postImage = (metaData, body) => {
const match = _imgTag[0].match(urlRegex);
if (match && match[0]) {
imageLink = match[0];
[imageLink] = match;
}
}
@ -100,51 +98,15 @@ const postImage = (metaData, body) => {
return '';
};
// export const protocolUrl2Obj = (url) => {
// let urlPart = url.split('://')[1];
// // remove last char if /
// if (urlPart.endsWith('/')) {
// urlPart = urlPart.substring(0, urlPart.length - 1);
// }
// const parts = urlPart.split('/');
// // filter
// if (parts.length === 1) {
// return { type: 'filter' };
// }
// // filter with tag
// if (parts.length === 2) {
// return { type: 'filter-tag', filter: parts[0], tag: parts[1] };
// }
// // account
// if (parts.length === 1 && parts[0].startsWith('@')) {
// return { type: 'account', account: parts[0].replace('@', '') };
// }
// // post
// if (parts.length === 3 && parts[1].startsWith('@')) {
// return {
// type: 'post',
// cat: parts[0],
// author: parts[1].replace('@', ''),
// permlink: parts[2],
// };
// }
// };
export const parseComments = comments => {
comments.map(comment => {
forEach(comments, comment => {
comment.pending_payout_value = parseFloat(comment.pending_payout_value).toFixed(3);
comment.vote_count = comment.active_votes.length;
comment.author_reputation = getReputation(comment.author_reputation);
comment.avatar = `https://steemitimages.com/u/${comment.author}/avatar/small`;
comment.markdownBody = comment.body;
comment.body = renderPostBody(comment);
comment.summary = `"${getPostSummary(comment.body, 100, true)}"`;
comment.summary = `"${postBodySummary(comment, 100, true)}"`;
});
return comments;
};

View File

@ -1,11 +0,0 @@
export default (url, width = 0, height = 0) => {
if (!url) {
return '';
}
const prefix = `https://steemitimages.com/${width}x${height}/`;
if (url.startsWith(prefix)) return url;
return `${prefix}${url}`;
};

View File

@ -1,15 +0,0 @@
import { getUserData, getAuthStatus } from '../realm/realm';
export const getUserIsLoggedIn = () => {
getAuthStatus()
.then(res => res.isLoggedIn)
.catch(() => null);
};
export const getUserDataFromRealm = () => {
getUserData()
.then(res => {
userData = Array.from(res);
})
.catch(() => null);
};

View File

@ -1,23 +1,24 @@
export const getReputation = reputation => {
if (reputation === null) return reputation;
let _reputation = String(parseInt(reputation));
let _reputation = String(parseInt(reputation, 10));
const neg = _reputation.charAt(0) === '-';
_reputation = neg ? _reputation.substring(1) : _reputation;
const str = _reputation;
const leadingDigits = parseInt(str.substring(0, 4));
const leadingDigits = parseInt(str.substring(0, 4), 10);
const log = Math.log(leadingDigits) / Math.log(10);
const n = str.length - 1;
let out = n + (log - parseInt(log));
let out = n + (log - parseInt(log, 10));
// eslint-disable-next-line no-restricted-globals
if (isNaN(out)) out = 0;
out = Math.max(out - 9, 0);
out = (neg ? -1 : 1) * out;
out *= neg ? -1 : 1;
out = out * 9 + 25;
out = parseInt(out);
out = parseInt(out, 10);
return out;
};

View File

@ -1,3 +1,4 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import qs from 'qs';
import { Linking } from 'react-native';

View File

@ -22,17 +22,17 @@ export const getReputation = input => {
return Math.floor(reputationLevel);
};
/* eslint-disable */
export const getName = about => {
if (about['profile'] && about['profile']['name']) {
return about['profile']['name'];
if (about.profile && about.profile.name) {
return about.profile.name;
}
return null;
};
export const getAvatar = about => {
if (about['profile'] && about['profile']['profile_image']) {
return about['profile']['profile_image'];
if (about.profile && about.profile.profile_image) {
return about.profile.profile_image;
}
return null;
};

View File

@ -10,8 +10,7 @@ export const groomingTransactionData = (transaction, steemPerMVests, formatNumbe
const result = {};
// eslint-disable-next-line
result.opName = transaction[1].op[0];
[result.opName] = transaction[1].op;
const opData = transaction[1].op[1];
const { timestamp } = transaction[1];