2
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3
Code licensed under the BSD License:
4
http://developer.yahoo.net/yui/license.txt
8
YUI.add('oop', function(Y) {
11
* Supplies object inheritance and manipulation utilities. This adds
12
* additional functionaity to what is provided in yui-base, and the
13
* methods are applied directly to the YUI instance. This module
14
* is required for most YUI components.
20
OP = Object.prototype,
21
CLONE_MARKER = "_~yuim~_";
23
// dispatch = function(o, f, c, proto, action) {
24
// if (o[action] && o.item) {
25
// return o[action].call(o, f, c);
27
// switch (A.test(o)) {
29
// return A[action](o, f, c);
31
// return A[action](Y.Array(o, 0, true), f, c);
33
// return Y.Object[action](o, f, c, proto);
39
* The following methods are added to the YUI instance
44
* Applies prototype properties from the supplier to the receiver.
45
* The receiver can be a constructor or an instance.
47
* @param {Function} r the object to receive the augmentation
48
* @param {Function} s the object that supplies the properties to augment
49
* @param ov {boolean} if true, properties already on the receiver
50
* will be overwritten if found on the supplier.
51
* @param wl {string[]} a whitelist. If supplied, only properties in
52
* this list will be applied to the receiver.
53
* @param args {Array | Any} arg or arguments to apply to the supplier
54
* constructor when initializing.
55
* @return {object} the augmented object
57
* @todo constructor optional?
58
* @todo understanding what an instance is augmented with
59
* @TODO best practices for overriding sequestered methods.
61
Y.augment = function(r, s, ov, wl, args) {
62
var sProto = s.prototype,
65
a = (args) ? Y.Array(args) : [],
68
applyConstructor = false,
69
sequestered, replacements, i;
71
// working on a class, so apply constructor infrastructure
72
if (rProto && construct) {
77
// sequester all of the functions in the supplier and replace with
78
// one that will restore all of them.
79
Y.each(sProto, function(v, k) {
80
replacements[k] = function() {
82
// overwrite the prototype with all of the sequestered functions,
83
// but only if it hasn't been overridden
84
for (i in sequestered) {
85
if (sequestered.hasOwnProperty(i) && (this[i] === replacements[i])) {
86
this[i] = sequestered[i];
90
// apply the constructor
91
construct.apply(this, a);
93
// apply the original sequestered function
94
return sequestered[k].apply(this, arguments);
97
if ((!wl || (k in wl)) && (ov || !(k in this))) {
98
if (L.isFunction(v)) {
99
// sequester the function
102
// replace the sequestered function with a function that will
103
// restore all sequestered functions and exectue the constructor.
104
this[k] = replacements[k];
113
// augmenting an instance, so apply the constructor immediately
115
applyConstructor = true;
118
Y.mix(target, newProto || sProto, ov, wl);
120
if (applyConstructor) {
128
* Applies object properties from the supplier to the receiver. If
129
* the target has the property, and the property is an object, the target
130
* object will be augmented with the supplier's value. If the property
131
* is an array, the suppliers value will be appended to the target.
133
* @param {Function} r the object to receive the augmentation
134
* @param {Function} s the object that supplies the properties to augment
135
* @param ov {boolean} if true, properties already on the receiver
136
* will be overwritten if found on the supplier.
137
* @param wl {string[]} a whitelist. If supplied, only properties in
138
* this list will be applied to the receiver.
139
* @return {object} the extended object
141
Y.aggregate = function(r, s, ov, wl) {
142
return Y.mix(r, s, ov, wl, 0, true);
146
* Utility to set up the prototype, constructor and superclass properties to
147
* support an inheritance strategy that can chain constructors and methods.
148
* Static members will not be inherited.
151
* @param {Function} r the object to modify
152
* @param {Function} s the object to inherit
153
* @param {Object} px prototype properties to add/override
154
* @param {Object} sx static properties to add/override
155
* @return {YUI} the YUI instance
157
Y.extend = function(r, s, px, sx) {
159
// @TODO error symbols
160
Y.error("extend failed, verify dependencies");
163
var sp = s.prototype, rp=Y.Object(sp);
169
// assign constructor property
170
if (s != Object && sp.constructor == OP.constructor) {
174
// add prototype overrides
179
// add object overrides
188
* Executes the supplied function for each item in
189
* a collection. Supports arrays, objects, and
192
* @param o the object to iterate
193
* @param f the function to execute. This function
194
* receives the value, key, and object as parameters
195
* @param proto if true, prototype properties are
196
* iterated on objects
197
* @return {YUI} the YUI instance
199
Y.each = function(o, f, c, proto) {
201
if (o.each && o.item) {
202
return o.each.call(o, f, c);
206
return A.each(o, f, c);
208
return A.each(Y.Array(o, 0, true), f, c);
210
return Y.Object.each(o, f, c, proto);
214
// return Y.Object.each(o, f, c);
217
// Y.each = function(o, f, c, proto) {
218
// return dispatch(o, f, c, proto, 'each');
222
* Executes the supplied function for each item in
223
* a collection. The operation stops if the function
224
* returns true. Supports arrays, objects, and
227
* @param o the object to iterate
228
* @param f the function to execute. This function
229
* receives the value, key, and object as parameters
230
* @param proto if true, prototype properties are
231
* iterated on objects
232
* @return {boolean} true if the function ever returns true, false otherwise
234
// Y.some = function(o, f, c, proto) {
235
// return dispatch(o, f, c, proto, 'some');
239
* Deep obj/array copy. Functions are cloned with Y.bind.
240
* Array-like objects are treated as arrays.
241
* Primitives are returned untouched. Optionally, a
242
* function can be provided to handle other data types,
243
* filter keys, validate values, etc.
246
* @param o what to clone
247
* @param safe {boolean} if true, objects will not have prototype
248
* items from the source. If false, they will. In this case, the
249
* original is initially protected, but the clone is not completely immune
250
* from changes to the source object prototype. Also, cloned prototype
251
* items that are deleted from the clone will result in the value
252
* of the source prototype being exposed. If operating on a non-safe
253
* clone, items should be nulled out rather than deleted.
255
* @param f optional function to apply to each item in a collection;
256
* it will be executed prior to applying the value to
257
* the new object. Return false to prevent the copy.
258
* @param c optional execution context for f
259
* @param owner Owner object passed when clone is iterating an
260
* object. Used to set up context for cloned functions.
261
* @return {Array|Object} the cloned object
263
Y.clone = function(o, safe, f, c, owner, cloned) {
265
if (!L.isObject(o)) {
269
var o2, marked = cloned || {}, stamp;
275
return new RegExp(o.source);
277
o2 = Y.bind(o, owner);
284
// #2528250 only one clone of a given object should be created.
285
if (o[CLONE_MARKER]) {
286
return marked[o[CLONE_MARKER]];
291
o2 = (safe) ? {} : Y.Object(o);
293
o[CLONE_MARKER] = stamp;
297
// #2528250 don't try to clone element properties
298
if (!o.addEventListener && !o.attachEvent) {
299
Y.each(o, function(v, k) {
300
if (!f || (f.call(c || this, v, k, this, o) !== false)) {
301
if (k !== CLONE_MARKER) {
302
this[k] = Y.clone(v, safe, f, c, owner || o, marked);
309
Y.each(marked, function(v, k) {
310
delete v[CLONE_MARKER];
320
* Returns a function that will execute the supplied function in the
321
* supplied object's context, optionally adding any additional
322
* supplied parameters to the beginning of the arguments collection the
323
* supplied to the function.
326
* @param f {Function|String} the function to bind, or a function name
327
* to execute on the context object
328
* @param c the execution context
329
* @param args* 0..n arguments to include before the arguments the
330
* function is executed with.
331
* @return {function} the wrapped function
333
Y.bind = function(f, c) {
334
var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
336
var fn = L.isString(f) ? c[f] : f,
337
args = (xargs) ? xargs.concat(Y.Array(arguments, 0, true)) : arguments;
338
return fn.apply(c || fn, args);
343
* Returns a function that will execute the supplied function in the
344
* supplied object's context, optionally adding any additional
345
* supplied parameters to the end of the arguments the function
349
* @param f {Function|String} the function to bind, or a function name
350
* to execute on the context object
351
* @param c the execution context
352
* @param args* 0..n arguments to append to the end of arguments collection
353
* supplied to the function
354
* @return {function} the wrapped function
356
Y.rbind = function(f, c) {
357
var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
359
var fn = L.isString(f) ? c[f] : f,
360
args = (xargs) ? Y.Array(arguments, 0, true).concat(xargs) : arguments;
361
return fn.apply(c || fn, args);