diff --git a/src/embed.ts b/src/embed.ts new file mode 100644 index 0000000..dcdd325 --- /dev/null +++ b/src/embed.ts @@ -0,0 +1,33 @@ + +import type { marked } from 'marked'; +import { MarkdownOptions } from './render'; + +export interface EmbedToken extends marked.Tokens.Generic { + media_type: string; + href: string; +} + +export function embed_ext(renderer: marked.Renderer, opts: MarkdownOptions) : marked.TokenizerExtension & marked.RendererExtension { + return { + name: 'embed', + level: 'inline', + start: (src) => src.match(/\{&/)?.index, + tokenizer(src, tokens) { + const rule = /^\{&\s+([^\s]+):\s*([^\s]+)\s+&\}/; + const match = rule.exec(src); + + if (match) { + return { + type: 'embed', + raw: match[0], + media_type: match[1], + href: match[2], + tokens: [ ] + }; + } + }, + renderer(token: EmbedToken) { + return ``; + } + }; +} diff --git a/src/html-sanitize.ts b/src/html-sanitize.ts index 0e0b060..1a2539a 100644 --- a/src/html-sanitize.ts +++ b/src/html-sanitize.ts @@ -9,5 +9,6 @@ export function sanitize_html(html: string, custom_elements?: CustomElementHandl const dom_purify = createDOMPurify(window as any as Window); return dom_purify.sanitize(html, { CUSTOM_ELEMENT_HANDLING: custom_elements, + ADD_TAGS: [ 'embed', 'object', 'video', 'audio', 'iframe' ], }); } diff --git a/src/render.ts b/src/render.ts index 47d43d9..6d47632 100644 --- a/src/render.ts +++ b/src/render.ts @@ -10,6 +10,7 @@ import { footnote_list_ext, footnote_ref_ext } from './footnotes'; import { description_list_ext } from './description-list'; import { resolve_async_bindings } from './async-steps'; import { base_url_walk_tokens } from './base-url'; +import { embed_ext } from './embed'; export interface MarkdownOptions { base_url?: string; @@ -64,6 +65,7 @@ function setup_marked(options: MarkdownOptions, marked_options: marked.MarkedOpt description_list_ext(marked_options.renderer, options), section_ext(marked_options.renderer, options), icon_ext(marked_options.renderer, options), + embed_ext(marked_options.renderer, options), ...(options.extensions || [ ]).map((ext) => { return ext(marked_options.renderer, options); }),