]>
Lady’s Gitweb - Lemon/blob - mod.js
51acb773424c3b1d4da29c90690d7f8541ed2c70
2 // ====================================================================
4 // Copyright © 2022 Lady [@ Lady’s Computer].
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
10 import { xhtmlNamespace
} from "./names.js";
13 * Create a D·O·M Element from a tagged template.
18 * Lemon("elementName", "namespace")`content`;
20 * Lemon("elementName", "namespace")({ attribute: "value" })`content`;
23 * Content may, via substitutions, include additional nodes. As a
24 * convenience, if the namespace is not defined, it is the X·H·T·M·L
25 * namespace. As a convenience, `Lemon.elementName` is a shorthand for
26 * `Lemon("element-name").` As a convenience, substitutions may take
27 * the form of an array of nodes.
29 const Lemon
= new Proxy(
30 Object
.defineProperties(
31 Object
.setPrototypeOf(
32 function (name
, namespace = xhtmlNamespace
) {
33 return Object
.setPrototypeOf(
36 namespace: `${namespace}`,
44 name
: { value
: "Lemon" },
45 prototype: { value
: Object
.create(Function
.prototype) },
49 /** If `P` doesn’t exist on `O`, calls `O` with `P` instead. */
51 if (typeof P
!= "string" || Reflect
.has(O
, P
)) {
52 return Reflect
.get(O
, P
, Receiver
);
53 } else if (typeof O
== "function") {
55 Array
.from(function* () {
56 for (const character
of P
) {
57 yield /[A-Z]/u.test(character
)
58 ? `-${character.toLowerCase()}`
72 * Creates an Element with `name`, `namespace`, and `attributes` drawn
73 * from this object and content determined by the provided strings and
76 const createNode = function (strings
, ...expressions
) {
77 const { attributes
, name
, namespace } = this;
78 const { raw
} = strings
;
79 const result
= document
.createElementNS(namespace, name
);
80 for (const [attName
, attValue
] of Object
.entries(attributes
)) {
81 result
.setAttribute(attName
, `${attValue}`);
83 const maxIndex
= Math
.max(raw
.length
, expressions
.length
);
84 for (let index
= 0; index
< maxIndex
; ++index
) {
85 result
.append(...nodesFromExpression(raw
[index
]));
86 result
.append(...nodesFromExpression(expressions
[index
]));
93 * Creates a new template tag builder with the provided attributes for
94 * for making Element’s with the `name` specified on this.
96 * As a shorthand, you can also use this function as a template tag
97 * itself, in which case it is treated as though its attributes were
100 const nodeTagBuilder = function (attrsOrStrings
, ...expressions
) {
101 const { name
, namespace } = this;
103 Array
.isArray(attrsOrStrings
) && "raw" in attrsOrStrings
&&
104 Array
.isArray(attrsOrStrings
.raw
)
106 // The first argument is usable as a template string.
107 return createNode
.call(
108 { attributes
: {}, document
, name
, namespace },
113 // The first argument is not a template string.
114 return createNode
.bind({
115 attributes
: { ...Object(attrsOrStrings
) },
123 /** Processes the provided expression and yields Nodes. */
124 const nodesFromExpression
= function* (expression
) {
125 if (expression
== null) {
126 // The expression is nullish.
129 // The expression is not nullish.
130 const expressionIsNode
= (() => {
132 Reflect
.get(Node
.prototype, "nodeType", expression
);
138 if (expressionIsNode
) {
139 // The expression is already a `Node`.
141 } else if (Array
.isArray(expression
)) {
142 // The expression is an array of expressions.
143 for (const subexpression
of expression
) {
144 yield* nodesFromExpression(subexpression
);
147 // The expression is something else.
148 yield document
.createTextNode(`${expression}`);
This page took 0.059053 seconds and 3 git commands to generate.