rasti 4.0.0-alpha.0 → 4.0.0-alpha.2
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 +0 -10
- package/dist/rasti.js +153 -106
- package/dist/rasti.min.js +1 -1
- package/es/Component.js +145 -100
- package/es/utils/getAttributesDiff.js +8 -6
- package/lib/Component.cjs +145 -100
- package/lib/utils/getAttributesDiff.cjs +8 -6
- package/package.json +1 -1
- package/src/Component.js +145 -100
- package/src/utils/getAttributesDiff.js +8 -6
package/README.md
CHANGED
|
@@ -187,16 +187,6 @@ For detailed information on how to use **Rasti**, refer to the [API documentatio
|
|
|
187
187
|
- **[v2.0.0](https://github.com/8tentaculos/rasti/releases/tag/v2.0.0)** - Introduced **Components**
|
|
188
188
|
- **[v1.0.0](https://github.com/8tentaculos/rasti/releases/tag/v1.0.0)** - Initial release
|
|
189
189
|
|
|
190
|
-
## Powered by **Rasti**
|
|
191
|
-
|
|
192
|
-
### [Crypto Babylon](https://cryptobabylon.net)
|
|
193
|
-
|
|
194
|
-
A market analytics platform efficiently rendering over 1000 dynamic rows, updated in real-time with thousands of messages per second via multiple WebSocket connections.
|
|
195
|
-
|
|
196
|
-
### [jsPacman](https://pacman.js.org)
|
|
197
|
-
|
|
198
|
-
A DOM-based remake of the classic Ms. Pac-Man game. **Rasti** powers its custom game engine.
|
|
199
|
-
|
|
200
190
|
## License
|
|
201
191
|
|
|
202
192
|
**Rasti** is open-source and available under the [MIT License](LICENSE).
|
package/dist/rasti.js
CHANGED
|
@@ -1242,12 +1242,14 @@
|
|
|
1242
1242
|
// Find attributes to add/update.
|
|
1243
1243
|
Object.keys(attributes).forEach(key => {
|
|
1244
1244
|
let value = attributes[key];
|
|
1245
|
-
|
|
1246
|
-
if (value
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
if (value
|
|
1250
|
-
|
|
1245
|
+
// Only add if the value is different from previous.
|
|
1246
|
+
if (value !== previous[key]) {
|
|
1247
|
+
if (value === true) {
|
|
1248
|
+
add[key] = '';
|
|
1249
|
+
} else if (value !== false) {
|
|
1250
|
+
if (value === null || typeof value === 'undefined') value = '';
|
|
1251
|
+
add[key] = value;
|
|
1252
|
+
}
|
|
1251
1253
|
}
|
|
1252
1254
|
});
|
|
1253
1255
|
// Find attributes to remove.
|
|
@@ -1594,7 +1596,7 @@
|
|
|
1594
1596
|
* @return {boolean} True if the element is a component root element.
|
|
1595
1597
|
* @private
|
|
1596
1598
|
*/
|
|
1597
|
-
const isComponent = (el) => el.
|
|
1599
|
+
const isComponent = (el) => !!el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1');
|
|
1598
1600
|
|
|
1599
1601
|
/**
|
|
1600
1602
|
* Check if an element has the Rasti data attribute.
|
|
@@ -1603,7 +1605,7 @@
|
|
|
1603
1605
|
* @return {boolean} True if the element has the data attribute.
|
|
1604
1606
|
* @private
|
|
1605
1607
|
*/
|
|
1606
|
-
const isElement = (el) => el.
|
|
1608
|
+
const isElement = (el) => !!el.dataset[Component.DATASET_ELEMENT];
|
|
1607
1609
|
|
|
1608
1610
|
/**
|
|
1609
1611
|
* Generate string with placeholders for interpolated expressions.
|
|
@@ -1715,21 +1717,39 @@
|
|
|
1715
1717
|
* modifies the expressions array adding the mount functions.
|
|
1716
1718
|
* @param main {string} The main template.
|
|
1717
1719
|
* @param {Array<any>} expressions Array of expressions.
|
|
1720
|
+
* @param {boolean} skipNormalization Skip placeholder normalization (for recursive calls).
|
|
1718
1721
|
* @return {string} The template with components tags replaced by expressions
|
|
1719
1722
|
* placeholders.
|
|
1720
1723
|
* @private
|
|
1721
1724
|
*/
|
|
1722
|
-
const expandComponents = (main, expressions) => {
|
|
1725
|
+
const expandComponents = (main, expressions, skipNormalization = false) => {
|
|
1723
1726
|
const PH = Component.PLACEHOLDER('(\\d+)');
|
|
1724
|
-
|
|
1727
|
+
const componentRefMap = new Map();
|
|
1728
|
+
// Normalize component references to use first placeholder index.
|
|
1729
|
+
// Only on first call, not on recursive calls.
|
|
1730
|
+
if (!skipNormalization) {
|
|
1731
|
+
main = main.replace(
|
|
1732
|
+
new RegExp(PH, 'g'),
|
|
1733
|
+
(match, idx) => {
|
|
1734
|
+
const expression = expressions[idx];
|
|
1735
|
+
if (expression && expression.prototype instanceof Component) {
|
|
1736
|
+
if (componentRefMap.has(expression)) {
|
|
1737
|
+
return componentRefMap.get(expression);
|
|
1738
|
+
}
|
|
1739
|
+
componentRefMap.set(expression, match);
|
|
1740
|
+
}
|
|
1741
|
+
return match;
|
|
1742
|
+
}
|
|
1743
|
+
);
|
|
1744
|
+
}
|
|
1745
|
+
// Match component tags with backreference to ensure correct pairing.
|
|
1725
1746
|
return main.replace(
|
|
1726
|
-
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)
|
|
1727
|
-
(match, openTag, openIdx, nonVoidAttrs, inner,
|
|
1728
|
-
let tag,
|
|
1747
|
+
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)</\\1>|<(${PH})([^>]*)/>`,'g'),
|
|
1748
|
+
(match, openTag, openIdx, nonVoidAttrs, inner, selfClosingTag, selfClosingIdx, selfClosingAttrs) => {
|
|
1749
|
+
let tag, attributesStr, innerList;
|
|
1729
1750
|
|
|
1730
1751
|
if (openTag) {
|
|
1731
|
-
tag =
|
|
1732
|
-
close = typeof closeIdx !== 'undefined' ? expressions[closeIdx] : closeTag;
|
|
1752
|
+
tag = expressions[openIdx];
|
|
1733
1753
|
attributesStr = nonVoidAttrs;
|
|
1734
1754
|
} else {
|
|
1735
1755
|
tag = typeof selfClosingIdx !== 'undefined' ? expressions[selfClosingIdx] : selfClosingTag;
|
|
@@ -1737,15 +1757,11 @@
|
|
|
1737
1757
|
}
|
|
1738
1758
|
// No component found.
|
|
1739
1759
|
if (!(tag.prototype instanceof Component)) return match;
|
|
1740
|
-
|
|
1741
|
-
let innerList;
|
|
1742
1760
|
// Non void component.
|
|
1743
|
-
if (
|
|
1744
|
-
// Close component tag must match open component tag.
|
|
1745
|
-
if (tag !== close) return match;
|
|
1761
|
+
if (openTag) {
|
|
1746
1762
|
// Process inner content same way as partial().
|
|
1747
1763
|
// Recursively expand inner components.
|
|
1748
|
-
const innerTemplate = expandComponents(inner, expressions);
|
|
1764
|
+
const innerTemplate = expandComponents(inner, expressions, true);
|
|
1749
1765
|
// Parse partial elements to handle dynamic attributes and events.
|
|
1750
1766
|
const parsedInner = parsePartialElements(innerTemplate, expressions);
|
|
1751
1767
|
// Split into items.
|
|
@@ -1978,7 +1994,7 @@
|
|
|
1978
1994
|
/*
|
|
1979
1995
|
* These option keys will be extended on the component instance.
|
|
1980
1996
|
*/
|
|
1981
|
-
const componentOptions = ['key', 'state', 'onCreate', 'onChange', 'onHydrate', 'onRecycle', 'onUpdate'];
|
|
1997
|
+
const componentOptions = ['key', 'state', 'onCreate', 'onChange', 'onHydrate', 'onMount', 'onRecycle', 'onUpdate'];
|
|
1982
1998
|
|
|
1983
1999
|
/**
|
|
1984
2000
|
* @lends module:Component
|
|
@@ -2046,34 +2062,6 @@
|
|
|
2046
2062
|
return events;
|
|
2047
2063
|
}
|
|
2048
2064
|
|
|
2049
|
-
/**
|
|
2050
|
-
* Subscribes to a `change` event on a model or emitter object and invokes the `onChange` lifecycle method.
|
|
2051
|
-
* The subscription is automatically cleaned up when the component is destroyed.
|
|
2052
|
-
* By default, the component subscribes to changes on `this.model`, `this.state`, and `this.props`.
|
|
2053
|
-
*
|
|
2054
|
-
* @param {Object} model - The model or emitter object to listen to.
|
|
2055
|
-
* @param {string} [type='change'] - The event type to listen for.
|
|
2056
|
-
* @param {Function} [listener=this.onChange] - The callback to invoke when the event is emitted.
|
|
2057
|
-
* @returns {Component} The current component instance for chaining.
|
|
2058
|
-
*/
|
|
2059
|
-
subscribe(model, type = 'change', listener = this.onChange) {
|
|
2060
|
-
// Check if model has `on` method.
|
|
2061
|
-
if (model.on) this.listenTo(model, type, listener);
|
|
2062
|
-
return this;
|
|
2063
|
-
}
|
|
2064
|
-
|
|
2065
|
-
/**
|
|
2066
|
-
* Tell if `Component` is a container.
|
|
2067
|
-
* In which case, it will not have an element by itself.
|
|
2068
|
-
* It will render a single expression which is expected to return a single component as child.
|
|
2069
|
-
* `this.el` will be a reference to that child component's element.
|
|
2070
|
-
* @return {boolean}
|
|
2071
|
-
* @private
|
|
2072
|
-
*/
|
|
2073
|
-
isContainer() {
|
|
2074
|
-
return this.template.elements.length === 0 && this.template.interpolations.length === 1;
|
|
2075
|
-
}
|
|
2076
|
-
|
|
2077
2065
|
/**
|
|
2078
2066
|
* Override super method. We don't want to ensure an element on instantiation.
|
|
2079
2067
|
* We will provide it later.
|
|
@@ -2097,6 +2085,34 @@
|
|
|
2097
2085
|
}
|
|
2098
2086
|
}
|
|
2099
2087
|
|
|
2088
|
+
/**
|
|
2089
|
+
* Tell if `Component` is a container.
|
|
2090
|
+
* In which case, it will not have an element by itself.
|
|
2091
|
+
* It will render a single expression which is expected to return a single component as child.
|
|
2092
|
+
* `this.el` will be a reference to that child component's element.
|
|
2093
|
+
* @return {boolean}
|
|
2094
|
+
* @private
|
|
2095
|
+
*/
|
|
2096
|
+
isContainer() {
|
|
2097
|
+
return this.template.elements.length === 0 && this.template.interpolations.length === 1;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
/**
|
|
2101
|
+
* Subscribes to a `change` event on a model or emitter object and invokes the `onChange` lifecycle method.
|
|
2102
|
+
* The subscription is automatically cleaned up when the component is destroyed.
|
|
2103
|
+
* By default, the component subscribes to changes on `this.model`, `this.state`, and `this.props`.
|
|
2104
|
+
*
|
|
2105
|
+
* @param {Object} model - The model or emitter object to listen to.
|
|
2106
|
+
* @param {string} [type='change'] - The event type to listen for.
|
|
2107
|
+
* @param {Function} [listener=this.onChange] - The callback to invoke when the event is emitted.
|
|
2108
|
+
* @returns {Component} The current component instance for chaining.
|
|
2109
|
+
*/
|
|
2110
|
+
subscribe(model, type = 'change', listener = this.onChange) {
|
|
2111
|
+
// Check if model has `on` method.
|
|
2112
|
+
if (model.on) this.listenTo(model, type, listener);
|
|
2113
|
+
return this;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2100
2116
|
/**
|
|
2101
2117
|
* Used internally on the render process.
|
|
2102
2118
|
* Attach the `Component` to the dom element providing `this.el`, delegate events,
|
|
@@ -2141,6 +2157,25 @@
|
|
|
2141
2157
|
return this;
|
|
2142
2158
|
}
|
|
2143
2159
|
|
|
2160
|
+
/**
|
|
2161
|
+
* Used internally on the render process.
|
|
2162
|
+
* Reuse a `Component` by replacing the placeholder comment with the real nodes.
|
|
2163
|
+
* Call `onRecycle` lifecycle method.
|
|
2164
|
+
* @param parent {node} The parent node.
|
|
2165
|
+
* @return {Component} The component instance.
|
|
2166
|
+
* @private
|
|
2167
|
+
*/
|
|
2168
|
+
recycle(parent) {
|
|
2169
|
+
// Locate the placeholder comment and replace it with the real nodes
|
|
2170
|
+
const toBeReplaced = findComment(parent, Component.MARKER_RECYCLED(this.uid), isComponent);
|
|
2171
|
+
// Replace it with this.el.
|
|
2172
|
+
toBeReplaced.replaceWith(...this.getNodes());
|
|
2173
|
+
// Call `onRecycle` lifecycle method.
|
|
2174
|
+
this.onRecycle.call(this);
|
|
2175
|
+
// Return `this` for chaining.
|
|
2176
|
+
return this;
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2144
2179
|
/**
|
|
2145
2180
|
* Get a `comment` marker with same data attribute as this component.
|
|
2146
2181
|
* Used to replace the component when it is recycled.
|
|
@@ -2167,65 +2202,19 @@
|
|
|
2167
2202
|
}
|
|
2168
2203
|
|
|
2169
2204
|
/**
|
|
2170
|
-
*
|
|
2171
|
-
*
|
|
2172
|
-
* Call `onRecycle` lifecycle method.
|
|
2173
|
-
* @param parent {node} The parent node.
|
|
2174
|
-
* @return {Component} The component instance.
|
|
2205
|
+
* Call onMount lifecycle method on children and self.
|
|
2206
|
+
* Used internally during the mount and render process.
|
|
2175
2207
|
* @private
|
|
2176
2208
|
*/
|
|
2177
|
-
|
|
2178
|
-
//
|
|
2179
|
-
|
|
2180
|
-
//
|
|
2181
|
-
|
|
2182
|
-
// Call `onRecycle` lifecycle method.
|
|
2183
|
-
this.onRecycle.call(this);
|
|
2209
|
+
callOnMount() {
|
|
2210
|
+
// Call onMount on children first.
|
|
2211
|
+
this.children.forEach(child => child.callOnMount());
|
|
2212
|
+
// Call onMount on self.
|
|
2213
|
+
this.onMount.call(this);
|
|
2184
2214
|
// Return `this` for chaining.
|
|
2185
2215
|
return this;
|
|
2186
2216
|
}
|
|
2187
2217
|
|
|
2188
|
-
/**
|
|
2189
|
-
* Lifecycle method. Called when the view is created, at the end of the `constructor`.
|
|
2190
|
-
* @param options {object} The view options.
|
|
2191
|
-
*/
|
|
2192
|
-
onCreate() {}
|
|
2193
|
-
|
|
2194
|
-
/**
|
|
2195
|
-
* Lifecycle method. Called when model emits `change` event.
|
|
2196
|
-
* By default calls `render` method.
|
|
2197
|
-
* This method can be extended with custom logic.
|
|
2198
|
-
* Maybe comparing new attributes with previous ones and calling
|
|
2199
|
-
* render when needed.
|
|
2200
|
-
* @param model {Rasti.Model} The model that emitted the event.
|
|
2201
|
-
* @param changed {object} Object containing keys and values that has changed.
|
|
2202
|
-
* @param [...args] {any} Any extra arguments passed to set method.
|
|
2203
|
-
*/
|
|
2204
|
-
onChange() {
|
|
2205
|
-
this.render();
|
|
2206
|
-
}
|
|
2207
|
-
|
|
2208
|
-
/**
|
|
2209
|
-
* Lifecycle method. Called when the component is rendered for the first time and hydrated.
|
|
2210
|
-
*/
|
|
2211
|
-
onHydrate() {}
|
|
2212
|
-
|
|
2213
|
-
/**
|
|
2214
|
-
* Lifecycle method. Called when the component is recycled (reused with the same key) and added to the DOM again.
|
|
2215
|
-
*/
|
|
2216
|
-
onRecycle() {}
|
|
2217
|
-
|
|
2218
|
-
/**
|
|
2219
|
-
* Lifecycle method. Called when the component is updated or re-rendered.
|
|
2220
|
-
*/
|
|
2221
|
-
onUpdate() {}
|
|
2222
|
-
|
|
2223
|
-
/**
|
|
2224
|
-
* Lifecycle method. Called when the component is destroyed.
|
|
2225
|
-
* @param {object} options Options object or any arguments passed to `destroy` method.
|
|
2226
|
-
*/
|
|
2227
|
-
onDestroy() {}
|
|
2228
|
-
|
|
2229
2218
|
/**
|
|
2230
2219
|
* Tagged template helper method.
|
|
2231
2220
|
* Used to create a partial template.
|
|
@@ -2351,6 +2340,7 @@
|
|
|
2351
2340
|
* - Components with a `key` are recycled if a previous child with the same key exists.
|
|
2352
2341
|
* - Unkeyed components are recycled if they have the same type and position in the template or partial.
|
|
2353
2342
|
* A recycled `Component` will call the `onRecycle` lifecycle method.
|
|
2343
|
+
* - 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).
|
|
2354
2344
|
* - If the active element is inside the component, it will retain focus after the render.
|
|
2355
2345
|
* @return {Component} The component instance.
|
|
2356
2346
|
*/
|
|
@@ -2420,12 +2410,12 @@
|
|
|
2420
2410
|
discarded.destroy();
|
|
2421
2411
|
});
|
|
2422
2412
|
// Add new children. Hydrate them.
|
|
2423
|
-
nextChildren.forEach(child =>
|
|
2424
|
-
this.addChild(child).hydrate(fragment);
|
|
2425
|
-
});
|
|
2413
|
+
nextChildren.forEach(child => this.addChild(child).hydrate(fragment));
|
|
2426
2414
|
|
|
2427
2415
|
interpolation.update(fragment);
|
|
2428
2416
|
});
|
|
2417
|
+
// Call onMount lifecycle method on all children after interpolations update.
|
|
2418
|
+
this.children.forEach(child => child.callOnMount());
|
|
2429
2419
|
// Destroy unused children.
|
|
2430
2420
|
previousChildren.forEach(prev => {
|
|
2431
2421
|
if (this.children.indexOf(prev) < 0) prev.destroy();
|
|
@@ -2449,6 +2439,55 @@
|
|
|
2449
2439
|
return this;
|
|
2450
2440
|
}
|
|
2451
2441
|
|
|
2442
|
+
/**
|
|
2443
|
+
* Lifecycle method. Called when the view is created, at the end of the `constructor`.
|
|
2444
|
+
* @param options {object} The view options.
|
|
2445
|
+
*/
|
|
2446
|
+
onCreate() {}
|
|
2447
|
+
|
|
2448
|
+
/**
|
|
2449
|
+
* Lifecycle method. Called when model emits `change` event.
|
|
2450
|
+
* By default calls `render` method.
|
|
2451
|
+
* This method can be extended with custom logic.
|
|
2452
|
+
* Maybe comparing new attributes with previous ones and calling
|
|
2453
|
+
* render when needed.
|
|
2454
|
+
* @param model {Rasti.Model} The model that emitted the event.
|
|
2455
|
+
* @param changed {object} Object containing keys and values that has changed.
|
|
2456
|
+
* @param [...args] {any} Any extra arguments passed to set method.
|
|
2457
|
+
*/
|
|
2458
|
+
onChange() {
|
|
2459
|
+
this.render();
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
/**
|
|
2463
|
+
* Lifecycle method. Called when the component is rendered for the first time and hydrated.
|
|
2464
|
+
*/
|
|
2465
|
+
onHydrate() {}
|
|
2466
|
+
|
|
2467
|
+
/**
|
|
2468
|
+
* Lifecycle method. Called when the component is mounted to the DOM.
|
|
2469
|
+
* This method is called after `onHydrate` and only when the component's element is actually present in the document.
|
|
2470
|
+
* It is called during the initial mount process (when using `Component.mount()`) and when new child components are added during render.
|
|
2471
|
+
* Use this method to perform operations that require the element to be in the DOM, such as measuring dimensions or focusing elements.
|
|
2472
|
+
*/
|
|
2473
|
+
onMount() {}
|
|
2474
|
+
|
|
2475
|
+
/**
|
|
2476
|
+
* Lifecycle method. Called when the component is recycled (reused with the same key) and added to the DOM again.
|
|
2477
|
+
*/
|
|
2478
|
+
onRecycle() {}
|
|
2479
|
+
|
|
2480
|
+
/**
|
|
2481
|
+
* Lifecycle method. Called when the component is updated or re-rendered.
|
|
2482
|
+
*/
|
|
2483
|
+
onUpdate() {}
|
|
2484
|
+
|
|
2485
|
+
/**
|
|
2486
|
+
* Lifecycle method. Called when the component is destroyed.
|
|
2487
|
+
* @param {object} options Options object or any arguments passed to `destroy` method.
|
|
2488
|
+
*/
|
|
2489
|
+
onDestroy() {}
|
|
2490
|
+
|
|
2452
2491
|
/**
|
|
2453
2492
|
* Mark a string as safe HTML to be rendered.
|
|
2454
2493
|
* Normally you don't need to use this method, as Rasti will automatically mark string literals
|
|
@@ -2485,6 +2524,7 @@
|
|
|
2485
2524
|
* Mount the component into the dom.
|
|
2486
2525
|
* It instantiate the Component view using options,
|
|
2487
2526
|
* appends its element into the DOM (if `el` is provided).
|
|
2527
|
+
* The `onMount` lifecycle method will be called after the component is added to the DOM.
|
|
2488
2528
|
* And returns the view instance.
|
|
2489
2529
|
* @static
|
|
2490
2530
|
* @param {object} [options] The view options.
|
|
@@ -2506,6 +2546,8 @@
|
|
|
2506
2546
|
// Append element to the DOM.
|
|
2507
2547
|
el.append(...component.render().getNodes());
|
|
2508
2548
|
}
|
|
2549
|
+
// Call onMount lifecycle method after nodes are in the DOM.
|
|
2550
|
+
component.callOnMount();
|
|
2509
2551
|
}
|
|
2510
2552
|
// Return component instance.
|
|
2511
2553
|
return component;
|
|
@@ -2686,6 +2728,11 @@
|
|
|
2686
2728
|
Component.ATTRIBUTE_ELEMENT = 'data-rasti-el';
|
|
2687
2729
|
Component.ATTRIBUTE_EVENT = (type) => `data-rasti-on-${type}`;
|
|
2688
2730
|
|
|
2731
|
+
/*
|
|
2732
|
+
* Dataset attribute used to identify elements.
|
|
2733
|
+
*/
|
|
2734
|
+
Component.DATASET_ELEMENT = 'rastiEl';
|
|
2735
|
+
|
|
2689
2736
|
/*
|
|
2690
2737
|
* Placeholders used to temporarily replace expressions in the template.
|
|
2691
2738
|
*/
|
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((e=>{let i=t[e];!0===i?s[e]="":!1!==i&&(null==i&&(i=""),s[e]=i)})),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 g(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 E(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=E(t,this.getStart(),this.isComponent),s=E(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))g(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 b(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 A=(t,e)=>i(t,e,e),v=t=>t.hasAttribute(j.ATTRIBUTE_ELEMENT)&&t.getAttribute(j.ATTRIBUTE_ELEMENT).endsWith("-1"),R=t=>t.hasAttribute(j.ATTRIBUTE_ELEMENT),L=(t,e)=>t.reduce(((t,s,i)=>(t.push(s),void 0!==e[i]&&t.push(j.PLACEHOLDER(i)),t)),[]).join(""),$=(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},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}),{}),M=(t,e)=>{const s={};return Object.keys(t).forEach((i=>{const n=i.match(/on(([A-Z]{1}[a-z]+)+)/);if(n&&n[1]){const r=n[1].toLowerCase(),h=t[i];if(h){const t=e.addListener(h,r);s[j.ATTRIBUTE_EVENT(r)]=t}}else s[i]=t[i]})),s},S=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)");return t.replace(new RegExp(`<(${s})([^>]*)>([\\s\\S]*?)</(${s})>|<(${s})([^>]*)/>`,"g"),((t,s,i,n,r,h,o,l,c,u)=>{let d,p,f,g;if(s?(d=void 0!==i?e[i]:s,p=void 0!==o?e[o]:h,f=n):(d=void 0!==c?e[c]:l,f=u),!(d.prototype instanceof j))return t;if(p){if(d!==p)return t;const s=S(r,e),i=k(s,e);g=$(i,e)}const E=w(f,e);return e.push((function(){const t=C(E,(t=>A(t,this)));return g&&(t.renderChildren=()=>new a(g.map((t=>A(t,this))))),d.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=M(C(u,(t=>A(t,this))),this.eventsManager);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(T(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 M(C(h,(t=>A(t,this))),this.eventsManager)};e.push((function(){const t=o.call(this);return j.markAsSafeHTML(T(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","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),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}subscribe(t,e="change",s=this.onChange){return t.on&&this.listenTo(t,e,s),this}isContainer(){return 0===this.template.elements.length&&1===this.template.interpolations.length}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))}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}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]}recycle(t){return E(t,j.MARKER_RECYCLED(this.uid),v).replaceWith(...this.getNodes()),this.onRecycle.call(this),this}onCreate(){}onChange(){this.render()}onHydrate(){}onRecycle(){}onUpdate(){}onDestroy(){}partial(t,...e){const s=$(k(S(L(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=b(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=b(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)})),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}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}static create(t,...e){"function"==typeof t&&(e=[t],t=["",""]);const s=[],i=[],n=$(N(x(S(L(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=>`data-rasti-on-${t}`,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(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 g(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 E(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=E(t,this.getStart(),this.isComponent),s=E(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))g(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.dataset[j.DATASET_ELEMENT]&&t.dataset[j.DATASET_ELEMENT].endsWith("-1"),R=t=>!!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},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}),{}),S=(t,e)=>{const s={};return Object.keys(t).forEach((i=>{const n=i.match(/on(([A-Z]{1}[a-z]+)+)/);if(n&&n[1]){const r=n[1].toLowerCase(),h=t[i];if(h){const t=e.addListener(h,r);s[j.ATTRIBUTE_EVENT(r)]=t}}else s[i]=t[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=$(r,e,!0),s=k(t,e);d=L(s,e)}const p=w(u,e);return e.push((function(){const t=C(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=S(C(u,(t=>A(t,this))),this.eventsManager);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 S(C(h,(t=>A(t,this))),this.eventsManager)};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),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 E(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($(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($(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=>`data-rasti-on-${t}`,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}));
|