This repository has been archived by the owner on Mar 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#4257 Added functionality to create previews for post links using op…
…en graph data from those links. (#4890)
- Loading branch information
Showing
15 changed files
with
460 additions
and
532 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 0 additions & 108 deletions
108
components/post_view/components/post_attachment_oembed.jsx
This file was deleted.
Oops, something went wrong.
212 changes: 212 additions & 0 deletions
212
components/post_view/components/post_attachment_opengraph.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
// 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.imageDimentions = { // Image dimentions in pixels. | ||
height: 150, | ||
width: 150 | ||
}; | ||
this.maxDescriptionLength = 300; | ||
this.descriptionEllipsis = '...'; | ||
this.fetchData = this.fetchData.bind(this); | ||
this.onOpenGraphMetadataChange = this.onOpenGraphMetadataChange.bind(this); | ||
this.toggleImageVisibility = this.toggleImageVisibility.bind(this); | ||
this.onImageLoad = this.onImageLoad.bind(this); | ||
} | ||
|
||
componentWillMount() { | ||
this.setState({ | ||
data: {}, | ||
imageLoaded: false, | ||
imageVisible: this.props.previewCollapsed.startsWith('false') | ||
}); | ||
this.fetchData(this.props.link); | ||
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
this.setState({imageVisible: nextProps.previewCollapsed.startsWith('false')}); | ||
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.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: false}); | ||
if (Utils.isEmptyObject(data)) { | ||
requestOpenGraphMetadata(url); | ||
} | ||
} | ||
|
||
getBestImageUrl() { | ||
const nearestPointData = CommonUtils.getNearestPoint(this.imageDimentions, this.state.data.images, 'width', 'height'); | ||
|
||
const bestImage = nearestPointData.nearestPoint; | ||
const bestImageLte = nearestPointData.nearestPointLte; // Best image <= 150px height and width | ||
|
||
let finalBestImage; | ||
|
||
if ( | ||
!Utils.isEmptyObject(bestImageLte) && | ||
bestImageLte.height <= this.imageDimentions.height && | ||
bestImageLte.width <= this.imageDimentions.width | ||
) { | ||
finalBestImage = bestImageLte; | ||
} else { | ||
finalBestImage = bestImage; | ||
} | ||
|
||
return finalBestImage.secure_url || finalBestImage.url; | ||
} | ||
|
||
toggleImageVisibility() { | ||
this.setState({imageVisible: !this.state.imageVisible}); | ||
} | ||
|
||
onImageLoad() { | ||
this.setState({imageLoaded: true}); | ||
} | ||
|
||
loadImage(src) { | ||
const img = new Image(); | ||
img.onload = this.onImageLoad; | ||
img.src = src; | ||
} | ||
|
||
imageToggleAnchoreTag(imageUrl) { | ||
if (imageUrl) { | ||
return ( | ||
<a | ||
className={'post__embed-visibility'} | ||
data-expanded={this.state.imageVisible} | ||
aria-label='Toggle Embed Visibility' | ||
onClick={this.toggleImageVisibility} | ||
/> | ||
); | ||
} | ||
return null; | ||
} | ||
|
||
imageTag(imageUrl) { | ||
if (imageUrl && this.state.imageVisible) { | ||
return ( | ||
<img | ||
className={this.state.imageLoaded ? 'attachment__image' : 'attachment__image loading'} | ||
src={this.state.imageLoaded ? imageUrl : null} | ||
/> | ||
); | ||
} | ||
return null; | ||
} | ||
|
||
render() { | ||
if (Utils.isEmptyObject(this.state.data) || Utils.isEmptyObject(this.state.data.description)) { | ||
return null; | ||
} | ||
|
||
const data = this.state.data; | ||
const imageUrl = this.getBestImageUrl(); | ||
var description = data.description; | ||
|
||
if (description.length > this.maxDescriptionLength) { | ||
description = description.substring(0, this.maxDescriptionLength - this.descriptionEllipsis.length) + this.descriptionEllipsis; | ||
} | ||
|
||
if (imageUrl && this.state.imageVisible) { | ||
this.loadImage(imageUrl); | ||
} | ||
|
||
return ( | ||
<div | ||
className='attachment attachment--oembed' | ||
ref='attachment' | ||
> | ||
<div className='attachment__content'> | ||
<div | ||
className={'clearfix attachment__container'} | ||
> | ||
<span className='sitename'>{data.site_name}</span> | ||
<h1 | ||
className='attachment__title has-link' | ||
> | ||
<a | ||
className='attachment__title-link' | ||
href={data.url || this.props.link} | ||
target='_blank' | ||
rel='noopener noreferrer' | ||
title={data.title || data.url || this.props.link} | ||
> | ||
{data.title || data.url || this.props.link} | ||
</a> | ||
</h1> | ||
<div > | ||
<div | ||
className={'attachment__body attachment__body--no_thumb'} | ||
> | ||
<div> | ||
<div> | ||
{description} | ||
{this.imageToggleAnchoreTag(imageUrl)} | ||
</div> | ||
{this.imageTag(imageUrl)} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
PostAttachmentOpenGraph.defaultProps = { | ||
previewCollapsed: 'false' | ||
}; | ||
|
||
PostAttachmentOpenGraph.propTypes = { | ||
link: React.PropTypes.string.isRequired, | ||
childComponentDidUpdateFunction: React.PropTypes.func, | ||
previewCollapsed: React.PropTypes.string | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.