diff options
Diffstat (limited to 'app/javascript/flavours/glitch/actions')
6 files changed, 108 insertions, 15 deletions
diff --git a/app/javascript/flavours/glitch/actions/accounts.js b/app/javascript/flavours/glitch/actions/accounts.js index 912a3d179..0cf64e076 100644 --- a/app/javascript/flavours/glitch/actions/accounts.js +++ b/app/javascript/flavours/glitch/actions/accounts.js @@ -5,6 +5,10 @@ export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST'; export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS'; export const ACCOUNT_FETCH_FAIL = 'ACCOUNT_FETCH_FAIL'; +export const ACCOUNT_LOOKUP_REQUEST = 'ACCOUNT_LOOKUP_REQUEST'; +export const ACCOUNT_LOOKUP_SUCCESS = 'ACCOUNT_LOOKUP_SUCCESS'; +export const ACCOUNT_LOOKUP_FAIL = 'ACCOUNT_LOOKUP_FAIL'; + export const ACCOUNT_FOLLOW_REQUEST = 'ACCOUNT_FOLLOW_REQUEST'; export const ACCOUNT_FOLLOW_SUCCESS = 'ACCOUNT_FOLLOW_SUCCESS'; export const ACCOUNT_FOLLOW_FAIL = 'ACCOUNT_FOLLOW_FAIL'; @@ -104,6 +108,34 @@ export function fetchAccount(id) { }; }; +export const lookupAccount = acct => (dispatch, getState) => { + dispatch(lookupAccountRequest(acct)); + + api(getState).get('/api/v1/accounts/lookup', { params: { acct } }).then(response => { + dispatch(fetchRelationships([response.data.id])); + dispatch(importFetchedAccount(response.data)); + dispatch(lookupAccountSuccess()); + }).catch(error => { + dispatch(lookupAccountFail(acct, error)); + }); +}; + +export const lookupAccountRequest = (acct) => ({ + type: ACCOUNT_LOOKUP_REQUEST, + acct, +}); + +export const lookupAccountSuccess = () => ({ + type: ACCOUNT_LOOKUP_SUCCESS, +}); + +export const lookupAccountFail = (acct, error) => ({ + type: ACCOUNT_LOOKUP_FAIL, + acct, + error, + skipAlert: true, +}); + export function fetchAccountRequest(id) { return { type: ACCOUNT_FETCH_REQUEST, diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index f83738093..261c72b2a 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -10,6 +10,7 @@ import { importFetchedAccounts } from './importer'; import { updateTimeline } from './timelines'; import { showAlertForError } from './alerts'; import { showAlert } from './alerts'; +import { openModal } from './modal'; import { defineMessages } from 'react-intl'; let cancelFetchComposeSuggestionsAccounts, cancelFetchComposeSuggestionsTags; @@ -38,6 +39,7 @@ export const THUMBNAIL_UPLOAD_PROGRESS = 'THUMBNAIL_UPLOAD_PROGRESS'; export const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR'; export const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY'; export const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT'; +export const COMPOSE_SUGGESTION_IGNORE = 'COMPOSE_SUGGESTION_IGNORE'; export const COMPOSE_SUGGESTION_TAGS_UPDATE = 'COMPOSE_SUGGESTION_TAGS_UPDATE'; export const COMPOSE_TAG_HISTORY_UPDATE = 'COMPOSE_TAG_HISTORY_UPDATE'; @@ -68,6 +70,11 @@ export const COMPOSE_POLL_OPTION_CHANGE = 'COMPOSE_POLL_OPTION_CHANGE'; export const COMPOSE_POLL_OPTION_REMOVE = 'COMPOSE_POLL_OPTION_REMOVE'; export const COMPOSE_POLL_SETTINGS_CHANGE = 'COMPOSE_POLL_SETTINGS_CHANGE'; +export const INIT_MEDIA_EDIT_MODAL = 'INIT_MEDIA_EDIT_MODAL'; + +export const COMPOSE_CHANGE_MEDIA_DESCRIPTION = 'COMPOSE_CHANGE_MEDIA_DESCRIPTION'; +export const COMPOSE_CHANGE_MEDIA_FOCUS = 'COMPOSE_CHANGE_MEDIA_FOCUS'; + const messages = defineMessages({ uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' }, uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, @@ -77,7 +84,7 @@ const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1); export const ensureComposeIsVisible = (getState, routerHistory) => { if (!getState().getIn(['compose', 'mounted']) && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) { - routerHistory.push('/statuses/new'); + routerHistory.push('/publish'); } }; @@ -170,7 +177,8 @@ export function submitCompose(routerHistory) { 'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']), }, }).then(function (response) { - if (routerHistory && routerHistory.location.pathname === '/statuses/new' + if (routerHistory + && (routerHistory.location.pathname === '/publish' || routerHistory.location.pathname === '/statuses/new') && window.history.state && !getState().getIn(['compose', 'advanced_options', 'threaded_mode'])) { routerHistory.goBack(); @@ -278,12 +286,15 @@ export function uploadCompose(files) { if (status === 200) { dispatch(uploadComposeSuccess(data, f)); } else if (status === 202) { + let tryCount = 1; const poll = () => { api(getState).get(`/api/v1/media/${data.id}`).then(response => { if (response.status === 200) { dispatch(uploadComposeSuccess(response.data, f)); } else if (response.status === 206) { - setTimeout(() => poll(), 1000); + let retryAfter = (Math.log2(tryCount) || 1) * 1000; + tryCount += 1; + setTimeout(() => poll(), retryAfter); } }).catch(error => dispatch(uploadComposeFail(error))); }; @@ -339,6 +350,32 @@ export const uploadThumbnailFail = error => ({ skipLoading: true, }); +export function initMediaEditModal(id) { + return dispatch => { + dispatch({ + type: INIT_MEDIA_EDIT_MODAL, + id, + }); + + dispatch(openModal('FOCAL_POINT', { id })); + }; +}; + +export function onChangeMediaDescription(description) { + return { + type: COMPOSE_CHANGE_MEDIA_DESCRIPTION, + description, + }; +}; + +export function onChangeMediaFocus(focusX, focusY) { + return { + type: COMPOSE_CHANGE_MEDIA_FOCUS, + focusX, + focusY, + }; +}; + export function changeUploadCompose(id, params) { return (dispatch, getState) => { dispatch(changeUploadComposeRequest()); @@ -529,13 +566,25 @@ export function selectComposeSuggestion(position, token, suggestion, path) { completion = '@' + getState().getIn(['accounts', suggestion.id, 'acct']); } - dispatch({ - type: COMPOSE_SUGGESTION_SELECT, - position, - token, - completion, - path, - }); + // We don't want to replace hashtags that vary only in case due to accessibility, but we need to fire off an event so that + // the suggestions are dismissed and the cursor moves forward. + if (suggestion.type !== 'hashtag' || token.slice(1).localeCompare(suggestion.name, undefined, { sensitivity: 'accent' }) !== 0) { + dispatch({ + type: COMPOSE_SUGGESTION_SELECT, + position, + token, + completion, + path, + }); + } else { + dispatch({ + type: COMPOSE_SUGGESTION_IGNORE, + position, + token, + completion, + path, + }); + } }; }; diff --git a/app/javascript/flavours/glitch/actions/importer/normalizer.js b/app/javascript/flavours/glitch/actions/importer/normalizer.js index 9b3bd0d56..bda15a9b0 100644 --- a/app/javascript/flavours/glitch/actions/importer/normalizer.js +++ b/app/javascript/flavours/glitch/actions/importer/normalizer.js @@ -54,15 +54,16 @@ export function normalizeStatus(status, normalOldStatus) { normalStatus.poll = status.poll.id; } - // Only calculate these values when status first encountered - // Otherwise keep the ones already in the reducer - if (normalOldStatus) { + // Only calculate these values when status first encountered and + // when the underlying values change. Otherwise keep the ones + // already in the reducer + if (normalOldStatus && normalOldStatus.get('content') === normalStatus.content && normalOldStatus.get('spoiler_text') === normalStatus.spoiler_text) { normalStatus.search_index = normalOldStatus.get('search_index'); normalStatus.contentHtml = normalOldStatus.get('contentHtml'); normalStatus.spoilerHtml = normalOldStatus.get('spoilerHtml'); } else { const spoilerText = normalStatus.spoiler_text || ''; - const searchContent = ([spoilerText, status.content].concat((status.poll && status.poll.options) ? status.poll.options.map(option => option.title) : [])).join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n'); + const searchContent = ([spoilerText, status.content].concat((status.poll && status.poll.options) ? status.poll.options.map(option => option.title) : [])).concat(status.media_attachments.map(att => att.description)).join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n'); const emojiMap = makeEmojiMap(normalStatus); normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent; diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index bd3a34e5d..4b00ea632 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -1,6 +1,6 @@ import api, { getLinks } from 'flavours/glitch/util/api'; import IntlMessageFormat from 'intl-messageformat'; -import { fetchRelationships } from './accounts'; +import { fetchFollowRequests, fetchRelationships } from './accounts'; import { importFetchedAccount, importFetchedAccounts, @@ -90,6 +90,10 @@ export function updateNotifications(notification, intlMessages, intlLocale) { filtered = regex && regex.test(searchIndex); } + if (['follow_request'].includes(notification.type)) { + dispatch(fetchFollowRequests()); + } + dispatch(submitMarkers()); if (showInColumn) { diff --git a/app/javascript/flavours/glitch/actions/statuses.js b/app/javascript/flavours/glitch/actions/statuses.js index 4d2bda78b..7db357df1 100644 --- a/app/javascript/flavours/glitch/actions/statuses.js +++ b/app/javascript/flavours/glitch/actions/statuses.js @@ -128,6 +128,9 @@ export function deleteStatusFail(id, error) { }; }; +export const updateStatus = status => dispatch => + dispatch(importFetchedStatus(status)); + export function fetchContext(id) { return (dispatch, getState) => { dispatch(fetchContextRequest(id)); diff --git a/app/javascript/flavours/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js index 35db5dcc9..223924534 100644 --- a/app/javascript/flavours/glitch/actions/streaming.js +++ b/app/javascript/flavours/glitch/actions/streaming.js @@ -10,6 +10,7 @@ import { } from './timelines'; import { updateNotifications, expandNotifications } from './notifications'; import { updateConversations } from './conversations'; +import { updateStatus } from './statuses'; import { fetchAnnouncements, updateAnnouncements, @@ -75,6 +76,9 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti case 'update': dispatch(updateTimeline(timelineId, JSON.parse(data.payload), options.accept)); break; + case 'status.update': + dispatch(updateStatus(JSON.parse(data.payload))); + break; case 'delete': dispatch(deleteFromTimelines(data.payload)); break; |