compose.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. import api from '../api';
  2. import { updateTimeline } from './timelines';
  3. import * as emojione from 'emojione';
  4. export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
  5. export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
  6. export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
  7. export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
  8. export const COMPOSE_REPLY = 'COMPOSE_REPLY';
  9. export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
  10. export const COMPOSE_MENTION = 'COMPOSE_MENTION';
  11. export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
  12. export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS';
  13. export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL';
  14. export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS';
  15. export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO';
  16. export const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR';
  17. export const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY';
  18. export const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT';
  19. export const COMPOSE_MOUNT = 'COMPOSE_MOUNT';
  20. export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT';
  21. export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE';
  22. export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE';
  23. export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
  24. export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
  25. export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
  26. export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
  27. export function changeCompose(text) {
  28. return {
  29. type: COMPOSE_CHANGE,
  30. text: text
  31. };
  32. };
  33. export function replyCompose(status, router) {
  34. return (dispatch, getState) => {
  35. dispatch({
  36. type: COMPOSE_REPLY,
  37. status: status
  38. });
  39. if (!getState().getIn(['compose', 'mounted'])) {
  40. router.push('/statuses/new');
  41. }
  42. };
  43. };
  44. export function cancelReplyCompose() {
  45. return {
  46. type: COMPOSE_REPLY_CANCEL
  47. };
  48. };
  49. export function mentionCompose(account, router) {
  50. return (dispatch, getState) => {
  51. dispatch({
  52. type: COMPOSE_MENTION,
  53. account: account
  54. });
  55. if (!getState().getIn(['compose', 'mounted'])) {
  56. router.push('/statuses/new');
  57. }
  58. };
  59. };
  60. export function submitCompose() {
  61. return function (dispatch, getState) {
  62. const status = emojione.shortnameToUnicode(getState().getIn(['compose', 'text'], ''));
  63. if (!status || !status.length) {
  64. return;
  65. }
  66. dispatch(submitComposeRequest());
  67. api(getState).post('/api/v1/statuses', {
  68. status,
  69. in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
  70. media_ids: getState().getIn(['compose', 'media_attachments']).map(item => item.get('id')),
  71. sensitive: getState().getIn(['compose', 'sensitive']),
  72. spoiler_text: getState().getIn(['compose', 'spoiler_text'], ''),
  73. visibility: getState().getIn(['compose', 'privacy'])
  74. }, {
  75. headers: {
  76. 'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey'])
  77. }
  78. }).then(function (response) {
  79. dispatch(submitComposeSuccess({ ...response.data }));
  80. // To make the app more responsive, immediately get the status into the columns
  81. dispatch(updateTimeline('home', { ...response.data }));
  82. if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
  83. if (getState().getIn(['timelines', 'community', 'loaded'])) {
  84. dispatch(updateTimeline('community', { ...response.data }));
  85. }
  86. if (getState().getIn(['timelines', 'public', 'loaded'])) {
  87. dispatch(updateTimeline('public', { ...response.data }));
  88. }
  89. }
  90. }).catch(function (error) {
  91. dispatch(submitComposeFail(error));
  92. });
  93. };
  94. };
  95. export function submitComposeRequest() {
  96. return {
  97. type: COMPOSE_SUBMIT_REQUEST
  98. };
  99. };
  100. export function submitComposeSuccess(status) {
  101. return {
  102. type: COMPOSE_SUBMIT_SUCCESS,
  103. status: status
  104. };
  105. };
  106. export function submitComposeFail(error) {
  107. return {
  108. type: COMPOSE_SUBMIT_FAIL,
  109. error: error
  110. };
  111. };
  112. export function uploadCompose(files) {
  113. return function (dispatch, getState) {
  114. if (getState().getIn(['compose', 'media_attachments']).size > 3) {
  115. return;
  116. }
  117. dispatch(uploadComposeRequest());
  118. let data = new FormData();
  119. data.append('file', files[0]);
  120. api(getState).post('/api/v1/media', data, {
  121. onUploadProgress: function (e) {
  122. dispatch(uploadComposeProgress(e.loaded, e.total));
  123. }
  124. }).then(function (response) {
  125. dispatch(uploadComposeSuccess(response.data));
  126. }).catch(function (error) {
  127. dispatch(uploadComposeFail(error));
  128. });
  129. };
  130. };
  131. export function uploadComposeRequest() {
  132. return {
  133. type: COMPOSE_UPLOAD_REQUEST,
  134. skipLoading: true
  135. };
  136. };
  137. export function uploadComposeProgress(loaded, total) {
  138. return {
  139. type: COMPOSE_UPLOAD_PROGRESS,
  140. loaded: loaded,
  141. total: total
  142. };
  143. };
  144. export function uploadComposeSuccess(media) {
  145. return {
  146. type: COMPOSE_UPLOAD_SUCCESS,
  147. media: media,
  148. skipLoading: true
  149. };
  150. };
  151. export function uploadComposeFail(error) {
  152. return {
  153. type: COMPOSE_UPLOAD_FAIL,
  154. error: error,
  155. skipLoading: true
  156. };
  157. };
  158. export function undoUploadCompose(media_id) {
  159. return {
  160. type: COMPOSE_UPLOAD_UNDO,
  161. media_id: media_id
  162. };
  163. };
  164. export function clearComposeSuggestions() {
  165. return {
  166. type: COMPOSE_SUGGESTIONS_CLEAR
  167. };
  168. };
  169. export function fetchComposeSuggestions(token) {
  170. return (dispatch, getState) => {
  171. api(getState).get('/api/v1/accounts/search', {
  172. params: {
  173. q: token,
  174. resolve: false,
  175. limit: 4
  176. }
  177. }).then(response => {
  178. dispatch(readyComposeSuggestions(token, response.data));
  179. });
  180. };
  181. };
  182. export function readyComposeSuggestions(token, accounts) {
  183. return {
  184. type: COMPOSE_SUGGESTIONS_READY,
  185. token,
  186. accounts
  187. };
  188. };
  189. export function selectComposeSuggestion(position, token, accountId) {
  190. return (dispatch, getState) => {
  191. const completion = getState().getIn(['accounts', accountId, 'acct']);
  192. dispatch({
  193. type: COMPOSE_SUGGESTION_SELECT,
  194. position,
  195. token,
  196. completion
  197. });
  198. };
  199. };
  200. export function mountCompose() {
  201. return {
  202. type: COMPOSE_MOUNT
  203. };
  204. };
  205. export function unmountCompose() {
  206. return {
  207. type: COMPOSE_UNMOUNT
  208. };
  209. };
  210. export function changeComposeSensitivity() {
  211. return {
  212. type: COMPOSE_SENSITIVITY_CHANGE,
  213. };
  214. };
  215. export function changeComposeSpoilerness() {
  216. return {
  217. type: COMPOSE_SPOILERNESS_CHANGE
  218. };
  219. };
  220. export function changeComposeSpoilerText(text) {
  221. return {
  222. type: COMPOSE_SPOILER_TEXT_CHANGE,
  223. text
  224. };
  225. };
  226. export function changeComposeVisibility(value) {
  227. return {
  228. type: COMPOSE_VISIBILITY_CHANGE,
  229. value
  230. };
  231. };
  232. export function insertEmojiCompose(position, emoji) {
  233. return {
  234. type: COMPOSE_EMOJI_INSERT,
  235. position,
  236. emoji
  237. };
  238. };