Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit c1e70ce

Browse files
codelogicmhevery
authored andcommitted
feat(blockhole): Change blockhole to have the insert / remove / move methods.
Closes #689
1 parent 4453e3e commit c1e70ce

File tree

11 files changed

+116
-197
lines changed

11 files changed

+116
-197
lines changed

lib/core_dom/block.dart

Lines changed: 38 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,61 @@
11
part of angular.core.dom;
22

3-
/**
4-
* ElementWrapper is an interface for [Block]s and [BlockHole]s. Its purpose is
5-
* to allow treating [Block] and [BlockHole] under same interface so that
6-
* [Block]s can be added after [BlockHole].
7-
*/
8-
abstract class ElementWrapper {
9-
List<dom.Node> elements;
10-
ElementWrapper next;
11-
ElementWrapper previous;
12-
}
13-
143
/**
154
* A Block is a fundamental building block of DOM. It is a chunk of DOM which
16-
* can not be structural changed. It can only have its attributes changed.
17-
* A Block can have [BlockHole]s embedded in its DOM. A [BlockHole] can
18-
* contain other [Block]s and it is the only way in which DOM can be changed
19-
* structurally.
5+
* can not be structurally changed. A Block can have [BlockHole] placeholders
6+
* embedded in its DOM. A [BlockHole] can contain other [Block]s and it is the
7+
* only way in which DOM structure can be modified.
208
*
219
* A [Block] is a collection of DOM nodes
22-
*
10+
2311
* A [Block] can be created from [BlockFactory].
2412
*
2513
*/
26-
class Block implements ElementWrapper {
27-
List<dom.Node> elements;
28-
ElementWrapper next;
29-
ElementWrapper previous;
14+
class Block {
15+
final List<dom.Node> nodes;
16+
Block(this.nodes);
17+
}
3018

19+
/**
20+
* A BlockHole maintains an ordered list of [Block]'s. It contains a
21+
* [placeholder] node that is used as the insertion point for block nodes.
22+
*/
23+
class BlockHole {
24+
final dom.Node placeholder;
3125
final NgAnimate _animate;
26+
final List<Block> _blocks = <Block>[];
3227

33-
Block(this.elements, this._animate);
34-
35-
Block insertAfter(ElementWrapper previousBlock) {
36-
// Update Link List.
37-
next = previousBlock.next;
38-
if (next != null) {
39-
next.previous = this;
40-
}
41-
previous = previousBlock;
42-
previousBlock.next = this;
28+
BlockHole(this.placeholder, this._animate);
4329

44-
// Update DOM
45-
List<dom.Node> previousElements = previousBlock.elements;
46-
dom.Node previousElement = previousElements[previousElements.length - 1];
47-
dom.Node insertBeforeElement = previousElement.nextNode;
48-
dom.Node parentElement = previousElement.parentNode;
30+
void insert(Block block, { Block insertAfter }) {
31+
dom.Node previousNode = _lastNode(insertAfter);
32+
_blocksInsertAfter(block, insertAfter);
4933

50-
_animate.insert(elements, parentElement, insertBefore: insertBeforeElement);
51-
52-
return this;
34+
_animate.insert(block.nodes, placeholder.parentNode,
35+
insertBefore: previousNode.nextNode);
5336
}
5437

55-
Block remove() {
56-
bool preventDefault = false;
57-
58-
_animate.remove(elements);
59-
60-
// Remove block from list
61-
if (previous != null && (previous.next = next) != null) {
62-
next.previous = previous;
63-
}
64-
next = previous = null;
65-
return this;
38+
void remove(Block block) {
39+
_blocks.remove(block);
40+
_animate.remove(block.nodes);
6641
}
6742

68-
Block moveAfter(ElementWrapper previousBlock) {
69-
var previousElements = previousBlock.elements,
70-
previousElement = previousElements[previousElements.length - 1],
71-
insertBeforeElement = previousElement.nextNode,
72-
parentElement = previousElement.parentNode;
73-
74-
elements.forEach((el) => parentElement.insertBefore(el, insertBeforeElement));
43+
void move(Block block, { Block moveAfter }) {
44+
dom.Node previousNode = _lastNode(moveAfter);
45+
_blocks.remove(block);
46+
_blocksInsertAfter(block, moveAfter);
7547

76-
// Remove block from list
77-
previous.next = next;
78-
if (next != null) {
79-
next.previous = previous;
80-
}
81-
// Add block to list
82-
next = previousBlock.next;
83-
if (next != null) {
84-
next.previous = this;
85-
}
86-
previous = previousBlock;
87-
previousBlock.next = this;
88-
return this;
48+
_animate.move(block.nodes, placeholder.parentNode,
49+
insertBefore: previousNode.nextNode);
8950
}
90-
}
9151

92-
/**
93-
* A BlockHole is an instance of a hole. BlockHoles designate where child
94-
* [Block]s can be added in parent [Block]. BlockHoles wrap a DOM element,
95-
* and act as references which allows more blocks to be added.
96-
*/
97-
class BlockHole extends ElementWrapper {
98-
List<dom.Node> elements;
99-
ElementWrapper previous;
100-
ElementWrapper next;
52+
void _blocksInsertAfter(Block block, Block insertAfter) {
53+
int index = (insertAfter != null) ? _blocks.indexOf(insertAfter) : -1;
54+
_blocks.insert(index + 1, block);
55+
}
10156

102-
BlockHole(this.elements);
57+
dom.Node _lastNode(Block insertAfter) =>
58+
insertAfter == null
59+
? placeholder
60+
: insertAfter.nodes[insertAfter.nodes.length - 1];
10361
}
104-

lib/core_dom/block_factory.dart

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ class BlockFactory implements Function {
3535
BoundBlockFactory bind(Injector injector) =>
3636
new BoundBlockFactory(this, injector);
3737

38-
Block call(Injector injector, [List<dom.Node> elements]) {
39-
if (elements == null) elements = cloneElements(templateElements);
38+
Block call(Injector injector, [List<dom.Node> nodes]) {
39+
if (nodes == null) nodes = cloneElements(templateElements);
4040
var timerId;
4141
try {
4242
assert((timerId = _perf.startTimer('ng.block')) != false);
43-
var block = new Block(elements, injector.get(NgAnimate));
44-
_link(block, elements, directivePositions, injector);
43+
var block = new Block(nodes);
44+
_link(block, nodes, directivePositions, injector);
4545
return block;
4646
} finally {
4747
assert(_perf.stopTimer(timerId) != false);
@@ -176,7 +176,8 @@ class BlockFactory implements Function {
176176
if (annotation.children == NgAnnotation.TRANSCLUDE_CHILDREN) {
177177
// Currently, transclude is only supported for NgDirective.
178178
assert(annotation is NgDirective);
179-
blockHoleFactory = (_) => new BlockHole([node]);
179+
blockHoleFactory = (_) => new BlockHole(node,
180+
parentInjector.get(NgAnimate));
180181
blockFactory = (_) => ref.blockFactory;
181182
boundBlockFactory = (Injector injector) =>
182183
ref.blockFactory.bind(injector);
@@ -384,7 +385,7 @@ class _ComponentFactory implements Function {
384385

385386
attachBlockToShadowDom(BlockFactory blockFactory) {
386387
var block = blockFactory(shadowInjector);
387-
shadowDom.nodes.addAll(block.elements);
388+
shadowDom.nodes.addAll(block.nodes);
388389
return shadowDom;
389390
}
390391

lib/directive/ng_if.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,18 @@ abstract class _NgUnlessIfAttrDirectiveBase {
2828
if (_block == null) {
2929
_childScope = _scope.createChild(new PrototypeMap(_scope.context));
3030
_block = _boundBlockFactory(_childScope);
31-
var insertBlock = _block;
31+
var block = _block;
3232
_scope.rootScope.domWrite(() {
33-
insertBlock.insertAfter(_blockHole);
33+
_blockHole.insert(block);
3434
});
3535
}
3636
}
3737

3838
void _ensureBlockDestroyed() {
3939
if (_block != null) {
40-
var removeBlock = _block;
40+
var block = _block;
4141
_scope.rootScope.domWrite(() {
42-
removeBlock.remove();
42+
_blockHole.remove(block);
4343
});
4444
_childScope.destroy();
4545
_block = null;

lib/directive/ng_include.dart

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,29 @@ class NgIncludeDirective {
2626
final Injector injector;
2727
final DirectiveMap directives;
2828

29-
Block _previousBlock;
30-
Scope _previousScope;
29+
Block _block;
30+
Scope _scope;
3131

3232
NgIncludeDirective(this.element, this.scope, this.blockCache, this.injector, this.directives);
3333

3434
_cleanUp() {
35-
if (_previousBlock == null) return;
35+
if (_block == null) return;
3636

37-
_previousBlock.remove();
38-
_previousScope.destroy();
37+
_block.nodes.forEach((node) => node.remove);
38+
_scope.destroy();
3939
element.innerHtml = '';
4040

41-
_previousBlock = null;
42-
_previousScope = null;
41+
_block = null;
42+
_scope = null;
4343
}
4444

4545
_updateContent(createBlock) {
4646
// create a new scope
47-
_previousScope = scope.createChild(new PrototypeMap(scope.context));
48-
_previousBlock = createBlock(injector.createChild([new Module()
49-
..value(Scope, _previousScope)]));
47+
_scope = scope.createChild(new PrototypeMap(scope.context));
48+
_block = createBlock(injector.createChild([new Module()
49+
..value(Scope, _scope)]));
5050

51-
_previousBlock.elements.forEach((elm) => element.append(elm));
51+
_block.nodes.forEach((node) => element.append(node));
5252
}
5353

5454

lib/directive/ng_repeat.dart

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class _Row {
66
Block block;
77
dom.Element startNode;
88
dom.Element endNode;
9-
List<dom.Element> elements;
9+
List<dom.Element> nodes;
1010

1111
_Row(this.id);
1212
}
@@ -177,20 +177,21 @@ class NgRepeatDirective {
177177
}
178178
// remove existing items
179179
_rows.forEach((key, row) {
180-
row.block.remove();
180+
_blockHole.remove(row.block);
181181
row.scope.destroy();
182182
});
183183
_rows = newRows;
184184
return newRowOrder;
185185
}
186186

187187
_onCollectionChange(Iterable collection) {
188-
dom.Node previousNode = _blockHole.elements[0]; // current position of the node
188+
dom.Node previousNode = _blockHole.placeholder; // current position of the
189+
// node
189190
dom.Node nextNode;
190191
Scope childScope;
191192
Map childContext;
192193
Scope trackById;
193-
ElementWrapper cursor = _blockHole;
194+
Block cursor;
194195

195196
List<_Row> newRowOrder = _computeNewRows(collection, trackById);
196197

@@ -211,7 +212,7 @@ class NgRepeatDirective {
211212

212213
if (row.startNode != nextNode) {
213214
// existing item which got moved
214-
row.block.moveAfter(cursor);
215+
_blockHole.move(row.block, moveAfter: cursor);
215216
}
216217
previousNode = row.endNode;
217218
} else {
@@ -237,10 +238,10 @@ class NgRepeatDirective {
237238
_rows[row.id] = row
238239
..block = block
239240
..scope = childScope
240-
..elements = block.elements
241-
..startNode = row.elements[0]
242-
..endNode = row.elements[row.elements.length - 1];
243-
block.insertAfter(cursor);
241+
..nodes = block.nodes
242+
..startNode = row.nodes[0]
243+
..endNode = row.nodes[row.nodes.length - 1];
244+
_blockHole.insert(block, insertAfter: cursor);
244245
}
245246
cursor = row.block;
246247
}

lib/directive/ng_switch.dart

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class NgSwitchDirective {
7474
set value(val) {
7575
currentBlocks
7676
..forEach((_BlockScopePair pair) {
77-
pair.block.remove();
77+
pair.hole.remove(pair.block);
7878
pair.scope.destroy();
7979
})
8080
..clear();
@@ -83,8 +83,10 @@ class NgSwitchDirective {
8383
(cases.containsKey(val) ? cases[val] : cases['?'])
8484
.forEach((_Case caze) {
8585
Scope childScope = scope.createChild(new PrototypeMap(scope.context));
86-
var block = caze.blockFactory(childScope)..insertAfter(caze.anchor);
87-
currentBlocks.add(new _BlockScopePair(block, childScope));
86+
var block = caze.blockFactory(childScope);
87+
caze.anchor.insert(block);
88+
currentBlocks.add(new _BlockScopePair(block, caze.anchor,
89+
childScope));
8890
});
8991
if (onChange != null) {
9092
onChange();
@@ -94,9 +96,10 @@ class NgSwitchDirective {
9496

9597
class _BlockScopePair {
9698
final Block block;
99+
final BlockHole hole;
97100
final Scope scope;
98101

99-
_BlockScopePair(this.block, this.scope);
102+
_BlockScopePair(this.block, this.hole, this.scope);
100103
}
101104

102105
class _Case {
@@ -121,7 +124,6 @@ class NgSwitchWhenDirective {
121124
set value(String value) => ngSwitch.addCase('!$value', hole, blockFactory);
122125
}
123126

124-
125127
@NgDirective(
126128
children: NgAnnotation.TRANSCLUDE_CHILDREN,
127129
selector: '[ng-switch-default]')

lib/routing/ng_view.dart

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ class NgViewDirective implements NgDetachAware, RouteProvider {
6767
final Scope scope;
6868
RouteHandle _route;
6969

70-
Block _previousBlock;
71-
Scope _previousScope;
70+
Block _block;
71+
Scope _scope;
7272
Route _viewRoute;
7373

7474
NgViewDirective(this.element, this.blockCache,
@@ -116,23 +116,23 @@ class NgViewDirective implements NgDetachAware, RouteProvider {
116116
var newDirectives = viewInjector.get(DirectiveMap);
117117
blockCache.fromUrl(templateUrl, newDirectives).then((blockFactory) {
118118
_cleanUp();
119-
_previousScope = scope.createChild(new PrototypeMap(scope.context));
120-
_previousBlock = blockFactory(
119+
_scope = scope.createChild(new PrototypeMap(scope.context));
120+
_block = blockFactory(
121121
viewInjector.createChild(
122-
[new Module()..value(Scope, _previousScope)]));
122+
[new Module()..value(Scope, _scope)]));
123123

124-
_previousBlock.elements.forEach((elm) => element.append(elm));
124+
_block.nodes.forEach((elm) => element.append(elm));
125125
});
126126
}
127127

128128
_cleanUp() {
129-
if (_previousBlock == null) return;
129+
if (_block == null) return;
130130

131-
_previousBlock.remove();
132-
_previousScope.destroy();
131+
_block.nodes.forEach((node) => node.remove());
132+
_scope.destroy();
133133

134-
_previousBlock = null;
135-
_previousScope = null;
134+
_block = null;
135+
_scope = null;
136136
}
137137

138138
Route get route => _viewRoute;

0 commit comments

Comments
 (0)