mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
[PLT-1249] Add close button 'x' to the right of a link preview (#7017)
* add close button 'x' to the right of a link preview * Updating webhook UI * UI improvements for close button * Adding hover state * Making the close button visible on mobile * previews are permanently disabled/closed for that link * make post as required props * fix JS error of undefined * fix update issue both at center and RHS view
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getOpenGraphMetadata} from 'mattermost-redux/actions/posts';
|
||||
import {getOpenGraphMetadataForUrl} from 'mattermost-redux/selectors/entities/posts';
|
||||
@@ -11,7 +12,8 @@ import PostAttachmentOpenGraph from './post_attachment_opengraph.jsx';
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps,
|
||||
openGraphData: getOpenGraphMetadataForUrl(state, ownProps.link)
|
||||
openGraphData: getOpenGraphMetadataForUrl(state, ownProps.link),
|
||||
currentUser: getCurrentUser(state),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {postListScrollChange} from 'actions/global_actions.jsx';
|
||||
import {updatePost} from 'actions/post_actions.jsx';
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import * as CommonUtils from 'utils/commons.jsx';
|
||||
import {PostTypes} from 'utils/constants.jsx';
|
||||
|
||||
export default class PostAttachmentOpenGraph extends React.PureComponent {
|
||||
static propTypes = {
|
||||
@@ -17,6 +19,16 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
|
||||
*/
|
||||
link: PropTypes.string.isRequired,
|
||||
|
||||
/**
|
||||
* The current user viewing the post
|
||||
*/
|
||||
currentUser: PropTypes.object,
|
||||
|
||||
/**
|
||||
* The post where this link is included
|
||||
*/
|
||||
post: PropTypes.object,
|
||||
|
||||
/**
|
||||
* The open graph data to render
|
||||
*/
|
||||
@@ -62,18 +74,28 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
|
||||
this.toggleImageVisibility = this.toggleImageVisibility.bind(this);
|
||||
this.onImageLoad = this.onImageLoad.bind(this);
|
||||
this.onImageError = this.onImageError.bind(this);
|
||||
this.handleRemovePreview = this.handleRemovePreview.bind(this);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const removePreview = this.isRemovePreview(this.props.post, this.props.currentUser);
|
||||
|
||||
this.setState({
|
||||
imageLoaded: this.IMAGE_LOADED.LOADING,
|
||||
imageVisible: this.props.previewCollapsed.startsWith('false'),
|
||||
hasLargeImage: false
|
||||
hasLargeImage: false,
|
||||
removePreview
|
||||
});
|
||||
this.fetchData(this.props.link);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!Utils.areObjectsEqual(nextProps.post, this.props.post)) {
|
||||
const removePreview = this.isRemovePreview(nextProps.post, nextProps.currentUser);
|
||||
this.setState({
|
||||
removePreview
|
||||
});
|
||||
}
|
||||
if (nextProps.link !== this.props.link) {
|
||||
this.fetchData(nextProps.link);
|
||||
}
|
||||
@@ -94,12 +116,12 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
getBestImageUrl() {
|
||||
if (Utils.isEmptyObject(this.props.openGraphData.images)) {
|
||||
getBestImageUrl(data) {
|
||||
if (Utils.isEmptyObject(data.images)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const bestImage = CommonUtils.getNearestPoint(this.imageDimentions, this.props.openGraphData.images, 'width', 'height');
|
||||
const bestImage = CommonUtils.getNearestPoint(this.imageDimentions, data.images, 'width', 'height');
|
||||
return bestImage.secure_url || bestImage.url;
|
||||
}
|
||||
|
||||
@@ -208,14 +230,50 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
|
||||
return text;
|
||||
}
|
||||
|
||||
handleRemovePreview() {
|
||||
const props = Object.assign({}, this.props.post.props);
|
||||
props[PostTypes.REMOVE_LINK_PREVIEW] = 'true';
|
||||
|
||||
const patchedPost = ({
|
||||
id: this.props.post.id,
|
||||
props
|
||||
});
|
||||
|
||||
updatePost(patchedPost, () => {
|
||||
this.setState({removePreview: true});
|
||||
});
|
||||
}
|
||||
|
||||
isRemovePreview(post, currentUser) {
|
||||
if (post && post.props && currentUser.id === post.user_id) {
|
||||
return post.props[PostTypes.REMOVE_LINK_PREVIEW] && post.props[PostTypes.REMOVE_LINK_PREVIEW] === 'true';
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.openGraphData || Utils.isEmptyObject(this.props.openGraphData.description)) {
|
||||
const data = this.props.openGraphData;
|
||||
if (!data || Utils.isEmptyObject(data.description) || this.state.removePreview) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = this.props.openGraphData;
|
||||
const imageUrl = this.getBestImageUrl();
|
||||
let removePreviewButton;
|
||||
if (this.props.currentUser.id === this.props.post.user_id) {
|
||||
removePreviewButton = (
|
||||
<button
|
||||
id='removePreviewButton'
|
||||
type='button'
|
||||
className='btn-close'
|
||||
aria-label='Close'
|
||||
onClick={this.handleRemovePreview}
|
||||
>
|
||||
<span aria-hidden='true'>{'×'}</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
const imageUrl = this.getBestImageUrl(data);
|
||||
if (imageUrl) {
|
||||
this.loadImage(imageUrl);
|
||||
}
|
||||
@@ -233,6 +291,7 @@ export default class PostAttachmentOpenGraph extends React.PureComponent {
|
||||
className={'attachment__body__wrap attachment__body__wrap--opengraph'}
|
||||
>
|
||||
<span className='sitename'>{this.truncateText(data.site_name)}</span>
|
||||
{removePreviewButton}
|
||||
<h1
|
||||
className={'attachment__title attachment__title--opengraph' + (data.title ? '' : ' is-url')}
|
||||
>
|
||||
|
||||
@@ -162,6 +162,7 @@ export default class PostBodyAdditionalContent extends React.PureComponent {
|
||||
<PostAttachmentOpenGraph
|
||||
link={link}
|
||||
previewCollapsed={this.props.previewCollapsed}
|
||||
post={this.props.post}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,17 @@
|
||||
|
||||
.post {
|
||||
.attachment {
|
||||
margin-left: -20px;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
.attachment__body__wrap {
|
||||
.btn-close {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.attachment--opengraph {
|
||||
max-width: 800px;
|
||||
}
|
||||
@@ -46,7 +57,7 @@
|
||||
border-radius: 4px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
margin: 5px 0;
|
||||
margin: 5px 0 5px 20px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
@@ -99,6 +110,42 @@
|
||||
vertical-align: top;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
@include opacity(.4);
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: inherit;
|
||||
font-size: 21px;
|
||||
font-weight: 500;
|
||||
height: 20px;
|
||||
left: -7px;
|
||||
line-height: 20px;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
text-shadow: none;
|
||||
visibility: hidden;
|
||||
width: 20px;
|
||||
z-index: 5;
|
||||
|
||||
span {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
line-height: 10px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include opacity(.9);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.btn-close {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.attachment__body {
|
||||
|
||||
@@ -1349,6 +1349,16 @@
|
||||
|
||||
.post {
|
||||
.attachment {
|
||||
.attachment__body__wrap {
|
||||
.btn-close {
|
||||
height: 30px;
|
||||
left: -15px;
|
||||
top: 7px;
|
||||
visibility: visible;
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.attachment__image {
|
||||
&.attachment__image--openraph {
|
||||
max-width: 200px;
|
||||
|
||||
@@ -270,7 +270,8 @@ export const PostTypes = {
|
||||
DISPLAYNAME_CHANGE: 'system_displayname_change',
|
||||
PURPOSE_CHANGE: 'system_purpose_change',
|
||||
CHANNEL_DELETED: 'system_channel_deleted',
|
||||
EPHEMERAL: 'system_ephemeral'
|
||||
EPHEMERAL: 'system_ephemeral',
|
||||
REMOVE_LINK_PREVIEW: 'remove_link_preview'
|
||||
};
|
||||
|
||||
export const StatTypes = keyMirror({
|
||||
|
||||
@@ -653,6 +653,8 @@ export function applyTheme(theme) {
|
||||
changeCss('.app__body .post.post--comment.other--root.current--user .post-comment, .app__body .more-modal__list .more-modal__row, .app__body .member-div:first-child, .app__body .member-div, .app__body .access-history__table .access__report, .app__body .activity-log__table', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.1));
|
||||
changeCss('@media(max-width: 1800px){.app__body .inner-wrap.move--left .post.post--comment.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07));
|
||||
changeCss('.app__body .post.post--hovered', 'background:' + changeOpacity(theme.centerChannelColor, 0.08));
|
||||
changeCss('.app__body .attachment__body__wrap.btn-close', 'background:' + changeOpacity(theme.centerChannelColor, 0.08));
|
||||
changeCss('.app__body .attachment__body__wrap.btn-close', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
||||
changeCss('@media(min-width: 768px){.app__body .post:hover, .app__body .more-modal__list .more-modal__row:hover, .app__body .modal .settings-modal .settings-table .settings-content .section-min:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.08));
|
||||
changeCss('.app__body .more-modal__row.more-modal__row--selected, .app__body .date-separator.hovered--before:after, .app__body .date-separator.hovered--after:before, .app__body .new-separator.hovered--after:before, .app__body .new-separator.hovered--before:after', 'background:' + changeOpacity(theme.centerChannelColor, 0.07));
|
||||
changeCss('@media(min-width: 768px){.app__body .suggestion-list__content .command:hover, .app__body .mentions__name:hover, .app__body .dropdown-menu>li>a:focus, .app__body .dropdown-menu>li>a:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.15));
|
||||
|
||||
Reference in New Issue
Block a user