From 803bf153e7fabbcc4b10a40b83a6e05fa0e35d28 Mon Sep 17 00:00:00 2001 From: Mustafa Buyukcelebi Date: Tue, 4 Jun 2019 10:23:46 +0300 Subject: [PATCH 1/6] Removed post render functions. Changed image urls --- .../postElements/body/view/postBodyView.js | 24 +- src/screens/drafts/screen/draftsScreen.js | 4 +- src/utils/formatter.js | 19 - src/utils/htmlSanitizer.js | 69 ---- src/utils/image.js | 19 +- src/utils/markdownToHtml.js | 342 ------------------ src/utils/post.js | 15 - src/utils/postParser.js | 74 +--- src/utils/proxifyImageSrc.js | 11 - src/utils/realm.js | 15 - src/utils/reputation.js | 11 +- src/utils/sendEmail.js | 1 + src/utils/user.js | 10 +- src/utils/wallet.js | 3 +- 14 files changed, 54 insertions(+), 563 deletions(-) delete mode 100644 src/utils/htmlSanitizer.js delete mode 100644 src/utils/markdownToHtml.js delete mode 100644 src/utils/proxifyImageSrc.js delete mode 100644 src/utils/realm.js diff --git a/src/components/postElements/body/view/postBodyView.js b/src/components/postElements/body/view/postBodyView.js index 5976a28a5..1c0667c74 100644 --- a/src/components/postElements/body/view/postBodyView.js +++ b/src/components/postElements/body/view/postBodyView.js @@ -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 { @@ -166,13 +168,21 @@ class PostBody extends PureComponent { a: (htmlAttribs, children, convertedCSSStyles, passProps) => { if (passProps.parentWrapper === 'Text') { return ( - this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}> + this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)} + > {children} ); } return ( - this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}> + this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)} + > {children} ); diff --git a/src/screens/drafts/screen/draftsScreen.js b/src/screens/drafts/screen/draftsScreen.js index 5104c26bf..b86c2eaa1 100644 --- a/src/screens/drafts/screen/draftsScreen.js +++ b/src/screens/drafts/screen/draftsScreen.js @@ -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 ( diff --git a/src/utils/formatter.js b/src/utils/formatter.js index b400ba37c..c8c84e989 100644 --- a/src/utils/formatter.js +++ b/src/utils/formatter.js @@ -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`; diff --git a/src/utils/htmlSanitizer.js b/src/utils/htmlSanitizer.js deleted file mode 100644 index c7b021a3d..000000000 --- a/src/utils/htmlSanitizer.js +++ /dev/null @@ -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 = `${el.innerText.replace('>', '>').replace('<', '<')}`; - } - - for (const attr of el.attributes) { - if (ALLOWED_ATTRS.indexOf(attr.name) === -1) { - el.removeAttribute(attr.name); - } - } - }); - - return node; -}; diff --git a/src/utils/image.js b/src/utils/image.js index f08fbbe3c..3bc1b7d85 100644 --- a/src/utils/image.js +++ b/src/utils/image.js @@ -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) => { diff --git a/src/utils/markdownToHtml.js b/src/utils/markdownToHtml.js deleted file mode 100644 index f993d9f89..000000000 --- a/src/utils/markdownToHtml.js +++ /dev/null @@ -1,342 +0,0 @@ -import Remarkable from 'remarkable'; -// TODO: Refactoring need! -const md = new Remarkable({ html: true, breaks: true, linkify: true }); - -// const imgCenterRegex = /([
]http(s?):)([/|.|\w|\s|-])*\.(?:jpg|gif|png|PNG|GIF|JPG)[
]/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>))/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 = /(
)/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 = /(]*>)/g; -const iframeRegex = /(?:]*)(?:(?:\/>)|(?:>.*?<\/iframe>))/g; -const hTagRegex = /(([^<]*)<\/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}@${user}`; - }); - -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}${tag.trim()}`; - }); - -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 `Image`; - } - - return link; - }); - -const handleHTag = input => input.replace(hTagRegex, tag => `
${tag}
`); - -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 `/${_permlink}`; - } - }); - -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, - () => '
', - ); - -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 `/${permlink}`; - }); - -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 => ``; -const imageBody = link => - `
`; -const gifBody = 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 `

