mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-18 04:43:55 +00:00
refac
This commit is contained in:
parent
92e64c1d59
commit
7c3980338b
2 changed files with 56 additions and 4 deletions
|
|
@ -16,7 +16,9 @@
|
|||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { setContext, onDestroy } from 'svelte';
|
||||
import { getAllContexts, mount, unmount, setContext, onDestroy } from 'svelte';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { downloadFileBlob } from '$lib/apis/terminal';
|
||||
import MarkdownTokens from '../Messages/Markdown/MarkdownTokens.svelte';
|
||||
import type { Token } from 'marked';
|
||||
|
|
@ -98,8 +100,48 @@
|
|||
allowRemoteContent: true,
|
||||
lexer: (source: string) => documentMarkdown.lexer(source),
|
||||
parseInline: (tokens: Token[]) =>
|
||||
documentMarkdown.Parser.parseInline(tokens, documentMarkdown.defaults)
|
||||
documentMarkdown.Parser.parseInline(tokens, documentMarkdown.defaults),
|
||||
renderHtml
|
||||
});
|
||||
const context = getAllContexts();
|
||||
function renderHtml(node: HTMLElement, props: { id: string; tokens: Token[]; top: boolean }) {
|
||||
let components: ReturnType<typeof mount>[] = [];
|
||||
const destroy = () => {
|
||||
components.forEach((component) => unmount(component));
|
||||
components = [];
|
||||
};
|
||||
const update = ({ id, tokens, top }: typeof props) => {
|
||||
destroy();
|
||||
const prefix = `markdown-${uuidv4()}`;
|
||||
// Parse HTML together; keep Markdown components in slots the document cannot forge.
|
||||
node.replaceChildren(
|
||||
DOMPurify.sanitize(
|
||||
tokens
|
||||
.map((token, index) =>
|
||||
token.type === 'html'
|
||||
? token.text
|
||||
: `<div id="${prefix}-${index}" style="display: contents"></div>`
|
||||
)
|
||||
.join(''),
|
||||
{ RETURN_DOM_FRAGMENT: true }
|
||||
)
|
||||
);
|
||||
tokens.forEach((token, index) => {
|
||||
const target = node.querySelector(`#${prefix}-${index}`);
|
||||
if (target) {
|
||||
components.push(
|
||||
mount(MarkdownTokens, {
|
||||
target,
|
||||
context,
|
||||
props: { id: `${id}-${index}`, tokens: [token], top, editCodeBlock: false }
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
update(props);
|
||||
return { update, destroy };
|
||||
}
|
||||
$: tokens = documentMarkdown.lexer(content);
|
||||
const resolveHtmlImages = (node: HTMLElement) => {
|
||||
let alive = true;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
<script lang="ts">
|
||||
import { decode } from 'html-entities';
|
||||
import { onMount, getContext } from 'svelte';
|
||||
import type { Action } from 'svelte/action';
|
||||
const i18n = getContext('i18n');
|
||||
const markdown = getContext<
|
||||
{ document?: boolean; lexer?: (source: string) => Token[] } | undefined
|
||||
| {
|
||||
document?: boolean;
|
||||
lexer?: (source: string) => Token[];
|
||||
renderHtml?: Action<HTMLElement, { id: string; tokens: Token[]; top: boolean }>;
|
||||
}
|
||||
| undefined
|
||||
>('markdown');
|
||||
|
||||
import fileSaver from 'file-saver';
|
||||
|
|
@ -135,6 +141,7 @@
|
|||
} text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition`;
|
||||
|
||||
$: displayTokens = getDisplayTokens(tokens);
|
||||
$: renderHtml = tokens.some((token) => token.type === 'html') ? markdown?.renderHtml : undefined;
|
||||
$: singlePlainBlock =
|
||||
displayTokens.length === 1 &&
|
||||
(displayTokens[0]?.type === 'paragraph' || displayTokens[0]?.type === 'text');
|
||||
|
|
@ -173,7 +180,10 @@
|
|||
</script>
|
||||
|
||||
<!-- {JSON.stringify(tokens)} -->
|
||||
{#each displayTokens as token, tokenIdx (tokenIdx)}
|
||||
{#if renderHtml}
|
||||
<div class="contents" use:renderHtml={{ id, tokens, top }}></div>
|
||||
{/if}
|
||||
{#each renderHtml ? [] : displayTokens as token, tokenIdx (tokenIdx)}
|
||||
{#if token.type === 'hr'}
|
||||
<hr class="border-gray-50 dark:border-gray-850/30" />
|
||||
{:else if token.type === 'heading'}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue