-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import {CONST} from 'facade/lang'; | ||
import {DependencyAnnotation} from 'di/di'; | ||
|
||
export class Parent extends DependencyAnnotation { | ||
@CONST() | ||
constructor() { | ||
} | ||
} | ||
|
||
export class Ancestor extends DependencyAnnotation { | ||
@CONST() | ||
constructor() { | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,48 @@ | ||
import {FIELD} from 'facade/lang'; | ||
import {FIELD, isPresent, isBlank, Type, int} from 'facade/lang'; | ||
import {List} from 'facade/collection'; | ||
import {ListWrapper} from 'facade/collection'; | ||
import {Key, Dependency, bind, Binding, NoProviderError, ProviderError} from 'di/di'; | ||
import {Parent, Ancestor} from 'core/annotations/visibility'; | ||
|
||
class TreeNode { | ||
@FIELD('_parent:TreeNode') | ||
@FIELD('_head:TreeNode') | ||
@FIELD('_tail:TreeNode') | ||
@FIELD('_next:TreeNode') | ||
@FIELD('_prev:TreeNode') | ||
constructor(parent:TreeNode) { | ||
this._parent = parent; | ||
this._head = null; | ||
this._tail = null; | ||
this._next = null; | ||
this._prev = null; | ||
if (isPresent(parent)) parent._addChild(this); | ||
} | ||
|
||
_addChild(child:TreeNode) { | ||
This comment has been minimized.
Sorry, something went wrong. |
||
if (isPresent(this._tail)) { | ||
this._tail._next = child; | ||
child._prev = this._tail; | ||
this._tail = child; | ||
} else { | ||
this._tail = this._head = child; | ||
} | ||
} | ||
|
||
parent() { | ||
return this._parent; | ||
} | ||
|
||
children() { | ||
var res = []; | ||
var child = this._head; | ||
while (child != null) { | ||
ListWrapper.push(res, child); | ||
child = child._next; | ||
} | ||
return res; | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -18,53 +62,100 @@ ElementInjector (ElementModule): | |
- 1:1 to DOM structure. | ||
PERF BENCHMARK: http://www.williambrownstreet.net/blog/2014/04/faster-angularjs-rendering-angularjs-and-reactjs/ | ||
*/ | ||
|
||
export class ProtoElementInjector { | ||
export class ProtoElementInjector extends TreeNode { | ||
/** | ||
parent:ProtoDirectiveInjector; | ||
next:ProtoDirectiveInjector; | ||
prev:ProtoDirectiveInjector; | ||
head:ProtoDirectiveInjector; | ||
tail:ProtoDirectiveInjector; | ||
DirectiveInjector cloneingInstance; | ||
DirectiveInjector cloningInstance; | ||
KeyMap keyMap; | ||
/// Because DI tree is sparse, this shows how far away is the Parent DI | ||
parentDistance:int = 1; /// 1 for non-sparse/normal depth. | ||
cKey:int; cFactory:Function; cParams:List<int>; | ||
keyId0:int; factory0:Function; params0:List<int>; | ||
keyId1:int; factory1:Function; params1:List<int>; | ||
keyId2:int; factory2:Function; params2:List<int>; | ||
keyId3:int; factory3:Function; params3:List<int>; | ||
keyId4:int; factory4:Function; params4:List<int>; | ||
keyId5:int; factory5:Function; params5:List<int>; | ||
keyId6:int; factory6:Function; params6:List<int>; | ||
keyId7:int; factory7:Function; params7:List<int>; | ||
keyId8:int; factory8:Function; params8:List<int>; | ||
keyId9:int; factory9:Function; params9:List<int>; | ||
queryKeyId0:int; | ||
queryKeyId1:int; | ||
_keyId0:int; factory0:Function; params0:List<int>; | ||
_keyId1:int; factory1:Function; params1:List<int>; | ||
_keyId2:int; factory2:Function; params2:List<int>; | ||
_keyId3:int; factory3:Function; params3:List<int>; | ||
_keyId4:int; factory4:Function; params4:List<int>; | ||
_keyId5:int; factory5:Function; params5:List<int>; | ||
_keyId6:int; factory6:Function; params6:List<int>; | ||
_keyId7:int; factory7:Function; params7:List<int>; | ||
_keyId8:int; factory8:Function; params8:List<int>; | ||
_keyId9:int; factory9:Function; params9:List<int>; | ||
query_keyId0:int; | ||
query_keyId1:int; | ||
textNodes:List<int>; | ||
hasProperties:boolean; | ||
events:Map<string, Expression>; | ||
elementInjector:ElementInjector; | ||
*/ | ||
constructor(parent:ProtoElementInjector) { | ||
@FIELD('_elementInjector:ElementInjector') | ||
@FIELD('_binding0:Binding') | ||
@FIELD('_binding1:Binding') | ||
@FIELD('_binding2:Binding') | ||
@FIELD('_key0:int') | ||
@FIELD('_key1:int') | ||
@FIELD('_key2:int') | ||
constructor(directiveTypes:List, parent:ProtoElementInjector) { | ||
This comment has been minimized.
Sorry, something went wrong.
rkirov
|
||
super(parent); | ||
|
||
this._elementInjector = null; | ||
|
||
this._binding0 = null; | ||
this._binding1 = null; | ||
this._binding2 = null; | ||
|
||
this._keyId0 = null; | ||
this._keyId1 = null; | ||
this._keyId2 = null; | ||
|
||
var length = directiveTypes.length; | ||
|
||
if (length > 0) { | ||
this._binding0 = this._createBinding(directiveTypes[0]); | ||
this._keyId0 = this._binding0.key.id; | ||
} | ||
|
||
if (length > 1) { | ||
this._binding1 = this._createBinding(directiveTypes[1]); | ||
this._keyId1 = this._binding1.key.id; | ||
} | ||
|
||
if (length > 2) { | ||
this._binding2 = this._createBinding(directiveTypes[2]); | ||
this._keyId2 = this._binding2.key.id; | ||
} | ||
|
||
// dummy fields to make analyzer happy | ||
this.textNodes = []; | ||
this.hasProperties = false; | ||
this.textNodes = null; | ||
} | ||
|
||
instantiate():ElementInjector { | ||
return new ElementInjector(this); | ||
instantiate({appInjector}={}):ElementInjector { | ||
var p = this._parent; | ||
var parentElementInjector = p == null ? null : p._elementInjector; | ||
this._elementInjector = new ElementInjector({ | ||
proto: this, | ||
parent: parentElementInjector, | ||
appInjector: appInjector | ||
}); | ||
return this._elementInjector; | ||
} | ||
|
||
_createBinding(directiveType:Type) { | ||
return bind(directiveType).toClass(directiveType); | ||
} | ||
} | ||
|
||
export class ElementInjector { | ||
export class ElementInjector extends TreeNode { | ||
This comment has been minimized.
Sorry, something went wrong.
rkirov
|
||
/* | ||
_protoInjector:ProtoElementInjector; | ||
injector:Injector; | ||
|
@@ -107,10 +198,86 @@ export class ElementInjector { | |
_query1:Query; | ||
*/ | ||
@FIELD('final protoInjector:ProtoElementInjector') | ||
constructor(protoInjector:ProtoElementInjector) { | ||
this.protoInjector = protoInjector; | ||
|
||
@FIELD('_proto:ProtoElementInjector') | ||
@FIELD('_appInjector:Injector') | ||
constructor({proto, parent, appInjector}) { | ||
super(parent); | ||
this._proto = proto; | ||
this._appInjector = appInjector; | ||
|
||
this._obj0 = null; | ||
this._obj1 = null; | ||
this._obj2 = null; | ||
} | ||
|
||
instantiateDirectives() { | ||
var p = this._proto; | ||
this._obj0 = this._new(p._binding0); | ||
this._obj1 = this._new(p._binding1); | ||
this._obj2 = this._new(p._binding2); | ||
} | ||
|
||
get(token) { | ||
return this._getByKey(Key.get(token), 0); | ||
} | ||
|
||
_new(binding:Binding) { | ||
if (isBlank(binding)) return null; | ||
|
||
var factory = binding.factory; | ||
var deps = binding.dependencies; | ||
var length = deps.length; | ||
|
||
var d0,d1,d2; | ||
try { | ||
d0 = length > 0 ? this._getByDependency(deps[0]) : null; | ||
d1 = length > 1 ? this._getByDependency(deps[1]) : null; | ||
d2 = length > 2 ? this._getByDependency(deps[2]) : null; | ||
} catch(e) { | ||
if (e instanceof ProviderError) e.addKey(binding.key); | ||
throw e; | ||
} | ||
|
||
var obj; | ||
switch(length) { | ||
case 0: obj = factory(); break; | ||
case 1: obj = factory(d0); break; | ||
case 2: obj = factory(d0, d1); break; | ||
case 3: obj = factory(d0, d1, d2); break; | ||
} | ||
|
||
return obj; | ||
} | ||
|
||
_getByDependency(dep:Dependency) { | ||
return this._getByKey(dep.key, this._depth(dep.properties)); | ||
} | ||
|
||
_getByKey(key:Key, depth:int) { | ||
var ei = this; | ||
while (ei != null && depth >= 0) { | ||
var obj = ei._getDirectiveByKey(key); | ||
if (isPresent(obj)) return obj; | ||
ei = ei._parent; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong. |
||
} | ||
return this._appInjector.get(key); | ||
} | ||
|
||
//TODO: this can be moved to Proto | ||
_depth(properties):int { | ||
if (properties.length == 0) return 0; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
vsavkin
Author
Owner
|
||
if (properties[0] instanceof Parent) return 1; | ||
if (properties[0] instanceof Ancestor) return 99999; | ||
This comment has been minimized.
Sorry, something went wrong.
rkirov
|
||
return 0; | ||
} | ||
|
||
_getDirectiveByKey(key:Key) { | ||
var p = this._proto; | ||
if (p._keyId0 === key.id) return this._obj0; | ||
if (p._keyId1 === key.id) return this._obj1; | ||
if (p._keyId2 === key.id) return this._obj2; | ||
return null; | ||
} | ||
} | ||
|
There is implicit assumption child being added is newly constructed with null pointers, since we do not reset child._next for example. That is fine because it is the only use, but add a comment.