/** * @fileoverview Rant Content Component for Rantii * @author retoor * @description Renders rant text with markdown, images, and media * @keywords rant, content, markdown, media, render */ import { BaseComponent } from './base-component.js'; import { categorizeLinks, processTextWithLinks, extractImageUrls, extractYoutubeUrls, extractNonMediaUrls, sanitizeUrl } from '../utils/url.js'; class RantContent extends BaseComponent { static get observedAttributes() { return ['text', 'links']; } init() { this.linksData = null; this.render(); } setLinks(links) { this.linksData = links; this.render(); } render() { const text = this.getAttr('text') || ''; const linksAttr = this.getAttr('links'); const links = this.linksData || (linksAttr ? JSON.parse(linksAttr) : null); this.addClass('rant-content'); let images = []; let youtubeLinks = []; let otherLinks = []; let renderedText = ''; if (links && links.length > 0) { const categorized = categorizeLinks(links); images = categorized.images.map(l => l.url); youtubeLinks = categorized.youtube.map(l => l.url); otherLinks = categorized.other; renderedText = processTextWithLinks(text, links); renderedText = renderedText.replace(/\n/g, '
'); } else { images = extractImageUrls(text); youtubeLinks = extractYoutubeUrls(text); const extractedOther = extractNonMediaUrls(text); otherLinks = extractedOther.map(url => ({ url, title: url })); renderedText = this.escapeHtml(text).replace(/\n/g, '
'); } let html = `
${renderedText}
`; if (images.length > 0) { html += `
${images.map(url => { const safeUrl = sanitizeUrl(url); return safeUrl ? `` : ''; }).join('')}
`; } if (youtubeLinks.length > 0) { html += `
${youtubeLinks.map(url => { const safeUrl = sanitizeUrl(url); return safeUrl ? `` : ''; }).join('')}
`; } if (otherLinks.length > 0) { html += ` `; } this.setHtml(html); } escapeHtml(str) { if (!str) return ''; return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } escapeAttr(str) { if (!str) return ''; return str .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(//g, '>'); } onAttributeChanged(name, oldValue, newValue) { this.render(); } setText(text, links = null) { this.linksData = links; this.setAttr('text', text); } } customElements.define('rant-content', RantContent); export { RantContent };