assign-gingerly 0.0.55 → 0.0.57
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/handlers/lazyLoad.js +60 -74
- package/handlers/lazyLoad.ts +94 -104
- package/handlers/lazyLoadSwitch.ts +2 -1
- package/markerUtils.js +127 -0
- package/markerUtils.ts +162 -0
- package/package.json +5 -1
- package/types/assign-gingerly/types.d.ts +82 -1
package/handlers/lazyLoad.js
CHANGED
|
@@ -19,8 +19,7 @@
|
|
|
19
19
|
* }, { withMethods: ['querySelector'], from: myVM });
|
|
20
20
|
*/
|
|
21
21
|
import { withTransition, ensureHideStyle, DEFAULT_HIDE_CLASS } from '../transitionHelper.js';
|
|
22
|
-
|
|
23
|
-
const MARKER_END = '?end';
|
|
22
|
+
import { findMarkers, createMarkers, getNodesBetweenMarkers, findMarkersSibling, createMarkersSibling } from '../markerUtils.js';
|
|
24
23
|
/**
|
|
25
24
|
* Get the marker name from a template element (uses its id).
|
|
26
25
|
*/
|
|
@@ -33,55 +32,6 @@ function getMarkerName(templateEl) {
|
|
|
33
32
|
}
|
|
34
33
|
return 'anonymous';
|
|
35
34
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Find existing start/end comment markers in a target element.
|
|
38
|
-
* Returns [startMarker, endMarker] or [null, null] if not found.
|
|
39
|
-
*/
|
|
40
|
-
function findMarkers(target, name) {
|
|
41
|
-
const startText = `${MARKER_START_PREFIX}${name}"`;
|
|
42
|
-
let startMarker = null;
|
|
43
|
-
let endMarker = null;
|
|
44
|
-
const walker = document.createTreeWalker(target, NodeFilter.SHOW_COMMENT);
|
|
45
|
-
let node;
|
|
46
|
-
while ((node = walker.nextNode())) {
|
|
47
|
-
if (!startMarker && node.data === startText) {
|
|
48
|
-
startMarker = node;
|
|
49
|
-
}
|
|
50
|
-
else if (startMarker && !endMarker && node.data === MARKER_END) {
|
|
51
|
-
endMarker = node;
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return [startMarker, endMarker];
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Create start/end markers and insert them into the target.
|
|
59
|
-
*/
|
|
60
|
-
function createMarkers(target, name, method) {
|
|
61
|
-
const startMarker = document.createComment(`${MARKER_START_PREFIX}${name}"`);
|
|
62
|
-
const endMarker = document.createComment(MARKER_END);
|
|
63
|
-
if (method === 'prepend') {
|
|
64
|
-
target.prepend(endMarker);
|
|
65
|
-
target.prepend(startMarker);
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
target.appendChild(startMarker);
|
|
69
|
-
target.appendChild(endMarker);
|
|
70
|
-
}
|
|
71
|
-
return [startMarker, endMarker];
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Get all nodes between start and end markers.
|
|
75
|
-
*/
|
|
76
|
-
function getNodesBetweenMarkers(start, end) {
|
|
77
|
-
const nodes = [];
|
|
78
|
-
let current = start.nextSibling;
|
|
79
|
-
while (current && current !== end) {
|
|
80
|
-
nodes.push(current);
|
|
81
|
-
current = current.nextSibling;
|
|
82
|
-
}
|
|
83
|
-
return nodes;
|
|
84
|
-
}
|
|
85
35
|
/**
|
|
86
36
|
* LazyLoadHandler — built-in handler for conditional template instantiation.
|
|
87
37
|
*
|
|
@@ -89,30 +39,36 @@ function getNodesBetweenMarkers(start, end) {
|
|
|
89
39
|
*/
|
|
90
40
|
export class LazyLoadHandler {
|
|
91
41
|
config;
|
|
42
|
+
static #markerCounter = 0;
|
|
92
43
|
constructor(config) {
|
|
93
44
|
this.config = config;
|
|
94
45
|
}
|
|
95
46
|
async assign(lhsTarget, resolvedParams) {
|
|
96
|
-
const { if: condition, instantiate, method = 'appendChild', forget = false, transitional = false, hideClass = DEFAULT_HIDE_CLASS } = resolvedParams;
|
|
47
|
+
const { if: condition, instantiate, method = 'appendChild', forget = false, transitional = false, hideClass = DEFAULT_HIDE_CLASS, hideCss, markerName, toggleInert = false, toggleDisabled = false } = resolvedParams;
|
|
97
48
|
if (!(lhsTarget instanceof Element)) {
|
|
98
49
|
throw new Error('builtIns.lazyLoad: lhsTarget must be a DOM Element');
|
|
99
50
|
}
|
|
100
|
-
|
|
101
|
-
|
|
51
|
+
let name = markerName ?? getMarkerName(instantiate) ?? (lhsTarget.id || 'anonymous');
|
|
52
|
+
if (name === 'anonymous' && method === 'after') {
|
|
53
|
+
const stored = lhsTarget.dataset?.agMarker;
|
|
54
|
+
if (stored) {
|
|
55
|
+
name = stored;
|
|
56
|
+
} else {
|
|
57
|
+
name = `_ag_${LazyLoadHandler.#markerCounter++}`;
|
|
58
|
+
if (lhsTarget.dataset) {
|
|
59
|
+
lhsTarget.dataset.agMarker = name;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
let [startMarker, endMarker] = method === 'after'
|
|
64
|
+
? findMarkersSibling(lhsTarget, name)
|
|
65
|
+
: findMarkers(lhsTarget, name);
|
|
102
66
|
if (condition) {
|
|
103
67
|
if (startMarker && endMarker) {
|
|
104
68
|
const nodes = getNodesBetweenMarkers(startMarker, endMarker);
|
|
105
69
|
if (nodes.length > 0) {
|
|
106
70
|
withTransition(startMarker, 'show', transitional, () => {
|
|
107
|
-
|
|
108
|
-
if (node instanceof Element) {
|
|
109
|
-
if (transitional) {
|
|
110
|
-
node.classList.remove(hideClass);
|
|
111
|
-
} else {
|
|
112
|
-
node.removeAttribute('hidden');
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
71
|
+
this.showNodes(nodes, transitional, hideClass, toggleInert, toggleDisabled);
|
|
116
72
|
});
|
|
117
73
|
}
|
|
118
74
|
else {
|
|
@@ -127,7 +83,11 @@ export class LazyLoadHandler {
|
|
|
127
83
|
}
|
|
128
84
|
}
|
|
129
85
|
else {
|
|
130
|
-
|
|
86
|
+
if (method === 'after') {
|
|
87
|
+
[startMarker, endMarker] = createMarkersSibling(lhsTarget, name);
|
|
88
|
+
} else {
|
|
89
|
+
[startMarker, endMarker] = createMarkers(lhsTarget, name, method);
|
|
90
|
+
}
|
|
131
91
|
if (transitional) {
|
|
132
92
|
ensureHideStyle(lhsTarget.getRootNode());
|
|
133
93
|
withTransition(startMarker, 'show', true, () => {
|
|
@@ -151,21 +111,47 @@ export class LazyLoadHandler {
|
|
|
151
111
|
}
|
|
152
112
|
else {
|
|
153
113
|
withTransition(startMarker, 'hide', transitional, () => {
|
|
154
|
-
|
|
155
|
-
if (node instanceof Element) {
|
|
156
|
-
if (transitional) {
|
|
157
|
-
ensureHideStyle(lhsTarget.getRootNode(), hideClass);
|
|
158
|
-
node.classList.add(hideClass);
|
|
159
|
-
} else {
|
|
160
|
-
node.setAttribute('hidden', '');
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
114
|
+
this.hideNodes(nodes, lhsTarget, transitional, hideClass, hideCss, toggleInert, toggleDisabled);
|
|
164
115
|
});
|
|
165
116
|
}
|
|
166
117
|
}
|
|
167
118
|
}
|
|
168
119
|
}
|
|
120
|
+
showNodes(nodes, transitional, hideClass, toggleInert, toggleDisabled) {
|
|
121
|
+
for (const node of nodes) {
|
|
122
|
+
if (node instanceof Element) {
|
|
123
|
+
if (transitional) {
|
|
124
|
+
node.classList.remove(hideClass);
|
|
125
|
+
} else {
|
|
126
|
+
node.removeAttribute('hidden');
|
|
127
|
+
}
|
|
128
|
+
if (toggleInert) {
|
|
129
|
+
node.removeAttribute('inert');
|
|
130
|
+
}
|
|
131
|
+
if (toggleDisabled && 'disabled' in node) {
|
|
132
|
+
node.disabled = false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
hideNodes(nodes, lhsTarget, transitional, hideClass, hideCss, toggleInert, toggleDisabled) {
|
|
138
|
+
for (const node of nodes) {
|
|
139
|
+
if (node instanceof Element) {
|
|
140
|
+
if (transitional) {
|
|
141
|
+
ensureHideStyle(lhsTarget.getRootNode(), hideClass, hideCss);
|
|
142
|
+
node.classList.add(hideClass);
|
|
143
|
+
} else {
|
|
144
|
+
node.setAttribute('hidden', '');
|
|
145
|
+
}
|
|
146
|
+
if (toggleInert) {
|
|
147
|
+
node.setAttribute('inert', '');
|
|
148
|
+
}
|
|
149
|
+
if (toggleDisabled && 'disabled' in node) {
|
|
150
|
+
node.disabled = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
169
155
|
cloneAndInsertSync(templateEl, startMarker, endMarker, lhsTarget, resolvedParams) {
|
|
170
156
|
let content;
|
|
171
157
|
if (templateEl instanceof HTMLTemplateElement) {
|
package/handlers/lazyLoad.ts
CHANGED
|
@@ -20,24 +20,11 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import type { AssignFromHandler } from '../assignFrom.js';
|
|
23
|
+
import type { LazyLoadResolvedParams, LazyLoadInstantiatedContext } from '../types/assign-gingerly/types.js';
|
|
23
24
|
import { withTransition, ensureHideStyle, DEFAULT_HIDE_CLASS } from '../transitionHelper.js';
|
|
25
|
+
import { findMarkers, createMarkers, getNodesBetweenMarkers, findMarkersSibling, createMarkersSibling, MARKER_START_PREFIX, MARKER_END } from '../markerUtils.js';
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
const MARKER_END = '?end';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Context passed to onInstantiated callbacks.
|
|
30
|
-
*/
|
|
31
|
-
export interface LazyLoadInstantiatedContext {
|
|
32
|
-
/** The inserted child nodes */
|
|
33
|
-
nodes: Node[];
|
|
34
|
-
/** The target element containing the markers */
|
|
35
|
-
target: Element;
|
|
36
|
-
/** The full handler config */
|
|
37
|
-
config: any;
|
|
38
|
-
/** The resolved parameters */
|
|
39
|
-
resolvedParams: Record<string, any>;
|
|
40
|
-
}
|
|
27
|
+
export type { LazyLoadResolvedParams, LazyLoadInstantiatedContext };
|
|
41
28
|
|
|
42
29
|
/**
|
|
43
30
|
* Get the marker name from a template element (uses its id).
|
|
@@ -52,61 +39,6 @@ function getMarkerName(templateEl: any): string {
|
|
|
52
39
|
return 'anonymous';
|
|
53
40
|
}
|
|
54
41
|
|
|
55
|
-
/**
|
|
56
|
-
* Find existing start/end comment markers in a target element.
|
|
57
|
-
* Returns [startMarker, endMarker] or [null, null] if not found.
|
|
58
|
-
*/
|
|
59
|
-
function findMarkers(target: Element, name: string): [Comment | null, Comment | null] {
|
|
60
|
-
const startText = `${MARKER_START_PREFIX}${name}"`;
|
|
61
|
-
let startMarker: Comment | null = null;
|
|
62
|
-
let endMarker: Comment | null = null;
|
|
63
|
-
|
|
64
|
-
const walker = document.createTreeWalker(target, NodeFilter.SHOW_COMMENT);
|
|
65
|
-
let node: Comment | null;
|
|
66
|
-
while ((node = walker.nextNode() as Comment | null)) {
|
|
67
|
-
if (!startMarker && node.data === startText) {
|
|
68
|
-
startMarker = node;
|
|
69
|
-
} else if (startMarker && !endMarker && node.data === MARKER_END) {
|
|
70
|
-
endMarker = node;
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return [startMarker, endMarker];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Create start/end markers and insert them into the target.
|
|
80
|
-
*/
|
|
81
|
-
function createMarkers(target: Element, name: string, method: string): [Comment, Comment] {
|
|
82
|
-
const startMarker = document.createComment(`${MARKER_START_PREFIX}${name}"`);
|
|
83
|
-
const endMarker = document.createComment(MARKER_END);
|
|
84
|
-
|
|
85
|
-
if (method === 'prepend') {
|
|
86
|
-
target.prepend(endMarker);
|
|
87
|
-
target.prepend(startMarker);
|
|
88
|
-
} else {
|
|
89
|
-
// Default: appendChild
|
|
90
|
-
target.appendChild(startMarker);
|
|
91
|
-
target.appendChild(endMarker);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return [startMarker, endMarker];
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Get all nodes between start and end markers.
|
|
99
|
-
*/
|
|
100
|
-
function getNodesBetweenMarkers(start: Comment, end: Comment): Node[] {
|
|
101
|
-
const nodes: Node[] = [];
|
|
102
|
-
let current: Node | null = start.nextSibling;
|
|
103
|
-
while (current && current !== end) {
|
|
104
|
-
nodes.push(current);
|
|
105
|
-
current = current.nextSibling;
|
|
106
|
-
}
|
|
107
|
-
return nodes;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
42
|
/**
|
|
111
43
|
* LazyLoadHandler — built-in handler for conditional template instantiation.
|
|
112
44
|
*
|
|
@@ -114,12 +46,13 @@ function getNodesBetweenMarkers(start: Comment, end: Comment): Node[] {
|
|
|
114
46
|
*/
|
|
115
47
|
export class LazyLoadHandler implements AssignFromHandler {
|
|
116
48
|
config: any;
|
|
49
|
+
static #markerCounter = 0;
|
|
117
50
|
|
|
118
51
|
constructor(config: any) {
|
|
119
52
|
this.config = config;
|
|
120
53
|
}
|
|
121
54
|
|
|
122
|
-
async assign(lhsTarget: any, resolvedParams:
|
|
55
|
+
async assign(lhsTarget: any, resolvedParams: LazyLoadResolvedParams): Promise<void> {
|
|
123
56
|
const {
|
|
124
57
|
if: condition,
|
|
125
58
|
instantiate,
|
|
@@ -127,42 +60,50 @@ export class LazyLoadHandler implements AssignFromHandler {
|
|
|
127
60
|
forget = false,
|
|
128
61
|
transitional = false,
|
|
129
62
|
hideClass = DEFAULT_HIDE_CLASS,
|
|
63
|
+
hideCss,
|
|
64
|
+
markerName,
|
|
65
|
+
toggleInert = false,
|
|
66
|
+
toggleDisabled = false,
|
|
130
67
|
} = resolvedParams;
|
|
131
68
|
|
|
132
69
|
if (!(lhsTarget instanceof Element)) {
|
|
133
70
|
throw new Error('builtIns.lazyLoad: lhsTarget must be a DOM Element');
|
|
134
71
|
}
|
|
135
72
|
|
|
136
|
-
|
|
73
|
+
// Determine marker name — auto-generate for 'after' mode if would be 'anonymous'
|
|
74
|
+
let name = markerName ?? getMarkerName(instantiate) ?? (lhsTarget.id || 'anonymous');
|
|
75
|
+
if (name === 'anonymous' && method === 'after') {
|
|
76
|
+
// Check for previously stored name on the anchor
|
|
77
|
+
const stored = (lhsTarget as HTMLElement).dataset?.agMarker;
|
|
78
|
+
if (stored) {
|
|
79
|
+
name = stored;
|
|
80
|
+
} else {
|
|
81
|
+
name = `_ag_${LazyLoadHandler.#markerCounter++}`;
|
|
82
|
+
if ((lhsTarget as HTMLElement).dataset) {
|
|
83
|
+
(lhsTarget as HTMLElement).dataset.agMarker = name;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
137
87
|
|
|
138
|
-
// Find or create markers
|
|
139
|
-
let [startMarker, endMarker] =
|
|
88
|
+
// Find or create markers based on method
|
|
89
|
+
let [startMarker, endMarker] = method === 'after'
|
|
90
|
+
? findMarkersSibling(lhsTarget, name)
|
|
91
|
+
: findMarkers(lhsTarget, name);
|
|
140
92
|
|
|
141
93
|
if (condition) {
|
|
142
94
|
// SHOW
|
|
143
95
|
if (startMarker && endMarker) {
|
|
144
|
-
// Markers exist — check if content is hidden or removed
|
|
145
96
|
const nodes = getNodesBetweenMarkers(startMarker, endMarker);
|
|
146
97
|
if (nodes.length > 0) {
|
|
147
98
|
// Content exists — show it
|
|
148
99
|
withTransition(startMarker, 'show', transitional, () => {
|
|
149
|
-
|
|
150
|
-
if (node instanceof Element) {
|
|
151
|
-
if (transitional) {
|
|
152
|
-
node.classList.remove(hideClass);
|
|
153
|
-
} else {
|
|
154
|
-
node.removeAttribute('hidden');
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
100
|
+
this.showNodes(nodes, transitional, hideClass, toggleInert, toggleDisabled);
|
|
158
101
|
});
|
|
159
102
|
} else {
|
|
160
103
|
// Content was removed (forget mode) — re-clone
|
|
161
104
|
if (transitional) {
|
|
162
105
|
ensureHideStyle(lhsTarget.getRootNode());
|
|
163
106
|
withTransition(startMarker, 'show', true, () => {
|
|
164
|
-
// cloneAndInsert is async but the transition callback is sync
|
|
165
|
-
// For transitions with clone, we insert synchronously
|
|
166
107
|
this.cloneAndInsertSync(instantiate, startMarker!, endMarker!, lhsTarget, resolvedParams);
|
|
167
108
|
});
|
|
168
109
|
} else {
|
|
@@ -171,7 +112,11 @@ export class LazyLoadHandler implements AssignFromHandler {
|
|
|
171
112
|
}
|
|
172
113
|
} else {
|
|
173
114
|
// No markers — first time. Create markers and clone template.
|
|
174
|
-
|
|
115
|
+
if (method === 'after') {
|
|
116
|
+
[startMarker, endMarker] = createMarkersSibling(lhsTarget, name);
|
|
117
|
+
} else {
|
|
118
|
+
[startMarker, endMarker] = createMarkers(lhsTarget, name, method);
|
|
119
|
+
}
|
|
175
120
|
if (transitional) {
|
|
176
121
|
ensureHideStyle(lhsTarget.getRootNode());
|
|
177
122
|
withTransition(startMarker, 'show', true, () => {
|
|
@@ -188,29 +133,74 @@ export class LazyLoadHandler implements AssignFromHandler {
|
|
|
188
133
|
if (nodes.length === 0) return;
|
|
189
134
|
|
|
190
135
|
if (forget) {
|
|
191
|
-
// Remove nodes entirely (markers persist for re-insertion)
|
|
192
136
|
withTransition(startMarker, 'hide', transitional, () => {
|
|
193
137
|
for (const node of nodes) {
|
|
194
138
|
node.parentNode?.removeChild(node);
|
|
195
139
|
}
|
|
196
140
|
});
|
|
197
141
|
} else {
|
|
198
|
-
// Hide nodes
|
|
199
142
|
withTransition(startMarker, 'hide', transitional, () => {
|
|
200
|
-
|
|
201
|
-
if (node instanceof Element) {
|
|
202
|
-
if (transitional) {
|
|
203
|
-
ensureHideStyle(lhsTarget.getRootNode(), hideClass);
|
|
204
|
-
node.classList.add(hideClass);
|
|
205
|
-
} else {
|
|
206
|
-
node.setAttribute('hidden', '');
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
143
|
+
this.hideNodes(nodes, lhsTarget, transitional, hideClass, hideCss, toggleInert, toggleDisabled);
|
|
210
144
|
});
|
|
211
145
|
}
|
|
212
146
|
}
|
|
213
|
-
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Show nodes — remove hidden/class and restore inert/disabled state.
|
|
152
|
+
*/
|
|
153
|
+
protected showNodes(
|
|
154
|
+
nodes: Node[],
|
|
155
|
+
transitional: boolean,
|
|
156
|
+
hideClass: string,
|
|
157
|
+
toggleInert: boolean,
|
|
158
|
+
toggleDisabled: boolean
|
|
159
|
+
): void {
|
|
160
|
+
for (const node of nodes) {
|
|
161
|
+
if (node instanceof Element) {
|
|
162
|
+
if (transitional) {
|
|
163
|
+
node.classList.remove(hideClass);
|
|
164
|
+
} else {
|
|
165
|
+
node.removeAttribute('hidden');
|
|
166
|
+
}
|
|
167
|
+
if (toggleInert) {
|
|
168
|
+
node.removeAttribute('inert');
|
|
169
|
+
}
|
|
170
|
+
if (toggleDisabled && 'disabled' in node) {
|
|
171
|
+
(node as any).disabled = false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Hide nodes — add hidden/class and set inert/disabled state.
|
|
179
|
+
*/
|
|
180
|
+
protected hideNodes(
|
|
181
|
+
nodes: Node[],
|
|
182
|
+
lhsTarget: Element,
|
|
183
|
+
transitional: boolean,
|
|
184
|
+
hideClass: string,
|
|
185
|
+
hideCss: string | undefined,
|
|
186
|
+
toggleInert: boolean,
|
|
187
|
+
toggleDisabled: boolean
|
|
188
|
+
): void {
|
|
189
|
+
for (const node of nodes) {
|
|
190
|
+
if (node instanceof Element) {
|
|
191
|
+
if (transitional) {
|
|
192
|
+
ensureHideStyle(lhsTarget.getRootNode(), hideClass, hideCss);
|
|
193
|
+
node.classList.add(hideClass);
|
|
194
|
+
} else {
|
|
195
|
+
node.setAttribute('hidden', '');
|
|
196
|
+
}
|
|
197
|
+
if (toggleInert) {
|
|
198
|
+
node.setAttribute('inert', '');
|
|
199
|
+
}
|
|
200
|
+
if (toggleDisabled && 'disabled' in node) {
|
|
201
|
+
(node as any).disabled = true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
214
204
|
}
|
|
215
205
|
}
|
|
216
206
|
|
|
@@ -224,7 +214,7 @@ export class LazyLoadHandler implements AssignFromHandler {
|
|
|
224
214
|
startMarker: Comment,
|
|
225
215
|
endMarker: Comment,
|
|
226
216
|
lhsTarget: Element,
|
|
227
|
-
resolvedParams:
|
|
217
|
+
resolvedParams: LazyLoadResolvedParams
|
|
228
218
|
): Node[] {
|
|
229
219
|
let content: DocumentFragment;
|
|
230
220
|
|
|
@@ -252,7 +242,7 @@ export class LazyLoadHandler implements AssignFromHandler {
|
|
|
252
242
|
startMarker: Comment,
|
|
253
243
|
endMarker: Comment,
|
|
254
244
|
lhsTarget: Element,
|
|
255
|
-
resolvedParams:
|
|
245
|
+
resolvedParams: LazyLoadResolvedParams
|
|
256
246
|
): Promise<Node[]> {
|
|
257
247
|
let content: DocumentFragment;
|
|
258
248
|
|
|
@@ -300,7 +290,7 @@ export class LazyLoadHandler implements AssignFromHandler {
|
|
|
300
290
|
protected async onCloneInserted(
|
|
301
291
|
nodes: Node[],
|
|
302
292
|
lhsTarget: Element,
|
|
303
|
-
resolvedParams:
|
|
293
|
+
resolvedParams: LazyLoadResolvedParams
|
|
304
294
|
): Promise<void> {
|
|
305
295
|
// No-op by default. Subclasses override.
|
|
306
296
|
}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import { LazyLoadHandler } from './lazyLoad.js';
|
|
24
24
|
import type { AssignFromHandler } from '../assignFrom.js';
|
|
25
|
+
import type { LazyLoadSwitchResolvedParams } from '../types/assign-gingerly/types.js';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Evaluate a comparison operation.
|
|
@@ -54,7 +55,7 @@ function evaluateOp(lhs: any, op: string, rhs: any): boolean {
|
|
|
54
55
|
*/
|
|
55
56
|
export class LazyLoadSwitchHandler extends LazyLoadHandler implements AssignFromHandler {
|
|
56
57
|
|
|
57
|
-
async assign(lhsTarget: any, resolvedParams:
|
|
58
|
+
async assign(lhsTarget: any, resolvedParams: LazyLoadSwitchResolvedParams): Promise<void> {
|
|
58
59
|
const { lhs, op = '===', rhs, ...rest } = resolvedParams;
|
|
59
60
|
const condition = evaluateOp(lhs, op, rhs);
|
|
60
61
|
// Delegate to parent with computed condition
|
package/markerUtils.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* markerUtils.js — Shared utilities for comment marker management.
|
|
3
|
+
*
|
|
4
|
+
* Used by lazyLoad, microDataJoin, and future template loop handlers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const MARKER_START_PREFIX = '?start name="';
|
|
8
|
+
export const MARKER_END = '?end';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Find existing start/end comment markers (TreeWalker approach).
|
|
12
|
+
*/
|
|
13
|
+
export function findMarkers(target, name) {
|
|
14
|
+
const startText = `${MARKER_START_PREFIX}${name}"`;
|
|
15
|
+
let startMarker = null;
|
|
16
|
+
let endMarker = null;
|
|
17
|
+
|
|
18
|
+
const walker = document.createTreeWalker(target, NodeFilter.SHOW_COMMENT);
|
|
19
|
+
let node;
|
|
20
|
+
while ((node = walker.nextNode())) {
|
|
21
|
+
if (!startMarker && node.data === startText) {
|
|
22
|
+
startMarker = node;
|
|
23
|
+
} else if (startMarker && !endMarker && node.data === MARKER_END) {
|
|
24
|
+
endMarker = node;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return [startMarker, endMarker];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Find existing start/end comment markers (XPath approach).
|
|
34
|
+
*/
|
|
35
|
+
export function findMarkersXPath(target, name) {
|
|
36
|
+
const startText = `${MARKER_START_PREFIX}${name}"`;
|
|
37
|
+
|
|
38
|
+
const startResult = document.evaluate(
|
|
39
|
+
`.//comment()[. = "${startText}"]`,
|
|
40
|
+
target,
|
|
41
|
+
null,
|
|
42
|
+
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
43
|
+
null
|
|
44
|
+
);
|
|
45
|
+
const startMarker = startResult.singleNodeValue;
|
|
46
|
+
if (!startMarker) return [null, null];
|
|
47
|
+
|
|
48
|
+
const endResult = document.evaluate(
|
|
49
|
+
`following-sibling::comment()[. = "${MARKER_END}"][1]`,
|
|
50
|
+
startMarker,
|
|
51
|
+
null,
|
|
52
|
+
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
53
|
+
null
|
|
54
|
+
);
|
|
55
|
+
const endMarker = endResult.singleNodeValue;
|
|
56
|
+
|
|
57
|
+
return [startMarker, endMarker];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Create start/end markers and insert them into the target.
|
|
62
|
+
*/
|
|
63
|
+
export function createMarkers(target, name, method = 'appendChild') {
|
|
64
|
+
const startMarker = document.createComment(`${MARKER_START_PREFIX}${name}"`);
|
|
65
|
+
const endMarker = document.createComment(MARKER_END);
|
|
66
|
+
|
|
67
|
+
if (method === 'prepend') {
|
|
68
|
+
target.prepend(endMarker);
|
|
69
|
+
target.prepend(startMarker);
|
|
70
|
+
} else {
|
|
71
|
+
target.appendChild(startMarker);
|
|
72
|
+
target.appendChild(endMarker);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return [startMarker, endMarker];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get all nodes between start and end markers.
|
|
80
|
+
*/
|
|
81
|
+
export function getNodesBetweenMarkers(start, end) {
|
|
82
|
+
const nodes = [];
|
|
83
|
+
let current = start.nextSibling;
|
|
84
|
+
while (current && current !== end) {
|
|
85
|
+
nodes.push(current);
|
|
86
|
+
current = current.nextSibling;
|
|
87
|
+
}
|
|
88
|
+
return nodes;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Find existing start/end comment markers among siblings of an anchor element.
|
|
93
|
+
* Used for 'after' insertion mode.
|
|
94
|
+
*/
|
|
95
|
+
export function findMarkersSibling(anchor, name) {
|
|
96
|
+
const startText = `${MARKER_START_PREFIX}${name}"`;
|
|
97
|
+
let startMarker = null;
|
|
98
|
+
let endMarker = null;
|
|
99
|
+
|
|
100
|
+
let current = anchor.nextSibling;
|
|
101
|
+
while (current) {
|
|
102
|
+
if (current.nodeType === Node.COMMENT_NODE) {
|
|
103
|
+
if (!startMarker && current.data === startText) {
|
|
104
|
+
startMarker = current;
|
|
105
|
+
} else if (startMarker && !endMarker && current.data === MARKER_END) {
|
|
106
|
+
endMarker = current;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
current = current.nextSibling;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return [startMarker, endMarker];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Create start/end markers as siblings after an anchor element.
|
|
118
|
+
* Used for 'after' insertion mode.
|
|
119
|
+
*/
|
|
120
|
+
export function createMarkersSibling(anchor, name) {
|
|
121
|
+
const startMarker = document.createComment(`${MARKER_START_PREFIX}${name}"`);
|
|
122
|
+
const endMarker = document.createComment(MARKER_END);
|
|
123
|
+
|
|
124
|
+
anchor.after(startMarker, endMarker);
|
|
125
|
+
|
|
126
|
+
return [startMarker, endMarker];
|
|
127
|
+
}
|
package/markerUtils.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* markerUtils.ts — Shared utilities for comment marker management.
|
|
3
|
+
*
|
|
4
|
+
* Used by lazyLoad, microDataJoin, and future template loop handlers.
|
|
5
|
+
* Provides finding, creating, and traversing comment marker pairs.
|
|
6
|
+
*
|
|
7
|
+
* Markers are HTML comment nodes with specific content:
|
|
8
|
+
* - Start: <!--?start name="markerName"-->
|
|
9
|
+
* - End: <!--?end-->
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const MARKER_START_PREFIX = '?start name="';
|
|
13
|
+
export const MARKER_END = '?end';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Find existing start/end comment markers in a target element (TreeWalker approach).
|
|
17
|
+
* Searches the subtree of `target` for matching comment nodes.
|
|
18
|
+
*
|
|
19
|
+
* @param target - The element to search within
|
|
20
|
+
* @param name - The marker name to find
|
|
21
|
+
* @returns [startMarker, endMarker] or [null, null] if not found
|
|
22
|
+
*/
|
|
23
|
+
export function findMarkers(target: Element | Node, name: string): [Comment | null, Comment | null] {
|
|
24
|
+
const startText = `${MARKER_START_PREFIX}${name}"`;
|
|
25
|
+
let startMarker: Comment | null = null;
|
|
26
|
+
let endMarker: Comment | null = null;
|
|
27
|
+
|
|
28
|
+
const walker = document.createTreeWalker(target as Node, NodeFilter.SHOW_COMMENT);
|
|
29
|
+
let node: Comment | null;
|
|
30
|
+
while ((node = walker.nextNode() as Comment | null)) {
|
|
31
|
+
if (!startMarker && node.data === startText) {
|
|
32
|
+
startMarker = node;
|
|
33
|
+
} else if (startMarker && !endMarker && node.data === MARKER_END) {
|
|
34
|
+
endMarker = node;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return [startMarker, endMarker];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Find existing start/end comment markers using XPath (alternative approach).
|
|
44
|
+
* May be faster in large DOMs due to engine-level indexing.
|
|
45
|
+
*
|
|
46
|
+
* @param target - The element to search within
|
|
47
|
+
* @param name - The marker name to find
|
|
48
|
+
* @returns [startMarker, endMarker] or [null, null] if not found
|
|
49
|
+
*/
|
|
50
|
+
export function findMarkersXPath(target: Element | Node, name: string): [Comment | null, Comment | null] {
|
|
51
|
+
const startText = `${MARKER_START_PREFIX}${name}"`;
|
|
52
|
+
|
|
53
|
+
const startResult = document.evaluate(
|
|
54
|
+
`.//comment()[. = "${startText}"]`,
|
|
55
|
+
target,
|
|
56
|
+
null,
|
|
57
|
+
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
58
|
+
null
|
|
59
|
+
);
|
|
60
|
+
const startMarker = startResult.singleNodeValue as Comment | null;
|
|
61
|
+
if (!startMarker) return [null, null];
|
|
62
|
+
|
|
63
|
+
// Find the next sibling comment that is the end marker
|
|
64
|
+
const endResult = document.evaluate(
|
|
65
|
+
`following-sibling::comment()[. = "${MARKER_END}"][1]`,
|
|
66
|
+
startMarker,
|
|
67
|
+
null,
|
|
68
|
+
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
69
|
+
null
|
|
70
|
+
);
|
|
71
|
+
const endMarker = endResult.singleNodeValue as Comment | null;
|
|
72
|
+
|
|
73
|
+
return [startMarker, endMarker];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create start/end markers and insert them into the target.
|
|
78
|
+
*
|
|
79
|
+
* @param target - The element to insert markers into
|
|
80
|
+
* @param name - The marker name
|
|
81
|
+
* @param method - 'appendChild' (default) or 'prepend'
|
|
82
|
+
* @returns [startMarker, endMarker]
|
|
83
|
+
*/
|
|
84
|
+
export function createMarkers(target: Element, name: string, method: string = 'appendChild'): [Comment, Comment] {
|
|
85
|
+
const startMarker = document.createComment(`${MARKER_START_PREFIX}${name}"`);
|
|
86
|
+
const endMarker = document.createComment(MARKER_END);
|
|
87
|
+
|
|
88
|
+
if (method === 'prepend') {
|
|
89
|
+
target.prepend(endMarker);
|
|
90
|
+
target.prepend(startMarker);
|
|
91
|
+
} else {
|
|
92
|
+
target.appendChild(startMarker);
|
|
93
|
+
target.appendChild(endMarker);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return [startMarker, endMarker];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get all nodes between start and end markers.
|
|
101
|
+
*
|
|
102
|
+
* @param start - The start comment marker
|
|
103
|
+
* @param end - The end comment marker
|
|
104
|
+
* @returns Array of nodes between the markers (exclusive of markers themselves)
|
|
105
|
+
*/
|
|
106
|
+
export function getNodesBetweenMarkers(start: Comment, end: Comment): Node[] {
|
|
107
|
+
const nodes: Node[] = [];
|
|
108
|
+
let current: Node | null = start.nextSibling;
|
|
109
|
+
while (current && current !== end) {
|
|
110
|
+
nodes.push(current);
|
|
111
|
+
current = current.nextSibling;
|
|
112
|
+
}
|
|
113
|
+
return nodes;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Find existing start/end comment markers among siblings of an anchor element.
|
|
118
|
+
* Used for 'after' insertion mode where markers are siblings, not children.
|
|
119
|
+
*
|
|
120
|
+
* @param anchor - The element after which markers were inserted
|
|
121
|
+
* @param name - The marker name to find
|
|
122
|
+
* @returns [startMarker, endMarker] or [null, null] if not found
|
|
123
|
+
*/
|
|
124
|
+
export function findMarkersSibling(anchor: Element | Node, name: string): [Comment | null, Comment | null] {
|
|
125
|
+
const startText = `${MARKER_START_PREFIX}${name}"`;
|
|
126
|
+
let startMarker: Comment | null = null;
|
|
127
|
+
let endMarker: Comment | null = null;
|
|
128
|
+
|
|
129
|
+
let current: Node | null = anchor.nextSibling;
|
|
130
|
+
while (current) {
|
|
131
|
+
if (current.nodeType === Node.COMMENT_NODE) {
|
|
132
|
+
const comment = current as Comment;
|
|
133
|
+
if (!startMarker && comment.data === startText) {
|
|
134
|
+
startMarker = comment;
|
|
135
|
+
} else if (startMarker && !endMarker && comment.data === MARKER_END) {
|
|
136
|
+
endMarker = comment;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
current = current.nextSibling;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return [startMarker, endMarker];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Create start/end markers as siblings after an anchor element.
|
|
148
|
+
* Used for 'after' insertion mode.
|
|
149
|
+
*
|
|
150
|
+
* @param anchor - The element to insert markers after
|
|
151
|
+
* @param name - The marker name
|
|
152
|
+
* @returns [startMarker, endMarker]
|
|
153
|
+
*/
|
|
154
|
+
export function createMarkersSibling(anchor: Element | Node, name: string): [Comment, Comment] {
|
|
155
|
+
const startMarker = document.createComment(`${MARKER_START_PREFIX}${name}"`);
|
|
156
|
+
const endMarker = document.createComment(MARKER_END);
|
|
157
|
+
|
|
158
|
+
// Insert after the anchor: anchor → startMarker → endMarker
|
|
159
|
+
(anchor as ChildNode).after(startMarker, endMarker);
|
|
160
|
+
|
|
161
|
+
return [startMarker, endMarker];
|
|
162
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "assign-gingerly",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.57",
|
|
4
4
|
"description": "This package provides a utility function for carefully merging one object into another.",
|
|
5
5
|
"homepage": "https://github.com/bahrus/assign-gingerly#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -110,6 +110,10 @@
|
|
|
110
110
|
"default": "./isAllowedImportPath.js",
|
|
111
111
|
"types": "./isAllowedImportPath.ts"
|
|
112
112
|
},
|
|
113
|
+
"./markerUtils.js": {
|
|
114
|
+
"default": "./markerUtils.js",
|
|
115
|
+
"types": "./markerUtils.ts"
|
|
116
|
+
},
|
|
113
117
|
"./inferredAssignments.js": {
|
|
114
118
|
"default": "./inferredAssignments.js",
|
|
115
119
|
"types": "./inferredAssignments.ts"
|
|
@@ -538,15 +538,96 @@ export interface LazyLoadConfig extends HandlerConfig {
|
|
|
538
538
|
if: string;
|
|
539
539
|
/** Template element to clone (resolved via protocol or path) */
|
|
540
540
|
instantiate: string;
|
|
541
|
-
/** Insert method: 'appendChild' (default) or '
|
|
541
|
+
/** Insert method: 'appendChild' (default), 'prepend', or 'after' (sibling after target) */
|
|
542
542
|
method?: string;
|
|
543
543
|
/** If true, removes nodes when hiding instead of adding hidden attribute */
|
|
544
544
|
forget?: boolean | string;
|
|
545
|
+
/** Enable view transitions */
|
|
546
|
+
transitional?: boolean | string;
|
|
547
|
+
/** CSS class for hiding (default: 'ag-hide', only used when transitional: true) */
|
|
548
|
+
hideClass?: string;
|
|
549
|
+
/** Custom CSS for the hide class (default: 'display: none') */
|
|
550
|
+
hideCss?: string;
|
|
545
551
|
/** Optional async callback invoked after cloning, resolved from the VM */
|
|
546
552
|
onInstantiated?: string;
|
|
553
|
+
/** Override auto-derived marker name */
|
|
554
|
+
markerName?: string;
|
|
555
|
+
/** Set inert attribute on hidden elements */
|
|
556
|
+
toggleInert?: boolean | string;
|
|
557
|
+
/** Set disabled property on hidden form elements */
|
|
558
|
+
toggleDisabled?: boolean | string;
|
|
547
559
|
};
|
|
548
560
|
}
|
|
549
561
|
|
|
562
|
+
/**
|
|
563
|
+
* Resolved parameters received by LazyLoadHandler.assign() after resolveValues processing.
|
|
564
|
+
*/
|
|
565
|
+
export interface LazyLoadResolvedParams {
|
|
566
|
+
/** Condition — resolved to actual truthy/falsy value */
|
|
567
|
+
if: any;
|
|
568
|
+
/** Template element — resolved to HTMLTemplateElement or DocumentFragment */
|
|
569
|
+
instantiate: HTMLTemplateElement | DocumentFragment;
|
|
570
|
+
/** Insertion method (default: 'appendChild') */
|
|
571
|
+
method?: 'appendChild' | 'prepend' | 'after';
|
|
572
|
+
/** Remove nodes on hide instead of using hidden attribute */
|
|
573
|
+
forget?: boolean;
|
|
574
|
+
/** Enable view transitions */
|
|
575
|
+
transitional?: boolean;
|
|
576
|
+
/** CSS class for hiding (default: 'ag-hide', only used when transitional: true) */
|
|
577
|
+
hideClass?: string;
|
|
578
|
+
/** Custom CSS for the hide class (default: 'display: none') */
|
|
579
|
+
hideCss?: string;
|
|
580
|
+
/** Callback after clone+insert */
|
|
581
|
+
onInstantiated?: (ctx: LazyLoadInstantiatedContext) => void | Promise<void>;
|
|
582
|
+
/** Override auto-derived marker name */
|
|
583
|
+
markerName?: string;
|
|
584
|
+
/** Set inert attribute on hidden elements (removes from a11y tree + interaction) */
|
|
585
|
+
toggleInert?: boolean;
|
|
586
|
+
/** Set disabled property on hidden form elements */
|
|
587
|
+
toggleDisabled?: boolean;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Configuration for the builtIns.lazyLoadSwitch handler.
|
|
592
|
+
*/
|
|
593
|
+
export interface LazyLoadSwitchConfig extends HandlerConfig {
|
|
594
|
+
do: 'builtIns.lazyLoadSwitch';
|
|
595
|
+
resolve: {
|
|
596
|
+
/** Left-hand side of comparison (resolved from VM) */
|
|
597
|
+
lhs: string;
|
|
598
|
+
/** Comparison operator (default: '===') */
|
|
599
|
+
op?: '===' | '!==' | '==' | '!=' | '<' | '>' | '<=' | '>=';
|
|
600
|
+
/** Right-hand side of comparison (resolved from VM or literal) */
|
|
601
|
+
rhs: string;
|
|
602
|
+
/** Template element to clone (resolved via protocol or path) */
|
|
603
|
+
instantiate: string;
|
|
604
|
+
/** Insert method: 'appendChild' (default), 'prepend', or 'after' */
|
|
605
|
+
method?: string;
|
|
606
|
+
/** If true, removes nodes when hiding instead of adding hidden attribute */
|
|
607
|
+
forget?: boolean | string;
|
|
608
|
+
/** Enable view transitions */
|
|
609
|
+
transitional?: boolean | string;
|
|
610
|
+
/** CSS class for hiding (default: 'ag-hide', only used when transitional: true) */
|
|
611
|
+
hideClass?: string;
|
|
612
|
+
/** Custom CSS for the hide class (default: 'display: none') */
|
|
613
|
+
hideCss?: string;
|
|
614
|
+
/** Optional async callback invoked after cloning, resolved from the VM */
|
|
615
|
+
onInstantiated?: string;
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Resolved parameters received by LazyLoadSwitchHandler.assign() after resolveValues processing.
|
|
621
|
+
*/
|
|
622
|
+
export interface LazyLoadSwitchResolvedParams extends Omit<LazyLoadResolvedParams, 'if'> {
|
|
623
|
+
/** Left-hand side — resolved to actual value */
|
|
624
|
+
lhs: any;
|
|
625
|
+
/** Comparison operator (default: '===') */
|
|
626
|
+
op?: '===' | '!==' | '==' | '!=' | '<' | '>' | '<=' | '>=';
|
|
627
|
+
/** Right-hand side — resolved to actual value */
|
|
628
|
+
rhs: any;
|
|
629
|
+
}
|
|
630
|
+
|
|
550
631
|
/**
|
|
551
632
|
* Context passed to onInstantiated callbacks after template cloning.
|
|
552
633
|
*/
|