rasti 4.0.0-alpha.4 → 4.0.0-alpha.5
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 +2 -2
- package/dist/rasti.js +137 -121
- package/dist/rasti.min.js +1 -1
- package/es/Component.js +118 -102
- package/es/core/Interpolation.js +19 -7
- package/es/index.js +0 -1
- package/lib/Component.cjs +118 -102
- package/lib/core/Interpolation.cjs +19 -7
- package/lib/index.cjs +0 -1
- package/package.json +2 -1
- package/src/Component.js +118 -102
- package/src/core/Interpolation.js +19 -7
- package/es/core/InterpolationWrapper.js +0 -14
- package/lib/core/InterpolationWrapper.cjs +0 -16
- package/src/core/InterpolationWrapper.js +0 -14
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<picture>
|
|
3
|
-
<source media="(prefers-color-scheme: dark)" srcset="docs/logo-dark.svg">
|
|
4
|
-
<img alt="Rasti.js" src="docs/logo.svg" height="120">
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.0.0-alpha.5/docs/logo-dark.svg">
|
|
4
|
+
<img alt="Rasti.js" src="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.0.0-alpha.5/docs/logo.svg" height="120">
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
package/dist/rasti.js
CHANGED
|
@@ -1088,19 +1088,6 @@
|
|
|
1088
1088
|
}
|
|
1089
1089
|
}
|
|
1090
1090
|
|
|
1091
|
-
/**
|
|
1092
|
-
* Wrapper for interpolation results with markers.
|
|
1093
|
-
* @param {number} interpolationUid The interpolation UID for markers.
|
|
1094
|
-
* @param {any} result The interpolation result.
|
|
1095
|
-
* @private
|
|
1096
|
-
*/
|
|
1097
|
-
class InterpolationWrapper {
|
|
1098
|
-
constructor(interpolationUid, result) {
|
|
1099
|
-
this.interpolationUid = interpolationUid;
|
|
1100
|
-
this.result = result;
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
1091
|
/**
|
|
1105
1092
|
* Manager for delegated events.
|
|
1106
1093
|
* @private
|
|
@@ -1482,6 +1469,7 @@
|
|
|
1482
1469
|
this.expression = options.expression;
|
|
1483
1470
|
this.isComponent = options.isComponent;
|
|
1484
1471
|
this.isElement = options.isElement;
|
|
1472
|
+
this.previousItems = [];
|
|
1485
1473
|
}
|
|
1486
1474
|
|
|
1487
1475
|
/**
|
|
@@ -1503,21 +1491,32 @@
|
|
|
1503
1491
|
* Update the interpolation content with a new fragment.
|
|
1504
1492
|
* Optimizes updates by syncing single non-component elements or replacing content entirely.
|
|
1505
1493
|
* @param {DocumentFragment} fragment The new content fragment to insert.
|
|
1494
|
+
* @param {Element} targetElement The target element to replace with the new fragment.
|
|
1506
1495
|
*/
|
|
1507
|
-
update(fragment) {
|
|
1496
|
+
update(fragment, targetElement) {
|
|
1497
|
+
if (targetElement) {
|
|
1498
|
+
targetElement.replaceWith(fragment.firstChild);
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1508
1502
|
const [startComment, endComment] = this.ref;
|
|
1509
1503
|
|
|
1510
1504
|
const currentFirstElement = startComment.nextSibling;
|
|
1511
|
-
const
|
|
1512
|
-
const
|
|
1505
|
+
const currentEmpty = currentFirstElement === endComment;
|
|
1506
|
+
const currentSingleChildElement = !currentEmpty && currentFirstElement.nextSibling === endComment;
|
|
1513
1507
|
const fragmentChildren = fragment.children;
|
|
1514
1508
|
|
|
1515
|
-
if (
|
|
1516
|
-
// There is a single child element that is not a component's root element. Sync node attributes and content.
|
|
1517
|
-
syncNode(currentFirstElement, fragmentChildren[0]);
|
|
1518
|
-
} else if (currentEmpty) {
|
|
1509
|
+
if (currentEmpty) {
|
|
1519
1510
|
// Interpolation is empty. Insert the fragment.
|
|
1520
1511
|
endComment.parentNode.insertBefore(fragment, endComment);
|
|
1512
|
+
} else if (currentSingleChildElement && fragmentChildren.length === 1) {
|
|
1513
|
+
if (!this.isElement(currentFirstElement)) {
|
|
1514
|
+
// There is a single child element that is not a component's root element. Sync node attributes and content.
|
|
1515
|
+
syncNode(currentFirstElement, fragmentChildren[0]);
|
|
1516
|
+
} else {
|
|
1517
|
+
// There is a single child element that is a component's root element. Replace it with the new child element.
|
|
1518
|
+
currentFirstElement.replaceWith(fragmentChildren[0]);
|
|
1519
|
+
}
|
|
1521
1520
|
} else {
|
|
1522
1521
|
// Interpolation is not empty. Replace the interpolation content.
|
|
1523
1522
|
const range = document.createRange();
|
|
@@ -1634,6 +1633,9 @@
|
|
|
1634
1633
|
*/
|
|
1635
1634
|
const splitPlaceholders = (main, expressions) => {
|
|
1636
1635
|
const PH = Component.PLACEHOLDER('(\\d+)');
|
|
1636
|
+
const matchSinglePlaceholder = main.match(new RegExp(`^${PH}$`));
|
|
1637
|
+
if (matchSinglePlaceholder) return [expressions[parseInt(matchSinglePlaceholder[1], 10)]];
|
|
1638
|
+
|
|
1637
1639
|
const regExp = new RegExp(`${PH}`, 'g');
|
|
1638
1640
|
const out = [];
|
|
1639
1641
|
let lastIndex = 0;
|
|
@@ -1642,7 +1644,7 @@
|
|
|
1642
1644
|
// so all the components are added as children by the parent component.
|
|
1643
1645
|
while ((match = regExp.exec(main)) !== null) {
|
|
1644
1646
|
const before = main.slice(lastIndex, match.index);
|
|
1645
|
-
out.push(Component.markAsSafeHTML(before), expressions[match[1]]);
|
|
1647
|
+
out.push(Component.markAsSafeHTML(before), expressions[parseInt(match[1], 10)]);
|
|
1646
1648
|
lastIndex = match.index + match[0].length;
|
|
1647
1649
|
}
|
|
1648
1650
|
out.push(Component.markAsSafeHTML(main.slice(lastIndex)));
|
|
@@ -1857,6 +1859,7 @@
|
|
|
1857
1859
|
const getSelector = function() {
|
|
1858
1860
|
return `[${Component.ATTRIBUTE_ELEMENT}="${generateElementUid(this.uid)}"]`;
|
|
1859
1861
|
};
|
|
1862
|
+
const elementIndex = elements.length;
|
|
1860
1863
|
// Add element reference to elements array.
|
|
1861
1864
|
elements.push({
|
|
1862
1865
|
getSelector,
|
|
@@ -1864,7 +1867,9 @@
|
|
|
1864
1867
|
});
|
|
1865
1868
|
// Add new expression to expressions array.
|
|
1866
1869
|
expressions.push(function() {
|
|
1867
|
-
const
|
|
1870
|
+
const element = this.template.elements[elementIndex];
|
|
1871
|
+
const attributes = element.getAttributes.call(this);
|
|
1872
|
+
element.previousAttributes = attributes;
|
|
1868
1873
|
return Component.markAsSafeHTML(getAttributesHTML(attributes));
|
|
1869
1874
|
});
|
|
1870
1875
|
// Replace attributes with placeholder.
|
|
@@ -1946,6 +1951,7 @@
|
|
|
1946
1951
|
function getEnd() {
|
|
1947
1952
|
return Component.MARKER_END(`${this.uid}-${currentInterpolationUid}`);
|
|
1948
1953
|
}
|
|
1954
|
+
const interpolationIndex = interpolations.length;
|
|
1949
1955
|
// Add interpolation reference to interpolations array.
|
|
1950
1956
|
interpolations.push({
|
|
1951
1957
|
getStart,
|
|
@@ -1954,9 +1960,7 @@
|
|
|
1954
1960
|
});
|
|
1955
1961
|
// Add new expression to expressions array.
|
|
1956
1962
|
expressions.push(function() {
|
|
1957
|
-
|
|
1958
|
-
const uid = `${this.uid}-${currentInterpolationUid}`;
|
|
1959
|
-
return new InterpolationWrapper(uid, result);
|
|
1963
|
+
return this.template.interpolations[interpolationIndex];
|
|
1960
1964
|
});
|
|
1961
1965
|
// Replace with new placeholder.
|
|
1962
1966
|
return Component.PLACEHOLDER(expressions.length - 1);
|
|
@@ -1997,7 +2001,7 @@
|
|
|
1997
2001
|
/*
|
|
1998
2002
|
* These option keys will be extended on the component instance.
|
|
1999
2003
|
*/
|
|
2000
|
-
const componentOptions = ['key', 'state', 'onCreate', 'onChange', 'onHydrate', '
|
|
2004
|
+
const componentOptions = ['key', 'state', 'onCreate', 'onChange', 'onHydrate', 'onRecycle', 'onUpdate'];
|
|
2001
2005
|
|
|
2002
2006
|
/**
|
|
2003
2007
|
* @lends module:Component
|
|
@@ -2130,8 +2134,7 @@
|
|
|
2130
2134
|
});
|
|
2131
2135
|
|
|
2132
2136
|
if (this.isContainer()) {
|
|
2133
|
-
//
|
|
2134
|
-
this.template.interpolations[0].hydrate(parent);
|
|
2137
|
+
// Don't hydrate interpolation markers for container components as we know they will have only one child.
|
|
2135
2138
|
// Call hydrate on children.
|
|
2136
2139
|
this.children[0].hydrate(parent);
|
|
2137
2140
|
// Set the first element as the component's element.
|
|
@@ -2165,14 +2168,21 @@
|
|
|
2165
2168
|
* Reuse a `Component` by replacing the placeholder comment with the real nodes.
|
|
2166
2169
|
* Call `onRecycle` lifecycle method.
|
|
2167
2170
|
* @param parent {node} The parent node.
|
|
2171
|
+
* @param props {object} The props to set on the recycled component.
|
|
2168
2172
|
* @return {Component} The component instance.
|
|
2169
2173
|
* @private
|
|
2170
2174
|
*/
|
|
2171
|
-
recycle(parent) {
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2175
|
+
recycle(parent, props) {
|
|
2176
|
+
if (parent) {
|
|
2177
|
+
// Locate the placeholder comment and replace it with the real nodes
|
|
2178
|
+
const toBeReplaced = findComment(parent, Component.MARKER_RECYCLED(this.uid), isComponent);
|
|
2179
|
+
// Replace it with this.el.
|
|
2180
|
+
toBeReplaced.replaceWith(this.el);
|
|
2181
|
+
}
|
|
2182
|
+
// Update props.
|
|
2183
|
+
if (props) {
|
|
2184
|
+
this.props.set(props);
|
|
2185
|
+
}
|
|
2176
2186
|
// Call `onRecycle` lifecycle method.
|
|
2177
2187
|
this.onRecycle.call(this);
|
|
2178
2188
|
// Return `this` for chaining.
|
|
@@ -2189,35 +2199,6 @@
|
|
|
2189
2199
|
return `<!--${Component.MARKER_RECYCLED(this.uid)}-->`;
|
|
2190
2200
|
}
|
|
2191
2201
|
|
|
2192
|
-
/**
|
|
2193
|
-
* Get the component nodes to be inserted into the DOM.
|
|
2194
|
-
* Used internally during the render process, you usually don't need to call it if you use
|
|
2195
|
-
* `mount()`.
|
|
2196
|
-
* For components that render HTML elements you can safely rely on `this.el`.
|
|
2197
|
-
* For container components that render another component you need the wrapper nodes to insert
|
|
2198
|
-
* them into the DOM; use `getNodes()` for that.
|
|
2199
|
-
* @return {Node[]} The component nodes.
|
|
2200
|
-
*/
|
|
2201
|
-
getNodes() {
|
|
2202
|
-
return this.isContainer() ?
|
|
2203
|
-
[this.template.interpolations[0].ref[0], ...this.children[0].getNodes(), this.template.interpolations[0].ref[1]] :
|
|
2204
|
-
[this.el];
|
|
2205
|
-
}
|
|
2206
|
-
|
|
2207
|
-
/**
|
|
2208
|
-
* Call onMount lifecycle method on children and self.
|
|
2209
|
-
* Used internally during the mount and render process.
|
|
2210
|
-
* @private
|
|
2211
|
-
*/
|
|
2212
|
-
callOnMount() {
|
|
2213
|
-
// Call onMount on children first.
|
|
2214
|
-
this.children.forEach(child => child.callOnMount());
|
|
2215
|
-
// Call onMount on self.
|
|
2216
|
-
this.onMount.call(this);
|
|
2217
|
-
// Return `this` for chaining.
|
|
2218
|
-
return this;
|
|
2219
|
-
}
|
|
2220
|
-
|
|
2221
2202
|
/**
|
|
2222
2203
|
* Tagged template helper method.
|
|
2223
2204
|
* Used to create a partial template.
|
|
@@ -2255,7 +2236,10 @@
|
|
|
2255
2236
|
const items = splitPlaceholders(
|
|
2256
2237
|
parsePartialElements(
|
|
2257
2238
|
expandComponents(
|
|
2258
|
-
addPlaceholders(
|
|
2239
|
+
addPlaceholders(
|
|
2240
|
+
strings,
|
|
2241
|
+
expressions
|
|
2242
|
+
).trim(),
|
|
2259
2243
|
expressions
|
|
2260
2244
|
),
|
|
2261
2245
|
expressions
|
|
@@ -2270,42 +2254,58 @@
|
|
|
2270
2254
|
* Render a template part.
|
|
2271
2255
|
* @param {any} part - The template part.
|
|
2272
2256
|
* @param {function} addChild - The addChild function.
|
|
2257
|
+
* @param {Array} items - The items array.
|
|
2273
2258
|
* @return {string} The rendered template part.
|
|
2274
2259
|
* @private
|
|
2275
2260
|
*/
|
|
2276
|
-
renderTemplatePart(part, addChild) {
|
|
2261
|
+
renderTemplatePart(part, addChild, items = []) {
|
|
2277
2262
|
const result = getExpressionResult(part, this);
|
|
2278
2263
|
|
|
2279
2264
|
const parse = item => {
|
|
2280
|
-
if (typeof item
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
if (item instanceof Partial) {
|
|
2285
|
-
this.pathManager.push();
|
|
2286
|
-
const out = item.items.map(subItem => { this.pathManager.increment(); return parse(subItem); }).join('');
|
|
2287
|
-
this.pathManager.pop();
|
|
2288
|
-
return out;
|
|
2289
|
-
}
|
|
2290
|
-
// Handle arrays (user loops) - disable tracking.
|
|
2291
|
-
if (Array.isArray(item)) {
|
|
2292
|
-
this.pathManager.pause();
|
|
2293
|
-
const out = deepFlat(item).map(parse).join('');
|
|
2294
|
-
this.pathManager.resume();
|
|
2295
|
-
return out;
|
|
2296
|
-
}
|
|
2297
|
-
// InterpolationWrapper: add markers and process maintaining tracking.
|
|
2298
|
-
if (item instanceof InterpolationWrapper) {
|
|
2299
|
-
this.pathManager.increment();
|
|
2300
|
-
const startMarker = `<!--${Component.MARKER_START(item.interpolationUid)}-->`;
|
|
2301
|
-
const endMarker = `<!--${Component.MARKER_END(item.interpolationUid)}-->`;
|
|
2302
|
-
return `${startMarker}${parse(item.result)}${endMarker}`;
|
|
2303
|
-
}
|
|
2265
|
+
if (typeof item === 'undefined' || item === null || item === false || item === true) {
|
|
2266
|
+
return '';
|
|
2267
|
+
}
|
|
2304
2268
|
|
|
2305
|
-
|
|
2269
|
+
if (item instanceof SafeHTML) {
|
|
2270
|
+
items.push(item);
|
|
2271
|
+
return item;
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
if (item instanceof Component) {
|
|
2275
|
+
items.push(item);
|
|
2276
|
+
return addChild(item);
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
if (item instanceof Partial) {
|
|
2280
|
+
// Single item.
|
|
2281
|
+
if (item.items.length === 1) return parse(item.items[0]);
|
|
2282
|
+
// Several items.
|
|
2283
|
+
this.pathManager.push();
|
|
2284
|
+
const out = item.items.map(subItem => { this.pathManager.increment(); return parse(subItem); }).join('');
|
|
2285
|
+
this.pathManager.pop();
|
|
2286
|
+
return out;
|
|
2287
|
+
}
|
|
2288
|
+
// Handle arrays (user loops) - disable tracking.
|
|
2289
|
+
if (Array.isArray(item)) {
|
|
2290
|
+
this.pathManager.pause();
|
|
2291
|
+
const out = deepFlat(item).map(parse).join('');
|
|
2292
|
+
this.pathManager.resume();
|
|
2293
|
+
return out;
|
|
2306
2294
|
}
|
|
2307
|
-
//
|
|
2308
|
-
|
|
2295
|
+
// Interpolation: add markers and process maintaining tracking.
|
|
2296
|
+
if (item instanceof Interpolation) {
|
|
2297
|
+
this.pathManager.increment();
|
|
2298
|
+
// Add Interpolation markers.
|
|
2299
|
+
const startMarker = this.isContainer() ? '' : `<!--${item.getStart()}-->`;
|
|
2300
|
+
const endMarker = this.isContainer() ? '' : `<!--${item.getEnd()}-->`;
|
|
2301
|
+
const interpolationResult = parse(getExpressionResult(item.expression, this));
|
|
2302
|
+
item.previousItems = items;
|
|
2303
|
+
return `${startMarker}${interpolationResult}${endMarker}`;
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
const sanitized = Component.sanitize(item);
|
|
2307
|
+
items.push(sanitized);
|
|
2308
|
+
return sanitized;
|
|
2309
2309
|
};
|
|
2310
2310
|
|
|
2311
2311
|
return `${parse(result)}`;
|
|
@@ -2343,7 +2343,6 @@
|
|
|
2343
2343
|
* - Components with a `key` are recycled if a previous child with the same key exists.
|
|
2344
2344
|
* - Unkeyed components are recycled if they have the same type and position in the template or partial.
|
|
2345
2345
|
* A recycled `Component` will call the `onRecycle` lifecycle method.
|
|
2346
|
-
* - All child components will have their `onMount` lifecycle method called after they are added to the DOM. New children will be hydrated first (calling their `onHydrate` lifecycle method).
|
|
2347
2346
|
* - If the active element is inside the component, it will retain focus after the render.
|
|
2348
2347
|
* @return {Component} The component instance.
|
|
2349
2348
|
*/
|
|
@@ -2402,23 +2401,35 @@
|
|
|
2402
2401
|
// Return the component or placeholder.
|
|
2403
2402
|
return out;
|
|
2404
2403
|
};
|
|
2405
|
-
|
|
2406
|
-
const
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2404
|
+
// Render the interpolation content and get the items.
|
|
2405
|
+
const previousItems = interpolation.previousItems;
|
|
2406
|
+
const items = [];
|
|
2407
|
+
const rendered = this.renderTemplatePart(interpolation.expression, addChild, items);
|
|
2408
|
+
interpolation.previousItems = items;
|
|
2409
|
+
|
|
2410
|
+
const recycle = ([recycled, discarded], fragment) => {
|
|
2411
|
+
// Add child, update props and recycle (move to new position if needed).
|
|
2412
|
+
this.addChild(recycled).recycle(fragment, discarded.props.toJSON());
|
|
2412
2413
|
// Destroy discarded component.
|
|
2413
2414
|
discarded.destroy();
|
|
2414
|
-
}
|
|
2415
|
-
//
|
|
2415
|
+
};
|
|
2416
|
+
// Same single component in the same position. Don't move it.
|
|
2417
|
+
if (previousItems.length === 1 && previousItems[0] instanceof Component &&
|
|
2418
|
+
items.length === 1 && items[0] instanceof Component &&
|
|
2419
|
+
recycledChildren.length === 1) {
|
|
2420
|
+
recycle(recycledChildren[0], null);
|
|
2421
|
+
return;
|
|
2422
|
+
}
|
|
2423
|
+
// Parse the rendered content and get the fragment.
|
|
2424
|
+
const fragment = parseHTML(rendered);
|
|
2425
|
+
// Add recycled components to children and move them to the new template in the fragment.
|
|
2426
|
+
recycledChildren.forEach(recycled => recycle(recycled, fragment));
|
|
2427
|
+
// Add new children. Hydrate them and update the interpolation.
|
|
2416
2428
|
nextChildren.forEach(child => this.addChild(child).hydrate(fragment));
|
|
2417
|
-
|
|
2418
|
-
|
|
2429
|
+
// Update the interpolation.
|
|
2430
|
+
const targetElement = this.isContainer() ? this.el : null;
|
|
2431
|
+
interpolation.update(fragment, targetElement);
|
|
2419
2432
|
});
|
|
2420
|
-
// Call onMount lifecycle method on all children after interpolations update.
|
|
2421
|
-
this.children.forEach(child => child.callOnMount());
|
|
2422
2433
|
// Destroy unused children.
|
|
2423
2434
|
previousChildren.forEach(prev => {
|
|
2424
2435
|
if (this.children.indexOf(prev) < 0) prev.destroy();
|
|
@@ -2443,8 +2454,11 @@
|
|
|
2443
2454
|
}
|
|
2444
2455
|
|
|
2445
2456
|
/**
|
|
2446
|
-
* Lifecycle method. Called when the
|
|
2447
|
-
*
|
|
2457
|
+
* Lifecycle method. Called when the component is created, at the end of the constructor.
|
|
2458
|
+
* This method receives the same arguments passed to the constructor (options and any additional parameters).
|
|
2459
|
+
* It executes both on client and server.
|
|
2460
|
+
* Use this method to define models or state that will be used later in `onHydrate`.
|
|
2461
|
+
* @param {...*} args The constructor arguments (options and any additional parameters).
|
|
2448
2462
|
*/
|
|
2449
2463
|
onCreate() {}
|
|
2450
2464
|
|
|
@@ -2463,31 +2477,35 @@
|
|
|
2463
2477
|
}
|
|
2464
2478
|
|
|
2465
2479
|
/**
|
|
2466
|
-
* Lifecycle method. Called when the component is rendered for the first time and hydrated.
|
|
2480
|
+
* Lifecycle method. Called when the component is rendered for the first time and hydrated in a DocumentFragment.
|
|
2481
|
+
* This method only executes on the client and only during the first render.
|
|
2482
|
+
* Use this method for client-only operations like making API requests or setting up browser-specific functionality.
|
|
2467
2483
|
*/
|
|
2468
2484
|
onHydrate() {}
|
|
2469
2485
|
|
|
2470
2486
|
/**
|
|
2471
|
-
* Lifecycle method. Called when the component is
|
|
2472
|
-
*
|
|
2473
|
-
*
|
|
2474
|
-
*
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
* Lifecycle method. Called when the component is recycled (reused with the same key) and added to the DOM again.
|
|
2487
|
+
* Lifecycle method. Called when the component is recycled and reused between renders.
|
|
2488
|
+
*
|
|
2489
|
+
* A component is recycled when:
|
|
2490
|
+
* - It has a `key` and a previous child with the same key exists
|
|
2491
|
+
* - It doesn't have a `key` but has the same type and position in the template or partial
|
|
2492
|
+
*
|
|
2493
|
+
* During recycling, the component instance is reused and its props are updated with new values.
|
|
2494
|
+
* The component's element may be moved in the DOM if the new template structure differs from the previous one.
|
|
2480
2495
|
*/
|
|
2481
2496
|
onRecycle() {}
|
|
2482
2497
|
|
|
2483
2498
|
/**
|
|
2484
2499
|
* Lifecycle method. Called when the component is updated or re-rendered.
|
|
2500
|
+
* This method is called when the component's state, model, or props change and trigger a re-render.
|
|
2501
|
+
* Use this method to perform operations that need to happen on every update.
|
|
2485
2502
|
*/
|
|
2486
2503
|
onUpdate() {}
|
|
2487
2504
|
|
|
2488
2505
|
/**
|
|
2489
2506
|
* Lifecycle method. Called when the component is destroyed.
|
|
2490
|
-
*
|
|
2507
|
+
* Use this method to clean up resources, cancel timers, remove event listeners, etc.
|
|
2508
|
+
* @param {...*} args Options object or any arguments passed to `destroy` method.
|
|
2491
2509
|
*/
|
|
2492
2510
|
onDestroy() {}
|
|
2493
2511
|
|
|
@@ -2547,10 +2565,8 @@
|
|
|
2547
2565
|
component.hydrate(el);
|
|
2548
2566
|
} else {
|
|
2549
2567
|
// Append element to the DOM.
|
|
2550
|
-
el.append(
|
|
2568
|
+
el.append(component.render().el);
|
|
2551
2569
|
}
|
|
2552
|
-
// Call onMount lifecycle method after nodes are in the DOM.
|
|
2553
|
-
component.callOnMount();
|
|
2554
2570
|
}
|
|
2555
2571
|
// Return component instance.
|
|
2556
2572
|
return component;
|
package/dist/rasti.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Rasti={})}(this,(function(t){"use strict";function e(t){if("function"!=typeof t)throw new TypeError("Listener must be a function")}class s{on(t,s){return e(s),this.listeners||(this.listeners={}),this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(s),()=>this.off(t,s)}once(t,s){e(s);const i=(...e)=>{s(...e),this.off(t,i)};return this.on(t,i)}off(t,e){this.listeners&&(t?this.listeners[t]&&(e?(this.listeners[t]=this.listeners[t].filter((t=>t!==e)),this.listeners[t].length||delete this.listeners[t]):delete this.listeners[t],Object.keys(this.listeners).length||delete this.listeners):delete this.listeners)}emit(t,...e){this.listeners&&this.listeners[t]&&this.listeners[t].slice().forEach((t=>t(...e)))}listenTo(t,e,s){return t.on(e,s),this.listeningTo||(this.listeningTo=[]),this.listeningTo.push({emitter:t,type:e,listener:s}),()=>this.stopListening(t,e,s)}listenToOnce(t,s,i){e(i);const n=(...e)=>{i(...e),this.stopListening(t,s,n)};return this.listenTo(t,s,n)}stopListening(t,e,s){this.listeningTo&&(this.listeningTo=this.listeningTo.filter((i=>!(!t||t===i.emitter&&!e||t===i.emitter&&e===i.type&&!s||t===i.emitter&&e===i.type&&s===i.listener)||(i.emitter.off(i.type,i.listener),!1))),this.listeningTo.length||delete this.listeningTo)}}const i=(t,e,...s)=>"function"!=typeof t?t:t.apply(e,s);class n extends s{constructor(){super(),this.preinitialize.apply(this,arguments),this.attributes=Object.assign({},i(this.defaults,this),this.parse.apply(this,arguments)),this.previous={},Object.keys(this.attributes).forEach(this.defineAttribute.bind(this))}preinitialize(){}defineAttribute(t){Object.defineProperty(this,`${this.constructor.attributePrefix}${t}`,{get:()=>this.get(t),set:e=>{this.set(t,e)}})}get(t){return this.attributes[t]}set(t,e,...s){let i,n;"object"==typeof t?(i=t,n=[e,...s]):(i={[t]:e},n=s);const r=this._changing;this._changing=!0;const h={};r||(this.previous=Object.assign({},this.attributes)),Object.keys(i).forEach((t=>{i[t]!==this.attributes[t]&&(h[t]=i[t],this.attributes[t]=i[t])}));const o=Object.keys(h);if(o.length&&(this._pending=["change",this,h,...n]),o.forEach((t=>{this.emit(`change:${t}`,this,i[t],...n)})),r)return this;for(;this._pending;){const t=this._pending;this._pending=null,this.emit.apply(this,t)}return this._pending=null,this._changing=!1,this}parse(t){return t}toJSON(){return Object.assign({},this.attributes)}}n.attributePrefix="";const r=["el","tag","attributes","events","model","template","onDestroy"];class h extends s{constructor(t={}){super(),this.preinitialize.apply(this,arguments),this.delegatedEventListeners=[],this.children=[],this.destroyQueue=[],this.viewOptions=[],r.forEach((e=>{e in t&&(this[e]=t[e],this.viewOptions.push(e))})),this.ensureUid(),this.ensureElement()}preinitialize(){}$(t){return this.el.querySelector(t)}$$(t){return this.el.querySelectorAll(t)}destroy(){return this.destroyChildren(),this.undelegateEvents(),this.stopListening(),this.off(),this.destroyQueue.forEach((t=>t())),this.destroyQueue=[],this.onDestroy.apply(this,arguments),this.destroyed=!0,this}onDestroy(){}addChild(t){return this.children.push(t),t}destroyChildren(){this.children.forEach((t=>t.destroy())),this.children=[]}ensureUid(){this.uid||(this.uid="r-"+ ++h.uid)}ensureElement(){if(this.el)this.el=i(this.el,this);else{const t=i(this.tag,this),e=i(this.attributes,this);this.el=this.createElement(t,e)}this.delegateEvents()}createElement(t="div",e={}){let s=document.createElement(t);return Object.keys(e).forEach((t=>s.setAttribute(t,e[t]))),s}removeElement(){return this.el.parentNode.removeChild(this.el),this}delegateEvents(t){if(t||(t=i(this.events,this)),!t)return this;this.delegatedEventListeners.length&&this.undelegateEvents();let s={};return Object.keys(t).forEach((i=>{const n=i.split(" "),r=n.shift(),h=n.join(" ");let o=t[i];"string"==typeof o&&(o=this[o]),e(o),s[r]||(s[r]=[]),s[r].push({selector:h,listener:o})})),Object.keys(s).forEach((t=>{const e=e=>{s[t].forEach((({selector:t,listener:s})=>{if(!t)return void s.call(this,e,this,this.el);let i=e.target;for(;i&&i!==this.el;)i.matches&&i.matches(t)&&s.call(this,e,this,i),i=i.parentElement}))};this.delegatedEventListeners.push({type:t,listener:e}),this.el.addEventListener(t,e)})),this}undelegateEvents(){return this.delegatedEventListeners.forEach((({type:t,listener:e})=>{this.el.removeEventListener(t,e)})),this.delegatedEventListeners=[],this}render(){return this.template&&(this.el.innerHTML=this.template(this.model)),this}static sanitize(t){return`${t}`.replace(/[&<>"']/g,(t=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[t])))}}h.uid=0;class o{constructor(t){this.value=t}toString(){return this.value}}class a{constructor(t){this.items=t}}class l{constructor(t,e){this.interpolationUid=t,this.result=e}}class c{constructor(){this.listeners=[],this.types=new Set,this.previousSize=0}addListener(t,e){return this.types.add(e),this.listeners.push(t),this.listeners.length-1}reset(){this.listeners=[],this.previousSize=this.types.size}hasPendingTypes(){return this.types.size>this.previousSize}}class u{constructor(){}reset(){this.paused=0,this.previous=this.tracked||new Map,this.tracked=new Map,this.positionStack=[0]}push(){this.positionStack.push(0)}pop(){this.positionStack.pop()}increment(){this.positionStack[this.positionStack.length-1]++}pause(){this.paused++}resume(){this.paused--}getPath(){return this.positionStack.join("-")}track(t){return 0===this.paused&&this.tracked.set(this.getPath(),t),t}findRecyclable(t){const e=this.previous.get(this.getPath());return e&&e.constructor===t&&!e.key?e:null}}const d=["value","checked","selected"];class p{constructor(t){this.getSelector=t.getSelector,this.getAttributes=t.getAttributes,this.previousAttributes={}}hydrate(t){this.ref=t.querySelector(this.getSelector())}update(){const t=this.getAttributes(),{remove:e,add:s}=function(t,e={}){const s={},i=[];return Object.keys(t).forEach((i=>{let n=t[i];n!==e[i]&&(!0===n?s[i]="":!1!==n&&(null==n&&(n=""),s[i]=n))})),Object.keys(e).forEach((s=>{(!(s in t)||e[s]!==t[s]&&!1===t[s])&&i.push(s)})),{add:s,remove:i}}(t,this.previousAttributes);this.previousAttributes=t,e.forEach((t=>{this.ref.removeAttribute(t),d.includes(t)&&t in this.ref&&(this.ref[t]="value"===t&&"")})),Object.keys(s).forEach((t=>{const e=s[t];this.ref.setAttribute(t,e),d.includes(t)&&t in this.ref&&(this.ref[t]="value"===t?e:!1!==e&&"false"!==e)}))}}const f=["value","checked","selected"];function E(t,e){t.nodeType===e.nodeType?t.nodeType!==Node.TEXT_NODE?t.tagName===e.tagName?(((t,e)=>{const s=e.attributes,i=t.attributes,n=new Set;for(let e=0,i=s.length;e<i;e++){const{name:i,value:r}=s[e];n.add(i),t.getAttribute(i)!==r&&t.setAttribute(i,r)}for(let e=i.length-1;e>=0;e--){const{name:s}=i[e];n.has(s)||t.removeAttribute(s)}for(let s=0,i=f.length;s<i;s++){const i=f[s];i in t&&t[i]!==e[i]&&(t[i]=e[i])}})(t,e),((t,e)=>{const s=t.childNodes,i=e.childNodes,n=s.length;if(n!==i.length)return!1;for(let t=0;t<n;t++)if(!s[t].isEqualNode(i[t]))return!1;return!0})(t,e)||((t,e)=>{const s=Array.from(e.childNodes);t.replaceChildren(...s)})(t,e)):t.replaceWith(e):t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue):t.replaceWith(e)}function g(t,e,s=(()=>!1),i){let n=i||t.firstChild;for(;n;){if(n.nodeType===Node.COMMENT_NODE&&n.data.trim()===e)return n;if(n.nodeType!==Node.ELEMENT_NODE||s(n)||!n.firstChild){for(;n&&!n.nextSibling;)if(n=n.parentNode,!n||n===t)return null;n&&(n=n.nextSibling)}else n=n.firstChild}return null}class m{constructor(t){this.getStart=t.getStart,this.getEnd=t.getEnd,this.expression=t.expression,this.isComponent=t.isComponent,this.isElement=t.isElement}hydrate(t){const e=g(t,this.getStart(),this.isComponent),s=g(t,this.getEnd(),this.isComponent,e);this.ref=[e,s]}update(t){const[e,s]=this.ref,i=e.nextSibling,n=i.nextSibling===s,r=i==s,h=t.children;if(n&&1===h.length&&!this.isElement(i))E(i,h[0]);else if(r)s.parentNode.insertBefore(t,s);else{const i=document.createRange();i.setStartAfter(e),i.setEndBefore(s),i.deleteContents(),i.insertNode(t)}}}const y=t=>t.reduce(((t,e)=>(Array.isArray(e)?t.push(...y(e)):t.push(e),t)),[]);function T(t){const e=document.createElement("template");return e.innerHTML=`${t}`.trim(),e.content}function b(t){const e=[];return Object.keys(t).forEach((s=>{let i=t[s];!0===i?e.push(s):!1!==i&&(null==i&&(i=""),e.push(`${s}="${i}"`))})),e.join(" ")}const A=(t,e)=>i(t,e,e),v=t=>!!(t&&t.dataset&&t.dataset[j.DATASET_ELEMENT]&&t.dataset[j.DATASET_ELEMENT].endsWith("-1")),R=t=>!!(t&&t.dataset&&t.dataset[j.DATASET_ELEMENT]),M=(t,e)=>t.reduce(((t,s,i)=>(t.push(s),void 0!==e[i]&&t.push(j.PLACEHOLDER(i)),t)),[]).join(""),L=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)"),i=new RegExp(`${s}`,"g"),n=[];let r,h=0;for(;null!==(r=i.exec(t));){const s=t.slice(h,r.index);n.push(j.markAsSafeHTML(s),e[r[1]]),h=r.index+r[0].length}return n.push(j.markAsSafeHTML(t.slice(h))),n},$=(t,e)=>t.reduce(((t,s)=>{const i=e(s[0]);if(1===s.length)"object"==typeof i?t=Object.assign(t,i):"string"==typeof i&&(t[i]=!0);else{const n=s[2]?e(s[1]):s[1];t[i]=n}return t}),{}),C=(t,e,s)=>{const i={};return Object.keys(t).forEach((n=>{const r=n.match(/on(([A-Z]{1}[a-z]+)+)/);if(r&&r[1]){const h=r[1].toLowerCase(),o=t[n];if(o){const t=e.addListener(o,h);i[s(h)]=t}}else i[n]=t[n]})),i},S=(t,e,s=!1)=>{const i=j.PLACEHOLDER("(\\d+)"),n=new Map;return s||(t=t.replace(new RegExp(i,"g"),((t,s)=>{const i=e[s];if(i&&i.prototype instanceof j){if(n.has(i))return n.get(i);n.set(i,t)}return t}))),t.replace(new RegExp(`<(${i})([^>]*)>([\\s\\S]*?)</\\1>|<(${i})([^>]*)/>`,"g"),((t,s,i,n,r,h,o,l)=>{let c,u,d;if(s?(c=e[i],u=n):(c=void 0!==o?e[o]:h,u=l),!(c.prototype instanceof j))return t;if(s){const t=S(r,e,!0),s=k(t,e);d=L(s,e)}const p=w(u,e);return e.push((function(){const t=$(p,(t=>A(t,this)));return d&&(t.renderChildren=()=>new a(d.map((t=>A(t,this))))),c.mount(t)})),j.PLACEHOLDER(e.length-1)}))},O=(t,e)=>{const s=j.PLACEHOLDER("(?:\\d+)");return t.replace(new RegExp(`<(${s}|[a-z]+[1-6]?)(?:\\s*)((?:"[^"]*"|'[^']*'|[^>])*)(/?>)`,"gi"),e)},x=(t,e,s)=>{const n=j.PLACEHOLDER("(?:\\d+)");if(t.match(new RegExp(`^\\s*${n}\\s*$`)))return t;if(!t.match(new RegExp(`^\\s*<([a-z]+[1-6]?|${n})([^>]*)>([\\s\\S]*?)</(\\1|${n})>\\s*$|^\\s*<([a-z]+[1-6]?|${n})([^>]*)/>\\s*$`)))throw new SyntaxError(`Template must have a single root element or be a container component: "${t.trim()}"`);let r=0;return O(t,((t,h,o,a)=>{const l=0===r,c=++r;if(!l&&!o.match(new RegExp(n)))return t;const u=w(o,e),d=t=>`${t}-${c}`,p=function(){const t=C($(u,(t=>A(t,this))),this.eventsManager,(t=>j.ATTRIBUTE_EVENT(t,this.uid)));return l&&this.attributes&&Object.assign(t,i(this.attributes,this)),t[j.ATTRIBUTE_ELEMENT]=d(this.uid),t};s.push({getSelector:function(){return`[${j.ATTRIBUTE_ELEMENT}="${d(this.uid)}"]`},getAttributes:p}),e.push((function(){const t=p.call(this);return j.markAsSafeHTML(b(t))}));return`<${h} ${j.PLACEHOLDER(e.length-1)}${a}`}))},k=(t,e)=>{const s=j.PLACEHOLDER("(?:\\d+)");return O(t,((t,i,n,r)=>{if(!n.match(new RegExp(s)))return t;const h=w(n,e),o=function(){return C($(h,(t=>A(t,this))),this.eventsManager,(t=>j.ATTRIBUTE_EVENT(t,this.uid)))};e.push((function(){const t=o.call(this);return j.markAsSafeHTML(b(t))}));return`<${i} ${j.PLACEHOLDER(e.length-1)}${r}`}))},N=(t,e,s)=>{const i=j.PLACEHOLDER("(\\d+)");let n=0;return t.replace(new RegExp(i,"g"),(function(i,r,h){const o=t.substring(0,h);if(o.lastIndexOf("<")>o.lastIndexOf(">"))return i;const a=++n;return s.push({getStart:function(){return j.MARKER_START(`${this.uid}-${a}`)},getEnd:function(){return j.MARKER_END(`${this.uid}-${a}`)},expression:e[r]}),e.push((function(){const t=A(e[r],this),s=`${this.uid}-${a}`;return new l(s,t)})),j.PLACEHOLDER(e.length-1)}))},w=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)"),i=[],n=new RegExp(`(${s}|[\\w-]+)(?:=(["']?)(?:${s}|((?:.?(?!["']?\\s+(?:\\S+)=|\\s*/?[>"']))+.))\\3)?`,"g");let r;for(;null!==(r=n.exec(t));){const[,t,s,n,h,o]=r,a=void 0!==s?e[parseInt(s,10)]:t,l=void 0!==h?e[parseInt(h,10)]:o;void 0!==l?i.push([a,l,!!n]):i.push([a])}return i},_=["key","state","onCreate","onChange","onHydrate","onMount","onRecycle","onUpdate"];class j extends h{constructor(t={}){super(...arguments),this.componentOptions=[],_.forEach((e=>{e in t&&(this[e]=t[e],this.componentOptions.push(e))}));const e={};Object.keys(t).forEach((s=>{this.viewOptions.includes(s)||this.componentOptions.includes(s)||(e[s]=t[s])})),this.props=new n(e),this.options=t,this.partial=this.partial.bind(this),this.onChange=this.onChange.bind(this),this.onCreate.apply(this,arguments)}events(){const t={};return this.eventsManager.types.forEach((s=>{const i=j.ATTRIBUTE_EVENT(s,this.uid),n=function(t,s,n){const r=n.getAttribute(i);if(r){let i=this.eventsManager.listeners[parseInt(r,10)];"string"==typeof i&&(i=this[i]),e(i),i.call(this,t,s,n)}};t[`${s} [${i}]`]=n,t[s]=n})),t}ensureElement(){this.eventsManager=new c,this.pathManager=new u,this.template=i(this.template,this),this.el&&(this.el=i(this.el,this),this.toString(),this.hydrate(this.el.parentNode))}isContainer(){return 0===this.template.elements.length&&1===this.template.interpolations.length}subscribe(t,e="change",s=this.onChange){return t.on&&this.listenTo(t,e,s),this}hydrate(t){return["model","state","props"].forEach((t=>{this[t]&&this.subscribe(this[t])})),this.isContainer()?(this.template.interpolations[0].hydrate(t),this.children[0].hydrate(t),this.el=this.children[0].el):(this.template.elements.forEach(((e,s)=>{0===s?(e.hydrate(t),this.el?e.ref=this.el:this.el=e.ref):e.hydrate(this.el)})),this.delegateEvents(),this.template.interpolations.forEach((t=>t.hydrate(this.el))),this.children.forEach((t=>t.hydrate(this.el)))),this.onHydrate.call(this),this}recycle(t){return g(t,j.MARKER_RECYCLED(this.uid),v).replaceWith(...this.getNodes()),this.onRecycle.call(this),this}getRecycledMarker(){return`\x3c!--${j.MARKER_RECYCLED(this.uid)}--\x3e`}getNodes(){return this.isContainer()?[this.template.interpolations[0].ref[0],...this.children[0].getNodes(),this.template.interpolations[0].ref[1]]:[this.el]}callOnMount(){return this.children.forEach((t=>t.callOnMount())),this.onMount.call(this),this}partial(t,...e){const s=L(k(S(M(t,e),e),e),e).map((t=>A(t,this)));return new a(s)}renderTemplatePart(t,e){const s=A(t,this),i=t=>{if(null!=t&&!1!==t&&!0!==t){if(t instanceof o)return t;if(t instanceof j)return e(t);if(t instanceof a){this.pathManager.push();const e=t.items.map((t=>(this.pathManager.increment(),i(t)))).join("");return this.pathManager.pop(),e}if(Array.isArray(t)){this.pathManager.pause();const e=y(t).map(i).join("");return this.pathManager.resume(),e}if(t instanceof l){this.pathManager.increment();const e=`\x3c!--${j.MARKER_START(t.interpolationUid)}--\x3e`,s=`\x3c!--${j.MARKER_END(t.interpolationUid)}--\x3e`;return`${e}${i(t.result)}${s}`}return j.sanitize(t)}return""};return`${i(s)}`}toString(){this.destroyChildren(),this.eventsManager.reset(),this.pathManager.reset();const t=t=>(this.pathManager.track(t),this.addChild(t));return this.template.parts.map((e=>this.renderTemplatePart(e,t))).join("")}render(){if(this.destroyed)return this;if(!this.el){const t=T(this);return this.hydrate(t),this}this.eventsManager.reset(),this.pathManager.reset();const t=this.isContainer()?null:document.activeElement;this.template.elements.forEach((t=>t.update()));const e=this.children;return this.children=[],this.template.interpolations.forEach((t=>{const s=[],i=[];this.pathManager.increment();const n=T(this.renderTemplatePart(t.expression,(t=>{let n=t,r=null;return r=t.key?e.find((e=>e.key===t.key)):this.pathManager.findRecyclable(t.constructor),r?(n=r.getRecycledMarker(),i.push([r,t]),r.key||this.pathManager.track(r)):(s.push(t),this.pathManager.track(t)),n})));i.forEach((([t,e])=>{this.addChild(t).recycle(n),t.props.set(e.props.toJSON()),e.destroy()})),s.forEach((t=>this.addChild(t).hydrate(n))),t.update(n)})),this.children.forEach((t=>t.callOnMount())),e.forEach((t=>{this.children.indexOf(t)<0&&t.destroy()})),this.isContainer()?this.el=this.children[0].el:this.eventsManager.hasPendingTypes()&&this.delegateEvents(),t&&this.el.contains(t)&&t.focus(),this.onUpdate.call(this),this}onCreate(){}onChange(){this.render()}onHydrate(){}onMount(){}onRecycle(){}onUpdate(){}onDestroy(){}static markAsSafeHTML(t){return new o(t)}static extend(t){const e=this;class s extends e{}return Object.assign(s.prototype,"function"==typeof t?t(e.prototype):t),s}static mount(t,e,s){const i=new this(t);return e&&(s?(i.toString(),i.hydrate(e)):e.append(...i.render().getNodes()),i.callOnMount()),i}static create(t,...e){"function"==typeof t&&(e=[t],t=["",""]);const s=[],i=[],n=L(N(x(S(M(t,e).trim(),e),e,s),e,i),e);return this.extend({template(){return{elements:s.map((t=>new p({getSelector:t.getSelector.bind(this),getAttributes:t.getAttributes.bind(this)}))),interpolations:i.map((t=>new m({getStart:t.getStart.bind(this),getEnd:t.getEnd.bind(this),expression:t.expression,isComponent:v,isElement:R}))),parts:n}}})}}j.ATTRIBUTE_ELEMENT="data-rasti-el",j.ATTRIBUTE_EVENT=(t,e)=>`data-rasti-on-${t}-${e}`,j.DATASET_ELEMENT="rastiEl",j.PLACEHOLDER=t=>`__RASTI-${t}__`,j.MARKER_RECYCLED=t=>`rasti-recycled-${t}`,j.MARKER_START=t=>`rasti-start-${t}`,j.MARKER_END=t=>`rasti-end-${t}`;var D=j.create`<div></div>`;t.Component=D,t.Emitter=s,t.Model=n,t.View=h}));
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Rasti={})}(this,(function(t){"use strict";function e(t){if("function"!=typeof t)throw new TypeError("Listener must be a function")}class s{on(t,s){return e(s),this.listeners||(this.listeners={}),this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(s),()=>this.off(t,s)}once(t,s){e(s);const i=(...e)=>{s(...e),this.off(t,i)};return this.on(t,i)}off(t,e){this.listeners&&(t?this.listeners[t]&&(e?(this.listeners[t]=this.listeners[t].filter((t=>t!==e)),this.listeners[t].length||delete this.listeners[t]):delete this.listeners[t],Object.keys(this.listeners).length||delete this.listeners):delete this.listeners)}emit(t,...e){this.listeners&&this.listeners[t]&&this.listeners[t].slice().forEach((t=>t(...e)))}listenTo(t,e,s){return t.on(e,s),this.listeningTo||(this.listeningTo=[]),this.listeningTo.push({emitter:t,type:e,listener:s}),()=>this.stopListening(t,e,s)}listenToOnce(t,s,i){e(i);const n=(...e)=>{i(...e),this.stopListening(t,s,n)};return this.listenTo(t,s,n)}stopListening(t,e,s){this.listeningTo&&(this.listeningTo=this.listeningTo.filter((i=>!(!t||t===i.emitter&&!e||t===i.emitter&&e===i.type&&!s||t===i.emitter&&e===i.type&&s===i.listener)||(i.emitter.off(i.type,i.listener),!1))),this.listeningTo.length||delete this.listeningTo)}}const i=(t,e,...s)=>"function"!=typeof t?t:t.apply(e,s);class n extends s{constructor(){super(),this.preinitialize.apply(this,arguments),this.attributes=Object.assign({},i(this.defaults,this),this.parse.apply(this,arguments)),this.previous={},Object.keys(this.attributes).forEach(this.defineAttribute.bind(this))}preinitialize(){}defineAttribute(t){Object.defineProperty(this,`${this.constructor.attributePrefix}${t}`,{get:()=>this.get(t),set:e=>{this.set(t,e)}})}get(t){return this.attributes[t]}set(t,e,...s){let i,n;"object"==typeof t?(i=t,n=[e,...s]):(i={[t]:e},n=s);const r=this._changing;this._changing=!0;const h={};r||(this.previous=Object.assign({},this.attributes)),Object.keys(i).forEach((t=>{i[t]!==this.attributes[t]&&(h[t]=i[t],this.attributes[t]=i[t])}));const o=Object.keys(h);if(o.length&&(this._pending=["change",this,h,...n]),o.forEach((t=>{this.emit(`change:${t}`,this,i[t],...n)})),r)return this;for(;this._pending;){const t=this._pending;this._pending=null,this.emit.apply(this,t)}return this._pending=null,this._changing=!1,this}parse(t){return t}toJSON(){return Object.assign({},this.attributes)}}n.attributePrefix="";const r=["el","tag","attributes","events","model","template","onDestroy"];class h extends s{constructor(t={}){super(),this.preinitialize.apply(this,arguments),this.delegatedEventListeners=[],this.children=[],this.destroyQueue=[],this.viewOptions=[],r.forEach((e=>{e in t&&(this[e]=t[e],this.viewOptions.push(e))})),this.ensureUid(),this.ensureElement()}preinitialize(){}$(t){return this.el.querySelector(t)}$$(t){return this.el.querySelectorAll(t)}destroy(){return this.destroyChildren(),this.undelegateEvents(),this.stopListening(),this.off(),this.destroyQueue.forEach((t=>t())),this.destroyQueue=[],this.onDestroy.apply(this,arguments),this.destroyed=!0,this}onDestroy(){}addChild(t){return this.children.push(t),t}destroyChildren(){this.children.forEach((t=>t.destroy())),this.children=[]}ensureUid(){this.uid||(this.uid="r-"+ ++h.uid)}ensureElement(){if(this.el)this.el=i(this.el,this);else{const t=i(this.tag,this),e=i(this.attributes,this);this.el=this.createElement(t,e)}this.delegateEvents()}createElement(t="div",e={}){let s=document.createElement(t);return Object.keys(e).forEach((t=>s.setAttribute(t,e[t]))),s}removeElement(){return this.el.parentNode.removeChild(this.el),this}delegateEvents(t){if(t||(t=i(this.events,this)),!t)return this;this.delegatedEventListeners.length&&this.undelegateEvents();let s={};return Object.keys(t).forEach((i=>{const n=i.split(" "),r=n.shift(),h=n.join(" ");let o=t[i];"string"==typeof o&&(o=this[o]),e(o),s[r]||(s[r]=[]),s[r].push({selector:h,listener:o})})),Object.keys(s).forEach((t=>{const e=e=>{s[t].forEach((({selector:t,listener:s})=>{if(!t)return void s.call(this,e,this,this.el);let i=e.target;for(;i&&i!==this.el;)i.matches&&i.matches(t)&&s.call(this,e,this,i),i=i.parentElement}))};this.delegatedEventListeners.push({type:t,listener:e}),this.el.addEventListener(t,e)})),this}undelegateEvents(){return this.delegatedEventListeners.forEach((({type:t,listener:e})=>{this.el.removeEventListener(t,e)})),this.delegatedEventListeners=[],this}render(){return this.template&&(this.el.innerHTML=this.template(this.model)),this}static sanitize(t){return`${t}`.replace(/[&<>"']/g,(t=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[t])))}}h.uid=0;class o{constructor(t){this.value=t}toString(){return this.value}}class a{constructor(t){this.items=t}}class l{constructor(){this.listeners=[],this.types=new Set,this.previousSize=0}addListener(t,e){return this.types.add(e),this.listeners.push(t),this.listeners.length-1}reset(){this.listeners=[],this.previousSize=this.types.size}hasPendingTypes(){return this.types.size>this.previousSize}}class c{constructor(){}reset(){this.paused=0,this.previous=this.tracked||new Map,this.tracked=new Map,this.positionStack=[0]}push(){this.positionStack.push(0)}pop(){this.positionStack.pop()}increment(){this.positionStack[this.positionStack.length-1]++}pause(){this.paused++}resume(){this.paused--}getPath(){return this.positionStack.join("-")}track(t){return 0===this.paused&&this.tracked.set(this.getPath(),t),t}findRecyclable(t){const e=this.previous.get(this.getPath());return e&&e.constructor===t&&!e.key?e:null}}const u=["value","checked","selected"];class p{constructor(t){this.getSelector=t.getSelector,this.getAttributes=t.getAttributes,this.previousAttributes={}}hydrate(t){this.ref=t.querySelector(this.getSelector())}update(){const t=this.getAttributes(),{remove:e,add:s}=function(t,e={}){const s={},i=[];return Object.keys(t).forEach((i=>{let n=t[i];n!==e[i]&&(!0===n?s[i]="":!1!==n&&(null==n&&(n=""),s[i]=n))})),Object.keys(e).forEach((s=>{(!(s in t)||e[s]!==t[s]&&!1===t[s])&&i.push(s)})),{add:s,remove:i}}(t,this.previousAttributes);this.previousAttributes=t,e.forEach((t=>{this.ref.removeAttribute(t),u.includes(t)&&t in this.ref&&(this.ref[t]="value"===t&&"")})),Object.keys(s).forEach((t=>{const e=s[t];this.ref.setAttribute(t,e),u.includes(t)&&t in this.ref&&(this.ref[t]="value"===t?e:!1!==e&&"false"!==e)}))}}const d=["value","checked","selected"];function f(t,e){t.nodeType===e.nodeType?t.nodeType!==Node.TEXT_NODE?t.tagName===e.tagName?(((t,e)=>{const s=e.attributes,i=t.attributes,n=new Set;for(let e=0,i=s.length;e<i;e++){const{name:i,value:r}=s[e];n.add(i),t.getAttribute(i)!==r&&t.setAttribute(i,r)}for(let e=i.length-1;e>=0;e--){const{name:s}=i[e];n.has(s)||t.removeAttribute(s)}for(let s=0,i=d.length;s<i;s++){const i=d[s];i in t&&t[i]!==e[i]&&(t[i]=e[i])}})(t,e),((t,e)=>{const s=t.childNodes,i=e.childNodes,n=s.length;if(n!==i.length)return!1;for(let t=0;t<n;t++)if(!s[t].isEqualNode(i[t]))return!1;return!0})(t,e)||((t,e)=>{const s=Array.from(e.childNodes);t.replaceChildren(...s)})(t,e)):t.replaceWith(e):t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue):t.replaceWith(e)}function g(t,e,s=(()=>!1),i){let n=i||t.firstChild;for(;n;){if(n.nodeType===Node.COMMENT_NODE&&n.data.trim()===e)return n;if(n.nodeType!==Node.ELEMENT_NODE||s(n)||!n.firstChild){for(;n&&!n.nextSibling;)if(n=n.parentNode,!n||n===t)return null;n&&(n=n.nextSibling)}else n=n.firstChild}return null}class E{constructor(t){this.getStart=t.getStart,this.getEnd=t.getEnd,this.expression=t.expression,this.isComponent=t.isComponent,this.isElement=t.isElement,this.previousItems=[]}hydrate(t){const e=g(t,this.getStart(),this.isComponent),s=g(t,this.getEnd(),this.isComponent,e);this.ref=[e,s]}update(t,e){if(e)return void e.replaceWith(t.firstChild);const[s,i]=this.ref,n=s.nextSibling,r=n===i,h=!r&&n.nextSibling===i,o=t.children;if(r)i.parentNode.insertBefore(t,i);else if(h&&1===o.length)this.isElement(n)?n.replaceWith(o[0]):f(n,o[0]);else{const e=document.createRange();e.setStartAfter(s),e.setEndBefore(i),e.deleteContents(),e.insertNode(t)}}}const m=t=>t.reduce(((t,e)=>(Array.isArray(e)?t.push(...m(e)):t.push(e),t)),[]);function y(t){const e=document.createElement("template");return e.innerHTML=`${t}`.trim(),e.content}function T(t){const e=[];return Object.keys(t).forEach((s=>{let i=t[s];!0===i?e.push(s):!1!==i&&(null==i&&(i=""),e.push(`${s}="${i}"`))})),e.join(" ")}const b=(t,e)=>i(t,e,e),v=t=>!!(t&&t.dataset&&t.dataset[_.DATASET_ELEMENT]&&t.dataset[_.DATASET_ELEMENT].endsWith("-1")),A=t=>!!(t&&t.dataset&&t.dataset[_.DATASET_ELEMENT]),R=(t,e)=>t.reduce(((t,s,i)=>(t.push(s),void 0!==e[i]&&t.push(_.PLACEHOLDER(i)),t)),[]).join(""),L=(t,e)=>{const s=_.PLACEHOLDER("(\\d+)"),i=t.match(new RegExp(`^${s}$`));if(i)return[e[parseInt(i[1],10)]];const n=new RegExp(`${s}`,"g"),r=[];let h,o=0;for(;null!==(h=n.exec(t));){const s=t.slice(o,h.index);r.push(_.markAsSafeHTML(s),e[parseInt(h[1],10)]),o=h.index+h[0].length}return r.push(_.markAsSafeHTML(t.slice(o))),r},C=(t,e)=>t.reduce(((t,s)=>{const i=e(s[0]);if(1===s.length)"object"==typeof i?t=Object.assign(t,i):"string"==typeof i&&(t[i]=!0);else{const n=s[2]?e(s[1]):s[1];t[i]=n}return t}),{}),$=(t,e,s)=>{const i={};return Object.keys(t).forEach((n=>{const r=n.match(/on(([A-Z]{1}[a-z]+)+)/);if(r&&r[1]){const h=r[1].toLowerCase(),o=t[n];if(o){const t=e.addListener(o,h);i[s(h)]=t}}else i[n]=t[n]})),i},S=(t,e,s=!1)=>{const i=_.PLACEHOLDER("(\\d+)"),n=new Map;return s||(t=t.replace(new RegExp(i,"g"),((t,s)=>{const i=e[s];if(i&&i.prototype instanceof _){if(n.has(i))return n.get(i);n.set(i,t)}return t}))),t.replace(new RegExp(`<(${i})([^>]*)>([\\s\\S]*?)</\\1>|<(${i})([^>]*)/>`,"g"),((t,s,i,n,r,h,o,l)=>{let c,u,p;if(s?(c=e[i],u=n):(c=void 0!==o?e[o]:h,u=l),!(c.prototype instanceof _))return t;if(s){const t=S(r,e,!0),s=x(t,e);p=L(s,e)}const d=w(u,e);return e.push((function(){const t=C(d,(t=>b(t,this)));return p&&(t.renderChildren=()=>new a(p.map((t=>b(t,this))))),c.mount(t)})),_.PLACEHOLDER(e.length-1)}))},M=(t,e)=>{const s=_.PLACEHOLDER("(?:\\d+)");return t.replace(new RegExp(`<(${s}|[a-z]+[1-6]?)(?:\\s*)((?:"[^"]*"|'[^']*'|[^>])*)(/?>)`,"gi"),e)},O=(t,e,s)=>{const n=_.PLACEHOLDER("(?:\\d+)");if(t.match(new RegExp(`^\\s*${n}\\s*$`)))return t;if(!t.match(new RegExp(`^\\s*<([a-z]+[1-6]?|${n})([^>]*)>([\\s\\S]*?)</(\\1|${n})>\\s*$|^\\s*<([a-z]+[1-6]?|${n})([^>]*)/>\\s*$`)))throw new SyntaxError(`Template must have a single root element or be a container component: "${t.trim()}"`);let r=0;return M(t,((t,h,o,a)=>{const l=0===r,c=++r;if(!l&&!o.match(new RegExp(n)))return t;const u=w(o,e),p=t=>`${t}-${c}`,d=s.length;s.push({getSelector:function(){return`[${_.ATTRIBUTE_ELEMENT}="${p(this.uid)}"]`},getAttributes:function(){const t=$(C(u,(t=>b(t,this))),this.eventsManager,(t=>_.ATTRIBUTE_EVENT(t,this.uid)));return l&&this.attributes&&Object.assign(t,i(this.attributes,this)),t[_.ATTRIBUTE_ELEMENT]=p(this.uid),t}}),e.push((function(){const t=this.template.elements[d],e=t.getAttributes.call(this);return t.previousAttributes=e,_.markAsSafeHTML(T(e))}));return`<${h} ${_.PLACEHOLDER(e.length-1)}${a}`}))},x=(t,e)=>{const s=_.PLACEHOLDER("(?:\\d+)");return M(t,((t,i,n,r)=>{if(!n.match(new RegExp(s)))return t;const h=w(n,e),o=function(){return $(C(h,(t=>b(t,this))),this.eventsManager,(t=>_.ATTRIBUTE_EVENT(t,this.uid)))};e.push((function(){const t=o.call(this);return _.markAsSafeHTML(T(t))}));return`<${i} ${_.PLACEHOLDER(e.length-1)}${r}`}))},k=(t,e,s)=>{const i=_.PLACEHOLDER("(\\d+)");let n=0;return t.replace(new RegExp(i,"g"),(function(i,r,h){const o=t.substring(0,h);if(o.lastIndexOf("<")>o.lastIndexOf(">"))return i;const a=++n;const l=s.length;return s.push({getStart:function(){return _.MARKER_START(`${this.uid}-${a}`)},getEnd:function(){return _.MARKER_END(`${this.uid}-${a}`)},expression:e[r]}),e.push((function(){return this.template.interpolations[l]})),_.PLACEHOLDER(e.length-1)}))},w=(t,e)=>{const s=_.PLACEHOLDER("(\\d+)"),i=[],n=new RegExp(`(${s}|[\\w-]+)(?:=(["']?)(?:${s}|((?:.?(?!["']?\\s+(?:\\S+)=|\\s*/?[>"']))+.))\\3)?`,"g");let r;for(;null!==(r=n.exec(t));){const[,t,s,n,h,o]=r,a=void 0!==s?e[parseInt(s,10)]:t,l=void 0!==h?e[parseInt(h,10)]:o;void 0!==l?i.push([a,l,!!n]):i.push([a])}return i},N=["key","state","onCreate","onChange","onHydrate","onRecycle","onUpdate"];class _ extends h{constructor(t={}){super(...arguments),this.componentOptions=[],N.forEach((e=>{e in t&&(this[e]=t[e],this.componentOptions.push(e))}));const e={};Object.keys(t).forEach((s=>{this.viewOptions.includes(s)||this.componentOptions.includes(s)||(e[s]=t[s])})),this.props=new n(e),this.options=t,this.partial=this.partial.bind(this),this.onChange=this.onChange.bind(this),this.onCreate.apply(this,arguments)}events(){const t={};return this.eventsManager.types.forEach((s=>{const i=_.ATTRIBUTE_EVENT(s,this.uid),n=function(t,s,n){const r=n.getAttribute(i);if(r){let i=this.eventsManager.listeners[parseInt(r,10)];"string"==typeof i&&(i=this[i]),e(i),i.call(this,t,s,n)}};t[`${s} [${i}]`]=n,t[s]=n})),t}ensureElement(){this.eventsManager=new l,this.pathManager=new c,this.template=i(this.template,this),this.el&&(this.el=i(this.el,this),this.toString(),this.hydrate(this.el.parentNode))}isContainer(){return 0===this.template.elements.length&&1===this.template.interpolations.length}subscribe(t,e="change",s=this.onChange){return t.on&&this.listenTo(t,e,s),this}hydrate(t){return["model","state","props"].forEach((t=>{this[t]&&this.subscribe(this[t])})),this.isContainer()?(this.children[0].hydrate(t),this.el=this.children[0].el):(this.template.elements.forEach(((e,s)=>{0===s?(e.hydrate(t),this.el?e.ref=this.el:this.el=e.ref):e.hydrate(this.el)})),this.delegateEvents(),this.template.interpolations.forEach((t=>t.hydrate(this.el))),this.children.forEach((t=>t.hydrate(this.el)))),this.onHydrate.call(this),this}recycle(t,e){if(t){g(t,_.MARKER_RECYCLED(this.uid),v).replaceWith(this.el)}return e&&this.props.set(e),this.onRecycle.call(this),this}getRecycledMarker(){return`\x3c!--${_.MARKER_RECYCLED(this.uid)}--\x3e`}partial(t,...e){const s=L(x(S(R(t,e).trim(),e),e),e).map((t=>b(t,this)));return new a(s)}renderTemplatePart(t,e,s=[]){const i=b(t,this),n=t=>{if(null==t||!1===t||!0===t)return"";if(t instanceof o)return s.push(t),t;if(t instanceof _)return s.push(t),e(t);if(t instanceof a){if(1===t.items.length)return n(t.items[0]);this.pathManager.push();const e=t.items.map((t=>(this.pathManager.increment(),n(t)))).join("");return this.pathManager.pop(),e}if(Array.isArray(t)){this.pathManager.pause();const e=m(t).map(n).join("");return this.pathManager.resume(),e}if(t instanceof E){this.pathManager.increment();const e=this.isContainer()?"":`\x3c!--${t.getStart()}--\x3e`,i=this.isContainer()?"":`\x3c!--${t.getEnd()}--\x3e`,r=n(b(t.expression,this));return t.previousItems=s,`${e}${r}${i}`}const i=_.sanitize(t);return s.push(i),i};return`${n(i)}`}toString(){this.destroyChildren(),this.eventsManager.reset(),this.pathManager.reset();const t=t=>(this.pathManager.track(t),this.addChild(t));return this.template.parts.map((e=>this.renderTemplatePart(e,t))).join("")}render(){if(this.destroyed)return this;if(!this.el){const t=y(this);return this.hydrate(t),this}this.eventsManager.reset(),this.pathManager.reset();const t=this.isContainer()?null:document.activeElement;this.template.elements.forEach((t=>t.update()));const e=this.children;return this.children=[],this.template.interpolations.forEach((t=>{const s=[],i=[];this.pathManager.increment();const n=t.previousItems,r=[],h=this.renderTemplatePart(t.expression,(t=>{let n=t,r=null;return r=t.key?e.find((e=>e.key===t.key)):this.pathManager.findRecyclable(t.constructor),r?(n=r.getRecycledMarker(),i.push([r,t]),r.key||this.pathManager.track(r)):(s.push(t),this.pathManager.track(t)),n}),r);t.previousItems=r;const o=([t,e],s)=>{this.addChild(t).recycle(s,e.props.toJSON()),e.destroy()};if(1===n.length&&n[0]instanceof _&&1===r.length&&r[0]instanceof _&&1===i.length)return void o(i[0],null);const a=y(h);i.forEach((t=>o(t,a))),s.forEach((t=>this.addChild(t).hydrate(a)));const l=this.isContainer()?this.el:null;t.update(a,l)})),e.forEach((t=>{this.children.indexOf(t)<0&&t.destroy()})),this.isContainer()?this.el=this.children[0].el:this.eventsManager.hasPendingTypes()&&this.delegateEvents(),t&&this.el.contains(t)&&t.focus(),this.onUpdate.call(this),this}onCreate(){}onChange(){this.render()}onHydrate(){}onRecycle(){}onUpdate(){}onDestroy(){}static markAsSafeHTML(t){return new o(t)}static extend(t){const e=this;class s extends e{}return Object.assign(s.prototype,"function"==typeof t?t(e.prototype):t),s}static mount(t,e,s){const i=new this(t);return e&&(s?(i.toString(),i.hydrate(e)):e.append(i.render().el)),i}static create(t,...e){"function"==typeof t&&(e=[t],t=["",""]);const s=[],i=[],n=L(k(O(S(R(t,e).trim(),e),e,s),e,i),e);return this.extend({template(){return{elements:s.map((t=>new p({getSelector:t.getSelector.bind(this),getAttributes:t.getAttributes.bind(this)}))),interpolations:i.map((t=>new E({getStart:t.getStart.bind(this),getEnd:t.getEnd.bind(this),expression:t.expression,isComponent:v,isElement:A}))),parts:n}}})}}_.ATTRIBUTE_ELEMENT="data-rasti-el",_.ATTRIBUTE_EVENT=(t,e)=>`data-rasti-on-${t}-${e}`,_.DATASET_ELEMENT="rastiEl",_.PLACEHOLDER=t=>`__RASTI-${t}__`,_.MARKER_RECYCLED=t=>`rasti-recycled-${t}`,_.MARKER_START=t=>`rasti-start-${t}`,_.MARKER_END=t=>`rasti-end-${t}`;var j=_.create`<div></div>`;t.Component=j,t.Emitter=s,t.Model=n,t.View=h}));
|