MM-11318: Expands shortened links inline. (#1993)

* MM-11318: Expands shortened links inline.

* MM-11318: Accepts only image/* mime types. Switches to HEAD request.

* MM-11318: Fix for YouTube links.

* MM-11318: Renames function because it handles non-images.

* MM-11318: Checks for unmounted. Doesn't request known youtube redirects.
This commit is contained in:
Martin Kraft 2018-08-24 15:02:07 -04:00 committed by Harrison Healey
parent 9b238781c0
commit b4ca6421a0
2 changed files with 54 additions and 6 deletions

View file

@ -22,7 +22,7 @@ import CustomPropTypes from 'app/constants/custom_prop_types';
import {emptyFunction} from 'app/utils/general';
import ImageCacheManager from 'app/utils/image_cache_manager';
import {previewImageAtIndex, calculateDimensions} from 'app/utils/images';
import {getYouTubeVideoId, isImageLink, isYoutubeLink} from 'app/utils/url';
import {getYouTubeVideoId, isImageLink, isYoutubeLink, getShortenedLink} from 'app/utils/url';
const VIEWPORT_IMAGE_OFFSET = 66;
const VIEWPORT_IMAGE_REPLY_OFFSET = 13;
@ -67,6 +67,7 @@ export default class PostBodyAdditionalContent extends PureComponent {
linkLoaded: false,
width: 0,
height: 0,
shortenedLink: null,
};
this.mounted = false;
@ -87,7 +88,7 @@ export default class PostBodyAdditionalContent extends PureComponent {
}
}
load = (props) => {
load = async (props) => {
const {link} = props;
if (link) {
let imageUrl;
@ -97,6 +98,20 @@ export default class PostBodyAdditionalContent extends PureComponent {
const videoId = getYouTubeVideoId(link);
imageUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`;
ImageCacheManager.cache(null, `https://i.ytimg.com/vi/${videoId}/default.jpg`, () => true);
} else {
const shortenedLink = await getShortenedLink(link);
if (shortenedLink) {
if (isImageLink(shortenedLink)) {
imageUrl = shortenedLink;
} else if (isYoutubeLink(shortenedLink)) {
const videoId = getYouTubeVideoId(shortenedLink);
imageUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`;
ImageCacheManager.cache(null, `https://i.ytimg.com/vi/${videoId}/default.jpg`, () => true);
}
if (this.mounted) {
this.setState({shortenedLink});
}
}
}
if (imageUrl) {
@ -157,7 +172,11 @@ export default class PostBodyAdditionalContent extends PureComponent {
};
generateToggleableEmbed = (isImage, isYouTube) => {
const {link} = this.props;
let {link} = this.props;
const {shortenedLink} = this.state;
if (shortenedLink) {
link = shortenedLink;
}
const {width, height, uri} = this.state;
const imgHeight = height;
@ -326,7 +345,12 @@ export default class PostBodyAdditionalContent extends PureComponent {
};
handlePreviewImage = () => {
const {link, navigator} = this.props;
const {shortenedLink} = this.state;
let {link} = this.props;
const {navigator} = this.props;
if (shortenedLink) {
link = shortenedLink;
}
const {
originalHeight,
originalWidth,
@ -391,8 +415,12 @@ export default class PostBodyAdditionalContent extends PureComponent {
};
render() {
const {link, openGraphData, postProps} = this.props;
const {linkLoadError} = this.state;
let {link} = this.props;
const {openGraphData, postProps} = this.props;
const {linkLoadError, shortenedLink} = this.state;
if (shortenedLink) {
link = shortenedLink;
}
const {attachments} = postProps;
if (!link && !attachments) {

View file

@ -43,6 +43,26 @@ export function isYoutubeLink(link) {
return link.trim().match(ytRegex);
}
export async function getShortenedLink(link) {
return new Promise(((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState !== XMLHttpRequest.DONE) {
return;
}
resolve(xhr.responseURL);
};
xhr.onerror = () => {
reject('');
};
xhr.open('HEAD', link);
xhr.send();
}));
}
export function isImageLink(link) {
let linkWithoutQuery = link;
if (link.indexOf('?') !== -1) {