@fluffjs/fluff 0.2.4 → 0.3.0
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/bundle.min.js +1 -0
- package/decorators/Component.d.ts +0 -8
- package/decorators/Component.js +0 -11
- package/decorators/Input.d.ts +1 -1
- package/decorators/InputOutputHelper.d.ts +2 -1
- package/decorators/InputOutputHelper.js +3 -1
- package/decorators/Output.d.ts +1 -1
- package/decorators/Pipe.d.ts +1 -0
- package/decorators/Pipe.js +1 -1
- package/decorators/Reactive.d.ts +2 -1
- package/decorators/Reactive.js +1 -1
- package/index.d.ts +2 -1
- package/index.js +1 -1
- package/interfaces/FluffHostElement.d.ts +13 -3
- package/interfaces/ReactiveOptions.d.ts +6 -0
- package/interfaces/ReactiveOptions.js +1 -0
- package/package.json +1 -1
- package/runtime/FluffBase.d.ts +11 -1
- package/runtime/FluffBase.js +50 -17
- package/runtime/FluffElementImpl.d.ts +9 -21
- package/runtime/FluffElementImpl.js +48 -149
- package/runtime/ForController.js +1 -2
- package/runtime/IfController.js +1 -2
- package/runtime/MarkerConfigGuards.d.ts +0 -2
- package/runtime/MarkerConfigGuards.js +0 -3
- package/runtime/MarkerController.d.ts +1 -9
- package/runtime/MarkerController.js +28 -144
- package/runtime/MarkerManager.d.ts +2 -1
- package/runtime/MarkerManager.js +1 -2
- package/runtime/MarkerManagerInterface.d.ts +3 -1
- package/runtime/SwitchController.js +1 -2
- package/runtime/TextController.d.ts +0 -1
- package/runtime/TextController.js +5 -19
- package/runtime/tests/TestChildTasksListComponent.js +2 -2
- package/runtime/tests/TestForComponent.js +2 -2
- package/runtime/tests/TestForReinsertBindsInputParentComponent.js +2 -2
- package/runtime/tests/TestForTextMarkerCollisionNoTrackParentComponent.js +2 -2
- package/runtime/tests/TestForTextMarkerCollisionParentComponent.js +2 -2
- package/runtime/tests/TestForUnsubscribeNestedParentComponent.js +2 -2
- package/runtime/tests/TestGetterReactivityComponent.js +2 -2
- package/runtime/tests/TestHarness.d.ts +9 -0
- package/runtime/tests/TestHarness.js +29 -0
- package/runtime/tests/TestIfReinsertBindsInputChildComponent.js +2 -2
- package/runtime/tests/TestIfReinsertBindsInputParentComponent.js +2 -2
- package/runtime/tests/TestIfUnsubscribeNestedParentComponent.js +2 -2
- package/runtime/tests/TestInterpolationNestedPropertyComponentBase.js +2 -2
- package/runtime/tests/TestLateDefineForComponent.js +2 -2
- package/runtime/tests/TestNullInputTextComponent.js +2 -2
- package/runtime/tests/TestOutputBindingParentComponent.js +2 -2
- package/runtime/tests/TestParentBindsTasksComponent.js +2 -2
- package/runtime/tests/TestSwitchReinsertBindsInputChildComponent.js +2 -2
- package/runtime/tests/TestSwitchReinsertBindsInputParentComponent.js +2 -2
- package/runtime/tests/TestSwitchUnsubscribeNestedParentComponent.js +2 -2
- package/runtime/tests/TestTemplateNestedMarkersComponent.js +2 -2
- package/runtime/tests/TestUnsubscribeNestedGrandchildComponent.js +2 -2
- package/runtime/tests/createPipeUnwrapTestComponent.js +2 -2
- package/runtime/tests/createTestInterpolationPipeComponent.js +2 -2
- package/runtime/tests/createTestInterpolationPipeWithArgsComponent.js +2 -2
- package/utils/Property.d.ts +8 -2
- package/utils/Property.js +48 -8
- package/utils/DomUtils.d.ts +0 -3
- package/utils/DomUtils.js +0 -6
package/runtime/ForController.js
CHANGED
package/runtime/IfController.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import type { BreakMarkerConfig } from '../interfaces/BreakMarkerConfig.js';
|
|
2
|
-
import type { FluffHostElement } from '../interfaces/FluffHostElement.js';
|
|
3
2
|
import type { ForMarkerConfig } from '../interfaces/ForMarkerConfig.js';
|
|
4
3
|
import type { IfMarkerConfig } from '../interfaces/IfMarkerConfig.js';
|
|
5
4
|
import type { MarkerConfig } from '../interfaces/MarkerConfig.js';
|
|
6
5
|
import type { SwitchMarkerConfig } from '../interfaces/SwitchMarkerConfig.js';
|
|
7
6
|
import type { TextMarkerConfig } from '../interfaces/TextMarkerConfig.js';
|
|
8
7
|
export declare class MarkerConfigGuards {
|
|
9
|
-
static isFluffHostElement(el: Element): el is FluffHostElement;
|
|
10
8
|
static isIfConfig(config: MarkerConfig): config is IfMarkerConfig;
|
|
11
9
|
static isForConfig(config: MarkerConfig): config is ForMarkerConfig;
|
|
12
10
|
static isSwitchConfig(config: MarkerConfig): config is SwitchMarkerConfig;
|
|
@@ -2,7 +2,6 @@ import type { FluffHostElement } from '../interfaces/FluffHostElement.js';
|
|
|
2
2
|
import type { PropertyChain } from '../interfaces/PropertyChain.js';
|
|
3
3
|
import type { RenderContext } from '../interfaces/RenderContext.js';
|
|
4
4
|
import type { Subscription } from '../interfaces/Subscription.js';
|
|
5
|
-
import { Property } from '../utils/Property.js';
|
|
6
5
|
import { type Scope } from './ScopeRegistry.js';
|
|
7
6
|
interface MarkerManagerLike {
|
|
8
7
|
getController: (id: number, startMarker: Comment) => MarkerController | undefined;
|
|
@@ -27,22 +26,15 @@ export declare abstract class MarkerController {
|
|
|
27
26
|
cleanup(): void;
|
|
28
27
|
updateRenderContext(renderContext?: RenderContext): void;
|
|
29
28
|
protected evaluateExpr(exprId: number): unknown;
|
|
30
|
-
private getCompiledExprFn;
|
|
31
29
|
protected getScope(): Scope;
|
|
32
30
|
protected collectLocalsFromScope(scope: Scope): Record<string, unknown>;
|
|
33
|
-
protected
|
|
34
|
-
private subscribeToPropertyChain;
|
|
35
|
-
private subscribeToNestedChain;
|
|
36
|
-
protected getReactivePropFromScope(propName: string, scope: Scope): Property<unknown> | undefined;
|
|
31
|
+
protected subscribeAndRun(deps: PropertyChain[], callback: () => void): void;
|
|
37
32
|
protected createChildScope(locals: Record<string, unknown>): Scope;
|
|
38
33
|
protected clearContentBetweenMarkersWithCleanup(bindingsSubscriptions: Subscription[]): void;
|
|
39
34
|
protected insertBeforeEndMarker(node: Node): void;
|
|
40
35
|
protected refreshParentBindings(): void;
|
|
41
|
-
protected processBindingsOnElement(el: HTMLElement, scope: Scope): void;
|
|
42
|
-
protected processBindingsOnElementWithSubscriptions(el: HTMLElement, scope: Scope, subscriptions: Subscription[]): void;
|
|
43
36
|
private __getFluffElementHost;
|
|
44
37
|
protected setScopeOnChildren(node: Node, scope: Scope, renderContext?: RenderContext, markerManager?: MarkerManagerLike, bindingsSubscriptions?: Subscription[]): void;
|
|
45
|
-
protected insertAndScopeTemplateContent(content: Node, nodes: Node[], scope: Scope, renderContext: RenderContext | undefined, markerManager: MarkerManagerLike | undefined, bindingsSubscriptions: Subscription[]): void;
|
|
46
38
|
protected cloneAndInsertTemplate(template: HTMLTemplateElement, context: Record<string, unknown>, renderContext: RenderContext | undefined, bindingsSubscriptions: Subscription[]): void;
|
|
47
39
|
protected processBindingsOnNode(node: HTMLElement, scope: Scope, bindingsSubscriptions?: Subscription[]): void;
|
|
48
40
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { DomUtils } from '../utils/DomUtils.js';
|
|
2
|
-
import { Property } from '../utils/Property.js';
|
|
3
1
|
import { FluffBase } from './FluffBase.js';
|
|
4
2
|
import { FluffElement } from './FluffElement.js';
|
|
5
|
-
import { MarkerConfigGuards } from './MarkerConfigGuards.js';
|
|
6
3
|
import { registerScope } from './ScopeRegistry.js';
|
|
4
|
+
const MARKER_REGEX = /^fluff:(if|for|switch|text|break):(\d+)$/;
|
|
7
5
|
export class MarkerController {
|
|
8
6
|
id;
|
|
9
7
|
startMarker;
|
|
@@ -44,21 +42,20 @@ export class MarkerController {
|
|
|
44
42
|
evaluateExpr(exprId) {
|
|
45
43
|
const scope = this.getScope();
|
|
46
44
|
const allLocals = this.collectLocalsFromScope(scope);
|
|
47
|
-
|
|
45
|
+
if (scope.host.__evaluateExpr) {
|
|
46
|
+
return scope.host.__evaluateExpr(exprId, allLocals);
|
|
47
|
+
}
|
|
48
|
+
const fn = FluffBase.__e[exprId];
|
|
49
|
+
if (typeof fn !== 'function') {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
48
52
|
try {
|
|
49
53
|
return fn(scope.host, allLocals);
|
|
50
54
|
}
|
|
51
|
-
catch
|
|
55
|
+
catch {
|
|
52
56
|
return undefined;
|
|
53
57
|
}
|
|
54
58
|
}
|
|
55
|
-
getCompiledExprFn(exprId) {
|
|
56
|
-
const fn = FluffBase.__e[exprId];
|
|
57
|
-
if (typeof fn !== 'function') {
|
|
58
|
-
throw new Error(`Missing compiled expression function for exprId ${exprId}`);
|
|
59
|
-
}
|
|
60
|
-
return fn;
|
|
61
|
-
}
|
|
62
59
|
getScope() {
|
|
63
60
|
if (this.parentScope) {
|
|
64
61
|
return this.parentScope;
|
|
@@ -79,114 +76,18 @@ export class MarkerController {
|
|
|
79
76
|
Object.assign(result, scope.locals);
|
|
80
77
|
return result;
|
|
81
78
|
}
|
|
82
|
-
|
|
79
|
+
subscribeAndRun(deps, callback) {
|
|
83
80
|
const scope = this.getScope();
|
|
84
|
-
|
|
81
|
+
const filteredDeps = deps.filter(dep => {
|
|
85
82
|
if (Array.isArray(dep)) {
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
if (dep.startsWith('['))
|
|
90
|
-
continue;
|
|
91
|
-
const reactiveProp = this.getReactivePropFromScope(dep, scope);
|
|
92
|
-
if (reactiveProp) {
|
|
93
|
-
const sub = reactiveProp.onChange.subscribe(callback);
|
|
94
|
-
this.subscriptions.push(sub);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
subscribeToPropertyChain(chain, scope, callback) {
|
|
100
|
-
if (chain.length === 0)
|
|
101
|
-
return;
|
|
102
|
-
const [first, ...rest] = chain;
|
|
103
|
-
if (first.startsWith('['))
|
|
104
|
-
return;
|
|
105
|
-
const reactiveProp = this.getReactivePropFromScope(first, scope);
|
|
106
|
-
if (reactiveProp) {
|
|
107
|
-
if (rest.length === 0) {
|
|
108
|
-
this.subscriptions.push(reactiveProp.onChange.subscribe(callback));
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
let nestedSubs = [];
|
|
112
|
-
const resubscribeNested = () => {
|
|
113
|
-
for (const sub of nestedSubs) {
|
|
114
|
-
sub.unsubscribe();
|
|
115
|
-
}
|
|
116
|
-
nestedSubs = [];
|
|
117
|
-
const currentValue = reactiveProp.getValue();
|
|
118
|
-
if (currentValue !== null && currentValue !== undefined) {
|
|
119
|
-
this.subscribeToNestedChain(currentValue, rest, callback, (sub) => {
|
|
120
|
-
nestedSubs.push(sub);
|
|
121
|
-
this.subscriptions.push(sub);
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
callback();
|
|
125
|
-
};
|
|
126
|
-
this.subscriptions.push(reactiveProp.onChange.subscribe(resubscribeNested));
|
|
127
|
-
const currentValue = reactiveProp.getValue();
|
|
128
|
-
if (currentValue !== null && currentValue !== undefined) {
|
|
129
|
-
this.subscribeToNestedChain(currentValue, rest, callback, (sub) => {
|
|
130
|
-
nestedSubs.push(sub);
|
|
131
|
-
this.subscriptions.push(sub);
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
subscribeToNestedChain(obj, chain, callback, addSub) {
|
|
138
|
-
if (chain.length === 0 || obj === null || obj === undefined)
|
|
139
|
-
return;
|
|
140
|
-
const [first, ...rest] = chain;
|
|
141
|
-
const prop = Reflect.get(obj, first);
|
|
142
|
-
if (prop instanceof Property) {
|
|
143
|
-
if (rest.length === 0) {
|
|
144
|
-
addSub(prop.onChange.subscribe(callback));
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
let nestedSubs = [];
|
|
148
|
-
const resubscribeNested = () => {
|
|
149
|
-
for (const sub of nestedSubs) {
|
|
150
|
-
sub.unsubscribe();
|
|
151
|
-
}
|
|
152
|
-
nestedSubs = [];
|
|
153
|
-
const currentValue = prop.getValue();
|
|
154
|
-
if (currentValue !== null && currentValue !== undefined) {
|
|
155
|
-
this.subscribeToNestedChain(currentValue, rest, callback, (sub) => {
|
|
156
|
-
nestedSubs.push(sub);
|
|
157
|
-
addSub(sub);
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
callback();
|
|
161
|
-
};
|
|
162
|
-
addSub(prop.onChange.subscribe(resubscribeNested));
|
|
163
|
-
const currentValue = prop.getValue();
|
|
164
|
-
if (currentValue !== null && currentValue !== undefined) {
|
|
165
|
-
this.subscribeToNestedChain(currentValue, rest, callback, (sub) => {
|
|
166
|
-
nestedSubs.push(sub);
|
|
167
|
-
addSub(sub);
|
|
168
|
-
});
|
|
169
|
-
}
|
|
83
|
+
return dep.length > 0 && !dep[0].startsWith('[');
|
|
170
84
|
}
|
|
85
|
+
return !dep.startsWith('[');
|
|
86
|
+
});
|
|
87
|
+
if (scope.host.__subscribeToExpression) {
|
|
88
|
+
scope.host.__subscribeToExpression(filteredDeps, scope, callback, this.subscriptions);
|
|
171
89
|
}
|
|
172
|
-
|
|
173
|
-
this.subscribeToNestedChain(prop, rest, callback, addSub);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
getReactivePropFromScope(propName, scope) {
|
|
177
|
-
if (propName in scope.locals) {
|
|
178
|
-
return undefined;
|
|
179
|
-
}
|
|
180
|
-
if (scope.parent) {
|
|
181
|
-
return this.getReactivePropFromScope(propName, scope.parent);
|
|
182
|
-
}
|
|
183
|
-
if (MarkerConfigGuards.isFluffHostElement(scope.host) && scope.host.__getReactiveProp) {
|
|
184
|
-
const reactiveProp = scope.host.__getReactiveProp(propName);
|
|
185
|
-
if (reactiveProp instanceof Property) {
|
|
186
|
-
return reactiveProp;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return undefined;
|
|
90
|
+
callback();
|
|
190
91
|
}
|
|
191
92
|
createChildScope(locals) {
|
|
192
93
|
return {
|
|
@@ -207,7 +108,7 @@ export class MarkerController {
|
|
|
207
108
|
while (current && current !== this.endMarker) {
|
|
208
109
|
const next = current.nextSibling;
|
|
209
110
|
if (current instanceof Comment) {
|
|
210
|
-
const markerMatch =
|
|
111
|
+
const markerMatch = MARKER_REGEX.exec(current.data);
|
|
211
112
|
if (markerMatch && this.markerManager?.cleanupController) {
|
|
212
113
|
const markerId = parseInt(markerMatch[2], 10);
|
|
213
114
|
this.markerManager.cleanupController(markerId, current);
|
|
@@ -239,24 +140,12 @@ export class MarkerController {
|
|
|
239
140
|
const scope = this.getScope();
|
|
240
141
|
fluffHost.__processBindingsOnElementPublic(parent, scope);
|
|
241
142
|
}
|
|
242
|
-
processBindingsOnElement(el, scope) {
|
|
243
|
-
const fluffHost = this.__getFluffElementHost();
|
|
244
|
-
if (!fluffHost)
|
|
245
|
-
return;
|
|
246
|
-
fluffHost.__processBindingsOnElementPublic(el, scope);
|
|
247
|
-
}
|
|
248
|
-
processBindingsOnElementWithSubscriptions(el, scope, subscriptions) {
|
|
249
|
-
const fluffHost = this.__getFluffElementHost();
|
|
250
|
-
if (!fluffHost)
|
|
251
|
-
return;
|
|
252
|
-
fluffHost.__processBindingsOnElementPublic(el, scope, subscriptions);
|
|
253
|
-
}
|
|
254
143
|
__getFluffElementHost() {
|
|
255
144
|
return this.host instanceof FluffElement ? this.host : null;
|
|
256
145
|
}
|
|
257
146
|
setScopeOnChildren(node, scope, renderContext, markerManager, bindingsSubscriptions) {
|
|
258
147
|
if (node instanceof Comment) {
|
|
259
|
-
const markerMatch =
|
|
148
|
+
const markerMatch = MARKER_REGEX.exec(node.data);
|
|
260
149
|
if (markerMatch && markerManager) {
|
|
261
150
|
const [, markerType, markerIdStr] = markerMatch;
|
|
262
151
|
const markerId = parseInt(markerIdStr, 10);
|
|
@@ -290,7 +179,7 @@ export class MarkerController {
|
|
|
290
179
|
node.__parentScope = scope;
|
|
291
180
|
this.processBindingsOnNode(node, scope, bindingsSubscriptions);
|
|
292
181
|
}
|
|
293
|
-
else if (node instanceof HTMLElement &&
|
|
182
|
+
else if (node instanceof HTMLElement && customElements.get(node.tagName.toLowerCase()) !== undefined) {
|
|
294
183
|
const scopeId = registerScope(scope);
|
|
295
184
|
node.setAttribute('data-fluff-scope-id', scopeId);
|
|
296
185
|
this.processBindingsOnNode(node, scope, bindingsSubscriptions);
|
|
@@ -302,12 +191,6 @@ export class MarkerController {
|
|
|
302
191
|
this.setScopeOnChildren(child, scope, renderContext, markerManager, bindingsSubscriptions);
|
|
303
192
|
}
|
|
304
193
|
}
|
|
305
|
-
insertAndScopeTemplateContent(content, nodes, scope, renderContext, markerManager, bindingsSubscriptions) {
|
|
306
|
-
this.insertBeforeEndMarker(content);
|
|
307
|
-
for (const node of nodes) {
|
|
308
|
-
this.setScopeOnChildren(node, scope, renderContext, markerManager, bindingsSubscriptions);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
194
|
cloneAndInsertTemplate(template, context, renderContext, bindingsSubscriptions) {
|
|
312
195
|
const content = template.content.cloneNode(true);
|
|
313
196
|
if (!(content instanceof DocumentFragment)) {
|
|
@@ -315,14 +198,15 @@ export class MarkerController {
|
|
|
315
198
|
}
|
|
316
199
|
const nodes = Array.from(content.childNodes);
|
|
317
200
|
const scope = this.createChildScope(context);
|
|
318
|
-
this.
|
|
201
|
+
this.insertBeforeEndMarker(content);
|
|
202
|
+
for (const node of nodes) {
|
|
203
|
+
this.setScopeOnChildren(node, scope, renderContext, this.markerManager, bindingsSubscriptions);
|
|
204
|
+
}
|
|
319
205
|
}
|
|
320
206
|
processBindingsOnNode(node, scope, bindingsSubscriptions) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
this.processBindingsOnElement(node, scope);
|
|
326
|
-
}
|
|
207
|
+
const fluffHost = this.__getFluffElementHost();
|
|
208
|
+
if (!fluffHost)
|
|
209
|
+
return;
|
|
210
|
+
fluffHost.__processBindingsOnElementPublic(node, scope, bindingsSubscriptions);
|
|
327
211
|
}
|
|
328
212
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MarkerConfigEntries } from './MarkerManagerInterface.js';
|
|
1
2
|
import type { MarkerController } from './MarkerController.js';
|
|
2
3
|
export declare class MarkerManager {
|
|
3
4
|
private readonly controllers;
|
|
@@ -5,7 +6,7 @@ export declare class MarkerManager {
|
|
|
5
6
|
private readonly host;
|
|
6
7
|
private readonly shadowRoot;
|
|
7
8
|
constructor(host: HTMLElement, shadowRoot: ShadowRoot);
|
|
8
|
-
initializeFromConfig(
|
|
9
|
+
initializeFromConfig(entries: MarkerConfigEntries): void;
|
|
9
10
|
ensureController(id: number, type: string, startMarker: Comment, endMarker: Comment | null): MarkerController | undefined;
|
|
10
11
|
getController(id: number, startMarker: Comment): MarkerController | undefined;
|
|
11
12
|
cleanupController(id: number, startMarker?: Comment): void;
|
package/runtime/MarkerManager.js
CHANGED
|
@@ -13,8 +13,7 @@ export class MarkerManager {
|
|
|
13
13
|
this.host = host;
|
|
14
14
|
this.shadowRoot = shadowRoot;
|
|
15
15
|
}
|
|
16
|
-
initializeFromConfig(
|
|
17
|
-
const entries = JSON.parse(configJson);
|
|
16
|
+
initializeFromConfig(entries) {
|
|
18
17
|
this.configs.clear();
|
|
19
18
|
for (const [id, config] of entries) {
|
|
20
19
|
this.configs.set(id, config);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { MarkerConfig } from '../interfaces/MarkerConfig.js';
|
|
2
|
+
export type MarkerConfigEntries = [number, MarkerConfig][];
|
|
1
3
|
export interface MarkerManagerInterface {
|
|
2
|
-
initializeFromConfig: (
|
|
4
|
+
initializeFromConfig: (entries: MarkerConfigEntries) => void;
|
|
3
5
|
cleanup: () => void;
|
|
4
6
|
}
|
|
@@ -6,5 +6,4 @@ export declare class TextController extends MarkerController {
|
|
|
6
6
|
constructor(id: number, startMarker: Comment, endMarker: Comment | null, host: HTMLElement, shadowRoot: ShadowRoot, config: TextMarkerConfig);
|
|
7
7
|
initialize(): void;
|
|
8
8
|
private formatValue;
|
|
9
|
-
private applyPipe;
|
|
10
9
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { getPipeTransform } from '../decorators/Pipe.js';
|
|
2
|
-
import { Property } from '../utils/Property.js';
|
|
3
1
|
import { MarkerController } from './MarkerController.js';
|
|
4
2
|
export class TextController extends MarkerController {
|
|
5
3
|
config;
|
|
@@ -15,18 +13,16 @@ export class TextController extends MarkerController {
|
|
|
15
13
|
const pipes = this.config.pipes ?? [];
|
|
16
14
|
const update = () => {
|
|
17
15
|
let result = this.evaluateExpr(this.config.exprId);
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
result = this.applyPipe(pipe.name, result, pipe.argExprIds);
|
|
16
|
+
if (this.host.__applyPipesForController) {
|
|
17
|
+
const scope = this.getScope();
|
|
18
|
+
const allLocals = this.collectLocalsFromScope(scope);
|
|
19
|
+
result = this.host.__applyPipesForController(result, pipes, allLocals);
|
|
23
20
|
}
|
|
24
21
|
if (this.textNode) {
|
|
25
22
|
this.textNode.textContent = this.formatValue(result);
|
|
26
23
|
}
|
|
27
24
|
};
|
|
28
|
-
this.
|
|
29
|
-
update();
|
|
25
|
+
this.subscribeAndRun(deps, update);
|
|
30
26
|
}
|
|
31
27
|
formatValue(result) {
|
|
32
28
|
if (result === null || result === undefined) {
|
|
@@ -43,14 +39,4 @@ export class TextController extends MarkerController {
|
|
|
43
39
|
}
|
|
44
40
|
return '';
|
|
45
41
|
}
|
|
46
|
-
applyPipe(name, value, args) {
|
|
47
|
-
const pipes = this.host.__pipes;
|
|
48
|
-
const pipeFn = pipes?.[name] ?? getPipeTransform(name);
|
|
49
|
-
if (!pipeFn) {
|
|
50
|
-
console.warn(`Pipe "${name}" not found`);
|
|
51
|
-
return value;
|
|
52
|
-
}
|
|
53
|
-
const evaluatedArgs = args.map(arg => this.evaluateExpr(arg));
|
|
54
|
-
return pipeFn(value, ...evaluatedArgs);
|
|
55
|
-
}
|
|
56
42
|
}
|
|
@@ -17,9 +17,9 @@ export class TestChildTasksListComponent extends FluffElement {
|
|
|
17
17
|
<div class="item"></div>
|
|
18
18
|
</template>
|
|
19
19
|
`;
|
|
20
|
-
this.__setMarkerConfigs(
|
|
20
|
+
this.__setMarkerConfigs([
|
|
21
21
|
[0, { type: 'for', iterator: 'task', iterableExprId: 2, deps: ['tasks'], hasEmpty: false }]
|
|
22
|
-
])
|
|
22
|
+
]);
|
|
23
23
|
}
|
|
24
24
|
__setupBindings() {
|
|
25
25
|
this.__initializeMarkers(MarkerManager);
|
|
@@ -10,9 +10,9 @@ export class TestForComponent extends FluffElement {
|
|
|
10
10
|
<test-for-child data-lid="l0"></test-for-child>
|
|
11
11
|
</template>
|
|
12
12
|
`;
|
|
13
|
-
this.__setMarkerConfigs(
|
|
13
|
+
this.__setMarkerConfigs([
|
|
14
14
|
[0, { type: 'for', iterator: 'item', iterableExprId: 0, deps: ['items'], hasEmpty: false }]
|
|
15
|
-
])
|
|
15
|
+
]);
|
|
16
16
|
}
|
|
17
17
|
__setupBindings() {
|
|
18
18
|
this.__initializeMarkers(MarkerManager);
|
|
@@ -42,9 +42,9 @@ export class TestForReinsertBindsInputParentComponent extends FluffElement {
|
|
|
42
42
|
<div class="empty">empty</div>
|
|
43
43
|
</template>
|
|
44
44
|
`;
|
|
45
|
-
this.__setMarkerConfigs(
|
|
45
|
+
this.__setMarkerConfigs([
|
|
46
46
|
[0, { type: 'for', iterator: 'item', iterableExprId: 0, deps: ['items'], hasEmpty: true }]
|
|
47
|
-
])
|
|
47
|
+
]);
|
|
48
48
|
const bindings = {
|
|
49
49
|
l0: [{ n: 'stats', b: 'property', e: 1, d: ['stats'] }]
|
|
50
50
|
};
|
|
@@ -17,10 +17,10 @@ export class TestForTextMarkerCollisionNoTrackParentComponent extends FluffEleme
|
|
|
17
17
|
<span class="tag"><!--fluff:text:9--><!--/fluff:text:9--></span>
|
|
18
18
|
</template>
|
|
19
19
|
`;
|
|
20
|
-
this.__setMarkerConfigs(
|
|
20
|
+
this.__setMarkerConfigs([
|
|
21
21
|
[0, { type: 'for', iterator: 'tag', iterableExprId: 0, deps: ['tags'], hasEmpty: false }],
|
|
22
22
|
[9, { type: 'text', exprId: 1, deps: ['tag'] }]
|
|
23
|
-
])
|
|
23
|
+
]);
|
|
24
24
|
}
|
|
25
25
|
__setupBindings() {
|
|
26
26
|
this.__initializeMarkers(MarkerManager);
|
|
@@ -28,7 +28,7 @@ export class TestForTextMarkerCollisionParentComponent extends FluffElement {
|
|
|
28
28
|
<span class="tag"><!--fluff:text:9--><!--/fluff:text:9--></span>
|
|
29
29
|
</template>
|
|
30
30
|
`;
|
|
31
|
-
this.__setMarkerConfigs(
|
|
31
|
+
this.__setMarkerConfigs([
|
|
32
32
|
[0, { type: 'for', iterator: 'tag', iterableExprId: 0, deps: ['tags'], trackBy: 'tag', hasEmpty: false }],
|
|
33
33
|
[
|
|
34
34
|
9,
|
|
@@ -39,7 +39,7 @@ export class TestForTextMarkerCollisionParentComponent extends FluffElement {
|
|
|
39
39
|
pipes: [{ name: 'lowercase', argExprIds: [] }, { name: 'capitalize', argExprIds: [] }]
|
|
40
40
|
}
|
|
41
41
|
]
|
|
42
|
-
])
|
|
42
|
+
]);
|
|
43
43
|
}
|
|
44
44
|
__setupBindings() {
|
|
45
45
|
this.__initializeMarkers(MarkerManager);
|
|
@@ -20,9 +20,9 @@ export class TestForUnsubscribeNestedParentComponent extends TestUnsubscribeNest
|
|
|
20
20
|
<div class="empty">empty</div>
|
|
21
21
|
</template>
|
|
22
22
|
`;
|
|
23
|
-
this.__setMarkerConfigs(
|
|
23
|
+
this.__setMarkerConfigs([
|
|
24
24
|
[0, { type: 'for', iterator: 'item', iterableExprId: 0, deps: ['items'], hasEmpty: true }]
|
|
25
|
-
])
|
|
25
|
+
]);
|
|
26
26
|
const bindings = {
|
|
27
27
|
l0: [{ n: 'stats', b: 'property', e: 1, d: ['stats'] }]
|
|
28
28
|
};
|
|
@@ -16,9 +16,9 @@ export class TestGetterReactivityComponent extends FluffElement {
|
|
|
16
16
|
this.__getShadowRoot().innerHTML = `
|
|
17
17
|
<div class="count"><!--fluff:text:0--><!--/fluff:text:0--></div>
|
|
18
18
|
`;
|
|
19
|
-
this.__setMarkerConfigs(
|
|
19
|
+
this.__setMarkerConfigs([
|
|
20
20
|
[0, { type: 'text', exprId: 0, deps: ['items'], pipes: [] }]
|
|
21
|
-
])
|
|
21
|
+
]);
|
|
22
22
|
}
|
|
23
23
|
__setupBindings() {
|
|
24
24
|
this.__initializeMarkers(MarkerManager);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ExpressionFn, type HandlerFn } from '../FluffBase.js';
|
|
2
|
+
export declare class TestHarness {
|
|
3
|
+
static setExpressionTable(expressions: ExpressionFn[], handlers: HandlerFn[]): void;
|
|
4
|
+
static resetExpressionTable(): void;
|
|
5
|
+
static defineCustomElement(tag: string, ctor: CustomElementConstructor): void;
|
|
6
|
+
static mount(tag: string): HTMLElement;
|
|
7
|
+
static tick(count?: number): Promise<void>;
|
|
8
|
+
static waitForTimeout(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FluffBase } from '../FluffBase.js';
|
|
2
|
+
export class TestHarness {
|
|
3
|
+
static setExpressionTable(expressions, handlers) {
|
|
4
|
+
FluffBase.__setExpressionTable(expressions, handlers);
|
|
5
|
+
}
|
|
6
|
+
static resetExpressionTable() {
|
|
7
|
+
FluffBase.__setExpressionTable([], []);
|
|
8
|
+
}
|
|
9
|
+
static defineCustomElement(tag, ctor) {
|
|
10
|
+
if (!customElements.get(tag)) {
|
|
11
|
+
customElements.define(tag, ctor);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
static mount(tag) {
|
|
15
|
+
const el = document.createElement(tag);
|
|
16
|
+
document.body.appendChild(el);
|
|
17
|
+
return el;
|
|
18
|
+
}
|
|
19
|
+
static async tick(count = 1) {
|
|
20
|
+
for (let i = 0; i < count; i++) {
|
|
21
|
+
await Promise.resolve();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
static async waitForTimeout() {
|
|
25
|
+
await new Promise((resolve) => {
|
|
26
|
+
setTimeout(resolve, 0);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -28,9 +28,9 @@ export class TestIfReinsertBindsInputChildComponent extends FluffElement {
|
|
|
28
28
|
this.__getShadowRoot().innerHTML = `
|
|
29
29
|
<div class="total"><!--fluff:text:0--><!--/fluff:text:0--></div>
|
|
30
30
|
`;
|
|
31
|
-
this.__setMarkerConfigs(
|
|
31
|
+
this.__setMarkerConfigs([
|
|
32
32
|
[0, { type: 'text', exprId: 2, deps: ['stats'], pipes: [] }]
|
|
33
|
-
])
|
|
33
|
+
]);
|
|
34
34
|
}
|
|
35
35
|
__setupBindings() {
|
|
36
36
|
this.__initializeMarkers(MarkerManager);
|
|
@@ -39,9 +39,9 @@ export class TestIfReinsertBindsInputParentComponent extends FluffElement {
|
|
|
39
39
|
<test-if-reinsert-binds-input-child x-fluff-component data-lid="l0"></test-if-reinsert-binds-input-child>
|
|
40
40
|
</template>
|
|
41
41
|
`;
|
|
42
|
-
this.__setMarkerConfigs(
|
|
42
|
+
this.__setMarkerConfigs([
|
|
43
43
|
[0, { type: 'if', branches: [{ exprId: 0, deps: ['show'] }] }]
|
|
44
|
-
])
|
|
44
|
+
]);
|
|
45
45
|
const bindings = {
|
|
46
46
|
l0: [{ n: 'stats', b: 'property', e: 1, d: ['stats'] }]
|
|
47
47
|
};
|
|
@@ -17,9 +17,9 @@ export class TestIfUnsubscribeNestedParentComponent extends TestUnsubscribeNeste
|
|
|
17
17
|
<test-unsubscribe-nested-child x-fluff-component data-lid="l0"></test-unsubscribe-nested-child>
|
|
18
18
|
</template>
|
|
19
19
|
`;
|
|
20
|
-
this.__setMarkerConfigs(
|
|
20
|
+
this.__setMarkerConfigs([
|
|
21
21
|
[0, { type: 'if', branches: [{ exprId: 0, deps: ['show'] }] }]
|
|
22
|
-
])
|
|
22
|
+
]);
|
|
23
23
|
const bindings = {
|
|
24
24
|
l0: [{ n: 'stats', b: 'property', e: 1, d: ['stats'] }]
|
|
25
25
|
};
|
|
@@ -19,9 +19,9 @@ export class TestInterpolationNestedPropertyComponentBase extends FluffElement {
|
|
|
19
19
|
}
|
|
20
20
|
__render() {
|
|
21
21
|
this.__getShadowRoot().innerHTML = '<!--fluff:text:0--><!--/fluff:text:0-->';
|
|
22
|
-
this.__setMarkerConfigs(
|
|
22
|
+
this.__setMarkerConfigs([
|
|
23
23
|
[0, { type: 'text', exprId: 0, deps: [['hostClass', 'childProp']], pipes: [] }]
|
|
24
|
-
])
|
|
24
|
+
]);
|
|
25
25
|
}
|
|
26
26
|
__setupBindings() {
|
|
27
27
|
this.__initializeMarkers(MarkerManager);
|
|
@@ -14,9 +14,9 @@ export class TestLateDefineForComponent extends FluffElement {
|
|
|
14
14
|
<late-define-for-child x-fluff-component="" data-lid="l0"></late-define-for-child>
|
|
15
15
|
</template>
|
|
16
16
|
`;
|
|
17
|
-
this.__setMarkerConfigs(
|
|
17
|
+
this.__setMarkerConfigs([
|
|
18
18
|
[0, { type: 'for', iterator: 'column', iterableExprId: 0, deps: ['columns'], hasEmpty: false }]
|
|
19
|
-
])
|
|
19
|
+
]);
|
|
20
20
|
}
|
|
21
21
|
__setupBindings() {
|
|
22
22
|
this.__initializeMarkers(MarkerManager);
|
|
@@ -25,10 +25,10 @@ export class TestNullInputTextComponent extends FluffElement {
|
|
|
25
25
|
</template>
|
|
26
26
|
<template data-fluff-branch="test-null-input-text-0-1"></template>
|
|
27
27
|
`;
|
|
28
|
-
this.__setMarkerConfigs(
|
|
28
|
+
this.__setMarkerConfigs([
|
|
29
29
|
[0, { type: 'if', branches: [{ exprId: 0, deps: ['isEditing'] }, { exprId: undefined, deps: [] }] }],
|
|
30
30
|
[1, { type: 'text', exprId: 1, deps: ['task'], pipes: [] }]
|
|
31
|
-
])
|
|
31
|
+
]);
|
|
32
32
|
}
|
|
33
33
|
__setupBindings() {
|
|
34
34
|
this.__initializeMarkers(MarkerManager);
|
|
@@ -23,9 +23,9 @@ export class TestOutputBindingParentComponent extends FluffElement {
|
|
|
23
23
|
<test-output-binding-child x-fluff-component data-lid="l0"></test-output-binding-child>
|
|
24
24
|
</template>
|
|
25
25
|
`;
|
|
26
|
-
this.__setMarkerConfigs(
|
|
26
|
+
this.__setMarkerConfigs([
|
|
27
27
|
[0, { type: 'if', branches: [{ exprId: 0, deps: ['show'] }] }]
|
|
28
|
-
])
|
|
28
|
+
]);
|
|
29
29
|
const bindings = {
|
|
30
30
|
l0: [{ n: 'edit', b: 'event', h: 0, d: ['onChildEdit'] }]
|
|
31
31
|
};
|