|
622 | 622 | }, source);
|
623 | 623 | };
|
624 | 624 |
|
625 |
| - /** |
626 |
| - * Returns the only element of an observable sequence that satisfies the condition in the optional predicate, and reports an exception if there is not exactly one element in the observable sequence. |
627 |
| - * @param {Function} [predicate] A predicate function to evaluate for elements in the source sequence. |
628 |
| - * @param {Any} [thisArg] Object to use as `this` when executing the predicate. |
629 |
| - * @returns {Observable} Sequence containing the single element in the observable sequence that satisfies the condition in the predicate. |
630 |
| - */ |
631 |
| - observableProto.single = function (predicate, thisArg) { |
632 |
| - if (isFunction(predicate)) { return this.filter(predicate, thisArg).single(); } |
633 |
| - var source = this; |
634 |
| - return new AnonymousObservable(function (o) { |
635 |
| - var value, seenValue = false; |
636 |
| - return source.subscribe(function (x) { |
637 |
| - if (seenValue) { |
638 |
| - o.onError(new Error('Sequence contains more than one element')); |
639 |
| - } else { |
640 |
| - value = x; |
641 |
| - seenValue = true; |
| 625 | + var SingleObserver = (function(__super__) { |
| 626 | + inherits(SingleObserver, __super__); |
| 627 | + function SingleObserver(o, obj, s) { |
| 628 | + this._o = o; |
| 629 | + this._obj = obj; |
| 630 | + this._s = s; |
| 631 | + this._i = 0; |
| 632 | + this._hv = false; |
| 633 | + this._v = null; |
| 634 | + __super__.call(this); |
| 635 | + } |
| 636 | + |
| 637 | + SingleObserver.prototype.next = function (x) { |
| 638 | + var shouldYield = false; |
| 639 | + if (this._obj.predicate) { |
| 640 | + var res = tryCatch(this._obj.predicate)(x, this._i++, this._s); |
| 641 | + if (res === errorObj) { return this._o.onError(res.e); } |
| 642 | + Boolean(res) && (shouldYield = true); |
| 643 | + } else if (!this._obj.predicate) { |
| 644 | + shouldYield = true; |
| 645 | + } |
| 646 | + if (shouldYield) { |
| 647 | + if (this._hv) { |
| 648 | + return this._o.onError(new Error('Sequence contains more than one matching element')); |
642 | 649 | }
|
643 |
| - }, function (e) { o.onError(e); }, function () { |
644 |
| - o.onNext(value); |
645 |
| - o.onCompleted(); |
646 |
| - }); |
647 |
| - }, source); |
648 |
| - }; |
| 650 | + this._hv = true; |
| 651 | + this._v = x; |
| 652 | + } |
| 653 | + }; |
| 654 | + SingleObserver.prototype.error = function (e) { this._o.onError(e); }; |
| 655 | + SingleObserver.prototype.completed = function () { |
| 656 | + if (this._hv) { |
| 657 | + this._o.onNext(this._v); |
| 658 | + this._o.onCompleted(); |
| 659 | + } |
| 660 | + else if (this._obj.defaultValue === undefined) { |
| 661 | + this._o.onError(new EmptyError()); |
| 662 | + } else { |
| 663 | + this._o.onNext(this._obj.defaultValue); |
| 664 | + this._o.onCompleted(); |
| 665 | + } |
| 666 | + }; |
| 667 | + |
| 668 | + return SingleObserver; |
| 669 | + }(AbstractObserver)); |
| 670 | + |
| 671 | + |
| 672 | + /** |
| 673 | + * Returns the only element of an observable sequence that satisfies the condition in the optional predicate, and reports an exception if there is not exactly one element in the observable sequence. |
| 674 | + * @returns {Observable} Sequence containing the single element in the observable sequence that satisfies the condition in the predicate. |
| 675 | + */ |
| 676 | + observableProto.single = function (predicate, thisArg) { |
| 677 | + var obj = {}, source = this; |
| 678 | + if (typeof arguments[0] === 'object') { |
| 679 | + obj = arguments[0]; |
| 680 | + } else { |
| 681 | + obj = { |
| 682 | + predicate: arguments[0], |
| 683 | + thisArg: arguments[1], |
| 684 | + defaultValue: arguments[2] |
| 685 | + }; |
| 686 | + } |
| 687 | + if (isFunction (obj.predicate)) { |
| 688 | + var fn = obj.predicate; |
| 689 | + obj.predicate = bindCallback(fn, obj.thisArg, 3); |
| 690 | + } |
| 691 | + return new AnonymousObservable(function (o) { |
| 692 | + return source.subscribe(new SingleObserver(o, obj, source)); |
| 693 | + }, source); |
| 694 | + }; |
649 | 695 |
|
650 | 696 | var FirstObserver = (function(__super__) {
|
651 | 697 | inherits(FirstObserver, __super__);
|
|
707 | 753 | }, source);
|
708 | 754 | };
|
709 | 755 |
|
| 756 | + var LastObserver = (function(__super__) { |
| 757 | + inherits(LastObserver, __super__); |
| 758 | + function LastObserver(o, obj, s) { |
| 759 | + this._o = o; |
| 760 | + this._obj = obj; |
| 761 | + this._s = s; |
| 762 | + this._i = 0; |
| 763 | + this._hv = false; |
| 764 | + this._v = null; |
| 765 | + __super__.call(this); |
| 766 | + } |
| 767 | + |
| 768 | + LastObserver.prototype.next = function (x) { |
| 769 | + var shouldYield = false; |
| 770 | + if (this._obj.predicate) { |
| 771 | + var res = tryCatch(this._obj.predicate)(x, this._i++, this._s); |
| 772 | + if (res === errorObj) { return this._o.onError(res.e); } |
| 773 | + Boolean(res) && (shouldYield = true); |
| 774 | + } else if (!this._obj.predicate) { |
| 775 | + shouldYield = true; |
| 776 | + } |
| 777 | + if (shouldYield) { |
| 778 | + this._hv = true; |
| 779 | + this._v = x; |
| 780 | + } |
| 781 | + }; |
| 782 | + LastObserver.prototype.error = function (e) { this._o.onError(e); }; |
| 783 | + LastObserver.prototype.completed = function () { |
| 784 | + if (this._hv) { |
| 785 | + this._o.onNext(this._v); |
| 786 | + this._o.onCompleted(); |
| 787 | + } |
| 788 | + else if (this._obj.defaultValue === undefined) { |
| 789 | + this._o.onError(new EmptyError()); |
| 790 | + } else { |
| 791 | + this._o.onNext(this._obj.defaultValue); |
| 792 | + this._o.onCompleted(); |
| 793 | + } |
| 794 | + }; |
| 795 | + |
| 796 | + return LastObserver; |
| 797 | + }(AbstractObserver)); |
| 798 | + |
710 | 799 | /**
|
711 | 800 | * Returns the last element of an observable sequence that satisfies the condition in the predicate if specified, else the last element.
|
712 | 801 | * @returns {Observable} Sequence containing the last element in the observable sequence that satisfies the condition in the predicate.
|
|
727 | 816 | obj.predicate = bindCallback(fn, obj.thisArg, 3);
|
728 | 817 | }
|
729 | 818 | return new AnonymousObservable(function (o) {
|
730 |
| - var value, seenValue = false, i = 0; |
731 |
| - return source.subscribe( |
732 |
| - function (x) { |
733 |
| - if (obj.predicate) { |
734 |
| - var res = tryCatch(obj.predicate)(x, i++, source); |
735 |
| - if (res === errorObj) { return o.onError(res.e); } |
736 |
| - if (res) { |
737 |
| - seenValue = true; |
738 |
| - value = x; |
739 |
| - } |
740 |
| - } else if (!obj.predicate) { |
741 |
| - seenValue = true; |
742 |
| - value = x; |
743 |
| - } |
744 |
| - }, |
745 |
| - function (e) { o.onError(e); }, |
746 |
| - function () { |
747 |
| - if (seenValue) { |
748 |
| - o.onNext(value); |
749 |
| - o.onCompleted(); |
750 |
| - } |
751 |
| - else if (obj.defaultValue === undefined) { |
752 |
| - o.onError(new EmptyError()); |
753 |
| - } else { |
754 |
| - o.onNext(obj.defaultValue); |
755 |
| - o.onCompleted(); |
756 |
| - } |
757 |
| - }); |
| 819 | + return source.subscribe(new LastObserver(o, obj, source)); |
758 | 820 | }, source);
|
759 | 821 | };
|
760 | 822 |
|
|
0 commit comments