${match[0]}

`; -// } - -// return iframeBody(match[0]); - -// }); - -// const createCenterImage = input => input.replace(imgCenterRegex, (link) => { -// let _link = link; - -// _link = _link.split('>')[1]; -// _link = _link.split('<')[0]; -// return `><`; -// }); - -// const changePullRightLeft = input => input.replace(pullRightLeftRegex, (item) => { -// const imageLink = item.match(linkRegex)[0]; - -// return `

`; -// }); - -// 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; -// }); diff --git a/src/utils/post.js b/src/utils/post.js index 87fd035aa..58e4df014 100644 --- a/src/utils/post.js +++ b/src/utils/post.js @@ -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'; diff --git a/src/utils/postParser.js b/src/utils/postParser.js index b95525c12..ec2173a33 100644 --- a/src/utils/postParser.js +++ b/src/utils/postParser.js @@ -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 = /(]*>)/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; }; diff --git a/src/utils/proxifyImageSrc.js b/src/utils/proxifyImageSrc.js deleted file mode 100644 index 2bab7c5ea..000000000 --- a/src/utils/proxifyImageSrc.js +++ /dev/null @@ -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}`; -}; diff --git a/src/utils/realm.js b/src/utils/realm.js deleted file mode 100644 index 7ebe66a0b..000000000 --- a/src/utils/realm.js +++ /dev/null @@ -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); -}; diff --git a/src/utils/reputation.js b/src/utils/reputation.js index 07c09d52c..c0a2c6d9a 100644 --- a/src/utils/reputation.js +++ b/src/utils/reputation.js @@ -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; }; diff --git a/src/utils/sendEmail.js b/src/utils/sendEmail.js index c6b798dcd..40319f559 100644 --- a/src/utils/sendEmail.js +++ b/src/utils/sendEmail.js @@ -1,3 +1,4 @@ +// eslint-disable-next-line import/no-extraneous-dependencies import qs from 'qs'; import { Linking } from 'react-native'; diff --git a/src/utils/user.js b/src/utils/user.js index e26402f15..d9059f7bd 100644 --- a/src/utils/user.js +++ b/src/utils/user.js @@ -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; }; diff --git a/src/utils/wallet.js b/src/utils/wallet.js index 384f9a6d0..dc1c3cd13 100644 --- a/src/utils/wallet.js +++ b/src/utils/wallet.js @@ -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]; From 68cf666d0e2593a2828b25de1ef78d4cf1393cea Mon Sep 17 00:00:00 2001 From: Mustafa Buyukcelebi Date: Sat, 8 Jun 2019 00:31:33 +0300 Subject: [PATCH 2/6] Fixed markdown editor bugs --- .../view/formats/applyListFormat.js | 38 ++++++++----- .../view/formats/applyWebLinkFormat.js | 10 ++-- .../view/formats/applyWrapFormat.js | 11 +--- .../view/formats/applyWrapFormatNewLines.js | 16 ++---- .../markdownEditor/view/formats/formats.js | 1 - .../markdownEditor/view/markdownEditorView.js | 55 ++++++++++--------- .../textInput/view/textInputView.js | 6 +- 7 files changed, 68 insertions(+), 69 deletions(-) diff --git a/src/components/markdownEditor/view/formats/applyListFormat.js b/src/components/markdownEditor/view/formats/applyListFormat.js index c39861060..640048213 100644 --- a/src/components/markdownEditor/view/formats/applyListFormat.js +++ b/src/components/markdownEditor/view/formats/applyListFormat.js @@ -1,32 +1,40 @@ import { replaceBetween } from './utils'; -export default ({ getState, item, setState }) => { - let { text } = getState(); - const { selection } = getState(); - text = text || ''; +export default async ({ getState, item, setState }) => { + const states = getState(); + let { text } = states; + const { selection } = states; let newText; let newSelection; - if (selection.start !== selection.end) { + + text = text || ''; + + const isSelected = selection.start === selection.end; + const hasLineBreakOnStart = text.substring(selection.start - 1, selection.start) === '\n'; + const hasLineBreakOnEnd = text.substring(selection.end - 1, selection.end) === '\n'; + + if (!isSelected && hasLineBreakOnStart) { newText = replaceBetween( text, selection, `${item.prefix} ${text.substring(selection.start, selection.end)}\n`, ); newSelection = { start: selection.end + 3, end: selection.end + 3 }; - } else if ( - selection.start === selection.end && - text.substring(selection.end - 1, selection.end) === '\n' - ) { + } else if (!isSelected && !hasLineBreakOnStart) { + newText = replaceBetween( + text, + selection, + `\n${item.prefix} ${text.substring(selection.start, selection.end)}\n`, + ); + newSelection = { start: selection.end + 3, end: selection.end + 3 }; + } else if (isSelected && hasLineBreakOnEnd) { newText = replaceBetween(text, selection, `${item.prefix} `); newSelection = { start: selection.start + 2, end: selection.start + 2 }; - } else { + } else if (isSelected && !hasLineBreakOnEnd) { newText = replaceBetween(text, selection, `\n${item.prefix} `); newSelection = { start: selection.start + 3, end: selection.start + 3 }; } - setState({ text: newText }, () => { - setTimeout(() => { - setState({ newSelection }); - }, 300); - }); + await setState({ text: newText, textUpdated: true }); + await setState({ newSelection }); }; diff --git a/src/components/markdownEditor/view/formats/applyWebLinkFormat.js b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js index 563a2297b..f33c3cead 100644 --- a/src/components/markdownEditor/view/formats/applyWebLinkFormat.js +++ b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js @@ -3,15 +3,15 @@ import { isStringWebLink, replaceBetween } from './utils'; export const writeUrlTextHere = 'https://example.com'; export const writeTextHereString = 'Text here'; -export default ({ getState, item, setState, isImage = null }) => { +export default async ({ getState, item, setState, isImage = null }) => { const { selection, text } = getState(); const imagePrefix = isImage ? '!' : ''; const itemText = item ? item.text : writeTextHereString; const itemUrl = item ? item.url : writeUrlTextHere; - let newText; let newSelection; const selectedText = text.substring(selection.start, selection.end); + if (selection.start !== selection.end) { if (isStringWebLink(selectedText)) { newText = replaceBetween(text, selection, `${imagePrefix}[${itemText}](${selectedText})`); @@ -40,7 +40,7 @@ export default ({ getState, item, setState, isImage = null }) => { }; } } - setState({ text: newText }, () => { - setState({ newSelection }); - }); + + await setState({ text: newText, textUpdated: true }); + await setState({ newSelection }); }; diff --git a/src/components/markdownEditor/view/formats/applyWrapFormat.js b/src/components/markdownEditor/view/formats/applyWrapFormat.js index 11ad6b4e3..d15d99c8e 100644 --- a/src/components/markdownEditor/view/formats/applyWrapFormat.js +++ b/src/components/markdownEditor/view/formats/applyWrapFormat.js @@ -8,19 +8,14 @@ export default ({ getState, item, setState }) => { item.wrapper.concat(text.substring(selection.start, selection.end), item.wrapper), ); let newPosition; + if (selection.start === selection.end) { newPosition = selection.end + item.wrapper.length; } else { newPosition = selection.end + item.wrapper.length * 2; } - const extra = { - newSelection: { - start: newPosition, - end: newPosition, - }, - }; - setState({ text: newText }, () => { - setState({ ...extra }); + setState({ text: newText, textUpdated: true }, () => { + setState({ newSelection: { start: newPosition, end: newPosition } }); }); }; diff --git a/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js index 6bc3657ea..f2744a793 100644 --- a/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js +++ b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js @@ -1,6 +1,6 @@ import { replaceBetween } from './utils'; -export default ({ getState, item, setState }) => { +export default async ({ getState, item, setState }) => { const { text, selection } = getState(); let newText = replaceBetween( text, @@ -41,15 +41,7 @@ export default ({ getState, item, setState }) => { )}`, ); } - const extra = { - newSelection: { - start: newPosition, - end: newPosition, - }, - }; - setState({ text: newText }, () => { - setTimeout(() => { - setState({ ...extra }); - }, 25); - }); + + await setState({ text: newText, textUpdated: true }); + await setState({ newSelection: { start: newPosition, end: newPosition } }); }; diff --git a/src/components/markdownEditor/view/formats/formats.js b/src/components/markdownEditor/view/formats/formats.js index 0d5ee0d2d..ced587e87 100644 --- a/src/components/markdownEditor/view/formats/formats.js +++ b/src/components/markdownEditor/view/formats/formats.js @@ -11,7 +11,6 @@ export default [ iconType: 'FontAwesome', wrapper: '**', onPress: applyWrapFormat, - // style: { fontWeight: 'bold' }, }, { key: 'I', diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index 68ae18a67..bb6a97507 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -22,8 +22,13 @@ export default class MarkdownEditorView extends Component { this.state = { text: props.draftBody || '', selection: { start: 0, end: 0 }, + textUpdated: false, newSelection: null, }; + + this.inputRef = React.createRef(); + this.galleryRef = React.createRef(); + this.clearRef = React.createRef(); } // Lifecycle functions @@ -47,8 +52,8 @@ export default class MarkdownEditorView extends Component { ) { applyImageLink({ getState: this._getState, - setState: (state, callback) => { - this.setState(state, callback); + setState: async (state, callback) => { + await this.setState(state, callback); }, item: { url: nextProps.uploadedImage.url, text: nextProps.uploadedImage.hash }, isImage: !!nextProps.uploadedImage, @@ -76,6 +81,14 @@ export default class MarkdownEditorView extends Component { // Component functions _changeText = input => { const { onChange, handleOnTextChange, handleIsValid, componentID } = this.props; + const { textUpdated } = this.state; + + if (textUpdated) { + this.setState({ + textUpdated: false, + }); + return; + } this.setState({ text: input }); @@ -100,14 +113,16 @@ export default class MarkdownEditorView extends Component { selection: newSelection, newSelection: null, }); - } else { - this.setState({ - selection: event.nativeEvent.selection, - }); + return; } + this.setState({ + selection: event.nativeEvent.selection, + }); }; - _getState = () => this.state; + _getState = () => { + return this.state; + }; _renderPreview = () => { const { text } = this.state; @@ -154,7 +169,7 @@ export default class MarkdownEditorView extends Component { onPress={() => Formats[9].onPress({ getState, setState })} /> this.ActionSheet.show()} + onPress={() => this.galleryRef.current.show()} style={styles.rightIcons} size={20} iconStyle={styles.icon} @@ -163,21 +178,13 @@ export default class MarkdownEditorView extends Component { /> this.ClearActionSheet.show()} + onPress={() => this.clearRef.current.show()} size={20} iconStyle={styles.clearIcon} iconType="FontAwesome" name="trash" /> - {/* TODO: After alpha */} - {/* */} ); @@ -203,7 +210,7 @@ export default class MarkdownEditorView extends Component { {!isPreviewActive ? ( this._changeText(e)} + onChangeText={this._changeText} onSelectionChange={this._handleOnSelectionChange} placeholder={intl.formatMessage({ id: isReply ? 'editor.reply_placeholder' : 'editor.default_placeholder', @@ -214,6 +221,7 @@ export default class MarkdownEditorView extends Component { style={styles.textWrapper} underlineColorAndroid="transparent" value={text} + innerRef={this.inputRef} /> ) : ( this._renderPreview() @@ -222,13 +230,12 @@ export default class MarkdownEditorView extends Component { this._renderEditorButtons({ getState: this._getState, setState: (state, callback) => { + this.inputRef.current.focus(); this.setState(state, callback); }, })} - - {/* TODO: This is a problem re-factor */} (this.ActionSheet = o)} + ref={this.galleryRef} options={[ intl.formatMessage({ id: 'editor.open_gallery', @@ -246,7 +253,7 @@ export default class MarkdownEditorView extends Component { }} /> (this.ClearActionSheet = o)} + ref={this.clearRef} title={intl.formatMessage({ id: 'alert.clear_alert', })} @@ -259,9 +266,7 @@ export default class MarkdownEditorView extends Component { }), ]} cancelButtonIndex={1} - onPress={index => { - index === 0 && this._handleClear(); - }} + onPress={index => index === 0 && this._handleClear()} /> ); diff --git a/src/components/textInput/view/textInputView.js b/src/components/textInput/view/textInputView.js index ce23aaaad..6b9411cb2 100644 --- a/src/components/textInput/view/textInputView.js +++ b/src/components/textInput/view/textInputView.js @@ -1,9 +1,9 @@ import React from 'react'; -import { connect } from 'react-redux'; import { TextInput } from 'react-native'; +import { connect } from 'react-redux'; -const TextInputView = props => ( - +const TextInputView = ({ isDarkTheme, innerRef, ...props }) => ( + ); const mapStateToProps = state => ({ From fc9982da144c4b54875c492fc01a668da48c24e3 Mon Sep 17 00:00:00 2001 From: Mustafa Buyukcelebi Date: Sat, 8 Jun 2019 00:48:03 +0300 Subject: [PATCH 3/6] Fixed clear editor button design issue --- src/components/markdownEditor/view/markdownEditorView.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js index bb6a97507..6a65dc4ae 100644 --- a/src/components/markdownEditor/view/markdownEditorView.js +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -183,6 +183,7 @@ export default class MarkdownEditorView extends Component { iconStyle={styles.clearIcon} iconType="FontAwesome" name="trash" + backgroundColor={styles.clearButtonWrapper.backgroundColor} /> From 326257bc4026bb1d31e320e19a28fbddffb077b7 Mon Sep 17 00:00:00 2001 From: Mustafa Buyukcelebi Date: Sun, 9 Jun 2019 20:14:33 +0300 Subject: [PATCH 4/6] Fixed comment issues --- src/components/comment/view/commentView.js | 211 +++++++++--------- .../comments/container/commentsContainer.js | 32 ++- src/components/comments/view/commentsView.js | 88 +++++--- src/components/postCard/view/postCardView.js | 4 +- .../postElements/body/view/postBodyView.js | 22 +- .../postView/view/postDisplayView.js | 4 +- src/config/locales/en-US.json | 3 +- src/screens/transfer/screen/transferScreen.js | 1 - 8 files changed, 218 insertions(+), 147 deletions(-) diff --git a/src/components/comment/view/commentView.js b/src/components/comment/view/commentView.js index fcb679d27..7a0dbe157 100644 --- a/src/components/comment/view/commentView.js +++ b/src/components/comment/view/commentView.js @@ -1,5 +1,5 @@ import React, { PureComponent, Fragment } from 'react'; -import { View, Text } from 'react-native'; +import { View, Text, TouchableWithoutFeedback } from 'react-native'; import ActionSheet from 'react-native-actionsheet'; import { injectIntl } from 'react-intl'; @@ -48,6 +48,7 @@ class CommentView extends PureComponent { fetchPost, handleDeleteComment, handleOnEditPress, + handleOnLongPress, handleOnReplyPress, handleOnUserPress, isLoggedIn, @@ -56,115 +57,121 @@ class CommentView extends PureComponent { marginLeft, voteCount, intl, - author, mainAuthor = { mainAuthor }, } = this.props; const { isShowSubComments, isPressedShowButton } = this.state; return ( - - - - - - {isLoggedIn && ( - - - - {voteCount} - handleOnReplyPress && handleOnReplyPress(comment)} - iconType="MaterialIcons" - /> - {currentAccountUsername === comment.author && ( - - handleOnEditPress && handleOnEditPress(comment)} - iconType="MaterialIcons" - /> - {!comment.children && !voteCount && ( - - this.ActionSheet.show()} - iconType="MaterialIcons" - /> - (this.ActionSheet = o)} - options={[ - intl.formatMessage({ id: 'alert.delete' }), - intl.formatMessage({ id: 'alert.cancel' }), - ]} - title={intl.formatMessage({ id: 'alert.delete' })} - destructiveButtonIndex={0} - cancelButtonIndex={1} - onPress={index => { - index === 0 ? handleDeleteComment(comment.permlink) : null; - }} - /> - - )} - - )} - - )} - {isShowMoreButton && ( - - this._showSubCommentsToggle()} - text={!isPressedShowButton ? `${comment.children} more replies` : ''} - /> - + + + + + + + {isLoggedIn && ( + + + + {voteCount} + handleOnReplyPress && handleOnReplyPress(comment)} + iconType="MaterialIcons" + /> + {currentAccountUsername === comment.author && ( + + handleOnEditPress && handleOnEditPress(comment)} + iconType="MaterialIcons" + /> + {!comment.children && !voteCount && ( + + this.ActionSheet.show()} + iconType="MaterialIcons" + /> + (this.ActionSheet = o)} + options={[ + intl.formatMessage({ id: 'alert.delete' }), + intl.formatMessage({ id: 'alert.cancel' }), + ]} + title={intl.formatMessage({ id: 'alert.delete' })} + destructiveButtonIndex={0} + cancelButtonIndex={1} + onPress={index => { + index === 0 ? handleDeleteComment(comment.permlink) : null; + }} + /> + + )} + + )} + + )} + {isShowMoreButton && ( + + this._showSubCommentsToggle()} + text={!isPressedShowButton ? `${comment.children} more replies` : ''} + /> + + )} + + {isShowSubComments && commentNumber > 0 && ( + )} - {isShowSubComments && commentNumber > 0 && ( - - )} - + ); } } diff --git a/src/components/comments/container/commentsContainer.js b/src/components/comments/container/commentsContainer.js index 3a971aba4..86f8fa035 100644 --- a/src/components/comments/container/commentsContainer.js +++ b/src/components/comments/container/commentsContainer.js @@ -1,18 +1,22 @@ import React, { Component } from 'react'; import { withNavigation } from 'react-navigation'; import { connect } from 'react-redux'; +import { injectIntl } from 'react-intl'; +import get from 'lodash/get'; import { getComments, deleteComment } from '../../../providers/steem/dsteem'; // Services and Actions +import { writeToClipboard } from '../../../utils/clipboard'; +import { toastNotification } from '../../../redux/actions/uiAction'; // Middleware // Constants -import { default as ROUTES } from '../../../constants/routeNames'; +import ROUTES from '../../../constants/routeNames'; // Component -import { CommentsView } from '..'; +import CommentsView from '../view/commentsView'; /* * Props Name Description Value @@ -163,6 +167,27 @@ class CommentsContainer extends Component { }); }; + _handleCommentCopyAction = (index, selectedComment) => { + const { dispatch, intl } = this.props; + + switch (index) { + case 0: + writeToClipboard(`https://steemit.com${get(selectedComment, 'url')}`).then(() => { + dispatch( + toastNotification( + intl.formatMessage({ + id: 'alert.copied', + }), + ), + ); + }); + break; + + default: + break; + } + }; + render() { const { comments: _comments, selectedPermlink } = this.state; const { @@ -196,6 +221,7 @@ class CommentsContainer extends Component { isLoggedIn={isLoggedIn} fetchPost={fetchPost} handleDeleteComment={this._handleDeleteComment} + handleCommentCopyAction={this._handleCommentCopyAction} {...this.props} /> ); @@ -208,4 +234,4 @@ const mapStateToProps = state => ({ pinCode: state.account.pin, }); -export default withNavigation(connect(mapStateToProps)(CommentsContainer)); +export default withNavigation(connect(mapStateToProps)(injectIntl(CommentsContainer))); diff --git a/src/components/comments/view/commentsView.js b/src/components/comments/view/commentsView.js index 9de1cfcf9..3be5d5571 100644 --- a/src/components/comments/view/commentsView.js +++ b/src/components/comments/view/commentsView.js @@ -1,7 +1,11 @@ -import React, { PureComponent } from 'react'; +import React, { PureComponent, Fragment } from 'react'; import { FlatList } from 'react-native'; +import ActionSheet from 'react-native-actionsheet'; +import get from 'lodash/get'; +import { injectIntl } from 'react-intl'; // Components +// eslint-disable-next-line import/no-cycle import { Comment } from '../../comment'; // Styles @@ -15,7 +19,10 @@ class CommentsView extends PureComponent { constructor(props) { super(props); - this.state = {}; + this.state = { + selectedComment: null, + }; + this.commentMenu = React.createRef(); } // Component Life Cycles @@ -24,6 +31,11 @@ class CommentsView extends PureComponent { _keyExtractor = item => item.permlink; + _openCommentMenu = item => { + this.setState({ selectedComment: item }); + this.commentMenu.current.show(); + }; + render() { const { mainAuthor, @@ -40,36 +52,56 @@ class CommentsView extends PureComponent { isShowSubComments, marginLeft, handleDeleteComment, + handleCommentCopyAction, + intl, } = this.props; + const { selectedComment } = this.state; return ( - ( - 0} - voteCount={item.net_votes} - isShowSubComments={isShowSubComments} - key={item.permlink} - marginLeft={marginLeft} - /> - )} - /> + + ( + 0} + voteCount={item.net_votes} + isShowSubComments={isShowSubComments} + key={item.permlink} + marginLeft={marginLeft} + handleOnLongPress={() => this._openCommentMenu(item)} + /> + )} + /> + handleCommentCopyAction(index, selectedComment)} + /> + ); } } -export default CommentsView; +export default injectIntl(CommentsView); diff --git a/src/components/postCard/view/postCardView.js b/src/components/postCard/view/postCardView.js index dbd4416d1..ca7f2d397 100644 --- a/src/components/postCard/view/postCardView.js +++ b/src/components/postCard/view/postCardView.js @@ -120,10 +120,10 @@ class PostCardView extends Component { {content.vote_count} - + {content.children} - + ); diff --git a/src/components/postElements/body/view/postBodyView.js b/src/components/postElements/body/view/postBodyView.js index 5976a28a5..46814cbae 100644 --- a/src/components/postElements/body/view/postBodyView.js +++ b/src/components/postElements/body/view/postBodyView.js @@ -1,7 +1,5 @@ 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'; @@ -48,7 +46,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 { @@ -148,7 +146,7 @@ class PostBody extends PureComponent { }; render() { - const { body, isComment } = this.props; + const { body, isComment, textSelectable = true } = this.props; const _initialDimensions = isComment ? { width: WIDTH - 50, height: 80 } : { width: WIDTH, height: 216 }; @@ -166,13 +164,21 @@ class PostBody extends PureComponent { a: (htmlAttribs, children, convertedCSSStyles, passProps) => { if (passProps.parentWrapper === 'Text') { return ( - this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}> + this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)} + > {children} ); } return ( - this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)}> + this._handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)} + > {children} ); @@ -185,7 +191,7 @@ class PostBody extends PureComponent { html={body} onLinkPress={(evt, href, hrefatr) => this._handleOnLinkPress(evt, href, hrefatr)} containerStyle={isComment ? styles.commentContainer : styles.container} - textSelectable + textSelectable={textSelectable} tagsStyles={isComment ? { img: { height: 120 } } : styles} ignoredTags={['script']} debug={false} diff --git a/src/components/postView/view/postDisplayView.js b/src/components/postView/view/postDisplayView.js index 115d520b9..0a7fc23c6 100644 --- a/src/components/postView/view/postDisplayView.js +++ b/src/components/postView/view/postDisplayView.js @@ -185,8 +185,8 @@ class PostDisplayView extends PureComponent { - Posted by {author || post.author} -{' '} + Posted by + {author || post.author} {formatedTime} {/* {isPostEnd && this._getTabBar()} */} diff --git a/src/config/locales/en-US.json b/src/config/locales/en-US.json index a85f266d5..9d0561a5c 100644 --- a/src/config/locales/en-US.json +++ b/src/config/locales/en-US.json @@ -199,7 +199,8 @@ }, "post": { "reblog_alert": "Are you sure you want to reblog?", - "removed_hint": "The post was removed by" + "removed_hint": "The post was removed by", + "copy_link": "Copy Link" }, "drafts": { "title": "Drafts", diff --git a/src/screens/transfer/screen/transferScreen.js b/src/screens/transfer/screen/transferScreen.js index 470235c89..111472222 100644 --- a/src/screens/transfer/screen/transferScreen.js +++ b/src/screens/transfer/screen/transferScreen.js @@ -1,4 +1,3 @@ -/* eslint-disable no-restricted-globals */ import React, { Fragment, Component } from 'react'; import { Text, View, WebView, ScrollView, TouchableOpacity } from 'react-native'; import ActionSheet from 'react-native-actionsheet'; From 515fb57aaa2b0959af704eadd7e790f0d5ca1cdf Mon Sep 17 00:00:00 2001 From: Mustafa Buyukcelebi Date: Tue, 11 Jun 2019 11:08:34 +0300 Subject: [PATCH 5/6] Comment changes --- .../markdownEditor/view/formats/applyWebLinkFormat.js | 5 +++-- .../markdownEditor/view/formats/applyWrapFormatNewLines.js | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/markdownEditor/view/formats/applyWebLinkFormat.js b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js index f33c3cead..2cf5ff0a7 100644 --- a/src/components/markdownEditor/view/formats/applyWebLinkFormat.js +++ b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js @@ -41,6 +41,7 @@ export default async ({ getState, item, setState, isImage = null }) => { } } - await setState({ text: newText, textUpdated: true }); - await setState({ newSelection }); + await setState({ text: newText, textUpdated: true }, async () => { + await setState({ newSelection }); + }); }; diff --git a/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js index f2744a793..96b188b95 100644 --- a/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js +++ b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js @@ -42,6 +42,7 @@ export default async ({ getState, item, setState }) => { ); } - await setState({ text: newText, textUpdated: true }); - await setState({ newSelection: { start: newPosition, end: newPosition } }); + await setState({ text: newText, textUpdated: true }, async () => { + await setState({ newSelection: { start: newPosition, end: newPosition } }); + }); }; From 8604493287736176c375796f7bb56f8ef7db1976 Mon Sep 17 00:00:00 2001 From: u-e Date: Tue, 11 Jun 2019 22:14:54 +0300 Subject: [PATCH 6/6] merged with master --- .../Pods-esteem-acknowledgements.markdown | 73 ++++++++++----- .../Pods-esteem-acknowledgements.plist | 91 ++++++++++++------- 2 files changed, 108 insertions(+), 56 deletions(-) diff --git a/ios/Pods/Target Support Files/Pods-esteem/Pods-esteem-acknowledgements.markdown b/ios/Pods/Target Support Files/Pods-esteem/Pods-esteem-acknowledgements.markdown index 4ab04f57f..a32c490d9 100644 --- a/ios/Pods/Target Support Files/Pods-esteem/Pods-esteem-acknowledgements.markdown +++ b/ios/Pods/Target Support Files/Pods-esteem/Pods-esteem-acknowledgements.markdown @@ -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 diff --git a/ios/Pods/Target Support Files/Pods-esteem/Pods-esteem-acknowledgements.plist b/ios/Pods/Target Support Files/Pods-esteem/Pods-esteem-acknowledgements.plist index 10ae8c73e..c640a907c 100644 --- a/ios/Pods/Target Support Files/Pods-esteem/Pods-esteem-acknowledgements.plist +++ b/ios/Pods/Target Support Files/Pods-esteem/Pods-esteem-acknowledgements.plist @@ -68,36 +68,6 @@ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI Type PSGroupSpecifier - - FooterText - 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. - - License - MIT - Title - BugsnagReactNative - Type - PSGroupSpecifier - FooterText Microsoft CodePush Plugin for React Native @@ -374,6 +344,35 @@ SOFTWARE. Type PSGroupSpecifier + + FooterText + 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. + + License + MIT + Title + JWT + Type + PSGroupSpecifier + FooterText Copyright (c) 2015 Katsuma Tanaka @@ -455,7 +454,7 @@ THE SOFTWARE. FooterText 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. Type PSGroupSpecifier + + FooterText + 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. + + License + MIT + Title + SSZipArchive + Type + PSGroupSpecifier + FooterText Boost Software License - Version 1.0 - August 17th, 2003