summaryrefslogtreecommitdiffstats
path: root/public/src/app/sdc/base-pubsub.ts
blob: f7fcadc7e15660e426841e08d49b49ac8cb26583 (plain)
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
declare const window: Window;

export interface IPubSubEvent {
  type: string;
  originId: string;
  data: any;
}

export interface ISubscriber {
  window: Window;
  locationUrl: string;
}

export class BasePubSub {
  subscribers: Map<string, ISubscriber>;
  eventsCallbacks: Array<Function>;
  clientId: string;
  eventsToWait: Map<string, Array<string>>;

  constructor(pluginId: string) {
    this.subscribers = new Map<string, ISubscriber>();
    this.eventsCallbacks = [];
    this.eventsToWait = new Map<string, Array<string>>();
    this.clientId = pluginId;
    this.onMessage = this.onMessage.bind(this);

    window.addEventListener('message', this.onMessage);
  }

  public register(
    subscriberId: string,
    subscriberWindow: Window,
    subscriberUrl: string
  ) {
    const subscriber = {
      window: subscriberWindow,
      locationUrl: subscriberUrl || subscriberWindow.location.href
    };

    this.subscribers.set(subscriberId, subscriber);
  }

  public unregister(subscriberId: string) {
    this.subscribers.delete(subscriberId);
  }

  public on(callback: Function) {
    const functionExists = this.eventsCallbacks.find((func: Function) => {
      return callback.toString() === func.toString();
    });

    if (!functionExists) {
      this.eventsCallbacks.push(callback);
    }
  }

  public off(callback: Function) {
    const index = this.eventsCallbacks.indexOf(callback);
    this.eventsCallbacks.splice(index, 1);
  }

  public notify(eventType: string, eventData?: any) {
    const eventObj = {
      type: eventType,
      data: eventData,
      originId: this.clientId
    };

    this.subscribers.forEach(
      (subscriber: ISubscriber, subscriberId: string) => {
        subscriber.window.postMessage(eventObj, subscriber.locationUrl);
      }
    );

    return {
      subscribe: function(callbackFn) {
        if (this.subscribers.size !== 0) {
          const subscribersToNotify = Array.from(this.subscribers.keys());

          const checkNotifyComplete = (subscriberId: string) => {
            const index = subscribersToNotify.indexOf(subscriberId);
            subscribersToNotify.splice(index, 1);

            if (subscribersToNotify.length === 0) {
              callbackFn();
            }
          };

          this.subscribers.forEach(
            (subscriber: ISubscriber, subscriberId: string) => {
              if (
                this.eventsToWait.has(subscriberId) &&
                this.eventsToWait.get(subscriberId).indexOf(eventType) !== -1
              ) {
                const actionCompletedFunction = (
                  eventData,
                  subId = subscriberId
                ) => {
                  if (eventData.type === 'ACTION_COMPLETED') {
                    checkNotifyComplete(subId);
                  }
                  this.off(actionCompletedFunction);
                };
                this.on(actionCompletedFunction);
              } else {
                checkNotifyComplete(subscriberId);
              }
            }
          );
        } else {
          callbackFn();
        }
      }.bind(this)
    };
  }

  protected onMessage(event: any) {
    if (this.subscribers.has(event.data.originId)) {
      this.eventsCallbacks.forEach((callback: Function) => {
        callback(event.data, event);
      });
    }
  }
}