feat(view): add onChange implementation to view.

This commit is contained in:
Rado Kirov
2014-10-27 23:16:31 -07:00
parent e1c84e02f8
commit b0c9d05ea7
7 changed files with 162 additions and 52 deletions

View File

@ -118,7 +118,6 @@ export class ProtoElementInjector extends TreeNode {
query_keyId1:int;
textNodes:List<int>;
hasProperties:boolean;
events:Map<string, Expression>;
elementInjector:ElementInjector;
@ -144,8 +143,10 @@ export class ProtoElementInjector extends TreeNode {
@FIELD('_key7:int')
@FIELD('_key8:int')
@FIELD('_key9:int')
@FIELD('textNodes:List<int>')
constructor(parent:ProtoElementInjector, bindings:List, textNodes:List) {
@FIELD('textNodeIndices:List<int>')
@FIELD('hasElementPropertyBindings:bool')
constructor(parent:ProtoElementInjector, bindings:List, textNodeIndices:List,
hasElementPropertyBindings:boolean) {
super(parent);
this._elementInjector = null;
@ -177,10 +178,8 @@ export class ProtoElementInjector extends TreeNode {
throw 'Maximum number of directives per element has been reached.';
}
this.textNodes = textNodes;
// dummy fields to make analyzer happy
this.hasProperties = false;
this.textNodeIndices = textNodeIndices;
this.hasElementPropertyBindings = hasElementPropertyBindings;
}
instantiate({view}):ElementInjector {
@ -418,5 +417,28 @@ export class ElementInjector extends TreeNode {
if (p._keyId9 === keyId) return this._obj9;
return _undefined;
}
getAtIndex(index:int) {
if (index == 0) return this._obj0;
if (index == 1) return this._obj1;
if (index == 2) return this._obj2;
if (index == 3) return this._obj3;
if (index == 4) return this._obj4;
if (index == 5) return this._obj5;
if (index == 6) return this._obj6;
if (index == 7) return this._obj7;
if (index == 8) return this._obj8;
if (index == 9) return this._obj9;
throw new OutOfBoundsAccess(index);
}
}
class OutOfBoundsAccess extends Error {
constructor(index) {
this.message = `Index ${index} is out-of-bounds.`;
}
toString() {
return this.message;
}
}

View File

@ -23,14 +23,15 @@ export class View {
/// to keep track of the nodes.
@FIELD('final nodes:List<Node>')
@FIELD('final onChangeDispatcher:OnChangeDispatcher')
constructor(fragment:DocumentFragment, elementInjector:List, rootElementInjectors:List, textNodes:List) {
constructor(fragment:DocumentFragment, elementInjector:List,
rootElementInjectors:List, textNodes:List, bindElements:List) {
this.fragment = fragment;
this.nodes = ListWrapper.clone(fragment.childNodes);
this.elementInjectors = elementInjector;
this.rootElementInjectors = rootElementInjectors;
this.onChangeDispatcher = null;
this.textNodes = textNodes;
this.bindElements = null;
this.bindElements = bindElements;
}
onRecordChange(record:Record, target) {
@ -39,7 +40,7 @@ export class View {
// we know that it is DirectivePropertyMemento
var directiveMemento:DirectivePropertyMemento = target;
directiveMemento.invoke(record, this.elementInjectors);
} else if (target instanceof ElementPropertyMemento) {
} else if (target instanceof ElementPropertyMemento) {
var elementMemento:ElementPropertyMemento = target;
elementMemento.invoke(record, this.bindElements);
} else {
@ -83,8 +84,10 @@ export class ProtoView {
var elementInjectors = ProtoView._createElementInjectors(elements, protos);
var rootElementInjectors = ProtoView._rootElementInjectors(elementInjectors);
var textNodes = ProtoView._textNodes(elements, protos);
var bindElements = ProtoView._bindElements(elements, protos);
return new View(fragment, elementInjectors, rootElementInjectors, textNodes);
return new View(fragment, elementInjectors, rootElementInjectors, textNodes,
bindElements);
}
static _createElementInjectors(elements, protos) {
@ -92,7 +95,11 @@ export class ProtoView {
for (var i = 0; i < protos.length; ++i) {
injectors[i] = ProtoView._createElementInjector(elements[i], protos[i]);
}
ListWrapper.forEach(protos, p => p.clearElementInjector());
// Cannot be rolled into loop above, because parentInjector pointers need
// to be set on the children.
for (var i = 0; i < protos.length; ++i) {
protos[i].clearElementInjector();
}
return injectors;
}
@ -108,16 +115,26 @@ export class ProtoView {
static _textNodes(elements, protos) {
var textNodes = [];
for (var i = 0; i < protos.length; ++i) {
ProtoView._collectTextNodes(textNodes, elements[i], protos[i]);
ProtoView._collectTextNodes(textNodes, elements[i],
protos[i].textNodeIndices);
}
return textNodes;
}
static _collectTextNodes(allTextNodes, element, proto) {
static _bindElements(elements, protos):List<Element> {
var bindElements = [];
for (var i = 0; i < protos.length; ++i) {
if (protos[i].hasElementPropertyBindings) ListWrapper.push(
bindElements, elements[i]);
}
return bindElements;
}
static _collectTextNodes(allTextNodes, element, indices) {
var childNodes = DOM.childNodes(element);
ListWrapper.forEach(proto.textNodes, (i) => {
ListWrapper.push(allTextNodes, childNodes[i]);
});
for (var i = 0; i < indices.length; ++i) {
ListWrapper.push(allTextNodes, childNodes[indices[i]]);
}
}
}
@ -129,8 +146,8 @@ export class ElementPropertyMemento {
this._propertyName = propertyName;
}
invoke(record:Record, elementInjectors:List<Element>) {
var element:Element = elementInjectors[this._elementIndex];
invoke(record:Record, bindElements:List<Element>) {
var element:Element = bindElements[this._elementIndex];
DOM.setProperty(element, this._propertyName, record.currentValue);
}
}
@ -138,14 +155,13 @@ export class ElementPropertyMemento {
export class DirectivePropertyMemento {
@FIELD('final _elementInjectorIndex:int')
@FIELD('final _directiveIndex:int')
@FIELD('final _setterName:String')
@FIELD('final _setterName:string')
@FIELD('final _setter:SetterFn')
constructor(
elementInjectorIndex:number,
directiveIndex:number,
setterName:String,
setter:SetterFn)
{
setterName:string,
setter:SetterFn) {
this._elementInjectorIndex = elementInjectorIndex;
this._directiveIndex = directiveIndex;
this._setterName = setterName;
@ -154,7 +170,7 @@ export class DirectivePropertyMemento {
invoke(record:Record, elementInjectors:List<ElementInjector>) {
var elementInjector:ElementInjector = elementInjectors[this._elementInjectorIndex];
var directive = elementInjectors[this._directiveIndex];
var directive = elementInjector.getAtIndex(this._directiveIndex);
this._setter(directive, record.currentValue);
}
}