@optionfactory/fml 8.0.0 → 8.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client-errors.iife.js +11 -8
- package/dist/client-errors.iife.js.map +1 -1
- package/dist/client-errors.iife.min.js +1 -1
- package/dist/client-errors.iife.min.js.map +1 -1
- package/dist/fml.css +10 -1
- package/dist/fml.css.map +1 -1
- package/dist/fml.d.mts +73 -13
- package/dist/fml.iife.js +598 -208
- package/dist/fml.iife.js.map +1 -1
- package/dist/fml.iife.min.js +1 -1
- package/dist/fml.iife.min.js.map +1 -1
- package/dist/fml.min.mjs +1 -1
- package/dist/fml.min.mjs.map +1 -1
- package/dist/fml.mjs +598 -208
- package/dist/fml.mjs.map +1 -1
- package/dist/ftl.d.mts +2 -1
- package/dist/ftl.iife.js +60 -33
- package/dist/ftl.iife.js.map +1 -1
- package/dist/ftl.iife.min.js +1 -1
- package/dist/ftl.iife.min.js.map +1 -1
- package/dist/ftl.min.mjs +1 -1
- package/dist/ftl.min.mjs.map +1 -1
- package/dist/ftl.mjs +60 -33
- package/dist/ftl.mjs.map +1 -1
- package/dist/ful.css +10 -1
- package/dist/ful.css.map +1 -1
- package/dist/ful.d.mts +22 -6
- package/dist/ful.iife.js +496 -166
- package/dist/ful.iife.js.map +1 -1
- package/dist/ful.iife.min.js +1 -1
- package/dist/ful.iife.min.js.map +1 -1
- package/dist/ful.min.mjs +1 -1
- package/dist/ful.min.mjs.map +1 -1
- package/dist/ful.mjs +496 -166
- package/dist/ful.mjs.map +1 -1
- package/dist/httpc.d.mts +49 -6
- package/dist/httpc.iife.js +40 -9
- package/dist/httpc.iife.js.map +1 -1
- package/dist/httpc.iife.min.js +1 -1
- package/dist/httpc.iife.min.js.map +1 -1
- package/dist/httpc.min.mjs +1 -1
- package/dist/httpc.min.mjs.map +1 -1
- package/dist/httpc.mjs +40 -9
- package/dist/httpc.mjs.map +1 -1
- package/package.json +6 -7
package/dist/ftl.mjs
CHANGED
|
@@ -3457,7 +3457,7 @@ class EvaluatingVisitor {
|
|
|
3457
3457
|
case '<=':
|
|
3458
3458
|
return lhs <= rhs;
|
|
3459
3459
|
default:
|
|
3460
|
-
throw new Error(
|
|
3460
|
+
throw new Error(`unknown cmp op ${node.op}`);
|
|
3461
3461
|
}
|
|
3462
3462
|
}
|
|
3463
3463
|
[nodes.call](node) {
|
|
@@ -3468,7 +3468,7 @@ class EvaluatingVisitor {
|
|
|
3468
3468
|
}
|
|
3469
3469
|
const fn = module[fnRef.value];
|
|
3470
3470
|
if (!fn) {
|
|
3471
|
-
throw new Error(`Function "#${fnRef.module === null ? '' : fnRef.module
|
|
3471
|
+
throw new Error(`Function "#${fnRef.module === null ? '' : `${fnRef.module}:`}${fnRef.value}" not found`);
|
|
3472
3472
|
}
|
|
3473
3473
|
const args = node.args.map((arg) => this.visit(arg));
|
|
3474
3474
|
return fn.apply(this.#resolve_proxy(), args);
|
|
@@ -3504,14 +3504,14 @@ class EvaluatingVisitor {
|
|
|
3504
3504
|
return cond ? cond : this.visit(node.ifFalse);
|
|
3505
3505
|
}
|
|
3506
3506
|
[nodes.access](node) {
|
|
3507
|
-
let prev
|
|
3507
|
+
let prev ;
|
|
3508
3508
|
let cur = this.visit(node.lhs);
|
|
3509
3509
|
for (let i = 0; i !== node.rhs.length; ++i) {
|
|
3510
3510
|
const rhs = node.rhs[i];
|
|
3511
3511
|
if (rhs.ns && cur == null) {
|
|
3512
3512
|
return undefined;
|
|
3513
3513
|
}
|
|
3514
|
-
let value
|
|
3514
|
+
let value ;
|
|
3515
3515
|
switch (rhs.type) {
|
|
3516
3516
|
case nodes.member: {
|
|
3517
3517
|
value = cur[rhs.rhs];
|
|
@@ -3552,7 +3552,7 @@ class EvaluatingVisitor {
|
|
|
3552
3552
|
case nodes.templated.ten:
|
|
3553
3553
|
return { type: nodes.dom.n, value: this.visit(node.value) };
|
|
3554
3554
|
default:
|
|
3555
|
-
throw new Error(
|
|
3555
|
+
throw new Error(`unknown node type ${node.type.toString()}`);
|
|
3556
3556
|
}
|
|
3557
3557
|
});
|
|
3558
3558
|
}
|
|
@@ -3728,7 +3728,7 @@ class Attributes {
|
|
|
3728
3728
|
.forEach((a) => {
|
|
3729
3729
|
const target = a.substring(prefix.length);
|
|
3730
3730
|
if (target === 'class') {
|
|
3731
|
-
const classes = from.getAttribute(prefix
|
|
3731
|
+
const classes = from.getAttribute(`${prefix}class`)?.split(/\s+/).filter((a) => a.length) ?? [];
|
|
3732
3732
|
to.classList.add(...classes);
|
|
3733
3733
|
return;
|
|
3734
3734
|
}
|
|
@@ -3820,8 +3820,7 @@ class Nodes {
|
|
|
3820
3820
|
* @returns
|
|
3821
3821
|
*/
|
|
3822
3822
|
static isParsed(el) {
|
|
3823
|
-
|
|
3824
|
-
for (let c = el; c; c = c.parentNode) {
|
|
3823
|
+
for (let c = /** @type {Node | null} */ (el); c; c = c.parentNode) {
|
|
3825
3824
|
if (c.nextSibling) {
|
|
3826
3825
|
return true;
|
|
3827
3826
|
}
|
|
@@ -3884,19 +3883,18 @@ class Nodes {
|
|
|
3884
3883
|
}
|
|
3885
3884
|
|
|
3886
3885
|
class NodeOperations {
|
|
3887
|
-
#forRemoval;
|
|
3888
|
-
constructor() {
|
|
3889
|
-
this.#forRemoval = [];
|
|
3890
|
-
}
|
|
3886
|
+
#forRemoval = new Set();
|
|
3891
3887
|
removed(node) {
|
|
3892
|
-
return this.#forRemoval.
|
|
3888
|
+
return this.#forRemoval.has(node);
|
|
3893
3889
|
}
|
|
3894
3890
|
remove(node) {
|
|
3895
3891
|
node.replaceChildren?.();
|
|
3896
3892
|
Object.keys(node.dataset || {})
|
|
3897
3893
|
.filter((k) => k.startsWith('tpl'))
|
|
3898
|
-
.forEach((k) =>
|
|
3899
|
-
|
|
3894
|
+
.forEach((k) => {
|
|
3895
|
+
delete node.dataset[k];
|
|
3896
|
+
});
|
|
3897
|
+
this.#forRemoval.add(node);
|
|
3900
3898
|
}
|
|
3901
3899
|
popData(node, key) {
|
|
3902
3900
|
const v = node.dataset[key];
|
|
@@ -3914,9 +3912,10 @@ class NodeOperations {
|
|
|
3914
3912
|
this.remove(ref);
|
|
3915
3913
|
}
|
|
3916
3914
|
cleanup() {
|
|
3917
|
-
|
|
3918
|
-
|
|
3915
|
+
for (const node of this.#forRemoval) {
|
|
3916
|
+
node.remove();
|
|
3919
3917
|
}
|
|
3918
|
+
this.#forRemoval.clear();
|
|
3920
3919
|
}
|
|
3921
3920
|
}
|
|
3922
3921
|
|
|
@@ -3971,7 +3970,7 @@ class CommandsHandler {
|
|
|
3971
3970
|
}
|
|
3972
3971
|
static tplRemove(node, value, ops, modules, dataStack) {
|
|
3973
3972
|
switch (value.toLowerCase()) {
|
|
3974
|
-
case 'tag':
|
|
3973
|
+
case 'tag': {
|
|
3975
3974
|
const fragment = new DocumentFragment();
|
|
3976
3975
|
while (node.firstChild) {
|
|
3977
3976
|
fragment.appendChild(node.firstChild);
|
|
@@ -3985,6 +3984,7 @@ class CommandsHandler {
|
|
|
3985
3984
|
ops.remove(node);
|
|
3986
3985
|
}
|
|
3987
3986
|
break;
|
|
3987
|
+
}
|
|
3988
3988
|
case 'body':
|
|
3989
3989
|
node.replaceChildren();
|
|
3990
3990
|
break;
|
|
@@ -4050,8 +4050,10 @@ class CommandsHandler {
|
|
|
4050
4050
|
}
|
|
4051
4051
|
}
|
|
4052
4052
|
|
|
4053
|
-
// Module-isolated string cache for dataset-to-attribute conversions
|
|
4053
|
+
// Module-isolated string cache for dataset-to-attribute conversions, bounded with
|
|
4054
|
+
// FIFO eviction like the expression ast cache
|
|
4054
4055
|
const attributeCache = new Map();
|
|
4056
|
+
const ATTRIBUTE_CACHE_MAX_SIZE = 1000;
|
|
4055
4057
|
|
|
4056
4058
|
/**
|
|
4057
4059
|
* Converts a tpl camelCase dataset key into a kebab-case attribute name.
|
|
@@ -4062,6 +4064,9 @@ const attributeCache = new Map();
|
|
|
4062
4064
|
function toAttr(dataSetKey) {
|
|
4063
4065
|
let cached = attributeCache.get(dataSetKey);
|
|
4064
4066
|
if (!cached) {
|
|
4067
|
+
if (attributeCache.size >= ATTRIBUTE_CACHE_MAX_SIZE) {
|
|
4068
|
+
attributeCache.delete(attributeCache.keys().next().value);
|
|
4069
|
+
}
|
|
4065
4070
|
cached = dataSetKey
|
|
4066
4071
|
.substring(3)
|
|
4067
4072
|
.split(/(?=[A-Z])/)
|
|
@@ -4196,9 +4201,10 @@ class Template {
|
|
|
4196
4201
|
* @param {string} expression
|
|
4197
4202
|
* @param {(typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED)?} [mode]
|
|
4198
4203
|
* @param {...*} data
|
|
4204
|
+
* @returns the evaluated expression result
|
|
4199
4205
|
*/
|
|
4200
4206
|
evaluate(expression, mode, ...data) {
|
|
4201
|
-
new ExpressionEvaluator(this.#modules, this.#dataStack).withOverlay(...data).evaluate(expression, mode);
|
|
4207
|
+
return new ExpressionEvaluator(this.#modules, this.#dataStack).withOverlay(...data).evaluate(expression, mode);
|
|
4202
4208
|
}
|
|
4203
4209
|
/**
|
|
4204
4210
|
* Returns an expression evaluator with bound modules and dataStack.
|
|
@@ -4343,8 +4349,8 @@ class RenderError extends Error {
|
|
|
4343
4349
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
4344
4350
|
node.nodeValue = node.nodeValue.trim();
|
|
4345
4351
|
}
|
|
4346
|
-
for (
|
|
4347
|
-
|
|
4352
|
+
for (let n = 0; n < node.childNodes.length; n++) {
|
|
4353
|
+
const child = node.childNodes[n];
|
|
4348
4354
|
if (child.nodeType === Node.TEXT_NODE) {
|
|
4349
4355
|
child.nodeValue = child.nodeValue.trim();
|
|
4350
4356
|
if (child.nodeValue.length === 0) {
|
|
@@ -4363,8 +4369,7 @@ class UpgradeQueue {
|
|
|
4363
4369
|
#q = new Map();
|
|
4364
4370
|
constructor() {
|
|
4365
4371
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
4366
|
-
|
|
4367
|
-
await Promise.all(pending);
|
|
4372
|
+
await this.settle();
|
|
4368
4373
|
document.dispatchEvent(
|
|
4369
4374
|
new CustomEvent('ftl:ready', {
|
|
4370
4375
|
bubbles: false,
|
|
@@ -4384,6 +4389,16 @@ class UpgradeQueue {
|
|
|
4384
4389
|
.finally(() => this.#q.delete(el));
|
|
4385
4390
|
this.#q.set(el, promise);
|
|
4386
4391
|
}
|
|
4392
|
+
/**
|
|
4393
|
+
* Waits for every queued upgrade, including the ones enqueued while waiting:
|
|
4394
|
+
* a component is only queued once its parent connects it, so a single pass would
|
|
4395
|
+
* miss everything nested.
|
|
4396
|
+
*/
|
|
4397
|
+
async settle() {
|
|
4398
|
+
while (this.#q.size !== 0) {
|
|
4399
|
+
await Promise.all(Array.from(this.#q.values()));
|
|
4400
|
+
}
|
|
4401
|
+
}
|
|
4387
4402
|
get entries() {
|
|
4388
4403
|
return this.#q.entries();
|
|
4389
4404
|
}
|
|
@@ -4578,18 +4593,30 @@ class Templates {
|
|
|
4578
4593
|
}
|
|
4579
4594
|
}
|
|
4580
4595
|
|
|
4581
|
-
|
|
4582
|
-
|
|
4596
|
+
/**
|
|
4597
|
+
* Waits for the queued upgrades matching the filter, including the ones enqueued while
|
|
4598
|
+
* waiting: a component is only queued once its parent connects it, so a single pass
|
|
4599
|
+
* would miss everything nested.
|
|
4600
|
+
* @param {(el: Element) => boolean} accept
|
|
4601
|
+
*/
|
|
4602
|
+
const settle = async (accept) => {
|
|
4603
|
+
for (;;) {
|
|
4583
4604
|
const pending = Array.from(registry.upgrades)
|
|
4584
|
-
.filter(([child
|
|
4585
|
-
.map(([
|
|
4605
|
+
.filter(([child]) => accept(child))
|
|
4606
|
+
.map(([, promise]) => promise);
|
|
4607
|
+
if (pending.length === 0) {
|
|
4608
|
+
return;
|
|
4609
|
+
}
|
|
4586
4610
|
await Promise.all(pending);
|
|
4587
4611
|
}
|
|
4612
|
+
};
|
|
4613
|
+
|
|
4614
|
+
class Rendering {
|
|
4615
|
+
static async waitFor(el) {
|
|
4616
|
+
await settle((child) => el.contains(child));
|
|
4617
|
+
}
|
|
4588
4618
|
static async waitForChildren(el) {
|
|
4589
|
-
|
|
4590
|
-
.filter(([child, promise]) => el !== child && el.contains(child))
|
|
4591
|
-
.map(([child, promise]) => promise);
|
|
4592
|
-
await Promise.all(pending);
|
|
4619
|
+
await settle((child) => el !== child && el.contains(child));
|
|
4593
4620
|
}
|
|
4594
4621
|
}
|
|
4595
4622
|
|
|
@@ -4631,7 +4658,7 @@ class ParsedElement extends HTMLElement {
|
|
|
4631
4658
|
template(name) {
|
|
4632
4659
|
const { modules, data } = registry.context();
|
|
4633
4660
|
let t = this.#bits().TEMPLATES[name ?? 'default'].withData(data).withModules(modules);
|
|
4634
|
-
for (
|
|
4661
|
+
for (const k of ['l10n', 'config']) {
|
|
4635
4662
|
const v = this.constructor[k];
|
|
4636
4663
|
if (v) {
|
|
4637
4664
|
t = t.withOverlay({ [k]: v });
|