rasti 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/rasti.js +122 -92
- package/dist/rasti.min.js +1 -1
- package/es/Component.js +98 -68
- package/es/View.js +24 -24
- package/lib/Component.cjs +98 -68
- package/lib/View.cjs +24 -24
- package/package.json +1 -1
- package/src/Component.js +98 -68
- package/src/View.js +24 -24
package/lib/Component.cjs
CHANGED
|
@@ -5,8 +5,12 @@ var utils_getResult = require('./utils/getResult.cjs');
|
|
|
5
5
|
var utils_deepFlat = require('./utils/deepFlat.cjs');
|
|
6
6
|
require('./Emitter.cjs');
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
9
|
* Wrapper class for HTML strings marked as safe.
|
|
10
|
+
* @class SafeHTML
|
|
11
|
+
* @param {string} value The HTML string to be marked as safe.
|
|
12
|
+
* @property {string} value The HTML string.
|
|
13
|
+
* @private
|
|
10
14
|
*/
|
|
11
15
|
class SafeHTML {
|
|
12
16
|
constructor(value) {
|
|
@@ -18,20 +22,22 @@ class SafeHTML {
|
|
|
18
22
|
}
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
/**
|
|
22
26
|
* Same as getResult, but pass context as argument to the expression.
|
|
23
27
|
* Used to evaluate expressions in the context of a component.
|
|
24
28
|
* @param {any} expression The expression to be evaluated.
|
|
25
29
|
* @param {any} context The context to call the expression with.
|
|
26
30
|
* @return {any} The result of the evaluated expression.
|
|
31
|
+
* @private
|
|
27
32
|
*/
|
|
28
33
|
const getExpressionResult = (expression, context) => utils_getResult(expression, context, context);
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
/**
|
|
31
36
|
* Generate string with placeholders for interpolated expressions.
|
|
32
37
|
* @param strings {array} Array of strings.
|
|
33
38
|
* @param expressions {array} Array of expressions.
|
|
34
39
|
* @return {string} String with placeholders.
|
|
40
|
+
* @private
|
|
35
41
|
*/
|
|
36
42
|
const addPlaceholders = (strings, expressions) =>
|
|
37
43
|
strings.reduce((out, string, i) => {
|
|
@@ -44,11 +50,12 @@ const addPlaceholders = (strings, expressions) =>
|
|
|
44
50
|
return out;
|
|
45
51
|
}, []).join('');
|
|
46
52
|
|
|
47
|
-
|
|
53
|
+
/**
|
|
48
54
|
* Generate one dimensional array with strings and expressions.
|
|
49
55
|
* @param main {string} The main template containing placeholders.
|
|
50
56
|
* @param expressions {array} Array of expressions to replace placeholders.
|
|
51
57
|
* @return {array} Array containing strings and expressions.
|
|
58
|
+
* @private
|
|
52
59
|
*/
|
|
53
60
|
const splitPlaceholders = (main, expressions) => {
|
|
54
61
|
const PH = Component.PLACEHOLDER_EXPRESSION('(\\d+)');
|
|
@@ -68,7 +75,7 @@ const splitPlaceholders = (main, expressions) => {
|
|
|
68
75
|
return out;
|
|
69
76
|
};
|
|
70
77
|
|
|
71
|
-
|
|
78
|
+
/**
|
|
72
79
|
* Expand attributes.
|
|
73
80
|
* @param attributes {array} Array of attributes as key, value pairs.
|
|
74
81
|
* @param getExpressionResult {function} Function to render expressions.
|
|
@@ -76,6 +83,7 @@ const splitPlaceholders = (main, expressions) => {
|
|
|
76
83
|
* @property {object} all All attributes.
|
|
77
84
|
* @property {object} events Event listeners.
|
|
78
85
|
* @property {object} attributes Attributes.
|
|
86
|
+
* @private
|
|
79
87
|
*/
|
|
80
88
|
const expandAttributes = (attributes, getExpressionResult) => {
|
|
81
89
|
const out = attributes.reduce((out, pair) => {
|
|
@@ -113,7 +121,7 @@ const expandAttributes = (attributes, getExpressionResult) => {
|
|
|
113
121
|
return out;
|
|
114
122
|
};
|
|
115
123
|
|
|
116
|
-
|
|
124
|
+
/**
|
|
117
125
|
* Replace component tags with expressions.
|
|
118
126
|
* `<${Component} />` or `<${Component}></${Component}>` will be replaced
|
|
119
127
|
* by a function that mounts the component.
|
|
@@ -122,6 +130,7 @@ const expandAttributes = (attributes, getExpressionResult) => {
|
|
|
122
130
|
* @param main {string} The main template.
|
|
123
131
|
* @return {string} The template with components tags replaced by expressions
|
|
124
132
|
* placeholders.
|
|
133
|
+
* @private
|
|
125
134
|
*/
|
|
126
135
|
const expandComponents = (main, expressions) => {
|
|
127
136
|
const PH = Component.PLACEHOLDER_EXPRESSION('(\\d+)');
|
|
@@ -161,7 +170,7 @@ const expandComponents = (main, expressions) => {
|
|
|
161
170
|
);
|
|
162
171
|
};
|
|
163
172
|
|
|
164
|
-
|
|
173
|
+
/**
|
|
165
174
|
* Parse match data to get tag, attributes, inner html and close tag.
|
|
166
175
|
* @param match {array}
|
|
167
176
|
* @return {object}
|
|
@@ -170,6 +179,7 @@ const expandComponents = (main, expressions) => {
|
|
|
170
179
|
* @property {string} close The closing tag.
|
|
171
180
|
* @property {array} attributes Array of attributes as key, value pairs.
|
|
172
181
|
* @property {string} raw The whole match.
|
|
182
|
+
* @private
|
|
173
183
|
*/
|
|
174
184
|
const parseMatch = (match, expressions) => {
|
|
175
185
|
const PH = Component.PLACEHOLDER_EXPRESSION('(\\d+)');
|
|
@@ -222,13 +232,7 @@ const selfClosingTags = {
|
|
|
222
232
|
/*
|
|
223
233
|
* These option keys will be extended on the component instance.
|
|
224
234
|
*/
|
|
225
|
-
const componentOptions =
|
|
226
|
-
key : true,
|
|
227
|
-
state : true,
|
|
228
|
-
onCreate : true,
|
|
229
|
-
onChange : true,
|
|
230
|
-
onRender : true
|
|
231
|
-
};
|
|
235
|
+
const componentOptions = ['key', 'state', 'onCreate', 'onChange', 'onRender'];
|
|
232
236
|
|
|
233
237
|
/**
|
|
234
238
|
* Components are a special kind of `View` that is designed to be easily composable,
|
|
@@ -261,9 +265,9 @@ const componentOptions = {
|
|
|
261
265
|
class Component extends View {
|
|
262
266
|
constructor(options = {}) {
|
|
263
267
|
super(...arguments);
|
|
264
|
-
// Extend "this" with options
|
|
265
|
-
|
|
266
|
-
if (
|
|
268
|
+
// Extend "this" with options.
|
|
269
|
+
componentOptions.forEach(key => {
|
|
270
|
+
if (key in options) this[key] = options[key];
|
|
267
271
|
});
|
|
268
272
|
// Store options by default.
|
|
269
273
|
this.options = options;
|
|
@@ -298,20 +302,22 @@ class Component extends View {
|
|
|
298
302
|
return this;
|
|
299
303
|
}
|
|
300
304
|
|
|
301
|
-
|
|
302
|
-
* Tell if
|
|
305
|
+
/**
|
|
306
|
+
* Tell if `Component` is a container.
|
|
303
307
|
* In which case, it will not have an element by itself.
|
|
304
308
|
* It will render a single expression which is expected to return a single component as child.
|
|
305
309
|
* `this.el` will be a reference to that child component's element.
|
|
306
310
|
* @return {boolean}
|
|
311
|
+
* @private
|
|
307
312
|
*/
|
|
308
313
|
isContainer() {
|
|
309
314
|
return !!(!this.tag && this.template);
|
|
310
315
|
}
|
|
311
316
|
|
|
312
|
-
|
|
313
|
-
* Override. We don't want to ensure an element on instantiation.
|
|
317
|
+
/**
|
|
318
|
+
* Override super method. We don't want to ensure an element on instantiation.
|
|
314
319
|
* We will provide it later.
|
|
320
|
+
* @private
|
|
315
321
|
*/
|
|
316
322
|
ensureElement() {
|
|
317
323
|
// If el is provided, delegate events.
|
|
@@ -322,18 +328,25 @@ class Component extends View {
|
|
|
322
328
|
}
|
|
323
329
|
}
|
|
324
330
|
|
|
325
|
-
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
* @
|
|
331
|
+
/**
|
|
332
|
+
* Locate the root element of the `Component` within a specified parent node.
|
|
333
|
+
* This is achieved by searching for the element using the unique data attribute assigned to the `Component`.
|
|
334
|
+
* @param {Node} parent - The parent node to search within.
|
|
335
|
+
* @return {Node} The root element of the component, or `null` if not found.
|
|
336
|
+
* @private
|
|
329
337
|
*/
|
|
330
338
|
findElement(parent) {
|
|
331
339
|
return (parent || document).querySelector(`[${Component.DATA_ATTRIBUTE_UID}="${this.uid}"]`);
|
|
332
340
|
}
|
|
333
341
|
|
|
334
|
-
|
|
335
|
-
*
|
|
336
|
-
*
|
|
342
|
+
/**
|
|
343
|
+
* Retrieve the attributes to be applied to the element.
|
|
344
|
+
* This includes attributes to be added, removed, and their HTML representation.
|
|
345
|
+
* @return {object} An object containing the following properties:
|
|
346
|
+
* @property {object} add - Attributes to be added to the element, with their values.
|
|
347
|
+
* @property {object} remove - Attributes to be removed from the element.
|
|
348
|
+
* @property {string} html - A string representation of the attributes for use in HTML.
|
|
349
|
+
* @private
|
|
337
350
|
*/
|
|
338
351
|
getAttributes() {
|
|
339
352
|
const add = {};
|
|
@@ -372,11 +385,13 @@ class Component extends View {
|
|
|
372
385
|
return { add, remove, html : html.join(' ') };
|
|
373
386
|
}
|
|
374
387
|
|
|
375
|
-
|
|
388
|
+
/**
|
|
376
389
|
* Used internally on the render process.
|
|
377
|
-
* Attach the
|
|
390
|
+
* Attach the `Component` to the dom element providing `this.el`, delegate events,
|
|
391
|
+
* subscribe to model changes and call `onRender` lifecycle method with `Component.RENDER_TYPE_HYDRATE` as argument.
|
|
378
392
|
* @param parent {node} The parent node.
|
|
379
393
|
* @return {Rasti.Component} The component instance.
|
|
394
|
+
* @private
|
|
380
395
|
*/
|
|
381
396
|
hydrate(parent) {
|
|
382
397
|
// Listen to model changes and call onChange.
|
|
@@ -384,13 +399,13 @@ class Component extends View {
|
|
|
384
399
|
// Listen to state changes and call onChange.
|
|
385
400
|
if (this.state) this.subscribe(this.state);
|
|
386
401
|
|
|
387
|
-
if (
|
|
402
|
+
if (this.isContainer()) {
|
|
403
|
+
this.children[0].hydrate(parent);
|
|
404
|
+
this.el = this.children[0].el;
|
|
405
|
+
} else {
|
|
388
406
|
this.el = this.findElement(parent);
|
|
389
407
|
this.delegateEvents();
|
|
390
408
|
this.children.forEach(child => child.hydrate(this.el));
|
|
391
|
-
} else {
|
|
392
|
-
this.children[0].hydrate(parent);
|
|
393
|
-
this.el = this.children[0].el;
|
|
394
409
|
}
|
|
395
410
|
// Call `onRender` lifecycle method.
|
|
396
411
|
this.onRender.call(this, Component.RENDER_TYPE_HYDRATE);
|
|
@@ -398,30 +413,38 @@ class Component extends View {
|
|
|
398
413
|
return this;
|
|
399
414
|
}
|
|
400
415
|
|
|
401
|
-
|
|
402
|
-
* Used internally
|
|
403
|
-
* Reuse a
|
|
416
|
+
/**
|
|
417
|
+
* Used internally on the render process.
|
|
418
|
+
* Reuse a `Component` that has `key` when its parent is rendered.
|
|
419
|
+
* Call `onRender` lifecycle method with `Component.RENDER_TYPE_RECYCLE` as argument.
|
|
404
420
|
* @param parent {node} The parent node.
|
|
405
421
|
* @return {Rasti.Component} The component instance.
|
|
422
|
+
* @private
|
|
406
423
|
*/
|
|
407
424
|
recycle(parent) {
|
|
408
425
|
// If component is a container, call recycle on its child.
|
|
409
|
-
if (this.isContainer())
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
426
|
+
if (this.isContainer()) {
|
|
427
|
+
this.children[0].recycle(parent);
|
|
428
|
+
} else {
|
|
429
|
+
// Find placeholder element to be replaced. It has same data attribute as this component.
|
|
430
|
+
const toBeReplaced = this.findElement(parent);
|
|
431
|
+
// Replace it with this.el.
|
|
432
|
+
toBeReplaced.replaceWith(this.el);
|
|
433
|
+
}
|
|
414
434
|
// Call `onRender` lifecycle method.
|
|
415
435
|
this.onRender.call(this, Component.RENDER_TYPE_RECYCLE);
|
|
416
436
|
// Return `this` for chaining.
|
|
417
437
|
return this;
|
|
418
438
|
}
|
|
419
439
|
|
|
420
|
-
|
|
421
|
-
*
|
|
440
|
+
/**
|
|
441
|
+
* Destroy the `Component`.
|
|
442
|
+
* Destroy children components if any, undelegate events, stop listening to events, call `onDestroy` lifecycle method.
|
|
422
443
|
* @param {object} options Options object or any arguments passed to `destroy` method will be passed to `onDestroy` method.
|
|
444
|
+
* @return {Rasti.View} Return `this` for chaining.
|
|
423
445
|
*/
|
|
424
446
|
destroy() {
|
|
447
|
+
// Call super destroy method.
|
|
425
448
|
super.destroy.apply(this, arguments);
|
|
426
449
|
// Set destroyed flag to prevent a last render after destroyed.
|
|
427
450
|
this.destroyed = true;
|
|
@@ -450,8 +473,11 @@ class Component extends View {
|
|
|
450
473
|
}
|
|
451
474
|
|
|
452
475
|
/**
|
|
453
|
-
* Lifecycle method. Called
|
|
454
|
-
*
|
|
476
|
+
* Lifecycle method. Called after the component is rendered.
|
|
477
|
+
* - When the component is rendered for the first time, this method is called with `Component.RENDER_TYPE_HYDRATE` as the argument.
|
|
478
|
+
* - When the component is updated or re-rendered, this method is called with `Component.RENDER_TYPE_RENDER` as the argument.
|
|
479
|
+
* - When the component is recycled (reused with the same key), this method is called with `Component.RENDER_TYPE_RECYCLE` as the argument.
|
|
480
|
+
* @param {string} type - The render type. Possible values are: `Component.RENDER_TYPE_HYDRATE`, `Component.RENDER_TYPE_RENDER` and `Component.RENDER_TYPE_RECYCLE`.
|
|
455
481
|
*/
|
|
456
482
|
onRender() {}
|
|
457
483
|
|
|
@@ -533,22 +559,26 @@ class Component extends View {
|
|
|
533
559
|
`<${tag} ${attributes} />`;
|
|
534
560
|
}
|
|
535
561
|
|
|
536
|
-
|
|
537
|
-
*
|
|
562
|
+
/**
|
|
563
|
+
* Render the `Component`.
|
|
564
|
+
* - If `this.el` is not present, the `Component` will be rendered as a string inside a `DocumentFragment` and hydrated, making `this.el` available. The `onRender` lifecycle method will be called with `Component.RENDER_TYPE_HYDRATE` as an argument.
|
|
565
|
+
* - If `this.el` is present, the method will update the attributes and inner HTML of the element, or recreate its child component in the case of a container. The `onRender` lifecycle method will be called with `Component.RENDER_TYPE_RENDER` as an argument.
|
|
566
|
+
* - When rendering child components, if the new children have the same key as the previous ones, they will be recycled. A recycled `Component` will call the `onRender` lifecycle method with `Component.RENDER_TYPE_RECYCLE` as an argument.
|
|
567
|
+
* - If the active element is inside the component, it will retain focus after the render.
|
|
568
|
+
* @return {Rasti.Component} The component instance.
|
|
538
569
|
*/
|
|
539
570
|
render() {
|
|
540
571
|
// Prevent a last re render if view is already destroyed.
|
|
541
572
|
if (this.destroyed) return this;
|
|
542
|
-
|
|
573
|
+
// If `this.el` is not present, render the view as a string and hydrate it.
|
|
574
|
+
if (!this.el) {
|
|
575
|
+
const fragment = this.createElement('template');
|
|
576
|
+
fragment.innerHTML = this;
|
|
577
|
+
this.hydrate(fragment.content);
|
|
578
|
+
return this;
|
|
579
|
+
}
|
|
580
|
+
// Update attributes.
|
|
543
581
|
if (!this.isContainer()) {
|
|
544
|
-
// If `this.el` is not present, render the view as a string and hydrate it.
|
|
545
|
-
if (!this.el) {
|
|
546
|
-
const fragment = this.createElement('template');
|
|
547
|
-
fragment.innerHTML = this;
|
|
548
|
-
this.hydrate(fragment.content);
|
|
549
|
-
return this;
|
|
550
|
-
}
|
|
551
|
-
// Set `this.el` attributes.
|
|
552
582
|
const attributes = this.getAttributes();
|
|
553
583
|
// Remove attributes.
|
|
554
584
|
Object.keys(attributes.remove).forEach(key => {
|
|
@@ -559,7 +589,7 @@ class Component extends View {
|
|
|
559
589
|
this.el.setAttribute(key, attributes.add[key]);
|
|
560
590
|
});
|
|
561
591
|
}
|
|
562
|
-
// Check for `template` to see if view has innerHTML.
|
|
592
|
+
// Check for `template` to see if view has innerHTML or a child component.
|
|
563
593
|
if (this.template) {
|
|
564
594
|
// Store active element.
|
|
565
595
|
const activeElement = document.activeElement;
|
|
@@ -600,8 +630,8 @@ class Component extends View {
|
|
|
600
630
|
this.addChild(nextChildren[0]).hydrate(fragment.content);
|
|
601
631
|
// Get next child element.
|
|
602
632
|
const nextEl = fragment.content.children[0];
|
|
603
|
-
//
|
|
604
|
-
|
|
633
|
+
// Replace `this.el` with nextEl.
|
|
634
|
+
this.el.replaceWith(nextEl);
|
|
605
635
|
// Set `this.el` to nextEl.
|
|
606
636
|
this.el = nextEl;
|
|
607
637
|
} else if (recycledChildren[0]) {
|
|
@@ -637,10 +667,10 @@ class Component extends View {
|
|
|
637
667
|
}
|
|
638
668
|
|
|
639
669
|
/**
|
|
640
|
-
* Mark a string as safe HTML to be rendered.
|
|
641
|
-
* Normally you don't need to use this method, as Rasti will automatically mark
|
|
642
|
-
* as safe HTML when the component is @link
|
|
643
|
-
* using the @link
|
|
670
|
+
* Mark a string as safe HTML to be rendered.
|
|
671
|
+
* Normally you don't need to use this method, as Rasti will automatically mark string literals
|
|
672
|
+
* as safe HTML when the component is {@link #module_component_create created} and when
|
|
673
|
+
* using the {@link #module_component__partial Component.partial} method.
|
|
644
674
|
* Be sure that the string is safe to be rendered, as it will be inserted into the DOM without any sanitization.
|
|
645
675
|
* @static
|
|
646
676
|
* @param {string} value
|
|
@@ -754,8 +784,8 @@ class Component extends View {
|
|
|
754
784
|
* // Create a navigation component. Add buttons as children. Iterate over items.
|
|
755
785
|
* const Navigation = Component.create`
|
|
756
786
|
* <nav>
|
|
757
|
-
* ${
|
|
758
|
-
* item =>
|
|
787
|
+
* ${({ options, partial }) => options.items.map(
|
|
788
|
+
* item => partial`<${Button}>${item.label}</${Button}>`
|
|
759
789
|
* )}
|
|
760
790
|
* </nav>
|
|
761
791
|
* `;
|
|
@@ -774,11 +804,11 @@ class Component extends View {
|
|
|
774
804
|
* ${self => self.renderChildren()}
|
|
775
805
|
* </button>
|
|
776
806
|
* `;
|
|
777
|
-
* // Create a container
|
|
807
|
+
* // Create a container that renders a Button component.
|
|
778
808
|
* const ButtonOk = Component.create`
|
|
779
809
|
* <${Button} className="ok">Ok</${Button}>
|
|
780
810
|
* `;
|
|
781
|
-
* // Create a
|
|
811
|
+
* // Create a container that renders a Button component, using a function.
|
|
782
812
|
* const ButtonCancel = Component.create(() => Button.mount({
|
|
783
813
|
* className: 'cancel',
|
|
784
814
|
* renderChildren: () => 'Cancel'
|
package/lib/View.cjs
CHANGED
|
@@ -6,15 +6,7 @@ var utils_getResult = require('./utils/getResult.cjs');
|
|
|
6
6
|
/*
|
|
7
7
|
* These option keys will be extended on the view instance.
|
|
8
8
|
*/
|
|
9
|
-
const viewOptions =
|
|
10
|
-
el : true,
|
|
11
|
-
tag : true,
|
|
12
|
-
attributes : true,
|
|
13
|
-
events : true,
|
|
14
|
-
model : true,
|
|
15
|
-
template : true,
|
|
16
|
-
onDestroy : true
|
|
17
|
-
};
|
|
9
|
+
const viewOptions = ['el', 'tag', 'attributes', 'events', 'model', 'template', 'onDestroy'];
|
|
18
10
|
|
|
19
11
|
/**
|
|
20
12
|
* - Listens for changes and renders the UI.
|
|
@@ -37,6 +29,7 @@ const viewOptions = {
|
|
|
37
29
|
* @property {object|function} events Object in the format `{'event selector' : 'listener'}`. It will be used to bind delegated event listeners to the root element. If it is a function, it will be called to get the events object, bound to the view instance. See {@link module_view_delegateevents View.delegateEvents}.
|
|
38
30
|
* @property {object} model A model or any object containing data and business logic.
|
|
39
31
|
* @property {function} template A function that returns a string with the view's inner HTML. See {@link module_view__render View.render}.
|
|
32
|
+
* @property {number} uid Unique identifier for the view instance. This can be used to generate unique IDs for elements within the view. It is automatically generated and should not be set manually.
|
|
40
33
|
* @example
|
|
41
34
|
* import { View } from 'rasti';
|
|
42
35
|
*
|
|
@@ -65,7 +58,7 @@ class View extends Emitter {
|
|
|
65
58
|
this.preinitialize.apply(this, arguments);
|
|
66
59
|
// Generate unique id.
|
|
67
60
|
// Useful to generate element ids.
|
|
68
|
-
this.uid = `
|
|
61
|
+
this.uid = `rasti-${++View.uid}`;
|
|
69
62
|
// Store delegated event listeners,
|
|
70
63
|
// so they can be unbound later.
|
|
71
64
|
this.delegatedEventListeners = [];
|
|
@@ -74,9 +67,9 @@ class View extends Emitter {
|
|
|
74
67
|
this.children = [];
|
|
75
68
|
// Mutable array to store handlers to be called on destroy.
|
|
76
69
|
this.destroyQueue = [];
|
|
77
|
-
// Extend "this" with options
|
|
78
|
-
|
|
79
|
-
if (
|
|
70
|
+
// Extend "this" with options.
|
|
71
|
+
viewOptions.forEach(key => {
|
|
72
|
+
if (key in options) this[key] = options[key];
|
|
80
73
|
});
|
|
81
74
|
// Ensure that the view has a root element at `this.el`.
|
|
82
75
|
this.ensureElement();
|
|
@@ -305,17 +298,16 @@ class View extends Emitter {
|
|
|
305
298
|
}
|
|
306
299
|
|
|
307
300
|
/**
|
|
308
|
-
* Renders the view.
|
|
301
|
+
* Renders the view.
|
|
309
302
|
* This method should be overridden with custom logic.
|
|
310
303
|
* The only convention is to manipulate the DOM within the scope of `this.el`,
|
|
311
|
-
* and to return `this` for chaining.
|
|
312
|
-
* If you add any child views, you should call `this.destroyChildren` before re-rendering.
|
|
313
|
-
* The default implementation
|
|
314
|
-
* of calling `this.template`, passing `this.model` as
|
|
315
|
-
* <br><br> ⚠ **Security Notice:** The default implementation utilizes `innerHTML
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* static method to escape HTML entities in a string.
|
|
304
|
+
* and to return `this` for chaining.
|
|
305
|
+
* If you add any child views, you should call `this.destroyChildren` before re-rendering.
|
|
306
|
+
* The default implementation updates `this.el`'s innerHTML with the result
|
|
307
|
+
* of calling `this.template`, passing `this.model` as the argument.
|
|
308
|
+
* <br><br> ⚠ **Security Notice:** The default implementation utilizes `innerHTML`, which may introduce Cross-Site Scripting (XSS) risks.
|
|
309
|
+
* Ensure that any user-generated content is properly sanitized before inserting it into the DOM.
|
|
310
|
+
* You can use the {@link #module_view_sanitize View.sanitize} static method to escape HTML entities in a string.
|
|
319
311
|
* For best practices on secure data handling, refer to the
|
|
320
312
|
* [OWASP's XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).<br><br>
|
|
321
313
|
* @return {Rasti.View} Returns `this` for chaining.
|
|
@@ -346,8 +338,16 @@ class View extends Emitter {
|
|
|
346
338
|
}
|
|
347
339
|
}
|
|
348
340
|
|
|
349
|
-
|
|
350
|
-
*
|
|
341
|
+
/**
|
|
342
|
+
* Counter for generating unique IDs for view instances.
|
|
343
|
+
* This is primarily used to assign unique identifiers to each view instance (`this.uid`), which can be helpful for tasks like
|
|
344
|
+
* generating element IDs.
|
|
345
|
+
* {@link #module_component Component}s use `this.uid` to generate data attributes for their elements, to be looked up on hydration.
|
|
346
|
+
* For server-side rendering, this counter should be reset to `0` on every request to ensure that the generated
|
|
347
|
+
* unique IDs match those on the client, enabling seamless hydration of components.
|
|
348
|
+
* @static
|
|
349
|
+
* @type {number}
|
|
350
|
+
* @default 0
|
|
351
351
|
*/
|
|
352
352
|
View.uid = 0;
|
|
353
353
|
|