[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:
Saturnino Abril
2017-08-03 14:29:31 +08:00
committed by GitHub
parent 345bb2236f
commit f3934bc7e1
7 changed files with 132 additions and 10 deletions

View File

@@ -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),
};
}

View File

@@ -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')}
>

View File

@@ -162,6 +162,7 @@ export default class PostBodyAdditionalContent extends React.PureComponent {
<PostAttachmentOpenGraph
link={link}
previewCollapsed={this.props.previewCollapsed}
post={this.props.post}
/>
);
}

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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({

View File

@@ -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));