diff --git a/modules/change_detection/src/change_detection.js b/modules/change_detection/src/change_detection.js index 3c578a523e..a03fdd770c 100644 --- a/modules/change_detection/src/change_detection.js +++ b/modules/change_detection/src/change_detection.js @@ -1,5 +1,22 @@ +import {WatchGroup} from './watch_group'; +import {Record} from './record'; + export class ChangeDetection { + + @FIELD('final _rootWatchGroup:WatchGroup') + constructor(watchGroup:WatchGroup) { + this._rootWatchGroup = watchGroup; + } + + detectChanges():int { + var current:Record = _rootWatchGroup._headRecord; + var count:number = 0; + while(current != null) { + if(current.check()) { + count++; + } + } + return count; + } - detectChanges():int {} - -} \ No newline at end of file +} diff --git a/modules/change_detection/src/proto_record.js b/modules/change_detection/src/proto_record.js deleted file mode 100644 index b7a05672fa..0000000000 --- a/modules/change_detection/src/proto_record.js +++ /dev/null @@ -1,3 +0,0 @@ -export class ProtoRecord { - -} \ No newline at end of file diff --git a/modules/change_detection/src/proto_watch_group.js b/modules/change_detection/src/proto_watch_group.js deleted file mode 100644 index 3c83902ab2..0000000000 --- a/modules/change_detection/src/proto_watch_group.js +++ /dev/null @@ -1,27 +0,0 @@ -export class ProtoWatchGroup { - watch( - expression:String, - context:dynamic, - {isCollection}) - { - - } -} - -/* -@Component( - bind: { - 'title': 'title', - 'name': 'name' - } -) -class MyComponent implements ChangeListener { - String name; - String title; - - onChange(List changes) { - - } -} - -*/ \ No newline at end of file diff --git a/modules/change_detection/src/record.js b/modules/change_detection/src/record.js index 0fefaefcc1..53fd496a37 100644 --- a/modules/change_detection/src/record.js +++ b/modules/change_detection/src/record.js @@ -1,4 +1,54 @@ -import {WatchGroup} from './watch_group'; +import {ProtoWatchGroup, WatchGroup} from './watch_group'; + +export class ProtoRecord { + + @FIELD('final watchGroup:ProtoWatchGroup') + @FIELD('final fieldName:String') + /// order list of all records. Including head/tail markers + @FIELD('next:ProtoRecord') + @FIELD('prev:ProtoRecord') + /// next record to dirty check + @FIELD('_checkNext:ProtoRecord') + @FIELD('_checkPrev:ProtoRecord') + // next notifier + @FIELD('_notifierNext:ProtoRecord') + // Opeque data which will be presented to WatchGroupDispatcher + @FIELD('dispatcherContext') + // IF we detect change, we have to update the _context of the + // next record. + @FIELD('_updateContext:ProtoRecord') + // May be removed if we don't support coelsence. + @FIELD('_updateContextNext:ProtoRecord') + @FIELD('_clone') + constructor(watchGroup:ProtoWatchGroup, fieldName:String) { + this.watchGroup = watchGroup; + this.fieldName = fieldName; + this._next = null; + this._prev = null; + this._checkNext = null; + this._checkPrev = null; + this._notifierNext = null; + this.dispatcherContext = null; + this._updateContext = null; + this._updateContextNext = null; + this._clone = null; + } + + instantiate(watchGroup:WatchGroup):Record { + var record = this._clone = new Record(watchGroup, this); + record._prev = this._prev._clone; + record._checkPrev = this._checkPrev._clone; + return _clone; + } + + instantiateComplete():Record { + var record = this._clone; + record._next = this._next._clone; + record._checkNext = this._checkNext._clone; + this._clone = null; + return this._next; + } +} /** @@ -19,13 +69,8 @@ import {WatchGroup} from './watch_group'; */ export class Record { - @FIELD('final _watchGroup:WatchGroup') - @FIELD('final _protoRecord:ProtoRecord') - @FIELD('_context') - @FIELD('_getter') - @FIELD('_arguments') - @FIELD('_previousValue') - @FIELD('_mode:int') + @FIELD('final watchGroup:WatchGroup') + @FIELD('final protoRecord:ProtoRecord') /// order list of all records. Including head/tail markers @FIELD('_next:Record') @FIELD('_prev:Record') @@ -37,18 +82,40 @@ export class Record { // notifier context will be present to the notifier to release // the object from notification/watching. @FIELD('_notifierContext') - // Opeque data which will be presented to WatchGroupDispatcher - @FIELD('_watchContext') // IF we detect change, we have to update the _context of the // next record. @FIELD('_updateContext:Record') // May be removed if we don't support coelsence. @FIELD('_updateContextNext:Record') - constructor() { + + @FIELD('_mode:int') + @FIELD('_context') + @FIELD('_getter') + @FIELD('_arguments') + @FIELD('currentValue') + @FIELD('previousValue') + constructor(watchGroup:WatchGroup, protoRecord:ProtoRecord) { + this.protoRecord = protoRecord; + this.watchGroup = watchGroup; + this._next = null; + this._prev = null; + this._checkNext = null; + this._checkPrev = null; + this._notifierNext = null; + this._notifierContext = null; + this._updateContext = null; + this._updateContextNext = null; + + this._mode = MODE_STATE_MARKER; + this._context = null; + this._getter = null; + this._arguments = null; + this.currentValue = null; + this.previousValue = null; } check():bool { - var mode = this.mode; + var mode = this._mode; var state = mode & MODE_MASK_STATE; var notify = mode & MODE_MASK_NOTIFY; var currentValue; @@ -67,14 +134,15 @@ export class Record { case MODE_STATE_MAP: case MODE_STATE_LIST: } - var previousValue = this._previousValue; + var previousValue = this.previousValue; if (isSame(previousValue, currentValue)) return false; if (previousValue instanceof String && currentValue instanceof String && previousValue == currentValue) { - this._previousValue = currentValue; + this.previousValue = currentValue; return false } - this.previousValue = previousValue; + this.previousValue = currentValue; + this.watchGroup.dispatcher.onRecordChange(this, this.protoRecord.dispatcherContext); return true; } } @@ -83,24 +151,24 @@ export class Record { // to use and which dereference mode to execute. // We use dirty checking aka no notification -var MODE_MASK_NOTIFY:number = 0xFF00; +const MODE_MASK_NOTIFY = 0xFF00; // Encodes the state of dereference -var MODE_MASK_STATE:int = 0x00FF; +const MODE_MASK_STATE = 0x00FF; -var MODE_PLUGIN_DIRTY_CHECK:int = 0x0000; -var MODE_STATE_MARKER:int = 0x0000; +const MODE_PLUGIN_DIRTY_CHECK = 0x0000; +const MODE_STATE_MARKER = 0x0000; /// _context[_protoRecord.propname] => _getter(_context) -var MODE_STATE_PROPERTY:int = 0x0001; +const MODE_STATE_PROPERTY = 0x0001; /// _context(_arguments) -var MODE_STATE_INVOKE_CLOSURE:int = 0x0002; +const MODE_STATE_INVOKE_CLOSURE = 0x0002; /// _getter(_context, _arguments) -var MODE_STATE_INVOKE_METHOD:int = 0x0003; +const MODE_STATE_INVOKE_METHOD = 0x0003; /// _context is Map => _previousValue is MapChangeRecord -var MODE_STATE_MAP:int = 0x0004; +const MODE_STATE_MAP = 0x0004; /// _context is Array/List/Iterable => _previousValue = ListChangeRecord -var MODE_STATE_LIST:int = 0x0005; +const MODE_STATE_LIST = 0x0005; function isSame(a, b) { if (a === b) { diff --git a/modules/change_detection/src/watch_group.js b/modules/change_detection/src/watch_group.js index 53b89fa1bd..dcc87dc4cd 100644 --- a/modules/change_detection/src/watch_group.js +++ b/modules/change_detection/src/watch_group.js @@ -1,4 +1,63 @@ +import {ProtoRecord, Record} from './record'; +import {WatchGroupDispatcher} from './watch_group_dispatcher'; + +export class ProtoWatchGroup { + @FIELD('final _headRecord:ProtoRecord') + @FIELD('final _tailRecord:ProtoRecord') + constructor() { + this._headRecord = null; + this._tailRecord = null; + } + + watch( + expression:String, + context, + {isCollection}) + { + /// IMPREMENT + } + + instantiate(dispatcher:WatchGroupDispatcher):WatchGroup { + var watchGroup:WatchGroup = new WatchGroup(this, dispatcher); + var head:Record = null; + var tail:Record = null; + var proto:ProtoRecord = this._headRecord; + + while(proto != null) { + tail = proto.instantiate(watchGroup); + if (head == null) head = tail; + proto = proto.next; + } + + proto = this._headRecord; + while(proto != null) { + proto = proto.instantiateComplete(); + } + + watchGroup._headRecord = head; + watchGroup._tailRecord = tail; + return watchGroup; + } +} + export class WatchGroup { + @FIELD('final protoWatchGroup:ProtoWatchGroup') @FIELD('final dispatcher:WatchGroupDispatcher') - constructor() {} -} \ No newline at end of file + @FIELD('final _headRecord:Record') + @FIELD('final _tailRecord:Record') + constructor(protoWatchGroup:ProtoWatchGroup, dispatcher:WatchGroupDispatcher) { + this.protoWatchGroup = protoWatchGroup; + this.dispatcher = dispatcher; + this._headRecord = null; + this._tailRecord = null; + } + + insertChildGroup(newChild:WatchGroup, insertAfter:WatchGroup) { + /// IMPLEMENT + } + + remove() { + /// IMPLEMENT + } + +} diff --git a/modules/change_detection/src/watch_group_dispatcher.js b/modules/change_detection/src/watch_group_dispatcher.js index 58fae35b74..1685cff545 100644 --- a/modules/change_detection/src/watch_group_dispatcher.js +++ b/modules/change_detection/src/watch_group_dispatcher.js @@ -1,4 +1,5 @@ +import {Record} from './record'; export class WatchGroupDispatcher { - notify(record:Record, context) {} -} \ No newline at end of file + onRecordChange(record:Record, context) {} +} diff --git a/modules/core/src/core.js b/modules/core/src/core.js index bfcb8bc763..fe4021a636 100644 --- a/modules/core/src/core.js +++ b/modules/core/src/core.js @@ -6,6 +6,7 @@ export * from './annotations/component'; export * from './annotations/template_config'; export * from 'change_detection/change_detection'; +export * from 'change_detection/watch_group'; export * from 'change_detection/record'; export * from './compiler/compiler'; diff --git a/modules/core/src/view/view.js b/modules/core/src/view/view.js index 506432ce43..51213c73a3 100644 --- a/modules/core/src/view/view.js +++ b/modules/core/src/view/view.js @@ -1,5 +1,6 @@ import {Node, DocumentFragment} from 'facade/dom'; import {ListWrapper wraps List} from 'facade/collection'; +import {WatchGroupDispatcher} from 'change_detection/watch_group_dispatcher'; import {Record} from 'change_detection/record'; @IMPLEMENTS(WatchGroupDispatcher) @@ -18,17 +19,17 @@ export class View { this._nodes = ListWrapper.clone(fragment.childNodes); } - notify(record:Record, target) { - /* + onRecordChange(record:Record, target) { // dispatch to element injector or text nodes based on context - if (Number.is(target)) { - // we know it refferst to _textNodes. - } else { + if (target is ElementInjectorTarge) { // we know that it is ElementInjectorTarge var eTarget:ElementInjectorTarget = target; onChangeDispatcher.notify(this, eTarget); eTarget.invoke(record, _elementInjectors); + } else { + // we know it refferst to _textNodes. + var textNodeIndex:number = target; + DOM.setText(this._textNodes[textNodeIndex], record.currentValue); } - */ } } diff --git a/modules/facade/src/dom.dart b/modules/facade/src/dom.dart index aa41098f83..2ee48f555e 100644 --- a/modules/facade/src/dom.dart +++ b/modules/facade/src/dom.dart @@ -2,7 +2,7 @@ library angular.core.facade.dom; import 'dart:html'; -export 'dart:html' show DocumentFragment, Node, Element, TemplateElement; +export 'dart:html' show DocumentFragment, Node, Element, TemplateElement, Text; class DOM { static query(selector) { @@ -14,7 +14,10 @@ class DOM { static getInnerHTML(el) { return el.innerHtml; } - static setInnerHTML(el, value) { + static setInnerHTML(el:, value) { el.innerHtml = value; } -} \ No newline at end of file + static setText(Text text, String value) { + text.text = value; + } +} diff --git a/modules/facade/src/dom.es6 b/modules/facade/src/dom.es6 index 87f2b0b921..b6d593bd6e 100644 --- a/modules/facade/src/dom.es6 +++ b/modules/facade/src/dom.es6 @@ -1,5 +1,6 @@ export var DocumentFragment = window.DocumentFragment; export var Node = window.Node; +export var Text = window.Text; export var Element = window.HTMLElement; export var TemplateElement = window.HTMLTemplateElement; @@ -16,4 +17,7 @@ export class DOM { static setInnerHTML(el, value) { el.innerHTML = value; } -} \ No newline at end of file + static setText(text:Text, value:String) { + text.nodeValue = value; + } +}