diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 6b562e5bf..e829eaa1f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -54,12 +54,12 @@ module.exports = { }, }, polyfills: [ - 'es:all', - 'fetch', - 'IntersectionObserver', - 'Promise', - 'URL', - 'URLSearchParams', + 'es:all', // core-js + 'IntersectionObserver', // npm:intersection-observer + 'Promise', // core-js + 'ResizeObserver', // npm:resize-observer-polyfill + 'URL', // core-js + 'URLSearchParams', // core-js ], }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e0e765d6..cd6a7a28b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Admin: redirect the homepage to any URL. - Compatibility: added compatibility with Friendica. - Posts: bot badge on statuses from bot accounts. +- Compatibility: improved browser support for older browsers. ### Changed - Chats: improved display of media attachments. diff --git a/app/soapbox/components/autosuggest-textarea.tsx b/app/soapbox/components/autosuggest-textarea.tsx index 1cdc7fa06..9736e5950 100644 --- a/app/soapbox/components/autosuggest-textarea.tsx +++ b/app/soapbox/components/autosuggest-textarea.tsx @@ -157,7 +157,8 @@ class AutosuggestTextarea extends ImmutablePureComponent if (lastTokenUpdated && !valueUpdated) { return false; } else { - return super.shouldComponentUpdate!(nextProps, nextState, undefined); + // https://stackoverflow.com/a/35962835 + return super.shouldComponentUpdate!.bind(this)(nextProps, nextState, undefined); } } diff --git a/app/soapbox/components/modal-root.tsx b/app/soapbox/components/modal-root.tsx index 6681072cd..8abc27eac 100644 --- a/app/soapbox/components/modal-root.tsx +++ b/app/soapbox/components/modal-root.tsx @@ -248,10 +248,9 @@ const ModalRoot: React.FC = ({ children, onCancel, onClose, type })
{children}
diff --git a/app/soapbox/features/ads/components/ad.tsx b/app/soapbox/features/ads/components/ad.tsx index c42eb3db5..75e649784 100644 --- a/app/soapbox/features/ads/components/ad.tsx +++ b/app/soapbox/features/ads/components/ad.tsx @@ -1,4 +1,5 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; +import axios from 'axios'; import React, { useState, useEffect, useRef } from 'react'; import { FormattedMessage } from 'react-intl'; @@ -24,9 +25,9 @@ const Ad: React.FC = ({ ad }) => { // Fetch the impression URL (if any) upon displaying the ad. // Don't fetch it more than once. - useQuery(['ads', 'impression', ad.impression], () => { + useQuery(['ads', 'impression', ad.impression], async () => { if (ad.impression) { - return fetch(ad.impression); + return await axios.get(ad.impression); } }, { cacheTime: Infinity, staleTime: Infinity }); diff --git a/app/soapbox/features/ads/providers/rumble.ts b/app/soapbox/features/ads/providers/rumble.ts index bc86e8686..68a006e00 100644 --- a/app/soapbox/features/ads/providers/rumble.ts +++ b/app/soapbox/features/ads/providers/rumble.ts @@ -1,3 +1,5 @@ +import axios from 'axios'; + import { getSettings } from 'soapbox/actions/settings'; import { getSoapboxConfig } from 'soapbox/actions/soapbox'; import { normalizeAd, normalizeCard } from 'soapbox/normalizers'; @@ -28,14 +30,13 @@ const RumbleAdProvider: AdProvider = { const endpoint = soapboxConfig.extensions.getIn(['ads', 'endpoint']) as string | undefined; if (endpoint) { - const response = await fetch(endpoint, { - headers: { - 'Accept-Language': settings.get('locale', '*') as string, - }, - }); - - if (response.ok) { - const data = await response.json() as RumbleApiResponse; + try { + const { data } = await axios.get(endpoint, { + headers: { + 'Accept-Language': settings.get('locale', '*') as string, + }, + }); + return data.ads.map(item => normalizeAd({ impression: item.impression, card: normalizeCard({ @@ -45,6 +46,8 @@ const RumbleAdProvider: AdProvider = { }), expires_at: new Date(item.expires * 1000), })); + } catch (e) { + // do nothing } } diff --git a/app/soapbox/features/ads/providers/truth.ts b/app/soapbox/features/ads/providers/truth.ts index 92f2e99f8..a9af3c0d7 100644 --- a/app/soapbox/features/ads/providers/truth.ts +++ b/app/soapbox/features/ads/providers/truth.ts @@ -1,3 +1,5 @@ +import axios from 'axios'; + import { getSettings } from 'soapbox/actions/settings'; import { normalizeCard } from 'soapbox/normalizers'; @@ -18,18 +20,19 @@ const TruthAdProvider: AdProvider = { const state = getState(); const settings = getSettings(state); - const response = await fetch('/api/v2/truth/ads?device=desktop', { - headers: { - 'Accept-Language': settings.get('locale', '*') as string, - }, - }); + try { + const { data } = await axios.get('/api/v2/truth/ads?device=desktop', { + headers: { + 'Accept-Language': settings.get('locale', '*') as string, + }, + }); - if (response.ok) { - const data = await response.json() as TruthAd[]; return data.map(item => ({ ...item, card: normalizeCard(item.card), })); + } catch (e) { + // do nothing } return []; diff --git a/app/soapbox/features/ui/__tests__/index.test.tsx b/app/soapbox/features/ui/__tests__/index.test.tsx index f3e32f5f7..0a55f3ca5 100644 --- a/app/soapbox/features/ui/__tests__/index.test.tsx +++ b/app/soapbox/features/ui/__tests__/index.test.tsx @@ -50,7 +50,7 @@ describe('', () => { await waitFor(() => { expect(screen.getByTestId('cta-banner')).toHaveTextContent('Sign up now to discuss'); }, { - timeout: 2000, + timeout: 5000, }); }); }); diff --git a/app/soapbox/hooks/useDimensions.ts b/app/soapbox/hooks/useDimensions.ts index b08c05f4e..ae0321e2b 100644 --- a/app/soapbox/hooks/useDimensions.ts +++ b/app/soapbox/hooks/useDimensions.ts @@ -1,5 +1,4 @@ import { useEffect, useMemo, useState } from 'react'; -import ResizeObserver from 'resize-observer-polyfill'; type UseDimensionsRect = { width: number, height: number }; type UseDimensionsResult = [Element | null, any, any] diff --git a/app/soapbox/main.tsx b/app/soapbox/main.tsx index 9fc753990..f5cf9f0f5 100644 --- a/app/soapbox/main.tsx +++ b/app/soapbox/main.tsx @@ -1,3 +1,5 @@ +import './polyfills'; + import * as OfflinePluginRuntime from '@lcdp/offline-plugin/runtime'; import React from 'react'; import { createRoot } from 'react-dom/client'; diff --git a/app/soapbox/polyfills.ts b/app/soapbox/polyfills.ts new file mode 100644 index 000000000..21947e4fe --- /dev/null +++ b/app/soapbox/polyfills.ts @@ -0,0 +1,8 @@ +import 'intersection-observer'; +import ResizeObserver from 'resize-observer-polyfill'; + +// Needed by Virtuoso +// https://github.com/petyosi/react-virtuoso#browser-support +if (!window.ResizeObserver) { + window.ResizeObserver = ResizeObserver; +} \ No newline at end of file diff --git a/app/soapbox/service-worker/web-push-notifications.ts b/app/soapbox/service-worker/web-push-notifications.ts index 872d255c6..8088ca902 100644 --- a/app/soapbox/service-worker/web-push-notifications.ts +++ b/app/soapbox/service-worker/web-push-notifications.ts @@ -1,3 +1,4 @@ +/* eslint-disable compat/compat */ import IntlMessageFormat from 'intl-messageformat'; import 'intl-pluralrules'; import unescape from 'lodash/unescape'; diff --git a/app/styles/components/modal.scss b/app/styles/components/modal.scss index 34e375acc..ed9a9912c 100644 --- a/app/styles/components/modal.scss +++ b/app/styles/components/modal.scss @@ -7,8 +7,8 @@ } .media-modal { - width: 100%; - height: 100%; + // https://stackoverflow.com/a/8468131 + @apply w-full h-full absolute inset-0; .audio-player.detailed, .extended-video-player { diff --git a/babel.config.cjs b/babel.config.cjs index 2d684880b..93b9db3e4 100644 --- a/babel.config.cjs +++ b/babel.config.cjs @@ -5,7 +5,7 @@ module.exports = (api) => { debug: false, modules: false, useBuiltIns: 'usage', - corejs: '3.15', + corejs: '3.27', }; const config = { diff --git a/package.json b/package.json index 06f47abdc..e48b340ea 100644 --- a/package.json +++ b/package.json @@ -31,9 +31,9 @@ }, "license": "AGPL-3.0-or-later", "browserslist": [ - "> 0.5%", + "> 0.2%", "last 2 versions", - "not IE 11", + "last 4 years", "not dead" ], "dependencies": { @@ -111,7 +111,7 @@ "cheerio": "^1.0.0-rc.10", "clsx": "^1.2.1", "copy-webpack-plugin": "^11.0.0", - "core-js": "^3.15.2", + "core-js": "^3.27.2", "cryptocurrency-icons": "^0.18.1", "css-loader": "^6.7.1", "cssnano": "^5.1.10", @@ -127,6 +127,7 @@ "http-link-header": "^1.0.2", "immutable": "^4.2.1", "imports-loader": "^4.0.0", + "intersection-observer": "^0.12.2", "intl-messageformat": "9.13.0", "intl-messageformat-parser": "^6.0.0", "intl-pluralrules": "^1.3.1", diff --git a/webpack/production.ts b/webpack/production.ts index 78845be37..810a943ef 100644 --- a/webpack/production.ts +++ b/webpack/production.ts @@ -50,7 +50,6 @@ const configuration: Configuration = { ], optional: [ '**/locale_*.js', // don't fetch every locale; the user only needs one - '**/*_polyfills-*.js', // the user may not need polyfills '**/*.chunk.js', // only cache chunks when needed '**/*.chunk.css', '**/*.woff2', // the user may have system-fonts enabled @@ -138,6 +137,7 @@ const configuration: Configuration = { '/apple-touch-icon.png', '/browserconfig.xml', '/robots.txt', + '/report.html', ]; if (backendRoutes.some(path => pathname.startsWith(path)) || pathname.endsWith('/embed')) { diff --git a/yarn.lock b/yarn.lock index a1fb69a9b..916d4ccda 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4498,16 +4498,16 @@ core-js-pure@^3.23.3: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.27.1.tgz#ede4a6b8440585c7190062757069c01d37a19dca" integrity sha512-BS2NHgwwUppfeoqOXqi08mUqS5FiZpuRuJJpKsaME7kJz0xxuk0xkhDdfMIlP/zLa80krBqss1LtD7f889heAw== -core-js@^3.15.2: - version "3.18.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.0.tgz#9af3f4a6df9ba3428a3fb1b171f1503b3f40cc49" - integrity sha512-WJeQqq6jOYgVgg4NrXKL0KLQhi0CT4ZOCvFL+3CQ5o7I6J8HkT5wd53EadMfqTDp1so/MT1J+w2ujhWcCJtN7w== - core-js@^3.16.2: version "3.23.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.23.5.tgz#1f82b0de5eece800827a2f59d597509c67650475" integrity sha512-7Vh11tujtAZy82da4duVreQysIoO2EvVrur7y6IzZkH1IHPSekuDi8Vuw1+YKjkbfWLRD7Nc9ICQ/sIUDutcyg== +core-js@^3.27.2: + version "3.27.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.27.2.tgz#85b35453a424abdcacb97474797815f4d62ebbf7" + integrity sha512-9ashVQskuh5AZEZ1JdQWp1GqSoC1e1G87MzRqg2gIfVAQ7Qn9K+uFj8EcniUFA4P2NLZfV+TOlX1SzoKfo+s7w== + core-js@^3.8.2: version "3.23.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.23.1.tgz#9f9a9255115f62c512db56d567f636da32ca0b78" @@ -6653,6 +6653,11 @@ intersection-observer@^0.12.0: resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.0.tgz#6c84628f67ce8698e5f9ccf857d97718745837aa" integrity sha512-2Vkz8z46Dv401zTWudDGwO7KiGHNDkMv417T5ItcNYfmvHR/1qCTVBO9vwH8zZmQ0WkA/1ARwpysR9bsnop4NQ== +intersection-observer@^0.12.2: + version "0.12.2" + resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.2.tgz#4a45349cc0cd91916682b1f44c28d7ec737dc375" + integrity sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg== + intl-messageformat-parser@6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-6.1.2.tgz#28c65f3689f538e66c7cf628881548d6a82ff3c2"