// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import React from 'react'; import OpenGraphStore from 'stores/opengraph_store.jsx'; import * as Utils from 'utils/utils.jsx'; import * as CommonUtils from 'utils/commons.jsx'; import {requestOpenGraphMetadata} from 'actions/global_actions.jsx'; export default class PostAttachmentOpenGraph extends React.Component { 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.fetchData = this.fetchData.bind(this); this.onOpenGraphMetadataChange = this.onOpenGraphMetadataChange.bind(this); this.toggleImageVisibility = this.toggleImageVisibility.bind(this); this.onImageLoad = this.onImageLoad.bind(this); this.onImageError = this.onImageError.bind(this); this.truncateText = this.truncateText.bind(this); } IMAGE_LOADED = { LOADING: 'loading', YES: 'yes', ERROR: 'error' } componentWillMount() { this.setState({ data: {}, imageLoaded: this.IMAGE_LOADED.LOADING, imageVisible: this.props.previewCollapsed.startsWith('false'), hasLargeImage: false }); this.fetchData(this.props.link); } componentWillReceiveProps(nextProps) { if (!Utils.areObjectsEqual(nextProps.link, this.props.link)) { this.fetchData(nextProps.link); } } shouldComponentUpdate(nextProps, nextState) { if (nextState.imageVisible !== this.state.imageVisible) { return true; } if (nextState.hasLargeImage !== this.state.hasLargeImage) { return true; } if (nextState.imageLoaded !== this.state.imageLoaded) { return true; } if (!Utils.areObjectsEqual(nextState.data, this.state.data)) { return true; } return false; } componentDidMount() { OpenGraphStore.addUrlDataChangeListener(this.onOpenGraphMetadataChange); } componentDidUpdate() { if (this.props.childComponentDidUpdateFunction) { this.props.childComponentDidUpdateFunction(); } } componentWillUnmount() { OpenGraphStore.removeUrlDataChangeListener(this.onOpenGraphMetadataChange); } onOpenGraphMetadataChange(url) { if (url === this.props.link) { this.fetchData(url); } } fetchData(url) { const data = OpenGraphStore.getOgInfo(url); this.setState({data, imageLoaded: this.IMAGE_LOADED.LOADING}); if (Utils.isEmptyObject(data)) { requestOpenGraphMetadata(url); } } getBestImageUrl() { if (Utils.isEmptyObject(this.state.data.images)) { return null; } const bestImage = CommonUtils.getNearestPoint(this.imageDimentions, this.state.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 (
{ this.smallImageContainer = div; }} > {imageElement}
); } imageTag(imageUrl, renderingForLargeImage = false) { var element = null; if ( imageUrl && renderingForLargeImage === this.state.hasLargeImage && (!renderingForLargeImage || (renderingForLargeImage && this.state.imageVisible)) ) { if (this.state.imageLoaded === this.IMAGE_LOADED.LOADING) { if (renderingForLargeImage) { element = ; } else { element = this.wrapInSmallImageContainer( ); } } else if (this.state.imageLoaded === this.IMAGE_LOADED.YES) { if (renderingForLargeImage) { element = ( ); } else { element = this.wrapInSmallImageContainer( { this.smallImageElement = img; }} /> ); } } else if (this.state.imageLoaded === this.IMAGE_LOADED.ERROR) { return null; } } return element; } truncateText(text, maxLength = this.textMaxLenght, ellipsis = this.textEllipsis) { if (text.length > maxLength) { return text.substring(0, maxLength - ellipsis.length) + ellipsis; } return text; } render() { if (Utils.isEmptyObject(this.state.data) || Utils.isEmptyObject(this.state.data.description)) { return null; } const data = this.state.data; const imageUrl = this.getBestImageUrl(); if (imageUrl) { this.loadImage(imageUrl); } return (
{this.truncateText(data.site_name)}

{this.truncateText(data.title || data.url || this.props.link)}

{this.truncateText(data.description)}   {this.imageToggleAnchoreTag(imageUrl)}
{this.imageTag(imageUrl, true)}
{this.imageTag(imageUrl, false)}
); } } PostAttachmentOpenGraph.defaultProps = { previewCollapsed: 'false' }; PostAttachmentOpenGraph.propTypes = { link: React.PropTypes.string.isRequired, childComponentDidUpdateFunction: React.PropTypes.func, previewCollapsed: React.PropTypes.string };