| OLD | NEW |
| 1 part of angular.core; | 1 part of angular.core; |
| 2 | 2 |
| 3 | 3 |
| 4 /** | 4 /** |
| 5 * Used by [Scope.$on] to notify the listeners of events. | 5 * Injected into the listener function within [Scope.$on] to provide event-speci
fic |
| 6 * details to the scope listener. |
| 6 */ | 7 */ |
| 7 class ScopeEvent { | 8 class ScopeEvent { |
| 9 |
| 10 /** |
| 11 * The name of the intercepted scope event. |
| 12 */ |
| 8 String name; | 13 String name; |
| 14 |
| 15 /** |
| 16 * The origin scope that triggered the event (via $broadcast or $emit). |
| 17 */ |
| 9 Scope targetScope; | 18 Scope targetScope; |
| 19 |
| 20 /** |
| 21 * The destination scope that intercepted the event. |
| 22 */ |
| 10 Scope currentScope; | 23 Scope currentScope; |
| 24 |
| 25 /** |
| 26 * true or false depending on if stopPropagation() was executed. |
| 27 */ |
| 11 bool propagationStopped = false; | 28 bool propagationStopped = false; |
| 29 |
| 30 /** |
| 31 * true or false depending on if preventDefault() was executed. |
| 32 */ |
| 12 bool defaultPrevented = false; | 33 bool defaultPrevented = false; |
| 13 | 34 |
| 35 /** |
| 36 ** [name] - The name of the scope event. |
| 37 ** [targetScope] - The destination scope that is listening on the event. |
| 38 */ |
| 14 ScopeEvent(this.name, this.targetScope); | 39 ScopeEvent(this.name, this.targetScope); |
| 15 | 40 |
| 41 /** |
| 42 * Prevents the intercepted event from propagating further to successive scope
s. |
| 43 */ |
| 16 stopPropagation () => propagationStopped = true; | 44 stopPropagation () => propagationStopped = true; |
| 45 |
| 46 /** |
| 47 * Sets the defaultPrevented flag to true. |
| 48 */ |
| 17 preventDefault() => defaultPrevented = true; | 49 preventDefault() => defaultPrevented = true; |
| 18 } | 50 } |
| 19 | 51 |
| 20 /** | 52 /** |
| 21 * Allows the configuration of [Scope.$digest] iteration maximum time-to-live | 53 * Allows the configuration of [Scope.$digest] iteration maximum time-to-live |
| 22 * value. Digest keeps checking the state of the watcher getters until it | 54 * value. Digest keeps checking the state of the watcher getters until it |
| 23 * can execute one full iteration with no watchers triggering. TTL is used | 55 * can execute one full iteration with no watchers triggering. TTL is used |
| 24 * to prevent an infinite loop where watch A triggers watch B which in turn | 56 * to prevent an infinite loop where watch A triggers watch B which in turn |
| 25 * triggers watch A. If the system does not stabilize in TTL iteration then | 57 * triggers watch A. If the system does not stabilize in TTL iteration then |
| 26 * an digest is stop an an exception is thrown. | 58 * an digest is stop an an exception is thrown. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 43 final ExceptionHandler _exceptionHandler; | 75 final ExceptionHandler _exceptionHandler; |
| 44 final Parser _parser; | 76 final Parser _parser; |
| 45 final NgZone _zone; | 77 final NgZone _zone; |
| 46 final num _ttl; | 78 final num _ttl; |
| 47 final Map<String, Object> _properties = {}; | 79 final Map<String, Object> _properties = {}; |
| 48 final _WatchList _watchers = new _WatchList(); | 80 final _WatchList _watchers = new _WatchList(); |
| 49 final Map<String, List<Function>> _listeners = {}; | 81 final Map<String, List<Function>> _listeners = {}; |
| 50 final bool _isolate; | 82 final bool _isolate; |
| 51 final bool _lazy; | 83 final bool _lazy; |
| 52 final Profiler _perf; | 84 final Profiler _perf; |
| 85 |
| 86 /** |
| 87 * The direct parent scope that created this scope (this can also be the $root
Scope) |
| 88 */ |
| 53 final Scope $parent; | 89 final Scope $parent; |
| 54 | 90 |
| 91 /** |
| 92 * The auto-incremented ID of the scope |
| 93 */ |
| 55 String $id; | 94 String $id; |
| 95 |
| 96 /** |
| 97 * The topmost scope of the application (same as $rootScope). |
| 98 */ |
| 56 Scope $root; | 99 Scope $root; |
| 57 num _nextId = 0; | 100 num _nextId = 0; |
| 58 String _phase; | 101 String _phase; |
| 59 List _innerAsyncQueue; | 102 List _innerAsyncQueue; |
| 60 List _outerAsyncQueue; | 103 List _outerAsyncQueue; |
| 61 Scope _nextSibling, _prevSibling, _childHead, _childTail; | 104 Scope _nextSibling, _prevSibling, _childHead, _childTail; |
| 62 bool _skipAutoDigest = false; | 105 bool _skipAutoDigest = false; |
| 63 bool _disabled = false; | 106 bool _disabled = false; |
| 64 | 107 |
| 108 _set$Properties() { |
| 109 _properties[r'this'] = this; |
| 110 _properties[r'$id'] = this.$id; |
| 111 _properties[r'$parent'] = this.$parent; |
| 112 _properties[r'$root'] = this.$root; |
| 113 } |
| 114 |
| 65 Scope(this._exceptionHandler, this._parser, ScopeDigestTTL ttl, | 115 Scope(this._exceptionHandler, this._parser, ScopeDigestTTL ttl, |
| 66 this._zone, this._perf): | 116 this._zone, this._perf): |
| 67 $parent = null, _isolate = false, _lazy = false, _ttl = ttl.ttl { | 117 $parent = null, _isolate = false, _lazy = false, _ttl = ttl.ttl { |
| 68 _properties[r'this']= this; | |
| 69 $root = this; | 118 $root = this; |
| 70 $id = '_${$root._nextId++}'; | 119 $id = '_${$root._nextId++}'; |
| 71 _innerAsyncQueue = []; | 120 _innerAsyncQueue = []; |
| 72 _outerAsyncQueue = []; | 121 _outerAsyncQueue = []; |
| 73 | 122 |
| 74 // Set up the zone to auto digest this scope. | 123 // Set up the zone to auto digest this scope. |
| 75 _zone.onTurnDone = _autoDigestOnTurnDone; | 124 _zone.onTurnDone = _autoDigestOnTurnDone; |
| 76 _zone.onError = (e, s, ls) => _exceptionHandler(e, s); | 125 _zone.onError = (e, s, ls) => _exceptionHandler(e, s); |
| 126 _set$Properties(); |
| 77 } | 127 } |
| 78 | 128 |
| 79 Scope._child(Scope parent, bool this._isolate, bool this._lazy, Profiler this.
_perf): | 129 Scope._child(Scope parent, bool this._isolate, bool this._lazy, Profiler this.
_perf): |
| 80 $parent = parent, _ttl = parent._ttl, _parser = parent._parser, | 130 $parent = parent, _ttl = parent._ttl, _parser = parent._parser, |
| 81 _exceptionHandler = parent._exceptionHandler, _zone = parent._zone { | 131 _exceptionHandler = parent._exceptionHandler, _zone = parent._zone { |
| 82 _properties[r'this'] = this; | |
| 83 $root = $parent.$root; | 132 $root = $parent.$root; |
| 84 $id = '_${$root._nextId++}'; | 133 $id = '_${$root._nextId++}'; |
| 85 _innerAsyncQueue = $parent._innerAsyncQueue; | 134 _innerAsyncQueue = $parent._innerAsyncQueue; |
| 86 _outerAsyncQueue = $parent._outerAsyncQueue; | 135 _outerAsyncQueue = $parent._outerAsyncQueue; |
| 87 | 136 |
| 88 _prevSibling = $parent._childTail; | 137 _prevSibling = $parent._childTail; |
| 89 if ($parent._childHead != null) { | 138 if ($parent._childHead != null) { |
| 90 $parent._childTail._nextSibling = this; | 139 $parent._childTail._nextSibling = this; |
| 91 $parent._childTail = this; | 140 $parent._childTail = this; |
| 92 } else { | 141 } else { |
| 93 $parent._childHead = $parent._childTail = this; | 142 $parent._childHead = $parent._childTail = this; |
| 94 } | 143 } |
| 144 _set$Properties(); |
| 95 } | 145 } |
| 96 | 146 |
| 97 _autoDigestOnTurnDone() { | 147 _autoDigestOnTurnDone() { |
| 98 if (_skipAutoDigest) { | 148 if ($root._skipAutoDigest) { |
| 99 _skipAutoDigest = false; | 149 $root._skipAutoDigest = false; |
| 100 } else { | 150 } else { |
| 101 $digest(); | 151 $digest(); |
| 102 } | 152 } |
| 103 } | 153 } |
| 104 | 154 |
| 105 _identical(a, b) => | 155 _identical(a, b) => |
| 106 identical(a, b) || | 156 identical(a, b) || |
| 107 (a is String && b is String && a == b) || | 157 (a is String && b is String && a == b) || |
| 108 (a is num && b is num && a.isNaN && b.isNaN); | 158 (a is num && b is num && a.isNaN && b.isNaN); |
| 109 | 159 |
| 110 containsKey(String name) => this[name] != null; | 160 containsKey(String name) { |
| 161 for (var scope = this; scope != null; scope = scope.$parent) { |
| 162 if (scope._properties.containsKey(name)) { |
| 163 return true; |
| 164 } else if(scope._isolate) { |
| 165 break; |
| 166 } |
| 167 } |
| 168 return false; |
| 169 } |
| 170 |
| 111 remove(String name) => this._properties.remove(name); | 171 remove(String name) => this._properties.remove(name); |
| 112 operator []=(String name, value) => _properties[name] = value; | 172 operator []=(String name, value) => _properties[name] = value; |
| 113 operator [](String name) { | 173 operator [](String name) { |
| 114 if (name == r'$id') return this.$id; | 174 for (var scope = this; scope != null; scope = scope.$parent) { |
| 115 if (name == r'$parent') return this.$parent; | |
| 116 if (name == r'$root') return this.$root; | |
| 117 var scope = this; | |
| 118 do { | |
| 119 if (scope._properties.containsKey(name)) { | 175 if (scope._properties.containsKey(name)) { |
| 120 return scope._properties[name]; | 176 return scope._properties[name]; |
| 121 } else if (!scope._isolate) { | 177 } else if(scope._isolate) { |
| 122 scope = scope.$parent; | 178 break; |
| 123 } else { | |
| 124 return null; | |
| 125 } | 179 } |
| 126 } while(scope != null); | 180 } |
| 127 return null; | 181 return null; |
| 128 } | 182 } |
| 129 | 183 |
| 130 noSuchMethod(Invocation invocation) { | 184 noSuchMethod(Invocation invocation) { |
| 131 var name = MirrorSystem.getName(invocation.memberName); | 185 var name = MirrorSystem.getName(invocation.memberName); |
| 132 if (invocation.isGetter) { | 186 if (invocation.isGetter) { |
| 133 return this[name]; | 187 return this[name]; |
| 134 } else if (invocation.isSetter) { | 188 } else if (invocation.isSetter) { |
| 135 var value = invocation.positionalArguments[0]; | 189 var value = invocation.positionalArguments[0]; |
| 136 name = name.substring(0, name.length - 1); | 190 name = name.substring(0, name.length - 1); |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 } | 429 } |
| 376 | 430 |
| 377 | 431 |
| 378 /** | 432 /** |
| 379 * Add this function to your code if you want to add a $digest | 433 * Add this function to your code if you want to add a $digest |
| 380 * and want to assert that the digest will be called on this turn. | 434 * and want to assert that the digest will be called on this turn. |
| 381 * This method will be deleted when we are comfortable with | 435 * This method will be deleted when we are comfortable with |
| 382 * auto-digesting scope. | 436 * auto-digesting scope. |
| 383 */ | 437 */ |
| 384 $$verifyDigestWillRun() { | 438 $$verifyDigestWillRun() { |
| 385 assert(!_skipAutoDigest); | 439 assert(!$root._skipAutoDigest); |
| 386 _zone.assertInTurn(); | 440 _zone.assertInTurn(); |
| 387 } | 441 } |
| 388 | 442 |
| 389 /** | 443 /** |
| 390 * *EXPERIMENTAL:* This feature is experimental. We reserve the right to chang
e or delete it. | 444 * *EXPERIMENTAL:* This feature is experimental. We reserve the right to chang
e or delete it. |
| 391 * | 445 * |
| 392 * Marks a scope as dirty. If the scope is lazy (see [$new]) then the scope wi
ll be included | 446 * Marks a scope as dirty. If the scope is lazy (see [$new]) then the scope wi
ll be included |
| 393 * in the next [$digest]. | 447 * in the next [$digest]. |
| 394 * | 448 * |
| 395 * NOTE: This has no effect for non-lazy scopes. | 449 * NOTE: This has no effect for non-lazy scopes. |
| 396 */ | 450 */ |
| 397 $dirty() { | 451 $dirty() { |
| 398 this._disabled = false; | 452 this._disabled = false; |
| 399 } | 453 } |
| 400 | 454 |
| 455 /** |
| 456 * Processes all of the watchers of the current scope and its children. |
| 457 * Because a watcher's listener can change the model, the `$digest()` operatio
n keeps calling |
| 458 * the watchers no further response data has changed. This means that it is po
ssible to get |
| 459 * into an infinite loop. This function will throw `'Maximum iteration limit e
xceeded.'` |
| 460 * if the number of iterations exceeds 10. |
| 461 * |
| 462 * There should really be no need to call $digest() in production code since e
verything is |
| 463 * handled behind the scenes with zones and object mutation events. However, i
n testing |
| 464 * both $digest and [$apply] are useful to control state and simulate the scop
e life cycle in |
| 465 * a step-by-step manner. |
| 466 * |
| 467 * Refer to [$watch], [$watchSet] or [$watchCollection] to see how to register
watchers that |
| 468 * are executed during the digest cycle. |
| 469 */ |
| 401 $digest() { | 470 $digest() { |
| 402 try { | 471 try { |
| 403 _beginPhase('\$digest'); | 472 _beginPhase('\$digest'); |
| 404 _digestWhileDirtyLoop(); | 473 _digestWhileDirtyLoop(); |
| 405 } catch (e, s) { | 474 } catch (e, s) { |
| 406 _exceptionHandler(e, s); | 475 _exceptionHandler(e, s); |
| 407 } finally { | 476 } finally { |
| 408 _clearPhase(); | 477 _clearPhase(); |
| 409 } | 478 } |
| 410 } | 479 } |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 _digestUpdatePerfCounters(watcherCount, scopeCount); | 651 _digestUpdatePerfCounters(watcherCount, scopeCount); |
| 583 } | 652 } |
| 584 | 653 |
| 585 | 654 |
| 586 void _digestUpdatePerfCounters(int watcherCount, int scopeCount) { | 655 void _digestUpdatePerfCounters(int watcherCount, int scopeCount) { |
| 587 _perf.counters['ng.scope.watchers'] = watcherCount; | 656 _perf.counters['ng.scope.watchers'] = watcherCount; |
| 588 _perf.counters['ng.scopes'] = scopeCount; | 657 _perf.counters['ng.scopes'] = scopeCount; |
| 589 } | 658 } |
| 590 | 659 |
| 591 | 660 |
| 661 /** |
| 662 * Removes the current scope (and all of its children) from the parent scope.
Removal implies |
| 663 * that calls to $digest() will no longer propagate to the current scope and i
ts children. |
| 664 * Removal also implies that the current scope is eligible for garbage collect
ion. |
| 665 * |
| 666 * The `$destroy()` operation is usually used within directives that perform t
ransclusion on |
| 667 * multiple child elements (like ngRepeat) which create multiple child scopes. |
| 668 * |
| 669 * Just before a scope is destroyed, a `$destroy` event is broadcasted on this
scope. This is |
| 670 * a great way for child scopes (such as shared directives or controllers) to
detect to and |
| 671 * perform any necessary cleanup before the scope is removed from the applicat
ion. |
| 672 * |
| 673 * Note that, in AngularDart, there is also a `$destroy` jQuery DOM event, whi
ch can be used to |
| 674 * clean up DOM bindings before an element is removed from the DOM. |
| 675 */ |
| 592 $destroy() { | 676 $destroy() { |
| 593 if ($root == this) return; // we can't remove the root node; | 677 if ($root == this) return; // we can't remove the root node; |
| 594 | 678 |
| 595 $broadcast(r'$destroy'); | 679 $broadcast(r'$destroy'); |
| 596 | 680 |
| 597 if ($parent._childHead == this) $parent._childHead = _nextSibling; | 681 if ($parent._childHead == this) $parent._childHead = _nextSibling; |
| 598 if ($parent._childTail == this) $parent._childTail = _prevSibling; | 682 if ($parent._childTail == this) $parent._childTail = _prevSibling; |
| 599 if (_prevSibling != null) _prevSibling._nextSibling = _nextSibling; | 683 if (_prevSibling != null) _prevSibling._nextSibling = _nextSibling; |
| 600 if (_nextSibling != null) _nextSibling._prevSibling = _prevSibling; | 684 if (_nextSibling != null) _nextSibling._prevSibling = _prevSibling; |
| 601 } | 685 } |
| 602 | 686 |
| 603 | 687 |
| 688 /** |
| 689 * Evaluates the expression against the current scope and returns the result.
Note that, the |
| 690 * expression data is relative to the data within the scope. Therefore an expr
ession such as |
| 691 * `a + b` will deference variables `a` and `b` and return a result so long as
`a` and `b` |
| 692 * exist on the scope. |
| 693 * |
| 694 * * [expr] - The expression that will be evaluated. This can be both a Functi
on or a String. |
| 695 * * [locals] - An optional Map of key/value data that will override any match
ing scope members |
| 696 * for the purposes of the evaluation. |
| 697 */ |
| 604 $eval(expr, [locals]) { | 698 $eval(expr, [locals]) { |
| 605 return relaxFnArgs(_compileToFn(expr))(locals == null ? this : new ScopeLoca
ls(this, locals)); | 699 return relaxFnArgs(_compileToFn(expr))(locals == null ? this : new ScopeLoca
ls(this, locals)); |
| 606 } | 700 } |
| 607 | 701 |
| 608 | 702 |
| 703 /** |
| 704 * Evaluates the expression against the current scope at a later point in time
. The $evalAsync |
| 705 * operation may not get run right away (depending if an existing digest cycle
is going on) and |
| 706 * may therefore be issued later on (by a follow-up digest cycle). Note that a
t least one digest |
| 707 * cycle will be performed after the expression is evaluated. However, If trig
gering an additional |
| 708 * digest cycle is not desired then this can be avoided by placing `{outsideDi
gest: true}` as |
| 709 * the 2nd parameter to the function. |
| 710 * |
| 711 * * [expr] - The expression that will be evaluated. This can be both a Functi
on or a String. |
| 712 * * [outsideDigest] - Whether or not to trigger a follow-up digest after eval
uation. |
| 713 */ |
| 609 $evalAsync(expr, {outsideDigest: false}) { | 714 $evalAsync(expr, {outsideDigest: false}) { |
| 610 if (outsideDigest) { | 715 if (outsideDigest) { |
| 611 _outerAsyncQueue.add(expr); | 716 _outerAsyncQueue.add(expr); |
| 612 } else { | 717 } else { |
| 613 _innerAsyncQueue.add(expr); | 718 _innerAsyncQueue.add(expr); |
| 614 } | 719 } |
| 615 } | 720 } |
| 616 | 721 |
| 617 | 722 |
| 618 /** | 723 /** |
| 619 * Skip running a $digest at the end of this turn. | 724 * Skip running a $digest at the end of this turn. |
| 620 * The primary use case is to skip the digest in the current VM turn because | 725 * The primary use case is to skip the digest in the current VM turn because |
| 621 * you just scheduled or are otherwise certain of an impending VM turn and the | 726 * you just scheduled or are otherwise certain of an impending VM turn and the |
| 622 * digest at the end of that turn is sufficient. You should be able to answer | 727 * digest at the end of that turn is sufficient. You should be able to answer |
| 623 * "No" to the question "Is there any other code that is aware that this VM | 728 * "No" to the question "Is there any other code that is aware that this VM |
| 624 * turn occured and therefore expected a digest?". If your answer is "Yes", | 729 * turn occurred and therefore expected a digest?". If your answer is "Yes", |
| 625 * then you run the risk that the very next VM turn is not for your event and | 730 * then you run the risk that the very next VM turn is not for your event and |
| 626 * now that other code runs in that turn and sees stale values. | 731 * now that other code runs in that turn and sees stale values. |
| 627 * | 732 * |
| 628 * You might call this function, for instance, from an event listener where, | 733 * You might call this function, for instance, from an event listener where, |
| 629 * though the event occured, you need to wait for another event before you can | 734 * though the event occurred, you need to wait for another event before you ca
n |
| 630 * perform something meaningful. You might schedule that other event, | 735 * perform something meaningful. You might schedule that other event, |
| 631 * set a flag for the handler of the other event to recognize, etc. and then | 736 * set a flag for the handler of the other event to recognize, etc. and then |
| 632 * call this method to skip the digest this cycle. Note that you should call | 737 * call this method to skip the digest this cycle. Note that you should call |
| 633 * this function *after* you have successfully confirmed that the expected VM | 738 * this function *after* you have successfully confirmed that the expected VM |
| 634 * turn will occur (perhaps by scheduling it) to ensure that the digest | 739 * turn will occur (perhaps by scheduling it) to ensure that the digest |
| 635 * actually does take place on that turn. | 740 * actually does take place on that turn. |
| 636 */ | 741 */ |
| 637 $skipAutoDigest() { | 742 $skipAutoDigest() { |
| 638 _zone.assertInTurn(); | 743 _zone.assertInTurn(); |
| 639 _skipAutoDigest = true; | 744 $root._skipAutoDigest = true; |
| 640 } | 745 } |
| 641 | 746 |
| 642 | 747 |
| 748 /** |
| 749 * Triggers a digest operation much like [$digest] does, however, also accepts
an |
| 750 * optional expression to evaluate alongside the digest operation. The result
of that |
| 751 * expression will be returned afterwards. Much like with $digest, $apply shou
ld only be |
| 752 * used within unit tests to simulate the life cycle of a scope. See [$digest]
to learn |
| 753 * more. |
| 754 * |
| 755 * * [expr] - optional expression which will be evaluated after the digest is
performed. See [$eval] |
| 756 * to learn more about expressions. |
| 757 */ |
| 643 $apply([expr]) { | 758 $apply([expr]) { |
| 644 return _zone.run(() { | 759 return _zone.run(() { |
| 645 var timerId; | 760 var timerId; |
| 646 try { | 761 try { |
| 647 assert((timerId = _perf.startTimer('ng.\$apply', _source(expr))) != fals
e); | 762 assert((timerId = _perf.startTimer('ng.\$apply', _source(expr))) != fals
e); |
| 648 return $eval(expr); | 763 return $eval(expr); |
| 649 } catch (e, s) { | 764 } catch (e, s) { |
| 650 _exceptionHandler(e, s); | 765 _exceptionHandler(e, s); |
| 651 } finally { | 766 } finally { |
| 652 assert(_perf.stopTimer(timerId) != false); | 767 assert(_perf.stopTimer(timerId) != false); |
| 653 } | 768 } |
| 654 }); | 769 }); |
| 655 } | 770 } |
| 656 | 771 |
| 657 | 772 |
| 773 /** |
| 774 * Registers a scope-based event listener to intercept events triggered by |
| 775 * [$broadcast] (from any parent scopes) or [$emit] (from child scopes) that |
| 776 * match the given event name. $on accepts two arguments: |
| 777 * |
| 778 * * [name] - Refers to the event name that the scope will listen on. |
| 779 * * [listener] - Refers to the callback function which is executed when the e
vent |
| 780 * is intercepted. |
| 781 * |
| 782 * |
| 783 * When the listener function is executed, an instance of [ScopeEvent] will be
passed |
| 784 * as the first parameter to the function. |
| 785 * |
| 786 * Any additional parameters available within the listener callback function a
re those that |
| 787 * are set by the $broadcast or $emit scope methods (which are set by the orig
in scope which |
| 788 * is the scope that first triggered the scope event). |
| 789 */ |
| 658 $on(name, listener) { | 790 $on(name, listener) { |
| 659 var namedListeners = _listeners[name]; | 791 var namedListeners = _listeners[name]; |
| 660 if (!_listeners.containsKey(name)) { | 792 if (!_listeners.containsKey(name)) { |
| 661 _listeners[name] = namedListeners = []; | 793 _listeners[name] = namedListeners = []; |
| 662 } | 794 } |
| 663 namedListeners.add(listener); | 795 namedListeners.add(listener); |
| 664 | 796 |
| 665 return () { | 797 return () { |
| 666 namedListeners.remove(listener); | 798 namedListeners.remove(listener); |
| 667 }; | 799 }; |
| 668 } | 800 } |
| 669 | 801 |
| 670 | 802 |
| 803 /** |
| 804 * Triggers a scope event referenced by the [name] parameters upwards towards
the root of the |
| 805 * scope tree. If intercepted, by a parent scope containing a matching scope e
vent listener |
| 806 * (which is registered via the [$on] scope method), then the event listener c
allback function |
| 807 * will be executed. |
| 808 * |
| 809 * * [name] - The scope event name that will be triggered. |
| 810 * * [args] - An optional list of arguments that will be fed into the listener
callback function |
| 811 * for any event listeners that are registered via [$on]. |
| 812 */ |
| 671 $emit(name, [List args]) { | 813 $emit(name, [List args]) { |
| 672 var empty = [], | 814 var empty = [], |
| 673 namedListeners, | 815 namedListeners, |
| 674 scope = this, | 816 scope = this, |
| 675 event = new ScopeEvent(name, this), | 817 event = new ScopeEvent(name, this), |
| 676 listenerArgs = [event], | 818 listenerArgs = [event], |
| 677 i; | 819 i; |
| 678 | 820 |
| 679 if (args != null) { | 821 if (args != null) { |
| 680 listenerArgs.addAll(args); | 822 listenerArgs.addAll(args); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 695 } | 837 } |
| 696 } | 838 } |
| 697 //traverse upwards | 839 //traverse upwards |
| 698 scope = scope.$parent; | 840 scope = scope.$parent; |
| 699 } while (scope != null); | 841 } while (scope != null); |
| 700 | 842 |
| 701 return event; | 843 return event; |
| 702 } | 844 } |
| 703 | 845 |
| 704 | 846 |
| 847 /** |
| 848 * Triggers a scope event referenced by the [name] parameters dowards towards
the leaf nodes of the |
| 849 * scope tree. If intercepted, by a child scope containing a matching scope ev
ent listener |
| 850 * (which is registered via the [$on] scope method), then the event listener c
allback function |
| 851 * will be executed. |
| 852 * |
| 853 * * [name] - The scope event name that will be triggered. |
| 854 * * [listenerArgs] - An optional list of arguments that will be fed into the
listener callback function |
| 855 * for any event listeners that are registered via [$on]. |
| 856 */ |
| 705 $broadcast(String name, [List listenerArgs]) { | 857 $broadcast(String name, [List listenerArgs]) { |
| 706 var target = this, | 858 var target = this, |
| 707 current = target, | 859 current = target, |
| 708 next = target, | 860 next = target, |
| 709 event = new ScopeEvent(name, this); | 861 event = new ScopeEvent(name, this); |
| 710 | 862 |
| 711 //down while you can, then up and next sibling or up and next sibling until
back at root | 863 //down while you can, then up and next sibling or up and next sibling until
back at root |
| 712 if (listenerArgs == null) { | 864 if (listenerArgs == null) { |
| 713 listenerArgs = []; | 865 listenerArgs = []; |
| 714 } | 866 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 760 | 912 |
| 761 _clearPhase() { | 913 _clearPhase() { |
| 762 assert(_perf.stopTimer('ng.phase.${$root._phase}') != false); | 914 assert(_perf.stopTimer('ng.phase.${$root._phase}') != false); |
| 763 $root._phase = null; | 915 $root._phase = null; |
| 764 } | 916 } |
| 765 | 917 |
| 766 Function _compileToFn(exp) { | 918 Function _compileToFn(exp) { |
| 767 if (exp == null) { | 919 if (exp == null) { |
| 768 return () => null; | 920 return () => null; |
| 769 } else if (exp is String) { | 921 } else if (exp is String) { |
| 770 return _parser(exp).eval; | 922 Expression expression = _parser(exp); |
| 923 return expression.eval; |
| 771 } else if (exp is Function) { | 924 } else if (exp is Function) { |
| 772 return exp; | 925 return exp; |
| 773 } else { | 926 } else { |
| 774 throw 'Expecting String or Function'; | 927 throw 'Expecting String or Function'; |
| 775 } | 928 } |
| 776 } | 929 } |
| 777 } | 930 } |
| 778 | 931 |
| 779 @proxy | 932 @proxy |
| 780 class ScopeLocals implements Scope, Map { | 933 class ScopeLocals implements Scope, Map { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 return JSON.encode(obj); | 1004 return JSON.encode(obj); |
| 852 } catch(e) { | 1005 } catch(e) { |
| 853 var ret = "NOT-JSONABLE"; | 1006 var ret = "NOT-JSONABLE"; |
| 854 // Keep prod fast. | 1007 // Keep prod fast. |
| 855 assert((() { | 1008 assert((() { |
| 856 var mirror = reflect(obj); | 1009 var mirror = reflect(obj); |
| 857 if (mirror is ClosureMirror) { | 1010 if (mirror is ClosureMirror) { |
| 858 // work-around dartbug.com/14130 | 1011 // work-around dartbug.com/14130 |
| 859 try { | 1012 try { |
| 860 ret = mirror.function.source; | 1013 ret = mirror.function.source; |
| 861 } on NoSuchMethodError catch (e) {} | 1014 } on NoSuchMethodError catch (e) { |
| 1015 } on UnimplementedError catch (e) { |
| 1016 } |
| 862 } | 1017 } |
| 863 return true; | 1018 return true; |
| 864 })()); | 1019 })()); |
| 865 return ret; | 1020 return ret; |
| 866 } | 1021 } |
| 867 } | 1022 } |
| 868 | 1023 |
| 869 String _source(obj) { | 1024 String _source(obj) { |
| 870 if (obj is Function) { | 1025 if (obj is Function) { |
| 871 var m = reflect(obj); | 1026 var m = reflect(obj); |
| 872 if (m is ClosureMirror) { | 1027 if (m is ClosureMirror) { |
| 873 // work-around dartbug.com/14130 | 1028 // work-around dartbug.com/14130 |
| 874 try { | 1029 try { |
| 875 return "FN: ${m.function.source}"; | 1030 return "FN: ${m.function.source}"; |
| 876 } on NoSuchMethodError catch (e) { | 1031 } on NoSuchMethodError catch (e) { |
| 877 } on UnimplementedError catch (e) { | 1032 } on UnimplementedError catch (e) { |
| 878 } | 1033 } |
| 879 } | 1034 } |
| 880 } | 1035 } |
| 881 return '$obj'; | 1036 return '$obj'; |
| 882 } | 1037 } |
| OLD | NEW |