]> cat aescling's git repositories - mastodon.git/blob - app/javascript/mastodon/features/ui/components/bundle.js
Fix audio attachments opening in video modal from media tab in web UI (#12056)
[mastodon.git] / app / javascript / mastodon / features / ui / components / bundle.js
1 import React from 'react';
2 import PropTypes from 'prop-types';
3
4 const emptyComponent = () => null;
5 const noop = () => { };
6
7 class Bundle extends React.PureComponent {
8
9 static propTypes = {
10 fetchComponent: PropTypes.func.isRequired,
11 loading: PropTypes.func,
12 error: PropTypes.func,
13 children: PropTypes.func.isRequired,
14 renderDelay: PropTypes.number,
15 onFetch: PropTypes.func,
16 onFetchSuccess: PropTypes.func,
17 onFetchFail: PropTypes.func,
18 }
19
20 static defaultProps = {
21 loading: emptyComponent,
22 error: emptyComponent,
23 renderDelay: 0,
24 onFetch: noop,
25 onFetchSuccess: noop,
26 onFetchFail: noop,
27 }
28
29 static cache = new Map
30
31 state = {
32 mod: undefined,
33 forceRender: false,
34 }
35
36 componentWillMount() {
37 this.load(this.props);
38 }
39
40 componentWillReceiveProps(nextProps) {
41 if (nextProps.fetchComponent !== this.props.fetchComponent) {
42 this.load(nextProps);
43 }
44 }
45
46 componentWillUnmount () {
47 if (this.timeout) {
48 clearTimeout(this.timeout);
49 }
50 }
51
52 load = (props) => {
53 const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props;
54 const cachedMod = Bundle.cache.get(fetchComponent);
55
56 if (fetchComponent === undefined) {
57 this.setState({ mod: null });
58 return Promise.resolve();
59 }
60
61 onFetch();
62
63 if (cachedMod) {
64 this.setState({ mod: cachedMod.default });
65 onFetchSuccess();
66 return Promise.resolve();
67 }
68
69 this.setState({ mod: undefined });
70
71 if (renderDelay !== 0) {
72 this.timestamp = new Date();
73 this.timeout = setTimeout(() => this.setState({ forceRender: true }), renderDelay);
74 }
75
76 return fetchComponent()
77 .then((mod) => {
78 Bundle.cache.set(fetchComponent, mod);
79 this.setState({ mod: mod.default });
80 onFetchSuccess();
81 })
82 .catch((error) => {
83 this.setState({ mod: null });
84 onFetchFail(error);
85 });
86 }
87
88 render() {
89 const { loading: Loading, error: Error, children, renderDelay } = this.props;
90 const { mod, forceRender } = this.state;
91 const elapsed = this.timestamp ? (new Date() - this.timestamp) : renderDelay;
92
93 if (mod === undefined) {
94 return (elapsed >= renderDelay || forceRender) ? <Loading /> : null;
95 }
96
97 if (mod === null) {
98 return <Error onRetry={this.load} />;
99 }
100
101 return children(mod);
102 }
103
104 }
105
106 export default Bundle;
This page took 0.229644 seconds and 4 git commands to generate.