@oscarpalmer/abydon 0.13.0 → 0.15.0
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/abydon.full.js +790 -763
- package/dist/constants.js +10 -0
- package/dist/fragment.js +38 -17
- package/dist/fragments.js +74 -0
- package/dist/helpers/dom.js +4 -4
- package/dist/helpers/index.js +4 -1
- package/dist/index.js +5 -1
- package/dist/node/attribute/index.js +19 -14
- package/dist/node/attribute/value.js +10 -12
- package/dist/node/event.js +7 -9
- package/dist/node/index.js +9 -4
- package/dist/node/value.js +84 -64
- package/dist/parse.js +7 -7
- package/package.json +14 -16
- package/src/constants.ts +20 -0
- package/src/fragment.ts +92 -29
- package/src/fragments.ts +134 -0
- package/src/helpers/dom.ts +3 -3
- package/src/helpers/index.ts +10 -0
- package/src/index.ts +16 -1
- package/src/models.ts +18 -4
- package/src/node/attribute/index.ts +24 -19
- package/src/node/attribute/value.ts +31 -28
- package/src/node/event.ts +11 -12
- package/src/node/index.ts +15 -6
- package/src/node/value.ts +186 -116
- package/src/parse.ts +10 -3
- package/types/constants.d.ts +9 -0
- package/types/fragment.d.ts +26 -8
- package/types/fragments.d.ts +13 -0
- package/types/helpers/index.d.ts +2 -0
- package/types/index.d.ts +5 -1
- package/types/models.d.ts +16 -4
- package/types/fragment.d.cts +0 -27
- package/types/helpers/dom.d.cts +0 -7
- package/types/helpers/index.d.cts +0 -29
- package/types/index.d.cts +0 -302
- package/types/models.d.cts +0 -107
- package/types/node/attribute/index.d.cts +0 -109
- package/types/node/attribute/value.d.cts +0 -109
- package/types/node/event.d.cts +0 -7
- package/types/node/index.d.cts +0 -108
- package/types/node/value.d.cts +0 -108
- package/types/parse.d.cts +0 -108
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const ABORT_CONTROLLERS = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
const ATTRIBUTE_CLASS_PREFIX_LENGTH = 6;
|
|
3
|
+
const EXPRESSION_ATTRIBUTE_CLASS = /^class\./;
|
|
4
|
+
const EXPRESSION_ATTRIBUTE_STYLE_FULL = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
|
|
5
|
+
const EXPRESSION_ATTRIBUTE_STYLE_PREFIX = /^style\./;
|
|
6
|
+
const EXPRESSION_COMMENT_FULL = /^<!--abydon\.(\d+)-->$/;
|
|
7
|
+
const EXPRESSION_COMMENT_CONTENT = /^abydon\.(\d+)$/;
|
|
8
|
+
const EXPRESSION_EVENT_NAME = /^@([\w-]+)(?::([a-z:]+))?$/i;
|
|
9
|
+
const REASON_EVENT_REMOVED = "Event removed as element was removed from document by Abydon";
|
|
10
|
+
export { ABORT_CONTROLLERS, ATTRIBUTE_CLASS_PREFIX_LENGTH, EXPRESSION_ATTRIBUTE_CLASS, EXPRESSION_ATTRIBUTE_STYLE_FULL, EXPRESSION_ATTRIBUTE_STYLE_PREFIX, EXPRESSION_COMMENT_CONTENT, EXPRESSION_COMMENT_FULL, EXPRESSION_EVENT_NAME, REASON_EVENT_REMOVED };
|
package/dist/fragment.js
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { parse } from "./parse.js";
|
|
2
|
+
import { isFragments } from "./helpers/index.js";
|
|
3
|
+
import { handleFragments } from "./fragments.js";
|
|
2
4
|
import { removeNodes } from "./helpers/dom.js";
|
|
3
5
|
import { mapNodes } from "./node/index.js";
|
|
6
|
+
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
4
7
|
import { html } from "@oscarpalmer/toretto/html";
|
|
5
8
|
var Fragment = class {
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
#data;
|
|
10
|
+
#configuration = {
|
|
11
|
+
identifier: void 0,
|
|
12
|
+
ignoreCache: false
|
|
13
|
+
};
|
|
8
14
|
get identifier() {
|
|
9
|
-
return this.
|
|
15
|
+
return this.#configuration.identifier;
|
|
10
16
|
}
|
|
11
17
|
constructor(strings, expressions) {
|
|
12
|
-
this
|
|
18
|
+
Object.defineProperty(this, "$fragment", { value: true });
|
|
19
|
+
this.#data = {
|
|
13
20
|
expressions,
|
|
14
21
|
strings,
|
|
15
22
|
items: [],
|
|
@@ -23,33 +30,47 @@ var Fragment = class {
|
|
|
23
30
|
appendTo(element) {
|
|
24
31
|
element.append(...this.get());
|
|
25
32
|
}
|
|
33
|
+
configure(configuration) {
|
|
34
|
+
const actual = isPlainObject(configuration) ? configuration : {};
|
|
35
|
+
if (actual.identifier !== void 0) this.#configuration.identifier = actual.identifier;
|
|
36
|
+
if (typeof actual.ignoreCache === "boolean") this.#configuration.ignoreCache = actual.ignoreCache;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
26
39
|
get() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const templated = html(
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
const data = this.#data;
|
|
41
|
+
if (data.items.length === 0) {
|
|
42
|
+
const templated = html(parse(data), {
|
|
43
|
+
ignoreCache: this.#configuration.ignoreCache,
|
|
44
|
+
sanitizeBooleanAttributes: false
|
|
45
|
+
});
|
|
46
|
+
data.items.splice(0, data.items.length, ...templated.map((node) => ({ nodes: [node] })));
|
|
47
|
+
mapNodes(data, data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes ?? []));
|
|
32
48
|
}
|
|
33
|
-
return [...
|
|
49
|
+
return [...data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes ?? [])];
|
|
34
50
|
}
|
|
35
51
|
identify(identifier) {
|
|
36
|
-
this.
|
|
52
|
+
this.#configuration.identifier = identifier;
|
|
37
53
|
return this;
|
|
38
54
|
}
|
|
39
55
|
remove() {
|
|
40
|
-
removeFragment(this
|
|
56
|
+
removeFragment(this.#data);
|
|
41
57
|
}
|
|
42
58
|
};
|
|
43
59
|
function removeFragment(data) {
|
|
44
60
|
removeMora(data);
|
|
45
|
-
|
|
61
|
+
let { length } = data.items;
|
|
46
62
|
for (let index = 0; index < length; index += 1) {
|
|
47
63
|
const { fragments, nodes } = data.items[index];
|
|
48
|
-
const
|
|
49
|
-
for (let
|
|
50
|
-
removeNodes(nodes);
|
|
64
|
+
const fragmentsLength = fragments?.length ?? 0;
|
|
65
|
+
for (let fragmentIndex = 0; fragmentIndex < fragmentsLength; fragmentIndex += 1) fragments?.[fragmentIndex]?.remove();
|
|
66
|
+
removeNodes(nodes ?? []);
|
|
67
|
+
}
|
|
68
|
+
data.items.length = 0;
|
|
69
|
+
length = data.values.length;
|
|
70
|
+
for (let index = 0; index < length; index += 1) {
|
|
71
|
+
const value = data.values[index];
|
|
72
|
+
if (isFragments(value)) handleFragments(value, true);
|
|
51
73
|
}
|
|
52
|
-
data.items.splice(0, length);
|
|
53
74
|
}
|
|
54
75
|
function removeMora(data) {
|
|
55
76
|
const unsubscribers = [...data.mora.subscribers];
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { isFragment, isFragments } from "./helpers/index.js";
|
|
2
|
+
import { array } from "@oscarpalmer/mora";
|
|
3
|
+
import { getString } from "@oscarpalmer/atoms/string";
|
|
4
|
+
var Fragments = class {
|
|
5
|
+
#state;
|
|
6
|
+
get items() {
|
|
7
|
+
return this.#state.mapped;
|
|
8
|
+
}
|
|
9
|
+
constructor(items, identify, fragment) {
|
|
10
|
+
Object.defineProperty(this, "$fragments", { value: true });
|
|
11
|
+
this.#state = {
|
|
12
|
+
fragment,
|
|
13
|
+
identify,
|
|
14
|
+
array: items,
|
|
15
|
+
instances: {},
|
|
16
|
+
mapped: array([]),
|
|
17
|
+
subscriber: void 0
|
|
18
|
+
};
|
|
19
|
+
states.set(this, this.#state);
|
|
20
|
+
initializeFragments(this.#state);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function handleFragments(item, remove) {
|
|
24
|
+
const state = isFragments(item) ? states.get(item) : item;
|
|
25
|
+
if (state != null) (remove ? removeFragments : initializeFragments)(state);
|
|
26
|
+
}
|
|
27
|
+
function handleItems(state, items) {
|
|
28
|
+
const keys = /* @__PURE__ */ new Set();
|
|
29
|
+
const mapped = [];
|
|
30
|
+
const { length } = items;
|
|
31
|
+
for (let index = 0; index < length; index += 1) {
|
|
32
|
+
const item = items[index];
|
|
33
|
+
const identifier = state.identify(item);
|
|
34
|
+
if (identifier == null) throw new Error("Identifier cannot be null or undefined");
|
|
35
|
+
const key = getString(identifier);
|
|
36
|
+
if (keys.has(key)) throw new Error(`Duplicate identifier found: "${key}"`);
|
|
37
|
+
let instance = state.instances[key];
|
|
38
|
+
if (instance == null) {
|
|
39
|
+
instance = state.fragment(item);
|
|
40
|
+
if (!isFragment(instance)) throw new Error("Fragment function must return a Fragment instance");
|
|
41
|
+
}
|
|
42
|
+
instance.identify(key);
|
|
43
|
+
state.instances[key] = instance;
|
|
44
|
+
keys.add(key);
|
|
45
|
+
mapped.push(instance);
|
|
46
|
+
}
|
|
47
|
+
state.mapped.set(mapped);
|
|
48
|
+
updateFragments(state, keys);
|
|
49
|
+
}
|
|
50
|
+
function initializeFragments(state) {
|
|
51
|
+
state.subscriber ??= state.array.subscribe((items) => {
|
|
52
|
+
handleItems(state, items);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function removeFragments(state) {
|
|
56
|
+
state.subscriber?.();
|
|
57
|
+
updateFragments(state);
|
|
58
|
+
state.subscriber = void 0;
|
|
59
|
+
}
|
|
60
|
+
function updateFragments(state, active) {
|
|
61
|
+
const next = {};
|
|
62
|
+
const previous = { ...state.instances };
|
|
63
|
+
const keys = Object.keys(previous);
|
|
64
|
+
const { length } = keys;
|
|
65
|
+
for (let index = 0; index < length; index += 1) {
|
|
66
|
+
const key = keys[index];
|
|
67
|
+
if (active?.has(key)) next[key] = previous[key];
|
|
68
|
+
else previous[key].remove();
|
|
69
|
+
}
|
|
70
|
+
state.instances = next;
|
|
71
|
+
active?.clear();
|
|
72
|
+
}
|
|
73
|
+
var states = /* @__PURE__ */ new WeakMap();
|
|
74
|
+
export { Fragments, handleFragments, initializeFragments };
|
package/dist/helpers/dom.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { removeEvents } from "../node/event.js";
|
|
2
1
|
import { isFragment } from "./index.js";
|
|
2
|
+
import { removeEvents } from "../node/event.js";
|
|
3
3
|
import { getString } from "@oscarpalmer/atoms/string";
|
|
4
4
|
import { isChildNode, isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
5
5
|
function createNodes(value) {
|
|
@@ -8,7 +8,7 @@ function createNodes(value) {
|
|
|
8
8
|
return [new Text(getString(value))];
|
|
9
9
|
}
|
|
10
10
|
function removeNodes(nodes) {
|
|
11
|
-
|
|
11
|
+
sanitizeNodes(nodes);
|
|
12
12
|
const { length } = nodes;
|
|
13
13
|
for (let index = 0; index < length; index += 1) nodes[index].remove();
|
|
14
14
|
}
|
|
@@ -17,12 +17,12 @@ function replaceNodes(from, to) {
|
|
|
17
17
|
const { length } = from;
|
|
18
18
|
for (let index = 1; index < length; index += 1) from[index].remove();
|
|
19
19
|
}
|
|
20
|
-
function
|
|
20
|
+
function sanitizeNodes(nodes) {
|
|
21
21
|
const { length } = nodes;
|
|
22
22
|
for (let index = 0; index < length; index += 1) {
|
|
23
23
|
const node = nodes[index];
|
|
24
24
|
if (isHTMLOrSVGElement(node)) removeEvents(node);
|
|
25
|
-
if (node.hasChildNodes())
|
|
25
|
+
if (node.hasChildNodes()) sanitizeNodes([...node.childNodes]);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
export { createNodes, removeNodes, replaceNodes };
|
package/dist/helpers/index.js
CHANGED
|
@@ -8,4 +8,7 @@ function compareArrays(first, second) {
|
|
|
8
8
|
function isFragment(value) {
|
|
9
9
|
return typeof value === "object" && value != null && "$fragment" in value && value.$fragment === true;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
function isFragments(value) {
|
|
12
|
+
return typeof value === "object" && value != null && "$fragments" in value && value.$fragments === true;
|
|
13
|
+
}
|
|
14
|
+
export { compareArrays, isFragment, isFragments };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { Fragments } from "./fragments.js";
|
|
1
2
|
import { Fragment } from "./fragment.js";
|
|
2
3
|
import "@oscarpalmer/mora";
|
|
3
4
|
export * from "@oscarpalmer/mora";
|
|
5
|
+
function fragments(array$1, identify, fragment) {
|
|
6
|
+
return new Fragments(array$1, identify, fragment);
|
|
7
|
+
}
|
|
4
8
|
function html(strings, ...values) {
|
|
5
9
|
return new Fragment(strings, values);
|
|
6
10
|
}
|
|
7
|
-
export { html };
|
|
11
|
+
export { fragments, html };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { EXPRESSION_COMMENT_FULL } from "../../constants.js";
|
|
1
2
|
import { mapEvent } from "../event.js";
|
|
2
|
-
import { setAttribute } from "./value.js";
|
|
3
|
+
import { setAttribute as setAttribute$1 } from "./value.js";
|
|
3
4
|
import { computed, isReactive } from "@oscarpalmer/mora";
|
|
4
|
-
|
|
5
|
+
import { isBooleanAttribute, setProperty } from "@oscarpalmer/toretto/attribute";
|
|
5
6
|
function getValue(data, original) {
|
|
6
|
-
const matches =
|
|
7
|
+
const matches = EXPRESSION_COMMENT_FULL.exec(original ?? "");
|
|
7
8
|
return matches == null ? original : data.values[+matches[1]];
|
|
8
9
|
}
|
|
9
10
|
function mapAttributes(data, element) {
|
|
@@ -12,23 +13,27 @@ function mapAttributes(data, element) {
|
|
|
12
13
|
for (let index = 0; index < length; index += 1) {
|
|
13
14
|
const { name, value } = attributes[index];
|
|
14
15
|
const actual = getValue(data, value);
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
switch (true) {
|
|
17
|
+
case name.startsWith("@"):
|
|
18
|
+
mapEvent(element, name, actual);
|
|
19
|
+
break;
|
|
20
|
+
case name.includes(".") || typeof actual === "function" || isReactive(actual):
|
|
21
|
+
mapValue(data, element, name, actual);
|
|
22
|
+
break;
|
|
23
|
+
case isBooleanAttribute(name):
|
|
24
|
+
setProperty(element, name, value);
|
|
25
|
+
break;
|
|
26
|
+
default: break;
|
|
27
|
+
}
|
|
17
28
|
}
|
|
18
29
|
}
|
|
19
30
|
function mapValue(data, element, name, value) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
setComputedAttribute(data, element, name, value);
|
|
23
|
-
break;
|
|
24
|
-
default:
|
|
25
|
-
setAttribute(data, element, name, value);
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
31
|
+
if (typeof value === "function") setComputedAttribute(data, element, name, value);
|
|
32
|
+
else setAttribute$1(data, element, name, value);
|
|
28
33
|
}
|
|
29
34
|
function setComputedAttribute(data, element, name, callback) {
|
|
30
35
|
const value = computed(callback);
|
|
31
36
|
data.mora.values.add(value);
|
|
32
|
-
setAttribute(data, element, name, value);
|
|
37
|
+
setAttribute$1(data, element, name, value);
|
|
33
38
|
}
|
|
34
39
|
export { mapAttributes };
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
+
import { ATTRIBUTE_CLASS_PREFIX_LENGTH, EXPRESSION_ATTRIBUTE_CLASS, EXPRESSION_ATTRIBUTE_STYLE_FULL, EXPRESSION_ATTRIBUTE_STYLE_PREFIX } from "../../constants.js";
|
|
1
2
|
import { isReactive } from "@oscarpalmer/mora";
|
|
2
3
|
import { getString } from "@oscarpalmer/atoms/string";
|
|
3
4
|
import { isBooleanAttribute, setAttribute as setAttribute$1 } from "@oscarpalmer/toretto/attribute";
|
|
4
|
-
var classExpression = /^class\./;
|
|
5
|
-
var styleFullExpression = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
|
|
6
|
-
var stylePrefixExpression = /^style\./;
|
|
7
5
|
function setAttribute(data, element, name, value) {
|
|
8
6
|
element.removeAttribute(name);
|
|
9
7
|
switch (true) {
|
|
10
|
-
case
|
|
8
|
+
case EXPRESSION_ATTRIBUTE_CLASS.test(name):
|
|
11
9
|
setClasses(data, element, name, value);
|
|
12
10
|
return;
|
|
13
|
-
case
|
|
11
|
+
case EXPRESSION_ATTRIBUTE_STYLE_PREFIX.test(name):
|
|
14
12
|
setStyle(data, element, name, value);
|
|
15
13
|
return;
|
|
16
14
|
default:
|
|
@@ -28,31 +26,31 @@ function setClasses(data, element, name, value) {
|
|
|
28
26
|
else update(value);
|
|
29
27
|
}
|
|
30
28
|
function setStyle(data, element, name, value) {
|
|
29
|
+
const [, property, unit] = EXPRESSION_ATTRIBUTE_STYLE_FULL.exec(name) ?? [];
|
|
30
|
+
if (property == null) return;
|
|
31
31
|
function update(value$1) {
|
|
32
32
|
if (value$1 == null || value$1 === false || value$1 === true && unit == null) element.style.removeProperty(property);
|
|
33
33
|
else element.style.setProperty(property, value$1 === true ? unit : getString(value$1));
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
if (property != null) if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
|
|
35
|
+
if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
|
|
37
36
|
else update(value);
|
|
38
37
|
}
|
|
39
38
|
function setValue(data, element, name, value) {
|
|
40
|
-
|
|
39
|
+
let callback;
|
|
40
|
+
if (isBooleanAttribute(name) && name in element) callback = name === "selected" ? updateSelected : updateProperty;
|
|
41
|
+
else callback = setAttribute$1;
|
|
41
42
|
if (isReactive(value)) data.mora.subscribers.add(value.subscribe((next) => {
|
|
42
43
|
callback(element, name, next);
|
|
43
44
|
}));
|
|
44
45
|
else callback(element, name, value);
|
|
45
46
|
}
|
|
46
|
-
function triggerSelectChange(select) {
|
|
47
|
-
if (select != null) select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
48
|
-
}
|
|
49
47
|
function updateProperty(element, name, value) {
|
|
50
48
|
element[name] = value === true;
|
|
51
49
|
}
|
|
52
50
|
function updateSelected(element, name, value) {
|
|
53
51
|
const select = element.closest("select");
|
|
54
52
|
const options = [...select?.options ?? []];
|
|
55
|
-
if (select != null && options.includes(element))
|
|
53
|
+
if (select != null && options.includes(element)) select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
56
54
|
updateProperty(element, name, value);
|
|
57
55
|
}
|
|
58
56
|
export { setAttribute };
|
package/dist/node/event.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
var eventNamePattern = /^@([\w-]+)(?::([a-z:]+))?$/i;
|
|
3
|
-
var reason = "Event removed as element was removed from document by Abydon";
|
|
1
|
+
import { ABORT_CONTROLLERS, EXPRESSION_EVENT_NAME, REASON_EVENT_REMOVED } from "../constants.js";
|
|
4
2
|
function getController(element) {
|
|
5
|
-
let controller =
|
|
3
|
+
let controller = ABORT_CONTROLLERS.get(element);
|
|
6
4
|
if (controller == null) {
|
|
7
5
|
controller = new AbortController();
|
|
8
|
-
|
|
6
|
+
ABORT_CONTROLLERS.set(element, controller);
|
|
9
7
|
}
|
|
10
8
|
return controller;
|
|
11
9
|
}
|
|
@@ -14,19 +12,19 @@ function getOptions(options) {
|
|
|
14
12
|
return {
|
|
15
13
|
capture: parts.includes("c") || parts.includes("capture"),
|
|
16
14
|
once: parts.includes("o") || parts.includes("once"),
|
|
17
|
-
passive: !parts.includes("a")
|
|
15
|
+
passive: !(parts.includes("a") || parts.includes("active"))
|
|
18
16
|
};
|
|
19
17
|
}
|
|
20
18
|
function mapEvent(element, name, value) {
|
|
21
19
|
element.removeAttribute(name);
|
|
22
|
-
const [, type, options] =
|
|
20
|
+
const [, type, options] = EXPRESSION_EVENT_NAME.exec(name) ?? [];
|
|
23
21
|
if (typeof value === "function" && type != null) element.addEventListener(type, value, {
|
|
24
22
|
...getOptions(options ?? ""),
|
|
25
23
|
signal: getController(element).signal
|
|
26
24
|
});
|
|
27
25
|
}
|
|
28
26
|
function removeEvents(element) {
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
ABORT_CONTROLLERS.get(element)?.abort(REASON_EVENT_REMOVED);
|
|
28
|
+
ABORT_CONTROLLERS.delete(element);
|
|
31
29
|
}
|
|
32
30
|
export { mapEvent, removeEvents };
|
package/dist/node/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { isFragment } from "../helpers/index.js";
|
|
1
|
+
import { isFragment, isFragments } from "../helpers/index.js";
|
|
2
|
+
import { handleFragments } from "../fragments.js";
|
|
3
|
+
import { EXPRESSION_COMMENT_CONTENT } from "../constants.js";
|
|
2
4
|
import { createNodes } from "../helpers/dom.js";
|
|
3
5
|
import { mapAttributes } from "./attribute/index.js";
|
|
4
6
|
import { setReactiveValue } from "./value.js";
|
|
5
7
|
import { computed, isReactive } from "@oscarpalmer/mora";
|
|
6
8
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
7
|
-
var commentExpression = /^abydon\.(\d+)$/;
|
|
8
9
|
function mapNode(data, comment) {
|
|
9
|
-
const matches =
|
|
10
|
+
const matches = EXPRESSION_COMMENT_CONTENT.exec(comment.textContent ?? "");
|
|
10
11
|
const value = matches == null ? null : data.values[+matches[1]];
|
|
11
12
|
if (value != null) mapValue(data, comment, value);
|
|
12
13
|
}
|
|
@@ -27,6 +28,10 @@ function mapValue(data, comment, value) {
|
|
|
27
28
|
case typeof value === "function":
|
|
28
29
|
setComputedValue(data, comment, value);
|
|
29
30
|
break;
|
|
31
|
+
case isFragments(value):
|
|
32
|
+
handleFragments(value, false);
|
|
33
|
+
setReactiveValue(data, comment, value.items);
|
|
34
|
+
break;
|
|
30
35
|
case isReactive(value):
|
|
31
36
|
setReactiveValue(data, comment, value);
|
|
32
37
|
break;
|
|
@@ -36,7 +41,7 @@ function mapValue(data, comment, value) {
|
|
|
36
41
|
}
|
|
37
42
|
}
|
|
38
43
|
function replaceComment(data, comment, value) {
|
|
39
|
-
const item = data.items.find((item$1) => item$1.nodes
|
|
44
|
+
const item = data.items.find((item$1) => item$1.nodes?.includes(comment));
|
|
40
45
|
const nodes = createNodes(value);
|
|
41
46
|
if (item != null) {
|
|
42
47
|
item.fragments = isFragment(value) ? [value] : void 0;
|
package/dist/node/value.js
CHANGED
|
@@ -3,91 +3,111 @@ import { createNodes, replaceNodes } from "../helpers/dom.js";
|
|
|
3
3
|
import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
|
|
4
4
|
import { getString } from "@oscarpalmer/atoms/string";
|
|
5
5
|
import { isChildNode } from "@oscarpalmer/toretto/is";
|
|
6
|
+
function addToArray(identifiers, items, nodes, added) {
|
|
7
|
+
let position = nodes[0];
|
|
8
|
+
const before = added && !identifiers.previous.includes(items.templates[0].identifier);
|
|
9
|
+
const next = items.next.flatMap((fragment) => fragment.get().flatMap((node) => ({
|
|
10
|
+
identifier: fragment.identifier,
|
|
11
|
+
value: node
|
|
12
|
+
})));
|
|
13
|
+
const { length } = next;
|
|
14
|
+
for (let index = 0; index < length; index += 1) {
|
|
15
|
+
const node = next[index];
|
|
16
|
+
if (!(added && identifiers.previous.includes(node.identifier))) if (index === 0 && before) position.before(node.value);
|
|
17
|
+
else position.after(node.value);
|
|
18
|
+
position = node.value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function handleArray(identifiers, items, nodes) {
|
|
22
|
+
const next = items.templates.map((template) => items.fragments?.find((fragment) => fragment.identifier === template.identifier) ?? template);
|
|
23
|
+
const comparison = compareArrays(items.fragments ?? [], items.templates);
|
|
24
|
+
if (comparison !== "removed") addToArray(identifiers, {
|
|
25
|
+
...items,
|
|
26
|
+
next
|
|
27
|
+
}, nodes, comparison === "added");
|
|
28
|
+
const toRemove = items.fragments?.filter((fragment) => !identifiers.next.includes(fragment.identifier)) ?? [];
|
|
29
|
+
const { length } = toRemove;
|
|
30
|
+
for (let index = 0; index < length; index += 1) toRemove[index].remove();
|
|
31
|
+
return {
|
|
32
|
+
fragments: next,
|
|
33
|
+
nodes: next.flatMap((fragment) => fragment.get())
|
|
34
|
+
};
|
|
35
|
+
}
|
|
6
36
|
function removeFragments(fragments) {
|
|
7
37
|
if (fragments != null) {
|
|
8
38
|
const { length } = fragments;
|
|
9
39
|
for (let index = 0; index < length; index += 1) fragments[index].remove();
|
|
10
40
|
}
|
|
11
41
|
}
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
42
|
+
function replaceText(item, comment, isNullable) {
|
|
43
|
+
let to;
|
|
44
|
+
if (isNullable) to = [comment];
|
|
45
|
+
else to = item.text == null ? [] : [item.text];
|
|
46
|
+
replaceNodes(item.nodes ?? [], to);
|
|
47
|
+
}
|
|
48
|
+
function setArray(item, comment, value) {
|
|
49
|
+
if (value.length === 0) return { nodes: setText(item, comment, value) };
|
|
50
|
+
let templates = value.filter((item$1) => isFragment(item$1) && item$1.identifier != null);
|
|
51
|
+
const next = templates.map((fragment) => fragment.identifier);
|
|
52
|
+
const previous = item.fragments?.map((fragment) => fragment.identifier) ?? [];
|
|
53
|
+
if (new Set(next).size !== templates.length) templates = [];
|
|
18
54
|
const noTemplates = templates.length === 0;
|
|
19
|
-
if (noTemplates || nodes == null ||
|
|
55
|
+
if (noTemplates || item.nodes == null || previous.some((identifier) => identifier == null)) return {
|
|
20
56
|
fragments: noTemplates ? void 0 : templates,
|
|
21
|
-
nodes: setNodes(
|
|
22
|
-
};
|
|
23
|
-
const next = templates.map((template) => fragments?.find((fragment) => fragment.identifier === template.identifier) ?? template);
|
|
24
|
-
const comparison = compareArrays(fragments ?? [], templates);
|
|
25
|
-
if (comparison !== "removed") {
|
|
26
|
-
let position = nodes[0];
|
|
27
|
-
const before = comparison === "added" && !oldIdentifiers.includes(templates[0].identifier);
|
|
28
|
-
const items = next.flatMap((fragment) => fragment.get().flatMap((node) => ({
|
|
29
|
-
identifier: fragment.identifier,
|
|
30
|
-
value: node
|
|
31
|
-
})));
|
|
32
|
-
const { length: length$1 } = items;
|
|
33
|
-
for (let index = 0; index < length$1; index += 1) {
|
|
34
|
-
const item = items[index];
|
|
35
|
-
if (comparison === "dissimilar" || !oldIdentifiers.includes(item.identifier)) if (index === 0 && before) position.before(item.value);
|
|
36
|
-
else position.after(item.value);
|
|
37
|
-
position = item.value;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
const toRemove = fragments?.filter((fragment) => !identifiers.includes(fragment.identifier)) ?? [];
|
|
41
|
-
const { length } = toRemove;
|
|
42
|
-
for (let index = 0; index < length; index += 1) toRemove[index].remove();
|
|
43
|
-
return {
|
|
44
|
-
fragments: next,
|
|
45
|
-
nodes: next.flatMap((fragment) => fragment.get())
|
|
57
|
+
nodes: setNodes(item, comment, noTemplates ? value.flatMap((item$1) => createNodes(item$1)) : templates.flatMap((template) => template.get()))
|
|
46
58
|
};
|
|
59
|
+
return handleArray({
|
|
60
|
+
next,
|
|
61
|
+
previous
|
|
62
|
+
}, {
|
|
63
|
+
templates,
|
|
64
|
+
fragments: item.fragments ?? []
|
|
65
|
+
}, item.nodes);
|
|
47
66
|
}
|
|
48
|
-
function setNodes(
|
|
49
|
-
if (nodes == null) {
|
|
67
|
+
function setNodes(item, comment, next) {
|
|
68
|
+
if (item.nodes == null) {
|
|
50
69
|
if (comment.parentNode != null) replaceNodes([comment], next);
|
|
51
|
-
else if (text
|
|
52
|
-
} else replaceNodes(nodes, next);
|
|
53
|
-
removeFragments(fragments);
|
|
70
|
+
else if (item.text?.parentNode != null) replaceNodes([item.text], next);
|
|
71
|
+
} else replaceNodes(item.nodes, next);
|
|
72
|
+
removeFragments(item.fragments);
|
|
54
73
|
return next;
|
|
55
74
|
}
|
|
56
75
|
function setReactiveValue(data, comment, reactive) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
let nodes;
|
|
76
|
+
let item = data.items.find((item$1) => item$1.nodes?.includes(comment));
|
|
77
|
+
item ??= {};
|
|
78
|
+
item.text = new Text();
|
|
61
79
|
data.mora.subscribers.add(reactive.subscribe((value) => {
|
|
62
|
-
if (Array.isArray(value))
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
nodes = typeof result === "boolean" ? result ? [text] : void 0 : result?.nodes;
|
|
66
|
-
} else {
|
|
67
|
-
const valueIsFragment = isFragment(value);
|
|
68
|
-
fragments = valueIsFragment ? [value] : void 0;
|
|
69
|
-
if (valueIsFragment || isChildNode(value)) nodes = setNodes(fragments, nodes, comment, text, createNodes(value));
|
|
70
|
-
else nodes = setText(fragments, nodes, comment, text, value);
|
|
71
|
-
}
|
|
72
|
-
if (item != null) {
|
|
73
|
-
item.fragments = fragments;
|
|
74
|
-
item.nodes = [...nodes ?? [comment]];
|
|
75
|
-
}
|
|
80
|
+
if (Array.isArray(value)) setReactiveValueForArray(item, comment, value);
|
|
81
|
+
else setReactiveValueForSingle(item, comment, value);
|
|
82
|
+
item.nodes = [...item.nodes ?? [comment]];
|
|
76
83
|
}));
|
|
77
84
|
}
|
|
78
|
-
function
|
|
85
|
+
function setReactiveValueForArray(item, comment, value) {
|
|
86
|
+
const result = setArray(item, comment, value);
|
|
87
|
+
item.fragments = typeof result === "boolean" ? void 0 : result?.fragments;
|
|
88
|
+
if (typeof result === "boolean") if (result) item.nodes = item.text == null ? [] : [item.text];
|
|
89
|
+
else item.nodes = void 0;
|
|
90
|
+
else item.nodes = result?.nodes;
|
|
91
|
+
}
|
|
92
|
+
function setReactiveValueForSingle(item, comment, value) {
|
|
93
|
+
const valueIsFragment = isFragment(value);
|
|
94
|
+
item.fragments = valueIsFragment ? [value] : void 0;
|
|
95
|
+
if (valueIsFragment || isChildNode(value)) item.nodes = setNodes(item, comment, createNodes(value));
|
|
96
|
+
else item.nodes = setText(item, comment, value);
|
|
97
|
+
}
|
|
98
|
+
function setText(item, comment, value) {
|
|
79
99
|
const isNullable = isNullableOrWhitespace(value);
|
|
80
|
-
text.textContent = isNullable ? "" : getString(value);
|
|
100
|
+
if (item.text != null) item.text.textContent = isNullable ? "" : getString(value);
|
|
81
101
|
let result = false;
|
|
82
|
-
if (nodes != null) {
|
|
83
|
-
|
|
102
|
+
if (item.nodes != null) {
|
|
103
|
+
replaceText(item, comment, isNullable);
|
|
84
104
|
result = !isNullable;
|
|
85
|
-
} else if (isNullable && comment.parentNode == null) text
|
|
86
|
-
else if (!isNullable && text
|
|
87
|
-
comment.replaceWith(text);
|
|
105
|
+
} else if (isNullable && comment.parentNode == null) item.text?.replaceWith(comment);
|
|
106
|
+
else if (!isNullable && item?.text?.parentNode == null) {
|
|
107
|
+
if (item.text != null) comment.replaceWith(item.text);
|
|
88
108
|
result = true;
|
|
89
109
|
}
|
|
90
|
-
removeFragments(fragments);
|
|
91
|
-
|
|
110
|
+
removeFragments(item.fragments);
|
|
111
|
+
if (result) return item.text == null ? [] : [item.text];
|
|
92
112
|
}
|
|
93
113
|
export { setReactiveValue };
|
package/dist/parse.js
CHANGED
|
@@ -6,16 +6,16 @@ function handleExpression(data, prefix, expression) {
|
|
|
6
6
|
for (let index = 0; index < length; index += 1) expressions += handleExpression(data, "", expression[index]);
|
|
7
7
|
return `${prefix}${expressions}`;
|
|
8
8
|
}
|
|
9
|
-
if (typeof expression === "function" || typeof expression === "object" && expression != null) {
|
|
10
|
-
const index = data.values.push(expression) - 1;
|
|
11
|
-
return `${prefix}<!--abydon.${index}-->`;
|
|
12
|
-
}
|
|
9
|
+
if (typeof expression === "function" || typeof expression === "object" && expression != null) return `${prefix}<!--abydon.${data.values.push(expression) - 1}-->`;
|
|
13
10
|
return isNullableOrWhitespace(expression) ? prefix : `${prefix}${expression}`;
|
|
14
11
|
}
|
|
15
12
|
function parse(data) {
|
|
13
|
+
if (data.template != null) return data.template;
|
|
16
14
|
const { length } = data.strings;
|
|
17
|
-
|
|
18
|
-
for (let index = 0; index < length; index += 1) template += handleExpression(data, data.strings[index], data.expressions[index]);
|
|
19
|
-
|
|
15
|
+
data.template = "";
|
|
16
|
+
for (let index = 0; index < length; index += 1) data.template += handleExpression(data, data.strings[index], data.expressions[index]);
|
|
17
|
+
data.expressions = [];
|
|
18
|
+
data.strings = [];
|
|
19
|
+
return data.template;
|
|
20
20
|
}
|
|
21
21
|
export { parse };
|