/
githubmirror
/
marktext
Обзор
Документация
Войти
/
githubmirror
/
marktext
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
packages/muya/src/block/commonMark/html/htmlPreview.ts
86 строк
3 KB
Ran Luo
fix(muya): render <video>/<audio> html blocks instead of the empty placeholder (#4604)
21 июн 2026, 10:20
Не верифицирован
21 июн 2026, 10:20
6bb7271
Код
Авторство
О чём код?
import type { Muya } from '../../../muya'; import type { IHtmlBlockState, TState } from '../../../state/types'; import { CLASS_NAMES, PREVIEW_DOMPURIFY_CONFIG } from '../../../config'; import { sanitize } from '../../../utils'; import { getImageSrc } from '../../../utils/image'; import logger from '../../../utils/logger'; import Parent from '../../base/parent'; const debug = logger('htmlPreview:'); // Elements whose rendered content comes from attributes (e.g. `src`) rather // than child nodes, so an empty tag body must not be treated as an empty block. const SELF_CONTAINED_MEDIA = new Set(['video', 'audio']); // A single element with an empty body (`<div></div>`), except self-contained // media elements whose content lives in attributes (`<video src=...></video>`). export function isEmptyHtmlBlock(html: string): boolean { // eslint-disable-next-line regexp/no-super-linear-backtracking, regexp/optimal-quantifier-concatenation const match = html.trim().match(/^<([a-z][a-z\d]*)[^>]*>\s*<\/\1>$/); return !!match && !SELF_CONTAINED_MEDIA.has(match[1]); } class HTMLPreview extends Parent { private _html: string; static override blockName = 'html-preview'; static create(muya: Muya, state: IHtmlBlockState) { const htmlBlock = new HTMLPreview(muya, state); return htmlBlock; } override get path() { debug.warn('You can never call `get path` in htmlPreview'); return []; } constructor(muya: Muya, { text }: IHtmlBlockState) { super(muya); this.tagName = 'div'; this._html = text; this.classList = [CLASS_NAMES.MU_HTML_PREVIEW]; this.attributes = { spellcheck: 'false', contenteditable: 'false', }; this.createDomNode(); this.update(); } update(html = this._html) { if (this._html !== html) this._html = html; const { disableHtml } = this.muya.options; const htmlContent = sanitize(html, PREVIEW_DOMPURIFY_CONFIG, disableHtml) as string; // handle empty html bock if (isEmptyHtmlBlock(htmlContent)) { this.domNode!.innerHTML = `<div class="${CLASS_NAMES.MU_EMPTY}"><Empty HTML Block></div>`; } else { const parser = new DOMParser(); const doc = parser.parseFromString(htmlContent, 'text/html'); const imgs = doc.documentElement.querySelectorAll('img'); for (const img of imgs) { const src = img.getAttribute('src')!; const imageSrc = getImageSrc(src); img.setAttribute('src', imageSrc.src); } this.domNode!.innerHTML = doc.documentElement!.querySelector('body')!.innerHTML; } } override getState(): TState { debug.warn('You can never call `getState` in htmlPreview'); return {} as TState; } } export default HTMLPreview;