parent
6e73300ff1
commit
d5e7f60f04
@ -318,7 +318,8 @@ function getOrCreateHostChangeDetector(currentNode: LViewNode | LElementNode):
|
|||||||
existingRef :
|
existingRef :
|
||||||
createViewRef(
|
createViewRef(
|
||||||
hostNode.data as LView,
|
hostNode.data as LView,
|
||||||
hostNode.view.directives ![hostNode.tNode !.flags >> TNodeFlags.INDX_SHIFT]);
|
hostNode.view
|
||||||
|
.directives ![hostNode.tNode !.flags >> TNodeFlags.DirectiveStartingIndexShift]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -382,23 +383,19 @@ export function getOrCreateInjectable<T>(
|
|||||||
// At this point, we have an injector which *may* contain the token, so we step through the
|
// At this point, we have an injector which *may* contain the token, so we step through the
|
||||||
// directives associated with the injector's corresponding node to get the directive instance.
|
// directives associated with the injector's corresponding node to get the directive instance.
|
||||||
const node = injector.node;
|
const node = injector.node;
|
||||||
|
|
||||||
// The size of the node's directive's list is stored in certain bits of the node's flags,
|
|
||||||
// so exact it with a mask and shift it back such that the bits reflect the real value.
|
|
||||||
const flags = node.tNode !.flags;
|
const flags = node.tNode !.flags;
|
||||||
const size = (flags & TNodeFlags.SIZE_MASK) >> TNodeFlags.SIZE_SHIFT;
|
const count = flags & TNodeFlags.DirectiveCountMask;
|
||||||
|
|
||||||
if (size !== 0) {
|
|
||||||
// The start index of the directives list is also part of the node's flags, but there is
|
|
||||||
// nothing to the "left" of it so it doesn't need a mask.
|
|
||||||
const start = flags >> TNodeFlags.INDX_SHIFT;
|
|
||||||
|
|
||||||
|
if (count !== 0) {
|
||||||
|
const start = flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
|
const end = start + count;
|
||||||
const defs = node.view.tView.directives !;
|
const defs = node.view.tView.directives !;
|
||||||
for (let i = start, ii = start + size; i < ii; i++) {
|
|
||||||
|
for (let i = start; i < end; i++) {
|
||||||
// Get the definition for the directive at this index and, if it is injectable (diPublic),
|
// Get the definition for the directive at this index and, if it is injectable (diPublic),
|
||||||
// and matches the given token, return the directive instance.
|
// and matches the given token, return the directive instance.
|
||||||
const directiveDef = defs[i] as DirectiveDef<any>;
|
const directiveDef = defs[i] as DirectiveDef<any>;
|
||||||
if (directiveDef.diPublic && directiveDef.type == token) {
|
if (directiveDef.type === token && directiveDef.diPublic) {
|
||||||
return getDirectiveInstance(node.view.directives ![i]);
|
return getDirectiveInstance(node.view.directives ![i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,15 +44,15 @@ export function queueInitHooks(
|
|||||||
export function queueLifecycleHooks(flags: number, currentView: LView): void {
|
export function queueLifecycleHooks(flags: number, currentView: LView): void {
|
||||||
const tView = currentView.tView;
|
const tView = currentView.tView;
|
||||||
if (tView.firstTemplatePass === true) {
|
if (tView.firstTemplatePass === true) {
|
||||||
const start = flags >> TNodeFlags.INDX_SHIFT;
|
const start = flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
const size = (flags & TNodeFlags.SIZE_MASK) >> TNodeFlags.SIZE_SHIFT;
|
const count = flags & TNodeFlags.DirectiveCountMask;
|
||||||
const end = start + size;
|
const end = start + count;
|
||||||
|
|
||||||
// It's necessary to loop through the directives at elementEnd() (rather than processing in
|
// It's necessary to loop through the directives at elementEnd() (rather than processing in
|
||||||
// directiveCreate) so we can preserve the current hook order. Content, view, and destroy
|
// directiveCreate) so we can preserve the current hook order. Content, view, and destroy
|
||||||
// hooks for projected components and directives must be called *before* their hosts.
|
// hooks for projected components and directives must be called *before* their hosts.
|
||||||
for (let i = start; i < end; i++) {
|
for (let i = start; i < end; i++) {
|
||||||
const def = (tView.directives ![i] as DirectiveDef<any>);
|
const def: DirectiveDef<any> = tView.directives ![i];
|
||||||
queueContentHooks(def, tView, i);
|
queueContentHooks(def, tView, i);
|
||||||
queueViewHooks(def, tView, i);
|
queueViewHooks(def, tView, i);
|
||||||
queueDestroyHooks(def, tView, i);
|
queueDestroyHooks(def, tView, i);
|
||||||
@ -97,9 +97,9 @@ function queueDestroyHooks(def: DirectiveDef<any>, tView: TView, i: number): voi
|
|||||||
* @param currentView The current view
|
* @param currentView The current view
|
||||||
*/
|
*/
|
||||||
export function executeInitHooks(currentView: LView, tView: TView, creationMode: boolean): void {
|
export function executeInitHooks(currentView: LView, tView: TView, creationMode: boolean): void {
|
||||||
if (currentView.lifecycleStage === LifecycleStage.INIT) {
|
if (currentView.lifecycleStage === LifecycleStage.Init) {
|
||||||
executeHooks(currentView.directives !, tView.initHooks, tView.checkHooks, creationMode);
|
executeHooks(currentView.directives !, tView.initHooks, tView.checkHooks, creationMode);
|
||||||
currentView.lifecycleStage = LifecycleStage.AFTER_INIT;
|
currentView.lifecycleStage = LifecycleStage.AfterInit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ export function leaveView(newView: LView): void {
|
|||||||
}
|
}
|
||||||
// Views should be clean and in update mode after being checked, so these bits are cleared
|
// Views should be clean and in update mode after being checked, so these bits are cleared
|
||||||
currentView.flags &= ~(LViewFlags.CreationMode | LViewFlags.Dirty);
|
currentView.flags &= ~(LViewFlags.CreationMode | LViewFlags.Dirty);
|
||||||
currentView.lifecycleStage = LifecycleStage.INIT;
|
currentView.lifecycleStage = LifecycleStage.Init;
|
||||||
currentView.bindingIndex = -1;
|
currentView.bindingIndex = -1;
|
||||||
enterView(newView, null);
|
enterView(newView, null);
|
||||||
}
|
}
|
||||||
@ -299,7 +299,7 @@ export function createLView<T>(
|
|||||||
template: template,
|
template: template,
|
||||||
context: context,
|
context: context,
|
||||||
dynamicViewCount: 0,
|
dynamicViewCount: 0,
|
||||||
lifecycleStage: LifecycleStage.INIT,
|
lifecycleStage: LifecycleStage.Init,
|
||||||
queries: null,
|
queries: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -599,8 +599,8 @@ function findDirectiveMatches(tNode: TNode): CurrentMatchesList|null {
|
|||||||
const def = registry[i];
|
const def = registry[i];
|
||||||
if (isNodeMatchingSelectorList(tNode, def.selectors !)) {
|
if (isNodeMatchingSelectorList(tNode, def.selectors !)) {
|
||||||
if ((def as ComponentDef<any>).template) {
|
if ((def as ComponentDef<any>).template) {
|
||||||
if (tNode.flags & TNodeFlags.Component) throwMultipleComponentError(tNode);
|
if (tNode.flags & TNodeFlags.isComponent) throwMultipleComponentError(tNode);
|
||||||
tNode.flags = TNodeFlags.Component;
|
tNode.flags = TNodeFlags.isComponent;
|
||||||
}
|
}
|
||||||
if (def.diPublic) def.diPublic(def);
|
if (def.diPublic) def.diPublic(def);
|
||||||
(matches || (matches = [])).push(def, null);
|
(matches || (matches = [])).push(def, null);
|
||||||
@ -650,7 +650,7 @@ export function initChangeDetectorIfExisting(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isComponent(tNode: TNode): boolean {
|
export function isComponent(tNode: TNode): boolean {
|
||||||
return (tNode.flags & TNodeFlags.Component) === TNodeFlags.Component;
|
return (tNode.flags & TNodeFlags.isComponent) === TNodeFlags.isComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -658,14 +658,15 @@ export function isComponent(tNode: TNode): boolean {
|
|||||||
*/
|
*/
|
||||||
function instantiateDirectivesDirectly() {
|
function instantiateDirectivesDirectly() {
|
||||||
const tNode = previousOrParentNode.tNode !;
|
const tNode = previousOrParentNode.tNode !;
|
||||||
const size = (tNode.flags & TNodeFlags.SIZE_MASK) >> TNodeFlags.SIZE_SHIFT;
|
const count = tNode.flags & TNodeFlags.DirectiveCountMask;
|
||||||
|
|
||||||
if (size > 0) {
|
if (count > 0) {
|
||||||
const startIndex = tNode.flags >> TNodeFlags.INDX_SHIFT;
|
const start = tNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
|
const end = start + count;
|
||||||
const tDirectives = currentView.tView.directives !;
|
const tDirectives = currentView.tView.directives !;
|
||||||
|
|
||||||
for (let i = startIndex; i < startIndex + size; i++) {
|
for (let i = start; i < end; i++) {
|
||||||
const def = tDirectives[i] as DirectiveDef<any>;
|
const def: DirectiveDef<any> = tDirectives[i];
|
||||||
directiveCreate(i, def.factory(), def);
|
directiveCreate(i, def.factory(), def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -818,7 +819,7 @@ export function hostElement(
|
|||||||
|
|
||||||
if (firstTemplatePass) {
|
if (firstTemplatePass) {
|
||||||
node.tNode = createTNode(tag as string, null, null);
|
node.tNode = createTNode(tag as string, null, null);
|
||||||
node.tNode.flags = TNodeFlags.Component;
|
node.tNode.flags = TNodeFlags.isComponent;
|
||||||
if (def.diPublic) def.diPublic(def);
|
if (def.diPublic) def.diPublic(def);
|
||||||
currentView.tView.directives = [def];
|
currentView.tView.directives = [def];
|
||||||
}
|
}
|
||||||
@ -1005,15 +1006,16 @@ function setInputsForProperty(inputs: PropertyAliasValue, value: any): void {
|
|||||||
*/
|
*/
|
||||||
function generatePropertyAliases(
|
function generatePropertyAliases(
|
||||||
tNodeFlags: TNodeFlags, direction: BindingDirection): PropertyAliases|null {
|
tNodeFlags: TNodeFlags, direction: BindingDirection): PropertyAliases|null {
|
||||||
const size = (tNodeFlags & TNodeFlags.SIZE_MASK) >> TNodeFlags.SIZE_SHIFT;
|
const count = tNodeFlags & TNodeFlags.DirectiveCountMask;
|
||||||
let propStore: PropertyAliases|null = null;
|
let propStore: PropertyAliases|null = null;
|
||||||
|
|
||||||
if (size > 0) {
|
if (count > 0) {
|
||||||
const start = tNodeFlags >> TNodeFlags.INDX_SHIFT;
|
const start = tNodeFlags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
|
const end = start + count;
|
||||||
const isInput = direction === BindingDirection.Input;
|
const isInput = direction === BindingDirection.Input;
|
||||||
const defs = currentView.tView.directives !;
|
const defs = currentView.tView.directives !;
|
||||||
|
|
||||||
for (let i = start, ii = start + size; i < ii; i++) {
|
for (let i = start; i < end; i++) {
|
||||||
const directiveDef = defs[i] as DirectiveDef<any>;
|
const directiveDef = defs[i] as DirectiveDef<any>;
|
||||||
const propertyAliasMap: {[publicName: string]: string} =
|
const propertyAliasMap: {[publicName: string]: string} =
|
||||||
isInput ? directiveDef.inputs : directiveDef.outputs;
|
isInput ? directiveDef.inputs : directiveDef.outputs;
|
||||||
@ -1211,7 +1213,7 @@ export function directiveCreate<T>(
|
|||||||
const instance = baseDirectiveCreate(index, directive, directiveDef);
|
const instance = baseDirectiveCreate(index, directive, directiveDef);
|
||||||
|
|
||||||
ngDevMode && assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.tNode');
|
ngDevMode && assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.tNode');
|
||||||
const tNode: TNode|null = previousOrParentNode.tNode !;
|
const tNode = previousOrParentNode.tNode;
|
||||||
|
|
||||||
const isComponent = (directiveDef as ComponentDef<T>).template;
|
const isComponent = (directiveDef as ComponentDef<T>).template;
|
||||||
if (isComponent) {
|
if (isComponent) {
|
||||||
@ -1275,9 +1277,19 @@ export function baseDirectiveCreate<T>(
|
|||||||
|
|
||||||
if (firstTemplatePass) {
|
if (firstTemplatePass) {
|
||||||
const flags = previousOrParentNode.tNode !.flags;
|
const flags = previousOrParentNode.tNode !.flags;
|
||||||
previousOrParentNode.tNode !.flags = (flags & TNodeFlags.SIZE_MASK) === 0 ?
|
if ((flags & TNodeFlags.DirectiveCountMask) === 0) {
|
||||||
(index << TNodeFlags.INDX_SHIFT) | TNodeFlags.SIZE_SKIP | flags & TNodeFlags.Component :
|
// When the first directive is created:
|
||||||
flags + TNodeFlags.SIZE_SKIP;
|
// - save the index,
|
||||||
|
// - set the number of directives to 1
|
||||||
|
previousOrParentNode.tNode !.flags =
|
||||||
|
index << TNodeFlags.DirectiveStartingIndexShift | flags & TNodeFlags.isComponent | 1;
|
||||||
|
} else {
|
||||||
|
// Only need to bump the size when subsequent directives are created
|
||||||
|
ngDevMode && assertNotEqual(
|
||||||
|
flags & TNodeFlags.DirectiveCountMask, TNodeFlags.DirectiveCountMask,
|
||||||
|
'Reached the max number of directives');
|
||||||
|
previousOrParentNode.tNode !.flags++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const diPublic = directiveDef !.diPublic;
|
const diPublic = directiveDef !.diPublic;
|
||||||
if (diPublic) diPublic(directiveDef !);
|
if (diPublic) diPublic(directiveDef !);
|
||||||
@ -1932,7 +1944,7 @@ export function getRootView(component: any): LView {
|
|||||||
export function detectChanges<T>(component: T): void {
|
export function detectChanges<T>(component: T): void {
|
||||||
const hostNode = _getComponentHostLElementNode(component);
|
const hostNode = _getComponentHostLElementNode(component);
|
||||||
ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView');
|
ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView');
|
||||||
const componentIndex = hostNode.tNode !.flags >> TNodeFlags.INDX_SHIFT;
|
const componentIndex = hostNode.tNode !.flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
const def = hostNode.view.tView.directives ![componentIndex] as ComponentDef<T>;
|
const def = hostNode.view.tView.directives ![componentIndex] as ComponentDef<T>;
|
||||||
detectChangesInternal(hostNode.data as LView, hostNode, def, component);
|
detectChangesInternal(hostNode.data as LView, hostNode, def, component);
|
||||||
}
|
}
|
||||||
|
@ -28,25 +28,17 @@ export const enum LNodeType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TNodeFlags corresponds to the TNode.flags property. It contains information
|
* Corresponds to the TNode.flags property.
|
||||||
* on how to map a particular set of bits to the node's first directive index
|
|
||||||
* (with INDX_SHIFT) or the node's directive count (with SIZE_MASK)
|
|
||||||
*/
|
*/
|
||||||
export const enum TNodeFlags {
|
export const enum TNodeFlags {
|
||||||
/** Whether or not this node is a component */
|
/** The number of directives on this node is encoded on the least significant bits */
|
||||||
Component = 0b001,
|
DirectiveCountMask = 0b00000000000000000000111111111111,
|
||||||
|
|
||||||
/** How far to shift the flags to get the first directive index on this node */
|
/** Then this bit is set when the node is a component */
|
||||||
INDX_SHIFT = 13,
|
isComponent = 0b1000000000000,
|
||||||
|
|
||||||
/** How far to shift the flags to get the number of directives on this node */
|
/** The index of the first directive on this node is encoded on the most significant bits */
|
||||||
SIZE_SHIFT = 1,
|
DirectiveStartingIndexShift = 13,
|
||||||
|
|
||||||
/** The amount to add to flags to increment size when each directive is added */
|
|
||||||
SIZE_SKIP = 2,
|
|
||||||
|
|
||||||
/** Mask to get the number of directives on this node */
|
|
||||||
SIZE_MASK = 0b00000000000000000001111111111110
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -408,10 +408,10 @@ export type HookData = (number | (() => void))[];
|
|||||||
export const enum LifecycleStage {
|
export const enum LifecycleStage {
|
||||||
|
|
||||||
/* Init hooks need to be run, if any. */
|
/* Init hooks need to be run, if any. */
|
||||||
INIT = 1,
|
Init = 1,
|
||||||
|
|
||||||
/* Content hooks need to be run, if any. Init hooks have already run. */
|
/* Content hooks need to be run, if any. Init hooks have already run. */
|
||||||
AFTER_INIT = 2,
|
AfterInit = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -193,13 +193,15 @@ function getIdxOfMatchingSelector(tNode: TNode, selector: string): number|null {
|
|||||||
* @param type Type of a directive to look for.
|
* @param type Type of a directive to look for.
|
||||||
* @returns Index of a found directive or null when none found.
|
* @returns Index of a found directive or null when none found.
|
||||||
*/
|
*/
|
||||||
function geIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
|
function getIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
|
||||||
const defs = node.view.tView.directives !;
|
const defs = node.view.tView.directives !;
|
||||||
const flags = node.tNode !.flags;
|
const flags = node.tNode !.flags;
|
||||||
const size = (flags & TNodeFlags.SIZE_MASK) >> TNodeFlags.SIZE_SHIFT;
|
const count = flags & TNodeFlags.DirectiveCountMask;
|
||||||
for (let i = flags >> TNodeFlags.INDX_SHIFT, ii = i + size; i < ii; i++) {
|
const start = flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
|
const end = start + count;
|
||||||
|
for (let i = start; i < end; i++) {
|
||||||
const def = defs[i] as DirectiveDef<any>;
|
const def = defs[i] as DirectiveDef<any>;
|
||||||
if (def.diPublic && def.type === type) {
|
if (def.type === type && def.diPublic) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,7 +214,7 @@ function readFromNodeInjector(
|
|||||||
if (read instanceof ReadFromInjectorFn) {
|
if (read instanceof ReadFromInjectorFn) {
|
||||||
return read.read(nodeInjector, node, directiveIdx);
|
return read.read(nodeInjector, node, directiveIdx);
|
||||||
} else {
|
} else {
|
||||||
const matchingIdx = geIdxOfMatchingDirective(node, read as Type<any>);
|
const matchingIdx = getIdxOfMatchingDirective(node, read as Type<any>);
|
||||||
if (matchingIdx !== null) {
|
if (matchingIdx !== null) {
|
||||||
return node.view.directives ![matchingIdx];
|
return node.view.directives ![matchingIdx];
|
||||||
}
|
}
|
||||||
@ -226,7 +228,7 @@ function add(query: LQuery<any>| null, node: LNode) {
|
|||||||
const predicate = query.predicate;
|
const predicate = query.predicate;
|
||||||
const type = predicate.type;
|
const type = predicate.type;
|
||||||
if (type) {
|
if (type) {
|
||||||
const directiveIdx = geIdxOfMatchingDirective(node, type);
|
const directiveIdx = getIdxOfMatchingDirective(node, type);
|
||||||
if (directiveIdx !== null) {
|
if (directiveIdx !== null) {
|
||||||
// a node is matching a predicate - determine what to read
|
// a node is matching a predicate - determine what to read
|
||||||
// if read token and / or strategy is not specified, use type as read token
|
// if read token and / or strategy is not specified, use type as read token
|
||||||
|
@ -74,7 +74,7 @@ describe('di', () => {
|
|||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
type: DirA,
|
type: DirA,
|
||||||
selectors: [['', 'dirA', '']],
|
selectors: [['', 'dirA', '']],
|
||||||
factory: () => new DirA,
|
factory: () => new DirA(),
|
||||||
features: [PublicFeature]
|
features: [PublicFeature]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user