Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/disposable/disposable.js
2868 views
1
// Copyright 2005 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Implements the disposable interface. The dispose method is used
17
* to clean up references and resources.
18
* @author [email protected] (Erik Arvidsson)
19
*/
20
21
22
goog.provide('goog.Disposable');
23
goog.provide('goog.dispose');
24
goog.provide('goog.disposeAll');
25
26
goog.require('goog.disposable.IDisposable');
27
28
29
30
/**
31
* Class that provides the basic implementation for disposable objects. If your
32
* class holds one or more references to COM objects, DOM nodes, or other
33
* disposable objects, it should extend this class or implement the disposable
34
* interface (defined in goog.disposable.IDisposable).
35
* @constructor
36
* @implements {goog.disposable.IDisposable}
37
*/
38
goog.Disposable = function() {
39
/**
40
* If monitoring the goog.Disposable instances is enabled, stores the creation
41
* stack trace of the Disposable instance.
42
* @type {string|undefined}
43
*/
44
this.creationStack;
45
46
if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
47
if (goog.Disposable.INCLUDE_STACK_ON_CREATION) {
48
this.creationStack = new Error().stack;
49
}
50
goog.Disposable.instances_[goog.getUid(this)] = this;
51
}
52
// Support sealing
53
this.disposed_ = this.disposed_;
54
this.onDisposeCallbacks_ = this.onDisposeCallbacks_;
55
};
56
57
58
/**
59
* @enum {number} Different monitoring modes for Disposable.
60
*/
61
goog.Disposable.MonitoringMode = {
62
/**
63
* No monitoring.
64
*/
65
OFF: 0,
66
/**
67
* Creating and disposing the goog.Disposable instances is monitored. All
68
* disposable objects need to call the {@code goog.Disposable} base
69
* constructor. The PERMANENT mode must be switched on before creating any
70
* goog.Disposable instances.
71
*/
72
PERMANENT: 1,
73
/**
74
* INTERACTIVE mode can be switched on and off on the fly without producing
75
* errors. It also doesn't warn if the disposable objects don't call the
76
* {@code goog.Disposable} base constructor.
77
*/
78
INTERACTIVE: 2
79
};
80
81
82
/**
83
* @define {number} The monitoring mode of the goog.Disposable
84
* instances. Default is OFF. Switching on the monitoring is only
85
* recommended for debugging because it has a significant impact on
86
* performance and memory usage. If switched off, the monitoring code
87
* compiles down to 0 bytes.
88
*/
89
goog.define('goog.Disposable.MONITORING_MODE', 0);
90
91
92
/**
93
* @define {boolean} Whether to attach creation stack to each created disposable
94
* instance; This is only relevant for when MonitoringMode != OFF.
95
*/
96
goog.define('goog.Disposable.INCLUDE_STACK_ON_CREATION', true);
97
98
99
/**
100
* Maps the unique ID of every undisposed {@code goog.Disposable} object to
101
* the object itself.
102
* @type {!Object<number, !goog.Disposable>}
103
* @private
104
*/
105
goog.Disposable.instances_ = {};
106
107
108
/**
109
* @return {!Array<!goog.Disposable>} All {@code goog.Disposable} objects that
110
* haven't been disposed of.
111
*/
112
goog.Disposable.getUndisposedObjects = function() {
113
var ret = [];
114
for (var id in goog.Disposable.instances_) {
115
if (goog.Disposable.instances_.hasOwnProperty(id)) {
116
ret.push(goog.Disposable.instances_[Number(id)]);
117
}
118
}
119
return ret;
120
};
121
122
123
/**
124
* Clears the registry of undisposed objects but doesn't dispose of them.
125
*/
126
goog.Disposable.clearUndisposedObjects = function() {
127
goog.Disposable.instances_ = {};
128
};
129
130
131
/**
132
* Whether the object has been disposed of.
133
* @type {boolean}
134
* @private
135
*/
136
goog.Disposable.prototype.disposed_ = false;
137
138
139
/**
140
* Callbacks to invoke when this object is disposed.
141
* @type {Array<!Function>}
142
* @private
143
*/
144
goog.Disposable.prototype.onDisposeCallbacks_;
145
146
147
/**
148
* @return {boolean} Whether the object has been disposed of.
149
* @override
150
*/
151
goog.Disposable.prototype.isDisposed = function() {
152
return this.disposed_;
153
};
154
155
156
/**
157
* @return {boolean} Whether the object has been disposed of.
158
* @deprecated Use {@link #isDisposed} instead.
159
*/
160
goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed;
161
162
163
/**
164
* Disposes of the object. If the object hasn't already been disposed of, calls
165
* {@link #disposeInternal}. Classes that extend {@code goog.Disposable} should
166
* override {@link #disposeInternal} in order to delete references to COM
167
* objects, DOM nodes, and other disposable objects. Reentrant.
168
*
169
* @return {void} Nothing.
170
* @override
171
*/
172
goog.Disposable.prototype.dispose = function() {
173
if (!this.disposed_) {
174
// Set disposed_ to true first, in case during the chain of disposal this
175
// gets disposed recursively.
176
this.disposed_ = true;
177
this.disposeInternal();
178
if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
179
var uid = goog.getUid(this);
180
if (goog.Disposable.MONITORING_MODE ==
181
goog.Disposable.MonitoringMode.PERMANENT &&
182
!goog.Disposable.instances_.hasOwnProperty(uid)) {
183
throw Error(
184
this + ' did not call the goog.Disposable base ' +
185
'constructor or was disposed of after a clearUndisposedObjects ' +
186
'call');
187
}
188
delete goog.Disposable.instances_[uid];
189
}
190
}
191
};
192
193
194
/**
195
* Associates a disposable object with this object so that they will be disposed
196
* together.
197
* @param {goog.disposable.IDisposable} disposable that will be disposed when
198
* this object is disposed.
199
*/
200
goog.Disposable.prototype.registerDisposable = function(disposable) {
201
this.addOnDisposeCallback(goog.partial(goog.dispose, disposable));
202
};
203
204
205
/**
206
* Invokes a callback function when this object is disposed. Callbacks are
207
* invoked in the order in which they were added. If a callback is added to
208
* an already disposed Disposable, it will be called immediately.
209
* @param {function(this:T):?} callback The callback function.
210
* @param {T=} opt_scope An optional scope to call the callback in.
211
* @template T
212
*/
213
goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) {
214
if (this.disposed_) {
215
goog.isDef(opt_scope) ? callback.call(opt_scope) : callback();
216
return;
217
}
218
if (!this.onDisposeCallbacks_) {
219
this.onDisposeCallbacks_ = [];
220
}
221
222
this.onDisposeCallbacks_.push(
223
goog.isDef(opt_scope) ? goog.bind(callback, opt_scope) : callback);
224
};
225
226
227
/**
228
* Deletes or nulls out any references to COM objects, DOM nodes, or other
229
* disposable objects. Classes that extend {@code goog.Disposable} should
230
* override this method.
231
* Not reentrant. To avoid calling it twice, it must only be called from the
232
* subclass' {@code disposeInternal} method. Everywhere else the public
233
* {@code dispose} method must be used.
234
* For example:
235
* <pre>
236
* mypackage.MyClass = function() {
237
* mypackage.MyClass.base(this, 'constructor');
238
* // Constructor logic specific to MyClass.
239
* ...
240
* };
241
* goog.inherits(mypackage.MyClass, goog.Disposable);
242
*
243
* mypackage.MyClass.prototype.disposeInternal = function() {
244
* // Dispose logic specific to MyClass.
245
* ...
246
* // Call superclass's disposeInternal at the end of the subclass's, like
247
* // in C++, to avoid hard-to-catch issues.
248
* mypackage.MyClass.base(this, 'disposeInternal');
249
* };
250
* </pre>
251
* @protected
252
*/
253
goog.Disposable.prototype.disposeInternal = function() {
254
if (this.onDisposeCallbacks_) {
255
while (this.onDisposeCallbacks_.length) {
256
this.onDisposeCallbacks_.shift()();
257
}
258
}
259
};
260
261
262
/**
263
* Returns True if we can verify the object is disposed.
264
* Calls {@code isDisposed} on the argument if it supports it. If obj
265
* is not an object with an isDisposed() method, return false.
266
* @param {*} obj The object to investigate.
267
* @return {boolean} True if we can verify the object is disposed.
268
*/
269
goog.Disposable.isDisposed = function(obj) {
270
if (obj && typeof obj.isDisposed == 'function') {
271
return obj.isDisposed();
272
}
273
return false;
274
};
275
276
277
/**
278
* Calls {@code dispose} on the argument if it supports it. If obj is not an
279
* object with a dispose() method, this is a no-op.
280
* @param {*} obj The object to dispose of.
281
*/
282
goog.dispose = function(obj) {
283
if (obj && typeof obj.dispose == 'function') {
284
obj.dispose();
285
}
286
};
287
288
289
/**
290
* Calls {@code dispose} on each member of the list that supports it. (If the
291
* member is an ArrayLike, then {@code goog.disposeAll()} will be called
292
* recursively on each of its members.) If the member is not an object with a
293
* {@code dispose()} method, then it is ignored.
294
* @param {...*} var_args The list.
295
*/
296
goog.disposeAll = function(var_args) {
297
for (var i = 0, len = arguments.length; i < len; ++i) {
298
var disposable = arguments[i];
299
if (goog.isArrayLike(disposable)) {
300
goog.disposeAll.apply(null, disposable);
301
} else {
302
goog.dispose(disposable);
303
}
304
}
305
};
306
307