agent-Specialization/static/src/app/bootstrap.ts

140 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// @ts-nocheck
import katex from 'katex';
function normalizeShowImageSrc(src: string) {
if (!src) return '';
const trimmed = src.trim();
if (/^https?:\/\//i.test(trimmed)) return trimmed;
if (trimmed.startsWith('/user_upload/')) return trimmed;
// 兼容容器内部路径:/workspace/.../user_upload/xxx.png 或 /workspace/user_upload/xxx
const idx = trimmed.toLowerCase().indexOf('/user_upload/');
if (idx >= 0) {
return '/user_upload/' + trimmed.slice(idx + '/user_upload/'.length);
}
if (trimmed.startsWith('/') || trimmed.startsWith('./') || trimmed.startsWith('../')) {
return trimmed;
}
return '';
}
function isSafeImageSrc(src: string) {
return !!normalizeShowImageSrc(src);
}
function escapeHtml(input: string) {
return input
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function renderShowImages(root: ParentNode | null = document) {
if (!root) return;
// 处理因自闭合解析导致的嵌套:把子 show_image 平铺到父后面
const nested = Array.from(root.querySelectorAll('show_image show_image')).reverse();
nested.forEach(child => {
const parent = child.parentElement;
if (parent && parent !== root) {
parent.after(child);
}
});
const nodes = Array.from(root.querySelectorAll('show_image:not([data-rendered])')).reverse();
nodes.forEach(node => {
// 将 show_image 内误被包裹的内容移动到当前节点之后,保持原有顺序
if (node.parentNode && node.firstChild) {
const parent = node.parentNode;
const ref = node.nextSibling; // 可能为 nullinsertBefore 会当 append
const children = Array.from(node.childNodes);
children.forEach(child => parent.insertBefore(child, ref));
}
const rawSrc = node.getAttribute('src') || '';
const mappedSrc = normalizeShowImageSrc(rawSrc);
if (!mappedSrc) {
node.setAttribute('data-rendered', '1');
node.setAttribute('data-rendered-error', 'invalid-src');
return;
}
const alt = node.getAttribute('alt') || '';
const safeAlt = escapeHtml(alt.trim());
const figure = document.createElement('figure');
figure.className = 'chat-inline-image';
const img = document.createElement('img');
img.loading = 'lazy';
img.src = mappedSrc;
img.alt = safeAlt;
img.onerror = () => {
figure.classList.add('chat-inline-image--error');
const tip = document.createElement('div');
tip.className = 'chat-inline-image__error';
tip.textContent = '图片加载失败';
figure.appendChild(tip);
};
figure.appendChild(img);
if (safeAlt) {
const caption = document.createElement('figcaption');
caption.innerHTML = safeAlt;
figure.appendChild(caption);
}
node.replaceChildren(figure);
node.setAttribute('data-rendered', '1');
});
}
let showImageObserver: MutationObserver | null = null;
export function setupShowImageObserver() {
if (showImageObserver) return;
const container = document.querySelector('.messages-area') || document.body;
if (!container) return;
renderShowImages(container);
showImageObserver = new MutationObserver(() => renderShowImages(container));
showImageObserver.observe(container, { childList: true, subtree: true });
}
export function teardownShowImageObserver() {
if (showImageObserver) {
showImageObserver.disconnect();
showImageObserver = null;
}
}
function updateViewportHeightVar() {
const docEl = document.documentElement;
const visualViewport = window.visualViewport;
if (visualViewport) {
const vh = visualViewport.height;
const bottomInset = Math.max(
0,
(window.innerHeight || docEl.clientHeight || vh) - visualViewport.height - visualViewport.offsetTop
);
docEl.style.setProperty('--app-viewport', `${vh}px`);
docEl.style.setProperty('--app-bottom-inset', `${bottomInset}px`);
} else {
const height = window.innerHeight || docEl.clientHeight;
if (height) {
docEl.style.setProperty('--app-viewport', `${height}px`);
}
docEl.style.setProperty('--app-bottom-inset', 'env(safe-area-inset-bottom, 0px)');
}
}
if (typeof window !== 'undefined') {
window.katex = katex;
updateViewportHeightVar();
window.addEventListener('resize', updateViewportHeightVar);
window.addEventListener('orientationchange', updateViewportHeightVar);
window.addEventListener('pageshow', updateViewportHeightVar);
if (window.visualViewport) {
window.visualViewport.addEventListener('resize', updateViewportHeightVar);
window.visualViewport.addEventListener('scroll', updateViewportHeightVar);
}
}