media_container.jsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import PropTypes from 'prop-types';
  2. import { PureComponent } from 'react';
  3. import { createPortal } from 'react-dom';
  4. import { fromJS } from 'immutable';
  5. import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
  6. import MediaGallery from 'mastodon/components/media_gallery';
  7. import ModalRoot from 'mastodon/components/modal_root';
  8. import Poll from 'mastodon/components/poll';
  9. import Audio from 'mastodon/features/audio';
  10. import Card from 'mastodon/features/status/components/card';
  11. import MediaModal from 'mastodon/features/ui/components/media_modal';
  12. import Video from 'mastodon/features/video';
  13. import { IntlProvider } from 'mastodon/locales';
  14. import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
  15. const MEDIA_COMPONENTS = { MediaGallery, Video, Card, Poll, Hashtag, Audio };
  16. export default class MediaContainer extends PureComponent {
  17. static propTypes = {
  18. components: PropTypes.object.isRequired,
  19. };
  20. state = {
  21. media: null,
  22. index: null,
  23. lang: null,
  24. time: null,
  25. backgroundColor: null,
  26. options: null,
  27. };
  28. handleOpenMedia = (media, index, lang) => {
  29. document.body.classList.add('with-modals--active');
  30. document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
  31. this.setState({ media, index, lang });
  32. };
  33. handleOpenVideo = (lang, options) => {
  34. const { components } = this.props;
  35. const { media } = JSON.parse(components[options.componentIndex].getAttribute('data-props'));
  36. const mediaList = fromJS(media);
  37. document.body.classList.add('with-modals--active');
  38. document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
  39. this.setState({ media: mediaList, lang, options });
  40. };
  41. handleCloseMedia = () => {
  42. document.body.classList.remove('with-modals--active');
  43. document.documentElement.style.marginRight = '0';
  44. this.setState({
  45. media: null,
  46. index: null,
  47. time: null,
  48. backgroundColor: null,
  49. options: null,
  50. });
  51. };
  52. setBackgroundColor = color => {
  53. this.setState({ backgroundColor: color });
  54. };
  55. render () {
  56. const { components } = this.props;
  57. let handleOpenVideo;
  58. // Don't offer to expand the video in a lightbox if we're in a frame
  59. if (window.self === window.top) {
  60. handleOpenVideo = this.handleOpenVideo;
  61. }
  62. return (
  63. <IntlProvider>
  64. <>
  65. {[].map.call(components, (component, i) => {
  66. const componentName = component.getAttribute('data-component');
  67. const Component = MEDIA_COMPONENTS[componentName];
  68. const { media, card, poll, hashtag, ...props } = JSON.parse(component.getAttribute('data-props'));
  69. Object.assign(props, {
  70. ...(media ? { media: fromJS(media) } : {}),
  71. ...(card ? { card: fromJS(card) } : {}),
  72. ...(poll ? { poll: fromJS(poll) } : {}),
  73. ...(hashtag ? { hashtag: fromJS(hashtag) } : {}),
  74. ...(componentName === 'Video' ? {
  75. componentIndex: i,
  76. onOpenVideo: handleOpenVideo,
  77. } : {
  78. onOpenMedia: this.handleOpenMedia,
  79. }),
  80. });
  81. return createPortal(
  82. <Component {...props} key={`media-${i}`} />,
  83. component,
  84. );
  85. })}
  86. <ModalRoot backgroundColor={this.state.backgroundColor} onClose={this.handleCloseMedia}>
  87. {this.state.media && (
  88. <MediaModal
  89. media={this.state.media}
  90. index={this.state.index || 0}
  91. lang={this.state.lang}
  92. currentTime={this.state.options?.startTime}
  93. autoPlay={this.state.options?.autoPlay}
  94. volume={this.state.options?.defaultVolume}
  95. onClose={this.handleCloseMedia}
  96. onChangeBackgroundColor={this.setBackgroundColor}
  97. />
  98. )}
  99. </ModalRoot>
  100. </>
  101. </IntlProvider>
  102. );
  103. }
  104. }