import { RenderingOptions } from '../../'; import { code } from './render/code'; import { math } from './render/math'; import { media } from './render/media'; import { reduce } from 'spica/memoize'; import { querySelectorAllWith } from 'typed-dom/query'; const selector = ':not(.invalid):is(.media:is(img:not([src])[data-src], a > :not(img).media), pre.code, .math)'; const extend = reduce((opts: RenderingOptions): RenderingOptions => ({ code, math, media: {}, ...opts })); export function render(source: HTMLElement, opts: RenderingOptions = {}): void { opts = extend(opts); const base = location.href; for (let es = querySelectorAllWith(source, selector), i = 0; i < es.length; ++i) { render_(base, es[i], opts); } } function render_(base: string, source: HTMLElement, opts: RenderingOptions): void { try { switch (true) { case !!opts.code && !source.firstElementChild && source.matches('pre.code'): return void opts.code!(source, opts.caches?.code); case !!opts.math && !source.firstElementChild && source.matches('.math'): return void opts.math!(source, opts.caches?.math); case source.matches('.media:not(img)'): assert(source.matches('a > .media')); return void source.parentElement!.parentElement!.replaceChild(source, source.parentElement!); case !!opts.media && source.matches('img.media:not([src])[data-src]'): { assert(source.matches('a > .media')); const el = media(base, source as HTMLImageElement, opts.media!, opts.caches?.media); if (!el) return; assert(el.matches('.media')); el.setAttribute('data-src', source.getAttribute('data-src')!); const scope = el.matches('img') ? source : source.parentElement as HTMLAnchorElement; return void scope.parentElement!.replaceChild(el, scope); } default: return; } } catch (reason) { console.error(reason); } }