UNPKG

3.6 kBJavaScriptView Raw
1import React from 'react';
2import Portal from 'react-portal';
3import * as Constants from './constants';
4import brokenImage from '../assets/broken-image-placeholder.png';
5import PropTypes from 'prop-types';
6
7export class ImageCell extends React.Component {
8 static propTypes = {
9 cellData: PropTypes.object.isRequired,
10 width: PropTypes.number.isRequired,
11 mixedContentImage: PropTypes.func,
12 disabled: PropTypes.bool,
13 }
14
15 constructor(props) {
16 super(props);
17
18 this.handleMouseEnter = this.handleMouseEnter.bind(this);
19 this.handleMouseLeave = this.handleMouseLeave.bind(this);
20
21 this.state = {
22 showPopover: false,
23 imageErrored: false,
24 };
25 }
26
27 handleMouseEnter(e) {
28 const clientRect = e.target.getBoundingClientRect();
29
30 this.setState({
31 showPopover: true,
32 popoverTop: (clientRect.top + clientRect.bottom) / 2,
33 popoverLeft: clientRect.left + this.props.width - 20,
34 });
35 }
36
37 handleMouseLeave() {
38 this.setState({
39 showPopover: false,
40 });
41 }
42
43 handleImageLoaded() {
44 // Treat 5x5 pixels as less as visually meaningless
45 // load about:blank to show the alt text instead
46 if (this.refs.img.width * this.refs.img.height <= 25) {
47 this.refs.img.src = 'about:blank';
48 }
49 }
50
51 handleImageError() {
52 this.setState({imageErrored: true});
53 }
54
55 render() {
56 const cellData = this.props.cellData;
57 let imageUrl, href, alt;
58
59 if (cellData.main && typeof cellData.main === 'object') {
60 imageUrl = cellData.main.src;
61 href = cellData.main.href || imageUrl;
62 alt = cellData.alt || cellData.main.alt;
63
64 } else {
65 imageUrl = cellData.main;
66 href = cellData.main;
67 alt = cellData.alt || cellData.main;
68 }
69
70 if ( ! imageUrl ) {
71 return <span/>;
72 }
73
74 if (this.props.mixedContentImage) {
75 imageUrl = this.props.mixedContentImage(imageUrl, imageUrl);
76 }
77 return (
78 <a
79 href={this.props.disabled ? 'javascript:void(0);' : href}
80 title={alt}
81 target="_blank"
82 style={{
83 display: 'inline-block',
84 }}
85 onMouseEnter={this.handleMouseEnter}
86 onMouseLeave={this.handleMouseLeave}
87 >
88 <img
89 ref="img"
90 className="example-image"
91 src={this.state.imageErrored ? brokenImage : imageUrl}
92 style={{
93 maxHeight: Constants.ROW_HEIGHT - 20,
94 maxWidth: this.props.width - 20,
95 minHeight: 5,
96 minWidth: 5,
97 marginTop: '-4px',
98 }}
99 title={alt}
100 alt={alt ? alt : 'Image'}
101 onLoad={this.handleImageLoaded.bind(this)}
102 onError={this.handleImageError.bind(this)}
103 />
104 <Portal isOpened={!!(imageUrl && this.state.showPopover)}>
105 <div className="popover fade right in" style={{
106 display: 'block',
107 position: 'absolute',
108 top: this.state.popoverTop,
109 left: this.state.popoverLeft,
110 transform: 'translateY(-50%)',
111 backgroundColor: '#fff',
112 }}>
113 <div className="arrow" style={{top: '50%'}}></div>
114 <div className="popover-content">
115 <img
116 style={{width: '100%'}}
117 src={this.state.imageErrored ? brokenImage : imageUrl}
118 title={this.state.imageErrored ? 'Image not found' : alt}
119 alt={this.state.imageErrored ? 'Image not found' : alt}
120 />
121 <span>{alt}</span>
122 </div>
123 </div>
124 </Portal>
125 </a>
126 );
127 }
128}