OLD | NEW |
1 part of angular.core.dom; | 1 part of angular.core.dom_internal; |
2 | 2 |
| 3 /// Callback function used to notify of attribute changes. |
| 4 typedef void _AttributeChanged(String newValue); |
| 5 |
| 6 /// Callback function used to notify of observer changes. |
| 7 typedef void Mustache(bool hasObservers); |
| 8 |
3 /** | 9 /** |
4 * Callback function used to notify of attribute changes. | 10 * NodeAttrs is a facade for element attributes. |
5 */ | 11 * |
6 typedef AttributeChanged(String newValue); | 12 * This facade allows reading and writing the attribute values as well as |
7 | 13 * adding observers triggered when: |
8 /** | 14 * - The value of an attribute changes, |
9 * NodeAttrs is a facade for element attributes. The facade is responsible | 15 * - An element becomes observed. |
10 * for normalizing attribute names as well as allowing access to the | |
11 * value of the directive. | |
12 */ | 16 */ |
13 class NodeAttrs { | 17 class NodeAttrs { |
14 final dom.Element element; | 18 final dom.Element element; |
15 | 19 |
16 Map<String, List<AttributeChanged>> _observers; | 20 Map<String, List<_AttributeChanged>> _observers; |
| 21 final _mustacheAttrs = <String, _MustacheAttr>{}; |
17 | 22 |
18 NodeAttrs(this.element); | 23 NodeAttrs(this.element); |
19 | 24 |
20 operator [](String attributeName) => | 25 operator [](String attrName) => element.attributes[attrName]; |
21 element.attributes[attributeName]; | |
22 | 26 |
23 operator []=(String attributeName, String value) { | 27 void operator []=(String attrName, String value) { |
| 28 if (_mustacheAttrs.containsKey(attrName)) { |
| 29 _mustacheAttrs[attrName].isComputed = true; |
| 30 } |
24 if (value == null) { | 31 if (value == null) { |
25 element.attributes.remove(attributeName); | 32 element.attributes.remove(attrName); |
26 } else { | 33 } else { |
27 element.attributes[attributeName] = value; | 34 element.attributes[attrName] = value; |
28 } | 35 } |
29 if (_observers != null && _observers.containsKey(attributeName)) { | 36 |
30 _observers[attributeName].forEach((fn) => fn(value)); | 37 if (_observers != null && _observers.containsKey(attrName)) { |
| 38 _observers[attrName].forEach((notifyFn) => notifyFn(value)); |
31 } | 39 } |
32 } | 40 } |
33 | 41 |
34 /** | 42 /** |
35 * Observe changes to the attribute by invoking the [AttributeChanged] | 43 * Observes changes to the attribute by invoking the [notifyFn] |
36 * function. On registration the [AttributeChanged] function gets invoked | 44 * function. On registration the [notifyFn] function gets invoked in order to |
37 * synchronise with the current value. | 45 * synchronize with the current value. |
| 46 * |
| 47 * When an observed is registered on an attributes any existing |
| 48 * [_observerListeners] will be called with the first parameter set to |
| 49 * [:true:] |
38 */ | 50 */ |
39 observe(String attributeName, AttributeChanged notifyFn) { | 51 observe(String attrName, notifyFn(String value)) { |
40 if (_observers == null) { | 52 if (_observers == null) _observers = <String, List<_AttributeChanged>>{}; |
41 _observers = new Map<String, List<AttributeChanged>>(); | 53 _observers.putIfAbsent(attrName, () => <_AttributeChanged>[]) |
| 54 .add(notifyFn); |
| 55 |
| 56 if (_mustacheAttrs.containsKey(attrName)) { |
| 57 if (_mustacheAttrs[attrName].isComputed) notifyFn(this[attrName]); |
| 58 _mustacheAttrs[attrName].notifyFn(true); |
| 59 } else { |
| 60 notifyFn(this[attrName]); |
42 } | 61 } |
43 if (!_observers.containsKey(attributeName)) { | |
44 _observers[attributeName] = new List<AttributeChanged>(); | |
45 } | |
46 _observers[attributeName].add(notifyFn); | |
47 notifyFn(this[attributeName]); | |
48 } | 62 } |
49 | 63 |
50 void forEach(void f(String k, String v)) { | 64 void forEach(void f(String k, String v)) { |
51 element.attributes.forEach(f); | 65 element.attributes.forEach(f); |
52 } | 66 } |
53 | 67 |
54 bool containsKey(String attributeName) => | 68 bool containsKey(String attrName) => element.attributes.containsKey(attrName); |
55 element.attributes.containsKey(attributeName); | |
56 | 69 |
57 Iterable<String> get keys => | 70 Iterable<String> get keys => element.attributes.keys; |
58 element.attributes.keys; | 71 |
| 72 /** |
| 73 * Registers a listener to be called when the attribute [attrName] becomes |
| 74 * observed. On registration [notifyFn] function gets invoked with [:false:] |
| 75 * as the first argument. |
| 76 */ |
| 77 void listenObserverChanges(String attrName, Mustache notifyFn) { |
| 78 _mustacheAttrs[attrName] = new _MustacheAttr(notifyFn); |
| 79 notifyFn(false); |
| 80 } |
59 } | 81 } |
60 | 82 |
61 /** | 83 /** |
62 * TemplateLoader is an asynchronous access to ShadowRoot which is | 84 * [TemplateLoader] is an asynchronous access to ShadowRoot which is |
63 * loaded asynchronously. It allows a Component to be notified when its | 85 * loaded asynchronously. It allows a Component to be notified when its |
64 * ShadowRoot is ready. | 86 * ShadowRoot is ready. |
65 */ | 87 */ |
66 class TemplateLoader { | 88 class TemplateLoader { |
67 final async.Future<dom.ShadowRoot> _template; | 89 final async.Future<dom.ShadowRoot> template; |
68 | 90 |
69 async.Future<dom.ShadowRoot> get template => _template; | 91 TemplateLoader(this.template); |
| 92 } |
70 | 93 |
71 TemplateLoader(this._template); | 94 class _MustacheAttr { |
| 95 // Listener trigger when the attribute becomes observed |
| 96 final Mustache notifyFn; |
| 97 // Whether the value has first been computed |
| 98 bool isComputed = false; |
| 99 |
| 100 _MustacheAttr(this.notifyFn); |
72 } | 101 } |
OLD | NEW |