aboutsummaryrefslogtreecommitdiff
path: root/contexts/data/lib/closure-library/closure/goog/labs/observe/observableset.js
blob: 8ce844e2b6ee95ae272132e6bee89e38e8e731ce (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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview A set of {@code goog.labs.observe.Observable}s that
 * allow registering and removing observers to all of the observables
 * in the set.
 */

goog.provide('goog.labs.observe.ObservableSet');

goog.require('goog.array');
goog.require('goog.labs.observe.Observer');



/**
 * Creates a set of observables.
 *
 * An ObservableSet is a collection of observables. Observers may be
 * reigstered and will receive notifications when any of the
 * observables notify. This class is meant to simplify management of
 * observations on multiple observables of the same nature.
 *
 * @constructor
 */
goog.labs.observe.ObservableSet = function() {
  /**
   * The observers registered with this set.
   * @type {!Array.<!goog.labs.observe.Observer>}
   * @private
   */
  this.observers_ = [];

  /**
   * The observables in this set.
   * @type {!Array.<!goog.labs.observe.Observable>}
   * @private
   */
  this.observables_ = [];
};


/**
 * Adds an observer that observes all observables in the set. If new
 * observables are added to or removed from the set, the observer will
 * be registered or unregistered accordingly.
 *
 * The observer will not be added if there is already an equivalent
 * observer.
 *
 * @param {!goog.labs.observe.Observer} observer The observer to invoke.
 * @return {boolean} Whether the observer is actually added.
 */
goog.labs.observe.ObservableSet.prototype.addObserver = function(observer) {
  // Check whether the observer already exists.
  if (goog.array.find(this.observers_, goog.partial(
          goog.labs.observe.Observer.equals, observer))) {
    return false;
  }

  this.observers_.push(observer);
  goog.array.forEach(this.observables_, function(o) {
    o.observe(observer);
  });
  return true;
};


/**
 * Removes an observer from the set. The observer will be removed from
 * all observables in the set. Does nothing if the observer is not in
 * the set.
 * @param {!goog.labs.observe.Observer} observer The observer to remove.
 * @return {boolean} Whether the observer is actually removed.
 */
goog.labs.observe.ObservableSet.prototype.removeObserver = function(observer) {
  // Check that the observer exists before removing.
  var removed = goog.array.removeIf(this.observers_, goog.partial(
      goog.labs.observe.Observer.equals, observer));

  if (removed) {
    goog.array.forEach(this.observables_, function(o) {
      o.unobserve(observer);
    });
  }
  return removed;
};


/**
 * Removes all registered observers.
 */
goog.labs.observe.ObservableSet.prototype.removeAllObservers = function() {
  this.unregisterAll_();
  this.observers_.length = 0;
};


/**
 * Adds an observable to the set. All previously added and future
 * observers will be added to the new observable as well.
 *
 * The observable will not be added if it is already registered in the
 * set.
 *
 * @param {!goog.labs.observe.Observable} observable The observable to add.
 * @return {boolean} Whether the observable is actually added.
 */
goog.labs.observe.ObservableSet.prototype.addObservable = function(observable) {
  if (goog.array.contains(this.observables_, observable)) {
    return false;
  }

  this.observables_.push(observable);
  goog.array.forEach(this.observers_, function(observer) {
    observable.observe(observer);
  });
  return true;
};


/**
 * Removes an observable from the set. All observers registered on the
 * set will be removed from the observable as well.
 * @param {!goog.labs.observe.Observable} observable The observable to remove.
 * @return {boolean} Whether the observable is actually removed.
 */
goog.labs.observe.ObservableSet.prototype.removeObservable = function(
    observable) {
  var removed = goog.array.remove(this.observables_, observable);
  if (removed) {
    goog.array.forEach(this.observers_, function(observer) {
      observable.unobserve(observer);
    });
  }
  return removed;
};


/**
 * Removes all registered observables.
 */
goog.labs.observe.ObservableSet.prototype.removeAllObservables = function() {
  this.unregisterAll_();
  this.observables_.length = 0;
};


/**
 * Removes all registered observations and observables.
 */
goog.labs.observe.ObservableSet.prototype.removeAll = function() {
  this.removeAllObservers();
  this.observables_.length = 0;
};


/**
 * Unregisters all registered observers from all registered observables.
 * @private
 */
goog.labs.observe.ObservableSet.prototype.unregisterAll_ = function() {
  goog.array.forEach(this.observers_, function(observer) {
    goog.array.forEach(this.observables_, function(o) {
      o.unobserve(observer);
    });
  }, this);
};