[build] upgrade eslint to 9.37.0 (#88)
Co-authored-by: tobi <tobi.smethurst@protonmail.com> Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/88 Co-authored-by: Zoë Bijl <moiety@noreply.codeberg.org> Co-committed-by: Zoë Bijl <moiety@noreply.codeberg.org>
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { createAppAsyncThunk } from 'mastodon/store/typed_functions';
|
||||
import { createAppAsyncThunk } from "mastodon/store/typed_functions";
|
||||
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
export const submitAccountNote = createAppAsyncThunk(
|
||||
'account_note/submit',
|
||||
async (args: { id: string; value: string }, { getState }) => {
|
||||
"account_note/submit",
|
||||
async (args: { id: string, value: string }, { getState }) => {
|
||||
// TODO: replace `unknown` with `ApiRelationshipJSON` when it is merged
|
||||
const response = await api(getState).post<unknown>(
|
||||
`/api/v1/accounts/${args.id}/note`,
|
||||
|
||||
@@ -1,84 +1,84 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
import { importFetchedAccount, importFetchedAccounts } from './importer';
|
||||
import { importFetchedAccount, importFetchedAccounts } from "./importer";
|
||||
|
||||
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_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_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';
|
||||
export const ACCOUNT_FOLLOW_REQUEST = "ACCOUNT_FOLLOW_REQUEST";
|
||||
export const ACCOUNT_FOLLOW_SUCCESS = "ACCOUNT_FOLLOW_SUCCESS";
|
||||
export const ACCOUNT_FOLLOW_FAIL = "ACCOUNT_FOLLOW_FAIL";
|
||||
|
||||
export const ACCOUNT_UNFOLLOW_REQUEST = 'ACCOUNT_UNFOLLOW_REQUEST';
|
||||
export const ACCOUNT_UNFOLLOW_SUCCESS = 'ACCOUNT_UNFOLLOW_SUCCESS';
|
||||
export const ACCOUNT_UNFOLLOW_FAIL = 'ACCOUNT_UNFOLLOW_FAIL';
|
||||
export const ACCOUNT_UNFOLLOW_REQUEST = "ACCOUNT_UNFOLLOW_REQUEST";
|
||||
export const ACCOUNT_UNFOLLOW_SUCCESS = "ACCOUNT_UNFOLLOW_SUCCESS";
|
||||
export const ACCOUNT_UNFOLLOW_FAIL = "ACCOUNT_UNFOLLOW_FAIL";
|
||||
|
||||
export const ACCOUNT_BLOCK_REQUEST = 'ACCOUNT_BLOCK_REQUEST';
|
||||
export const ACCOUNT_BLOCK_SUCCESS = 'ACCOUNT_BLOCK_SUCCESS';
|
||||
export const ACCOUNT_BLOCK_FAIL = 'ACCOUNT_BLOCK_FAIL';
|
||||
export const ACCOUNT_BLOCK_REQUEST = "ACCOUNT_BLOCK_REQUEST";
|
||||
export const ACCOUNT_BLOCK_SUCCESS = "ACCOUNT_BLOCK_SUCCESS";
|
||||
export const ACCOUNT_BLOCK_FAIL = "ACCOUNT_BLOCK_FAIL";
|
||||
|
||||
export const ACCOUNT_UNBLOCK_REQUEST = 'ACCOUNT_UNBLOCK_REQUEST';
|
||||
export const ACCOUNT_UNBLOCK_SUCCESS = 'ACCOUNT_UNBLOCK_SUCCESS';
|
||||
export const ACCOUNT_UNBLOCK_FAIL = 'ACCOUNT_UNBLOCK_FAIL';
|
||||
export const ACCOUNT_UNBLOCK_REQUEST = "ACCOUNT_UNBLOCK_REQUEST";
|
||||
export const ACCOUNT_UNBLOCK_SUCCESS = "ACCOUNT_UNBLOCK_SUCCESS";
|
||||
export const ACCOUNT_UNBLOCK_FAIL = "ACCOUNT_UNBLOCK_FAIL";
|
||||
|
||||
export const ACCOUNT_MUTE_REQUEST = 'ACCOUNT_MUTE_REQUEST';
|
||||
export const ACCOUNT_MUTE_SUCCESS = 'ACCOUNT_MUTE_SUCCESS';
|
||||
export const ACCOUNT_MUTE_FAIL = 'ACCOUNT_MUTE_FAIL';
|
||||
export const ACCOUNT_MUTE_REQUEST = "ACCOUNT_MUTE_REQUEST";
|
||||
export const ACCOUNT_MUTE_SUCCESS = "ACCOUNT_MUTE_SUCCESS";
|
||||
export const ACCOUNT_MUTE_FAIL = "ACCOUNT_MUTE_FAIL";
|
||||
|
||||
export const ACCOUNT_UNMUTE_REQUEST = 'ACCOUNT_UNMUTE_REQUEST';
|
||||
export const ACCOUNT_UNMUTE_SUCCESS = 'ACCOUNT_UNMUTE_SUCCESS';
|
||||
export const ACCOUNT_UNMUTE_FAIL = 'ACCOUNT_UNMUTE_FAIL';
|
||||
export const ACCOUNT_UNMUTE_REQUEST = "ACCOUNT_UNMUTE_REQUEST";
|
||||
export const ACCOUNT_UNMUTE_SUCCESS = "ACCOUNT_UNMUTE_SUCCESS";
|
||||
export const ACCOUNT_UNMUTE_FAIL = "ACCOUNT_UNMUTE_FAIL";
|
||||
|
||||
export const ACCOUNT_PIN_REQUEST = 'ACCOUNT_PIN_REQUEST';
|
||||
export const ACCOUNT_PIN_SUCCESS = 'ACCOUNT_PIN_SUCCESS';
|
||||
export const ACCOUNT_PIN_FAIL = 'ACCOUNT_PIN_FAIL';
|
||||
export const ACCOUNT_PIN_REQUEST = "ACCOUNT_PIN_REQUEST";
|
||||
export const ACCOUNT_PIN_SUCCESS = "ACCOUNT_PIN_SUCCESS";
|
||||
export const ACCOUNT_PIN_FAIL = "ACCOUNT_PIN_FAIL";
|
||||
|
||||
export const ACCOUNT_UNPIN_REQUEST = 'ACCOUNT_UNPIN_REQUEST';
|
||||
export const ACCOUNT_UNPIN_SUCCESS = 'ACCOUNT_UNPIN_SUCCESS';
|
||||
export const ACCOUNT_UNPIN_FAIL = 'ACCOUNT_UNPIN_FAIL';
|
||||
export const ACCOUNT_UNPIN_REQUEST = "ACCOUNT_UNPIN_REQUEST";
|
||||
export const ACCOUNT_UNPIN_SUCCESS = "ACCOUNT_UNPIN_SUCCESS";
|
||||
export const ACCOUNT_UNPIN_FAIL = "ACCOUNT_UNPIN_FAIL";
|
||||
|
||||
export const FOLLOWERS_FETCH_REQUEST = 'FOLLOWERS_FETCH_REQUEST';
|
||||
export const FOLLOWERS_FETCH_SUCCESS = 'FOLLOWERS_FETCH_SUCCESS';
|
||||
export const FOLLOWERS_FETCH_FAIL = 'FOLLOWERS_FETCH_FAIL';
|
||||
export const FOLLOWERS_FETCH_REQUEST = "FOLLOWERS_FETCH_REQUEST";
|
||||
export const FOLLOWERS_FETCH_SUCCESS = "FOLLOWERS_FETCH_SUCCESS";
|
||||
export const FOLLOWERS_FETCH_FAIL = "FOLLOWERS_FETCH_FAIL";
|
||||
|
||||
export const FOLLOWERS_EXPAND_REQUEST = 'FOLLOWERS_EXPAND_REQUEST';
|
||||
export const FOLLOWERS_EXPAND_SUCCESS = 'FOLLOWERS_EXPAND_SUCCESS';
|
||||
export const FOLLOWERS_EXPAND_FAIL = 'FOLLOWERS_EXPAND_FAIL';
|
||||
export const FOLLOWERS_EXPAND_REQUEST = "FOLLOWERS_EXPAND_REQUEST";
|
||||
export const FOLLOWERS_EXPAND_SUCCESS = "FOLLOWERS_EXPAND_SUCCESS";
|
||||
export const FOLLOWERS_EXPAND_FAIL = "FOLLOWERS_EXPAND_FAIL";
|
||||
|
||||
export const FOLLOWING_FETCH_REQUEST = 'FOLLOWING_FETCH_REQUEST';
|
||||
export const FOLLOWING_FETCH_SUCCESS = 'FOLLOWING_FETCH_SUCCESS';
|
||||
export const FOLLOWING_FETCH_FAIL = 'FOLLOWING_FETCH_FAIL';
|
||||
export const FOLLOWING_FETCH_REQUEST = "FOLLOWING_FETCH_REQUEST";
|
||||
export const FOLLOWING_FETCH_SUCCESS = "FOLLOWING_FETCH_SUCCESS";
|
||||
export const FOLLOWING_FETCH_FAIL = "FOLLOWING_FETCH_FAIL";
|
||||
|
||||
export const FOLLOWING_EXPAND_REQUEST = 'FOLLOWING_EXPAND_REQUEST';
|
||||
export const FOLLOWING_EXPAND_SUCCESS = 'FOLLOWING_EXPAND_SUCCESS';
|
||||
export const FOLLOWING_EXPAND_FAIL = 'FOLLOWING_EXPAND_FAIL';
|
||||
export const FOLLOWING_EXPAND_REQUEST = "FOLLOWING_EXPAND_REQUEST";
|
||||
export const FOLLOWING_EXPAND_SUCCESS = "FOLLOWING_EXPAND_SUCCESS";
|
||||
export const FOLLOWING_EXPAND_FAIL = "FOLLOWING_EXPAND_FAIL";
|
||||
|
||||
export const RELATIONSHIPS_FETCH_REQUEST = 'RELATIONSHIPS_FETCH_REQUEST';
|
||||
export const RELATIONSHIPS_FETCH_SUCCESS = 'RELATIONSHIPS_FETCH_SUCCESS';
|
||||
export const RELATIONSHIPS_FETCH_FAIL = 'RELATIONSHIPS_FETCH_FAIL';
|
||||
export const RELATIONSHIPS_FETCH_REQUEST = "RELATIONSHIPS_FETCH_REQUEST";
|
||||
export const RELATIONSHIPS_FETCH_SUCCESS = "RELATIONSHIPS_FETCH_SUCCESS";
|
||||
export const RELATIONSHIPS_FETCH_FAIL = "RELATIONSHIPS_FETCH_FAIL";
|
||||
|
||||
export const FOLLOW_REQUESTS_FETCH_REQUEST = 'FOLLOW_REQUESTS_FETCH_REQUEST';
|
||||
export const FOLLOW_REQUESTS_FETCH_SUCCESS = 'FOLLOW_REQUESTS_FETCH_SUCCESS';
|
||||
export const FOLLOW_REQUESTS_FETCH_FAIL = 'FOLLOW_REQUESTS_FETCH_FAIL';
|
||||
export const FOLLOW_REQUESTS_FETCH_REQUEST = "FOLLOW_REQUESTS_FETCH_REQUEST";
|
||||
export const FOLLOW_REQUESTS_FETCH_SUCCESS = "FOLLOW_REQUESTS_FETCH_SUCCESS";
|
||||
export const FOLLOW_REQUESTS_FETCH_FAIL = "FOLLOW_REQUESTS_FETCH_FAIL";
|
||||
|
||||
export const FOLLOW_REQUESTS_EXPAND_REQUEST = 'FOLLOW_REQUESTS_EXPAND_REQUEST';
|
||||
export const FOLLOW_REQUESTS_EXPAND_SUCCESS = 'FOLLOW_REQUESTS_EXPAND_SUCCESS';
|
||||
export const FOLLOW_REQUESTS_EXPAND_FAIL = 'FOLLOW_REQUESTS_EXPAND_FAIL';
|
||||
export const FOLLOW_REQUESTS_EXPAND_REQUEST = "FOLLOW_REQUESTS_EXPAND_REQUEST";
|
||||
export const FOLLOW_REQUESTS_EXPAND_SUCCESS = "FOLLOW_REQUESTS_EXPAND_SUCCESS";
|
||||
export const FOLLOW_REQUESTS_EXPAND_FAIL = "FOLLOW_REQUESTS_EXPAND_FAIL";
|
||||
|
||||
export const FOLLOW_REQUEST_AUTHORIZE_REQUEST = 'FOLLOW_REQUEST_AUTHORIZE_REQUEST';
|
||||
export const FOLLOW_REQUEST_AUTHORIZE_SUCCESS = 'FOLLOW_REQUEST_AUTHORIZE_SUCCESS';
|
||||
export const FOLLOW_REQUEST_AUTHORIZE_FAIL = 'FOLLOW_REQUEST_AUTHORIZE_FAIL';
|
||||
export const FOLLOW_REQUEST_AUTHORIZE_REQUEST = "FOLLOW_REQUEST_AUTHORIZE_REQUEST";
|
||||
export const FOLLOW_REQUEST_AUTHORIZE_SUCCESS = "FOLLOW_REQUEST_AUTHORIZE_SUCCESS";
|
||||
export const FOLLOW_REQUEST_AUTHORIZE_FAIL = "FOLLOW_REQUEST_AUTHORIZE_FAIL";
|
||||
|
||||
export const FOLLOW_REQUEST_REJECT_REQUEST = 'FOLLOW_REQUEST_REJECT_REQUEST';
|
||||
export const FOLLOW_REQUEST_REJECT_SUCCESS = 'FOLLOW_REQUEST_REJECT_SUCCESS';
|
||||
export const FOLLOW_REQUEST_REJECT_FAIL = 'FOLLOW_REQUEST_REJECT_FAIL';
|
||||
export const FOLLOW_REQUEST_REJECT_REQUEST = "FOLLOW_REQUEST_REJECT_REQUEST";
|
||||
export const FOLLOW_REQUEST_REJECT_SUCCESS = "FOLLOW_REQUEST_REJECT_SUCCESS";
|
||||
export const FOLLOW_REQUEST_REJECT_FAIL = "FOLLOW_REQUEST_REJECT_FAIL";
|
||||
|
||||
export const ACCOUNT_REVEAL = 'ACCOUNT_REVEAL';
|
||||
export const ACCOUNT_REVEAL = "ACCOUNT_REVEAL";
|
||||
|
||||
export function fetchAccount(id) {
|
||||
return (dispatch, getState) => {
|
||||
@@ -97,7 +97,7 @@ export function fetchAccount(id) {
|
||||
export const lookupAccount = acct => (dispatch, getState) => {
|
||||
dispatch(lookupAccountRequest(acct));
|
||||
|
||||
api(getState).get('/api/v1/accounts/lookup', { params: { acct } }).then(response => {
|
||||
api(getState).get("/api/v1/accounts/lookup", { params: { acct } }).then(response => {
|
||||
dispatch(fetchRelationships([response.data.id]));
|
||||
dispatch(importFetchedAccount(response.data));
|
||||
dispatch(lookupAccountSuccess());
|
||||
@@ -146,8 +146,8 @@ export function fetchAccountFail(id, error) {
|
||||
|
||||
export function followAccount(id, options = { reblogs: true }) {
|
||||
return (dispatch, getState) => {
|
||||
const alreadyFollowing = getState().getIn(['relationships', id, 'following']);
|
||||
const locked = getState().getIn(['accounts', id, 'locked'], false);
|
||||
const alreadyFollowing = getState().getIn(["relationships", id, "following"]);
|
||||
const locked = getState().getIn(["accounts", id, "locked"], false);
|
||||
|
||||
dispatch(followAccountRequest(id, locked));
|
||||
|
||||
@@ -164,7 +164,7 @@ export function unfollowAccount(id) {
|
||||
dispatch(unfollowAccountRequest(id));
|
||||
|
||||
api(getState).post(`/api/v1/accounts/${id}/unfollow`).then(response => {
|
||||
dispatch(unfollowAccountSuccess(response.data, getState().get('statuses')));
|
||||
dispatch(unfollowAccountSuccess(response.data, getState().get("statuses")));
|
||||
}).catch(error => {
|
||||
dispatch(unfollowAccountFail(error));
|
||||
});
|
||||
@@ -229,7 +229,7 @@ export function blockAccount(id) {
|
||||
|
||||
api(getState).post(`/api/v1/accounts/${id}/block`).then(response => {
|
||||
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
|
||||
dispatch(blockAccountSuccess(response.data, getState().get('statuses')));
|
||||
dispatch(blockAccountSuccess(response.data, getState().get("statuses")));
|
||||
}).catch(error => {
|
||||
dispatch(blockAccountFail(id, error));
|
||||
});
|
||||
@@ -298,7 +298,7 @@ export function muteAccount(id, notifications, duration=0) {
|
||||
|
||||
api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications, duration }).then(response => {
|
||||
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
|
||||
dispatch(muteAccountSuccess(response.data, getState().get('statuses')));
|
||||
dispatch(muteAccountSuccess(response.data, getState().get("statuses")));
|
||||
}).catch(error => {
|
||||
dispatch(muteAccountFail(id, error));
|
||||
});
|
||||
@@ -366,7 +366,7 @@ export function fetchFollowers(id) {
|
||||
dispatch(fetchFollowersRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchFollowersSuccess(id, response.data, next ? next.uri : null));
|
||||
@@ -404,7 +404,7 @@ export function fetchFollowersFail(id, error) {
|
||||
|
||||
export function expandFollowers(id) {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['user_lists', 'followers', id, 'next']);
|
||||
const url = getState().getIn(["user_lists", "followers", id, "next"]);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
@@ -413,7 +413,7 @@ export function expandFollowers(id) {
|
||||
dispatch(expandFollowersRequest(id));
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandFollowersSuccess(id, response.data, next ? next.uri : null));
|
||||
@@ -453,7 +453,7 @@ export function fetchFollowing(id) {
|
||||
dispatch(fetchFollowingRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/accounts/${id}/following`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchFollowingSuccess(id, response.data, next ? next.uri : null));
|
||||
@@ -491,7 +491,7 @@ export function fetchFollowingFail(id, error) {
|
||||
|
||||
export function expandFollowing(id) {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['user_lists', 'following', id, 'next']);
|
||||
const url = getState().getIn(["user_lists", "following", id, "next"]);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
@@ -500,7 +500,7 @@ export function expandFollowing(id) {
|
||||
dispatch(expandFollowingRequest(id));
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandFollowingSuccess(id, response.data, next ? next.uri : null));
|
||||
@@ -538,9 +538,9 @@ export function expandFollowingFail(id, error) {
|
||||
export function fetchRelationships(accountIds) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const loadedRelationships = state.get('relationships');
|
||||
const loadedRelationships = state.get("relationships");
|
||||
const newAccountIds = accountIds.filter(id => loadedRelationships.get(id, null) === null);
|
||||
const signedIn = !!state.getIn(['meta', 'me']);
|
||||
const signedIn = !!state.getIn(["meta", "me"]);
|
||||
|
||||
if (!signedIn || newAccountIds.length === 0) {
|
||||
return;
|
||||
@@ -548,7 +548,7 @@ export function fetchRelationships(accountIds) {
|
||||
|
||||
dispatch(fetchRelationshipsRequest(newAccountIds));
|
||||
|
||||
api(getState).get(`/api/v1/accounts/relationships?${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => {
|
||||
api(getState).get(`/api/v1/accounts/relationships?${newAccountIds.map(id => `id[]=${id}`).join("&")}`).then(response => {
|
||||
dispatch(fetchRelationshipsSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchRelationshipsFail(error));
|
||||
@@ -585,8 +585,8 @@ export function fetchFollowRequests() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchFollowRequestsRequest());
|
||||
|
||||
api(getState).get('/api/v1/follow_requests').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
api(getState).get("/api/v1/follow_requests").then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => dispatch(fetchFollowRequestsFail(error)));
|
||||
@@ -616,7 +616,7 @@ export function fetchFollowRequestsFail(error) {
|
||||
|
||||
export function expandFollowRequests() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['user_lists', 'follow_requests', 'next']);
|
||||
const url = getState().getIn(["user_lists", "follow_requests", "next"]);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
@@ -625,7 +625,7 @@ export function expandFollowRequests() {
|
||||
dispatch(expandFollowRequestsRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => dispatch(expandFollowRequestsFail(error)));
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { defineMessages } from 'react-intl';
|
||||
import { defineMessages } from "react-intl";
|
||||
|
||||
const messages = defineMessages({
|
||||
unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },
|
||||
unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },
|
||||
rateLimitedTitle: { id: 'alert.rate_limited.title', defaultMessage: 'Rate limited' },
|
||||
rateLimitedMessage: { id: 'alert.rate_limited.message', defaultMessage: 'Please retry after {retry_time, time, medium}.' },
|
||||
unexpectedTitle: { id: "alert.unexpected.title", defaultMessage: "Oops!" },
|
||||
unexpectedMessage: { id: "alert.unexpected.message", defaultMessage: "An unexpected error occurred." },
|
||||
rateLimitedTitle: { id: "alert.rate_limited.title", defaultMessage: "Rate limited" },
|
||||
rateLimitedMessage: { id: "alert.rate_limited.message", defaultMessage: "Please retry after {retry_time, time, medium}." },
|
||||
});
|
||||
|
||||
export const ALERT_SHOW = 'ALERT_SHOW';
|
||||
export const ALERT_DISMISS = 'ALERT_DISMISS';
|
||||
export const ALERT_CLEAR = 'ALERT_CLEAR';
|
||||
export const ALERT_NOOP = 'ALERT_NOOP';
|
||||
export const ALERT_SHOW = "ALERT_SHOW";
|
||||
export const ALERT_DISMISS = "ALERT_DISMISS";
|
||||
export const ALERT_CLEAR = "ALERT_CLEAR";
|
||||
export const ALERT_NOOP = "ALERT_NOOP";
|
||||
|
||||
export const dismissAlert = alert => ({
|
||||
type: ALERT_DISMISS,
|
||||
@@ -36,11 +36,11 @@ export const showAlertForError = (error, skipNotFound = false) => {
|
||||
}
|
||||
|
||||
// Rate limit errors
|
||||
if (status === 429 && headers['x-ratelimit-reset']) {
|
||||
if (status === 429 && headers["x-ratelimit-reset"]) {
|
||||
return showAlert({
|
||||
title: messages.rateLimitedTitle,
|
||||
message: messages.rateLimitedMessage,
|
||||
values: { 'retry_time': new Date(headers['x-ratelimit-reset']) },
|
||||
values: { "retry_time": new Date(headers["x-ratelimit-reset"]) },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { normalizeAnnouncement } from './importer/normalizer';
|
||||
import { normalizeAnnouncement } from "./importer/normalizer";
|
||||
|
||||
export const ANNOUNCEMENTS_FETCH_REQUEST = 'ANNOUNCEMENTS_FETCH_REQUEST';
|
||||
export const ANNOUNCEMENTS_FETCH_SUCCESS = 'ANNOUNCEMENTS_FETCH_SUCCESS';
|
||||
export const ANNOUNCEMENTS_FETCH_FAIL = 'ANNOUNCEMENTS_FETCH_FAIL';
|
||||
export const ANNOUNCEMENTS_UPDATE = 'ANNOUNCEMENTS_UPDATE';
|
||||
export const ANNOUNCEMENTS_DELETE = 'ANNOUNCEMENTS_DELETE';
|
||||
export const ANNOUNCEMENTS_FETCH_REQUEST = "ANNOUNCEMENTS_FETCH_REQUEST";
|
||||
export const ANNOUNCEMENTS_FETCH_SUCCESS = "ANNOUNCEMENTS_FETCH_SUCCESS";
|
||||
export const ANNOUNCEMENTS_FETCH_FAIL = "ANNOUNCEMENTS_FETCH_FAIL";
|
||||
export const ANNOUNCEMENTS_UPDATE = "ANNOUNCEMENTS_UPDATE";
|
||||
export const ANNOUNCEMENTS_DELETE = "ANNOUNCEMENTS_DELETE";
|
||||
|
||||
export const ANNOUNCEMENTS_DISMISS_REQUEST = 'ANNOUNCEMENTS_DISMISS_REQUEST';
|
||||
export const ANNOUNCEMENTS_DISMISS_SUCCESS = 'ANNOUNCEMENTS_DISMISS_SUCCESS';
|
||||
export const ANNOUNCEMENTS_DISMISS_FAIL = 'ANNOUNCEMENTS_DISMISS_FAIL';
|
||||
export const ANNOUNCEMENTS_DISMISS_REQUEST = "ANNOUNCEMENTS_DISMISS_REQUEST";
|
||||
export const ANNOUNCEMENTS_DISMISS_SUCCESS = "ANNOUNCEMENTS_DISMISS_SUCCESS";
|
||||
export const ANNOUNCEMENTS_DISMISS_FAIL = "ANNOUNCEMENTS_DISMISS_FAIL";
|
||||
|
||||
export const ANNOUNCEMENTS_REACTION_ADD_REQUEST = 'ANNOUNCEMENTS_REACTION_ADD_REQUEST';
|
||||
export const ANNOUNCEMENTS_REACTION_ADD_SUCCESS = 'ANNOUNCEMENTS_REACTION_ADD_SUCCESS';
|
||||
export const ANNOUNCEMENTS_REACTION_ADD_FAIL = 'ANNOUNCEMENTS_REACTION_ADD_FAIL';
|
||||
export const ANNOUNCEMENTS_REACTION_ADD_REQUEST = "ANNOUNCEMENTS_REACTION_ADD_REQUEST";
|
||||
export const ANNOUNCEMENTS_REACTION_ADD_SUCCESS = "ANNOUNCEMENTS_REACTION_ADD_SUCCESS";
|
||||
export const ANNOUNCEMENTS_REACTION_ADD_FAIL = "ANNOUNCEMENTS_REACTION_ADD_FAIL";
|
||||
|
||||
export const ANNOUNCEMENTS_REACTION_REMOVE_REQUEST = 'ANNOUNCEMENTS_REACTION_REMOVE_REQUEST';
|
||||
export const ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS = 'ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS';
|
||||
export const ANNOUNCEMENTS_REACTION_REMOVE_FAIL = 'ANNOUNCEMENTS_REACTION_REMOVE_FAIL';
|
||||
export const ANNOUNCEMENTS_REACTION_REMOVE_REQUEST = "ANNOUNCEMENTS_REACTION_REMOVE_REQUEST";
|
||||
export const ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS = "ANNOUNCEMENTS_REACTION_REMOVE_SUCCESS";
|
||||
export const ANNOUNCEMENTS_REACTION_REMOVE_FAIL = "ANNOUNCEMENTS_REACTION_REMOVE_FAIL";
|
||||
|
||||
export const ANNOUNCEMENTS_REACTION_UPDATE = 'ANNOUNCEMENTS_REACTION_UPDATE';
|
||||
export const ANNOUNCEMENTS_REACTION_UPDATE = "ANNOUNCEMENTS_REACTION_UPDATE";
|
||||
|
||||
export const ANNOUNCEMENTS_TOGGLE_SHOW = 'ANNOUNCEMENTS_TOGGLE_SHOW';
|
||||
export const ANNOUNCEMENTS_TOGGLE_SHOW = "ANNOUNCEMENTS_TOGGLE_SHOW";
|
||||
|
||||
const noOp = () => {};
|
||||
|
||||
export const fetchAnnouncements = (done = noOp) => (dispatch, getState) => {
|
||||
dispatch(fetchAnnouncementsRequest());
|
||||
|
||||
api(getState).get('/api/v1/announcements').then(response => {
|
||||
api(getState).get("/api/v1/announcements").then(response => {
|
||||
dispatch(fetchAnnouncementsSuccess(response.data.map(x => normalizeAnnouncement(x))));
|
||||
}).catch(error => {
|
||||
dispatch(fetchAnnouncementsFail(error));
|
||||
@@ -88,13 +88,13 @@ export const dismissAnnouncementFail = (announcementId, error) => ({
|
||||
});
|
||||
|
||||
export const addReaction = (announcementId, name) => (dispatch, getState) => {
|
||||
const announcement = getState().getIn(['announcements', 'items']).find(x => x.get('id') === announcementId);
|
||||
const announcement = getState().getIn(["announcements", "items"]).find(x => x.get("id") === announcementId);
|
||||
|
||||
let alreadyAdded = false;
|
||||
|
||||
if (announcement) {
|
||||
const reaction = announcement.get('reactions').find(x => x.get('name') === name);
|
||||
if (reaction && reaction.get('me')) {
|
||||
const reaction = announcement.get("reactions").find(x => x.get("name") === name);
|
||||
if (reaction && reaction.get("me")) {
|
||||
alreadyAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import { createAction } from "@reduxjs/toolkit";
|
||||
|
||||
import type { LayoutType } from '../is_mobile';
|
||||
import { type LayoutType } from "../is_mobile";
|
||||
|
||||
export const focusApp = createAction('APP_FOCUS');
|
||||
export const unfocusApp = createAction('APP_UNFOCUS');
|
||||
export const focusApp = createAction("APP_FOCUS");
|
||||
export const unfocusApp = createAction("APP_UNFOCUS");
|
||||
|
||||
interface ChangeLayoutPayload {
|
||||
layout: LayoutType;
|
||||
layout: LayoutType,
|
||||
}
|
||||
export const changeLayout =
|
||||
createAction<ChangeLayoutPayload>('APP_LAYOUT_CHANGE');
|
||||
createAction<ChangeLayoutPayload>("APP_LAYOUT_CHANGE");
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { openModal } from './modal';
|
||||
import { fetchRelationships } from "./accounts";
|
||||
import { importFetchedAccounts } from "./importer";
|
||||
import { openModal } from "./modal";
|
||||
|
||||
export const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST';
|
||||
export const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS';
|
||||
export const BLOCKS_FETCH_FAIL = 'BLOCKS_FETCH_FAIL';
|
||||
export const BLOCKS_FETCH_REQUEST = "BLOCKS_FETCH_REQUEST";
|
||||
export const BLOCKS_FETCH_SUCCESS = "BLOCKS_FETCH_SUCCESS";
|
||||
export const BLOCKS_FETCH_FAIL = "BLOCKS_FETCH_FAIL";
|
||||
|
||||
export const BLOCKS_EXPAND_REQUEST = 'BLOCKS_EXPAND_REQUEST';
|
||||
export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS';
|
||||
export const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL';
|
||||
export const BLOCKS_EXPAND_REQUEST = "BLOCKS_EXPAND_REQUEST";
|
||||
export const BLOCKS_EXPAND_SUCCESS = "BLOCKS_EXPAND_SUCCESS";
|
||||
export const BLOCKS_EXPAND_FAIL = "BLOCKS_EXPAND_FAIL";
|
||||
|
||||
export const BLOCKS_INIT_MODAL = 'BLOCKS_INIT_MODAL';
|
||||
export const BLOCKS_INIT_MODAL = "BLOCKS_INIT_MODAL";
|
||||
|
||||
export function fetchBlocks() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchBlocksRequest());
|
||||
|
||||
api(getState).get('/api/v1/blocks').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
api(getState).get("/api/v1/blocks").then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
@@ -50,7 +50,7 @@ export function fetchBlocksFail(error) {
|
||||
|
||||
export function expandBlocks() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['user_lists', 'blocks', 'next']);
|
||||
const url = getState().getIn(["user_lists", "blocks", "next"]);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
@@ -59,7 +59,7 @@ export function expandBlocks() {
|
||||
dispatch(expandBlocksRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandBlocksSuccess(response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
@@ -95,6 +95,6 @@ export function initBlockModal(account) {
|
||||
account,
|
||||
});
|
||||
|
||||
dispatch(openModal({ modalType: 'BLOCK' }));
|
||||
dispatch(openModal({ modalType: "BLOCK" }));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
import { importFetchedStatuses } from "./importer";
|
||||
|
||||
export const BOOKMARKED_STATUSES_FETCH_REQUEST = 'BOOKMARKED_STATUSES_FETCH_REQUEST';
|
||||
export const BOOKMARKED_STATUSES_FETCH_SUCCESS = 'BOOKMARKED_STATUSES_FETCH_SUCCESS';
|
||||
export const BOOKMARKED_STATUSES_FETCH_FAIL = 'BOOKMARKED_STATUSES_FETCH_FAIL';
|
||||
export const BOOKMARKED_STATUSES_FETCH_REQUEST = "BOOKMARKED_STATUSES_FETCH_REQUEST";
|
||||
export const BOOKMARKED_STATUSES_FETCH_SUCCESS = "BOOKMARKED_STATUSES_FETCH_SUCCESS";
|
||||
export const BOOKMARKED_STATUSES_FETCH_FAIL = "BOOKMARKED_STATUSES_FETCH_FAIL";
|
||||
|
||||
export const BOOKMARKED_STATUSES_EXPAND_REQUEST = 'BOOKMARKED_STATUSES_EXPAND_REQUEST';
|
||||
export const BOOKMARKED_STATUSES_EXPAND_SUCCESS = 'BOOKMARKED_STATUSES_EXPAND_SUCCESS';
|
||||
export const BOOKMARKED_STATUSES_EXPAND_FAIL = 'BOOKMARKED_STATUSES_EXPAND_FAIL';
|
||||
export const BOOKMARKED_STATUSES_EXPAND_REQUEST = "BOOKMARKED_STATUSES_EXPAND_REQUEST";
|
||||
export const BOOKMARKED_STATUSES_EXPAND_SUCCESS = "BOOKMARKED_STATUSES_EXPAND_SUCCESS";
|
||||
export const BOOKMARKED_STATUSES_EXPAND_FAIL = "BOOKMARKED_STATUSES_EXPAND_FAIL";
|
||||
|
||||
export function fetchBookmarkedStatuses() {
|
||||
return (dispatch, getState) => {
|
||||
if (getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) {
|
||||
if (getState().getIn(["status_lists", "bookmarks", "isLoading"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(fetchBookmarkedStatusesRequest());
|
||||
|
||||
api(getState).get('/api/v1/bookmarks').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
api(getState).get("/api/v1/bookmarks").then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedStatuses(response.data));
|
||||
dispatch(fetchBookmarkedStatusesSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => {
|
||||
@@ -51,16 +51,16 @@ export function fetchBookmarkedStatusesFail(error) {
|
||||
|
||||
export function expandBookmarkedStatuses() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['status_lists', 'bookmarks', 'next'], null);
|
||||
const url = getState().getIn(["status_lists", "bookmarks", "next"], null);
|
||||
|
||||
if (url === null || getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) {
|
||||
if (url === null || getState().getIn(["status_lists", "bookmarks", "isLoading"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(expandBookmarkedStatusesRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedStatuses(response.data));
|
||||
dispatch(expandBookmarkedStatusesSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { openModal } from './modal';
|
||||
import { openModal } from "./modal";
|
||||
|
||||
export const BOOSTS_INIT_MODAL = 'BOOSTS_INIT_MODAL';
|
||||
export const BOOSTS_CHANGE_PRIVACY = 'BOOSTS_CHANGE_PRIVACY';
|
||||
export const BOOSTS_INIT_MODAL = "BOOSTS_INIT_MODAL";
|
||||
export const BOOSTS_CHANGE_PRIVACY = "BOOSTS_CHANGE_PRIVACY";
|
||||
|
||||
export function initBoostModal(props) {
|
||||
return (dispatch, getState) => {
|
||||
const default_privacy = getState().getIn(['compose', 'default_privacy']);
|
||||
const default_privacy = getState().getIn(["compose", "default_privacy"]);
|
||||
|
||||
const privacy = props.status.get('visibility') === 'private' ? 'private' : default_privacy;
|
||||
const privacy = props.status.get("visibility") === "private" ? "private" : default_privacy;
|
||||
|
||||
dispatch({
|
||||
type: BOOSTS_INIT_MODAL,
|
||||
@@ -15,7 +15,7 @@ export function initBoostModal(props) {
|
||||
});
|
||||
|
||||
dispatch(openModal({
|
||||
modalType: 'BOOST',
|
||||
modalType: "BOOST",
|
||||
modalProps: props,
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST';
|
||||
export const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS';
|
||||
export const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL';
|
||||
export const BUNDLE_FETCH_REQUEST = "BUNDLE_FETCH_REQUEST";
|
||||
export const BUNDLE_FETCH_SUCCESS = "BUNDLE_FETCH_SUCCESS";
|
||||
export const BUNDLE_FETCH_FAIL = "BUNDLE_FETCH_FAIL";
|
||||
|
||||
export function fetchBundleRequest(skipLoading) {
|
||||
return {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { saveSettings } from './settings';
|
||||
import { saveSettings } from "./settings";
|
||||
|
||||
export const COLUMN_ADD = 'COLUMN_ADD';
|
||||
export const COLUMN_REMOVE = 'COLUMN_REMOVE';
|
||||
export const COLUMN_MOVE = 'COLUMN_MOVE';
|
||||
export const COLUMN_PARAMS_CHANGE = 'COLUMN_PARAMS_CHANGE';
|
||||
export const COLUMN_ADD = "COLUMN_ADD";
|
||||
export const COLUMN_REMOVE = "COLUMN_REMOVE";
|
||||
export const COLUMN_MOVE = "COLUMN_MOVE";
|
||||
export const COLUMN_PARAMS_CHANGE = "COLUMN_PARAMS_CHANGE";
|
||||
|
||||
export function addColumn(id, params) {
|
||||
return dispatch => {
|
||||
|
||||
@@ -1,95 +1,95 @@
|
||||
import { defineMessages } from 'react-intl';
|
||||
import { defineMessages } from "react-intl";
|
||||
|
||||
import axios from 'axios';
|
||||
import { throttle } from 'lodash';
|
||||
import axios from "axios";
|
||||
import { throttle } from "lodash";
|
||||
|
||||
import api from 'mastodon/api';
|
||||
import { search as emojiSearch } from 'mastodon/features/emoji/emoji_mart_search_light';
|
||||
import { tagHistory } from 'mastodon/settings';
|
||||
import api from "mastodon/api";
|
||||
import { search as emojiSearch } from "mastodon/features/emoji/emoji_mart_search_light";
|
||||
import { tagHistory } from "mastodon/settings";
|
||||
|
||||
import { showAlert, showAlertForError } from './alerts';
|
||||
import { useEmoji } from './emojis';
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
import { openModal } from './modal';
|
||||
import { updateTimeline } from './timelines';
|
||||
import { showAlert, showAlertForError } from "./alerts";
|
||||
import { useEmoji } from "./emojis";
|
||||
import { importFetchedAccounts, importFetchedStatus } from "./importer";
|
||||
import { openModal } from "./modal";
|
||||
import { updateTimeline } from "./timelines";
|
||||
|
||||
/** @type {AbortController | undefined} */
|
||||
let fetchComposeSuggestionsAccountsController;
|
||||
/** @type {AbortController | undefined} */
|
||||
let fetchComposeSuggestionsTagsController;
|
||||
|
||||
export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
|
||||
export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
|
||||
export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
||||
export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
|
||||
export const COMPOSE_REPLY = 'COMPOSE_REPLY';
|
||||
export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
|
||||
export const COMPOSE_DIRECT = 'COMPOSE_DIRECT';
|
||||
export const COMPOSE_MENTION = 'COMPOSE_MENTION';
|
||||
export const COMPOSE_RESET = 'COMPOSE_RESET';
|
||||
export const COMPOSE_CHANGE = "COMPOSE_CHANGE";
|
||||
export const COMPOSE_SUBMIT_REQUEST = "COMPOSE_SUBMIT_REQUEST";
|
||||
export const COMPOSE_SUBMIT_SUCCESS = "COMPOSE_SUBMIT_SUCCESS";
|
||||
export const COMPOSE_SUBMIT_FAIL = "COMPOSE_SUBMIT_FAIL";
|
||||
export const COMPOSE_REPLY = "COMPOSE_REPLY";
|
||||
export const COMPOSE_REPLY_CANCEL = "COMPOSE_REPLY_CANCEL";
|
||||
export const COMPOSE_DIRECT = "COMPOSE_DIRECT";
|
||||
export const COMPOSE_MENTION = "COMPOSE_MENTION";
|
||||
export const COMPOSE_RESET = "COMPOSE_RESET";
|
||||
|
||||
export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
|
||||
export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS';
|
||||
export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL';
|
||||
export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS';
|
||||
export const COMPOSE_UPLOAD_PROCESSING = 'COMPOSE_UPLOAD_PROCESSING';
|
||||
export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO';
|
||||
export const COMPOSE_UPLOAD_REQUEST = "COMPOSE_UPLOAD_REQUEST";
|
||||
export const COMPOSE_UPLOAD_SUCCESS = "COMPOSE_UPLOAD_SUCCESS";
|
||||
export const COMPOSE_UPLOAD_FAIL = "COMPOSE_UPLOAD_FAIL";
|
||||
export const COMPOSE_UPLOAD_PROGRESS = "COMPOSE_UPLOAD_PROGRESS";
|
||||
export const COMPOSE_UPLOAD_PROCESSING = "COMPOSE_UPLOAD_PROCESSING";
|
||||
export const COMPOSE_UPLOAD_UNDO = "COMPOSE_UPLOAD_UNDO";
|
||||
|
||||
export const THUMBNAIL_UPLOAD_REQUEST = 'THUMBNAIL_UPLOAD_REQUEST';
|
||||
export const THUMBNAIL_UPLOAD_SUCCESS = 'THUMBNAIL_UPLOAD_SUCCESS';
|
||||
export const THUMBNAIL_UPLOAD_FAIL = 'THUMBNAIL_UPLOAD_FAIL';
|
||||
export const THUMBNAIL_UPLOAD_PROGRESS = 'THUMBNAIL_UPLOAD_PROGRESS';
|
||||
export const THUMBNAIL_UPLOAD_REQUEST = "THUMBNAIL_UPLOAD_REQUEST";
|
||||
export const THUMBNAIL_UPLOAD_SUCCESS = "THUMBNAIL_UPLOAD_SUCCESS";
|
||||
export const THUMBNAIL_UPLOAD_FAIL = "THUMBNAIL_UPLOAD_FAIL";
|
||||
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_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';
|
||||
export const COMPOSE_TAG_HISTORY_UPDATE = "COMPOSE_TAG_HISTORY_UPDATE";
|
||||
|
||||
export const COMPOSE_MOUNT = 'COMPOSE_MOUNT';
|
||||
export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT';
|
||||
export const COMPOSE_MOUNT = "COMPOSE_MOUNT";
|
||||
export const COMPOSE_UNMOUNT = "COMPOSE_UNMOUNT";
|
||||
|
||||
export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE';
|
||||
export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE';
|
||||
export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
|
||||
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
||||
export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE';
|
||||
export const COMPOSE_LANGUAGE_CHANGE = 'COMPOSE_LANGUAGE_CHANGE';
|
||||
export const COMPOSE_SENSITIVITY_CHANGE = "COMPOSE_SENSITIVITY_CHANGE";
|
||||
export const COMPOSE_SPOILERNESS_CHANGE = "COMPOSE_SPOILERNESS_CHANGE";
|
||||
export const COMPOSE_SPOILER_TEXT_CHANGE = "COMPOSE_SPOILER_TEXT_CHANGE";
|
||||
export const COMPOSE_VISIBILITY_CHANGE = "COMPOSE_VISIBILITY_CHANGE";
|
||||
export const COMPOSE_COMPOSING_CHANGE = "COMPOSE_COMPOSING_CHANGE";
|
||||
export const COMPOSE_LANGUAGE_CHANGE = "COMPOSE_LANGUAGE_CHANGE";
|
||||
|
||||
export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
|
||||
export const COMPOSE_EMOJI_INSERT = "COMPOSE_EMOJI_INSERT";
|
||||
|
||||
export const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST';
|
||||
export const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS';
|
||||
export const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL';
|
||||
export const COMPOSE_UPLOAD_CHANGE_REQUEST = "COMPOSE_UPLOAD_UPDATE_REQUEST";
|
||||
export const COMPOSE_UPLOAD_CHANGE_SUCCESS = "COMPOSE_UPLOAD_UPDATE_SUCCESS";
|
||||
export const COMPOSE_UPLOAD_CHANGE_FAIL = "COMPOSE_UPLOAD_UPDATE_FAIL";
|
||||
|
||||
export const COMPOSE_POLL_ADD = 'COMPOSE_POLL_ADD';
|
||||
export const COMPOSE_POLL_REMOVE = 'COMPOSE_POLL_REMOVE';
|
||||
export const COMPOSE_POLL_OPTION_ADD = 'COMPOSE_POLL_OPTION_ADD';
|
||||
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 COMPOSE_POLL_ADD = "COMPOSE_POLL_ADD";
|
||||
export const COMPOSE_POLL_REMOVE = "COMPOSE_POLL_REMOVE";
|
||||
export const COMPOSE_POLL_OPTION_ADD = "COMPOSE_POLL_OPTION_ADD";
|
||||
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 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';
|
||||
export const COMPOSE_CHANGE_MEDIA_DESCRIPTION = "COMPOSE_CHANGE_MEDIA_DESCRIPTION";
|
||||
export const COMPOSE_CHANGE_MEDIA_FOCUS = "COMPOSE_CHANGE_MEDIA_FOCUS";
|
||||
|
||||
export const COMPOSE_SET_STATUS = 'COMPOSE_SET_STATUS';
|
||||
export const COMPOSE_FOCUS = 'COMPOSE_FOCUS';
|
||||
export const COMPOSE_SET_STATUS = "COMPOSE_SET_STATUS";
|
||||
export const COMPOSE_FOCUS = "COMPOSE_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.' },
|
||||
open: { id: 'compose.published.open', defaultMessage: 'Open' },
|
||||
published: { id: 'compose.published.body', defaultMessage: 'Post published.' },
|
||||
saved: { id: 'compose.saved.body', defaultMessage: 'Post saved.' },
|
||||
uploadErrorLimit: { id: "upload_error.limit", defaultMessage: "File upload limit exceeded." },
|
||||
uploadErrorPoll: { id: "upload_error.poll", defaultMessage: "File upload not allowed with polls." },
|
||||
open: { id: "compose.published.open", defaultMessage: "Open" },
|
||||
published: { id: "compose.published.body", defaultMessage: "Post published." },
|
||||
saved: { id: "compose.saved.body", defaultMessage: "Post saved." },
|
||||
});
|
||||
|
||||
export const ensureComposeIsVisible = (getState, routerHistory) => {
|
||||
if (!getState().getIn(['compose', 'mounted'])) {
|
||||
routerHistory.push('/publish');
|
||||
if (!getState().getIn(["compose", "mounted"])) {
|
||||
routerHistory.push("/publish");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -165,9 +165,9 @@ export function directCompose(account, routerHistory) {
|
||||
|
||||
export function submitCompose(routerHistory) {
|
||||
return function (dispatch, getState) {
|
||||
const status = getState().getIn(['compose', 'text'], '');
|
||||
const media = getState().getIn(['compose', 'media_attachments']);
|
||||
const statusId = getState().getIn(['compose', 'id'], null);
|
||||
const status = getState().getIn(["compose", "text"], "");
|
||||
const media = getState().getIn(["compose", "media_attachments"]);
|
||||
const statusId = getState().getIn(["compose", "id"], null);
|
||||
|
||||
if ((!status || !status.length) && media.size === 0) {
|
||||
return;
|
||||
@@ -183,37 +183,37 @@ export function submitCompose(routerHistory) {
|
||||
media_attributes = media.map(item => {
|
||||
let focus;
|
||||
|
||||
if (item.getIn(['meta', 'focus'])) {
|
||||
focus = `${item.getIn(['meta', 'focus', 'x']).toFixed(2)},${item.getIn(['meta', 'focus', 'y']).toFixed(2)}`;
|
||||
if (item.getIn(["meta", "focus"])) {
|
||||
focus = `${item.getIn(["meta", "focus", "x"]).toFixed(2)},${item.getIn(["meta", "focus", "y"]).toFixed(2)}`;
|
||||
}
|
||||
|
||||
return {
|
||||
id: item.get('id'),
|
||||
description: item.get('description'),
|
||||
id: item.get("id"),
|
||||
description: item.get("description"),
|
||||
focus,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
api(getState).request({
|
||||
url: statusId === null ? '/api/v1/statuses' : `/api/v1/statuses/${statusId}`,
|
||||
method: statusId === null ? 'post' : 'put',
|
||||
url: statusId === null ? "/api/v1/statuses" : `/api/v1/statuses/${statusId}`,
|
||||
method: statusId === null ? "post" : "put",
|
||||
data: {
|
||||
status,
|
||||
in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
|
||||
media_ids: media.map(item => item.get('id')),
|
||||
in_reply_to_id: getState().getIn(["compose", "in_reply_to"], null),
|
||||
media_ids: media.map(item => item.get("id")),
|
||||
media_attributes,
|
||||
sensitive: getState().getIn(['compose', 'sensitive']),
|
||||
spoiler_text: getState().getIn(['compose', 'spoiler']) ? getState().getIn(['compose', 'spoiler_text'], '') : '',
|
||||
visibility: getState().getIn(['compose', 'privacy']),
|
||||
poll: getState().getIn(['compose', 'poll'], null),
|
||||
language: getState().getIn(['compose', 'language']),
|
||||
sensitive: getState().getIn(["compose", "sensitive"]),
|
||||
spoiler_text: getState().getIn(["compose", "spoiler"]) ? getState().getIn(["compose", "spoiler_text"], "") : "",
|
||||
visibility: getState().getIn(["compose", "privacy"]),
|
||||
poll: getState().getIn(["compose", "poll"], null),
|
||||
language: getState().getIn(["compose", "language"]),
|
||||
},
|
||||
headers: {
|
||||
'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),
|
||||
"Idempotency-Key": getState().getIn(["compose", "idempotencyKey"]),
|
||||
},
|
||||
}).then(function (response) {
|
||||
if (routerHistory && (routerHistory.location.pathname === '/publish' || routerHistory.location.pathname === '/statuses/new') && window.history.state) {
|
||||
if (routerHistory && (routerHistory.location.pathname === "/publish" || routerHistory.location.pathname === "/statuses/new") && window.history.state) {
|
||||
routerHistory.goBack();
|
||||
}
|
||||
|
||||
@@ -223,9 +223,9 @@ export function submitCompose(routerHistory) {
|
||||
// To make the app more responsive, immediately push the status
|
||||
// into the columns
|
||||
const insertIfOnline = timelineId => {
|
||||
const timeline = getState().getIn(['timelines', timelineId]);
|
||||
const timeline = getState().getIn(["timelines", timelineId]);
|
||||
|
||||
if (timeline && timeline.get('items').size > 0 && timeline.getIn(['items', 0]) !== null && timeline.get('online')) {
|
||||
if (timeline && timeline.get("items").size > 0 && timeline.getIn(["items", 0]) !== null && timeline.get("online")) {
|
||||
dispatch(updateTimeline(timelineId, { ...response.data }));
|
||||
}
|
||||
};
|
||||
@@ -234,14 +234,14 @@ export function submitCompose(routerHistory) {
|
||||
dispatch(importFetchedStatus({ ...response.data }));
|
||||
}
|
||||
|
||||
if (statusId === null && response.data.visibility !== 'direct') {
|
||||
insertIfOnline('home');
|
||||
if (statusId === null && response.data.visibility !== "direct") {
|
||||
insertIfOnline("home");
|
||||
}
|
||||
|
||||
if (statusId === null && response.data.in_reply_to_id === null && response.data.visibility === 'public') {
|
||||
insertIfOnline('community');
|
||||
if (statusId === null && response.data.in_reply_to_id === null && response.data.visibility === "public") {
|
||||
insertIfOnline("community");
|
||||
if (!response.data.local_only) {
|
||||
insertIfOnline('public');
|
||||
insertIfOnline("public");
|
||||
}
|
||||
insertIfOnline(`account:${response.data.account.id}`);
|
||||
}
|
||||
@@ -281,8 +281,8 @@ export function submitComposeFail(error) {
|
||||
export function uploadCompose(files) {
|
||||
return function (dispatch, getState) {
|
||||
const uploadLimit = 4;
|
||||
const media = getState().getIn(['compose', 'media_attachments']);
|
||||
const pending = getState().getIn(['compose', 'pending_media_attachments']);
|
||||
const media = getState().getIn(["compose", "media_attachments"]);
|
||||
const pending = getState().getIn(["compose", "pending_media_attachments"]);
|
||||
const progress = new Array(files.length).fill(0);
|
||||
|
||||
let total = Array.from(files).reduce((a, v) => a + v.size, 0);
|
||||
@@ -292,7 +292,7 @@ export function uploadCompose(files) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getState().getIn(['compose', 'poll'])) {
|
||||
if (getState().getIn(["compose", "poll"])) {
|
||||
dispatch(showAlert({ message: messages.uploadErrorPoll }));
|
||||
return;
|
||||
}
|
||||
@@ -300,12 +300,14 @@ export function uploadCompose(files) {
|
||||
dispatch(uploadComposeRequest());
|
||||
|
||||
for (const [i, file] of Array.from(files).entries()) {
|
||||
if (media.size + i > 3) break;
|
||||
if (media.size + i > 3) {
|
||||
break;
|
||||
}
|
||||
|
||||
const data = new FormData();
|
||||
data.append('file', file);
|
||||
data.append("file", file);
|
||||
|
||||
api(getState).post('/api/v2/media', data, {
|
||||
api(getState).post("/api/v2/media", data, {
|
||||
onUploadProgress: function({ loaded }){
|
||||
progress[i] = loaded;
|
||||
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
||||
@@ -350,7 +352,7 @@ export const uploadThumbnail = (id, file) => (dispatch, getState) => {
|
||||
const total = file.size;
|
||||
const data = new FormData();
|
||||
|
||||
data.append('thumbnail', file);
|
||||
data.append("thumbnail", file);
|
||||
|
||||
api(getState).put(`/api/v1/media/${id}`, data, {
|
||||
onUploadProgress: ({ loaded }) => {
|
||||
@@ -395,7 +397,7 @@ export function initMediaEditModal(id) {
|
||||
});
|
||||
|
||||
dispatch(openModal({
|
||||
modalType: 'FOCAL_POINT',
|
||||
modalType: "FOCAL_POINT",
|
||||
modalProps: { id },
|
||||
}));
|
||||
};
|
||||
@@ -420,16 +422,16 @@ export function changeUploadCompose(id, params) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(changeUploadComposeRequest());
|
||||
|
||||
let media = getState().getIn(['compose', 'media_attachments']).find((item) => item.get('id') === id);
|
||||
let media = getState().getIn(["compose", "media_attachments"]).find((item) => item.get("id") === id);
|
||||
|
||||
// Editing already-attached media is deferred to editing the post itself.
|
||||
// For simplicity's sake, fake an API reply.
|
||||
if (media && !media.get('unattached')) {
|
||||
if (media && !media.get("unattached")) {
|
||||
const { focus, ...other } = params;
|
||||
const data = { ...media.toJS(), ...other };
|
||||
|
||||
if (focus) {
|
||||
const [x, y] = focus.split(',');
|
||||
const [x, y] = focus.split(",");
|
||||
data.meta = { focus: { x: parseFloat(x), y: parseFloat(y) } };
|
||||
}
|
||||
|
||||
@@ -523,7 +525,7 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) =>
|
||||
|
||||
fetchComposeSuggestionsAccountsController = new AbortController();
|
||||
|
||||
api(getState).get('/api/v1/accounts/search', {
|
||||
api(getState).get("/api/v1/accounts/search", {
|
||||
signal: fetchComposeSuggestionsAccountsController.signal,
|
||||
|
||||
params: {
|
||||
@@ -544,7 +546,7 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) =>
|
||||
}, 200, { leading: true, trailing: true });
|
||||
|
||||
const fetchComposeSuggestionsEmojis = (dispatch, getState, token) => {
|
||||
const results = emojiSearch(token.replace(':', ''), { maxResults: 5 });
|
||||
const results = emojiSearch(token.replace(":", ""), { maxResults: 5 });
|
||||
dispatch(readyComposeSuggestionsEmojis(token, results));
|
||||
};
|
||||
|
||||
@@ -557,11 +559,11 @@ const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => {
|
||||
|
||||
fetchComposeSuggestionsTagsController = new AbortController();
|
||||
|
||||
api(getState).get('/api/v2/search', {
|
||||
api(getState).get("/api/v2/search", {
|
||||
signal: fetchComposeSuggestionsTagsController.signal,
|
||||
|
||||
params: {
|
||||
type: 'hashtags',
|
||||
type: "hashtags",
|
||||
q: token.slice(1),
|
||||
resolve: false,
|
||||
limit: 4,
|
||||
@@ -581,15 +583,15 @@ const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => {
|
||||
export function fetchComposeSuggestions(token) {
|
||||
return (dispatch, getState) => {
|
||||
switch (token[0]) {
|
||||
case ':':
|
||||
fetchComposeSuggestionsEmojis(dispatch, getState, token);
|
||||
break;
|
||||
case '#':
|
||||
fetchComposeSuggestionsTags(dispatch, getState, token);
|
||||
break;
|
||||
default:
|
||||
fetchComposeSuggestionsAccounts(dispatch, getState, token);
|
||||
break;
|
||||
case ":":
|
||||
fetchComposeSuggestionsEmojis(dispatch, getState, token);
|
||||
break;
|
||||
case "#":
|
||||
fetchComposeSuggestionsTags(dispatch, getState, token);
|
||||
break;
|
||||
default:
|
||||
fetchComposeSuggestionsAccounts(dispatch, getState, token);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -620,22 +622,22 @@ export function selectComposeSuggestion(position, token, suggestion, path) {
|
||||
return (dispatch, getState) => {
|
||||
let completion, startPosition;
|
||||
|
||||
if (suggestion.type === 'emoji') {
|
||||
if (suggestion.type === "emoji") {
|
||||
completion = suggestion.native || suggestion.colons;
|
||||
startPosition = position - 1;
|
||||
|
||||
dispatch(useEmoji(suggestion));
|
||||
} else if (suggestion.type === 'hashtag') {
|
||||
} else if (suggestion.type === "hashtag") {
|
||||
completion = `#${suggestion.name}`;
|
||||
startPosition = position - 1;
|
||||
} else if (suggestion.type === 'account') {
|
||||
completion = getState().getIn(['accounts', suggestion.id, 'acct']);
|
||||
} else if (suggestion.type === "account") {
|
||||
completion = getState().getIn(["accounts", suggestion.id, "acct"]);
|
||||
startPosition = position;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (suggestion.type !== "hashtag" || token.slice(1).localeCompare(suggestion.name, undefined, { sensitivity: "accent" }) !== 0) {
|
||||
dispatch({
|
||||
type: COMPOSE_SUGGESTION_SELECT,
|
||||
position: startPosition,
|
||||
@@ -671,7 +673,7 @@ export function updateTagHistory(tags) {
|
||||
|
||||
export function hydrateCompose() {
|
||||
return (dispatch, getState) => {
|
||||
const me = getState().getIn(['meta', 'me']);
|
||||
const me = getState().getIn(["meta", "me"]);
|
||||
const history = tagHistory.get(me);
|
||||
|
||||
if (history !== null) {
|
||||
@@ -683,14 +685,14 @@ export function hydrateCompose() {
|
||||
function insertIntoTagHistory(recognizedTags, text) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const oldHistory = state.getIn(['compose', 'tagHistory']);
|
||||
const me = state.getIn(['meta', 'me']);
|
||||
const oldHistory = state.getIn(["compose", "tagHistory"]);
|
||||
const me = state.getIn(["meta", "me"]);
|
||||
|
||||
// FIXME: Matching input hashtags with recognized hashtags has become more
|
||||
// complicated because of new normalization rules, it's no longer just
|
||||
// a case sensitivity issue
|
||||
const names = recognizedTags.map(tag => {
|
||||
const matches = text.match(new RegExp(`#${tag.name}`, 'i'));
|
||||
const matches = text.match(new RegExp(`#${tag.name}`, "i"));
|
||||
|
||||
if (matches && matches.length > 0) {
|
||||
return matches[0].slice(1);
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
import {
|
||||
importFetchedAccounts,
|
||||
importFetchedStatuses,
|
||||
importFetchedStatus,
|
||||
} from './importer';
|
||||
} from "./importer";
|
||||
|
||||
export const CONVERSATIONS_MOUNT = 'CONVERSATIONS_MOUNT';
|
||||
export const CONVERSATIONS_UNMOUNT = 'CONVERSATIONS_UNMOUNT';
|
||||
export const CONVERSATIONS_MOUNT = "CONVERSATIONS_MOUNT";
|
||||
export const CONVERSATIONS_UNMOUNT = "CONVERSATIONS_UNMOUNT";
|
||||
|
||||
export const CONVERSATIONS_FETCH_REQUEST = 'CONVERSATIONS_FETCH_REQUEST';
|
||||
export const CONVERSATIONS_FETCH_SUCCESS = 'CONVERSATIONS_FETCH_SUCCESS';
|
||||
export const CONVERSATIONS_FETCH_FAIL = 'CONVERSATIONS_FETCH_FAIL';
|
||||
export const CONVERSATIONS_UPDATE = 'CONVERSATIONS_UPDATE';
|
||||
export const CONVERSATIONS_FETCH_REQUEST = "CONVERSATIONS_FETCH_REQUEST";
|
||||
export const CONVERSATIONS_FETCH_SUCCESS = "CONVERSATIONS_FETCH_SUCCESS";
|
||||
export const CONVERSATIONS_FETCH_FAIL = "CONVERSATIONS_FETCH_FAIL";
|
||||
export const CONVERSATIONS_UPDATE = "CONVERSATIONS_UPDATE";
|
||||
|
||||
export const CONVERSATIONS_READ = 'CONVERSATIONS_READ';
|
||||
export const CONVERSATIONS_READ = "CONVERSATIONS_READ";
|
||||
|
||||
export const CONVERSATIONS_DELETE_REQUEST = 'CONVERSATIONS_DELETE_REQUEST';
|
||||
export const CONVERSATIONS_DELETE_SUCCESS = 'CONVERSATIONS_DELETE_SUCCESS';
|
||||
export const CONVERSATIONS_DELETE_FAIL = 'CONVERSATIONS_DELETE_FAIL';
|
||||
export const CONVERSATIONS_DELETE_REQUEST = "CONVERSATIONS_DELETE_REQUEST";
|
||||
export const CONVERSATIONS_DELETE_SUCCESS = "CONVERSATIONS_DELETE_SUCCESS";
|
||||
export const CONVERSATIONS_DELETE_FAIL = "CONVERSATIONS_DELETE_FAIL";
|
||||
|
||||
export const mountConversations = () => ({
|
||||
type: CONVERSATIONS_MOUNT,
|
||||
@@ -43,14 +43,14 @@ export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => {
|
||||
const params = { max_id: maxId };
|
||||
|
||||
if (!maxId) {
|
||||
params.since_id = getState().getIn(['conversations', 'items', 0, 'last_status']);
|
||||
params.since_id = getState().getIn(["conversations", "items", 0, "last_status"]);
|
||||
}
|
||||
|
||||
const isLoadingRecent = !!params.since_id;
|
||||
|
||||
api(getState).get('/api/v1/conversations', { params })
|
||||
api(getState).get("/api/v1/conversations", { params })
|
||||
.then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
|
||||
dispatch(importFetchedAccounts(response.data.reduce((aggr, item) => aggr.concat(item.accounts), [])));
|
||||
dispatch(importFetchedStatuses(response.data.map(item => item.last_status).filter(x => !!x)));
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
export const CUSTOM_EMOJIS_FETCH_REQUEST = 'CUSTOM_EMOJIS_FETCH_REQUEST';
|
||||
export const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS';
|
||||
export const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL';
|
||||
export const CUSTOM_EMOJIS_FETCH_REQUEST = "CUSTOM_EMOJIS_FETCH_REQUEST";
|
||||
export const CUSTOM_EMOJIS_FETCH_SUCCESS = "CUSTOM_EMOJIS_FETCH_SUCCESS";
|
||||
export const CUSTOM_EMOJIS_FETCH_FAIL = "CUSTOM_EMOJIS_FETCH_FAIL";
|
||||
|
||||
export function fetchCustomEmojis() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchCustomEmojisRequest());
|
||||
|
||||
api(getState).get('/api/v1/custom_emojis').then(response => {
|
||||
api(getState).get("/api/v1/custom_emojis").then(response => {
|
||||
dispatch(fetchCustomEmojisSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchCustomEmojisFail(error));
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { fetchRelationships } from "./accounts";
|
||||
import { importFetchedAccounts } from "./importer";
|
||||
|
||||
export const DIRECTORY_FETCH_REQUEST = 'DIRECTORY_FETCH_REQUEST';
|
||||
export const DIRECTORY_FETCH_SUCCESS = 'DIRECTORY_FETCH_SUCCESS';
|
||||
export const DIRECTORY_FETCH_FAIL = 'DIRECTORY_FETCH_FAIL';
|
||||
export const DIRECTORY_FETCH_REQUEST = "DIRECTORY_FETCH_REQUEST";
|
||||
export const DIRECTORY_FETCH_SUCCESS = "DIRECTORY_FETCH_SUCCESS";
|
||||
export const DIRECTORY_FETCH_FAIL = "DIRECTORY_FETCH_FAIL";
|
||||
|
||||
export const DIRECTORY_EXPAND_REQUEST = 'DIRECTORY_EXPAND_REQUEST';
|
||||
export const DIRECTORY_EXPAND_SUCCESS = 'DIRECTORY_EXPAND_SUCCESS';
|
||||
export const DIRECTORY_EXPAND_FAIL = 'DIRECTORY_EXPAND_FAIL';
|
||||
export const DIRECTORY_EXPAND_REQUEST = "DIRECTORY_EXPAND_REQUEST";
|
||||
export const DIRECTORY_EXPAND_SUCCESS = "DIRECTORY_EXPAND_SUCCESS";
|
||||
export const DIRECTORY_EXPAND_FAIL = "DIRECTORY_EXPAND_FAIL";
|
||||
|
||||
export const fetchDirectory = params => (dispatch, getState) => {
|
||||
dispatch(fetchDirectoryRequest());
|
||||
|
||||
api(getState).get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => {
|
||||
api(getState).get("/api/v1/directory", { params: { ...params, limit: 20 } }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchDirectorySuccess(data));
|
||||
dispatch(fetchRelationships(data.map(x => x.id)));
|
||||
@@ -38,9 +38,9 @@ export const fetchDirectoryFail = error => ({
|
||||
export const expandDirectory = params => (dispatch, getState) => {
|
||||
dispatch(expandDirectoryRequest());
|
||||
|
||||
const loadedItems = getState().getIn(['user_lists', 'directory', 'items']).size;
|
||||
const loadedItems = getState().getIn(["user_lists", "directory", "items"]).size;
|
||||
|
||||
api(getState).get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => {
|
||||
api(getState).get("/api/v1/directory", { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(expandDirectorySuccess(data));
|
||||
dispatch(fetchRelationships(data.map(x => x.id)));
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
export const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST';
|
||||
export const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS';
|
||||
export const DOMAIN_BLOCK_FAIL = 'DOMAIN_BLOCK_FAIL';
|
||||
export const DOMAIN_BLOCK_REQUEST = "DOMAIN_BLOCK_REQUEST";
|
||||
export const DOMAIN_BLOCK_SUCCESS = "DOMAIN_BLOCK_SUCCESS";
|
||||
export const DOMAIN_BLOCK_FAIL = "DOMAIN_BLOCK_FAIL";
|
||||
|
||||
export const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST';
|
||||
export const DOMAIN_UNBLOCK_SUCCESS = 'DOMAIN_UNBLOCK_SUCCESS';
|
||||
export const DOMAIN_UNBLOCK_FAIL = 'DOMAIN_UNBLOCK_FAIL';
|
||||
export const DOMAIN_UNBLOCK_REQUEST = "DOMAIN_UNBLOCK_REQUEST";
|
||||
export const DOMAIN_UNBLOCK_SUCCESS = "DOMAIN_UNBLOCK_SUCCESS";
|
||||
export const DOMAIN_UNBLOCK_FAIL = "DOMAIN_UNBLOCK_FAIL";
|
||||
|
||||
export const DOMAIN_BLOCKS_FETCH_REQUEST = 'DOMAIN_BLOCKS_FETCH_REQUEST';
|
||||
export const DOMAIN_BLOCKS_FETCH_SUCCESS = 'DOMAIN_BLOCKS_FETCH_SUCCESS';
|
||||
export const DOMAIN_BLOCKS_FETCH_FAIL = 'DOMAIN_BLOCKS_FETCH_FAIL';
|
||||
export const DOMAIN_BLOCKS_FETCH_REQUEST = "DOMAIN_BLOCKS_FETCH_REQUEST";
|
||||
export const DOMAIN_BLOCKS_FETCH_SUCCESS = "DOMAIN_BLOCKS_FETCH_SUCCESS";
|
||||
export const DOMAIN_BLOCKS_FETCH_FAIL = "DOMAIN_BLOCKS_FETCH_FAIL";
|
||||
|
||||
export const DOMAIN_BLOCKS_EXPAND_REQUEST = 'DOMAIN_BLOCKS_EXPAND_REQUEST';
|
||||
export const DOMAIN_BLOCKS_EXPAND_SUCCESS = 'DOMAIN_BLOCKS_EXPAND_SUCCESS';
|
||||
export const DOMAIN_BLOCKS_EXPAND_FAIL = 'DOMAIN_BLOCKS_EXPAND_FAIL';
|
||||
export const DOMAIN_BLOCKS_EXPAND_REQUEST = "DOMAIN_BLOCKS_EXPAND_REQUEST";
|
||||
export const DOMAIN_BLOCKS_EXPAND_SUCCESS = "DOMAIN_BLOCKS_EXPAND_SUCCESS";
|
||||
export const DOMAIN_BLOCKS_EXPAND_FAIL = "DOMAIN_BLOCKS_EXPAND_FAIL";
|
||||
|
||||
export function blockDomain(domain) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(blockDomainRequest(domain));
|
||||
|
||||
api(getState).post('/api/v1/domain_blocks', { domain }).then(() => {
|
||||
const at_domain = '@' + domain;
|
||||
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
|
||||
api(getState).post("/api/v1/domain_blocks", { domain }).then(() => {
|
||||
const at_domain = "@" + domain;
|
||||
const accounts = getState().get("accounts").filter(item => item.get("acct").endsWith(at_domain)).valueSeq().map(item => item.get("id"));
|
||||
|
||||
dispatch(blockDomainSuccess(domain, accounts));
|
||||
}).catch(err => {
|
||||
@@ -58,9 +58,9 @@ export function unblockDomain(domain) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unblockDomainRequest(domain));
|
||||
|
||||
api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(() => {
|
||||
const at_domain = '@' + domain;
|
||||
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
|
||||
api(getState).delete("/api/v1/domain_blocks", { params: { domain } }).then(() => {
|
||||
const at_domain = "@" + domain;
|
||||
const accounts = getState().get("accounts").filter(item => item.get("acct").endsWith(at_domain)).valueSeq().map(item => item.get("id"));
|
||||
dispatch(unblockDomainSuccess(domain, accounts));
|
||||
}).catch(err => {
|
||||
dispatch(unblockDomainFail(domain, err));
|
||||
@@ -95,8 +95,8 @@ export function fetchDomainBlocks() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchDomainBlocksRequest());
|
||||
|
||||
api(getState).get('/api/v1/domain_blocks').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
api(getState).get("/api/v1/domain_blocks").then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(err => {
|
||||
dispatch(fetchDomainBlocksFail(err));
|
||||
@@ -127,7 +127,7 @@ export function fetchDomainBlocksFail(error) {
|
||||
|
||||
export function expandDomainBlocks() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['domain_lists', 'blocks', 'next']);
|
||||
const url = getState().getIn(["domain_lists", "blocks", "next"]);
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
@@ -136,7 +136,7 @@ export function expandDomainBlocks() {
|
||||
dispatch(expandDomainBlocksRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(err => {
|
||||
dispatch(expandDomainBlocksFail(err));
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import { createAction } from "@reduxjs/toolkit";
|
||||
|
||||
export const openDropdownMenu = createAction<{
|
||||
id: string;
|
||||
keyboard: boolean;
|
||||
scrollKey: string;
|
||||
}>('dropdownMenu/open');
|
||||
id: string,
|
||||
keyboard: boolean,
|
||||
scrollKey: string,
|
||||
}>("dropdownMenu/open");
|
||||
|
||||
export const closeDropdownMenu = createAction<{ id: string }>(
|
||||
'dropdownMenu/close',
|
||||
"dropdownMenu/close",
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { saveSettings } from './settings';
|
||||
import { saveSettings } from "./settings";
|
||||
|
||||
export const EMOJI_USE = 'EMOJI_USE';
|
||||
export const EMOJI_USE = "EMOJI_USE";
|
||||
|
||||
export function useEmoji(emoji) {
|
||||
return dispatch => {
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
import { importFetchedStatuses } from "./importer";
|
||||
|
||||
export const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST';
|
||||
export const FAVOURITED_STATUSES_FETCH_SUCCESS = 'FAVOURITED_STATUSES_FETCH_SUCCESS';
|
||||
export const FAVOURITED_STATUSES_FETCH_FAIL = 'FAVOURITED_STATUSES_FETCH_FAIL';
|
||||
export const FAVOURITED_STATUSES_FETCH_REQUEST = "FAVOURITED_STATUSES_FETCH_REQUEST";
|
||||
export const FAVOURITED_STATUSES_FETCH_SUCCESS = "FAVOURITED_STATUSES_FETCH_SUCCESS";
|
||||
export const FAVOURITED_STATUSES_FETCH_FAIL = "FAVOURITED_STATUSES_FETCH_FAIL";
|
||||
|
||||
export const FAVOURITED_STATUSES_EXPAND_REQUEST = 'FAVOURITED_STATUSES_EXPAND_REQUEST';
|
||||
export const FAVOURITED_STATUSES_EXPAND_SUCCESS = 'FAVOURITED_STATUSES_EXPAND_SUCCESS';
|
||||
export const FAVOURITED_STATUSES_EXPAND_FAIL = 'FAVOURITED_STATUSES_EXPAND_FAIL';
|
||||
export const FAVOURITED_STATUSES_EXPAND_REQUEST = "FAVOURITED_STATUSES_EXPAND_REQUEST";
|
||||
export const FAVOURITED_STATUSES_EXPAND_SUCCESS = "FAVOURITED_STATUSES_EXPAND_SUCCESS";
|
||||
export const FAVOURITED_STATUSES_EXPAND_FAIL = "FAVOURITED_STATUSES_EXPAND_FAIL";
|
||||
|
||||
export function fetchFavouritedStatuses() {
|
||||
return (dispatch, getState) => {
|
||||
if (getState().getIn(['status_lists', 'favourites', 'isLoading'])) {
|
||||
if (getState().getIn(["status_lists", "favourites", "isLoading"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(fetchFavouritedStatusesRequest());
|
||||
|
||||
api(getState).get('/api/v1/favourites').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
api(getState).get("/api/v1/favourites").then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedStatuses(response.data));
|
||||
dispatch(fetchFavouritedStatusesSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => {
|
||||
@@ -54,16 +54,16 @@ export function fetchFavouritedStatusesFail(error) {
|
||||
|
||||
export function expandFavouritedStatuses() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['status_lists', 'favourites', 'next'], null);
|
||||
const url = getState().getIn(["status_lists", "favourites", "next"], null);
|
||||
|
||||
if (url === null || getState().getIn(['status_lists', 'favourites', 'isLoading'])) {
|
||||
if (url === null || getState().getIn(["status_lists", "favourites", "isLoading"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(expandFavouritedStatusesRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedStatuses(response.data));
|
||||
dispatch(expandFavouritedStatusesSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
export const FEATURED_TAGS_FETCH_REQUEST = 'FEATURED_TAGS_FETCH_REQUEST';
|
||||
export const FEATURED_TAGS_FETCH_SUCCESS = 'FEATURED_TAGS_FETCH_SUCCESS';
|
||||
export const FEATURED_TAGS_FETCH_FAIL = 'FEATURED_TAGS_FETCH_FAIL';
|
||||
export const FEATURED_TAGS_FETCH_REQUEST = "FEATURED_TAGS_FETCH_REQUEST";
|
||||
export const FEATURED_TAGS_FETCH_SUCCESS = "FEATURED_TAGS_FETCH_SUCCESS";
|
||||
export const FEATURED_TAGS_FETCH_FAIL = "FEATURED_TAGS_FETCH_FAIL";
|
||||
|
||||
export const fetchFeaturedTags = (id) => (dispatch, getState) => {
|
||||
if (getState().getIn(['user_lists', 'featured_tags', id, 'items'])) {
|
||||
if (getState().getIn(["user_lists", "featured_tags", id, "items"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { openModal } from './modal';
|
||||
import { openModal } from "./modal";
|
||||
|
||||
export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
|
||||
export const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';
|
||||
export const FILTERS_FETCH_FAIL = 'FILTERS_FETCH_FAIL';
|
||||
export const FILTERS_FETCH_REQUEST = "FILTERS_FETCH_REQUEST";
|
||||
export const FILTERS_FETCH_SUCCESS = "FILTERS_FETCH_SUCCESS";
|
||||
export const FILTERS_FETCH_FAIL = "FILTERS_FETCH_FAIL";
|
||||
|
||||
export const FILTERS_STATUS_CREATE_REQUEST = 'FILTERS_STATUS_CREATE_REQUEST';
|
||||
export const FILTERS_STATUS_CREATE_SUCCESS = 'FILTERS_STATUS_CREATE_SUCCESS';
|
||||
export const FILTERS_STATUS_CREATE_FAIL = 'FILTERS_STATUS_CREATE_FAIL';
|
||||
export const FILTERS_STATUS_CREATE_REQUEST = "FILTERS_STATUS_CREATE_REQUEST";
|
||||
export const FILTERS_STATUS_CREATE_SUCCESS = "FILTERS_STATUS_CREATE_SUCCESS";
|
||||
export const FILTERS_STATUS_CREATE_FAIL = "FILTERS_STATUS_CREATE_FAIL";
|
||||
|
||||
export const FILTERS_CREATE_REQUEST = 'FILTERS_CREATE_REQUEST';
|
||||
export const FILTERS_CREATE_SUCCESS = 'FILTERS_CREATE_SUCCESS';
|
||||
export const FILTERS_CREATE_FAIL = 'FILTERS_CREATE_FAIL';
|
||||
export const FILTERS_CREATE_REQUEST = "FILTERS_CREATE_REQUEST";
|
||||
export const FILTERS_CREATE_SUCCESS = "FILTERS_CREATE_SUCCESS";
|
||||
export const FILTERS_CREATE_FAIL = "FILTERS_CREATE_FAIL";
|
||||
|
||||
export const initAddFilter = (status, { contextType }) => dispatch =>
|
||||
dispatch(openModal({
|
||||
modalType: 'FILTER',
|
||||
modalType: "FILTER",
|
||||
modalProps: {
|
||||
statusId: status?.get('id'),
|
||||
statusId: status?.get("id"),
|
||||
contextType: contextType,
|
||||
},
|
||||
}));
|
||||
@@ -30,7 +30,7 @@ export const fetchFilters = () => (dispatch, getState) => {
|
||||
});
|
||||
|
||||
api(getState)
|
||||
.get('/api/v2/filters')
|
||||
.get("/api/v2/filters")
|
||||
.then(({ data }) => dispatch({
|
||||
type: FILTERS_FETCH_SUCCESS,
|
||||
filters: data,
|
||||
@@ -49,10 +49,14 @@ export const createFilterStatus = (params, onSuccess, onFail) => (dispatch, getS
|
||||
|
||||
api(getState).post(`/api/v2/filters/${params.filter_id}/statuses`, params).then(response => {
|
||||
dispatch(createFilterStatusSuccess(response.data));
|
||||
if (onSuccess) onSuccess();
|
||||
if (onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
}).catch(error => {
|
||||
dispatch(createFilterStatusFail(error));
|
||||
if (onFail) onFail();
|
||||
if (onFail) {
|
||||
onFail();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -73,12 +77,16 @@ export const createFilterStatusFail = error => ({
|
||||
export const createFilter = (params, onSuccess, onFail) => (dispatch, getState) => {
|
||||
dispatch(createFilterRequest());
|
||||
|
||||
api(getState).post('/api/v2/filters', params).then(response => {
|
||||
api(getState).post("/api/v2/filters", params).then(response => {
|
||||
dispatch(createFilterSuccess(response.data));
|
||||
if (onSuccess) onSuccess(response.data);
|
||||
if (onSuccess) {
|
||||
onSuccess(response.data);
|
||||
}
|
||||
}).catch(error => {
|
||||
dispatch(createFilterFail(error));
|
||||
if (onFail) onFail();
|
||||
if (onFail) {
|
||||
onFail();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export const HEIGHT_CACHE_SET = 'HEIGHT_CACHE_SET';
|
||||
export const HEIGHT_CACHE_CLEAR = 'HEIGHT_CACHE_CLEAR';
|
||||
export const HEIGHT_CACHE_SET = "HEIGHT_CACHE_SET";
|
||||
export const HEIGHT_CACHE_CLEAR = "HEIGHT_CACHE_CLEAR";
|
||||
|
||||
export function setHeight (key, id, height) {
|
||||
return {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { importFetchedAccounts } from "./importer";
|
||||
|
||||
export const HISTORY_FETCH_REQUEST = 'HISTORY_FETCH_REQUEST';
|
||||
export const HISTORY_FETCH_SUCCESS = 'HISTORY_FETCH_SUCCESS';
|
||||
export const HISTORY_FETCH_FAIL = 'HISTORY_FETCH_FAIL';
|
||||
export const HISTORY_FETCH_REQUEST = "HISTORY_FETCH_REQUEST";
|
||||
export const HISTORY_FETCH_SUCCESS = "HISTORY_FETCH_SUCCESS";
|
||||
export const HISTORY_FETCH_FAIL = "HISTORY_FETCH_FAIL";
|
||||
|
||||
export const fetchHistory = statusId => (dispatch, getState) => {
|
||||
const loading = getState().getIn(['history', statusId, 'loading']);
|
||||
const loading = getState().getIn(["history", statusId, "loading"]);
|
||||
|
||||
if (loading) {
|
||||
return;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { normalizeAccount, normalizeStatus, normalizePoll } from './normalizer';
|
||||
import { normalizeAccount, normalizeStatus, normalizePoll } from "./normalizer";
|
||||
|
||||
export const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT';
|
||||
export const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT';
|
||||
export const STATUS_IMPORT = 'STATUS_IMPORT';
|
||||
export const STATUSES_IMPORT = 'STATUSES_IMPORT';
|
||||
export const POLLS_IMPORT = 'POLLS_IMPORT';
|
||||
export const FILTERS_IMPORT = 'FILTERS_IMPORT';
|
||||
export const ACCOUNT_IMPORT = "ACCOUNT_IMPORT";
|
||||
export const ACCOUNTS_IMPORT = "ACCOUNTS_IMPORT";
|
||||
export const STATUS_IMPORT = "STATUS_IMPORT";
|
||||
export const STATUSES_IMPORT = "STATUSES_IMPORT";
|
||||
export const POLLS_IMPORT = "POLLS_IMPORT";
|
||||
export const FILTERS_IMPORT = "FILTERS_IMPORT";
|
||||
|
||||
function pushUnique(array, object) {
|
||||
if (array.every(element => element.id !== object.id)) {
|
||||
@@ -69,7 +69,7 @@ export function importFetchedStatuses(statuses) {
|
||||
const filters = [];
|
||||
|
||||
function processStatus(status) {
|
||||
pushUnique(normalStatuses, normalizeStatus(status, getState().getIn(['statuses', status.id])));
|
||||
pushUnique(normalStatuses, normalizeStatus(status, getState().getIn(["statuses", status.id])));
|
||||
pushUnique(accounts, status.account);
|
||||
|
||||
if (status.filtered) {
|
||||
@@ -81,7 +81,7 @@ export function importFetchedStatuses(statuses) {
|
||||
}
|
||||
|
||||
if (status.poll && status.poll.id) {
|
||||
pushUnique(polls, normalizePoll(status.poll, getState().getIn(['polls', status.poll.id])));
|
||||
pushUnique(polls, normalizePoll(status.poll, getState().getIn(["polls", status.poll.id])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,6 @@ export function importFetchedStatuses(statuses) {
|
||||
|
||||
export function importFetchedPoll(poll) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(importPolls([normalizePoll(poll, getState().getIn(['polls', poll.id]))]));
|
||||
dispatch(importPolls([normalizePoll(poll, getState().getIn(["polls", poll.id]))]));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import escapeTextContentForBrowser from "escape-html";
|
||||
|
||||
import emojify from '../../features/emoji/emoji';
|
||||
import { expandSpoilers } from '../../initial_state';
|
||||
import { unescapeHTML } from '../../utils/html';
|
||||
import emojify from "../../features/emoji/emoji";
|
||||
import { expandSpoilers } from "../../initial_state";
|
||||
import { unescapeHTML } from "../../utils/html";
|
||||
|
||||
const domParser = new DOMParser();
|
||||
|
||||
@@ -12,9 +12,9 @@ const makeEmojiMap = emojis => emojis.reduce((obj, emoji) => {
|
||||
}, {});
|
||||
|
||||
export function searchTextFromRawStatus (status) {
|
||||
const spoilerText = status.spoiler_text || '';
|
||||
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');
|
||||
return domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
|
||||
const spoilerText = status.spoiler_text || "";
|
||||
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");
|
||||
return domParser.parseFromString(searchContent, "text/html").documentElement.textContent;
|
||||
}
|
||||
|
||||
export function normalizeAccount(account) {
|
||||
@@ -70,41 +70,41 @@ export function normalizeStatus(status, 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');
|
||||
normalStatus.spoiler_text = normalOldStatus.get('spoiler_text');
|
||||
normalStatus.hidden = normalOldStatus.get('hidden');
|
||||
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");
|
||||
normalStatus.spoiler_text = normalOldStatus.get("spoiler_text");
|
||||
normalStatus.hidden = normalOldStatus.get("hidden");
|
||||
|
||||
if (normalOldStatus.get('translation')) {
|
||||
normalStatus.translation = normalOldStatus.get('translation');
|
||||
if (normalOldStatus.get("translation")) {
|
||||
normalStatus.translation = normalOldStatus.get("translation");
|
||||
}
|
||||
} else {
|
||||
// If the status has a CW but no contents, treat the CW as if it were the
|
||||
// status' contents, to avoid having a CW toggle with seemingly no effect.
|
||||
if (normalStatus.spoiler_text && !normalStatus.content) {
|
||||
normalStatus.content = normalStatus.spoiler_text;
|
||||
normalStatus.spoiler_text = '';
|
||||
normalStatus.spoiler_text = "";
|
||||
}
|
||||
|
||||
const spoilerText = normalStatus.spoiler_text || '';
|
||||
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 spoilerText = normalStatus.spoiler_text || "";
|
||||
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.emojis);
|
||||
|
||||
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
|
||||
normalStatus.search_index = domParser.parseFromString(searchContent, "text/html").documentElement.textContent;
|
||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
||||
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
|
||||
}
|
||||
|
||||
if (normalOldStatus) {
|
||||
const list = normalOldStatus.get('media_attachments');
|
||||
const list = normalOldStatus.get("media_attachments");
|
||||
if (normalStatus.media_attachments && list) {
|
||||
normalStatus.media_attachments.forEach(item => {
|
||||
const oldItem = list.find(i => i.get('id') === item.id);
|
||||
if (oldItem && oldItem.get('description') === item.description) {
|
||||
item.translation = oldItem.get('translation');
|
||||
const oldItem = list.find(i => i.get("id") === item.id);
|
||||
if (oldItem && oldItem.get("description") === item.description) {
|
||||
item.translation = oldItem.get("translation");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -114,7 +114,7 @@ export function normalizeStatus(status, normalOldStatus) {
|
||||
}
|
||||
|
||||
export function normalizeStatusTranslation(translation, status) {
|
||||
const emojiMap = makeEmojiMap(status.get('emojis').toJS());
|
||||
const emojiMap = makeEmojiMap(status.get("emojis").toJS());
|
||||
|
||||
const normalTranslation = {
|
||||
detected_source_language: translation.detected_source_language,
|
||||
@@ -139,8 +139,8 @@ export function normalizePoll(poll, normalOldPoll) {
|
||||
titleHtml: emojify(escapeTextContentForBrowser(option.title), emojiMap),
|
||||
};
|
||||
|
||||
if (normalOldPoll && normalOldPoll.getIn(['options', index, 'title']) === option.title) {
|
||||
normalOption.translation = normalOldPoll.getIn(['options', index, 'translation']);
|
||||
if (normalOldPoll && normalOldPoll.getIn(["options", index, "title"]) === option.title) {
|
||||
normalOption.translation = normalOldPoll.getIn(["options", index, "translation"]);
|
||||
}
|
||||
|
||||
return normalOption;
|
||||
@@ -150,7 +150,7 @@ export function normalizePoll(poll, normalOldPoll) {
|
||||
}
|
||||
|
||||
export function normalizePollOptionTranslation(translation, poll) {
|
||||
const emojiMap = makeEmojiMap(poll.get('emojis').toJS());
|
||||
const emojiMap = makeEmojiMap(poll.get("emojis").toJS());
|
||||
|
||||
const normalTranslation = {
|
||||
...translation,
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
import { fetchRelationships } from "./accounts";
|
||||
import { importFetchedAccounts, importFetchedStatus } from "./importer";
|
||||
|
||||
export const REBLOG_REQUEST = 'REBLOG_REQUEST';
|
||||
export const REBLOG_SUCCESS = 'REBLOG_SUCCESS';
|
||||
export const REBLOG_FAIL = 'REBLOG_FAIL';
|
||||
export const REBLOG_REQUEST = "REBLOG_REQUEST";
|
||||
export const REBLOG_SUCCESS = "REBLOG_SUCCESS";
|
||||
export const REBLOG_FAIL = "REBLOG_FAIL";
|
||||
|
||||
export const REBLOGS_EXPAND_REQUEST = 'REBLOGS_EXPAND_REQUEST';
|
||||
export const REBLOGS_EXPAND_SUCCESS = 'REBLOGS_EXPAND_SUCCESS';
|
||||
export const REBLOGS_EXPAND_FAIL = 'REBLOGS_EXPAND_FAIL';
|
||||
export const REBLOGS_EXPAND_REQUEST = "REBLOGS_EXPAND_REQUEST";
|
||||
export const REBLOGS_EXPAND_SUCCESS = "REBLOGS_EXPAND_SUCCESS";
|
||||
export const REBLOGS_EXPAND_FAIL = "REBLOGS_EXPAND_FAIL";
|
||||
|
||||
export const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST';
|
||||
export const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS';
|
||||
export const FAVOURITE_FAIL = 'FAVOURITE_FAIL';
|
||||
export const FAVOURITE_REQUEST = "FAVOURITE_REQUEST";
|
||||
export const FAVOURITE_SUCCESS = "FAVOURITE_SUCCESS";
|
||||
export const FAVOURITE_FAIL = "FAVOURITE_FAIL";
|
||||
|
||||
export const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST';
|
||||
export const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS';
|
||||
export const UNREBLOG_FAIL = 'UNREBLOG_FAIL';
|
||||
export const UNREBLOG_REQUEST = "UNREBLOG_REQUEST";
|
||||
export const UNREBLOG_SUCCESS = "UNREBLOG_SUCCESS";
|
||||
export const UNREBLOG_FAIL = "UNREBLOG_FAIL";
|
||||
|
||||
export const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST';
|
||||
export const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS';
|
||||
export const UNFAVOURITE_FAIL = 'UNFAVOURITE_FAIL';
|
||||
export const UNFAVOURITE_REQUEST = "UNFAVOURITE_REQUEST";
|
||||
export const UNFAVOURITE_SUCCESS = "UNFAVOURITE_SUCCESS";
|
||||
export const UNFAVOURITE_FAIL = "UNFAVOURITE_FAIL";
|
||||
|
||||
export const REBLOGS_FETCH_REQUEST = 'REBLOGS_FETCH_REQUEST';
|
||||
export const REBLOGS_FETCH_SUCCESS = 'REBLOGS_FETCH_SUCCESS';
|
||||
export const REBLOGS_FETCH_FAIL = 'REBLOGS_FETCH_FAIL';
|
||||
export const REBLOGS_FETCH_REQUEST = "REBLOGS_FETCH_REQUEST";
|
||||
export const REBLOGS_FETCH_SUCCESS = "REBLOGS_FETCH_SUCCESS";
|
||||
export const REBLOGS_FETCH_FAIL = "REBLOGS_FETCH_FAIL";
|
||||
|
||||
export const FAVOURITES_FETCH_REQUEST = 'FAVOURITES_FETCH_REQUEST';
|
||||
export const FAVOURITES_FETCH_SUCCESS = 'FAVOURITES_FETCH_SUCCESS';
|
||||
export const FAVOURITES_FETCH_FAIL = 'FAVOURITES_FETCH_FAIL';
|
||||
export const FAVOURITES_FETCH_REQUEST = "FAVOURITES_FETCH_REQUEST";
|
||||
export const FAVOURITES_FETCH_SUCCESS = "FAVOURITES_FETCH_SUCCESS";
|
||||
export const FAVOURITES_FETCH_FAIL = "FAVOURITES_FETCH_FAIL";
|
||||
|
||||
export const FAVOURITES_EXPAND_REQUEST = 'FAVOURITES_EXPAND_REQUEST';
|
||||
export const FAVOURITES_EXPAND_SUCCESS = 'FAVOURITES_EXPAND_SUCCESS';
|
||||
export const FAVOURITES_EXPAND_FAIL = 'FAVOURITES_EXPAND_FAIL';
|
||||
export const FAVOURITES_EXPAND_REQUEST = "FAVOURITES_EXPAND_REQUEST";
|
||||
export const FAVOURITES_EXPAND_SUCCESS = "FAVOURITES_EXPAND_SUCCESS";
|
||||
export const FAVOURITES_EXPAND_FAIL = "FAVOURITES_EXPAND_FAIL";
|
||||
|
||||
export const PIN_REQUEST = 'PIN_REQUEST';
|
||||
export const PIN_SUCCESS = 'PIN_SUCCESS';
|
||||
export const PIN_FAIL = 'PIN_FAIL';
|
||||
export const PIN_REQUEST = "PIN_REQUEST";
|
||||
export const PIN_SUCCESS = "PIN_SUCCESS";
|
||||
export const PIN_FAIL = "PIN_FAIL";
|
||||
|
||||
export const UNPIN_REQUEST = 'UNPIN_REQUEST';
|
||||
export const UNPIN_SUCCESS = 'UNPIN_SUCCESS';
|
||||
export const UNPIN_FAIL = 'UNPIN_FAIL';
|
||||
export const UNPIN_REQUEST = "UNPIN_REQUEST";
|
||||
export const UNPIN_SUCCESS = "UNPIN_SUCCESS";
|
||||
export const UNPIN_FAIL = "UNPIN_FAIL";
|
||||
|
||||
export const BOOKMARK_REQUEST = 'BOOKMARK_REQUEST';
|
||||
export const BOOKMARK_SUCCESS = 'BOOKMARKED_SUCCESS';
|
||||
export const BOOKMARK_FAIL = 'BOOKMARKED_FAIL';
|
||||
export const BOOKMARK_REQUEST = "BOOKMARK_REQUEST";
|
||||
export const BOOKMARK_SUCCESS = "BOOKMARKED_SUCCESS";
|
||||
export const BOOKMARK_FAIL = "BOOKMARKED_FAIL";
|
||||
|
||||
export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST';
|
||||
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
||||
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
||||
export const UNBOOKMARK_REQUEST = "UNBOOKMARKED_REQUEST";
|
||||
export const UNBOOKMARK_SUCCESS = "UNBOOKMARKED_SUCCESS";
|
||||
export const UNBOOKMARK_FAIL = "UNBOOKMARKED_FAIL";
|
||||
|
||||
export function reblog(status, visibility) {
|
||||
return function (dispatch, getState) {
|
||||
dispatch(reblogRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) {
|
||||
api(getState).post(`/api/v1/statuses/${status.get("id")}/reblog`, { visibility }).then(function (response) {
|
||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||
dispatch(importFetchedStatus(response.data.reblog));
|
||||
@@ -70,7 +70,7 @@ export function unreblog(status) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unreblogRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => {
|
||||
api(getState).post(`/api/v1/statuses/${status.get("id")}/unreblog`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unreblogSuccess(status));
|
||||
}).catch(error => {
|
||||
@@ -133,7 +133,7 @@ export function favourite(status) {
|
||||
return function (dispatch, getState) {
|
||||
dispatch(favouriteRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) {
|
||||
api(getState).post(`/api/v1/statuses/${status.get("id")}/favourite`).then(function (response) {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(favouriteSuccess(status));
|
||||
}).catch(function (error) {
|
||||
@@ -146,7 +146,7 @@ export function unfavourite(status) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unfavouriteRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => {
|
||||
api(getState).post(`/api/v1/statuses/${status.get("id")}/unfavourite`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unfavouriteSuccess(status));
|
||||
}).catch(error => {
|
||||
@@ -209,7 +209,7 @@ export function bookmark(status) {
|
||||
return function (dispatch, getState) {
|
||||
dispatch(bookmarkRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function (response) {
|
||||
api(getState).post(`/api/v1/statuses/${status.get("id")}/bookmark`).then(function (response) {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(bookmarkSuccess(status, response.data));
|
||||
}).catch(function (error) {
|
||||
@@ -222,7 +222,7 @@ export function unbookmark(status) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unbookmarkRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => {
|
||||
api(getState).post(`/api/v1/statuses/${status.get("id")}/unbookmark`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unbookmarkSuccess(status, response.data));
|
||||
}).catch(error => {
|
||||
@@ -282,7 +282,7 @@ export function fetchReblogs(id) {
|
||||
dispatch(fetchReblogsRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchReblogsSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
@@ -318,7 +318,7 @@ export function fetchReblogsFail(id, error) {
|
||||
|
||||
export function expandReblogs(id) {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['user_lists', 'reblogged_by', id, 'next']);
|
||||
const url = getState().getIn(["user_lists", "reblogged_by", id, "next"]);
|
||||
if (url === null) {
|
||||
return;
|
||||
}
|
||||
@@ -326,7 +326,7 @@ export function expandReblogs(id) {
|
||||
dispatch(expandReblogsRequest(id));
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandReblogsSuccess(id, response.data, next ? next.uri : null));
|
||||
@@ -364,7 +364,7 @@ export function fetchFavourites(id) {
|
||||
dispatch(fetchFavouritesRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchFavouritesSuccess(id, response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
@@ -400,7 +400,7 @@ export function fetchFavouritesFail(id, error) {
|
||||
|
||||
export function expandFavourites(id) {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['user_lists', 'favourited_by', id, 'next']);
|
||||
const url = getState().getIn(["user_lists", "favourited_by", id, "next"]);
|
||||
if (url === null) {
|
||||
return;
|
||||
}
|
||||
@@ -408,7 +408,7 @@ export function expandFavourites(id) {
|
||||
dispatch(expandFavouritesRequest(id));
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandFavouritesSuccess(id, response.data, next ? next.uri : null));
|
||||
@@ -445,7 +445,7 @@ export function pin(status) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(pinRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => {
|
||||
api(getState).post(`/api/v1/statuses/${status.get("id")}/pin`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(pinSuccess(status));
|
||||
}).catch(error => {
|
||||
@@ -483,7 +483,7 @@ export function unpin (status) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unpinRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => {
|
||||
api(getState).post(`/api/v1/statuses/${status.get("id")}/unpin`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unpinSuccess(status));
|
||||
}).catch(error => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { saveSettings } from './settings';
|
||||
import { saveSettings } from "./settings";
|
||||
|
||||
export const LANGUAGE_USE = 'LANGUAGE_USE';
|
||||
export const LANGUAGE_USE = "LANGUAGE_USE";
|
||||
|
||||
export const useLanguage = language => dispatch => {
|
||||
dispatch({
|
||||
|
||||
@@ -1,57 +1,57 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { showAlertForError } from './alerts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { showAlertForError } from "./alerts";
|
||||
import { importFetchedAccounts } from "./importer";
|
||||
|
||||
export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';
|
||||
export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';
|
||||
export const LIST_FETCH_FAIL = 'LIST_FETCH_FAIL';
|
||||
export const LIST_FETCH_REQUEST = "LIST_FETCH_REQUEST";
|
||||
export const LIST_FETCH_SUCCESS = "LIST_FETCH_SUCCESS";
|
||||
export const LIST_FETCH_FAIL = "LIST_FETCH_FAIL";
|
||||
|
||||
export const LISTS_FETCH_REQUEST = 'LISTS_FETCH_REQUEST';
|
||||
export const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS';
|
||||
export const LISTS_FETCH_FAIL = 'LISTS_FETCH_FAIL';
|
||||
export const LISTS_FETCH_REQUEST = "LISTS_FETCH_REQUEST";
|
||||
export const LISTS_FETCH_SUCCESS = "LISTS_FETCH_SUCCESS";
|
||||
export const LISTS_FETCH_FAIL = "LISTS_FETCH_FAIL";
|
||||
|
||||
export const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE';
|
||||
export const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET';
|
||||
export const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP';
|
||||
export const LIST_EDITOR_TITLE_CHANGE = "LIST_EDITOR_TITLE_CHANGE";
|
||||
export const LIST_EDITOR_RESET = "LIST_EDITOR_RESET";
|
||||
export const LIST_EDITOR_SETUP = "LIST_EDITOR_SETUP";
|
||||
|
||||
export const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST';
|
||||
export const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS';
|
||||
export const LIST_CREATE_FAIL = 'LIST_CREATE_FAIL';
|
||||
export const LIST_CREATE_REQUEST = "LIST_CREATE_REQUEST";
|
||||
export const LIST_CREATE_SUCCESS = "LIST_CREATE_SUCCESS";
|
||||
export const LIST_CREATE_FAIL = "LIST_CREATE_FAIL";
|
||||
|
||||
export const LIST_UPDATE_REQUEST = 'LIST_UPDATE_REQUEST';
|
||||
export const LIST_UPDATE_SUCCESS = 'LIST_UPDATE_SUCCESS';
|
||||
export const LIST_UPDATE_FAIL = 'LIST_UPDATE_FAIL';
|
||||
export const LIST_UPDATE_REQUEST = "LIST_UPDATE_REQUEST";
|
||||
export const LIST_UPDATE_SUCCESS = "LIST_UPDATE_SUCCESS";
|
||||
export const LIST_UPDATE_FAIL = "LIST_UPDATE_FAIL";
|
||||
|
||||
export const LIST_DELETE_REQUEST = 'LIST_DELETE_REQUEST';
|
||||
export const LIST_DELETE_SUCCESS = 'LIST_DELETE_SUCCESS';
|
||||
export const LIST_DELETE_FAIL = 'LIST_DELETE_FAIL';
|
||||
export const LIST_DELETE_REQUEST = "LIST_DELETE_REQUEST";
|
||||
export const LIST_DELETE_SUCCESS = "LIST_DELETE_SUCCESS";
|
||||
export const LIST_DELETE_FAIL = "LIST_DELETE_FAIL";
|
||||
|
||||
export const LIST_ACCOUNTS_FETCH_REQUEST = 'LIST_ACCOUNTS_FETCH_REQUEST';
|
||||
export const LIST_ACCOUNTS_FETCH_SUCCESS = 'LIST_ACCOUNTS_FETCH_SUCCESS';
|
||||
export const LIST_ACCOUNTS_FETCH_FAIL = 'LIST_ACCOUNTS_FETCH_FAIL';
|
||||
export const LIST_ACCOUNTS_FETCH_REQUEST = "LIST_ACCOUNTS_FETCH_REQUEST";
|
||||
export const LIST_ACCOUNTS_FETCH_SUCCESS = "LIST_ACCOUNTS_FETCH_SUCCESS";
|
||||
export const LIST_ACCOUNTS_FETCH_FAIL = "LIST_ACCOUNTS_FETCH_FAIL";
|
||||
|
||||
export const LIST_EDITOR_SUGGESTIONS_CHANGE = 'LIST_EDITOR_SUGGESTIONS_CHANGE';
|
||||
export const LIST_EDITOR_SUGGESTIONS_READY = 'LIST_EDITOR_SUGGESTIONS_READY';
|
||||
export const LIST_EDITOR_SUGGESTIONS_CLEAR = 'LIST_EDITOR_SUGGESTIONS_CLEAR';
|
||||
export const LIST_EDITOR_SUGGESTIONS_CHANGE = "LIST_EDITOR_SUGGESTIONS_CHANGE";
|
||||
export const LIST_EDITOR_SUGGESTIONS_READY = "LIST_EDITOR_SUGGESTIONS_READY";
|
||||
export const LIST_EDITOR_SUGGESTIONS_CLEAR = "LIST_EDITOR_SUGGESTIONS_CLEAR";
|
||||
|
||||
export const LIST_EDITOR_ADD_REQUEST = 'LIST_EDITOR_ADD_REQUEST';
|
||||
export const LIST_EDITOR_ADD_SUCCESS = 'LIST_EDITOR_ADD_SUCCESS';
|
||||
export const LIST_EDITOR_ADD_FAIL = 'LIST_EDITOR_ADD_FAIL';
|
||||
export const LIST_EDITOR_ADD_REQUEST = "LIST_EDITOR_ADD_REQUEST";
|
||||
export const LIST_EDITOR_ADD_SUCCESS = "LIST_EDITOR_ADD_SUCCESS";
|
||||
export const LIST_EDITOR_ADD_FAIL = "LIST_EDITOR_ADD_FAIL";
|
||||
|
||||
export const LIST_EDITOR_REMOVE_REQUEST = 'LIST_EDITOR_REMOVE_REQUEST';
|
||||
export const LIST_EDITOR_REMOVE_SUCCESS = 'LIST_EDITOR_REMOVE_SUCCESS';
|
||||
export const LIST_EDITOR_REMOVE_FAIL = 'LIST_EDITOR_REMOVE_FAIL';
|
||||
export const LIST_EDITOR_REMOVE_REQUEST = "LIST_EDITOR_REMOVE_REQUEST";
|
||||
export const LIST_EDITOR_REMOVE_SUCCESS = "LIST_EDITOR_REMOVE_SUCCESS";
|
||||
export const LIST_EDITOR_REMOVE_FAIL = "LIST_EDITOR_REMOVE_FAIL";
|
||||
|
||||
export const LIST_ADDER_RESET = 'LIST_ADDER_RESET';
|
||||
export const LIST_ADDER_SETUP = 'LIST_ADDER_SETUP';
|
||||
export const LIST_ADDER_RESET = "LIST_ADDER_RESET";
|
||||
export const LIST_ADDER_SETUP = "LIST_ADDER_SETUP";
|
||||
|
||||
export const LIST_ADDER_LISTS_FETCH_REQUEST = 'LIST_ADDER_LISTS_FETCH_REQUEST';
|
||||
export const LIST_ADDER_LISTS_FETCH_SUCCESS = 'LIST_ADDER_LISTS_FETCH_SUCCESS';
|
||||
export const LIST_ADDER_LISTS_FETCH_FAIL = 'LIST_ADDER_LISTS_FETCH_FAIL';
|
||||
export const LIST_ADDER_LISTS_FETCH_REQUEST = "LIST_ADDER_LISTS_FETCH_REQUEST";
|
||||
export const LIST_ADDER_LISTS_FETCH_SUCCESS = "LIST_ADDER_LISTS_FETCH_SUCCESS";
|
||||
export const LIST_ADDER_LISTS_FETCH_FAIL = "LIST_ADDER_LISTS_FETCH_FAIL";
|
||||
|
||||
export const fetchList = id => (dispatch, getState) => {
|
||||
if (getState().getIn(['lists', id])) {
|
||||
if (getState().getIn(["lists", id])) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export const fetchListFail = (id, error) => ({
|
||||
export const fetchLists = () => (dispatch, getState) => {
|
||||
dispatch(fetchListsRequest());
|
||||
|
||||
api(getState).get('/api/v1/lists')
|
||||
api(getState).get("/api/v1/lists")
|
||||
.then(({ data }) => dispatch(fetchListsSuccess(data)))
|
||||
.catch(err => dispatch(fetchListsFail(err)));
|
||||
};
|
||||
@@ -101,8 +101,8 @@ export const fetchListsFail = error => ({
|
||||
});
|
||||
|
||||
export const submitListEditor = shouldReset => (dispatch, getState) => {
|
||||
const listId = getState().getIn(['listEditor', 'listId']);
|
||||
const title = getState().getIn(['listEditor', 'title']);
|
||||
const listId = getState().getIn(["listEditor", "listId"]);
|
||||
const title = getState().getIn(["listEditor", "title"]);
|
||||
|
||||
if (listId === null) {
|
||||
dispatch(createList(title, shouldReset));
|
||||
@@ -114,7 +114,7 @@ export const submitListEditor = shouldReset => (dispatch, getState) => {
|
||||
export const setupListEditor = listId => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: LIST_EDITOR_SETUP,
|
||||
list: getState().getIn(['lists', listId]),
|
||||
list: getState().getIn(["lists", listId]),
|
||||
});
|
||||
|
||||
dispatch(fetchListAccounts(listId));
|
||||
@@ -128,7 +128,7 @@ export const changeListEditorTitle = value => ({
|
||||
export const createList = (title, shouldReset) => (dispatch, getState) => {
|
||||
dispatch(createListRequest());
|
||||
|
||||
api(getState).post('/api/v1/lists', { title }).then(({ data }) => {
|
||||
api(getState).post("/api/v1/lists", { title }).then(({ data }) => {
|
||||
dispatch(createListSuccess(data));
|
||||
|
||||
if (shouldReset) {
|
||||
@@ -154,7 +154,7 @@ export const createListFail = error => ({
|
||||
export const updateList = (id, title, shouldReset, isExclusive, replies_policy) => (dispatch, getState) => {
|
||||
dispatch(updateListRequest(id));
|
||||
|
||||
api(getState).put(`/api/v1/lists/${id}`, { title, replies_policy, exclusive: typeof isExclusive === 'undefined' ? undefined : !!isExclusive }).then(({ data }) => {
|
||||
api(getState).put(`/api/v1/lists/${id}`, { title, replies_policy, exclusive: typeof isExclusive === "undefined" ? undefined : !!isExclusive }).then(({ data }) => {
|
||||
dispatch(updateListSuccess(data));
|
||||
|
||||
if (shouldReset) {
|
||||
@@ -242,7 +242,7 @@ export const fetchListSuggestions = q => (dispatch, getState) => {
|
||||
following: true,
|
||||
};
|
||||
|
||||
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
|
||||
api(getState).get("/api/v1/accounts/search", { params }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchListSuggestionsReady(q, data));
|
||||
}).catch(error => dispatch(showAlertForError(error)));
|
||||
@@ -264,7 +264,7 @@ export const changeListSuggestions = value => ({
|
||||
});
|
||||
|
||||
export const addToListEditor = accountId => (dispatch, getState) => {
|
||||
dispatch(addToList(getState().getIn(['listEditor', 'listId']), accountId));
|
||||
dispatch(addToList(getState().getIn(["listEditor", "listId"]), accountId));
|
||||
};
|
||||
|
||||
export const addToList = (listId, accountId) => (dispatch, getState) => {
|
||||
@@ -295,7 +295,7 @@ export const addToListFail = (listId, accountId, error) => ({
|
||||
});
|
||||
|
||||
export const removeFromListEditor = accountId => (dispatch, getState) => {
|
||||
dispatch(removeFromList(getState().getIn(['listEditor', 'listId']), accountId));
|
||||
dispatch(removeFromList(getState().getIn(["listEditor", "listId"]), accountId));
|
||||
};
|
||||
|
||||
export const removeFromList = (listId, accountId) => (dispatch, getState) => {
|
||||
@@ -332,7 +332,7 @@ export const resetListAdder = () => ({
|
||||
export const setupListAdder = accountId => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: LIST_ADDER_SETUP,
|
||||
account: getState().getIn(['accounts', accountId]),
|
||||
account: getState().getIn(["accounts", accountId]),
|
||||
});
|
||||
dispatch(fetchLists());
|
||||
dispatch(fetchAccountLists(accountId));
|
||||
@@ -364,10 +364,10 @@ export const fetchAccountListsFail = (id, err) => ({
|
||||
});
|
||||
|
||||
export const addToListAdder = listId => (dispatch, getState) => {
|
||||
dispatch(addToList(listId, getState().getIn(['listAdder', 'accountId'])));
|
||||
dispatch(addToList(listId, getState().getIn(["listAdder", "accountId"])));
|
||||
};
|
||||
|
||||
export const removeFromListAdder = listId => (dispatch, getState) => {
|
||||
dispatch(removeFromList(listId, getState().getIn(['listAdder', 'accountId'])));
|
||||
dispatch(removeFromList(listId, getState().getIn(["listAdder", "accountId"])));
|
||||
};
|
||||
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import { List as ImmutableList } from "immutable";
|
||||
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce } from "lodash";
|
||||
|
||||
import api from '../api';
|
||||
import { compareId } from '../compare_id';
|
||||
import api from "../api";
|
||||
import { compareId } from "../compare_id";
|
||||
|
||||
export const MARKERS_FETCH_REQUEST = 'MARKERS_FETCH_REQUEST';
|
||||
export const MARKERS_FETCH_SUCCESS = 'MARKERS_FETCH_SUCCESS';
|
||||
export const MARKERS_FETCH_FAIL = 'MARKERS_FETCH_FAIL';
|
||||
export const MARKERS_SUBMIT_SUCCESS = 'MARKERS_SUBMIT_SUCCESS';
|
||||
export const MARKERS_FETCH_REQUEST = "MARKERS_FETCH_REQUEST";
|
||||
export const MARKERS_FETCH_SUCCESS = "MARKERS_FETCH_SUCCESS";
|
||||
export const MARKERS_FETCH_FAIL = "MARKERS_FETCH_FAIL";
|
||||
export const MARKERS_SUBMIT_SUCCESS = "MARKERS_SUBMIT_SUCCESS";
|
||||
|
||||
export const synchronouslySubmitMarkers = () => (dispatch, getState) => {
|
||||
const accessToken = getState().getIn(['meta', 'access_token'], '');
|
||||
const accessToken = getState().getIn(["meta", "access_token"], "");
|
||||
const params = _buildParams(getState());
|
||||
|
||||
if (Object.keys(params).length === 0 || accessToken === '') {
|
||||
if (Object.keys(params).length === 0 || accessToken === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// The Fetch API allows us to perform requests that will be carried out
|
||||
// after the page closes. But that only works if the `keepalive` attribute
|
||||
// is supported.
|
||||
if (window.fetch && 'keepalive' in new Request('')) {
|
||||
fetch('/api/v1/markers', {
|
||||
if (window.fetch && "keepalive" in new Request("")) {
|
||||
fetch("/api/v1/markers", {
|
||||
keepalive: true,
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
@@ -38,13 +38,13 @@ export const synchronouslySubmitMarkers = () => (dispatch, getState) => {
|
||||
// FormData for DoorKeeper to recognize the token.
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('bearer_token', accessToken);
|
||||
formData.append("bearer_token", accessToken);
|
||||
|
||||
for (const [id, value] of Object.entries(params)) {
|
||||
formData.append(`${id}[last_read_id]`, value.last_read_id);
|
||||
}
|
||||
|
||||
if (navigator.sendBeacon('/api/v1/markers', formData)) {
|
||||
if (navigator.sendBeacon("/api/v1/markers", formData)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -54,9 +54,9 @@ export const synchronouslySubmitMarkers = () => (dispatch, getState) => {
|
||||
try {
|
||||
const client = new XMLHttpRequest();
|
||||
|
||||
client.open('POST', '/api/v1/markers', false);
|
||||
client.setRequestHeader('Content-Type', 'application/json');
|
||||
client.setRequestHeader('Authorization', `Bearer ${accessToken}`);
|
||||
client.open("POST", "/api/v1/markers", false);
|
||||
client.setRequestHeader("Content-Type", "application/json");
|
||||
client.setRequestHeader("Authorization", `Bearer ${accessToken}`);
|
||||
client.send(JSON.stringify(params));
|
||||
} catch (e) {
|
||||
// Do not make the BeforeUnload handler error out
|
||||
@@ -66,16 +66,16 @@ export const synchronouslySubmitMarkers = () => (dispatch, getState) => {
|
||||
const _buildParams = (state) => {
|
||||
const params = {};
|
||||
|
||||
const lastHomeId = state.getIn(['timelines', 'home', 'items'], ImmutableList()).find(item => item !== null);
|
||||
const lastNotificationId = state.getIn(['notifications', 'lastReadId']);
|
||||
const lastHomeId = state.getIn(["timelines", "home", "items"], ImmutableList()).find(item => item !== null);
|
||||
const lastNotificationId = state.getIn(["notifications", "lastReadId"]);
|
||||
|
||||
if (lastHomeId && compareId(lastHomeId, state.getIn(['markers', 'home'])) > 0) {
|
||||
if (lastHomeId && compareId(lastHomeId, state.getIn(["markers", "home"])) > 0) {
|
||||
params.home = {
|
||||
last_read_id: lastHomeId,
|
||||
};
|
||||
}
|
||||
|
||||
if (lastNotificationId && compareId(lastNotificationId, state.getIn(['markers', 'notifications'])) > 0) {
|
||||
if (lastNotificationId && compareId(lastNotificationId, state.getIn(["markers", "notifications"])) > 0) {
|
||||
params.notifications = {
|
||||
last_read_id: lastNotificationId,
|
||||
};
|
||||
@@ -85,14 +85,14 @@ const _buildParams = (state) => {
|
||||
};
|
||||
|
||||
const debouncedSubmitMarkers = debounce((dispatch, getState) => {
|
||||
const accessToken = getState().getIn(['meta', 'access_token'], '');
|
||||
const accessToken = getState().getIn(["meta", "access_token"], "");
|
||||
const params = _buildParams(getState());
|
||||
|
||||
if (Object.keys(params).length === 0 || accessToken === '') {
|
||||
if (Object.keys(params).length === 0 || accessToken === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
api(getState).post('/api/v1/markers', params).then(() => {
|
||||
api(getState).post("/api/v1/markers", params).then(() => {
|
||||
dispatch(submitMarkersSuccess(params));
|
||||
}).catch(() => {});
|
||||
}, 300000, { leading: true, trailing: true });
|
||||
@@ -116,11 +116,11 @@ export function submitMarkers(params = {}) {
|
||||
}
|
||||
|
||||
export const fetchMarkers = () => (dispatch, getState) => {
|
||||
const params = { timeline: ['notifications'] };
|
||||
const params = { timeline: ["notifications"] };
|
||||
|
||||
dispatch(fetchMarkersRequest());
|
||||
|
||||
api(getState).get('/api/v1/markers', { params }).then(response => {
|
||||
api(getState).get("/api/v1/markers", { params }).then(response => {
|
||||
dispatch(fetchMarkersSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchMarkersFail(error));
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import { createAction } from "@reduxjs/toolkit";
|
||||
|
||||
import type { ModalProps } from 'mastodon/reducers/modal';
|
||||
import { type ModalProps } from "mastodon/reducers/modal";
|
||||
|
||||
import type { MODAL_COMPONENTS } from '../features/ui/components/modal_root';
|
||||
import { type MODAL_COMPONENTS } from "../features/ui/components/modal_root";
|
||||
|
||||
export type ModalType = keyof typeof MODAL_COMPONENTS;
|
||||
|
||||
interface OpenModalPayload {
|
||||
modalType: ModalType;
|
||||
modalProps: ModalProps;
|
||||
modalType: ModalType,
|
||||
modalProps: ModalProps,
|
||||
}
|
||||
export const openModal = createAction<OpenModalPayload>('MODAL_OPEN');
|
||||
export const openModal = createAction<OpenModalPayload>("MODAL_OPEN");
|
||||
|
||||
interface CloseModalPayload {
|
||||
modalType: ModalType | undefined;
|
||||
ignoreFocus: boolean;
|
||||
modalType: ModalType | undefined,
|
||||
ignoreFocus: boolean,
|
||||
}
|
||||
export const closeModal = createAction<CloseModalPayload>('MODAL_CLOSE');
|
||||
export const closeModal = createAction<CloseModalPayload>("MODAL_CLOSE");
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { openModal } from './modal';
|
||||
import { fetchRelationships } from "./accounts";
|
||||
import { importFetchedAccounts } from "./importer";
|
||||
import { openModal } from "./modal";
|
||||
|
||||
export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';
|
||||
export const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';
|
||||
export const MUTES_FETCH_FAIL = 'MUTES_FETCH_FAIL';
|
||||
export const MUTES_FETCH_REQUEST = "MUTES_FETCH_REQUEST";
|
||||
export const MUTES_FETCH_SUCCESS = "MUTES_FETCH_SUCCESS";
|
||||
export const MUTES_FETCH_FAIL = "MUTES_FETCH_FAIL";
|
||||
|
||||
export const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST';
|
||||
export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS';
|
||||
export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL';
|
||||
export const MUTES_EXPAND_REQUEST = "MUTES_EXPAND_REQUEST";
|
||||
export const MUTES_EXPAND_SUCCESS = "MUTES_EXPAND_SUCCESS";
|
||||
export const MUTES_EXPAND_FAIL = "MUTES_EXPAND_FAIL";
|
||||
|
||||
export const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL';
|
||||
export const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS';
|
||||
export const MUTES_CHANGE_DURATION = 'MUTES_CHANGE_DURATION';
|
||||
export const MUTES_INIT_MODAL = "MUTES_INIT_MODAL";
|
||||
export const MUTES_TOGGLE_HIDE_NOTIFICATIONS = "MUTES_TOGGLE_HIDE_NOTIFICATIONS";
|
||||
export const MUTES_CHANGE_DURATION = "MUTES_CHANGE_DURATION";
|
||||
|
||||
export function fetchMutes() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchMutesRequest());
|
||||
|
||||
api(getState).get('/api/v1/mutes').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
api(getState).get("/api/v1/mutes").then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchMutesSuccess(response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
@@ -52,7 +52,7 @@ export function fetchMutesFail(error) {
|
||||
|
||||
export function expandMutes() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['user_lists', 'mutes', 'next']);
|
||||
const url = getState().getIn(["user_lists", "mutes", "next"]);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
@@ -61,7 +61,7 @@ export function expandMutes() {
|
||||
dispatch(expandMutesRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(expandMutesSuccess(response.data, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
@@ -97,7 +97,7 @@ export function initMuteModal(account) {
|
||||
account,
|
||||
});
|
||||
|
||||
dispatch(openModal({ modalType: 'MUTE' }));
|
||||
dispatch(openModal({ modalType: "MUTE" }));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
import { IntlMessageFormat } from 'intl-messageformat';
|
||||
import { defineMessages } from 'react-intl';
|
||||
import { IntlMessageFormat } from "intl-messageformat";
|
||||
import { defineMessages } from "react-intl";
|
||||
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import { List as ImmutableList } from "immutable";
|
||||
|
||||
import { compareId } from 'mastodon/compare_id';
|
||||
import { usePendingItems as preferPendingItems } from 'mastodon/initial_state';
|
||||
import { compareId } from "mastodon/compare_id";
|
||||
import { usePendingItems as preferPendingItems } from "mastodon/initial_state";
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
import { unescapeHTML } from '../utils/html';
|
||||
import { requestNotificationPermission } from '../utils/notifications';
|
||||
import api, { getLinks } from "../api";
|
||||
import { unescapeHTML } from "../utils/html";
|
||||
import { requestNotificationPermission } from "../utils/notifications";
|
||||
|
||||
import { fetchFollowRequests, fetchRelationships } from './accounts';
|
||||
import { fetchFollowRequests, fetchRelationships } from "./accounts";
|
||||
import {
|
||||
importFetchedAccount,
|
||||
importFetchedAccounts,
|
||||
importFetchedStatus,
|
||||
importFetchedStatuses,
|
||||
} from './importer';
|
||||
import { submitMarkers } from './markers';
|
||||
import { register as registerPushNotifications } from './push_notifications';
|
||||
import { saveSettings } from './settings';
|
||||
} from "./importer";
|
||||
import { submitMarkers } from "./markers";
|
||||
import { register as registerPushNotifications } from "./push_notifications";
|
||||
import { saveSettings } from "./settings";
|
||||
|
||||
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
|
||||
export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';
|
||||
export const NOTIFICATIONS_UPDATE = "NOTIFICATIONS_UPDATE";
|
||||
export const NOTIFICATIONS_UPDATE_NOOP = "NOTIFICATIONS_UPDATE_NOOP";
|
||||
|
||||
export const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST';
|
||||
export const NOTIFICATIONS_EXPAND_SUCCESS = 'NOTIFICATIONS_EXPAND_SUCCESS';
|
||||
export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL';
|
||||
export const NOTIFICATIONS_EXPAND_REQUEST = "NOTIFICATIONS_EXPAND_REQUEST";
|
||||
export const NOTIFICATIONS_EXPAND_SUCCESS = "NOTIFICATIONS_EXPAND_SUCCESS";
|
||||
export const NOTIFICATIONS_EXPAND_FAIL = "NOTIFICATIONS_EXPAND_FAIL";
|
||||
|
||||
export const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET';
|
||||
export const NOTIFICATIONS_FILTER_SET = "NOTIFICATIONS_FILTER_SET";
|
||||
|
||||
export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR';
|
||||
export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP';
|
||||
export const NOTIFICATIONS_LOAD_PENDING = 'NOTIFICATIONS_LOAD_PENDING';
|
||||
export const NOTIFICATIONS_CLEAR = "NOTIFICATIONS_CLEAR";
|
||||
export const NOTIFICATIONS_SCROLL_TOP = "NOTIFICATIONS_SCROLL_TOP";
|
||||
export const NOTIFICATIONS_LOAD_PENDING = "NOTIFICATIONS_LOAD_PENDING";
|
||||
|
||||
export const NOTIFICATIONS_MOUNT = 'NOTIFICATIONS_MOUNT';
|
||||
export const NOTIFICATIONS_UNMOUNT = 'NOTIFICATIONS_UNMOUNT';
|
||||
export const NOTIFICATIONS_MOUNT = "NOTIFICATIONS_MOUNT";
|
||||
export const NOTIFICATIONS_UNMOUNT = "NOTIFICATIONS_UNMOUNT";
|
||||
|
||||
export const NOTIFICATIONS_MARK_AS_READ = 'NOTIFICATIONS_MARK_AS_READ';
|
||||
export const NOTIFICATIONS_MARK_AS_READ = "NOTIFICATIONS_MARK_AS_READ";
|
||||
|
||||
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
||||
export const NOTIFICATIONS_SET_BROWSER_PERMISSION = 'NOTIFICATIONS_SET_BROWSER_PERMISSION';
|
||||
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = "NOTIFICATIONS_SET_BROWSER_SUPPORT";
|
||||
export const NOTIFICATIONS_SET_BROWSER_PERMISSION = "NOTIFICATIONS_SET_BROWSER_PERMISSION";
|
||||
|
||||
defineMessages({
|
||||
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
||||
group: { id: 'notifications.group', defaultMessage: '{count} notifications' },
|
||||
mention: { id: "notification.mention", defaultMessage: "{name} mentioned you" },
|
||||
group: { id: "notifications.group", defaultMessage: "{count} notifications" },
|
||||
});
|
||||
|
||||
const fetchRelatedRelationships = (dispatch, notifications) => {
|
||||
const accountIds = notifications.filter(item => ['follow', 'follow_request', 'admin.sign_up'].indexOf(item.type) !== -1).map(item => item.account.id);
|
||||
const accountIds = notifications.filter(item => ["follow", "follow_request", "admin.sign_up"].indexOf(item.type) !== -1).map(item => item.account.id);
|
||||
|
||||
if (accountIds.length > 0) {
|
||||
dispatch(fetchRelationships(accountIds));
|
||||
@@ -61,24 +61,24 @@ export const loadPending = () => ({
|
||||
|
||||
export function updateNotifications(notification, intlMessages, intlLocale) {
|
||||
return (dispatch, getState) => {
|
||||
const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']);
|
||||
const showInColumn = activeFilter === 'all' ? getState().getIn(['settings', 'notifications', 'shows', notification.type], true) : activeFilter === notification.type;
|
||||
const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true);
|
||||
const playSound = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true);
|
||||
const activeFilter = getState().getIn(["settings", "notifications", "quickFilter", "active"]);
|
||||
const showInColumn = activeFilter === "all" ? getState().getIn(["settings", "notifications", "shows", notification.type], true) : activeFilter === notification.type;
|
||||
const showAlert = getState().getIn(["settings", "notifications", "alerts", notification.type], true);
|
||||
const playSound = getState().getIn(["settings", "notifications", "sounds", notification.type], true);
|
||||
|
||||
let filtered = false;
|
||||
|
||||
if (['mention', 'status'].includes(notification.type) && notification.status.filtered) {
|
||||
const filters = notification.status.filtered.filter(result => result.filter.context.includes('notifications'));
|
||||
if (["mention", "status"].includes(notification.type) && notification.status.filtered) {
|
||||
const filters = notification.status.filtered.filter(result => result.filter.context.includes("notifications"));
|
||||
|
||||
if (filters.some(result => result.filter.filter_action === 'hide')) {
|
||||
if (filters.some(result => result.filter.filter_action === "hide")) {
|
||||
return;
|
||||
}
|
||||
|
||||
filtered = filters.length > 0;
|
||||
}
|
||||
|
||||
if (['follow_request'].includes(notification.type)) {
|
||||
if (["follow_request"].includes(notification.type)) {
|
||||
dispatch(fetchFollowRequests());
|
||||
}
|
||||
|
||||
@@ -99,25 +99,25 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
|
||||
type: NOTIFICATIONS_UPDATE,
|
||||
notification,
|
||||
usePendingItems: preferPendingItems,
|
||||
meta: (playSound && !filtered) ? { sound: 'boop' } : undefined,
|
||||
meta: (playSound && !filtered) ? { sound: "boop" } : undefined,
|
||||
});
|
||||
|
||||
fetchRelatedRelationships(dispatch, [notification]);
|
||||
} else if (playSound && !filtered) {
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_UPDATE_NOOP,
|
||||
meta: { sound: 'boop' },
|
||||
meta: { sound: "boop" },
|
||||
});
|
||||
}
|
||||
|
||||
// Desktop notifications
|
||||
if (typeof window.Notification !== 'undefined' && showAlert && !filtered) {
|
||||
if (typeof window.Notification !== "undefined" && showAlert && !filtered) {
|
||||
const title = new IntlMessageFormat(intlMessages[`notification.${notification.type}`], intlLocale).format({ name: notification.account.display_name.length > 0 ? notification.account.display_name : notification.account.username });
|
||||
const body = (notification.status && notification.status.spoiler_text.length > 0) ? notification.status.spoiler_text : unescapeHTML(notification.status ? notification.status.content : '');
|
||||
const body = (notification.status && notification.status.spoiler_text.length > 0) ? notification.status.spoiler_text : unescapeHTML(notification.status ? notification.status.content : "");
|
||||
|
||||
const notify = new Notification(title, { body, icon: notification.account.avatar, tag: notification.id });
|
||||
|
||||
notify.addEventListener('click', () => {
|
||||
notify.addEventListener("click", () => {
|
||||
window.focus();
|
||||
notify.close();
|
||||
});
|
||||
@@ -125,20 +125,20 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
|
||||
};
|
||||
}
|
||||
|
||||
const excludeTypesFromSettings = state => state.getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();
|
||||
const excludeTypesFromSettings = state => state.getIn(["settings", "notifications", "shows"]).filter(enabled => !enabled).keySeq().toJS();
|
||||
|
||||
const excludeTypesFromFilter = filter => {
|
||||
const allTypes = ImmutableList([
|
||||
'follow',
|
||||
'follow_request',
|
||||
'favourite',
|
||||
'reblog',
|
||||
'mention',
|
||||
'poll',
|
||||
'status',
|
||||
'update',
|
||||
'admin.sign_up',
|
||||
'admin.report',
|
||||
"follow",
|
||||
"follow_request",
|
||||
"favourite",
|
||||
"reblog",
|
||||
"mention",
|
||||
"poll",
|
||||
"status",
|
||||
"update",
|
||||
"admin.sign_up",
|
||||
"admin.report",
|
||||
]);
|
||||
|
||||
return allTypes.filterNot(item => item === filter).toJS();
|
||||
@@ -150,11 +150,11 @@ let expandNotificationsController = new AbortController();
|
||||
|
||||
export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) {
|
||||
return (dispatch, getState) => {
|
||||
const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']);
|
||||
const notifications = getState().get('notifications');
|
||||
const activeFilter = getState().getIn(["settings", "notifications", "quickFilter", "active"]);
|
||||
const notifications = getState().get("notifications");
|
||||
const isLoadingMore = !!maxId;
|
||||
|
||||
if (notifications.get('isLoading')) {
|
||||
if (notifications.get("isLoading")) {
|
||||
if (forceLoad) {
|
||||
expandNotificationsController.abort();
|
||||
expandNotificationsController = new AbortController();
|
||||
@@ -166,14 +166,14 @@ export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) {
|
||||
|
||||
const params = {
|
||||
max_id: maxId,
|
||||
exclude_types: activeFilter === 'all'
|
||||
exclude_types: activeFilter === "all"
|
||||
? excludeTypesFromSettings(getState())
|
||||
: excludeTypesFromFilter(activeFilter),
|
||||
};
|
||||
|
||||
if (!params.max_id && (notifications.get('items', ImmutableList()).size + notifications.get('pendingItems', ImmutableList()).size) > 0) {
|
||||
const a = notifications.getIn(['pendingItems', 0, 'id']);
|
||||
const b = notifications.getIn(['items', 0, 'id']);
|
||||
if (!params.max_id && (notifications.get("items", ImmutableList()).size + notifications.get("pendingItems", ImmutableList()).size) > 0) {
|
||||
const a = notifications.getIn(["pendingItems", 0, "id"]);
|
||||
const b = notifications.getIn(["items", 0, "id"]);
|
||||
|
||||
if (a && b && compareId(a, b) > 0) {
|
||||
params.since_id = a;
|
||||
@@ -186,8 +186,8 @@ export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) {
|
||||
|
||||
dispatch(expandNotificationsRequest(isLoadingMore));
|
||||
|
||||
api(getState).get('/api/v1/notifications', { params, signal: expandNotificationsController.signal }).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
api(getState).get("/api/v1/notifications", { params, signal: expandNotificationsController.signal }).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
|
||||
dispatch(importFetchedAccounts(response.data.map(item => item.account)));
|
||||
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status)));
|
||||
@@ -227,7 +227,7 @@ export function expandNotificationsFail(error, isLoadingMore) {
|
||||
type: NOTIFICATIONS_EXPAND_FAIL,
|
||||
error,
|
||||
skipLoading: !isLoadingMore,
|
||||
skipAlert: !isLoadingMore || error.name === 'AbortError',
|
||||
skipAlert: !isLoadingMore || error.name === "AbortError",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ export function clearNotifications() {
|
||||
type: NOTIFICATIONS_CLEAR,
|
||||
});
|
||||
|
||||
api(getState).post('/api/v1/notifications/clear');
|
||||
api(getState).post("/api/v1/notifications/clear");
|
||||
};
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ export function setFilter (filterType) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_FILTER_SET,
|
||||
path: ['notifications', 'quickFilter', 'active'],
|
||||
path: ["notifications", "quickFilter", "active"],
|
||||
value: filterType,
|
||||
});
|
||||
dispatch(expandNotifications({ forceLoad: true }));
|
||||
@@ -276,13 +276,13 @@ export const markNotificationsAsRead = () => ({
|
||||
// Browser support
|
||||
export function setupBrowserNotifications() {
|
||||
return dispatch => {
|
||||
dispatch(setBrowserSupport('Notification' in window));
|
||||
if ('Notification' in window) {
|
||||
dispatch(setBrowserSupport("Notification" in window));
|
||||
if ("Notification" in window) {
|
||||
dispatch(setBrowserPermission(Notification.permission));
|
||||
}
|
||||
|
||||
if ('Notification' in window && 'permissions' in navigator) {
|
||||
navigator.permissions.query({ name: 'notifications' }).then((status) => {
|
||||
if ("Notification" in window && "permissions" in navigator) {
|
||||
navigator.permissions.query({ name: "notifications" }).then((status) => {
|
||||
status.onchange = () => dispatch(setBrowserPermission(Notification.permission));
|
||||
}).catch(console.warn);
|
||||
}
|
||||
@@ -295,7 +295,7 @@ export function requestBrowserPermission(callback = noOp) {
|
||||
dispatch(setBrowserPermission(permission));
|
||||
callback(permission);
|
||||
|
||||
if (permission === 'granted') {
|
||||
if (permission === "granted") {
|
||||
dispatch(registerPushNotifications());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { changeSetting, saveSettings } from './settings';
|
||||
import { changeSetting, saveSettings } from "./settings";
|
||||
|
||||
export const INTRODUCTION_VERSION = 20181216044202;
|
||||
|
||||
export const closeOnboarding = () => dispatch => {
|
||||
dispatch(changeSetting(['introductionVersion'], INTRODUCTION_VERSION));
|
||||
dispatch(changeSetting(["introductionVersion"], INTRODUCTION_VERSION));
|
||||
dispatch(saveSettings());
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @ts-check
|
||||
|
||||
export const PICTURE_IN_PICTURE_DEPLOY = 'PICTURE_IN_PICTURE_DEPLOY';
|
||||
export const PICTURE_IN_PICTURE_REMOVE = 'PICTURE_IN_PICTURE_REMOVE';
|
||||
export const PICTURE_IN_PICTURE_DEPLOY = "PICTURE_IN_PICTURE_DEPLOY";
|
||||
export const PICTURE_IN_PICTURE_REMOVE = "PICTURE_IN_PICTURE_REMOVE";
|
||||
|
||||
/**
|
||||
* @typedef MediaProps
|
||||
@@ -26,7 +26,7 @@ export const deployPictureInPicture = (statusId, accountId, playerType, props) =
|
||||
// @ts-expect-error
|
||||
return (dispatch, getState) => {
|
||||
// Do not open a player for a toot that does not exist
|
||||
if (getState().hasIn(['statuses', statusId])) {
|
||||
if (getState().hasIn(["statuses", statusId])) {
|
||||
dispatch({
|
||||
type: PICTURE_IN_PICTURE_DEPLOY,
|
||||
statusId,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import api from '../api';
|
||||
import { me } from '../initial_state';
|
||||
import api from "../api";
|
||||
import { me } from "../initial_state";
|
||||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
import { importFetchedStatuses } from "./importer";
|
||||
|
||||
export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';
|
||||
export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';
|
||||
export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';
|
||||
export const PINNED_STATUSES_FETCH_REQUEST = "PINNED_STATUSES_FETCH_REQUEST";
|
||||
export const PINNED_STATUSES_FETCH_SUCCESS = "PINNED_STATUSES_FETCH_SUCCESS";
|
||||
export const PINNED_STATUSES_FETCH_FAIL = "PINNED_STATUSES_FETCH_FAIL";
|
||||
|
||||
export function fetchPinnedStatuses() {
|
||||
return (dispatch, getState) => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { importFetchedPoll } from './importer';
|
||||
import { importFetchedPoll } from "./importer";
|
||||
|
||||
export const POLL_VOTE_REQUEST = 'POLL_VOTE_REQUEST';
|
||||
export const POLL_VOTE_SUCCESS = 'POLL_VOTE_SUCCESS';
|
||||
export const POLL_VOTE_FAIL = 'POLL_VOTE_FAIL';
|
||||
export const POLL_VOTE_REQUEST = "POLL_VOTE_REQUEST";
|
||||
export const POLL_VOTE_SUCCESS = "POLL_VOTE_SUCCESS";
|
||||
export const POLL_VOTE_FAIL = "POLL_VOTE_FAIL";
|
||||
|
||||
export const POLL_FETCH_REQUEST = 'POLL_FETCH_REQUEST';
|
||||
export const POLL_FETCH_SUCCESS = 'POLL_FETCH_SUCCESS';
|
||||
export const POLL_FETCH_FAIL = 'POLL_FETCH_FAIL';
|
||||
export const POLL_FETCH_REQUEST = "POLL_FETCH_REQUEST";
|
||||
export const POLL_FETCH_SUCCESS = "POLL_FETCH_SUCCESS";
|
||||
export const POLL_FETCH_FAIL = "POLL_FETCH_FAIL";
|
||||
|
||||
export const vote = (pollId, choices) => (dispatch, getState) => {
|
||||
dispatch(voteRequest());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { saveSettings } from './registerer';
|
||||
import { setAlerts } from './setter';
|
||||
import { saveSettings } from "./registerer";
|
||||
import { setAlerts } from "./setter";
|
||||
|
||||
export function changeAlerts(path, value) {
|
||||
return dispatch => {
|
||||
@@ -13,5 +13,5 @@ export {
|
||||
SET_BROWSER_SUPPORT,
|
||||
SET_SUBSCRIPTION,
|
||||
SET_ALERTS,
|
||||
} from './setter';
|
||||
export { register } from './registerer';
|
||||
} from "./setter";
|
||||
export { register } from "./registerer";
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import api from '../../api';
|
||||
import { me } from '../../initial_state';
|
||||
import { pushNotificationsSetting } from '../../settings';
|
||||
import { decode as decodeBase64 } from '../../utils/base64';
|
||||
import api from "../../api";
|
||||
import { me } from "../../initial_state";
|
||||
import { pushNotificationsSetting } from "../../settings";
|
||||
import { decode as decodeBase64 } from "../../utils/base64";
|
||||
|
||||
import { setBrowserSupport, setSubscription, clearSubscription } from './setter';
|
||||
import { setBrowserSupport, setSubscription, clearSubscription } from "./setter";
|
||||
|
||||
// Taken from https://www.npmjs.com/package/web-push
|
||||
const urlBase64ToUint8Array = (base64String) => {
|
||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||
const padding = "=".repeat((4 - base64String.length % 4) % 4);
|
||||
const base64 = (base64String + padding)
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
.replace(/-/g, "+")
|
||||
.replace(/_/g, "/");
|
||||
|
||||
return decodeBase64(base64);
|
||||
};
|
||||
|
||||
const getApplicationServerKey = () => document.querySelector('[name="applicationServerKey"]').getAttribute('content');
|
||||
const getApplicationServerKey = () => document.querySelector("[name=\"applicationServerKey\"]").getAttribute("content");
|
||||
|
||||
const getRegistration = () => navigator.serviceWorker.ready;
|
||||
|
||||
@@ -42,11 +42,11 @@ const sendSubscriptionToBackend = (subscription) => {
|
||||
}
|
||||
}
|
||||
|
||||
return api().post('/api/web/push_subscriptions', params).then(response => response.data);
|
||||
return api().post("/api/web/push_subscriptions", params).then(response => response.data);
|
||||
};
|
||||
|
||||
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
|
||||
const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype);
|
||||
const supportsPushNotifications = ("serviceWorker" in navigator && "PushManager" in window && "getKey" in PushSubscription.prototype);
|
||||
|
||||
export function register () {
|
||||
return (dispatch, getState) => {
|
||||
@@ -54,7 +54,7 @@ export function register () {
|
||||
|
||||
if (supportsPushNotifications) {
|
||||
if (!getApplicationServerKey()) {
|
||||
console.error('The VAPID public key is not set. You will not be able to receive Web Push Notifications.');
|
||||
console.error("The VAPID public key is not set. You will not be able to receive Web Push Notifications.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export function register () {
|
||||
// We have a subscription, check if it is still valid
|
||||
const currentServerKey = (new Uint8Array(subscription.options.applicationServerKey)).toString();
|
||||
const subscriptionServerKey = urlBase64ToUint8Array(getApplicationServerKey()).toString();
|
||||
const serverEndpoint = getState().getIn(['push_notifications', 'subscription', 'endpoint']);
|
||||
const serverEndpoint = getState().getIn(["push_notifications", "subscription", "endpoint"]);
|
||||
|
||||
// If the VAPID public key did not change and the endpoint corresponds
|
||||
// to the endpoint saved in the backend, the subscription is valid
|
||||
@@ -93,10 +93,10 @@ export function register () {
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.code === 20 && error.name === 'AbortError') {
|
||||
console.warn('Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.');
|
||||
} else if (error.code === 5 && error.name === 'InvalidCharacterError') {
|
||||
console.error('The VAPID public key seems to be invalid:', getApplicationServerKey());
|
||||
if (error.code === 20 && error.name === "AbortError") {
|
||||
console.warn("Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.");
|
||||
} else if (error.code === 5 && error.name === "InvalidCharacterError") {
|
||||
console.error("The VAPID public key seems to be invalid:", getApplicationServerKey());
|
||||
}
|
||||
|
||||
// Clear alerts and hide UI settings
|
||||
@@ -111,19 +111,19 @@ export function register () {
|
||||
})
|
||||
.catch(console.warn);
|
||||
} else {
|
||||
console.warn('Your browser does not support Web Push Notifications.');
|
||||
console.warn("Your browser does not support Web Push Notifications.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function saveSettings() {
|
||||
return (_, getState) => {
|
||||
const state = getState().get('push_notifications');
|
||||
const subscription = state.get('subscription');
|
||||
const alerts = state.get('alerts');
|
||||
const state = getState().get("push_notifications");
|
||||
const subscription = state.get("subscription");
|
||||
const alerts = state.get("alerts");
|
||||
const data = { alerts };
|
||||
|
||||
api().put(`/api/web/push_subscriptions/${subscription.get('id')}`, {
|
||||
api().put(`/api/web/push_subscriptions/${subscription.get("id")}`, {
|
||||
data,
|
||||
}).then(() => {
|
||||
if (me) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
||||
export const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION';
|
||||
export const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION';
|
||||
export const SET_ALERTS = 'PUSH_NOTIFICATIONS_SET_ALERTS';
|
||||
export const SET_BROWSER_SUPPORT = "PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT";
|
||||
export const SET_SUBSCRIPTION = "PUSH_NOTIFICATIONS_SET_SUBSCRIPTION";
|
||||
export const CLEAR_SUBSCRIPTION = "PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION";
|
||||
export const SET_ALERTS = "PUSH_NOTIFICATIONS_SET_ALERTS";
|
||||
|
||||
export function setBrowserSupport (value) {
|
||||
return {
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { openModal } from './modal';
|
||||
import { openModal } from "./modal";
|
||||
|
||||
export const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST';
|
||||
export const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS';
|
||||
export const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL';
|
||||
export const REPORT_SUBMIT_REQUEST = "REPORT_SUBMIT_REQUEST";
|
||||
export const REPORT_SUBMIT_SUCCESS = "REPORT_SUBMIT_SUCCESS";
|
||||
export const REPORT_SUBMIT_FAIL = "REPORT_SUBMIT_FAIL";
|
||||
|
||||
export const initReport = (account, status) => dispatch =>
|
||||
dispatch(openModal({
|
||||
modalType: 'REPORT',
|
||||
modalType: "REPORT",
|
||||
modalProps: {
|
||||
accountId: account.get('id'),
|
||||
statusId: status?.get('id'),
|
||||
accountId: account.get("id"),
|
||||
statusId: status?.get("id"),
|
||||
},
|
||||
}));
|
||||
|
||||
export const submitReport = (params, onSuccess, onFail) => (dispatch, getState) => {
|
||||
dispatch(submitReportRequest());
|
||||
|
||||
api(getState).post('/api/v1/reports', params).then(response => {
|
||||
api(getState).post("/api/v1/reports", params).then(response => {
|
||||
dispatch(submitReportSuccess(response.data));
|
||||
if (onSuccess) onSuccess();
|
||||
if (onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
}).catch(error => {
|
||||
dispatch(submitReportFail(error));
|
||||
if (onFail) onFail();
|
||||
if (onFail) {
|
||||
onFail();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { fromJS } from 'immutable';
|
||||
import { fromJS } from "immutable";
|
||||
|
||||
import { searchHistory } from 'mastodon/settings';
|
||||
import { searchHistory } from "mastodon/settings";
|
||||
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
||||
import { fetchRelationships } from "./accounts";
|
||||
import { importFetchedAccounts, importFetchedStatuses } from "./importer";
|
||||
|
||||
export const SEARCH_CHANGE = 'SEARCH_CHANGE';
|
||||
export const SEARCH_CLEAR = 'SEARCH_CLEAR';
|
||||
export const SEARCH_SHOW = 'SEARCH_SHOW';
|
||||
export const SEARCH_CHANGE = "SEARCH_CHANGE";
|
||||
export const SEARCH_CLEAR = "SEARCH_CLEAR";
|
||||
export const SEARCH_SHOW = "SEARCH_SHOW";
|
||||
|
||||
export const SEARCH_FETCH_REQUEST = 'SEARCH_FETCH_REQUEST';
|
||||
export const SEARCH_FETCH_SUCCESS = 'SEARCH_FETCH_SUCCESS';
|
||||
export const SEARCH_FETCH_FAIL = 'SEARCH_FETCH_FAIL';
|
||||
export const SEARCH_FETCH_REQUEST = "SEARCH_FETCH_REQUEST";
|
||||
export const SEARCH_FETCH_SUCCESS = "SEARCH_FETCH_SUCCESS";
|
||||
export const SEARCH_FETCH_FAIL = "SEARCH_FETCH_FAIL";
|
||||
|
||||
export const SEARCH_EXPAND_REQUEST = 'SEARCH_EXPAND_REQUEST';
|
||||
export const SEARCH_EXPAND_SUCCESS = 'SEARCH_EXPAND_SUCCESS';
|
||||
export const SEARCH_EXPAND_FAIL = 'SEARCH_EXPAND_FAIL';
|
||||
export const SEARCH_EXPAND_REQUEST = "SEARCH_EXPAND_REQUEST";
|
||||
export const SEARCH_EXPAND_SUCCESS = "SEARCH_EXPAND_SUCCESS";
|
||||
export const SEARCH_EXPAND_FAIL = "SEARCH_EXPAND_FAIL";
|
||||
|
||||
export const SEARCH_HISTORY_UPDATE = 'SEARCH_HISTORY_UPDATE';
|
||||
export const SEARCH_HISTORY_UPDATE = "SEARCH_HISTORY_UPDATE";
|
||||
|
||||
export function changeSearch(value) {
|
||||
return {
|
||||
@@ -36,17 +36,17 @@ export function clearSearch() {
|
||||
|
||||
export function submitSearch(type) {
|
||||
return (dispatch, getState) => {
|
||||
const value = getState().getIn(['search', 'value']);
|
||||
const signedIn = !!getState().getIn(['meta', 'me']);
|
||||
const value = getState().getIn(["search", "value"]);
|
||||
const signedIn = !!getState().getIn(["meta", "me"]);
|
||||
|
||||
if (value.length === 0) {
|
||||
dispatch(fetchSearchSuccess({ accounts: [], statuses: [], hashtags: [] }, '', type));
|
||||
dispatch(fetchSearchSuccess({ accounts: [], statuses: [], hashtags: [] }, "", type));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(fetchSearchRequest(type));
|
||||
|
||||
api(getState).get('/api/v2/search', {
|
||||
api(getState).get("/api/v2/search", {
|
||||
params: {
|
||||
q: value,
|
||||
resolve: signedIn,
|
||||
@@ -94,12 +94,12 @@ export function fetchSearchFail(error) {
|
||||
}
|
||||
|
||||
export const expandSearch = type => (dispatch, getState) => {
|
||||
const value = getState().getIn(['search', 'value']);
|
||||
const offset = getState().getIn(['search', 'results', type]).size - 1;
|
||||
const value = getState().getIn(["search", "value"]);
|
||||
const offset = getState().getIn(["search", "results", type]).size - 1;
|
||||
|
||||
dispatch(expandSearchRequest(type));
|
||||
|
||||
api(getState).get('/api/v2/search', {
|
||||
api(getState).get("/api/v2/search", {
|
||||
params: {
|
||||
q: value,
|
||||
type,
|
||||
@@ -144,7 +144,7 @@ export const showSearch = () => ({
|
||||
});
|
||||
|
||||
export const openURL = (value, history, onFailure) => (dispatch, getState) => {
|
||||
const signedIn = !!getState().getIn(['meta', 'me']);
|
||||
const signedIn = !!getState().getIn(["meta", "me"]);
|
||||
|
||||
if (!signedIn) {
|
||||
if (onFailure) {
|
||||
@@ -156,7 +156,7 @@ export const openURL = (value, history, onFailure) => (dispatch, getState) => {
|
||||
|
||||
dispatch(fetchSearchRequest());
|
||||
|
||||
api(getState).get('/api/v2/search', { params: { q: value, resolve: true } }).then(response => {
|
||||
api(getState).get("/api/v2/search", { params: { q: value, resolve: true } }).then(response => {
|
||||
if (response.data.accounts?.length > 0) {
|
||||
dispatch(importFetchedAccounts(response.data.accounts));
|
||||
history.push(`/@${response.data.accounts[0].acct}`);
|
||||
@@ -178,8 +178,8 @@ export const openURL = (value, history, onFailure) => (dispatch, getState) => {
|
||||
};
|
||||
|
||||
export const clickSearchResult = (q, type) => (dispatch, getState) => {
|
||||
const previous = getState().getIn(['search', 'recent']);
|
||||
const me = getState().getIn(['meta', 'me']);
|
||||
const previous = getState().getIn(["search", "recent"]);
|
||||
const me = getState().getIn(["meta", "me"]);
|
||||
const current = previous.add(fromJS({ type, q })).takeLast(4);
|
||||
|
||||
searchHistory.set(me, current.toJS());
|
||||
@@ -187,9 +187,9 @@ export const clickSearchResult = (q, type) => (dispatch, getState) => {
|
||||
};
|
||||
|
||||
export const forgetSearchResult = q => (dispatch, getState) => {
|
||||
const previous = getState().getIn(['search', 'recent']);
|
||||
const me = getState().getIn(['meta', 'me']);
|
||||
const current = previous.filterNot(result => result.get('q') === q);
|
||||
const previous = getState().getIn(["search", "recent"]);
|
||||
const me = getState().getIn(["meta", "me"]);
|
||||
const current = previous.filterNot(result => result.get("q") === q);
|
||||
|
||||
searchHistory.set(me, current.toJS());
|
||||
dispatch(updateSearchHistory(current));
|
||||
@@ -201,7 +201,7 @@ export const updateSearchHistory = recent => ({
|
||||
});
|
||||
|
||||
export const hydrateSearch = () => (dispatch, getState) => {
|
||||
const me = getState().getIn(['meta', 'me']);
|
||||
const me = getState().getIn(["meta", "me"]);
|
||||
const history = searchHistory.get(me);
|
||||
|
||||
if (history !== null) {
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { importFetchedAccount } from './importer';
|
||||
import { importFetchedAccount } from "./importer";
|
||||
|
||||
export const SERVER_FETCH_REQUEST = 'Server_FETCH_REQUEST';
|
||||
export const SERVER_FETCH_SUCCESS = 'Server_FETCH_SUCCESS';
|
||||
export const SERVER_FETCH_FAIL = 'Server_FETCH_FAIL';
|
||||
export const SERVER_FETCH_REQUEST = "Server_FETCH_REQUEST";
|
||||
export const SERVER_FETCH_SUCCESS = "Server_FETCH_SUCCESS";
|
||||
export const SERVER_FETCH_FAIL = "Server_FETCH_FAIL";
|
||||
|
||||
export const SERVER_DOMAIN_BLOCKS_FETCH_REQUEST = 'SERVER_DOMAIN_BLOCKS_FETCH_REQUEST';
|
||||
export const SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS = 'SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS';
|
||||
export const SERVER_DOMAIN_BLOCKS_FETCH_FAIL = 'SERVER_DOMAIN_BLOCKS_FETCH_FAIL';
|
||||
export const SERVER_DOMAIN_BLOCKS_FETCH_REQUEST = "SERVER_DOMAIN_BLOCKS_FETCH_REQUEST";
|
||||
export const SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS = "SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS";
|
||||
export const SERVER_DOMAIN_BLOCKS_FETCH_FAIL = "SERVER_DOMAIN_BLOCKS_FETCH_FAIL";
|
||||
|
||||
export const fetchServer = () => (dispatch, getState) => {
|
||||
if (getState().getIn(['server', 'server', 'isLoading'])) {
|
||||
if (getState().getIn(["server", "server", "isLoading"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,15 +20,19 @@ export const fetchServer = () => (dispatch, getState) => {
|
||||
/* global data */
|
||||
try {
|
||||
api(getState)
|
||||
.get('/api/v2/instance').then({ data }).catch(error => {
|
||||
.get("/api/v2/instance").then({ data }).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
if (data.contact.account) dispatch(importFetchedAccount(data.contact.account));
|
||||
if (data.contact.account) {
|
||||
dispatch(importFetchedAccount(data.contact.account));
|
||||
}
|
||||
dispatch(fetchServerSuccess(data));
|
||||
} catch (e) {
|
||||
api(getState)
|
||||
.get('/api/v1/instance').then(({ data }) => {
|
||||
if (data.contact_account) dispatch(importFetchedAccount(data.contact_account));
|
||||
.get("/api/v1/instance").then(({ data }) => {
|
||||
if (data.contact_account) {
|
||||
dispatch(importFetchedAccount(data.contact_account));
|
||||
}
|
||||
dispatch(fetchServerSuccess(data));
|
||||
}).catch(err => dispatch(fetchServerFail(err)));
|
||||
}
|
||||
@@ -49,14 +53,14 @@ const fetchServerFail = error => ({
|
||||
});
|
||||
|
||||
export const fetchDomainBlocks = () => (dispatch, getState) => {
|
||||
if (getState().getIn(['server', 'domainBlocks', 'isLoading'])) {
|
||||
if (getState().getIn(["server", "domainBlocks", "isLoading"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(fetchDomainBlocksRequest());
|
||||
|
||||
api(getState)
|
||||
.get('/api/v1/instance/domain_blocks')
|
||||
.get("/api/v1/instance/domain_blocks")
|
||||
.then(({ data }) => dispatch(fetchDomainBlocksSuccess(true, data)))
|
||||
.catch(err => {
|
||||
if (err.response.status === 404) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce } from "lodash";
|
||||
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { showAlertForError } from './alerts';
|
||||
import { showAlertForError } from "./alerts";
|
||||
|
||||
export const SETTING_CHANGE = 'SETTING_CHANGE';
|
||||
export const SETTING_SAVE = 'SETTING_SAVE';
|
||||
export const SETTING_CHANGE = "SETTING_CHANGE";
|
||||
export const SETTING_SAVE = "SETTING_SAVE";
|
||||
|
||||
export function changeSetting(path, value) {
|
||||
return dispatch => {
|
||||
@@ -20,13 +20,13 @@ export function changeSetting(path, value) {
|
||||
}
|
||||
|
||||
const debouncedSave = debounce((dispatch, getState) => {
|
||||
if (getState().getIn(['settings', 'saved'])) {
|
||||
if (getState().getIn(["settings", "saved"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS();
|
||||
const data = getState().get("settings").filter((_, path) => path !== "saved").toJS();
|
||||
|
||||
api().put('/api/web/settings', { data })
|
||||
api().put("/api/web/settings", { data })
|
||||
.then(() => dispatch({ type: SETTING_SAVE }))
|
||||
.catch(error => dispatch(showAlertForError(error)));
|
||||
}, 5000, { trailing: true });
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { ensureComposeIsVisible, setComposeToStatus } from './compose';
|
||||
import { importFetchedStatus, importFetchedStatuses, importFetchedAccount } from './importer';
|
||||
import { deleteFromTimelines } from './timelines';
|
||||
import { ensureComposeIsVisible, setComposeToStatus } from "./compose";
|
||||
import { importFetchedStatus, importFetchedStatuses, importFetchedAccount } from "./importer";
|
||||
import { deleteFromTimelines } from "./timelines";
|
||||
|
||||
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
|
||||
export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS';
|
||||
export const STATUS_FETCH_FAIL = 'STATUS_FETCH_FAIL';
|
||||
export const STATUS_FETCH_REQUEST = "STATUS_FETCH_REQUEST";
|
||||
export const STATUS_FETCH_SUCCESS = "STATUS_FETCH_SUCCESS";
|
||||
export const STATUS_FETCH_FAIL = "STATUS_FETCH_FAIL";
|
||||
|
||||
export const STATUS_DELETE_REQUEST = 'STATUS_DELETE_REQUEST';
|
||||
export const STATUS_DELETE_SUCCESS = 'STATUS_DELETE_SUCCESS';
|
||||
export const STATUS_DELETE_FAIL = 'STATUS_DELETE_FAIL';
|
||||
export const STATUS_DELETE_REQUEST = "STATUS_DELETE_REQUEST";
|
||||
export const STATUS_DELETE_SUCCESS = "STATUS_DELETE_SUCCESS";
|
||||
export const STATUS_DELETE_FAIL = "STATUS_DELETE_FAIL";
|
||||
|
||||
export const CONTEXT_FETCH_REQUEST = 'CONTEXT_FETCH_REQUEST';
|
||||
export const CONTEXT_FETCH_SUCCESS = 'CONTEXT_FETCH_SUCCESS';
|
||||
export const CONTEXT_FETCH_FAIL = 'CONTEXT_FETCH_FAIL';
|
||||
export const CONTEXT_FETCH_REQUEST = "CONTEXT_FETCH_REQUEST";
|
||||
export const CONTEXT_FETCH_SUCCESS = "CONTEXT_FETCH_SUCCESS";
|
||||
export const CONTEXT_FETCH_FAIL = "CONTEXT_FETCH_FAIL";
|
||||
|
||||
export const STATUS_MUTE_REQUEST = 'STATUS_MUTE_REQUEST';
|
||||
export const STATUS_MUTE_SUCCESS = 'STATUS_MUTE_SUCCESS';
|
||||
export const STATUS_MUTE_FAIL = 'STATUS_MUTE_FAIL';
|
||||
export const STATUS_MUTE_REQUEST = "STATUS_MUTE_REQUEST";
|
||||
export const STATUS_MUTE_SUCCESS = "STATUS_MUTE_SUCCESS";
|
||||
export const STATUS_MUTE_FAIL = "STATUS_MUTE_FAIL";
|
||||
|
||||
export const STATUS_UNMUTE_REQUEST = 'STATUS_UNMUTE_REQUEST';
|
||||
export const STATUS_UNMUTE_SUCCESS = 'STATUS_UNMUTE_SUCCESS';
|
||||
export const STATUS_UNMUTE_FAIL = 'STATUS_UNMUTE_FAIL';
|
||||
export const STATUS_UNMUTE_REQUEST = "STATUS_UNMUTE_REQUEST";
|
||||
export const STATUS_UNMUTE_SUCCESS = "STATUS_UNMUTE_SUCCESS";
|
||||
export const STATUS_UNMUTE_FAIL = "STATUS_UNMUTE_FAIL";
|
||||
|
||||
export const STATUS_REVEAL = 'STATUS_REVEAL';
|
||||
export const STATUS_HIDE = 'STATUS_HIDE';
|
||||
export const STATUS_COLLAPSE = 'STATUS_COLLAPSE';
|
||||
export const STATUS_REVEAL = "STATUS_REVEAL";
|
||||
export const STATUS_HIDE = "STATUS_HIDE";
|
||||
export const STATUS_COLLAPSE = "STATUS_COLLAPSE";
|
||||
|
||||
export const REDRAFT = 'REDRAFT';
|
||||
export const REDRAFT = "REDRAFT";
|
||||
|
||||
export const STATUS_FETCH_SOURCE_REQUEST = 'STATUS_FETCH_SOURCE_REQUEST';
|
||||
export const STATUS_FETCH_SOURCE_SUCCESS = 'STATUS_FETCH_SOURCE_SUCCESS';
|
||||
export const STATUS_FETCH_SOURCE_FAIL = 'STATUS_FETCH_SOURCE_FAIL';
|
||||
export const STATUS_FETCH_SOURCE_REQUEST = "STATUS_FETCH_SOURCE_REQUEST";
|
||||
export const STATUS_FETCH_SOURCE_SUCCESS = "STATUS_FETCH_SOURCE_SUCCESS";
|
||||
export const STATUS_FETCH_SOURCE_FAIL = "STATUS_FETCH_SOURCE_FAIL";
|
||||
|
||||
export const STATUS_TRANSLATE_REQUEST = 'STATUS_TRANSLATE_REQUEST';
|
||||
export const STATUS_TRANSLATE_SUCCESS = 'STATUS_TRANSLATE_SUCCESS';
|
||||
export const STATUS_TRANSLATE_FAIL = 'STATUS_TRANSLATE_FAIL';
|
||||
export const STATUS_TRANSLATE_UNDO = 'STATUS_TRANSLATE_UNDO';
|
||||
export const STATUS_TRANSLATE_REQUEST = "STATUS_TRANSLATE_REQUEST";
|
||||
export const STATUS_TRANSLATE_SUCCESS = "STATUS_TRANSLATE_SUCCESS";
|
||||
export const STATUS_TRANSLATE_FAIL = "STATUS_TRANSLATE_FAIL";
|
||||
export const STATUS_TRANSLATE_UNDO = "STATUS_TRANSLATE_UNDO";
|
||||
|
||||
export function fetchStatusRequest(id, skipLoading) {
|
||||
return {
|
||||
@@ -49,7 +49,7 @@ export function fetchStatusRequest(id, skipLoading) {
|
||||
|
||||
export function fetchStatus(id, forceFetch = false) {
|
||||
return (dispatch, getState) => {
|
||||
const skipLoading = !forceFetch && getState().getIn(['statuses', id], null) !== null;
|
||||
const skipLoading = !forceFetch && getState().getIn(["statuses", id], null) !== null;
|
||||
|
||||
dispatch(fetchContext(id));
|
||||
|
||||
@@ -94,10 +94,10 @@ export function redraft(status, raw_text) {
|
||||
}
|
||||
|
||||
export const editStatus = (id, routerHistory) => (dispatch, getState) => {
|
||||
let status = getState().getIn(['statuses', id]);
|
||||
let status = getState().getIn(["statuses", id]);
|
||||
|
||||
if (status.get('poll')) {
|
||||
status = status.set('poll', getState().getIn(['polls', status.get('poll')]));
|
||||
if (status.get("poll")) {
|
||||
status = status.set("poll", getState().getIn(["polls", status.get("poll")]));
|
||||
}
|
||||
|
||||
dispatch(fetchStatusSourceRequest());
|
||||
@@ -126,10 +126,10 @@ export const fetchStatusSourceFail = error => ({
|
||||
|
||||
export function deleteStatus(id, routerHistory, withRedraft = false) {
|
||||
return (dispatch, getState) => {
|
||||
let status = getState().getIn(['statuses', id]);
|
||||
let status = getState().getIn(["statuses", id]);
|
||||
|
||||
if (status.get('poll')) {
|
||||
status = status.set('poll', getState().getIn(['polls', status.get('poll')]));
|
||||
if (status.get("poll")) {
|
||||
status = status.set("poll", getState().getIn(["polls", status.get("poll")]));
|
||||
}
|
||||
|
||||
dispatch(deleteStatusRequest(id));
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Iterable, fromJS } from 'immutable';
|
||||
import { Iterable, fromJS } from "immutable";
|
||||
|
||||
import { hydrateCompose } from './compose';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { hydrateSearch } from './search';
|
||||
import { hydrateCompose } from "./compose";
|
||||
import { importFetchedAccounts } from "./importer";
|
||||
import { hydrateSearch } from "./search";
|
||||
|
||||
export const STORE_HYDRATE = 'STORE_HYDRATE';
|
||||
export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY';
|
||||
export const STORE_HYDRATE = "STORE_HYDRATE";
|
||||
export const STORE_HYDRATE_LAZY = "STORE_HYDRATE_LAZY";
|
||||
|
||||
const convertState = rawState =>
|
||||
fromJS(rawState, (k, v) =>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
// @ts-check
|
||||
|
||||
import { getLocale } from '../locales';
|
||||
import { connectStream } from '../stream';
|
||||
import { getLocale } from "../locales";
|
||||
import { connectStream } from "../stream";
|
||||
|
||||
import {
|
||||
fetchAnnouncements,
|
||||
updateAnnouncements,
|
||||
updateReaction as updateAnnouncementsReaction,
|
||||
deleteAnnouncement,
|
||||
} from './announcements';
|
||||
import { updateConversations } from './conversations';
|
||||
import { updateNotifications, expandNotifications } from './notifications';
|
||||
import { updateStatus } from './statuses';
|
||||
} from "./announcements";
|
||||
import { updateConversations } from "./conversations";
|
||||
import { updateNotifications, expandNotifications } from "./notifications";
|
||||
import { updateStatus } from "./statuses";
|
||||
import {
|
||||
updateTimeline,
|
||||
deleteFromTimelines,
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
fillPublicTimelineGaps,
|
||||
fillCommunityTimelineGaps,
|
||||
fillListTimelineGaps,
|
||||
} from './timelines';
|
||||
} from "./timelines";
|
||||
|
||||
/**
|
||||
* @param {number} max
|
||||
@@ -45,7 +45,7 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
|
||||
const { messages } = getLocale();
|
||||
|
||||
return connectStream(channelName, params, (dispatch, getState) => {
|
||||
const locale = getState().getIn(['meta', 'locale']);
|
||||
const locale = getState().getIn(["meta", "locale"]);
|
||||
|
||||
// @ts-expect-error
|
||||
let pollingId;
|
||||
@@ -87,36 +87,36 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
|
||||
|
||||
onReceive(data) {
|
||||
switch (data.event) {
|
||||
case 'update':
|
||||
case "update":
|
||||
// @ts-expect-error
|
||||
dispatch(updateTimeline(timelineId, JSON.parse(data.payload), options.accept));
|
||||
break;
|
||||
case 'status.update':
|
||||
dispatch(updateTimeline(timelineId, JSON.parse(data.payload), options.accept));
|
||||
break;
|
||||
case "status.update":
|
||||
// @ts-expect-error
|
||||
dispatch(updateStatus(JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'delete':
|
||||
dispatch(deleteFromTimelines(data.payload));
|
||||
break;
|
||||
case 'notification':
|
||||
dispatch(updateStatus(JSON.parse(data.payload)));
|
||||
break;
|
||||
case "delete":
|
||||
dispatch(deleteFromTimelines(data.payload));
|
||||
break;
|
||||
case "notification":
|
||||
// @ts-expect-error
|
||||
dispatch(updateNotifications(JSON.parse(data.payload), messages, locale));
|
||||
break;
|
||||
case 'conversation':
|
||||
dispatch(updateNotifications(JSON.parse(data.payload), messages, locale));
|
||||
break;
|
||||
case "conversation":
|
||||
// @ts-expect-error
|
||||
dispatch(updateConversations(JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'announcement':
|
||||
dispatch(updateConversations(JSON.parse(data.payload)));
|
||||
break;
|
||||
case "announcement":
|
||||
// @ts-expect-error
|
||||
dispatch(updateAnnouncements(JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'announcement.reaction':
|
||||
dispatch(updateAnnouncements(JSON.parse(data.payload)));
|
||||
break;
|
||||
case "announcement.reaction":
|
||||
// @ts-expect-error
|
||||
dispatch(updateAnnouncementsReaction(JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'announcement.delete':
|
||||
dispatch(deleteAnnouncement(data.payload));
|
||||
break;
|
||||
dispatch(updateAnnouncementsReaction(JSON.parse(data.payload)));
|
||||
break;
|
||||
case "announcement.delete":
|
||||
dispatch(deleteAnnouncement(data.payload));
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -128,9 +128,7 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
|
||||
* @param {function(): void} done
|
||||
*/
|
||||
const refreshHomeTimelineAndNotification = (dispatch, done) => {
|
||||
// @ts-expect-error
|
||||
dispatch(expandHomeTimeline({}, () =>
|
||||
// @ts-expect-error
|
||||
dispatch(expandNotifications({}, () =>
|
||||
dispatch(fetchAnnouncements(done))))));
|
||||
};
|
||||
@@ -140,7 +138,7 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
|
||||
*/
|
||||
export const connectUserStream = () =>
|
||||
// @ts-expect-error
|
||||
connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification, fillGaps: fillHomeTimelineGaps });
|
||||
connectTimelineStream("home", "user", {}, { fallback: refreshHomeTimelineAndNotification, fillGaps: fillHomeTimelineGaps });
|
||||
|
||||
/**
|
||||
* @param {Object} options
|
||||
@@ -148,7 +146,7 @@ export const connectUserStream = () =>
|
||||
* @returns {function(): void}
|
||||
*/
|
||||
export const connectCommunityStream = ({ onlyMedia } = {}) =>
|
||||
connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => (fillCommunityTimelineGaps({ onlyMedia })) });
|
||||
connectTimelineStream(`community${onlyMedia ? ":media" : ""}`, `public:local${onlyMedia ? ":media" : ""}`, {}, { fillGaps: () => (fillCommunityTimelineGaps({ onlyMedia })) });
|
||||
|
||||
/**
|
||||
* @param {Object} options
|
||||
@@ -157,7 +155,7 @@ export const connectCommunityStream = ({ onlyMedia } = {}) =>
|
||||
* @returns {function(): void}
|
||||
*/
|
||||
export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) =>
|
||||
connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => fillPublicTimelineGaps({ onlyMedia, onlyRemote }) });
|
||||
connectTimelineStream(`public${onlyRemote ? ":remote" : ""}${onlyMedia ? ":media" : ""}`, `public${onlyRemote ? ":remote" : ""}${onlyMedia ? ":media" : ""}`, {}, { fillGaps: () => fillPublicTimelineGaps({ onlyMedia, onlyRemote }) });
|
||||
|
||||
/**
|
||||
* @param {string} columnId
|
||||
@@ -167,17 +165,17 @@ export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) =>
|
||||
* @returns {function(): void}
|
||||
*/
|
||||
export const connectHashtagStream = (columnId, tagName, onlyLocal, accept) =>
|
||||
connectTimelineStream(`hashtag:${columnId}${onlyLocal ? ':local' : ''}`, `hashtag${onlyLocal ? ':local' : ''}`, { tag: tagName }, { accept });
|
||||
connectTimelineStream(`hashtag:${columnId}${onlyLocal ? ":local" : ""}`, `hashtag${onlyLocal ? ":local" : ""}`, { tag: tagName }, { accept });
|
||||
|
||||
/**
|
||||
* @returns {function(): void}
|
||||
*/
|
||||
export const connectDirectStream = () =>
|
||||
connectTimelineStream('direct', 'direct');
|
||||
connectTimelineStream("direct", "direct");
|
||||
|
||||
/**
|
||||
* @param {string} listId
|
||||
* @returns {function(): void}
|
||||
*/
|
||||
export const connectListStream = listId =>
|
||||
connectTimelineStream(`list:${listId}`, 'list', { list: listId }, { fillGaps: () => fillListTimelineGaps(listId) });
|
||||
connectTimelineStream(`list:${listId}`, "list", { list: listId }, { fillGaps: () => fillListTimelineGaps(listId) });
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import api from '../api';
|
||||
import api from "../api";
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { fetchRelationships } from "./accounts";
|
||||
import { importFetchedAccounts } from "./importer";
|
||||
|
||||
export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST';
|
||||
export const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS';
|
||||
export const SUGGESTIONS_FETCH_FAIL = 'SUGGESTIONS_FETCH_FAIL';
|
||||
export const SUGGESTIONS_FETCH_REQUEST = "SUGGESTIONS_FETCH_REQUEST";
|
||||
export const SUGGESTIONS_FETCH_SUCCESS = "SUGGESTIONS_FETCH_SUCCESS";
|
||||
export const SUGGESTIONS_FETCH_FAIL = "SUGGESTIONS_FETCH_FAIL";
|
||||
|
||||
export const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS';
|
||||
export const SUGGESTIONS_DISMISS = "SUGGESTIONS_DISMISS";
|
||||
|
||||
export function fetchSuggestions(withRelationships = false) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchSuggestionsRequest());
|
||||
|
||||
api(getState).get('/api/v2/suggestions', { params: { limit: 20 } }).then(response => {
|
||||
api(getState).get("/api/v2/suggestions", { params: { limit: 20 } }).then(response => {
|
||||
dispatch(importFetchedAccounts(response.data.map(x => x.account)));
|
||||
dispatch(fetchSuggestionsSuccess(response.data));
|
||||
|
||||
@@ -57,7 +57,7 @@ export const dismissSuggestion = accountId => (dispatch, getState) => {
|
||||
api(getState).delete(`/api/v1/suggestions/${accountId}`).then(() => {
|
||||
dispatch(fetchSuggestionsRequest());
|
||||
|
||||
api(getState).get('/api/v2/suggestions').then(response => {
|
||||
api(getState).get("/api/v2/suggestions").then(response => {
|
||||
dispatch(importFetchedAccounts(response.data.map(x => x.account)));
|
||||
dispatch(fetchSuggestionsSuccess(response.data));
|
||||
}).catch(error => dispatch(fetchSuggestionsFail(error)));
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
export const HASHTAG_FETCH_REQUEST = 'HASHTAG_FETCH_REQUEST';
|
||||
export const HASHTAG_FETCH_SUCCESS = 'HASHTAG_FETCH_SUCCESS';
|
||||
export const HASHTAG_FETCH_FAIL = 'HASHTAG_FETCH_FAIL';
|
||||
export const HASHTAG_FETCH_REQUEST = "HASHTAG_FETCH_REQUEST";
|
||||
export const HASHTAG_FETCH_SUCCESS = "HASHTAG_FETCH_SUCCESS";
|
||||
export const HASHTAG_FETCH_FAIL = "HASHTAG_FETCH_FAIL";
|
||||
|
||||
export const FOLLOWED_HASHTAGS_FETCH_REQUEST = 'FOLLOWED_HASHTAGS_FETCH_REQUEST';
|
||||
export const FOLLOWED_HASHTAGS_FETCH_SUCCESS = 'FOLLOWED_HASHTAGS_FETCH_SUCCESS';
|
||||
export const FOLLOWED_HASHTAGS_FETCH_FAIL = 'FOLLOWED_HASHTAGS_FETCH_FAIL';
|
||||
export const FOLLOWED_HASHTAGS_FETCH_REQUEST = "FOLLOWED_HASHTAGS_FETCH_REQUEST";
|
||||
export const FOLLOWED_HASHTAGS_FETCH_SUCCESS = "FOLLOWED_HASHTAGS_FETCH_SUCCESS";
|
||||
export const FOLLOWED_HASHTAGS_FETCH_FAIL = "FOLLOWED_HASHTAGS_FETCH_FAIL";
|
||||
|
||||
export const FOLLOWED_HASHTAGS_EXPAND_REQUEST = 'FOLLOWED_HASHTAGS_EXPAND_REQUEST';
|
||||
export const FOLLOWED_HASHTAGS_EXPAND_SUCCESS = 'FOLLOWED_HASHTAGS_EXPAND_SUCCESS';
|
||||
export const FOLLOWED_HASHTAGS_EXPAND_FAIL = 'FOLLOWED_HASHTAGS_EXPAND_FAIL';
|
||||
export const FOLLOWED_HASHTAGS_EXPAND_REQUEST = "FOLLOWED_HASHTAGS_EXPAND_REQUEST";
|
||||
export const FOLLOWED_HASHTAGS_EXPAND_SUCCESS = "FOLLOWED_HASHTAGS_EXPAND_SUCCESS";
|
||||
export const FOLLOWED_HASHTAGS_EXPAND_FAIL = "FOLLOWED_HASHTAGS_EXPAND_FAIL";
|
||||
|
||||
export const HASHTAG_FOLLOW_REQUEST = 'HASHTAG_FOLLOW_REQUEST';
|
||||
export const HASHTAG_FOLLOW_SUCCESS = 'HASHTAG_FOLLOW_SUCCESS';
|
||||
export const HASHTAG_FOLLOW_FAIL = 'HASHTAG_FOLLOW_FAIL';
|
||||
export const HASHTAG_FOLLOW_REQUEST = "HASHTAG_FOLLOW_REQUEST";
|
||||
export const HASHTAG_FOLLOW_SUCCESS = "HASHTAG_FOLLOW_SUCCESS";
|
||||
export const HASHTAG_FOLLOW_FAIL = "HASHTAG_FOLLOW_FAIL";
|
||||
|
||||
export const HASHTAG_UNFOLLOW_REQUEST = 'HASHTAG_UNFOLLOW_REQUEST';
|
||||
export const HASHTAG_UNFOLLOW_SUCCESS = 'HASHTAG_UNFOLLOW_SUCCESS';
|
||||
export const HASHTAG_UNFOLLOW_FAIL = 'HASHTAG_UNFOLLOW_FAIL';
|
||||
export const HASHTAG_UNFOLLOW_REQUEST = "HASHTAG_UNFOLLOW_REQUEST";
|
||||
export const HASHTAG_UNFOLLOW_SUCCESS = "HASHTAG_UNFOLLOW_SUCCESS";
|
||||
export const HASHTAG_UNFOLLOW_FAIL = "HASHTAG_UNFOLLOW_FAIL";
|
||||
|
||||
export const fetchHashtag = name => (dispatch, getState) => {
|
||||
dispatch(fetchHashtagRequest());
|
||||
@@ -48,8 +48,8 @@ export const fetchHashtagFail = error => ({
|
||||
export const fetchFollowedHashtags = () => (dispatch, getState) => {
|
||||
dispatch(fetchFollowedHashtagsRequest());
|
||||
|
||||
api(getState).get('/api/v1/followed_tags').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
api(getState).get("/api/v1/followed_tags").then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(fetchFollowedHashtagsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(err => {
|
||||
dispatch(fetchFollowedHashtagsFail(err));
|
||||
@@ -79,7 +79,7 @@ export function fetchFollowedHashtagsFail(error) {
|
||||
|
||||
export function expandFollowedHashtags() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['followed_tags', 'next']);
|
||||
const url = getState().getIn(["followed_tags", "next"]);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
@@ -88,7 +88,7 @@ export function expandFollowedHashtags() {
|
||||
dispatch(expandFollowedHashtagsRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(expandFollowedHashtagsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => {
|
||||
dispatch(expandFollowedHashtagsFail(error));
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from "immutable";
|
||||
|
||||
import api, { getLinks } from 'mastodon/api';
|
||||
import { compareId } from 'mastodon/compare_id';
|
||||
import { usePendingItems as preferPendingItems } from 'mastodon/initial_state';
|
||||
import api, { getLinks } from "mastodon/api";
|
||||
import { compareId } from "mastodon/compare_id";
|
||||
import { usePendingItems as preferPendingItems } from "mastodon/initial_state";
|
||||
|
||||
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||
import { submitMarkers } from './markers';
|
||||
import { importFetchedStatus, importFetchedStatuses } from "./importer";
|
||||
import { submitMarkers } from "./markers";
|
||||
|
||||
export const TIMELINE_UPDATE = 'TIMELINE_UPDATE';
|
||||
export const TIMELINE_DELETE = 'TIMELINE_DELETE';
|
||||
export const TIMELINE_CLEAR = 'TIMELINE_CLEAR';
|
||||
export const TIMELINE_UPDATE = "TIMELINE_UPDATE";
|
||||
export const TIMELINE_DELETE = "TIMELINE_DELETE";
|
||||
export const TIMELINE_CLEAR = "TIMELINE_CLEAR";
|
||||
|
||||
export const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST';
|
||||
export const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS';
|
||||
export const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL';
|
||||
export const TIMELINE_EXPAND_REQUEST = "TIMELINE_EXPAND_REQUEST";
|
||||
export const TIMELINE_EXPAND_SUCCESS = "TIMELINE_EXPAND_SUCCESS";
|
||||
export const TIMELINE_EXPAND_FAIL = "TIMELINE_EXPAND_FAIL";
|
||||
|
||||
export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP';
|
||||
export const TIMELINE_LOAD_PENDING = 'TIMELINE_LOAD_PENDING';
|
||||
export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
|
||||
export const TIMELINE_CONNECT = 'TIMELINE_CONNECT';
|
||||
export const TIMELINE_SCROLL_TOP = "TIMELINE_SCROLL_TOP";
|
||||
export const TIMELINE_LOAD_PENDING = "TIMELINE_LOAD_PENDING";
|
||||
export const TIMELINE_DISCONNECT = "TIMELINE_DISCONNECT";
|
||||
export const TIMELINE_CONNECT = "TIMELINE_CONNECT";
|
||||
|
||||
export const TIMELINE_MARK_AS_PARTIAL = 'TIMELINE_MARK_AS_PARTIAL';
|
||||
export const TIMELINE_MARK_AS_PARTIAL = "TIMELINE_MARK_AS_PARTIAL";
|
||||
|
||||
export const loadPending = timeline => ({
|
||||
type: TIMELINE_LOAD_PENDING,
|
||||
@@ -29,11 +29,11 @@ export const loadPending = timeline => ({
|
||||
|
||||
export function updateTimeline(timeline, status, accept) {
|
||||
return (dispatch, getState) => {
|
||||
if (typeof accept === 'function' && !accept(status)) {
|
||||
if (typeof accept === "function" && !accept(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getState().getIn(['timelines', timeline, 'isPartial'])) {
|
||||
if (getState().getIn(["timelines", timeline, "isPartial"])) {
|
||||
// Prevent new items from being added to a partial timeline,
|
||||
// since it will be reloaded anyway
|
||||
|
||||
@@ -49,7 +49,7 @@ export function updateTimeline(timeline, status, accept) {
|
||||
usePendingItems: preferPendingItems,
|
||||
});
|
||||
|
||||
if (timeline === 'home') {
|
||||
if (timeline === "home") {
|
||||
dispatch(submitMarkers());
|
||||
}
|
||||
};
|
||||
@@ -57,9 +57,9 @@ export function updateTimeline(timeline, status, accept) {
|
||||
|
||||
export function deleteFromTimelines(id) {
|
||||
return (dispatch, getState) => {
|
||||
const accountId = getState().getIn(['statuses', id, 'account']);
|
||||
const references = getState().get('statuses').filter(status => status.get('reblog') === id).map(status => status.get('id'));
|
||||
const reblogOf = getState().getIn(['statuses', id, 'reblog'], null);
|
||||
const accountId = getState().getIn(["statuses", id, "account"]);
|
||||
const references = getState().get("statuses").filter(status => status.get("reblog") === id).map(status => status.get("id"));
|
||||
const reblogOf = getState().getIn(["statuses", id, "reblog"], null);
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_DELETE,
|
||||
@@ -87,17 +87,17 @@ const parseTags = (tags = {}, mode) => {
|
||||
|
||||
export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
||||
return (dispatch, getState) => {
|
||||
const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
|
||||
const timeline = getState().getIn(["timelines", timelineId], ImmutableMap());
|
||||
const isLoadingMore = !!params.max_id;
|
||||
|
||||
if (timeline.get('isLoading')) {
|
||||
if (timeline.get("isLoading")) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.max_id && !params.pinned && (timeline.get('items', ImmutableList()).size + timeline.get('pendingItems', ImmutableList()).size) > 0) {
|
||||
const a = timeline.getIn(['pendingItems', 0]);
|
||||
const b = timeline.getIn(['items', 0]);
|
||||
if (!params.max_id && !params.pinned && (timeline.get("items", ImmutableList()).size + timeline.get("pendingItems", ImmutableList()).size) > 0) {
|
||||
const a = timeline.getIn(["pendingItems", 0]);
|
||||
const b = timeline.getIn(["items", 0]);
|
||||
|
||||
if (a && b && compareId(a, b) > 0) {
|
||||
params.since_id = a;
|
||||
@@ -111,11 +111,11 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
||||
dispatch(expandTimelineRequest(timelineId, isLoadingMore));
|
||||
|
||||
api(getState).get(path, { params }).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedStatuses(response.data));
|
||||
dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.status === 206, isLoadingRecent, isLoadingMore, isLoadingRecent && preferPendingItems));
|
||||
|
||||
if (timelineId === 'home') {
|
||||
if (timelineId === "home") {
|
||||
dispatch(submitMarkers());
|
||||
}
|
||||
}).catch(error => {
|
||||
@@ -128,8 +128,8 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
||||
|
||||
export function fillTimelineGaps(timelineId, path, params = {}, done = noOp) {
|
||||
return (dispatch, getState) => {
|
||||
const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
|
||||
const items = timeline.get('items');
|
||||
const timeline = getState().getIn(["timelines", timelineId], ImmutableMap());
|
||||
const items = timeline.get("items");
|
||||
const nullIndexes = items.map((statusId, index) => statusId === null ? index : null);
|
||||
const gaps = nullIndexes.map(index => index > 0 ? items.get(index - 1) : null);
|
||||
|
||||
@@ -142,26 +142,26 @@ export function fillTimelineGaps(timelineId, path, params = {}, done = noOp) {
|
||||
};
|
||||
}
|
||||
|
||||
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
||||
export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||
export const expandAccountTimeline = (accountId, { maxId, withReplies, tagged } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, exclude_reblogs: withReplies, tagged, max_id: maxId });
|
||||
export const expandAccountFeaturedTimeline = (accountId, { tagged } = {}) => expandTimeline(`account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true, tagged });
|
||||
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline("home", "/api/v1/timelines/home", { max_id: maxId }, done);
|
||||
export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ":remote" : ""}${onlyMedia ? ":media" : ""}`, "/api/v1/timelines/public", { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ":media" : ""}`, "/api/v1/timelines/public", { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||
export const expandAccountTimeline = (accountId, { maxId, withReplies, tagged } = {}) => expandTimeline(`account:${accountId}${withReplies ? ":with_replies" : ""}${tagged ? `:${tagged}` : ""}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, exclude_reblogs: withReplies, tagged, max_id: maxId });
|
||||
export const expandAccountFeaturedTimeline = (accountId, { tagged } = {}) => expandTimeline(`account:${accountId}:pinned${tagged ? `:${tagged}` : ""}`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true, tagged });
|
||||
export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 });
|
||||
export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done);
|
||||
export const expandHashtagTimeline = (hashtag, { maxId, tags, local } = {}, done = noOp) => {
|
||||
return expandTimeline(`hashtag:${hashtag}${local ? ':local' : ''}`, `/api/v1/timelines/tag/${hashtag}`, {
|
||||
return expandTimeline(`hashtag:${hashtag}${local ? ":local" : ""}`, `/api/v1/timelines/tag/${hashtag}`, {
|
||||
max_id: maxId,
|
||||
any: parseTags(tags, 'any'),
|
||||
all: parseTags(tags, 'all'),
|
||||
none: parseTags(tags, 'none'),
|
||||
any: parseTags(tags, "any"),
|
||||
all: parseTags(tags, "all"),
|
||||
none: parseTags(tags, "none"),
|
||||
local: local,
|
||||
}, done);
|
||||
};
|
||||
|
||||
export const fillHomeTimelineGaps = (done = noOp) => fillTimelineGaps('home', '/api/v1/timelines/home', {}, done);
|
||||
export const fillPublicTimelineGaps = ({ onlyMedia, onlyRemote } = {}, done = noOp) => fillTimelineGaps(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, only_media: !!onlyMedia }, done);
|
||||
export const fillCommunityTimelineGaps = ({ onlyMedia } = {}, done = noOp) => fillTimelineGaps(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, only_media: !!onlyMedia }, done);
|
||||
export const fillHomeTimelineGaps = (done = noOp) => fillTimelineGaps("home", "/api/v1/timelines/home", {}, done);
|
||||
export const fillPublicTimelineGaps = ({ onlyMedia, onlyRemote } = {}, done = noOp) => fillTimelineGaps(`public${onlyRemote ? ":remote" : ""}${onlyMedia ? ":media" : ""}`, "/api/v1/timelines/public", { remote: !!onlyRemote, only_media: !!onlyMedia }, done);
|
||||
export const fillCommunityTimelineGaps = ({ onlyMedia } = {}, done = noOp) => fillTimelineGaps(`community${onlyMedia ? ":media" : ""}`, "/api/v1/timelines/public", { local: true, only_media: !!onlyMedia }, done);
|
||||
export const fillListTimelineGaps = (id, done = noOp) => fillTimelineGaps(`list:${id}`, `/api/v1/timelines/list/${id}`, {}, done);
|
||||
|
||||
export function expandTimelineRequest(timeline, isLoadingMore) {
|
||||
@@ -191,7 +191,7 @@ export function expandTimelineFail(timeline, error, isLoadingMore) {
|
||||
timeline,
|
||||
error,
|
||||
skipLoading: !isLoadingMore,
|
||||
skipNotFound: timeline.startsWith('account:'),
|
||||
skipNotFound: timeline.startsWith("account:"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import api, { getLinks } from "../api";
|
||||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
import { importFetchedStatuses } from "./importer";
|
||||
|
||||
export const TRENDS_TAGS_FETCH_REQUEST = 'TRENDS_TAGS_FETCH_REQUEST';
|
||||
export const TRENDS_TAGS_FETCH_SUCCESS = 'TRENDS_TAGS_FETCH_SUCCESS';
|
||||
export const TRENDS_TAGS_FETCH_FAIL = 'TRENDS_TAGS_FETCH_FAIL';
|
||||
export const TRENDS_TAGS_FETCH_REQUEST = "TRENDS_TAGS_FETCH_REQUEST";
|
||||
export const TRENDS_TAGS_FETCH_SUCCESS = "TRENDS_TAGS_FETCH_SUCCESS";
|
||||
export const TRENDS_TAGS_FETCH_FAIL = "TRENDS_TAGS_FETCH_FAIL";
|
||||
|
||||
export const TRENDS_LINKS_FETCH_REQUEST = 'TRENDS_LINKS_FETCH_REQUEST';
|
||||
export const TRENDS_LINKS_FETCH_SUCCESS = 'TRENDS_LINKS_FETCH_SUCCESS';
|
||||
export const TRENDS_LINKS_FETCH_FAIL = 'TRENDS_LINKS_FETCH_FAIL';
|
||||
export const TRENDS_LINKS_FETCH_REQUEST = "TRENDS_LINKS_FETCH_REQUEST";
|
||||
export const TRENDS_LINKS_FETCH_SUCCESS = "TRENDS_LINKS_FETCH_SUCCESS";
|
||||
export const TRENDS_LINKS_FETCH_FAIL = "TRENDS_LINKS_FETCH_FAIL";
|
||||
|
||||
export const TRENDS_STATUSES_FETCH_REQUEST = 'TRENDS_STATUSES_FETCH_REQUEST';
|
||||
export const TRENDS_STATUSES_FETCH_SUCCESS = 'TRENDS_STATUSES_FETCH_SUCCESS';
|
||||
export const TRENDS_STATUSES_FETCH_FAIL = 'TRENDS_STATUSES_FETCH_FAIL';
|
||||
export const TRENDS_STATUSES_FETCH_REQUEST = "TRENDS_STATUSES_FETCH_REQUEST";
|
||||
export const TRENDS_STATUSES_FETCH_SUCCESS = "TRENDS_STATUSES_FETCH_SUCCESS";
|
||||
export const TRENDS_STATUSES_FETCH_FAIL = "TRENDS_STATUSES_FETCH_FAIL";
|
||||
|
||||
export const TRENDS_STATUSES_EXPAND_REQUEST = 'TRENDS_STATUSES_EXPAND_REQUEST';
|
||||
export const TRENDS_STATUSES_EXPAND_SUCCESS = 'TRENDS_STATUSES_EXPAND_SUCCESS';
|
||||
export const TRENDS_STATUSES_EXPAND_FAIL = 'TRENDS_STATUSES_EXPAND_FAIL';
|
||||
export const TRENDS_STATUSES_EXPAND_REQUEST = "TRENDS_STATUSES_EXPAND_REQUEST";
|
||||
export const TRENDS_STATUSES_EXPAND_SUCCESS = "TRENDS_STATUSES_EXPAND_SUCCESS";
|
||||
export const TRENDS_STATUSES_EXPAND_FAIL = "TRENDS_STATUSES_EXPAND_FAIL";
|
||||
|
||||
export const fetchTrendingHashtags = () => (dispatch, getState) => {
|
||||
dispatch(fetchTrendingHashtagsRequest());
|
||||
|
||||
api(getState)
|
||||
.get('/api/v1/trends/tags')
|
||||
.get("/api/v1/trends/tags")
|
||||
.then(({ data }) => dispatch(fetchTrendingHashtagsSuccess(data)))
|
||||
.catch(err => dispatch(fetchTrendingHashtagsFail(err)));
|
||||
};
|
||||
@@ -49,7 +49,7 @@ export const fetchTrendingLinks = () => (dispatch, getState) => {
|
||||
dispatch(fetchTrendingLinksRequest());
|
||||
|
||||
api(getState)
|
||||
.get('/api/v1/trends/links')
|
||||
.get("/api/v1/trends/links")
|
||||
.then(({ data }) => dispatch(fetchTrendingLinksSuccess(data)))
|
||||
.catch(err => dispatch(fetchTrendingLinksFail(err)));
|
||||
};
|
||||
@@ -73,14 +73,14 @@ export const fetchTrendingLinksFail = error => ({
|
||||
});
|
||||
|
||||
export const fetchTrendingStatuses = () => (dispatch, getState) => {
|
||||
if (getState().getIn(['status_lists', 'trending', 'isLoading'])) {
|
||||
if (getState().getIn(["status_lists", "trending", "isLoading"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(fetchTrendingStatusesRequest());
|
||||
|
||||
api(getState).get('/api/v1/trends/statuses').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
api(getState).get("/api/v1/trends/statuses").then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedStatuses(response.data));
|
||||
dispatch(fetchTrendingStatusesSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(err => dispatch(fetchTrendingStatusesFail(err)));
|
||||
@@ -107,16 +107,16 @@ export const fetchTrendingStatusesFail = error => ({
|
||||
|
||||
|
||||
export const expandTrendingStatuses = () => (dispatch, getState) => {
|
||||
const url = getState().getIn(['status_lists', 'trending', 'next'], null);
|
||||
const url = getState().getIn(["status_lists", "trending", "next"], null);
|
||||
|
||||
if (url === null || getState().getIn(['status_lists', 'trending', 'isLoading'])) {
|
||||
if (url === null || getState().getIn(["status_lists", "trending", "isLoading"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(expandTrendingStatusesRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
const next = getLinks(response).refs.find(link => link.rel === "next");
|
||||
dispatch(importFetchedStatuses(response.data));
|
||||
dispatch(expandTrendingStatusesSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios';
|
||||
import axios from 'axios';
|
||||
import LinkHeader from 'http-link-header';
|
||||
import { type AxiosResponse, type RawAxiosRequestHeaders } from "axios";
|
||||
import axios from "axios";
|
||||
import LinkHeader from "http-link-header";
|
||||
|
||||
import ready from './ready';
|
||||
import type { GetState } from './store';
|
||||
import ready from "./ready";
|
||||
import { type GetState } from "./store";
|
||||
|
||||
export const getLinks = (response: AxiosResponse) => {
|
||||
const value = response.headers.link as string | undefined;
|
||||
@@ -19,11 +19,11 @@ const csrfHeader: RawAxiosRequestHeaders = {};
|
||||
|
||||
const setCSRFHeader = () => {
|
||||
const csrfToken = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name=csrf-token]',
|
||||
"meta[name=csrf-token]",
|
||||
);
|
||||
|
||||
if (csrfToken) {
|
||||
csrfHeader['X-CSRF-Token'] = csrfToken.content;
|
||||
csrfHeader["X-CSRF-Token"] = csrfToken.content;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ void ready(setCSRFHeader);
|
||||
|
||||
const authorizationHeaderFromState = (getState?: GetState) => {
|
||||
const accessToken =
|
||||
getState && (getState().meta.get('access_token', '') as string);
|
||||
getState && (getState().meta.get("access_token", "") as string);
|
||||
|
||||
if (!accessToken) {
|
||||
return {};
|
||||
@@ -42,7 +42,6 @@ const authorizationHeaderFromState = (getState?: GetState) => {
|
||||
} as RawAxiosRequestHeaders;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function api(getState: GetState) {
|
||||
return axios.create({
|
||||
headers: {
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
import type { ApiCustomEmojiJSON } from './custom_emoji';
|
||||
import { type ApiCustomEmojiJSON } from "./custom_emoji";
|
||||
|
||||
export interface ApiAccountFieldJSON {
|
||||
name: string;
|
||||
value: string;
|
||||
verified_at: string | null;
|
||||
name: string,
|
||||
value: string,
|
||||
verified_at: string | null,
|
||||
}
|
||||
|
||||
export interface ApiAccountRoleJSON {
|
||||
color: string;
|
||||
id: string;
|
||||
name: string;
|
||||
color: string,
|
||||
id: string,
|
||||
name: string,
|
||||
}
|
||||
|
||||
// See app/serializers/rest/account_serializer.rb
|
||||
export interface ApiAccountJSON {
|
||||
acct: string;
|
||||
avatar: string;
|
||||
avatar_static: string;
|
||||
bot: boolean;
|
||||
created_at: string;
|
||||
discoverable: boolean;
|
||||
display_name: string;
|
||||
emojis: ApiCustomEmojiJSON[];
|
||||
fields: ApiAccountFieldJSON[];
|
||||
followers_count: number;
|
||||
following_count: number;
|
||||
group: boolean;
|
||||
header: string;
|
||||
header_static: string;
|
||||
id: string;
|
||||
last_status_at: string;
|
||||
locked: boolean;
|
||||
noindex: boolean;
|
||||
note: string;
|
||||
roles: ApiAccountJSON[];
|
||||
statuses_count: number;
|
||||
uri: string;
|
||||
url: string;
|
||||
username: string;
|
||||
moved?: ApiAccountJSON;
|
||||
suspended?: boolean;
|
||||
limited?: boolean;
|
||||
memorial?: boolean;
|
||||
acct: string,
|
||||
avatar: string,
|
||||
avatar_static: string,
|
||||
bot: boolean,
|
||||
created_at: string,
|
||||
discoverable: boolean,
|
||||
display_name: string,
|
||||
emojis: ApiCustomEmojiJSON[],
|
||||
fields: ApiAccountFieldJSON[],
|
||||
followers_count: number,
|
||||
following_count: number,
|
||||
group: boolean,
|
||||
header: string,
|
||||
header_static: string,
|
||||
id: string,
|
||||
last_status_at: string,
|
||||
locked: boolean,
|
||||
noindex: boolean,
|
||||
note: string,
|
||||
roles: ApiAccountJSON[],
|
||||
statuses_count: number,
|
||||
uri: string,
|
||||
url: string,
|
||||
username: string,
|
||||
moved?: ApiAccountJSON,
|
||||
suspended?: boolean,
|
||||
limited?: boolean,
|
||||
memorial?: boolean,
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// See app/serializers/rest/account_serializer.rb
|
||||
export interface ApiCustomEmojiJSON {
|
||||
shortcode: string;
|
||||
static_url: string;
|
||||
url: string;
|
||||
category?: string;
|
||||
visible_in_picker: boolean;
|
||||
shortcode: string,
|
||||
static_url: string,
|
||||
url: string,
|
||||
category?: string,
|
||||
visible_in_picker: boolean,
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
// See app/serializers/rest/relationship_serializer.rb
|
||||
export interface ApiRelationshipJSON {
|
||||
blocked_by: boolean;
|
||||
blocking: boolean;
|
||||
domain_blocking: boolean;
|
||||
endorsed: boolean;
|
||||
followed_by: boolean;
|
||||
following: boolean;
|
||||
id: string;
|
||||
languages: string[] | null;
|
||||
muting_notifications: boolean;
|
||||
muting: boolean;
|
||||
note: string;
|
||||
notifying: boolean;
|
||||
requested_by: boolean;
|
||||
requested: boolean;
|
||||
showing_reblogs: boolean;
|
||||
blocked_by: boolean,
|
||||
blocking: boolean,
|
||||
domain_blocking: boolean,
|
||||
endorsed: boolean,
|
||||
followed_by: boolean,
|
||||
following: boolean,
|
||||
id: string,
|
||||
languages: string[] | null,
|
||||
muting_notifications: boolean,
|
||||
muting: boolean,
|
||||
note: string,
|
||||
notifying: boolean,
|
||||
requested_by: boolean,
|
||||
requested: boolean,
|
||||
showing_reblogs: boolean,
|
||||
}
|
||||
|
||||
@@ -1,87 +1,87 @@
|
||||
const DIGIT_CHARACTERS = [
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'I',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'M',
|
||||
'N',
|
||||
'O',
|
||||
'P',
|
||||
'Q',
|
||||
'R',
|
||||
'S',
|
||||
'T',
|
||||
'U',
|
||||
'V',
|
||||
'W',
|
||||
'X',
|
||||
'Y',
|
||||
'Z',
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
'#',
|
||||
'$',
|
||||
'%',
|
||||
'*',
|
||||
'+',
|
||||
',',
|
||||
'-',
|
||||
'.',
|
||||
':',
|
||||
';',
|
||||
'=',
|
||||
'?',
|
||||
'@',
|
||||
'[',
|
||||
']',
|
||||
'^',
|
||||
'_',
|
||||
'{',
|
||||
'|',
|
||||
'}',
|
||||
'~',
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z",
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"e",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"i",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
"#",
|
||||
"$",
|
||||
"%",
|
||||
"*",
|
||||
"+",
|
||||
",",
|
||||
"-",
|
||||
".",
|
||||
":",
|
||||
";",
|
||||
"=",
|
||||
"?",
|
||||
"@",
|
||||
"[",
|
||||
"]",
|
||||
"^",
|
||||
"_",
|
||||
"{",
|
||||
"|",
|
||||
"}",
|
||||
"~",
|
||||
];
|
||||
|
||||
export const decode83 = (str: string) => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Rails from '@rails/ujs';
|
||||
import 'font-awesome/css/font-awesome.css';
|
||||
import Rails from "@rails/ujs";
|
||||
import "font-awesome/css/font-awesome.css";
|
||||
|
||||
export function start() {
|
||||
require.context('../images/', true);
|
||||
require.context("../images/", true);
|
||||
|
||||
try {
|
||||
Rails.start();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import renderer from 'react-test-renderer';
|
||||
import renderer from "react-test-renderer";
|
||||
|
||||
import AutosuggestEmoji from '../autosuggest_emoji';
|
||||
import AutosuggestEmoji from "../autosuggest_emoji";
|
||||
|
||||
describe('<AutosuggestEmoji />', () => {
|
||||
it('renders native emoji', () => {
|
||||
describe("<AutosuggestEmoji />", () => {
|
||||
it("renders native emoji", () => {
|
||||
const emoji = {
|
||||
native: '💙',
|
||||
colons: ':foobar:',
|
||||
native: "💙",
|
||||
colons: ":foobar:",
|
||||
};
|
||||
const component = renderer.create(<AutosuggestEmoji emoji={emoji} />);
|
||||
const tree = component.toJSON();
|
||||
@@ -14,12 +14,12 @@ describe('<AutosuggestEmoji />', () => {
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders emoji with custom url', () => {
|
||||
it("renders emoji with custom url", () => {
|
||||
const emoji = {
|
||||
custom: true,
|
||||
imageUrl: 'http://example.com/emoji.png',
|
||||
native: 'foobar',
|
||||
colons: ':foobar:',
|
||||
imageUrl: "http://example.com/emoji.png",
|
||||
native: "foobar",
|
||||
colons: ":foobar:",
|
||||
};
|
||||
const component = renderer.create(<AutosuggestEmoji emoji={emoji} />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { fromJS } from 'immutable';
|
||||
import { fromJS } from "immutable";
|
||||
|
||||
import renderer from 'react-test-renderer';
|
||||
import renderer from "react-test-renderer";
|
||||
|
||||
import { Avatar } from '../avatar';
|
||||
import { Avatar } from "../avatar";
|
||||
|
||||
describe('<Avatar />', () => {
|
||||
describe("<Avatar />", () => {
|
||||
const account = fromJS({
|
||||
username: 'alice',
|
||||
acct: 'alice',
|
||||
display_name: 'Alice',
|
||||
avatar: '/animated/alice.gif',
|
||||
avatar_static: '/static/alice.jpg',
|
||||
username: "alice",
|
||||
acct: "alice",
|
||||
display_name: "Alice",
|
||||
avatar: "/animated/alice.gif",
|
||||
avatar_static: "/static/alice.jpg",
|
||||
});
|
||||
|
||||
const size = 100;
|
||||
|
||||
describe('Autoplay', () => {
|
||||
it('renders a animated avatar', () => {
|
||||
describe("Autoplay", () => {
|
||||
it("renders a animated avatar", () => {
|
||||
const component = renderer.create(<Avatar account={account} animate size={size} />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
@@ -24,8 +24,8 @@ describe('<Avatar />', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Still', () => {
|
||||
it('renders a still avatar', () => {
|
||||
describe("Still", () => {
|
||||
it("renders a still avatar", () => {
|
||||
const component = renderer.create(<Avatar account={account} size={size} />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import { fromJS } from 'immutable';
|
||||
import { fromJS } from "immutable";
|
||||
|
||||
import renderer from 'react-test-renderer';
|
||||
import renderer from "react-test-renderer";
|
||||
|
||||
import { AvatarOverlay } from '../avatar_overlay';
|
||||
import { AvatarOverlay } from "../avatar_overlay";
|
||||
|
||||
describe('<AvatarOverlay', () => {
|
||||
describe("<AvatarOverlay", () => {
|
||||
const account = fromJS({
|
||||
username: 'alice',
|
||||
acct: 'alice',
|
||||
display_name: 'Alice',
|
||||
avatar: '/animated/alice.gif',
|
||||
avatar_static: '/static/alice.jpg',
|
||||
username: "alice",
|
||||
acct: "alice",
|
||||
display_name: "Alice",
|
||||
avatar: "/animated/alice.gif",
|
||||
avatar_static: "/static/alice.jpg",
|
||||
});
|
||||
|
||||
const friend = fromJS({
|
||||
username: 'eve',
|
||||
acct: 'eve@blackhat.lair',
|
||||
display_name: 'Evelyn',
|
||||
avatar: '/animated/eve.gif',
|
||||
avatar_static: '/static/eve.jpg',
|
||||
username: "eve",
|
||||
acct: "eve@blackhat.lair",
|
||||
display_name: "Evelyn",
|
||||
avatar: "/animated/eve.gif",
|
||||
avatar_static: "/static/eve.jpg",
|
||||
});
|
||||
|
||||
it('renders a overlay avatar', () => {
|
||||
it("renders a overlay avatar", () => {
|
||||
const component = renderer.create(<AvatarOverlay account={account} friend={friend} />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
import { render, fireEvent, screen } from '@testing-library/react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import { render, fireEvent, screen } from "@testing-library/react";
|
||||
import renderer from "react-test-renderer";
|
||||
|
||||
import Button from '../button';
|
||||
import Button from "../button";
|
||||
|
||||
describe('<Button />', () => {
|
||||
it('renders a button element', () => {
|
||||
describe("<Button />", () => {
|
||||
it("renders a button element", () => {
|
||||
const component = renderer.create(<Button />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders the given text', () => {
|
||||
const text = 'foo';
|
||||
it("renders the given text", () => {
|
||||
const text = "foo";
|
||||
const component = renderer.create(<Button text={text} />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('handles click events using the given handler', () => {
|
||||
it("handles click events using the given handler", () => {
|
||||
const handler = jest.fn();
|
||||
render(<Button onClick={handler}>button</Button>);
|
||||
fireEvent.click(screen.getByText('button'));
|
||||
fireEvent.click(screen.getByText("button"));
|
||||
|
||||
expect(handler.mock.calls.length).toEqual(1);
|
||||
expect(handler.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not handle click events if props.disabled given', () => {
|
||||
it("does not handle click events if props.disabled given", () => {
|
||||
const handler = jest.fn();
|
||||
render(<Button onClick={handler} disabled>button</Button>);
|
||||
fireEvent.click(screen.getByText('button'));
|
||||
fireEvent.click(screen.getByText("button"));
|
||||
|
||||
expect(handler.mock.calls.length).toEqual(0);
|
||||
expect(handler.mock.calls).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('renders a disabled attribute if props.disabled given', () => {
|
||||
it("renders a disabled attribute if props.disabled given", () => {
|
||||
const component = renderer.create(<Button disabled />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders the children', () => {
|
||||
it("renders the children", () => {
|
||||
const children = <p>children</p>;
|
||||
const component = renderer.create(<Button>{children}</Button>);
|
||||
const tree = component.toJSON();
|
||||
@@ -50,8 +50,8 @@ describe('<Button />', () => {
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders the props.text instead of children', () => {
|
||||
const text = 'foo';
|
||||
it("renders the props.text instead of children", () => {
|
||||
const text = "foo";
|
||||
const children = <p>children</p>;
|
||||
const component = renderer.create(<Button text={text}>{children}</Button>);
|
||||
const tree = component.toJSON();
|
||||
@@ -59,14 +59,14 @@ describe('<Button />', () => {
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders class="button--block" if props.block given', () => {
|
||||
it("renders class=\"button--block\" if props.block given", () => {
|
||||
const component = renderer.create(<Button block />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('adds class "button-secondary" if props.secondary given', () => {
|
||||
it("adds class \"button-secondary\" if props.secondary given", () => {
|
||||
const component = renderer.create(<Button secondary />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { fromJS } from 'immutable';
|
||||
import { fromJS } from "immutable";
|
||||
|
||||
import renderer from 'react-test-renderer';
|
||||
import renderer from "react-test-renderer";
|
||||
|
||||
import { DisplayName } from '../display_name';
|
||||
import { DisplayName } from "../display_name";
|
||||
|
||||
describe('<DisplayName />', () => {
|
||||
it('renders display name + account name', () => {
|
||||
describe("<DisplayName />", () => {
|
||||
it("renders display name + account name", () => {
|
||||
const account = fromJS({
|
||||
username: 'bar',
|
||||
acct: 'bar@baz',
|
||||
display_name_html: '<p>Foo</p>',
|
||||
username: "bar",
|
||||
acct: "bar@baz",
|
||||
display_name_html: "<p>Foo</p>",
|
||||
});
|
||||
const component = renderer.create(<DisplayName account={account} />);
|
||||
const tree = component.toJSON();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { fromJS } from 'immutable';
|
||||
import { fromJS } from "immutable";
|
||||
|
||||
import type { StatusLike } from '../hashtag_bar';
|
||||
import { computeHashtagBarForStatus } from '../hashtag_bar';
|
||||
import { type StatusLike } from "../hashtag_bar";
|
||||
import { computeHashtagBarForStatus } from "../hashtag_bar";
|
||||
|
||||
function createStatus(
|
||||
content: string,
|
||||
@@ -12,43 +12,43 @@ function createStatus(
|
||||
return fromJS({
|
||||
tags: hashtags.map((name) => ({ name })),
|
||||
contentHtml: content,
|
||||
media_attachments: hasMedia ? ['fakeMedia'] : [],
|
||||
media_attachments: hasMedia ? ["fakeMedia"] : [],
|
||||
spoiler_text: spoilerText,
|
||||
}) as unknown as StatusLike; // need to force the type here, as it is not properly defined
|
||||
}
|
||||
|
||||
describe('computeHashtagBarForStatus', () => {
|
||||
it('does nothing when there are no tags', () => {
|
||||
const status = createStatus('<p>Simple text</p>', []);
|
||||
describe("computeHashtagBarForStatus", () => {
|
||||
it("does nothing when there are no tags", () => {
|
||||
const status = createStatus("<p>Simple text</p>", []);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
computeHashtagBarForStatus(status);
|
||||
|
||||
expect(hashtagsInBar).toEqual([]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p>Simple text</p>"`,
|
||||
"\"<p>Simple text</p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('displays out of band hashtags in the bar', () => {
|
||||
it("displays out of band hashtags in the bar", () => {
|
||||
const status = createStatus(
|
||||
'<p>Simple text <a href="test">#hashtag</a></p>',
|
||||
['hashtag', 'test'],
|
||||
"<p>Simple text <a href=\"test\">#hashtag</a></p>",
|
||||
["hashtag", "test"],
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
computeHashtagBarForStatus(status);
|
||||
|
||||
expect(hashtagsInBar).toEqual(['test']);
|
||||
expect(hashtagsInBar).toEqual(["test"]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p>Simple text <a href="test">#hashtag</a></p>"`,
|
||||
"\"<p>Simple text <a href=\"test\">#hashtag</a></p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('does not truncate the contents when the last child is a text node', () => {
|
||||
it("does not truncate the contents when the last child is a text node", () => {
|
||||
const status = createStatus(
|
||||
'this is a #<a class="zrl" href="https://example.com/search?tag=test">test</a>. Some more text',
|
||||
['test'],
|
||||
"this is a #<a class=\"zrl\" href=\"https://example.com/search?tag=test\">test</a>. Some more text",
|
||||
["test"],
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
@@ -56,29 +56,29 @@ describe('computeHashtagBarForStatus', () => {
|
||||
|
||||
expect(hashtagsInBar).toEqual([]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"this is a #<a class="zrl" href="https://example.com/search?tag=test">test</a>. Some more text"`,
|
||||
"\"this is a #<a class=\"zrl\" href=\"https://example.com/search?tag=test\">test</a>. Some more text\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('extract tags from the last line', () => {
|
||||
it("extract tags from the last line", () => {
|
||||
const status = createStatus(
|
||||
'<p>Simple text</p><p><a href="test">#hashtag</a></p>',
|
||||
['hashtag'],
|
||||
"<p>Simple text</p><p><a href=\"test\">#hashtag</a></p>",
|
||||
["hashtag"],
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
computeHashtagBarForStatus(status);
|
||||
|
||||
expect(hashtagsInBar).toEqual(['hashtag']);
|
||||
expect(hashtagsInBar).toEqual(["hashtag"]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p>Simple text</p>"`,
|
||||
"\"<p>Simple text</p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('does not include tags from content', () => {
|
||||
it("does not include tags from content", () => {
|
||||
const status = createStatus(
|
||||
'<p>Simple text with a <a href="test">#hashtag</a></p><p><a href="test">#hashtag</a></p>',
|
||||
['hashtag'],
|
||||
"<p>Simple text with a <a href=\"test\">#hashtag</a></p><p><a href=\"test\">#hashtag</a></p>",
|
||||
["hashtag"],
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
@@ -86,14 +86,14 @@ describe('computeHashtagBarForStatus', () => {
|
||||
|
||||
expect(hashtagsInBar).toEqual([]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p>Simple text with a <a href="test">#hashtag</a></p>"`,
|
||||
"\"<p>Simple text with a <a href=\"test\">#hashtag</a></p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('works with one line status and hashtags', () => {
|
||||
it("works with one line status and hashtags", () => {
|
||||
const status = createStatus(
|
||||
'<p><a href="test">#test</a>. And another <a href="test">#hashtag</a></p>',
|
||||
['hashtag', 'test'],
|
||||
"<p><a href=\"test\">#test</a>. And another <a href=\"test\">#hashtag</a></p>",
|
||||
["hashtag", "test"],
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
@@ -101,44 +101,44 @@ describe('computeHashtagBarForStatus', () => {
|
||||
|
||||
expect(hashtagsInBar).toEqual([]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p><a href="test">#test</a>. And another <a href="test">#hashtag</a></p>"`,
|
||||
"\"<p><a href=\"test\">#test</a>. And another <a href=\"test\">#hashtag</a></p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('de-duplicate accentuated characters with case differences', () => {
|
||||
it("de-duplicate accentuated characters with case differences", () => {
|
||||
const status = createStatus(
|
||||
'<p>Text</p><p><a href="test">#éaa</a> <a href="test">#Éaa</a></p>',
|
||||
['éaa'],
|
||||
"<p>Text</p><p><a href=\"test\">#éaa</a> <a href=\"test\">#Éaa</a></p>",
|
||||
["éaa"],
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
computeHashtagBarForStatus(status);
|
||||
|
||||
expect(hashtagsInBar).toEqual(['Éaa']);
|
||||
expect(hashtagsInBar).toEqual(["Éaa"]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p>Text</p>"`,
|
||||
"\"<p>Text</p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('handles server-side normalized tags with accentuated characters', () => {
|
||||
it("handles server-side normalized tags with accentuated characters", () => {
|
||||
const status = createStatus(
|
||||
'<p>Text</p><p><a href="test">#éaa</a> <a href="test">#Éaa</a></p>',
|
||||
['eaa'], // The server may normalize the hashtags in the `tags` attribute
|
||||
"<p>Text</p><p><a href=\"test\">#éaa</a> <a href=\"test\">#Éaa</a></p>",
|
||||
["eaa"], // The server may normalize the hashtags in the `tags` attribute
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
computeHashtagBarForStatus(status);
|
||||
|
||||
expect(hashtagsInBar).toEqual(['Éaa']);
|
||||
expect(hashtagsInBar).toEqual(["Éaa"]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p>Text</p>"`,
|
||||
"\"<p>Text</p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('does not display in bar a hashtag in content with a case difference', () => {
|
||||
it("does not display in bar a hashtag in content with a case difference", () => {
|
||||
const status = createStatus(
|
||||
'<p>Text <a href="test">#Éaa</a></p><p><a href="test">#éaa</a></p>',
|
||||
['éaa'],
|
||||
"<p>Text <a href=\"test\">#Éaa</a></p><p><a href=\"test\">#éaa</a></p>",
|
||||
["éaa"],
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
@@ -146,14 +146,14 @@ describe('computeHashtagBarForStatus', () => {
|
||||
|
||||
expect(hashtagsInBar).toEqual([]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p>Text <a href="test">#Éaa</a></p>"`,
|
||||
"\"<p>Text <a href=\"test\">#Éaa</a></p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('does not modify a status with a line of hashtags only', () => {
|
||||
it("does not modify a status with a line of hashtags only", () => {
|
||||
const status = createStatus(
|
||||
'<p><a href="test">#test</a> <a href="test">#hashtag</a></p>',
|
||||
['test', 'hashtag'],
|
||||
"<p><a href=\"test\">#test</a> <a href=\"test\">#hashtag</a></p>",
|
||||
["test", "hashtag"],
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
@@ -161,14 +161,14 @@ describe('computeHashtagBarForStatus', () => {
|
||||
|
||||
expect(hashtagsInBar).toEqual([]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p><a href="test">#test</a> <a href="test">#hashtag</a></p>"`,
|
||||
"\"<p><a href=\"test\">#test</a> <a href=\"test\">#hashtag</a></p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('puts the hashtags in the bar if a status content has hashtags in the only line and has a media', () => {
|
||||
it("puts the hashtags in the bar if a status content has hashtags in the only line and has a media", () => {
|
||||
const status = createStatus(
|
||||
'<p>This is my content! <a href="test">#hashtag</a></p>',
|
||||
['hashtag'],
|
||||
"<p>This is my content! <a href=\"test\">#hashtag</a></p>",
|
||||
["hashtag"],
|
||||
true,
|
||||
);
|
||||
|
||||
@@ -177,30 +177,30 @@ describe('computeHashtagBarForStatus', () => {
|
||||
|
||||
expect(hashtagsInBar).toEqual([]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p>This is my content! <a href="test">#hashtag</a></p>"`,
|
||||
"\"<p>This is my content! <a href=\"test\">#hashtag</a></p>\"",
|
||||
);
|
||||
});
|
||||
|
||||
it('puts the hashtags in the bar if a status content is only hashtags and has a media', () => {
|
||||
it("puts the hashtags in the bar if a status content is only hashtags and has a media", () => {
|
||||
const status = createStatus(
|
||||
'<p><a href="test">#test</a> <a href="test">#hashtag</a></p>',
|
||||
['test', 'hashtag'],
|
||||
"<p><a href=\"test\">#test</a> <a href=\"test\">#hashtag</a></p>",
|
||||
["test", "hashtag"],
|
||||
true,
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
computeHashtagBarForStatus(status);
|
||||
|
||||
expect(hashtagsInBar).toEqual(['test', 'hashtag']);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(`""`);
|
||||
expect(hashtagsInBar).toEqual(["test", "hashtag"]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot("\"\"");
|
||||
});
|
||||
|
||||
it('does not use the hashtag bar if the status content is only hashtags, has a CW and a media', () => {
|
||||
it("does not use the hashtag bar if the status content is only hashtags, has a CW and a media", () => {
|
||||
const status = createStatus(
|
||||
'<p><a href="test">#test</a> <a href="test">#hashtag</a></p>',
|
||||
['test', 'hashtag'],
|
||||
"<p><a href=\"test\">#test</a> <a href=\"test\">#hashtag</a></p>",
|
||||
["test", "hashtag"],
|
||||
true,
|
||||
'My CW text',
|
||||
"My CW text",
|
||||
);
|
||||
|
||||
const { hashtagsInBar, statusContentProps } =
|
||||
@@ -208,7 +208,7 @@ describe('computeHashtagBarForStatus', () => {
|
||||
|
||||
expect(hashtagsInBar).toEqual([]);
|
||||
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
|
||||
`"<p><a href="test">#test</a> <a href="test">#hashtag</a></p>"`,
|
||||
"\"<p><a href=\"test\">#test</a> <a href=\"test\">#hashtag</a></p>\"",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
import classNames from "classnames";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { EmptyAccount } from 'mastodon/components/empty_account';
|
||||
import { ShortNumber } from 'mastodon/components/short_number';
|
||||
import { VerifiedBadge } from 'mastodon/components/verified_badge';
|
||||
import { EmptyAccount } from "mastodon/components/empty_account";
|
||||
import { ShortNumber } from "mastodon/components/short_number";
|
||||
import { VerifiedBadge } from "mastodon/components/verified_badge";
|
||||
|
||||
import { me } from '../initial_state';
|
||||
import { me } from "../initial_state";
|
||||
|
||||
import { Avatar } from './avatar';
|
||||
import Button from './button';
|
||||
import { FollowersCounter } from './counters';
|
||||
import { DisplayName } from './display_name';
|
||||
import { IconButton } from './icon_button';
|
||||
import { RelativeTimestamp } from './relative_timestamp';
|
||||
import { Avatar } from "./avatar";
|
||||
import Button from "./button";
|
||||
import { FollowersCounter } from "./counters";
|
||||
import { DisplayName } from "./display_name";
|
||||
import { IconButton } from "./icon_button";
|
||||
import { RelativeTimestamp } from "./relative_timestamp";
|
||||
|
||||
const messages = defineMessages({
|
||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||
cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' },
|
||||
unblock: { id: 'account.unblock_short', defaultMessage: 'Unblock' },
|
||||
unmute: { id: 'account.unmute_short', defaultMessage: 'Unmute' },
|
||||
mute_notifications: { id: 'account.mute_notifications_short', defaultMessage: 'Mute notifications' },
|
||||
unmute_notifications: { id: 'account.unmute_notifications_short', defaultMessage: 'Unmute notifications' },
|
||||
mute: { id: 'account.mute_short', defaultMessage: 'Mute' },
|
||||
block: { id: 'account.block_short', defaultMessage: 'Block' },
|
||||
follow: { id: "account.follow", defaultMessage: "Follow" },
|
||||
unfollow: { id: "account.unfollow", defaultMessage: "Unfollow" },
|
||||
cancel_follow_request: { id: "account.cancel_follow_request", defaultMessage: "Withdraw follow request" },
|
||||
unblock: { id: "account.unblock_short", defaultMessage: "Unblock" },
|
||||
unmute: { id: "account.unmute_short", defaultMessage: "Unmute" },
|
||||
mute_notifications: { id: "account.mute_notifications_short", defaultMessage: "Mute notifications" },
|
||||
unmute_notifications: { id: "account.unmute_notifications_short", defaultMessage: "Unmute notifications" },
|
||||
mute: { id: "account.mute_short", defaultMessage: "Mute" },
|
||||
block: { id: "account.block_short", defaultMessage: "Block" },
|
||||
});
|
||||
|
||||
class Account extends ImmutablePureComponent {
|
||||
@@ -90,8 +90,8 @@ class Account extends ImmutablePureComponent {
|
||||
if (hidden) {
|
||||
return (
|
||||
<>
|
||||
{account.get('display_name')}
|
||||
{account.get('username')}
|
||||
{account.get("display_name")}
|
||||
{account.get("username")}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -100,11 +100,11 @@ class Account extends ImmutablePureComponent {
|
||||
|
||||
if (actionIcon && onActionClick) {
|
||||
buttons = <IconButton icon={actionIcon} title={actionTitle} onClick={this.handleAction} />;
|
||||
} else if (!actionIcon && account.get('id') !== me && account.get('relationship', null) !== null) {
|
||||
const following = account.getIn(['relationship', 'following']);
|
||||
const requested = account.getIn(['relationship', 'requested']);
|
||||
const blocking = account.getIn(['relationship', 'blocking']);
|
||||
const muting = account.getIn(['relationship', 'muting']);
|
||||
} else if (!actionIcon && account.get("id") !== me && account.get("relationship", null) !== null) {
|
||||
const following = account.getIn(["relationship", "following"]);
|
||||
const requested = account.getIn(["relationship", "requested"]);
|
||||
const blocking = account.getIn(["relationship", "blocking"]);
|
||||
const muting = account.getIn(["relationship", "muting"]);
|
||||
|
||||
if (requested) {
|
||||
buttons = <Button text={intl.formatMessage(messages.cancel_follow_request)} onClick={this.handleFollow} />;
|
||||
@@ -113,7 +113,7 @@ class Account extends ImmutablePureComponent {
|
||||
} else if (muting) {
|
||||
let hidingNotificationsButton;
|
||||
|
||||
if (account.getIn(['relationship', 'muting_notifications'])) {
|
||||
if (account.getIn(["relationship", "muting_notifications"])) {
|
||||
hidingNotificationsButton = <Button text={intl.formatMessage(messages.unmute_notifications)} onClick={this.handleUnmuteNotifications} />;
|
||||
} else {
|
||||
hidingNotificationsButton = <Button text={intl.formatMessage(messages.mute_notifications)} onClick={this.handleMuteNotifications} />;
|
||||
@@ -125,33 +125,33 @@ class Account extends ImmutablePureComponent {
|
||||
{hidingNotificationsButton}
|
||||
</>
|
||||
);
|
||||
} else if (defaultAction === 'mute') {
|
||||
} else if (defaultAction === "mute") {
|
||||
buttons = <Button title={intl.formatMessage(messages.mute)} onClick={this.handleMute} />;
|
||||
} else if (defaultAction === 'block') {
|
||||
} else if (defaultAction === "block") {
|
||||
buttons = <Button text={intl.formatMessage(messages.block)} onClick={this.handleBlock} />;
|
||||
} else if (!account.get('moved') || following) {
|
||||
} else if (!account.get("moved") || following) {
|
||||
buttons = <Button text={intl.formatMessage(following ? messages.unfollow : messages.follow)} onClick={this.handleFollow} />;
|
||||
}
|
||||
}
|
||||
|
||||
let muteTimeRemaining;
|
||||
|
||||
if (account.get('mute_expires_at')) {
|
||||
muteTimeRemaining = <>· <RelativeTimestamp timestamp={account.get('mute_expires_at')} futureDate /></>;
|
||||
if (account.get("mute_expires_at")) {
|
||||
muteTimeRemaining = <>· <RelativeTimestamp timestamp={account.get("mute_expires_at")} futureDate /></>;
|
||||
}
|
||||
|
||||
let verification;
|
||||
|
||||
const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
|
||||
const firstVerifiedField = account.get("fields").find(item => !!item.get("verified_at"));
|
||||
|
||||
if (firstVerifiedField) {
|
||||
verification = <VerifiedBadge link={firstVerifiedField.get('value')} />;
|
||||
verification = <VerifiedBadge link={firstVerifiedField.get("value")} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('account', { 'account--minimal': minimal })}>
|
||||
<div className={classNames("account", { "account--minimal": minimal })}>
|
||||
<div className='account__wrapper'>
|
||||
<Link key={account.get('id')} className='account__display-name' title={account.get('acct')} to={`/@${account.get('acct')}`}>
|
||||
<Link key={account.get("id")} className='account__display-name' title={account.get("acct")} to={`/@${account.get("acct")}`}>
|
||||
<div className='account__avatar-wrapper'>
|
||||
<Avatar account={account} size={size} />
|
||||
</div>
|
||||
@@ -160,7 +160,7 @@ class Account extends ImmutablePureComponent {
|
||||
<DisplayName account={account} />
|
||||
{!minimal && (
|
||||
<div className='account__details'>
|
||||
<ShortNumber value={account.get('followers_count')} renderer={FollowersCounter} /> {verification} {muteTimeRemaining}
|
||||
<ShortNumber value={account.get("followers_count")} renderer={FollowersCounter} /> {verification} {muteTimeRemaining}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -173,10 +173,10 @@ class Account extends ImmutablePureComponent {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{withBio && (account.get('note').length > 0 ? (
|
||||
{withBio && (account.get("note").length > 0 ? (
|
||||
<div
|
||||
className='account__note translate'
|
||||
dangerouslySetInnerHTML={{ __html: account.get('note_emojified') }}
|
||||
dangerouslySetInnerHTML={{ __html: account.get("note_emojified") }}
|
||||
/>
|
||||
) : (
|
||||
<div className='account__note account__note--missing'><FormattedMessage id='account.no_bio' defaultMessage='No description provided.' /></div>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedNumber } from 'react-intl';
|
||||
import { FormattedNumber } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { Sparklines, SparklinesCurve } from 'react-sparklines';
|
||||
import { Sparklines, SparklinesCurve } from "react-sparklines";
|
||||
|
||||
import api from 'mastodon/api';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
import api from "mastodon/api";
|
||||
import { Skeleton } from "mastodon/components/skeleton";
|
||||
|
||||
const percIncrease = (a, b) => {
|
||||
let percent;
|
||||
@@ -48,7 +48,7 @@ export default class Counter extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { measure, start_at, end_at, params } = this.props;
|
||||
|
||||
api().post('/api/v1/admin/measures', { keys: [measure], start_at, end_at, [measure]: params }).then(res => {
|
||||
api().post("/api/v1/admin/measures", { keys: [measure], start_at, end_at, [measure]: params }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
@@ -78,7 +78,7 @@ export default class Counter extends PureComponent {
|
||||
content = (
|
||||
<>
|
||||
<span className='sparkline__value__total'>{measure.human_value || <FormattedNumber value={measure.total} />}</span>
|
||||
{measure.previous_total && (<span className={classNames('sparkline__value__change', { positive: percentChange > 0, negative: percentChange < 0 })}>{percentChange > 0 && '+'}<FormattedNumber value={percentChange} style='percent' /></span>)}
|
||||
{measure.previous_total && (<span className={classNames("sparkline__value__change", { positive: percentChange > 0, negative: percentChange < 0 })}>{percentChange > 0 && "+"}<FormattedNumber value={percentChange} style='percent' /></span>)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedNumber } from 'react-intl';
|
||||
import { FormattedNumber } from "react-intl";
|
||||
|
||||
import api from 'mastodon/api';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
import { roundTo10 } from 'mastodon/utils/numbers';
|
||||
import api from "mastodon/api";
|
||||
import { Skeleton } from "mastodon/components/skeleton";
|
||||
import { roundTo10 } from "mastodon/utils/numbers";
|
||||
|
||||
export default class Dimension extends PureComponent {
|
||||
|
||||
@@ -26,7 +26,7 @@ export default class Dimension extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { start_at, end_at, dimension, limit, params } = this.props;
|
||||
|
||||
api().post('/api/v1/admin/dimensions', { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => {
|
||||
api().post("/api/v1/admin/dimensions", { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
@@ -74,7 +74,7 @@ export default class Dimension extends PureComponent {
|
||||
</td>
|
||||
|
||||
<td className='dimension__item__value'>
|
||||
{typeof item.human_value !== 'undefined' ? item.human_value : <FormattedNumber value={item.value} />}
|
||||
{typeof item.human_value !== "undefined" ? item.human_value : <FormattedNumber value={item.value} />}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedNumber, FormattedMessage } from 'react-intl';
|
||||
import { FormattedNumber, FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import api from 'mastodon/api';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
import api from "mastodon/api";
|
||||
import { Skeleton } from "mastodon/components/skeleton";
|
||||
|
||||
export default class ImpactReport extends PureComponent {
|
||||
|
||||
@@ -27,8 +27,8 @@ export default class ImpactReport extends PureComponent {
|
||||
include_subdomains: true,
|
||||
};
|
||||
|
||||
api().post('/api/v1/admin/measures', {
|
||||
keys: ['instance_accounts', 'instance_follows', 'instance_followers'],
|
||||
api().post("/api/v1/admin/measures", {
|
||||
keys: ["instance_accounts", "instance_follows", "instance_followers"],
|
||||
start_at: null,
|
||||
end_at: null,
|
||||
instance_accounts: params,
|
||||
@@ -63,7 +63,7 @@ export default class ImpactReport extends PureComponent {
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr className={classNames('dimension__item', { negative: !loading && data[1].total > 0 })}>
|
||||
<tr className={classNames("dimension__item", { negative: !loading && data[1].total > 0 })}>
|
||||
<td className='dimension__item__key'>
|
||||
<FormattedMessage id='admin.impact_report.instance_follows' defaultMessage='Followers their users would lose' />
|
||||
</td>
|
||||
@@ -73,7 +73,7 @@ export default class ImpactReport extends PureComponent {
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr className={classNames('dimension__item', { negative: !loading && data[2].total > 0 })}>
|
||||
<tr className={classNames("dimension__item", { negative: !loading && data[2].total > 0 })}>
|
||||
<td className='dimension__item__key'>
|
||||
<FormattedMessage id='admin.impact_report.instance_followers' defaultMessage='Followers our users would lose' />
|
||||
</td>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import { injectIntl, defineMessages } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import api from 'mastodon/api';
|
||||
import api from "mastodon/api";
|
||||
|
||||
const messages = defineMessages({
|
||||
legal: { id: 'report.categories.legal', defaultMessage: 'Legal' },
|
||||
other: { id: 'report.categories.other', defaultMessage: 'Other' },
|
||||
spam: { id: 'report.categories.spam', defaultMessage: 'Spam' },
|
||||
violation: { id: 'report.categories.violation', defaultMessage: 'Content violates one or more server rules' },
|
||||
legal: { id: "report.categories.legal", defaultMessage: "Legal" },
|
||||
other: { id: "report.categories.other", defaultMessage: "Other" },
|
||||
spam: { id: "report.categories.spam", defaultMessage: "Spam" },
|
||||
violation: { id: "report.categories.violation", defaultMessage: "Content violates one or more server rules" },
|
||||
});
|
||||
|
||||
class Category extends PureComponent {
|
||||
@@ -37,11 +37,11 @@ class Category extends PureComponent {
|
||||
const { id, text, disabled, selected, children } = this.props;
|
||||
|
||||
return (
|
||||
<div tabIndex={0} role='button' className={classNames('report-reason-selector__category', { selected, disabled })} onClick={this.handleClick}>
|
||||
<div tabIndex={0} role='button' className={classNames("report-reason-selector__category", { selected, disabled })} onClick={this.handleClick}>
|
||||
{selected && <input type='hidden' name='report[category]' value={id} />}
|
||||
|
||||
<div className='report-reason-selector__category__label'>
|
||||
<span className={classNames('poll__input', { active: selected, disabled })} />
|
||||
<span className={classNames("poll__input", { active: selected, disabled })} />
|
||||
{text}
|
||||
</div>
|
||||
|
||||
@@ -78,8 +78,8 @@ class Rule extends PureComponent {
|
||||
const { id, text, disabled, selected } = this.props;
|
||||
|
||||
return (
|
||||
<div tabIndex={0} role='button' className={classNames('report-reason-selector__rule', { selected, disabled })} onClick={this.handleClick}>
|
||||
<span className={classNames('poll__input', { checkbox: true, active: selected, disabled })} />
|
||||
<div tabIndex={0} role='button' className={classNames("report-reason-selector__rule", { selected, disabled })} onClick={this.handleClick}>
|
||||
<span className={classNames("poll__input", { checkbox: true, active: selected, disabled })} />
|
||||
{selected && <input type='hidden' name='report[rule_ids][]' value={id} />}
|
||||
{text}
|
||||
</div>
|
||||
@@ -105,7 +105,7 @@ class ReportReasonSelector extends PureComponent {
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
api().get('/api/v1/instance').then(res => {
|
||||
api().get("/api/v1/instance").then(res => {
|
||||
this.setState({
|
||||
rules: res.data.rules,
|
||||
});
|
||||
@@ -150,10 +150,10 @@ class ReportReasonSelector extends PureComponent {
|
||||
|
||||
return (
|
||||
<div className='report-reason-selector'>
|
||||
<Category id='other' text={intl.formatMessage(messages.other)} selected={category === 'other'} onSelect={this.handleSelect} disabled={disabled} />
|
||||
<Category id='legal' text={intl.formatMessage(messages.legal)} selected={category === 'legal'} onSelect={this.handleSelect} disabled={disabled} />
|
||||
<Category id='spam' text={intl.formatMessage(messages.spam)} selected={category === 'spam'} onSelect={this.handleSelect} disabled={disabled} />
|
||||
<Category id='violation' text={intl.formatMessage(messages.violation)} selected={category === 'violation'} onSelect={this.handleSelect} disabled={disabled}>
|
||||
<Category id='other' text={intl.formatMessage(messages.other)} selected={category === "other"} onSelect={this.handleSelect} disabled={disabled} />
|
||||
<Category id='legal' text={intl.formatMessage(messages.legal)} selected={category === "legal"} onSelect={this.handleSelect} disabled={disabled} />
|
||||
<Category id='spam' text={intl.formatMessage(messages.spam)} selected={category === "spam"} onSelect={this.handleSelect} disabled={disabled} />
|
||||
<Category id='violation' text={intl.formatMessage(messages.violation)} selected={category === "violation"} onSelect={this.handleSelect} disabled={disabled}>
|
||||
{rules.map(rule => <Rule key={rule.id} id={rule.id} text={rule.text} selected={rule_ids.includes(rule.id)} onToggle={this.handleToggle} disabled={disabled} />)}
|
||||
</Category>
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage, FormattedNumber, FormattedDate } from 'react-intl';
|
||||
import { FormattedMessage, FormattedNumber, FormattedDate } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import api from 'mastodon/api';
|
||||
import { roundTo10 } from 'mastodon/utils/numbers';
|
||||
import api from "mastodon/api";
|
||||
import { roundTo10 } from "mastodon/utils/numbers";
|
||||
|
||||
const dateForCohort = cohort => {
|
||||
const timeZone = 'UTC';
|
||||
const timeZone = "UTC";
|
||||
switch(cohort.frequency) {
|
||||
case 'day':
|
||||
return <FormattedDate value={cohort.period} month='long' day='2-digit' timeZone={timeZone} />;
|
||||
default:
|
||||
return <FormattedDate value={cohort.period} month='long' year='numeric' timeZone={timeZone} />;
|
||||
case "day":
|
||||
return <FormattedDate value={cohort.period} month='long' day='2-digit' timeZone={timeZone} />;
|
||||
default:
|
||||
return <FormattedDate value={cohort.period} month='long' year='numeric' timeZone={timeZone} />;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ export default class Retention extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { start_at, end_at, frequency } = this.props;
|
||||
|
||||
api().post('/api/v1/admin/retention', { start_at, end_at, frequency }).then(res => {
|
||||
api().post("/api/v1/admin/retention", { start_at, end_at, frequency }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
@@ -96,7 +96,7 @@ export default class Retention extends PureComponent {
|
||||
|
||||
return (
|
||||
<td key={retention.date}>
|
||||
<div className={classNames('retention__table__box', 'retention__table__average', `retention__table__box--${roundTo10(average * 100)}`)}>
|
||||
<div className={classNames("retention__table__box", "retention__table__average", `retention__table__box--${roundTo10(average * 100)}`)}>
|
||||
<FormattedNumber value={average} style='percent' />
|
||||
</div>
|
||||
</td>
|
||||
@@ -122,7 +122,7 @@ export default class Retention extends PureComponent {
|
||||
|
||||
{cohort.data.slice(1).map(retention => (
|
||||
<td key={retention.date}>
|
||||
<div className={classNames('retention__table__box', `retention__table__box--${roundTo10(retention.rate * 100)}`)}>
|
||||
<div className={classNames("retention__table__box", `retention__table__box--${roundTo10(retention.rate * 100)}`)}>
|
||||
<FormattedNumber value={retention.rate} style='percent' />
|
||||
</div>
|
||||
</td>
|
||||
@@ -136,11 +136,11 @@ export default class Retention extends PureComponent {
|
||||
|
||||
let title = null;
|
||||
switch(frequency) {
|
||||
case 'day':
|
||||
title = <FormattedMessage id='admin.dashboard.daily_retention' defaultMessage='User retention rate by day after sign-up' />;
|
||||
break;
|
||||
default:
|
||||
title = <FormattedMessage id='admin.dashboard.monthly_retention' defaultMessage='User retention rate by month after sign-up' />;
|
||||
case "day":
|
||||
title = <FormattedMessage id='admin.dashboard.daily_retention' defaultMessage='User retention rate by day after sign-up' />;
|
||||
break;
|
||||
default:
|
||||
title = <FormattedMessage id='admin.dashboard.monthly_retention' defaultMessage='User retention rate by month after sign-up' />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import api from 'mastodon/api';
|
||||
import Hashtag from 'mastodon/components/hashtag';
|
||||
import api from "mastodon/api";
|
||||
import Hashtag from "mastodon/components/hashtag";
|
||||
|
||||
export default class Trends extends PureComponent {
|
||||
|
||||
@@ -22,7 +22,7 @@ export default class Trends extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { limit } = this.props;
|
||||
|
||||
api().get('/api/v1/admin/trends/tags', { params: { limit } }).then(res => {
|
||||
api().get("/api/v1/admin/trends/tags", { params: { limit } }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
@@ -57,7 +57,7 @@ export default class Trends extends PureComponent {
|
||||
people={hashtag.history[0].accounts * 1 + hashtag.history[1].accounts * 1}
|
||||
uses={hashtag.history[0].uses * 1 + hashtag.history[1].uses * 1}
|
||||
history={hashtag.history.reverse().map(day => day.uses)}
|
||||
className={classNames(hashtag.requires_review && 'trends__item--requires-review', !hashtag.trendable && !hashtag.requires_review && 'trends__item--disabled')}
|
||||
className={classNames(hashtag.requires_review && "trends__item--requires-review", !hashtag.trendable && !hashtag.requires_review && "trends__item--disabled")}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import { TransitionMotion, spring } from 'react-motion';
|
||||
import { TransitionMotion, spring } from "react-motion";
|
||||
|
||||
import { reduceMotion } from '../initial_state';
|
||||
import { reduceMotion } from "../initial_state";
|
||||
|
||||
import { ShortNumber } from './short_number';
|
||||
import { ShortNumber } from "./short_number";
|
||||
|
||||
interface Props {
|
||||
value: number;
|
||||
value: number,
|
||||
}
|
||||
export const AnimatedNumber: React.FC<Props> = ({ value }) => {
|
||||
const [previousValue, setPreviousValue] = useState(value);
|
||||
@@ -48,7 +48,7 @@ export const AnimatedNumber: React.FC<Props> = ({ value }) => {
|
||||
<span
|
||||
key={key}
|
||||
style={{
|
||||
position: direction * style.y > 0 ? 'absolute' : 'static',
|
||||
position: direction * style.y > 0 ? "absolute" : "static",
|
||||
transform: `translateY(${style.y * 100}%)`,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { Icon } from "mastodon/components/icon";
|
||||
|
||||
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
|
||||
const filename = url => url.split("/").pop().split("#")[0].split("?")[0];
|
||||
|
||||
export default class AttachmentList extends ImmutablePureComponent {
|
||||
|
||||
@@ -22,7 +22,7 @@ export default class AttachmentList extends ImmutablePureComponent {
|
||||
const { media, compact } = this.props;
|
||||
|
||||
return (
|
||||
<div className={classNames('attachment-list', { compact })}>
|
||||
<div className={classNames("attachment-list", { compact })}>
|
||||
{!compact && (
|
||||
<div className='attachment-list__icon'>
|
||||
<Icon id='link' />
|
||||
@@ -31,13 +31,13 @@ export default class AttachmentList extends ImmutablePureComponent {
|
||||
|
||||
<ul className='attachment-list__list'>
|
||||
{media.map(attachment => {
|
||||
const displayUrl = attachment.get('remote_url') || attachment.get('url');
|
||||
const displayUrl = attachment.get("remote_url") || attachment.get("url");
|
||||
|
||||
return (
|
||||
<li key={attachment.get('id')}>
|
||||
<li key={attachment.get("id")}>
|
||||
<a href={displayUrl} target='_blank' rel='noopener noreferrer'>
|
||||
{compact && <Icon id='link' />}
|
||||
{compact && ' ' }
|
||||
{compact && " " }
|
||||
{displayUrl ? filename(displayUrl) : <FormattedMessage id='attachments_list.unprocessed' defaultMessage='(unprocessed)' />}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { assetHost } from 'mastodon/utils/config';
|
||||
import { assetHost } from "mastodon/utils/config";
|
||||
|
||||
import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light';
|
||||
import unicodeMapping from "../features/emoji/emoji_unicode_mapping_light";
|
||||
|
||||
export default class AutosuggestEmoji extends PureComponent {
|
||||
|
||||
@@ -18,7 +18,7 @@ export default class AutosuggestEmoji extends PureComponent {
|
||||
if (emoji.custom) {
|
||||
url = emoji.imageUrl;
|
||||
} else {
|
||||
const mapping = unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\uFE0F$/, '')];
|
||||
const mapping = unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\uFE0F$/, "")];
|
||||
|
||||
if (!mapping) {
|
||||
return null;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { ShortNumber } from 'mastodon/components/short_number';
|
||||
import { ShortNumber } from "mastodon/components/short_number";
|
||||
|
||||
interface Props {
|
||||
tag: {
|
||||
name: string;
|
||||
url?: string;
|
||||
name: string,
|
||||
url?: string,
|
||||
history?: {
|
||||
uses: number;
|
||||
accounts: string;
|
||||
day: string;
|
||||
}[];
|
||||
following?: boolean;
|
||||
type: 'hashtag';
|
||||
};
|
||||
uses: number,
|
||||
accounts: string,
|
||||
day: string,
|
||||
}[],
|
||||
following?: boolean,
|
||||
type: "hashtag",
|
||||
},
|
||||
}
|
||||
|
||||
export const AutosuggestHashtag: React.FC<Props> = ({ tag }) => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
|
||||
import AutosuggestAccountContainer from "../features/compose/containers/autosuggest_account_container";
|
||||
|
||||
import AutosuggestEmoji from './autosuggest_emoji';
|
||||
import { AutosuggestHashtag } from './autosuggest_hashtag';
|
||||
import AutosuggestEmoji from "./autosuggest_emoji";
|
||||
import { AutosuggestHashtag } from "./autosuggest_hashtag";
|
||||
|
||||
const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => {
|
||||
let word;
|
||||
@@ -59,7 +59,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
||||
|
||||
static defaultProps = {
|
||||
autoFocus: true,
|
||||
searchTokens: ['@', ':', '#'],
|
||||
searchTokens: ["@", ":", "#"],
|
||||
};
|
||||
|
||||
state = {
|
||||
@@ -100,39 +100,39 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
if (suggestions.size === 0 || suggestionsHidden) {
|
||||
document.querySelector('.ui').parentElement.focus();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
this.setState({ suggestionsHidden: true });
|
||||
}
|
||||
case "Escape":
|
||||
if (suggestions.size === 0 || suggestionsHidden) {
|
||||
document.querySelector(".ui").parentElement.focus();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
this.setState({ suggestionsHidden: true });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
||||
}
|
||||
break;
|
||||
case "ArrowDown":
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
||||
}
|
||||
break;
|
||||
case "ArrowUp":
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'Enter':
|
||||
case 'Tab':
|
||||
break;
|
||||
case "Enter":
|
||||
case "Tab":
|
||||
// Select suggestion
|
||||
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
||||
}
|
||||
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
if (e.defaultPrevented || !this.props.onKeyDown) {
|
||||
@@ -151,7 +151,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
onSuggestionClick = (e) => {
|
||||
const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index'));
|
||||
const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute("data-index"));
|
||||
e.preventDefault();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);
|
||||
this.input.focus();
|
||||
@@ -171,19 +171,19 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
||||
const { selectedSuggestion } = this.state;
|
||||
let inner, key;
|
||||
|
||||
if (suggestion.type === 'emoji') {
|
||||
if (suggestion.type === "emoji") {
|
||||
inner = <AutosuggestEmoji emoji={suggestion} />;
|
||||
key = suggestion.id;
|
||||
} else if (suggestion.type ==='hashtag') {
|
||||
} else if (suggestion.type ==="hashtag") {
|
||||
inner = <AutosuggestHashtag tag={suggestion} />;
|
||||
key = suggestion.name;
|
||||
} else if (suggestion.type === 'account') {
|
||||
} else if (suggestion.type === "account") {
|
||||
inner = <AutosuggestAccountContainer id={suggestion.id} />;
|
||||
key = suggestion.id;
|
||||
}
|
||||
|
||||
return (
|
||||
<div role='button' tabIndex={0} key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
|
||||
<div role='button' tabIndex={0} key={key} data-index={i} className={classNames("autosuggest-textarea__suggestions__item", { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
|
||||
{inner}
|
||||
</div>
|
||||
);
|
||||
@@ -196,7 +196,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
||||
return (
|
||||
<div className='autosuggest-input'>
|
||||
<label>
|
||||
<span style={{ display: 'none' }}>{placeholder}</span>
|
||||
<span style={{ display: "none" }}>{placeholder}</span>
|
||||
|
||||
<input
|
||||
type='text'
|
||||
@@ -220,7 +220,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
|
||||
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? "" : "autosuggest-textarea__suggestions--visible"}`}>
|
||||
{suggestions.map(this.renderSuggestion)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import Textarea from 'react-textarea-autosize';
|
||||
import Textarea from "react-textarea-autosize";
|
||||
|
||||
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
|
||||
import AutosuggestAccountContainer from "../features/compose/containers/autosuggest_account_container";
|
||||
|
||||
import AutosuggestEmoji from './autosuggest_emoji';
|
||||
import { AutosuggestHashtag } from './autosuggest_hashtag';
|
||||
import AutosuggestEmoji from "./autosuggest_emoji";
|
||||
import { AutosuggestHashtag } from "./autosuggest_hashtag";
|
||||
|
||||
const textAtCursorMatchesToken = (str, caretPosition) => {
|
||||
let word;
|
||||
@@ -24,7 +24,7 @@ const textAtCursorMatchesToken = (str, caretPosition) => {
|
||||
word = str.slice(left, right + caretPosition);
|
||||
}
|
||||
|
||||
if (!word || word.trim().length < 3 || ['@', ':', '#'].indexOf(word[0]) === -1) {
|
||||
if (!word || word.trim().length < 3 || ["@", ":", "#"].indexOf(word[0]) === -1) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
@@ -97,39 +97,39 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
if (suggestions.size === 0 || suggestionsHidden) {
|
||||
document.querySelector('.ui').parentElement.focus();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
this.setState({ suggestionsHidden: true });
|
||||
}
|
||||
case "Escape":
|
||||
if (suggestions.size === 0 || suggestionsHidden) {
|
||||
document.querySelector(".ui").parentElement.focus();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
this.setState({ suggestionsHidden: true });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
||||
}
|
||||
break;
|
||||
case "ArrowDown":
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
||||
}
|
||||
break;
|
||||
case "ArrowUp":
|
||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'Enter':
|
||||
case 'Tab':
|
||||
break;
|
||||
case "Enter":
|
||||
case "Tab":
|
||||
// Select suggestion
|
||||
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
||||
}
|
||||
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
if (e.defaultPrevented || !this.props.onKeyDown) {
|
||||
@@ -151,7 +151,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
onSuggestionClick = (e) => {
|
||||
const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index'));
|
||||
const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute("data-index"));
|
||||
e.preventDefault();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);
|
||||
this.textarea.focus();
|
||||
@@ -178,19 +178,19 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||
const { selectedSuggestion } = this.state;
|
||||
let inner, key;
|
||||
|
||||
if (suggestion.type === 'emoji') {
|
||||
if (suggestion.type === "emoji") {
|
||||
inner = <AutosuggestEmoji emoji={suggestion} />;
|
||||
key = suggestion.id;
|
||||
} else if (suggestion.type === 'hashtag') {
|
||||
} else if (suggestion.type === "hashtag") {
|
||||
inner = <AutosuggestHashtag tag={suggestion} />;
|
||||
key = suggestion.name;
|
||||
} else if (suggestion.type === 'account') {
|
||||
} else if (suggestion.type === "account") {
|
||||
inner = <AutosuggestAccountContainer id={suggestion.id} />;
|
||||
key = suggestion.id;
|
||||
}
|
||||
|
||||
return (
|
||||
<div role='button' tabIndex={0} key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
|
||||
<div role='button' tabIndex={0} key={key} data-index={i} className={classNames("autosuggest-textarea__suggestions__item", { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
|
||||
{inner}
|
||||
</div>
|
||||
);
|
||||
@@ -204,7 +204,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||
<div className='compose-form__autosuggest-wrapper' key='autosuggest-wrapper'>
|
||||
<div className='autosuggest-textarea'>
|
||||
<label>
|
||||
<span style={{ display: 'none' }}>{placeholder}</span>
|
||||
<span style={{ display: "none" }}>{placeholder}</span>
|
||||
|
||||
<Textarea
|
||||
ref={this.setTextarea}
|
||||
@@ -229,7 +229,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||
</div>,
|
||||
|
||||
<div className='autosuggest-textarea__suggestions-wrapper' key='suggestions-wrapper'>
|
||||
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
|
||||
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? "" : "autosuggest-textarea__suggestions--visible"}`}>
|
||||
{suggestions.map(this.renderSuggestion)}
|
||||
</div>
|
||||
</div>,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { useHovering } from '../../hooks/useHovering';
|
||||
import type { Account } from '../../types/resources';
|
||||
import { autoPlayGif } from '../initial_state';
|
||||
import { useHovering } from "../../hooks/useHovering";
|
||||
import { type Account } from "../../types/resources";
|
||||
import { autoPlayGif } from "../initial_state";
|
||||
|
||||
interface Props {
|
||||
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||
size: number;
|
||||
style?: React.CSSProperties;
|
||||
inline?: boolean;
|
||||
animate?: boolean;
|
||||
account: Account | undefined, // FIXME: remove `undefined` once we know for sure its always there
|
||||
size: number,
|
||||
style?: React.CSSProperties,
|
||||
inline?: boolean,
|
||||
animate?: boolean,
|
||||
}
|
||||
|
||||
export const Avatar: React.FC<Props> = ({
|
||||
@@ -29,19 +29,19 @@ export const Avatar: React.FC<Props> = ({
|
||||
|
||||
const src =
|
||||
hovering || animate
|
||||
? account?.get('avatar')
|
||||
: account?.get('avatar_static');
|
||||
? account?.get("avatar")
|
||||
: account?.get("avatar_static");
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('account__avatar', {
|
||||
'account__avatar-inline': inline,
|
||||
className={classNames("account__avatar", {
|
||||
"account__avatar-inline": inline,
|
||||
})}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
style={style}
|
||||
>
|
||||
{src && <img src={src} alt={account?.get('acct')} />}
|
||||
{src && <img src={src} alt={account?.get("acct")} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
|
||||
import { autoPlayGif } from '../initial_state';
|
||||
import { autoPlayGif } from "../initial_state";
|
||||
|
||||
import { Avatar } from './avatar';
|
||||
import { Avatar } from "./avatar";
|
||||
|
||||
export default class AvatarComposite extends PureComponent {
|
||||
|
||||
@@ -24,10 +24,10 @@ export default class AvatarComposite extends PureComponent {
|
||||
|
||||
let width = 50;
|
||||
let height = 100;
|
||||
let top = 'auto';
|
||||
let left = 'auto';
|
||||
let bottom = 'auto';
|
||||
let right = 'auto';
|
||||
let top = "auto";
|
||||
let left = "auto";
|
||||
let bottom = "auto";
|
||||
let right = "auto";
|
||||
|
||||
if (size === 1) {
|
||||
width = 100;
|
||||
@@ -39,35 +39,35 @@ export default class AvatarComposite extends PureComponent {
|
||||
|
||||
if (size === 2) {
|
||||
if (index === 0) {
|
||||
right = '1px';
|
||||
right = "1px";
|
||||
} else {
|
||||
left = '1px';
|
||||
left = "1px";
|
||||
}
|
||||
} else if (size === 3) {
|
||||
if (index === 0) {
|
||||
right = '1px';
|
||||
right = "1px";
|
||||
} else if (index > 0) {
|
||||
left = '1px';
|
||||
left = "1px";
|
||||
}
|
||||
|
||||
if (index === 1) {
|
||||
bottom = '1px';
|
||||
bottom = "1px";
|
||||
} else if (index > 1) {
|
||||
top = '1px';
|
||||
top = "1px";
|
||||
}
|
||||
} else if (size === 4) {
|
||||
if (index === 0 || index === 2) {
|
||||
right = '1px';
|
||||
right = "1px";
|
||||
}
|
||||
|
||||
if (index === 1 || index === 3) {
|
||||
left = '1px';
|
||||
left = "1px";
|
||||
}
|
||||
|
||||
if (index < 2) {
|
||||
bottom = '1px';
|
||||
bottom = "1px";
|
||||
} else {
|
||||
top = '1px';
|
||||
top = "1px";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export default class AvatarComposite extends PureComponent {
|
||||
};
|
||||
|
||||
return (
|
||||
<div key={account.get('id')} style={style}>
|
||||
<div key={account.get("id")} style={style}>
|
||||
<Avatar account={account} animate={animate} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useHovering } from '../../hooks/useHovering';
|
||||
import type { Account } from '../../types/resources';
|
||||
import { autoPlayGif } from '../initial_state';
|
||||
import { useHovering } from "../../hooks/useHovering";
|
||||
import { type Account } from "../../types/resources";
|
||||
import { autoPlayGif } from "../initial_state";
|
||||
|
||||
interface Props {
|
||||
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||
friend: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||
size?: number;
|
||||
baseSize?: number;
|
||||
overlaySize?: number;
|
||||
account: Account | undefined, // FIXME: remove `undefined` once we know for sure its always there
|
||||
friend: Account | undefined, // FIXME: remove `undefined` once we know for sure its always there
|
||||
size?: number,
|
||||
baseSize?: number,
|
||||
overlaySize?: number,
|
||||
}
|
||||
|
||||
export const AvatarOverlay: React.FC<Props> = ({
|
||||
@@ -20,11 +20,11 @@ export const AvatarOverlay: React.FC<Props> = ({
|
||||
const { hovering, handleMouseEnter, handleMouseLeave } =
|
||||
useHovering(autoPlayGif);
|
||||
const accountSrc = hovering
|
||||
? account?.get('avatar')
|
||||
: account?.get('avatar_static');
|
||||
? account?.get("avatar")
|
||||
: account?.get("avatar_static");
|
||||
const friendSrc = hovering
|
||||
? friend?.get('avatar')
|
||||
: friend?.get('avatar_static');
|
||||
? friend?.get("avatar")
|
||||
: friend?.get("avatar_static");
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -38,7 +38,7 @@ export const AvatarOverlay: React.FC<Props> = ({
|
||||
className='account__avatar'
|
||||
style={{ width: `${baseSize}px`, height: `${baseSize}px` }}
|
||||
>
|
||||
{accountSrc && <img src={accountSrc} alt={account?.get('acct')} />}
|
||||
{accountSrc && <img src={accountSrc} alt={account?.get("acct")} />}
|
||||
</div>
|
||||
</div>
|
||||
<div className='account__avatar-overlay-overlay'>
|
||||
@@ -46,7 +46,7 @@ export const AvatarOverlay: React.FC<Props> = ({
|
||||
className='account__avatar'
|
||||
style={{ width: `${overlaySize}px`, height: `${overlaySize}px` }}
|
||||
>
|
||||
{friendSrc && <img src={friendSrc} alt={friend?.get('acct')} />}
|
||||
{friendSrc && <img src={friendSrc} alt={friend?.get("acct")} />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { ReactComponent as GroupsIcon } from '@material-design-icons/svg/outlined/group.svg';
|
||||
import { ReactComponent as PersonIcon } from '@material-design-icons/svg/outlined/person.svg';
|
||||
import { ReactComponent as SmartToyIcon } from '@material-design-icons/svg/outlined/smart_toy.svg';
|
||||
import { ReactComponent as GroupsIcon } from "@material-design-icons/svg/outlined/group.svg";
|
||||
import { ReactComponent as PersonIcon } from "@material-design-icons/svg/outlined/person.svg";
|
||||
import { ReactComponent as SmartToyIcon } from "@material-design-icons/svg/outlined/smart_toy.svg";
|
||||
|
||||
|
||||
export const Badge = ({ icon, label, domain }) => (
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { memo, useRef, useEffect } from 'react';
|
||||
import { memo, useRef, useEffect } from "react";
|
||||
|
||||
import { decode } from 'blurhash';
|
||||
import { decode } from "blurhash";
|
||||
|
||||
interface Props extends React.HTMLAttributes<HTMLCanvasElement> {
|
||||
hash: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
dummy?: boolean; // Whether dummy mode is enabled. If enabled, nothing is rendered and canvas left untouched
|
||||
children?: never;
|
||||
hash: string,
|
||||
width?: number,
|
||||
height?: number,
|
||||
dummy?: boolean, // Whether dummy mode is enabled. If enabled, nothing is rendered and canvas left untouched
|
||||
children?: never,
|
||||
}
|
||||
const Blurhash: React.FC<Props> = ({
|
||||
hash,
|
||||
@@ -25,16 +25,18 @@ const Blurhash: React.FC<Props> = ({
|
||||
// eslint-disable-next-line no-self-assign
|
||||
canvas.width = canvas.width; // resets canvas
|
||||
|
||||
if (dummy || !hash) return;
|
||||
if (dummy || !hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const pixels = decode(hash, width, height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
const ctx = canvas.getContext("2d");
|
||||
const imageData = new ImageData(pixels, width, height);
|
||||
|
||||
ctx?.putImageData(imageData, 0, 0);
|
||||
} catch (err) {
|
||||
console.error('Blurhash decoding failure', { err, hash });
|
||||
console.error("Blurhash decoding failure", { err, hash });
|
||||
}
|
||||
}, [dummy, hash, width, height]);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
export default class Button extends PureComponent {
|
||||
|
||||
@@ -18,7 +18,7 @@ export default class Button extends PureComponent {
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
type: 'button',
|
||||
type: "button",
|
||||
};
|
||||
|
||||
handleClick = (e) => {
|
||||
@@ -36,9 +36,9 @@ export default class Button extends PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const className = classNames('button', this.props.className, {
|
||||
'button-secondary': this.props.secondary,
|
||||
'button--block': this.props.block,
|
||||
const className = classNames("button", this.props.className, {
|
||||
"button-secondary": this.props.secondary,
|
||||
"button--block": this.props.block,
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
interface Props {
|
||||
size: number;
|
||||
strokeWidth: number;
|
||||
size: number,
|
||||
strokeWidth: number,
|
||||
}
|
||||
|
||||
export const CircularProgress: React.FC<Props> = ({ size, strokeWidth }) => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import { supportsPassiveEvents } from "detect-passive-events";
|
||||
|
||||
import { scrollTop } from '../scroll';
|
||||
import { scrollTop } from "../scroll";
|
||||
|
||||
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
|
||||
|
||||
@@ -21,7 +21,7 @@ export default class Column extends PureComponent {
|
||||
if (this.props.bindToDocument) {
|
||||
scrollable = document.scrollingElement;
|
||||
} else {
|
||||
scrollable = this.node.querySelector('.scrollable');
|
||||
scrollable = this.node.querySelector(".scrollable");
|
||||
}
|
||||
|
||||
if (!scrollable) {
|
||||
@@ -32,7 +32,7 @@ export default class Column extends PureComponent {
|
||||
}
|
||||
|
||||
handleWheel = () => {
|
||||
if (typeof this._interruptScrollAnimation !== 'function') {
|
||||
if (typeof this._interruptScrollAnimation !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,17 +45,17 @@ export default class Column extends PureComponent {
|
||||
|
||||
componentDidMount () {
|
||||
if (this.props.bindToDocument) {
|
||||
document.addEventListener('wheel', this.handleWheel, listenerOptions);
|
||||
document.addEventListener("wheel", this.handleWheel, listenerOptions);
|
||||
} else {
|
||||
this.node.addEventListener('wheel', this.handleWheel, listenerOptions);
|
||||
this.node.addEventListener("wheel", this.handleWheel, listenerOptions);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.props.bindToDocument) {
|
||||
document.removeEventListener('wheel', this.handleWheel, listenerOptions);
|
||||
document.removeEventListener("wheel", this.handleWheel, listenerOptions);
|
||||
} else {
|
||||
this.node.removeEventListener('wheel', this.handleWheel, listenerOptions);
|
||||
this.node.removeEventListener("wheel", this.handleWheel, listenerOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { Icon } from "mastodon/components/icon";
|
||||
|
||||
export default class ColumnBackButton extends PureComponent {
|
||||
|
||||
@@ -26,7 +26,7 @@ export default class ColumnBackButton extends PureComponent {
|
||||
} else if (router.history.location?.state?.fromMastodon) {
|
||||
router.history.goBack();
|
||||
} else {
|
||||
router.history.push('/');
|
||||
router.history.push("/");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ export default class ColumnBackButton extends PureComponent {
|
||||
// The portal container and the component may be rendered to the DOM in
|
||||
// the same React render pass, so the container might not be available at
|
||||
// the time `render()` is called.
|
||||
const container = document.getElementById('tabs-bar__portal');
|
||||
const container = document.getElementById("tabs-bar__portal");
|
||||
if (container === null) {
|
||||
// The container wasn't available, force a re-render so that the
|
||||
// component can eventually be inserted in the container and not scroll
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { Icon } from "mastodon/components/icon";
|
||||
|
||||
import ColumnBackButton from './column_back_button';
|
||||
import ColumnBackButton from "./column_back_button";
|
||||
|
||||
export default class ColumnBackButtonSlim extends ColumnBackButton {
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
|
||||
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
||||
import { FormattedMessage, injectIntl, defineMessages } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { Icon } from "mastodon/components/icon";
|
||||
|
||||
const messages = defineMessages({
|
||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||
hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
|
||||
moveLeft: { id: 'column_header.moveLeft_settings', defaultMessage: 'Move column to the left' },
|
||||
moveRight: { id: 'column_header.moveRight_settings', defaultMessage: 'Move column to the right' },
|
||||
show: { id: "column_header.show_settings", defaultMessage: "Show settings" },
|
||||
hide: { id: "column_header.hide_settings", defaultMessage: "Hide settings" },
|
||||
moveLeft: { id: "column_header.moveLeft_settings", defaultMessage: "Move column to the left" },
|
||||
moveRight: { id: "column_header.moveRight_settings", defaultMessage: "Move column to the right" },
|
||||
});
|
||||
|
||||
class ColumnHeader extends PureComponent {
|
||||
@@ -68,7 +68,7 @@ class ColumnHeader extends PureComponent {
|
||||
if (router.history.location?.state?.fromMastodon) {
|
||||
router.history.goBack();
|
||||
} else {
|
||||
router.history.push('/');
|
||||
router.history.push("/");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -78,7 +78,7 @@ class ColumnHeader extends PureComponent {
|
||||
|
||||
handlePin = () => {
|
||||
if (!this.props.pinned) {
|
||||
this.context.router.history.replace('/');
|
||||
this.context.router.history.replace("/");
|
||||
}
|
||||
|
||||
this.props.onPin();
|
||||
@@ -89,21 +89,21 @@ class ColumnHeader extends PureComponent {
|
||||
const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues } = this.props;
|
||||
const { collapsed, animating } = this.state;
|
||||
|
||||
const wrapperClassName = classNames('column-header__wrapper', {
|
||||
'active': active,
|
||||
const wrapperClassName = classNames("column-header__wrapper", {
|
||||
"active": active,
|
||||
});
|
||||
|
||||
const buttonClassName = classNames('column-header', {
|
||||
'active': active,
|
||||
const buttonClassName = classNames("column-header", {
|
||||
"active": active,
|
||||
});
|
||||
|
||||
const collapsibleClassName = classNames('column-header__collapsible', {
|
||||
'collapsed': collapsed,
|
||||
'animating': animating,
|
||||
const collapsibleClassName = classNames("column-header__collapsible", {
|
||||
"collapsed": collapsed,
|
||||
"animating": animating,
|
||||
});
|
||||
|
||||
const collapsibleButtonClassName = classNames('column-header__button', {
|
||||
'active': !collapsed,
|
||||
const collapsibleButtonClassName = classNames("column-header__button", {
|
||||
"active": !collapsed,
|
||||
});
|
||||
|
||||
let extraContent, pinButton, moveButtons, backButton, collapseButton;
|
||||
@@ -200,7 +200,7 @@ class ColumnHeader extends PureComponent {
|
||||
// The portal container and the component may be rendered to the DOM in
|
||||
// the same React render pass, so the container might not be available at
|
||||
// the time `render()` is called.
|
||||
const container = document.getElementById('tabs-bar__portal');
|
||||
const container = document.getElementById("tabs-bar__portal");
|
||||
if (container === null) {
|
||||
// The container wasn't available, force a re-render so that the
|
||||
// component can eventually be inserted in the container and not scroll
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
export const StatusesCounter = (
|
||||
displayNumber: React.ReactNode,
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { type PropsWithChildren } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { defineMessages, useIntl } from "react-intl";
|
||||
|
||||
import { bannerSettings } from 'mastodon/settings';
|
||||
import { bannerSettings } from "mastodon/settings";
|
||||
|
||||
import { IconButton } from './icon_button';
|
||||
import { IconButton } from "./icon_button";
|
||||
|
||||
const messages = defineMessages({
|
||||
dismiss: { id: 'dismissable_banner.dismiss', defaultMessage: 'Dismiss' },
|
||||
dismiss: { id: "dismissable_banner.dismiss", defaultMessage: "Dismiss" },
|
||||
});
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
id: string,
|
||||
}
|
||||
|
||||
export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
import type { List } from 'immutable';
|
||||
import { type List } from "immutable";
|
||||
|
||||
import type { Account } from '../../types/resources';
|
||||
import { autoPlayGif } from '../initial_state';
|
||||
import { type Account } from "../../types/resources";
|
||||
import { autoPlayGif } from "../initial_state";
|
||||
|
||||
import { Skeleton } from './skeleton';
|
||||
import { Skeleton } from "./skeleton";
|
||||
|
||||
interface Props {
|
||||
account?: Account;
|
||||
others?: List<Account>;
|
||||
localDomain?: string;
|
||||
account?: Account,
|
||||
others?: List<Account>,
|
||||
localDomain?: string,
|
||||
}
|
||||
|
||||
export class DisplayName extends React.PureComponent<Props> {
|
||||
@@ -22,11 +22,13 @@ export class DisplayName extends React.PureComponent<Props> {
|
||||
}
|
||||
|
||||
const emojis =
|
||||
currentTarget.querySelectorAll<HTMLImageElement>('img.custom-emoji');
|
||||
currentTarget.querySelectorAll<HTMLImageElement>("img.custom-emoji");
|
||||
|
||||
emojis.forEach((emoji) => {
|
||||
const originalSrc = emoji.getAttribute('data-original');
|
||||
if (originalSrc != null) emoji.src = originalSrc;
|
||||
const originalSrc = emoji.getAttribute("data-original");
|
||||
if (originalSrc != null) {
|
||||
emoji.src = originalSrc;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -38,11 +40,13 @@ export class DisplayName extends React.PureComponent<Props> {
|
||||
}
|
||||
|
||||
const emojis =
|
||||
currentTarget.querySelectorAll<HTMLImageElement>('img.custom-emoji');
|
||||
currentTarget.querySelectorAll<HTMLImageElement>("img.custom-emoji");
|
||||
|
||||
emojis.forEach((emoji) => {
|
||||
const staticSrc = emoji.getAttribute('data-static');
|
||||
if (staticSrc != null) emoji.src = staticSrc;
|
||||
const staticSrc = emoji.getAttribute("data-static");
|
||||
if (staticSrc != null) {
|
||||
emoji.src = staticSrc;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -63,22 +67,22 @@ export class DisplayName extends React.PureComponent<Props> {
|
||||
displayName = others
|
||||
.take(2)
|
||||
.map((a) => (
|
||||
<bdi key={a.get('id')}>
|
||||
<bdi key={a.get("id")}>
|
||||
<strong
|
||||
className='display-name__html'
|
||||
dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }}
|
||||
dangerouslySetInnerHTML={{ __html: a.get("display_name_html") }}
|
||||
/>
|
||||
</bdi>
|
||||
))
|
||||
.reduce((prev, cur) => [prev, ', ', cur]);
|
||||
.reduce((prev, cur) => [prev, ", ", cur]);
|
||||
|
||||
if (others.size - 2 > 0) {
|
||||
suffix = `+${others.size - 2}`;
|
||||
}
|
||||
} else if (account) {
|
||||
let acct = account.get('acct');
|
||||
let acct = account.get("acct");
|
||||
|
||||
if (!acct.includes('@') && localDomain) {
|
||||
if (!acct.includes("@") && localDomain) {
|
||||
acct = `${acct}@${localDomain}`;
|
||||
}
|
||||
|
||||
@@ -87,7 +91,7 @@ export class DisplayName extends React.PureComponent<Props> {
|
||||
<strong
|
||||
className='display-name__html'
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: account.get('display_name_html'),
|
||||
__html: account.get("display_name_html"),
|
||||
}}
|
||||
/>
|
||||
</bdi>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback } from "react";
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { defineMessages, useIntl } from "react-intl";
|
||||
|
||||
import { IconButton } from './icon_button';
|
||||
import { IconButton } from "./icon_button";
|
||||
|
||||
const messages = defineMessages({
|
||||
unblockDomain: {
|
||||
id: 'account.unblock_domain',
|
||||
defaultMessage: 'Unblock domain {domain}',
|
||||
id: "account.unblock_domain",
|
||||
defaultMessage: "Unblock domain {domain}",
|
||||
},
|
||||
});
|
||||
|
||||
interface Props {
|
||||
domain: string;
|
||||
onUnblockDomain: (domain: string) => void;
|
||||
domain: string,
|
||||
onUnblockDomain: (domain: string) => void,
|
||||
}
|
||||
|
||||
export const Domain: React.FC<Props> = ({ domain, onUnblockDomain }) => {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent, cloneElement, Children } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent, cloneElement, Children } from "react";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import Overlay from 'react-overlays/Overlay';
|
||||
import { supportsPassiveEvents } from "detect-passive-events";
|
||||
import Overlay from "react-overlays/Overlay";
|
||||
|
||||
import { CircularProgress } from "./circular_progress";
|
||||
import { IconButton } from './icon_button';
|
||||
import { IconButton } from "./icon_button";
|
||||
|
||||
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
|
||||
let id = 0;
|
||||
@@ -44,9 +44,9 @@ class DropdownMenu extends PureComponent {
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
document.addEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener('keydown', this.handleKeyDown, { capture: true });
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.addEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener("keydown", this.handleKeyDown, { capture: true });
|
||||
document.addEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
|
||||
if (this.focusedItem && this.props.openedViaKeyboard) {
|
||||
this.focusedItem.focus({ preventScroll: true });
|
||||
@@ -54,9 +54,9 @@ class DropdownMenu extends PureComponent {
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
document.removeEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener('keydown', this.handleKeyDown, { capture: true });
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.removeEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener("keydown", this.handleKeyDown, { capture: true });
|
||||
document.removeEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
@@ -68,33 +68,33 @@ class DropdownMenu extends PureComponent {
|
||||
};
|
||||
|
||||
handleKeyDown = e => {
|
||||
const items = Array.from(this.node.querySelectorAll('a, button'));
|
||||
const items = Array.from(this.node.querySelectorAll("a, button"));
|
||||
const index = items.indexOf(document.activeElement);
|
||||
let element = null;
|
||||
|
||||
switch(e.key) {
|
||||
case 'ArrowDown':
|
||||
element = items[index+1] || items[0];
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
element = items[index-1] || items[items.length-1];
|
||||
break;
|
||||
case 'Tab':
|
||||
if (e.shiftKey) {
|
||||
element = items[index-1] || items[items.length-1];
|
||||
} else {
|
||||
case "ArrowDown":
|
||||
element = items[index+1] || items[0];
|
||||
}
|
||||
break;
|
||||
case 'Home':
|
||||
element = items[0];
|
||||
break;
|
||||
case 'End':
|
||||
element = items[items.length-1];
|
||||
break;
|
||||
case 'Escape':
|
||||
this.props.onClose();
|
||||
break;
|
||||
break;
|
||||
case "ArrowUp":
|
||||
element = items[index-1] || items[items.length-1];
|
||||
break;
|
||||
case "Tab":
|
||||
if (e.shiftKey) {
|
||||
element = items[index-1] || items[items.length-1];
|
||||
} else {
|
||||
element = items[index+1] || items[0];
|
||||
}
|
||||
break;
|
||||
case "Home":
|
||||
element = items[0];
|
||||
break;
|
||||
case "End":
|
||||
element = items[items.length-1];
|
||||
break;
|
||||
case "Escape":
|
||||
this.props.onClose();
|
||||
break;
|
||||
}
|
||||
|
||||
if (element) {
|
||||
@@ -105,7 +105,7 @@ class DropdownMenu extends PureComponent {
|
||||
};
|
||||
|
||||
handleItemKeyPress = e => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
this.handleClick(e);
|
||||
}
|
||||
};
|
||||
@@ -120,10 +120,10 @@ class DropdownMenu extends PureComponent {
|
||||
return <li key={`sep-${i}`} className='dropdown-menu__separator' />;
|
||||
}
|
||||
|
||||
const { text, href = '#', target = '_blank', method, dangerous } = option;
|
||||
const { text, href = "#", target = "_blank", method, dangerous } = option;
|
||||
|
||||
return (
|
||||
<li className={classNames('dropdown-menu__item', { 'dropdown-menu__item--dangerous': dangerous })} key={`${text}-${i}`}>
|
||||
<li className={classNames("dropdown-menu__item", { "dropdown-menu__item--dangerous": dangerous })} key={`${text}-${i}`}>
|
||||
<a href={href} target={target} data-method={method} rel='noopener noreferrer' role='button' tabIndex={0} ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyPress={this.handleItemKeyPress} data-index={i}>
|
||||
{text}
|
||||
</a>
|
||||
@@ -137,7 +137,7 @@ class DropdownMenu extends PureComponent {
|
||||
let renderItem = this.props.renderItem || this.renderItem;
|
||||
|
||||
return (
|
||||
<div className={classNames('dropdown-menu__container', { 'dropdown-menu__container--loading': loading })} ref={this.setRef}>
|
||||
<div className={classNames("dropdown-menu__container", { "dropdown-menu__container--loading": loading })} ref={this.setRef}>
|
||||
{loading && (
|
||||
<CircularProgress size={30} strokeWidth={3.5} />
|
||||
)}
|
||||
@@ -149,7 +149,7 @@ class DropdownMenu extends PureComponent {
|
||||
)}
|
||||
|
||||
{!loading && (
|
||||
<ul className={classNames('dropdown-menu__container__list', { 'dropdown-menu__container__list--scrollable': scrollable })}>
|
||||
<ul className={classNames("dropdown-menu__container__list", { "dropdown-menu__container__list--scrollable": scrollable })}>
|
||||
{items.map((option, i) => renderItem(option, i, { onClick: this.handleClick, onKeyPress: this.handleItemKeyPress }))}
|
||||
</ul>
|
||||
)}
|
||||
@@ -186,7 +186,7 @@ export default class Dropdown extends PureComponent {
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
title: 'Menu',
|
||||
title: "Menu",
|
||||
};
|
||||
|
||||
state = {
|
||||
@@ -197,7 +197,7 @@ export default class Dropdown extends PureComponent {
|
||||
if (this.state.id === this.props.openDropdownId) {
|
||||
this.handleClose();
|
||||
} else {
|
||||
this.props.onOpen(this.state.id, this.handleItemClick, type !== 'click');
|
||||
this.props.onOpen(this.state.id, this.handleItemClick, type !== "click");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -217,35 +217,35 @@ export default class Dropdown extends PureComponent {
|
||||
|
||||
handleButtonKeyDown = (e) => {
|
||||
switch(e.key) {
|
||||
case ' ':
|
||||
case 'Enter':
|
||||
this.handleMouseDown();
|
||||
break;
|
||||
case " ":
|
||||
case "Enter":
|
||||
this.handleMouseDown();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyPress = (e) => {
|
||||
switch(e.key) {
|
||||
case ' ':
|
||||
case 'Enter':
|
||||
this.handleClick(e);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
case " ":
|
||||
case "Enter":
|
||||
this.handleClick(e);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
handleItemClick = e => {
|
||||
const { onItemClick } = this.props;
|
||||
const i = Number(e.currentTarget.getAttribute('data-index'));
|
||||
const i = Number(e.currentTarget.getAttribute("data-index"));
|
||||
const item = this.props.items[i];
|
||||
|
||||
this.handleClose();
|
||||
|
||||
if (typeof onItemClick === 'function') {
|
||||
if (typeof onItemClick === "function") {
|
||||
e.preventDefault();
|
||||
onItemClick(item, i);
|
||||
} else if (item && typeof item.action === 'function') {
|
||||
} else if (item && typeof item.action === "function") {
|
||||
e.preventDefault();
|
||||
item.action();
|
||||
} else if (item && item.to) {
|
||||
@@ -297,7 +297,7 @@ export default class Dropdown extends PureComponent {
|
||||
onKeyPress: this.handleKeyPress,
|
||||
}) : (
|
||||
<IconButton
|
||||
icon={!open ? icon : 'close'}
|
||||
icon={!open ? icon : "close"}
|
||||
title={title}
|
||||
active={open}
|
||||
disabled={disabled}
|
||||
@@ -314,7 +314,7 @@ export default class Dropdown extends PureComponent {
|
||||
<span ref={this.setTargetRef}>
|
||||
{button}
|
||||
</span>
|
||||
<Overlay show={open} offset={[5, 5]} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
|
||||
<Overlay show={open} offset={[5, 5]} placement={"bottom"} flip target={this.findTarget} popperConfig={{ strategy: "fixed" }}>
|
||||
{({ props, arrowProps, placement }) => (
|
||||
<div {...props}>
|
||||
<div className={`dropdown-animation dropdown-menu ${placement}`}>
|
||||
|
||||
+6
-6
@@ -1,8 +1,8 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { openDropdownMenu, closeDropdownMenu } from 'mastodon/actions/dropdown_menu';
|
||||
import { fetchHistory } from 'mastodon/actions/history';
|
||||
import DropdownMenu from 'mastodon/components/dropdown_menu';
|
||||
import { openDropdownMenu, closeDropdownMenu } from "mastodon/actions/dropdown_menu";
|
||||
import { fetchHistory } from "mastodon/actions/history";
|
||||
import DropdownMenu from "mastodon/components/dropdown_menu";
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -12,8 +12,8 @@ import DropdownMenu from 'mastodon/components/dropdown_menu';
|
||||
const mapStateToProps = (state, { statusId }) => ({
|
||||
openDropdownId: state.dropdownMenu.openId,
|
||||
openedViaKeyboard: state.dropdownMenu.keyboard,
|
||||
items: state.getIn(['history', statusId, 'items']),
|
||||
loading: state.getIn(['history', statusId, 'loading']),
|
||||
items: state.getIn(["history", statusId, "items"]),
|
||||
loading: state.getIn(["history", statusId, "loading"]),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch, { statusId }) => ({
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
import { FormattedMessage, injectIntl } from "react-intl";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import InlineAccount from 'mastodon/components/inline_account';
|
||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
||||
import { openModal } from "mastodon/actions/modal";
|
||||
import { Icon } from "mastodon/components/icon";
|
||||
import InlineAccount from "mastodon/components/inline_account";
|
||||
import { RelativeTimestamp } from "mastodon/components/relative_timestamp";
|
||||
|
||||
import DropdownMenu from './containers/dropdown_menu_container';
|
||||
import DropdownMenu from "./containers/dropdown_menu_container";
|
||||
|
||||
const mapDispatchToProps = (dispatch, { statusId }) => ({
|
||||
|
||||
onItemClick (index) {
|
||||
dispatch(openModal({
|
||||
modalType: 'COMPARE_HISTORY',
|
||||
modalType: "COMPARE_HISTORY",
|
||||
modalProps: { index, statusId },
|
||||
}));
|
||||
},
|
||||
@@ -44,17 +44,17 @@ class EditedTimestamp extends PureComponent {
|
||||
};
|
||||
|
||||
renderItem = (item, index, { onClick, onKeyPress }) => {
|
||||
const formattedDate = <RelativeTimestamp timestamp={item.get('created_at')} short={false} />;
|
||||
const formattedName = <InlineAccount accountId={item.get('account')} />;
|
||||
const formattedDate = <RelativeTimestamp timestamp={item.get("created_at")} short={false} />;
|
||||
const formattedName = <InlineAccount accountId={item.get("account")} />;
|
||||
|
||||
const label = item.get('original') ? (
|
||||
const label = item.get("original") ? (
|
||||
<FormattedMessage id='status.history.created' defaultMessage='{name} created {date}' values={{ name: formattedName, date: formattedDate }} />
|
||||
) : (
|
||||
<FormattedMessage id='status.history.edited' defaultMessage='{name} edited {date}' values={{ name: formattedName, date: formattedDate }} />
|
||||
);
|
||||
|
||||
return (
|
||||
<li className='dropdown-menu__item edited-timestamp__history__item' key={item.get('created_at')}>
|
||||
<li className='dropdown-menu__item edited-timestamp__history__item' key={item.get("created_at")}>
|
||||
<button data-index={index} onClick={onClick} onKeyPress={onKeyPress}>{label}</button>
|
||||
</li>
|
||||
);
|
||||
@@ -66,7 +66,7 @@ class EditedTimestamp extends PureComponent {
|
||||
return (
|
||||
<DropdownMenu statusId={statusId} renderItem={this.renderItem} scrollable renderHeader={this.renderHeader} onItemClick={this.handleItemClick}>
|
||||
<button className='dropdown-menu__text-button'>
|
||||
<FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: intl.formatDate(timestamp, { hour12: false, month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) }} /> <Icon id='caret-down' />
|
||||
<FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: intl.formatDate(timestamp, { hour12: false, month: "short", day: "2-digit", hour: "2-digit", minute: "2-digit" }) }} /> <Icon id='caret-down' />
|
||||
</button>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { DisplayName } from 'mastodon/components/display_name';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
import { DisplayName } from "mastodon/components/display_name";
|
||||
import { Skeleton } from "mastodon/components/skeleton";
|
||||
|
||||
interface Props {
|
||||
size?: number;
|
||||
minimal?: boolean;
|
||||
size?: number,
|
||||
minimal?: boolean,
|
||||
}
|
||||
|
||||
export const EmptyAccount: React.FC<Props> = ({
|
||||
@@ -15,7 +15,7 @@ export const EmptyAccount: React.FC<Props> = ({
|
||||
minimal = false,
|
||||
}) => {
|
||||
return (
|
||||
<div className={classNames('account', { 'account--minimal': minimal })}>
|
||||
<div className={classNames("account", { "account--minimal": minimal })}>
|
||||
<div className='account__wrapper'>
|
||||
<div className='account__display-name'>
|
||||
<div className='account__avatar-wrapper'>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import StackTrace from 'stacktrace-js';
|
||||
import StackTrace from "stacktrace-js";
|
||||
|
||||
import { version, source_url } from 'mastodon/initial_state';
|
||||
import { version, source_url } from "mastodon/initial_state";
|
||||
|
||||
export default class ErrorBoundary extends PureComponent {
|
||||
|
||||
@@ -34,7 +34,7 @@ export default class ErrorBoundary extends PureComponent {
|
||||
|
||||
StackTrace.fromError(error).then((stackframes) => {
|
||||
this.setState({
|
||||
mappedStackTrace: stackframes.map((sf) => sf.toString()).join('\n'),
|
||||
mappedStackTrace: stackframes.map((sf) => sf.toString()).join("\n"),
|
||||
});
|
||||
}).catch(() => {
|
||||
this.setState({
|
||||
@@ -45,23 +45,23 @@ export default class ErrorBoundary extends PureComponent {
|
||||
|
||||
handleCopyStackTrace = () => {
|
||||
const { errorMessage, stackTrace, mappedStackTrace } = this.state;
|
||||
const textarea = document.createElement('textarea');
|
||||
const textarea = document.createElement("textarea");
|
||||
|
||||
let contents = [errorMessage, stackTrace];
|
||||
if (mappedStackTrace) {
|
||||
contents.push(mappedStackTrace);
|
||||
}
|
||||
|
||||
textarea.textContent = contents.join('\n\n\n');
|
||||
textarea.style.position = 'fixed';
|
||||
textarea.textContent = contents.join("\n\n\n");
|
||||
textarea.style.position = "fixed";
|
||||
|
||||
document.body.appendChild(textarea);
|
||||
|
||||
try {
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
document.execCommand("copy");
|
||||
} catch (e) {
|
||||
|
||||
console.error(e);
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
@@ -77,7 +77,7 @@ export default class ErrorBoundary extends PureComponent {
|
||||
return this.props.children;
|
||||
}
|
||||
|
||||
const likelyBrowserAddonIssue = errorMessage && errorMessage.includes('NotFoundError');
|
||||
const likelyBrowserAddonIssue = errorMessage && errorMessage.includes("NotFoundError");
|
||||
|
||||
return (
|
||||
<div className='error-boundary'>
|
||||
@@ -98,7 +98,7 @@ export default class ErrorBoundary extends PureComponent {
|
||||
)}
|
||||
</p>
|
||||
|
||||
<p className='error-boundary__footer'>Mastodon v{version} · <a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='errors.unexpected_crash.report_issue' defaultMessage='Report issue' /></a> · <button onClick={this.handleCopyStackTrace} className={copied ? 'copied' : ''}><FormattedMessage id='errors.unexpected_crash.copy_stacktrace' defaultMessage='Copy stacktrace to clipboard' /></button></p>
|
||||
<p className='error-boundary__footer'>Mastodon v{version} · <a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='errors.unexpected_crash.report_issue' defaultMessage='Report issue' /></a> · <button onClick={this.handleCopyStackTrace} className={copied ? "copied" : ""}><FormattedMessage id='errors.unexpected_crash.copy_stacktrace' defaultMessage='Copy stacktrace to clipboard' /></button></p>
|
||||
</div>
|
||||
|
||||
<Helmet>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
src: string;
|
||||
key: string;
|
||||
alt?: string;
|
||||
lang?: string;
|
||||
width: number;
|
||||
height: number;
|
||||
onClick?: () => void;
|
||||
src: string,
|
||||
key: string,
|
||||
alt?: string,
|
||||
lang?: string,
|
||||
width: number,
|
||||
height: number,
|
||||
onClick?: () => void,
|
||||
}
|
||||
|
||||
export const GIFV: React.FC<Props> = ({
|
||||
@@ -36,7 +36,7 @@ export const GIFV: React.FC<Props> = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<div className='gifv' style={{ position: 'relative' }}>
|
||||
<div className='gifv' style={{ position: "relative" }}>
|
||||
{loading && (
|
||||
<canvas
|
||||
width={width}
|
||||
@@ -63,7 +63,7 @@ export const GIFV: React.FC<Props> = ({
|
||||
playsInline
|
||||
onClick={handleClick}
|
||||
onLoadedData={handleLoadedData}
|
||||
style={{ position: loading ? 'absolute' : 'static', top: 0, left: 0 }}
|
||||
style={{ position: loading ? "absolute" : "static", top: 0, left: 0 }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
// @ts-check
|
||||
import PropTypes from 'prop-types';
|
||||
import { Component } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { Component } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
import classNames from "classnames";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
|
||||
import { Sparklines, SparklinesCurve } from 'react-sparklines';
|
||||
import { Sparklines, SparklinesCurve } from "react-sparklines";
|
||||
|
||||
import { ShortNumber } from 'mastodon/components/short_number';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
import { ShortNumber } from "mastodon/components/short_number";
|
||||
import { Skeleton } from "mastodon/components/skeleton";
|
||||
|
||||
class SilentErrorBoundary extends Component {
|
||||
|
||||
@@ -57,11 +57,11 @@ export const accountsCountRenderer = (displayNumber, pluralReady) => (
|
||||
// @ts-expect-error
|
||||
export const ImmutableHashtag = ({ hashtag }) => (
|
||||
<Hashtag
|
||||
name={hashtag.get('name')}
|
||||
to={`/tags/${hashtag.get('name')}`}
|
||||
people={hashtag.getIn(['history', 0, 'accounts']) * 1 + hashtag.getIn(['history', 1, 'accounts']) * 1}
|
||||
name={hashtag.get("name")}
|
||||
to={`/tags/${hashtag.get("name")}`}
|
||||
people={hashtag.getIn(["history", 0, "accounts"]) * 1 + hashtag.getIn(["history", 1, "accounts"]) * 1}
|
||||
// @ts-expect-error
|
||||
history={hashtag.get('history').reverse().map((day) => day.get('uses')).toArray()}
|
||||
history={hashtag.get("history").reverse().map((day) => day.get("uses")).toArray()}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -71,7 +71,7 @@ ImmutableHashtag.propTypes = {
|
||||
|
||||
// @ts-expect-error
|
||||
const Hashtag = ({ name, to, people, uses, history, className, description, withGraph }) => (
|
||||
<div className={classNames('trends__item', className)}>
|
||||
<div className={classNames("trends__item", className)}>
|
||||
<div className='trends__item__name'>
|
||||
<Link to={to}>
|
||||
{name ? <>#<span>{name}</span></> : <Skeleton width={50} />}
|
||||
@@ -80,11 +80,11 @@ const Hashtag = ({ name, to, people, uses, history, className, description, with
|
||||
{description ? (
|
||||
<span>{description}</span>
|
||||
) : (
|
||||
typeof people !== 'undefined' ? <ShortNumber value={people} renderer={accountsCountRenderer} /> : <Skeleton width={100} />
|
||||
typeof people !== "undefined" ? <ShortNumber value={people} renderer={accountsCountRenderer} /> : <Skeleton width={100} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{typeof uses !== 'undefined' && (
|
||||
{typeof uses !== "undefined" && (
|
||||
<div className='trends__item__current'>
|
||||
<ShortNumber value={uses} />
|
||||
</div>
|
||||
@@ -94,7 +94,7 @@ const Hashtag = ({ name, to, people, uses, history, className, description, with
|
||||
<div className='trends__item__sparkline'>
|
||||
<SilentErrorBoundary>
|
||||
<Sparklines width={50} height={28} data={history ? history : Array.from(Array(7)).map(() => 0)}>
|
||||
<SparklinesCurve style={{ fill: 'none' }} />
|
||||
<SparklinesCurve style={{ fill: "none" }} />
|
||||
</Sparklines>
|
||||
</SilentErrorBoundary>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useState, useCallback } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import type { List, Record } from 'immutable';
|
||||
import { type List, type Record } from "immutable";
|
||||
|
||||
import { groupBy, minBy } from 'lodash';
|
||||
import { groupBy, minBy } from "lodash";
|
||||
|
||||
import { getStatusContent } from './status_content';
|
||||
import { getStatusContent } from "./status_content";
|
||||
|
||||
// Fit on a single line on desktop
|
||||
const VISIBLE_HASHTAGS = 3;
|
||||
@@ -16,27 +16,27 @@ const VISIBLE_HASHTAGS = 3;
|
||||
// Those types are not correct, they need to be replaced once this part of the state is typed
|
||||
export type TagLike = Record<{ name: string }>;
|
||||
export type StatusLike = Record<{
|
||||
tags: List<TagLike>;
|
||||
contentHTML: string;
|
||||
media_attachments: List<unknown>;
|
||||
spoiler_text?: string;
|
||||
tags: List<TagLike>,
|
||||
contentHTML: string,
|
||||
media_attachments: List<unknown>,
|
||||
spoiler_text?: string,
|
||||
}>;
|
||||
|
||||
function normalizeHashtag(hashtag: string) {
|
||||
return (
|
||||
hashtag && hashtag.startsWith('#') ? hashtag.slice(1) : hashtag
|
||||
).normalize('NFKC');
|
||||
hashtag && hashtag.startsWith("#") ? hashtag.slice(1) : hashtag
|
||||
).normalize("NFKC");
|
||||
}
|
||||
|
||||
function isNodeLinkHashtag(element: Node): element is HTMLLinkElement {
|
||||
return (
|
||||
element instanceof HTMLAnchorElement &&
|
||||
// it may be a <a> starting with a hashtag
|
||||
(element.textContent.startsWith('#') ||
|
||||
(element.textContent.startsWith("#") ||
|
||||
// or a #<a>
|
||||
element.previousSibling?.textContent?.[
|
||||
element.previousSibling.textContent.length - 1
|
||||
] === '#')
|
||||
] === "#")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -48,11 +48,13 @@ function isNodeLinkHashtag(element: Node): element is HTMLLinkElement {
|
||||
*/
|
||||
function uniqueHashtagsWithCaseHandling(hashtags: string[]) {
|
||||
const groups = groupBy(hashtags, (tag) =>
|
||||
tag.normalize('NFKD').toLowerCase(),
|
||||
tag.normalize("NFKD").toLowerCase(),
|
||||
);
|
||||
|
||||
return Object.values(groups).map((tags) => {
|
||||
if (tags.length === 1) return tags[0];
|
||||
if (tags.length === 1) {
|
||||
return tags[0];
|
||||
}
|
||||
|
||||
// The best match is the one where we have the less difference between upper and lower case letter count
|
||||
const best = minBy(tags, (tag) => {
|
||||
@@ -72,27 +74,27 @@ function uniqueHashtagsWithCaseHandling(hashtags: string[]) {
|
||||
|
||||
// Create the collator once, this is much more efficient
|
||||
const collator = new Intl.Collator(undefined, {
|
||||
sensitivity: 'base', // we use this to emulate the ASCII folding done on the server-side, hopefuly more efficiently
|
||||
sensitivity: "base", // we use this to emulate the ASCII folding done on the server-side, hopefuly more efficiently
|
||||
});
|
||||
|
||||
function localeAwareInclude(collection: string[], value: string) {
|
||||
const normalizedValue = value.normalize('NFKC');
|
||||
const normalizedValue = value.normalize("NFKC");
|
||||
|
||||
return !!collection.find(
|
||||
(item) => collator.compare(item.normalize('NFKC'), normalizedValue) === 0,
|
||||
(item) => collator.compare(item.normalize("NFKC"), normalizedValue) === 0,
|
||||
);
|
||||
}
|
||||
|
||||
// We use an intermediate function here to make it easier to test
|
||||
export function computeHashtagBarForStatus(status: StatusLike): {
|
||||
statusContentProps: { statusContent: string };
|
||||
hashtagsInBar: string[];
|
||||
statusContentProps: { statusContent: string },
|
||||
hashtagsInBar: string[],
|
||||
} {
|
||||
let statusContent = getStatusContent(status);
|
||||
|
||||
const tagNames = status
|
||||
.get('tags')
|
||||
.map((tag) => tag.get('name'))
|
||||
.get("tags")
|
||||
.map((tag) => tag.get("name"))
|
||||
.toJS();
|
||||
|
||||
// this is returned if we stop the processing early, it does not change what is displayed
|
||||
@@ -102,24 +104,30 @@ export function computeHashtagBarForStatus(status: StatusLike): {
|
||||
};
|
||||
|
||||
// return early if this status does not have any tags
|
||||
if (tagNames.length === 0) return defaultResult;
|
||||
if (tagNames.length === 0) {
|
||||
return defaultResult;
|
||||
}
|
||||
|
||||
const template = document.createElement('template');
|
||||
const template = document.createElement("template");
|
||||
template.innerHTML = statusContent.trim();
|
||||
|
||||
const lastChild = template.content.lastChild;
|
||||
|
||||
if (!lastChild || lastChild.nodeType === Node.TEXT_NODE) return defaultResult;
|
||||
if (!lastChild || lastChild.nodeType === Node.TEXT_NODE) {
|
||||
return defaultResult;
|
||||
}
|
||||
|
||||
template.content.removeChild(lastChild);
|
||||
const contentWithoutLastLine = template;
|
||||
|
||||
// First, try to parse
|
||||
const contentHashtags = Array.from(
|
||||
contentWithoutLastLine.content.querySelectorAll<HTMLLinkElement>('a[href]'),
|
||||
contentWithoutLastLine.content.querySelectorAll<HTMLLinkElement>("a[href]"),
|
||||
).reduce<string[]>((result, link) => {
|
||||
if (isNodeLinkHashtag(link)) {
|
||||
if (link.textContent) result.push(normalizeHashtag(link.textContent));
|
||||
if (link.textContent) {
|
||||
result.push(normalizeHashtag(link.textContent));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}, []);
|
||||
@@ -129,7 +137,7 @@ export function computeHashtagBarForStatus(status: StatusLike): {
|
||||
// try to see if the last line is only hashtags
|
||||
let onlyHashtags = true;
|
||||
|
||||
const normalizedTagNames = tagNames.map((tag) => tag.normalize('NFKC'));
|
||||
const normalizedTagNames = tagNames.map((tag) => tag.normalize("NFKC"));
|
||||
|
||||
Array.from(lastChild.childNodes).forEach((node) => {
|
||||
if (isNodeLinkHashtag(node) && node.textContent) {
|
||||
@@ -141,9 +149,10 @@ export function computeHashtagBarForStatus(status: StatusLike): {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!localeAwareInclude(contentHashtags, normalized))
|
||||
// only add it if it does not appear in the rest of the content
|
||||
// only add it if it does not appear in the rest of the content
|
||||
if (!localeAwareInclude(contentHashtags, normalized)) {
|
||||
lastLineHashtags.push(normalized);
|
||||
}
|
||||
} else if (node.nodeType !== Node.TEXT_NODE || node.nodeValue?.trim()) {
|
||||
// not a space
|
||||
onlyHashtags = false;
|
||||
@@ -151,7 +160,7 @@ export function computeHashtagBarForStatus(status: StatusLike): {
|
||||
});
|
||||
|
||||
const hashtagsInBar = tagNames.filter((tag) => {
|
||||
const normalizedTag = tag.normalize('NFKC');
|
||||
const normalizedTag = tag.normalize("NFKC");
|
||||
// the tag does not appear at all in the status content, it is an out-of-band tag
|
||||
return (
|
||||
!localeAwareInclude(contentHashtags, normalizedTag) &&
|
||||
@@ -160,8 +169,8 @@ export function computeHashtagBarForStatus(status: StatusLike): {
|
||||
});
|
||||
|
||||
const isOnlyOneLine = contentWithoutLastLine.content.childElementCount === 0;
|
||||
const hasMedia = status.get('media_attachments').size > 0;
|
||||
const hasSpoiler = !!status.get('spoiler_text');
|
||||
const hasMedia = status.get("media_attachments").size > 0;
|
||||
const hasSpoiler = !!status.get("spoiler_text");
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- due to https://github.com/microsoft/TypeScript/issues/9998
|
||||
if (onlyHashtags && ((hasMedia && !hasSpoiler) || !isOnlyOneLine)) {
|
||||
@@ -179,25 +188,8 @@ export function computeHashtagBarForStatus(status: StatusLike): {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will process a status to, at the same time (avoiding parsing it twice):
|
||||
* - build the HashtagBar for this status
|
||||
* - remove the last-line hashtags from the status content
|
||||
* @param status The status to process
|
||||
* @returns Props to be passed to the <StatusContent> component, and the hashtagBar to render
|
||||
*/
|
||||
export function getHashtagBarForStatus(status: StatusLike) {
|
||||
const { statusContentProps, hashtagsInBar } =
|
||||
computeHashtagBarForStatus(status);
|
||||
|
||||
return {
|
||||
statusContentProps,
|
||||
hashtagBar: <HashtagBar hashtags={hashtagsInBar} />,
|
||||
};
|
||||
}
|
||||
|
||||
const HashtagBar: React.FC<{
|
||||
hashtags: string[];
|
||||
hashtags: string[],
|
||||
}> = ({ hashtags }) => {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const handleClick = useCallback(() => {
|
||||
@@ -232,3 +224,21 @@ const HashtagBar: React.FC<{
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will process a status to, at the same time (avoiding parsing it twice):
|
||||
* - build the HashtagBar for this status
|
||||
* - remove the last-line hashtags from the status content
|
||||
* @param status The status to process
|
||||
* @returns Props to be passed to the <StatusContent> component, and the hashtagBar to render
|
||||
*/
|
||||
export function getHashtagBarForStatus(status: StatusLike) {
|
||||
const { statusContentProps, hashtagsInBar } =
|
||||
computeHashtagBarForStatus(status);
|
||||
|
||||
return {
|
||||
statusContentProps,
|
||||
hashtagBar: <HashtagBar hashtags={hashtagsInBar} />,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
interface Props extends React.HTMLAttributes<HTMLImageElement> {
|
||||
id: string;
|
||||
className?: string;
|
||||
fixedWidth?: boolean;
|
||||
children?: never;
|
||||
id: string,
|
||||
className?: string,
|
||||
fixedWidth?: boolean,
|
||||
children?: never,
|
||||
}
|
||||
|
||||
export const Icon: React.FC<Props> = ({
|
||||
@@ -14,7 +14,7 @@ export const Icon: React.FC<Props> = ({
|
||||
...other
|
||||
}) => (
|
||||
<i
|
||||
className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })}
|
||||
className={classNames("fa", `fa-${id}`, className, { "fa-fw": fixedWidth })}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import { PureComponent } from 'react';
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { AnimatedNumber } from './animated_number';
|
||||
import { Icon } from './icon';
|
||||
import { AnimatedNumber } from "./animated_number";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
onMouseDown?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
|
||||
onKeyPress?: React.KeyboardEventHandler<HTMLButtonElement>;
|
||||
size: number;
|
||||
active: boolean;
|
||||
expanded?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
activeStyle?: React.CSSProperties;
|
||||
disabled: boolean;
|
||||
inverted?: boolean;
|
||||
animate: boolean;
|
||||
overlay: boolean;
|
||||
tabIndex: number;
|
||||
counter?: number;
|
||||
href?: string;
|
||||
ariaHidden: boolean;
|
||||
className?: string,
|
||||
title: string,
|
||||
icon: string,
|
||||
onClick?: React.MouseEventHandler<HTMLButtonElement>,
|
||||
onMouseDown?: React.MouseEventHandler<HTMLButtonElement>,
|
||||
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>,
|
||||
onKeyPress?: React.KeyboardEventHandler<HTMLButtonElement>,
|
||||
size: number,
|
||||
active: boolean,
|
||||
expanded?: boolean,
|
||||
style?: React.CSSProperties,
|
||||
activeStyle?: React.CSSProperties,
|
||||
disabled: boolean,
|
||||
inverted?: boolean,
|
||||
animate: boolean,
|
||||
overlay: boolean,
|
||||
tabIndex: number,
|
||||
counter?: number,
|
||||
href?: string,
|
||||
ariaHidden: boolean,
|
||||
}
|
||||
interface States {
|
||||
activate: boolean;
|
||||
deactivate: boolean;
|
||||
activate: boolean,
|
||||
deactivate: boolean,
|
||||
}
|
||||
export class IconButton extends PureComponent<Props, States> {
|
||||
static defaultProps = {
|
||||
@@ -48,7 +48,9 @@ export class IconButton extends PureComponent<Props, States> {
|
||||
};
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (!nextProps.animate) return;
|
||||
if (!nextProps.animate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.props.active && !nextProps.active) {
|
||||
this.setState({ activate: false, deactivate: true });
|
||||
@@ -65,12 +67,6 @@ export class IconButton extends PureComponent<Props, States> {
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyPress: React.KeyboardEventHandler<HTMLButtonElement> = (e) => {
|
||||
if (this.props.onKeyPress && !this.props.disabled) {
|
||||
this.props.onKeyPress(e);
|
||||
}
|
||||
};
|
||||
|
||||
handleMouseDown: React.MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
if (!this.props.disabled && this.props.onMouseDown) {
|
||||
this.props.onMouseDown(e);
|
||||
@@ -110,24 +106,24 @@ export class IconButton extends PureComponent<Props, States> {
|
||||
|
||||
const { activate, deactivate } = this.state;
|
||||
|
||||
const classes = classNames(className, 'icon-button', {
|
||||
const classes = classNames(className, "icon-button", {
|
||||
active,
|
||||
disabled,
|
||||
inverted,
|
||||
activate,
|
||||
deactivate,
|
||||
overlayed: overlay,
|
||||
'icon-button--with-counter': typeof counter !== 'undefined',
|
||||
"icon-button--with-counter": typeof counter !== "undefined",
|
||||
});
|
||||
|
||||
if (typeof counter !== 'undefined') {
|
||||
style.width = 'auto';
|
||||
if (typeof counter !== "undefined") {
|
||||
style.width = "auto";
|
||||
}
|
||||
|
||||
let contents = (
|
||||
<>
|
||||
<Icon id={icon} fixedWidth aria-hidden='true' />{' '}
|
||||
{typeof counter !== 'undefined' && (
|
||||
<Icon id={icon} fixedWidth aria-hidden='true' />{" "}
|
||||
{typeof counter !== "undefined" && (
|
||||
<span className='icon-button__counter'>
|
||||
<AnimatedNumber value={counter} />
|
||||
</span>
|
||||
@@ -154,7 +150,6 @@ export class IconButton extends PureComponent<Props, States> {
|
||||
onClick={this.handleClick}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
style={style}
|
||||
tabIndex={tabIndex}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Icon } from './icon';
|
||||
import { Icon } from "./icon";
|
||||
|
||||
const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num);
|
||||
const formatNumber = (num: number): number | string => (num > 40 ? "40+" : num);
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
count: number;
|
||||
issueBadge: boolean;
|
||||
className: string;
|
||||
id: string,
|
||||
count: number,
|
||||
issueBadge: boolean,
|
||||
className: string,
|
||||
}
|
||||
export const IconWithBadge: React.FC<Props> = ({
|
||||
id,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user