1 |
|
2 |
|
3 | const React = require('react');
|
4 | const PropTypes = require('prop-types');
|
5 | const Lightbox = require('./Lightbox');
|
6 |
|
7 | class Image extends React.Component {
|
8 | constructor(props) {
|
9 | super(props);
|
10 |
|
11 | this.state = {
|
12 | lightbox: false,
|
13 | };
|
14 | this.lightbox = React.createRef();
|
15 |
|
16 | this.toggle = this.toggle.bind(this);
|
17 | this.handleKey = this.handleKey.bind(this);
|
18 |
|
19 | this.isEmoji = props.className === 'emoji';
|
20 | }
|
21 |
|
22 | componentDidMount() {
|
23 | this.lightboxSetup();
|
24 | }
|
25 |
|
26 | toggle(toState) {
|
27 | if (this.props.className === 'emoji') return;
|
28 |
|
29 | if (typeof toState === 'undefined') toState = !this.state.lightbox;
|
30 |
|
31 | if (toState) this.lightboxSetup();
|
32 |
|
33 | this.setState({ lightbox: toState });
|
34 | }
|
35 |
|
36 | lightboxSetup() {
|
37 | const $el = this.lightbox.current;
|
38 | setTimeout(() => {
|
39 | $el.scrollTop = ($el.scrollHeight - $el.offsetHeight) / 2;
|
40 | }, 0);
|
41 | }
|
42 |
|
43 | handleKey(e) {
|
44 | let { key, metaKey: cmd } = e;
|
45 |
|
46 | cmd = cmd ? 'cmd+' : '';
|
47 | key = `${cmd}${key.toLowerCase()}`;
|
48 |
|
49 | switch (key) {
|
50 | case 'cmd+.':
|
51 | case 'escape':
|
52 |
|
53 | this.toggle(false);
|
54 | break;
|
55 | case ' ':
|
56 | case 'enter':
|
57 |
|
58 | if (!this.state.open) this.toggle(true);
|
59 | e.preventDefault();
|
60 | default:
|
61 | }
|
62 | }
|
63 |
|
64 | render() {
|
65 | const { alt } = this.props;
|
66 | if (this.isEmoji) {
|
67 | return <img {...this.props} alt={alt} loading="lazy" />;
|
68 | }
|
69 | return (
|
70 | <span className="img" onClick={() => this.toggle()} onKeyDown={this.handleKey} role={'button'} tabIndex={0}>
|
71 | <img {...this.props} alt={alt} />
|
72 | <Lightbox
|
73 | ref={this.lightbox}
|
74 | {...this.props}
|
75 | onScroll={() => this.toggle(false)}
|
76 | opened={this.state.lightbox}
|
77 | />
|
78 | </span>
|
79 | );
|
80 | }
|
81 | }
|
82 |
|
83 | Image.propTypes = {
|
84 | align: PropTypes.string,
|
85 | alt: PropTypes.string,
|
86 | caption: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
87 | className: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
88 | height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
89 | src: PropTypes.string.isRequired,
|
90 | title: PropTypes.string,
|
91 | width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
92 | };
|
93 |
|
94 | Image.defaultProps = {
|
95 | align: '',
|
96 | alt: '',
|
97 | caption: '',
|
98 | height: 'auto',
|
99 | src: '',
|
100 | title: '',
|
101 | width: 'auto',
|
102 | };
|
103 |
|
104 | module.exports = sanitizeSchema => {
|
105 | sanitizeSchema.attributes.img = ['className', 'title', 'alt', 'width', 'height', 'align', 'src', 'longDesc'];
|
106 | return Image;
|
107 | };
|