diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 3addbc8234..70c1696bc4 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -262,7 +262,7 @@ export {getModuleFactory__POST_R3__ as ɵgetModuleFactory__POST_R3__} from './li export { publishGlobalUtil as ɵpublishGlobalUtil, publishDefaultGlobalUtils as ɵpublishDefaultGlobalUtils -} from './render3/global_utils'; +} from './render3/util/global_utils'; export {createInjector as ɵcreateInjector} from './di/r3_injector'; diff --git a/packages/core/src/debug/debug_node.ts b/packages/core/src/debug/debug_node.ts index 0a8dd3636d..2317d315f0 100644 --- a/packages/core/src/debug/debug_node.ts +++ b/packages/core/src/debug/debug_node.ts @@ -7,13 +7,14 @@ */ import {Injector} from '../di'; -import {getComponent, getContext, getInjectionTokens, getInjector, getListeners, getLocalRefs, getViewComponent, isBrowserEvents, loadLContext, loadLContextFromNode} from '../render3/discovery_utils'; +import {getViewComponent} from '../render3/global_utils_api'; import {TNode} from '../render3/interfaces/node'; import {StylingIndex} from '../render3/interfaces/styling'; import {LView, TData, TVIEW} from '../render3/interfaces/view'; import {getProp, getValue, isClassBasedValue} from '../render3/styling/class_and_style_bindings'; import {getStylingContext} from '../render3/styling/util'; -import {INTERPOLATION_DELIMITER, isPropMetadataString, renderStringify} from '../render3/util'; +import {getComponent, getContext, getInjectionTokens, getInjector, getListeners, getLocalRefs, isBrowserEvents, loadLContext, loadLContextFromNode} from '../render3/util/discovery_utils'; +import {INTERPOLATION_DELIMITER, isPropMetadataString, renderStringify} from '../render3/util/misc_utils'; import {assertDomNode} from '../util/assert'; import {DebugContext} from '../view/index'; diff --git a/packages/core/src/render3/assert.ts b/packages/core/src/render3/assert.ts index 1547afac00..8dc9d23802 100644 --- a/packages/core/src/render3/assert.ts +++ b/packages/core/src/render3/assert.ts @@ -11,7 +11,7 @@ import {assertDefined, assertEqual, throwError} from '../util/assert'; import {getComponentDef, getNgModuleDef} from './definition'; import {TNode} from './interfaces/node'; import {LView} from './interfaces/view'; -import {isLContainer, isLView} from './util'; +import {isLContainer, isLView} from './util/view_utils'; export function assertComponentType( diff --git a/packages/core/src/render3/bindings.ts b/packages/core/src/render3/bindings.ts index f46d21ab2a..c3a105ae3b 100644 --- a/packages/core/src/render3/bindings.ts +++ b/packages/core/src/render3/bindings.ts @@ -12,7 +12,7 @@ import {throwErrorIfNoChangesMode} from './errors'; import {LView} from './interfaces/view'; import {getCheckNoChangesMode} from './state'; import {NO_CHANGE} from './tokens'; -import {isDifferent} from './util'; +import {isDifferent} from './util/misc_utils'; diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 087516d321..a784d1ebca 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -16,7 +16,6 @@ import {assertDefined} from '../util/assert'; import {assertComponentType} from './assert'; import {getComponentDef} from './definition'; import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di'; -import {publishDefaultGlobalUtils} from './global_utils'; import {registerPostOrderHooks, registerPreOrderHooks} from './hooks'; import {CLEAN_PROMISE, addToViewTree, createLView, createNodeAtIndex, createTView, getOrCreateTView, initNodeFlags, instantiateRootComponent, invokeHostBindingsInCreationMode, locateHostElement, queueComponentIndexForCheck, refreshDescendantViews} from './instructions'; import {ComponentDef, ComponentType, RenderFlags} from './interfaces/definition'; @@ -24,8 +23,12 @@ import {TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node'; import {PlayerHandler} from './interfaces/player'; import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; import {CONTEXT, FLAGS, HEADER_OFFSET, LView, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view'; +import {applyOnCreateInstructions} from './node_util'; import {enterView, getPreviousOrParentTNode, leaveView, resetComponentState, setCurrentDirectiveDef} from './state'; -import {applyOnCreateInstructions, defaultScheduler, getRootView, readPatchedLView, renderStringify} from './util'; +import {publishDefaultGlobalUtils} from './util/global_utils'; +import {defaultScheduler, renderStringify} from './util/misc_utils'; +import {getRootContext, getRootView} from './util/view_traversal_utils'; +import {readPatchedLView} from './util/view_utils'; @@ -245,19 +248,6 @@ export function LifecycleHooksFeature(component: any, def: ComponentDef): v rootTView, { directiveStart: dirIndex, directiveEnd: dirIndex + 1 } as TNode); } -/** - * Retrieve the root context for any component by walking the parent `LView` until - * reaching the root `LView`. - * - * @param component any component - */ -function getRootContext(component: any): RootContext { - const rootContext = getRootView(component)[CONTEXT] as RootContext; - ngDevMode && assertDefined(rootContext, 'rootContext'); - return rootContext; -} - - /** * Wait on component until it is rendered. * diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index ee81969b3e..3938a6c16c 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -32,7 +32,8 @@ import {TContainerNode, TElementContainerNode, TElementNode} from './interfaces/ import {RNode, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer'; import {HEADER_OFFSET, LView, LViewFlags, RootContext, TVIEW} from './interfaces/view'; import {enterView, leaveView} from './state'; -import {defaultScheduler, getTNode} from './util'; +import {defaultScheduler} from './util/misc_utils'; +import {getTNode} from './util/view_utils'; import {createElementRef} from './view_engine_compatibility'; import {RootViewRef, ViewRef} from './view_ref'; diff --git a/packages/core/src/render3/context_discovery.ts b/packages/core/src/render3/context_discovery.ts index 3a69d2f6a9..acaff2267e 100644 --- a/packages/core/src/render3/context_discovery.ts +++ b/packages/core/src/render3/context_discovery.ts @@ -6,13 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ import '../util/ng_dev_mode'; + import {assertDomNode} from '../util/assert'; + import {EMPTY_ARRAY} from './empty'; import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; import {TNode, TNodeFlags} from './interfaces/node'; import {RElement} from './interfaces/renderer'; import {CONTEXT, HEADER_OFFSET, HOST, LView, TVIEW} from './interfaces/view'; -import {getComponentViewByIndex, getNativeByTNode, readElementValue, readPatchedData} from './util'; +import {getComponentViewByIndex, getNativeByTNode, readElementValue, readPatchedData} from './util/view_utils'; diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 981a9952c7..6d94a78756 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -21,7 +21,10 @@ import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TN import {DECLARATION_VIEW, INJECTOR, LView, TData, TVIEW, TView, T_HOST} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; import {getLView, getPreviousOrParentTNode, setTNodeAndViewData} from './state'; -import {findComponentView, getParentInjectorIndex, getParentInjectorView, hasParentInjector, isComponent, isComponentDef, renderStringify} from './util'; +import {getParentInjectorIndex, getParentInjectorView, hasParentInjector} from './util/injector_utils'; +import {renderStringify} from './util/misc_utils'; +import {findComponentView} from './util/view_traversal_utils'; +import {isComponent, isComponentDef} from './util/view_utils'; diff --git a/packages/core/src/render3/di_setup.ts b/packages/core/src/render3/di_setup.ts index 15286a4b77..5956beb39a 100644 --- a/packages/core/src/render3/di_setup.ts +++ b/packages/core/src/render3/di_setup.ts @@ -18,7 +18,7 @@ import {NodeInjectorFactory} from './interfaces/injector'; import {TContainerNode, TElementContainerNode, TElementNode, TNodeFlags, TNodeProviderIndexes} from './interfaces/node'; import {LView, TData, TVIEW, TView} from './interfaces/view'; import {getLView, getPreviousOrParentTNode} from './state'; -import {isComponentDef} from './util'; +import {isComponentDef} from './util/view_utils'; diff --git a/packages/core/src/render3/features/inherit_definition_feature.ts b/packages/core/src/render3/features/inherit_definition_feature.ts index 2b26a20846..201e78302b 100644 --- a/packages/core/src/render3/features/inherit_definition_feature.ts +++ b/packages/core/src/render3/features/inherit_definition_feature.ts @@ -10,7 +10,7 @@ import {Type} from '../../interface/type'; import {fillProperties} from '../../util/property'; import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty'; import {ComponentDef, DirectiveDef, DirectiveDefFeature, RenderFlags} from '../interfaces/definition'; -import {isComponentDef} from '../util'; +import {isComponentDef} from '../util/view_utils'; import {NgOnChangesFeature} from './ng_onchanges_feature'; diff --git a/packages/core/src/render3/global_utils_api.ts b/packages/core/src/render3/global_utils_api.ts index 1279e05f83..33ec54e78b 100644 --- a/packages/core/src/render3/global_utils_api.ts +++ b/packages/core/src/render3/global_utils_api.ts @@ -15,6 +15,6 @@ * file in the public_api_guard test. */ -export {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getRootComponents, getViewComponent} from './discovery_utils'; export {markDirty} from './instructions'; export {getPlayers} from './players'; +export {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getRootComponents, getViewComponent} from './util/discovery_utils'; diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index 81986abcee..3349450dce 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -22,7 +22,9 @@ import {BINDING_INDEX, HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST} fro import {appendChild, createTextNode, nativeRemoveNode} from './node_manipulation'; import {getIsParent, getLView, getPreviousOrParentTNode, setIsParent, setPreviousOrParentTNode} from './state'; import {NO_CHANGE} from './tokens'; -import {addAllToArray, getNativeByIndex, getNativeByTNode, getTNode, isLContainer, renderStringify} from './util'; +import {addAllToArray} from './util/array_utils'; +import {renderStringify} from './util/misc_utils'; +import {getNativeByIndex, getNativeByTNode, getTNode, isLContainer} from './util/view_utils'; const MARKER = `�`; const ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/; diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 5e76b64721..d6a2faa716 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -7,11 +7,11 @@ */ import {LifecycleHooksFeature, renderComponent, whenRendered} from './component'; import {defineBase, defineComponent, defineDirective, defineNgModule, definePipe, setComponentScope} from './definition'; -import {getComponent, getDirectives, getHostElement, getRenderedText} from './discovery_utils'; import {InheritDefinitionFeature} from './features/inherit_definition_feature'; import {NgOnChangesFeature} from './features/ng_onchanges_feature'; import {ProvidersFeature} from './features/providers_feature'; import {BaseDef, ComponentDef, ComponentDefWithMeta, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveDefWithMeta, DirectiveType, PipeDef, PipeDefWithMeta} from './interfaces/definition'; +import {getComponent, getDirectives, getHostElement, getRenderedText} from './util/discovery_utils'; export {ComponentFactory, ComponentFactoryResolver, ComponentRef, injectComponentFactoryResolver} from './component_ref'; export {getFactoryOf, getInheritedFactory} from './di'; @@ -19,6 +19,7 @@ export {RenderFlags} from './interfaces/definition'; export {CssSelectorList} from './interfaces/projection'; + // clang-format off export { allocHostVars, @@ -146,7 +147,7 @@ export { export {templateRefExtractor} from './view_engine_compatibility_prebound'; -export {resolveWindow, resolveDocument, resolveBody} from './util'; +export {resolveWindow, resolveDocument, resolveBody} from './util/misc_utils'; // clang-format on diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 8ed23c6aaf..191260dc02 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -38,12 +38,15 @@ import {BINDING_INDEX, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_VIE import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert'; import {appendChild, appendProjectedNode, createTextNode, insertView, removeView} from './node_manipulation'; import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher'; -import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCurrentDirectiveDef, getElementDepthCount, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, isCreationMode, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setIsParent, setPreviousOrParentTNode,} from './state'; +import {applyOnCreateInstructions} from './node_util'; +import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCurrentDirectiveDef, getElementDepthCount, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, isCreationMode, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setIsParent, setPreviousOrParentTNode} from './state'; import {getInitialClassNameValue, getInitialStyleStringValue, initializeStaticContext as initializeStaticStylingContext, patchContextWithStaticAttrs, renderInitialClasses, renderInitialStyles, renderStyling, updateClassProp as updateElementClassProp, updateContextWithBindings, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings'; import {BoundPlayerFactory} from './styling/player_factory'; import {ANIMATION_PROP_PREFIX, allocateDirectiveIntoContext, createEmptyStylingContext, forceClassesAsString, forceStylesAsString, getStylingContext, hasClassInput, hasStyleInput, hasStyling, isAnimationProp} from './styling/util'; import {NO_CHANGE} from './tokens'; -import {INTERPOLATION_DELIMITER, applyOnCreateInstructions, findComponentView, getComponentViewByIndex, getLViewParent, getNativeByIndex, getNativeByTNode, getRootContext, getRootView, getTNode, isComponent, isComponentDef, isContentQueryHost, isRootView, loadInternal, readElementValue, readPatchedLView, renderStringify} from './util'; +import {INTERPOLATION_DELIMITER, renderStringify} from './util/misc_utils'; +import {findComponentView, getLViewParent, getRootContext, getRootView} from './util/view_traversal_utils'; +import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isComponent, isComponentDef, isContentQueryHost, isRootView, loadInternal, readElementValue, readPatchedLView} from './util/view_utils'; diff --git a/packages/core/src/render3/jit/directive.ts b/packages/core/src/render3/jit/directive.ts index 8a9b96f1e0..f26e338b32 100644 --- a/packages/core/src/render3/jit/directive.ts +++ b/packages/core/src/render3/jit/directive.ts @@ -18,7 +18,7 @@ import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from import {ViewEncapsulation} from '../../metadata/view'; import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty'; import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from '../fields'; -import {renderStringify} from '../util'; +import {renderStringify} from '../util/misc_utils'; import {angularCoreEnv} from './environment'; import {flushModuleScopingQueueAsMuchAsPossible, patchComponentDefWithScope, transitiveScopesFor} from './module'; diff --git a/packages/core/src/render3/jit/module.ts b/packages/core/src/render3/jit/module.ts index 0ef0cc7298..9831537ed6 100644 --- a/packages/core/src/render3/jit/module.ts +++ b/packages/core/src/render3/jit/module.ts @@ -19,7 +19,7 @@ import {getComponentDef, getDirectiveDef, getNgModuleDef, getPipeDef} from '../d import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from '../fields'; import {ComponentDef} from '../interfaces/definition'; import {NgModuleType} from '../ng_module_ref'; -import {renderStringify} from '../util'; +import {renderStringify} from '../util/misc_utils'; import {angularCoreEnv} from './environment'; diff --git a/packages/core/src/render3/jit/pipe.ts b/packages/core/src/render3/jit/pipe.ts index 4319e4a330..bf1ea25e92 100644 --- a/packages/core/src/render3/jit/pipe.ts +++ b/packages/core/src/render3/jit/pipe.ts @@ -11,7 +11,7 @@ import {reflectDependencies} from '../../di/jit/util'; import {Type} from '../../interface/type'; import {Pipe} from '../../metadata/directives'; import {NG_PIPE_DEF} from '../fields'; -import {renderStringify} from '../util'; +import {renderStringify} from '../util/misc_utils'; import {angularCoreEnv} from './environment'; diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index b77cd76de0..21f07e3838 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -19,7 +19,9 @@ import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection' import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; import {CHILD_HEAD, CLEANUP, FLAGS, HEADER_OFFSET, HookData, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, T_HOST, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; import {assertNodeType} from './node_assert'; -import {findComponentView, getLViewParent, getNativeByTNode, isComponent, isLContainer, isLView, isRootView, readElementValue, renderStringify} from './util'; +import {renderStringify} from './util/misc_utils'; +import {findComponentView, getLViewParent} from './util/view_traversal_utils'; +import {getNativeByTNode, isComponent, isLContainer, isLView, isRootView, readElementValue} from './util/view_utils'; const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5; diff --git a/packages/core/src/render3/node_util.ts b/packages/core/src/render3/node_util.ts new file mode 100644 index 0000000000..56ff6889d8 --- /dev/null +++ b/packages/core/src/render3/node_util.ts @@ -0,0 +1,61 @@ +/** + * @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 {RelativeInjectorLocation} from './interfaces/injector'; +import {TContainerNode, TElementNode, TNode} from './interfaces/node'; +import {DECLARATION_VIEW, LView, T_HOST} from './interfaces/view'; +import {getParentInjectorViewOffset} from './util/injector_utils'; + +export function applyOnCreateInstructions(tNode: TNode) { + // there may be some instructions that need to run in a specific + // order because the CREATE block in a directive runs before the + // CREATE block in a template. To work around this instructions + // can get access to the function array below and defer any code + // to run after the element is created. + let fns: Function[]|null; + if (fns = tNode.onElementCreationFns) { + for (let i = 0; i < fns.length; i++) { + fns[i](); + } + tNode.onElementCreationFns = null; + } +} + +/** + * Unwraps a parent injector location number to find the view offset from the current injector, + * then walks up the declaration view tree until the TNode of the parent injector is found. + * + * @param location The location of the parent injector, which contains the view offset + * @param startView The LView instance from which to start walking up the view tree + * @param startTNode The TNode instance of the starting element + * @returns The TNode of the parent injector + */ +export function getParentInjectorTNode( + location: RelativeInjectorLocation, startView: LView, startTNode: TNode): TElementNode| + TContainerNode|null { + if (startTNode.parent && startTNode.parent.injectorIndex !== -1) { + // view offset is 0 + const injectorIndex = startTNode.parent.injectorIndex; + let parentTNode = startTNode.parent; + while (parentTNode.parent != null && injectorIndex == parentTNode.injectorIndex) { + parentTNode = parentTNode.parent; + } + return parentTNode; + } + let viewOffset = getParentInjectorViewOffset(location); + // view offset is 1 + let parentView = startView; + let parentTNode = startView[T_HOST] as TElementNode; + // view offset is superior to 1 + while (viewOffset > 1) { + parentView = parentView[DECLARATION_VIEW] !; + parentTNode = parentView[T_HOST] as TElementNode; + viewOffset--; + } + return parentTNode; +} diff --git a/packages/core/src/render3/players.ts b/packages/core/src/render3/players.ts index a221938d52..97adb5cd11 100644 --- a/packages/core/src/render3/players.ts +++ b/packages/core/src/render3/players.ts @@ -12,7 +12,7 @@ import {scheduleTick} from './instructions'; import {ComponentInstance, DirectiveInstance, Player} from './interfaces/player'; import {RootContextFlags} from './interfaces/view'; import {addPlayerInternal, getOrCreatePlayerContext, getPlayerContext, getPlayersInternal, getStylingContext, throwInvalidRefError} from './styling/util'; -import {getRootContext} from './util'; +import {getRootContext} from './util/view_traversal_utils'; /** * Adds a player to an element, directive or component instance that will later be diff --git a/packages/core/src/render3/styling/class_and_style_bindings.ts b/packages/core/src/render3/styling/class_and_style_bindings.ts index 7c7e559411..85d47fa232 100644 --- a/packages/core/src/render3/styling/class_and_style_bindings.ts +++ b/packages/core/src/render3/styling/class_and_style_bindings.ts @@ -13,7 +13,7 @@ import {RElement, Renderer3, RendererStyleFlags3, isProceduralRenderer} from '.. import {DirectiveOwnerAndPlayerBuilderIndex, DirectiveRegistryValues, DirectiveRegistryValuesIndex, InitialStylingValues, InitialStylingValuesIndex, MapBasedOffsetValues, MapBasedOffsetValuesIndex, SinglePropOffsetValues, SinglePropOffsetValuesIndex, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling'; import {LView, RootContext} from '../interfaces/view'; import {NO_CHANGE} from '../tokens'; -import {getRootContext} from '../util'; +import {getRootContext} from '../util/view_traversal_utils'; import {BoundPlayerFactory} from './player_factory'; import {addPlayerInternal, allocPlayerContext, allocateDirectiveIntoContext, createEmptyStylingContext, getPlayerContext} from './util'; diff --git a/packages/core/src/render3/styling/util.ts b/packages/core/src/render3/styling/util.ts index 599613cf3b..3984d699e8 100644 --- a/packages/core/src/render3/styling/util.ts +++ b/packages/core/src/render3/styling/util.ts @@ -16,7 +16,7 @@ import {PlayState, Player, PlayerContext, PlayerIndex} from '../interfaces/playe import {RElement} from '../interfaces/renderer'; import {InitialStylingValues, InitialStylingValuesIndex, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling'; import {HEADER_OFFSET, HOST, LView, RootContext} from '../interfaces/view'; -import {getTNode} from '../util'; +import {getTNode} from '../util/view_utils'; import {CorePlayerHandler} from './core_player_handler'; diff --git a/packages/core/src/render3/util.ts b/packages/core/src/render3/util.ts deleted file mode 100644 index d9d02c1aad..0000000000 --- a/packages/core/src/render3/util.ts +++ /dev/null @@ -1,363 +0,0 @@ -/** - * @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 {assertDataInRange, assertDefined, assertGreaterThan, assertLessThan} from '../util/assert'; -import {global} from '../util/global'; - -import {assertLView} from './assert'; -import {LCONTAINER_LENGTH, LContainer} from './interfaces/container'; -import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; -import {ComponentDef, DirectiveDef} from './interfaces/definition'; -import {NO_PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags} from './interfaces/injector'; -import {TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node'; -import {RComment, RElement, RText} from './interfaces/renderer'; -import {CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, PARENT, RootContext, TData, TVIEW, T_HOST} from './interfaces/view'; - - - -/** - * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of - * that LContainer, which is an LView - * @param lView the lView whose parent to get - */ -export function getLViewParent(lView: LView): LView|null { - ngDevMode && assertLView(lView); - const parent = lView[PARENT]; - return isLContainer(parent) ? parent[PARENT] ! : parent; -} - -/** - * Returns true if the value is an {@link LView} - * @param value the value to check - */ -export function isLView(value: any): value is LView { - return Array.isArray(value) && value.length >= HEADER_OFFSET; -} - -/** - * Returns whether the values are different from a change detection stand point. - * - * Constraints are relaxed in checkNoChanges mode. See `devModeEqual` for details. - */ -export function isDifferent(a: any, b: any): boolean { - // NaN is the only value that is not equal to itself so the first - // test checks if both a and b are not NaN - return !(a !== a && b !== b) && a !== b; -} - -/** - * Used for stringify render output in Ivy. - */ -export function renderStringify(value: any): string { - if (typeof value == 'function') return value.name || value; - if (typeof value == 'string') return value; - if (value == null) return ''; - if (typeof value == 'object' && typeof value.type == 'function') - return value.type.name || value.type; - return '' + value; -} - -/** - * Flattens an array in non-recursive way. Input arrays are not modified. - */ -export function flatten(list: any[]): any[] { - const result: any[] = []; - let i = 0; - - while (i < list.length) { - const item = list[i]; - if (Array.isArray(item)) { - if (item.length > 0) { - list = item.concat(list.slice(i + 1)); - i = 0; - } else { - i++; - } - } else { - result.push(item); - i++; - } - } - - return result; -} - -/** Retrieves a value from any `LView` or `TData`. */ -export function loadInternal(view: LView | TData, index: number): T { - ngDevMode && assertDataInRange(view, index + HEADER_OFFSET); - return view[index + HEADER_OFFSET]; -} - -/** - * Takes the value of a slot in `LView` and returns the element node. - * - * Normally, element nodes are stored flat, but if the node has styles/classes on it, - * it might be wrapped in a styling context. Or if that node has a directive that injects - * ViewContainerRef, it may be wrapped in an LContainer. Or if that node is a component, - * it will be wrapped in LView. It could even have all three, so we keep looping - * until we find something that isn't an array. - * - * @param value The initial value in `LView` - */ -export function readElementValue(value: any): RElement { - while (Array.isArray(value)) { - value = value[HOST] as any; - } - return value; -} - -/** - * Retrieves an element value from the provided `viewData`, by unwrapping - * from any containers, component views, or style contexts. - */ -export function getNativeByIndex(index: number, lView: LView): RElement { - return readElementValue(lView[index + HEADER_OFFSET]); -} - -export function getNativeByTNode(tNode: TNode, hostView: LView): RElement|RText|RComment { - return readElementValue(hostView[tNode.index]); -} - -export function getTNode(index: number, view: LView): TNode { - ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode'); - ngDevMode && assertLessThan(index, view[TVIEW].data.length, 'wrong index for TNode'); - return view[TVIEW].data[index + HEADER_OFFSET] as TNode; -} - -export function getComponentViewByIndex(nodeIndex: number, hostView: LView): LView { - // Could be an LView or an LContainer. If LContainer, unwrap to find LView. - const slotValue = hostView[nodeIndex]; - const lView = isLView(slotValue) ? slotValue : slotValue[HOST]; - ngDevMode && assertLView(lView); - return lView; -} - -export function isContentQueryHost(tNode: TNode): boolean { - return (tNode.flags & TNodeFlags.hasContentQuery) !== 0; -} - -export function isComponent(tNode: TNode): boolean { - return (tNode.flags & TNodeFlags.isComponent) === TNodeFlags.isComponent; -} - -export function isComponentDef(def: DirectiveDef): def is ComponentDef { - return (def as ComponentDef).template !== null; -} - -export function isLContainer(value: any): value is LContainer { - // Styling contexts are also arrays, but their first index contains an element node - return Array.isArray(value) && value.length === LCONTAINER_LENGTH; -} - -export function isRootView(target: LView): boolean { - return (target[FLAGS] & LViewFlags.IsRoot) !== 0; -} - -/** - * Retrieve the root view from any component or `LView` by walking the parent `LView` until - * reaching the root `LView`. - * - * @param componentOrLView any component or `LView` - */ -export function getRootView(componentOrLView: LView | {}): LView { - ngDevMode && assertDefined(componentOrLView, 'component'); - let lView = isLView(componentOrLView) ? componentOrLView : readPatchedLView(componentOrLView) !; - while (lView && !(lView[FLAGS] & LViewFlags.IsRoot)) { - lView = getLViewParent(lView) !; - } - ngDevMode && assertLView(lView); - return lView; -} -/** - * Returns the `RootContext` instance that is associated with - * the application where the target is situated. It does this by walking the parent views until it - * gets to the root view, then getting the context off of that. - * - * @param viewOrComponent the `LView` or component to get the root context for. - */ -export function getRootContext(viewOrComponent: LView | {}): RootContext { - const rootView = getRootView(viewOrComponent); - ngDevMode && - assertDefined(rootView[CONTEXT], 'RootView has no context. Perhaps it is disconnected?'); - return rootView[CONTEXT] as RootContext; -} - -/** - * Returns the monkey-patch value data present on the target (which could be - * a component, directive or a DOM node). - */ -export function readPatchedData(target: any): LView|LContext|null { - ngDevMode && assertDefined(target, 'Target expected'); - return target[MONKEY_PATCH_KEY_NAME]; -} - -export function readPatchedLView(target: any): LView|null { - const value = readPatchedData(target); - if (value) { - return Array.isArray(value) ? value : (value as LContext).lView; - } - return null; -} - -export function hasParentInjector(parentLocation: RelativeInjectorLocation): boolean { - return parentLocation !== NO_PARENT_INJECTOR; -} - -export function getParentInjectorIndex(parentLocation: RelativeInjectorLocation): number { - return (parentLocation as any as number) & RelativeInjectorLocationFlags.InjectorIndexMask; -} - -export function getParentInjectorViewOffset(parentLocation: RelativeInjectorLocation): number { - return (parentLocation as any as number) >> RelativeInjectorLocationFlags.ViewOffsetShift; -} - -/** - * Unwraps a parent injector location number to find the view offset from the current injector, - * then walks up the declaration view tree until the view is found that contains the parent - * injector. - * - * @param location The location of the parent injector, which contains the view offset - * @param startView The LView instance from which to start walking up the view tree - * @returns The LView instance that contains the parent injector - */ -export function getParentInjectorView(location: RelativeInjectorLocation, startView: LView): LView { - let viewOffset = getParentInjectorViewOffset(location); - let parentView = startView; - // For most cases, the parent injector can be found on the host node (e.g. for component - // or container), but we must keep the loop here to support the rarer case of deeply nested - // tags or inline views, where the parent injector might live many views - // above the child injector. - while (viewOffset > 0) { - parentView = parentView[DECLARATION_VIEW] !; - viewOffset--; - } - return parentView; -} - -/** - * Unwraps a parent injector location number to find the view offset from the current injector, - * then walks up the declaration view tree until the TNode of the parent injector is found. - * - * @param location The location of the parent injector, which contains the view offset - * @param startView The LView instance from which to start walking up the view tree - * @param startTNode The TNode instance of the starting element - * @returns The TNode of the parent injector - */ -export function getParentInjectorTNode( - location: RelativeInjectorLocation, startView: LView, startTNode: TNode): TElementNode| - TContainerNode|null { - if (startTNode.parent && startTNode.parent.injectorIndex !== -1) { - // view offset is 0 - const injectorIndex = startTNode.parent.injectorIndex; - let parentTNode = startTNode.parent; - while (parentTNode.parent != null && injectorIndex == parentTNode.injectorIndex) { - parentTNode = parentTNode.parent; - } - return parentTNode; - } - - let viewOffset = getParentInjectorViewOffset(location); - // view offset is 1 - let parentView = startView; - let parentTNode = startView[T_HOST] as TElementNode; - - // view offset is superior to 1 - while (viewOffset > 1) { - parentView = parentView[DECLARATION_VIEW] !; - parentTNode = parentView[T_HOST] as TElementNode; - viewOffset--; - } - return parentTNode; -} - -export const defaultScheduler = - (typeof requestAnimationFrame !== 'undefined' && requestAnimationFrame || // browser only - setTimeout // everything else - ).bind(global); - -/** - * Equivalent to ES6 spread, add each item to an array. - * - * @param items The items to add - * @param arr The array to which you want to add the items - */ -export function addAllToArray(items: any[], arr: any[]) { - for (let i = 0; i < items.length; i++) { - arr.push(items[i]); - } -} - -/** - * Given a current view, finds the nearest component's host (LElement). - * - * @param lView LView for which we want a host element node - * @returns The host node - */ -export function findComponentView(lView: LView): LView { - let rootTNode = lView[T_HOST]; - - while (rootTNode && rootTNode.type === TNodeType.View) { - ngDevMode && assertDefined(lView[DECLARATION_VIEW], 'lView[DECLARATION_VIEW]'); - lView = lView[DECLARATION_VIEW] !; - rootTNode = lView[T_HOST]; - } - - ngDevMode && assertLView(lView); - return lView; -} - -export function resolveWindow(element: RElement & {ownerDocument: Document}) { - return {name: 'window', target: element.ownerDocument.defaultView}; -} - -export function resolveDocument(element: RElement & {ownerDocument: Document}) { - return {name: 'document', target: element.ownerDocument}; -} - -export function resolveBody(element: RElement & {ownerDocument: Document}) { - return {name: 'body', target: element.ownerDocument.body}; -} - -/** - * The special delimiter we use to separate property names, prefixes, and suffixes - * in property binding metadata. See storeBindingMetadata(). - * - * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter - * because it is a very uncommon character that is unlikely to be part of a user's - * property names or interpolation strings. If it is in fact used in a property - * binding, DebugElement.properties will not return the correct value for that - * binding. However, there should be no runtime effect for real applications. - * - * This character is typically rendered as a question mark inside of a diamond. - * See https://en.wikipedia.org/wiki/Specials_(Unicode_block) - * - */ -export const INTERPOLATION_DELIMITER = `�`; - -/** - * Determines whether or not the given string is a property metadata string. - * See storeBindingMetadata(). - */ -export function isPropMetadataString(str: string): boolean { - return str.indexOf(INTERPOLATION_DELIMITER) >= 0; -} - -export function applyOnCreateInstructions(tNode: TNode) { - // there may be some instructions that need to run in a specific - // order because the CREATE block in a directive runs before the - // CREATE block in a template. To work around this instructions - // can get access to the function array below and defer any code - // to run after the element is created. - let fns: Function[]|null; - if (fns = tNode.onElementCreationFns) { - for (let i = 0; i < fns.length; i++) { - fns[i](); - } - tNode.onElementCreationFns = null; - } -} \ No newline at end of file diff --git a/packages/core/src/render3/util/array_utils.ts b/packages/core/src/render3/util/array_utils.ts new file mode 100644 index 0000000000..894da85195 --- /dev/null +++ b/packages/core/src/render3/util/array_utils.ts @@ -0,0 +1,42 @@ +/** + * @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 + */ + +/** +* Equivalent to ES6 spread, add each item to an array. +* +* @param items The items to add +* @param arr The array to which you want to add the items +*/ +export function addAllToArray(items: any[], arr: any[]) { + for (let i = 0; i < items.length; i++) { + arr.push(items[i]); + } +} + +/** + * Flattens an array in non-recursive way. Input arrays are not modified. + */ +export function flatten(list: any[]): any[] { + const result: any[] = []; + let i = 0; + while (i < list.length) { + const item = list[i]; + if (Array.isArray(item)) { + if (item.length > 0) { + list = item.concat(list.slice(i + 1)); + i = 0; + } else { + i++; + } + } else { + result.push(item); + i++; + } + } + return result; +} diff --git a/packages/core/src/render3/discovery_utils.ts b/packages/core/src/render3/util/discovery_utils.ts similarity index 94% rename from packages/core/src/render3/discovery_utils.ts rename to packages/core/src/render3/util/discovery_utils.ts index 25d870bb0b..35bb9ea02b 100644 --- a/packages/core/src/render3/discovery_utils.ts +++ b/packages/core/src/render3/util/discovery_utils.ts @@ -6,16 +6,18 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector} from '../di/injector'; +import {Injector} from '../../di/injector'; -import {assertLView} from './assert'; -import {discoverLocalRefs, getComponentAtNodeIndex, getDirectivesAtNodeIndex, getLContext} from './context_discovery'; -import {NodeInjector} from './di'; -import {LContext} from './interfaces/context'; -import {DirectiveDef} from './interfaces/definition'; -import {TElementNode, TNode, TNodeProviderIndexes} from './interfaces/node'; -import {CLEANUP, CONTEXT, FLAGS, HOST, LView, LViewFlags, TVIEW} from './interfaces/view'; -import {getLViewParent, getRootContext, readElementValue, renderStringify} from './util'; +import {assertLView} from '../assert'; +import {discoverLocalRefs, getComponentAtNodeIndex, getDirectivesAtNodeIndex, getLContext} from '../context_discovery'; +import {NodeInjector} from '../di'; +import {LContext} from '../interfaces/context'; +import {DirectiveDef} from '../interfaces/definition'; +import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node'; +import {CLEANUP, CONTEXT, FLAGS, HOST, LView, LViewFlags, TVIEW} from '../interfaces/view'; +import {renderStringify} from './misc_utils'; +import {getLViewParent, getRootContext} from './view_traversal_utils'; +import {readElementValue} from './view_utils'; diff --git a/packages/core/src/render3/global_utils.ts b/packages/core/src/render3/util/global_utils.ts similarity index 94% rename from packages/core/src/render3/global_utils.ts rename to packages/core/src/render3/util/global_utils.ts index d2ff76ccba..9d009dcfd6 100644 --- a/packages/core/src/render3/global_utils.ts +++ b/packages/core/src/render3/util/global_utils.ts @@ -5,10 +5,10 @@ * 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 {assertDefined} from '../util/assert'; -import {global} from '../util/global'; +import {assertDefined} from '../../util/assert'; +import {global} from '../../util/global'; -import {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getPlayers, getRootComponents, getViewComponent, markDirty} from './global_utils_api'; +import {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getPlayers, getRootComponents, getViewComponent, markDirty} from '../global_utils_api'; diff --git a/packages/core/src/render3/util/injector_utils.ts b/packages/core/src/render3/util/injector_utils.ts new file mode 100644 index 0000000000..0de9682a56 --- /dev/null +++ b/packages/core/src/render3/util/injector_utils.ts @@ -0,0 +1,44 @@ +/** + * @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 {NO_PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags} from '../interfaces/injector'; +import {DECLARATION_VIEW, LView} from '../interfaces/view'; +/// Parent Injector Utils /////////////////////////////////////////////////////////////// +export function hasParentInjector(parentLocation: RelativeInjectorLocation): boolean { + return parentLocation !== NO_PARENT_INJECTOR; +} + +export function getParentInjectorIndex(parentLocation: RelativeInjectorLocation): number { + return (parentLocation as any as number) & RelativeInjectorLocationFlags.InjectorIndexMask; +} + +export function getParentInjectorViewOffset(parentLocation: RelativeInjectorLocation): number { + return (parentLocation as any as number) >> RelativeInjectorLocationFlags.ViewOffsetShift; +} + +/** + * Unwraps a parent injector location number to find the view offset from the current injector, + * then walks up the declaration view tree until the view is found that contains the parent + * injector. + * + * @param location The location of the parent injector, which contains the view offset + * @param startView The LView instance from which to start walking up the view tree + * @returns The LView instance that contains the parent injector + */ +export function getParentInjectorView(location: RelativeInjectorLocation, startView: LView): LView { + let viewOffset = getParentInjectorViewOffset(location); + let parentView = startView; + // For most cases, the parent injector can be found on the host node (e.g. for component + // or container), but we must keep the loop here to support the rarer case of deeply nested + // tags or inline views, where the parent injector might live many views + // above the child injector. + while (viewOffset > 0) { + parentView = parentView[DECLARATION_VIEW] !; + viewOffset--; + } + return parentView; +} diff --git a/packages/core/src/render3/util/misc_utils.ts b/packages/core/src/render3/util/misc_utils.ts new file mode 100644 index 0000000000..829a2d16a6 --- /dev/null +++ b/packages/core/src/render3/util/misc_utils.ts @@ -0,0 +1,78 @@ +/** + * @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 {assertDefined} from '../../util/assert'; +import {global} from '../../util/global'; +import {RElement} from '../interfaces/renderer'; +import {CONTEXT, LView, RootContext} from '../interfaces/view'; +import {getRootView} from './view_traversal_utils'; + +/** + * Returns whether the values are different from a change detection stand point. + * + * Constraints are relaxed in checkNoChanges mode. See `devModeEqual` for details. + */ +export function isDifferent(a: any, b: any): boolean { + // NaN is the only value that is not equal to itself so the first + // test checks if both a and b are not NaN + return !(a !== a && b !== b) && a !== b; +} + +/** + * Used for stringify render output in Ivy. + */ +export function renderStringify(value: any): string { + if (typeof value == 'function') return value.name || value; + if (typeof value == 'string') return value; + if (value == null) return ''; + if (typeof value == 'object' && typeof value.type == 'function') + return value.type.name || value.type; + return '' + value; +} + + +export const defaultScheduler = + (typeof requestAnimationFrame !== 'undefined' && requestAnimationFrame || // browser only + setTimeout // everything else + ).bind(global); + +export function resolveWindow(element: RElement & {ownerDocument: Document}) { + return {name: 'window', target: element.ownerDocument.defaultView}; +} + +export function resolveDocument(element: RElement & {ownerDocument: Document}) { + return {name: 'document', target: element.ownerDocument}; +} + +export function resolveBody(element: RElement & {ownerDocument: Document}) { + return {name: 'body', target: element.ownerDocument.body}; +} + +/** + * The special delimiter we use to separate property names, prefixes, and suffixes + * in property binding metadata. See storeBindingMetadata(). + * + * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter + * because it is a very uncommon character that is unlikely to be part of a user's + * property names or interpolation strings. If it is in fact used in a property + * binding, DebugElement.properties will not return the correct value for that + * binding. However, there should be no runtime effect for real applications. + * + * This character is typically rendered as a question mark inside of a diamond. + * See https://en.wikipedia.org/wiki/Specials_(Unicode_block) + * + */ +export const INTERPOLATION_DELIMITER = `�`; + +/** + * Determines whether or not the given string is a property metadata string. + * See storeBindingMetadata(). + */ +export function isPropMetadataString(str: string): boolean { + return str.indexOf(INTERPOLATION_DELIMITER) >= 0; +} diff --git a/packages/core/src/render3/util/view_traversal_utils.ts b/packages/core/src/render3/util/view_traversal_utils.ts new file mode 100644 index 0000000000..dc672ec83e --- /dev/null +++ b/packages/core/src/render3/util/view_traversal_utils.ts @@ -0,0 +1,73 @@ +/** + * @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 {assertDefined} from '../../util/assert'; +import {assertLView} from '../assert'; +import {TNodeType} from '../interfaces/node'; +import {CONTEXT, DECLARATION_VIEW, FLAGS, LView, LViewFlags, PARENT, RootContext, T_HOST} from '../interfaces/view'; + +import {isLContainer, isLView, readPatchedLView} from './view_utils'; + + +/** + * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of + * that LContainer, which is an LView + * @param lView the lView whose parent to get + */ +export function getLViewParent(lView: LView): LView|null { + ngDevMode && assertLView(lView); + const parent = lView[PARENT]; + return isLContainer(parent) ? parent[PARENT] ! : parent; +} + +/** + * Retrieve the root view from any component or `LView` by walking the parent `LView` until + * reaching the root `LView`. + * + * @param componentOrLView any component or `LView` + */ +export function getRootView(componentOrLView: LView | {}): LView { + ngDevMode && assertDefined(componentOrLView, 'component'); + let lView = isLView(componentOrLView) ? componentOrLView : readPatchedLView(componentOrLView) !; + while (lView && !(lView[FLAGS] & LViewFlags.IsRoot)) { + lView = getLViewParent(lView) !; + } + ngDevMode && assertLView(lView); + return lView; +} + +/** + * Given a current view, finds the nearest component's host (LElement). + * + * @param lView LView for which we want a host element node + * @returns The host node + */ +export function findComponentView(lView: LView): LView { + let rootTNode = lView[T_HOST]; + while (rootTNode && rootTNode.type === TNodeType.View) { + ngDevMode && assertDefined(lView[DECLARATION_VIEW], 'lView[DECLARATION_VIEW]'); + lView = lView[DECLARATION_VIEW] !; + rootTNode = lView[T_HOST]; + } + ngDevMode && assertLView(lView); + return lView; +} + +/** + * Returns the `RootContext` instance that is associated with + * the application where the target is situated. It does this by walking the parent views until it + * gets to the root view, then getting the context off of that. + * + * @param viewOrComponent the `LView` or component to get the root context for. + */ +export function getRootContext(viewOrComponent: LView | {}): RootContext { + const rootView = getRootView(viewOrComponent); + ngDevMode && + assertDefined(rootView[CONTEXT], 'RootView has no context. Perhaps it is disconnected?'); + return rootView[CONTEXT] as RootContext; +} diff --git a/packages/core/src/render3/util/view_utils.ts b/packages/core/src/render3/util/view_utils.ts new file mode 100644 index 0000000000..a5743424b1 --- /dev/null +++ b/packages/core/src/render3/util/view_utils.ts @@ -0,0 +1,112 @@ +/** + * @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 {assertDataInRange, assertDefined, assertGreaterThan, assertLessThan} from '../../util/assert'; +import {LCONTAINER_LENGTH, LContainer} from '../interfaces/container'; +import {LContext, MONKEY_PATCH_KEY_NAME} from '../interfaces/context'; +import {ComponentDef, DirectiveDef} from '../interfaces/definition'; +import {TNode, TNodeFlags} from '../interfaces/node'; +import {RComment, RElement, RText} from '../interfaces/renderer'; +import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, TData, TVIEW} from '../interfaces/view'; + + + +/** + * Takes the value of a slot in `LView` and returns the element node. + * + * Normally, element nodes are stored flat, but if the node has styles/classes on it, + * it might be wrapped in a styling context. Or if that node has a directive that injects + * ViewContainerRef, it may be wrapped in an LContainer. Or if that node is a component, + * it will be wrapped in LView. It could even have all three, so we keep looping + * until we find something that isn't an array. + * + * @param value The initial value in `LView` + */ +export function readElementValue(value: any): RElement { + while (Array.isArray(value)) { + value = value[HOST] as any; + } + return value; +} + +/** + * Retrieves an element value from the provided `viewData`, by unwrapping + * from any containers, component views, or style contexts. + */ +export function getNativeByIndex(index: number, lView: LView): RElement { + return readElementValue(lView[index + HEADER_OFFSET]); +} + +export function getNativeByTNode(tNode: TNode, hostView: LView): RElement|RText|RComment { + return readElementValue(hostView[tNode.index]); +} + +export function getTNode(index: number, view: LView): TNode { + ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode'); + ngDevMode && assertLessThan(index, view[TVIEW].data.length, 'wrong index for TNode'); + return view[TVIEW].data[index + HEADER_OFFSET] as TNode; +} + +/** + * Returns true if the value is an {@link LView} + * @param value the value to check + */ +export function isLView(value: any): value is LView { + return Array.isArray(value) && value.length >= HEADER_OFFSET; +} + +/** Retrieves a value from any `LView` or `TData`. */ +export function loadInternal(view: LView | TData, index: number): T { + ngDevMode && assertDataInRange(view, index + HEADER_OFFSET); + return view[index + HEADER_OFFSET]; +} + +export function getComponentViewByIndex(nodeIndex: number, hostView: LView): LView { + // Could be an LView or an LContainer. If LContainer, unwrap to find LView. + const slotValue = hostView[nodeIndex]; + const lView = isLView(slotValue) ? slotValue : slotValue[HOST]; + return lView; +} + +export function isContentQueryHost(tNode: TNode): boolean { + return (tNode.flags & TNodeFlags.hasContentQuery) !== 0; +} + +export function isComponent(tNode: TNode): boolean { + return (tNode.flags & TNodeFlags.isComponent) === TNodeFlags.isComponent; +} + +export function isComponentDef(def: DirectiveDef): def is ComponentDef { + return (def as ComponentDef).template !== null; +} + +export function isLContainer(value: any): value is LContainer { + // Styling contexts are also arrays, but their first index contains an element node + return Array.isArray(value) && value.length === LCONTAINER_LENGTH; +} + +export function isRootView(target: LView): boolean { + return (target[FLAGS] & LViewFlags.IsRoot) !== 0; +} + +/** + * Returns the monkey-patch value data present on the target (which could be + * a component, directive or a DOM node). + */ +export function readPatchedData(target: any): LView|LContext|null { + ngDevMode && assertDefined(target, 'Target expected'); + return target[MONKEY_PATCH_KEY_NAME]; +} + +export function readPatchedLView(target: any): LView|null { + const value = readPatchedData(target); + if (value) { + return Array.isArray(value) ? value : (value as LContext).lView; + } + return null; +} diff --git a/packages/core/src/render3/view_engine_compatibility.ts b/packages/core/src/render3/view_engine_compatibility.ts index a601d2e3f3..45560d57fe 100644 --- a/packages/core/src/render3/view_engine_compatibility.ts +++ b/packages/core/src/render3/view_engine_compatibility.ts @@ -25,8 +25,11 @@ import {RComment, RElement, isProceduralRenderer} from './interfaces/renderer'; import {CONTEXT, LView, QUERIES, RENDERER, TView, T_HOST} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; import {addRemoveViewFromContainer, appendChild, detachView, getBeforeNodeForView, insertView, nativeInsertBefore, nativeNextSibling, nativeParentNode, removeView} from './node_manipulation'; +import {getParentInjectorTNode} from './node_util'; import {getLView, getPreviousOrParentTNode} from './state'; -import {findComponentView, getComponentViewByIndex, getNativeByTNode, getParentInjectorTNode, getParentInjectorView, hasParentInjector, isComponent, isLContainer, isRootView} from './util'; +import {getParentInjectorView, hasParentInjector} from './util/injector_utils'; +import {findComponentView} from './util/view_traversal_utils'; +import {getComponentViewByIndex, getNativeByTNode, isComponent, isLContainer, isRootView} from './util/view_utils'; import {ViewRef} from './view_ref'; diff --git a/packages/core/src/render3/view_ref.ts b/packages/core/src/render3/view_ref.ts index 810e75401a..a25468d911 100644 --- a/packages/core/src/render3/view_ref.ts +++ b/packages/core/src/render3/view_ref.ts @@ -15,7 +15,8 @@ import {checkNoChangesInRootView, checkNoChangesInternal, detectChangesInRootVie import {TNode, TNodeType, TViewNode} from './interfaces/node'; import {FLAGS, HOST, LView, LViewFlags, PARENT, T_HOST} from './interfaces/view'; import {destroyLView} from './node_manipulation'; -import {getLViewParent, getNativeByTNode} from './util'; +import {getLViewParent} from './util/view_traversal_utils'; +import {getNativeByTNode} from './util/view_utils'; diff --git a/packages/core/src/sanitization/sanitization.ts b/packages/core/src/sanitization/sanitization.ts index c4c6b7cb4f..f935d6f14d 100644 --- a/packages/core/src/sanitization/sanitization.ts +++ b/packages/core/src/sanitization/sanitization.ts @@ -8,7 +8,7 @@ import {SANITIZER} from '../render3/interfaces/view'; import {getLView} from '../render3/state'; -import {renderStringify} from '../render3/util'; +import {renderStringify} from '../render3/util/misc_utils'; import {BypassType, allowSanitizationBypass} from './bypass'; import {_sanitizeHtml as _sanitizeHtml} from './html_sanitizer'; diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index 0aa0c0eded..411c6f90c3 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -16,7 +16,7 @@ import {ProvidersFeature, defineDirective, elementProperty, load, templateRefExt import {allocHostVars, bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLView, createTView, directiveInject, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, injectAttribute, interpolation2, projection, projectionDef, reference, template, text, textBinding, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions'; import {isProceduralRenderer, RElement} from '../../src/render3/interfaces/renderer'; import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node'; -import {getNativeByIndex} from '../../src/render3/util'; +import {getNativeByIndex} from '../../src/render3/util/view_utils'; import {LViewFlags} from '../../src/render3/interfaces/view'; import {enterView, leaveView, getLView} from '../../src/render3/state'; import {ViewRef} from '../../src/render3/view_ref'; diff --git a/packages/core/test/render3/discovery_utils_spec.ts b/packages/core/test/render3/discovery_utils_spec.ts index 8ae1366a10..1a9a2a8637 100644 --- a/packages/core/test/render3/discovery_utils_spec.ts +++ b/packages/core/test/render3/discovery_utils_spec.ts @@ -7,8 +7,8 @@ */ import {StaticInjector} from '../../src/di/injector'; import {createInjector} from '../../src/di/r3_injector'; -import {getComponent, getContext, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getRootComponents, getViewComponent, loadLContext} from '../../src/render3/discovery_utils'; import {ProvidersFeature, RenderFlags, defineComponent, defineDirective, elementContainerEnd, elementContainerStart, getHostElement, i18n, i18nApply, i18nExp} from '../../src/render3/index'; +import {getComponent, getContext, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getRootComponents, getViewComponent, loadLContext} from '../../src/render3/util/discovery_utils'; import {element, elementEnd, elementStart, elementStyling, elementStylingApply, template, bind, elementProperty, text, textBinding, markDirty, listener} from '../../src/render3/instructions'; import {ComponentFixture} from './render_util'; diff --git a/packages/core/test/render3/global_utils_spec.ts b/packages/core/test/render3/global_utils_spec.ts index fe0c35994e..712d95cf85 100644 --- a/packages/core/test/render3/global_utils_spec.ts +++ b/packages/core/test/render3/global_utils_spec.ts @@ -7,9 +7,9 @@ */ import {ɵmarkDirty as markDirty} from '@angular/core'; -import {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getRootComponents, getViewComponent} from '../../src/render3/discovery_utils'; -import {GLOBAL_PUBLISH_EXPANDO_KEY, GlobalDevModeContainer, publishDefaultGlobalUtils, publishGlobalUtil} from '../../src/render3/global_utils'; import {getPlayers} from '../../src/render3/players'; +import {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getRootComponents, getViewComponent} from '../../src/render3/util/discovery_utils'; +import {GLOBAL_PUBLISH_EXPANDO_KEY, GlobalDevModeContainer, publishDefaultGlobalUtils, publishGlobalUtil} from '../../src/render3/util/global_utils'; import {global} from '../../src/util/global'; describe('global utils', () => { diff --git a/packages/core/test/render3/i18n_spec.ts b/packages/core/test/render3/i18n_spec.ts index 20a04d53cb..89c6cadfe5 100644 --- a/packages/core/test/render3/i18n_spec.ts +++ b/packages/core/test/render3/i18n_spec.ts @@ -12,7 +12,7 @@ import {defineComponent, defineDirective} from '../../src/render3/definition'; import {getTranslationForTemplate, i18n, i18nApply, i18nAttributes, i18nEnd, i18nExp, i18nPostprocess, i18nStart} from '../../src/render3/i18n'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {AttributeMarker} from '../../src/render3/interfaces/node'; -import {getNativeByIndex, getTNode} from '../../src/render3/util'; +import {getNativeByIndex, getTNode} from '../../src/render3/util/view_utils'; import {NgIf} from './common_with_def'; import {allocHostVars, element, elementEnd, elementStart, template, text, nextContext, bind, elementProperty, projectionDef, projection, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions'; import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nUpdateOpCode, I18nUpdateOpCodes, TI18n} from '../../src/render3/interfaces/i18n'; @@ -264,9 +264,9 @@ describe('Runtime i18n', () => { }); it('for ICU expressions', () => { - const MSG_DIV = `{�0�, plural, - =0 {no emails!} - =1 {one email} + const MSG_DIV = `{�0�, plural, + =0 {no emails!} + =1 {one email} other {�0� emails} }`; const nbConsts = 1; @@ -377,10 +377,10 @@ describe('Runtime i18n', () => { it('for nested ICU expressions', () => { const MSG_DIV = `{�0�, plural, - =0 {zero} - other {�0� {�1�, select, - cat {cats} - dog {dogs} + =0 {zero} + other {�0� {�1�, select, + cat {cats} + dog {dogs} other {animals} }!} }`; @@ -649,9 +649,9 @@ describe('Runtime i18n', () => { }); it('for ICU expressions', () => { - const MSG_DIV = `{�0�, plural, - =0 {no emails!} - =1 {one email} + const MSG_DIV = `{�0�, plural, + =0 {no emails!} + =1 {one email} other {�0� emails} }`; const fixture = prepareFixture(() => { @@ -665,11 +665,11 @@ describe('Runtime i18n', () => { }); it('for multiple ICU expressions', () => { - const MSG_DIV = `{�0�, plural, - =0 {no emails!} - =1 {one email} + const MSG_DIV = `{�0�, plural, + =0 {no emails!} + =1 {one email} other {�0� emails} - } - {�0�, select, + } - {�0�, select, other {(�0�)} }`; const fixture = prepareFixture(() => { @@ -683,11 +683,11 @@ describe('Runtime i18n', () => { }); it('for multiple ICU expressions inside html', () => { - const MSG_DIV = `�#2�{�0�, plural, - =0 {no emails!} - =1 {one email} + const MSG_DIV = `�#2�{�0�, plural, + =0 {no emails!} + =1 {one email} other {�0� emails} - }�/#2��#3�{�0�, select, + }�/#2��#3�{�0�, select, other {(�0�)} }�/#3�`; const fixture = prepareFixture(() => { @@ -763,9 +763,9 @@ describe('Runtime i18n', () => { }); it('for ICU expressions inside ', () => { - const MSG_DIV = `{�0�, plural, - =0 {no emails!} - =1 {one email} + const MSG_DIV = `{�0�, plural, + =0 {no emails!} + =1 {one email} other {�0� emails} }`; const fixture = prepareFixture( @@ -790,10 +790,10 @@ describe('Runtime i18n', () => { it('for nested ICU expressions', () => { const MSG_DIV = `{�0�, plural, - =0 {zero} - other {�0� {�1�, select, - cat {cats} - dog {dogs} + =0 {zero} + other {�0� {�1�, select, + cat {cats} + dog {dogs} other {animals} }!} }`; @@ -1017,9 +1017,9 @@ describe('Runtime i18n', () => { }); it('for ICU expressions', () => { - const MSG_DIV = `{�0�, plural, - =0 {no emails!} - =1 {one email} + const MSG_DIV = `{�0�, plural, + =0 {no emails!} + =1 {one email} other {�0� emails} }`; const ctx = {value0: 0, value1: 'emails label'}; @@ -1062,11 +1062,11 @@ describe('Runtime i18n', () => { }); it('for multiple ICU expressions', () => { - const MSG_DIV = `{�0�, plural, - =0 {no emails!} - =1 {one email} + const MSG_DIV = `{�0�, plural, + =0 {no emails!} + =1 {one email} other {�0� emails} - } - {�0�, select, + } - {�0�, select, other {(�0�)} }`; const ctx = {value0: 0, value1: 'emails label'}; @@ -1114,11 +1114,11 @@ describe('Runtime i18n', () => { }); it('for multiple ICU expressions', () => { - const MSG_DIV = `�#2�{�0�, plural, - =0 {no emails!} - =1 {one email} + const MSG_DIV = `�#2�{�0�, plural, + =0 {no emails!} + =1 {one email} other {�0� emails} - }�/#2��#3�{�0�, select, + }�/#2��#3�{�0�, select, other {(�0�)} }�/#3�`; const ctx = {value0: 0, value1: 'emails label'}; @@ -1175,10 +1175,10 @@ describe('Runtime i18n', () => { it('for nested ICU expressions', () => { const MSG_DIV = `{�0�, plural, - =0 {zero} - other {�0� {�1�, select, - cat {cats} - dog {dogs} + =0 {zero} + other {�0� {�1�, select, + cat {cats} + dog {dogs} other {animals} }!} }`; @@ -1372,9 +1372,9 @@ describe('Runtime i18n', () => { // } // - const MSG_DIV_1 = `trad {�0�, plural, - =0 {no emails!} - =1 {one email} + const MSG_DIV_1 = `trad {�0�, plural, + =0 {no emails!} + =1 {one email} other {�0� emails} }`; const MSG_DIV_1_ATTR_1 = ['title', `start �1� middle �0� end`]; diff --git a/packages/core/test/render3/providers_spec.ts b/packages/core/test/render3/providers_spec.ts index 5de7ee1360..ac6641171d 100644 --- a/packages/core/test/render3/providers_spec.ts +++ b/packages/core/test/render3/providers_spec.ts @@ -9,11 +9,11 @@ import {Component as _Component, ComponentFactoryResolver, ElementRef, InjectFlags, Injectable as _Injectable, InjectionToken, InjectorType, Provider, RendererFactory2, ViewContainerRef, defineInjectable, defineInjector, inject, ɵNgModuleDef as NgModuleDef} from '../../src/core'; import {forwardRef} from '../../src/di/forward_ref'; import {createInjector} from '../../src/di/r3_injector'; -import {getInjector} from '../../src/render3/discovery_utils'; import {ProvidersFeature, defineComponent, defineDirective, directiveInject, injectComponentFactoryResolver} from '../../src/render3/index'; import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, text, textBinding} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {NgModuleFactory} from '../../src/render3/ng_module_ref'; +import {getInjector} from '../../src/render3/util/discovery_utils'; import {getRendererFactory2} from './imported_renderer2'; import {ComponentFixture} from './render_util'; diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index 637ec8cf66..5362544d1a 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -11,7 +11,7 @@ import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/cor import {EventEmitter} from '../..'; import {AttributeMarker, ProvidersFeature, defineComponent, defineDirective, detectChanges} from '../../src/render3/index'; -import {getNativeByIndex} from '../../src/render3/util'; +import {getNativeByIndex} from '../../src/render3/util/view_utils'; import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, reference, template, text} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index ac3b3aea76..9515e46c6a 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -33,7 +33,7 @@ import {PlayerHandler} from '../../src/render3/interfaces/player'; import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, RendererStyleFlags3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; import {HEADER_OFFSET, LView} from '../../src/render3/interfaces/view'; import {destroyLView} from '../../src/render3/node_manipulation'; -import {getRootView} from '../../src/render3/util'; +import {getRootView} from '../../src/render3/util/view_traversal_utils'; import {Sanitizer} from '../../src/sanitization/security'; import {getRendererFactory2} from './imported_renderer2'; diff --git a/packages/core/test/render3/util_spec.ts b/packages/core/test/render3/util_spec.ts index 25cde7d74b..36290be8b2 100644 --- a/packages/core/test/render3/util_spec.ts +++ b/packages/core/test/render3/util_spec.ts @@ -8,7 +8,8 @@ import {devModeEqual} from '@angular/core/src/change_detection/change_detection_util'; -import {flatten, isDifferent} from '../../src/render3/util'; +import {flatten} from '../../src/render3/util/array_utils'; +import {isDifferent} from '../../src/render3/util/misc_utils'; describe('util', () => { diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index 03b87d8f37..b10c1ae45b 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -17,7 +17,7 @@ import {RElement} from '../../src/render3/interfaces/renderer'; import {NgModuleFactory} from '../../src/render3/ng_module_ref'; import {pipe, pipeBind1} from '../../src/render3/pipe'; import {getLView} from '../../src/render3/state'; -import {getNativeByIndex} from '../../src/render3/util'; +import {getNativeByIndex} from '../../src/render3/util/view_utils'; import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound'; import {NgForOf} from '../../test/render3/common_with_def';