diff --git a/src/app/components/cards/MarkdownViewer.jsx b/src/app/components/cards/MarkdownViewer.jsx index 51e3dbb0a57728cfe901a4b06b75648d8c86e0b2..a0892698e3b09542bfc49e4f946e120ad2e84cbd 100644 --- a/src/app/components/cards/MarkdownViewer.jsx +++ b/src/app/components/cards/MarkdownViewer.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import Remarkable from 'remarkable'; -import sanitizeConfig from 'app/utils/SanitizeConfig'; +import sanitizeConfig, { noImageText } from 'app/utils/SanitizeConfig'; import sanitize from 'sanitize-html'; import HtmlReady from 'shared/HtmlReady'; import tt from 'counterpart'; @@ -26,6 +26,27 @@ const remarkableToSpec = new Remarkable({ }); class MarkdownViewer extends Component { + static propTypes = { + // HTML properties + text: PropTypes.string, + className: PropTypes.string, + large: PropTypes.bool, + highQualityPost: PropTypes.bool, + noImage: PropTypes.bool, + allowDangerousHTML: PropTypes.bool, + hideImages: PropTypes.bool, // whether to replace images with just a span containing the src url + breaks: PropTypes.bool, // true to use bastardized markdown that cares about newlines + // used for the ImageUserBlockList + }; + + static defaultProps = { + allowDangerousHTML: false, + breaks: true, + className: '', + hideImages: false, + large: false, + }; + constructor() { super(); this.state = { allowNoImage: true }; @@ -42,9 +63,7 @@ class MarkdownViewer extends Component { }; render() { - const { - noImage, hideImages, noLink, noImageText, noLinkText - } = this.props; + const { noImage, hideImages } = this.props; const { allowNoImage } = this.state; let { text } = this.props; if (!text) text = ''; // text can be empty, still view the link meta data @@ -91,9 +110,6 @@ class MarkdownViewer extends Component { large, highQualityPost, noImage: noImage && allowNoImage, - noImageText, - noLink, - noLinkText, }) ); } @@ -168,36 +184,6 @@ class MarkdownViewer extends Component { } } -MarkdownViewer.propTypes = { - // HTML properties - text: PropTypes.string, - className: PropTypes.string, - large: PropTypes.bool, - highQualityPost: PropTypes.bool, - noImage: PropTypes.bool, - noImageText: PropTypes.string, - noLink: PropTypes.bool, - noLinkText: PropTypes.string, - allowDangerousHTML: PropTypes.bool, - hideImages: PropTypes.bool, // whether to replace images with just a span containing the src url - breaks: PropTypes.bool, // true to use bastardized markdown that cares about newlines - // used for the ImageUserBlockList -}; - -MarkdownViewer.defaultProps = { - allowDangerousHTML: false, - breaks: true, - className: '', - hideImages: false, - large: false, - text: undefined, - highQualityPost: false, - noImage: false, - noImageText: undefined, - noLink: false, - noLinkText: undefined, -}; - export default connect((state, ownProps) => { return { ...ownProps }; })(MarkdownViewer); diff --git a/src/app/components/cards/PostFull.jsx b/src/app/components/cards/PostFull.jsx index d3afa4643990579307d6f6a1ca57e9a376564c28..30ba998d718a23f95823f9b558ce37cdfc4a81e2 100644 --- a/src/app/components/cards/PostFull.jsx +++ b/src/app/components/cards/PostFull.jsx @@ -29,7 +29,6 @@ import LoadingIndicator from 'app/components/elements/LoadingIndicator'; import { allowDelete } from 'app/utils/StateFunctions'; import { Role } from 'app/utils/Community'; import UserNames from 'app/components/elements/UserNames'; -import {List} from "immutable"; import ContentEditedWrapper from '../elements/ContentEditedWrapper'; import { isUrlWhitelisted } from "../../utils/Phishing"; @@ -105,7 +104,6 @@ class PostFull extends React.Component { showPromotePost: PropTypes.func.isRequired, showExplorePost: PropTypes.func.isRequired, togglePinnedPost: PropTypes.func.isRequired, - muteList: PropTypes.object, }; constructor(props) { @@ -117,8 +115,6 @@ class PostFull extends React.Component { this.linkedInShare = this.linkedInShare.bind(this); this.showExplorePost = this.showExplorePost.bind(this); - this.state = { showMutedList: false }; - this.onShowReply = () => { const { state: { showReply, formId }, @@ -245,8 +241,8 @@ class PostFull extends React.Component { onTogglePin = (isPinned) => { const { - community, username, post, postref - } = this.props; + community, username, post, postref +} = this.props; if (!community || !username) console.error('pin fail', this.props); const key = ['content', postref, 'stats', 'is_pinned']; @@ -260,12 +256,11 @@ class PostFull extends React.Component { render() { const { props: { - username, post, community, viewer_role, muteList - }, + username, post, community, viewer_role +}, state: { - PostFullReplyEditor, PostFullEditEditor, formId, showReply, showEdit, - showMutedList, - }, + PostFullReplyEditor, PostFullEditEditor, formId, showReply, showEdit +}, onShowReply, onShowEdit, onDeletePost, @@ -329,7 +324,7 @@ class PostFull extends React.Component { const bShowLoading = false; // hide images if user is on blacklist - const authorIsBlocked = ImageUserBlockList.includes(author); + const hideImages = ImageUserBlockList.includes(author); const replyParams = { author, @@ -419,20 +414,6 @@ class PostFull extends React.Component { </div> ); - const allowReply = Role.canComment(community, viewer_role); - const canReblog = !isReply; - const canPromote = false && !post.get('is_paidout') && !isReply; - const canPin = post.get('depth') == 0 && Role.atLeast(viewer_role, 'mod'); - const canMute = username && Role.atLeast(viewer_role, 'mod'); - const canFlag = username && community && Role.atLeast(viewer_role, 'guest'); - const canReply = allowReply && post.get('depth') < 255; - const canEdit = username === author && !showEdit; - const canDelete = username === author && allowDelete(post); - const isGray = post.getIn(['stats', 'gray']); - const isMuted = muteList.has(post.get('author')) && !showMutedList; - - const isPinned = post.getIn(['stats', 'is_pinned'], false); - if (isReply) { const rooturl = post.get('url'); const prnturl = `/${category}/@${parent_author}/${parent_permlink}`; @@ -457,53 +438,31 @@ class PostFull extends React.Component { ); } - if (isMuted) { - post_header = ( - <div className="callout"> - <div> - <h4>This user is in your mute list.</h4> - <p>For safety reasons, links on this post will be disabled.</p> - </div> - <ul> - <li> - <a - role="link" - tabIndex={0} - onClick={() => { - this.setState((prevState) => { - return { showMutedList: !prevState.showMutedList }; - }); - }} - > - Enable links - </a> - </li> - </ul> - </div> - ); - } + const allowReply = Role.canComment(community, viewer_role); + const canReblog = !isReply; + const canPromote = false && !post.get('is_paidout') && !isReply; + const canPin = post.get('depth') == 0 && Role.atLeast(viewer_role, 'mod'); + const canMute = username && Role.atLeast(viewer_role, 'mod'); + const canFlag = username && community && Role.atLeast(viewer_role, 'guest'); + const canReply = allowReply && post.get('depth') < 255; + const canEdit = username === author && !showEdit; + const canDelete = username === author && allowDelete(post); + + const isPinned = post.getIn(['stats', 'is_pinned'], false); let contentBody; if (bShowLoading) { contentBody = <LoadingIndicator type="circle-strong" />; } else { - const noLink = isGray || authorIsBlocked; - const noLinkText = tt('g.no_link_text'); - const noImage = isGray; - const noImageText = tt('g.no_image_text'); - contentBody = ( <MarkdownViewer formId={formId + '-viewer'} text={content_body} large highQualityPost={high_quality_post} - noImage={noImage} - noImageText={noImageText} - hideImages={authorIsBlocked} - noLink={noLink} - noLinkText={noLinkText} + noImage={post.getIn(['stats', 'gray'])} + hideImages={hideImages} /> ); } @@ -511,7 +470,7 @@ class PostFull extends React.Component { return ( <div> <article - className={classnames('PostFull', 'hentry', { isMuted })} + className={classnames('PostFull', 'hentry')} itemScope itemType="http://schema.org/Blog" onClick={this.postClickHandler} @@ -608,19 +567,17 @@ class PostFull extends React.Component { export default connect( (state, ownProps) => { - const username = state.user.getIn(['current', 'username']); const postref = ownProps.post; const post = ownProps.cont.get(postref); + const category = post.get('category'); const community = state.global.getIn(['community', category, 'name']); - const muteList = state.global.getIn(['follow', 'getFollowingAsync', username, 'ignore_result'], List()); return { post, postref, community, - username, - muteList, + username: state.user.getIn(['current', 'username']), viewer_role: state.global.getIn(['community', community, 'context', 'role'], 'guest'), }; }, diff --git a/src/app/components/cards/PostFull.scss b/src/app/components/cards/PostFull.scss index 69c4ed6de88024b9e27c7340e979ea94e8d8d579..26be1effd22d1bd863c600449ae37bf75c2c6a2a 100644 --- a/src/app/components/cards/PostFull.scss +++ b/src/app/components/cards/PostFull.scss @@ -149,9 +149,6 @@ @extend .link; @extend .link--accent; } - .isMuted & a { - pointer-events: none; - } } .PostFull__footer { diff --git a/src/app/locales/en.json b/src/app/locales/en.json index c2f5bbf521f0503bc128312c3530533b5b2ce3d6..a6e664e5eddb600017ff3b29432b9ab44121f04b 100644 --- a/src/app/locales/en.json +++ b/src/app/locales/en.json @@ -118,9 +118,6 @@ "reputation": "Reputation", "reveal_comment": "Reveal Comment", "will_be_hidden_due_to_low_rating": "Will be hidden due to low rating", - "images_links_disabled_due_to_low_rating": "Due to low rating, images and links from this post will be disabled.", - "no_image_text": "(Image not shown due to low ratings)", - "no_link_text": "(Link not shown due to low ratings or blacklist)", "request": "request", "required": "Required", "rewards": "Rewards", diff --git a/src/app/utils/SanitizeConfig.js b/src/app/utils/SanitizeConfig.js index 28de6f2b41871f08737f0bbe14fad26ac46e46e2..198f1e0b03553fddc89b2546cbd5291b2039e023 100644 --- a/src/app/utils/SanitizeConfig.js +++ b/src/app/utils/SanitizeConfig.js @@ -4,6 +4,7 @@ import { getPhishingWarningMessage, getExternalLinkWarningMessage } from 'shared import { validateIframeUrl as validateEmbbeddedPlayerIframeUrl } from 'app/components/elements/EmbeddedPlayers'; +export const noImageText = '(Image not shown due to low ratings)'; export const allowedTags = ` div, iframe, del, a, p, b, i, q, br, ul, li, ol, img, h1, h2, h3, h4, h5, h6, hr, @@ -14,17 +15,9 @@ export const allowedTags = ` .split(/,\s*/); // Medium insert plugin uses: div, figure, figcaption, iframe -export default ( - { - large = true, - highQualityPost = true, - noImage = false, - noImageText = '(Link not shown due to low ratings)', - sanitizeErrors = [], - noLink = false, - noLinkText = '(Image not shown due to low ratings)', - } -) => ({ +export default ({ + large = true, highQualityPost = true, noImage = false, sanitizeErrors = [] +}) => ({ allowedTags, // figure, figcaption, @@ -100,7 +93,7 @@ export default ( return { tagName: 'div', text: `(Unsupported ${srcAtty})` }; }, img: (tagName, attribs) => { - if (noImage) return { tagName: 'i', text: noImageText }; + if (noImage) return { tagName: 'div', text: noImageText }; //See https://github.com/punkave/sanitize-html/issues/117 let { src } = attribs; const { alt } = attribs; @@ -167,12 +160,6 @@ export default ( }; }, a: (tagName, attribs) => { - if (noLink) { - return { - tagName: 'i', - text: noLinkText, - }; - } let { href } = attribs; if (!href) href = '#'; href = href.trim();