@angular/core
Version:
Angular - the core framework
796 lines • 114 kB
JavaScript
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as tslib_1 from "tslib";
import { ViewEncapsulation } from '../metadata/view';
import { assertDefined, assertDomNode } from '../util/assert';
import { assertLContainer, assertLView } from './assert';
import { attachPatchData } from './context_discovery';
import { CONTAINER_HEADER_OFFSET, NATIVE, unusedValueExportToPlacateAjd as unused1 } from './interfaces/container';
import { NodeInjectorFactory } from './interfaces/injector';
import { unusedValueExportToPlacateAjd as unused2 } from './interfaces/node';
import { unusedValueExportToPlacateAjd as unused3 } from './interfaces/projection';
import { isProceduralRenderer, unusedValueExportToPlacateAjd as unused4 } from './interfaces/renderer';
import { CHILD_HEAD, CLEANUP, FLAGS, HOST, NEXT, PARENT, QUERIES, RENDERER, TVIEW, T_HOST, unusedValueExportToPlacateAjd as unused5 } from './interfaces/view';
import { assertNodeOfPossibleTypes, assertNodeType } from './node_assert';
import { renderStringify } from './util/misc_utils';
import { findComponentView, getLViewParent } from './util/view_traversal_utils';
import { getNativeByTNode, isLContainer, isLView, isRootView, unwrapRNode, viewAttachedToContainer } from './util/view_utils';
var unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
export function getLContainer(tNode, embeddedView) {
ngDevMode && assertLView(embeddedView);
var container = embeddedView[PARENT];
if (tNode.index === -1) {
// This is a dynamically created view inside a dynamic container.
// The parent isn't an LContainer if the embedded view hasn't been attached yet.
return isLContainer(container) ? container : null;
}
else {
ngDevMode && assertLContainer(container);
// This is a inline view node (e.g. embeddedViewStart)
return container;
}
}
/**
* Retrieves render parent for a given view.
* Might be null if a view is not yet attached to any container.
*/
function getContainerRenderParent(tViewNode, view) {
var container = getLContainer(tViewNode, view);
return container ? nativeParentNode(view[RENDERER], container[NATIVE]) : null;
}
/**
* NOTE: for performance reasons, the possible actions are inlined within the function instead of
* being passed as an argument.
*/
function executeActionOnElementOrContainer(action, renderer, parent, lNodeToHandle, beforeNode) {
ngDevMode && assertDefined(lNodeToHandle, '\'lNodeToHandle\' is undefined');
var lContainer;
var isComponent = false;
// We are expecting an RNode, but in the case of a component or LContainer the `RNode` is wrapped
// in an array which needs to be unwrapped. We need to know if it is a component and if
// it has LContainer so that we can process all of those cases appropriately.
if (isLContainer(lNodeToHandle)) {
lContainer = lNodeToHandle;
}
else if (isLView(lNodeToHandle)) {
isComponent = true;
ngDevMode && assertDefined(lNodeToHandle[HOST], 'HOST must be defined for a component LView');
lNodeToHandle = lNodeToHandle[HOST];
}
var rNode = unwrapRNode(lNodeToHandle);
ngDevMode && assertDomNode(rNode);
if (action === 0 /* Insert */) {
nativeInsertBefore(renderer, parent, rNode, beforeNode || null);
}
else if (action === 1 /* Detach */) {
nativeRemoveNode(renderer, rNode, isComponent);
}
else if (action === 2 /* Destroy */) {
ngDevMode && ngDevMode.rendererDestroyNode++;
renderer.destroyNode(rNode);
}
if (lContainer != null) {
executeActionOnContainer(renderer, action, lContainer, parent, beforeNode);
}
}
export function createTextNode(value, renderer) {
return isProceduralRenderer(renderer) ? renderer.createText(renderStringify(value)) :
renderer.createTextNode(renderStringify(value));
}
export function addRemoveViewFromContainer(lView, insertMode, beforeNode) {
var renderParent = getContainerRenderParent(lView[TVIEW].node, lView);
ngDevMode && assertNodeType(lView[TVIEW].node, 2 /* View */);
if (renderParent) {
var renderer = lView[RENDERER];
var action = insertMode ? 0 /* Insert */ : 1 /* Detach */;
executeActionOnView(renderer, action, lView, renderParent, beforeNode);
}
}
/**
* Detach a `LView` from the DOM by detaching its nodes.
*
* @param lView the `LView` to be detached.
*/
export function renderDetachView(lView) {
executeActionOnView(lView[RENDERER], 1 /* Detach */, lView, null, null);
}
/**
* Traverses down and up the tree of views and containers to remove listeners and
* call onDestroy callbacks.
*
* Notes:
* - Because it's used for onDestroy calls, it needs to be bottom-up.
* - Must process containers instead of their views to avoid splicing
* when views are destroyed and re-added.
* - Using a while loop because it's faster than recursion
* - Destroy only called on movement to sibling or movement to parent (laterally or up)
*
* @param rootView The view to destroy
*/
export function destroyViewTree(rootView) {
// If the view has no children, we can clean it up and return early.
var lViewOrLContainer = rootView[CHILD_HEAD];
if (!lViewOrLContainer) {
return cleanUpView(rootView);
}
while (lViewOrLContainer) {
var next = null;
if (isLView(lViewOrLContainer)) {
// If LView, traverse down to child.
next = lViewOrLContainer[CHILD_HEAD];
}
else {
ngDevMode && assertLContainer(lViewOrLContainer);
// If container, traverse down to its first LView.
var firstView = lViewOrLContainer[CONTAINER_HEADER_OFFSET];
if (firstView)
next = firstView;
}
if (!next) {
// Only clean up view when moving to the side or up, as destroy hooks
// should be called in order from the bottom up.
while (lViewOrLContainer && !lViewOrLContainer[NEXT] && lViewOrLContainer !== rootView) {
cleanUpView(lViewOrLContainer);
lViewOrLContainer = getParentState(lViewOrLContainer, rootView);
}
cleanUpView(lViewOrLContainer || rootView);
next = lViewOrLContainer && lViewOrLContainer[NEXT];
}
lViewOrLContainer = next;
}
}
/**
* Inserts a view into a container.
*
* This adds the view to the container's array of active views in the correct
* position. It also adds the view's elements to the DOM if the container isn't a
* root node of another view (in that case, the view's elements will be added when
* the container's parent view is added later).
*
* @param lView The view to insert
* @param lContainer The container into which the view should be inserted
* @param index Which index in the container to insert the child view into
*/
export function insertView(lView, lContainer, index) {
ngDevMode && assertLView(lView);
ngDevMode && assertLContainer(lContainer);
var indexInContainer = CONTAINER_HEADER_OFFSET + index;
var containerLength = lContainer.length;
if (index > 0) {
// This is a new view, we need to add it to the children.
lContainer[indexInContainer - 1][NEXT] = lView;
}
if (index < containerLength - CONTAINER_HEADER_OFFSET) {
lView[NEXT] = lContainer[indexInContainer];
lContainer.splice(CONTAINER_HEADER_OFFSET + index, 0, lView);
}
else {
lContainer.push(lView);
lView[NEXT] = null;
}
lView[PARENT] = lContainer;
// Notify query that a new view has been added
if (lView[QUERIES]) {
lView[QUERIES].insertView(index);
}
// Sets the attached flag
lView[FLAGS] |= 128 /* Attached */;
}
/**
* Detaches a view from a container.
*
* This method splices the view from the container's array of active views. It also
* removes the view's elements from the DOM.
*
* @param lContainer The container from which to detach a view
* @param removeIndex The index of the view to detach
* @returns Detached LView instance.
*/
export function detachView(lContainer, removeIndex) {
if (lContainer.length <= CONTAINER_HEADER_OFFSET)
return;
var indexInContainer = CONTAINER_HEADER_OFFSET + removeIndex;
var viewToDetach = lContainer[indexInContainer];
if (viewToDetach) {
if (removeIndex > 0) {
lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT];
}
lContainer.splice(CONTAINER_HEADER_OFFSET + removeIndex, 1);
addRemoveViewFromContainer(viewToDetach, false);
if ((viewToDetach[FLAGS] & 128 /* Attached */) &&
!(viewToDetach[FLAGS] & 256 /* Destroyed */) && viewToDetach[QUERIES]) {
viewToDetach[QUERIES].removeView();
}
viewToDetach[PARENT] = null;
viewToDetach[NEXT] = null;
// Unsets the attached flag
viewToDetach[FLAGS] &= ~128 /* Attached */;
}
return viewToDetach;
}
/**
* Removes a view from a container, i.e. detaches it and then destroys the underlying LView.
*
* @param lContainer The container from which to remove a view
* @param removeIndex The index of the view to remove
*/
export function removeView(lContainer, removeIndex) {
var detachedView = detachView(lContainer, removeIndex);
detachedView && destroyLView(detachedView);
}
/**
* A standalone function which destroys an LView,
* conducting cleanup (e.g. removing listeners, calling onDestroys).
*
* @param lView The view to be destroyed.
*/
export function destroyLView(lView) {
if (!(lView[FLAGS] & 256 /* Destroyed */)) {
var renderer = lView[RENDERER];
if (isProceduralRenderer(renderer) && renderer.destroyNode) {
executeActionOnView(renderer, 2 /* Destroy */, lView, null, null);
}
destroyViewTree(lView);
}
}
/**
* Determines which LViewOrLContainer to jump to when traversing back up the
* tree in destroyViewTree.
*
* Normally, the view's parent LView should be checked, but in the case of
* embedded views, the container (which is the view node's parent, but not the
* LView's parent) needs to be checked for a possible next property.
*
* @param lViewOrLContainer The LViewOrLContainer for which we need a parent state
* @param rootView The rootView, so we don't propagate too far up the view tree
* @returns The correct parent LViewOrLContainer
*/
export function getParentState(lViewOrLContainer, rootView) {
var tNode;
if (isLView(lViewOrLContainer) && (tNode = lViewOrLContainer[T_HOST]) &&
tNode.type === 2 /* View */) {
// if it's an embedded view, the state needs to go up to the container, in case the
// container has a next
return getLContainer(tNode, lViewOrLContainer);
}
else {
// otherwise, use parent view for containers or component views
return lViewOrLContainer[PARENT] === rootView ? null : lViewOrLContainer[PARENT];
}
}
/**
* Calls onDestroys hooks for all directives and pipes in a given view and then removes all
* listeners. Listeners are removed as the last step so events delivered in the onDestroys hooks
* can be propagated to @Output listeners.
*
* @param view The LView to clean up
*/
function cleanUpView(view) {
if (isLView(view) && !(view[FLAGS] & 256 /* Destroyed */)) {
// Usually the Attached flag is removed when the view is detached from its parent, however
// if it's a root view, the flag won't be unset hence why we're also removing on destroy.
view[FLAGS] &= ~128 /* Attached */;
// Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook
// runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If
// We don't flag the view as destroyed before the hooks, this could lead to an infinite loop.
// This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is
// really more of an "afterDestroy" hook if you think about it.
view[FLAGS] |= 256 /* Destroyed */;
executeOnDestroys(view);
removeListeners(view);
var hostTNode = view[T_HOST];
// For component views only, the local renderer is destroyed as clean up time.
if (hostTNode && hostTNode.type === 3 /* Element */ && isProceduralRenderer(view[RENDERER])) {
ngDevMode && ngDevMode.rendererDestroy++;
view[RENDERER].destroy();
}
// For embedded views still attached to a container: remove query result from this view.
if (viewAttachedToContainer(view) && view[QUERIES]) {
view[QUERIES].removeView();
}
}
}
/** Removes listeners and unsubscribes from output subscriptions */
function removeListeners(lView) {
var tCleanup = lView[TVIEW].cleanup;
if (tCleanup !== null) {
var lCleanup = lView[CLEANUP];
for (var i = 0; i < tCleanup.length - 1; i += 2) {
if (typeof tCleanup[i] === 'string') {
// This is a native DOM listener
var idxOrTargetGetter = tCleanup[i + 1];
var target = typeof idxOrTargetGetter === 'function' ?
idxOrTargetGetter(lView) :
unwrapRNode(lView[idxOrTargetGetter]);
var listener = lCleanup[tCleanup[i + 2]];
var useCaptureOrSubIdx = tCleanup[i + 3];
if (typeof useCaptureOrSubIdx === 'boolean') {
// native DOM listener registered with Renderer3
target.removeEventListener(tCleanup[i], listener, useCaptureOrSubIdx);
}
else {
if (useCaptureOrSubIdx >= 0) {
// unregister
lCleanup[useCaptureOrSubIdx]();
}
else {
// Subscription
lCleanup[-useCaptureOrSubIdx].unsubscribe();
}
}
i += 2;
}
else {
// This is a cleanup function that is grouped with the index of its context
var context = lCleanup[tCleanup[i + 1]];
tCleanup[i].call(context);
}
}
lView[CLEANUP] = null;
}
}
/** Calls onDestroy hooks for this view */
function executeOnDestroys(view) {
var tView = view[TVIEW];
var destroyHooks;
if (tView != null && (destroyHooks = tView.destroyHooks) != null) {
for (var i = 0; i < destroyHooks.length; i += 2) {
var context = view[destroyHooks[i]];
// Only call the destroy hook if the context has been requested.
if (!(context instanceof NodeInjectorFactory)) {
destroyHooks[i + 1].call(context);
}
}
}
}
/**
* Returns a native element if a node can be inserted into the given parent.
*
* There are two reasons why we may not be able to insert a element immediately.
* - Projection: When creating a child content element of a component, we have to skip the
* insertion because the content of a component will be projected.
* `<component><content>delayed due to projection</content></component>`
* - Parent container is disconnected: This can happen when we are inserting a view into
* parent container, which itself is disconnected. For example the parent container is part
* of a View which has not be inserted or is made for projection but has not been inserted
* into destination.
*/
function getRenderParent(tNode, currentView) {
// Nodes of the top-most view can be inserted eagerly.
if (isRootView(currentView)) {
return nativeParentNode(currentView[RENDERER], getNativeByTNode(tNode, currentView));
}
// Skip over element and ICU containers as those are represented by a comment node and
// can't be used as a render parent.
var parent = getHighestElementOrICUContainer(tNode);
var renderParent = parent.parent;
// If the parent is null, then we are inserting across views: either into an embedded view or a
// component view.
if (renderParent == null) {
var hostTNode = currentView[T_HOST];
if (hostTNode.type === 2 /* View */) {
// We are inserting a root element of an embedded view We might delay insertion of children
// for a given view if it is disconnected. This might happen for 2 main reasons:
// - view is not inserted into any container(view was created but not inserted yet)
// - view is inserted into a container but the container itself is not inserted into the DOM
// (container might be part of projection or child of a view that is not inserted yet).
// In other words we can insert children of a given view if this view was inserted into a
// container and the container itself has its render parent determined.
return getContainerRenderParent(hostTNode, currentView);
}
else {
// We are inserting a root element of the component view into the component host element and
// it should always be eager.
return getHostNative(currentView);
}
}
else {
var isIcuCase = parent && parent.type === 5 /* IcuContainer */;
// If the parent of this node is an ICU container, then it is represented by comment node and we
// need to use it as an anchor. If it is projected then its direct parent node is the renderer.
if (isIcuCase && parent.flags & 2 /* isProjected */) {
return getNativeByTNode(parent, currentView).parentNode;
}
ngDevMode && assertNodeType(renderParent, 3 /* Element */);
if (renderParent.flags & 1 /* isComponent */ && !isIcuCase) {
var tData = currentView[TVIEW].data;
var tNode_1 = tData[renderParent.index];
var encapsulation = tData[tNode_1.directiveStart].encapsulation;
// We've got a parent which is an element in the current view. We just need to verify if the
// parent element is not a component. Component's content nodes are not inserted immediately
// because they will be projected, and so doing insert at this point would be wasteful.
// Since the projection would then move it to its final destination. Note that we can't
// make this assumption when using the Shadow DOM, because the native projection placeholders
// (<content> or <slot>) have to be in place as elements are being inserted.
if (encapsulation !== ViewEncapsulation.ShadowDom &&
encapsulation !== ViewEncapsulation.Native) {
return null;
}
}
return getNativeByTNode(renderParent, currentView);
}
}
/**
* Gets the native host element for a given view. Will return null if the current view does not have
* a host element.
*/
function getHostNative(currentView) {
ngDevMode && assertLView(currentView);
var hostTNode = currentView[T_HOST];
return hostTNode && hostTNode.type === 3 /* Element */ ?
getNativeByTNode(hostTNode, getLViewParent(currentView)) :
null;
}
/**
* Inserts a native node before another native node for a given parent using {@link Renderer3}.
* This is a utility function that can be used when native nodes were determined - it abstracts an
* actual renderer being used.
*/
export function nativeInsertBefore(renderer, parent, child, beforeNode) {
ngDevMode && ngDevMode.rendererInsertBefore++;
if (isProceduralRenderer(renderer)) {
renderer.insertBefore(parent, child, beforeNode);
}
else {
parent.insertBefore(child, beforeNode, true);
}
}
function nativeAppendChild(renderer, parent, child) {
ngDevMode && ngDevMode.rendererAppendChild++;
if (isProceduralRenderer(renderer)) {
renderer.appendChild(parent, child);
}
else {
parent.appendChild(child);
}
}
function nativeAppendOrInsertBefore(renderer, parent, child, beforeNode) {
if (beforeNode !== null) {
nativeInsertBefore(renderer, parent, child, beforeNode);
}
else {
nativeAppendChild(renderer, parent, child);
}
}
/** Removes a node from the DOM given its native parent. */
function nativeRemoveChild(renderer, parent, child, isHostElement) {
if (isProceduralRenderer(renderer)) {
renderer.removeChild(parent, child, isHostElement);
}
else {
parent.removeChild(child);
}
}
/**
* Returns a native parent of a given native node.
*/
export function nativeParentNode(renderer, node) {
return (isProceduralRenderer(renderer) ? renderer.parentNode(node) : node.parentNode);
}
/**
* Returns a native sibling of a given native node.
*/
export function nativeNextSibling(renderer, node) {
return isProceduralRenderer(renderer) ? renderer.nextSibling(node) : node.nextSibling;
}
/**
* Finds a native "anchor" node for cases where we can't append a native child directly
* (`appendChild`) and need to use a reference (anchor) node for the `insertBefore` operation.
* @param parentTNode
* @param lView
*/
function getNativeAnchorNode(parentTNode, lView) {
if (parentTNode.type === 2 /* View */) {
var lContainer = getLContainer(parentTNode, lView);
var index = lContainer.indexOf(lView, CONTAINER_HEADER_OFFSET) - CONTAINER_HEADER_OFFSET;
return getBeforeNodeForView(index, lContainer);
}
else if (parentTNode.type === 4 /* ElementContainer */ ||
parentTNode.type === 5 /* IcuContainer */) {
return getNativeByTNode(parentTNode, lView);
}
return null;
}
/**
* Appends the `child` native node (or a collection of nodes) to the `parent`.
*
* The element insertion might be delayed {@link canInsertNativeNode}.
*
* @param childEl The native child (or children) that should be appended
* @param childTNode The TNode of the child element
* @param currentView The current LView
* @returns Whether or not the child was appended
*/
export function appendChild(childEl, childTNode, currentView) {
var e_1, _a;
var renderParent = getRenderParent(childTNode, currentView);
if (renderParent != null) {
var renderer = currentView[RENDERER];
var parentTNode = childTNode.parent || currentView[T_HOST];
var anchorNode = getNativeAnchorNode(parentTNode, currentView);
if (Array.isArray(childEl)) {
try {
for (var childEl_1 = tslib_1.__values(childEl), childEl_1_1 = childEl_1.next(); !childEl_1_1.done; childEl_1_1 = childEl_1.next()) {
var nativeNode = childEl_1_1.value;
nativeAppendOrInsertBefore(renderer, renderParent, nativeNode, anchorNode);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (childEl_1_1 && !childEl_1_1.done && (_a = childEl_1.return)) _a.call(childEl_1);
}
finally { if (e_1) throw e_1.error; }
}
}
else {
nativeAppendOrInsertBefore(renderer, renderParent, childEl, anchorNode);
}
}
}
/**
* Gets the top-level element or an ICU container if those containers are nested.
*
* @param tNode The starting TNode for which we should skip element and ICU containers
* @returns The TNode of the highest level ICU container or element container
*/
function getHighestElementOrICUContainer(tNode) {
while (tNode.parent != null && (tNode.parent.type === 4 /* ElementContainer */ ||
tNode.parent.type === 5 /* IcuContainer */)) {
tNode = tNode.parent;
}
return tNode;
}
export function getBeforeNodeForView(viewIndexInContainer, lContainer) {
var nextViewIndex = CONTAINER_HEADER_OFFSET + viewIndexInContainer + 1;
if (nextViewIndex < lContainer.length) {
var lView = lContainer[nextViewIndex];
ngDevMode && assertDefined(lView[T_HOST], 'Missing Host TNode');
var tViewNodeChild = lView[T_HOST].child;
return tViewNodeChild !== null ? getNativeByTNode(tViewNodeChild, lView) : lContainer[NATIVE];
}
else {
return lContainer[NATIVE];
}
}
/**
* Removes a native node itself using a given renderer. To remove the node we are looking up its
* parent from the native tree as not all platforms / browsers support the equivalent of
* node.remove().
*
* @param renderer A renderer to be used
* @param rNode The native node that should be removed
* @param isHostElement A flag indicating if a node to be removed is a host of a component.
*/
export function nativeRemoveNode(renderer, rNode, isHostElement) {
var nativeParent = nativeParentNode(renderer, rNode);
if (nativeParent) {
nativeRemoveChild(renderer, nativeParent, rNode, isHostElement);
}
}
/**
* Appends nodes to a target projection place. Nodes to insert were previously re-distribution and
* stored on a component host level.
* @param lView A LView where nodes are inserted (target LView)
* @param tProjectionNode A projection node where previously re-distribution should be appended
* (target insertion place)
* @param selectorIndex A bucket from where nodes to project should be taken
* @param componentView A where projectable nodes were initially created (source view)
*/
export function appendProjectedNodes(lView, tProjectionNode, selectorIndex, componentView) {
var projectedView = componentView[PARENT];
var componentNode = componentView[T_HOST];
var nodeToProject = componentNode.projection[selectorIndex];
if (Array.isArray(nodeToProject)) {
appendChild(nodeToProject, tProjectionNode, lView);
}
else {
while (nodeToProject) {
if (!(nodeToProject.flags & 32 /* isDetached */)) {
if (nodeToProject.type === 1 /* Projection */) {
appendProjectedNodes(lView, tProjectionNode, nodeToProject.projection, findComponentView(projectedView));
}
else {
// This flag must be set now or we won't know that this node is projected
// if the nodes are inserted into a container later.
nodeToProject.flags |= 2 /* isProjected */;
appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView);
}
}
nodeToProject = nodeToProject.projectionNext;
}
}
}
/**
* Loops over all children of a TNode container and appends them to the DOM
*
* @param ngContainerChildTNode The first child of the TNode container
* @param tProjectionNode The projection (ng-content) TNode
* @param currentView Current LView
* @param projectionView Projection view (view above current)
*/
function appendProjectedChildren(ngContainerChildTNode, tProjectionNode, currentView, projectionView) {
while (ngContainerChildTNode) {
appendProjectedNode(ngContainerChildTNode, tProjectionNode, currentView, projectionView);
ngContainerChildTNode = ngContainerChildTNode.next;
}
}
/**
* Appends a projected node to the DOM, or in the case of a projected container,
* appends the nodes from all of the container's active views to the DOM.
*
* @param projectedTNode The TNode to be projected
* @param tProjectionNode The projection (ng-content) TNode
* @param currentView Current LView
* @param projectionView Projection view (view above current)
*/
function appendProjectedNode(projectedTNode, tProjectionNode, currentView, projectionView) {
var native = getNativeByTNode(projectedTNode, projectionView);
appendChild(native, tProjectionNode, currentView);
// the projected contents are processed while in the shadow view (which is the currentView)
// therefore we need to extract the view where the host element lives since it's the
// logical container of the content projected views
attachPatchData(native, projectionView);
var nodeOrContainer = projectionView[projectedTNode.index];
if (projectedTNode.type === 0 /* Container */) {
// The node we are adding is a container and we are adding it to an element which
// is not a component (no more re-projection).
// Alternatively a container is projected at the root of a component's template
// and can't be re-projected (as not content of any component).
// Assign the final projection location in those cases.
for (var i = CONTAINER_HEADER_OFFSET; i < nodeOrContainer.length; i++) {
addRemoveViewFromContainer(nodeOrContainer[i], true, nodeOrContainer[NATIVE]);
}
}
else if (projectedTNode.type === 5 /* IcuContainer */) {
// The node we are adding is an ICU container which is why we also need to project all the
// children nodes that might have been created previously and are linked to this anchor
var ngContainerChildTNode = projectedTNode.child;
appendProjectedChildren(ngContainerChildTNode, ngContainerChildTNode, projectionView, projectionView);
}
else {
if (projectedTNode.type === 4 /* ElementContainer */) {
appendProjectedChildren(projectedTNode.child, tProjectionNode, currentView, projectionView);
}
if (isLContainer(nodeOrContainer)) {
appendChild(nodeOrContainer[NATIVE], tProjectionNode, currentView);
}
}
}
/**
* `executeActionOnView` performs an operation on the view as specified in `action` (insert, detach,
* destroy)
*
* Inserting a view without projection or containers at top level is simple. Just iterate over the
* root nodes of the View, and for each node perform the `action`.
*
* Things get more complicated with containers and projections. That is because coming across:
* - Container: implies that we have to insert/remove/destroy the views of that container as well
* which in turn can have their own Containers at the View roots.
* - Projection: implies that we have to insert/remove/destroy the nodes of the projection. The
* complication is that the nodes we are projecting can themselves have Containers
* or other Projections.
*
* As you can see this is a very recursive problem. While the recursive implementation is not the
* most efficient one, trying to unroll the nodes non-recursively results in very complex code that
* is very hard (to maintain). We are sacrificing a bit of performance for readability using a
* recursive implementation.
*
* @param renderer Renderer to use
* @param action action to perform (insert, detach, destroy)
* @param lView The LView which needs to be inserted, detached, destroyed.
* @param renderParent parent DOM element for insertion/removal.
* @param beforeNode Before which node the insertions should happen.
*/
function executeActionOnView(renderer, action, lView, renderParent, beforeNode) {
var tView = lView[TVIEW];
ngDevMode && assertNodeType(tView.node, 2 /* View */);
var viewRootTNode = tView.node.child;
while (viewRootTNode !== null) {
executeActionOnNode(renderer, action, lView, viewRootTNode, renderParent, beforeNode);
viewRootTNode = viewRootTNode.next;
}
}
/**
* `executeActionOnProjection` performs an operation on the projection specified by `action`
* (insert, detach, destroy).
*
* Inserting a projection requires us to locate the projected nodes from the parent component. The
* complication is that those nodes themselves could be re-projected from their parent component.
*
* @param renderer Renderer to use
* @param action action to perform (insert, detach, destroy)
* @param lView The LView which needs to be inserted, detached, destroyed.
* @param renderParent parent DOM element for insertion/removal.
* @param beforeNode Before which node the insertions should happen.
*/
function executeActionOnProjection(renderer, action, lView, tProjectionNode, renderParent, beforeNode) {
var componentLView = findComponentView(lView);
var componentNode = componentLView[T_HOST];
var nodeToProject = componentNode.projection[tProjectionNode.projection];
if (Array.isArray(nodeToProject)) {
for (var i = 0; i < nodeToProject.length; i++) {
var rNode = nodeToProject[i];
ngDevMode && assertDomNode(rNode);
executeActionOnElementOrContainer(action, renderer, renderParent, rNode, beforeNode);
}
}
else {
var projectionTNode = nodeToProject;
var projectedComponentLView = componentLView[PARENT];
while (projectionTNode !== null) {
executeActionOnNode(renderer, action, projectedComponentLView, projectionTNode, renderParent, beforeNode);
projectionTNode = projectionTNode.projectionNext;
}
}
}
/**
* `executeActionOnContainer` performs an operation on the container and its views as specified by
* `action` (insert, detach, destroy)
*
* Inserting a Container is complicated by the fact that the container may have Views which
* themselves have containers or projections.
*
* @param renderer Renderer to use
* @param action action to perform (insert, detach, destroy)
* @param lContainer The LContainer which needs to be inserted, detached, destroyed.
* @param renderParent parent DOM element for insertion/removal.
* @param beforeNode Before which node the insertions should happen.
*/
function executeActionOnContainer(renderer, action, lContainer, renderParent, beforeNode) {
ngDevMode && assertLContainer(lContainer);
var anchor = lContainer[NATIVE]; // LContainer has its own before node.
var native = unwrapRNode(lContainer);
// An LContainer can be created dynamically on any node by injecting ViewContainerRef.
// Asking for a ViewContainerRef on an element will result in a creation of a separate anchor node
// (comment in the DOM) that will be different from the LContainer's host node. In this particular
// case we need to execute action on 2 nodes:
// - container's host node (this is done in the executeNodeAction)
// - container's host node (this is done here)
if (anchor !== native) {
executeActionOnElementOrContainer(action, renderer, renderParent, anchor, beforeNode);
}
for (var i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
var lView = lContainer[i];
executeActionOnView(renderer, action, lView, renderParent, anchor);
}
}
/**
* `executeActionOnElementContainer` performs an operation on the ng-container node and its child
* nodes as specified by the `action` (insert, detach, destroy).
*
* @param renderer Renderer to use
* @param action action to perform (insert, detach, destroy)
* @param lView The LView which needs to be inserted, detached, destroyed.
* @param tElementContainerNode The TNode associated with the ElementContainer.
* @param renderParent parent DOM element for insertion/removal.
* @param beforeNode Before which node the insertions should happen.
*/
function executeActionOnElementContainer(renderer, action, lView, tElementContainerNode, renderParent, beforeNode) {
var node = lView[tElementContainerNode.index];
executeActionOnElementOrContainer(action, renderer, renderParent, node, beforeNode);
var childTNode = tElementContainerNode.child;
while (childTNode) {
executeActionOnNode(renderer, action, lView, childTNode, renderParent, beforeNode);
childTNode = childTNode.next;
}
}
function executeActionOnNode(renderer, action, lView, tNode, renderParent, beforeNode) {
var elementContainerRootTNodeType = tNode.type;
if (elementContainerRootTNodeType === 4 /* ElementContainer */) {
executeActionOnElementContainer(renderer, action, lView, tNode, renderParent, beforeNode);
}
else if (elementContainerRootTNodeType === 1 /* Projection */) {
executeActionOnProjection(renderer, action, lView, tNode, renderParent, beforeNode);
}
else {
ngDevMode && assertNodeOfPossibleTypes(tNode, 3 /* Element */, 0 /* Container */);
executeActionOnElementOrContainer(action, renderer, renderParent, lView[tNode.index], beforeNode);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9tYW5pcHVsYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3NyYy9yZW5kZXIzL25vZGVfbWFuaXB1bGF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRzs7QUFFSCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQztBQUNuRCxPQUFPLEVBQUMsYUFBYSxFQUFFLGFBQWEsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBRTVELE9BQU8sRUFBQyxnQkFBZ0IsRUFBRSxXQUFXLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDdkQsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQ3BELE9BQU8sRUFBQyx1QkFBdUIsRUFBYyxNQUFNLEVBQUUsNkJBQTZCLElBQUksT0FBTyxFQUFDLE1BQU0sd0JBQXdCLENBQUM7QUFFN0gsT0FBTyxFQUFDLG1CQUFtQixFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFDMUQsT0FBTyxFQUFnRyw2QkFBNkIsSUFBSSxPQUFPLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUMxSyxPQUFPLEVBQUMsNkJBQTZCLElBQUksT0FBTyxFQUFDLE1BQU0seUJBQXlCLENBQUM7QUFDakYsT0FBTyxFQUF5RCxvQkFBb0IsRUFBRSw2QkFBNkIsSUFBSSxPQUFPLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUU3SixPQUFPLEVBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUErQixJQUFJLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSw2QkFBNkIsSUFBSSxPQUFPLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUMxTCxPQUFPLEVBQUMseUJBQXlCLEVBQUUsY0FBYyxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQ3hFLE9B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