mirror of
https://git.shipoclu.com/moon/plspace.git
synced 2026-08-13 02:42:30 +00:00
refactor and fix all references to emojis
This commit is contained in:
@@ -261,6 +261,9 @@ export interface Notification {
|
||||
created_at: string
|
||||
account: Account
|
||||
status?: Status | null
|
||||
/** Pleroma/Akkoma emoji-reaction notification payload. */
|
||||
emoji?: string | null
|
||||
emoji_url?: string | null
|
||||
}
|
||||
|
||||
export interface Context {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Notification } from './api/types'
|
||||
import type { CustomEmoji, Notification } from './api/types'
|
||||
import { toPlainText } from './util/html'
|
||||
import { displayNameOf, profilePath } from './util/profile'
|
||||
|
||||
@@ -53,6 +53,30 @@ export interface NotificationPresentation {
|
||||
href: string
|
||||
}
|
||||
|
||||
export interface NotificationEmoji {
|
||||
text: string
|
||||
emojis: CustomEmoji[]
|
||||
}
|
||||
|
||||
/** Turn Pleroma's separate reaction name/URL fields into EmojiText input. */
|
||||
export function emojiForNotification(notification: Notification): NotificationEmoji | null {
|
||||
const text = notification.emoji?.trim()
|
||||
if (!text) return null
|
||||
const shortcode = text.match(/^:([^:]+):$/)?.[1]
|
||||
if (!shortcode || !notification.emoji_url) return { text, emojis: [] }
|
||||
return {
|
||||
text,
|
||||
emojis: [
|
||||
{
|
||||
shortcode,
|
||||
url: notification.emoji_url,
|
||||
static_url: notification.emoji_url,
|
||||
visible_in_picker: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
const MESSAGE: Record<string, string> = {
|
||||
mention: 'mentioned you in an entry',
|
||||
status: 'posted a new entry',
|
||||
|
||||
+19
-3
@@ -119,6 +119,15 @@ export function escapeHtml(value: string): string {
|
||||
* Runs on the *sanitized* string and only injects `<img>` with a URL taken from
|
||||
* the emoji list, so it cannot reintroduce markup from the original content.
|
||||
*/
|
||||
export function safeCustomEmojiUrl(value: string): string | null {
|
||||
try {
|
||||
const url = new URL(value, window.location.href)
|
||||
return url.protocol === 'http:' || url.protocol === 'https:' ? url.href : null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function applyEmojis(html: string, emojis: CustomEmoji[] | undefined): string {
|
||||
if (!emojis?.length) return html
|
||||
const table = new Map(emojis.map((emoji) => [emoji.shortcode, emoji]))
|
||||
@@ -128,7 +137,9 @@ function applyEmojis(html: string, emojis: CustomEmoji[] | undefined): string {
|
||||
const replaced = text.replace(/:([a-zA-Z0-9_+-]+):/g, (whole, shortcode: string) => {
|
||||
const emoji = table.get(shortcode)
|
||||
if (!emoji) return whole
|
||||
return `<img class="custom-emoji" src="${escapeHtml(emoji.url)}" alt=":${escapeHtml(
|
||||
const url = safeCustomEmojiUrl(emoji.url)
|
||||
if (!url) return whole
|
||||
return `<img class="custom-emoji" src="${escapeHtml(url)}" alt=":${escapeHtml(
|
||||
shortcode,
|
||||
)}:" title=":${escapeHtml(shortcode)}:" draggable="false" />`
|
||||
})
|
||||
@@ -213,7 +224,12 @@ export function toPlainText(source: string | null | undefined): string {
|
||||
return (container.textContent ?? '').replace(/\s+/g, ' ').trim()
|
||||
}
|
||||
|
||||
/** Emoji-substituted display name, safe for `{@html}`. */
|
||||
/** Emoji-substituted plain text, escaped and safe for `{@html}`. */
|
||||
export function renderEmojiText(text: string, emojis: CustomEmoji[] | undefined): string {
|
||||
return applyEmojis(escapeHtml(text), emojis)
|
||||
}
|
||||
|
||||
/** Backward-compatible semantic name for existing display-name callers. */
|
||||
export function renderDisplayName(name: string, emojis: CustomEmoji[] | undefined): string {
|
||||
return applyEmojis(escapeHtml(name), emojis)
|
||||
return renderEmojiText(name, emojis)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user