Ability to generate non-HTML sublanguages, e.g. SVG

This commit is contained in:
Tony Garnock-Jones 2022-01-20 20:48:53 +01:00
parent 83cc561cce
commit 6f07bfafae
1 changed files with 34 additions and 21 deletions

View File

@ -30,9 +30,11 @@ export function isFlattenInto(x: any): x is FlattenInto {
} }
export class HtmlFragments implements FlattenInto { export class HtmlFragments implements FlattenInto {
readonly contextElementName: string | undefined;
readonly pieces: Array<HtmlFragment>; readonly pieces: Array<HtmlFragment>;
constructor(pieces: Array<HtmlFragment> = []) { constructor(pieces: Array<HtmlFragment> = [], contextElementName?: string) {
this.contextElementName = contextElementName;
this.pieces = pieces; this.pieces = pieces;
} }
@ -54,7 +56,12 @@ export class HtmlFragments implements FlattenInto {
nodes(): Array<ChildNode> { nodes(): Array<ChildNode> {
let n = document.createElement('template'); let n = document.createElement('template');
const nodeMap: PlaceholderNodeMap = {}; const nodeMap: PlaceholderNodeMap = {};
n.innerHTML = this.toString(nodeMap); const source = this.toString(nodeMap);
if (this.contextElementName !== void 0) {
n.innerHTML = `<${this.contextElementName}>${source}</${this.contextElementName}>`;
} else {
n.innerHTML = source;
}
for (const p of Array.from(n.querySelectorAll('placeholder'))) { for (const p of Array.from(n.querySelectorAll('placeholder'))) {
const e = nodeMap[p.id]; const e = nodeMap[p.id];
if (e) { if (e) {
@ -62,7 +69,11 @@ export class HtmlFragments implements FlattenInto {
p.remove(); p.remove();
} }
} }
return Array.from(n.content.childNodes); if (this.contextElementName !== void 0) {
return Array.from(n.content.firstElementChild!.childNodes);
} else {
return Array.from(n.content.childNodes);
}
} }
toString(nodeMap?: PlaceholderNodeMap) { toString(nodeMap?: PlaceholderNodeMap) {
@ -120,25 +131,27 @@ export function join(pieces: Array<HtmlFragment>, separator: HtmlFragment): Arra
} }
} }
export function template( export function makeTemplate(contextElementName?: string)
constantParts: TemplateStringsArray, : (constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>) => HtmlFragments {
... variableParts: Array<HtmlFragment>): HtmlFragments return (constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>) => {
{ const pieces: Array<HtmlFragment> = [];
const pieces: Array<HtmlFragment> = []; function pushConst(i: number) {
function pushConst(i: number) { const r = constantParts.raw[i].trimLeft();
const r = constantParts.raw[i].trimLeft(); if (r) pieces.push(r);
if (r) pieces.push(r); }
} pushConst(0);
pushConst(0); variableParts.forEach((vp, vpIndex) => {
variableParts.forEach((vp, vpIndex) => { flattenInto(pieces, vp, { escapeStrings: true });
flattenInto(pieces, vp, { escapeStrings: true }); pushConst(vpIndex + 1);
pushConst(vpIndex + 1); });
}); return new HtmlFragments(pieces, contextElementName);
return new HtmlFragments(pieces); };
}; }
export function raw(str: string) { export const template = makeTemplate();
return new HtmlFragments([str]);
export function raw(str: string, contextElementName?: string) {
return new HtmlFragments([str], contextElementName);
} }
export default template; export default template;