Render chat and previews through the shared HTML cleaner
Why: The conversation and office fallbacks wrote marked output straight into the page, including converted docx HTML. Evidence: html-sinks ratchet forbids new innerHTML writes outside @ui safeHtml. Impact: Conversation keeps line-break rendering. Unsafe links are stripped after docx and pptx preview. dompurify is deduped with the UI package. Refs: feature/sillytavern-review Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+9
-4
@@ -1,8 +1,7 @@
|
||||
// 预览能力装配(裁定 D1–D4):把重解析器经 configureFilePreviewLoaders 注入 @ui。
|
||||
// 全部 dynamic import——对应格式首次预览时才下载 chunk,主 bundle 不含解析器。
|
||||
// 链接预览 fetcher 走服务端 /api/url-preview(SSRF 防护在服务端执行端)。
|
||||
import { configureFilePreviewLoaders, configureLinkPreviewFetcher } from '@ui'
|
||||
import { marked } from 'marked'
|
||||
import { configureFilePreviewLoaders, configureLinkPreviewFetcher, renderMarkdown, setSafeHTML, stripUnsafeLinks } from '@ui'
|
||||
import { auth } from './auth'
|
||||
import type { LinkPreviewData } from '@ui'
|
||||
|
||||
@@ -28,7 +27,7 @@ const renderTextFallback = (el: HTMLElement, buf: ArrayBuffer, name: string | un
|
||||
note.textContent = `「${name ?? '该文件'}」不是有效的 ${kindLabel} 文件(缺少 ZIP 结构),已按文本内容展示;需要正式格式请让智能体重新生成。`
|
||||
const body = document.createElement('div')
|
||||
body.className = 'doc-viewer'
|
||||
body.innerHTML = marked.parse(new TextDecoder().decode(buf)) as string
|
||||
setSafeHTML(body, renderMarkdown(new TextDecoder().decode(buf), { breaks: true }))
|
||||
el.innerHTML = ''
|
||||
el.append(note, body)
|
||||
}
|
||||
@@ -43,13 +42,18 @@ const docxLoader = async (el: HTMLElement, source: { contentUrl?: string; name?:
|
||||
const { renderAsync } = await import('docx-preview')
|
||||
el.innerHTML = ''
|
||||
await renderAsync(buf, el, el, { className: 'docx', inWrapper: true, breakPages: true })
|
||||
stripUnsafeLinks(el)
|
||||
return
|
||||
} catch (err) {
|
||||
console.error('[preview:docx] page render failed, falling back', source.name, err)
|
||||
}
|
||||
const mammoth = await import('mammoth')
|
||||
const { value } = await mammoth.convertToHtml({ arrayBuffer: buf })
|
||||
el.innerHTML = `<div class="doc-viewer">${value}</div>`
|
||||
el.innerHTML = ''
|
||||
const body = document.createElement('div')
|
||||
body.className = 'doc-viewer'
|
||||
setSafeHTML(body, value)
|
||||
el.append(body)
|
||||
}
|
||||
|
||||
const xlsxLoader = async (el: HTMLElement, source: { contentUrl?: string; name?: string }) => {
|
||||
@@ -120,6 +124,7 @@ const pptxLoader = async (el: HTMLElement, source: { contentUrl?: string; name?:
|
||||
el.append(stage)
|
||||
const previewer = init(stage, { width: stage.clientWidth || 900 })
|
||||
await previewer.preview(buf)
|
||||
stripUnsafeLinks(el)
|
||||
}
|
||||
|
||||
export function wirePreviewCapabilities() {
|
||||
|
||||
Reference in New Issue
Block a user