From 8c2f45a5999dfa0b7df90cb7bb0c847bfe1e46ff Mon Sep 17 00:00:00 2001 From: terrablue <102580937+terrablue@users.noreply.github.com> Date: Fri, 20 May 2022 17:57:32 +0200 Subject: [PATCH] support slots in web components --- source/handlers/DOM/Node.js | 19 +++++++++++++++++-- source/handlers/DOM/Parser.js | 8 ++++---- source/handlers/html.js | 17 ++++++++--------- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/source/handlers/DOM/Node.js b/source/handlers/DOM/Node.js index 4c3a4599..e02b350f 100644 --- a/source/handlers/DOM/Node.js +++ b/source/handlers/DOM/Node.js @@ -36,13 +36,15 @@ const fulfill = async (attribute, source) => { export default class Node { #data; + #slottables; - constructor(parent, content = "div", data) { + constructor(parent, content = "div", data, slottables) { if (parent !== undefined) { this.parent = parent; this.parent.attach(this); } this.#data = data; + this.#slottables = slottables; this.attributes = {}; if (content !== undefined) { const [tag_name] = content.split(" "); @@ -74,6 +76,14 @@ export default class Node { this.#data = value; } + get slottables() { + return this.#slottables ?? this.parent?.slottables; + } + + set slottables(value) { + this.#slottables = value; + } + attach(child) { this.children.push(child); child.parent = this; @@ -120,9 +130,14 @@ export default class Node { async compose(components) { if (components[this.tag_name]) { - return Parser.parse(components[this.tag_name], this.attributes) + return Parser.parse(components[this.tag_name], this.attributes, this.children) .compose(components); } + if (this.tag_name === "slot" && this.slottables.length > 0) { + const slottable = this.slottables.shift(); + slottable.parent = this.parent; + return slottable; + } this.children = await Promise.all(this.children.map(child => child.compose(components))); return this; diff --git a/source/handlers/DOM/Parser.js b/source/handlers/DOM/Parser.js index 1b487048..1c728f53 100644 --- a/source/handlers/DOM/Parser.js +++ b/source/handlers/DOM/Parser.js @@ -6,14 +6,14 @@ const open_and_close_tag = "open_and_close_tag"; const last_index = -1; export default class Parser { - constructor(html, data) { + constructor(html, data, children) { this.html = html; this.index = 0; this.result = []; this.buffer = ""; this.balance = 0; this.reading_tag = false; - this.node = new Node(undefined, undefined, data); + this.node = new Node(undefined, undefined, data, children); this.tree = this.node; } @@ -129,7 +129,7 @@ export default class Parser { return this.return_checked(); } - static parse(html, data) { - return new Parser(html, data).parse(); + static parse(html, data, children) { + return new Parser(html, data, children).parse(); } } diff --git a/source/handlers/html.js b/source/handlers/html.js index 1a9f3ac7..c3588d16 100644 --- a/source/handlers/html.js +++ b/source/handlers/html.js @@ -5,21 +5,20 @@ import _conf from "../conf.js"; const conf = _conf(); const {paths: {components: path}} = conf; -const components = {}; -if (await File.exists(path)) { - const names = await File.list(path); - for (const name of names) { - components[name.slice(0, -5)] = await File.read(`${path}/${name}`); - } -} +const ending = -5; +const load_file = async name => + [name.slice(0, ending), await File.read(`${path}/${name}`)]; +const components = await File.exists(path) + ? Object.fromEntries(await Promise.all((await File.list(path)).map(load_file))) + : {}; const last = -1; export default async (strings, ...keys) => { - const html = await (await (await Parser.parse(strings + const html = await (await Parser.parse(strings .slice(0, last) .map((string, i) => `${string}$${i}`) .join("") + strings[strings.length + last], await Promise.all(keys)) - .unfold(components))) + .unfold(components)) .render(); const body = (await index(conf)).replace("", () => `${html}`); const code = 200;