@angular/core 17.0.0-next.4 → 17.0.0-next.6
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/esm2022/rxjs-interop/src/to_signal.mjs +13 -11
- package/esm2022/src/application_init.mjs +3 -3
- package/esm2022/src/application_module.mjs +3 -3
- package/esm2022/src/application_ref.mjs +23 -6
- package/esm2022/src/change_detection/differs/default_iterable_differ.mjs +1 -2
- package/esm2022/src/console.mjs +2 -2
- package/esm2022/src/core.mjs +2 -2
- package/esm2022/src/core_private_export.mjs +4 -2
- package/esm2022/src/core_render3_private_export.mjs +3 -2
- package/esm2022/src/errors.mjs +1 -1
- package/esm2022/src/hydration/api.mjs +7 -8
- package/esm2022/src/hydration/views.mjs +3 -3
- package/esm2022/src/initial_render_pending_tasks.mjs +2 -2
- package/esm2022/src/linker/compiler.mjs +2 -2
- package/esm2022/src/linker/query_list.mjs +7 -10
- package/esm2022/src/linker/view_container_ref.mjs +12 -10
- package/esm2022/src/metadata/ng_module_def.mjs +1 -1
- package/esm2022/src/render3/after_render_hooks.mjs +100 -13
- package/esm2022/src/render3/deps_tracker/api.mjs +1 -1
- package/esm2022/src/render3/deps_tracker/deps_tracker.mjs +16 -10
- package/esm2022/src/render3/index.mjs +2 -2
- package/esm2022/src/render3/instructions/control_flow.mjs +6 -4
- package/esm2022/src/render3/instructions/defer.mjs +495 -112
- package/esm2022/src/render3/instructions/defer_events.mjs +154 -0
- package/esm2022/src/render3/instructions/shared.mjs +1 -1
- package/esm2022/src/render3/instructions/template.mjs +9 -2
- package/esm2022/src/render3/interfaces/defer.mjs +64 -1
- package/esm2022/src/render3/interfaces/definition.mjs +1 -1
- package/esm2022/src/render3/local_compilation.mjs +8 -2
- package/esm2022/src/render3/metadata.mjs +2 -2
- package/esm2022/src/render3/reactive_lview_consumer.mjs +1 -1
- package/esm2022/src/render3/reactivity/effect.mjs +3 -15
- package/esm2022/src/render3/scope.mjs +10 -4
- package/esm2022/src/render3/state.mjs +2 -11
- package/esm2022/src/render3/util/view_utils.mjs +17 -3
- package/esm2022/src/signals/src/api.mjs +2 -2
- package/esm2022/src/signals/src/computed.mjs +50 -45
- package/esm2022/src/signals/src/graph.mjs +7 -2
- package/esm2022/src/signals/src/signal.mjs +11 -6
- package/esm2022/src/signals/src/watch.mjs +40 -12
- package/esm2022/src/testability/testability.mjs +5 -5
- package/esm2022/src/util/assert.mjs +6 -1
- package/esm2022/src/version.mjs +1 -1
- package/esm2022/testing/src/component_fixture.mjs +19 -2
- package/esm2022/testing/src/defer.mjs +84 -0
- package/esm2022/testing/src/logger.mjs +4 -4
- package/esm2022/testing/src/test_bed.mjs +12 -2
- package/esm2022/testing/src/test_bed_common.mjs +1 -1
- package/esm2022/testing/src/test_bed_compiler.mjs +5 -2
- package/esm2022/testing/src/testing.mjs +3 -1
- package/fesm2022/core.mjs +1691 -930
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +13 -11
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +109 -3
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +279 -49
- package/package.json +3 -3
- package/rxjs-interop/index.d.ts +1 -1
- package/schematics/migrations/block-template-entities/bundle.js +23249 -0
- package/schematics/migrations/block-template-entities/bundle.js.map +7 -0
- package/schematics/migrations.json +4 -9
- package/schematics/ng-generate/standalone-migration/bundle.js +2867 -2021
- package/schematics/ng-generate/standalone-migration/bundle.js.map +4 -4
- package/testing/index.d.ts +43 -1
- package/schematics/migrations/guard-and-resolve-interfaces/bundle.js +0 -694
- package/schematics/migrations/guard-and-resolve-interfaces/bundle.js.map +0 -7
- package/schematics/migrations/remove-module-id/bundle.js +0 -368
- package/schematics/migrations/remove-module-id/bundle.js.map +0 -7
package/fesm2022/core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v17.0.0-next.
|
|
2
|
+
* @license Angular v17.0.0-next.6
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -333,6 +333,11 @@ function assertDomNode(node) {
|
|
|
333
333
|
throwError(`The provided value must be an instance of a DOM Node but got ${stringify(node)}`);
|
|
334
334
|
}
|
|
335
335
|
}
|
|
336
|
+
function assertElement(node) {
|
|
337
|
+
if (!(node instanceof Element)) {
|
|
338
|
+
throwError(`The provided value must be an element but got ${stringify(node)}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
336
341
|
function assertIndexInRange(arr, index) {
|
|
337
342
|
assertDefined(arr, 'Array must be defined.');
|
|
338
343
|
const maxLen = arr.length;
|
|
@@ -2264,7 +2269,7 @@ function getFactoryDef(type, throwNotFound) {
|
|
|
2264
2269
|
*
|
|
2265
2270
|
* This can be used to auto-unwrap signals in various cases, or to auto-wrap non-signal values.
|
|
2266
2271
|
*/
|
|
2267
|
-
const SIGNAL = Symbol('SIGNAL');
|
|
2272
|
+
const SIGNAL = /* @__PURE__ */ Symbol('SIGNAL');
|
|
2268
2273
|
/**
|
|
2269
2274
|
* Checks if the given `value` is a reactive `Signal`.
|
|
2270
2275
|
*
|
|
@@ -2445,7 +2450,9 @@ function consumerAfterComputation(node, prevConsumer) {
|
|
|
2445
2450
|
}
|
|
2446
2451
|
}
|
|
2447
2452
|
// Truncate the producer tracking arrays.
|
|
2448
|
-
|
|
2453
|
+
// Perf note: this is essentially truncating the length to `node.nextProducerIndex`, but
|
|
2454
|
+
// benchmarking has shown that individual pop operations are faster.
|
|
2455
|
+
while (node.producerNode.length > node.nextProducerIndex) {
|
|
2449
2456
|
node.producerNode.pop();
|
|
2450
2457
|
node.producerLastReadVersion.pop();
|
|
2451
2458
|
node.producerIndexOfThis.pop();
|
|
@@ -2519,6 +2526,9 @@ function producerAddLiveConsumer(node, consumer, indexOfThis) {
|
|
|
2519
2526
|
function producerRemoveLiveConsumerAtIndex(node, idx) {
|
|
2520
2527
|
assertProducerNode(node);
|
|
2521
2528
|
assertConsumerNode(node);
|
|
2529
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode && idx >= node.liveConsumerNode.length) {
|
|
2530
|
+
throw new Error(`Assertion error: active consumer index ${idx} is out of bounds of ${node.liveConsumerNode.length} consumers)`);
|
|
2531
|
+
}
|
|
2522
2532
|
if (node.liveConsumerNode.length === 1) {
|
|
2523
2533
|
// When removing the last live consumer, we will no longer be live. We need to remove
|
|
2524
2534
|
// ourselves from our producers' tracking (which may cause consumer-producers to lose
|
|
@@ -2583,60 +2593,65 @@ function computed(computation, options) {
|
|
|
2583
2593
|
* A dedicated symbol used before a computed value has been calculated for the first time.
|
|
2584
2594
|
* Explicitly typed as `any` so we can use it as signal's value.
|
|
2585
2595
|
*/
|
|
2586
|
-
const UNSET = Symbol('UNSET');
|
|
2596
|
+
const UNSET = /* @__PURE__ */ Symbol('UNSET');
|
|
2587
2597
|
/**
|
|
2588
2598
|
* A dedicated symbol used in place of a computed signal value to indicate that a given computation
|
|
2589
2599
|
* is in progress. Used to detect cycles in computation chains.
|
|
2590
2600
|
* Explicitly typed as `any` so we can use it as signal's value.
|
|
2591
2601
|
*/
|
|
2592
|
-
const COMPUTING = Symbol('COMPUTING');
|
|
2602
|
+
const COMPUTING = /* @__PURE__ */ Symbol('COMPUTING');
|
|
2593
2603
|
/**
|
|
2594
2604
|
* A dedicated symbol used in place of a computed signal value to indicate that a given computation
|
|
2595
2605
|
* failed. The thrown error is cached until the computation gets dirty again.
|
|
2596
2606
|
* Explicitly typed as `any` so we can use it as signal's value.
|
|
2597
2607
|
*/
|
|
2598
|
-
const ERRORED = Symbol('ERRORED');
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
}
|
|
2608
|
+
const ERRORED = /* @__PURE__ */ Symbol('ERRORED');
|
|
2609
|
+
// Note: Using an IIFE here to ensure that the spread assignment is not considered
|
|
2610
|
+
// a side-effect, ending up preserving `COMPUTED_NODE` and `REACTIVE_NODE`.
|
|
2611
|
+
// TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved.
|
|
2612
|
+
const COMPUTED_NODE = /* @__PURE__ */ (() => {
|
|
2613
|
+
return {
|
|
2614
|
+
...REACTIVE_NODE,
|
|
2615
|
+
value: UNSET,
|
|
2616
|
+
dirty: true,
|
|
2617
|
+
error: null,
|
|
2618
|
+
equal: defaultEquals,
|
|
2619
|
+
producerMustRecompute(node) {
|
|
2620
|
+
// Force a recomputation if there's no current value, or if the current value is in the
|
|
2621
|
+
// process of being calculated (which should throw an error).
|
|
2622
|
+
return node.value === UNSET || node.value === COMPUTING;
|
|
2623
|
+
},
|
|
2624
|
+
producerRecomputeValue(node) {
|
|
2625
|
+
if (node.value === COMPUTING) {
|
|
2626
|
+
// Our computation somehow led to a cyclic read of itself.
|
|
2627
|
+
throw new Error('Detected cycle in computations.');
|
|
2628
|
+
}
|
|
2629
|
+
const oldValue = node.value;
|
|
2630
|
+
node.value = COMPUTING;
|
|
2631
|
+
const prevConsumer = consumerBeforeComputation(node);
|
|
2632
|
+
let newValue;
|
|
2633
|
+
try {
|
|
2634
|
+
newValue = node.computation();
|
|
2635
|
+
}
|
|
2636
|
+
catch (err) {
|
|
2637
|
+
newValue = ERRORED;
|
|
2638
|
+
node.error = err;
|
|
2639
|
+
}
|
|
2640
|
+
finally {
|
|
2641
|
+
consumerAfterComputation(node, prevConsumer);
|
|
2642
|
+
}
|
|
2643
|
+
if (oldValue !== UNSET && oldValue !== ERRORED && newValue !== ERRORED &&
|
|
2644
|
+
node.equal(oldValue, newValue)) {
|
|
2645
|
+
// No change to `valueVersion` - old and new values are
|
|
2646
|
+
// semantically equivalent.
|
|
2647
|
+
node.value = oldValue;
|
|
2648
|
+
return;
|
|
2649
|
+
}
|
|
2650
|
+
node.value = newValue;
|
|
2651
|
+
node.version++;
|
|
2652
|
+
},
|
|
2653
|
+
};
|
|
2654
|
+
})();
|
|
2640
2655
|
|
|
2641
2656
|
function defaultThrowError() {
|
|
2642
2657
|
throw new Error();
|
|
@@ -2681,11 +2696,16 @@ function setPostSignalSetFn(fn) {
|
|
|
2681
2696
|
postSignalSetFn = fn;
|
|
2682
2697
|
return prev;
|
|
2683
2698
|
}
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2699
|
+
// Note: Using an IIFE here to ensure that the spread assignment is not considered
|
|
2700
|
+
// a side-effect, ending up preserving `COMPUTED_NODE` and `REACTIVE_NODE`.
|
|
2701
|
+
// TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved.
|
|
2702
|
+
const SIGNAL_NODE = /* @__PURE__ */ (() => {
|
|
2703
|
+
return {
|
|
2704
|
+
...REACTIVE_NODE,
|
|
2705
|
+
equal: defaultEquals,
|
|
2706
|
+
readonlyFn: undefined,
|
|
2707
|
+
};
|
|
2708
|
+
})();
|
|
2689
2709
|
function signalValueChanged(node) {
|
|
2690
2710
|
node.version++;
|
|
2691
2711
|
producerNotifyConsumers(node);
|
|
@@ -2754,7 +2774,27 @@ function watch(fn, schedule, allowSignalWrites) {
|
|
|
2754
2774
|
const registerOnCleanup = (cleanupFn) => {
|
|
2755
2775
|
node.cleanupFn = cleanupFn;
|
|
2756
2776
|
};
|
|
2777
|
+
function isWatchNodeDestroyed(node) {
|
|
2778
|
+
return node.fn === null && node.schedule === null;
|
|
2779
|
+
}
|
|
2780
|
+
function destroyWatchNode(node) {
|
|
2781
|
+
if (!isWatchNodeDestroyed(node)) {
|
|
2782
|
+
consumerDestroy(node); // disconnect watcher from the reactive graph
|
|
2783
|
+
node.cleanupFn();
|
|
2784
|
+
// nullify references to the integration functions to mark node as destroyed
|
|
2785
|
+
node.fn = null;
|
|
2786
|
+
node.schedule = null;
|
|
2787
|
+
node.cleanupFn = NOOP_CLEANUP_FN;
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2757
2790
|
const run = () => {
|
|
2791
|
+
if (node.fn === null) {
|
|
2792
|
+
// trying to run a destroyed watch is noop
|
|
2793
|
+
return;
|
|
2794
|
+
}
|
|
2795
|
+
if (isInNotificationPhase()) {
|
|
2796
|
+
throw new Error(`Schedulers cannot synchronously execute watches while scheduling.`);
|
|
2797
|
+
}
|
|
2758
2798
|
node.dirty = false;
|
|
2759
2799
|
if (node.hasRun && !consumerPollProducersForChange(node)) {
|
|
2760
2800
|
return;
|
|
@@ -2774,20 +2814,28 @@ function watch(fn, schedule, allowSignalWrites) {
|
|
|
2774
2814
|
notify: () => consumerMarkDirty(node),
|
|
2775
2815
|
run,
|
|
2776
2816
|
cleanup: () => node.cleanupFn(),
|
|
2817
|
+
destroy: () => destroyWatchNode(node),
|
|
2777
2818
|
};
|
|
2778
2819
|
return node.ref;
|
|
2779
2820
|
}
|
|
2780
2821
|
const NOOP_CLEANUP_FN = () => { };
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2822
|
+
// Note: Using an IIFE here to ensure that the spread assignment is not considered
|
|
2823
|
+
// a side-effect, ending up preserving `COMPUTED_NODE` and `REACTIVE_NODE`.
|
|
2824
|
+
// TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved.
|
|
2825
|
+
const WATCH_NODE = /* @__PURE__ */ (() => {
|
|
2826
|
+
return {
|
|
2827
|
+
...REACTIVE_NODE,
|
|
2828
|
+
consumerIsAlwaysLive: true,
|
|
2829
|
+
consumerAllowSignalWrites: false,
|
|
2830
|
+
consumerMarkedDirty: (node) => {
|
|
2831
|
+
if (node.schedule !== null) {
|
|
2832
|
+
node.schedule(node.ref);
|
|
2833
|
+
}
|
|
2834
|
+
},
|
|
2835
|
+
hasRun: false,
|
|
2836
|
+
cleanupFn: NOOP_CLEANUP_FN,
|
|
2837
|
+
};
|
|
2838
|
+
})();
|
|
2791
2839
|
|
|
2792
2840
|
function setAlternateWeakRefImpl(impl) {
|
|
2793
2841
|
// TODO: remove this function
|
|
@@ -3082,6 +3130,20 @@ function clearViewRefreshFlag(lView) {
|
|
|
3082
3130
|
updateViewsToRefresh(lView, -1);
|
|
3083
3131
|
}
|
|
3084
3132
|
}
|
|
3133
|
+
/**
|
|
3134
|
+
* Walks up the LView hierarchy.
|
|
3135
|
+
* @param nestingLevel Number of times to walk up in hierarchy.
|
|
3136
|
+
* @param currentView View from which to start the lookup.
|
|
3137
|
+
*/
|
|
3138
|
+
function walkUpViews(nestingLevel, currentView) {
|
|
3139
|
+
while (nestingLevel > 0) {
|
|
3140
|
+
ngDevMode &&
|
|
3141
|
+
assertDefined(currentView[DECLARATION_VIEW], 'Declaration view should be defined if nesting level is greater than 0.');
|
|
3142
|
+
currentView = currentView[DECLARATION_VIEW];
|
|
3143
|
+
nestingLevel--;
|
|
3144
|
+
}
|
|
3145
|
+
return currentView;
|
|
3146
|
+
}
|
|
3085
3147
|
/**
|
|
3086
3148
|
* Updates the `DESCENDANT_VIEWS_TO_REFRESH` counter on the parents of the `LView` as well as the
|
|
3087
3149
|
* parents above that whose
|
|
@@ -3583,15 +3645,6 @@ function nextContextImpl(level) {
|
|
|
3583
3645
|
walkUpViews(level, instructionState.lFrame.contextLView);
|
|
3584
3646
|
return contextLView[CONTEXT];
|
|
3585
3647
|
}
|
|
3586
|
-
function walkUpViews(nestingLevel, currentView) {
|
|
3587
|
-
while (nestingLevel > 0) {
|
|
3588
|
-
ngDevMode &&
|
|
3589
|
-
assertDefined(currentView[DECLARATION_VIEW], 'Declaration view should be defined if nesting level is greater than 0.');
|
|
3590
|
-
currentView = currentView[DECLARATION_VIEW];
|
|
3591
|
-
nestingLevel--;
|
|
3592
|
-
}
|
|
3593
|
-
return currentView;
|
|
3594
|
-
}
|
|
3595
3648
|
/**
|
|
3596
3649
|
* Gets the currently selected element index.
|
|
3597
3650
|
*
|
|
@@ -7272,7 +7325,7 @@ function isPlatformBrowser(injector) {
|
|
|
7272
7325
|
*
|
|
7273
7326
|
* @deprecated For migration purposes only, to be removed soon.
|
|
7274
7327
|
*/
|
|
7275
|
-
const USE_RUNTIME_DEPS_TRACKER_FOR_JIT =
|
|
7328
|
+
const USE_RUNTIME_DEPS_TRACKER_FOR_JIT = true;
|
|
7276
7329
|
/**
|
|
7277
7330
|
* An implementation of DepsTrackerApi which will be used for JIT and local compilation.
|
|
7278
7331
|
*/
|
|
@@ -7320,12 +7373,13 @@ class DepsTracker {
|
|
|
7320
7373
|
dependencies: [
|
|
7321
7374
|
...scope.compilation.directives,
|
|
7322
7375
|
...scope.compilation.pipes,
|
|
7376
|
+
...scope.compilation.ngModules,
|
|
7323
7377
|
]
|
|
7324
7378
|
};
|
|
7325
7379
|
}
|
|
7326
7380
|
else {
|
|
7327
7381
|
if (!this.ownerNgModule.has(type)) {
|
|
7328
|
-
|
|
7382
|
+
throw new RuntimeError(1001 /* RuntimeErrorCode.RUNTIME_DEPS_ORPHAN_COMPONENT */, `Orphan component found! Trying to render the component ${type.name} without first loading the NgModule that declares it. Make sure that you import the component's NgModule in the NgModule or the standalone component in which you are trying to render this component. Also make sure the way the app is bundled and served always includes the component's NgModule before the component.`);
|
|
7329
7383
|
}
|
|
7330
7384
|
const scope = this.getNgModuleScope(this.ownerNgModule.get(type));
|
|
7331
7385
|
if (scope.compilation.isPoisoned) {
|
|
@@ -7353,12 +7407,8 @@ class DepsTracker {
|
|
|
7353
7407
|
}
|
|
7354
7408
|
/** @override */
|
|
7355
7409
|
clearScopeCacheFor(type) {
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
}
|
|
7359
|
-
else if (isComponent(type)) {
|
|
7360
|
-
this.standaloneComponentsScopeCache.delete(type);
|
|
7361
|
-
}
|
|
7410
|
+
this.ngModulesScopeCache.delete(type);
|
|
7411
|
+
this.standaloneComponentsScopeCache.delete(type);
|
|
7362
7412
|
}
|
|
7363
7413
|
/** @override */
|
|
7364
7414
|
getNgModuleScope(type) {
|
|
@@ -7432,6 +7482,12 @@ class DepsTracker {
|
|
|
7432
7482
|
// check for it.
|
|
7433
7483
|
addSet(exportedScope.exported.directives, scope.exported.directives);
|
|
7434
7484
|
addSet(exportedScope.exported.pipes, scope.exported.pipes);
|
|
7485
|
+
// Some test toolings which run in JIT mode depend on this behavior that the exported scope
|
|
7486
|
+
// should also be present in the compilation scope, even though AoT does not support this
|
|
7487
|
+
// and it is also in odds with NgModule metadata definitions. Without this some tests in
|
|
7488
|
+
// Google will fail.
|
|
7489
|
+
addSet(exportedScope.exported.directives, scope.compilation.directives);
|
|
7490
|
+
addSet(exportedScope.exported.pipes, scope.compilation.pipes);
|
|
7435
7491
|
}
|
|
7436
7492
|
else if (isPipe(exported)) {
|
|
7437
7493
|
scope.exported.pipes.add(exported);
|
|
@@ -7457,9 +7513,10 @@ class DepsTracker {
|
|
|
7457
7513
|
// Standalone components are always able to self-reference.
|
|
7458
7514
|
directives: new Set([type]),
|
|
7459
7515
|
pipes: new Set(),
|
|
7516
|
+
ngModules: new Set(),
|
|
7460
7517
|
},
|
|
7461
7518
|
};
|
|
7462
|
-
for (const rawImport of rawImports ?? []) {
|
|
7519
|
+
for (const rawImport of flatten(rawImports ?? [])) {
|
|
7463
7520
|
const imported = resolveForwardRef(rawImport);
|
|
7464
7521
|
try {
|
|
7465
7522
|
verifyStandaloneImport(imported, type);
|
|
@@ -7470,6 +7527,7 @@ class DepsTracker {
|
|
|
7470
7527
|
return ans;
|
|
7471
7528
|
}
|
|
7472
7529
|
if (isNgModule(imported)) {
|
|
7530
|
+
ans.compilation.ngModules.add(imported);
|
|
7473
7531
|
const importedScope = this.getNgModuleScope(imported);
|
|
7474
7532
|
// Short-circuit if an imported NgModule has corrupted exported scope.
|
|
7475
7533
|
if (importedScope.exported.isPoisoned) {
|
|
@@ -10849,7 +10907,7 @@ class Version {
|
|
|
10849
10907
|
/**
|
|
10850
10908
|
* @publicApi
|
|
10851
10909
|
*/
|
|
10852
|
-
const VERSION = new Version('17.0.0-next.
|
|
10910
|
+
const VERSION = new Version('17.0.0-next.6');
|
|
10853
10911
|
|
|
10854
10912
|
// This default value is when checking the hierarchy for a token.
|
|
10855
10913
|
//
|
|
@@ -11535,10 +11593,77 @@ function shouldBeIgnoredByZone(applyArgs) {
|
|
|
11535
11593
|
|
|
11536
11594
|
// Public API for Zone
|
|
11537
11595
|
|
|
11596
|
+
/**
|
|
11597
|
+
* The phase to run an `afterRender` or `afterNextRender` callback in.
|
|
11598
|
+
*
|
|
11599
|
+
* Callbacks in the same phase run in the order they are registered. Phases run in the
|
|
11600
|
+
* following order after each render:
|
|
11601
|
+
*
|
|
11602
|
+
* 1. `AfterRenderPhase.EarlyRead`
|
|
11603
|
+
* 2. `AfterRenderPhase.Write`
|
|
11604
|
+
* 3. `AfterRenderPhase.MixedReadWrite`
|
|
11605
|
+
* 4. `AfterRenderPhase.Read`
|
|
11606
|
+
*
|
|
11607
|
+
* Angular is unable to verify or enforce that phases are used correctly, and instead
|
|
11608
|
+
* relies on each developer to follow the guidelines documented for each value and
|
|
11609
|
+
* carefully choose the appropriate one, refactoring their code if necessary. By doing
|
|
11610
|
+
* so, Angular is better able to minimize the performance degradation associated with
|
|
11611
|
+
* manual DOM access, ensuring the best experience for the end users of your application
|
|
11612
|
+
* or library.
|
|
11613
|
+
*
|
|
11614
|
+
* @developerPreview
|
|
11615
|
+
*/
|
|
11616
|
+
var AfterRenderPhase;
|
|
11617
|
+
(function (AfterRenderPhase) {
|
|
11618
|
+
/**
|
|
11619
|
+
* Use `AfterRenderPhase.EarlyRead` for callbacks that only need to **read** from the
|
|
11620
|
+
* DOM before a subsequent `AfterRenderPhase.Write` callback, for example to perform
|
|
11621
|
+
* custom layout that the browser doesn't natively support. **Never** use this phase
|
|
11622
|
+
* for callbacks that can write to the DOM or when `AfterRenderPhase.Read` is adequate.
|
|
11623
|
+
*
|
|
11624
|
+
* <div class="alert is-important">
|
|
11625
|
+
*
|
|
11626
|
+
* Using this value can degrade performance.
|
|
11627
|
+
* Instead, prefer using built-in browser functionality when possible.
|
|
11628
|
+
*
|
|
11629
|
+
* </div>
|
|
11630
|
+
*/
|
|
11631
|
+
AfterRenderPhase[AfterRenderPhase["EarlyRead"] = 0] = "EarlyRead";
|
|
11632
|
+
/**
|
|
11633
|
+
* Use `AfterRenderPhase.Write` for callbacks that only **write** to the DOM. **Never**
|
|
11634
|
+
* use this phase for callbacks that can read from the DOM.
|
|
11635
|
+
*/
|
|
11636
|
+
AfterRenderPhase[AfterRenderPhase["Write"] = 1] = "Write";
|
|
11637
|
+
/**
|
|
11638
|
+
* Use `AfterRenderPhase.MixedReadWrite` for callbacks that read from or write to the
|
|
11639
|
+
* DOM, that haven't been refactored to use a different phase. **Never** use this phase
|
|
11640
|
+
* for callbacks that can use a different phase instead.
|
|
11641
|
+
*
|
|
11642
|
+
* <div class="alert is-critical">
|
|
11643
|
+
*
|
|
11644
|
+
* Using this value can **significantly** degrade performance.
|
|
11645
|
+
* Instead, prefer refactoring into multiple callbacks using a more specific phase.
|
|
11646
|
+
*
|
|
11647
|
+
* </div>
|
|
11648
|
+
*/
|
|
11649
|
+
AfterRenderPhase[AfterRenderPhase["MixedReadWrite"] = 2] = "MixedReadWrite";
|
|
11650
|
+
/**
|
|
11651
|
+
* Use `AfterRenderPhase.Read` for callbacks that only **read** from the DOM. **Never**
|
|
11652
|
+
* use this phase for callbacks that can write to the DOM.
|
|
11653
|
+
*/
|
|
11654
|
+
AfterRenderPhase[AfterRenderPhase["Read"] = 3] = "Read";
|
|
11655
|
+
})(AfterRenderPhase || (AfterRenderPhase = {}));
|
|
11538
11656
|
/**
|
|
11539
11657
|
* Register a callback to be invoked each time the application
|
|
11540
11658
|
* finishes rendering.
|
|
11541
11659
|
*
|
|
11660
|
+
* <div class="alert is-critical">
|
|
11661
|
+
*
|
|
11662
|
+
* You should always explicitly specify a non-default [phase](api/core/AfterRenderPhase), or you
|
|
11663
|
+
* risk significant performance degradation.
|
|
11664
|
+
*
|
|
11665
|
+
* </div>
|
|
11666
|
+
*
|
|
11542
11667
|
* Note that the callback will run
|
|
11543
11668
|
* - in the order it was registered
|
|
11544
11669
|
* - once per render
|
|
@@ -11569,7 +11694,7 @@ function shouldBeIgnoredByZone(applyArgs) {
|
|
|
11569
11694
|
* constructor() {
|
|
11570
11695
|
* afterRender(() => {
|
|
11571
11696
|
* console.log('content height: ' + this.contentRef.nativeElement.scrollHeight);
|
|
11572
|
-
* });
|
|
11697
|
+
* }, {phase: AfterRenderPhase.Read});
|
|
11573
11698
|
* }
|
|
11574
11699
|
* }
|
|
11575
11700
|
* ```
|
|
@@ -11590,7 +11715,8 @@ function afterRender(callback, options) {
|
|
|
11590
11715
|
const callbackHandler = afterRenderEventManager.handler ??= new AfterRenderCallbackHandlerImpl();
|
|
11591
11716
|
const ngZone = injector.get(NgZone);
|
|
11592
11717
|
const errorHandler = injector.get(ErrorHandler, null, { optional: true });
|
|
11593
|
-
const
|
|
11718
|
+
const phase = options?.phase ?? AfterRenderPhase.MixedReadWrite;
|
|
11719
|
+
const instance = new AfterRenderCallback(ngZone, errorHandler, phase, callback);
|
|
11594
11720
|
destroy = () => {
|
|
11595
11721
|
callbackHandler.unregister(instance);
|
|
11596
11722
|
unregisterFn();
|
|
@@ -11602,6 +11728,13 @@ function afterRender(callback, options) {
|
|
|
11602
11728
|
* Register a callback to be invoked the next time the application
|
|
11603
11729
|
* finishes rendering.
|
|
11604
11730
|
*
|
|
11731
|
+
* <div class="alert is-critical">
|
|
11732
|
+
*
|
|
11733
|
+
* You should always explicitly specify a non-default [phase](api/core/AfterRenderPhase), or you
|
|
11734
|
+
* risk significant performance degradation.
|
|
11735
|
+
*
|
|
11736
|
+
* </div>
|
|
11737
|
+
*
|
|
11605
11738
|
* Note that the callback will run
|
|
11606
11739
|
* - in the order it was registered
|
|
11607
11740
|
* - on browser platforms only
|
|
@@ -11633,7 +11766,7 @@ function afterRender(callback, options) {
|
|
|
11633
11766
|
* constructor() {
|
|
11634
11767
|
* afterNextRender(() => {
|
|
11635
11768
|
* this.chart = new MyChart(this.chartRef.nativeElement);
|
|
11636
|
-
* });
|
|
11769
|
+
* }, {phase: AfterRenderPhase.Write});
|
|
11637
11770
|
* }
|
|
11638
11771
|
* }
|
|
11639
11772
|
* ```
|
|
@@ -11654,7 +11787,8 @@ function afterNextRender(callback, options) {
|
|
|
11654
11787
|
const callbackHandler = afterRenderEventManager.handler ??= new AfterRenderCallbackHandlerImpl();
|
|
11655
11788
|
const ngZone = injector.get(NgZone);
|
|
11656
11789
|
const errorHandler = injector.get(ErrorHandler, null, { optional: true });
|
|
11657
|
-
const
|
|
11790
|
+
const phase = options?.phase ?? AfterRenderPhase.MixedReadWrite;
|
|
11791
|
+
const instance = new AfterRenderCallback(ngZone, errorHandler, phase, () => {
|
|
11658
11792
|
destroy?.();
|
|
11659
11793
|
callback();
|
|
11660
11794
|
});
|
|
@@ -11669,9 +11803,10 @@ function afterNextRender(callback, options) {
|
|
|
11669
11803
|
* A wrapper around a function to be used as an after render callback.
|
|
11670
11804
|
*/
|
|
11671
11805
|
class AfterRenderCallback {
|
|
11672
|
-
constructor(zone, errorHandler, callbackFn) {
|
|
11806
|
+
constructor(zone, errorHandler, phase, callbackFn) {
|
|
11673
11807
|
this.zone = zone;
|
|
11674
11808
|
this.errorHandler = errorHandler;
|
|
11809
|
+
this.phase = phase;
|
|
11675
11810
|
this.callbackFn = callbackFn;
|
|
11676
11811
|
}
|
|
11677
11812
|
invoke() {
|
|
@@ -11690,7 +11825,13 @@ class AfterRenderCallback {
|
|
|
11690
11825
|
class AfterRenderCallbackHandlerImpl {
|
|
11691
11826
|
constructor() {
|
|
11692
11827
|
this.executingCallbacks = false;
|
|
11693
|
-
this.
|
|
11828
|
+
this.buckets = {
|
|
11829
|
+
// Note: the order of these keys controls the order the phases are run.
|
|
11830
|
+
[AfterRenderPhase.EarlyRead]: new Set(),
|
|
11831
|
+
[AfterRenderPhase.Write]: new Set(),
|
|
11832
|
+
[AfterRenderPhase.MixedReadWrite]: new Set(),
|
|
11833
|
+
[AfterRenderPhase.Read]: new Set(),
|
|
11834
|
+
};
|
|
11694
11835
|
this.deferredCallbacks = new Set();
|
|
11695
11836
|
}
|
|
11696
11837
|
validateBegin() {
|
|
@@ -11703,26 +11844,30 @@ class AfterRenderCallbackHandlerImpl {
|
|
|
11703
11844
|
register(callback) {
|
|
11704
11845
|
// If we're currently running callbacks, new callbacks should be deferred
|
|
11705
11846
|
// until the next render operation.
|
|
11706
|
-
const target = this.executingCallbacks ? this.deferredCallbacks : this.
|
|
11847
|
+
const target = this.executingCallbacks ? this.deferredCallbacks : this.buckets[callback.phase];
|
|
11707
11848
|
target.add(callback);
|
|
11708
11849
|
}
|
|
11709
11850
|
unregister(callback) {
|
|
11710
|
-
this.
|
|
11851
|
+
this.buckets[callback.phase].delete(callback);
|
|
11711
11852
|
this.deferredCallbacks.delete(callback);
|
|
11712
11853
|
}
|
|
11713
11854
|
execute() {
|
|
11714
11855
|
this.executingCallbacks = true;
|
|
11715
|
-
for (const
|
|
11716
|
-
callback
|
|
11856
|
+
for (const bucket of Object.values(this.buckets)) {
|
|
11857
|
+
for (const callback of bucket) {
|
|
11858
|
+
callback.invoke();
|
|
11859
|
+
}
|
|
11717
11860
|
}
|
|
11718
11861
|
this.executingCallbacks = false;
|
|
11719
11862
|
for (const callback of this.deferredCallbacks) {
|
|
11720
|
-
this.
|
|
11863
|
+
this.buckets[callback.phase].add(callback);
|
|
11721
11864
|
}
|
|
11722
11865
|
this.deferredCallbacks.clear();
|
|
11723
11866
|
}
|
|
11724
11867
|
destroy() {
|
|
11725
|
-
this.
|
|
11868
|
+
for (const bucket of Object.values(this.buckets)) {
|
|
11869
|
+
bucket.clear();
|
|
11870
|
+
}
|
|
11726
11871
|
this.deferredCallbacks.clear();
|
|
11727
11872
|
}
|
|
11728
11873
|
}
|
|
@@ -17636,7 +17781,6 @@ class DefaultIterableDiffer {
|
|
|
17636
17781
|
this.length = index;
|
|
17637
17782
|
}
|
|
17638
17783
|
this._truncate(record);
|
|
17639
|
-
// @ts-expect-error overwriting a readonly member
|
|
17640
17784
|
this.collection = collection;
|
|
17641
17785
|
return this.isDirty;
|
|
17642
17786
|
}
|
|
@@ -18584,67 +18728,6 @@ const defaultKeyValueDiffers = new KeyValueDiffers(keyValDiff);
|
|
|
18584
18728
|
* Change detection enables data binding in Angular.
|
|
18585
18729
|
*/
|
|
18586
18730
|
|
|
18587
|
-
function createAndRenderEmbeddedLView(declarationLView, templateTNode, context, options) {
|
|
18588
|
-
const embeddedTView = templateTNode.tView;
|
|
18589
|
-
ngDevMode && assertDefined(embeddedTView, 'TView must be defined for a template node.');
|
|
18590
|
-
ngDevMode && assertTNodeForLView(templateTNode, declarationLView);
|
|
18591
|
-
// Embedded views follow the change detection strategy of the view they're declared in.
|
|
18592
|
-
const isSignalView = declarationLView[FLAGS] & 4096 /* LViewFlags.SignalView */;
|
|
18593
|
-
const viewFlags = isSignalView ? 4096 /* LViewFlags.SignalView */ : 16 /* LViewFlags.CheckAlways */;
|
|
18594
|
-
const embeddedLView = createLView(declarationLView, embeddedTView, context, viewFlags, null, templateTNode, null, null, null, options?.injector ?? null, options?.dehydratedView ?? null);
|
|
18595
|
-
const declarationLContainer = declarationLView[templateTNode.index];
|
|
18596
|
-
ngDevMode && assertLContainer(declarationLContainer);
|
|
18597
|
-
embeddedLView[DECLARATION_LCONTAINER] = declarationLContainer;
|
|
18598
|
-
const declarationViewLQueries = declarationLView[QUERIES];
|
|
18599
|
-
if (declarationViewLQueries !== null) {
|
|
18600
|
-
embeddedLView[QUERIES] = declarationViewLQueries.createEmbeddedView(embeddedTView);
|
|
18601
|
-
}
|
|
18602
|
-
// execute creation mode of a view
|
|
18603
|
-
renderView(embeddedTView, embeddedLView, context);
|
|
18604
|
-
return embeddedLView;
|
|
18605
|
-
}
|
|
18606
|
-
function getLViewFromLContainer(lContainer, index) {
|
|
18607
|
-
const adjustedIndex = CONTAINER_HEADER_OFFSET + index;
|
|
18608
|
-
// avoid reading past the array boundaries
|
|
18609
|
-
if (adjustedIndex < lContainer.length) {
|
|
18610
|
-
const lView = lContainer[adjustedIndex];
|
|
18611
|
-
ngDevMode && assertLView(lView);
|
|
18612
|
-
return lView;
|
|
18613
|
-
}
|
|
18614
|
-
return undefined;
|
|
18615
|
-
}
|
|
18616
|
-
/**
|
|
18617
|
-
* Returns whether an elements that belong to a view should be
|
|
18618
|
-
* inserted into the DOM. For client-only cases, DOM elements are
|
|
18619
|
-
* always inserted. For hydration cases, we check whether serialized
|
|
18620
|
-
* info is available for a view and the view is not in a "skip hydration"
|
|
18621
|
-
* block (in which case view contents was re-created, thus needing insertion).
|
|
18622
|
-
*/
|
|
18623
|
-
function shouldAddViewToDom(tNode, dehydratedView) {
|
|
18624
|
-
return !dehydratedView || hasInSkipHydrationBlockFlag(tNode);
|
|
18625
|
-
}
|
|
18626
|
-
function addLViewToLContainer(lContainer, lView, index, addToDOM = true) {
|
|
18627
|
-
const tView = lView[TVIEW];
|
|
18628
|
-
// insert to the view tree so the new view can be change-detected
|
|
18629
|
-
insertView(tView, lView, lContainer, index);
|
|
18630
|
-
// insert to the view to the DOM tree
|
|
18631
|
-
if (addToDOM) {
|
|
18632
|
-
const beforeNode = getBeforeNodeForView(index, lContainer);
|
|
18633
|
-
const renderer = lView[RENDERER];
|
|
18634
|
-
const parentRNode = nativeParentNode(renderer, lContainer[NATIVE]);
|
|
18635
|
-
if (parentRNode !== null) {
|
|
18636
|
-
addViewToDOM(tView, lContainer[T_HOST], renderer, lView, parentRNode, beforeNode);
|
|
18637
|
-
}
|
|
18638
|
-
}
|
|
18639
|
-
}
|
|
18640
|
-
function removeLViewFromLContainer(lContainer, index) {
|
|
18641
|
-
const lView = detachView(lContainer, index);
|
|
18642
|
-
if (lView !== undefined) {
|
|
18643
|
-
destroyLView(lView[TVIEW], lView);
|
|
18644
|
-
}
|
|
18645
|
-
return lView;
|
|
18646
|
-
}
|
|
18647
|
-
|
|
18648
18731
|
const AT_THIS_LOCATION = '<-- AT THIS LOCATION';
|
|
18649
18732
|
/**
|
|
18650
18733
|
* Retrieves a user friendly string for a given TNodeType for use in
|
|
@@ -19005,6 +19088,95 @@ function shorten(input, maxLength = 50) {
|
|
|
19005
19088
|
return input.length > maxLength ? `${input.substring(0, maxLength - 1)}…` : input;
|
|
19006
19089
|
}
|
|
19007
19090
|
|
|
19091
|
+
/**
|
|
19092
|
+
* Removes all dehydrated views from a given LContainer:
|
|
19093
|
+
* both in internal data structure, as well as removing
|
|
19094
|
+
* corresponding DOM nodes that belong to that dehydrated view.
|
|
19095
|
+
*/
|
|
19096
|
+
function removeDehydratedViews(lContainer) {
|
|
19097
|
+
const views = lContainer[DEHYDRATED_VIEWS] ?? [];
|
|
19098
|
+
const parentLView = lContainer[PARENT];
|
|
19099
|
+
const renderer = parentLView[RENDERER];
|
|
19100
|
+
for (const view of views) {
|
|
19101
|
+
removeDehydratedView(view, renderer);
|
|
19102
|
+
ngDevMode && ngDevMode.dehydratedViewsRemoved++;
|
|
19103
|
+
}
|
|
19104
|
+
// Reset the value to an empty array to indicate that no
|
|
19105
|
+
// further processing of dehydrated views is needed for
|
|
19106
|
+
// this view container (i.e. do not trigger the lookup process
|
|
19107
|
+
// once again in case a `ViewContainerRef` is created later).
|
|
19108
|
+
lContainer[DEHYDRATED_VIEWS] = EMPTY_ARRAY;
|
|
19109
|
+
}
|
|
19110
|
+
/**
|
|
19111
|
+
* Helper function to remove all nodes from a dehydrated view.
|
|
19112
|
+
*/
|
|
19113
|
+
function removeDehydratedView(dehydratedView, renderer) {
|
|
19114
|
+
let nodesRemoved = 0;
|
|
19115
|
+
let currentRNode = dehydratedView.firstChild;
|
|
19116
|
+
if (currentRNode) {
|
|
19117
|
+
const numNodes = dehydratedView.data[NUM_ROOT_NODES];
|
|
19118
|
+
while (nodesRemoved < numNodes) {
|
|
19119
|
+
ngDevMode && validateSiblingNodeExists(currentRNode);
|
|
19120
|
+
const nextSibling = currentRNode.nextSibling;
|
|
19121
|
+
nativeRemoveNode(renderer, currentRNode, false);
|
|
19122
|
+
currentRNode = nextSibling;
|
|
19123
|
+
nodesRemoved++;
|
|
19124
|
+
}
|
|
19125
|
+
}
|
|
19126
|
+
}
|
|
19127
|
+
/**
|
|
19128
|
+
* Walks over all views within this LContainer invokes dehydrated views
|
|
19129
|
+
* cleanup function for each one.
|
|
19130
|
+
*/
|
|
19131
|
+
function cleanupLContainer(lContainer) {
|
|
19132
|
+
removeDehydratedViews(lContainer);
|
|
19133
|
+
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
19134
|
+
cleanupLView(lContainer[i]);
|
|
19135
|
+
}
|
|
19136
|
+
}
|
|
19137
|
+
/**
|
|
19138
|
+
* Walks over `LContainer`s and components registered within
|
|
19139
|
+
* this LView and invokes dehydrated views cleanup function for each one.
|
|
19140
|
+
*/
|
|
19141
|
+
function cleanupLView(lView) {
|
|
19142
|
+
const tView = lView[TVIEW];
|
|
19143
|
+
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
|
|
19144
|
+
if (isLContainer(lView[i])) {
|
|
19145
|
+
const lContainer = lView[i];
|
|
19146
|
+
cleanupLContainer(lContainer);
|
|
19147
|
+
}
|
|
19148
|
+
else if (isLView(lView[i])) {
|
|
19149
|
+
// This is a component, enter the `cleanupLView` recursively.
|
|
19150
|
+
cleanupLView(lView[i]);
|
|
19151
|
+
}
|
|
19152
|
+
}
|
|
19153
|
+
}
|
|
19154
|
+
/**
|
|
19155
|
+
* Walks over all views registered within the ApplicationRef and removes
|
|
19156
|
+
* all dehydrated views from all `LContainer`s along the way.
|
|
19157
|
+
*/
|
|
19158
|
+
function cleanupDehydratedViews(appRef) {
|
|
19159
|
+
const viewRefs = appRef._views;
|
|
19160
|
+
for (const viewRef of viewRefs) {
|
|
19161
|
+
const lNode = getLNodeForHydration(viewRef);
|
|
19162
|
+
// An `lView` might be `null` if a `ViewRef` represents
|
|
19163
|
+
// an embedded view (not a component view).
|
|
19164
|
+
if (lNode !== null && lNode[HOST] !== null) {
|
|
19165
|
+
if (isLView(lNode)) {
|
|
19166
|
+
cleanupLView(lNode);
|
|
19167
|
+
}
|
|
19168
|
+
else {
|
|
19169
|
+
// Cleanup in the root component view
|
|
19170
|
+
const componentLView = lNode[HOST];
|
|
19171
|
+
cleanupLView(componentLView);
|
|
19172
|
+
// Cleanup in all views within this view container
|
|
19173
|
+
cleanupLContainer(lNode);
|
|
19174
|
+
}
|
|
19175
|
+
ngDevMode && ngDevMode.dehydratedViewsCleanupRuns++;
|
|
19176
|
+
}
|
|
19177
|
+
}
|
|
19178
|
+
}
|
|
19179
|
+
|
|
19008
19180
|
/**
|
|
19009
19181
|
* Regexp that extracts a reference node information from the compressed node location.
|
|
19010
19182
|
* The reference node is represented as either:
|
|
@@ -19327,6 +19499,561 @@ function calcPathForNode(tNode, lView) {
|
|
|
19327
19499
|
return path;
|
|
19328
19500
|
}
|
|
19329
19501
|
|
|
19502
|
+
/**
|
|
19503
|
+
* Given a current DOM node and a serialized information about the views
|
|
19504
|
+
* in a container, walks over the DOM structure, collecting the list of
|
|
19505
|
+
* dehydrated views.
|
|
19506
|
+
*/
|
|
19507
|
+
function locateDehydratedViewsInContainer(currentRNode, serializedViews) {
|
|
19508
|
+
const dehydratedViews = [];
|
|
19509
|
+
for (const serializedView of serializedViews) {
|
|
19510
|
+
// Repeats a view multiple times as needed, based on the serialized information
|
|
19511
|
+
// (for example, for *ngFor-produced views).
|
|
19512
|
+
for (let i = 0; i < (serializedView[MULTIPLIER] ?? 1); i++) {
|
|
19513
|
+
const view = {
|
|
19514
|
+
data: serializedView,
|
|
19515
|
+
firstChild: null,
|
|
19516
|
+
};
|
|
19517
|
+
if (serializedView[NUM_ROOT_NODES] > 0) {
|
|
19518
|
+
// Keep reference to the first node in this view,
|
|
19519
|
+
// so it can be accessed while invoking template instructions.
|
|
19520
|
+
view.firstChild = currentRNode;
|
|
19521
|
+
// Move over to the next node after this view, which can
|
|
19522
|
+
// either be a first node of the next view or an anchor comment
|
|
19523
|
+
// node after the last view in a container.
|
|
19524
|
+
currentRNode = siblingAfter(serializedView[NUM_ROOT_NODES], currentRNode);
|
|
19525
|
+
}
|
|
19526
|
+
dehydratedViews.push(view);
|
|
19527
|
+
}
|
|
19528
|
+
}
|
|
19529
|
+
return [currentRNode, dehydratedViews];
|
|
19530
|
+
}
|
|
19531
|
+
/**
|
|
19532
|
+
* Reference to a function that searches for a matching dehydrated views
|
|
19533
|
+
* stored on a given lContainer.
|
|
19534
|
+
* Returns `null` by default, when hydration is not enabled.
|
|
19535
|
+
*/
|
|
19536
|
+
let _findMatchingDehydratedViewImpl = (lContainer, template) => null;
|
|
19537
|
+
/**
|
|
19538
|
+
* Retrieves the next dehydrated view from the LContainer and verifies that
|
|
19539
|
+
* it matches a given template id (from the TView that was used to create this
|
|
19540
|
+
* instance of a view). If the id doesn't match, that means that we are in an
|
|
19541
|
+
* unexpected state and can not complete the reconciliation process. Thus,
|
|
19542
|
+
* all dehydrated views from this LContainer are removed (including corresponding
|
|
19543
|
+
* DOM nodes) and the rendering is performed as if there were no dehydrated views
|
|
19544
|
+
* in this container.
|
|
19545
|
+
*/
|
|
19546
|
+
function findMatchingDehydratedViewImpl(lContainer, template) {
|
|
19547
|
+
const views = lContainer[DEHYDRATED_VIEWS];
|
|
19548
|
+
if (!template || views === null || views.length === 0) {
|
|
19549
|
+
return null;
|
|
19550
|
+
}
|
|
19551
|
+
const view = views[0];
|
|
19552
|
+
// Verify whether the first dehydrated view in the container matches
|
|
19553
|
+
// the template id passed to this function (that originated from a TView
|
|
19554
|
+
// that was used to create an instance of an embedded or component views.
|
|
19555
|
+
if (view.data[TEMPLATE_ID] === template) {
|
|
19556
|
+
// If the template id matches - extract the first view and return it.
|
|
19557
|
+
return views.shift();
|
|
19558
|
+
}
|
|
19559
|
+
else {
|
|
19560
|
+
// Otherwise, we are at the state when reconciliation can not be completed,
|
|
19561
|
+
// thus we remove all dehydrated views within this container (remove them
|
|
19562
|
+
// from internal data structures as well as delete associated elements from
|
|
19563
|
+
// the DOM tree).
|
|
19564
|
+
removeDehydratedViews(lContainer);
|
|
19565
|
+
return null;
|
|
19566
|
+
}
|
|
19567
|
+
}
|
|
19568
|
+
function enableFindMatchingDehydratedViewImpl() {
|
|
19569
|
+
_findMatchingDehydratedViewImpl = findMatchingDehydratedViewImpl;
|
|
19570
|
+
}
|
|
19571
|
+
function findMatchingDehydratedView(lContainer, template) {
|
|
19572
|
+
return _findMatchingDehydratedViewImpl(lContainer, template);
|
|
19573
|
+
}
|
|
19574
|
+
|
|
19575
|
+
function createAndRenderEmbeddedLView(declarationLView, templateTNode, context, options) {
|
|
19576
|
+
const embeddedTView = templateTNode.tView;
|
|
19577
|
+
ngDevMode && assertDefined(embeddedTView, 'TView must be defined for a template node.');
|
|
19578
|
+
ngDevMode && assertTNodeForLView(templateTNode, declarationLView);
|
|
19579
|
+
// Embedded views follow the change detection strategy of the view they're declared in.
|
|
19580
|
+
const isSignalView = declarationLView[FLAGS] & 4096 /* LViewFlags.SignalView */;
|
|
19581
|
+
const viewFlags = isSignalView ? 4096 /* LViewFlags.SignalView */ : 16 /* LViewFlags.CheckAlways */;
|
|
19582
|
+
const embeddedLView = createLView(declarationLView, embeddedTView, context, viewFlags, null, templateTNode, null, null, null, options?.injector ?? null, options?.dehydratedView ?? null);
|
|
19583
|
+
const declarationLContainer = declarationLView[templateTNode.index];
|
|
19584
|
+
ngDevMode && assertLContainer(declarationLContainer);
|
|
19585
|
+
embeddedLView[DECLARATION_LCONTAINER] = declarationLContainer;
|
|
19586
|
+
const declarationViewLQueries = declarationLView[QUERIES];
|
|
19587
|
+
if (declarationViewLQueries !== null) {
|
|
19588
|
+
embeddedLView[QUERIES] = declarationViewLQueries.createEmbeddedView(embeddedTView);
|
|
19589
|
+
}
|
|
19590
|
+
// execute creation mode of a view
|
|
19591
|
+
renderView(embeddedTView, embeddedLView, context);
|
|
19592
|
+
return embeddedLView;
|
|
19593
|
+
}
|
|
19594
|
+
function getLViewFromLContainer(lContainer, index) {
|
|
19595
|
+
const adjustedIndex = CONTAINER_HEADER_OFFSET + index;
|
|
19596
|
+
// avoid reading past the array boundaries
|
|
19597
|
+
if (adjustedIndex < lContainer.length) {
|
|
19598
|
+
const lView = lContainer[adjustedIndex];
|
|
19599
|
+
ngDevMode && assertLView(lView);
|
|
19600
|
+
return lView;
|
|
19601
|
+
}
|
|
19602
|
+
return undefined;
|
|
19603
|
+
}
|
|
19604
|
+
/**
|
|
19605
|
+
* Returns whether an elements that belong to a view should be
|
|
19606
|
+
* inserted into the DOM. For client-only cases, DOM elements are
|
|
19607
|
+
* always inserted. For hydration cases, we check whether serialized
|
|
19608
|
+
* info is available for a view and the view is not in a "skip hydration"
|
|
19609
|
+
* block (in which case view contents was re-created, thus needing insertion).
|
|
19610
|
+
*/
|
|
19611
|
+
function shouldAddViewToDom(tNode, dehydratedView) {
|
|
19612
|
+
return !dehydratedView || hasInSkipHydrationBlockFlag(tNode);
|
|
19613
|
+
}
|
|
19614
|
+
function addLViewToLContainer(lContainer, lView, index, addToDOM = true) {
|
|
19615
|
+
const tView = lView[TVIEW];
|
|
19616
|
+
// insert to the view tree so the new view can be change-detected
|
|
19617
|
+
insertView(tView, lView, lContainer, index);
|
|
19618
|
+
// insert to the view to the DOM tree
|
|
19619
|
+
if (addToDOM) {
|
|
19620
|
+
const beforeNode = getBeforeNodeForView(index, lContainer);
|
|
19621
|
+
const renderer = lView[RENDERER];
|
|
19622
|
+
const parentRNode = nativeParentNode(renderer, lContainer[NATIVE]);
|
|
19623
|
+
if (parentRNode !== null) {
|
|
19624
|
+
addViewToDOM(tView, lContainer[T_HOST], renderer, lView, parentRNode, beforeNode);
|
|
19625
|
+
}
|
|
19626
|
+
}
|
|
19627
|
+
}
|
|
19628
|
+
function removeLViewFromLContainer(lContainer, index) {
|
|
19629
|
+
const lView = detachView(lContainer, index);
|
|
19630
|
+
if (lView !== undefined) {
|
|
19631
|
+
destroyLView(lView[TVIEW], lView);
|
|
19632
|
+
}
|
|
19633
|
+
return lView;
|
|
19634
|
+
}
|
|
19635
|
+
|
|
19636
|
+
/**
|
|
19637
|
+
* Represents a container where one or more views can be attached to a component.
|
|
19638
|
+
*
|
|
19639
|
+
* Can contain *host views* (created by instantiating a
|
|
19640
|
+
* component with the `createComponent()` method), and *embedded views*
|
|
19641
|
+
* (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method).
|
|
19642
|
+
*
|
|
19643
|
+
* A view container instance can contain other view containers,
|
|
19644
|
+
* creating a [view hierarchy](guide/glossary#view-hierarchy).
|
|
19645
|
+
*
|
|
19646
|
+
* @usageNotes
|
|
19647
|
+
*
|
|
19648
|
+
* The example below demonstrates how the `createComponent` function can be used
|
|
19649
|
+
* to create an instance of a ComponentRef dynamically and attach it to an ApplicationRef,
|
|
19650
|
+
* so that it gets included into change detection cycles.
|
|
19651
|
+
*
|
|
19652
|
+
* Note: the example uses standalone components, but the function can also be used for
|
|
19653
|
+
* non-standalone components (declared in an NgModule) as well.
|
|
19654
|
+
*
|
|
19655
|
+
* ```typescript
|
|
19656
|
+
* @Component({
|
|
19657
|
+
* standalone: true,
|
|
19658
|
+
* selector: 'dynamic',
|
|
19659
|
+
* template: `<span>This is a content of a dynamic component.</span>`,
|
|
19660
|
+
* })
|
|
19661
|
+
* class DynamicComponent {
|
|
19662
|
+
* vcr = inject(ViewContainerRef);
|
|
19663
|
+
* }
|
|
19664
|
+
*
|
|
19665
|
+
* @Component({
|
|
19666
|
+
* standalone: true,
|
|
19667
|
+
* selector: 'app',
|
|
19668
|
+
* template: `<main>Hi! This is the main content.</main>`,
|
|
19669
|
+
* })
|
|
19670
|
+
* class AppComponent {
|
|
19671
|
+
* vcr = inject(ViewContainerRef);
|
|
19672
|
+
*
|
|
19673
|
+
* ngAfterViewInit() {
|
|
19674
|
+
* const compRef = this.vcr.createComponent(DynamicComponent);
|
|
19675
|
+
* compRef.changeDetectorRef.detectChanges();
|
|
19676
|
+
* }
|
|
19677
|
+
* }
|
|
19678
|
+
* ```
|
|
19679
|
+
*
|
|
19680
|
+
* @see {@link ComponentRef}
|
|
19681
|
+
* @see {@link EmbeddedViewRef}
|
|
19682
|
+
*
|
|
19683
|
+
* @publicApi
|
|
19684
|
+
*/
|
|
19685
|
+
class ViewContainerRef {
|
|
19686
|
+
/**
|
|
19687
|
+
* @internal
|
|
19688
|
+
* @nocollapse
|
|
19689
|
+
*/
|
|
19690
|
+
static { this.__NG_ELEMENT_ID__ = injectViewContainerRef; }
|
|
19691
|
+
}
|
|
19692
|
+
/**
|
|
19693
|
+
* Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef
|
|
19694
|
+
* already exists, retrieves the existing ViewContainerRef.
|
|
19695
|
+
*
|
|
19696
|
+
* @returns The ViewContainerRef instance to use
|
|
19697
|
+
*/
|
|
19698
|
+
function injectViewContainerRef() {
|
|
19699
|
+
const previousTNode = getCurrentTNode();
|
|
19700
|
+
return createContainerRef(previousTNode, getLView());
|
|
19701
|
+
}
|
|
19702
|
+
const VE_ViewContainerRef = ViewContainerRef;
|
|
19703
|
+
// TODO(alxhub): cleaning up this indirection triggers a subtle bug in Closure in g3. Once the fix
|
|
19704
|
+
// for that lands, this can be cleaned up.
|
|
19705
|
+
const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
|
|
19706
|
+
constructor(_lContainer, _hostTNode, _hostLView) {
|
|
19707
|
+
super();
|
|
19708
|
+
this._lContainer = _lContainer;
|
|
19709
|
+
this._hostTNode = _hostTNode;
|
|
19710
|
+
this._hostLView = _hostLView;
|
|
19711
|
+
}
|
|
19712
|
+
get element() {
|
|
19713
|
+
return createElementRef(this._hostTNode, this._hostLView);
|
|
19714
|
+
}
|
|
19715
|
+
get injector() {
|
|
19716
|
+
return new NodeInjector(this._hostTNode, this._hostLView);
|
|
19717
|
+
}
|
|
19718
|
+
/** @deprecated No replacement */
|
|
19719
|
+
get parentInjector() {
|
|
19720
|
+
const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostLView);
|
|
19721
|
+
if (hasParentInjector(parentLocation)) {
|
|
19722
|
+
const parentView = getParentInjectorView(parentLocation, this._hostLView);
|
|
19723
|
+
const injectorIndex = getParentInjectorIndex(parentLocation);
|
|
19724
|
+
ngDevMode && assertNodeInjector(parentView, injectorIndex);
|
|
19725
|
+
const parentTNode = parentView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */];
|
|
19726
|
+
return new NodeInjector(parentTNode, parentView);
|
|
19727
|
+
}
|
|
19728
|
+
else {
|
|
19729
|
+
return new NodeInjector(null, this._hostLView);
|
|
19730
|
+
}
|
|
19731
|
+
}
|
|
19732
|
+
clear() {
|
|
19733
|
+
while (this.length > 0) {
|
|
19734
|
+
this.remove(this.length - 1);
|
|
19735
|
+
}
|
|
19736
|
+
}
|
|
19737
|
+
get(index) {
|
|
19738
|
+
const viewRefs = getViewRefs(this._lContainer);
|
|
19739
|
+
return viewRefs !== null && viewRefs[index] || null;
|
|
19740
|
+
}
|
|
19741
|
+
get length() {
|
|
19742
|
+
return this._lContainer.length - CONTAINER_HEADER_OFFSET;
|
|
19743
|
+
}
|
|
19744
|
+
createEmbeddedView(templateRef, context, indexOrOptions) {
|
|
19745
|
+
let index;
|
|
19746
|
+
let injector;
|
|
19747
|
+
if (typeof indexOrOptions === 'number') {
|
|
19748
|
+
index = indexOrOptions;
|
|
19749
|
+
}
|
|
19750
|
+
else if (indexOrOptions != null) {
|
|
19751
|
+
index = indexOrOptions.index;
|
|
19752
|
+
injector = indexOrOptions.injector;
|
|
19753
|
+
}
|
|
19754
|
+
const dehydratedView = findMatchingDehydratedView(this._lContainer, templateRef.ssrId);
|
|
19755
|
+
const viewRef = templateRef.createEmbeddedViewImpl(context || {}, injector, dehydratedView);
|
|
19756
|
+
this.insertImpl(viewRef, index, shouldAddViewToDom(this._hostTNode, dehydratedView));
|
|
19757
|
+
return viewRef;
|
|
19758
|
+
}
|
|
19759
|
+
createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) {
|
|
19760
|
+
const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType);
|
|
19761
|
+
let index;
|
|
19762
|
+
// This function supports 2 signatures and we need to handle options correctly for both:
|
|
19763
|
+
// 1. When first argument is a Component type. This signature also requires extra
|
|
19764
|
+
// options to be provided as object (more ergonomic option).
|
|
19765
|
+
// 2. First argument is a Component factory. In this case extra options are represented as
|
|
19766
|
+
// positional arguments. This signature is less ergonomic and will be deprecated.
|
|
19767
|
+
if (isComponentFactory) {
|
|
19768
|
+
if (ngDevMode) {
|
|
19769
|
+
assertEqual(typeof indexOrOptions !== 'object', true, 'It looks like Component factory was provided as the first argument ' +
|
|
19770
|
+
'and an options object as the second argument. This combination of arguments ' +
|
|
19771
|
+
'is incompatible. You can either change the first argument to provide Component ' +
|
|
19772
|
+
'type or change the second argument to be a number (representing an index at ' +
|
|
19773
|
+
'which to insert the new component\'s host view into this container)');
|
|
19774
|
+
}
|
|
19775
|
+
index = indexOrOptions;
|
|
19776
|
+
}
|
|
19777
|
+
else {
|
|
19778
|
+
if (ngDevMode) {
|
|
19779
|
+
assertDefined(getComponentDef(componentFactoryOrType), `Provided Component class doesn't contain Component definition. ` +
|
|
19780
|
+
`Please check whether provided class has @Component decorator.`);
|
|
19781
|
+
assertEqual(typeof indexOrOptions !== 'number', true, 'It looks like Component type was provided as the first argument ' +
|
|
19782
|
+
'and a number (representing an index at which to insert the new component\'s ' +
|
|
19783
|
+
'host view into this container as the second argument. This combination of arguments ' +
|
|
19784
|
+
'is incompatible. Please use an object as the second argument instead.');
|
|
19785
|
+
}
|
|
19786
|
+
const options = (indexOrOptions || {});
|
|
19787
|
+
if (ngDevMode && options.environmentInjector && options.ngModuleRef) {
|
|
19788
|
+
throwError(`Cannot pass both environmentInjector and ngModuleRef options to createComponent().`);
|
|
19789
|
+
}
|
|
19790
|
+
index = options.index;
|
|
19791
|
+
injector = options.injector;
|
|
19792
|
+
projectableNodes = options.projectableNodes;
|
|
19793
|
+
environmentInjector = options.environmentInjector || options.ngModuleRef;
|
|
19794
|
+
}
|
|
19795
|
+
const componentFactory = isComponentFactory ?
|
|
19796
|
+
componentFactoryOrType :
|
|
19797
|
+
new ComponentFactory(getComponentDef(componentFactoryOrType));
|
|
19798
|
+
const contextInjector = injector || this.parentInjector;
|
|
19799
|
+
// If an `NgModuleRef` is not provided explicitly, try retrieving it from the DI tree.
|
|
19800
|
+
if (!environmentInjector && componentFactory.ngModule == null) {
|
|
19801
|
+
// For the `ComponentFactory` case, entering this logic is very unlikely, since we expect that
|
|
19802
|
+
// an instance of a `ComponentFactory`, resolved via `ComponentFactoryResolver` would have an
|
|
19803
|
+
// `ngModule` field. This is possible in some test scenarios and potentially in some JIT-based
|
|
19804
|
+
// use-cases. For the `ComponentFactory` case we preserve backwards-compatibility and try
|
|
19805
|
+
// using a provided injector first, then fall back to the parent injector of this
|
|
19806
|
+
// `ViewContainerRef` instance.
|
|
19807
|
+
//
|
|
19808
|
+
// For the factory-less case, it's critical to establish a connection with the module
|
|
19809
|
+
// injector tree (by retrieving an instance of an `NgModuleRef` and accessing its injector),
|
|
19810
|
+
// so that a component can use DI tokens provided in MgModules. For this reason, we can not
|
|
19811
|
+
// rely on the provided injector, since it might be detached from the DI tree (for example, if
|
|
19812
|
+
// it was created via `Injector.create` without specifying a parent injector, or if an
|
|
19813
|
+
// injector is retrieved from an `NgModuleRef` created via `createNgModule` using an
|
|
19814
|
+
// NgModule outside of a module tree). Instead, we always use `ViewContainerRef`'s parent
|
|
19815
|
+
// injector, which is normally connected to the DI tree, which includes module injector
|
|
19816
|
+
// subtree.
|
|
19817
|
+
const _injector = isComponentFactory ? contextInjector : this.parentInjector;
|
|
19818
|
+
// DO NOT REFACTOR. The code here used to have a `injector.get(NgModuleRef, null) ||
|
|
19819
|
+
// undefined` expression which seems to cause internal google apps to fail. This is documented
|
|
19820
|
+
// in the following internal bug issue: go/b/142967802
|
|
19821
|
+
const result = _injector.get(EnvironmentInjector, null);
|
|
19822
|
+
if (result) {
|
|
19823
|
+
environmentInjector = result;
|
|
19824
|
+
}
|
|
19825
|
+
}
|
|
19826
|
+
const componentDef = getComponentDef(componentFactory.componentType ?? {});
|
|
19827
|
+
const dehydratedView = findMatchingDehydratedView(this._lContainer, componentDef?.id ?? null);
|
|
19828
|
+
const rNode = dehydratedView?.firstChild ?? null;
|
|
19829
|
+
const componentRef = componentFactory.create(contextInjector, projectableNodes, rNode, environmentInjector);
|
|
19830
|
+
this.insertImpl(componentRef.hostView, index, shouldAddViewToDom(this._hostTNode, dehydratedView));
|
|
19831
|
+
return componentRef;
|
|
19832
|
+
}
|
|
19833
|
+
insert(viewRef, index) {
|
|
19834
|
+
return this.insertImpl(viewRef, index, true);
|
|
19835
|
+
}
|
|
19836
|
+
insertImpl(viewRef, index, addToDOM) {
|
|
19837
|
+
const lView = viewRef._lView;
|
|
19838
|
+
if (ngDevMode && viewRef.destroyed) {
|
|
19839
|
+
throw new Error('Cannot insert a destroyed View in a ViewContainer!');
|
|
19840
|
+
}
|
|
19841
|
+
if (viewAttachedToContainer(lView)) {
|
|
19842
|
+
// If view is already attached, detach it first so we clean up references appropriately.
|
|
19843
|
+
const prevIdx = this.indexOf(viewRef);
|
|
19844
|
+
// A view might be attached either to this or a different container. The `prevIdx` for
|
|
19845
|
+
// those cases will be:
|
|
19846
|
+
// equal to -1 for views attached to this ViewContainerRef
|
|
19847
|
+
// >= 0 for views attached to a different ViewContainerRef
|
|
19848
|
+
if (prevIdx !== -1) {
|
|
19849
|
+
this.detach(prevIdx);
|
|
19850
|
+
}
|
|
19851
|
+
else {
|
|
19852
|
+
const prevLContainer = lView[PARENT];
|
|
19853
|
+
ngDevMode &&
|
|
19854
|
+
assertEqual(isLContainer(prevLContainer), true, 'An attached view should have its PARENT point to a container.');
|
|
19855
|
+
// We need to re-create a R3ViewContainerRef instance since those are not stored on
|
|
19856
|
+
// LView (nor anywhere else).
|
|
19857
|
+
const prevVCRef = new R3ViewContainerRef(prevLContainer, prevLContainer[T_HOST], prevLContainer[PARENT]);
|
|
19858
|
+
prevVCRef.detach(prevVCRef.indexOf(viewRef));
|
|
19859
|
+
}
|
|
19860
|
+
}
|
|
19861
|
+
// Logical operation of adding `LView` to `LContainer`
|
|
19862
|
+
const adjustedIdx = this._adjustIndex(index);
|
|
19863
|
+
const lContainer = this._lContainer;
|
|
19864
|
+
addLViewToLContainer(lContainer, lView, adjustedIdx, addToDOM);
|
|
19865
|
+
viewRef.attachToViewContainerRef();
|
|
19866
|
+
addToArray(getOrCreateViewRefs(lContainer), adjustedIdx, viewRef);
|
|
19867
|
+
return viewRef;
|
|
19868
|
+
}
|
|
19869
|
+
move(viewRef, newIndex) {
|
|
19870
|
+
if (ngDevMode && viewRef.destroyed) {
|
|
19871
|
+
throw new Error('Cannot move a destroyed View in a ViewContainer!');
|
|
19872
|
+
}
|
|
19873
|
+
return this.insert(viewRef, newIndex);
|
|
19874
|
+
}
|
|
19875
|
+
indexOf(viewRef) {
|
|
19876
|
+
const viewRefsArr = getViewRefs(this._lContainer);
|
|
19877
|
+
return viewRefsArr !== null ? viewRefsArr.indexOf(viewRef) : -1;
|
|
19878
|
+
}
|
|
19879
|
+
remove(index) {
|
|
19880
|
+
const adjustedIdx = this._adjustIndex(index, -1);
|
|
19881
|
+
const detachedView = detachView(this._lContainer, adjustedIdx);
|
|
19882
|
+
if (detachedView) {
|
|
19883
|
+
// Before destroying the view, remove it from the container's array of `ViewRef`s.
|
|
19884
|
+
// This ensures the view container length is updated before calling
|
|
19885
|
+
// `destroyLView`, which could recursively call view container methods that
|
|
19886
|
+
// rely on an accurate container length.
|
|
19887
|
+
// (e.g. a method on this view container being called by a child directive's OnDestroy
|
|
19888
|
+
// lifecycle hook)
|
|
19889
|
+
removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx);
|
|
19890
|
+
destroyLView(detachedView[TVIEW], detachedView);
|
|
19891
|
+
}
|
|
19892
|
+
}
|
|
19893
|
+
detach(index) {
|
|
19894
|
+
const adjustedIdx = this._adjustIndex(index, -1);
|
|
19895
|
+
const view = detachView(this._lContainer, adjustedIdx);
|
|
19896
|
+
const wasDetached = view && removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx) != null;
|
|
19897
|
+
return wasDetached ? new ViewRef$1(view) : null;
|
|
19898
|
+
}
|
|
19899
|
+
_adjustIndex(index, shift = 0) {
|
|
19900
|
+
if (index == null) {
|
|
19901
|
+
return this.length + shift;
|
|
19902
|
+
}
|
|
19903
|
+
if (ngDevMode) {
|
|
19904
|
+
assertGreaterThan(index, -1, `ViewRef index must be positive, got ${index}`);
|
|
19905
|
+
// +1 because it's legal to insert at the end.
|
|
19906
|
+
assertLessThan(index, this.length + 1 + shift, 'index');
|
|
19907
|
+
}
|
|
19908
|
+
return index;
|
|
19909
|
+
}
|
|
19910
|
+
};
|
|
19911
|
+
function getViewRefs(lContainer) {
|
|
19912
|
+
return lContainer[VIEW_REFS];
|
|
19913
|
+
}
|
|
19914
|
+
function getOrCreateViewRefs(lContainer) {
|
|
19915
|
+
return (lContainer[VIEW_REFS] || (lContainer[VIEW_REFS] = []));
|
|
19916
|
+
}
|
|
19917
|
+
/**
|
|
19918
|
+
* Creates a ViewContainerRef and stores it on the injector.
|
|
19919
|
+
*
|
|
19920
|
+
* @param hostTNode The node that is requesting a ViewContainerRef
|
|
19921
|
+
* @param hostLView The view to which the node belongs
|
|
19922
|
+
* @returns The ViewContainerRef instance to use
|
|
19923
|
+
*/
|
|
19924
|
+
function createContainerRef(hostTNode, hostLView) {
|
|
19925
|
+
ngDevMode && assertTNodeType(hostTNode, 12 /* TNodeType.AnyContainer */ | 3 /* TNodeType.AnyRNode */);
|
|
19926
|
+
let lContainer;
|
|
19927
|
+
const slotValue = hostLView[hostTNode.index];
|
|
19928
|
+
if (isLContainer(slotValue)) {
|
|
19929
|
+
// If the host is a container, we don't need to create a new LContainer
|
|
19930
|
+
lContainer = slotValue;
|
|
19931
|
+
}
|
|
19932
|
+
else {
|
|
19933
|
+
// An LContainer anchor can not be `null`, but we set it here temporarily
|
|
19934
|
+
// and update to the actual value later in this function (see
|
|
19935
|
+
// `_locateOrCreateAnchorNode`).
|
|
19936
|
+
lContainer = createLContainer(slotValue, hostLView, null, hostTNode);
|
|
19937
|
+
hostLView[hostTNode.index] = lContainer;
|
|
19938
|
+
addToViewTree(hostLView, lContainer);
|
|
19939
|
+
}
|
|
19940
|
+
_locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue);
|
|
19941
|
+
return new R3ViewContainerRef(lContainer, hostTNode, hostLView);
|
|
19942
|
+
}
|
|
19943
|
+
/**
|
|
19944
|
+
* Creates and inserts a comment node that acts as an anchor for a view container.
|
|
19945
|
+
*
|
|
19946
|
+
* If the host is a regular element, we have to insert a comment node manually which will
|
|
19947
|
+
* be used as an anchor when inserting elements. In this specific case we use low-level DOM
|
|
19948
|
+
* manipulation to insert it.
|
|
19949
|
+
*/
|
|
19950
|
+
function insertAnchorNode(hostLView, hostTNode) {
|
|
19951
|
+
const renderer = hostLView[RENDERER];
|
|
19952
|
+
ngDevMode && ngDevMode.rendererCreateComment++;
|
|
19953
|
+
const commentNode = renderer.createComment(ngDevMode ? 'container' : '');
|
|
19954
|
+
const hostNative = getNativeByTNode(hostTNode, hostLView);
|
|
19955
|
+
const parentOfHostNative = nativeParentNode(renderer, hostNative);
|
|
19956
|
+
nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
|
|
19957
|
+
return commentNode;
|
|
19958
|
+
}
|
|
19959
|
+
let _locateOrCreateAnchorNode = createAnchorNode;
|
|
19960
|
+
let _populateDehydratedViewsInLContainer = (lContainer, tNode, hostLView) => false; // noop by default
|
|
19961
|
+
/**
|
|
19962
|
+
* Looks up dehydrated views that belong to a given LContainer and populates
|
|
19963
|
+
* this information into the `LContainer[DEHYDRATED_VIEWS]` slot. When running
|
|
19964
|
+
* in client-only mode, this function is a noop.
|
|
19965
|
+
*
|
|
19966
|
+
* @param lContainer LContainer that should be populated.
|
|
19967
|
+
* @param tNode Corresponding TNode.
|
|
19968
|
+
* @param hostLView LView that hosts LContainer.
|
|
19969
|
+
* @returns a boolean flag that indicates whether a populating operation
|
|
19970
|
+
* was successful. The operation might be unsuccessful in case is has completed
|
|
19971
|
+
* previously, we are rendering in client-only mode or this content is located
|
|
19972
|
+
* in a skip hydration section.
|
|
19973
|
+
*/
|
|
19974
|
+
function populateDehydratedViewsInLContainer(lContainer, tNode, hostLView) {
|
|
19975
|
+
return _populateDehydratedViewsInLContainer(lContainer, tNode, hostLView);
|
|
19976
|
+
}
|
|
19977
|
+
/**
|
|
19978
|
+
* Regular creation mode: an anchor is created and
|
|
19979
|
+
* assigned to the `lContainer[NATIVE]` slot.
|
|
19980
|
+
*/
|
|
19981
|
+
function createAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
|
|
19982
|
+
// We already have a native element (anchor) set, return.
|
|
19983
|
+
if (lContainer[NATIVE])
|
|
19984
|
+
return;
|
|
19985
|
+
let commentNode;
|
|
19986
|
+
// If the host is an element container, the native host element is guaranteed to be a
|
|
19987
|
+
// comment and we can reuse that comment as anchor element for the new LContainer.
|
|
19988
|
+
// The comment node in question is already part of the DOM structure so we don't need to append
|
|
19989
|
+
// it again.
|
|
19990
|
+
if (hostTNode.type & 8 /* TNodeType.ElementContainer */) {
|
|
19991
|
+
commentNode = unwrapRNode(slotValue);
|
|
19992
|
+
}
|
|
19993
|
+
else {
|
|
19994
|
+
commentNode = insertAnchorNode(hostLView, hostTNode);
|
|
19995
|
+
}
|
|
19996
|
+
lContainer[NATIVE] = commentNode;
|
|
19997
|
+
}
|
|
19998
|
+
/**
|
|
19999
|
+
* Hydration logic that looks up all dehydrated views in this container
|
|
20000
|
+
* and puts them into `lContainer[DEHYDRATED_VIEWS]` slot.
|
|
20001
|
+
*
|
|
20002
|
+
* @returns a boolean flag that indicates whether a populating operation
|
|
20003
|
+
* was successful. The operation might be unsuccessful in case is has completed
|
|
20004
|
+
* previously, we are rendering in client-only mode or this content is located
|
|
20005
|
+
* in a skip hydration section.
|
|
20006
|
+
*/
|
|
20007
|
+
function populateDehydratedViewsInLContainerImpl(lContainer, tNode, hostLView) {
|
|
20008
|
+
// We already have a native element (anchor) set and the process
|
|
20009
|
+
// of finding dehydrated views happened (so the `lContainer[DEHYDRATED_VIEWS]`
|
|
20010
|
+
// is not null), exit early.
|
|
20011
|
+
if (lContainer[NATIVE] && lContainer[DEHYDRATED_VIEWS]) {
|
|
20012
|
+
return true;
|
|
20013
|
+
}
|
|
20014
|
+
const hydrationInfo = hostLView[HYDRATION];
|
|
20015
|
+
const noOffsetIndex = tNode.index - HEADER_OFFSET;
|
|
20016
|
+
// TODO(akushnir): this should really be a single condition, refactor the code
|
|
20017
|
+
// to use `hasInSkipHydrationBlockFlag` logic inside `isInSkipHydrationBlock`.
|
|
20018
|
+
const skipHydration = isInSkipHydrationBlock(tNode) || hasInSkipHydrationBlockFlag(tNode);
|
|
20019
|
+
const isNodeCreationMode = !hydrationInfo || skipHydration || isDisconnectedNode$1(hydrationInfo, noOffsetIndex);
|
|
20020
|
+
// Regular creation mode.
|
|
20021
|
+
if (isNodeCreationMode) {
|
|
20022
|
+
return false;
|
|
20023
|
+
}
|
|
20024
|
+
// Hydration mode, looking up an anchor node and dehydrated views in DOM.
|
|
20025
|
+
const currentRNode = getSegmentHead(hydrationInfo, noOffsetIndex);
|
|
20026
|
+
const serializedViews = hydrationInfo.data[CONTAINERS]?.[noOffsetIndex];
|
|
20027
|
+
ngDevMode &&
|
|
20028
|
+
assertDefined(serializedViews, 'Unexpected state: no hydration info available for a given TNode, ' +
|
|
20029
|
+
'which represents a view container.');
|
|
20030
|
+
const [commentNode, dehydratedViews] = locateDehydratedViewsInContainer(currentRNode, serializedViews);
|
|
20031
|
+
if (ngDevMode) {
|
|
20032
|
+
validateMatchingNode(commentNode, Node.COMMENT_NODE, null, hostLView, tNode, true);
|
|
20033
|
+
// Do not throw in case this node is already claimed (thus `false` as a second
|
|
20034
|
+
// argument). If this container is created based on an `<ng-template>`, the comment
|
|
20035
|
+
// node would be already claimed from the `template` instruction. If an element acts
|
|
20036
|
+
// as an anchor (e.g. <div #vcRef>), a separate comment node would be created/located,
|
|
20037
|
+
// so we need to claim it here.
|
|
20038
|
+
markRNodeAsClaimedByHydration(commentNode, false);
|
|
20039
|
+
}
|
|
20040
|
+
lContainer[NATIVE] = commentNode;
|
|
20041
|
+
lContainer[DEHYDRATED_VIEWS] = dehydratedViews;
|
|
20042
|
+
return true;
|
|
20043
|
+
}
|
|
20044
|
+
function locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
|
|
20045
|
+
if (!_populateDehydratedViewsInLContainer(lContainer, hostTNode, hostLView)) {
|
|
20046
|
+
// Populating dehydrated views operation returned `false`, which indicates
|
|
20047
|
+
// that the logic was running in client-only mode, this an anchor comment
|
|
20048
|
+
// node should be created for this container.
|
|
20049
|
+
createAnchorNode(lContainer, hostLView, hostTNode, slotValue);
|
|
20050
|
+
}
|
|
20051
|
+
}
|
|
20052
|
+
function enableLocateOrCreateContainerRefImpl() {
|
|
20053
|
+
_locateOrCreateAnchorNode = locateOrCreateAnchorNode;
|
|
20054
|
+
_populateDehydratedViewsInLContainer = populateDehydratedViewsInLContainerImpl;
|
|
20055
|
+
}
|
|
20056
|
+
|
|
19330
20057
|
function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
|
|
19331
20058
|
ngDevMode && assertFirstCreatePass(tView);
|
|
19332
20059
|
ngDevMode && ngDevMode.firstCreatePass++;
|
|
@@ -19373,7 +20100,13 @@ function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, local
|
|
|
19373
20100
|
appendChild(tView, lView, comment, tNode);
|
|
19374
20101
|
}
|
|
19375
20102
|
attachPatchData(comment, lView);
|
|
19376
|
-
|
|
20103
|
+
const lContainer = createLContainer(comment, lView, comment, tNode);
|
|
20104
|
+
lView[adjustedIndex] = lContainer;
|
|
20105
|
+
addToViewTree(lView, lContainer);
|
|
20106
|
+
// If hydration is enabled, looks up dehydrated views in the DOM
|
|
20107
|
+
// using hydration annotation info and stores those views on LContainer.
|
|
20108
|
+
// In client-only mode, this function is a noop.
|
|
20109
|
+
populateDehydratedViewsInLContainer(lContainer, tNode, lView);
|
|
19377
20110
|
if (isDirectiveHost(tNode)) {
|
|
19378
20111
|
createDirectivesInstances(tView, lView, tNode);
|
|
19379
20112
|
}
|
|
@@ -19461,8 +20194,9 @@ function ɵɵconditional(containerIndex, matchingTemplateIndex, value) {
|
|
|
19461
20194
|
// a truthy value and as the consequence we've got no view to show.
|
|
19462
20195
|
if (matchingTemplateIndex !== -1) {
|
|
19463
20196
|
const templateTNode = getExistingTNode(hostLView[TVIEW], matchingTemplateIndex);
|
|
19464
|
-
const
|
|
19465
|
-
|
|
20197
|
+
const dehydratedView = findMatchingDehydratedView(lContainer, templateTNode.tView.ssrId);
|
|
20198
|
+
const embeddedLView = createAndRenderEmbeddedLView(hostLView, templateTNode, value, { dehydratedView });
|
|
20199
|
+
addLViewToLContainer(lContainer, embeddedLView, viewInContainerIdx, shouldAddViewToDom(templateTNode, dehydratedView));
|
|
19466
20200
|
}
|
|
19467
20201
|
}
|
|
19468
20202
|
else {
|
|
@@ -19584,656 +20318,290 @@ function ɵɵrepeater(metadataSlotIdx, collection) {
|
|
|
19584
20318
|
}
|
|
19585
20319
|
else if (currentIndex === null) {
|
|
19586
20320
|
// remove
|
|
19587
|
-
adjustedPreviousIndex = adjustToLastLContainerIndex(lContainer, adjustedPreviousIndex);
|
|
19588
|
-
removeLViewFromLContainer(lContainer, adjustedPreviousIndex);
|
|
19589
|
-
needsIndexUpdate = true;
|
|
19590
|
-
}
|
|
19591
|
-
else if (adjustedPreviousIndex !== null) {
|
|
19592
|
-
// move
|
|
19593
|
-
const existingLView = detachExistingView(lContainer, adjustedPreviousIndex);
|
|
19594
|
-
addLViewToLContainer(lContainer, existingLView, currentIndex);
|
|
19595
|
-
needsIndexUpdate = true;
|
|
19596
|
-
}
|
|
19597
|
-
});
|
|
19598
|
-
// A trackBy function might return the same value even if the underlying item changed - re-bind
|
|
19599
|
-
// it in the context.
|
|
19600
|
-
changes.forEachIdentityChange((record) => {
|
|
19601
|
-
const viewIdx = adjustToLastLContainerIndex(lContainer, record.currentIndex);
|
|
19602
|
-
const lView = getExistingLViewFromLContainer(lContainer, viewIdx);
|
|
19603
|
-
lView[CONTEXT].$implicit = record.item;
|
|
19604
|
-
});
|
|
19605
|
-
// moves in the container might caused context's index to get out of order, re-adjust
|
|
19606
|
-
if (needsIndexUpdate) {
|
|
19607
|
-
for (let i = 0; i < lContainer.length - CONTAINER_HEADER_OFFSET; i++) {
|
|
19608
|
-
const lView = getExistingLViewFromLContainer(lContainer, i);
|
|
19609
|
-
lView[CONTEXT].$index = i;
|
|
19610
|
-
}
|
|
19611
|
-
}
|
|
19612
|
-
}
|
|
19613
|
-
// handle empty blocks
|
|
19614
|
-
const bindingIndex = nextBindingIndex();
|
|
19615
|
-
if (metadata.hasEmptyBlock) {
|
|
19616
|
-
const hasItemsInCollection = differ.length > 0;
|
|
19617
|
-
if (bindingUpdated(hostLView, bindingIndex, hasItemsInCollection)) {
|
|
19618
|
-
const emptyTemplateIndex = metadataSlotIdx + 2;
|
|
19619
|
-
const lContainer = getLContainer(hostLView, HEADER_OFFSET + emptyTemplateIndex);
|
|
19620
|
-
if (hasItemsInCollection) {
|
|
19621
|
-
removeLViewFromLContainer(lContainer, 0);
|
|
19622
|
-
}
|
|
19623
|
-
else {
|
|
19624
|
-
const emptyTemplateTNode = getExistingTNode(hostTView, emptyTemplateIndex);
|
|
19625
|
-
const embeddedLView = createAndRenderEmbeddedLView(hostLView, emptyTemplateTNode, undefined);
|
|
19626
|
-
addLViewToLContainer(lContainer, embeddedLView, 0);
|
|
19627
|
-
}
|
|
19628
|
-
}
|
|
19629
|
-
}
|
|
19630
|
-
}
|
|
19631
|
-
function getLContainer(lView, index) {
|
|
19632
|
-
const lContainer = lView[index];
|
|
19633
|
-
ngDevMode && assertLContainer(lContainer);
|
|
19634
|
-
return lContainer;
|
|
19635
|
-
}
|
|
19636
|
-
function adjustToLastLContainerIndex(lContainer, index) {
|
|
19637
|
-
return index !== null ? index : lContainer.length - CONTAINER_HEADER_OFFSET;
|
|
19638
|
-
}
|
|
19639
|
-
function detachExistingView(lContainer, index) {
|
|
19640
|
-
const existingLView = detachView(lContainer, index);
|
|
19641
|
-
ngDevMode && assertLView(existingLView);
|
|
19642
|
-
return existingLView;
|
|
19643
|
-
}
|
|
19644
|
-
function getExistingLViewFromLContainer(lContainer, index) {
|
|
19645
|
-
const existingLView = getLViewFromLContainer(lContainer, index);
|
|
19646
|
-
ngDevMode && assertLView(existingLView);
|
|
19647
|
-
return existingLView;
|
|
19648
|
-
}
|
|
19649
|
-
function getExistingTNode(tView, index) {
|
|
19650
|
-
const tNode = getTNode(tView, index + HEADER_OFFSET);
|
|
19651
|
-
ngDevMode && assertTNode(tNode);
|
|
19652
|
-
return tNode;
|
|
19653
|
-
}
|
|
19654
|
-
|
|
19655
|
-
/**
|
|
19656
|
-
* Removes all dehydrated views from a given LContainer:
|
|
19657
|
-
* both in internal data structure, as well as removing
|
|
19658
|
-
* corresponding DOM nodes that belong to that dehydrated view.
|
|
19659
|
-
*/
|
|
19660
|
-
function removeDehydratedViews(lContainer) {
|
|
19661
|
-
const views = lContainer[DEHYDRATED_VIEWS] ?? [];
|
|
19662
|
-
const parentLView = lContainer[PARENT];
|
|
19663
|
-
const renderer = parentLView[RENDERER];
|
|
19664
|
-
for (const view of views) {
|
|
19665
|
-
removeDehydratedView(view, renderer);
|
|
19666
|
-
ngDevMode && ngDevMode.dehydratedViewsRemoved++;
|
|
19667
|
-
}
|
|
19668
|
-
// Reset the value to an empty array to indicate that no
|
|
19669
|
-
// further processing of dehydrated views is needed for
|
|
19670
|
-
// this view container (i.e. do not trigger the lookup process
|
|
19671
|
-
// once again in case a `ViewContainerRef` is created later).
|
|
19672
|
-
lContainer[DEHYDRATED_VIEWS] = EMPTY_ARRAY;
|
|
19673
|
-
}
|
|
19674
|
-
/**
|
|
19675
|
-
* Helper function to remove all nodes from a dehydrated view.
|
|
19676
|
-
*/
|
|
19677
|
-
function removeDehydratedView(dehydratedView, renderer) {
|
|
19678
|
-
let nodesRemoved = 0;
|
|
19679
|
-
let currentRNode = dehydratedView.firstChild;
|
|
19680
|
-
if (currentRNode) {
|
|
19681
|
-
const numNodes = dehydratedView.data[NUM_ROOT_NODES];
|
|
19682
|
-
while (nodesRemoved < numNodes) {
|
|
19683
|
-
ngDevMode && validateSiblingNodeExists(currentRNode);
|
|
19684
|
-
const nextSibling = currentRNode.nextSibling;
|
|
19685
|
-
nativeRemoveNode(renderer, currentRNode, false);
|
|
19686
|
-
currentRNode = nextSibling;
|
|
19687
|
-
nodesRemoved++;
|
|
19688
|
-
}
|
|
19689
|
-
}
|
|
19690
|
-
}
|
|
19691
|
-
/**
|
|
19692
|
-
* Walks over all views within this LContainer invokes dehydrated views
|
|
19693
|
-
* cleanup function for each one.
|
|
19694
|
-
*/
|
|
19695
|
-
function cleanupLContainer(lContainer) {
|
|
19696
|
-
removeDehydratedViews(lContainer);
|
|
19697
|
-
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
19698
|
-
cleanupLView(lContainer[i]);
|
|
19699
|
-
}
|
|
19700
|
-
}
|
|
19701
|
-
/**
|
|
19702
|
-
* Walks over `LContainer`s and components registered within
|
|
19703
|
-
* this LView and invokes dehydrated views cleanup function for each one.
|
|
19704
|
-
*/
|
|
19705
|
-
function cleanupLView(lView) {
|
|
19706
|
-
const tView = lView[TVIEW];
|
|
19707
|
-
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
|
|
19708
|
-
if (isLContainer(lView[i])) {
|
|
19709
|
-
const lContainer = lView[i];
|
|
19710
|
-
cleanupLContainer(lContainer);
|
|
19711
|
-
}
|
|
19712
|
-
else if (isLView(lView[i])) {
|
|
19713
|
-
// This is a component, enter the `cleanupLView` recursively.
|
|
19714
|
-
cleanupLView(lView[i]);
|
|
19715
|
-
}
|
|
19716
|
-
}
|
|
19717
|
-
}
|
|
19718
|
-
/**
|
|
19719
|
-
* Walks over all views registered within the ApplicationRef and removes
|
|
19720
|
-
* all dehydrated views from all `LContainer`s along the way.
|
|
19721
|
-
*/
|
|
19722
|
-
function cleanupDehydratedViews(appRef) {
|
|
19723
|
-
const viewRefs = appRef._views;
|
|
19724
|
-
for (const viewRef of viewRefs) {
|
|
19725
|
-
const lNode = getLNodeForHydration(viewRef);
|
|
19726
|
-
// An `lView` might be `null` if a `ViewRef` represents
|
|
19727
|
-
// an embedded view (not a component view).
|
|
19728
|
-
if (lNode !== null && lNode[HOST] !== null) {
|
|
19729
|
-
if (isLView(lNode)) {
|
|
19730
|
-
cleanupLView(lNode);
|
|
19731
|
-
}
|
|
19732
|
-
else {
|
|
19733
|
-
// Cleanup in the root component view
|
|
19734
|
-
const componentLView = lNode[HOST];
|
|
19735
|
-
cleanupLView(componentLView);
|
|
19736
|
-
// Cleanup in all views within this view container
|
|
19737
|
-
cleanupLContainer(lNode);
|
|
19738
|
-
}
|
|
19739
|
-
ngDevMode && ngDevMode.dehydratedViewsCleanupRuns++;
|
|
19740
|
-
}
|
|
19741
|
-
}
|
|
19742
|
-
}
|
|
19743
|
-
|
|
19744
|
-
/**
|
|
19745
|
-
* Given a current DOM node and a serialized information about the views
|
|
19746
|
-
* in a container, walks over the DOM structure, collecting the list of
|
|
19747
|
-
* dehydrated views.
|
|
19748
|
-
*/
|
|
19749
|
-
function locateDehydratedViewsInContainer(currentRNode, serializedViews) {
|
|
19750
|
-
const dehydratedViews = [];
|
|
19751
|
-
for (const serializedView of serializedViews) {
|
|
19752
|
-
// Repeats a view multiple times as needed, based on the serialized information
|
|
19753
|
-
// (for example, for *ngFor-produced views).
|
|
19754
|
-
for (let i = 0; i < (serializedView[MULTIPLIER] ?? 1); i++) {
|
|
19755
|
-
const view = {
|
|
19756
|
-
data: serializedView,
|
|
19757
|
-
firstChild: null,
|
|
19758
|
-
};
|
|
19759
|
-
if (serializedView[NUM_ROOT_NODES] > 0) {
|
|
19760
|
-
// Keep reference to the first node in this view,
|
|
19761
|
-
// so it can be accessed while invoking template instructions.
|
|
19762
|
-
view.firstChild = currentRNode;
|
|
19763
|
-
// Move over to the next node after this view, which can
|
|
19764
|
-
// either be a first node of the next view or an anchor comment
|
|
19765
|
-
// node after the last view in a container.
|
|
19766
|
-
currentRNode = siblingAfter(serializedView[NUM_ROOT_NODES], currentRNode);
|
|
19767
|
-
}
|
|
19768
|
-
dehydratedViews.push(view);
|
|
19769
|
-
}
|
|
19770
|
-
}
|
|
19771
|
-
return [currentRNode, dehydratedViews];
|
|
19772
|
-
}
|
|
19773
|
-
/**
|
|
19774
|
-
* Reference to a function that searches for a matching dehydrated views
|
|
19775
|
-
* stored on a given lContainer.
|
|
19776
|
-
* Returns `null` by default, when hydration is not enabled.
|
|
19777
|
-
*/
|
|
19778
|
-
let _findMatchingDehydratedViewImpl = (lContainer, template) => null;
|
|
19779
|
-
/**
|
|
19780
|
-
* Retrieves the next dehydrated view from the LContainer and verifies that
|
|
19781
|
-
* it matches a given template id (from the TView that was used to create this
|
|
19782
|
-
* instance of a view). If the id doesn't match, that means that we are in an
|
|
19783
|
-
* unexpected state and can not complete the reconciliation process. Thus,
|
|
19784
|
-
* all dehydrated views from this LContainer are removed (including corresponding
|
|
19785
|
-
* DOM nodes) and the rendering is performed as if there were no dehydrated views
|
|
19786
|
-
* in this container.
|
|
19787
|
-
*/
|
|
19788
|
-
function findMatchingDehydratedViewImpl(lContainer, template) {
|
|
19789
|
-
const views = lContainer[DEHYDRATED_VIEWS] ?? [];
|
|
19790
|
-
if (!template || views.length === 0) {
|
|
19791
|
-
return null;
|
|
19792
|
-
}
|
|
19793
|
-
const view = views[0];
|
|
19794
|
-
// Verify whether the first dehydrated view in the container matches
|
|
19795
|
-
// the template id passed to this function (that originated from a TView
|
|
19796
|
-
// that was used to create an instance of an embedded or component views.
|
|
19797
|
-
if (view.data[TEMPLATE_ID] === template) {
|
|
19798
|
-
// If the template id matches - extract the first view and return it.
|
|
19799
|
-
return views.shift();
|
|
19800
|
-
}
|
|
19801
|
-
else {
|
|
19802
|
-
// Otherwise, we are at the state when reconciliation can not be completed,
|
|
19803
|
-
// thus we remove all dehydrated views within this container (remove them
|
|
19804
|
-
// from internal data structures as well as delete associated elements from
|
|
19805
|
-
// the DOM tree).
|
|
19806
|
-
removeDehydratedViews(lContainer);
|
|
19807
|
-
return null;
|
|
19808
|
-
}
|
|
19809
|
-
}
|
|
19810
|
-
function enableFindMatchingDehydratedViewImpl() {
|
|
19811
|
-
_findMatchingDehydratedViewImpl = findMatchingDehydratedViewImpl;
|
|
19812
|
-
}
|
|
19813
|
-
function findMatchingDehydratedView(lContainer, template) {
|
|
19814
|
-
return _findMatchingDehydratedViewImpl(lContainer, template);
|
|
19815
|
-
}
|
|
19816
|
-
|
|
19817
|
-
/**
|
|
19818
|
-
* Represents a container where one or more views can be attached to a component.
|
|
19819
|
-
*
|
|
19820
|
-
* Can contain *host views* (created by instantiating a
|
|
19821
|
-
* component with the `createComponent()` method), and *embedded views*
|
|
19822
|
-
* (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method).
|
|
19823
|
-
*
|
|
19824
|
-
* A view container instance can contain other view containers,
|
|
19825
|
-
* creating a [view hierarchy](guide/glossary#view-hierarchy).
|
|
19826
|
-
*
|
|
19827
|
-
* @usageNotes
|
|
19828
|
-
*
|
|
19829
|
-
* The example below demonstrates how the `createComponent` function can be used
|
|
19830
|
-
* to create an instance of a ComponentRef dynamically and attach it to an ApplicationRef,
|
|
19831
|
-
* so that it gets included into change detection cycles.
|
|
19832
|
-
*
|
|
19833
|
-
* Note: the example uses standalone components, but the function can also be used for
|
|
19834
|
-
* non-standalone components (declared in an NgModule) as well.
|
|
19835
|
-
*
|
|
19836
|
-
* ```typescript
|
|
19837
|
-
* @Component({
|
|
19838
|
-
* standalone: true,
|
|
19839
|
-
* selector: 'dynamic',
|
|
19840
|
-
* template: `<span>This is a content of a dynamic component.</span>`,
|
|
19841
|
-
* })
|
|
19842
|
-
* class DynamicComponent {
|
|
19843
|
-
* vcr = inject(ViewContainerRef);
|
|
19844
|
-
* }
|
|
19845
|
-
*
|
|
19846
|
-
* @Component({
|
|
19847
|
-
* standalone: true,
|
|
19848
|
-
* selector: 'app',
|
|
19849
|
-
* template: `<main>Hi! This is the main content.</main>`,
|
|
19850
|
-
* })
|
|
19851
|
-
* class AppComponent {
|
|
19852
|
-
* vcr = inject(ViewContainerRef);
|
|
19853
|
-
*
|
|
19854
|
-
* ngAfterViewInit() {
|
|
19855
|
-
* const compRef = this.vcr.createComponent(DynamicComponent);
|
|
19856
|
-
* compRef.changeDetectorRef.detectChanges();
|
|
19857
|
-
* }
|
|
19858
|
-
* }
|
|
19859
|
-
* ```
|
|
19860
|
-
*
|
|
19861
|
-
* @see {@link ComponentRef}
|
|
19862
|
-
* @see {@link EmbeddedViewRef}
|
|
19863
|
-
*
|
|
19864
|
-
* @publicApi
|
|
19865
|
-
*/
|
|
19866
|
-
class ViewContainerRef {
|
|
19867
|
-
/**
|
|
19868
|
-
* @internal
|
|
19869
|
-
* @nocollapse
|
|
19870
|
-
*/
|
|
19871
|
-
static { this.__NG_ELEMENT_ID__ = injectViewContainerRef; }
|
|
19872
|
-
}
|
|
19873
|
-
/**
|
|
19874
|
-
* Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef
|
|
19875
|
-
* already exists, retrieves the existing ViewContainerRef.
|
|
19876
|
-
*
|
|
19877
|
-
* @returns The ViewContainerRef instance to use
|
|
19878
|
-
*/
|
|
19879
|
-
function injectViewContainerRef() {
|
|
19880
|
-
const previousTNode = getCurrentTNode();
|
|
19881
|
-
return createContainerRef(previousTNode, getLView());
|
|
19882
|
-
}
|
|
19883
|
-
const VE_ViewContainerRef = ViewContainerRef;
|
|
19884
|
-
// TODO(alxhub): cleaning up this indirection triggers a subtle bug in Closure in g3. Once the fix
|
|
19885
|
-
// for that lands, this can be cleaned up.
|
|
19886
|
-
const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
|
|
19887
|
-
constructor(_lContainer, _hostTNode, _hostLView) {
|
|
19888
|
-
super();
|
|
19889
|
-
this._lContainer = _lContainer;
|
|
19890
|
-
this._hostTNode = _hostTNode;
|
|
19891
|
-
this._hostLView = _hostLView;
|
|
19892
|
-
}
|
|
19893
|
-
get element() {
|
|
19894
|
-
return createElementRef(this._hostTNode, this._hostLView);
|
|
19895
|
-
}
|
|
19896
|
-
get injector() {
|
|
19897
|
-
return new NodeInjector(this._hostTNode, this._hostLView);
|
|
19898
|
-
}
|
|
19899
|
-
/** @deprecated No replacement */
|
|
19900
|
-
get parentInjector() {
|
|
19901
|
-
const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostLView);
|
|
19902
|
-
if (hasParentInjector(parentLocation)) {
|
|
19903
|
-
const parentView = getParentInjectorView(parentLocation, this._hostLView);
|
|
19904
|
-
const injectorIndex = getParentInjectorIndex(parentLocation);
|
|
19905
|
-
ngDevMode && assertNodeInjector(parentView, injectorIndex);
|
|
19906
|
-
const parentTNode = parentView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */];
|
|
19907
|
-
return new NodeInjector(parentTNode, parentView);
|
|
19908
|
-
}
|
|
19909
|
-
else {
|
|
19910
|
-
return new NodeInjector(null, this._hostLView);
|
|
19911
|
-
}
|
|
19912
|
-
}
|
|
19913
|
-
clear() {
|
|
19914
|
-
while (this.length > 0) {
|
|
19915
|
-
this.remove(this.length - 1);
|
|
19916
|
-
}
|
|
19917
|
-
}
|
|
19918
|
-
get(index) {
|
|
19919
|
-
const viewRefs = getViewRefs(this._lContainer);
|
|
19920
|
-
return viewRefs !== null && viewRefs[index] || null;
|
|
19921
|
-
}
|
|
19922
|
-
get length() {
|
|
19923
|
-
return this._lContainer.length - CONTAINER_HEADER_OFFSET;
|
|
19924
|
-
}
|
|
19925
|
-
createEmbeddedView(templateRef, context, indexOrOptions) {
|
|
19926
|
-
let index;
|
|
19927
|
-
let injector;
|
|
19928
|
-
if (typeof indexOrOptions === 'number') {
|
|
19929
|
-
index = indexOrOptions;
|
|
19930
|
-
}
|
|
19931
|
-
else if (indexOrOptions != null) {
|
|
19932
|
-
index = indexOrOptions.index;
|
|
19933
|
-
injector = indexOrOptions.injector;
|
|
19934
|
-
}
|
|
19935
|
-
const dehydratedView = findMatchingDehydratedView(this._lContainer, templateRef.ssrId);
|
|
19936
|
-
const viewRef = templateRef.createEmbeddedViewImpl(context || {}, injector, dehydratedView);
|
|
19937
|
-
this.insertImpl(viewRef, index, shouldAddViewToDom(this._hostTNode, dehydratedView));
|
|
19938
|
-
return viewRef;
|
|
19939
|
-
}
|
|
19940
|
-
createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) {
|
|
19941
|
-
const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType);
|
|
19942
|
-
let index;
|
|
19943
|
-
// This function supports 2 signatures and we need to handle options correctly for both:
|
|
19944
|
-
// 1. When first argument is a Component type. This signature also requires extra
|
|
19945
|
-
// options to be provided as object (more ergonomic option).
|
|
19946
|
-
// 2. First argument is a Component factory. In this case extra options are represented as
|
|
19947
|
-
// positional arguments. This signature is less ergonomic and will be deprecated.
|
|
19948
|
-
if (isComponentFactory) {
|
|
19949
|
-
if (ngDevMode) {
|
|
19950
|
-
assertEqual(typeof indexOrOptions !== 'object', true, 'It looks like Component factory was provided as the first argument ' +
|
|
19951
|
-
'and an options object as the second argument. This combination of arguments ' +
|
|
19952
|
-
'is incompatible. You can either change the first argument to provide Component ' +
|
|
19953
|
-
'type or change the second argument to be a number (representing an index at ' +
|
|
19954
|
-
'which to insert the new component\'s host view into this container)');
|
|
19955
|
-
}
|
|
19956
|
-
index = indexOrOptions;
|
|
19957
|
-
}
|
|
19958
|
-
else {
|
|
19959
|
-
if (ngDevMode) {
|
|
19960
|
-
assertDefined(getComponentDef(componentFactoryOrType), `Provided Component class doesn't contain Component definition. ` +
|
|
19961
|
-
`Please check whether provided class has @Component decorator.`);
|
|
19962
|
-
assertEqual(typeof indexOrOptions !== 'number', true, 'It looks like Component type was provided as the first argument ' +
|
|
19963
|
-
'and a number (representing an index at which to insert the new component\'s ' +
|
|
19964
|
-
'host view into this container as the second argument. This combination of arguments ' +
|
|
19965
|
-
'is incompatible. Please use an object as the second argument instead.');
|
|
20321
|
+
adjustedPreviousIndex = adjustToLastLContainerIndex(lContainer, adjustedPreviousIndex);
|
|
20322
|
+
removeLViewFromLContainer(lContainer, adjustedPreviousIndex);
|
|
20323
|
+
needsIndexUpdate = true;
|
|
19966
20324
|
}
|
|
19967
|
-
|
|
19968
|
-
|
|
19969
|
-
|
|
20325
|
+
else if (adjustedPreviousIndex !== null) {
|
|
20326
|
+
// move
|
|
20327
|
+
const existingLView = detachExistingView(lContainer, adjustedPreviousIndex);
|
|
20328
|
+
addLViewToLContainer(lContainer, existingLView, currentIndex);
|
|
20329
|
+
needsIndexUpdate = true;
|
|
19970
20330
|
}
|
|
19971
|
-
|
|
19972
|
-
|
|
19973
|
-
|
|
19974
|
-
|
|
19975
|
-
|
|
19976
|
-
|
|
19977
|
-
|
|
19978
|
-
|
|
19979
|
-
|
|
19980
|
-
|
|
19981
|
-
|
|
19982
|
-
|
|
19983
|
-
|
|
19984
|
-
// `ngModule` field. This is possible in some test scenarios and potentially in some JIT-based
|
|
19985
|
-
// use-cases. For the `ComponentFactory` case we preserve backwards-compatibility and try
|
|
19986
|
-
// using a provided injector first, then fall back to the parent injector of this
|
|
19987
|
-
// `ViewContainerRef` instance.
|
|
19988
|
-
//
|
|
19989
|
-
// For the factory-less case, it's critical to establish a connection with the module
|
|
19990
|
-
// injector tree (by retrieving an instance of an `NgModuleRef` and accessing its injector),
|
|
19991
|
-
// so that a component can use DI tokens provided in MgModules. For this reason, we can not
|
|
19992
|
-
// rely on the provided injector, since it might be detached from the DI tree (for example, if
|
|
19993
|
-
// it was created via `Injector.create` without specifying a parent injector, or if an
|
|
19994
|
-
// injector is retrieved from an `NgModuleRef` created via `createNgModule` using an
|
|
19995
|
-
// NgModule outside of a module tree). Instead, we always use `ViewContainerRef`'s parent
|
|
19996
|
-
// injector, which is normally connected to the DI tree, which includes module injector
|
|
19997
|
-
// subtree.
|
|
19998
|
-
const _injector = isComponentFactory ? contextInjector : this.parentInjector;
|
|
19999
|
-
// DO NOT REFACTOR. The code here used to have a `injector.get(NgModuleRef, null) ||
|
|
20000
|
-
// undefined` expression which seems to cause internal google apps to fail. This is documented
|
|
20001
|
-
// in the following internal bug issue: go/b/142967802
|
|
20002
|
-
const result = _injector.get(EnvironmentInjector, null);
|
|
20003
|
-
if (result) {
|
|
20004
|
-
environmentInjector = result;
|
|
20331
|
+
});
|
|
20332
|
+
// A trackBy function might return the same value even if the underlying item changed - re-bind
|
|
20333
|
+
// it in the context.
|
|
20334
|
+
changes.forEachIdentityChange((record) => {
|
|
20335
|
+
const viewIdx = adjustToLastLContainerIndex(lContainer, record.currentIndex);
|
|
20336
|
+
const lView = getExistingLViewFromLContainer(lContainer, viewIdx);
|
|
20337
|
+
lView[CONTEXT].$implicit = record.item;
|
|
20338
|
+
});
|
|
20339
|
+
// moves in the container might caused context's index to get out of order, re-adjust
|
|
20340
|
+
if (needsIndexUpdate) {
|
|
20341
|
+
for (let i = 0; i < lContainer.length - CONTAINER_HEADER_OFFSET; i++) {
|
|
20342
|
+
const lView = getExistingLViewFromLContainer(lContainer, i);
|
|
20343
|
+
lView[CONTEXT].$index = i;
|
|
20005
20344
|
}
|
|
20006
20345
|
}
|
|
20007
|
-
const componentDef = getComponentDef(componentFactory.componentType ?? {});
|
|
20008
|
-
const dehydratedView = findMatchingDehydratedView(this._lContainer, componentDef?.id ?? null);
|
|
20009
|
-
const rNode = dehydratedView?.firstChild ?? null;
|
|
20010
|
-
const componentRef = componentFactory.create(contextInjector, projectableNodes, rNode, environmentInjector);
|
|
20011
|
-
this.insertImpl(componentRef.hostView, index, shouldAddViewToDom(this._hostTNode, dehydratedView));
|
|
20012
|
-
return componentRef;
|
|
20013
20346
|
}
|
|
20014
|
-
|
|
20015
|
-
|
|
20016
|
-
|
|
20017
|
-
|
|
20018
|
-
|
|
20019
|
-
|
|
20020
|
-
|
|
20021
|
-
|
|
20022
|
-
|
|
20023
|
-
// If view is already attached, detach it first so we clean up references appropriately.
|
|
20024
|
-
const prevIdx = this.indexOf(viewRef);
|
|
20025
|
-
// A view might be attached either to this or a different container. The `prevIdx` for
|
|
20026
|
-
// those cases will be:
|
|
20027
|
-
// equal to -1 for views attached to this ViewContainerRef
|
|
20028
|
-
// >= 0 for views attached to a different ViewContainerRef
|
|
20029
|
-
if (prevIdx !== -1) {
|
|
20030
|
-
this.detach(prevIdx);
|
|
20347
|
+
// handle empty blocks
|
|
20348
|
+
const bindingIndex = nextBindingIndex();
|
|
20349
|
+
if (metadata.hasEmptyBlock) {
|
|
20350
|
+
const hasItemsInCollection = differ.length > 0;
|
|
20351
|
+
if (bindingUpdated(hostLView, bindingIndex, hasItemsInCollection)) {
|
|
20352
|
+
const emptyTemplateIndex = metadataSlotIdx + 2;
|
|
20353
|
+
const lContainer = getLContainer(hostLView, HEADER_OFFSET + emptyTemplateIndex);
|
|
20354
|
+
if (hasItemsInCollection) {
|
|
20355
|
+
removeLViewFromLContainer(lContainer, 0);
|
|
20031
20356
|
}
|
|
20032
20357
|
else {
|
|
20033
|
-
const
|
|
20034
|
-
|
|
20035
|
-
|
|
20036
|
-
// We need to re-create a R3ViewContainerRef instance since those are not stored on
|
|
20037
|
-
// LView (nor anywhere else).
|
|
20038
|
-
const prevVCRef = new R3ViewContainerRef(prevLContainer, prevLContainer[T_HOST], prevLContainer[PARENT]);
|
|
20039
|
-
prevVCRef.detach(prevVCRef.indexOf(viewRef));
|
|
20358
|
+
const emptyTemplateTNode = getExistingTNode(hostTView, emptyTemplateIndex);
|
|
20359
|
+
const embeddedLView = createAndRenderEmbeddedLView(hostLView, emptyTemplateTNode, undefined);
|
|
20360
|
+
addLViewToLContainer(lContainer, embeddedLView, 0);
|
|
20040
20361
|
}
|
|
20041
20362
|
}
|
|
20042
|
-
// Logical operation of adding `LView` to `LContainer`
|
|
20043
|
-
const adjustedIdx = this._adjustIndex(index);
|
|
20044
|
-
const lContainer = this._lContainer;
|
|
20045
|
-
addLViewToLContainer(lContainer, lView, adjustedIdx, addToDOM);
|
|
20046
|
-
viewRef.attachToViewContainerRef();
|
|
20047
|
-
addToArray(getOrCreateViewRefs(lContainer), adjustedIdx, viewRef);
|
|
20048
|
-
return viewRef;
|
|
20049
|
-
}
|
|
20050
|
-
move(viewRef, newIndex) {
|
|
20051
|
-
if (ngDevMode && viewRef.destroyed) {
|
|
20052
|
-
throw new Error('Cannot move a destroyed View in a ViewContainer!');
|
|
20053
|
-
}
|
|
20054
|
-
return this.insert(viewRef, newIndex);
|
|
20055
|
-
}
|
|
20056
|
-
indexOf(viewRef) {
|
|
20057
|
-
const viewRefsArr = getViewRefs(this._lContainer);
|
|
20058
|
-
return viewRefsArr !== null ? viewRefsArr.indexOf(viewRef) : -1;
|
|
20059
|
-
}
|
|
20060
|
-
remove(index) {
|
|
20061
|
-
const adjustedIdx = this._adjustIndex(index, -1);
|
|
20062
|
-
const detachedView = detachView(this._lContainer, adjustedIdx);
|
|
20063
|
-
if (detachedView) {
|
|
20064
|
-
// Before destroying the view, remove it from the container's array of `ViewRef`s.
|
|
20065
|
-
// This ensures the view container length is updated before calling
|
|
20066
|
-
// `destroyLView`, which could recursively call view container methods that
|
|
20067
|
-
// rely on an accurate container length.
|
|
20068
|
-
// (e.g. a method on this view container being called by a child directive's OnDestroy
|
|
20069
|
-
// lifecycle hook)
|
|
20070
|
-
removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx);
|
|
20071
|
-
destroyLView(detachedView[TVIEW], detachedView);
|
|
20072
|
-
}
|
|
20073
|
-
}
|
|
20074
|
-
detach(index) {
|
|
20075
|
-
const adjustedIdx = this._adjustIndex(index, -1);
|
|
20076
|
-
const view = detachView(this._lContainer, adjustedIdx);
|
|
20077
|
-
const wasDetached = view && removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx) != null;
|
|
20078
|
-
return wasDetached ? new ViewRef$1(view) : null;
|
|
20079
|
-
}
|
|
20080
|
-
_adjustIndex(index, shift = 0) {
|
|
20081
|
-
if (index == null) {
|
|
20082
|
-
return this.length + shift;
|
|
20083
|
-
}
|
|
20084
|
-
if (ngDevMode) {
|
|
20085
|
-
assertGreaterThan(index, -1, `ViewRef index must be positive, got ${index}`);
|
|
20086
|
-
// +1 because it's legal to insert at the end.
|
|
20087
|
-
assertLessThan(index, this.length + 1 + shift, 'index');
|
|
20088
|
-
}
|
|
20089
|
-
return index;
|
|
20090
20363
|
}
|
|
20091
|
-
};
|
|
20092
|
-
function getViewRefs(lContainer) {
|
|
20093
|
-
return lContainer[VIEW_REFS];
|
|
20094
20364
|
}
|
|
20095
|
-
function
|
|
20096
|
-
|
|
20365
|
+
function getLContainer(lView, index) {
|
|
20366
|
+
const lContainer = lView[index];
|
|
20367
|
+
ngDevMode && assertLContainer(lContainer);
|
|
20368
|
+
return lContainer;
|
|
20369
|
+
}
|
|
20370
|
+
function adjustToLastLContainerIndex(lContainer, index) {
|
|
20371
|
+
return index !== null ? index : lContainer.length - CONTAINER_HEADER_OFFSET;
|
|
20097
20372
|
}
|
|
20373
|
+
function detachExistingView(lContainer, index) {
|
|
20374
|
+
const existingLView = detachView(lContainer, index);
|
|
20375
|
+
ngDevMode && assertLView(existingLView);
|
|
20376
|
+
return existingLView;
|
|
20377
|
+
}
|
|
20378
|
+
function getExistingLViewFromLContainer(lContainer, index) {
|
|
20379
|
+
const existingLView = getLViewFromLContainer(lContainer, index);
|
|
20380
|
+
ngDevMode && assertLView(existingLView);
|
|
20381
|
+
return existingLView;
|
|
20382
|
+
}
|
|
20383
|
+
function getExistingTNode(tView, index) {
|
|
20384
|
+
const tNode = getTNode(tView, index + HEADER_OFFSET);
|
|
20385
|
+
ngDevMode && assertTNode(tNode);
|
|
20386
|
+
return tNode;
|
|
20387
|
+
}
|
|
20388
|
+
|
|
20098
20389
|
/**
|
|
20099
|
-
*
|
|
20390
|
+
* Describes the state of defer block dependency loading.
|
|
20391
|
+
*/
|
|
20392
|
+
var DeferDependenciesLoadingState;
|
|
20393
|
+
(function (DeferDependenciesLoadingState) {
|
|
20394
|
+
/** Initial state, dependency loading is not yet triggered */
|
|
20395
|
+
DeferDependenciesLoadingState[DeferDependenciesLoadingState["NOT_STARTED"] = 0] = "NOT_STARTED";
|
|
20396
|
+
/** Dependency loading is in progress */
|
|
20397
|
+
DeferDependenciesLoadingState[DeferDependenciesLoadingState["IN_PROGRESS"] = 1] = "IN_PROGRESS";
|
|
20398
|
+
/** Dependency loading has completed successfully */
|
|
20399
|
+
DeferDependenciesLoadingState[DeferDependenciesLoadingState["COMPLETE"] = 2] = "COMPLETE";
|
|
20400
|
+
/** Dependency loading has failed */
|
|
20401
|
+
DeferDependenciesLoadingState[DeferDependenciesLoadingState["FAILED"] = 3] = "FAILED";
|
|
20402
|
+
})(DeferDependenciesLoadingState || (DeferDependenciesLoadingState = {}));
|
|
20403
|
+
/**
|
|
20404
|
+
* Describes the current state of this defer block instance.
|
|
20100
20405
|
*
|
|
20101
|
-
* @
|
|
20102
|
-
* @
|
|
20103
|
-
* @returns The ViewContainerRef instance to use
|
|
20406
|
+
* @publicApi
|
|
20407
|
+
* @developerPreview
|
|
20104
20408
|
*/
|
|
20105
|
-
|
|
20106
|
-
|
|
20107
|
-
|
|
20108
|
-
|
|
20109
|
-
|
|
20110
|
-
|
|
20111
|
-
|
|
20112
|
-
|
|
20113
|
-
|
|
20114
|
-
|
|
20115
|
-
|
|
20116
|
-
// `_locateOrCreateAnchorNode`).
|
|
20117
|
-
lContainer = createLContainer(slotValue, hostLView, null, hostTNode);
|
|
20118
|
-
hostLView[hostTNode.index] = lContainer;
|
|
20119
|
-
addToViewTree(hostLView, lContainer);
|
|
20120
|
-
}
|
|
20121
|
-
_locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue);
|
|
20122
|
-
return new R3ViewContainerRef(lContainer, hostTNode, hostLView);
|
|
20123
|
-
}
|
|
20409
|
+
var DeferBlockState;
|
|
20410
|
+
(function (DeferBlockState) {
|
|
20411
|
+
/** The placeholder block content is rendered */
|
|
20412
|
+
DeferBlockState[DeferBlockState["Placeholder"] = 0] = "Placeholder";
|
|
20413
|
+
/** The loading block content is rendered */
|
|
20414
|
+
DeferBlockState[DeferBlockState["Loading"] = 1] = "Loading";
|
|
20415
|
+
/** The main content block content is rendered */
|
|
20416
|
+
DeferBlockState[DeferBlockState["Complete"] = 2] = "Complete";
|
|
20417
|
+
/** The error block content is rendered */
|
|
20418
|
+
DeferBlockState[DeferBlockState["Error"] = 3] = "Error";
|
|
20419
|
+
})(DeferBlockState || (DeferBlockState = {}));
|
|
20124
20420
|
/**
|
|
20125
|
-
*
|
|
20421
|
+
* Describes the initial state of this defer block instance.
|
|
20126
20422
|
*
|
|
20127
|
-
*
|
|
20128
|
-
*
|
|
20129
|
-
* manipulation to insert it.
|
|
20423
|
+
* Note: this state is internal only and *must* be represented
|
|
20424
|
+
* with a number lower than any value in the `DeferBlockState` enum.
|
|
20130
20425
|
*/
|
|
20131
|
-
|
|
20132
|
-
|
|
20133
|
-
|
|
20134
|
-
|
|
20135
|
-
|
|
20136
|
-
const parentOfHostNative = nativeParentNode(renderer, hostNative);
|
|
20137
|
-
nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
|
|
20138
|
-
return commentNode;
|
|
20139
|
-
}
|
|
20140
|
-
let _locateOrCreateAnchorNode = createAnchorNode;
|
|
20141
|
-
let _populateDehydratedViewsInContainer = (lContainer, lView, tNode) => false; // noop by default
|
|
20426
|
+
var DeferBlockInternalState;
|
|
20427
|
+
(function (DeferBlockInternalState) {
|
|
20428
|
+
/** Initial state. Nothing is rendered yet. */
|
|
20429
|
+
DeferBlockInternalState[DeferBlockInternalState["Initial"] = -1] = "Initial";
|
|
20430
|
+
})(DeferBlockInternalState || (DeferBlockInternalState = {}));
|
|
20142
20431
|
/**
|
|
20143
|
-
*
|
|
20144
|
-
*
|
|
20145
|
-
|
|
20432
|
+
* A slot in the `LDeferBlockDetails` array that contains a number
|
|
20433
|
+
* that represent a current block state that is being rendered.
|
|
20434
|
+
*/
|
|
20435
|
+
const DEFER_BLOCK_STATE = 0;
|
|
20436
|
+
/**
|
|
20437
|
+
* Options for configuring defer blocks behavior.
|
|
20438
|
+
* @publicApi
|
|
20439
|
+
* @developerPreview
|
|
20440
|
+
*/
|
|
20441
|
+
var DeferBlockBehavior;
|
|
20442
|
+
(function (DeferBlockBehavior) {
|
|
20443
|
+
/**
|
|
20444
|
+
* Manual triggering mode for defer blocks. Provides control over when defer blocks render
|
|
20445
|
+
* and which state they render. This is the default behavior in test environments.
|
|
20446
|
+
*/
|
|
20447
|
+
DeferBlockBehavior[DeferBlockBehavior["Manual"] = 0] = "Manual";
|
|
20448
|
+
/**
|
|
20449
|
+
* Playthrough mode for defer blocks. This mode behaves like defer blocks would in a browser.
|
|
20450
|
+
*/
|
|
20451
|
+
DeferBlockBehavior[DeferBlockBehavior["Playthrough"] = 1] = "Playthrough";
|
|
20452
|
+
})(DeferBlockBehavior || (DeferBlockBehavior = {}));
|
|
20453
|
+
|
|
20454
|
+
/*!
|
|
20455
|
+
* @license
|
|
20456
|
+
* Copyright Google LLC All Rights Reserved.
|
|
20146
20457
|
*
|
|
20147
|
-
*
|
|
20148
|
-
*
|
|
20149
|
-
* was successful. The operation might be unsuccessful in case is has completed
|
|
20150
|
-
* previously, we are rendering in client-only mode or this content is located
|
|
20151
|
-
* in a skip hydration section.
|
|
20458
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
20459
|
+
* found in the LICENSE file at https://angular.io/license
|
|
20152
20460
|
*/
|
|
20153
|
-
|
|
20154
|
-
|
|
20461
|
+
/** Configuration object used to register passive and capturing events. */
|
|
20462
|
+
const eventListenerOptions = {
|
|
20463
|
+
passive: true,
|
|
20464
|
+
capture: true
|
|
20465
|
+
};
|
|
20466
|
+
/** Keeps track of the currently-registered `on hover` triggers. */
|
|
20467
|
+
const hoverTriggers = new WeakMap();
|
|
20468
|
+
/** Keeps track of the currently-registered `on interaction` triggers. */
|
|
20469
|
+
const interactionTriggers = new WeakMap();
|
|
20470
|
+
/** Names of the events considered as interaction events. */
|
|
20471
|
+
const interactionEventNames = ['click', 'keydown'];
|
|
20472
|
+
/** Object keeping track of registered callbacks for a deferred block trigger. */
|
|
20473
|
+
class DeferEventEntry {
|
|
20474
|
+
constructor() {
|
|
20475
|
+
this.callbacks = new Set();
|
|
20476
|
+
this.listener = () => {
|
|
20477
|
+
for (const callback of this.callbacks) {
|
|
20478
|
+
callback();
|
|
20479
|
+
}
|
|
20480
|
+
};
|
|
20481
|
+
}
|
|
20155
20482
|
}
|
|
20156
20483
|
/**
|
|
20157
|
-
*
|
|
20158
|
-
*
|
|
20484
|
+
* Registers an interaction trigger.
|
|
20485
|
+
* @param trigger Element that is the trigger.
|
|
20486
|
+
* @param callback Callback to be invoked when the trigger is interacted with.
|
|
20487
|
+
*/
|
|
20488
|
+
function onInteraction(trigger, callback) {
|
|
20489
|
+
let entry = interactionTriggers.get(trigger);
|
|
20490
|
+
// If this is the first entry for this element, add the listeners.
|
|
20491
|
+
if (!entry) {
|
|
20492
|
+
// Note that using managing events centrally like this lends itself well to using global
|
|
20493
|
+
// event delegation. It currently does delegation at the element level, rather than the
|
|
20494
|
+
// document level, because:
|
|
20495
|
+
// 1. Global delegation is the most effective when there are a lot of events being registered
|
|
20496
|
+
// at the same time. Deferred blocks are unlikely to be used in such a way.
|
|
20497
|
+
// 2. Matching events to their target isn't free. For each `click` and `keydown` event we
|
|
20498
|
+
// would have look through all the triggers and check if the target either is the element
|
|
20499
|
+
// itself or it's contained within the element. Given that `click` and `keydown` are some
|
|
20500
|
+
// of the most common events, this may end up introducing a lot of runtime overhead.
|
|
20501
|
+
// 3. We're still registering only two events per element, no matter how many deferred blocks
|
|
20502
|
+
// are referencing it.
|
|
20503
|
+
entry = new DeferEventEntry();
|
|
20504
|
+
interactionTriggers.set(trigger, entry);
|
|
20505
|
+
for (const name of interactionEventNames) {
|
|
20506
|
+
trigger.addEventListener(name, entry.listener, eventListenerOptions);
|
|
20507
|
+
}
|
|
20508
|
+
}
|
|
20509
|
+
entry.callbacks.add(callback);
|
|
20510
|
+
return () => {
|
|
20511
|
+
const { callbacks, listener } = entry;
|
|
20512
|
+
callbacks.delete(callback);
|
|
20513
|
+
if (callbacks.size === 0) {
|
|
20514
|
+
interactionTriggers.delete(trigger);
|
|
20515
|
+
for (const name of interactionEventNames) {
|
|
20516
|
+
trigger.removeEventListener(name, listener, eventListenerOptions);
|
|
20517
|
+
}
|
|
20518
|
+
}
|
|
20519
|
+
};
|
|
20520
|
+
}
|
|
20521
|
+
/**
|
|
20522
|
+
* Registers a hover trigger.
|
|
20523
|
+
* @param trigger Element that is the trigger.
|
|
20524
|
+
* @param callback Callback to be invoked when the trigger is hovered over.
|
|
20159
20525
|
*/
|
|
20160
|
-
function
|
|
20161
|
-
|
|
20162
|
-
|
|
20163
|
-
|
|
20164
|
-
|
|
20165
|
-
|
|
20166
|
-
|
|
20167
|
-
// The comment node in question is already part of the DOM structure so we don't need to append
|
|
20168
|
-
// it again.
|
|
20169
|
-
if (hostTNode.type & 8 /* TNodeType.ElementContainer */) {
|
|
20170
|
-
commentNode = unwrapRNode(slotValue);
|
|
20171
|
-
}
|
|
20172
|
-
else {
|
|
20173
|
-
commentNode = insertAnchorNode(hostLView, hostTNode);
|
|
20526
|
+
function onHover(trigger, callback) {
|
|
20527
|
+
let entry = hoverTriggers.get(trigger);
|
|
20528
|
+
// If this is the first entry for this element, add the listener.
|
|
20529
|
+
if (!entry) {
|
|
20530
|
+
entry = new DeferEventEntry();
|
|
20531
|
+
trigger.addEventListener('mouseenter', entry.listener, eventListenerOptions);
|
|
20532
|
+
hoverTriggers.set(trigger, entry);
|
|
20174
20533
|
}
|
|
20175
|
-
|
|
20534
|
+
entry.callbacks.add(callback);
|
|
20535
|
+
return () => {
|
|
20536
|
+
const { callbacks, listener } = entry;
|
|
20537
|
+
callbacks.delete(callback);
|
|
20538
|
+
if (callbacks.size === 0) {
|
|
20539
|
+
trigger.removeEventListener('mouseenter', listener, eventListenerOptions);
|
|
20540
|
+
hoverTriggers.delete(trigger);
|
|
20541
|
+
}
|
|
20542
|
+
};
|
|
20176
20543
|
}
|
|
20177
20544
|
/**
|
|
20178
|
-
*
|
|
20179
|
-
*
|
|
20180
|
-
*
|
|
20181
|
-
* @
|
|
20182
|
-
* was successful. The operation might be unsuccessful in case is has completed
|
|
20183
|
-
* previously, we are rendering in client-only mode or this content is located
|
|
20184
|
-
* in a skip hydration section.
|
|
20545
|
+
* Registers a viewport trigger.
|
|
20546
|
+
* @param trigger Element that is the trigger.
|
|
20547
|
+
* @param callback Callback to be invoked when the trigger comes into the viewport.
|
|
20548
|
+
* @param injector Injector that can be used by the trigger to resolve DI tokens.
|
|
20185
20549
|
*/
|
|
20186
|
-
function
|
|
20187
|
-
|
|
20188
|
-
// of finding dehydrated views happened (so the `lContainer[DEHYDRATED_VIEWS]`
|
|
20189
|
-
// is not null), exit early.
|
|
20190
|
-
if (lContainer[NATIVE] && lContainer[DEHYDRATED_VIEWS]) {
|
|
20191
|
-
return true;
|
|
20192
|
-
}
|
|
20193
|
-
const hydrationInfo = hostLView[HYDRATION];
|
|
20194
|
-
const noOffsetIndex = hostTNode.index - HEADER_OFFSET;
|
|
20195
|
-
// TODO(akushnir): this should really be a single condition, refactor the code
|
|
20196
|
-
// to use `hasInSkipHydrationBlockFlag` logic inside `isInSkipHydrationBlock`.
|
|
20197
|
-
const skipHydration = isInSkipHydrationBlock(hostTNode) || hasInSkipHydrationBlockFlag(hostTNode);
|
|
20198
|
-
const isNodeCreationMode = !hydrationInfo || skipHydration || isDisconnectedNode$1(hydrationInfo, noOffsetIndex);
|
|
20199
|
-
// Regular creation mode.
|
|
20200
|
-
if (isNodeCreationMode) {
|
|
20201
|
-
return false;
|
|
20202
|
-
}
|
|
20203
|
-
// Hydration mode, looking up an anchor node and dehydrated views in DOM.
|
|
20204
|
-
const currentRNode = getSegmentHead(hydrationInfo, noOffsetIndex);
|
|
20205
|
-
const serializedViews = hydrationInfo.data[CONTAINERS]?.[noOffsetIndex];
|
|
20206
|
-
ngDevMode &&
|
|
20207
|
-
assertDefined(serializedViews, 'Unexpected state: no hydration info available for a given TNode, ' +
|
|
20208
|
-
'which represents a view container.');
|
|
20209
|
-
const [commentNode, dehydratedViews] = locateDehydratedViewsInContainer(currentRNode, serializedViews);
|
|
20210
|
-
if (ngDevMode) {
|
|
20211
|
-
validateMatchingNode(commentNode, Node.COMMENT_NODE, null, hostLView, hostTNode, true);
|
|
20212
|
-
// Do not throw in case this node is already claimed (thus `false` as a second
|
|
20213
|
-
// argument). If this container is created based on an `<ng-template>`, the comment
|
|
20214
|
-
// node would be already claimed from the `template` instruction. If an element acts
|
|
20215
|
-
// as an anchor (e.g. <div #vcRef>), a separate comment node would be created/located,
|
|
20216
|
-
// so we need to claim it here.
|
|
20217
|
-
markRNodeAsClaimedByHydration(commentNode, false);
|
|
20218
|
-
}
|
|
20219
|
-
lContainer[NATIVE] = commentNode;
|
|
20220
|
-
lContainer[DEHYDRATED_VIEWS] = dehydratedViews;
|
|
20221
|
-
return true;
|
|
20550
|
+
function onViewport(trigger, callback, injector) {
|
|
20551
|
+
return injector.get(DeferIntersectionManager).register(trigger, callback);
|
|
20222
20552
|
}
|
|
20223
|
-
|
|
20224
|
-
|
|
20225
|
-
|
|
20226
|
-
|
|
20227
|
-
|
|
20228
|
-
|
|
20553
|
+
/** Keeps track of the registered `viewport` triggers. */
|
|
20554
|
+
class DeferIntersectionManager {
|
|
20555
|
+
/** @nocollapse */
|
|
20556
|
+
static { this.ɵprov = ɵɵdefineInjectable({
|
|
20557
|
+
token: DeferIntersectionManager,
|
|
20558
|
+
providedIn: 'root',
|
|
20559
|
+
factory: () => new DeferIntersectionManager(inject(NgZone)),
|
|
20560
|
+
}); }
|
|
20561
|
+
constructor(ngZone) {
|
|
20562
|
+
this.ngZone = ngZone;
|
|
20563
|
+
/** `IntersectionObserver` used to observe `viewport` triggers. */
|
|
20564
|
+
this.intersectionObserver = null;
|
|
20565
|
+
/** Number of elements currently observed with `viewport` triggers. */
|
|
20566
|
+
this.observedViewportElements = 0;
|
|
20567
|
+
/** Currently-registered `viewport` triggers. */
|
|
20568
|
+
this.viewportTriggers = new WeakMap();
|
|
20569
|
+
this.intersectionCallback = entries => {
|
|
20570
|
+
for (const current of entries) {
|
|
20571
|
+
// Only invoke the callbacks if the specific element is intersecting.
|
|
20572
|
+
if (current.isIntersecting && this.viewportTriggers.has(current.target)) {
|
|
20573
|
+
this.ngZone.run(this.viewportTriggers.get(current.target).listener);
|
|
20574
|
+
}
|
|
20575
|
+
}
|
|
20576
|
+
};
|
|
20577
|
+
}
|
|
20578
|
+
register(trigger, callback) {
|
|
20579
|
+
let entry = this.viewportTriggers.get(trigger);
|
|
20580
|
+
if (!this.intersectionObserver) {
|
|
20581
|
+
this.intersectionObserver =
|
|
20582
|
+
this.ngZone.runOutsideAngular(() => new IntersectionObserver(this.intersectionCallback));
|
|
20583
|
+
}
|
|
20584
|
+
if (!entry) {
|
|
20585
|
+
entry = new DeferEventEntry();
|
|
20586
|
+
this.ngZone.runOutsideAngular(() => this.intersectionObserver.observe(trigger));
|
|
20587
|
+
this.viewportTriggers.set(trigger, entry);
|
|
20588
|
+
this.observedViewportElements++;
|
|
20589
|
+
}
|
|
20590
|
+
entry.callbacks.add(callback);
|
|
20591
|
+
return () => {
|
|
20592
|
+
entry.callbacks.delete(callback);
|
|
20593
|
+
if (entry.callbacks.size === 0) {
|
|
20594
|
+
this.intersectionObserver?.unobserve(trigger);
|
|
20595
|
+
this.viewportTriggers.delete(trigger);
|
|
20596
|
+
this.observedViewportElements--;
|
|
20597
|
+
}
|
|
20598
|
+
if (this.observedViewportElements === 0) {
|
|
20599
|
+
this.intersectionObserver?.disconnect();
|
|
20600
|
+
this.intersectionObserver = null;
|
|
20601
|
+
}
|
|
20602
|
+
};
|
|
20229
20603
|
}
|
|
20230
20604
|
}
|
|
20231
|
-
function enableLocateOrCreateContainerRefImpl() {
|
|
20232
|
-
_locateOrCreateAnchorNode = locateOrCreateAnchorNode;
|
|
20233
|
-
_populateDehydratedViewsInContainer = populateDehydratedViewsInContainerImpl;
|
|
20234
|
-
}
|
|
20235
|
-
|
|
20236
|
-
const DEFER_BLOCK_STATE = 0;
|
|
20237
20605
|
|
|
20238
20606
|
/**
|
|
20239
20607
|
* Returns whether defer blocks should be triggered.
|
|
@@ -20242,27 +20610,25 @@ const DEFER_BLOCK_STATE = 0;
|
|
|
20242
20610
|
* only placeholder content is rendered (if provided).
|
|
20243
20611
|
*/
|
|
20244
20612
|
function shouldTriggerDeferBlock(injector) {
|
|
20613
|
+
const config = injector.get(DEFER_BLOCK_CONFIG, null, { optional: true });
|
|
20614
|
+
if (config?.behavior === DeferBlockBehavior.Manual) {
|
|
20615
|
+
return false;
|
|
20616
|
+
}
|
|
20245
20617
|
return isPlatformBrowser(injector);
|
|
20246
20618
|
}
|
|
20247
20619
|
/**
|
|
20248
|
-
*
|
|
20249
|
-
* where those functions are not available (e.g. Node.js).
|
|
20250
|
-
*/
|
|
20251
|
-
const _requestIdleCallback = typeof requestIdleCallback !== 'undefined' ? requestIdleCallback : setTimeout;
|
|
20252
|
-
const _cancelIdleCallback = typeof requestIdleCallback !== 'undefined' ? cancelIdleCallback : clearTimeout;
|
|
20253
|
-
/**
|
|
20254
|
-
* Creates runtime data structures for `{#defer}` blocks.
|
|
20620
|
+
* Creates runtime data structures for defer blocks.
|
|
20255
20621
|
*
|
|
20256
20622
|
* @param index Index of the `defer` instruction.
|
|
20257
20623
|
* @param primaryTmplIndex Index of the template with the primary block content.
|
|
20258
20624
|
* @param dependencyResolverFn Function that contains dependencies for this defer block.
|
|
20259
|
-
* @param loadingTmplIndex Index of the template with the
|
|
20260
|
-
* @param placeholderTmplIndex Index of the template with the
|
|
20261
|
-
* @param errorTmplIndex Index of the template with the
|
|
20262
|
-
* @param loadingConfigIndex Index in the constants array of the configuration of the
|
|
20625
|
+
* @param loadingTmplIndex Index of the template with the loading block content.
|
|
20626
|
+
* @param placeholderTmplIndex Index of the template with the placeholder block content.
|
|
20627
|
+
* @param errorTmplIndex Index of the template with the error block content.
|
|
20628
|
+
* @param loadingConfigIndex Index in the constants array of the configuration of the loading.
|
|
20263
20629
|
* block.
|
|
20264
20630
|
* @param placeholderConfigIndexIndex in the constants array of the configuration of the
|
|
20265
|
-
*
|
|
20631
|
+
* placeholder block.
|
|
20266
20632
|
*
|
|
20267
20633
|
* @codeGenApi
|
|
20268
20634
|
*/
|
|
@@ -20285,18 +20651,20 @@ function ɵɵdefer(index, primaryTmplIndex, dependencyResolverFn, loadingTmplInd
|
|
|
20285
20651
|
getConstant(tViewConsts, loadingConfigIndex) :
|
|
20286
20652
|
null,
|
|
20287
20653
|
dependencyResolverFn: dependencyResolverFn ?? null,
|
|
20288
|
-
loadingState:
|
|
20654
|
+
loadingState: DeferDependenciesLoadingState.NOT_STARTED,
|
|
20289
20655
|
loadingPromise: null,
|
|
20290
20656
|
};
|
|
20291
20657
|
setTDeferBlockDetails(tView, adjustedIndex, deferBlockConfig);
|
|
20292
20658
|
}
|
|
20293
|
-
|
|
20294
|
-
// In client-only mode, this operation is noop.
|
|
20659
|
+
const tNode = getCurrentTNode();
|
|
20295
20660
|
const lContainer = lView[adjustedIndex];
|
|
20296
|
-
|
|
20661
|
+
// If hydration is enabled, looks up dehydrated views in the DOM
|
|
20662
|
+
// using hydration annotation info and stores those views on LContainer.
|
|
20663
|
+
// In client-only mode, this function is a noop.
|
|
20664
|
+
populateDehydratedViewsInLContainer(lContainer, tNode, lView);
|
|
20297
20665
|
// Init instance-specific defer details and store it.
|
|
20298
20666
|
const lDetails = [];
|
|
20299
|
-
lDetails[DEFER_BLOCK_STATE] =
|
|
20667
|
+
lDetails[DEFER_BLOCK_STATE] = DeferBlockInternalState.Initial;
|
|
20300
20668
|
setLDeferBlockDetails(lView, adjustedIndex, lDetails);
|
|
20301
20669
|
}
|
|
20302
20670
|
/**
|
|
@@ -20311,13 +20679,13 @@ function ɵɵdeferWhen(rawValue) {
|
|
|
20311
20679
|
const tNode = getSelectedTNode();
|
|
20312
20680
|
const lDetails = getLDeferBlockDetails(lView, tNode);
|
|
20313
20681
|
const renderedState = lDetails[DEFER_BLOCK_STATE];
|
|
20314
|
-
if (value === false && renderedState ===
|
|
20682
|
+
if (value === false && renderedState === DeferBlockInternalState.Initial) {
|
|
20315
20683
|
// If nothing is rendered yet, render a placeholder (if defined).
|
|
20316
20684
|
renderPlaceholder(lView, tNode);
|
|
20317
20685
|
}
|
|
20318
20686
|
else if (value === true &&
|
|
20319
|
-
(renderedState ===
|
|
20320
|
-
renderedState ===
|
|
20687
|
+
(renderedState === DeferBlockInternalState.Initial ||
|
|
20688
|
+
renderedState === DeferBlockState.Placeholder)) {
|
|
20321
20689
|
// The `when` condition has changed to `true`, trigger defer block loading
|
|
20322
20690
|
// if the block is either in initial (nothing is rendered) or a placeholder
|
|
20323
20691
|
// state.
|
|
@@ -20337,27 +20705,24 @@ function ɵɵdeferPrefetchWhen(rawValue) {
|
|
|
20337
20705
|
const tView = lView[TVIEW];
|
|
20338
20706
|
const tNode = getSelectedTNode();
|
|
20339
20707
|
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
20340
|
-
if (value === true && tDetails.loadingState ===
|
|
20708
|
+
if (value === true && tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
20341
20709
|
// If loading has not been started yet, trigger it now.
|
|
20342
|
-
|
|
20710
|
+
triggerPrefetching(tDetails, lView);
|
|
20343
20711
|
}
|
|
20344
20712
|
}
|
|
20345
20713
|
}
|
|
20346
20714
|
/**
|
|
20347
|
-
* Sets up
|
|
20715
|
+
* Sets up logic to handle the `on idle` deferred trigger.
|
|
20348
20716
|
* @codeGenApi
|
|
20349
20717
|
*/
|
|
20350
20718
|
function ɵɵdeferOnIdle() {
|
|
20351
20719
|
const lView = getLView();
|
|
20352
20720
|
const tNode = getCurrentTNode();
|
|
20353
20721
|
renderPlaceholder(lView, tNode);
|
|
20354
|
-
|
|
20355
|
-
// callback in case an LView got destroyed before an `idle` callback
|
|
20356
|
-
// is invoked.
|
|
20357
|
-
onIdle(() => triggerDeferBlock(lView, tNode), lView);
|
|
20722
|
+
onIdle(() => triggerDeferBlock(lView, tNode), lView, true /* withLViewCleanup */);
|
|
20358
20723
|
}
|
|
20359
20724
|
/**
|
|
20360
|
-
*
|
|
20725
|
+
* Sets up logic to handle the `prefetch on idle` deferred trigger.
|
|
20361
20726
|
* @codeGenApi
|
|
20362
20727
|
*/
|
|
20363
20728
|
function ɵɵdeferPrefetchOnIdle() {
|
|
@@ -20365,26 +20730,54 @@ function ɵɵdeferPrefetchOnIdle() {
|
|
|
20365
20730
|
const tNode = getCurrentTNode();
|
|
20366
20731
|
const tView = lView[TVIEW];
|
|
20367
20732
|
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
20368
|
-
if (tDetails.loadingState ===
|
|
20369
|
-
//
|
|
20370
|
-
|
|
20371
|
-
//
|
|
20372
|
-
|
|
20373
|
-
|
|
20374
|
-
|
|
20375
|
-
|
|
20376
|
-
|
|
20377
|
-
|
|
20378
|
-
|
|
20379
|
-
|
|
20733
|
+
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
20734
|
+
// Prevent scheduling more than one `requestIdleCallback` call
|
|
20735
|
+
// for each defer block. For this reason we use only a trigger
|
|
20736
|
+
// identifier in a key, so all instances would use the same key.
|
|
20737
|
+
const key = String(0 /* DeferBlockTriggers.OnIdle */);
|
|
20738
|
+
const injector = lView[INJECTOR$1];
|
|
20739
|
+
const manager = injector.get(DeferBlockCleanupManager);
|
|
20740
|
+
if (!manager.has(tDetails, key)) {
|
|
20741
|
+
// In case of prefetching, we intentionally avoid cancelling resource loading if
|
|
20742
|
+
// an underlying LView get destroyed (thus passing `null` as a second argument),
|
|
20743
|
+
// because there might be other LViews (that represent embedded views) that
|
|
20744
|
+
// depend on resource loading.
|
|
20745
|
+
const prefetch = () => triggerPrefetching(tDetails, lView);
|
|
20746
|
+
const cleanupFn = onIdle(prefetch, lView, false /* withLViewCleanup */);
|
|
20747
|
+
registerTDetailsCleanup(injector, tDetails, key, cleanupFn);
|
|
20748
|
+
}
|
|
20749
|
+
}
|
|
20750
|
+
}
|
|
20751
|
+
/**
|
|
20752
|
+
* Sets up logic to handle the `on immediate` deferred trigger.
|
|
20380
20753
|
* @codeGenApi
|
|
20381
20754
|
*/
|
|
20382
|
-
function ɵɵdeferOnImmediate() {
|
|
20755
|
+
function ɵɵdeferOnImmediate() {
|
|
20756
|
+
const lView = getLView();
|
|
20757
|
+
const tNode = getCurrentTNode();
|
|
20758
|
+
const tView = lView[TVIEW];
|
|
20759
|
+
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
20760
|
+
// Render placeholder block only if loading template is not present
|
|
20761
|
+
// to avoid content flickering, since it would be immediately replaced
|
|
20762
|
+
// by the loading block.
|
|
20763
|
+
if (tDetails.loadingTmplIndex === null) {
|
|
20764
|
+
renderPlaceholder(lView, tNode);
|
|
20765
|
+
}
|
|
20766
|
+
triggerDeferBlock(lView, tNode);
|
|
20767
|
+
}
|
|
20383
20768
|
/**
|
|
20384
|
-
*
|
|
20769
|
+
* Sets up logic to handle the `prefetch on immediate` deferred trigger.
|
|
20385
20770
|
* @codeGenApi
|
|
20386
20771
|
*/
|
|
20387
|
-
function ɵɵdeferPrefetchOnImmediate() {
|
|
20772
|
+
function ɵɵdeferPrefetchOnImmediate() {
|
|
20773
|
+
const lView = getLView();
|
|
20774
|
+
const tNode = getCurrentTNode();
|
|
20775
|
+
const tView = lView[TVIEW];
|
|
20776
|
+
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
20777
|
+
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
20778
|
+
triggerResourceLoading(tDetails, lView);
|
|
20779
|
+
}
|
|
20780
|
+
}
|
|
20388
20781
|
/**
|
|
20389
20782
|
* Creates runtime data structures for the `on timer` deferred trigger.
|
|
20390
20783
|
* @param delay Amount of time to wait before loading the content.
|
|
@@ -20399,67 +20792,207 @@ function ɵɵdeferOnTimer(delay) { } // TODO: implement runtime logic.
|
|
|
20399
20792
|
function ɵɵdeferPrefetchOnTimer(delay) { } // TODO: implement runtime logic.
|
|
20400
20793
|
/**
|
|
20401
20794
|
* Creates runtime data structures for the `on hover` deferred trigger.
|
|
20795
|
+
* @param triggerIndex Index at which to find the trigger element.
|
|
20796
|
+
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
20402
20797
|
* @codeGenApi
|
|
20403
20798
|
*/
|
|
20404
|
-
function ɵɵdeferOnHover() {
|
|
20799
|
+
function ɵɵdeferOnHover(triggerIndex, walkUpTimes) {
|
|
20800
|
+
const lView = getLView();
|
|
20801
|
+
const tNode = getCurrentTNode();
|
|
20802
|
+
renderPlaceholder(lView, tNode);
|
|
20803
|
+
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onHover, () => triggerDeferBlock(lView, tNode));
|
|
20804
|
+
}
|
|
20405
20805
|
/**
|
|
20406
20806
|
* Creates runtime data structures for the `prefetch on hover` deferred trigger.
|
|
20807
|
+
* @param triggerIndex Index at which to find the trigger element.
|
|
20808
|
+
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
20407
20809
|
* @codeGenApi
|
|
20408
20810
|
*/
|
|
20409
|
-
function ɵɵdeferPrefetchOnHover() {
|
|
20811
|
+
function ɵɵdeferPrefetchOnHover(triggerIndex, walkUpTimes) {
|
|
20812
|
+
const lView = getLView();
|
|
20813
|
+
const tNode = getCurrentTNode();
|
|
20814
|
+
const tView = lView[TVIEW];
|
|
20815
|
+
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
20816
|
+
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
20817
|
+
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onHover, () => triggerPrefetching(tDetails, lView));
|
|
20818
|
+
}
|
|
20819
|
+
}
|
|
20410
20820
|
/**
|
|
20411
20821
|
* Creates runtime data structures for the `on interaction` deferred trigger.
|
|
20412
|
-
* @param
|
|
20822
|
+
* @param triggerIndex Index at which to find the trigger element.
|
|
20823
|
+
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
20413
20824
|
* @codeGenApi
|
|
20414
20825
|
*/
|
|
20415
|
-
function ɵɵdeferOnInteraction(
|
|
20826
|
+
function ɵɵdeferOnInteraction(triggerIndex, walkUpTimes) {
|
|
20827
|
+
const lView = getLView();
|
|
20828
|
+
const tNode = getCurrentTNode();
|
|
20829
|
+
renderPlaceholder(lView, tNode);
|
|
20830
|
+
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onInteraction, () => triggerDeferBlock(lView, tNode));
|
|
20831
|
+
}
|
|
20416
20832
|
/**
|
|
20417
20833
|
* Creates runtime data structures for the `prefetch on interaction` deferred trigger.
|
|
20418
|
-
* @param
|
|
20834
|
+
* @param triggerIndex Index at which to find the trigger element.
|
|
20835
|
+
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
20419
20836
|
* @codeGenApi
|
|
20420
20837
|
*/
|
|
20421
|
-
function ɵɵdeferPrefetchOnInteraction(
|
|
20838
|
+
function ɵɵdeferPrefetchOnInteraction(triggerIndex, walkUpTimes) {
|
|
20839
|
+
const lView = getLView();
|
|
20840
|
+
const tNode = getCurrentTNode();
|
|
20841
|
+
const tView = lView[TVIEW];
|
|
20842
|
+
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
20843
|
+
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
20844
|
+
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onInteraction, () => triggerPrefetching(tDetails, lView));
|
|
20845
|
+
}
|
|
20846
|
+
}
|
|
20422
20847
|
/**
|
|
20423
20848
|
* Creates runtime data structures for the `on viewport` deferred trigger.
|
|
20424
|
-
* @param
|
|
20849
|
+
* @param triggerIndex Index at which to find the trigger element.
|
|
20850
|
+
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
20425
20851
|
* @codeGenApi
|
|
20426
20852
|
*/
|
|
20427
|
-
function ɵɵdeferOnViewport(
|
|
20853
|
+
function ɵɵdeferOnViewport(triggerIndex, walkUpTimes) {
|
|
20854
|
+
const lView = getLView();
|
|
20855
|
+
const tNode = getCurrentTNode();
|
|
20856
|
+
renderPlaceholder(lView, tNode);
|
|
20857
|
+
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onViewport, () => triggerDeferBlock(lView, tNode));
|
|
20858
|
+
}
|
|
20428
20859
|
/**
|
|
20429
20860
|
* Creates runtime data structures for the `prefetch on viewport` deferred trigger.
|
|
20430
|
-
* @param
|
|
20861
|
+
* @param triggerIndex Index at which to find the trigger element.
|
|
20862
|
+
* @param walkUpTimes Number of times to walk up/down the tree hierarchy to find the trigger.
|
|
20431
20863
|
* @codeGenApi
|
|
20432
20864
|
*/
|
|
20433
|
-
function ɵɵdeferPrefetchOnViewport(
|
|
20865
|
+
function ɵɵdeferPrefetchOnViewport(triggerIndex, walkUpTimes) {
|
|
20866
|
+
const lView = getLView();
|
|
20867
|
+
const tNode = getCurrentTNode();
|
|
20868
|
+
const tView = lView[TVIEW];
|
|
20869
|
+
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
20870
|
+
if (tDetails.loadingState === DeferDependenciesLoadingState.NOT_STARTED) {
|
|
20871
|
+
registerDomTrigger(lView, tNode, triggerIndex, walkUpTimes, onViewport, () => triggerPrefetching(tDetails, lView));
|
|
20872
|
+
}
|
|
20873
|
+
}
|
|
20434
20874
|
/********** Helper functions **********/
|
|
20875
|
+
/**
|
|
20876
|
+
* Helper function to get the LView in which a deferred block's trigger is rendered.
|
|
20877
|
+
* @param deferredHostLView LView in which the deferred block is defined.
|
|
20878
|
+
* @param deferredTNode TNode defining the deferred block.
|
|
20879
|
+
* @param walkUpTimes Number of times to go up in the view hierarchy to find the trigger's view.
|
|
20880
|
+
* A negative value means that the trigger is inside the block's placeholder, while an undefined
|
|
20881
|
+
* value means that the trigger is in the same LView as the deferred block.
|
|
20882
|
+
*/
|
|
20883
|
+
function getTriggerLView(deferredHostLView, deferredTNode, walkUpTimes) {
|
|
20884
|
+
// The trigger is in the same view, we don't need to traverse.
|
|
20885
|
+
if (walkUpTimes == null) {
|
|
20886
|
+
return deferredHostLView;
|
|
20887
|
+
}
|
|
20888
|
+
// A positive value or zero means that the trigger is in a parent view.
|
|
20889
|
+
if (walkUpTimes >= 0) {
|
|
20890
|
+
return walkUpViews(walkUpTimes, deferredHostLView);
|
|
20891
|
+
}
|
|
20892
|
+
// If the value is negative, it means that the trigger is inside the placeholder.
|
|
20893
|
+
const deferredContainer = deferredHostLView[deferredTNode.index];
|
|
20894
|
+
ngDevMode && assertLContainer(deferredContainer);
|
|
20895
|
+
const triggerLView = deferredContainer[CONTAINER_HEADER_OFFSET] ?? null;
|
|
20896
|
+
// We need to null check, because the placeholder might not have been rendered yet.
|
|
20897
|
+
if (ngDevMode && triggerLView !== null) {
|
|
20898
|
+
const lDetails = getLDeferBlockDetails(deferredHostLView, deferredTNode);
|
|
20899
|
+
const renderedState = lDetails[DEFER_BLOCK_STATE];
|
|
20900
|
+
assertEqual(renderedState, DeferBlockState.Placeholder, 'Expected a placeholder to be rendered in this defer block.');
|
|
20901
|
+
assertLView(triggerLView);
|
|
20902
|
+
}
|
|
20903
|
+
return triggerLView;
|
|
20904
|
+
}
|
|
20905
|
+
/**
|
|
20906
|
+
* Gets the element that a deferred block's trigger is pointing to.
|
|
20907
|
+
* @param triggerLView LView in which the trigger is defined.
|
|
20908
|
+
* @param triggerIndex Index at which the trigger element should've been rendered.
|
|
20909
|
+
*/
|
|
20910
|
+
function getTriggerElement(triggerLView, triggerIndex) {
|
|
20911
|
+
const element = getNativeByIndex(HEADER_OFFSET + triggerIndex, triggerLView);
|
|
20912
|
+
ngDevMode && assertElement(element);
|
|
20913
|
+
return element;
|
|
20914
|
+
}
|
|
20915
|
+
/**
|
|
20916
|
+
* Registers a DOM-node based trigger.
|
|
20917
|
+
* @param initialLView LView in which the defer block is rendered.
|
|
20918
|
+
* @param tNode TNode representing the defer block.
|
|
20919
|
+
* @param triggerIndex Index at which to find the trigger element.
|
|
20920
|
+
* @param walkUpTimes Number of times to go up/down in the view hierarchy to find the trigger.
|
|
20921
|
+
* @param registerFn Function that will register the DOM events.
|
|
20922
|
+
* @param callback Callback to be invoked when the trigger receives the event that should render
|
|
20923
|
+
* the deferred block.
|
|
20924
|
+
*/
|
|
20925
|
+
function registerDomTrigger(initialLView, tNode, triggerIndex, walkUpTimes, registerFn, callback) {
|
|
20926
|
+
const injector = initialLView[INJECTOR$1];
|
|
20927
|
+
// Assumption: the `afterRender` reference should be destroyed
|
|
20928
|
+
// automatically so we don't need to keep track of it.
|
|
20929
|
+
const afterRenderRef = afterRender(() => {
|
|
20930
|
+
const lDetails = getLDeferBlockDetails(initialLView, tNode);
|
|
20931
|
+
const renderedState = lDetails[DEFER_BLOCK_STATE];
|
|
20932
|
+
// If the block was loaded before the trigger was resolved, we don't need to do anything.
|
|
20933
|
+
if (renderedState !== DeferBlockInternalState.Initial &&
|
|
20934
|
+
renderedState !== DeferBlockState.Placeholder) {
|
|
20935
|
+
afterRenderRef.destroy();
|
|
20936
|
+
return;
|
|
20937
|
+
}
|
|
20938
|
+
const triggerLView = getTriggerLView(initialLView, tNode, walkUpTimes);
|
|
20939
|
+
// Keep polling until we resolve the trigger's LView.
|
|
20940
|
+
// `afterRender` should stop automatically if the view is destroyed.
|
|
20941
|
+
if (!triggerLView) {
|
|
20942
|
+
return;
|
|
20943
|
+
}
|
|
20944
|
+
// It's possible that the trigger's view was destroyed before we resolved the trigger element.
|
|
20945
|
+
if (triggerLView[FLAGS] & 256 /* LViewFlags.Destroyed */) {
|
|
20946
|
+
afterRenderRef.destroy();
|
|
20947
|
+
return;
|
|
20948
|
+
}
|
|
20949
|
+
// TODO: add integration with `DeferBlockCleanupManager`.
|
|
20950
|
+
const element = getTriggerElement(triggerLView, triggerIndex);
|
|
20951
|
+
const cleanup = registerFn(element, () => {
|
|
20952
|
+
callback();
|
|
20953
|
+
removeLViewOnDestroy(triggerLView, cleanup);
|
|
20954
|
+
if (initialLView !== triggerLView) {
|
|
20955
|
+
removeLViewOnDestroy(initialLView, cleanup);
|
|
20956
|
+
}
|
|
20957
|
+
cleanup();
|
|
20958
|
+
}, injector);
|
|
20959
|
+
afterRenderRef.destroy();
|
|
20960
|
+
storeLViewOnDestroy(triggerLView, cleanup);
|
|
20961
|
+
// Since the trigger and deferred block might be in different
|
|
20962
|
+
// views, we have to register the callback in both locations.
|
|
20963
|
+
if (initialLView !== triggerLView) {
|
|
20964
|
+
storeLViewOnDestroy(initialLView, cleanup);
|
|
20965
|
+
}
|
|
20966
|
+
}, { injector });
|
|
20967
|
+
}
|
|
20435
20968
|
/**
|
|
20436
20969
|
* Helper function to schedule a callback to be invoked when a browser becomes idle.
|
|
20437
20970
|
*
|
|
20438
20971
|
* @param callback A function to be invoked when a browser becomes idle.
|
|
20439
|
-
* @param lView
|
|
20440
|
-
*
|
|
20441
|
-
*
|
|
20442
|
-
*
|
|
20443
|
-
* LView got destroyed prior to th block rendering.
|
|
20972
|
+
* @param lView LView that hosts an instance of a defer block.
|
|
20973
|
+
* @param withLViewCleanup A flag that indicates whether a scheduled callback
|
|
20974
|
+
* should be cancelled in case an LView is destroyed before a callback
|
|
20975
|
+
* was invoked.
|
|
20444
20976
|
*/
|
|
20445
|
-
function onIdle(callback, lView) {
|
|
20446
|
-
|
|
20447
|
-
const
|
|
20448
|
-
|
|
20449
|
-
|
|
20450
|
-
|
|
20451
|
-
|
|
20452
|
-
|
|
20453
|
-
|
|
20454
|
-
|
|
20977
|
+
function onIdle(callback, lView, withLViewCleanup) {
|
|
20978
|
+
const injector = lView[INJECTOR$1];
|
|
20979
|
+
const scheduler = injector.get(OnIdleScheduler);
|
|
20980
|
+
const cleanupFn = () => scheduler.remove(callback);
|
|
20981
|
+
const wrappedCallback = withLViewCleanup ? wrapWithLViewCleanup(callback, lView, cleanupFn) : callback;
|
|
20982
|
+
scheduler.add(wrappedCallback);
|
|
20983
|
+
return cleanupFn;
|
|
20984
|
+
}
|
|
20985
|
+
/**
|
|
20986
|
+
* Wraps a given callback into a logic that registers a cleanup function
|
|
20987
|
+
* in the LView cleanup slot, to be invoked when an LView is destroyed.
|
|
20988
|
+
*/
|
|
20989
|
+
function wrapWithLViewCleanup(callback, lView, cleanup) {
|
|
20990
|
+
const wrappedCallback = () => {
|
|
20455
20991
|
callback();
|
|
20456
|
-
|
|
20457
|
-
|
|
20458
|
-
|
|
20459
|
-
|
|
20460
|
-
// is invoked.
|
|
20461
|
-
storeLViewOnDestroy(lView, removeIdleCallback);
|
|
20462
|
-
}
|
|
20992
|
+
removeLViewOnDestroy(lView, cleanup);
|
|
20993
|
+
};
|
|
20994
|
+
storeLViewOnDestroy(lView, cleanup);
|
|
20995
|
+
return wrappedCallback;
|
|
20463
20996
|
}
|
|
20464
20997
|
/**
|
|
20465
20998
|
* Calculates a data slot index for defer block info (either static or
|
|
@@ -20496,6 +21029,23 @@ function setTDeferBlockDetails(tView, deferBlockIndex, deferBlockConfig) {
|
|
|
20496
21029
|
ngDevMode && assertIndexInDeclRange(tView, slotIndex);
|
|
20497
21030
|
tView.data[slotIndex] = deferBlockConfig;
|
|
20498
21031
|
}
|
|
21032
|
+
function getTemplateIndexForState(newState, hostLView, tNode) {
|
|
21033
|
+
const tView = hostLView[TVIEW];
|
|
21034
|
+
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
21035
|
+
switch (newState) {
|
|
21036
|
+
case DeferBlockState.Complete:
|
|
21037
|
+
return tDetails.primaryTmplIndex;
|
|
21038
|
+
case DeferBlockState.Loading:
|
|
21039
|
+
return tDetails.loadingTmplIndex;
|
|
21040
|
+
case DeferBlockState.Error:
|
|
21041
|
+
return tDetails.errorTmplIndex;
|
|
21042
|
+
case DeferBlockState.Placeholder:
|
|
21043
|
+
return tDetails.placeholderTmplIndex;
|
|
21044
|
+
default:
|
|
21045
|
+
ngDevMode && throwError(`Unexpected defer block state: ${newState}`);
|
|
21046
|
+
return null;
|
|
21047
|
+
}
|
|
21048
|
+
}
|
|
20499
21049
|
/**
|
|
20500
21050
|
* Transitions a defer block to the new state. Updates the necessary
|
|
20501
21051
|
* data structures and renders corresponding block.
|
|
@@ -20503,9 +21053,8 @@ function setTDeferBlockDetails(tView, deferBlockIndex, deferBlockConfig) {
|
|
|
20503
21053
|
* @param newState New state that should be applied to the defer block.
|
|
20504
21054
|
* @param tNode TNode that represents a defer block.
|
|
20505
21055
|
* @param lContainer Represents an instance of a defer block.
|
|
20506
|
-
* @param stateTmplIndex Index of a template that should be rendered.
|
|
20507
21056
|
*/
|
|
20508
|
-
function renderDeferBlockState(newState, tNode, lContainer
|
|
21057
|
+
function renderDeferBlockState(newState, tNode, lContainer) {
|
|
20509
21058
|
const hostLView = lContainer[PARENT];
|
|
20510
21059
|
// Check if this view is not destroyed. Since the loading process was async,
|
|
20511
21060
|
// the view might end up being destroyed by the time rendering happens.
|
|
@@ -20515,6 +21064,7 @@ function renderDeferBlockState(newState, tNode, lContainer, stateTmplIndex) {
|
|
|
20515
21064
|
ngDevMode && assertTNodeForLView(tNode, hostLView);
|
|
20516
21065
|
const lDetails = getLDeferBlockDetails(hostLView, tNode);
|
|
20517
21066
|
ngDevMode && assertDefined(lDetails, 'Expected a defer block state defined');
|
|
21067
|
+
const stateTmplIndex = getTemplateIndexForState(newState, hostLView, tNode);
|
|
20518
21068
|
// Note: we transition to the next state if the previous state was represented
|
|
20519
21069
|
// with a number that is less than the next state. For example, if the current
|
|
20520
21070
|
// state is "loading" (represented as `2`), we should not show a placeholder
|
|
@@ -20525,7 +21075,7 @@ function renderDeferBlockState(newState, tNode, lContainer, stateTmplIndex) {
|
|
|
20525
21075
|
const adjustedIndex = stateTmplIndex + HEADER_OFFSET;
|
|
20526
21076
|
const tNode = getTNode(hostTView, adjustedIndex);
|
|
20527
21077
|
// There is only 1 view that can be present in an LContainer that
|
|
20528
|
-
// represents a
|
|
21078
|
+
// represents a defer block, so always refer to the first one.
|
|
20529
21079
|
const viewIndex = 0;
|
|
20530
21080
|
removeLViewFromLContainer(lContainer, viewIndex);
|
|
20531
21081
|
const dehydratedView = findMatchingDehydratedView(lContainer, tNode.tView.ssrId);
|
|
@@ -20533,18 +21083,27 @@ function renderDeferBlockState(newState, tNode, lContainer, stateTmplIndex) {
|
|
|
20533
21083
|
addLViewToLContainer(lContainer, embeddedLView, viewIndex, shouldAddViewToDom(tNode, dehydratedView));
|
|
20534
21084
|
}
|
|
20535
21085
|
}
|
|
21086
|
+
/**
|
|
21087
|
+
* Trigger prefetching of dependencies for a defer block.
|
|
21088
|
+
*
|
|
21089
|
+
* @param tDetails Static information about this defer block.
|
|
21090
|
+
* @param lView LView of a host view.
|
|
21091
|
+
*/
|
|
21092
|
+
function triggerPrefetching(tDetails, lView) {
|
|
21093
|
+
if (lView[INJECTOR$1] && shouldTriggerDeferBlock(lView[INJECTOR$1])) {
|
|
21094
|
+
triggerResourceLoading(tDetails, lView);
|
|
21095
|
+
}
|
|
21096
|
+
}
|
|
20536
21097
|
/**
|
|
20537
21098
|
* Trigger loading of defer block dependencies if the process hasn't started yet.
|
|
20538
21099
|
*
|
|
20539
21100
|
* @param tDetails Static information about this defer block.
|
|
20540
|
-
* @param tView TView of a host view.
|
|
20541
21101
|
* @param lView LView of a host view.
|
|
20542
21102
|
*/
|
|
20543
|
-
function triggerResourceLoading(tDetails,
|
|
21103
|
+
function triggerResourceLoading(tDetails, lView) {
|
|
20544
21104
|
const injector = lView[INJECTOR$1];
|
|
20545
|
-
|
|
20546
|
-
|
|
20547
|
-
tDetails.loadingState !== 1 /* DeferDependenciesLoadingState.SCHEDULED */)) {
|
|
21105
|
+
const tView = lView[TVIEW];
|
|
21106
|
+
if (tDetails.loadingState !== DeferDependenciesLoadingState.NOT_STARTED) {
|
|
20548
21107
|
// If the loading status is different from initial one, it means that
|
|
20549
21108
|
// the loading of dependencies is in progress and there is nothing to do
|
|
20550
21109
|
// in this function. All details can be obtained from the `tDetails` object.
|
|
@@ -20552,21 +21111,24 @@ function triggerResourceLoading(tDetails, tView, lView) {
|
|
|
20552
21111
|
}
|
|
20553
21112
|
const primaryBlockTNode = getPrimaryBlockTNode(tView, tDetails);
|
|
20554
21113
|
// Switch from NOT_STARTED -> IN_PROGRESS state.
|
|
20555
|
-
tDetails.loadingState =
|
|
21114
|
+
tDetails.loadingState = DeferDependenciesLoadingState.IN_PROGRESS;
|
|
20556
21115
|
// Check if dependency function interceptor is configured.
|
|
20557
21116
|
const deferDependencyInterceptor = injector.get(DEFER_BLOCK_DEPENDENCY_INTERCEPTOR, null, { optional: true });
|
|
20558
21117
|
const dependenciesFn = deferDependencyInterceptor ?
|
|
20559
21118
|
deferDependencyInterceptor.intercept(tDetails.dependencyResolverFn) :
|
|
20560
21119
|
tDetails.dependencyResolverFn;
|
|
20561
21120
|
// The `dependenciesFn` might be `null` when all dependencies within
|
|
20562
|
-
// a given
|
|
21121
|
+
// a given defer block were eagerly references elsewhere in a file,
|
|
20563
21122
|
// thus no dynamic `import()`s were produced.
|
|
20564
21123
|
if (!dependenciesFn) {
|
|
20565
21124
|
tDetails.loadingPromise = Promise.resolve().then(() => {
|
|
20566
|
-
tDetails.loadingState =
|
|
21125
|
+
tDetails.loadingState = DeferDependenciesLoadingState.COMPLETE;
|
|
20567
21126
|
});
|
|
20568
21127
|
return;
|
|
20569
21128
|
}
|
|
21129
|
+
// Defer block may have multiple prefetch triggers. Once the loading
|
|
21130
|
+
// starts, invoke all clean functions, since they are no longer needed.
|
|
21131
|
+
invokeTDetailsCleanup(injector, tDetails);
|
|
20570
21132
|
// Start downloading of defer block dependencies.
|
|
20571
21133
|
tDetails.loadingPromise = Promise.allSettled(dependenciesFn()).then(results => {
|
|
20572
21134
|
let failed = false;
|
|
@@ -20594,10 +21156,10 @@ function triggerResourceLoading(tDetails, tView, lView) {
|
|
|
20594
21156
|
// Loading is completed, we no longer need this Promise.
|
|
20595
21157
|
tDetails.loadingPromise = null;
|
|
20596
21158
|
if (failed) {
|
|
20597
|
-
tDetails.loadingState =
|
|
21159
|
+
tDetails.loadingState = DeferDependenciesLoadingState.FAILED;
|
|
20598
21160
|
}
|
|
20599
21161
|
else {
|
|
20600
|
-
tDetails.loadingState =
|
|
21162
|
+
tDetails.loadingState = DeferDependenciesLoadingState.COMPLETE;
|
|
20601
21163
|
// Update directive and pipe registries to add newly downloaded dependencies.
|
|
20602
21164
|
const primaryBlockTView = primaryBlockTNode.tView;
|
|
20603
21165
|
if (directiveDefs.length > 0) {
|
|
@@ -20613,13 +21175,13 @@ function triggerResourceLoading(tDetails, tView, lView) {
|
|
|
20613
21175
|
}
|
|
20614
21176
|
});
|
|
20615
21177
|
}
|
|
20616
|
-
/** Utility function to render
|
|
21178
|
+
/** Utility function to render placeholder content (if present) */
|
|
20617
21179
|
function renderPlaceholder(lView, tNode) {
|
|
20618
21180
|
const tView = lView[TVIEW];
|
|
20619
21181
|
const lContainer = lView[tNode.index];
|
|
20620
21182
|
ngDevMode && assertLContainer(lContainer);
|
|
20621
21183
|
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
20622
|
-
renderDeferBlockState(
|
|
21184
|
+
renderDeferBlockState(DeferBlockState.Placeholder, tNode, lContainer);
|
|
20623
21185
|
}
|
|
20624
21186
|
/**
|
|
20625
21187
|
* Subscribes to the "loading" Promise and renders corresponding defer sub-block,
|
|
@@ -20632,13 +21194,13 @@ function renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer) {
|
|
|
20632
21194
|
ngDevMode &&
|
|
20633
21195
|
assertDefined(tDetails.loadingPromise, 'Expected loading Promise to exist on this defer block');
|
|
20634
21196
|
tDetails.loadingPromise.then(() => {
|
|
20635
|
-
if (tDetails.loadingState ===
|
|
21197
|
+
if (tDetails.loadingState === DeferDependenciesLoadingState.COMPLETE) {
|
|
20636
21198
|
ngDevMode && assertDeferredDependenciesLoaded(tDetails);
|
|
20637
21199
|
// Everything is loaded, show the primary block content
|
|
20638
|
-
renderDeferBlockState(
|
|
21200
|
+
renderDeferBlockState(DeferBlockState.Complete, tNode, lContainer);
|
|
20639
21201
|
}
|
|
20640
|
-
else if (tDetails.loadingState ===
|
|
20641
|
-
renderDeferBlockState(
|
|
21202
|
+
else if (tDetails.loadingState === DeferDependenciesLoadingState.FAILED) {
|
|
21203
|
+
renderDeferBlockState(DeferBlockState.Error, tNode, lContainer);
|
|
20642
21204
|
}
|
|
20643
21205
|
});
|
|
20644
21206
|
}
|
|
@@ -20662,26 +21224,25 @@ function triggerDeferBlock(lView, tNode) {
|
|
|
20662
21224
|
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
20663
21225
|
// Condition is triggered, try to render loading state and start downloading.
|
|
20664
21226
|
// Note: if a block is in a loading, completed or an error state, this call would be a noop.
|
|
20665
|
-
renderDeferBlockState(
|
|
21227
|
+
renderDeferBlockState(DeferBlockState.Loading, tNode, lContainer);
|
|
20666
21228
|
switch (tDetails.loadingState) {
|
|
20667
|
-
case
|
|
20668
|
-
|
|
20669
|
-
triggerResourceLoading(tDetails, lView[TVIEW], lView);
|
|
21229
|
+
case DeferDependenciesLoadingState.NOT_STARTED:
|
|
21230
|
+
triggerResourceLoading(tDetails, lView);
|
|
20670
21231
|
// The `loadingState` might have changed to "loading".
|
|
20671
21232
|
if (tDetails.loadingState ===
|
|
20672
|
-
|
|
21233
|
+
DeferDependenciesLoadingState.IN_PROGRESS) {
|
|
20673
21234
|
renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer);
|
|
20674
21235
|
}
|
|
20675
21236
|
break;
|
|
20676
|
-
case
|
|
21237
|
+
case DeferDependenciesLoadingState.IN_PROGRESS:
|
|
20677
21238
|
renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer);
|
|
20678
21239
|
break;
|
|
20679
|
-
case
|
|
21240
|
+
case DeferDependenciesLoadingState.COMPLETE:
|
|
20680
21241
|
ngDevMode && assertDeferredDependenciesLoaded(tDetails);
|
|
20681
|
-
renderDeferBlockState(
|
|
21242
|
+
renderDeferBlockState(DeferBlockState.Complete, tNode, lContainer);
|
|
20682
21243
|
break;
|
|
20683
|
-
case
|
|
20684
|
-
renderDeferBlockState(
|
|
21244
|
+
case DeferDependenciesLoadingState.FAILED:
|
|
21245
|
+
renderDeferBlockState(DeferBlockState.Error, tNode, lContainer);
|
|
20685
21246
|
break;
|
|
20686
21247
|
default:
|
|
20687
21248
|
if (ngDevMode) {
|
|
@@ -20695,7 +21256,7 @@ function triggerDeferBlock(lView, tNode) {
|
|
|
20695
21256
|
* block in completed state.
|
|
20696
21257
|
*/
|
|
20697
21258
|
function assertDeferredDependenciesLoaded(tDetails) {
|
|
20698
|
-
assertEqual(tDetails.loadingState,
|
|
21259
|
+
assertEqual(tDetails.loadingState, DeferDependenciesLoadingState.COMPLETE, 'Expecting all deferred dependencies to be loaded.');
|
|
20699
21260
|
}
|
|
20700
21261
|
/**
|
|
20701
21262
|
* **INTERNAL**, avoid referencing it in application code.
|
|
@@ -20704,6 +21265,193 @@ function assertDeferredDependenciesLoaded(tDetails) {
|
|
|
20704
21265
|
* implementation.
|
|
20705
21266
|
*/
|
|
20706
21267
|
const DEFER_BLOCK_DEPENDENCY_INTERCEPTOR = new InjectionToken(ngDevMode ? 'DEFER_BLOCK_DEPENDENCY_INTERCEPTOR' : '');
|
|
21268
|
+
/**
|
|
21269
|
+
* Determines if a given value matches the expected structure of a defer block
|
|
21270
|
+
*
|
|
21271
|
+
* We can safely rely on the primaryTmplIndex because every defer block requires
|
|
21272
|
+
* that a primary template exists. All the other template options are optional.
|
|
21273
|
+
*/
|
|
21274
|
+
function isTDeferBlockDetails(value) {
|
|
21275
|
+
return (typeof value === 'object') &&
|
|
21276
|
+
(typeof value.primaryTmplIndex === 'number');
|
|
21277
|
+
}
|
|
21278
|
+
/**
|
|
21279
|
+
* Internal token used for configuring defer block behavior.
|
|
21280
|
+
*/
|
|
21281
|
+
const DEFER_BLOCK_CONFIG = new InjectionToken(ngDevMode ? 'DEFER_BLOCK_CONFIG' : '');
|
|
21282
|
+
/**
|
|
21283
|
+
* Retrieves all defer blocks in a given LView.
|
|
21284
|
+
*
|
|
21285
|
+
* @param lView lView with defer blocks
|
|
21286
|
+
* @param deferBlocks defer block aggregator array
|
|
21287
|
+
*/
|
|
21288
|
+
function getDeferBlocks(lView, deferBlocks) {
|
|
21289
|
+
const tView = lView[TVIEW];
|
|
21290
|
+
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
|
|
21291
|
+
if (isLContainer(lView[i])) {
|
|
21292
|
+
const lContainer = lView[i];
|
|
21293
|
+
// An LContainer may represent an instance of a defer block, in which case
|
|
21294
|
+
// we store it as a result. Otherwise, keep iterating over LContainer views and
|
|
21295
|
+
// look for defer blocks.
|
|
21296
|
+
const isLast = i === tView.bindingStartIndex - 1;
|
|
21297
|
+
if (!isLast) {
|
|
21298
|
+
const tNode = tView.data[i];
|
|
21299
|
+
const tDetails = getTDeferBlockDetails(tView, tNode);
|
|
21300
|
+
if (isTDeferBlockDetails(tDetails)) {
|
|
21301
|
+
deferBlocks.push({ lContainer, lView, tNode, tDetails });
|
|
21302
|
+
// This LContainer represents a defer block, so we exit
|
|
21303
|
+
// this iteration and don't inspect views in this LContainer.
|
|
21304
|
+
continue;
|
|
21305
|
+
}
|
|
21306
|
+
}
|
|
21307
|
+
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
21308
|
+
getDeferBlocks(lContainer[i], deferBlocks);
|
|
21309
|
+
}
|
|
21310
|
+
}
|
|
21311
|
+
else if (isLView(lView[i])) {
|
|
21312
|
+
// This is a component, enter the `getDeferBlocks` recursively.
|
|
21313
|
+
getDeferBlocks(lView[i], deferBlocks);
|
|
21314
|
+
}
|
|
21315
|
+
}
|
|
21316
|
+
}
|
|
21317
|
+
/**
|
|
21318
|
+
* Registers a cleanup function associated with a prefetching trigger
|
|
21319
|
+
* of a given defer block.
|
|
21320
|
+
*/
|
|
21321
|
+
function registerTDetailsCleanup(injector, tDetails, key, cleanupFn) {
|
|
21322
|
+
injector.get(DeferBlockCleanupManager).add(tDetails, key, cleanupFn);
|
|
21323
|
+
}
|
|
21324
|
+
/**
|
|
21325
|
+
* Invokes all registered prefetch cleanup triggers
|
|
21326
|
+
* and removes all cleanup functions afterwards.
|
|
21327
|
+
*/
|
|
21328
|
+
function invokeTDetailsCleanup(injector, tDetails) {
|
|
21329
|
+
injector.get(DeferBlockCleanupManager).cleanup(tDetails);
|
|
21330
|
+
}
|
|
21331
|
+
/**
|
|
21332
|
+
* Internal service to keep track of cleanup functions associated
|
|
21333
|
+
* with defer blocks. This class is used to manage cleanup functions
|
|
21334
|
+
* created for prefetching triggers.
|
|
21335
|
+
*/
|
|
21336
|
+
class DeferBlockCleanupManager {
|
|
21337
|
+
constructor() {
|
|
21338
|
+
this.blocks = new Map();
|
|
21339
|
+
}
|
|
21340
|
+
add(tDetails, key, callback) {
|
|
21341
|
+
if (!this.blocks.has(tDetails)) {
|
|
21342
|
+
this.blocks.set(tDetails, new Map());
|
|
21343
|
+
}
|
|
21344
|
+
const block = this.blocks.get(tDetails);
|
|
21345
|
+
if (!block.has(key)) {
|
|
21346
|
+
block.set(key, []);
|
|
21347
|
+
}
|
|
21348
|
+
const callbacks = block.get(key);
|
|
21349
|
+
callbacks.push(callback);
|
|
21350
|
+
}
|
|
21351
|
+
has(tDetails, key) {
|
|
21352
|
+
return !!this.blocks.get(tDetails)?.has(key);
|
|
21353
|
+
}
|
|
21354
|
+
cleanup(tDetails) {
|
|
21355
|
+
const block = this.blocks.get(tDetails);
|
|
21356
|
+
if (block) {
|
|
21357
|
+
for (const callbacks of Object.values(block)) {
|
|
21358
|
+
for (const callback of callbacks) {
|
|
21359
|
+
callback();
|
|
21360
|
+
}
|
|
21361
|
+
}
|
|
21362
|
+
this.blocks.delete(tDetails);
|
|
21363
|
+
}
|
|
21364
|
+
}
|
|
21365
|
+
ngOnDestroy() {
|
|
21366
|
+
for (const [block] of this.blocks) {
|
|
21367
|
+
this.cleanup(block);
|
|
21368
|
+
}
|
|
21369
|
+
this.blocks.clear();
|
|
21370
|
+
}
|
|
21371
|
+
/** @nocollapse */
|
|
21372
|
+
static { this.ɵprov = ɵɵdefineInjectable({
|
|
21373
|
+
token: DeferBlockCleanupManager,
|
|
21374
|
+
providedIn: 'root',
|
|
21375
|
+
factory: () => new DeferBlockCleanupManager(),
|
|
21376
|
+
}); }
|
|
21377
|
+
}
|
|
21378
|
+
/**
|
|
21379
|
+
* Use shims for the `requestIdleCallback` and `cancelIdleCallback` functions for
|
|
21380
|
+
* environments where those functions are not available (e.g. Node.js and Safari).
|
|
21381
|
+
*
|
|
21382
|
+
* Note: we wrap the `requestIdleCallback` call into a function, so that it can be
|
|
21383
|
+
* overridden/mocked in test environment and picked up by the runtime code.
|
|
21384
|
+
*/
|
|
21385
|
+
const _requestIdleCallback = () => typeof requestIdleCallback !== 'undefined' ? requestIdleCallback : setTimeout;
|
|
21386
|
+
const _cancelIdleCallback = () => typeof requestIdleCallback !== 'undefined' ? cancelIdleCallback : clearTimeout;
|
|
21387
|
+
/**
|
|
21388
|
+
* Helper service to schedule `requestIdleCallback`s for batches of defer blocks,
|
|
21389
|
+
* to avoid calling `requestIdleCallback` for each defer block (e.g. if
|
|
21390
|
+
* defer blocks are defined inside a for loop).
|
|
21391
|
+
*/
|
|
21392
|
+
class OnIdleScheduler {
|
|
21393
|
+
constructor() {
|
|
21394
|
+
// Indicates whether current callbacks are being invoked.
|
|
21395
|
+
this.executingCallbacks = false;
|
|
21396
|
+
// Currently scheduled idle callback id.
|
|
21397
|
+
this.idleId = null;
|
|
21398
|
+
// Set of callbacks to be invoked next.
|
|
21399
|
+
this.current = new Set();
|
|
21400
|
+
// Set of callbacks collected while invoking current set of callbacks.
|
|
21401
|
+
// Those callbacks are scheduled for the next idle period.
|
|
21402
|
+
this.deferred = new Set();
|
|
21403
|
+
this.requestIdleCallback = _requestIdleCallback().bind(globalThis);
|
|
21404
|
+
this.cancelIdleCallback = _cancelIdleCallback().bind(globalThis);
|
|
21405
|
+
}
|
|
21406
|
+
add(callback) {
|
|
21407
|
+
const target = this.executingCallbacks ? this.deferred : this.current;
|
|
21408
|
+
target.add(callback);
|
|
21409
|
+
if (this.idleId === null) {
|
|
21410
|
+
this.scheduleIdleCallback();
|
|
21411
|
+
}
|
|
21412
|
+
}
|
|
21413
|
+
remove(callback) {
|
|
21414
|
+
this.current.delete(callback);
|
|
21415
|
+
this.deferred.delete(callback);
|
|
21416
|
+
}
|
|
21417
|
+
scheduleIdleCallback() {
|
|
21418
|
+
const callback = () => {
|
|
21419
|
+
this.cancelIdleCallback(this.idleId);
|
|
21420
|
+
this.idleId = null;
|
|
21421
|
+
this.executingCallbacks = true;
|
|
21422
|
+
for (const callback of this.current) {
|
|
21423
|
+
callback();
|
|
21424
|
+
}
|
|
21425
|
+
this.current.clear();
|
|
21426
|
+
this.executingCallbacks = false;
|
|
21427
|
+
// If there are any callbacks added during an invocation
|
|
21428
|
+
// of the current ones - make them "current" and schedule
|
|
21429
|
+
// a new idle callback.
|
|
21430
|
+
if (this.deferred.size > 0) {
|
|
21431
|
+
for (const callback of this.deferred) {
|
|
21432
|
+
this.current.add(callback);
|
|
21433
|
+
}
|
|
21434
|
+
this.deferred.clear();
|
|
21435
|
+
this.scheduleIdleCallback();
|
|
21436
|
+
}
|
|
21437
|
+
};
|
|
21438
|
+
this.idleId = this.requestIdleCallback(callback);
|
|
21439
|
+
}
|
|
21440
|
+
ngOnDestroy() {
|
|
21441
|
+
if (this.idleId !== null) {
|
|
21442
|
+
this.cancelIdleCallback(this.idleId);
|
|
21443
|
+
this.idleId = null;
|
|
21444
|
+
}
|
|
21445
|
+
this.current.clear();
|
|
21446
|
+
this.deferred.clear();
|
|
21447
|
+
}
|
|
21448
|
+
/** @nocollapse */
|
|
21449
|
+
static { this.ɵprov = ɵɵdefineInjectable({
|
|
21450
|
+
token: OnIdleScheduler,
|
|
21451
|
+
providedIn: 'root',
|
|
21452
|
+
factory: () => new OnIdleScheduler(),
|
|
21453
|
+
}); }
|
|
21454
|
+
}
|
|
20707
21455
|
|
|
20708
21456
|
function elementStartFirstCreatePass(index, tView, lView, name, attrsIndex, localRefsIndex) {
|
|
20709
21457
|
ngDevMode && assertFirstCreatePass(tView);
|
|
@@ -25507,6 +26255,10 @@ function ɵɵsetNgModuleScope(type, scope) {
|
|
|
25507
26255
|
ngModuleDef.declarations = convertToTypeArray(scope.declarations || EMPTY_ARRAY);
|
|
25508
26256
|
ngModuleDef.imports = convertToTypeArray(scope.imports || EMPTY_ARRAY);
|
|
25509
26257
|
ngModuleDef.exports = convertToTypeArray(scope.exports || EMPTY_ARRAY);
|
|
26258
|
+
if (scope.bootstrap) {
|
|
26259
|
+
// This only happens in local compilation mode.
|
|
26260
|
+
ngModuleDef.bootstrap = convertToTypeArray(scope.bootstrap);
|
|
26261
|
+
}
|
|
25510
26262
|
depsTracker.registerNgModule(type, scope);
|
|
25511
26263
|
});
|
|
25512
26264
|
}
|
|
@@ -25514,11 +26266,12 @@ function convertToTypeArray(values) {
|
|
|
25514
26266
|
if (typeof values === 'function') {
|
|
25515
26267
|
return values;
|
|
25516
26268
|
}
|
|
25517
|
-
|
|
25518
|
-
|
|
26269
|
+
const flattenValues = flatten(values);
|
|
26270
|
+
if (flattenValues.some(isForwardRef)) {
|
|
26271
|
+
return () => flattenValues.map(resolveForwardRef).map(maybeUnwrapModuleWithProviders);
|
|
25519
26272
|
}
|
|
25520
26273
|
else {
|
|
25521
|
-
return
|
|
26274
|
+
return flattenValues.map(maybeUnwrapModuleWithProviders);
|
|
25522
26275
|
}
|
|
25523
26276
|
}
|
|
25524
26277
|
function maybeUnwrapModuleWithProviders(value) {
|
|
@@ -25919,7 +26672,7 @@ function getAsyncClassMetadata(type) {
|
|
|
25919
26672
|
}
|
|
25920
26673
|
/**
|
|
25921
26674
|
* Handles the process of applying metadata info to a component class in case
|
|
25922
|
-
* component template had
|
|
26675
|
+
* component template had defer blocks (thus some dependencies became deferrable).
|
|
25923
26676
|
*
|
|
25924
26677
|
* @param type Component class where metadata should be added
|
|
25925
26678
|
* @param dependencyLoaderFn Function that loads dependencies
|
|
@@ -26667,16 +27420,13 @@ class QueryList {
|
|
|
26667
27420
|
* are compared as is (without any pre-processing).
|
|
26668
27421
|
*/
|
|
26669
27422
|
reset(resultsTree, identityAccessor) {
|
|
26670
|
-
|
|
26671
|
-
// QueryList (but not for QueryList itself.)
|
|
26672
|
-
const self = this;
|
|
26673
|
-
self.dirty = false;
|
|
27423
|
+
this.dirty = false;
|
|
26674
27424
|
const newResultFlat = flatten(resultsTree);
|
|
26675
|
-
if (this._changesDetected = !arrayEquals(
|
|
26676
|
-
|
|
26677
|
-
|
|
26678
|
-
|
|
26679
|
-
|
|
27425
|
+
if (this._changesDetected = !arrayEquals(this._results, newResultFlat, identityAccessor)) {
|
|
27426
|
+
this._results = newResultFlat;
|
|
27427
|
+
this.length = newResultFlat.length;
|
|
27428
|
+
this.last = newResultFlat[this.length - 1];
|
|
27429
|
+
this.first = newResultFlat[0];
|
|
26680
27430
|
}
|
|
26681
27431
|
}
|
|
26682
27432
|
/**
|
|
@@ -27244,7 +27994,13 @@ function ɵɵtemplateRefExtractor(tNode, lView) {
|
|
|
27244
27994
|
|
|
27245
27995
|
function ɵɵgetComponentDepsFactory(type, rawImports) {
|
|
27246
27996
|
return () => {
|
|
27247
|
-
|
|
27997
|
+
try {
|
|
27998
|
+
return depsTracker.getComponentDependencies(type, rawImports).dependencies;
|
|
27999
|
+
}
|
|
28000
|
+
catch (e) {
|
|
28001
|
+
console.error(`Computing dependencies in local compilation mode for the component "${type.name}" failed with the exception:`, e);
|
|
28002
|
+
throw e;
|
|
28003
|
+
}
|
|
27248
28004
|
};
|
|
27249
28005
|
}
|
|
27250
28006
|
|
|
@@ -28743,10 +29499,10 @@ class ApplicationInitStatus {
|
|
|
28743
29499
|
static { this.ɵfac = function ApplicationInitStatus_Factory(t) { return new (t || ApplicationInitStatus)(); }; }
|
|
28744
29500
|
static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationInitStatus, factory: ApplicationInitStatus.ɵfac, providedIn: 'root' }); }
|
|
28745
29501
|
}
|
|
28746
|
-
(
|
|
29502
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
|
|
28747
29503
|
type: Injectable,
|
|
28748
29504
|
args: [{ providedIn: 'root' }]
|
|
28749
|
-
}],
|
|
29505
|
+
}], () => [], null); })();
|
|
28750
29506
|
|
|
28751
29507
|
class Console {
|
|
28752
29508
|
log(message) {
|
|
@@ -28761,7 +29517,7 @@ class Console {
|
|
|
28761
29517
|
static { this.ɵfac = function Console_Factory(t) { return new (t || Console)(); }; }
|
|
28762
29518
|
static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Console, factory: Console.ɵfac, providedIn: 'platform' }); }
|
|
28763
29519
|
}
|
|
28764
|
-
(
|
|
29520
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Console, [{
|
|
28765
29521
|
type: Injectable,
|
|
28766
29522
|
args: [{ providedIn: 'platform' }]
|
|
28767
29523
|
}], null, null); })();
|
|
@@ -28972,7 +29728,7 @@ class InitialRenderPendingTasks {
|
|
|
28972
29728
|
static { this.ɵfac = function InitialRenderPendingTasks_Factory(t) { return new (t || InitialRenderPendingTasks)(); }; }
|
|
28973
29729
|
static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: InitialRenderPendingTasks, factory: InitialRenderPendingTasks.ɵfac, providedIn: 'root' }); }
|
|
28974
29730
|
}
|
|
28975
|
-
(
|
|
29731
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(InitialRenderPendingTasks, [{
|
|
28976
29732
|
type: Injectable,
|
|
28977
29733
|
args: [{ providedIn: 'root' }]
|
|
28978
29734
|
}], null, null); })();
|
|
@@ -29060,7 +29816,7 @@ class Compiler {
|
|
|
29060
29816
|
static { this.ɵfac = function Compiler_Factory(t) { return new (t || Compiler)(); }; }
|
|
29061
29817
|
static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Compiler, factory: Compiler.ɵfac, providedIn: 'root' }); }
|
|
29062
29818
|
}
|
|
29063
|
-
(
|
|
29819
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Compiler, [{
|
|
29064
29820
|
type: Injectable,
|
|
29065
29821
|
args: [{ providedIn: 'root' }]
|
|
29066
29822
|
}], null, null); })();
|
|
@@ -30024,12 +30780,12 @@ class Testability {
|
|
|
30024
30780
|
static { this.ɵfac = function Testability_Factory(t) { return new (t || Testability)(ɵɵinject(NgZone), ɵɵinject(TestabilityRegistry), ɵɵinject(TESTABILITY_GETTER)); }; }
|
|
30025
30781
|
static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: Testability, factory: Testability.ɵfac }); }
|
|
30026
30782
|
}
|
|
30027
|
-
(
|
|
30783
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Testability, [{
|
|
30028
30784
|
type: Injectable
|
|
30029
|
-
}],
|
|
30785
|
+
}], () => [{ type: NgZone }, { type: TestabilityRegistry }, { type: undefined, decorators: [{
|
|
30030
30786
|
type: Inject,
|
|
30031
30787
|
args: [TESTABILITY_GETTER]
|
|
30032
|
-
}] }]
|
|
30788
|
+
}] }], null); })();
|
|
30033
30789
|
/**
|
|
30034
30790
|
* A global registry of {@link Testability} instances for specific elements.
|
|
30035
30791
|
* @publicApi
|
|
@@ -30091,7 +30847,7 @@ class TestabilityRegistry {
|
|
|
30091
30847
|
static { this.ɵfac = function TestabilityRegistry_Factory(t) { return new (t || TestabilityRegistry)(); }; }
|
|
30092
30848
|
static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: TestabilityRegistry, factory: TestabilityRegistry.ɵfac, providedIn: 'platform' }); }
|
|
30093
30849
|
}
|
|
30094
|
-
(
|
|
30850
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(TestabilityRegistry, [{
|
|
30095
30851
|
type: Injectable,
|
|
30096
30852
|
args: [{ providedIn: 'platform' }]
|
|
30097
30853
|
}], null, null); })();
|
|
@@ -30534,10 +31290,10 @@ class PlatformRef {
|
|
|
30534
31290
|
static { this.ɵfac = function PlatformRef_Factory(t) { return new (t || PlatformRef)(ɵɵinject(Injector)); }; }
|
|
30535
31291
|
static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: PlatformRef, factory: PlatformRef.ɵfac, providedIn: 'platform' }); }
|
|
30536
31292
|
}
|
|
30537
|
-
(
|
|
31293
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PlatformRef, [{
|
|
30538
31294
|
type: Injectable,
|
|
30539
31295
|
args: [{ providedIn: 'platform' }]
|
|
30540
|
-
}],
|
|
31296
|
+
}], () => [{ type: Injector }], null); })();
|
|
30541
31297
|
// Transforms a set of `BootstrapOptions` (supported by the NgModule-based bootstrap APIs) ->
|
|
30542
31298
|
// `NgZoneOptions` that are recognized by the NgZone constructor. Passing no options will result in
|
|
30543
31299
|
// a set of default options returned.
|
|
@@ -30917,7 +31673,7 @@ class ApplicationRef {
|
|
|
30917
31673
|
static { this.ɵfac = function ApplicationRef_Factory(t) { return new (t || ApplicationRef)(); }; }
|
|
30918
31674
|
static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationRef, factory: ApplicationRef.ɵfac, providedIn: 'root' }); }
|
|
30919
31675
|
}
|
|
30920
|
-
(
|
|
31676
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationRef, [{
|
|
30921
31677
|
type: Injectable,
|
|
30922
31678
|
args: [{ providedIn: 'root' }]
|
|
30923
31679
|
}], null, null); })();
|
|
@@ -30976,7 +31732,7 @@ class NgZoneChangeDetectionScheduler {
|
|
|
30976
31732
|
static { this.ɵfac = function NgZoneChangeDetectionScheduler_Factory(t) { return new (t || NgZoneChangeDetectionScheduler)(); }; }
|
|
30977
31733
|
static { this.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: NgZoneChangeDetectionScheduler, factory: NgZoneChangeDetectionScheduler.ɵfac, providedIn: 'root' }); }
|
|
30978
31734
|
}
|
|
30979
|
-
(
|
|
31735
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NgZoneChangeDetectionScheduler, [{
|
|
30980
31736
|
type: Injectable,
|
|
30981
31737
|
args: [{ providedIn: 'root' }]
|
|
30982
31738
|
}], null, null); })();
|
|
@@ -31033,6 +31789,23 @@ function provideZoneChangeDetection(options) {
|
|
|
31033
31789
|
zoneProviders,
|
|
31034
31790
|
]);
|
|
31035
31791
|
}
|
|
31792
|
+
let whenStableStore;
|
|
31793
|
+
/**
|
|
31794
|
+
* Returns a Promise that resolves when the application becomes stable after this method is called
|
|
31795
|
+
* the first time.
|
|
31796
|
+
*/
|
|
31797
|
+
function whenStable(applicationRef) {
|
|
31798
|
+
whenStableStore ??= new WeakMap();
|
|
31799
|
+
const cachedWhenStable = whenStableStore.get(applicationRef);
|
|
31800
|
+
if (cachedWhenStable) {
|
|
31801
|
+
return cachedWhenStable;
|
|
31802
|
+
}
|
|
31803
|
+
const whenStablePromise = applicationRef.isStable.pipe(first((isStable) => isStable)).toPromise().then(() => void 0);
|
|
31804
|
+
whenStableStore.set(applicationRef, whenStablePromise);
|
|
31805
|
+
// Be a good citizen and clean the store `onDestroy` even though we are using `WeakMap`.
|
|
31806
|
+
applicationRef.onDestroy(() => whenStableStore?.delete(applicationRef));
|
|
31807
|
+
return whenStablePromise;
|
|
31808
|
+
}
|
|
31036
31809
|
|
|
31037
31810
|
/**
|
|
31038
31811
|
* Returns whether Angular is in development mode.
|
|
@@ -31752,9 +32525,9 @@ class ApplicationModule {
|
|
|
31752
32525
|
static { this.ɵmod = /*@__PURE__*/ ɵɵdefineNgModule({ type: ApplicationModule }); }
|
|
31753
32526
|
static { this.ɵinj = /*@__PURE__*/ ɵɵdefineInjector({}); }
|
|
31754
32527
|
}
|
|
31755
|
-
(
|
|
32528
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationModule, [{
|
|
31756
32529
|
type: NgModule
|
|
31757
|
-
}],
|
|
32530
|
+
}], () => [{ type: ApplicationRef }], null); })();
|
|
31758
32531
|
|
|
31759
32532
|
/**
|
|
31760
32533
|
* A collection that tracks all serialized views (`ngh` DOM annotations)
|
|
@@ -32300,8 +33073,8 @@ function printHydrationStats(injector) {
|
|
|
32300
33073
|
/**
|
|
32301
33074
|
* Returns a Promise that is resolved when an application becomes stable.
|
|
32302
33075
|
*/
|
|
32303
|
-
function
|
|
32304
|
-
const
|
|
33076
|
+
function whenStableWithTimeout(appRef, injector) {
|
|
33077
|
+
const whenStablePromise = whenStable(appRef);
|
|
32305
33078
|
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
32306
33079
|
const timeoutTime = APPLICATION_IS_STABLE_TIMEOUT;
|
|
32307
33080
|
const console = injector.get(Console);
|
|
@@ -32312,9 +33085,9 @@ function whenStable(appRef, injector) {
|
|
|
32312
33085
|
const timeoutId = ngZone.runOutsideAngular(() => {
|
|
32313
33086
|
return setTimeout(() => logWarningOnStableTimedout(timeoutTime, console), timeoutTime);
|
|
32314
33087
|
});
|
|
32315
|
-
|
|
33088
|
+
whenStablePromise.finally(() => clearTimeout(timeoutId));
|
|
32316
33089
|
}
|
|
32317
|
-
return
|
|
33090
|
+
return whenStablePromise;
|
|
32318
33091
|
}
|
|
32319
33092
|
/**
|
|
32320
33093
|
* Returns a set of providers required to setup hydration support
|
|
@@ -32393,7 +33166,7 @@ function withDomHydration() {
|
|
|
32393
33166
|
//
|
|
32394
33167
|
// Note: the cleanup task *MUST* be scheduled within the Angular zone
|
|
32395
33168
|
// to ensure that change detection is properly run afterward.
|
|
32396
|
-
|
|
33169
|
+
whenStableWithTimeout(appRef, injector).then(() => {
|
|
32397
33170
|
NgZone.assertInAngularZone();
|
|
32398
33171
|
cleanupDehydratedViews(appRef);
|
|
32399
33172
|
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
@@ -32689,19 +33462,11 @@ class EffectHandle {
|
|
|
32689
33462
|
this.effectFn = effectFn;
|
|
32690
33463
|
this.creationZone = creationZone;
|
|
32691
33464
|
this.errorHandler = errorHandler;
|
|
32692
|
-
this.alive = true;
|
|
32693
33465
|
this.watcher =
|
|
32694
33466
|
watch((onCleanup) => this.runEffect(onCleanup), () => this.schedule(), allowSignalWrites);
|
|
32695
33467
|
this.unregisterOnDestroy = destroyRef?.onDestroy(() => this.destroy());
|
|
32696
33468
|
}
|
|
32697
33469
|
runEffect(onCleanup) {
|
|
32698
|
-
if (!this.alive) {
|
|
32699
|
-
// Running a destroyed effect is a no-op.
|
|
32700
|
-
return;
|
|
32701
|
-
}
|
|
32702
|
-
if (ngDevMode && isInNotificationPhase()) {
|
|
32703
|
-
throw new Error(`Schedulers cannot synchronously execute effects while scheduling.`);
|
|
32704
|
-
}
|
|
32705
33470
|
try {
|
|
32706
33471
|
this.effectFn(onCleanup);
|
|
32707
33472
|
}
|
|
@@ -32713,17 +33478,13 @@ class EffectHandle {
|
|
|
32713
33478
|
this.watcher.run();
|
|
32714
33479
|
}
|
|
32715
33480
|
schedule() {
|
|
32716
|
-
if (!this.alive) {
|
|
32717
|
-
return;
|
|
32718
|
-
}
|
|
32719
33481
|
this.scheduler.scheduleEffect(this);
|
|
32720
33482
|
}
|
|
32721
33483
|
notify() {
|
|
32722
33484
|
this.watcher.notify();
|
|
32723
33485
|
}
|
|
32724
33486
|
destroy() {
|
|
32725
|
-
this.
|
|
32726
|
-
this.watcher.cleanup();
|
|
33487
|
+
this.watcher.destroy();
|
|
32727
33488
|
this.unregisterOnDestroy?.();
|
|
32728
33489
|
// Note: if the effect is currently scheduled, it's not un-scheduled, and so the scheduler will
|
|
32729
33490
|
// retain a reference to it. Attempting to execute it will be a no-op.
|
|
@@ -32935,5 +33696,5 @@ if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
|
32935
33696
|
* Generated bundle index. Do not edit.
|
|
32936
33697
|
*/
|
|
32937
33698
|
|
|
32938
|
-
export { ANIMATION_MODULE_TYPE, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, CSP_NONCE, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Compiler, CompilerFactory, Component, ComponentFactory$1 as ComponentFactory, ComponentFactoryResolver$1 as ComponentFactoryResolver, ComponentRef$1 as ComponentRef, ContentChild, ContentChildren, DEFAULT_CURRENCY_CODE, DebugElement, DebugEventListener, DebugNode, DefaultIterableDiffer, DestroyRef, Directive, ENVIRONMENT_INITIALIZER, ElementRef, EmbeddedViewRef, EnvironmentInjector, ErrorHandler, EventEmitter, Host, HostBinding, HostListener, INJECTOR, Inject, InjectFlags, Injectable, InjectionToken, Injector, Input, IterableDiffers, KeyValueDiffers, LOCALE_ID, MissingTranslationStrategy, ModuleWithComponentFactories, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory$1 as NgModuleFactory, NgModuleRef$1 as NgModuleRef, NgProbeToken, NgZone, Optional, Output, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, Renderer2, RendererFactory2, RendererStyleFlags2, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, TransferState, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef, afterNextRender, afterRender, asNativeElements, assertInInjectionContext, assertPlatform, booleanAttribute, computed, createComponent, createEnvironmentInjector, createNgModule, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, effect, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, importProvidersFrom, inject, isDevMode, isSignal, isStandalone, makeEnvironmentProviders, makeStateKey, mergeApplicationConfig, numberAttribute, platformCore, provideZoneChangeDetection, reflectComponentType, resolveForwardRef, runInInjectionContext, setTestabilityGetter, signal, untracked, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, AfterRenderEventManager as ɵAfterRenderEventManager, ComponentFactory$1 as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, DEFER_BLOCK_DEPENDENCY_INTERCEPTOR as ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, ENABLED_SSR_FEATURES as ɵENABLED_SSR_FEATURES, EffectScheduler as ɵEffectScheduler, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, IS_HYDRATION_DOM_REUSE_ENABLED as ɵIS_HYDRATION_DOM_REUSE_ENABLED, InitialRenderPendingTasks as ɵInitialRenderPendingTasks, LContext as ɵLContext, LifecycleHooksFeature as ɵLifecycleHooksFeature, LocaleDataIndex as ɵLocaleDataIndex, NG_COMP_DEF as ɵNG_COMP_DEF, NG_DIR_DEF as ɵNG_DIR_DEF, NG_ELEMENT_ID as ɵNG_ELEMENT_ID, NG_INJ_DEF as ɵNG_INJ_DEF, NG_MOD_DEF as ɵNG_MOD_DEF, NG_PIPE_DEF as ɵNG_PIPE_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, NO_CHANGE as ɵNO_CHANGE, NgModuleFactory as ɵNgModuleFactory, NoopNgZone as ɵNoopNgZone, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, NgModuleRef as ɵRender3NgModuleRef, RuntimeError as ɵRuntimeError, SSR_CONTENT_INTEGRITY_MARKER as ɵSSR_CONTENT_INTEGRITY_MARKER, TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER, USE_RUNTIME_DEPS_TRACKER_FOR_JIT as ɵUSE_RUNTIME_DEPS_TRACKER_FOR_JIT, ViewRef$1 as ɵViewRef, XSS_SECURITY_URL as ɵXSS_SECURITY_URL, ZoneAwareQueueingScheduler as ɵZoneAwareQueueingScheduler, _sanitizeHtml as ɵ_sanitizeHtml, _sanitizeUrl as ɵ_sanitizeUrl, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, annotateForHydration as ɵannotateForHydration, bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, compileNgModuleFactory as ɵcompileNgModuleFactory, compilePipe as ɵcompilePipe, convertToBitFlags as ɵconvertToBitFlags, createInjector as ɵcreateInjector, defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers, depsTracker as ɵdepsTracker, detectChanges as ɵdetectChanges, devModeEqual as ɵdevModeEqual, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, formatRuntimeError as ɵformatRuntimeError, generateStandaloneInDeclarationsError as ɵgenerateStandaloneInDeclarationsError, getAsyncClassMetadata as ɵgetAsyncClassMetadata, getDebugNode as ɵgetDebugNode, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getSanitizationBypassType as ɵgetSanitizationBypassType, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, internalCreateApplication as ɵinternalCreateApplication, isBoundToModule as ɵisBoundToModule, isComponentDefPendingResolution as ɵisComponentDefPendingResolution, isEnvironmentProviders as ɵisEnvironmentProviders, isInjectable as ɵisInjectable, isNgModule as ɵisNgModule, isPromise as ɵisPromise, isSubscribable as ɵisSubscribable, noSideEffects as ɵnoSideEffects, patchComponentDefWithScope as ɵpatchComponentDefWithScope, publishDefaultGlobalUtils$1 as ɵpublishDefaultGlobalUtils, publishGlobalUtil as ɵpublishGlobalUtil, registerLocaleData as ɵregisterLocaleData, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, restoreComponentResolutionQueue as ɵrestoreComponentResolutionQueue, setAllowDuplicateNgModuleIdsForTest as ɵsetAllowDuplicateNgModuleIdsForTest, setAlternateWeakRefImpl as ɵsetAlternateWeakRefImpl, setClassMetadata as ɵsetClassMetadata, setClassMetadataAsync as ɵsetClassMetadataAsync, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setInjectorProfilerContext as ɵsetInjectorProfilerContext, setLocaleId as ɵsetLocaleId, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, store as ɵstore, stringify as ɵstringify, transitiveScopesFor as ɵtransitiveScopesFor, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapSafeValue as ɵunwrapSafeValue, withDomHydration as ɵwithDomHydration, ɵɵCopyDefinitionFeature, FactoryTarget as ɵɵFactoryTarget, ɵɵHostDirectivesFeature, ɵɵInheritDefinitionFeature, ɵɵInputTransformsFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵStandaloneFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵcomponentInstance, ɵɵconditional, ɵɵcontentQuery, ɵɵdefer, ɵɵdeferOnHover, ɵɵdeferOnIdle, ɵɵdeferOnImmediate, ɵɵdeferOnInteraction, ɵɵdeferOnTimer, ɵɵdeferOnViewport, ɵɵdeferPrefetchOnHover, ɵɵdeferPrefetchOnIdle, ɵɵdeferPrefetchOnImmediate, ɵɵdeferPrefetchOnInteraction, ɵɵdeferPrefetchOnTimer, ɵɵdeferPrefetchOnViewport, ɵɵdeferPrefetchWhen, ɵɵdeferWhen, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetComponentDepsFactory, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵngDeclareComponent, ɵɵngDeclareDirective, ɵɵngDeclareFactory, ɵɵngDeclareInjectable, ɵɵngDeclareInjector, ɵɵngDeclareNgModule, ɵɵngDeclarePipe, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryRefresh, ɵɵreference, registerNgModuleType as ɵɵregisterNgModuleType, ɵɵrepeater, ɵɵrepeaterCreate, ɵɵrepeaterTrackByIdentity, ɵɵrepeaterTrackByIndex, ɵɵresetView, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵtrustConstantHtml, ɵɵtrustConstantResourceUrl, ɵɵvalidateIframeAttribute, ɵɵviewQuery };
|
|
33699
|
+
export { ANIMATION_MODULE_TYPE, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, AfterRenderPhase, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, CSP_NONCE, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Compiler, CompilerFactory, Component, ComponentFactory$1 as ComponentFactory, ComponentFactoryResolver$1 as ComponentFactoryResolver, ComponentRef$1 as ComponentRef, ContentChild, ContentChildren, DEFAULT_CURRENCY_CODE, DebugElement, DebugEventListener, DebugNode, DefaultIterableDiffer, DestroyRef, Directive, ENVIRONMENT_INITIALIZER, ElementRef, EmbeddedViewRef, EnvironmentInjector, ErrorHandler, EventEmitter, Host, HostBinding, HostListener, INJECTOR, Inject, InjectFlags, Injectable, InjectionToken, Injector, Input, IterableDiffers, KeyValueDiffers, LOCALE_ID, MissingTranslationStrategy, ModuleWithComponentFactories, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory$1 as NgModuleFactory, NgModuleRef$1 as NgModuleRef, NgProbeToken, NgZone, Optional, Output, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, Renderer2, RendererFactory2, RendererStyleFlags2, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, TransferState, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef, afterNextRender, afterRender, asNativeElements, assertInInjectionContext, assertPlatform, booleanAttribute, computed, createComponent, createEnvironmentInjector, createNgModule, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, effect, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, importProvidersFrom, inject, isDevMode, isSignal, isStandalone, makeEnvironmentProviders, makeStateKey, mergeApplicationConfig, numberAttribute, platformCore, provideZoneChangeDetection, reflectComponentType, resolveForwardRef, runInInjectionContext, setTestabilityGetter, signal, untracked, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, AfterRenderEventManager as ɵAfterRenderEventManager, CONTAINER_HEADER_OFFSET as ɵCONTAINER_HEADER_OFFSET, ComponentFactory$1 as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, DEFER_BLOCK_CONFIG as ɵDEFER_BLOCK_CONFIG, DEFER_BLOCK_DEPENDENCY_INTERCEPTOR as ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, DeferBlockBehavior as ɵDeferBlockBehavior, DeferBlockState as ɵDeferBlockState, ENABLED_SSR_FEATURES as ɵENABLED_SSR_FEATURES, EffectScheduler as ɵEffectScheduler, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, IS_HYDRATION_DOM_REUSE_ENABLED as ɵIS_HYDRATION_DOM_REUSE_ENABLED, InitialRenderPendingTasks as ɵInitialRenderPendingTasks, LContext as ɵLContext, LifecycleHooksFeature as ɵLifecycleHooksFeature, LocaleDataIndex as ɵLocaleDataIndex, NG_COMP_DEF as ɵNG_COMP_DEF, NG_DIR_DEF as ɵNG_DIR_DEF, NG_ELEMENT_ID as ɵNG_ELEMENT_ID, NG_INJ_DEF as ɵNG_INJ_DEF, NG_MOD_DEF as ɵNG_MOD_DEF, NG_PIPE_DEF as ɵNG_PIPE_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, NO_CHANGE as ɵNO_CHANGE, NgModuleFactory as ɵNgModuleFactory, NoopNgZone as ɵNoopNgZone, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, NgModuleRef as ɵRender3NgModuleRef, RuntimeError as ɵRuntimeError, SSR_CONTENT_INTEGRITY_MARKER as ɵSSR_CONTENT_INTEGRITY_MARKER, TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER, USE_RUNTIME_DEPS_TRACKER_FOR_JIT as ɵUSE_RUNTIME_DEPS_TRACKER_FOR_JIT, ViewRef$1 as ɵViewRef, XSS_SECURITY_URL as ɵXSS_SECURITY_URL, ZoneAwareQueueingScheduler as ɵZoneAwareQueueingScheduler, _sanitizeHtml as ɵ_sanitizeHtml, _sanitizeUrl as ɵ_sanitizeUrl, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, annotateForHydration as ɵannotateForHydration, bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, compileNgModuleFactory as ɵcompileNgModuleFactory, compilePipe as ɵcompilePipe, convertToBitFlags as ɵconvertToBitFlags, createInjector as ɵcreateInjector, defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers, depsTracker as ɵdepsTracker, detectChanges as ɵdetectChanges, devModeEqual as ɵdevModeEqual, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, formatRuntimeError as ɵformatRuntimeError, generateStandaloneInDeclarationsError as ɵgenerateStandaloneInDeclarationsError, getAsyncClassMetadata as ɵgetAsyncClassMetadata, getDebugNode as ɵgetDebugNode, getDeferBlocks as ɵgetDeferBlocks, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getSanitizationBypassType as ɵgetSanitizationBypassType, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, internalCreateApplication as ɵinternalCreateApplication, isBoundToModule as ɵisBoundToModule, isComponentDefPendingResolution as ɵisComponentDefPendingResolution, isEnvironmentProviders as ɵisEnvironmentProviders, isInjectable as ɵisInjectable, isNgModule as ɵisNgModule, isPromise as ɵisPromise, isSubscribable as ɵisSubscribable, noSideEffects as ɵnoSideEffects, patchComponentDefWithScope as ɵpatchComponentDefWithScope, publishDefaultGlobalUtils$1 as ɵpublishDefaultGlobalUtils, publishGlobalUtil as ɵpublishGlobalUtil, registerLocaleData as ɵregisterLocaleData, renderDeferBlockState as ɵrenderDeferBlockState, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, restoreComponentResolutionQueue as ɵrestoreComponentResolutionQueue, setAllowDuplicateNgModuleIdsForTest as ɵsetAllowDuplicateNgModuleIdsForTest, setAlternateWeakRefImpl as ɵsetAlternateWeakRefImpl, setClassMetadata as ɵsetClassMetadata, setClassMetadataAsync as ɵsetClassMetadataAsync, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setInjectorProfilerContext as ɵsetInjectorProfilerContext, setLocaleId as ɵsetLocaleId, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, store as ɵstore, stringify as ɵstringify, transitiveScopesFor as ɵtransitiveScopesFor, triggerResourceLoading as ɵtriggerResourceLoading, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapSafeValue as ɵunwrapSafeValue, whenStable as ɵwhenStable, withDomHydration as ɵwithDomHydration, ɵɵCopyDefinitionFeature, FactoryTarget as ɵɵFactoryTarget, ɵɵHostDirectivesFeature, ɵɵInheritDefinitionFeature, ɵɵInputTransformsFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵStandaloneFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵcomponentInstance, ɵɵconditional, ɵɵcontentQuery, ɵɵdefer, ɵɵdeferOnHover, ɵɵdeferOnIdle, ɵɵdeferOnImmediate, ɵɵdeferOnInteraction, ɵɵdeferOnTimer, ɵɵdeferOnViewport, ɵɵdeferPrefetchOnHover, ɵɵdeferPrefetchOnIdle, ɵɵdeferPrefetchOnImmediate, ɵɵdeferPrefetchOnInteraction, ɵɵdeferPrefetchOnTimer, ɵɵdeferPrefetchOnViewport, ɵɵdeferPrefetchWhen, ɵɵdeferWhen, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetComponentDepsFactory, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵngDeclareComponent, ɵɵngDeclareDirective, ɵɵngDeclareFactory, ɵɵngDeclareInjectable, ɵɵngDeclareInjector, ɵɵngDeclareNgModule, ɵɵngDeclarePipe, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryRefresh, ɵɵreference, registerNgModuleType as ɵɵregisterNgModuleType, ɵɵrepeater, ɵɵrepeaterCreate, ɵɵrepeaterTrackByIdentity, ɵɵrepeaterTrackByIndex, ɵɵresetView, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵtrustConstantHtml, ɵɵtrustConstantResourceUrl, ɵɵvalidateIframeAttribute, ɵɵviewQuery };
|
|
32939
33700
|
//# sourceMappingURL=core.mjs.map
|