| Index: packages/template_binding/test/custom_element_bindings_test.dart
|
| diff --git a/packages/template_binding/test/custom_element_bindings_test.dart b/packages/template_binding/test/custom_element_bindings_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0d7429aeeecd67aaacd74c94cc0036540b021694
|
| --- /dev/null
|
| +++ b/packages/template_binding/test/custom_element_bindings_test.dart
|
| @@ -0,0 +1,177 @@
|
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library template_binding.test.custom_element_bindings_test;
|
| +
|
| +import 'dart:async';
|
| +import 'dart:html';
|
| +import 'dart:collection' show MapView;
|
| +import 'package:template_binding/template_binding.dart';
|
| +import 'package:observe/observe.dart';
|
| +import 'package:unittest/html_config.dart';
|
| +import 'package:unittest/unittest.dart';
|
| +import 'package:web_components/polyfill.dart';
|
| +import 'utils.dart';
|
| +import 'package:observe/mirrors_used.dart'; // make test smaller
|
| +import 'package:smoke/mirrors.dart' as smoke;
|
| +
|
| +Future _registered;
|
| +
|
| +main() => dirtyCheckZone().run(() {
|
| + smoke.useMirrors();
|
| + useHtmlConfiguration();
|
| +
|
| + _registered = customElementsReady.then((_) {
|
| + document.registerElement('my-custom-element', MyCustomElement);
|
| + });
|
| +
|
| + group('Custom Element Bindings', customElementBindingsTest);
|
| +});
|
| +
|
| +customElementBindingsTest() {
|
| + setUp(() {
|
| + document.body.append(testDiv = new DivElement());
|
| + return _registered;
|
| + });
|
| +
|
| + tearDown(() {
|
| + testDiv.remove();
|
| + testDiv = null;
|
| + });
|
| +
|
| + test('override bind/bindFinished', () {
|
| + var element = new MyCustomElement();
|
| + var model = toObservable({'a': new Point(123, 444), 'b': new Monster(100)});
|
| +
|
| + var pointBinding = nodeBind(element)
|
| + .bind('my-point', new PathObserver(model, 'a'));
|
| +
|
| + var scaryBinding = nodeBind(element)
|
| + .bind('scary-monster', new PathObserver(model, 'b'));
|
| +
|
| + expect(element.attributes, isNot(contains('my-point')));
|
| + expect(element.attributes, isNot(contains('scary-monster')));
|
| +
|
| + expect(element.myPoint, model['a']);
|
| + expect(element.scaryMonster, model['b']);
|
| +
|
| + model['a'] = null;
|
| + return new Future(() {
|
| + expect(element.myPoint, null);
|
| + expect(element.bindFinishedCalled, 0);
|
| + pointBinding.close();
|
| +
|
| + model['a'] = new Point(1, 2);
|
| + model['b'] = new Monster(200);
|
| + }).then(endOfMicrotask).then((_) {
|
| + expect(element.scaryMonster, model['b']);
|
| + expect(element.myPoint, null, reason: 'a was unbound');
|
| +
|
| + scaryBinding.close();
|
| + model['b'] = null;
|
| + }).then(endOfMicrotask).then((_) {
|
| + expect(element.scaryMonster.health, 200);
|
| + expect(element.bindFinishedCalled, 0);
|
| + });
|
| + });
|
| +
|
| + test('template bind uses overridden custom element bind', () {
|
| +
|
| + var model = toObservable({'a': new Point(123, 444), 'b': new Monster(100)});
|
| + var div = createTestHtml('<template bind>'
|
| + '<my-custom-element my-point="{{a}}" scary-monster="{{b}}">'
|
| + '</my-custom-element>'
|
| + '</template>');
|
| +
|
| + templateBind(div.query('template')).model = model;
|
| + var element;
|
| + return new Future(() {
|
| + element = div.nodes[1];
|
| +
|
| + expect(element is MyCustomElement, true,
|
| + reason: '$element should be a MyCustomElement');
|
| +
|
| + expect(element.myPoint, model['a']);
|
| + expect(element.scaryMonster, model['b']);
|
| +
|
| + expect(element.attributes, isNot(contains('my-point')));
|
| + expect(element.attributes, isNot(contains('scary-monster')));
|
| +
|
| + expect(element.bindFinishedCalled, 1);
|
| +
|
| + model['a'] = null;
|
| + }).then(endOfMicrotask).then((_) {
|
| + expect(element.myPoint, null);
|
| + expect(element.bindFinishedCalled, 1);
|
| +
|
| +
|
| + templateBind(div.query('template')).model = null;
|
| + }).then(endOfMicrotask).then((_) {
|
| + // Note: the detached element
|
| + expect(element.parentNode is DocumentFragment, true,
|
| + reason: 'removed element is added back to its document fragment');
|
| + expect(element.parentNode.parentNode, null,
|
| + reason: 'document fragment is detached');
|
| + expect(element.bindFinishedCalled, 1);
|
| +
|
| + model['a'] = new Point(1, 2);
|
| + model['b'] = new Monster(200);
|
| + }).then(endOfMicrotask).then((_) {
|
| + expect(element.myPoint, null, reason: 'model was unbound');
|
| + expect(element.scaryMonster.health, 100, reason: 'model was unbound');
|
| + expect(element.bindFinishedCalled, 1);
|
| + });
|
| + });
|
| +
|
| +}
|
| +
|
| +class Monster {
|
| + int health;
|
| + Monster(this.health);
|
| +}
|
| +
|
| +/** Demonstrates a custom element overriding bind/bindFinished. */
|
| +class MyCustomElement extends HtmlElement implements NodeBindExtension {
|
| + Point myPoint;
|
| + Monster scaryMonster;
|
| + int bindFinishedCalled = 0;
|
| +
|
| + factory MyCustomElement() => new Element.tag('my-custom-element');
|
| +
|
| + MyCustomElement.created() : super.created();
|
| +
|
| + Bindable bind(String name, value, {oneTime: false}) {
|
| + switch (name) {
|
| + case 'my-point':
|
| + case 'scary-monster':
|
| + attributes.remove(name);
|
| + if (oneTime) {
|
| + _setProperty(name, value);
|
| + return null;
|
| + }
|
| + _setProperty(name, value.open((x) => _setProperty(name, x)));
|
| +
|
| + if (!enableBindingsReflection) return value;
|
| + if (bindings == null) bindings = {};
|
| + var old = bindings[name];
|
| + if (old != null) old.close();
|
| + return bindings[name] = value;
|
| + }
|
| + return nodeBindFallback(this).bind(name, value, oneTime: oneTime);
|
| + }
|
| +
|
| + void bindFinished() {
|
| + bindFinishedCalled++;
|
| + }
|
| +
|
| + get bindings => nodeBindFallback(this).bindings;
|
| + set bindings(x) => nodeBindFallback(this).bindings = x;
|
| + get templateInstance => nodeBindFallback(this).templateInstance;
|
| +
|
| + void _setProperty(String property, newValue) {
|
| + if (property == 'my-point') myPoint = newValue;
|
| + if (property == 'scary-monster') scaryMonster = newValue;
|
| + }
|
| +}
|
| +
|
|
|