From e15bcf0ffd833777df495788e7943cac29cbac11 Mon Sep 17 00:00:00 2001 From: vsavkin Date: Fri, 14 Nov 2014 12:34:35 -0800 Subject: [PATCH] refactor(ChangeDetector): pass formatters when instantiating a watch group --- modules/change_detection/src/record.js | 10 ++++++++-- modules/change_detection/src/watch_group.js | 19 ++++++++----------- .../test/change_detector_spec.js | 12 ++++++------ modules/core/src/compiler/view.js | 4 ++-- modules/core/test/compiler/view_spec.js | 16 ++++++++-------- 5 files changed, 32 insertions(+), 29 deletions(-) diff --git a/modules/change_detection/src/record.js b/modules/change_detection/src/record.js index fff5e451af..5eb1723597 100644 --- a/modules/change_detection/src/record.js +++ b/modules/change_detection/src/record.js @@ -1,6 +1,6 @@ import {ProtoWatchGroup, WatchGroup} from './watch_group'; import {FIELD, isPresent, int, StringWrapper, FunctionWrapper, BaseException} from 'facade/lang'; -import {ListWrapper} from 'facade/collection'; +import {ListWrapper, MapWrapper} from 'facade/collection'; import {ClosureMap} from 'change_detection/parser/closure_map'; var _fresh = new Object(); @@ -8,6 +8,7 @@ var _fresh = new Object(); export const PROTO_RECORD_CONST = 'const'; export const PROTO_RECORD_PURE_FUNCTION = 'func'; export const PROTO_RECORD_CLOSURE = 'closure'; +export const PROTO_RECORD_FORMATTTER = 'formatter'; export const PROTO_RECORD_METHOD = 'method'; export const PROTO_RECORD_PROPERTY = 'property'; @@ -79,7 +80,7 @@ export class Record { // Otherwise it is the context used by WatchGroupDispatcher. @FIELD('dest') - constructor(watchGroup:WatchGroup, protoRecord:ProtoRecord) { + constructor(watchGroup:WatchGroup, protoRecord:ProtoRecord, formatters:Map) { this.watchGroup = watchGroup; this.protoRecord = protoRecord; @@ -105,6 +106,11 @@ export class Record { this.funcOrValue = protoRecord.funcOrValue; this.args = ListWrapper.createFixedSize(protoRecord.arity); + } else if (type === PROTO_RECORD_FORMATTTER) { + this.mode = MODE_STATE_INVOKE_PURE_FUNCTION; + this.funcOrValue = MapWrapper.get(formatters, protoRecord.funcOrValue); + this.args = ListWrapper.createFixedSize(protoRecord.arity); + } else if (type === PROTO_RECORD_METHOD) { this.mode = MODE_STATE_INVOKE_METHOD; this.funcOrValue = protoRecord.funcOrValue; diff --git a/modules/change_detection/src/watch_group.js b/modules/change_detection/src/watch_group.js index fc484f43c4..f8b93ad8f4 100644 --- a/modules/change_detection/src/watch_group.js +++ b/modules/change_detection/src/watch_group.js @@ -1,5 +1,5 @@ import {ProtoRecord, Record, PROTO_RECORD_CONST, PROTO_RECORD_PURE_FUNCTION, - PROTO_RECORD_PROPERTY, PROTO_RECORD_METHOD, PROTO_RECORD_CLOSURE} from './record'; + PROTO_RECORD_PROPERTY, PROTO_RECORD_METHOD, PROTO_RECORD_CLOSURE, PROTO_RECORD_FORMATTTER} from './record'; import {FIELD, IMPLEMENTS, isBlank, isPresent, int, toBool, autoConvertAdd, BaseException} from 'facade/lang'; import {ListWrapper, MapWrapper} from 'facade/collection'; import {AST, AccessMember, ImplicitReceiver, AstVisitor, LiteralPrimitive, @@ -9,9 +9,7 @@ import {AST, AccessMember, ImplicitReceiver, AstVisitor, LiteralPrimitive, export class ProtoWatchGroup { @FIELD('headRecord:ProtoRecord') @FIELD('tailRecord:ProtoRecord') - constructor(formatters=null) { - this.formatters = formatters; - + constructor() { this.headRecord = null; this.tailRecord = null; } @@ -47,25 +45,25 @@ export class ProtoWatchGroup { // TODO(rado): the type annotation should be dispatcher:WatchGroupDispatcher. // but @Implements is not ready yet. - instantiate(dispatcher):WatchGroup { + instantiate(dispatcher, formatters:Map):WatchGroup { var watchGroup:WatchGroup = new WatchGroup(this, dispatcher); if (this.headRecord !== null) { - this._createRecords(watchGroup); + this._createRecords(watchGroup, formatters); this._setDestination(); } return watchGroup; } - _createRecords(watchGroup:WatchGroup) { + _createRecords(watchGroup:WatchGroup, formatters:Map) { var tail, prevRecord; - watchGroup.headRecord = tail = new Record(watchGroup, this.headRecord); + watchGroup.headRecord = tail = new Record(watchGroup, this.headRecord, formatters); this.headRecord.recordInConstruction = watchGroup.headRecord; for (var proto = this.headRecord.next; proto != null; proto = proto.next) { prevRecord = tail; - tail = new Record(watchGroup, proto); + tail = new Record(watchGroup, proto, formatters); proto.recordInConstruction = tail; tail.prev = prevRecord; @@ -178,8 +176,7 @@ class ProtoRecordCreator { } visitFormatter(ast:Formatter, dest) { - var formatter = this.protoWatchGroup.formatters[ast.name]; - var record = this.construct(PROTO_RECORD_PURE_FUNCTION, formatter, ast.allArgs.length, dest); + var record = this.construct(PROTO_RECORD_FORMATTTER, ast.name, ast.allArgs.length, dest); for (var i = 0; i < ast.allArgs.length; ++i) { ast.allArgs[i].visit(this, new Destination(record, i)); } diff --git a/modules/change_detection/test/change_detector_spec.js b/modules/change_detection/test/change_detector_spec.js index 3197c11c78..3677949d98 100644 --- a/modules/change_detection/test/change_detector_spec.js +++ b/modules/change_detection/test/change_detector_spec.js @@ -22,11 +22,11 @@ export function main() { } function createChangeDetector(memo:string, exp:string, context = null, formatters = null) { - var pwg = new ProtoWatchGroup(formatters); + var pwg = new ProtoWatchGroup(); pwg.watch(ast(exp), memo, false); var dispatcher = new LoggingDispatcher(); - var wg = pwg.instantiate(dispatcher); + var wg = pwg.instantiate(dispatcher, formatters); wg.setContext(context); var cd = new ChangeDetector(wg); @@ -153,10 +153,10 @@ export function main() { }); it("should support formatters", () => { - var formatters = { - "uppercase" : (v) => v.toUpperCase(), - "wrap" : (v, before, after) => `${before}${v}${after}` - }; + var formatters = MapWrapper.createFromPairs([ + ["uppercase", (v) => v.toUpperCase()], + ["wrap", (v, before, after) => `${before}${v}${after}`] + ]); expect(executeWatch('str', '"aBc" | uppercase', null, formatters)).toEqual(['str=ABC']); expect(executeWatch('str', '"b" | wrap:"a":"c"', null, formatters)).toEqual(['str=abc']); }); diff --git a/modules/core/src/compiler/view.js b/modules/core/src/compiler/view.js index 6b52323a4c..9a82eeebaa 100644 --- a/modules/core/src/compiler/view.js +++ b/modules/core/src/compiler/view.js @@ -1,5 +1,5 @@ import {DOM, Element, Node, Text, DocumentFragment, TemplateElement} from 'facade/dom'; -import {ListWrapper} from 'facade/collection'; +import {ListWrapper, MapWrapper} from 'facade/collection'; import {ProtoWatchGroup, WatchGroup, WatchGroupDispatcher} from 'change_detection/watch_group'; import {Record} from 'change_detection/record'; import {AST} from 'change_detection/parser/ast'; @@ -38,7 +38,7 @@ export class View { this.onChangeDispatcher = null; this.textNodes = textNodes; this.bindElements = bindElements; - this.watchGroup = protoWatchGroup.instantiate(this); + this.watchGroup = protoWatchGroup.instantiate(this, MapWrapper.create()); this.watchGroup.setContext(context); } diff --git a/modules/core/test/compiler/view_spec.js b/modules/core/test/compiler/view_spec.js index 32cab0b94d..a7f0082eda 100644 --- a/modules/core/test/compiler/view_spec.js +++ b/modules/core/test/compiler/view_spec.js @@ -24,7 +24,7 @@ export function main() { describe('collect root nodes', () => { it('should use the ProtoView element if it is no TemplateElement', () => { - var pv = new ProtoView(createElement('
'), new ProtoWatchGroup(null)); + var pv = new ProtoView(createElement('
'), new ProtoWatchGroup()); var view = pv.instantiate(null, null); expect(view.nodes.length).toBe(1); expect(view.nodes[0].getAttribute('id')).toEqual('1'); @@ -43,7 +43,7 @@ export function main() { describe('collect elements with property bindings', () => { it('should collect property bindings on the root element if it has the ng-binding class', () => { - var pv = new ProtoView(createElement('
'), new ProtoWatchGroup(null)); + var pv = new ProtoView(createElement('
'), new ProtoWatchGroup()); pv.bindElement(null); pv.bindElementProperty('prop', parser.parseBinding('a')); @@ -54,7 +54,7 @@ export function main() { it('should collect property bindings on child elements with ng-binding class', () => { var pv = new ProtoView(createElement('
'), - new ProtoWatchGroup(null)); + new ProtoWatchGroup()); pv.bindElement(null); pv.bindElementProperty('a', parser.parseBinding('b')); @@ -68,7 +68,7 @@ export function main() { describe('collect text nodes with bindings', () => { it('should collect text nodes under the root element', () => { - var pv = new ProtoView(createElement('
{{}}{{}}
'), new ProtoWatchGroup(null)); + var pv = new ProtoView(createElement('
{{}}{{}}
'), new ProtoWatchGroup()); pv.bindElement(null); pv.bindTextNode(0, parser.parseBinding('a')); pv.bindTextNode(2, parser.parseBinding('b')); @@ -81,7 +81,7 @@ export function main() { it('should collect text nodes with bindings on child elements with ng-binding class', () => { var pv = new ProtoView(createElement('
{{}}
'), - new ProtoWatchGroup(null)); + new ProtoWatchGroup()); pv.bindElement(null); pv.bindTextNode(0, parser.parseBinding('b')); @@ -149,7 +149,7 @@ export function main() { it('should consume text node changes', () => { var pv = new ProtoView(createElement('
{{}}
'), - new ProtoWatchGroup(null)); + new ProtoWatchGroup()); pv.bindElement(null); pv.bindTextNode(0, parser.parseBinding('foo')); createView(pv); @@ -161,7 +161,7 @@ export function main() { it('should consume element binding changes', () => { var pv = new ProtoView(createElement('
'), - new ProtoWatchGroup(null)); + new ProtoWatchGroup()); pv.bindElement(null); pv.bindElementProperty('id', parser.parseBinding('foo')); createView(pv); @@ -173,7 +173,7 @@ export function main() { it('should consume directive watch expression change.', () => { var pv = new ProtoView(createElement('
'), - new ProtoWatchGroup(null)); + new ProtoWatchGroup()); pv.bindElement(new ProtoElementInjector(null, 0, [Directive])); pv.bindDirectiveProperty( 0, parser.parseBinding('foo'), 'prop', closureMap.setter('prop')); createView(pv);