diff --git a/apps/web/src/views/detail.ejs b/apps/web/src/views/detail.ejs index 045ca66..6742287 100644 --- a/apps/web/src/views/detail.ejs +++ b/apps/web/src/views/detail.ejs @@ -194,16 +194,32 @@ ); } - function highlightXml(str) { - return escapeHtml(str) - .replace(/<(\/?)([\w:-]+)/g, '<$1$2') - .replace(/([\w:-]+)(=)("[^&]*")/g, '$1$2$3'); + function highlightHtml(str) { + const esc = escapeHtml(str); + return esc + // Comments: + .replace(/<!--[\s\S]*?-->/g, '$&') + // DOCTYPE + .replace(/<!(DOCTYPE[^&]*?)>/gi, '<!$1>') + // Tags: <$1$2') + // Closing > and /> + .replace(/(\/?)\s*>/g, '$1>') + // Attributes: name="value" or name='value' + .replace(/([\w:-]+)(=)("[^&]*?"|'[^&]*?')/g, + '$1$2$3') + // Boolean/valueless attributes (standalone word between tag name and >) + .replace(/(<\/span>)\s+([\w:-]+)(?=\s|)/g, + '$1 $2') + // Inline CSS: style content between quotes (already green, make more specific) + // Entity references: & < etc + .replace(/&[\w#]+;/g, '$&'); } function highlightBody(body, contentType) { const ct = (contentType || '').toLowerCase(); if (ct.includes('json')) return highlightJson(body); - if (ct.includes('xml') || ct.includes('html')) return highlightXml(body); + if (ct.includes('xml') || ct.includes('html')) return highlightHtml(body); return escapeHtml(body); }