rasti 3.0.1 → 4.0.0-alpha.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/README.md +40 -19
- package/dist/rasti.js +1787 -628
- package/dist/rasti.min.js +1 -1
- package/es/Component.js +748 -473
- package/es/Emitter.js +182 -28
- package/es/Model.js +237 -51
- package/es/View.js +73 -31
- package/es/core/Element.js +55 -0
- package/es/core/EventsManager.js +41 -0
- package/es/core/Interpolation.js +70 -0
- package/es/core/InterpolationWrapper.js +14 -0
- package/es/core/Partial.js +12 -0
- package/es/core/PathManager.js +88 -0
- package/es/core/SafeHTML.js +17 -0
- package/es/index.js +13 -0
- package/es/utils/deepFlat.js +4 -2
- package/es/utils/findComment.js +42 -0
- package/es/utils/getAttributesDiff.js +33 -0
- package/es/utils/getAttributesHTML.js +25 -0
- package/es/utils/getResult.js +4 -2
- package/es/utils/parseHTML.js +14 -0
- package/es/utils/syncNode.js +109 -0
- package/es/utils/validateListener.js +14 -0
- package/lib/Component.cjs +749 -474
- package/lib/Emitter.cjs +182 -28
- package/lib/Model.cjs +237 -51
- package/lib/View.cjs +73 -31
- package/lib/core/Element.cjs +57 -0
- package/lib/core/EventsManager.cjs +43 -0
- package/lib/core/Interpolation.cjs +72 -0
- package/lib/core/InterpolationWrapper.cjs +16 -0
- package/lib/core/Partial.cjs +14 -0
- package/lib/core/PathManager.cjs +90 -0
- package/lib/core/SafeHTML.cjs +19 -0
- package/lib/index.cjs +13 -0
- package/lib/utils/deepFlat.cjs +4 -2
- package/lib/utils/findComment.cjs +44 -0
- package/lib/utils/getAttributesDiff.cjs +35 -0
- package/lib/utils/getAttributesHTML.cjs +27 -0
- package/lib/utils/getResult.cjs +4 -2
- package/lib/utils/parseHTML.cjs +16 -0
- package/lib/utils/syncNode.cjs +111 -0
- package/lib/utils/validateListener.cjs +16 -0
- package/package.json +11 -8
- package/src/Component.js +745 -472
- package/src/Emitter.js +182 -28
- package/src/Model.js +236 -51
- package/src/View.js +73 -31
- package/src/core/Element.js +55 -0
- package/src/core/EventsManager.js +41 -0
- package/src/core/Interpolation.js +70 -0
- package/src/core/InterpolationWrapper.js +14 -0
- package/src/core/Partial.js +12 -0
- package/src/core/PathManager.js +88 -0
- package/src/core/SafeHTML.js +17 -0
- package/src/index.js +4 -5
- package/src/utils/deepFlat.js +4 -2
- package/src/utils/findComment.js +40 -0
- package/src/utils/getAttributesDiff.js +31 -0
- package/src/utils/getAttributesHTML.js +23 -0
- package/src/utils/getResult.js +6 -2
- package/src/utils/parseHTML.js +12 -0
- package/src/utils/syncNode.js +107 -0
- package/src/utils/validateListener.js +12 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Properties that should be mirrored from source to target.
|
|
3
|
+
* @type {string[]}
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
const SYNC_PROPS = ['value', 'checked', 'selected'];
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Compares two elements to see if their child nodes are structurally equal.
|
|
10
|
+
* @param {Element} a First element to compare.
|
|
11
|
+
* @param {Element} b Second element to compare.
|
|
12
|
+
* @return {boolean} True if all child nodes are deeply equal.
|
|
13
|
+
* @private
|
|
14
|
+
*/
|
|
15
|
+
const areChildNodesEqual = (a, b) => {
|
|
16
|
+
const aChildren = a.childNodes;
|
|
17
|
+
const bChildren = b.childNodes;
|
|
18
|
+
const aLength = aChildren.length;
|
|
19
|
+
|
|
20
|
+
if (aLength !== bChildren.length) return false;
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < aLength; i++) {
|
|
23
|
+
if (!aChildren[i].isEqualNode(bChildren[i])) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Synchronizes attributes and key DOM properties (value, checked, selected).
|
|
32
|
+
* Assumes tagName is already the same.
|
|
33
|
+
* @param {Element} targetEl Target DOM element to update.
|
|
34
|
+
* @param {Element} sourceEl Source DOM element to copy attributes from.
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
const syncAttributes = (targetEl, sourceEl) => {
|
|
38
|
+
// Add, update and remove attributes.
|
|
39
|
+
const srcAttrs = sourceEl.attributes;
|
|
40
|
+
const tgtAttrs = targetEl.attributes;
|
|
41
|
+
const srcAttrNames = new Set();
|
|
42
|
+
|
|
43
|
+
for (let i = 0, l = srcAttrs.length; i < l; i++) {
|
|
44
|
+
const { name, value } = srcAttrs[i];
|
|
45
|
+
srcAttrNames.add(name);
|
|
46
|
+
if (targetEl.getAttribute(name) !== value) targetEl.setAttribute(name, value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let i = tgtAttrs.length - 1; i >= 0; i--) {
|
|
50
|
+
const { name } = tgtAttrs[i];
|
|
51
|
+
if (!srcAttrNames.has(name)) targetEl.removeAttribute(name);
|
|
52
|
+
}
|
|
53
|
+
// Sync key DOM properties.
|
|
54
|
+
for (let i = 0, l = SYNC_PROPS.length; i < l; i++) {
|
|
55
|
+
const prop = SYNC_PROPS[i];
|
|
56
|
+
if (prop in targetEl && targetEl[prop] !== sourceEl[prop]) {
|
|
57
|
+
targetEl[prop] = sourceEl[prop];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Replaces all child nodes of targetEl with those from sourceEl.
|
|
64
|
+
* Moves the nodes without cloning.
|
|
65
|
+
* @param {Element} targetEl The element whose children will be replaced.
|
|
66
|
+
* @param {Element} sourceEl The element providing new children.
|
|
67
|
+
* @module
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
const syncNodeContent = (targetEl, sourceEl) => {
|
|
71
|
+
const children = Array.from(sourceEl.childNodes);
|
|
72
|
+
targetEl.replaceChildren(...children);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Synchronizes the contents of one DOM node to match another.
|
|
77
|
+
* It performs a shallow sync: tag name, attributes, properties, and child nodes.
|
|
78
|
+
* If tag names or node types differ, it replaces the node entirely.
|
|
79
|
+
* @param {Node} targetNode The node currently in the DOM to be updated.
|
|
80
|
+
* @param {Node} sourceNode The reference node to sync from (not in the DOM).
|
|
81
|
+
* @private
|
|
82
|
+
*/
|
|
83
|
+
function syncNode(targetNode, sourceNode) {
|
|
84
|
+
// Replace if node types are different (e.g. element vs text).
|
|
85
|
+
if (targetNode.nodeType !== sourceNode.nodeType) {
|
|
86
|
+
targetNode.replaceWith(sourceNode);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
// Text node: sync value.
|
|
90
|
+
if (targetNode.nodeType === Node.TEXT_NODE) {
|
|
91
|
+
if (targetNode.nodeValue !== sourceNode.nodeValue) {
|
|
92
|
+
targetNode.nodeValue = sourceNode.nodeValue;
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Element node: check tag.
|
|
97
|
+
if (targetNode.tagName !== sourceNode.tagName) {
|
|
98
|
+
targetNode.replaceWith(sourceNode);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Sync attributes and DOM properties.
|
|
102
|
+
syncAttributes(targetNode, sourceNode);
|
|
103
|
+
// Sync child nodes if necessary.
|
|
104
|
+
if (!areChildNodesEqual(targetNode, sourceNode)) {
|
|
105
|
+
syncNodeContent(targetNode, sourceNode);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { syncNode as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates that the listener is a function.
|
|
3
|
+
* @param {Function} listener The listener to validate.
|
|
4
|
+
* @throws {TypeError} If the listener is not a function.
|
|
5
|
+
* @module
|
|
6
|
+
* @private
|
|
7
|
+
*/
|
|
8
|
+
function validateListener(listener) {
|
|
9
|
+
if (typeof listener !== 'function') {
|
|
10
|
+
throw new TypeError('Listener must be a function');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { validateListener as default };
|