@thomas-siegfried/tapout 0.0.1 → 0.0.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/LICENSE +21 -21
- package/README.md +1205 -1205
- package/package.json +55 -55
- package/src/applyBindings.ts +372 -372
- package/src/arrayToDomMapping.ts +300 -300
- package/src/attributeInterpolationMarkup.ts +91 -91
- package/src/bindingContext.ts +207 -207
- package/src/bindingEvent.ts +198 -198
- package/src/bindingProvider.ts +260 -260
- package/src/bindings.ts +963 -963
- package/src/compareArrays.ts +122 -122
- package/src/componentBinding.ts +318 -318
- package/src/componentDecorator.ts +62 -62
- package/src/components.ts +367 -367
- package/src/computed.ts +439 -439
- package/src/configure.ts +52 -52
- package/src/controlFlowBindings.ts +206 -206
- package/src/core.ts +60 -60
- package/src/decorators.ts +407 -407
- package/src/dependencyDetection.ts +76 -76
- package/src/disposable.ts +36 -36
- package/src/domData.ts +42 -42
- package/src/domNodeDisposal.ts +94 -94
- package/src/effects.ts +29 -29
- package/src/event.ts +173 -173
- package/src/expressionRewriting.ts +219 -219
- package/src/extenders.ts +102 -102
- package/src/filters.ts +91 -91
- package/src/index.ts +150 -150
- package/src/interpolationMarkup.ts +130 -130
- package/src/memoization.ts +71 -71
- package/src/namespacedBindings.ts +132 -132
- package/src/observable.ts +48 -48
- package/src/observableArray.ts +397 -397
- package/src/options.ts +25 -25
- package/src/selectExtensions.ts +68 -68
- package/src/slotBinding.ts +84 -84
- package/src/subscribable.ts +266 -266
- package/src/tasks.ts +79 -79
- package/src/templateEngine.ts +108 -108
- package/src/templateRendering.ts +399 -399
- package/src/templateRewriting.ts +94 -94
- package/src/templateSources.ts +134 -134
- package/src/utils.ts +123 -123
- package/src/utilsDom.ts +87 -87
- package/src/virtualElements.ts +153 -153
- package/src/wireParams.ts +49 -49
package/src/configure.ts
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import { options } from './options.js';
|
|
2
|
-
import { bindingHandlers, instance as providerInstance } from './bindingProvider.js';
|
|
3
|
-
import { enableInterpolationMarkup } from './interpolationMarkup.js';
|
|
4
|
-
import { enableAttributeInterpolationMarkup } from './attributeInterpolationMarkup.js';
|
|
5
|
-
import { enableNamespacedBindings } from './namespacedBindings.js';
|
|
6
|
-
import { enableTextFilter } from './filters.js';
|
|
7
|
-
|
|
8
|
-
let _enabledInterpolation = false;
|
|
9
|
-
let _enabledAttributeInterpolation = false;
|
|
10
|
-
let _enabledNamespacedBindings = false;
|
|
11
|
-
let _enabledFilters = false;
|
|
12
|
-
|
|
13
|
-
function enableFiltersGlobal(): void {
|
|
14
|
-
for (const key of Object.keys(bindingHandlers)) {
|
|
15
|
-
enableTextFilter(key);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function ensureConfigured(): void {
|
|
20
|
-
if (options.interpolation && !_enabledInterpolation) {
|
|
21
|
-
_enabledInterpolation = true;
|
|
22
|
-
enableInterpolationMarkup();
|
|
23
|
-
}
|
|
24
|
-
if (options.attributeInterpolation && !_enabledAttributeInterpolation) {
|
|
25
|
-
_enabledAttributeInterpolation = true;
|
|
26
|
-
enableAttributeInterpolationMarkup();
|
|
27
|
-
}
|
|
28
|
-
if (options.namespacedBindings && !_enabledNamespacedBindings) {
|
|
29
|
-
_enabledNamespacedBindings = true;
|
|
30
|
-
enableNamespacedBindings();
|
|
31
|
-
}
|
|
32
|
-
if (options.filters && !_enabledFilters) {
|
|
33
|
-
_enabledFilters = true;
|
|
34
|
-
enableFiltersGlobal();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function resetConfigured(): void {
|
|
39
|
-
_enabledInterpolation = false;
|
|
40
|
-
_enabledAttributeInterpolation = false;
|
|
41
|
-
_enabledNamespacedBindings = false;
|
|
42
|
-
_enabledFilters = false;
|
|
43
|
-
providerInstance.bindingCache = {};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function enableAll(): void {
|
|
47
|
-
options.interpolation = true;
|
|
48
|
-
options.attributeInterpolation = true;
|
|
49
|
-
options.namespacedBindings = true;
|
|
50
|
-
options.filters = true;
|
|
51
|
-
ensureConfigured();
|
|
52
|
-
}
|
|
1
|
+
import { options } from './options.js';
|
|
2
|
+
import { bindingHandlers, instance as providerInstance } from './bindingProvider.js';
|
|
3
|
+
import { enableInterpolationMarkup } from './interpolationMarkup.js';
|
|
4
|
+
import { enableAttributeInterpolationMarkup } from './attributeInterpolationMarkup.js';
|
|
5
|
+
import { enableNamespacedBindings } from './namespacedBindings.js';
|
|
6
|
+
import { enableTextFilter } from './filters.js';
|
|
7
|
+
|
|
8
|
+
let _enabledInterpolation = false;
|
|
9
|
+
let _enabledAttributeInterpolation = false;
|
|
10
|
+
let _enabledNamespacedBindings = false;
|
|
11
|
+
let _enabledFilters = false;
|
|
12
|
+
|
|
13
|
+
function enableFiltersGlobal(): void {
|
|
14
|
+
for (const key of Object.keys(bindingHandlers)) {
|
|
15
|
+
enableTextFilter(key);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function ensureConfigured(): void {
|
|
20
|
+
if (options.interpolation && !_enabledInterpolation) {
|
|
21
|
+
_enabledInterpolation = true;
|
|
22
|
+
enableInterpolationMarkup();
|
|
23
|
+
}
|
|
24
|
+
if (options.attributeInterpolation && !_enabledAttributeInterpolation) {
|
|
25
|
+
_enabledAttributeInterpolation = true;
|
|
26
|
+
enableAttributeInterpolationMarkup();
|
|
27
|
+
}
|
|
28
|
+
if (options.namespacedBindings && !_enabledNamespacedBindings) {
|
|
29
|
+
_enabledNamespacedBindings = true;
|
|
30
|
+
enableNamespacedBindings();
|
|
31
|
+
}
|
|
32
|
+
if (options.filters && !_enabledFilters) {
|
|
33
|
+
_enabledFilters = true;
|
|
34
|
+
enableFiltersGlobal();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function resetConfigured(): void {
|
|
39
|
+
_enabledInterpolation = false;
|
|
40
|
+
_enabledAttributeInterpolation = false;
|
|
41
|
+
_enabledNamespacedBindings = false;
|
|
42
|
+
_enabledFilters = false;
|
|
43
|
+
providerInstance.bindingCache = {};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function enableAll(): void {
|
|
47
|
+
options.interpolation = true;
|
|
48
|
+
options.attributeInterpolation = true;
|
|
49
|
+
options.namespacedBindings = true;
|
|
50
|
+
options.filters = true;
|
|
51
|
+
ensureConfigured();
|
|
52
|
+
}
|
|
@@ -1,206 +1,206 @@
|
|
|
1
|
-
import { Computed } from './computed.js';
|
|
2
|
-
import type { BindingHandler } from './bindingProvider.js';
|
|
3
|
-
import type { AllBindingsAccessor } from './expressionRewriting.js';
|
|
4
|
-
import type { CreateChildContextOptions, BindingContextOptions } from './bindingContext.js';
|
|
5
|
-
import { bindingHandlers } from './bindingProvider.js';
|
|
6
|
-
import { BindingContext } from './bindingContext.js';
|
|
7
|
-
import { applyBindingsToDescendants } from './applyBindings.js';
|
|
8
|
-
import { addDisposeCallback } from './domNodeDisposal.js';
|
|
9
|
-
import { getDependenciesCount, getCurrentComputed } from './dependencyDetection.js';
|
|
10
|
-
import { bindingEvent } from './bindingEvent.js';
|
|
11
|
-
import { nativeTemplateEngine } from './templateEngine.js';
|
|
12
|
-
import {
|
|
13
|
-
allowedVirtualElementBindings,
|
|
14
|
-
virtualChildNodes,
|
|
15
|
-
virtualEmptyNode,
|
|
16
|
-
virtualSetChildren,
|
|
17
|
-
} from './virtualElements.js';
|
|
18
|
-
import { unwrapObservable } from './utils.js';
|
|
19
|
-
import { cloneNodes } from './utilsDom.js';
|
|
20
|
-
|
|
21
|
-
// ---- if / ifnot / with ----
|
|
22
|
-
|
|
23
|
-
function makeWithIfBinding(
|
|
24
|
-
bindingKey: string,
|
|
25
|
-
isWith?: boolean,
|
|
26
|
-
isNot?: boolean,
|
|
27
|
-
): void {
|
|
28
|
-
const handler: BindingHandler = {
|
|
29
|
-
init(element, valueAccessor, allBindings, _viewModel, bindingContext) {
|
|
30
|
-
let didDisplayOnLastUpdate: boolean | undefined;
|
|
31
|
-
let savedNodes: Node[] | undefined;
|
|
32
|
-
let completeOnRender: boolean;
|
|
33
|
-
let needAsyncContext: boolean;
|
|
34
|
-
let renderOnEveryChange: boolean | undefined;
|
|
35
|
-
|
|
36
|
-
const contextOptions: Record<string, unknown> = {};
|
|
37
|
-
|
|
38
|
-
if (isWith) {
|
|
39
|
-
const as = (allBindings as AllBindingsAccessor).get('as') as string | undefined;
|
|
40
|
-
const noChildContext = (allBindings as AllBindingsAccessor).get('noChildContext') as boolean | undefined;
|
|
41
|
-
renderOnEveryChange = !(as && noChildContext);
|
|
42
|
-
contextOptions.as = as;
|
|
43
|
-
contextOptions.noChildContext = noChildContext;
|
|
44
|
-
contextOptions.exportDependencies = renderOnEveryChange;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
completeOnRender = (allBindings as AllBindingsAccessor).get('completeOn') === 'render';
|
|
48
|
-
needAsyncContext = completeOnRender || (allBindings as AllBindingsAccessor).has(bindingEvent.descendantsComplete);
|
|
49
|
-
|
|
50
|
-
const computed = new Computed(() => {
|
|
51
|
-
const value = unwrapObservable(valueAccessor());
|
|
52
|
-
const shouldDisplay = !isNot !== !value;
|
|
53
|
-
const isInitial = !savedNodes;
|
|
54
|
-
let childContext: BindingContext | undefined;
|
|
55
|
-
|
|
56
|
-
if (!renderOnEveryChange && shouldDisplay === didDisplayOnLastUpdate) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let currentBindingContext = bindingContext!;
|
|
61
|
-
if (needAsyncContext) {
|
|
62
|
-
currentBindingContext = bindingEvent.startPossiblyAsyncContentBinding(element, currentBindingContext);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (shouldDisplay) {
|
|
66
|
-
if (!isWith || renderOnEveryChange) {
|
|
67
|
-
const currentComputed = getCurrentComputed();
|
|
68
|
-
if (currentComputed) {
|
|
69
|
-
contextOptions.dataDependency = currentComputed as unknown as Computed<unknown>;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (isWith) {
|
|
74
|
-
childContext = currentBindingContext.createChildContext(
|
|
75
|
-
typeof value === 'function' ? value : valueAccessor,
|
|
76
|
-
contextOptions as CreateChildContextOptions,
|
|
77
|
-
);
|
|
78
|
-
} else if (getDependenciesCount()) {
|
|
79
|
-
childContext = currentBindingContext.extend(null, contextOptions as BindingContextOptions);
|
|
80
|
-
} else {
|
|
81
|
-
childContext = currentBindingContext;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (isInitial && getDependenciesCount()) {
|
|
86
|
-
savedNodes = cloneNodes(Array.from(virtualChildNodes(element)), true);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (shouldDisplay) {
|
|
90
|
-
if (!isInitial) {
|
|
91
|
-
virtualSetChildren(element, cloneNodes(savedNodes!));
|
|
92
|
-
}
|
|
93
|
-
applyBindingsToDescendants(childContext!, element);
|
|
94
|
-
} else {
|
|
95
|
-
virtualEmptyNode(element);
|
|
96
|
-
if (!completeOnRender) {
|
|
97
|
-
bindingEvent.notify(element, bindingEvent.childrenComplete);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
didDisplayOnLastUpdate = shouldDisplay;
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
addDisposeCallback(element, () => computed.dispose());
|
|
105
|
-
|
|
106
|
-
return { controlsDescendantBindings: true };
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
bindingHandlers[bindingKey] = handler;
|
|
111
|
-
allowedVirtualElementBindings[bindingKey] = true;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
makeWithIfBinding('if');
|
|
115
|
-
makeWithIfBinding('ifnot', false, true);
|
|
116
|
-
makeWithIfBinding('with', true);
|
|
117
|
-
|
|
118
|
-
// ---- let ----
|
|
119
|
-
|
|
120
|
-
const letHandler: BindingHandler = {
|
|
121
|
-
init(element, valueAccessor, _allBindings, _viewModel, bindingContext) {
|
|
122
|
-
const innerContext = bindingContext!.extend(
|
|
123
|
-
valueAccessor as () => Record<string, unknown>,
|
|
124
|
-
);
|
|
125
|
-
applyBindingsToDescendants(innerContext, element);
|
|
126
|
-
return { controlsDescendantBindings: true };
|
|
127
|
-
},
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
bindingHandlers['let'] = letHandler;
|
|
131
|
-
allowedVirtualElementBindings['let'] = true;
|
|
132
|
-
|
|
133
|
-
// ---- using ----
|
|
134
|
-
|
|
135
|
-
const usingHandler: BindingHandler = {
|
|
136
|
-
init(element, valueAccessor, allBindings, _viewModel, bindingContext) {
|
|
137
|
-
let options: { as?: string; noChildContext?: boolean } | undefined;
|
|
138
|
-
if ((allBindings as AllBindingsAccessor).has('as')) {
|
|
139
|
-
options = {
|
|
140
|
-
as: (allBindings as AllBindingsAccessor).get('as') as string,
|
|
141
|
-
noChildContext: (allBindings as AllBindingsAccessor).get('noChildContext') as boolean | undefined,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
const innerContext = bindingContext!.createChildContext(valueAccessor, options);
|
|
145
|
-
applyBindingsToDescendants(innerContext, element);
|
|
146
|
-
return { controlsDescendantBindings: true };
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
bindingHandlers['using'] = usingHandler;
|
|
151
|
-
allowedVirtualElementBindings['using'] = true;
|
|
152
|
-
|
|
153
|
-
// ---- foreach ----
|
|
154
|
-
|
|
155
|
-
function makeTemplateValueAccessor(valueAccessor: () => unknown): () => Record<string, unknown> {
|
|
156
|
-
return () => {
|
|
157
|
-
const modelValue = valueAccessor();
|
|
158
|
-
// Peek without setting dependency
|
|
159
|
-
const unwrappedValue = (modelValue && typeof modelValue === 'object' && 'peek' in (modelValue as Record<string, unknown>))
|
|
160
|
-
? (modelValue as { peek(): unknown }).peek()
|
|
161
|
-
: modelValue;
|
|
162
|
-
|
|
163
|
-
if (!unwrappedValue || typeof (unwrappedValue as unknown[]).length === 'number') {
|
|
164
|
-
return { foreach: modelValue, templateEngine: nativeTemplateEngine };
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
unwrapObservable(modelValue);
|
|
168
|
-
const obj = unwrappedValue as Record<string, unknown>;
|
|
169
|
-
return {
|
|
170
|
-
foreach: obj.data,
|
|
171
|
-
as: obj.as,
|
|
172
|
-
noChildContext: obj.noChildContext,
|
|
173
|
-
includeDestroyed: obj.includeDestroyed,
|
|
174
|
-
afterAdd: obj.afterAdd,
|
|
175
|
-
beforeRemove: obj.beforeRemove,
|
|
176
|
-
afterRender: obj.afterRender,
|
|
177
|
-
beforeMove: obj.beforeMove,
|
|
178
|
-
afterMove: obj.afterMove,
|
|
179
|
-
templateEngine: nativeTemplateEngine,
|
|
180
|
-
};
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const foreachHandler: BindingHandler = {
|
|
185
|
-
init(element, valueAccessor, allBindings, viewModel, bindingContext) {
|
|
186
|
-
return bindingHandlers['template'].init!(
|
|
187
|
-
element,
|
|
188
|
-
makeTemplateValueAccessor(valueAccessor),
|
|
189
|
-
allBindings,
|
|
190
|
-
viewModel,
|
|
191
|
-
bindingContext,
|
|
192
|
-
);
|
|
193
|
-
},
|
|
194
|
-
update(element, valueAccessor, allBindings, viewModel, bindingContext) {
|
|
195
|
-
return bindingHandlers['template'].update!(
|
|
196
|
-
element,
|
|
197
|
-
makeTemplateValueAccessor(valueAccessor),
|
|
198
|
-
allBindings,
|
|
199
|
-
viewModel,
|
|
200
|
-
bindingContext,
|
|
201
|
-
);
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
bindingHandlers['foreach'] = foreachHandler;
|
|
206
|
-
allowedVirtualElementBindings['foreach'] = true;
|
|
1
|
+
import { Computed } from './computed.js';
|
|
2
|
+
import type { BindingHandler } from './bindingProvider.js';
|
|
3
|
+
import type { AllBindingsAccessor } from './expressionRewriting.js';
|
|
4
|
+
import type { CreateChildContextOptions, BindingContextOptions } from './bindingContext.js';
|
|
5
|
+
import { bindingHandlers } from './bindingProvider.js';
|
|
6
|
+
import { BindingContext } from './bindingContext.js';
|
|
7
|
+
import { applyBindingsToDescendants } from './applyBindings.js';
|
|
8
|
+
import { addDisposeCallback } from './domNodeDisposal.js';
|
|
9
|
+
import { getDependenciesCount, getCurrentComputed } from './dependencyDetection.js';
|
|
10
|
+
import { bindingEvent } from './bindingEvent.js';
|
|
11
|
+
import { nativeTemplateEngine } from './templateEngine.js';
|
|
12
|
+
import {
|
|
13
|
+
allowedVirtualElementBindings,
|
|
14
|
+
virtualChildNodes,
|
|
15
|
+
virtualEmptyNode,
|
|
16
|
+
virtualSetChildren,
|
|
17
|
+
} from './virtualElements.js';
|
|
18
|
+
import { unwrapObservable } from './utils.js';
|
|
19
|
+
import { cloneNodes } from './utilsDom.js';
|
|
20
|
+
|
|
21
|
+
// ---- if / ifnot / with ----
|
|
22
|
+
|
|
23
|
+
function makeWithIfBinding(
|
|
24
|
+
bindingKey: string,
|
|
25
|
+
isWith?: boolean,
|
|
26
|
+
isNot?: boolean,
|
|
27
|
+
): void {
|
|
28
|
+
const handler: BindingHandler = {
|
|
29
|
+
init(element, valueAccessor, allBindings, _viewModel, bindingContext) {
|
|
30
|
+
let didDisplayOnLastUpdate: boolean | undefined;
|
|
31
|
+
let savedNodes: Node[] | undefined;
|
|
32
|
+
let completeOnRender: boolean;
|
|
33
|
+
let needAsyncContext: boolean;
|
|
34
|
+
let renderOnEveryChange: boolean | undefined;
|
|
35
|
+
|
|
36
|
+
const contextOptions: Record<string, unknown> = {};
|
|
37
|
+
|
|
38
|
+
if (isWith) {
|
|
39
|
+
const as = (allBindings as AllBindingsAccessor).get('as') as string | undefined;
|
|
40
|
+
const noChildContext = (allBindings as AllBindingsAccessor).get('noChildContext') as boolean | undefined;
|
|
41
|
+
renderOnEveryChange = !(as && noChildContext);
|
|
42
|
+
contextOptions.as = as;
|
|
43
|
+
contextOptions.noChildContext = noChildContext;
|
|
44
|
+
contextOptions.exportDependencies = renderOnEveryChange;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
completeOnRender = (allBindings as AllBindingsAccessor).get('completeOn') === 'render';
|
|
48
|
+
needAsyncContext = completeOnRender || (allBindings as AllBindingsAccessor).has(bindingEvent.descendantsComplete);
|
|
49
|
+
|
|
50
|
+
const computed = new Computed(() => {
|
|
51
|
+
const value = unwrapObservable(valueAccessor());
|
|
52
|
+
const shouldDisplay = !isNot !== !value;
|
|
53
|
+
const isInitial = !savedNodes;
|
|
54
|
+
let childContext: BindingContext | undefined;
|
|
55
|
+
|
|
56
|
+
if (!renderOnEveryChange && shouldDisplay === didDisplayOnLastUpdate) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let currentBindingContext = bindingContext!;
|
|
61
|
+
if (needAsyncContext) {
|
|
62
|
+
currentBindingContext = bindingEvent.startPossiblyAsyncContentBinding(element, currentBindingContext);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (shouldDisplay) {
|
|
66
|
+
if (!isWith || renderOnEveryChange) {
|
|
67
|
+
const currentComputed = getCurrentComputed();
|
|
68
|
+
if (currentComputed) {
|
|
69
|
+
contextOptions.dataDependency = currentComputed as unknown as Computed<unknown>;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (isWith) {
|
|
74
|
+
childContext = currentBindingContext.createChildContext(
|
|
75
|
+
typeof value === 'function' ? value : valueAccessor,
|
|
76
|
+
contextOptions as CreateChildContextOptions,
|
|
77
|
+
);
|
|
78
|
+
} else if (getDependenciesCount()) {
|
|
79
|
+
childContext = currentBindingContext.extend(null, contextOptions as BindingContextOptions);
|
|
80
|
+
} else {
|
|
81
|
+
childContext = currentBindingContext;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (isInitial && getDependenciesCount()) {
|
|
86
|
+
savedNodes = cloneNodes(Array.from(virtualChildNodes(element)), true);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (shouldDisplay) {
|
|
90
|
+
if (!isInitial) {
|
|
91
|
+
virtualSetChildren(element, cloneNodes(savedNodes!));
|
|
92
|
+
}
|
|
93
|
+
applyBindingsToDescendants(childContext!, element);
|
|
94
|
+
} else {
|
|
95
|
+
virtualEmptyNode(element);
|
|
96
|
+
if (!completeOnRender) {
|
|
97
|
+
bindingEvent.notify(element, bindingEvent.childrenComplete);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
didDisplayOnLastUpdate = shouldDisplay;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
addDisposeCallback(element, () => computed.dispose());
|
|
105
|
+
|
|
106
|
+
return { controlsDescendantBindings: true };
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
bindingHandlers[bindingKey] = handler;
|
|
111
|
+
allowedVirtualElementBindings[bindingKey] = true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
makeWithIfBinding('if');
|
|
115
|
+
makeWithIfBinding('ifnot', false, true);
|
|
116
|
+
makeWithIfBinding('with', true);
|
|
117
|
+
|
|
118
|
+
// ---- let ----
|
|
119
|
+
|
|
120
|
+
const letHandler: BindingHandler = {
|
|
121
|
+
init(element, valueAccessor, _allBindings, _viewModel, bindingContext) {
|
|
122
|
+
const innerContext = bindingContext!.extend(
|
|
123
|
+
valueAccessor as () => Record<string, unknown>,
|
|
124
|
+
);
|
|
125
|
+
applyBindingsToDescendants(innerContext, element);
|
|
126
|
+
return { controlsDescendantBindings: true };
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
bindingHandlers['let'] = letHandler;
|
|
131
|
+
allowedVirtualElementBindings['let'] = true;
|
|
132
|
+
|
|
133
|
+
// ---- using ----
|
|
134
|
+
|
|
135
|
+
const usingHandler: BindingHandler = {
|
|
136
|
+
init(element, valueAccessor, allBindings, _viewModel, bindingContext) {
|
|
137
|
+
let options: { as?: string; noChildContext?: boolean } | undefined;
|
|
138
|
+
if ((allBindings as AllBindingsAccessor).has('as')) {
|
|
139
|
+
options = {
|
|
140
|
+
as: (allBindings as AllBindingsAccessor).get('as') as string,
|
|
141
|
+
noChildContext: (allBindings as AllBindingsAccessor).get('noChildContext') as boolean | undefined,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const innerContext = bindingContext!.createChildContext(valueAccessor, options);
|
|
145
|
+
applyBindingsToDescendants(innerContext, element);
|
|
146
|
+
return { controlsDescendantBindings: true };
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
bindingHandlers['using'] = usingHandler;
|
|
151
|
+
allowedVirtualElementBindings['using'] = true;
|
|
152
|
+
|
|
153
|
+
// ---- foreach ----
|
|
154
|
+
|
|
155
|
+
function makeTemplateValueAccessor(valueAccessor: () => unknown): () => Record<string, unknown> {
|
|
156
|
+
return () => {
|
|
157
|
+
const modelValue = valueAccessor();
|
|
158
|
+
// Peek without setting dependency
|
|
159
|
+
const unwrappedValue = (modelValue && typeof modelValue === 'object' && 'peek' in (modelValue as Record<string, unknown>))
|
|
160
|
+
? (modelValue as { peek(): unknown }).peek()
|
|
161
|
+
: modelValue;
|
|
162
|
+
|
|
163
|
+
if (!unwrappedValue || typeof (unwrappedValue as unknown[]).length === 'number') {
|
|
164
|
+
return { foreach: modelValue, templateEngine: nativeTemplateEngine };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
unwrapObservable(modelValue);
|
|
168
|
+
const obj = unwrappedValue as Record<string, unknown>;
|
|
169
|
+
return {
|
|
170
|
+
foreach: obj.data,
|
|
171
|
+
as: obj.as,
|
|
172
|
+
noChildContext: obj.noChildContext,
|
|
173
|
+
includeDestroyed: obj.includeDestroyed,
|
|
174
|
+
afterAdd: obj.afterAdd,
|
|
175
|
+
beforeRemove: obj.beforeRemove,
|
|
176
|
+
afterRender: obj.afterRender,
|
|
177
|
+
beforeMove: obj.beforeMove,
|
|
178
|
+
afterMove: obj.afterMove,
|
|
179
|
+
templateEngine: nativeTemplateEngine,
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const foreachHandler: BindingHandler = {
|
|
185
|
+
init(element, valueAccessor, allBindings, viewModel, bindingContext) {
|
|
186
|
+
return bindingHandlers['template'].init!(
|
|
187
|
+
element,
|
|
188
|
+
makeTemplateValueAccessor(valueAccessor),
|
|
189
|
+
allBindings,
|
|
190
|
+
viewModel,
|
|
191
|
+
bindingContext,
|
|
192
|
+
);
|
|
193
|
+
},
|
|
194
|
+
update(element, valueAccessor, allBindings, viewModel, bindingContext) {
|
|
195
|
+
return bindingHandlers['template'].update!(
|
|
196
|
+
element,
|
|
197
|
+
makeTemplateValueAccessor(valueAccessor),
|
|
198
|
+
allBindings,
|
|
199
|
+
viewModel,
|
|
200
|
+
bindingContext,
|
|
201
|
+
);
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
bindingHandlers['foreach'] = foreachHandler;
|
|
206
|
+
allowedVirtualElementBindings['foreach'] = true;
|
package/src/core.ts
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
export { options } from './options.js';
|
|
2
|
-
|
|
3
|
-
export const version = '1.0.0';
|
|
4
|
-
|
|
5
|
-
export { Subscribable, Subscription, isSubscribable, isReadableSubscribable, valuesArePrimitiveAndEqual } from './subscribable.js';
|
|
6
|
-
export type { SubscriptionCallback, ReadableSubscribable } from './subscribable.js';
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
begin,
|
|
10
|
-
end,
|
|
11
|
-
registerDependency,
|
|
12
|
-
ignore,
|
|
13
|
-
getDependenciesCount,
|
|
14
|
-
getDependencies,
|
|
15
|
-
isInitial,
|
|
16
|
-
getCurrentComputed,
|
|
17
|
-
} from './dependencyDetection.js';
|
|
18
|
-
export type { TrackingFrame } from './dependencyDetection.js';
|
|
19
|
-
|
|
20
|
-
export { Observable, isObservable } from './observable.js';
|
|
21
|
-
|
|
22
|
-
export { ObservableArray, isObservableArray, DESTROY, isDestroyed } from './observableArray.js';
|
|
23
|
-
|
|
24
|
-
export { compareArrays, findMovesInArrayComparison } from './compareArrays.js';
|
|
25
|
-
export type { ArrayChange, CompareArraysOptions } from './compareArrays.js';
|
|
26
|
-
|
|
27
|
-
export { Computed, PureComputed, isComputed, isPureComputed } from './computed.js';
|
|
28
|
-
export type { ComputedOptions } from './computed.js';
|
|
29
|
-
|
|
30
|
-
export { registerExtender, throttle, debounce } from './extenders.js';
|
|
31
|
-
export type { ExtenderHandler, ExtenderMap, ExtenderOptions, RateLimitOptions } from './extenders.js';
|
|
32
|
-
|
|
33
|
-
export { effect, observe } from './effects.js';
|
|
34
|
-
export type { EffectHandle } from './effects.js';
|
|
35
|
-
|
|
36
|
-
export { Event, EventSubscribable, EventSubscription, AggregateEvent, isEvent, isEventSubscribable, isAggregateEvent } from './event.js';
|
|
37
|
-
export type { EventCallback, Constructor } from './event.js';
|
|
38
|
-
|
|
39
|
-
export { DisposableGroup } from './disposable.js';
|
|
40
|
-
export type { Disposable } from './disposable.js';
|
|
41
|
-
|
|
42
|
-
export { reactive, reactiveArray, computed, getObservable, replaceObservable } from './decorators.js';
|
|
43
|
-
|
|
44
|
-
export {
|
|
45
|
-
unwrapObservable, peekObservable, toJS, toJSON, when,
|
|
46
|
-
catchFunctionErrors,
|
|
47
|
-
} from './utils.js';
|
|
48
|
-
|
|
49
|
-
export { schedule, cancel, runEarly, resetForTesting } from './tasks.js';
|
|
50
|
-
import * as tasks from './tasks.js';
|
|
51
|
-
export { tasks };
|
|
52
|
-
|
|
53
|
-
import { Observable } from './observable.js';
|
|
54
|
-
import { Computed } from './computed.js';
|
|
55
|
-
|
|
56
|
-
export function isWritableObservable(value: unknown): value is Observable<unknown> | Computed<unknown> {
|
|
57
|
-
if (value instanceof Observable) return true;
|
|
58
|
-
if (value instanceof Computed) return value.hasWriteFunction;
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
1
|
+
export { options } from './options.js';
|
|
2
|
+
|
|
3
|
+
export const version = '1.0.0';
|
|
4
|
+
|
|
5
|
+
export { Subscribable, Subscription, isSubscribable, isReadableSubscribable, valuesArePrimitiveAndEqual } from './subscribable.js';
|
|
6
|
+
export type { SubscriptionCallback, ReadableSubscribable } from './subscribable.js';
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
begin,
|
|
10
|
+
end,
|
|
11
|
+
registerDependency,
|
|
12
|
+
ignore,
|
|
13
|
+
getDependenciesCount,
|
|
14
|
+
getDependencies,
|
|
15
|
+
isInitial,
|
|
16
|
+
getCurrentComputed,
|
|
17
|
+
} from './dependencyDetection.js';
|
|
18
|
+
export type { TrackingFrame } from './dependencyDetection.js';
|
|
19
|
+
|
|
20
|
+
export { Observable, isObservable } from './observable.js';
|
|
21
|
+
|
|
22
|
+
export { ObservableArray, isObservableArray, DESTROY, isDestroyed } from './observableArray.js';
|
|
23
|
+
|
|
24
|
+
export { compareArrays, findMovesInArrayComparison } from './compareArrays.js';
|
|
25
|
+
export type { ArrayChange, CompareArraysOptions } from './compareArrays.js';
|
|
26
|
+
|
|
27
|
+
export { Computed, PureComputed, isComputed, isPureComputed } from './computed.js';
|
|
28
|
+
export type { ComputedOptions } from './computed.js';
|
|
29
|
+
|
|
30
|
+
export { registerExtender, throttle, debounce } from './extenders.js';
|
|
31
|
+
export type { ExtenderHandler, ExtenderMap, ExtenderOptions, RateLimitOptions } from './extenders.js';
|
|
32
|
+
|
|
33
|
+
export { effect, observe } from './effects.js';
|
|
34
|
+
export type { EffectHandle } from './effects.js';
|
|
35
|
+
|
|
36
|
+
export { Event, EventSubscribable, EventSubscription, AggregateEvent, isEvent, isEventSubscribable, isAggregateEvent } from './event.js';
|
|
37
|
+
export type { EventCallback, Constructor } from './event.js';
|
|
38
|
+
|
|
39
|
+
export { DisposableGroup } from './disposable.js';
|
|
40
|
+
export type { Disposable } from './disposable.js';
|
|
41
|
+
|
|
42
|
+
export { reactive, reactiveArray, computed, getObservable, replaceObservable } from './decorators.js';
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
unwrapObservable, peekObservable, toJS, toJSON, when,
|
|
46
|
+
catchFunctionErrors,
|
|
47
|
+
} from './utils.js';
|
|
48
|
+
|
|
49
|
+
export { schedule, cancel, runEarly, resetForTesting } from './tasks.js';
|
|
50
|
+
import * as tasks from './tasks.js';
|
|
51
|
+
export { tasks };
|
|
52
|
+
|
|
53
|
+
import { Observable } from './observable.js';
|
|
54
|
+
import { Computed } from './computed.js';
|
|
55
|
+
|
|
56
|
+
export function isWritableObservable(value: unknown): value is Observable<unknown> | Computed<unknown> {
|
|
57
|
+
if (value instanceof Observable) return true;
|
|
58
|
+
if (value instanceof Computed) return value.hasWriteFunction;
|
|
59
|
+
return false;
|
|
60
|
+
}
|