@angular/core
Version:
Angular - the core framework
965 lines • 118 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @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 { 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';
/** @type {?} */
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
/**
* @param {?} tNode
* @param {?} embeddedView
* @return {?}
*/
export function getLContainer(tNode, embeddedView) {
ngDevMode && assertLView(embeddedView);
/** @type {?} */
const container = (/** @type {?} */ (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.
* @param {?} tViewNode
* @param {?} view
* @return {?}
*/
function getContainerRenderParent(tViewNode, view) {
/** @type {?} */
const container = getLContainer(tViewNode, view);
return container ? nativeParentNode(view[RENDERER], container[NATIVE]) : null;
}
/** @enum {number} */
const WalkTNodeTreeAction = {
/** node insert in the native environment */
Insert: 0,
/** node detach from the native environment */
Detach: 1,
/** node destruction using the renderer's API */
Destroy: 2,
};
/**
* NOTE: for performance reasons, the possible actions are inlined within the function instead of
* being passed as an argument.
* @param {?} action
* @param {?} renderer
* @param {?} parent
* @param {?} lNodeToHandle
* @param {?=} beforeNode
* @return {?}
*/
function executeActionOnElementOrContainer(action, renderer, parent, lNodeToHandle, beforeNode) {
ngDevMode && assertDefined(lNodeToHandle, '\'lNodeToHandle\' is undefined');
/** @type {?} */
let lContainer;
/** @type {?} */
let 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 = (/** @type {?} */ (lNodeToHandle[HOST]));
}
/** @type {?} */
const rNode = unwrapRNode(lNodeToHandle);
ngDevMode && assertDomNode(rNode);
if (action === 0 /* Insert */) {
nativeInsertBefore(renderer, (/** @type {?} */ (parent)), rNode, beforeNode || null);
}
else if (action === 1 /* Detach */) {
nativeRemoveNode(renderer, rNode, isComponent);
}
else if (action === 2 /* Destroy */) {
ngDevMode && ngDevMode.rendererDestroyNode++;
(/** @type {?} */ (((/** @type {?} */ (renderer))).destroyNode))(rNode);
}
if (lContainer != null) {
executeActionOnContainer(renderer, action, lContainer, parent, beforeNode);
}
}
/**
* @param {?} value
* @param {?} renderer
* @return {?}
*/
export function createTextNode(value, renderer) {
return isProceduralRenderer(renderer) ? renderer.createText(renderStringify(value)) :
renderer.createTextNode(renderStringify(value));
}
/**
* @param {?} lView
* @param {?} insertMode
* @param {?=} beforeNode
* @return {?}
*/
export function addRemoveViewFromContainer(lView, insertMode, beforeNode) {
/** @type {?} */
const renderParent = getContainerRenderParent((/** @type {?} */ (lView[TVIEW].node)), lView);
ngDevMode && assertNodeType((/** @type {?} */ (lView[TVIEW].node)), 2 /* View */);
if (renderParent) {
/** @type {?} */
const renderer = lView[RENDERER];
/** @type {?} */
const 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.
* @return {?}
*/
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
* @return {?}
*/
export function destroyViewTree(rootView) {
// If the view has no children, we can clean it up and return early.
/** @type {?} */
let lViewOrLContainer = rootView[CHILD_HEAD];
if (!lViewOrLContainer) {
return cleanUpView(rootView);
}
while (lViewOrLContainer) {
/** @type {?} */
let 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.
/** @type {?} */
const 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 && !(/** @type {?} */ (lViewOrLContainer))[NEXT] && lViewOrLContainer !== rootView) {
cleanUpView(lViewOrLContainer);
lViewOrLContainer = getParentState(lViewOrLContainer, rootView);
}
cleanUpView(lViewOrLContainer || rootView);
next = lViewOrLContainer && (/** @type {?} */ (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
* @return {?}
*/
export function insertView(lView, lContainer, index) {
ngDevMode && assertLView(lView);
ngDevMode && assertLContainer(lContainer);
/** @type {?} */
const indexInContainer = CONTAINER_HEADER_OFFSET + index;
/** @type {?} */
const 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]) {
(/** @type {?} */ (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
* @return {?} Detached LView instance.
*/
export function detachView(lContainer, removeIndex) {
if (lContainer.length <= CONTAINER_HEADER_OFFSET)
return;
/** @type {?} */
const indexInContainer = CONTAINER_HEADER_OFFSET + removeIndex;
/** @type {?} */
const viewToDetach = lContainer[indexInContainer];
if (viewToDetach) {
if (removeIndex > 0) {
lContainer[indexInContainer - 1][NEXT] = (/** @type {?} */ (viewToDetach[NEXT]));
}
lContainer.splice(CONTAINER_HEADER_OFFSET + removeIndex, 1);
addRemoveViewFromContainer(viewToDetach, false);
if ((viewToDetach[FLAGS] & 128 /* Attached */) &&
!(viewToDetach[FLAGS] & 256 /* Destroyed */) && viewToDetach[QUERIES]) {
(/** @type {?} */ (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
* @return {?}
*/
export function removeView(lContainer, removeIndex) {
/** @type {?} */
const 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.
* @return {?}
*/
export function destroyLView(lView) {
if (!(lView[FLAGS] & 256 /* Destroyed */)) {
/** @type {?} */
const 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
* @return {?} The correct parent LViewOrLContainer
*/
export function getParentState(lViewOrLContainer, rootView) {
/** @type {?} */
let 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((/** @type {?} */ (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
* @return {?}
*/
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);
/** @type {?} */
const 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++;
((/** @type {?} */ (view[RENDERER]))).destroy();
}
// For embedded views still attached to a container: remove query result from this view.
if (viewAttachedToContainer(view) && view[QUERIES]) {
(/** @type {?} */ (view[QUERIES])).removeView();
}
}
}
/**
* Removes listeners and unsubscribes from output subscriptions
* @param {?} lView
* @return {?}
*/
function removeListeners(lView) {
/** @type {?} */
const tCleanup = lView[TVIEW].cleanup;
if (tCleanup !== null) {
/** @type {?} */
const lCleanup = (/** @type {?} */ (lView[CLEANUP]));
for (let i = 0; i < tCleanup.length - 1; i += 2) {
if (typeof tCleanup[i] === 'string') {
// This is a native DOM listener
/** @type {?} */
const idxOrTargetGetter = tCleanup[i + 1];
/** @type {?} */
const target = typeof idxOrTargetGetter === 'function' ?
idxOrTargetGetter(lView) :
unwrapRNode(lView[idxOrTargetGetter]);
/** @type {?} */
const listener = lCleanup[tCleanup[i + 2]];
/** @type {?} */
const 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
/** @type {?} */
const context = lCleanup[tCleanup[i + 1]];
tCleanup[i].call(context);
}
}
lView[CLEANUP] = null;
}
}
/**
* Calls onDestroy hooks for this view
* @param {?} view
* @return {?}
*/
function executeOnDestroys(view) {
/** @type {?} */
const tView = view[TVIEW];
/** @type {?} */
let destroyHooks;
if (tView != null && (destroyHooks = tView.destroyHooks) != null) {
for (let i = 0; i < destroyHooks.length; i += 2) {
/** @type {?} */
const context = view[(/** @type {?} */ (destroyHooks[i]))];
// Only call the destroy hook if the context has been requested.
if (!(context instanceof NodeInjectorFactory)) {
((/** @type {?} */ (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.
* @param {?} tNode
* @param {?} currentView
* @return {?}
*/
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.
/** @type {?} */
const parent = getHighestElementOrICUContainer(tNode);
/** @type {?} */
const 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) {
/** @type {?} */
const hostTNode = (/** @type {?} */ (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((/** @type {?} */ (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 {
/** @type {?} */
const 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 (/** @type {?} */ (getNativeByTNode(parent, currentView).parentNode));
}
ngDevMode && assertNodeType(renderParent, 3 /* Element */);
if (renderParent.flags & 1 /* isComponent */ && !isIcuCase) {
/** @type {?} */
const tData = currentView[TVIEW].data;
/** @type {?} */
const tNode = (/** @type {?} */ (tData[renderParent.index]));
/** @type {?} */
const encapsulation = ((/** @type {?} */ (tData[tNode.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 (/** @type {?} */ (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.
* @param {?} currentView
* @return {?}
*/
function getHostNative(currentView) {
ngDevMode && assertLView(currentView);
/** @type {?} */
const hostTNode = currentView[T_HOST];
return hostTNode && hostTNode.type === 3 /* Element */ ?
((/** @type {?} */ (getNativeByTNode(hostTNode, (/** @type {?} */ (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.
* @param {?} renderer
* @param {?} parent
* @param {?} child
* @param {?} beforeNode
* @return {?}
*/
export function nativeInsertBefore(renderer, parent, child, beforeNode) {
ngDevMode && ngDevMode.rendererInsertBefore++;
if (isProceduralRenderer(renderer)) {
renderer.insertBefore(parent, child, beforeNode);
}
else {
parent.insertBefore(child, beforeNode, true);
}
}
/**
* @param {?} renderer
* @param {?} parent
* @param {?} child
* @return {?}
*/
function nativeAppendChild(renderer, parent, child) {
ngDevMode && ngDevMode.rendererAppendChild++;
if (isProceduralRenderer(renderer)) {
renderer.appendChild(parent, child);
}
else {
parent.appendChild(child);
}
}
/**
* @param {?} renderer
* @param {?} parent
* @param {?} child
* @param {?} beforeNode
* @return {?}
*/
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.
* @param {?} renderer
* @param {?} parent
* @param {?} child
* @param {?=} isHostElement
* @return {?}
*/
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.
* @param {?} renderer
* @param {?} node
* @return {?}
*/
export function nativeParentNode(renderer, node) {
return (/** @type {?} */ ((isProceduralRenderer(renderer) ? renderer.parentNode(node) : node.parentNode)));
}
/**
* Returns a native sibling of a given native node.
* @param {?} renderer
* @param {?} node
* @return {?}
*/
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
* @return {?}
*/
function getNativeAnchorNode(parentTNode, lView) {
if (parentTNode.type === 2 /* View */) {
/** @type {?} */
const lContainer = (/** @type {?} */ (getLContainer((/** @type {?} */ (parentTNode)), lView)));
/** @type {?} */
const 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
* @return {?} Whether or not the child was appended
*/
export function appendChild(childEl, childTNode, currentView) {
/** @type {?} */
const renderParent = getRenderParent(childTNode, currentView);
if (renderParent != null) {
/** @type {?} */
const renderer = currentView[RENDERER];
/** @type {?} */
const parentTNode = childTNode.parent || (/** @type {?} */ (currentView[T_HOST]));
/** @type {?} */
const anchorNode = getNativeAnchorNode(parentTNode, currentView);
if (Array.isArray(childEl)) {
for (let nativeNode of childEl) {
nativeAppendOrInsertBefore(renderer, renderParent, nativeNode, anchorNode);
}
}
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
* @return {?} 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;
}
/**
* @param {?} viewIndexInContainer
* @param {?} lContainer
* @return {?}
*/
export function getBeforeNodeForView(viewIndexInContainer, lContainer) {
/** @type {?} */
const nextViewIndex = CONTAINER_HEADER_OFFSET + viewIndexInContainer + 1;
if (nextViewIndex < lContainer.length) {
/** @type {?} */
const lView = (/** @type {?} */ (lContainer[nextViewIndex]));
ngDevMode && assertDefined(lView[T_HOST], 'Missing Host TNode');
/** @type {?} */
const tViewNodeChild = ((/** @type {?} */ (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.
* @return {?}
*/
export function nativeRemoveNode(renderer, rNode, isHostElement) {
/** @type {?} */
const 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)
* @return {?}
*/
export function appendProjectedNodes(lView, tProjectionNode, selectorIndex, componentView) {
/** @type {?} */
const projectedView = (/** @type {?} */ ((/** @type {?} */ (componentView[PARENT]))));
/** @type {?} */
const componentNode = (/** @type {?} */ (componentView[T_HOST]));
/** @type {?} */
let nodeToProject = ((/** @type {?} */ (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, ((/** @type {?} */ (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)
* @return {?}
*/
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)
* @return {?}
*/
function appendProjectedNode(projectedTNode, tProjectionNode, currentView, projectionView) {
/** @type {?} */
const 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);
/** @type {?} */
const 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 (let 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
/** @type {?} */
let ngContainerChildTNode = (/** @type {?} */ (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.
* @return {?}
*/
function executeActionOnView(renderer, action, lView, renderParent, beforeNode) {
/** @type {?} */
const tView = lView[TVIEW];
ngDevMode && assertNodeType((/** @type {?} */ (tView.node)), 2 /* View */);
/** @type {?} */
let viewRootTNode = (/** @type {?} */ (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 {?} tProjectionNode
* @param {?} renderParent parent DOM element for insertion/removal.
* @param {?} beforeNode Before which node the insertions should happen.
* @return {?}
*/
function executeActionOnProjection(renderer, action, lView, tProjectionNode, renderParent, beforeNode) {
/** @type {?} */
const componentLView = findComponentView(lView);
/** @type {?} */
const componentNode = (/** @type {?} */ (componentLView[T_HOST]));
/** @type {?} */
const nodeToProject = (/** @type {?} */ ((/** @type {?} */ (componentNode.projection))[tProjectionNode.projection]));
if (Array.isArray(nodeToProject)) {
for (let i = 0; i < nodeToProject.length; i++) {
/** @type {?} */
const rNode = nodeToProject[i];
ngDevMode && assertDomNode(rNode);
executeActionOnElementOrContainer(action, renderer, renderParent, rNode, beforeNode);
}
}
else {
/** @type {?} */
let projectionTNode = nodeToProject;
/** @type {?} */
const projectedComponentLView = (/** @type {?} */ (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.
* @return {?}
*/
function executeActionOnContainer(renderer, action, lContainer, renderParent, beforeNode) {
ngDevMode && assertLContainer(lContainer);
/** @type {?} */
const anchor = lContainer[NATIVE];
// LContainer has its own before node.
/** @type {?} */
const 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 (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
/** @type {?} */
const lView = (/** @type {?} */ (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.
* @return {?}
*/
function executeActionOnElementContainer(renderer, action, lView, tElementContainerNode, renderParent, beforeNode) {
/** @type {?} */
const node = lView[tElementContainerNode.index];
executeActionOnElementOrContainer(action, renderer, renderParent, node, beforeNode);
/** @type {?} */
let childTNode = tElementContainerNode.child;
while (childTNode) {
executeActionOnNode(renderer, action, lView, childTNode, renderParent, beforeNode);
childTNode = childTNode.next;
}
}
/**
* @param {?} renderer
* @param {?} action
* @param {?} lView
* @param {?} tNode
* @param {?} renderParent
* @param {?} beforeNode
* @return {?}
*/
function executeActionOnNode(renderer, action, lView, tNode, renderParent, beforeNode) {
/** @type {?} */
const elementContainerRootTNodeType = tNode.type;
if (elementContainerRootTNodeType === 4 /* ElementContainer */) {
executeActionOnElementContainer(renderer, action, lView, (/** @type {?} */ (tNode)), renderParent, beforeNode);
}
else if (elementContainerRootTNodeType === 1 /* Projection */) {
executeActionOnProjection(renderer, action, lView, (/** @type {?} */ (tNode)), renderParent, beforeNode);
}
else {
ngDevMode && assertNodeOfPossibleTypes(tNode, 3 /* Element */, 0 /* Container */);
executeActionOnElementOrContainer(action, renderer, renderParent, lView[tNode.index], beforeNode);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9tYW5pcHVsYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3NyYy9yZW5kZXIzL25vZGVfbWFuaXB1bGF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBUUEsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sa0JBQWtCLENBQUM7QUFDbkQsT0FBTyxFQUFDLGFBQWEsRUFBRSxhQUFhLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUU1RCxPQUFPLEVBQUMsZ0JBQWdCLEVBQUUsV0FBVyxFQUFDLE1BQU0sVUFBVSxDQUFDO0FBQ3ZELE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUNwRCxPQUFPLEVBQUMsdUJBQXVCLEVBQWMsTUFBTSxFQUFFLDZCQUE2QixJQUFJLE9BQU8sRUFBQyxNQUFNLHdCQUF3QixDQUFDO0FBRTdILE9BQU8sRUFBQyxtQkFBbUIsRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBQzFELE9BQU8sRUFBZ0csNkJBQTZCLElBQUksT0FBTyxFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFDMUssT0FBTyxFQUFDLDZCQUE2QixJQUFJLE9BQU8sRUFBQyxNQUFNLHlCQUF5QixDQUFDO0FBQ2pGLE9BQU8sRUFBeUQsb0JBQW9CLEVBQUUsNkJBQTZCLElBQUksT0FBTyxFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFFN0osT0FBTyxFQUFDLFVBQVUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBK0IsSUFBSSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsNkJBQTZCLElBQUksT0FBTyxFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFDMUwsT0FBTyxFQUFDLHlCQUF5QixFQUFFLGNBQWMsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUN4RSxPQUFPLEVBQUMsZUFBZSxF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