/** * AIM "Yellow Smiley" set (AIM 4.x/5.x). Typed codes become the original * 19ร—19 GIFs from /static/smileys (local-only, AOL artwork). When a GIF is * missing the browser shows the img alt text, which is the Unicode emoji. */ export interface Smiley { file: string; codes: string[]; label: string; emoji: string; } export const SMILEYS: Smiley[] = [ { file: '01', codes: [':-)', ':)'], label: 'Content', emoji: '๐Ÿ™‚' }, { file: '02', codes: [';-)', ';)'], label: 'Clin dโ€™ล“il', emoji: '๐Ÿ˜‰' }, { file: '03', codes: [':-(', ':('], label: 'Triste', emoji: '๐Ÿ™' }, { file: '04', codes: [':-P', ':-p', ':P', ':p'], label: 'Langue', emoji: '๐Ÿ˜›' }, { file: '05', codes: ['=-O', '=-o'], label: 'Surpris', emoji: '๐Ÿ˜ฎ' }, { file: '06', codes: [':-*'], label: 'Bisou', emoji: '๐Ÿ˜˜' }, { file: '07', codes: ['>:o'], label: 'Crie', emoji: '๐Ÿ˜ ' }, { file: '08', codes: [':-D', ':D'], label: 'Rire', emoji: '๐Ÿ˜' }, { file: '09', codes: [':-$'], label: 'Radin', emoji: '๐Ÿค‘' }, { file: '10', codes: [':-!'], label: 'Gaffe', emoji: '๐Ÿ˜ฌ' }, { file: '11', codes: [':-['], label: 'Gรชnรฉ', emoji: '๐Ÿ˜ณ' }, { file: '12', codes: ['O:-)'], label: 'Innocent', emoji: '๐Ÿ˜‡' }, { file: '13', codes: [':-\\'], label: 'Indรฉcis', emoji: '๐Ÿ˜•' }, { file: '14', codes: [":'("], label: 'Pleure', emoji: '๐Ÿ˜ข' }, { file: '15', codes: [':-X', ':-x'], label: 'Bouche cousue', emoji: '๐Ÿค' }, { file: '16', codes: ['8-)'], label: 'Cool', emoji: '๐Ÿ˜Ž' } ]; const escape = (text: string) => text .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); // Codes are matched on already-escaped HTML, so match their escaped form. const byEscapedCode = new Map(); for (const smiley of SMILEYS) for (const code of smiley.codes) byEscapedCode.set(escape(code), smiley); const pattern = new RegExp( // Longest first so "O:-)" wins over ":-)"; codes must not touch letters/digits. `(^|[^\\w])(${[...byEscapedCode.keys()] .sort((a, b) => b.length - a.length) .map((c) => c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) .join('|')})(?=$|[^\\w])`, 'g' ); export function smileyImg(smiley: Smiley) { return `${smiley.emoji}`; } /** * Replace smiley codes in escaped HTML text. Only text between tags is * touched so attributes (style="color: โ€ฆ") are never rewritten. */ export function replaceSmileys(html: string): string { return html .split(/(<[^>]*>)/) .map((part) => part.startsWith('<') ? part : part.replace(pattern, (_, before: string, code: string) => { const smiley = byEscapedCode.get(code); return smiley ? before + smileyImg(smiley) : _; }) ) .join(''); }