Code coverage report for src/operator/windowToggle.ts

Statements: 100% (83 / 83)      Branches: 100% (2 / 2)      Functions: 100% (21 / 21)      Lines: 100% (76 / 76)      Ignored: none     

All files » src/operator/ » windowToggle.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133  1   1 1   1 1   1   15     1   15 15     1 15       1             1 15   1 15 15 15 15     1 61 61 61 59       1 6 6 5   6     1 7 7 6 6 6   7     1 29 29 29 1   28       28 28 28 28 28       1 20 20 20 20 20 20   1   1 28 28 28     1 18     1 2     1 2   1   1 15 15     1 29     1 1     1     1  
import {Operator} from '../Operator';
import {Subscriber} from '../Subscriber';
import {Observable} from '../Observable';
import {Subject} from '../Subject';
import {Subscription} from '../Subscription';
 
import {tryCatch} from '../util/tryCatch';
import {errorObject} from '../util/errorObject';
 
export function windowToggle<T, O>(openings: Observable<O>,
                                   closingSelector: (openValue: O) => Observable<any>): Observable<Observable<T>> {
  return this.lift(new WindowToggleOperator<T, T, O>(openings, closingSelector));
}
 
class WindowToggleOperator<T, R, O> implements Operator<T, R> {
 
  constructor(private openings: Observable<O>,
              private closingSelector: (openValue: O) => Observable<any>) {
  }
 
  call(subscriber: Subscriber<T>): Subscriber<T> {
    return new WindowToggleSubscriber<T, O>(
      subscriber, this.openings, this.closingSelector
    );
  }
}
 
interface WindowContext<T> {
  window: Subject<T>;
  subscription: Subscription<T>;
}
 
class WindowToggleSubscriber<T, O> extends Subscriber<T> {
  private contexts: Array<WindowContext<T>> = [];
 
  constructor(destination: Subscriber<T>,
              private openings: Observable<O>,
              private closingSelector: (openValue: O) => Observable<any>) {
    super(destination);
    this.add(this.openings._subscribe(new WindowToggleOpeningsSubscriber(this)));
  }
 
  _next(value: T) {
    const contexts = this.contexts;
    const len = contexts.length;
    for (let i = 0; i < len; i++) {
      contexts[i].window.next(value);
    }
  }
 
  _error(err: any) {
    const contexts = this.contexts;
    while (contexts.length > 0) {
      contexts.shift().window.error(err);
    }
    this.destination.error(err);
  }
 
  _complete() {
    const contexts = this.contexts;
    while (contexts.length > 0) {
      const context = contexts.shift();
      context.window.complete();
      context.subscription.unsubscribe();
    }
    this.destination.complete();
  }
 
  openWindow(value: O) {
    const closingSelector = this.closingSelector;
    let closingNotifier = tryCatch(closingSelector)(value);
    if (closingNotifier === errorObject) {
      this.error(closingNotifier.e);
    } else {
      let context = {
        window: new Subject<T>(),
        subscription: new Subscription()
      };
      this.contexts.push(context);
      this.destination.next(context.window);
      const subscriber = new WindowClosingNotifierSubscriber<T, O>(this, context);
      const subscription = closingNotifier._subscribe(subscriber);
      this.add(context.subscription.add(subscription));
    }
  }
 
  closeWindow(context: WindowContext<T>) {
    const { window, subscription } = context;
    const contexts = this.contexts;
    contexts.splice(contexts.indexOf(context), 1);
    window.complete();
    this.remove(subscription);
    subscription.unsubscribe();
  }
}
 
class WindowClosingNotifierSubscriber<T, O> extends Subscriber<T> {
  constructor(private parent: WindowToggleSubscriber<T, O>,
              private windowContext: { window: Subject<T>, subscription: Subscription<T> }) {
    super(null);
  }
 
  _next() {
    this.parent.closeWindow(this.windowContext);
  }
 
  _error(err) {
    this.parent.error(err);
  }
 
  _complete() {
    this.parent.closeWindow(this.windowContext);
  }
}
 
class WindowToggleOpeningsSubscriber<T> extends Subscriber<T> {
  constructor(private parent: WindowToggleSubscriber<any, T>) {
    super();
  }
 
  _next(value: T) {
    this.parent.openWindow(value);
  }
 
  _error(err) {
    this.parent.error(err);
  }
 
  _complete() {
    // noop
  }
}