Skip to content

Commit c3a1e1a

Browse files
committed
Version 0.6.15.2 .
svn merge -c 25799 https://dart.googlecode.com/svn/branches/bleeding_edge trunk git-svn-id: http://dart.googlecode.com/svn/trunk@25802 260f80e4-7a28-3924-810f-c04153c831b5
1 parent 06b7bd7 commit c3a1e1a

11 files changed

+125
-178
lines changed

pkg/custom_element/lib/custom_element.dart

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import 'src/custom_tag_name.dart';
3131
void registerCustomElement(String localName, CustomElement create()) {
3232
if (_customElements == null) {
3333
_customElements = {};
34-
CustomElement.templateCreated.add(initCustomElements);
34+
mdv.instanceCreated.add(initCustomElements);
3535
// TODO(jmesserly): use MutationObserver to watch for inserts?
3636
}
3737

@@ -159,46 +159,6 @@ class CustomElement implements Element {
159159

160160
getShadowRoot(String componentName) => _generatedRoots[componentName];
161161

162-
163-
/**
164-
* *Warning*: This is an implementation helper for Custom Elements and
165-
* should not be used in your code.
166-
*
167-
* Clones the template, instantiates custom elements and hooks events, then
168-
* returns it.
169-
*/
170-
DocumentFragment cloneTemplate(DocumentFragment shadowTemplate) {
171-
var result = shadowTemplate.clone(true);
172-
// TODO(jmesserly): should bindModel ensure this happens?
173-
TemplateElement.bootstrap(result);
174-
if (_templateCreated != null) {
175-
for (var callback in _templateCreated) callback(result);
176-
}
177-
return result;
178-
}
179-
180-
// TODO(jmesserly): ideally this would be a stream, but they don't allow
181-
// reentrancy.
182-
static Set<DocumentFragmentCreated> _templateCreated;
183-
184-
/**
185-
* *Warning*: This is an implementation helper for Custom Elements and
186-
* should not be used in your code.
187-
*
188-
* This event is fired whenever a template is instantiated via
189-
* [cloneTemplate] or via [Element.createInstance]
190-
*/
191-
// TODO(jmesserly): This is a hack, and is neccesary for the polyfill
192-
// because custom elements are not upgraded during clone()
193-
static Set<DocumentFragmentCreated> get templateCreated {
194-
if (_templateCreated == null) {
195-
_templateCreated = new Set<DocumentFragmentCreated>();
196-
mdv.instanceCreated.listen((value) {
197-
for (var callback in _templateCreated) callback(value);
198-
});
199-
}
200-
return _templateCreated;
201-
}
202162
/**
203163
* Invoked when this component gets created.
204164
* Note that [root] will be a [ShadowRoot] if the browser supports Shadow DOM.
@@ -230,7 +190,7 @@ class CustomElement implements Element {
230190
host.createInstance(model, delegate);
231191
createBinding(String name, model, String path) =>
232192
host.createBinding(name, model, path);
233-
void bind(String name, model, String path) => host.bind(name, model, path);
193+
bind(String name, model, String path) => host.bind(name, model, path);
234194
void unbind(String name) => host.unbind(name);
235195
void unbindAll() => host.unbindAll();
236196
get bindings => host.bindings;
@@ -659,8 +619,6 @@ class CustomElement implements Element {
659619
}
660620

661621

662-
typedef DocumentFragmentCreated(DocumentFragment fragment);
663-
664622
Map<String, Function> _customElements;
665623

666624
void _initCustomElement(Element node, CustomElement ctor()) {

pkg/mdv/lib/mdv.dart

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ void initialize() {
3636
TemplateElement.mdvPackage = _mdv;
3737
}
3838

39-
StreamController<DocumentFragment> _instanceCreated;
39+
40+
typedef DocumentFragmentCreated(DocumentFragment fragment);
41+
42+
// TODO(jmesserly): ideally this would be a stream, but they don't allow
43+
// reentrancy.
44+
Set<DocumentFragmentCreated> _instanceCreated;
4045

4146
/**
4247
* *Warning*: This is an implementation helper for Model-Driven Views and
@@ -49,11 +54,11 @@ StreamController<DocumentFragment> _instanceCreated;
4954
// because custom elements are not upgraded during clone()
5055
// TODO(jmesserly): polymer removed this in:
5156
// https://github.com/Polymer/platform/commit/344ffeaae475babb529403f6608588a0fc73f4e7
52-
Stream<DocumentFragment> get instanceCreated {
57+
Set<DocumentFragmentCreated> get instanceCreated {
5358
if (_instanceCreated == null) {
54-
_instanceCreated = new StreamController<DocumentFragment>(sync: true);
59+
_instanceCreated = new Set<DocumentFragmentCreated>();
5560
}
56-
return _instanceCreated.stream;
61+
return _instanceCreated;
5762
}
5863

5964

pkg/mdv/lib/src/node.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ class _NodeExtension {
1919
*/
2020
NodeBinding bind(String name, model, String path) {
2121
var binding = bindings[name];
22-
if (binding != null) binding.close();
22+
if (binding != null) binding.close();
23+
24+
// Note: dispatch through the xtag so a custom element can override it.
25+
binding = (node is Element ? (node as Element).xtag : node)
26+
.createBinding(name, model, path);
2327

24-
binding = createBinding(name, model, path);
2528
bindings[name] = binding;
2629
if (binding == null) {
2730
window.console.error('Unhandled binding to Node: '

pkg/mdv/lib/src/template.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ class _TemplateExtension extends _ElementExtension {
4141
var instance = _createDeepCloneAndDecorateTemplates(
4242
template.ref.content, delegate);
4343

44-
if (_instanceCreated != null) _instanceCreated.add(instance);
44+
if (_instanceCreated != null) {
45+
for (var callback in _instanceCreated) callback(instance);
46+
}
4547

4648
_addBindings(instance, model, delegate);
4749
_addTemplateInstanceRecord(instance, model);

pkg/mdv/test/custom_element_bindings_test.dart

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,12 @@ customElementBindingsTest() {
126126
'</my-custom-element>'
127127
'</template>');
128128

129-
mdv.instanceCreated.listen((fragment) {
129+
callback(fragment) {
130130
for (var e in fragment.queryAll('my-custom-element')) {
131131
new MyCustomElement.attach(e);
132132
}
133-
});
133+
}
134+
mdv.instanceCreated.add(callback);
134135

135136
div.query('template').model = model;
136137
performMicrotaskCheckpoint();
@@ -161,6 +162,8 @@ customElementBindingsTest() {
161162

162163
expect(element.xtag.myPoint, null, reason: 'model was unbound');
163164
expect(element.xtag.scaryMonster.health, 100, reason: 'model was unbound');
165+
166+
mdv.instanceCreated.remove(callback);
164167
});
165168

166169
}
@@ -177,64 +180,45 @@ class MyCustomElement implements Element {
177180
Point myPoint;
178181
Monster scaryMonster;
179182

180-
StreamSubscription _sub1, _sub2;
181-
182183
MyCustomElement() : this.attach(new Element.tag('my-custom-element'));
183184

184185
MyCustomElement.attach(this.real) {
185186
real.xtag = this;
186187
}
187188

188-
189189
get attributes => real.attributes;
190+
get bindings => real.bindings;
190191

191-
void bind(String name, model, String path) {
192+
NodeBinding createBinding(String name, model, String path) {
192193
switch (name) {
193194
case 'my-point':
194-
unbind('my-point');
195-
attributes.remove('my-point');
196-
197-
_sub1 = new PathObserver(model, path).bindSync((v) {
198-
myPoint = v;
199-
});
200-
return;
201195
case 'scary-monster':
202-
unbind('scary-monster');
203-
attributes.remove('scary-monster');
204-
205-
_sub2 = new PathObserver(model, path).bindSync((v) {
206-
scaryMonster = v;
207-
});
208-
return;
196+
return new _MyCustomBinding(this, name, model, path);
209197
}
210-
real.bind(name, model, path);
198+
return real.createBinding(name, model, path);
211199
}
212200

213-
void unbind(String name) {
214-
switch (name) {
215-
case 'my-point':
216-
if (_sub1 != null) {
217-
_sub1.cancel();
218-
_sub1 = null;
219-
}
220-
return;
221-
case 'scary-monster':
222-
if (_sub2 != null) {
223-
_sub2.cancel();
224-
_sub2 = null;
225-
}
226-
return;
227-
}
228-
real.unbind(name);
201+
bind(String name, model, String path) => real.bind(name, model, path);
202+
void unbind(String name) => real.unbind(name);
203+
void unbindAll() => real.unbindAll();
204+
}
205+
206+
class _MyCustomBinding extends mdv.NodeBinding {
207+
_MyCustomBinding(MyCustomElement node, property, model, path)
208+
: super(node, property, model, path) {
209+
210+
node.attributes.remove(property);
229211
}
230212

231-
void unbindAll() {
232-
unbind('my-point');
233-
unbind('scary-monster');
234-
real.unbindAll();
213+
MyCustomElement get node => super.node;
214+
215+
void boundValueChanged(newValue) {
216+
if (property == 'my-point') node.myPoint = newValue;
217+
if (property == 'scary-monster') node.scaryMonster = newValue;
235218
}
236219
}
237220

221+
238222
/**
239223
* Demonstrates a custom element can override attributes []= and remove.
240224
* and see changes that the data binding system is making to the attributes.
@@ -253,7 +237,9 @@ class WithAttrsCustomElement implements Element {
253237
real.xtag = this;
254238
}
255239

256-
void bind(String name, model, String path) => real.bind(name, model, path);
240+
createBinding(String name, model, String path) =>
241+
real.createBinding(name, model, path);
242+
bind(String name, model, String path) => real.bind(name, model, path);
257243
void unbind(String name) => real.unbind(name);
258244
void unbindAll() => real.unbindAll();
259245
}

pkg/mdv/test/mdv_test_utils.dart

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import 'dart:html';
99
import 'package:observe/observe.dart';
1010
import 'package:unittest/unittest.dart';
1111

12+
import 'package:observe/src/microtask.dart';
13+
export 'package:observe/src/microtask.dart';
14+
1215
final bool parserHasNativeTemplate = () {
1316
var div = new DivElement()..innerHtml = '<table><template>';
1417
return div.firstChild.firstChild != null &&
@@ -61,42 +64,6 @@ class FooBarNotifyModel extends ChangeNotifierBase implements FooBarModel {
6164
}
6265
}
6366

64-
// TODO(jmesserly): this is a copy/paste from observe_test_utils.dart
65-
// Is it worth putting it in its own package, or in an existing one?
66-
67-
void performMicrotaskCheckpoint() {
68-
Observable.dirtyCheck();
69-
70-
while (_pending.length > 0) {
71-
var pending = _pending;
72-
_pending = [];
73-
74-
for (var callback in pending) {
75-
try {
76-
callback();
77-
} catch (e, s) {
78-
new Completer().completeError(e, s);
79-
}
80-
}
81-
82-
Observable.dirtyCheck();
83-
}
84-
}
85-
86-
List<Function> _pending = [];
87-
88-
wrapMicrotask(void testCase()) {
89-
return () {
90-
runZonedExperimental(() {
91-
try {
92-
testCase();
93-
} finally {
94-
performMicrotaskCheckpoint();
95-
}
96-
}, onRunAsync: (callback) => _pending.add(callback));
97-
};
98-
}
99-
10067
observeTest(name, testCase) => test(name, wrapMicrotask(testCase));
10168

10269
solo_observeTest(name, testCase) => solo_test(name, wrapMicrotask(testCase));

pkg/mdv/test/template_element_test.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,10 +1694,12 @@ templateElementTests() {
16941694

16951695
observeTest('instanceCreated hack', () {
16961696
var called = false;
1697-
var sub = mdv.instanceCreated.listen((node) {
1697+
1698+
callback(node) {
16981699
called = true;
16991700
expect(node.nodeType, Node.DOCUMENT_FRAGMENT_NODE);
1700-
});
1701+
}
1702+
mdv.instanceCreated.add(callback);
17011703

17021704
var div = createTestHtml('<template bind="{{}}">Foo</template>');
17031705
expect(called, false);
@@ -1706,7 +1708,7 @@ templateElementTests() {
17061708
performMicrotaskCheckpoint();
17071709
expect(called, true);
17081710

1709-
sub.cancel();
1711+
mdv.instanceCreated.remove(callback);
17101712
});
17111713
}
17121714

pkg/observe/lib/observe.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ import 'dart:mirrors';
8080
// above.
8181
import 'src/dirty_check.dart';
8282

83+
// TODO(jmesserly): should this be public? For now we're just using it inside
84+
// Polymer.
85+
import 'src/microtask.dart';
86+
8387
part 'src/change_notifier.dart';
8488
part 'src/change_record.dart';
8589
part 'src/compound_binding.dart';

pkg/observe/lib/src/microtask.dart

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/**
6+
* *Warning*: this library is **internal**, and APIs are subject to change.
7+
*
8+
* Wraps a callback using [wrapMicrotask] and provides the ability to pump all
9+
* observable objects and [runAsync] calls via [performMicrotaskCheckpoint].
10+
*/
11+
library observe.src.microtask;
12+
13+
import 'dart:async' show Completer, runZonedExperimental;
14+
import 'package:observe/observe.dart' show Observable;
15+
16+
// TODO(jmesserly): remove "microtask" from these names and instead import
17+
// the library "as microtask"?
18+
19+
/**
20+
* This change pumps events relevant to observers and data-binding tests.
21+
* This must be used inside an [observeTest].
22+
*
23+
* Executes all pending [runAsync] calls on the event loop, as well as
24+
* performing [Observable.dirtyCheck], until there are no more pending events.
25+
* It will always dirty check at least once.
26+
*/
27+
void performMicrotaskCheckpoint() {
28+
Observable.dirtyCheck();
29+
30+
while (_pending.length > 0) {
31+
var pending = _pending;
32+
_pending = [];
33+
34+
for (var callback in pending) {
35+
try {
36+
callback();
37+
} catch (e, s) {
38+
new Completer().completeError(e, s);
39+
}
40+
}
41+
42+
Observable.dirtyCheck();
43+
}
44+
}
45+
46+
List<Function> _pending = [];
47+
48+
/**
49+
* Wraps the [testCase] in a zone that supports [performMicrotaskCheckpoint],
50+
* and returns the test case.
51+
*/
52+
wrapMicrotask(void testCase()) {
53+
return () {
54+
runZonedExperimental(() {
55+
try {
56+
testCase();
57+
} finally {
58+
performMicrotaskCheckpoint();
59+
}
60+
}, onRunAsync: (callback) => _pending.add(callback));
61+
};
62+
}

0 commit comments

Comments
 (0)