import { isIntegerId } from 'soapbox/utils/numbers'; import type { IntlShape } from 'react-intl'; import type { Status } from 'soapbox/schemas'; /** Get the initial visibility of media attachments from user settings. */ export const defaultMediaVisibility = >( status: T | undefined | null, displayMedia: string, ): boolean => { if (!status) return false; status = getActualStatus(status); const isUnderReview = status.visibility === 'self'; if (isUnderReview) { return false; } return (displayMedia !== 'hide_all' && !status.sensitive || displayMedia === 'show_all'); }; /** Grab the first external link from a status. */ export const getFirstExternalLink = (status: Pick): HTMLAnchorElement | null => { try { // Pulled from Pleroma's media parser const selector = 'a:not(.mention,.hashtag,.attachment,[rel~="tag"])'; const element = document.createElement('div'); element.innerHTML = status.content; return element.querySelector(selector); } catch { return null; } }; /** Whether the status is expected to have a Card after it loads. */ export const shouldHaveCard = (status: Pick): boolean => { return Boolean(getFirstExternalLink(status)); }; /** Whether the media IDs on this status have integer IDs (opposed to FlakeIds). */ // https://gitlab.com/soapbox-pub/soapbox/-/merge_requests/1087 export const hasIntegerMediaIds = (status: Pick): boolean => { return status.media_attachments.some(({ id }) => isIntegerId(id)); }; /** Sanitize status text for use with screen readers. */ export const textForScreenReader = ( intl: IntlShape, status: Pick, rebloggedByText?: string, ): string => { const { account } = status; if (!account || typeof account !== 'object') return ''; const displayName = account.display_name; const values = [ displayName.length === 0 ? account.acct.split('@')[0] : displayName, status.spoiler_text && status.hidden ? status.spoiler_text : status.search_index.slice(status.spoiler_text.length), intl.formatDate(status.created_at, { hour: '2-digit', minute: '2-digit', month: 'short', day: 'numeric' }), account.acct, ]; if (rebloggedByText) { values.push(rebloggedByText); } return values.join(', '); }; /** Get reblogged status if any, otherwise return the original status. */ export const getActualStatus = (status: T): T => { if (status?.reblog && typeof status?.reblog === 'object') { return status.reblog; } else { return status; } };