import Immutable from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import punycode from 'punycode'; import classnames from 'classnames'; import Icon from '../../../../components/icon'; const IDNA_PREFIX = 'xn--'; const decodeIDNA = domain => { return domain .split('.') .map(part => part.indexOf(IDNA_PREFIX) === 0 ? punycode.decode(part.slice(IDNA_PREFIX.length)) : part) .join('.'); }; const getHostname = url => { const parser = document.createElement('a'); parser.href = url; return parser.hostname; }; const trim = (text, len) => { const cut = text.indexOf(' ', len); if (cut === -1) { return text; } return text.substring(0, cut) + (text.length > len ? '…' : ''); }; const domParser = new DOMParser(); const addAutoPlay = html => { const document = domParser.parseFromString(html, 'text/html').documentElement; const iframe = document.querySelector('iframe'); if (iframe) { if (iframe.src.indexOf('?') !== -1) { iframe.src += '&'; } else { iframe.src += '?'; } iframe.src += 'autoplay=1&auto_play=1'; // DOM parser creates html/body elements around original HTML fragment, // so we need to get innerHTML out of the body and not the entire document return document.querySelector('body').innerHTML; } return html; }; export default class Card extends ImmutablePureComponent { static propTypes = { card: ImmutablePropTypes.map, onOpenMedia: PropTypes.func.isRequired, defaultWidth: PropTypes.number, cacheWidth: PropTypes.func, }; static defaultProps = { }; state = { width: this.props.defaultWidth || 280, embedded: false, }; componentWillReceiveProps (nextProps) { if (!Immutable.is(this.props.card, nextProps.card)) { this.setState({ embedded: false }); } } handlePhotoClick = () => { const { card, onOpenMedia } = this.props; onOpenMedia( Immutable.fromJS([ { type: 'image', url: card.get('embed_url'), description: card.get('title'), meta: { original: { width: card.get('width'), height: card.get('height'), }, }, }, ]), 0 ); }; handleEmbedClick = () => { const { card } = this.props; if (card.get('type') === 'photo') { this.handlePhotoClick(); } else { this.setState({ embedded: true }); } } setRef = c => { if (c) { if (this.props.cacheWidth) this.props.cacheWidth(c.offsetWidth); this.setState({ width: c.offsetWidth }); } } renderVideo () { const { card } = this.props const content = { __html: addAutoPlay(card.get('html')) } const { width } = this.state const ratio = card.get('width') / card.get('height') const height = width / ratio return (
) } render () { const { card } = this.props const { width, embedded } = this.state if (card === null) return null const maxDescription = 160 const cardImg = card.get('image') const provider = card.get('provider_name').length === 0 ? decodeIDNA(getHostname(card.get('url'))) : card.get('provider_name') const horizontal = (card.get('width') > card.get('height') && (card.get('width') + 100 >= width)) || card.get('type') !== 'link' || embedded const interactive = card.get('type') !== 'link' const title = interactive ? ( {card.get('title')} ) : ( {card.get('title')} ) const description = (
{title}

{trim(card.get('description') || '', maxDescription)}

{provider}
) let embed = '' let thumbnail = interactive ? : if (interactive) { if (embedded) { embed = this.renderVideo() } let iconVariant = 'play' if (card.get('type') === 'photo') { iconVariant = 'search-plus' } return (
{ !!embed && embed} { !embed && thumbnail} { !embed &&
}
{description}
) } else if (cardImg) { embed = (
{thumbnail}
) } else { embed = (
) } return (
{embed} {description}
) } }