]> cat aescling's git repositories - mastodon.git/blob - app/javascript/mastodon/actions/statuses.js
Summary: fix slowness due to layout thrashing when reloading a large … (#12661)
[mastodon.git] / app / javascript / mastodon / actions / statuses.js
1 import api from '../api';
2 import openDB from '../storage/db';
3 import { evictStatus } from '../storage/modifier';
4
5 import { deleteFromTimelines } from './timelines';
6 import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer';
7 import { ensureComposeIsVisible } from './compose';
8
9 export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
10 export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS';
11 export const STATUS_FETCH_FAIL = 'STATUS_FETCH_FAIL';
12
13 export const STATUS_DELETE_REQUEST = 'STATUS_DELETE_REQUEST';
14 export const STATUS_DELETE_SUCCESS = 'STATUS_DELETE_SUCCESS';
15 export const STATUS_DELETE_FAIL = 'STATUS_DELETE_FAIL';
16
17 export const CONTEXT_FETCH_REQUEST = 'CONTEXT_FETCH_REQUEST';
18 export const CONTEXT_FETCH_SUCCESS = 'CONTEXT_FETCH_SUCCESS';
19 export const CONTEXT_FETCH_FAIL = 'CONTEXT_FETCH_FAIL';
20
21 export const STATUS_MUTE_REQUEST = 'STATUS_MUTE_REQUEST';
22 export const STATUS_MUTE_SUCCESS = 'STATUS_MUTE_SUCCESS';
23 export const STATUS_MUTE_FAIL = 'STATUS_MUTE_FAIL';
24
25 export const STATUS_UNMUTE_REQUEST = 'STATUS_UNMUTE_REQUEST';
26 export const STATUS_UNMUTE_SUCCESS = 'STATUS_UNMUTE_SUCCESS';
27 export const STATUS_UNMUTE_FAIL = 'STATUS_UNMUTE_FAIL';
28
29 export const STATUS_REVEAL = 'STATUS_REVEAL';
30 export const STATUS_HIDE = 'STATUS_HIDE';
31 export const STATUS_COLLAPSE = 'STATUS_COLLAPSE';
32
33 export const REDRAFT = 'REDRAFT';
34
35 export function fetchStatusRequest(id, skipLoading) {
36 return {
37 type: STATUS_FETCH_REQUEST,
38 id,
39 skipLoading,
40 };
41 };
42
43 function getFromDB(dispatch, getState, accountIndex, index, id) {
44 return new Promise((resolve, reject) => {
45 const request = index.get(id);
46
47 request.onerror = reject;
48
49 request.onsuccess = () => {
50 const promises = [];
51
52 if (!request.result) {
53 reject();
54 return;
55 }
56
57 dispatch(importStatus(request.result));
58
59 if (getState().getIn(['accounts', request.result.account], null) === null) {
60 promises.push(new Promise((accountResolve, accountReject) => {
61 const accountRequest = accountIndex.get(request.result.account);
62
63 accountRequest.onerror = accountReject;
64 accountRequest.onsuccess = () => {
65 if (!request.result) {
66 accountReject();
67 return;
68 }
69
70 dispatch(importAccount(accountRequest.result));
71 accountResolve();
72 };
73 }));
74 }
75
76 if (request.result.reblog && getState().getIn(['statuses', request.result.reblog], null) === null) {
77 promises.push(getFromDB(dispatch, getState, accountIndex, index, request.result.reblog));
78 }
79
80 resolve(Promise.all(promises));
81 };
82 });
83 }
84
85 export function fetchStatus(id) {
86 return (dispatch, getState) => {
87 const skipLoading = getState().getIn(['statuses', id], null) !== null;
88
89 dispatch(fetchContext(id));
90
91 if (skipLoading) {
92 return;
93 }
94
95 dispatch(fetchStatusRequest(id, skipLoading));
96
97 openDB().then(db => {
98 const transaction = db.transaction(['accounts', 'statuses'], 'read');
99 const accountIndex = transaction.objectStore('accounts').index('id');
100 const index = transaction.objectStore('statuses').index('id');
101
102 return getFromDB(dispatch, getState, accountIndex, index, id).then(() => {
103 db.close();
104 }, error => {
105 db.close();
106 throw error;
107 });
108 }).then(() => {
109 dispatch(fetchStatusSuccess(skipLoading));
110 }, () => api(getState).get(`/api/v1/statuses/${id}`).then(response => {
111 dispatch(importFetchedStatus(response.data));
112 dispatch(fetchStatusSuccess(skipLoading));
113 })).catch(error => {
114 dispatch(fetchStatusFail(id, error, skipLoading));
115 });
116 };
117 };
118
119 export function fetchStatusSuccess(skipLoading) {
120 return {
121 type: STATUS_FETCH_SUCCESS,
122 skipLoading,
123 };
124 };
125
126 export function fetchStatusFail(id, error, skipLoading) {
127 return {
128 type: STATUS_FETCH_FAIL,
129 id,
130 error,
131 skipLoading,
132 skipAlert: true,
133 };
134 };
135
136 export function redraft(status, raw_text) {
137 return {
138 type: REDRAFT,
139 status,
140 raw_text,
141 };
142 };
143
144 export function deleteStatus(id, routerHistory, withRedraft = false) {
145 return (dispatch, getState) => {
146 let status = getState().getIn(['statuses', id]);
147
148 if (status.get('poll')) {
149 status = status.set('poll', getState().getIn(['polls', status.get('poll')]));
150 }
151
152 dispatch(deleteStatusRequest(id));
153
154 api(getState).delete(`/api/v1/statuses/${id}`).then(response => {
155 evictStatus(id);
156 dispatch(deleteStatusSuccess(id));
157 dispatch(deleteFromTimelines(id));
158
159 if (withRedraft) {
160 dispatch(redraft(status, response.data.text));
161 ensureComposeIsVisible(getState, routerHistory);
162 }
163 }).catch(error => {
164 dispatch(deleteStatusFail(id, error));
165 });
166 };
167 };
168
169 export function deleteStatusRequest(id) {
170 return {
171 type: STATUS_DELETE_REQUEST,
172 id: id,
173 };
174 };
175
176 export function deleteStatusSuccess(id) {
177 return {
178 type: STATUS_DELETE_SUCCESS,
179 id: id,
180 };
181 };
182
183 export function deleteStatusFail(id, error) {
184 return {
185 type: STATUS_DELETE_FAIL,
186 id: id,
187 error: error,
188 };
189 };
190
191 export function fetchContext(id) {
192 return (dispatch, getState) => {
193 dispatch(fetchContextRequest(id));
194
195 api(getState).get(`/api/v1/statuses/${id}/context`).then(response => {
196 dispatch(importFetchedStatuses(response.data.ancestors.concat(response.data.descendants)));
197 dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants));
198
199 }).catch(error => {
200 if (error.response && error.response.status === 404) {
201 dispatch(deleteFromTimelines(id));
202 }
203
204 dispatch(fetchContextFail(id, error));
205 });
206 };
207 };
208
209 export function fetchContextRequest(id) {
210 return {
211 type: CONTEXT_FETCH_REQUEST,
212 id,
213 };
214 };
215
216 export function fetchContextSuccess(id, ancestors, descendants) {
217 return {
218 type: CONTEXT_FETCH_SUCCESS,
219 id,
220 ancestors,
221 descendants,
222 statuses: ancestors.concat(descendants),
223 };
224 };
225
226 export function fetchContextFail(id, error) {
227 return {
228 type: CONTEXT_FETCH_FAIL,
229 id,
230 error,
231 skipAlert: true,
232 };
233 };
234
235 export function muteStatus(id) {
236 return (dispatch, getState) => {
237 dispatch(muteStatusRequest(id));
238
239 api(getState).post(`/api/v1/statuses/${id}/mute`).then(() => {
240 dispatch(muteStatusSuccess(id));
241 }).catch(error => {
242 dispatch(muteStatusFail(id, error));
243 });
244 };
245 };
246
247 export function muteStatusRequest(id) {
248 return {
249 type: STATUS_MUTE_REQUEST,
250 id,
251 };
252 };
253
254 export function muteStatusSuccess(id) {
255 return {
256 type: STATUS_MUTE_SUCCESS,
257 id,
258 };
259 };
260
261 export function muteStatusFail(id, error) {
262 return {
263 type: STATUS_MUTE_FAIL,
264 id,
265 error,
266 };
267 };
268
269 export function unmuteStatus(id) {
270 return (dispatch, getState) => {
271 dispatch(unmuteStatusRequest(id));
272
273 api(getState).post(`/api/v1/statuses/${id}/unmute`).then(() => {
274 dispatch(unmuteStatusSuccess(id));
275 }).catch(error => {
276 dispatch(unmuteStatusFail(id, error));
277 });
278 };
279 };
280
281 export function unmuteStatusRequest(id) {
282 return {
283 type: STATUS_UNMUTE_REQUEST,
284 id,
285 };
286 };
287
288 export function unmuteStatusSuccess(id) {
289 return {
290 type: STATUS_UNMUTE_SUCCESS,
291 id,
292 };
293 };
294
295 export function unmuteStatusFail(id, error) {
296 return {
297 type: STATUS_UNMUTE_FAIL,
298 id,
299 error,
300 };
301 };
302
303 export function hideStatus(ids) {
304 if (!Array.isArray(ids)) {
305 ids = [ids];
306 }
307
308 return {
309 type: STATUS_HIDE,
310 ids,
311 };
312 };
313
314 export function revealStatus(ids) {
315 if (!Array.isArray(ids)) {
316 ids = [ids];
317 }
318
319 return {
320 type: STATUS_REVEAL,
321 ids,
322 };
323 };
324
325 export function toggleStatusCollapse(id, isCollapsed) {
326 return {
327 type: STATUS_COLLAPSE,
328 id,
329 isCollapsed,
330 };
331 }
This page took 0.128052 seconds and 4 git commands to generate.