// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. 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 = { /** * The link to display the open graph data for */ 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 */ openGraphData: PropTypes.object, /** * Set to collapse the preview */ previewCollapsed: PropTypes.string, actions: PropTypes.shape({ /** * The function to get open graph data for a link */ getOpenGraphMetadata: PropTypes.func.isRequired }).isRequired } constructor(props) { super(props); this.largeImageMinWidth = 150; this.imageDimentions = { // Image dimentions in pixels. height: 80, width: 80 }; this.textMaxLenght = 300; this.textEllipsis = '...'; this.largeImageMinRatio = 16 / 9; this.smallImageContainerLeftPadding = 15; this.imageRatio = null; this.smallImageContainer = null; this.smallImageElement = null; this.IMAGE_LOADED = { LOADING: 'loading', YES: 'yes', ERROR: 'error' }; this.fetchData = this.fetchData.bind(this); 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, 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); } if (nextProps.previewCollapsed !== this.props.previewCollapsed) { this.setState({ imageVisible: nextProps.previewCollapsed.startsWith('false') }); } } componentDidUpdate() { postListScrollChange(); } fetchData(url) { if (!this.props.openGraphData) { this.props.actions.getOpenGraphMetadata(url); } } getBestImageUrl(data) { if (Utils.isEmptyObject(data.images)) { return null; } const bestImage = CommonUtils.getNearestPoint(this.imageDimentions, data.images, 'width', 'height'); return bestImage.secure_url || bestImage.url; } toggleImageVisibility() { this.setState({imageVisible: !this.state.imageVisible}); } onImageLoad(image) { this.imageRatio = image.target.naturalWidth / image.target.naturalHeight; if ( image.target.naturalWidth >= this.largeImageMinWidth && this.imageRatio >= this.largeImageMinRatio && !this.state.hasLargeImage ) { this.setState({ hasLargeImage: true }); } this.setState({ imageLoaded: this.IMAGE_LOADED.YES }); } onImageError() { this.setState({imageLoaded: this.IMAGE_LOADED.ERROR}); } loadImage(src) { const img = new Image(); img.onload = this.onImageLoad; img.onerror = this.onImageError; img.src = src; } imageToggleAnchoreTag(imageUrl) { if (imageUrl && this.state.hasLargeImage) { return ( ); } return null; } wrapInSmallImageContainer(imageElement) { return (