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 {
readonly contextElementName: string | undefined;
readonly pieces: Array<HtmlFragment>;
constructor(pieces: Array<HtmlFragment> = []) {
constructor(pieces: Array<HtmlFragment> = [], contextElementName?: string) {
this.contextElementName = contextElementName;
this.pieces = pieces;
}
@ -54,7 +56,12 @@ export class HtmlFragments implements FlattenInto {
nodes(): Array<ChildNode> {
let n = document.createElement('template');
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'))) {
const e = nodeMap[p.id];
if (e) {
@ -62,7 +69,11 @@ export class HtmlFragments implements FlattenInto {
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) {
@ -120,25 +131,27 @@ export function join(pieces: Array<HtmlFragment>, separator: HtmlFragment): Arra
}
}
export function template(
constantParts: TemplateStringsArray,
... variableParts: Array<HtmlFragment>): HtmlFragments
{
const pieces: Array<HtmlFragment> = [];
function pushConst(i: number) {
const r = constantParts.raw[i].trimLeft();
if (r) pieces.push(r);
}
pushConst(0);
variableParts.forEach((vp, vpIndex) => {
flattenInto(pieces, vp, { escapeStrings: true });
pushConst(vpIndex + 1);
});
return new HtmlFragments(pieces);
};
export function makeTemplate(contextElementName?: string)
: (constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>) => HtmlFragments {
return (constantParts: TemplateStringsArray, ... variableParts: Array<HtmlFragment>) => {
const pieces: Array<HtmlFragment> = [];
function pushConst(i: number) {
const r = constantParts.raw[i].trimLeft();
if (r) pieces.push(r);
}
pushConst(0);
variableParts.forEach((vp, vpIndex) => {
flattenInto(pieces, vp, { escapeStrings: true });
pushConst(vpIndex + 1);
});
return new HtmlFragments(pieces, contextElementName);
};
}
export function raw(str: string) {
return new HtmlFragments([str]);
export const template = makeTemplate();
export function raw(str: string, contextElementName?: string) {
return new HtmlFragments([str], contextElementName);
}
export default template;