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.

241 lines
5.4 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. /*
  2. `<ComposeAdvancedOptions>`
  3. ==========================
  4. > For more information on the contents of this file, please contact:
  5. >
  6. > - surinna [@srn@dev.glitch.social]
  7. This adds an advanced options dropdown to the toot compose box, for
  8. toggles that don't necessarily fit elsewhere.
  9. __Props:__
  10. - __`values` (`ImmutablePropTypes.contains(…).isRequired`) :__
  11. An Immutable map with the following values:
  12. - __`do_not_federate` (`PropTypes.bool.isRequired`) :__
  13. Specifies whether or not to federate the status.
  14. - __`onChange` (`PropTypes.func.isRequired`) :__
  15. The function to call when a toggle is changed. We pass this from
  16. our container to the toggle.
  17. - __`intl` (`PropTypes.object.isRequired`) :__
  18. Our internationalization object, inserted by `@injectIntl`.
  19. __State:__
  20. - __`open` :__
  21. This tells whether the dropdown is currently open or closed.
  22. */
  23. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  24. /*
  25. Imports:
  26. --------
  27. */
  28. // Package imports //
  29. import React from 'react';
  30. import PropTypes from 'prop-types';
  31. import ImmutablePropTypes from 'react-immutable-proptypes';
  32. import { injectIntl, defineMessages } from 'react-intl';
  33. // Mastodon imports //
  34. import IconButton from '../../../../mastodon/components/icon_button';
  35. // Our imports //
  36. import ComposeAdvancedOptionsToggle from './toggle';
  37. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  38. /*
  39. Inital setup:
  40. -------------
  41. The `messages` constant is used to define any messages that we need
  42. from inside props. These are the various titles and labels on our
  43. toggles.
  44. `iconStyle` styles the icon used for the dropdown button.
  45. */
  46. const messages = defineMessages({
  47. local_only_short :
  48. { id: 'advanced-options.local-only.short', defaultMessage: 'Local-only' },
  49. local_only_long :
  50. { id: 'advanced-options.local-only.long', defaultMessage: 'Do not post to other instances' },
  51. advanced_options_icon_title :
  52. { id: 'advanced_options.icon_title', defaultMessage: 'Advanced options' },
  53. });
  54. const iconStyle = {
  55. height : null,
  56. lineHeight : '27px',
  57. };
  58. /*
  59. Implementation:
  60. ---------------
  61. */
  62. @injectIntl
  63. export default class ComposeAdvancedOptions extends React.PureComponent {
  64. static propTypes = {
  65. values : ImmutablePropTypes.contains({
  66. do_not_federate : PropTypes.bool.isRequired,
  67. }).isRequired,
  68. onChange : PropTypes.func.isRequired,
  69. intl : PropTypes.object.isRequired,
  70. };
  71. state = {
  72. open: false,
  73. };
  74. /*
  75. ### `onToggleDropdown()`
  76. This function toggles the opening and closing of the advanced options
  77. dropdown.
  78. */
  79. onToggleDropdown = () => {
  80. this.setState({ open: !this.state.open });
  81. };
  82. /*
  83. ### `onGlobalClick(e)`
  84. This function closes the advanced options dropdown if you click
  85. anywhere else on the screen.
  86. */
  87. onGlobalClick = (e) => {
  88. if (e.target !== this.node && !this.node.contains(e.target) && this.state.open) {
  89. this.setState({ open: false });
  90. }
  91. }
  92. /*
  93. ### `componentDidMount()`, `componentWillUnmount()`
  94. This function closes the advanced options dropdown if you click
  95. anywhere else on the screen.
  96. */
  97. componentDidMount () {
  98. window.addEventListener('click', this.onGlobalClick);
  99. window.addEventListener('touchstart', this.onGlobalClick);
  100. }
  101. componentWillUnmount () {
  102. window.removeEventListener('click', this.onGlobalClick);
  103. window.removeEventListener('touchstart', this.onGlobalClick);
  104. }
  105. /*
  106. ### `setRef(c)`
  107. `setRef()` stores a reference to the dropdown's `<div> in `this.node`.
  108. */
  109. setRef = (c) => {
  110. this.node = c;
  111. }
  112. /*
  113. ### `render()`
  114. `render()` actually puts our component on the screen.
  115. */
  116. render () {
  117. const { open } = this.state;
  118. const { intl, values } = this.props;
  119. /*
  120. The `options` array provides all of the available advanced options
  121. alongside their icon, text, and name.
  122. */
  123. const options = [
  124. { icon: 'wifi', shortText: messages.local_only_short, longText: messages.local_only_long, name: 'do_not_federate' },
  125. ];
  126. /*
  127. `anyEnabled` tells us if any of our advanced options have been enabled.
  128. */
  129. const anyEnabled = values.some((enabled) => enabled);
  130. /*
  131. `optionElems` takes our `options` and creates
  132. `<ComposeAdvancedOptionsToggle>`s out of them. We use the `name` of the
  133. toggle as its `key` so that React can keep track of it.
  134. */
  135. const optionElems = options.map((option) => {
  136. return (
  137. <ComposeAdvancedOptionsToggle
  138. onChange={this.props.onChange}
  139. active={values.get(option.name)}
  140. key={option.name}
  141. name={option.name}
  142. shortText={intl.formatMessage(option.shortText)}
  143. longText={intl.formatMessage(option.longText)}
  144. />
  145. );
  146. });
  147. /*
  148. Finally, we can render our component.
  149. */
  150. return (
  151. <div ref={this.setRef} className={`advanced-options-dropdown ${open ? 'open' : ''} ${anyEnabled ? 'active' : ''} `}>
  152. <div className='advanced-options-dropdown__value'>
  153. <IconButton
  154. className='advanced-options-dropdown__value'
  155. title={intl.formatMessage(messages.advanced_options_icon_title)}
  156. icon='ellipsis-h' active={open || anyEnabled}
  157. size={18}
  158. style={iconStyle}
  159. onClick={this.onToggleDropdown}
  160. />
  161. </div>
  162. <div className='advanced-options-dropdown__dropdown'>
  163. {optionElems}
  164. </div>
  165. </div>
  166. );
  167. }
  168. }