huge-table
Version:
Table component to handle huge sets of data, based on Facebook's FixedDataTable
129 lines (113 loc) • 3.52 kB
JavaScript
import React from 'react';
import Portal from 'react-portal';
import * as Constants from './constants';
import brokenImage from '../assets/broken-image-placeholder.png';
import PropTypes from 'prop-types';
export class ImageCell extends React.Component {
static propTypes = {
cellData: PropTypes.object.isRequired,
width: PropTypes.number.isRequired,
mixedContentImage: PropTypes.func,
}
constructor(props) {
super(props);
this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
this.state = {
showPopover: false,
imageErrored: false,
};
}
handleMouseEnter(e) {
const clientRect = e.target.getBoundingClientRect();
this.setState({
showPopover: true,
popoverTop: (clientRect.top + clientRect.bottom) / 2,
popoverLeft: clientRect.left + this.props.width - 20,
});
}
handleMouseLeave() {
this.setState({
showPopover: false,
});
}
handleImageLoaded() {
// Treat 5x5 pixels as less as visually meaningless
// load about:blank to show the alt text instead
if (this.refs.img.width * this.refs.img.height <= 25) {
this.refs.img.src = 'about:blank';
}
}
handleImageError() {
this.setState({imageErrored: true});
}
render() {
const cellData = this.props.cellData;
let imageUrl, href, alt;
if (cellData.main && typeof cellData.main === 'object') {
imageUrl = cellData.main.src;
href = cellData.main.href || imageUrl;
alt = cellData.alt || cellData.main.alt;
} else {
imageUrl = cellData.main;
href = cellData.main;
alt = cellData.alt || cellData.main;
}
if ( ! imageUrl ) {
return <span/>;
}
if (this.props.mixedContentImage) {
imageUrl = this.props.mixedContentImage(imageUrl, imageUrl);
}
return (
<a
href={href}
title={alt}
target="_blank"
style={{
display: 'inline-block',
}}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
>
<img
ref="img"
className="example-image"
src={this.state.imageErrored ? brokenImage : imageUrl}
style={{
maxHeight: Constants.ROW_HEIGHT - 20,
maxWidth: this.props.width - 20,
minHeight: 5,
minWidth: 5,
marginTop: '-4px',
}}
title={alt}
alt={alt ? alt : 'Image'}
onLoad={this.handleImageLoaded.bind(this)}
onError={this.handleImageError.bind(this)}
/>
<Portal isOpened={!!(imageUrl && this.state.showPopover)}>
<div className="popover fade right in" style={{
display: 'block',
position: 'absolute',
top: this.state.popoverTop,
left: this.state.popoverLeft,
transform: 'translateY(-50%)',
backgroundColor: '#fff',
}}>
<div className="arrow" style={{top: '50%'}}></div>
<div className="popover-content">
<img
style={{width: '100%'}}
src={this.state.imageErrored ? brokenImage : imageUrl}
title={this.state.imageErrored ? 'Image not found' : alt}
alt={this.state.imageErrored ? 'Image not found' : alt}
/>
<span>{alt}</span>
</div>
</div>
</Portal>
</a>
);
}
}