You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
4.6 KiB

  1. import ImmutablePropTypes from 'react-immutable-proptypes';
  2. import PureRenderMixin from 'react-addons-pure-render-mixin';
  3. import IconButton from './icon_button';
  4. import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
  5. const messages = defineMessages({
  6. toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' }
  7. });
  8. const outerStyle = {
  9. marginTop: '8px',
  10. overflow: 'hidden',
  11. width: '100%',
  12. boxSizing: 'border-box',
  13. position: 'relative'
  14. };
  15. const spoilerStyle = {
  16. background: '#000',
  17. color: '#fff',
  18. textAlign: 'center',
  19. height: '100%',
  20. cursor: 'pointer',
  21. display: 'flex',
  22. alignItems: 'center',
  23. justifyContent: 'center',
  24. flexDirection: 'column'
  25. };
  26. const spoilerSpanStyle = {
  27. display: 'block',
  28. fontSize: '14px',
  29. };
  30. const spoilerSubSpanStyle = {
  31. display: 'block',
  32. fontSize: '11px',
  33. fontWeight: '500'
  34. };
  35. const spoilerButtonStyle = {
  36. position: 'absolute',
  37. top: '6px',
  38. left: '8px',
  39. zIndex: '100'
  40. };
  41. const MediaGallery = React.createClass({
  42. getInitialState () {
  43. return {
  44. visible: !this.props.sensitive
  45. };
  46. },
  47. propTypes: {
  48. sensitive: React.PropTypes.bool,
  49. media: ImmutablePropTypes.list.isRequired,
  50. height: React.PropTypes.number.isRequired,
  51. onOpenMedia: React.PropTypes.func.isRequired,
  52. intl: React.PropTypes.object.isRequired
  53. },
  54. mixins: [PureRenderMixin],
  55. handleClick (index, e) {
  56. if (e.button === 0) {
  57. e.preventDefault();
  58. this.props.onOpenMedia(this.props.media, index);
  59. }
  60. e.stopPropagation();
  61. },
  62. handleOpen () {
  63. this.setState({ visible: !this.state.visible });
  64. },
  65. render () {
  66. const { media, intl, sensitive } = this.props;
  67. let children;
  68. if (!this.state.visible) {
  69. if (sensitive) {
  70. children = (
  71. <div style={spoilerStyle} onClick={this.handleOpen}>
  72. <span style={spoilerSpanStyle}><FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' /></span>
  73. <span style={spoilerSubSpanStyle}><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span>
  74. </div>
  75. );
  76. } else {
  77. children = (
  78. <div style={spoilerStyle} onClick={this.handleOpen}>
  79. <span style={spoilerSpanStyle}><FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' /></span>
  80. <span style={spoilerSubSpanStyle}><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span>
  81. </div>
  82. );
  83. }
  84. } else {
  85. const size = media.take(4).size;
  86. children = media.take(4).map((attachment, i) => {
  87. let width = 50;
  88. let height = 100;
  89. let top = 'auto';
  90. let left = 'auto';
  91. let bottom = 'auto';
  92. let right = 'auto';
  93. if (size === 1) {
  94. width = 100;
  95. }
  96. if (size === 4 || (size === 3 && i > 0)) {
  97. height = 50;
  98. }
  99. if (size === 2) {
  100. if (i === 0) {
  101. right = '2px';
  102. } else {
  103. left = '2px';
  104. }
  105. } else if (size === 3) {
  106. if (i === 0) {
  107. right = '2px';
  108. } else if (i > 0) {
  109. left = '2px';
  110. }
  111. if (i === 1) {
  112. bottom = '2px';
  113. } else if (i > 1) {
  114. top = '2px';
  115. }
  116. } else if (size === 4) {
  117. if (i === 0 || i === 2) {
  118. right = '2px';
  119. }
  120. if (i === 1 || i === 3) {
  121. left = '2px';
  122. }
  123. if (i < 2) {
  124. bottom = '2px';
  125. } else {
  126. top = '2px';
  127. }
  128. }
  129. return (
  130. <div key={attachment.get('id')} style={{ boxSizing: 'border-box', position: 'relative', left: left, top: top, right: right, bottom: bottom, float: 'left', border: 'none', display: 'block', width: `${width}%`, height: `${height}%` }}>
  131. <a href={attachment.get('remote_url') ? attachment.get('remote_url') : attachment.get('url')} onClick={this.handleClick.bind(this, i)} target='_blank' style={{ display: 'block', width: '100%', height: '100%', background: `url(${attachment.get('preview_url')}) no-repeat center`, textDecoration: 'none', backgroundSize: 'cover', cursor: 'zoom-in' }} />
  132. </div>
  133. );
  134. });
  135. }
  136. return (
  137. <div style={{ ...outerStyle, height: `${this.props.height}px` }}>
  138. <div style={spoilerButtonStyle} >
  139. <IconButton title={intl.formatMessage(messages.toggle_visible)} icon={this.state.visible ? 'eye' : 'eye-slash'} onClick={this.handleOpen} />
  140. </div>
  141. {children}
  142. </div>
  143. );
  144. }
  145. });
  146. export default injectIntl(MediaGallery);